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)
-
-
-
-
- \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("{");
\c.content
-