Improvements on the evaluator
This commit is contained in:
@@ -1,46 +1,5 @@
|
||||
|
||||
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>
|
||||
if 1 == 2: {
|
||||
let a = 1
|
||||
} else {
|
||||
let b =
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
+120
-68
@@ -43,6 +43,7 @@ typedef enum {
|
||||
typedef struct {
|
||||
ScopeType type;
|
||||
int sym_base;
|
||||
int max_vars;
|
||||
FunctionCall* calls;
|
||||
} Scope;
|
||||
|
||||
@@ -212,29 +213,48 @@ int count_nodes(Node *head)
|
||||
return n;
|
||||
}
|
||||
|
||||
int 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 i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int find_symbol_in_function(Assembler *a, String name)
|
||||
Scope *parent_scope(Assembler *a)
|
||||
{
|
||||
assert(a->num_scopes > 0);
|
||||
|
||||
// Find the index of the parent function scope or the global scope
|
||||
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--;
|
||||
|
||||
for (int i = a->num_syms-1; i >= a->scopes[parent].sym_base; i--)
|
||||
if (streq(a->syms[i].name, name))
|
||||
return i;
|
||||
Scope *scope = &a->scopes[parent];
|
||||
|
||||
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)
|
||||
@@ -244,14 +264,21 @@ int declare_variable(Assembler *a, String name)
|
||||
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",
|
||||
name.len, name.ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
a->syms[a->num_syms] = (Symbol) { SYMBOL_VAR, name, -1 };
|
||||
return a->num_syms++;
|
||||
int off = count_local_vars(a);
|
||||
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)
|
||||
@@ -261,14 +288,13 @@ int declare_function(Assembler *a, String name, int off)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (find_symbol_in_local_scope(a, name) >= 0) {
|
||||
assembler_report(a, "Symbol '%.*s' already declared in this scope",
|
||||
name.len, name.ptr);
|
||||
if (find_symbol_in_local_scope(a, name)) {
|
||||
assembler_report(a, "Symbol '%.*s' already declared in this scope", name.len, name.ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
a->syms[a->num_syms] = (Symbol) { SYMBOL_FUNC, name, off };
|
||||
return a->num_syms++;
|
||||
a->syms[a->num_syms++] = (Symbol) { SYMBOL_FUNC, name, off };
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -352,6 +378,7 @@ int push_scope(Assembler *a, ScopeType type)
|
||||
Scope *scope = &a->scopes[a->num_scopes++];
|
||||
scope->type = type;
|
||||
scope->sym_base = a->num_syms;
|
||||
scope->max_vars = 0;
|
||||
scope->calls = NULL;
|
||||
return 0;
|
||||
}
|
||||
@@ -364,15 +391,14 @@ int pop_scope(Assembler *a)
|
||||
FunctionCall **prev = &scope->calls;
|
||||
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;
|
||||
call = call->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
Symbol *sym = &a->syms[idx];
|
||||
if (sym->type != SYMBOL_FUNC) {
|
||||
assembler_report(a, "Symbol '%.*s' is not a function", call->name.len, call->name.ptr);
|
||||
return -1;
|
||||
@@ -405,8 +431,6 @@ int pop_scope(Assembler *a)
|
||||
|
||||
void assemble_node(Assembler *a, Node *node)
|
||||
{
|
||||
printf("Compiling [%.*s]\n", node->text.len, node->text.ptr);
|
||||
|
||||
switch (node->type) {
|
||||
|
||||
case NODE_FUNC_DECL:
|
||||
@@ -420,6 +444,9 @@ void assemble_node(Assembler *a, Node *node)
|
||||
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;
|
||||
@@ -434,11 +461,11 @@ void assemble_node(Assembler *a, Node *node)
|
||||
|
||||
for (int i = arg_count-1; i >= 0; i--) {
|
||||
|
||||
int idx = declare_variable(a, args[i]->sval);
|
||||
if (idx < 0) return;
|
||||
int off = declare_variable(a, args[i]->sval);
|
||||
if (off < 0) return;
|
||||
|
||||
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)) {
|
||||
@@ -450,6 +477,8 @@ void assemble_node(Assembler *a, Node *node)
|
||||
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;
|
||||
|
||||
@@ -493,14 +522,16 @@ void assemble_node(Assembler *a, Node *node)
|
||||
|
||||
case NODE_VAR_DECL:
|
||||
{
|
||||
int idx = declare_variable(a, node->var_name);
|
||||
if (idx < 0) return;
|
||||
int off = declare_variable(a, node->var_name);
|
||||
if (off < 0) return;
|
||||
|
||||
if (node->var_value) {
|
||||
if (node->var_value)
|
||||
assemble_node(a, node->var_value);
|
||||
append_u8(&a->out, OPCODE_SETV);
|
||||
append_u8(&a->out, idx);
|
||||
}
|
||||
else
|
||||
append_u8(&a->out, OPCODE_PUSHN);
|
||||
|
||||
append_u8(&a->out, OPCODE_SETV);
|
||||
append_u8(&a->out, off);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -726,13 +757,17 @@ void assemble_node(Assembler *a, Node *node)
|
||||
case NODE_VALUE_VAR:
|
||||
{
|
||||
String name = node->sval;
|
||||
int idx = find_symbol_in_function(a, name);
|
||||
if (idx < 0) {
|
||||
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, idx); // TODO: make this relative to the frame
|
||||
append_u8(&a->out, sym->off);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -794,20 +829,20 @@ void assemble_node(Assembler *a, Node *node)
|
||||
|
||||
String name = dst->sval;
|
||||
|
||||
int idx = find_symbol_in_function(a, name);
|
||||
if (idx < 0) {
|
||||
Symbol *sym = find_symbol_in_function(a, name);
|
||||
if (sym == NULL) {
|
||||
assembler_report(a, "Undeclared variable '%.*s'", name.len, name.ptr);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
assemble_node(a, src);
|
||||
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) {
|
||||
|
||||
@@ -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};
|
||||
|
||||
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);
|
||||
if (ret < 0) {
|
||||
if (ret < 0)
|
||||
return (AssembleResult) { (Program) {0}, a.errlen };
|
||||
}
|
||||
|
||||
append_u8(&a.out, OPCODE_VARS);
|
||||
int p = append_u32(&a.out, 0);
|
||||
|
||||
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);
|
||||
if (ret < 0) {
|
||||
if (ret < 0)
|
||||
return (AssembleResult) { (Program) {0}, a.errlen };
|
||||
}
|
||||
|
||||
patch_u32(&a.out, p1, a.out.len - 3 * sizeof(uint32_t));
|
||||
patch_u32(&a.out, p2, a.strings_len);
|
||||
OutputBuffer out = {0};
|
||||
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);
|
||||
|
||||
Program p = {
|
||||
a.out.ptr,
|
||||
a.out.len,
|
||||
};
|
||||
|
||||
return (AssembleResult) { p, a.errlen };
|
||||
free(a.out.ptr);
|
||||
return (AssembleResult) { (Program) { out.ptr, out.len }, a.errlen };
|
||||
}
|
||||
|
||||
void print_program(Program p)
|
||||
@@ -899,7 +931,7 @@ void print_program(Program p)
|
||||
|
||||
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++]) {
|
||||
|
||||
@@ -907,6 +939,10 @@ void print_program(Program p)
|
||||
printf("NOPE");
|
||||
break;
|
||||
|
||||
case OPCODE_EXIT:
|
||||
printf("EXIT");
|
||||
break;
|
||||
|
||||
case OPCODE_PUSHI:
|
||||
{
|
||||
uint64_t x;
|
||||
@@ -971,6 +1007,12 @@ void print_program(Program p)
|
||||
}
|
||||
break;
|
||||
|
||||
case OPCODE_PUSHN:
|
||||
{
|
||||
printf("PUSHN");
|
||||
}
|
||||
break;
|
||||
|
||||
case OPCODE_POP:
|
||||
printf("POP");
|
||||
break;
|
||||
@@ -1051,14 +1093,24 @@ void print_program(Program p)
|
||||
memcpy(&num, p.ptr + cur, sizeof(uint8_t));
|
||||
cur += sizeof(uint8_t);
|
||||
|
||||
uint8_t off;
|
||||
memcpy(&off, 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;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
enum {
|
||||
OPCODE_NOPE = 0x00,
|
||||
OPCODE_EXIT = 0x23,
|
||||
OPCODE_PUSHI = 0x01,
|
||||
OPCODE_PUSHF = 0x02,
|
||||
OPCODE_PUSHS = 0x03,
|
||||
@@ -27,6 +28,7 @@ enum {
|
||||
OPCODE_JUMP = 0x13,
|
||||
OPCODE_JIFP = 0x14,
|
||||
OPCODE_CALL = 0x15,
|
||||
OPCODE_VARS = 0x22,
|
||||
OPCODE_RET = 0x16,
|
||||
OPCODE_APPEND = 0x17,
|
||||
OPCODE_INSERT1 = 0x18,
|
||||
|
||||
+511
-160
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -3,6 +3,6 @@
|
||||
|
||||
#include "assemble.h"
|
||||
|
||||
void eval(Program program);
|
||||
int eval(Program p, Arena *a, char *errbuf, int errmax);
|
||||
|
||||
#endif // WL_EVAL_INCLUDED
|
||||
|
||||
+6
-1
@@ -2,6 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "file.h"
|
||||
#include "eval.h"
|
||||
#include "parse.h"
|
||||
#include "assemble.h"
|
||||
|
||||
@@ -35,7 +36,11 @@ int main(void)
|
||||
|
||||
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(mem);
|
||||
|
||||
+2
-2
@@ -361,7 +361,6 @@ Token next_token(Parser *p)
|
||||
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_NQL };
|
||||
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_DIV };
|
||||
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_CLOSE };
|
||||
@@ -1737,7 +1737,7 @@ void print_node(Node *node)
|
||||
printf(" = ");
|
||||
print_node(node->var_value);
|
||||
}
|
||||
printf(";");
|
||||
//printf(";");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user