aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-10-01 11:34:25 +0200
committerHimbeer <himbeer@disroot.org>2024-10-01 13:51:28 +0200
commit659e0cc1099cd119bcd372928feed340b1d80cb7 (patch)
tree7caaeb13326318164b8ebabf1804e2e5f7486228
parent412123d583f748b5f3797e6a57acae22cb1ffa80 (diff)
Implement statement parsing
-rw-r--r--src/parse.c306
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 '}'");