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)
-
-
-
-
- \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)
+
+
+
+
+ \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;
}
\c.content
-