From 1d13ffc11817918e82f0dea192afa38e118186f0 Mon Sep 17 00:00:00 2001 From: cozis Date: Sat, 2 Apr 2022 23:07:37 +0200 Subject: [PATCH] added break statement --- examples/json.noja | 26 ++++++++++++--- src/compiler/ASTi.h | 1 + src/compiler/compile.c | 76 +++++++++++++++++++++++++++--------------- src/compiler/parse.c | 31 +++++++++++++++++ 4 files changed, 103 insertions(+), 31 deletions(-) diff --git a/examples/json.noja b/examples/json.noja index f3ad389..ead191d 100644 --- a/examples/json.noja +++ b/examples/json.noja @@ -9,8 +9,11 @@ fun is_digit(c) and unicode(c) >= unicode('0'); fun skip(ctx, test) - while not ended(ctx) and test(current(ctx)): + while not ended(ctx): { + if not test(current(ctx)): + break; next(ctx); + } fun ended(ctx) return ctx.i == count(ctx.str); @@ -20,8 +23,10 @@ fun next(ctx) { ctx.i = ctx.i + 1; } -fun current(ctx) +fun current(ctx) { + assert(ctx.i < count(ctx.str)); return ctx.str[ctx.i]; +} fun parse(str) { @@ -32,9 +37,10 @@ fun parse(str) { skip(ctx, is_space); - if ended(ctx): - # JSON source string only contains whitespace. + if ended(ctx): { + print('Source only contains whitespace'); return none; + } return parse_any_value(ctx); } @@ -75,4 +81,14 @@ fun parse_any_value(ctx) { assert(false); } -parse(); \ No newline at end of file + +tests = [ + '', + '1' +]; + +i = 0; +while i < count(tests): { + parse(tests[i]); + i = i + 1; +} diff --git a/src/compiler/ASTi.h b/src/compiler/ASTi.h index 3c0c740..98ad2c7 100644 --- a/src/compiler/ASTi.h +++ b/src/compiler/ASTi.h @@ -41,6 +41,7 @@ typedef enum { NODE_FUNC, NODE_ARG, NODE_WHILE, + NODE_BREAK, NODE_DOWHILE, } NodeKind; diff --git a/src/compiler/compile.c b/src/compiler/compile.c index 12d4156..ddd10fc 100644 --- a/src/compiler/compile.c +++ b/src/compiler/compile.c @@ -75,7 +75,7 @@ static Opcode exprkind_to_opcode(ExprKind kind) } } -static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) +static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_dest, Error *error) { assert(node != NULL); @@ -105,7 +105,7 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) OperExprNode *oper = (OperExprNode*) expr; for(Node *operand = oper->head; operand; operand = operand->next) - if(!emit_instr_for_node(exeb, operand, error)) + if(!emit_instr_for_node(exeb, operand, break_dest, error)) return 0; return ExeBuilder_Append(exeb, error, @@ -121,7 +121,7 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) lop = oper->head; rop = lop->next; - if(!emit_instr_for_node(exeb, rop, error)) + if(!emit_instr_for_node(exeb, rop, break_dest, error)) return 0; if(((ExprNode*) lop)->kind == EXPR_IDENT) @@ -137,10 +137,10 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) Node *idx = ((IndexSelectionExprNode*) lop)->idx; Node *set = ((IndexSelectionExprNode*) lop)->set; - if(!emit_instr_for_node(exeb, set, error)) + if(!emit_instr_for_node(exeb, set, break_dest, error)) return 0; - if(!emit_instr_for_node(exeb, idx, error)) + if(!emit_instr_for_node(exeb, idx, break_dest, error)) return 0; if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT2, NULL, 0, node->offset, node->length)) @@ -207,7 +207,7 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) if(!ExeBuilder_Append(exeb, error, OPCODE_PUSHINT, &op, 1, item->offset, item->length)) return 0; - if(!emit_instr_for_node(exeb, item, error)) + if(!emit_instr_for_node(exeb, item, break_dest, error)) return 0; if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT, NULL, 0, item->offset, item->length)) @@ -234,10 +234,10 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) while(item) { - if(!emit_instr_for_node(exeb, key, error)) + if(!emit_instr_for_node(exeb, key, break_dest, error)) return 0; - if(!emit_instr_for_node(exeb, item, error)) + if(!emit_instr_for_node(exeb, item, break_dest, error)) return 0; if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT, NULL, 0, item->offset, item->length)) @@ -258,13 +258,13 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) while(arg) { - if(!emit_instr_for_node(exeb, arg, error)) + if(!emit_instr_for_node(exeb, arg, break_dest, error)) return 0; arg = arg->next; } - if(!emit_instr_for_node(exeb, p->func, error)) + if(!emit_instr_for_node(exeb, p->func, break_dest, error)) return 0; Operand op = { .type = OPTP_INT, .as_int = p->argc }; @@ -275,10 +275,10 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) { IndexSelectionExprNode *sel = (IndexSelectionExprNode*) expr; - if(!emit_instr_for_node(exeb, sel->set, error)) + if(!emit_instr_for_node(exeb, sel->set, break_dest, error)) return 0; - if(!emit_instr_for_node(exeb, sel->idx, error)) + if(!emit_instr_for_node(exeb, sel->idx, break_dest, error)) return 0; return ExeBuilder_Append(exeb, error, OPCODE_SELECT, NULL, 0, node->offset, node->length); @@ -300,11 +300,24 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) break; } + case NODE_BREAK: + { + if(break_dest == NULL) + { + Error_Report(error, 0, "Break not inside a loop"); + return 0; + } + Operand op = (Operand) { .type = OPTP_PROMISE, .as_promise = break_dest }; + if(!ExeBuilder_Append(exeb, error, OPCODE_JUMP, &op, 1, node->offset, node->length)) + return 0; + return 1; + } + case NODE_IFELSE: { IfElseNode *ifelse = (IfElseNode*) node; - if(!emit_instr_for_node(exeb, ifelse->condition, error)) + if(!emit_instr_for_node(exeb, ifelse->condition, break_dest, error)) return 0; if(ifelse->false_branch) @@ -322,7 +335,7 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFNOTANDPOP, &op, 1, node->offset, node->length)) return 0; - if(!emit_instr_for_node(exeb, ifelse->true_branch, error)) + if(!emit_instr_for_node(exeb, ifelse->true_branch, break_dest, error)) return 0; if(ifelse->true_branch->kind == NODE_EXPR) @@ -339,7 +352,7 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) long long int temp = ExeBuilder_InstrCount(exeb); Promise_Resolve(else_offset, &temp, sizeof(temp)); - if(!emit_instr_for_node(exeb, ifelse->false_branch, error)) + if(!emit_instr_for_node(exeb, ifelse->false_branch, break_dest, error)) return 0; if(ifelse->false_branch->kind == NODE_EXPR) @@ -368,7 +381,7 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFNOTANDPOP, &(Operand) { .type = OPTP_PROMISE, .as_promise = done_offset }, 1, node->offset, node->length)) return 0; - if(!emit_instr_for_node(exeb, ifelse->true_branch, error)) + if(!emit_instr_for_node(exeb, ifelse->true_branch, break_dest, error)) return 0; if(ifelse->true_branch->kind == NODE_EXPR) @@ -412,14 +425,14 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) long long int temp = ExeBuilder_InstrCount(exeb); Promise_Resolve(start_offset, &temp, sizeof(temp)); - if(!emit_instr_for_node(exeb, whl->condition, error)) + if(!emit_instr_for_node(exeb, whl->condition, break_dest, error)) return 0; Operand op = { .type = OPTP_PROMISE, .as_promise = end_offset }; if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFNOTANDPOP, &op, 1, whl->condition->offset, whl->condition->length)) return 0; - if(!emit_instr_for_node(exeb, whl->body, error)) + if(!emit_instr_for_node(exeb, whl->body, end_offset, error)) return 0; if(whl->body->kind == NODE_EXPR) @@ -452,9 +465,16 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) * JUMPIFANDPOP start */ + Promise *end_offset = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); + if(end_offset == NULL) + { + Error_Report(error, 1, "No memory"); + return 0; + } + long long int start = ExeBuilder_InstrCount(exeb); - if(!emit_instr_for_node(exeb, dowhl->body, error)) + if(!emit_instr_for_node(exeb, dowhl->body, end_offset, error)) return 0; if(dowhl->body->kind == NODE_EXPR) @@ -464,12 +484,16 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) return 0; } - if(!emit_instr_for_node(exeb, dowhl->condition, error)) + if(!emit_instr_for_node(exeb, dowhl->condition, break_dest, error)) return 0; Operand op = { .type = OPTP_INT, .as_int = start }; if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFANDPOP, &op, 1, dowhl->condition->offset, dowhl->condition->length)) return 0; + + long long int temp = ExeBuilder_InstrCount(exeb); + Promise_Resolve(end_offset, &temp, sizeof(temp)); + Promise_Free(end_offset); return 1; } @@ -481,7 +505,7 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) while(stmt) { - if(!emit_instr_for_node(exeb, stmt, error)) + if(!emit_instr_for_node(exeb, stmt, break_dest, error)) return 0; if(stmt->kind == NODE_EXPR) @@ -501,7 +525,7 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) { ReturnNode *ret = (ReturnNode*) node; - if(!emit_instr_for_node(exeb, ret->val, error)) + if(!emit_instr_for_node(exeb, ret->val, break_dest, error)) return 0; if(!ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, ret->base.offset, ret->base.length)) @@ -558,7 +582,7 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) // Assign the arguments. if(func->argv) - assert(func->argv->kind == NODE_ARG); + { assert(func->argv->kind == NODE_ARG); } ArgumentNode *arg = (ArgumentNode*) func->argv; @@ -573,12 +597,12 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) return 0; if(arg->base.next) - assert(arg->base.next->kind == NODE_ARG); + { assert(arg->base.next->kind == NODE_ARG); } arg = (ArgumentNode*) arg->base.next; } - if(!emit_instr_for_node(exeb, func->body, error)) + if(!emit_instr_for_node(exeb, func->body, NULL, error)) return 0; // Write a return instruction, just @@ -644,7 +668,7 @@ Executable *compile(AST *ast, BPAlloc *alloc, Error *error) if(exeb != NULL) { - if(!emit_instr_for_node(exeb, ast->root, error)) + if(!emit_instr_for_node(exeb, ast->root, NULL, error)) return 0; if(ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, Source_GetSize(ast->src), 0)) diff --git a/src/compiler/parse.c b/src/compiler/parse.c index 867e0e1..7046c21 100644 --- a/src/compiler/parse.c +++ b/src/compiler/parse.c @@ -101,6 +101,7 @@ typedef enum { TKWFALSE, TKWRETURN, TKWWHILE, + TKWBREAK, TKWDO, TEQL, @@ -235,6 +236,7 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error) { TKWFALSE, 5, "false" }, { TKWRETURN, 6, "return" }, { TKWWHILE, 5, "while" }, + { TKWBREAK, 5, "break" }, { TKWDO, 2, "do" }, }; @@ -567,6 +569,35 @@ static Node *parse_statement(Context *ctx) return node; } + case TKWBREAK: + { + Token *token = current_token(ctx); + + next(ctx); // Consume the "break". + + if(current(ctx) != ';') + { + Error_Report(ctx->error, 0, "Got token \"%.*s\" where \";\" was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } + + next(ctx); // Consume the ';'. + + Node *node = BPAlloc_Malloc(ctx->alloc, sizeof(Node)); + + if(node == NULL) + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } + + node->kind = NODE_BREAK; + node->next = NULL; + node->offset = token->offset; + node->length = token->length; + return node; + } + case TKWRETURN: { int offset = current_token(ctx)->offset;