From 97c3c15ea0cfc46007e6077317f9ef51927874f5 Mon Sep 17 00:00:00 2001 From: cozis Date: Mon, 1 Nov 2021 03:20:07 +0000 Subject: [PATCH] added compound statements --- .gitignore | 3 +- samples/if-else.noja | 9 +++++- src/common/executable.c | 2 ++ src/common/executable.h | 1 + src/compiler/ASTi.h | 5 ++++ src/compiler/compile.c | 45 ++++++++++++++++++++++++++++ src/compiler/parse.c | 66 +++++++++++++++++++++++++++++++++++++++-- src/runtime/runtime.c | 11 +++++++ 8 files changed, 138 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index c510a28..873dd5f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build -temp \ No newline at end of file +temp +vgcore.* \ No newline at end of file diff --git a/samples/if-else.noja b/samples/if-else.noja index f2d4105..bc5f155 100644 --- a/samples/if-else.noja +++ b/samples/if-else.noja @@ -1,2 +1,9 @@ -if true 3; else none; \ No newline at end of file +if false + { + 3; + 2; + } +else + 4; +99; \ No newline at end of file diff --git a/src/common/executable.c b/src/common/executable.c index ea11885..4f3ef82 100644 --- a/src/common/executable.c +++ b/src/common/executable.c @@ -48,6 +48,8 @@ static const InstrInfo instr_table[] = { [OPCODE_MUL] = {"MUL", 0, NULL}, [OPCODE_DIV] = {"DIV", 0, NULL}, + [OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}}, + [OPCODE_PUSHINT] = {"PUSHINT", 1, (OperandType[]) {OPTP_INT}}, [OPCODE_PUSHFLT] = {"PUSHFLT", 1, (OperandType[]) {OPTP_FLOAT}}, [OPCODE_PUSHSTR] = {"PUSHSTR", 1, (OperandType[]) {OPTP_STRING}}, diff --git a/src/common/executable.h b/src/common/executable.h index 39050d2..d3769c1 100644 --- a/src/common/executable.h +++ b/src/common/executable.h @@ -28,6 +28,7 @@ typedef enum { OPCODE_SUB, OPCODE_MUL, OPCODE_DIV, + OPCODE_POP, OPCODE_PUSHINT, OPCODE_PUSHFLT, OPCODE_PUSHSTR, diff --git a/src/compiler/ASTi.h b/src/compiler/ASTi.h index faeab33..7c81a72 100644 --- a/src/compiler/ASTi.h +++ b/src/compiler/ASTi.h @@ -7,6 +7,7 @@ typedef enum { NODE_EXPR, NODE_IFELSE, + NODE_COMP, } NodeKind; typedef enum { @@ -81,4 +82,8 @@ typedef struct { Node *false_branch; } IfElseNode; +typedef struct { + Node base; + Node *head; +} CompoundNode; #endif \ No newline at end of file diff --git a/src/compiler/compile.c b/src/compiler/compile.c index 98cf0a6..9e7b5e9 100644 --- a/src/compiler/compile.c +++ b/src/compiler/compile.c @@ -119,6 +119,13 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) if(!emit_instr_for_node(exeb, ifelse->true_branch, error)) return 0; + if(ifelse->true_branch->kind == NODE_EXPR) + { + Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 }; + if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, ifelse->true_branch->offset, 0)) + return 0; + } + op = (Operand) { .type = OPTP_PROMISE, .as_promise = done_offset }; if(!ExeBuilder_Append(exeb, error, OPCODE_JUMP, &op, 1, node->offset, node->length)) return 0; @@ -129,6 +136,13 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) if(!emit_instr_for_node(exeb, ifelse->false_branch, error)) return 0; + if(ifelse->false_branch->kind == NODE_EXPR) + { + Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 }; + if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, ifelse->false_branch->offset, 0)) + return 0; + } + temp = ExeBuilder_InstrCount(exeb); Promise_Resolve(done_offset, &temp, sizeof(temp)); @@ -151,6 +165,13 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) if(!emit_instr_for_node(exeb, ifelse->true_branch, error)) return 0; + if(ifelse->true_branch->kind == NODE_EXPR) + { + Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 }; + if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, ifelse->true_branch->offset, 0)) + return 0; + } + long long int temp = ExeBuilder_InstrCount(exeb); Promise_Resolve(done_offset, &temp, sizeof(temp)); @@ -160,6 +181,30 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) return 1; } + case NODE_COMP: + { + CompoundNode *comp = (CompoundNode*) node; + + Node *stmt = comp->head; + + while(stmt) + { + if(!emit_instr_for_node(exeb, stmt, error)) + return 0; + + if(stmt->kind == NODE_EXPR) + { + Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 }; + if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, stmt->offset, 0)) + return 0; + } + + stmt = stmt->next; + } + + return 1; + } + default: UNREACHABLE; return 0; diff --git a/src/compiler/parse.c b/src/compiler/parse.c index f0c0a70..652e6c1 100644 --- a/src/compiler/parse.c +++ b/src/compiler/parse.c @@ -49,6 +49,7 @@ static Node *parse_statement(Context *ctx); static Node *parse_expression(Context *ctx); static Node *parse_expression_statement(Context *ctx); static Node *parse_ifelse_statement(Context *ctx); +static Node *parse_compound_statement(Context *ctx, TokenKind end); static inline _Bool isoper(char c) { @@ -275,7 +276,7 @@ AST *parse(Source *src, BPAlloc *alloc, Error *error) ctx.alloc = alloc; ctx.error = error; - Node *root = parse_statement(&ctx); + Node *root = parse_compound_statement(&ctx, TDONE); if(root == NULL) return NULL; @@ -352,6 +353,19 @@ static Node *parse_statement(Context *ctx) case TKWIF: return parse_ifelse_statement(ctx); + + case '{': + { + next(ctx); // Consume the '{'. + + Node *node = parse_compound_statement(ctx, '}'); + + if(node != NULL) + next(ctx); // Consume the '}'. + + return node; + } + } Error_Report(ctx->error, 0, "Got token \"%.*s\" where the start of a statement was expected", @@ -834,7 +848,7 @@ static inline int precedenceof(Token *tok) return 2; default: - return -10000000; + return -100000000; } UNREACHABLE; @@ -980,4 +994,52 @@ static Node *parse_ifelse_statement(Context *ctx) } return (Node*) ifelse; +} + +static Node *parse_compound_statement(Context *ctx, TokenKind end) +{ + int end_offset; + Node *head, **tail; + + tail = &head; + *tail = NULL; + + while(current(ctx) != end && current(ctx) != TDONE) + { + Node *temp = parse_statement(ctx); + + if(temp == NULL) + return NULL; + + *tail = temp; + tail = &temp->next; + + end_offset = temp->offset + temp->length; + } + + if(current(ctx) != end) + { + Error_Report(ctx->error, 0, "Source ended inside compound statement"); + return NULL; + } + + CompoundNode *node; + { + node = BPAlloc_Malloc(ctx->alloc, sizeof(CompoundNode)); + + if(node == NULL) + { + // ERROR: No memory. + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } + + node->base.kind = NODE_COMP; + node->base.next = NULL; + node->base.offset = head->offset; + node->base.length = end_offset - head->offset; + node->head = head; + } + + return (Node*) node; } \ No newline at end of file diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index c186a17..d979461 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -342,6 +342,8 @@ static _Bool step(Runtime *runtime, Error *error) case OPCODE_MUL: case OPCODE_DIV: { + assert(opc == 0); + Object *rop = Stack_Top(runtime->stack, 0); Object *lop = Stack_Top(runtime->stack, -1); @@ -363,6 +365,15 @@ static _Bool step(Runtime *runtime, Error *error) break; } + case OPCODE_POP: + { + assert(opc == 1); + + if(!Runtime_Pop(runtime, error, ops[0].as_int)) + return 0; + return 1; + } + case OPCODE_PUSHINT: { assert(opc == 1);