diff options
author | Himbeer <himbeer@disroot.org> | 2024-10-01 11:34:25 +0200 |
---|---|---|
committer | Himbeer <himbeer@disroot.org> | 2024-10-01 13:51:28 +0200 |
commit | 659e0cc1099cd119bcd372928feed340b1d80cb7 (patch) | |
tree | 7caaeb13326318164b8ebabf1804e2e5f7486228 | |
parent | 412123d583f748b5f3797e6a57acae22cb1ffa80 (diff) |
Implement statement parsing
-rw-r--r-- | src/parse.c | 306 |
1 files changed, 303 insertions, 3 deletions
diff --git a/src/parse.c b/src/parse.c index e906271..d491e4f 100644 --- a/src/parse.c +++ b/src/parse.c @@ -11,6 +11,7 @@ static bool parse_disjunction_e(struct lexer *lexer, struct disjunction_e *out); 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 noreturn void error(struct location loc, const char *fmt, ...) @@ -104,10 +105,10 @@ parse_string(struct lexer *lexer, char **out) bool isstr = false; while (lex(lexer, &s) == T_STRING) { if (*out) { - *out = strdup(s.info.str); - } else { size_t sz = strlen(*out) + strlen(s.info.str) + 1; *out = must_realloc(*out, sz); + } else { + *out = strdup(s.info.str); } isstr = true; @@ -1073,13 +1074,312 @@ parse_externfunc(struct lexer *lexer, struct ast_externfunc *out) } static bool +parse_return(struct lexer *lexer, struct ast_return *out) +{ + if (!match(lexer, T_RETURN)) { + return false; + } + + if (!parse_expr(lexer, &out->value)) { + error(lex_loc(lexer), "syntax error: expected expression"); + } + + return true; +} + +static bool +parse_break(struct lexer *lexer, const char **out) +{ + if (!match(lexer, T_BREAK)) { + return false; + } + + if (!match(lexer, T_COLON)) { + *out = NULL; + return true; + } + + struct token label; + if (lex(lexer, &label) != T_NAME) { + error(lex_loc(lexer), "syntax error: expected name"); + } + *out = label.info.str; + + return true; +} + +static bool +parse_continue(struct lexer *lexer, const char **out) +{ + if (!match(lexer, T_CONTINUE)) { + return false; + } + + if (!match(lexer, T_COLON)) { + *out = NULL; + return true; + } + + struct token label; + if (lex(lexer, &label) != T_NAME) { + error(lex_loc(lexer), "syntax error: expected name"); + } + *out = label.info.str; + + return true; +} + +static bool +parse_declaration(struct lexer *lexer, struct ast_declaration *out) +{ + if (!match(lexer, T_LET)) { + return false; + } + + if (match(lexer, T_MUT)) { + out->mut = true; + } else { + out->mut = false; + } + + struct token name; + if (lex(lexer, &name) != T_NAME) { + error(lex_loc(lexer), "syntax error: expected name"); + } + out->name = name.info.str; + + if (!match(lexer, T_ASSIGN)) { + error(lex_loc(lexer), "syntax error: expected '='"); + } + + if (!parse_expr(lexer, &out->value)) { + error(lex_loc(lexer), "syntax error: expected expression"); + } + + return true; +} + +static bool +parse_subindex(struct lexer *lexer, struct ast_expr *out) +{ + if (!match(lexer, T_LBRACKET)) { + return false; + } + + if (!parse_expr(lexer, out)) { + error(lex_loc(lexer), "syntax error: expected expression"); + } + + if (!match(lexer, T_RBRACKET)) { + error(lex_loc(lexer), "syntax error: expected ']'"); + } + + return true; +} + +static bool +parse_subfield(struct lexer *lexer, const char **out) +{ + if (!match(lexer, T_DOT)) { + return false; + } + + struct token name; + if (lex(lexer, &name) != T_NAME) { + error(lex_loc(lexer), "syntax error: expected name"); + } + *out = name.info.str; + + return true; +} + +static bool +parse_loc_postfix(struct lexer *lexer, struct loc_postfix *out) +{ + if (parse_subindex(lexer, &out->id.index)) { + out->sub = SUB_INDEX; + return true; + } + if (parse_subfield(lexer, &out->id.field)) { + out->sub = SUB_FIELD; + return true; + } + + return false; +} + +static bool +parse_location(struct lexer *lexer, struct ast_location *out) +{ + struct token name; + if (lex(lexer, &name) != T_NAME) { + unlex(lexer, &name); + return false; + } + + out->subs = must_calloc(1, sizeof(struct loc_postfix)); + out->subsz = 1; + out->sublen = 0; + + struct loc_postfix sub; + while (parse_loc_postfix(lexer, &sub)) { + if (out->sublen >= out->subsz) { + out->subsz *= 2; + size_t sz = sizeof(struct loc_postfix) * out->subsz; + out->subs = must_realloc(out->subs, sz); + } + out->subs[out->sublen++] = sub; + } + + return true; +} + +static bool +parse_assignment(struct lexer *lexer, struct ast_assign *out) +{ + if (!parse_location(lexer, &out->dst)) { + return false; + } + + if (!match(lexer, T_ASSIGN)) { + error(lex_loc(lexer), "syntax error: expected '='"); + } + + if (!parse_expr(lexer, &out->value)) { + error(lex_loc(lexer), "syntax error: expected expression"); + } + + return true; +} + +static bool +parse_call(struct lexer *lexer, struct call_e *out) +{ + /* TODO */ + return false; +} + +static bool +parse_defer(struct lexer *lexer, struct call_e *out) +{ + if (!match(lexer, T_DEFER)) { + return false; + } + + struct path path; + if (!parse_path(lexer, &path)) { + error(lex_loc(lexer), "syntax error: expected path"); + } + + if (!parse_call_e(lexer, out, path)) { + error(lex_loc(lexer), "syntax error: expected call"); + } + + return true; +} + +static bool +parse_statement(struct lexer *lexer, struct ast_statement *out) +{ + if (parse_return(lexer, &out->stmt.ret)) { + out->action = STM_RETURN; + if (!match(lexer, T_SEMICOLON)) { + error(lex_loc(lexer), "syntax error: expected semicolon"); + } + return true; + } + if (parse_break(lexer, &out->stmt.brklabel)) { + out->action = STM_BREAK; + if (!match(lexer, T_SEMICOLON)) { + error(lex_loc(lexer), "syntax error: expected semicolon"); + } + return true; + } + if (parse_continue(lexer, &out->stmt.brklabel)) { + out->action = STM_CONTINUE; + if (!match(lexer, T_SEMICOLON)) { + error(lex_loc(lexer), "syntax error: expected semicolon"); + } + return true; + } + if (parse_declaration(lexer, &out->stmt.decl)) { + out->action = STM_DECL; + if (!match(lexer, T_SEMICOLON)) { + error(lex_loc(lexer), "syntax error: expected semicolon"); + } + 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->action = STM_DEFER; + if (!match(lexer, T_SEMICOLON)) { + error(lex_loc(lexer), "syntax error: expected semicolon"); + } + return true; + } + + return false; +} + +static bool +parse_control(struct lexer *lexer, struct ast_control *out) +{ + /* TODO */ + return false; +} + +static bool +parse_command(struct lexer *lexer, struct ast_cmd *out) +{ + if (parse_block(lexer, &out->cmd.blk)) { + out->kind = CMD_BLOCK; + return true; + } + if (parse_statement(lexer, &out->cmd.stmt)) { + out->kind = CMD_STATEMENT; + return true; + } + if (parse_control(lexer, &out->cmd.ctl)) { + out->kind = CMD_CONTROL; + return true; + } + + return false; +} + +static bool parse_block(struct lexer *lexer, struct ast_block *out) { if (!match(lexer, T_LBRACE)) { return false; } - /* TODO */ + out->cmds = must_calloc(1, sizeof(struct ast_cmd)); + out->cmdsz = 1; + out->cmdlen = 0; + + struct ast_cmd cmd; + while (parse_command(lexer, &cmd)) { + if (out->cmdlen >= out->cmdsz) { + out->cmdsz *= 2; + size_t sz = sizeof(struct ast_cmd) * out->cmdsz; + out->cmds = must_realloc(out->cmds, sz); + } + out->cmds[out->cmdlen++] = cmd; + } if (!match(lexer, T_RBRACE)) { error(lex_loc(lexer), "syntax error: expected '}'"); |