aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2025-05-08 15:10:34 +0200
committerHimbeer <himbeer@disroot.org>2025-05-08 15:10:34 +0200
commitaf5c04c06b32727def8be04f0f73a09c9d5d8972 (patch)
tree6ec2da723e9ad00fcea31bc32aa610dd67299769 /src
parent299a8632fbe235cf2eacbeb91b4c1538ec0427c3 (diff)
Implement statement parsingHEADmain
Diffstat (limited to 'src')
-rw-r--r--src/parse.c290
1 files changed, 289 insertions, 1 deletions
diff --git a/src/parse.c b/src/parse.c
index 656edde..88ebe3e 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -847,6 +847,294 @@ parse_union(struct lexer *lexer, struct ast_union *un)
}
static int
+parse_local_s(struct lexer *lexer, struct ast_local *lv)
+{
+ lv->loc = lex_loc(lexer);
+
+ if (!match(lexer, T_LET)) {
+ return 0;
+ }
+
+ struct token nametok;
+ if (lex(lexer, &nametok) != T_NAME) {
+ error(nametok.loc, "expected local variable name after 'let'");
+ }
+ lv->name = nametok.info.str;
+
+ if (!parse_type(lexer, &lv->type)) {
+ error(lex_loc(lexer), "expected local variable type after its name");
+ }
+
+ lv->init = NULL;
+ if (match(lexer, T_ASSIGN)) {
+ lv->init = must_malloc(sizeof(struct expr));
+ if (!parse_expr(lexer, lv->init)) {
+ error(lex_loc(lexer), "expected initialization expression after '='");
+ }
+ }
+
+ return 1;
+}
+
+static int
+parse_assign_s(struct lexer *lexer, struct ast_assign *a, enum stmt *kind)
+{
+ if (match(lexer, T_ASSIGN)) {
+ *kind = S_ASSIGN;
+ } else if (match(lexer, T_ADDASSIGN)) {
+ *kind = S_ADDASSIGN;
+ } else if (match(lexer, T_SUBASSIGN)) {
+ *kind = S_SUBASSIGN;
+ } else if (match(lexer, T_MULASSIGN)) {
+ *kind = S_MULASSIGN;
+ } else if (match(lexer, T_DIVASSIGN)) {
+ *kind = S_DIVASSIGN;
+ } else if (match(lexer, T_MODASSIGN)) {
+ *kind = S_REMASSIGN;
+ } else if (match(lexer, T_BANDASSIGN)) {
+ *kind = S_BANDASSIGN;
+ } else if (match(lexer, T_BORASSIGN)) {
+ *kind = S_BORASSIGN;
+ } else if (match(lexer, T_BXORASSIGN)) {
+ *kind = S_BXORASSIGN;
+ } else {
+ return 0;
+ }
+
+ if (!parse_expr(lexer, &a->rhs)) {
+ error(lex_loc(lexer), "expected expression on right-hand side of assignment");
+ }
+
+ return 1;
+}
+
+static int
+parse_crement_s(struct lexer *lexer, enum stmt *kind)
+{
+ if (match(lexer, T_INCR)) {
+ *kind = S_INCR;
+ } else if (match(lexer, T_DECR)) {
+ *kind = S_DECR;
+ } else {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+parse_else(struct lexer *lexer, struct ast_else *alt)
+{
+ alt->loc = lex_loc(lexer);
+
+ if (!match(lexer, T_ELSE)) {
+ return 0;
+ }
+
+ alt->action.conditional = must_malloc(sizeof(struct ast_if));
+ if (parse_if(lexer, alt->action.conditional)) {
+ alt->cond = 1;
+ return 1;
+ }
+ free(alt->action.conditional);
+
+ alt->cond = 0;
+
+ if (!match(lexer, T_LBRACE)) {
+ error(lex_loc(lexer), "expected 'if' or '{' after 'else'");
+ }
+
+ alt->action.body.stmts = must_calloc(1, sizeof(struct ast_stmt));
+ alt->action.body.stmtsz = 1;
+ alt->action.body.stmtlen = 0;
+
+ struct ast_stmt stmt;
+ while (parse_stmt(lexer, &stmt, 0)) {
+ if (alt->action.body.stmtlen >= alt->action.body.stmtsz) {
+ alt->action.body.stmtsz *= 2;
+ size_t newsz = alt->action.body.stmtsz * sizeof(struct ast_stmt);
+ alt->action.body.stmts = must_realloc(alt->action.body.stmts, newsz);
+ }
+ alt->action.body.stmts[alt->action.body.stmtlen++] = stmt;
+ }
+
+ if (!match(lexer, T_RBRACE)) {
+ error(lex_loc(lexer), "expected '}' to close else body");
+ }
+
+ return 1;
+}
+
+static int
+parse_if(struct lexer *lexer, struct ast_if *cnd)
+{
+ cnd->loc = lex_loc(lexer);
+
+ if (!match(lexer, T_IF)) {
+ return 0;
+ }
+
+ if (!parse_expr(lexer, &cnd->cond)) {
+ error(lex_loc(lexer), "expected condition expression after 'if'");
+ }
+
+ if (!match(lexer, T_LBRACE)) {
+ error(lex_loc(lexer), "expected '{' after if condition");
+ }
+
+ cnd->stmts = must_calloc(1, sizeof(struct ast_stmt));
+ cnd->stmtsz = 1;
+ cnd->stmtlen = 0;
+
+ struct ast_stmt stmt;
+ while (parse_stmt(lexer, &stmt, 0)) {
+ if (cnd->stmtlen >= cnd->stmtsz) {
+ cnd->stmtsz *= 2;
+ size_t newsz = cnd->stmtsz * sizeof(struct ast_stmt);
+ cnd->stmts = must_realloc(cnd->stmts, newsz);
+ }
+ cnd->stmts[cnd->stmtlen++] = stmt;
+ }
+
+ if (!match(lexer, T_RBRACE)) {
+ error(lex_loc(lexer), "expected '}' to close if body");
+ }
+
+ cnd->alt = must_malloc(sizeof(struct ast_else));
+ if (!parse_else(lexer, cnd->alt)) {
+ free(cnd->alt);
+ cnd->alt = NULL;
+ }
+
+ return 1;
+}
+
+static int
+parse_for(struct lexer *lexer, struct ast_for *loop)
+{
+ loop->loc = lex_loc(lexer);
+
+ if (!match(lexer, T_FOR)) {
+ return 0;
+ }
+
+ loop->init = must_malloc(sizeof(struct ast_stmt));
+ if (!parse_stmt(lexer, loop->init, 1)) {
+ free(loop->init);
+ loop->init = NULL;
+ } else if (loop->init->kind >= S_IF) {
+ error(loop->init->loc, "for loop initializer must not be an if statement, for loop, return or expression");
+ }
+
+ if (!match(lexer, T_SEMICOLON)) {
+ error(lex_loc(lexer), "expected ';' before loop condition");
+ }
+
+ if (!parse_expr(lexer, &loop->cond)) {
+ error(lex_loc(lexer), "expected loop condition expression");
+ }
+
+ if (!match(lexer, T_SEMICOLON)) {
+ error(lex_loc(lexer), "expected ';' after loop condition");
+ }
+
+ loop->step = must_malloc(sizeof(struct ast_stmt));
+ if (!parse_stmt(lexer, loop->step, 1)) {
+ free(loop->step);
+ loop->step = NULL;
+ } else if (loop->step->kind >= S_IF) {
+ error(loop->step->loc, "for loop step must not be an if statement, for loop, return or expression");
+ }
+
+ if (!match(lexer, T_LBRACE)) {
+ error(lex_loc(lexer), "expected '{'");
+ }
+
+ loop->stmts = must_calloc(1, sizeof(struct ast_stmt));
+ loop->stmtsz = 1;
+ loop->stmtlen = 0;
+
+ struct ast_stmt stmt;
+ while (parse_stmt(lexer, &stmt, 0)) {
+ if (loop->stmtlen >= loop->stmtsz) {
+ loop->stmtsz *= 2;
+ size_t newsz = loop->stmtsz * sizeof(struct ast_stmt);
+ loop->stmts = must_realloc(loop->stmts, newsz);
+ }
+ loop->stmts[loop->stmtlen++] = stmt;
+ }
+
+ if (!match(lexer, T_RBRACE)) {
+ error(lex_loc(lexer), "expected '}' to close for loop body");
+ }
+
+ return 1;
+}
+
+static int
+parse_return_s(struct lexer *lexer, struct ast_return *ret)
+{
+ ret->loc = lex_loc(lexer);
+
+ if (!match(lexer, T_RETURN)) {
+ return 0;
+ }
+
+ ret->value = must_malloc(sizeof(struct expr));
+ if (!parse_expr(lexer, ret->value)) {
+ free(ret->value);
+ ret->value = NULL;
+ }
+
+ return 1;
+}
+
+static int
+parse_stmt_exprbased(struct lexer *lexer, struct ast_stmt *stmt)
+{
+ struct expr e;
+ if (!parse_expr(lexer, &e)) {
+ return 0;
+ }
+
+ if (parse_assign_s(lexer, &stmt->stmt.assign, &stmt->kind)) {
+ stmt->stmt.assign.lhs = e;
+ } else if (parse_crement_s(lexer, &stmt->kind)) {
+ stmt->stmt.e = e;
+ } else {
+ stmt->kind = S_EXPR;
+ stmt->stmt.e = e;
+ }
+
+ return 1;
+}
+
+static int
+parse_stmt(struct lexer *lexer, struct ast_stmt *stmt, int nosemi)
+{
+ stmt->loc = lex_loc(lexer);
+
+ if (parse_local_s(lexer, &stmt->stmt.localvar)) {
+ stmt->kind = S_LOCALVAR;
+ } else if (parse_if(lexer, &stmt->stmt.conditional)) {
+ stmt->kind = S_IF;
+ } else if (parse_for(lexer, &stmt->stmt.loop)) {
+ stmt->kind = S_FOR;
+ } else if (parse_return_s(lexer, &stmt->stmt.ret)) {
+ stmt->kind = S_RETURN;
+ } else if (!parse_stmt_exprbased(lexer, stmt)) {
+ return 0;
+ }
+
+ int needsemi = stmt->kind != S_IF && stmt->kind != S_FOR;
+ if (needsemi && !nosemi && !match(lexer, T_SEMICOLON)) {
+ error(lex_loc(lexer), "expected semicolon after statement");
+ }
+
+ return 1;
+}
+
+static int
parse_func(struct lexer *lexer, struct ast_func *fn)
{
fn->loc = lex_loc(lexer);
@@ -905,7 +1193,7 @@ parse_func(struct lexer *lexer, struct ast_func *fn)
fn->stmtlen = 0;
struct ast_stmt stmt;
- while (parse_stmt(lexer, &stmt)) {
+ while (parse_stmt(lexer, &stmt, 0)) {
if (fn->stmtlen >= fn->stmtsz) {
fn->stmtsz *= 2;
size_t newsz = fn->stmtsz * sizeof(struct ast_stmt);