Files
rosetta/toolchain/ifc/parse.c

288 lines
5.4 KiB
C
Raw Normal View History

#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, &param_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;
}