From 9f96f1ffaa4a1a7cdde8401fc669e94e8a34ff70 Mon Sep 17 00:00:00 2001 From: Francesco Cozzuto Date: Mon, 4 Aug 2025 15:36:59 +0200 Subject: [PATCH] Looking good --- Makefile | 2 +- main.wl | 8 +- old_2.wl | 46 -- src/assemble.c | 1377 +++++++++++++++++++++++++++++------------------- src/assemble.h | 12 +- src/eval.c | 276 +++++++--- src/main.c | 6 +- src/parse.c | 65 ++- 8 files changed, 1123 insertions(+), 669 deletions(-) diff --git a/Makefile b/Makefile index 39e065a..18d6090 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,2 @@ all: - gcc src/basic.c src/file.c src/parse.c src/assemble.c src/eval.c src/main.c -o wl -Wall -Wextra -O0 -g3 \ No newline at end of file + gcc src/basic.c src/file.c src/parse.c src/assemble.c src/eval.c src/main.c -o wl -Wall -Wextra -O0 -g3 diff --git a/main.wl b/main.wl index 871badc..57344a1 100644 --- a/main.wl +++ b/main.wl @@ -1,5 +1,5 @@ -let a = 5 -let b = 5 -if a == b: print "a and b are the same\n" -else print "they are not the same!\n" \ No newline at end of file +fun a(name) + My name is \(name) + +a("Francesco") diff --git a/old_2.wl b/old_2.wl index 6163f6a..e69de29 100644 --- a/old_2.wl +++ b/old_2.wl @@ -1,46 +0,0 @@ - -let title = "My Website" - -let posts = [ - { - name: "Post Title 1", - date: "1 Jan 2025", - comments: [ - { author: "User 1", date: "1 Jan 2025", content: "This is a comment" }, - { author: "User 2", date: "2 Jan 2025", content: "Second comment" }, - ] - }, - { - name: "Post Title 2", - date: "4 July 2022", - comments: [ - { author: "User 1", date: "1 Jan 2025", content: "This is a comment" }, - { author: "User 2", date: "2 Jan 2025", content: "Second comment" }, - ] - }, -] - -fun render_comment(c) -
- \c.author (\c.date) -

\c.content

