diff --git a/main.wl b/main.wl index 6163f6a..1e67c99 100644 --- a/main.wl +++ b/main.wl @@ -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) -
- \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) -
- - +if 1 == 2: { + let a = 1 +} else { + let b = +} \ No newline at end of file diff --git a/old_2.wl b/old_2.wl index e69de29..6163f6a 100644 --- a/old_2.wl +++ b/old_2.wl @@ -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) +
+ \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 944b2c2..f185134 100644 --- a/src/assemble.c +++ b/src/assemble.c @@ -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; diff --git a/src/assemble.h b/src/assemble.h index f7f6515..18fd38e 100644 --- a/src/assemble.h +++ b/src/assemble.h @@ -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, diff --git a/src/eval.c b/src/eval.c index 1b3e22d..5c12368 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1,4 +1,7 @@ +#include +#include #include +#include #ifndef WL_AMALGAMATION #include "eval.h" @@ -32,16 +35,20 @@ typedef enum { typedef uint64_t Value; +#define ITEMS_PER_MAP_BATCH 8 +#define ITEMS_PER_ARRAY_BATCH 16 + typedef struct MapItems MapItems; struct MapItems { MapItems *next; - Value keys[8]; - Value items[8]; + Value keys [ITEMS_PER_MAP_BATCH]; + Value items[ITEMS_PER_MAP_BATCH]; }; typedef struct { Type type; int count; + int tail_count; MapItems head; MapItems *tail; } MapValue; @@ -49,12 +56,13 @@ typedef struct { typedef struct ArrayItems ArrayItems; struct ArrayItems { ArrayItems *next; - Value items[16]; + Value items[ITEMS_PER_ARRAY_BATCH]; }; typedef struct { Type type; int count; + int tail_count; ArrayItems head; ArrayItems *tail; } ArrayValue; @@ -76,15 +84,22 @@ typedef struct { } StringValue; typedef struct { + int base; + int return_off; } Frame; typedef struct { - Program p; + String code; + String data; int off; Arena *a; + char *errbuf; + int errmax; + int errlen; + int frame_depth; Frame frames[FRAME_LIMIT]; @@ -98,6 +113,28 @@ typedef struct { #define VALUE_FALSE ((Value) 2) #define VALUE_ERROR ((Value) 6) +void eval_report(Eval *e, char *fmt, ...) +{ + if (e->errmax == 0 || e->errlen > 0) + return; + + int len = snprintf(e->errbuf, e->errmax, "Error: "); + if (len < 0) { + // TODO + } + + va_list args; + va_start(args, fmt); + int ret = vsnprintf(e->errbuf + len, e->errmax - len, fmt, args); + va_end(args); + if (ret < 0) { + // TODO + } + len += ret; + + e->errlen = len; +} + Type type_of(Value v) { // 000 none @@ -143,36 +180,50 @@ String get_str(Value *v) if ((*v & 7) == 6) return (String) { (char*) v, strnlen((char*) v, 7) }; - StringValue *p = (StringValue*) v; + StringValue *p = (StringValue*) (*v & ~(uintptr_t) 7); return (String) { p->data, p->len }; } +MapValue *get_map(Value v) +{ + return (MapValue*) (v & ~(uintptr_t) 7); +} + +ArrayValue *get_array(Value v) +{ + return (ArrayValue*) (v & ~(uintptr_t) 7); +} + Value make_int(Eval *e, int64_t x) { - if (x <= (1ULL << 60)-1 && x >= -(1ULL << 60)) + if (x <= (int64_t) (1ULL << 60)-1 && x >= (int64_t) -(1ULL << 60)) return ((Value) x >> 3) | 3; IntValue *v = alloc(e->a, (int) sizeof(IntValue), _Alignof(IntValue)); - if (v == NULL) + if (v == NULL) { + eval_report(e, "Out of memory"); return VALUE_ERROR; + } v->type = TYPE_INT; v->raw = x; - ASSERT(((uintptr_t) v & 7) == 0); + assert(((uintptr_t) v & 7) == 0); return ((Value) v) | 7; } Value make_float(Eval *e, float x) { FloatValue *v = alloc(e->a, (int) sizeof(FloatValue), _Alignof(FloatValue)); - if (v == NULL) + if (v == NULL) { + eval_report(e, "Out of memory"); return VALUE_ERROR; + } v->type = TYPE_FLOAT; v->raw = x; - ASSERT(((uintptr_t) v & 7) == 0); + assert(((uintptr_t) v & 7) == 0); return ((Value) v) | 7; } @@ -185,16 +236,140 @@ Value make_str(Eval *e, String x) } StringValue *v = alloc(e->a, (int) sizeof(StringValue) + x.len, _Alignof(StringValue)); - if (v == NULL) + if (v == NULL) { + eval_report(e, "Out of memory"); return VALUE_ERROR; + } v->len = x.len; memcpy(v->data, x.ptr, x.len); - ASSERT(((uintptr_t) v & 7) == 0); + assert(((uintptr_t) v & 7) == 0); return ((Value) v) | 7; } +Value make_map(Eval *e) +{ + MapValue *m = alloc(e->a, (int) sizeof(MapValue), _Alignof(MapValue)); + if (m == NULL) { + eval_report(e, "Out of memory"); + return VALUE_ERROR; + } + + m->type = TYPE_MAP; + m->count = 0; + m->tail_count = 0; + m->tail = &m->head; + + return (Value) m | 7; +} + +Value make_array(Eval *e) +{ + ArrayValue *a = alloc(e->a, (int) sizeof(ArrayValue), _Alignof(ArrayValue)); + if (a == NULL) { + eval_report(e, "Out of memory"); + return VALUE_ERROR; + } + + a->type = TYPE_ARRAY; + a->count = 0; + a->tail_count = 0; + a->tail = &a->head; + + return (Value) a | 7; +} + +b32 valeq(Value a, Value b); + +int map_select(Eval *e, Value map, Value key, Value *val) +{ + MapValue *p = get_map(map); + 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++) + if (valeq(batch->keys[i], key)) { + *val = batch->items[i]; + return 0; + } + + batch = batch->next; + } + + return -1; +} + +int map_insert(Eval *e, Value map, Value key, Value val) +{ + MapValue *p = get_map(map); + if (p->tail_count == ITEMS_PER_MAP_BATCH) { + + MapItems *batch = alloc(e->a, (int) sizeof(MapItems), _Alignof(MapItems)); + if (batch == NULL) { + eval_report(e, "Out of memory"); + return -1; + } + + batch->next = NULL; + p->tail = batch; + p->tail_count = 0; + } + + p->tail->keys[p->tail_count] = key; + p->tail->items[p->tail_count] = val; + p->tail_count++; + p->count++; + return 0; +} + +Value *array_select(Eval *e, Value array, uint32_t key) +{ + ArrayValue *p = get_array(array); + ArrayItems *batch = &p->head; + int cursor = 0; + while (batch) { + + int num = ITEMS_PER_MAP_BATCH; + if (batch->next == NULL) + num = p->tail_count; + + if (cursor <= key && key < cursor + num) + return &batch->items[key - cursor]; + + batch = batch->next; + cursor += num; + } + + return NULL; +} + +int array_append(Eval *e, Value array, Value val) +{ + ArrayValue *p = get_array(array); + if (p->tail_count == ITEMS_PER_MAP_BATCH) { + + ArrayItems *batch = alloc(e->a, (int) sizeof(ArrayItems), _Alignof(ArrayItems)); + if (batch == NULL) { + eval_report(e, "Out of memory"); + return -1; + } + + batch->next = NULL; + p->tail = batch; + p->tail_count = 0; + } + + p->tail->items[p->tail_count] = val; + p->tail_count++; + p->count++; + return 0; +} + b32 valeq(Value a, Value b) { Type t1 = type_of(a); @@ -224,7 +399,7 @@ b32 valeq(Value a, Value b) return false; // TODO case TYPE_STRING: - return streq(get_str(a), get_str(b)); + return streq(get_str(&a), get_str(&b)); case TYPE_ERROR: return true; @@ -233,64 +408,150 @@ b32 valeq(Value a, Value b) return false; } -void step(Eval *e) +b32 valgrt(Value a, Value b) { - uint8_t b = ((uint8_t*) e->p.ptr)[e->off++]; + Type t1 = type_of(a); + Type t2 = type_of(b); - switch (b) { + if (t1 != t2) + return false; + + switch (t1) { + + case TYPE_NONE: + return VALUE_FALSE; + + case TYPE_BOOL: + return VALUE_FALSE; + + case TYPE_INT: + return get_int(a) > get_int(b); + + case TYPE_FLOAT: + return get_float(a) > get_float(b); + + case TYPE_MAP: + return false; + + case TYPE_ARRAY: + return false; + + case TYPE_STRING: + return false; + + case TYPE_ERROR: + return false; + } + + return false; +} + +int step(Eval *e) +{ + uint8_t opcode = e->code.ptr[e->off++]; + switch (opcode) { case OPCODE_NOPE: - // Do nothing + { + // Do nothing + } + break; + + case OPCODE_EXIT: + { + return 1; + } + break; + + case OPCODE_PUSHN: + { + e->eval_stack[e->eval_depth++] = VALUE_NONE; + } break; case OPCODE_PUSHI: { int64_t x; - - memcpy(&x, (uint8_t*) e->p.ptr + e->off, sizeof(x)); + memcpy(&x, (uint8_t*) e->code.ptr + e->off, sizeof(x)); e->off += (int) sizeof(x); - e->eval_stack[e->eval_depth++] = x; + Value v = make_int(e, x); + if (v == VALUE_ERROR) return -1; + + e->eval_stack[e->eval_depth++] = v; } break; case OPCODE_PUSHF: { double x; - - memcpy(&x, (uint8_t*) e->p.ptr + e->off, sizeof(x)); + memcpy(&x, (uint8_t*) e->code.ptr + e->off, sizeof(x)); e->off += (int) sizeof(x); - e->eval_stack[e->eval_depth++] = x; + Value v = make_float(e, x); + if (v == VALUE_ERROR) return -1; + + e->eval_stack[e->eval_depth++] = v; } break; case OPCODE_PUSHS: { - // TODO + uint32_t off; + memcpy(&off, (uint8_t*) e->code.ptr + e->off, sizeof(uint32_t)); + e->off += (int) sizeof(uint32_t); + + uint32_t len; + memcpy(&len, (uint8_t*) e->code.ptr + e->off, sizeof(uint32_t)); + e->off += (int) sizeof(uint32_t); + + Value v = make_str(e, (String) { e->data.ptr + off, len }); + if (v == VALUE_ERROR) return -1; + + e->eval_stack[e->eval_depth++] = v; } break; case OPCODE_PUSHV: { - // TODO + uint8_t idx; + 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]; } break; case OPCODE_PUSHA: { - // TODO + uint32_t cap; + memcpy(&cap, (uint8_t*) e->code.ptr + e->off, sizeof(uint32_t)); + e->off += sizeof(uint32_t); + + Value v = make_array(e); + if (v == VALUE_ERROR) return -1; + + e->eval_stack[e->eval_depth++] = v; } break; case OPCODE_PUSHM: { - // TODO + uint32_t cap; + memcpy(&cap, (uint8_t*) e->code.ptr + e->off, sizeof(uint32_t)); + e->off += sizeof(uint32_t); + + Value v = make_map(e); + if (v == VALUE_ERROR) return -1; + + e->eval_stack[e->eval_depth++] = v; } break; case OPCODE_POP: - e->eval_depth--; + { + e->eval_depth--; + } break; case OPCODE_NEG: @@ -303,7 +564,8 @@ void step(Eval *e) else if (t == TYPE_INT) r = make_int(e, -get_int(a)); else if (t == TYPE_FLOAT) r = make_float(e, -get_float(a)); else { - // TODO + eval_report(e, "Invalid operation on non-numeric value"); + return -1; } e->eval_stack[e->eval_depth++] = r; @@ -338,6 +600,11 @@ void step(Eval *e) Value b = e->eval_stack[e->eval_depth-1]; e->eval_depth -= 2; + if (type_of(a) != TYPE_INT || type_of(b) != TYPE_INT) { + eval_report(e, "Invalid operation on non-numeric value"); + return -1; + } + Value r = valgrt(a, b) || valeq(a, b) ? VALUE_FALSE : VALUE_TRUE; e->eval_stack[e->eval_depth++] = r; } @@ -349,6 +616,11 @@ void step(Eval *e) Value b = e->eval_stack[e->eval_depth-1]; e->eval_depth -= 2; + if (type_of(a) != TYPE_INT || type_of(b) != TYPE_INT) { + eval_report(e, "Invalid operation on non-numeric value"); + return -1; + } + Value r = valgrt(a, b) ? VALUE_TRUE : VALUE_FALSE; e->eval_stack[e->eval_depth++] = r; } @@ -374,9 +646,7 @@ void step(Eval *e) int64_t v = get_int(b); // TODO: check overflow and underflow r = make_int(e, u + v); - if (r == VALUE_ERROR) { - // TODO - } + if (r == VALUE_ERROR) return -1; } break; @@ -385,9 +655,7 @@ void step(Eval *e) float u = (float) get_int(a); float v = get_float(b); r = make_float(e, u + v); - if (r == VALUE_ERROR) { - // TODO - } + if (r == VALUE_ERROR) return -1; } break; @@ -396,9 +664,7 @@ void step(Eval *e) float u = get_float(a); float v = (float) get_int(b); r = make_float(e, u + v); - if (r == VALUE_ERROR) { - // TODO - } + if (r == VALUE_ERROR) return -1; } break; @@ -408,15 +674,13 @@ void step(Eval *e) float v = get_float(b); // TODO: check overflow and underflow r = make_float(e, u + v); - if (r == VALUE_ERROR) { - // TODO - } + if (r == VALUE_ERROR) return -1; } break; default: - // TODO - break; + eval_report(e, "Invalid operation on non-numeric value"); + return -1; } e->eval_stack[e->eval_depth++] = r; @@ -429,7 +693,6 @@ void step(Eval *e) Value b = e->eval_stack[e->eval_depth-1]; e->eval_depth -= 2; - Type t1 = type_of(a); Type t2 = type_of(b); @@ -442,9 +705,7 @@ void step(Eval *e) int64_t v = get_int(b); // TODO: check overflow and underflow r = make_int(e, u - v); - if (r == VALUE_ERROR) { - // TODO - } + if (r == VALUE_ERROR) return -1; } break; @@ -453,9 +714,7 @@ void step(Eval *e) float u = (float) get_int(a); float v = get_float(b); r = make_float(e, u - v); - if (r == VALUE_ERROR) { - // TODO - } + if (r == VALUE_ERROR) return -1; } break; @@ -464,9 +723,7 @@ void step(Eval *e) float u = get_float(a); float v = (float) get_int(b); r = make_float(e, u - v); - if (r == VALUE_ERROR) { - // TODO - } + if (r == VALUE_ERROR) return -1; } break; @@ -476,15 +733,13 @@ void step(Eval *e) float v = get_float(b); // TODO: check overflow and underflow r = make_float(e, u - v); - if (r == VALUE_ERROR) { - // TODO - } + if (r == VALUE_ERROR) return -1; } break; default: - // TODO - break; + eval_report(e, "Invalid operation on non-numeric value"); + return -1; } e->eval_stack[e->eval_depth++] = r; @@ -497,7 +752,6 @@ void step(Eval *e) Value b = e->eval_stack[e->eval_depth-1]; e->eval_depth -= 2; - Type t1 = type_of(a); Type t2 = type_of(b); @@ -510,9 +764,7 @@ void step(Eval *e) int64_t v = get_int(b); // TODO: check overflow and underflow r = make_int(e, u * v); - if (r == VALUE_ERROR) { - // TODO - } + if (r == VALUE_ERROR) return -1; } break; @@ -521,9 +773,7 @@ void step(Eval *e) float u = (float) get_int(a); float v = get_float(b); r = make_float(e, u * v); - if (r == VALUE_ERROR) { - // TODO - } + if (r == VALUE_ERROR) return -1; } break; @@ -532,9 +782,7 @@ void step(Eval *e) float u = get_float(a); float v = (float) get_int(b); r = make_float(e, u * v); - if (r == VALUE_ERROR) { - // TODO - } + if (r == VALUE_ERROR) return -1; } break; @@ -544,15 +792,13 @@ void step(Eval *e) float v = get_float(b); // TODO: check overflow and underflow r = make_float(e, u * v); - if (r == VALUE_ERROR) { - // TODO - } + if (r == VALUE_ERROR) return -1; } break; default: - // TODO - break; + eval_report(e, "Invalid operation on non-numeric value"); + return -1; } e->eval_stack[e->eval_depth++] = r; @@ -578,9 +824,7 @@ void step(Eval *e) int64_t u = get_int(a); int64_t v = get_int(b); r = make_int(e, u / v); - if (r == VALUE_ERROR) { - // TODO - } + if (r == VALUE_ERROR) return -1; } break; @@ -591,9 +835,7 @@ void step(Eval *e) float u = (float) get_int(a); float v = get_float(b); r = make_float(e, u / v); - if (r == VALUE_ERROR) { - // TODO - } + if (r == VALUE_ERROR) return -1; } break; @@ -604,9 +846,7 @@ void step(Eval *e) float u = get_float(a); float v = (float) get_int(b); r = make_float(e, u / v); - if (r == VALUE_ERROR) { - // TODO - } + if (r == VALUE_ERROR) return -1; } break; @@ -615,15 +855,13 @@ void step(Eval *e) float u = get_float(a); float v = get_float(b); r = make_float(e, u / v); - if (r == VALUE_ERROR) { - // TODO - } + if (r == VALUE_ERROR) return -1; } break; default: - // TODO - break; + eval_report(e, "Invalid operation on non-numeric value"); + return -1; } e->eval_stack[e->eval_depth++] = r; @@ -639,98 +877,104 @@ void step(Eval *e) Type t1 = type_of(a); Type t2 = type_of(b); - Value r; - switch (TYPE_PAIR(t1, t2)) { - - case TYPE_PAIR(TYPE_INT, TYPE_INT): - { - // TODO: check division by 0 - - int64_t u = get_int(a); - int64_t v = get_int(b); - r = make_int(e, u % v); - if (r == VALUE_ERROR) { - // TODO - } - } - break; - - case TYPE_PAIR(TYPE_INT, TYPE_FLOAT): - { - // TODO: check division by 0 - - float u = (float) get_int(a); - float v = get_float(b); - r = make_float(e, u % v); - if (r == VALUE_ERROR) { - // TODO - } - } - break; - - case TYPE_PAIR(TYPE_FLOAT, TYPE_INT): - { - // TODO: check division by 0 - - float u = get_float(a); - float v = (float) get_int(b); - r = make_float(e, u % v); - if (r == VALUE_ERROR) { - // TODO - } - } - break; - - case TYPE_PAIR(TYPE_FLOAT, TYPE_FLOAT): - { - float u = get_float(a); - float v = get_float(b); - r = make_float(e, u % v); - if (r == VALUE_ERROR) { - // TODO - } - } - break; - - default: - // TODO - break; + if (t1 != TYPE_INT || t2 != TYPE_INT) { + eval_report(e, "Invalid modulo operation on non-integer value"); + return -1; } + int64_t u = get_int(a); + int64_t v = get_int(b); + Value r = make_int(e, u % v); + if (r == VALUE_ERROR) return -1; + e->eval_stack[e->eval_depth++] = r; } break; case OPCODE_SETV: { - // TODO + uint8_t x; + 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]; } break; case OPCODE_JUMP: { uint32_t x; - - memcpy(&x, (uint8_t*) e->p.ptr + e->off, (int) sizeof(x)); - e->off = (int) sizeof(x); + memcpy(&x, (uint8_t*) e->code.ptr + e->off, (int) sizeof(x)); + e->off = x; } break; case OPCODE_JIFP: { - // TODO + uint32_t x; + memcpy(&x, (uint8_t*) e->code.ptr + e->off, (int) sizeof(x)); + e->off += (int) sizeof(x); + + Value a = e->eval_stack[--e->eval_depth]; + + if (a == VALUE_FALSE) + e->off = x; + else { + if (a != VALUE_TRUE) { + eval_report(e, "Invalid operation on non-boolean value"); + return -1; + } + } } break; case OPCODE_CALL: { - // TODO + 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) { + 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->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: { - // TODO + 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; } break; @@ -740,7 +984,13 @@ void step(Eval *e) Value set = e->eval_stack[e->eval_depth-2]; e->eval_depth--; - // TODO + if (type_of(set) != TYPE_ARRAY) { + eval_report(e, "Invalid operation on non-array value"); + return -1; + } + + int ret = array_append(e, set, val); + if (ret < 0) return -1; } break; @@ -751,7 +1001,24 @@ void step(Eval *e) Value set = e->eval_stack[e->eval_depth-3]; e->eval_depth -= 2; - // TODO + if (type_of(set) == TYPE_ARRAY) { + + Value *dst = array_select(e, set, key); + if (dst == NULL) { + eval_report(e, "Index out of range"); + return -1; + } + *dst = val; + + } else if (type_of(set) == TYPE_MAP) { + + int ret = map_insert(e, set, key, val); + if (ret < 0) return -1; + + } else { + eval_report(e, "Invalid insertion on non-array and non-map value"); + return -1; + } } break; @@ -762,26 +1029,110 @@ void step(Eval *e) Value val = e->eval_stack[e->eval_depth-3]; e->eval_depth -= 2; - // TODO + if (type_of(set) == TYPE_ARRAY) { + + Value *dst = array_select(e, set, key); + if (dst == NULL) { + eval_report(e, "Index out of range"); + return -1; + } + *dst = val; + + } else if (type_of(set) == TYPE_MAP) { + + int ret = map_insert(e, set, key, val); + if (ret < 0) return -1; + + } else { + eval_report(e, "Invalid insertion on non-array and non-map value"); + return -1; + } } break; case OPCODE_SELECT: { - // TODO + Value key = e->eval_stack[e->eval_depth-1]; + Value set = e->eval_stack[e->eval_depth-2]; + e->eval_depth -= 2; + + Value r; + if (type_of(set) == TYPE_ARRAY) { + + Value *src = array_select(e, set, key); + if (src == NULL) { + assert(0); // TODO + } + r = *src; + + } else if (type_of(set) == TYPE_MAP) { + + int ret = map_select(e, set, key, &r); + if (ret < 0) { + assert(0); // TODO + } + + } else { + eval_report(e, "Invalid selection from non-array and non-map value"); + return -1; + } + + e->eval_stack[e->eval_depth++] = r; } break; default: - break; + eval_report(e, "Invalid opcode (offset %d)", e->off-1); + return -1; } + + return 0; } -void eval(Program p) +int eval(Program p, Arena *a, char *errbuf, int errmax) { - Eval e = { p, 0 }; - for (;;) - step(&e); + 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)); - // TODO + if (magic != 0xFEEDBEEF) { + snprintf(errbuf, errmax, "Invalid program"); + 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 }, + .off=0, + .a=a, + .errbuf=errbuf, + .errmax=errmax, + .errlen=0, + .frame_depth=0, + .eval_depth=0, + }; + + Frame *f = &e.frames[e.frame_depth++]; + f->base = 0; + f->return_off = 0; + + for (;;) { + int ret = step(&e); + if (ret < 0) return -1; + if (ret == 1) break; + } + + return 0; } \ No newline at end of file diff --git a/src/eval.h b/src/eval.h index ae8db83..5622851 100644 --- a/src/eval.h +++ b/src/eval.h @@ -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 diff --git a/src/main.c b/src/main.c index 464b143..177339f 100644 --- a/src/main.c +++ b/src/main.c @@ -2,6 +2,7 @@ #include #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); diff --git a/src/parse.c b/src/parse.c index b15f736..b6dd31a 100644 --- a/src/parse.c +++ b/src/parse.c @@ -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; }