added break statement

This commit is contained in:
cozis
2022-04-02 23:07:37 +02:00
parent d03bb4937d
commit 1d13ffc118
4 changed files with 103 additions and 31 deletions
+21 -5
View File
@@ -9,8 +9,11 @@ fun is_digit(c)
and unicode(c) >= unicode('0'); and unicode(c) >= unicode('0');
fun skip(ctx, test) fun skip(ctx, test)
while not ended(ctx) and test(current(ctx)): while not ended(ctx): {
if not test(current(ctx)):
break;
next(ctx); next(ctx);
}
fun ended(ctx) fun ended(ctx)
return ctx.i == count(ctx.str); return ctx.i == count(ctx.str);
@@ -20,8 +23,10 @@ fun next(ctx) {
ctx.i = ctx.i + 1; ctx.i = ctx.i + 1;
} }
fun current(ctx) fun current(ctx) {
assert(ctx.i < count(ctx.str));
return ctx.str[ctx.i]; return ctx.str[ctx.i];
}
fun parse(str) { fun parse(str) {
@@ -32,9 +37,10 @@ fun parse(str) {
skip(ctx, is_space); skip(ctx, is_space);
if ended(ctx): if ended(ctx): {
# JSON source string only contains whitespace. print('Source only contains whitespace');
return none; return none;
}
return parse_any_value(ctx); return parse_any_value(ctx);
} }
@@ -75,4 +81,14 @@ fun parse_any_value(ctx) {
assert(false); assert(false);
} }
parse();
tests = [
'',
'1'
];
i = 0;
while i < count(tests): {
parse(tests[i]);
i = i + 1;
}
+1
View File
@@ -41,6 +41,7 @@ typedef enum {
NODE_FUNC, NODE_FUNC,
NODE_ARG, NODE_ARG,
NODE_WHILE, NODE_WHILE,
NODE_BREAK,
NODE_DOWHILE, NODE_DOWHILE,
} NodeKind; } NodeKind;
+50 -26
View File
@@ -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); assert(node != NULL);
@@ -105,7 +105,7 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
OperExprNode *oper = (OperExprNode*) expr; OperExprNode *oper = (OperExprNode*) expr;
for(Node *operand = oper->head; operand; operand = operand->next) 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 0;
return ExeBuilder_Append(exeb, error, return ExeBuilder_Append(exeb, error,
@@ -121,7 +121,7 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
lop = oper->head; lop = oper->head;
rop = lop->next; rop = lop->next;
if(!emit_instr_for_node(exeb, rop, error)) if(!emit_instr_for_node(exeb, rop, break_dest, error))
return 0; return 0;
if(((ExprNode*) lop)->kind == EXPR_IDENT) 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 *idx = ((IndexSelectionExprNode*) lop)->idx;
Node *set = ((IndexSelectionExprNode*) lop)->set; 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; return 0;
if(!emit_instr_for_node(exeb, idx, error)) if(!emit_instr_for_node(exeb, idx, break_dest, error))
return 0; return 0;
if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT2, NULL, 0, node->offset, node->length)) 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)) if(!ExeBuilder_Append(exeb, error, OPCODE_PUSHINT, &op, 1, item->offset, item->length))
return 0; return 0;
if(!emit_instr_for_node(exeb, item, error)) if(!emit_instr_for_node(exeb, item, break_dest, error))
return 0; return 0;
if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT, NULL, 0, item->offset, item->length)) 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) while(item)
{ {
if(!emit_instr_for_node(exeb, key, error)) if(!emit_instr_for_node(exeb, key, break_dest, error))
return 0; return 0;
if(!emit_instr_for_node(exeb, item, error)) if(!emit_instr_for_node(exeb, item, break_dest, error))
return 0; return 0;
if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT, NULL, 0, item->offset, item->length)) 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) while(arg)
{ {
if(!emit_instr_for_node(exeb, arg, error)) if(!emit_instr_for_node(exeb, arg, break_dest, error))
return 0; return 0;
arg = arg->next; 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; return 0;
Operand op = { .type = OPTP_INT, .as_int = p->argc }; 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; 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; 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 0;
return ExeBuilder_Append(exeb, error, OPCODE_SELECT, NULL, 0, node->offset, node->length); 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; 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: case NODE_IFELSE:
{ {
IfElseNode *ifelse = (IfElseNode*) node; 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; return 0;
if(ifelse->false_branch) 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)) if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFNOTANDPOP, &op, 1, node->offset, node->length))
return 0; 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; return 0;
if(ifelse->true_branch->kind == NODE_EXPR) 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); long long int temp = ExeBuilder_InstrCount(exeb);
Promise_Resolve(else_offset, &temp, sizeof(temp)); 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; return 0;
if(ifelse->false_branch->kind == NODE_EXPR) 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)) if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFNOTANDPOP, &(Operand) { .type = OPTP_PROMISE, .as_promise = done_offset }, 1, node->offset, node->length))
return 0; 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; return 0;
if(ifelse->true_branch->kind == NODE_EXPR) 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); long long int temp = ExeBuilder_InstrCount(exeb);
Promise_Resolve(start_offset, &temp, sizeof(temp)); 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; return 0;
Operand op = { .type = OPTP_PROMISE, .as_promise = end_offset }; Operand op = { .type = OPTP_PROMISE, .as_promise = end_offset };
if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFNOTANDPOP, &op, 1, whl->condition->offset, whl->condition->length)) if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFNOTANDPOP, &op, 1, whl->condition->offset, whl->condition->length))
return 0; return 0;
if(!emit_instr_for_node(exeb, whl->body, error)) if(!emit_instr_for_node(exeb, whl->body, end_offset, error))
return 0; return 0;
if(whl->body->kind == NODE_EXPR) if(whl->body->kind == NODE_EXPR)
@@ -452,9 +465,16 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
* JUMPIFANDPOP start * 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); 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; return 0;
if(dowhl->body->kind == NODE_EXPR) if(dowhl->body->kind == NODE_EXPR)
@@ -464,12 +484,16 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
return 0; return 0;
} }
if(!emit_instr_for_node(exeb, dowhl->condition, error)) if(!emit_instr_for_node(exeb, dowhl->condition, break_dest, error))
return 0; return 0;
Operand op = { .type = OPTP_INT, .as_int = start }; Operand op = { .type = OPTP_INT, .as_int = start };
if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFANDPOP, &op, 1, dowhl->condition->offset, dowhl->condition->length)) if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFANDPOP, &op, 1, dowhl->condition->offset, dowhl->condition->length))
return 0; return 0;
long long int temp = ExeBuilder_InstrCount(exeb);
Promise_Resolve(end_offset, &temp, sizeof(temp));
Promise_Free(end_offset);
return 1; return 1;
} }
@@ -481,7 +505,7 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
while(stmt) while(stmt)
{ {
if(!emit_instr_for_node(exeb, stmt, error)) if(!emit_instr_for_node(exeb, stmt, break_dest, error))
return 0; return 0;
if(stmt->kind == NODE_EXPR) 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; 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; return 0;
if(!ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, ret->base.offset, ret->base.length)) 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. // Assign the arguments.
if(func->argv) if(func->argv)
assert(func->argv->kind == NODE_ARG); { assert(func->argv->kind == NODE_ARG); }
ArgumentNode *arg = (ArgumentNode*) func->argv; ArgumentNode *arg = (ArgumentNode*) func->argv;
@@ -573,12 +597,12 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
return 0; return 0;
if(arg->base.next) if(arg->base.next)
assert(arg->base.next->kind == NODE_ARG); { assert(arg->base.next->kind == NODE_ARG); }
arg = (ArgumentNode*) arg->base.next; 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; return 0;
// Write a return instruction, just // Write a return instruction, just
@@ -644,7 +668,7 @@ Executable *compile(AST *ast, BPAlloc *alloc, Error *error)
if(exeb != NULL) if(exeb != NULL)
{ {
if(!emit_instr_for_node(exeb, ast->root, error)) if(!emit_instr_for_node(exeb, ast->root, NULL, error))
return 0; return 0;
if(ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, Source_GetSize(ast->src), 0)) if(ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, Source_GetSize(ast->src), 0))
+31
View File
@@ -101,6 +101,7 @@ typedef enum {
TKWFALSE, TKWFALSE,
TKWRETURN, TKWRETURN,
TKWWHILE, TKWWHILE,
TKWBREAK,
TKWDO, TKWDO,
TEQL, TEQL,
@@ -235,6 +236,7 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error)
{ TKWFALSE, 5, "false" }, { TKWFALSE, 5, "false" },
{ TKWRETURN, 6, "return" }, { TKWRETURN, 6, "return" },
{ TKWWHILE, 5, "while" }, { TKWWHILE, 5, "while" },
{ TKWBREAK, 5, "break" },
{ TKWDO, 2, "do" }, { TKWDO, 2, "do" },
}; };
@@ -567,6 +569,35 @@ static Node *parse_statement(Context *ctx)
return node; 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: case TKWRETURN:
{ {
int offset = current_token(ctx)->offset; int offset = current_token(ctx)->offset;