-
- \for child in c.children: - render_comment(child) -
-
- - - - \title - - - This is regular text - \for post in posts: -
- \post.title (\post.date) - \for comment in post.comments: - render_comment(comment) -
- - diff --git a/src/assemble.c b/src/assemble.c index dbe6a84..6a09787 100644 --- a/src/assemble.c +++ b/src/assemble.c @@ -11,6 +11,7 @@ #define MAX_SCOPES 32 #define MAX_SYMBOLS 1024 +#define MAX_DEPTH 128 typedef struct FunctionCall FunctionCall; struct FunctionCall { @@ -38,6 +39,7 @@ typedef enum { SCOPE_IF, SCOPE_ELSE, SCOPE_BLOCK, + SCOPE_HTML, } ScopeType; typedef struct { @@ -130,7 +132,7 @@ void append_mem(OutputBuffer *out, void *ptr, int len) if (out->cap - out->len < len) { - int new_cap = MAX(512, 2 * out->cap); + int new_cap = MAX(out->len + len, 2 * out->cap); char *new_ptr = malloc(new_cap); if (new_ptr == NULL) { out->err = true; @@ -172,7 +174,7 @@ int append_u32(OutputBuffer *out, uint32_t x) return off; } -int append_u64(OutputBuffer *out, uint64_t x) +int append_s64(OutputBuffer *out, int64_t x) { int off = out->len; append_mem(out, &x, (int) sizeof(x)); @@ -230,9 +232,15 @@ Scope *parent_scope(Assembler *a) return scope; } +b32 global_scope(Assembler *a) +{ + return parent_scope(a)->type == SCOPE_GLOBAL; +} + Symbol *find_symbol_in_local_scope(Assembler *a, String name) { - for (int i = a->num_syms-1; i >= a->scopes[a->num_scopes-1].sym_base; i--) + Scope *scope = &a->scopes[a->num_scopes-1]; + for (int i = a->num_syms-1; i >= scope->sym_base; i--) if (streq(a->syms[i].name, name)) return &a->syms[i]; return NULL; @@ -297,43 +305,6 @@ int declare_function(Assembler *a, String name, int off) return 0; } -/* -void assemble_html_node_inner(Assembler *a, Node *node, OutputBuffer *tmp) -{ - append_u8(tmp, '<'); - append_mem(tmp, node->tagname.ptr, node->tagname.len); - - Node *attr = node->params; - while (attr) { - append_u8(tmp, ' '); - append_mem(tmp, attr->attr_name.ptr, attr->attr_name.len); - if (attr->attr_value) { - append_u8(tmp, '='); - // TODO - } - attr = attr->next; - } - append_u8(tmp, '>'); - - Node *child = node->child; - while (child) { - // TODO - child = child->next; - } - - append_u8(tmp, '<'); - append_u8(tmp, '/'); - append_mem(tmp, node->tagname.ptr, node->tagname.len); - append_u8(tmp, '>'); -} - -void assemble_html_node(Assembler *a, Node *node) -{ - OutputBuffer tmp; - assemble_html_node_inner(a, node, &tmp); -} -*/ - b32 is_expr(Node *node) { switch (node->type) { @@ -429,69 +400,95 @@ int pop_scope(Assembler *a) return 0; } -void assemble_node(Assembler *a, Node *node) +void assemble_statement(Assembler *a, Node *node, b32 pop_expr); + +typedef struct { + OutputBuffer tmp; +} HTMLAssembler; + +void write_buffered_html(Assembler *a, HTMLAssembler *ha) +{ + if (ha->tmp.len == 0) + return; + + int off = add_string_literal(a, (String) { ha->tmp.ptr, ha->tmp.len }); + append_u8(&a->out, OPCODE_PUSHS); + append_u32(&a->out, off); + append_u32(&a->out, ha->tmp.len); + + free(ha->tmp.ptr); + ha->tmp.ptr = NULL; + ha->tmp.len = 0; + ha->tmp.cap = 0; +} + +void assemble_html_2(Assembler *a, HTMLAssembler *ha, Node *node) +{ + append_u8(&ha->tmp, '<'); + append_mem(&ha->tmp, node->tagname.ptr, node->tagname.len); + + Node *attr = node->params; + while (attr) { + + String name = attr->attr_name; + Node *value = attr->attr_value; + + append_u8(&ha->tmp, ' '); + append_mem(&ha->tmp, name.ptr, name.len); + + if (value) { + append_u8(&ha->tmp, '='); + + if (value->type == NODE_VALUE_STR) { + append_u8(&ha->tmp, '"'); + append_mem(&ha->tmp, + value->sval.ptr, // TODO: escape + value->sval.len + ); + append_u8(&ha->tmp, '"'); + } else { + write_buffered_html(a, ha); + assemble_statement(a, value, false); + } + } + attr = attr->next; + } + append_u8(&ha->tmp, '>'); + + Node *child = node->child; + while (child) { + if (child->type == NODE_VALUE_STR) + append_mem(&ha->tmp, child->sval.ptr, child->sval.len); + else if (child->type == NODE_VALUE_HTML) + assemble_html_2(a, ha, child); + else { + write_buffered_html(a, ha); + assemble_statement(a, child, false); + } + child = child->next; + } + + append_u8(&ha->tmp, '<'); + append_u8(&ha->tmp, '/'); + append_mem(&ha->tmp, node->tagname.ptr, node->tagname.len); + append_u8(&ha->tmp, '>'); +} + +void assemble_html(Assembler *a, Node *node) +{ + HTMLAssembler ha = { + .tmp={.ptr=NULL,.len=0,.cap=0,.err=false}, + }; + assemble_html_2(a, &ha, node); + write_buffered_html(a, &ha); +} + +void assemble_expr(Assembler *a, Node *node, int num_results) { switch (node->type) { - case NODE_PRINT: - { - assemble_node(a, node->left); - append_u8(&a->out, OPCODE_PRINT); - append_u8(&a->out, OPCODE_POP); - } - break; - - case NODE_FUNC_DECL: - { - append_u8(&a->out, OPCODE_JUMP); - int p1 = append_u32(&a->out, 0); - - int ret = declare_function(a, node->func_name, current_offset(&a->out)); - if (ret < 0) return; - - ret = push_scope(a, SCOPE_FUNC); - if (ret < 0) return; - - append_u8(&a->out, OPCODE_VARS); - int p = append_u32(&a->out, 0); - - Node *args[32]; - int arg_count = 0; - Node *arg = node->func_args; - while (arg) { - if (arg_count == COUNT(args)) { - assembler_report(a, "Argument limit reached"); - return; - } - args[arg_count++] = arg; - arg = arg->next; - } - - for (int i = arg_count-1; i >= 0; i--) { - - int off = declare_variable(a, args[i]->sval); - if (off < 0) return; - - append_u8(&a->out, OPCODE_SETV); - append_u8(&a->out, off); - } - - if (is_expr(node->func_body)) { - assemble_node(a, node->func_body); - append_u8(&a->out, OPCODE_RET); - } else { - assemble_node(a, node->func_body); - append_u8(&a->out, OPCODE_PUSHN); - append_u8(&a->out, OPCODE_RET); - } - - patch_u32(&a->out, p, a->scopes[a->num_scopes-1].max_vars); - - ret = pop_scope(a); - if (ret < 0) return; - - patch_with_current_offset(&a->out, p1); - } + default: + assert(0); break; case NODE_FUNC_CALL: @@ -499,10 +496,12 @@ void assemble_node(Assembler *a, Node *node) Node *func = node->left; Node *args = node->right; + append_u8(&a->out, OPCODE_GROUP); + int arg_count = 0; Node *arg = args; while (arg) { - assemble_node(a, arg); + assemble_expr(a, arg, 1); arg_count++; arg = arg->next; } @@ -510,9 +509,17 @@ void assemble_node(Assembler *a, Node *node) assert(func->type == NODE_VALUE_VAR); append_u8(&a->out, OPCODE_CALL); - append_u8(&a->out, arg_count); int p = append_u32(&a->out, 0); + if (num_results == 0) + append_u8(&a->out, OPCODE_GPOP); + else if (num_results != -1) { + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results); + } + + append_u8(&a->out, OPCODE_GCOALESCE); + FunctionCall *call = alloc(a->a, sizeof(FunctionCall), _Alignof(FunctionCall)); if (call == NULL) { assembler_report(a, "Out of memory"); @@ -528,13 +535,444 @@ void assemble_node(Assembler *a, Node *node) } break; + case NODE_OPER_POS: + assemble_expr(a, node->left, num_results); + break; + + case NODE_OPER_NEG: + assemble_expr(a, node->left, 1); + append_u8(&a->out, OPCODE_NEG); + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1 && num_results != 1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + break; + + case NODE_OPER_EQL: + assemble_expr(a, node->left, 1); + assemble_expr(a, node->right, 1); + append_u8(&a->out, OPCODE_EQL); + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1 && num_results != 1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + break; + + case NODE_OPER_NQL: + assemble_expr(a, node->left, 1); + assemble_expr(a, node->right, 1); + append_u8(&a->out, OPCODE_NQL); + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1 && num_results != 1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + break; + + case NODE_OPER_LSS: + assemble_expr(a, node->left, 1); + assemble_expr(a, node->right, 1); + append_u8(&a->out, OPCODE_LSS); + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1 && num_results != 1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + break; + + case NODE_OPER_GRT: + assemble_expr(a, node->left, 1); + assemble_expr(a, node->right, 1); + append_u8(&a->out, OPCODE_GRT); + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1 && num_results != 1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + break; + + case NODE_OPER_ADD: + assemble_expr(a, node->left, 1); + assemble_expr(a, node->right, 1); + append_u8(&a->out, OPCODE_ADD); + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1 && num_results != 1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + break; + + case NODE_OPER_SUB: + assemble_expr(a, node->left, 1); + assemble_expr(a, node->right, 1); + append_u8(&a->out, OPCODE_SUB); + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1 && num_results != 1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + break; + + case NODE_OPER_MUL: + assemble_expr(a, node->left, 1); + assemble_expr(a, node->right, 1); + append_u8(&a->out, OPCODE_MUL); + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1 && num_results != 1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + break; + + case NODE_OPER_DIV: + assemble_expr(a, node->left, 1); + assemble_expr(a, node->right, 1); + append_u8(&a->out, OPCODE_DIV); + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1 && num_results != 1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + break; + + case NODE_OPER_MOD: + assemble_expr(a, node->left, 1); + assemble_expr(a, node->right, 1); + append_u8(&a->out, OPCODE_MOD); + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1 && num_results != 1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + break; + + case NODE_VALUE_INT: + append_u8(&a->out, OPCODE_PUSHI); + append_s64(&a->out, node->ival); + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1 && num_results != 1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + break; + + case NODE_VALUE_FLOAT: + append_u8 (&a->out, OPCODE_PUSHF); + append_f64(&a->out, node->dval); + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1 && num_results != 1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + break; + + case NODE_VALUE_STR: + { + int off = add_string_literal(a, node->sval); + append_u8(&a->out, OPCODE_PUSHS); + append_u32(&a->out, off); + append_u32(&a->out, node->sval.len); + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1 && num_results != 1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + } + break; + + case NODE_VALUE_VAR: + { + String name = node->sval; + Symbol *sym = find_symbol_in_function(a, name); + if (sym == NULL) { + assembler_report(a, "Reference to undefined variable '%.*s'", name.len, name.ptr); + return; + } + if (sym->type != SYMBOL_VAR) { + assembler_report(a, "Symbol '%.*s' is not a variable", sym->name.len, sym->name.ptr); + return; + } + append_u8(&a->out, OPCODE_PUSHV); + append_u8(&a->out, sym->off); + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + } + break; + + case NODE_VALUE_HTML: + { + if (num_results != -1) + append_u8(&a->out, OPCODE_GROUP); + + assemble_html(a, node); + + if (num_results != -1) { + + append_u8(&a->out, OPCODE_GPACK); + + if (num_results > 1) { + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + } + } + break; + + case NODE_VALUE_ARRAY: + { + append_u8(&a->out, OPCODE_PUSHA); + append_u32(&a->out, count_nodes(node->child)); + + Node *child = node->child; + while (child) { + assemble_expr(a, child, 1); + append_u8(&a->out, OPCODE_APPEND); + child = child->next; + } + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + } + break; + + case NODE_VALUE_MAP: + { + append_u8(&a->out, OPCODE_PUSHM); + append_u32(&a->out, count_nodes(node->child)); + + Node *child = node->child; + while (child) { + assemble_expr(a, child, 1); + assemble_expr(a, child->key, 1); + append_u8(&a->out, OPCODE_INSERT1); + child = child->next; + } + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + } + break; + + case NODE_SELECT: + { + Node *set = node->left; + Node *key = node->right; + + assemble_expr(a, set, 1); + assemble_expr(a, key, 1); + append_u8(&a->out, OPCODE_SELECT); + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + } + break; + + case NODE_NESTED: + assemble_expr(a, node->left, num_results); + break; + + case NODE_OPER_ASS: + { + Node *dst = node->left; + Node *src = node->right; + + if (dst->type == NODE_VALUE_VAR) { + + String name = dst->sval; + + Symbol *sym = find_symbol_in_function(a, name); + if (sym == NULL) { + assembler_report(a, "Undeclared variable '%.*s'", name.len, name.ptr); + return; + } + + if (sym->type != SYMBOL_VAR) { + assembler_report(a, "Symbol '%.*s' can't be assigned to", name.len, name.ptr); + return; + } + + assemble_expr(a, src, 1); + append_u8(&a->out, OPCODE_SETV); + append_u8(&a->out, sym->off); + + } else if (dst->type == NODE_SELECT) { + + assemble_expr(a, src, 1); + assemble_expr(a, dst->left, 1); + assemble_expr(a, dst->right, 1); + append_u8(&a->out, OPCODE_INSERT2); + + } else { + + assembler_report(a, "Assignment left side can't be assigned to"); + return; + } + + if (num_results == 0) + append_u8(&a->out, OPCODE_POP); + else if (num_results != -1 && num_results != 1) { + append_u8(&a->out, OPCODE_GROUP); + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, num_results-1); + append_u8(&a->out, OPCODE_GCOALESCE); + } + } + break; + } +} + +void assemble_statement(Assembler *a, Node *node, b32 pop_expr) +{ + switch (node->type) { + + case NODE_PRINT: + { + append_u8(&a->out, OPCODE_GROUP); + assemble_expr(a, node->left, -1); + append_u8(&a->out, OPCODE_GPRINT); + append_u8(&a->out, OPCODE_GPOP); + } + break; + + case NODE_FUNC_DECL: + { + append_u8(&a->out, OPCODE_JUMP); + int p1 = append_u32(&a->out, 0); + + int ret = declare_function(a, node->func_name, current_offset(&a->out)); + if (ret < 0) return; + + ret = push_scope(a, SCOPE_FUNC); + if (ret < 0) return; + + int arg_count = count_nodes(node->func_args); + + append_u8(&a->out, OPCODE_GTRUNC); + append_u32(&a->out, arg_count); + + append_u8(&a->out, OPCODE_GTRUNC); + int p = append_u32(&a->out, 0); + + Node *arg = node->func_args; + int idx = 0; + while (arg) { + + int off = declare_variable(a, arg->sval); + if (off < 0) return; + + assert(off == idx); + + arg = arg->next; + } + + append_u8(&a->out, OPCODE_GROUP); + + if (is_expr(node->func_body)) { + assemble_expr(a, node->func_body, -1); + } else { + assemble_statement(a, node->func_body, true); + append_u8(&a->out, OPCODE_PUSHN); + } + + append_u8(&a->out, OPCODE_GOVERWRITE); + append_u8(&a->out, OPCODE_RET); + + patch_u32(&a->out, p, a->scopes[a->num_scopes-1].max_vars); + + ret = pop_scope(a); + if (ret < 0) return; + + patch_with_current_offset(&a->out, p1); + } + break; + case NODE_VAR_DECL: { int off = declare_variable(a, node->var_name); if (off < 0) return; if (node->var_value) - assemble_node(a, node->var_value); + assemble_expr(a, node->var_value, 1); else append_u8(&a->out, OPCODE_PUSHN); @@ -550,9 +988,7 @@ void assemble_node(Assembler *a, Node *node) Node *stmt = node->left; while (stmt) { - assemble_node(a, stmt); - if (is_expr(stmt)) - append_u8(&a->out, OPCODE_POP); + assemble_statement(a, stmt, pop_expr); stmt = stmt->next; } @@ -584,7 +1020,7 @@ void assemble_node(Assembler *a, Node *node) if (node->right) { - assemble_node(a, node->cond); + assemble_expr(a, node->cond, 1); append_u8(&a->out, OPCODE_JIFP); int p1 = append_u32(&a->out, 0); @@ -592,7 +1028,7 @@ void assemble_node(Assembler *a, Node *node) int ret = push_scope(a, SCOPE_IF); if (ret < 0) return; - assemble_node(a, node->left); + assemble_statement(a, node->left, pop_expr); ret = pop_scope(a); if (ret < 0) return; @@ -605,7 +1041,7 @@ void assemble_node(Assembler *a, Node *node) ret = push_scope(a, SCOPE_ELSE); if (ret < 0) return; - assemble_node(a, node->right); + assemble_statement(a, node->right, pop_expr); ret = pop_scope(a); if (ret < 0) return; @@ -614,7 +1050,7 @@ void assemble_node(Assembler *a, Node *node) } else { - assemble_node(a, node->cond); + assemble_expr(a, node->cond, 1); append_u8(&a->out, OPCODE_JIFP); int p1 = append_u32(&a->out, 0); @@ -622,7 +1058,7 @@ void assemble_node(Assembler *a, Node *node) int ret = push_scope(a, SCOPE_IF); if (ret < 0) return; - assemble_node(a, node->left); + assemble_statement(a, node->left, pop_expr); ret = pop_scope(a); if (ret < 0) return; @@ -644,7 +1080,7 @@ void assemble_node(Assembler *a, Node *node) int start = current_offset(&a->out); - assemble_node(a, node->cond); + assemble_expr(a, node->cond, 1); append_u8(&a->out, OPCODE_JIFP); int p = append_u32(&a->out, 0); @@ -652,7 +1088,7 @@ void assemble_node(Assembler *a, Node *node) int ret = push_scope(a, SCOPE_WHILE); if (ret < 0) return; - assemble_node(a, node->left); + assemble_statement(a, node->left, pop_expr); ret = pop_scope(a); if (ret < 0) return; @@ -666,208 +1102,25 @@ void assemble_node(Assembler *a, Node *node) case NODE_FOR: { - assemble_node(a, node->for_set); + assemble_expr(a, node->for_set, 1); // TODO int ret = push_scope(a, SCOPE_FOR); if (ret < 0) return; - assemble_node(a, node->left); + declare_variable(a, node->for_var1); + declare_variable(a, node->for_var2); + + assemble_statement(a, node->left, pop_expr); ret = pop_scope(a); if (ret < 0) return; } break; - case NODE_OPER_POS: - assemble_node(a, node->left); - break; - - case NODE_OPER_NEG: - assemble_node(a, node->left); - append_u8(&a->out, OPCODE_NEG); - break; - - case NODE_OPER_EQL: - assemble_node(a, node->left); - assemble_node(a, node->right); - append_u8(&a->out, OPCODE_EQL); - break; - - case NODE_OPER_NQL: - assemble_node(a, node->left); - assemble_node(a, node->right); - append_u8(&a->out, OPCODE_NQL); - break; - - case NODE_OPER_LSS: - assemble_node(a, node->left); - assemble_node(a, node->right); - append_u8(&a->out, OPCODE_LSS); - break; - - case NODE_OPER_GRT: - assemble_node(a, node->left); - assemble_node(a, node->right); - append_u8(&a->out, OPCODE_GRT); - break; - - case NODE_OPER_ADD: - assemble_node(a, node->left); - assemble_node(a, node->right); - append_u8(&a->out, OPCODE_ADD); - break; - - case NODE_OPER_SUB: - assemble_node(a, node->left); - assemble_node(a, node->right); - append_u8(&a->out, OPCODE_SUB); - break; - - case NODE_OPER_MUL: - assemble_node(a, node->left); - assemble_node(a, node->right); - append_u8(&a->out, OPCODE_MUL); - break; - - case NODE_OPER_DIV: - assemble_node(a, node->left); - assemble_node(a, node->right); - append_u8(&a->out, OPCODE_DIV); - break; - - case NODE_OPER_MOD: - assemble_node(a, node->left); - assemble_node(a, node->right); - append_u8(&a->out, OPCODE_MOD); - break; - - case NODE_VALUE_INT: - append_u8(&a->out, OPCODE_PUSHI); - append_u64(&a->out, node->ival); - break; - - case NODE_VALUE_FLOAT: - append_u8 (&a->out, OPCODE_PUSHF); - append_f64(&a->out, node->dval); - break; - - case NODE_VALUE_STR: - { - int off = add_string_literal(a, node->sval); - append_u8(&a->out, OPCODE_PUSHS); - append_u32(&a->out, off); - append_u32(&a->out, node->sval.len); - } - break; - - case NODE_VALUE_VAR: - { - String name = node->sval; - Symbol *sym = find_symbol_in_function(a, name); - if (sym == NULL) { - assembler_report(a, "Reference to undefined variable '%.*s'", name.len, name.ptr); - return; - } - if (sym->type != SYMBOL_VAR) { - assembler_report(a, "Symbol '%.*s' is not a variable", sym->name.len, sym->name.ptr); - return; - } - append_u8(&a->out, OPCODE_PUSHV); - append_u8(&a->out, sym->off); - } - break; - - case NODE_VALUE_HTML: - // TODO - //assemble_html_node(a, node); - break; - - case NODE_VALUE_ARRAY: - { - append_u8(&a->out, OPCODE_PUSHA); - append_u32(&a->out, count_nodes(node->child)); - - Node *child = node->child; - while (child) { - assemble_node(a, child); - append_u8(&a->out, OPCODE_APPEND); - child = child->next; - } - } - break; - - case NODE_VALUE_MAP: - { - append_u8(&a->out, OPCODE_PUSHM); - append_u32(&a->out, count_nodes(node->child)); - - Node *child = node->child; - while (child) { - assemble_node(a, child); - assemble_node(a, child->key); - append_u8(&a->out, OPCODE_INSERT1); - child = child->next; - } - } - break; - - case NODE_SELECT: - { - Node *set = node->left; - Node *key = node->right; - - assemble_node(a, set); - assemble_node(a, key); - append_u8(&a->out, OPCODE_SELECT); - } - break; - - case NODE_NESTED: - assemble_node(a, node->left); - break; - - case NODE_OPER_ASS: - { - Node *dst = node->left; - Node *src = node->right; - - if (dst->type == NODE_VALUE_VAR) { - - String name = dst->sval; - - Symbol *sym = find_symbol_in_function(a, name); - if (sym == NULL) { - assembler_report(a, "Undeclared variable '%.*s'", name.len, name.ptr); - return; - } - - if (sym->type != SYMBOL_VAR) { - assembler_report(a, "Symbol '%.*s' can't be assigned to", name.len, name.ptr); - return; - } - - assemble_node(a, src); - append_u8(&a->out, OPCODE_SETV); - append_u8(&a->out, sym->off); - - } else if (dst->type == NODE_SELECT) { - - assemble_node(a, src); - assemble_node(a, dst->left); - assemble_node(a, dst->right); - append_u8(&a->out, OPCODE_INSERT2); - - } else { - - assembler_report(a, "Assignment left side can't be assigned to"); - return; - } - } - break; - default: + assemble_expr(a, node, pop_expr ? 0 : -1); break; } } @@ -886,10 +1139,19 @@ AssembleResult assemble(Node *root, Arena *arena, char *errbuf, int errmax) if (ret < 0) return (AssembleResult) { (Program) {0}, a.errlen }; - append_u8(&a.out, OPCODE_VARS); + append_u8(&a.out, OPCODE_GROUP); + + append_u8(&a.out, OPCODE_GTRUNC); int p = append_u32(&a.out, 0); - assemble_node(&a, root); + append_u8(&a.out, OPCODE_GROUP); + + assemble_statement(&a, root, false); + + append_u8(&a.out, OPCODE_GPRINT); + append_u8(&a.out, OPCODE_GPOP); + + append_u8(&a.out, OPCODE_GPOP); append_u8(&a.out, OPCODE_EXIT); patch_u32(&a.out, p, a.scopes[a.num_scopes-1].max_vars); @@ -909,241 +1171,296 @@ AssembleResult assemble(Node *root, Arena *arena, char *errbuf, int errmax) return (AssembleResult) { (Program) { out.ptr, out.len }, a.errlen }; } -void print_program(Program p) +int parse_program_header(Program p, String *code, String *data, char *errbuf, int errmax) { - if (p.len < 3 * sizeof(uint32_t)) { - printf("Invalid program"); - return; + if ((uint32_t) p.len < 3 * sizeof(uint32_t)) { + snprintf(errbuf, errmax, "Invalid program"); + return -1; } - uint32_t cur = 0; - uint32_t magic; - memcpy(&magic, p.ptr + cur, sizeof(uint32_t)); - cur += sizeof(uint32_t); - uint32_t code_size; - memcpy(&code_size, p.ptr + cur, sizeof(uint32_t)); - cur += sizeof(uint32_t); - uint32_t data_size; - memcpy(&data_size, p.ptr + cur, sizeof(uint32_t)); - cur += sizeof(uint32_t); + memcpy(&magic, p.ptr + 0, sizeof(uint32_t)); + memcpy(&code_size, p.ptr + 4, sizeof(uint32_t)); + memcpy(&data_size, p.ptr + 8, sizeof(uint32_t)); - if (3 * sizeof(uint32_t) + code_size + data_size != p.len) { - printf("Invalid program"); + if (magic != 0xFEEDBEEF) { + snprintf(errbuf, errmax, "Invalid program"); + return -1; + } + + if (code_size + data_size + 3 * sizeof(uint32_t) != (uint32_t) p.len) { + snprintf(errbuf, errmax, "Invalid program"); + return -1; + } + + *code = (String) { p.ptr + 3 * sizeof(uint32_t), code_size }; + *data = (String) { p.ptr + 3 * sizeof(uint32_t) + code_size, data_size }; + return 0; +} + +void print_program(Program program) +{ + String code; + String data; + + char err[128]; + if (parse_program_header(program, &code, &data, err, COUNT(err)) < 0) { + printf("%s\n", err); return; } - printf("Program size is %d\n", p.len); - - while (cur < code_size + 3 * sizeof(uint32_t)) { - - printf("%" LLU ": ", cur - 3 * sizeof(uint32_t)); - - switch (((uint8_t*) p.ptr)[cur++]) { - - case OPCODE_NOPE: - printf("NOPE"); - break; - - case OPCODE_EXIT: - printf("EXIT"); - break; - - case OPCODE_PUSHI: - { - uint64_t x; - memcpy(&x, p.ptr + cur, sizeof(uint64_t)); - cur += sizeof(uint64_t); - - printf("PUSHI %" LLU, x); - } - break; - - case OPCODE_PUSHF: - { - double x; - memcpy(&x, p.ptr + cur, sizeof(double)); - cur += sizeof(double); - - printf("PUSHF %lf", x); - } - break; - - case OPCODE_PUSHS: - { - uint32_t off; - memcpy(&off, p.ptr + cur, sizeof(uint32_t)); - cur += sizeof(uint32_t); - - uint32_t len; - memcpy(&len, p.ptr + cur, sizeof(uint32_t)); - cur += sizeof(uint32_t); - - printf("PUSHS \"%.*s\"", len, (char*) p.ptr + 3 * sizeof(uint32_t) + code_size + off); - } - break; - - case OPCODE_PUSHV: - { - uint8_t idx; - memcpy(&idx, p.ptr + cur, sizeof(uint8_t)); - cur += sizeof(uint8_t); - - printf("PUSHV %u", idx); - } - break; - - case OPCODE_PUSHA: - { - uint32_t cap; - memcpy(&cap, p.ptr + cur, sizeof(uint32_t)); - cur += sizeof(uint32_t); - - printf("PUSHA %u", cap); - } - break; - - case OPCODE_PUSHM: - { - uint32_t cap; - memcpy(&cap, p.ptr + cur, sizeof(uint32_t)); - cur += sizeof(uint32_t); - - printf("PUSHM %u", cap); - } - break; - - case OPCODE_PUSHN: - { - printf("PUSHN"); - } - break; - - case OPCODE_POP: - printf("POP"); - break; - - case OPCODE_NEG: - printf("NEG"); - break; - - case OPCODE_EQL: - printf("EQL"); - break; - - case OPCODE_NQL: - printf("NQL"); - break; - - case OPCODE_LSS: - printf("LSS"); - break; - - case OPCODE_GRT: - printf("GRT"); - break; - - case OPCODE_ADD: - printf("ADD"); - break; - - case OPCODE_SUB: - printf("SUB"); - break; - - case OPCODE_MUL: - printf("MUL"); - break; - - case OPCODE_DIV: - printf("DIV"); - break; - - case OPCODE_MOD: - printf("MOD"); - break; - - case OPCODE_SETV: - { - uint8_t idx; - memcpy(&idx, p.ptr + cur, sizeof(uint8_t)); - cur += sizeof(uint8_t); - - printf("SETV %u", idx); - } - break; - - case OPCODE_JUMP: - { - uint32_t off; - memcpy(&off, p.ptr + cur, sizeof(uint32_t)); - cur += sizeof(uint32_t); - - printf("JUMP %u", off); - } - break; - - case OPCODE_JIFP: - { - uint32_t off; - memcpy(&off, p.ptr + cur, sizeof(uint32_t)); - cur += sizeof(uint32_t); - - printf("JIFP %u", off); - } - break; - - case OPCODE_CALL: - { - uint8_t num; - memcpy(&num, p.ptr + cur, sizeof(uint8_t)); - cur += sizeof(uint8_t); - - uint32_t off; - memcpy(&off, p.ptr + cur, sizeof(uint32_t)); - cur += sizeof(uint32_t); - - printf("CALL %u %u", num, off); - } - break; - - case OPCODE_VARS: - { - uint32_t num; - memcpy(&num, p.ptr + cur, sizeof(uint32_t)); - cur += sizeof(uint32_t); - - printf("VARS %u", num); - } - break; - - case OPCODE_RET: - printf("RET"); - break; - - case OPCODE_APPEND: - printf("APPEND"); - break; - - case OPCODE_INSERT1: - printf("INSERT1"); - break; - - case OPCODE_INSERT2: - printf("INSERT2"); - break; - - case OPCODE_SELECT: - printf("SELECT"); - break; - - case OPCODE_PRINT: - printf("PRINT"); - break; - } - + char *p = code.ptr; + for (;;) { + printf(" %-3d: ", (int) (p - code.ptr)); + p = print_instruction(p, data.ptr); printf("\n"); + if (p == code.ptr + code.len) + break; } -} \ No newline at end of file +} + +char *print_instruction(char *p, char *data) +{ + switch (*(p++)) { + + default: + printf("(unknown opcode 0x%x)", *p); + break; + + case OPCODE_NOPE: + printf("NOPE"); + break; + + case OPCODE_EXIT: + printf("EXIT"); + break; + + case OPCODE_GROUP: + { + printf("GROUP"); + } + break; + + case OPCODE_GPOP: + { + printf("GPOP"); + } + break; + + case OPCODE_GPRINT: + { + printf("GPRINT"); + } + break; + + case OPCODE_GTRUNC: + { + uint32_t off; + memcpy(&off, p, sizeof(uint32_t)); + p += sizeof(uint32_t); + + printf("GTRUNC %u", off); + } + break; + + case OPCODE_GCOALESCE: + { + printf("GCOALESCE"); + } + break; + + case OPCODE_GOVERWRITE: + { + printf("GOVERWRITE"); + } + break; + + case OPCODE_GPACK: + { + printf("GPACK"); + } + break; + + case OPCODE_PUSHI: + { + int64_t x; + memcpy(&x, p, sizeof(int64_t)); + p += sizeof(int64_t); + + printf("PUSHI %" LLU, x); + } + break; + + case OPCODE_PUSHF: + { + double x; + memcpy(&x, p, sizeof(double)); + p += sizeof(double); + + printf("PUSHF %lf", x); + } + break; + + case OPCODE_PUSHS: + { + uint32_t off; + memcpy(&off, p, sizeof(uint32_t)); + p += sizeof(uint32_t); + + uint32_t len; + memcpy(&len, p, sizeof(uint32_t)); + p += sizeof(uint32_t); + + printf("PUSHS \"%.*s\"", (int) len, (char*) data + off); + } + break; + + case OPCODE_PUSHV: + { + uint8_t idx; + memcpy(&idx, p, sizeof(uint8_t)); + p += sizeof(uint8_t); + + printf("PUSHV %u", idx); + } + break; + + case OPCODE_PUSHA: + { + uint32_t cap; + memcpy(&cap, p, sizeof(uint32_t)); + p += sizeof(uint32_t); + + printf("PUSHA %u", cap); + } + break; + + case OPCODE_PUSHM: + { + uint32_t cap; + memcpy(&cap, p, sizeof(uint32_t)); + p += sizeof(uint32_t); + + printf("PUSHM %u", cap); + } + break; + + case OPCODE_PUSHN: + { + printf("PUSHN"); + } + break; + + case OPCODE_POP: + printf("POP"); + break; + + case OPCODE_NEG: + printf("NEG"); + break; + + case OPCODE_EQL: + printf("EQL"); + break; + + case OPCODE_NQL: + printf("NQL"); + break; + + case OPCODE_LSS: + printf("LSS"); + break; + + case OPCODE_GRT: + printf("GRT"); + break; + + case OPCODE_ADD: + printf("ADD"); + break; + + case OPCODE_SUB: + printf("SUB"); + break; + + case OPCODE_MUL: + printf("MUL"); + break; + + case OPCODE_DIV: + printf("DIV"); + break; + + case OPCODE_MOD: + printf("MOD"); + break; + + case OPCODE_SETV: + { + uint8_t idx; + memcpy(&idx, p, sizeof(uint8_t)); + p += sizeof(uint8_t); + + printf("SETV %u", idx); + } + break; + + case OPCODE_JUMP: + { + uint32_t off; + memcpy(&off, p, sizeof(uint32_t)); + p += sizeof(uint32_t); + + printf("JUMP %u", off); + } + break; + + case OPCODE_JIFP: + { + uint32_t off; + memcpy(&off, p, sizeof(uint32_t)); + p += sizeof(uint32_t); + + printf("JIFP %u", off); + } + break; + + case OPCODE_CALL: + { + uint32_t off; + memcpy(&off, p, sizeof(uint32_t)); + p += sizeof(uint32_t); + + printf("CALL %u", off); + } + break; + + case OPCODE_RET: + printf("RET"); + break; + + case OPCODE_APPEND: + printf("APPEND"); + break; + + case OPCODE_INSERT1: + printf("INSERT1"); + break; + + case OPCODE_INSERT2: + printf("INSERT2"); + break; + + case OPCODE_SELECT: + printf("SELECT"); + break; + + case OPCODE_PRINT: + printf("PRINT"); + break; + } + + return p; +} diff --git a/src/assemble.h b/src/assemble.h index d971cca..5703d87 100644 --- a/src/assemble.h +++ b/src/assemble.h @@ -6,6 +6,13 @@ enum { OPCODE_NOPE = 0x00, OPCODE_EXIT = 0x23, + OPCODE_GROUP = 0x25, + OPCODE_GPOP = 0x26, + OPCODE_GPRINT = 0x27, + OPCODE_GTRUNC = 0x28, + OPCODE_GCOALESCE = 0x29, + OPCODE_GOVERWRITE = 0x2A, + OPCODE_GPACK = 0x2B, OPCODE_PUSHI = 0x01, OPCODE_PUSHF = 0x02, OPCODE_PUSHS = 0x03, @@ -28,7 +35,6 @@ enum { OPCODE_JUMP = 0x13, OPCODE_JIFP = 0x14, OPCODE_CALL = 0x15, - OPCODE_VARS = 0x22, OPCODE_RET = 0x16, OPCODE_APPEND = 0x17, OPCODE_INSERT1 = 0x18, @@ -47,7 +53,9 @@ typedef struct { int errlen; } AssembleResult; -void print_program(Program p); +int parse_program_header(Program p, String *code, String *data, char *errbuf, int errmax); +void print_program(Program program); +char *print_instruction(char *p, char *data); AssembleResult assemble(Node *root, Arena *arena, char *errbuf, int errmax); #endif // WL_ASSEMBLE_INCLUDED \ No newline at end of file diff --git a/src/eval.c b/src/eval.c index 17b64f8..905e0a4 100644 --- a/src/eval.c +++ b/src/eval.c @@ -9,6 +9,7 @@ #define FRAME_LIMIT 128 #define EVAL_STACK_LIMIT 128 +#define GROUP_LIMIT 128 #define HEAP_BASE 0xFEEDBEEFFEEDBEEF @@ -84,8 +85,8 @@ typedef struct { } StringValue; typedef struct { - int base; - int return_off; + int group; + int return_addr; } Frame; typedef struct { @@ -100,12 +101,15 @@ typedef struct { int errmax; int errlen; - int frame_depth; + int num_frames; Frame frames[FRAME_LIMIT]; int eval_depth; Value eval_stack[EVAL_STACK_LIMIT]; + int num_groups; + int groups[GROUP_LIMIT]; + } Eval; #define VALUE_NONE ((Value) 0) @@ -224,7 +228,7 @@ Value make_float(Eval *e, float x) return ((Value) v) | 7; } -Value make_str(Eval *e, String x) +Value make_str(Eval *e, String x) // TODO: This should reuse the string contents when possible { StringValue *v = alloc(e->a, (int) sizeof(StringValue) + x.len, 8); if (v == NULL) { @@ -276,6 +280,8 @@ b32 valeq(Value a, Value b); int map_select(Eval *e, Value map, Value key, Value *val) { + (void) e; + MapValue *p = get_map(map); MapItems *batch = &p->head; while (batch) { @@ -319,8 +325,37 @@ int map_insert(Eval *e, Value map, Value key, Value val) return 0; } -Value *array_select(Eval *e, Value array, uint32_t key) +void value_print(Value v); + +void map_print(Value v) { + printf("{ "); + + MapValue *p = get_map(v); + MapItems *batch = &p->head; + while (batch) { + + int num = ITEMS_PER_MAP_BATCH; + if (batch->next == NULL) + num = p->tail_count; + + for (int i = 0; i < num; i++) { + value_print(batch->keys[i]); + printf(": "); + value_print(batch->items[i]); + printf(", "); + } + + batch = batch->next; + } + + printf("}"); +} + +Value *array_select(Eval *e, Value array, int key) +{ + (void) e; + ArrayValue *p = get_array(array); ArrayItems *batch = &p->head; int cursor = 0; @@ -362,6 +397,25 @@ int array_append(Eval *e, Value array, Value val) return 0; } +void array_print(Value v) +{ + ArrayValue *p = get_array(v); + ArrayItems *batch = &p->head; + int cursor = 0; + while (batch) { + + int num = ITEMS_PER_MAP_BATCH; + if (batch->next == NULL) + num = p->tail_count; + + for (int i = 0; i < num; i++) + value_print(batch->items[i]); + + batch = batch->next; + cursor += num; + } +} + b32 valeq(Value a, Value b) { Type t1 = type_of(a); @@ -438,9 +492,58 @@ b32 valgrt(Value a, Value b) return false; } +void value_print(Value v) +{ + switch (type_of(v)) { + + case TYPE_NONE: + printf("none"); + break; + + case TYPE_BOOL: + printf(v == VALUE_TRUE ? "true" : "false"); + break; + + case TYPE_INT: + printf("%" LLD, get_int(v)); + break; + + case TYPE_FLOAT: + printf("%lf", get_float(v)); + break; + + case TYPE_MAP: + map_print(v); + break; + + case TYPE_ARRAY: + array_print(v); + break; + + case TYPE_STRING: + { + String s = get_str(v); + printf("%.*s", s.len, s.ptr); + } + break; + + case TYPE_ERROR: + printf("error"); + break; + } + fflush(stdout); +} + int step(Eval *e) { - uint8_t opcode = e->code.ptr[e->off++]; + uint8_t opcode = e->code.ptr[e->off]; +/* + printf("%-3d: ", e->off); + print_instruction(e->code.ptr + e->off, e->data.ptr); + printf("\n"); +*/ + e->off++; + switch (opcode) { case OPCODE_NOPE: @@ -455,6 +558,77 @@ int step(Eval *e) } break; + case OPCODE_GROUP: + { + e->groups[e->num_groups++] = e->eval_depth; + } + break; + + case OPCODE_GPOP: + { + int group = e->groups[--e->num_groups]; + e->eval_depth = group; + } + break; + + case OPCODE_GPRINT: + { + for (int i = e->groups[e->num_groups-1]; i < e->eval_depth; i++) + value_print(e->eval_stack[i]); + } + break; + + case OPCODE_GCOALESCE: + { + e->num_groups--; + } + break; + + case OPCODE_GTRUNC: + { + uint32_t num; + memcpy(&num, (uint8_t*) e->code.ptr + e->off, sizeof(uint32_t)); + e->off += (int) sizeof(uint32_t); + + int group_size = e->eval_depth - e->groups[e->num_groups-1]; + + if (group_size < (int) num) { + for (int i = 0; i < (int) num - group_size; i++) + e->eval_stack[e->eval_depth + i] = VALUE_NONE; + } + + e->eval_depth = e->groups[e->num_groups-1] + num; + } + break; + + case OPCODE_GOVERWRITE: + { + int current = e->groups[e->num_groups-1]; + int parent = e->groups[e->num_groups-2]; + + int current_size = e->eval_depth - current; + + for (int i = 0; i < current_size; i++) + e->eval_stack[parent + i] = e->eval_stack[current + i]; + + e->num_groups--; + e->eval_depth = parent + current_size; + } + break; + + case OPCODE_GPACK: + { + Value array = make_array(e); + if (array == VALUE_ERROR) + return -1; + for (int i = e->groups[e->num_groups-1]; i < e->eval_depth; i++) + array_append(e, array, e->eval_stack[i]); + + e->eval_depth = e->groups[--e->num_groups]; + e->eval_stack[e->eval_depth++] = array; + } + break; + case OPCODE_PUSHN: { e->eval_stack[e->eval_depth++] = VALUE_NONE; @@ -510,7 +684,10 @@ int step(Eval *e) memcpy(&idx, (uint8_t*) e->code.ptr + e->off, sizeof(uint8_t)); e->off += sizeof(uint8_t); - e->eval_stack[e->eval_depth++] = e->eval_stack[e->frames[e->frame_depth-1].base + idx]; + int group = e->frames[e->num_frames-1].group; + Value v = e->eval_stack[e->groups[group] + idx]; + + e->eval_stack[e->eval_depth++] = v; } break; @@ -542,6 +719,7 @@ int step(Eval *e) case OPCODE_POP: { + assert(e->num_groups == 0 || e->eval_depth > e->groups[e->num_groups-1]); e->eval_depth--; } break; @@ -889,8 +1067,8 @@ int step(Eval *e) memcpy(&x, (uint8_t*) e->code.ptr + e->off, (int) sizeof(x)); e->off += (int) sizeof(x); - Frame *f = &e->frames[e->frame_depth-1]; - e->eval_stack[f->base + x] = e->eval_stack[--e->eval_depth]; + Frame *f = &e->frames[e->num_frames-1]; + e->eval_stack[e->groups[f->group] + x] = e->eval_stack[--e->eval_depth]; } break; @@ -923,50 +1101,23 @@ int step(Eval *e) case OPCODE_CALL: { - uint8_t num; - memcpy(&num, (uint8_t*) e->code.ptr + e->off, sizeof(uint8_t)); - e->off += (int) sizeof(uint8_t); - uint32_t off; memcpy(&off, (uint8_t*) e->code.ptr + e->off, sizeof(uint32_t)); e->off += (int) sizeof(uint32_t); - // Push a dummy value for the return value - e->eval_stack[e->eval_depth++] = VALUE_NONE; - - if (e->frame_depth == FRAME_LIMIT) { + if (e->num_frames == FRAME_LIMIT) { eval_report(e, "Frame limit reached"); return -1; } - Frame *f = &e->frames[e->frame_depth++]; - f->base = e->eval_depth; - f->return_off = e->off; + e->frames[e->num_frames++] = (Frame) {.return_addr=e->off, .group=e->num_groups-1}; e->off = off; } break; - case OPCODE_VARS: - { - uint32_t num; - memcpy(&num, e->code.ptr + e->off, sizeof(uint32_t)); - e->off += sizeof(uint32_t); - - e->eval_depth += num; - } - break; - case OPCODE_RET: { - Frame *f = &e->frames[--e->frame_depth]; - - assert(e->eval_depth > f->base); - Value r = e->eval_stack[--e->eval_depth]; - - e->off = f->return_off; - e->eval_depth = f->base; - - e->eval_stack[e->eval_depth-1] = r; + e->off = e->frames[--e->num_frames].return_addr; } break; @@ -1076,18 +1227,7 @@ int step(Eval *e) case OPCODE_PRINT: { Value v = e->eval_stack[e->eval_depth-1]; - - switch (type_of(v)) { - case TYPE_NONE : printf("none"); break; - case TYPE_BOOL : printf(v == VALUE_TRUE ? "true" : "false"); break; - case TYPE_INT : printf("%" LLD, get_int(v)); break; - case TYPE_FLOAT : printf("%lf", get_float(v)); break; - case TYPE_MAP : printf("map"); break; - case TYPE_ARRAY : printf("array"); break; - case TYPE_STRING: printf("%.*s", get_str(v).len, get_str(v).ptr); break; - case TYPE_ERROR : printf("error"); break; - } - fflush(stdout); + value_print(v); } break; @@ -1101,42 +1241,27 @@ int step(Eval *e) int eval(Program p, Arena *a, char *errbuf, int errmax) { - if (p.len < 3 * sizeof(uint32_t)) { - snprintf(errbuf, errmax, "Invalid program"); - return -1; - } - uint32_t magic; - uint32_t code_size; - uint32_t data_size; - memcpy(&magic, p.ptr + 0, sizeof(uint32_t)); - memcpy(&code_size, p.ptr + 4, sizeof(uint32_t)); - memcpy(&data_size, p.ptr + 8, sizeof(uint32_t)); + String code; + String data; - if (magic != 0xFEEDBEEF) { - snprintf(errbuf, errmax, "Invalid program"); + int ret = parse_program_header(p, &code, &data, errbuf, errmax); + if (ret < 0) return -1; - } - - if (code_size + data_size + 3 * sizeof(uint32_t) != p.len) { - snprintf(errbuf, errmax, "Invalid program"); - return -1; - } Eval e = { - .code = { p.ptr + 3 * sizeof(uint32_t), code_size }, - .data = { p.ptr + 3 * sizeof(uint32_t) + code_size, data_size }, + .code=code, + .data=data, .off=0, .a=a, .errbuf=errbuf, .errmax=errmax, .errlen=0, - .frame_depth=0, + .num_frames=0, .eval_depth=0, + .num_groups=0, }; - Frame *f = &e.frames[e.frame_depth++]; - f->base = 0; - f->return_off = 0; + e.frames[e.num_frames++] = (Frame) { 0, 0 }; for (;;) { int ret = step(&e); @@ -1144,5 +1269,6 @@ int eval(Program p, Arena *a, char *errbuf, int errmax) if (ret == 1) break; } + e.num_frames--; return 0; } \ No newline at end of file diff --git a/src/main.c b/src/main.c index c9c40ec..177339f 100644 --- a/src/main.c +++ b/src/main.c @@ -25,8 +25,8 @@ int main(void) return -1; } - //print_node(parse_result.node); - //printf("\n"); + print_node(parse_result.node); + printf("\n"); AssembleResult assemble_result = assemble(parse_result.node, &a, err, COUNT(err)); if (assemble_result.errlen) { @@ -34,7 +34,7 @@ int main(void) return -1; } - //print_program(assemble_result.program); + print_program(assemble_result.program); ret = eval(assemble_result.program, &a, err, COUNT(err)); if (ret < 0) { diff --git a/src/parse.c b/src/parse.c index 44fac6b..dc69a8e 100644 --- a/src/parse.c +++ b/src/parse.c @@ -203,8 +203,19 @@ Node *alloc_node(Parser *p) Token next_token(Parser *p) { - while (p->s.cur < p->s.len && is_space(p->s.src[p->s.cur])) - p->s.cur++; + for (;;) { + while (p->s.cur < p->s.len && is_space(p->s.src[p->s.cur])) + p->s.cur++; + + if (!consume_str(&p->s, S(""))) + break; + p->s.cur++; + } + } if (p->s.cur == p->s.len) return (Token) { .type=TOKEN_END }; @@ -406,6 +417,7 @@ Token next_token_or_newline(Parser *p) enum { IGNORE_GRT = 1 << 0, IGNORE_LSS = 1 << 1, + IGNORE_DIV = 1 << 2, }; Node *parse_stmt(Parser *p, int opflags); @@ -429,6 +441,7 @@ Node *parse_html(Parser *p) Node *param_head; Node **param_tail = ¶m_head; + b32 no_body = false; for (;;) { int param_offset = p->s.cur; @@ -437,8 +450,20 @@ Node *parse_html(Parser *p) Node *attr_value; t = next_token(p); + if (t.type == TOKEN_OPER_GRT) break; + + if (t.type == TOKEN_OPER_DIV) { + t = next_token(p); + if (t.type != TOKEN_OPER_GRT) { + parser_report(p, "Invalid token '/' inside an HTML tag"); + return NULL; + } + no_body = true; + break; + } + if (t.type != TOKEN_IDENT) { parser_report(p, "Invalid token inside HTML tag"); return NULL; @@ -449,7 +474,7 @@ Node *parse_html(Parser *p) t = next_token(p); if (t.type == TOKEN_OPER_ASS) { - attr_value = parse_expr(p, IGNORE_GRT); + attr_value = parse_expr(p, IGNORE_GRT | IGNORE_DIV); if (attr_value == NULL) return NULL; @@ -476,13 +501,26 @@ Node *parse_html(Parser *p) Node *head; Node **tail = &head; - for (;;) { + if (!no_body) for (;;) { for (;;) { int off = p->s.cur; - while (p->s.cur < p->s.len && p->s.src[p->s.cur] != '<' && p->s.src[p->s.cur] != '\\') - p->s.cur++; + + for (;;) { + + while (p->s.cur < p->s.len && p->s.src[p->s.cur] != '<' && p->s.src[p->s.cur] != '\\') + p->s.cur++; + + if (!consume_str(&p->s, S(""))) + break; + p->s.cur++; + } + } if (p->s.cur > off) { @@ -715,9 +753,13 @@ int precedence(Token t, int flags) return 3; case TOKEN_OPER_MUL: - case TOKEN_OPER_DIV: case TOKEN_OPER_MOD: - return 3; + return 4; + + case TOKEN_OPER_DIV: + if (flags & IGNORE_DIV) + return -1; + return 4; default: break; @@ -1481,6 +1523,13 @@ void print_node(Node *node) { switch (node->type) { + case NODE_PRINT: + { + printf("print "); + print_node(node->left); + } + break; + case NODE_BLOCK: { printf("{");