diff options
author | Himbeer <himbeer@disroot.org> | 2024-10-07 13:32:07 +0200 |
---|---|---|
committer | Himbeer <himbeer@disroot.org> | 2024-10-07 13:32:07 +0200 |
commit | 991d4095ba596c55ef4d043a496d5cf63fd667d1 (patch) | |
tree | 81b8cbb600c8c57c00b7df01fa9cea5563de23ee | |
parent | 5ba544c4e016de3d61a296ceeaf7c4a143f3c118 (diff) |
Implement expression-based language redesign
This is the implementation of commit
ce68792c848caee2f184e7a6392d9f1e958da1a1.
-rw-r--r-- | include/cmd.h | 66 | ||||
-rw-r--r-- | include/expr.h | 69 | ||||
-rw-r--r-- | include/parse.h | 109 | ||||
-rw-r--r-- | src/parse.c | 94 |
4 files changed, 183 insertions, 155 deletions
diff --git a/include/cmd.h b/include/cmd.h new file mode 100644 index 0000000..2cf69b4 --- /dev/null +++ b/include/cmd.h @@ -0,0 +1,66 @@ +#ifndef CERC_CMD_H +#define CERC_CMD_H +#include "type.h" + +struct ast_return { + struct ast_expr *value; +}; + +struct ast_break { + const char *label; + struct ast_expr *value; +}; + +struct ast_declaration { + bool mut; + const char *name; + struct ast_expr *value; +}; + +enum statement { + STM_RETURN, + STM_BREAK, + STM_CONTINUE, + STM_DECL, + STM_DEFER, +}; + +struct ast_statement { + enum statement action; + union { + struct ast_return ret; + struct ast_break brk; + struct ast_declaration decl; + struct assign_e *assign; + struct call_e *call; + } stmt; +}; + +struct ast_func { + bool exported; + const char *name; + struct type *ret; + struct ast_param *params; + int paramsz, paramlen; + struct ast_block *block; +}; +struct ast_block { + const char *label; + struct ast_cmd *cmds; + int cmdsz, cmdlen; +}; + +enum command { + CMD_BLOCK, + CMD_STATEMENT, +}; + +struct ast_cmd { + enum command kind; + union { + struct ast_block blk; + struct ast_statement stmt; + } cmd; +}; + +#endif diff --git a/include/expr.h b/include/expr.h index 5a16f30..5f57349 100644 --- a/include/expr.h +++ b/include/expr.h @@ -1,6 +1,7 @@ #ifndef CERC_EXPR_H #define CERC_EXPR_H #include <stdbool.h> +#include "cmd.h" #include "lex.h" #include "type.h" @@ -15,6 +16,38 @@ struct array_e { int elemsz, elemlen; }; +struct elseif { + struct disjunction_e *cond; + struct ast_block blk; +}; + +struct if_e { + struct disjunction_e *cond; + struct ast_block blk; + struct elseif *alts; + struct ast_block *alt; + int altsz, altlen; +}; + +struct for_e { + struct ast_assign *init, *action; + struct disjunction_e *cond; + struct ast_block blk; +}; + +enum control { + CTL_IF, + CTL_FOR, +}; + +struct control_e { + enum control kind; + union { + struct if_e branch; + struct for_e loop; + } ctl; +}; + enum literal { LIT_BOOL, LIT_STRING, @@ -32,26 +65,52 @@ struct literal_e { } lit; }; -struct call_e { +struct location_e { struct path *path; + struct loc_postfix *subs; + int subsz, sublen; +}; + +struct assign_e { + struct location_e dst; + struct ast_expr *value; +}; + +struct call_e { + struct location_e *loc; struct disjunction_e *args; int argsz, arglen; }; +enum named { + NMD_ASSIGN, + NMD_CALL, + NMD_LOCATION, +}; + +struct named_e { + enum named kind; + struct location_e loc; + union { + struct assign_e assign; + struct call_e call; + } nmd; +}; + enum primary { + PRM_CONTROL, PRM_GROUPING, PRM_LITERAL, - PRM_CALL, - PRM_PATH, + PRM_NAMED, }; struct primary_e { enum primary kind; union { + struct control_e ctl; struct disjunction_e *grp; struct literal_e lit; - struct call_e call; - struct path *path; + struct named_e nmd; } prim; }; diff --git a/include/parse.h b/include/parse.h index 0889f91..5b97353 100644 --- a/include/parse.h +++ b/include/parse.h @@ -18,27 +18,6 @@ struct ast_param { struct type type; }; -struct ast_block { - const char *label; - struct ast_cmd *cmds; - int cmdsz, cmdlen; -}; - -struct ast_return { - struct ast_expr *value; -}; - -struct ast_break { - const char *label; - struct ast_expr *value; -}; - -struct ast_declaration { - bool mut; - const char *name; - struct ast_expr value; -}; - enum subfield { SUB_INDEX, SUB_FIELD, @@ -52,94 +31,6 @@ struct loc_postfix { } id; }; -struct ast_location { - const char *name; - struct loc_postfix *subs; - int subsz, sublen; -}; - -struct ast_assign { - struct ast_location dst; - struct ast_expr value; -}; - -enum statement { - STM_RETURN, - STM_BREAK, - STM_CONTINUE, - STM_DECL, - STM_ASSIGN, - STM_CALL, - STM_DEFER, -}; - -struct ast_statement { - enum statement action; - union { - struct ast_return ret; - struct ast_break brk; - struct ast_declaration decl; - struct ast_assign assign; - struct call_e call; - } stmt; -}; - -struct ast_elseif { - struct ast_expr cond; - struct ast_block blk; -}; - -struct ast_if { - struct ast_expr cond; - struct ast_block blk; - struct ast_elseif *alts; - struct ast_block *alt; - int altsz, altlen; -}; - -struct ast_for { - struct ast_assign *init, *action; - struct ast_expr cond; - struct ast_block blk; -}; - -enum control { - CTL_IF, - CTL_FOR, -}; - -struct ast_control { - enum control kind; - union { - struct ast_if branch; - struct ast_for loop; - } ctl; -}; - -enum command { - CMD_BLOCK, - CMD_STATEMENT, - CMD_CONTROL, -}; - -struct ast_cmd { - enum command kind; - union { - struct ast_block blk; - struct ast_statement stmt; - struct ast_control ctl; - } cmd; -}; - -struct ast_func { - bool exported; - const char *name; - struct type ret; - struct ast_param *params; - int paramsz, paramlen; - struct ast_block block; -}; - enum const_global { CST_TYPE, CST_BOOL, diff --git a/src/parse.c b/src/parse.c index ee115d8..c5ced09 100644 --- a/src/parse.c +++ b/src/parse.c @@ -12,6 +12,9 @@ static bool parse_disjunction_e(struct lexer *lexer, static bool parse_array(struct lexer *lexer, struct type *out); static bool parse_type(struct lexer *lexer, struct type *out); static bool parse_block(struct lexer *lexer, struct ast_block *out); +static bool parse_control_e(struct lexer *lexer, struct control_e *out); +static bool parse_location(struct lexer *lexer, struct location_e *out); +static bool parse_assignment_e(struct lexer *lexer, struct assign_e *out); static noreturn void error(struct location loc, const char *fmt, ...) @@ -188,14 +191,13 @@ parse_literal_e(struct lexer *lexer, struct literal_e *out) // Invariant: Only called from parse_primary_e with path already consumed. static bool -parse_call_e(struct lexer *lexer, struct call_e *out, struct path path) +parse_call_e(struct lexer *lexer, struct call_e *out, struct location_e *loc) { if (!match(lexer, T_LPAREN)) { return false; } - out->path = must_malloc(sizeof(struct path)); - *out->path = path; + out->loc = loc; out->args = must_calloc(1, sizeof(struct disjunction_e)); out->argsz = 1; @@ -219,8 +221,32 @@ parse_call_e(struct lexer *lexer, struct call_e *out, struct path path) } static bool +parse_named_e(struct lexer *lexer, struct named_e *out) +{ + if (!parse_location(lexer, &out->loc)) { + return false; + } + + if (parse_assignment_e(lexer, &out->nmd.assign)) { + out->kind = NMD_ASSIGN; + return true; + } + if (parse_call_e(lexer, &out->nmd.call, &out->loc)) { + out->kind = NMD_CALL; + return true; + } + + out->kind = NMD_LOCATION; + return true; +} + +static bool parse_primary_e(struct lexer *lexer, struct primary_e *out) { + if (parse_control_e(lexer, &out->prim.ctl)) { + out->kind = PRM_CONTROL; + return true; + } out->prim.grp = must_malloc(sizeof(struct disjunction_e)); if (parse_grouping_e(lexer, out->prim.grp)) { out->kind = PRM_GROUPING; @@ -231,14 +257,12 @@ parse_primary_e(struct lexer *lexer, struct primary_e *out) out->kind = PRM_LITERAL; return true; } - out->prim.path = must_malloc(sizeof(struct path)); - if (parse_path(lexer, out->prim.path)) { - out->kind = PRM_PATH; - if (parse_call_e(lexer, &out->prim.call, *out->prim.path)) { - out->kind = PRM_CALL; - } + if (parse_named_e(lexer, &out->prim.nmd)) { + out->kind = PRM_NAMED; return true; } + + return false; } static bool @@ -1178,7 +1202,8 @@ parse_declaration(struct lexer *lexer, struct ast_declaration *out) error(lex_loc(lexer), "syntax error: expected '='"); } - if (!parse_expr(lexer, &out->value)) { + out->value = must_malloc(sizeof(struct ast_expr)); + if (!parse_expr(lexer, out->value)) { error(lex_loc(lexer), "syntax error: expected expression"); } @@ -1235,11 +1260,11 @@ parse_loc_postfix(struct lexer *lexer, struct loc_postfix *out) } static bool -parse_location(struct lexer *lexer, struct ast_location *out) +parse_location(struct lexer *lexer, struct location_e *out) { - struct token name; - if (lex(lexer, &name) != T_NAME) { - unlex(lexer, &name); + out->path = must_malloc(sizeof(struct path)); + if (!parse_path(lexer, out->path)) { + free(out->path); return false; } @@ -1261,7 +1286,7 @@ parse_location(struct lexer *lexer, struct ast_location *out) } static bool -parse_assignment(struct lexer *lexer, struct ast_assign *out) +parse_assignment_e(struct lexer *lexer, struct assign_e *out) { if (!parse_location(lexer, &out->dst)) { return false; @@ -1271,7 +1296,8 @@ parse_assignment(struct lexer *lexer, struct ast_assign *out) error(lex_loc(lexer), "syntax error: expected '='"); } - if (!parse_expr(lexer, &out->value)) { + out->value = must_malloc(sizeof(struct ast_expr)); + if (!parse_expr(lexer, out->value)) { error(lex_loc(lexer), "syntax error: expected expression"); } @@ -1292,12 +1318,12 @@ parse_defer(struct lexer *lexer, struct call_e *out) return false; } - struct path path; - if (!parse_path(lexer, &path)) { + struct location_e *loc = must_malloc(sizeof(struct location_e)); + if (!parse_location(lexer, loc)) { error(lex_loc(lexer), "syntax error: expected path"); } - if (!parse_call_e(lexer, out, path)) { + if (!parse_call_e(lexer, out, loc)) { error(lex_loc(lexer), "syntax error: expected call"); } @@ -1335,33 +1361,21 @@ parse_statement(struct lexer *lexer, struct ast_statement *out) } return true; } - if (parse_assignment(lexer, &out->stmt.assign)) { - out->action = STM_ASSIGN; - if (!match(lexer, T_SEMICOLON)) { - error(lex_loc(lexer), "syntax error: expected semicolon"); - } - return true; - } - if (parse_call(lexer, &out->stmt.call)) { - out->action = STM_CALL; - if (!match(lexer, T_SEMICOLON)) { - error(lex_loc(lexer), "syntax error: expected semicolon"); - } - return true; - } - if (parse_defer(lexer, &out->stmt.call)) { + out->stmt.call = must_malloc(sizeof(struct call_e)); + if (parse_defer(lexer, out->stmt.call)) { out->action = STM_DEFER; if (!match(lexer, T_SEMICOLON)) { error(lex_loc(lexer), "syntax error: expected semicolon"); } return true; } + free(out->stmt.call); return false; } static bool -parse_control(struct lexer *lexer, struct ast_control *out) +parse_control_e(struct lexer *lexer, struct control_e *out) { /* TODO */ return false; @@ -1378,10 +1392,6 @@ parse_command(struct lexer *lexer, struct ast_cmd *out) out->kind = CMD_STATEMENT; return true; } - if (parse_control(lexer, &out->cmd.ctl)) { - out->kind = CMD_CONTROL; - return true; - } return false; } @@ -1476,9 +1486,11 @@ parse_function(struct lexer *lexer, struct ast_func *out) error(lex_loc(lexer), "syntax error: expected ')'"); } - bool nonvoid = parse_type(lexer, &out->ret); + out->ret = must_malloc(sizeof(struct type)); + bool nonvoid = parse_type(lexer, out->ret); - if (!parse_block(lexer, &out->block)) { + out->block = must_malloc(sizeof(struct ast_block)); + if (!parse_block(lexer, out->block)) { error(lex_loc(lexer), "syntax error: expected block"); } |