Improvements on the evaluator

This commit is contained in:
2025-08-03 21:58:14 +02:00
parent ed9db8fe34
commit e108ee858b
8 changed files with 693 additions and 278 deletions
+5 -46
View File
@@ -1,46 +1,5 @@
if 1 == 2: {
let title = "My Website" let a = 1
} else {
let posts = [ let b =
{ }
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)
<div class="comment">
<a>\c.author (\c.date)</a>
<p>\c.content</p>
<div class="comment-children">
\for child in c.children:
render_comment(child)
</div>
</div>
<html>
<head>
<title>\title</title>
</head>
<body>
<a>This is regular text</a>
\for post in posts:
<div class="post">
<a>\post.title (\post.date)</a>
\for comment in post.comments:
render_comment(comment)
</div>
</body>
</html>
+46
View File
@@ -0,0 +1,46 @@
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)
<div class="comment">
<a>\c.author (\c.date)</a>
<p>\c.content</p>
<div class="comment-children">
\for child in c.children:
render_comment(child)
</div>
</div>
<html>
<head>
<title>\title</title>
</head>
<body>
<a>This is regular text</a>
\for post in posts:
<div class="post">
<a>\post.title (\post.date)</a>
\for comment in post.comments:
render_comment(comment)
</div>
</body>
</html>
+119 -67
View File
@@ -43,6 +43,7 @@ typedef enum {
typedef struct { typedef struct {
ScopeType type; ScopeType type;
int sym_base; int sym_base;
int max_vars;
FunctionCall* calls; FunctionCall* calls;
} Scope; } Scope;
@@ -212,29 +213,48 @@ int count_nodes(Node *head)
return n; return n;
} }
int find_symbol_in_local_scope(Assembler *a, String name) Scope *parent_scope(Assembler *a)
{
for (int i = a->num_syms-1; i >= a->scopes[a->num_scopes-1].sym_base; i--)
if (streq(a->syms[i].name, name))
return i;
return -1;
}
int find_symbol_in_function(Assembler *a, String name)
{ {
assert(a->num_scopes > 0); assert(a->num_scopes > 0);
// Find the index of the parent function scope or the global scope
int parent = a->num_scopes-1; int parent = a->num_scopes-1;
while (parent > 1 && a->scopes[parent].type != SCOPE_FUNC) while (a->scopes[parent].type != SCOPE_FUNC
&& a->scopes[parent].type != SCOPE_GLOBAL)
parent--; parent--;
for (int i = a->num_syms-1; i >= a->scopes[parent].sym_base; i--) Scope *scope = &a->scopes[parent];
if (streq(a->syms[i].name, name))
return i;
return -1; assert(scope->type == SCOPE_GLOBAL
|| scope->type == SCOPE_FUNC);
return scope;
}
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--)
if (streq(a->syms[i].name, name))
return &a->syms[i];
return NULL;
}
Symbol *find_symbol_in_function(Assembler *a, String name)
{
Scope *scope = parent_scope(a);
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;
}
int count_local_vars(Assembler *a)
{
int n = 0;
Scope *scope = parent_scope(a);
for (int i = scope->sym_base; i < a->num_syms; i++)
if (a->syms[i].type == SYMBOL_VAR)
n++;
return n;
} }
int declare_variable(Assembler *a, String name) int declare_variable(Assembler *a, String name)
@@ -244,14 +264,21 @@ int declare_variable(Assembler *a, String name)
return -1; return -1;
} }
if (find_symbol_in_local_scope(a, name) >= 0) { if (find_symbol_in_local_scope(a, name)) {
assembler_report(a, "Symbol '%.*s' already declared in this scope", assembler_report(a, "Symbol '%.*s' already declared in this scope",
name.len, name.ptr); name.len, name.ptr);
return -1; return -1;
} }
a->syms[a->num_syms] = (Symbol) { SYMBOL_VAR, name, -1 }; int off = count_local_vars(a);
return a->num_syms++; a->syms[a->num_syms++] = (Symbol) { SYMBOL_VAR, name, off };
Scope *scope = parent_scope(a);
if (scope->max_vars < off + 1)
scope->max_vars = off + 1;
return off;
} }
int declare_function(Assembler *a, String name, int off) int declare_function(Assembler *a, String name, int off)
@@ -261,14 +288,13 @@ int declare_function(Assembler *a, String name, int off)
return -1; return -1;
} }
if (find_symbol_in_local_scope(a, name) >= 0) { if (find_symbol_in_local_scope(a, name)) {
assembler_report(a, "Symbol '%.*s' already declared in this scope", assembler_report(a, "Symbol '%.*s' already declared in this scope", name.len, name.ptr);
name.len, name.ptr);
return -1; return -1;
} }
a->syms[a->num_syms] = (Symbol) { SYMBOL_FUNC, name, off }; a->syms[a->num_syms++] = (Symbol) { SYMBOL_FUNC, name, off };
return a->num_syms++; return 0;
} }
/* /*
@@ -352,6 +378,7 @@ int push_scope(Assembler *a, ScopeType type)
Scope *scope = &a->scopes[a->num_scopes++]; Scope *scope = &a->scopes[a->num_scopes++];
scope->type = type; scope->type = type;
scope->sym_base = a->num_syms; scope->sym_base = a->num_syms;
scope->max_vars = 0;
scope->calls = NULL; scope->calls = NULL;
return 0; return 0;
} }
@@ -364,15 +391,14 @@ int pop_scope(Assembler *a)
FunctionCall **prev = &scope->calls; FunctionCall **prev = &scope->calls;
while (call) { while (call) {
int idx = find_symbol_in_local_scope(a, call->name); Symbol *sym = find_symbol_in_local_scope(a, call->name);
if (idx == -1) { if (sym == NULL) {
prev = &call->next; prev = &call->next;
call = call->next; call = call->next;
continue; continue;
} }
Symbol *sym = &a->syms[idx];
if (sym->type != SYMBOL_FUNC) { if (sym->type != SYMBOL_FUNC) {
assembler_report(a, "Symbol '%.*s' is not a function", call->name.len, call->name.ptr); assembler_report(a, "Symbol '%.*s' is not a function", call->name.len, call->name.ptr);
return -1; return -1;
@@ -405,8 +431,6 @@ int pop_scope(Assembler *a)
void assemble_node(Assembler *a, Node *node) void assemble_node(Assembler *a, Node *node)
{ {
printf("Compiling [%.*s]\n", node->text.len, node->text.ptr);
switch (node->type) { switch (node->type) {
case NODE_FUNC_DECL: case NODE_FUNC_DECL:
@@ -420,6 +444,9 @@ void assemble_node(Assembler *a, Node *node)
ret = push_scope(a, SCOPE_FUNC); ret = push_scope(a, SCOPE_FUNC);
if (ret < 0) return; if (ret < 0) return;
append_u8(&a->out, OPCODE_VARS);
int p = append_u32(&a->out, 0);
Node *args[32]; Node *args[32];
int arg_count = 0; int arg_count = 0;
Node *arg = node->func_args; Node *arg = node->func_args;
@@ -434,11 +461,11 @@ void assemble_node(Assembler *a, Node *node)
for (int i = arg_count-1; i >= 0; i--) { for (int i = arg_count-1; i >= 0; i--) {
int idx = declare_variable(a, args[i]->sval); int off = declare_variable(a, args[i]->sval);
if (idx < 0) return; if (off < 0) return;
append_u8(&a->out, OPCODE_SETV); append_u8(&a->out, OPCODE_SETV);
append_u8(&a->out, idx); // TODO: make this relative to the frame append_u8(&a->out, off);
} }
if (is_expr(node->func_body)) { if (is_expr(node->func_body)) {
@@ -450,6 +477,8 @@ void assemble_node(Assembler *a, Node *node)
append_u8(&a->out, OPCODE_RET); append_u8(&a->out, OPCODE_RET);
} }
patch_u32(&a->out, p, a->scopes[a->num_scopes-1].max_vars);
ret = pop_scope(a); ret = pop_scope(a);
if (ret < 0) return; if (ret < 0) return;
@@ -493,14 +522,16 @@ void assemble_node(Assembler *a, Node *node)
case NODE_VAR_DECL: case NODE_VAR_DECL:
{ {
int idx = declare_variable(a, node->var_name); int off = declare_variable(a, node->var_name);
if (idx < 0) return; if (off < 0) return;
if (node->var_value) { if (node->var_value)
assemble_node(a, node->var_value); assemble_node(a, node->var_value);
else
append_u8(&a->out, OPCODE_PUSHN);
append_u8(&a->out, OPCODE_SETV); append_u8(&a->out, OPCODE_SETV);
append_u8(&a->out, idx); append_u8(&a->out, off);
}
} }
break; break;
@@ -726,13 +757,17 @@ void assemble_node(Assembler *a, Node *node)
case NODE_VALUE_VAR: case NODE_VALUE_VAR:
{ {
String name = node->sval; String name = node->sval;
int idx = find_symbol_in_function(a, name); Symbol *sym = find_symbol_in_function(a, name);
if (idx < 0) { if (sym == NULL) {
assembler_report(a, "Reference to undefined variable '%.*s'", name.len, name.ptr); assembler_report(a, "Reference to undefined variable '%.*s'", name.len, name.ptr);
return; 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, OPCODE_PUSHV);
append_u8(&a->out, idx); // TODO: make this relative to the frame append_u8(&a->out, sym->off);
} }
break; break;
@@ -794,20 +829,20 @@ void assemble_node(Assembler *a, Node *node)
String name = dst->sval; String name = dst->sval;
int idx = find_symbol_in_function(a, name); Symbol *sym = find_symbol_in_function(a, name);
if (idx < 0) { if (sym == NULL) {
assembler_report(a, "Undeclared variable '%.*s'", name.len, name.ptr); assembler_report(a, "Undeclared variable '%.*s'", name.len, name.ptr);
return; return;
} }
if (a->syms[idx].type != SYMBOL_VAR) { if (sym->type != SYMBOL_VAR) {
assembler_report(a, "Symbol '%.*s' can't be assigned to", name.len, name.ptr); assembler_report(a, "Symbol '%.*s' can't be assigned to", name.len, name.ptr);
return; return;
} }
assemble_node(a, src); assemble_node(a, src);
append_u8(&a->out, OPCODE_SETV); append_u8(&a->out, OPCODE_SETV);
append_u8(&a->out, idx); // TODO: this index should be relative to the frame append_u8(&a->out, sym->off);
} else if (dst->type == NODE_SELECT) { } else if (dst->type == NODE_SELECT) {
@@ -839,34 +874,31 @@ AssembleResult assemble(Node *root, Arena *arena, char *errbuf, int errmax)
{ {
Assembler a = {0, .a=arena, .errbuf=errbuf, .errmax=errmax, .errlen=0}; Assembler a = {0, .a=arena, .errbuf=errbuf, .errmax=errmax, .errlen=0};
append_u32(&a.out, 0xFEEDBEEF); // magic
int p1 = append_u32(&a.out, 0); // code size
int p2 = append_u32(&a.out, 0); // data size
int ret = push_scope(&a, SCOPE_GLOBAL); int ret = push_scope(&a, SCOPE_GLOBAL);
if (ret < 0) { if (ret < 0)
return (AssembleResult) { (Program) {0}, a.errlen }; return (AssembleResult) { (Program) {0}, a.errlen };
}
append_u8(&a.out, OPCODE_VARS);
int p = append_u32(&a.out, 0);
assemble_node(&a, root); assemble_node(&a, root);
append_u8(&a.out, OPCODE_NOPE); append_u8(&a.out, OPCODE_EXIT);
patch_u32(&a.out, p, a.scopes[a.num_scopes-1].max_vars);
ret = pop_scope(&a); ret = pop_scope(&a);
if (ret < 0) { if (ret < 0)
return (AssembleResult) { (Program) {0}, a.errlen }; return (AssembleResult) { (Program) {0}, a.errlen };
}
patch_u32(&a.out, p1, a.out.len - 3 * sizeof(uint32_t)); OutputBuffer out = {0};
patch_u32(&a.out, p2, a.strings_len); append_u32(&out, 0xFEEDBEEF); // magic
append_u32(&out, a.out.len); // code size
append_u32(&out, a.strings_len); // data size
append_mem(&out, a.out.ptr, a.out.len);
append_mem(&out, a.strings, a.strings_len);
append_mem(&a.out, a.strings, a.strings_len); free(a.out.ptr);
return (AssembleResult) { (Program) { out.ptr, out.len }, a.errlen };
Program p = {
a.out.ptr,
a.out.len,
};
return (AssembleResult) { p, a.errlen };
} }
void print_program(Program p) void print_program(Program p)
@@ -899,7 +931,7 @@ void print_program(Program p)
while (cur < code_size + 3 * sizeof(uint32_t)) { while (cur < code_size + 3 * sizeof(uint32_t)) {
printf("%d: ", cur - 3 * sizeof(uint32_t)); printf("%" LLU ": ", cur - 3 * sizeof(uint32_t));
switch (((uint8_t*) p.ptr)[cur++]) { switch (((uint8_t*) p.ptr)[cur++]) {
@@ -907,6 +939,10 @@ void print_program(Program p)
printf("NOPE"); printf("NOPE");
break; break;
case OPCODE_EXIT:
printf("EXIT");
break;
case OPCODE_PUSHI: case OPCODE_PUSHI:
{ {
uint64_t x; uint64_t x;
@@ -971,6 +1007,12 @@ void print_program(Program p)
} }
break; break;
case OPCODE_PUSHN:
{
printf("PUSHN");
}
break;
case OPCODE_POP: case OPCODE_POP:
printf("POP"); printf("POP");
break; break;
@@ -1051,14 +1093,24 @@ void print_program(Program p)
memcpy(&num, p.ptr + cur, sizeof(uint8_t)); memcpy(&num, p.ptr + cur, sizeof(uint8_t));
cur += sizeof(uint8_t); cur += sizeof(uint8_t);
uint8_t off; uint32_t off;
memcpy(&off, p.ptr + cur, sizeof(uint8_t)); memcpy(&off, p.ptr + cur, sizeof(uint32_t));
cur += sizeof(uint8_t); cur += sizeof(uint32_t);
printf("CALL %u %u", num, off); printf("CALL %u %u", num, off);
} }
break; 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: case OPCODE_RET:
printf("RET"); printf("RET");
break; break;
+2
View File
@@ -5,6 +5,7 @@
enum { enum {
OPCODE_NOPE = 0x00, OPCODE_NOPE = 0x00,
OPCODE_EXIT = 0x23,
OPCODE_PUSHI = 0x01, OPCODE_PUSHI = 0x01,
OPCODE_PUSHF = 0x02, OPCODE_PUSHF = 0x02,
OPCODE_PUSHS = 0x03, OPCODE_PUSHS = 0x03,
@@ -27,6 +28,7 @@ enum {
OPCODE_JUMP = 0x13, OPCODE_JUMP = 0x13,
OPCODE_JIFP = 0x14, OPCODE_JIFP = 0x14,
OPCODE_CALL = 0x15, OPCODE_CALL = 0x15,
OPCODE_VARS = 0x22,
OPCODE_RET = 0x16, OPCODE_RET = 0x16,
OPCODE_APPEND = 0x17, OPCODE_APPEND = 0x17,
OPCODE_INSERT1 = 0x18, OPCODE_INSERT1 = 0x18,
+509 -158
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -3,6 +3,6 @@
#include "assemble.h" #include "assemble.h"
void eval(Program program); int eval(Program p, Arena *a, char *errbuf, int errmax);
#endif // WL_EVAL_INCLUDED #endif // WL_EVAL_INCLUDED
+6 -1
View File
@@ -2,6 +2,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "file.h" #include "file.h"
#include "eval.h"
#include "parse.h" #include "parse.h"
#include "assemble.h" #include "assemble.h"
@@ -35,7 +36,11 @@ int main(void)
print_program(assemble_result.program); print_program(assemble_result.program);
eval(assemble_result.program); ret = eval(assemble_result.program, &a, err, COUNT(err));
if (ret < 0) {
printf("%s\n", err);
return -1;
}
free(src.ptr); free(src.ptr);
free(mem); free(mem);
+2 -2
View File
@@ -361,7 +361,6 @@ Token next_token(Parser *p)
return (Token) { .type=TOKEN_VALUE_STR, .sval=(String) { .ptr=buf, .len=len } }; return (Token) { .type=TOKEN_VALUE_STR, .sval=(String) { .ptr=buf, .len=len } };
} }
if (consume_str(&p->s, S("="))) return (Token) { .type=TOKEN_OPER_ASS };
if (consume_str(&p->s, S("=="))) return (Token) { .type=TOKEN_OPER_EQL }; if (consume_str(&p->s, S("=="))) return (Token) { .type=TOKEN_OPER_EQL };
if (consume_str(&p->s, S("!="))) return (Token) { .type=TOKEN_OPER_NQL }; if (consume_str(&p->s, S("!="))) return (Token) { .type=TOKEN_OPER_NQL };
if (consume_str(&p->s, S("<"))) return (Token) { .type=TOKEN_OPER_LSS }; if (consume_str(&p->s, S("<"))) return (Token) { .type=TOKEN_OPER_LSS };
@@ -371,6 +370,7 @@ Token next_token(Parser *p)
if (consume_str(&p->s, S("*"))) return (Token) { .type=TOKEN_OPER_MUL }; if (consume_str(&p->s, S("*"))) return (Token) { .type=TOKEN_OPER_MUL };
if (consume_str(&p->s, S("/"))) return (Token) { .type=TOKEN_OPER_DIV }; if (consume_str(&p->s, S("/"))) return (Token) { .type=TOKEN_OPER_DIV };
if (consume_str(&p->s, S("%"))) return (Token) { .type=TOKEN_OPER_MOD }; if (consume_str(&p->s, S("%"))) return (Token) { .type=TOKEN_OPER_MOD };
if (consume_str(&p->s, S("="))) return (Token) { .type=TOKEN_OPER_ASS };
if (consume_str(&p->s, S("("))) return (Token) { .type=TOKEN_PAREN_OPEN }; if (consume_str(&p->s, S("("))) return (Token) { .type=TOKEN_PAREN_OPEN };
if (consume_str(&p->s, S(")"))) return (Token) { .type=TOKEN_PAREN_CLOSE }; if (consume_str(&p->s, S(")"))) return (Token) { .type=TOKEN_PAREN_CLOSE };
@@ -1737,7 +1737,7 @@ void print_node(Node *node)
printf(" = "); printf(" = ");
print_node(node->var_value); print_node(node->var_value);
} }
printf(";"); //printf(";");
} }
break; break;
} }