288 lines
5.4 KiB
C
288 lines
5.4 KiB
C
|
|
#include "ctx.h"
|
||
|
|
#include "interface.h"
|
||
|
|
#include "lex.h"
|
||
|
|
#include "msg.h"
|
||
|
|
|
||
|
|
#include <stdio.h>
|
||
|
|
|
||
|
|
#define report_error(...) fprintf(stderr, __VA_ARGS__)
|
||
|
|
|
||
|
|
static bool peek_keyword(struct lex *lex, enum token_keyword kw)
|
||
|
|
{
|
||
|
|
struct token *tok = lex_peek(lex);
|
||
|
|
return (tok && tok->tok_type == TOK_KEYWORD && tok->tok_kw == kw);
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool parse_keyword(struct lex *lex, enum token_keyword kw)
|
||
|
|
{
|
||
|
|
struct token *tok = lex_peek(lex);
|
||
|
|
if (!tok || tok->tok_type != TOK_KEYWORD || tok->tok_kw != kw) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
lex_advance(lex);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool parse_symbol(struct lex *lex, enum token_symbol sym)
|
||
|
|
{
|
||
|
|
struct token *tok = lex_peek(lex);
|
||
|
|
if (!tok || tok->tok_type != TOK_SYMBOL || tok->tok_sym != sym) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
lex_advance(lex);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool parse_word(struct lex *lex, char **out)
|
||
|
|
{
|
||
|
|
struct token *tok = lex_peek(lex);
|
||
|
|
if (!tok || tok->tok_type != TOK_WORD) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
*out = tok->tok_str;
|
||
|
|
tok->tok_str = NULL;
|
||
|
|
lex_advance(lex);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct msg_definition *parse_msg_definition(struct ctx *ctx, struct lex *lex)
|
||
|
|
{
|
||
|
|
struct msg_definition *msg = NULL;
|
||
|
|
|
||
|
|
if (!parse_keyword(lex, KW_MSG)) {
|
||
|
|
report_error("expected `msg` keyword\n");
|
||
|
|
goto fail;
|
||
|
|
}
|
||
|
|
|
||
|
|
char *msg_name = NULL;
|
||
|
|
if (!parse_word(lex, &msg_name)) {
|
||
|
|
report_error("expected message identifier\n");
|
||
|
|
goto fail;
|
||
|
|
}
|
||
|
|
|
||
|
|
msg = msg_definition_create(msg_name);
|
||
|
|
free(msg_name);
|
||
|
|
|
||
|
|
if (!parse_symbol(lex, SYM_LEFT_PAREN)) {
|
||
|
|
report_error("expected `(` after message identifier\n");
|
||
|
|
goto fail;
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t i = 0;
|
||
|
|
bool ok = true;
|
||
|
|
while (ok) {
|
||
|
|
if (parse_symbol(lex, SYM_RIGHT_PAREN)) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (i > 0 && !parse_symbol(lex, SYM_COMMA)) {
|
||
|
|
report_error("expected `,` after message parameter\n");
|
||
|
|
ok = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
char *type_name;
|
||
|
|
if (!parse_word(lex, &type_name)) {
|
||
|
|
report_error("expected message parameter type\n");
|
||
|
|
ok = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
const struct type *type = ctx_get_type(ctx, type_name);
|
||
|
|
if (!type) {
|
||
|
|
report_error(
|
||
|
|
"message parameter has unknown type "
|
||
|
|
"'%s'\n",
|
||
|
|
type_name);
|
||
|
|
free(type_name);
|
||
|
|
ok = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
free(type_name);
|
||
|
|
|
||
|
|
char *param_name;
|
||
|
|
if (!parse_word(lex, ¶m_name)) {
|
||
|
|
report_error("expected message parameter name\n");
|
||
|
|
ok = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool duplicate = msg_definition_has_param(msg, param_name)
|
||
|
|
|| msg_definition_has_result(msg, param_name);
|
||
|
|
if (duplicate) {
|
||
|
|
free(param_name);
|
||
|
|
report_error(
|
||
|
|
"message has multiple parameters/results with "
|
||
|
|
"name '%s'\n",
|
||
|
|
param_name);
|
||
|
|
ok = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
msg_definition_add_param(msg, type, param_name);
|
||
|
|
free(param_name);
|
||
|
|
i++;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!ok) {
|
||
|
|
goto fail;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!parse_symbol(lex, SYM_HYPHEN_RIGHT_ANGLE)) {
|
||
|
|
report_error("expected `->` after message parameter list\n");
|
||
|
|
goto fail;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!parse_symbol(lex, SYM_LEFT_PAREN)) {
|
||
|
|
report_error("expected `(` for message results list\n");
|
||
|
|
goto fail;
|
||
|
|
}
|
||
|
|
|
||
|
|
i = 0;
|
||
|
|
while (ok) {
|
||
|
|
if (parse_symbol(lex, SYM_RIGHT_PAREN)) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (i > 0 && !parse_symbol(lex, SYM_COMMA)) {
|
||
|
|
report_error(
|
||
|
|
"expected `,` or `)` after message result\n");
|
||
|
|
ok = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
char *type_name;
|
||
|
|
if (!parse_word(lex, &type_name)) {
|
||
|
|
report_error("expected message result type\n");
|
||
|
|
ok = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
const struct type *type = ctx_get_type(ctx, type_name);
|
||
|
|
if (!type) {
|
||
|
|
report_error(
|
||
|
|
"message result has unknown type "
|
||
|
|
"'%s'\n",
|
||
|
|
type_name);
|
||
|
|
free(type_name);
|
||
|
|
ok = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
free(type_name);
|
||
|
|
|
||
|
|
char *result_name;
|
||
|
|
if (!parse_word(lex, &result_name)) {
|
||
|
|
report_error("expected message parameter name\n");
|
||
|
|
ok = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool duplicate = msg_definition_has_param(msg, result_name)
|
||
|
|
|| msg_definition_has_result(msg, result_name);
|
||
|
|
if (duplicate) {
|
||
|
|
report_error(
|
||
|
|
"message has multiple parameters/results with "
|
||
|
|
"name '%s'\n",
|
||
|
|
result_name);
|
||
|
|
free(result_name);
|
||
|
|
ok = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
msg_definition_add_result(msg, type, result_name);
|
||
|
|
free(result_name);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!parse_symbol(lex, SYM_SEMICOLON)) {
|
||
|
|
report_error("expected `;` after message definition\n");
|
||
|
|
goto fail;
|
||
|
|
}
|
||
|
|
|
||
|
|
return msg;
|
||
|
|
|
||
|
|
fail:
|
||
|
|
if (msg) {
|
||
|
|
msg_definition_destroy(msg);
|
||
|
|
}
|
||
|
|
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct interface_definition *parse_interface_definition(
|
||
|
|
struct ctx *ctx,
|
||
|
|
struct lex *lex)
|
||
|
|
{
|
||
|
|
struct interface_definition *iface = NULL;
|
||
|
|
|
||
|
|
if (!parse_keyword(lex, KW_INTERFACE)) {
|
||
|
|
report_error("expected `interface` keyword");
|
||
|
|
goto fail;
|
||
|
|
}
|
||
|
|
|
||
|
|
char *if_name = NULL;
|
||
|
|
if (!parse_word(lex, &if_name)) {
|
||
|
|
report_error("expected interface identifier");
|
||
|
|
goto fail;
|
||
|
|
}
|
||
|
|
|
||
|
|
iface = interface_definition_create(if_name);
|
||
|
|
free(if_name);
|
||
|
|
if (!iface) {
|
||
|
|
goto fail;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!parse_symbol(lex, SYM_LEFT_BRACE)) {
|
||
|
|
report_error("expected `{` after interface identifier");
|
||
|
|
goto fail;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ok = true;
|
||
|
|
|
||
|
|
while (ok) {
|
||
|
|
if (parse_symbol(lex, SYM_RIGHT_BRACE)) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (peek_keyword(lex, KW_MSG)) {
|
||
|
|
struct msg_definition *msg
|
||
|
|
= parse_msg_definition(ctx, lex);
|
||
|
|
if (!msg) {
|
||
|
|
ok = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (interface_definition_has_msg(
|
||
|
|
iface,
|
||
|
|
msg->msg_name)) {
|
||
|
|
msg_definition_destroy(msg);
|
||
|
|
ok = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
interface_definition_add_msg(iface, msg);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
report_error("expected `}` or message definition\n");
|
||
|
|
ok = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!ok) {
|
||
|
|
goto fail;
|
||
|
|
}
|
||
|
|
|
||
|
|
return iface;
|
||
|
|
|
||
|
|
fail:
|
||
|
|
if (iface) {
|
||
|
|
interface_definition_destroy(iface);
|
||
|
|
}
|
||
|
|
|
||
|
|
return NULL;
|
||
|
|
}
|