diff --git a/Makefile b/Makefile index 8e6b94a..39e065a 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,2 @@ all: - gcc src/basic.c src/file.c src/parse.c src/assemble.c src/main.c -o wl -Wall -Wextra -O0 -g3 \ No newline at end of file + gcc src/basic.c src/file.c src/parse.c src/assemble.c src/eval.c src/main.c -o wl -Wall -Wextra -O0 -g3 \ No newline at end of file diff --git a/main.wl b/main.wl index 6482ea8..6163f6a 100644 --- a/main.wl +++ b/main.wl @@ -1,6 +1,7 @@ -title = "My Website" -posts = [ +let title = "My Website" + +let posts = [ { name: "Post Title 1", date: "1 Jan 2025", @@ -21,7 +22,7 @@ posts = [ fun render_comment(c)
- \{c.author} (\c.date) + \c.author (\c.date)

\c.content

\for child in c.children: @@ -34,11 +35,12 @@ fun render_comment(c) \title + This is regular text \for post in posts:
- \{post.title} (\post.date) + \post.title (\post.date) \for comment in post.comments: - render_comment(comment) + render_comment(comment)
diff --git a/old_2.wl b/old_2.wl new file mode 100644 index 0000000..e69de29 diff --git a/src/assemble.c b/src/assemble.c index ffda626..944b2c2 100644 --- a/src/assemble.c +++ b/src/assemble.c @@ -2,15 +2,15 @@ #include #include #include +#include #ifndef WL_AMALGAMATION #include "parse.h" #include "assemble.h" #endif -#define MAX_SCOPES 32 -#define MAX_VARS 1024 -#define MAX_STRING_LITERALS 1024 +#define MAX_SCOPES 32 +#define MAX_SYMBOLS 1024 typedef struct FunctionCall FunctionCall; struct FunctionCall { @@ -19,23 +19,31 @@ struct FunctionCall { int off; }; +typedef enum { + SYMBOL_VAR, + SYMBOL_FUNC, +} SymbolType; + typedef struct { - String name; -} Variable; + SymbolType type; + String name; + int off; +} Symbol; typedef enum { + SCOPE_GLOBAL, SCOPE_FUNC, SCOPE_FOR, SCOPE_WHILE, SCOPE_IF, SCOPE_ELSE, + SCOPE_BLOCK, } ScopeType; typedef struct { - ScopeType type; - int var_base; - // TODO - FunctionCall *calls; + ScopeType type; + int sym_base; + FunctionCall* calls; } Scope; typedef struct { @@ -51,8 +59,8 @@ typedef struct { OutputBuffer out; - int num_vars; - Variable vars[MAX_VARS]; + int num_syms; + Symbol syms[MAX_SYMBOLS]; int num_scopes; Scope scopes[MAX_SCOPES]; @@ -183,6 +191,11 @@ void patch_with_current_offset(OutputBuffer *out, int off) patch_mem(out, off, &x, (int) sizeof(x)); } +void patch_u32(OutputBuffer *out, int off, uint32_t x) +{ + patch_mem(out, off, &x, (int) sizeof(x)); +} + int current_offset(OutputBuffer *out) { return out->len; @@ -199,33 +212,63 @@ int count_nodes(Node *head) return n; } -int find_variable(Assembler *a, String name) +int find_symbol_in_local_scope(Assembler *a, String name) { - Scope *scope = &a->scopes[a->num_scopes-1]; - for (int i = scope->var_base; i < a->num_vars; i++) - if (streq(name, a->vars[i].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; - assembler_report(a, "Undeclared variable '%.*s'", name.len, name.ptr); + return -1; } -int declare_var(Assembler *a, String name) +int find_symbol_in_function(Assembler *a, String name) { - if (a->num_vars == MAX_VARS) { - assembler_report(a, "Variable limit reached"); + 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) + parent--; + + for (int i = a->num_syms-1; i >= a->scopes[parent].sym_base; i--) + if (streq(a->syms[i].name, name)) + return i; + + return -1; +} + +int declare_variable(Assembler *a, String name) +{ + if (a->num_syms == MAX_SYMBOLS) { + assembler_report(a, "Symbol limit reached"); return -1; } - Scope *scope = &a->scopes[a->num_scopes-1]; - for (int i = scope->var_base; i < a->num_vars; i++) - if (streq(name, a->vars[i].name)) { - assembler_report(a, "Variable '%.*s' declared twice", name.len, name.ptr); - 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); + return -1; + } - int idx = a->num_vars++; - a->vars[idx] = (Variable) { name }; - return idx - scope->var_base; + a->syms[a->num_syms] = (Symbol) { SYMBOL_VAR, name, -1 }; + return a->num_syms++; +} + +int declare_function(Assembler *a, String name, int off) +{ + if (a->num_syms == MAX_SYMBOLS) { + assembler_report(a, "Symbol limit reached"); + 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); + return -1; + } + + a->syms[a->num_syms] = (Symbol) { SYMBOL_FUNC, name, off }; + return a->num_syms++; } /* @@ -273,6 +316,7 @@ b32 is_expr(Node *node) break; case NODE_SELECT: + case NODE_NESTED: case NODE_FUNC_CALL: case NODE_OPER_POS: case NODE_OPER_NEG: @@ -299,8 +343,70 @@ b32 is_expr(Node *node) return false; } +int push_scope(Assembler *a, ScopeType type) +{ + if (a->num_scopes == MAX_SCOPES) { + assembler_report(a, "Scope limit reached"); + return -1; + } + Scope *scope = &a->scopes[a->num_scopes++]; + scope->type = type; + scope->sym_base = a->num_syms; + scope->calls = NULL; + return 0; +} + +int pop_scope(Assembler *a) +{ + Scope *scope = &a->scopes[a->num_scopes-1]; + + FunctionCall *call = scope->calls; + FunctionCall **prev = &scope->calls; + while (call) { + + int idx = find_symbol_in_local_scope(a, call->name); + + if (idx == -1) { + 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; + } + + patch_u32(&a->out, call->off, sym->off); + + *prev = call->next; + call = call->next; + } + + if (scope->calls) { + + if (a->num_scopes == 1) { + assembler_report(a, "Undefined function '%.*s'", + scope->calls->name.len, + scope->calls->name.ptr); + return -1; + } + + Scope *parent_scope = &a->scopes[a->num_scopes-2]; + *prev = parent_scope->calls; + parent_scope->calls = scope->calls; + } + + a->num_syms = scope->sym_base; + a->num_scopes--; + return 0; +} + void assemble_node(Assembler *a, Node *node) { + printf("Compiling [%.*s]\n", node->text.len, node->text.ptr); + switch (node->type) { case NODE_FUNC_DECL: @@ -308,30 +414,44 @@ void assemble_node(Assembler *a, Node *node) append_u8(&a->out, OPCODE_JUMP); int p1 = append_u32(&a->out, 0); - // TODO: resolve references + int ret = declare_function(a, node->func_name, current_offset(&a->out)); + if (ret < 0) return; - int arg_count = count_nodes(node->func_args); + ret = push_scope(a, SCOPE_FUNC); + if (ret < 0) return; Node *args[32]; - if (arg_count > COUNT(args)) { - assembler_report(a, "Argument limit reached"); - return; + int arg_count = 0; + Node *arg = node->func_args; + while (arg) { + if (arg_count == COUNT(args)) { + assembler_report(a, "Argument limit reached"); + return; + } + args[arg_count++] = arg; + arg = arg->next; } for (int i = arg_count-1; i >= 0; i--) { - int idx = declare_var(a, args[i]->sval); + int idx = declare_variable(a, args[i]->sval); if (idx < 0) return; append_u8(&a->out, OPCODE_SETV); - append_u8(&a->out, idx); + append_u8(&a->out, idx); // TODO: make this relative to the frame } if (is_expr(node->func_body)) { assemble_node(a, node->func_body); append_u8(&a->out, OPCODE_RET); - } else + } else { assemble_node(a, node->func_body); + append_u8(&a->out, OPCODE_PUSHN); + append_u8(&a->out, OPCODE_RET); + } + + ret = pop_scope(a); + if (ret < 0) return; patch_with_current_offset(&a->out, p1); } @@ -350,37 +470,30 @@ void assemble_node(Assembler *a, Node *node) arg = arg->next; } - if (func->type == NODE_VALUE_VAR) { - assemble_node(a, arg); - append_u8(&a->out, OPCODE_SCALL); - append_u8(&a->out, arg_count); - int p = append_u32(&a->out, 0); + assert(func->type == NODE_VALUE_VAR); - FunctionCall *call = alloc(a->a, sizeof(FunctionCall), _Alignof(FunctionCall)); - if (call == NULL) { - assembler_report(a, "Out of memory"); - return; - } - call->name = func->sval; - call->off = p; + append_u8(&a->out, OPCODE_CALL); + append_u8(&a->out, arg_count); + int p = append_u32(&a->out, 0); - Scope *scope = &a->scopes[a->num_scopes-1]; - - call->next = scope->calls; - scope->calls = call; - - } else { - assemble_node(a, func); - assemble_node(a, arg); - append_u8(&a->out, OPCODE_DCALL); - append_u8(&a->out, arg_count); + FunctionCall *call = alloc(a->a, sizeof(FunctionCall), _Alignof(FunctionCall)); + if (call == NULL) { + assembler_report(a, "Out of memory"); + return; } + call->name = func->sval; + call->off = p; + + Scope *scope = &a->scopes[a->num_scopes-1]; + + call->next = scope->calls; + scope->calls = call; } break; case NODE_VAR_DECL: { - int idx = declare_var(a, node->var_name); + int idx = declare_variable(a, node->var_name); if (idx < 0) return; if (node->var_value) { @@ -393,13 +506,19 @@ void assemble_node(Assembler *a, Node *node) case NODE_BLOCK: { - Node *stmt = node->child; + int ret = push_scope(a, SCOPE_BLOCK); + if (ret < 0) return; + + Node *stmt = node->left; while (stmt) { assemble_node(a, stmt); if (is_expr(stmt)) append_u8(&a->out, OPCODE_POP); stmt = stmt->next; } + + ret = pop_scope(a); + if (ret < 0) return; } break; @@ -431,15 +550,27 @@ void assemble_node(Assembler *a, Node *node) append_u8(&a->out, OPCODE_JIFP); int p1 = append_u32(&a->out, 0); + int ret = push_scope(a, SCOPE_IF); + if (ret < 0) return; + assemble_node(a, node->left); + ret = pop_scope(a); + if (ret < 0) return; + append_u8(&a->out, OPCODE_JUMP); int p2 = append_u32(&a->out, 0); patch_with_current_offset(&a->out, p1); + ret = push_scope(a, SCOPE_ELSE); + if (ret < 0) return; + assemble_node(a, node->right); + ret = pop_scope(a); + if (ret < 0) return; + patch_with_current_offset(&a->out, p2); } else { @@ -449,8 +580,14 @@ void assemble_node(Assembler *a, Node *node) append_u8(&a->out, OPCODE_JIFP); int p1 = append_u32(&a->out, 0); + int ret = push_scope(a, SCOPE_IF); + if (ret < 0) return; + assemble_node(a, node->left); + ret = pop_scope(a); + if (ret < 0) return; + patch_with_current_offset(&a->out, p1); } } @@ -473,8 +610,14 @@ void assemble_node(Assembler *a, Node *node) append_u8(&a->out, OPCODE_JIFP); int p = append_u32(&a->out, 0); + int ret = push_scope(a, SCOPE_WHILE); + if (ret < 0) return; + assemble_node(a, node->left); + ret = pop_scope(a); + if (ret < 0) return; + append_u8(&a->out, OPCODE_JUMP); append_u32(&a->out, start); @@ -485,7 +628,16 @@ void assemble_node(Assembler *a, Node *node) case NODE_FOR: { assemble_node(a, node->for_set); + // TODO + + int ret = push_scope(a, SCOPE_FOR); + if (ret < 0) return; + + assemble_node(a, node->left); + + ret = pop_scope(a); + if (ret < 0) return; } break; @@ -572,8 +724,16 @@ void assemble_node(Assembler *a, Node *node) break; case NODE_VALUE_VAR: - append_u8 (&a->out, OPCODE_PUSHV); - append_u64(&a->out, node->ival); + { + String name = node->sval; + int idx = find_symbol_in_function(a, name); + if (idx < 0) { + assembler_report(a, "Reference to undefined variable '%.*s'", name.len, name.ptr); + return; + } + append_u8(&a->out, OPCODE_PUSHV); + append_u8(&a->out, idx); // TODO: make this relative to the frame + } break; case NODE_VALUE_HTML: @@ -598,7 +758,7 @@ void assemble_node(Assembler *a, Node *node) case NODE_VALUE_MAP: { append_u8(&a->out, OPCODE_PUSHM); - append_u64(&a->out, count_nodes(node->child)); + append_u32(&a->out, count_nodes(node->child)); Node *child = node->child; while (child) { @@ -621,6 +781,10 @@ void assemble_node(Assembler *a, Node *node) } break; + case NODE_NESTED: + assemble_node(a, node->left); + break; + case NODE_OPER_ASS: { Node *dst = node->left; @@ -628,12 +792,22 @@ void assemble_node(Assembler *a, Node *node) if (dst->type == NODE_VALUE_VAR) { - int idx = find_variable(a, dst->sval); - if (idx < 0) return; + String name = dst->sval; + + int idx = find_symbol_in_function(a, name); + if (idx < 0) { + assembler_report(a, "Undeclared variable '%.*s'", name.len, name.ptr); + return; + } + + if (a->syms[idx].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); + append_u8(&a->out, idx); // TODO: this index should be relative to the frame } else if (dst->type == NODE_SELECT) { @@ -655,14 +829,257 @@ void assemble_node(Assembler *a, Node *node) } } -AssembleResult assemble(Node *root, char *errbuf, int errmax) +typedef struct { + uint32_t magic; + uint32_t code_size; + uint32_t data_size; +} Header; + +AssembleResult assemble(Node *root, Arena *arena, char *errbuf, int errmax) { - Assembler a = {0, .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); + if (ret < 0) { + return (AssembleResult) { (Program) {0}, a.errlen }; + } + assemble_node(&a, root); append_u8(&a.out, OPCODE_NOPE); - Program p; - // TODO + ret = pop_scope(&a); + 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); + + append_mem(&a.out, a.strings, a.strings_len); + + Program p = { + a.out.ptr, + a.out.len, + }; return (AssembleResult) { p, a.errlen }; } + +void print_program(Program p) +{ + if (p.len < 3 * sizeof(uint32_t)) { + printf("Invalid program"); + return; + } + + uint32_t cur = 0; + + uint32_t magic; + memcpy(&magic, p.ptr + cur, sizeof(uint32_t)); + cur += sizeof(uint32_t); + + uint32_t code_size; + memcpy(&code_size, p.ptr + cur, sizeof(uint32_t)); + cur += sizeof(uint32_t); + + uint32_t data_size; + memcpy(&data_size, p.ptr + cur, sizeof(uint32_t)); + cur += sizeof(uint32_t); + + if (3 * sizeof(uint32_t) + code_size + data_size != p.len) { + printf("Invalid program"); + return; + } + + printf("Program size is %d\n", p.len); + + while (cur < code_size + 3 * sizeof(uint32_t)) { + + printf("%d: ", cur - 3 * sizeof(uint32_t)); + + switch (((uint8_t*) p.ptr)[cur++]) { + + case OPCODE_NOPE: + printf("NOPE"); + break; + + case OPCODE_PUSHI: + { + uint64_t x; + memcpy(&x, p.ptr + cur, sizeof(uint64_t)); + cur += sizeof(uint64_t); + + printf("PUSHI %" LLU, x); + } + break; + + case OPCODE_PUSHF: + { + double x; + memcpy(&x, p.ptr + cur, sizeof(double)); + cur += sizeof(double); + + printf("PUSHF %lf", x); + } + break; + + case OPCODE_PUSHS: + { + uint32_t off; + memcpy(&off, p.ptr + cur, sizeof(uint32_t)); + cur += sizeof(uint32_t); + + uint32_t len; + memcpy(&len, p.ptr + cur, sizeof(uint32_t)); + cur += sizeof(uint32_t); + + printf("PUSHS \"%.*s\"", len, (char*) p.ptr + 3 * sizeof(uint32_t) + code_size + off); + } + break; + + case OPCODE_PUSHV: + { + uint8_t idx; + memcpy(&idx, p.ptr + cur, sizeof(uint8_t)); + cur += sizeof(uint8_t); + + printf("PUSHV %u", idx); + } + break; + + case OPCODE_PUSHA: + { + uint32_t cap; + memcpy(&cap, p.ptr + cur, sizeof(uint32_t)); + cur += sizeof(uint32_t); + + printf("PUSHA %u", cap); + } + break; + + case OPCODE_PUSHM: + { + uint32_t cap; + memcpy(&cap, p.ptr + cur, sizeof(uint32_t)); + cur += sizeof(uint32_t); + + printf("PUSHM %u", cap); + } + break; + + case OPCODE_POP: + printf("POP"); + break; + + case OPCODE_NEG: + printf("NEG"); + break; + + case OPCODE_EQL: + printf("EQL"); + break; + + case OPCODE_NQL: + printf("NQL"); + break; + + case OPCODE_LSS: + printf("LSS"); + break; + + case OPCODE_GRT: + printf("GRT"); + break; + + case OPCODE_ADD: + printf("ADD"); + break; + + case OPCODE_SUB: + printf("SUB"); + break; + + case OPCODE_MUL: + printf("MUL"); + break; + + case OPCODE_DIV: + printf("DIV"); + break; + + case OPCODE_MOD: + printf("MOD"); + break; + + case OPCODE_SETV: + { + uint8_t idx; + memcpy(&idx, p.ptr + cur, sizeof(uint8_t)); + cur += sizeof(uint8_t); + + printf("SETV %u", idx); + } + break; + + case OPCODE_JUMP: + { + uint32_t off; + memcpy(&off, p.ptr + cur, sizeof(uint32_t)); + cur += sizeof(uint32_t); + + printf("JUMP %u", off); + } + break; + + case OPCODE_JIFP: + { + uint32_t off; + memcpy(&off, p.ptr + cur, sizeof(uint32_t)); + cur += sizeof(uint32_t); + + printf("JIFP %u", off); + } + break; + + case OPCODE_CALL: + { + uint8_t num; + memcpy(&num, p.ptr + cur, sizeof(uint8_t)); + cur += sizeof(uint8_t); + + uint8_t off; + memcpy(&off, p.ptr + cur, sizeof(uint8_t)); + cur += sizeof(uint8_t); + + printf("CALL %u %u", num, off); + } + break; + + case OPCODE_RET: + printf("RET"); + break; + + case OPCODE_APPEND: + printf("APPEND"); + break; + + case OPCODE_INSERT1: + printf("INSERT1"); + break; + + case OPCODE_INSERT2: + printf("INSERT2"); + break; + + case OPCODE_SELECT: + printf("SELECT"); + break; + } + + printf("\n"); + } +} \ No newline at end of file diff --git a/src/assemble.h b/src/assemble.h index 04b7551..f7f6515 100644 --- a/src/assemble.h +++ b/src/assemble.h @@ -11,6 +11,7 @@ enum { OPCODE_PUSHV = 0x04, OPCODE_PUSHA = 0x05, OPCODE_PUSHM = 0x06, + OPCODE_PUSHN = 0x21, OPCODE_POP = 0x07, OPCODE_NEG = 0x08, OPCODE_EQL = 0x09, @@ -25,13 +26,12 @@ enum { OPCODE_SETV = 0x12, OPCODE_JUMP = 0x13, OPCODE_JIFP = 0x14, - OPCODE_SCALL = 0x15, - OPCODE_DCALL = 0x16, - OPCODE_RET = 0x17, - OPCODE_APPEND = 0x18, - OPCODE_INSERT1 = 0x19, - OPCODE_INSERT2 = 0x20, - OPCODE_SELECT = 0x21, + OPCODE_CALL = 0x15, + OPCODE_RET = 0x16, + OPCODE_APPEND = 0x17, + OPCODE_INSERT1 = 0x18, + OPCODE_INSERT2 = 0x19, + OPCODE_SELECT = 0x20, }; typedef struct { @@ -44,6 +44,7 @@ typedef struct { int errlen; } AssembleResult; -AssembleResult assemble(Node *root, char *errbuf, int errmax); +void print_program(Program p); +AssembleResult assemble(Node *root, Arena *arena, char *errbuf, int errmax); #endif // WL_ASSEMBLE_INCLUDED \ No newline at end of file diff --git a/src/eval.c b/src/eval.c index f100b52..a260347 100644 --- a/src/eval.c +++ b/src/eval.c @@ -6,6 +6,72 @@ #define FRAME_LIMIT 128 #define EVAL_STACK_LIMIT 128 +#define HEAP_BASE 0xFEEDBEEFFEEDBEEF + +/* +int +float +array +map +html +bool +none +*/ + +/* +000 none +001 true +010 false +011 short str +100 +101 +110 +111 pointer +*/ + +typedef struct { + uint64_t data; +} Value; + +typedef struct { + uint64_t data; +} Pointer; + +typedef enum { + TYPE_NONE, + TYPE_BOOL, + TYPE_MAP, + TYPE_ARRAY, + TYPE_STRING, +} Type; + +typedef struct MapItems MapItems; +struct MapItems { + Pointer next; + Value keys[8]; + Value items[8]; +}; + +typedef struct { + Type type; + int count; + MapItems head; + Pointer tail; +} Map; + +typedef struct ArrayItems ArrayItems; +struct ArrayItems { + ArrayItems *next; + Value items[16]; +}; + +typedef struct { + Type type; + int count; + ArrayItems head; + ArrayItems *tail; +} Array; + typedef struct { } Frame; diff --git a/src/main.c b/src/main.c index 6c92fb3..464b143 100644 --- a/src/main.c +++ b/src/main.c @@ -3,6 +3,7 @@ #include "file.h" #include "parse.h" +#include "assemble.h" int main(void) { @@ -17,14 +18,24 @@ int main(void) char *mem = malloc(1<<20); Arena a = { mem, 1<<20, 0 }; - ParseResult result = parse(src, &a, err, COUNT(err)); - if (result.node == NULL) { - printf("%.*s\n", result.errlen, err); + ParseResult parse_result = parse(src, &a, err, COUNT(err)); + if (parse_result.node == NULL) { + printf("%.*s\n", parse_result.errlen, err); return -1; } - print_node(result.node); - fflush(stdout); + print_node(parse_result.node); + printf("\n"); + + AssembleResult assemble_result = assemble(parse_result.node, &a, err, COUNT(err)); + if (assemble_result.errlen) { + printf("%.*s\n", parse_result.errlen, err); + return -1; + } + + print_program(assemble_result.program); + + eval(assemble_result.program); free(src.ptr); free(mem); diff --git a/src/parse.c b/src/parse.c index 3001ff3..b15f736 100644 --- a/src/parse.c +++ b/src/parse.c @@ -158,7 +158,7 @@ String tok2str(Token token, char *buf, int max) return S("???"); } -void report(Parser *p, char *fmt, ...) +void parser_report(Parser *p, char *fmt, ...) { if (p->errmax == 0 || p->errlen > 0) return; @@ -192,7 +192,7 @@ Node *alloc_node(Parser *p) { Node *n = alloc(p->a, sizeof(Node), _Alignof(Node)); if (n == NULL) { - report(p, "Out of memory"); + parser_report(p, "Out of memory"); return NULL; } @@ -262,7 +262,7 @@ Token next_token(Parser *p) do { int d = p->s.src[p->s.cur++] - '0'; if (buf > (UINT64_MAX - d) / 10) { - report(p, "Integer literal overflow"); + parser_report(p, "Integer literal overflow"); return (Token) { .type=TOKEN_ERROR }; } buf = buf * 10 + d; @@ -296,7 +296,7 @@ Token next_token(Parser *p) buf = NULL; if (buf == NULL) { - report(p, "Out of memory"); + parser_report(p, "Out of memory"); return (Token) { .type=TOKEN_ERROR }; } @@ -310,12 +310,12 @@ Token next_token(Parser *p) } if (p->s.cur == p->s.len) { - report(p, "String literal wasn't closed"); + parser_report(p, "String literal wasn't closed"); return (Token) { .type=TOKEN_ERROR }; } if (!is_printable(p->s.src[p->s.cur])) { - report(p, "Invalid byte in string literal"); + parser_report(p, "Invalid byte in string literal"); return (Token) { .type=TOKEN_ERROR }; } @@ -324,7 +324,7 @@ Token next_token(Parser *p) p->s.cur++; if (p->s.cur == p->s.len) { - report(p, "Missing special character after escape character \\"); + parser_report(p, "Missing special character after escape character \\"); return (Token) { .type=TOKEN_ERROR }; } @@ -350,7 +350,7 @@ Token next_token(Parser *p) break; default: - report(p, "Invalid character after escape character \\"); + parser_report(p, "Invalid character after escape character \\"); return (Token) { .type=TOKEN_ERROR }; } @@ -382,7 +382,7 @@ Token next_token(Parser *p) if (consume_str(&p->s, S(","))) return (Token) { .type=TOKEN_COMMA }; if (consume_str(&p->s, S(":"))) return (Token) { .type=TOKEN_COLON }; - report(p, "Invalid character '%c'", c); + parser_report(p, "Invalid character '%c'", c); return (Token) { .type=TOKEN_ERROR }; } @@ -411,12 +411,14 @@ Node *parse_expr(Parser *p, int opflags); Node *parse_html(Parser *p) { // NOTE: The first < was already consumed + + int node_offset = p->s.cur-1; Token t = next_token(p); if (t.type != TOKEN_IDENT) { char buf[1<<8]; String ts = tok2str(t, buf, COUNT(buf)); - report(p, "HTML tag doesn't start with a name (got '%.*s' instead)", ts.len, ts.ptr); + parser_report(p, "HTML tag doesn't start with a name (got '%.*s' instead)", ts.len, ts.ptr); return NULL; } String tagname = t.sval; @@ -426,6 +428,8 @@ Node *parse_html(Parser *p) for (;;) { + int param_offset = p->s.cur; + String attr_name; Node *attr_value; @@ -433,7 +437,7 @@ Node *parse_html(Parser *p) if (t.type == TOKEN_OPER_GRT) break; if (t.type != TOKEN_IDENT) { - report(p, "Invalid token inside HTML tag"); + parser_report(p, "Invalid token inside HTML tag"); return NULL; } attr_name = t.sval; @@ -456,6 +460,7 @@ Node *parse_html(Parser *p) return NULL; child->type = NODE_HTML_PARAM; + child->text = (String) { p->s.src + param_offset, p->s.cur - param_offset }; child->attr_name = attr_name; child->attr_value = attr_value; @@ -483,6 +488,7 @@ Node *parse_html(Parser *p) return NULL; child->type = NODE_VALUE_STR; + child->text = (String) { p->s.src + off, p->s.cur - off }; child->sval = (String) { p->s.src + off, p->s.cur - off }; *tail = child; @@ -492,7 +498,7 @@ Node *parse_html(Parser *p) if (p->s.cur == p->s.len || p->s.src[p->s.cur] == '<') break; - p->s.cur++; // Consume \ + p->s.cur++; // Consume "\" { Node *child = parse_stmt(p, IGNORE_LSS); @@ -505,7 +511,7 @@ Node *parse_html(Parser *p) } if (p->s.cur == p->s.len) { - report(p, "Missing closing HTML tag"); + parser_report(p, "Missing closing HTML tag"); return NULL; } p->s.cur++; // Consume < @@ -517,7 +523,7 @@ Node *parse_html(Parser *p) if (t.type == TOKEN_IDENT && streqcase(t.sval, tagname)) { t = next_token(p); if (t.type != TOKEN_OPER_GRT) { - report(p, "Unexpected token in closing HTML tag"); + parser_report(p, "Unexpected token in closing HTML tag"); return NULL; } break; @@ -541,6 +547,7 @@ Node *parse_html(Parser *p) return NULL; parent->type = NODE_VALUE_HTML; + parent->text = (String) { p->s.src + node_offset, p->s.cur - node_offset }; parent->tagname = tagname; parent->params = param_head; parent->child = head; @@ -552,6 +559,8 @@ Node *parse_array(Parser *p) { // Left bracket already consumed + int start = p->s.cur; + Node *head; Node **tail = &head; @@ -591,6 +600,7 @@ Node *parse_array(Parser *p) return NULL; parent->type = NODE_VALUE_ARRAY; + parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->child = head; return parent; @@ -600,6 +610,8 @@ Node *parse_map(Parser *p) { // Left bracket already consumed + int start = p->s.cur; + Node *head; Node **tail = &head; @@ -622,6 +634,7 @@ Node *parse_map(Parser *p) return NULL; key->type = NODE_VALUE_STR; + key->text = t.sval; key->sval = t.sval; } else { @@ -634,7 +647,7 @@ Node *parse_map(Parser *p) t = next_token(p); if (t.type != TOKEN_COLON) { - report(p, "Missing ':' after key inside map literal"); + parser_report(p, "Missing ':' after key inside map literal"); return NULL; } @@ -667,6 +680,7 @@ Node *parse_map(Parser *p) return NULL; parent->type = NODE_VALUE_MAP; + parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->child = head; return parent; @@ -716,6 +730,8 @@ b32 right_associative(Token t) Node *parse_atom(Parser *p) { + int start = p->s.cur; + Token t = next_token(p); Node *ret; @@ -731,6 +747,7 @@ Node *parse_atom(Parser *p) return NULL; parent->type = NODE_OPER_POS; + parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = child; ret = parent; @@ -748,6 +765,7 @@ Node *parse_atom(Parser *p) return NULL; parent->type = NODE_OPER_NEG; + parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = child; ret = parent; @@ -761,6 +779,7 @@ Node *parse_atom(Parser *p) return NULL; node->type = NODE_VALUE_VAR; + node->text = (String) { p->s.src + start, p->s.cur - start }; node->sval = t.sval; ret = node; @@ -774,6 +793,7 @@ Node *parse_atom(Parser *p) return NULL; node->type = NODE_VALUE_INT; + node->text = (String) { p->s.src + start, p->s.cur - start }; node->ival = t.uval; ret = node; @@ -787,6 +807,7 @@ Node *parse_atom(Parser *p) return NULL; node->type = NODE_VALUE_FLOAT; + node->text = (String) { p->s.src + start, p->s.cur - start }; node->dval = t.dval; ret = node; @@ -800,6 +821,7 @@ Node *parse_atom(Parser *p) return NULL; node->type = NODE_VALUE_STR; + node->text = (String) { p->s.src + start, p->s.cur - start }; node->sval = t.sval; ret = node; @@ -824,11 +846,19 @@ Node *parse_atom(Parser *p) Token t = next_token(p); if (t.type != TOKEN_PAREN_CLOSE) { - report(p, "Missing ')' after expression"); + parser_report(p, "Missing ')' after expression"); return NULL; } - ret = node; + Node *parent = alloc_node(p); + if (parent == NULL) + return NULL; + + parent->type = NODE_NESTED; + parent->text = (String) { p->s.src + start, p->s.cur - start }; + parent->left = node; + + ret = parent; } break; @@ -856,7 +886,7 @@ Node *parse_atom(Parser *p) { char buf[1<<8]; String str = tok2str(t, buf, COUNT(buf)); - report(p, "Invalid token \'%.*s\' inside expression", str.len, str.ptr); + parser_report(p, "Invalid token \'%.*s\' inside expression", str.len, str.ptr); } return NULL; } @@ -868,7 +898,7 @@ Node *parse_atom(Parser *p) t = next_token(p); if (t.type != TOKEN_IDENT) { - report(p, "Invalid token after '.' where an identifier was expected"); + parser_report(p, "Invalid token after '.' where an identifier was expected"); return NULL; } @@ -877,6 +907,7 @@ Node *parse_atom(Parser *p) return NULL; child->type = NODE_VALUE_STR; + child->text = t.sval; child->sval = t.sval; Node *parent = alloc_node(p); @@ -884,6 +915,7 @@ Node *parse_atom(Parser *p) return NULL; parent->type = NODE_SELECT; + parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = ret; parent->right = child; @@ -897,7 +929,7 @@ Node *parse_atom(Parser *p) t = next_token(p); if (t.type != TOKEN_BRACKET_CLOSE) { - report(p, "Missing token ']'"); + parser_report(p, "Missing token ']'"); return NULL; } @@ -906,12 +938,13 @@ Node *parse_atom(Parser *p) return NULL; parent->type = NODE_SELECT; + parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = ret; parent->right = child; ret = parent; - } else if (t.type == TOKEN_PAREN_OPEN) { + } else if (t.type == TOKEN_PAREN_OPEN && ret->type == NODE_VALUE_VAR) { Node *arg_head; Node **arg_tail = &arg_head; @@ -936,7 +969,7 @@ Node *parse_atom(Parser *p) break; if (t.type != TOKEN_COMMA) { - report(p, "Expected ',' after argument in function call"); + parser_report(p, "Expected ',' after argument in function call"); return NULL; } } @@ -949,6 +982,7 @@ Node *parse_atom(Parser *p) return NULL; parent->type = NODE_FUNC_CALL; + parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = ret; parent->right = arg_head; @@ -963,7 +997,7 @@ Node *parse_atom(Parser *p) return ret; } -Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int flags) +Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int start, int flags) { for (;;) { @@ -974,6 +1008,8 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int flags) break; } + int right_start = p->s.cur; + Node *right = parse_atom(p); if (right == NULL) return NULL; @@ -992,7 +1028,7 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int flags) if (p2 <= p1 && (p1 != p2 || !right_associative(t2))) break; - right = parse_expr_inner(p, right, p1 + (p2 > p1), flags); + right = parse_expr_inner(p, right, p1 + (p2 > p1), right_start, flags); if (right == NULL) return NULL; } @@ -1001,6 +1037,7 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int flags) if (parent == NULL) return NULL; + parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = left; parent->right = right; @@ -1016,7 +1053,7 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int flags) case TOKEN_OPER_DIV: parent->type = NODE_OPER_DIV; break; case TOKEN_OPER_MOD: parent->type = NODE_OPER_MOD; break; default: - report(p, "Operator not implemented"); + parser_report(p, "Operator not implemented"); return NULL; } @@ -1028,11 +1065,13 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int flags) Node *parse_expr(Parser *p, int flags) { + int start = p->s.cur; + Node *left = parse_atom(p); if (left == NULL) return NULL; - return parse_expr_inner(p, left, 0, flags); + return parse_expr_inner(p, left, 0, start, flags); } Node *parse_expr_stmt(Parser *p, int opflags) @@ -1046,9 +1085,11 @@ Node *parse_expr_stmt(Parser *p, int opflags) Node *parse_ifelse_stmt(Parser *p, int opflags) { + int start = p->s.cur; + Token t = next_token(p); if (t.type != TOKEN_KWORD_IF) { - report(p, "Missing 'if' keyword before if statement"); + parser_report(p, "Missing 'if' keyword before if statement"); return NULL; } @@ -1058,7 +1099,7 @@ Node *parse_ifelse_stmt(Parser *p, int opflags) t = next_token(p); if (t.type != TOKEN_COLON) { - report(p, "Missing ':' after if condition"); + parser_report(p, "Missing ':' after if condition"); return NULL; } @@ -1085,6 +1126,7 @@ Node *parse_ifelse_stmt(Parser *p, int opflags) return NULL; parent->type = NODE_IFELSE; + parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = if_stmt; parent->right = else_stmt; parent->cond = cond; @@ -1094,15 +1136,17 @@ Node *parse_ifelse_stmt(Parser *p, int opflags) Node *parse_for_stmt(Parser *p, int opflags) { + int start = p->s.cur; + Token t = next_token(p); if (t.type != TOKEN_KWORD_FOR) { - report(p, "Missing 'for' keyword at the start of a for statement"); + parser_report(p, "Missing 'for' keyword at the start of a for statement"); return NULL; } t = next_token(p); if (t.type != TOKEN_IDENT) { - report(p, "Missing iteraion variable name in for statement"); + parser_report(p, "Missing iteraion variable name in for statement"); return NULL; } String var1 = t.sval; @@ -1114,7 +1158,7 @@ Node *parse_for_stmt(Parser *p, int opflags) t = next_token(p); if (t.type != TOKEN_IDENT) { - report(p, "Missing iteration variable name after ',' in for statement"); + parser_report(p, "Missing iteration variable name after ',' in for statement"); return NULL; } var2 = t.sval; @@ -1123,7 +1167,7 @@ Node *parse_for_stmt(Parser *p, int opflags) } if (t.type != TOKEN_KWORD_IN) { - report(p, "Missing 'in' keyword after iteration variable name in for statement"); + parser_report(p, "Missing 'in' keyword after iteration variable name in for statement"); return NULL; } @@ -1133,7 +1177,7 @@ Node *parse_for_stmt(Parser *p, int opflags) t = next_token(p); if (t.type != TOKEN_COLON) { - report(p, "Missing ':' after for statement set expression"); + parser_report(p, "Missing ':' after for statement set expression"); return NULL; } @@ -1146,6 +1190,7 @@ Node *parse_for_stmt(Parser *p, int opflags) return NULL; parent->type = NODE_FOR; + parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = body; parent->for_var1 = var1; parent->for_var2 = var2; @@ -1156,9 +1201,11 @@ Node *parse_for_stmt(Parser *p, int opflags) Node *parse_while_stmt(Parser *p, int opflags) { + int start = p->s.cur; + Token t = next_token(p); if (t.type != TOKEN_KWORD_WHILE) { - report(p, "Missing keyword 'while' at the start of a while statement"); + parser_report(p, "Missing keyword 'while' at the start of a while statement"); return NULL; } @@ -1168,7 +1215,7 @@ Node *parse_while_stmt(Parser *p, int opflags) t = next_token(p); if (t.type != TOKEN_COLON) { - report(p, "Missing token ':' after while statement condition"); + parser_report(p, "Missing token ':' after while statement condition"); return NULL; } @@ -1181,6 +1228,7 @@ Node *parse_while_stmt(Parser *p, int opflags) return NULL; parent->type = NODE_WHILE; + parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = stmt; parent->cond = cond; @@ -1189,10 +1237,12 @@ Node *parse_while_stmt(Parser *p, int opflags) Node *parse_block_stmt(Parser *p, b32 curly) { + int start = p->s.cur; + if (curly) { Token t = next_token(p); if (t.type != TOKEN_CURLY_OPEN) { - report(p, "Missing '{' at the start of a block statement"); + parser_report(p, "Missing '{' at the start of a block statement"); return NULL; } } @@ -1228,6 +1278,7 @@ Node *parse_block_stmt(Parser *p, b32 curly) return NULL; parent->type = NODE_BLOCK; + parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = head; return parent; @@ -1235,22 +1286,24 @@ Node *parse_block_stmt(Parser *p, b32 curly) Node *parse_func_decl(Parser *p, int opflags) { + int start = p->s.cur; + Token t = next_token(p); if (t.type != TOKEN_KWORD_FUN) { - report(p, "Missing keyword 'fun' at the start of a function declaration"); + parser_report(p, "Missing keyword 'fun' at the start of a function declaration"); return NULL; } t = next_token(p); if (t.type != TOKEN_IDENT) { - report(p, "Missing function name after 'fun' keyword"); + parser_report(p, "Missing function name after 'fun' keyword"); return NULL; } String name = t.sval; t = next_token(p); if (t.type != TOKEN_PAREN_OPEN) { - report(p, "Missing '(' after function name in declaration"); + parser_report(p, "Missing '(' after function name in declaration"); return NULL; } @@ -1264,9 +1317,11 @@ Node *parse_func_decl(Parser *p, int opflags) for (;;) { + int arg_start = p->s.cur; + t = next_token(p); if (t.type != TOKEN_IDENT) { - report(p, "Missing argument name in function declaration"); + parser_report(p, "Missing argument name in function declaration"); return NULL; } String argname = t.sval; @@ -1276,6 +1331,7 @@ Node *parse_func_decl(Parser *p, int opflags) return NULL; node->type = NODE_FUNC_ARG; + node->text = (String) { p->s.src + arg_start, p->s.cur - arg_start }; node->sval = argname; *arg_tail = node; @@ -1305,6 +1361,7 @@ Node *parse_func_decl(Parser *p, int opflags) return NULL; parent->type = NODE_FUNC_DECL; + parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->func_name = name; parent->func_args = arg_head; parent->func_body = body; @@ -1314,15 +1371,17 @@ Node *parse_func_decl(Parser *p, int opflags) Node *parse_var_decl(Parser *p, int opflags) { + int start = p->s.cur; + Token t = next_token(p); if (t.type != TOKEN_KWORD_LET) { - report(p, "Missing keyword 'let' at the start of a variable declaration"); + parser_report(p, "Missing keyword 'let' at the start of a variable declaration"); return NULL; } t = next_token(p); if (t.type != TOKEN_IDENT) { - report(p, "Missing variable name after 'let' keyword"); + parser_report(p, "Missing variable name after 'let' keyword"); return NULL; } String name = t.sval; @@ -1347,6 +1406,7 @@ Node *parse_var_decl(Parser *p, int opflags) return NULL; parent->type = NODE_VAR_DECL; + parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->var_name = name; parent->var_value = value; @@ -1555,14 +1615,13 @@ void print_node(Node *node) } printf(">"); - Node *child = node->child; while (child) { print_node(child); child = child->next; } - printf("<%.*s>", + printf("", node->tagname.len, node->tagname.ptr ); @@ -1676,7 +1735,7 @@ void print_node(Node *node) node->var_name.ptr); if (node->var_value) { printf(" = "); - print_node(node); + print_node(node->var_value); } printf(";"); } diff --git a/src/parse.h b/src/parse.h index 52f454b..c76ee08 100644 --- a/src/parse.h +++ b/src/parse.h @@ -17,6 +17,7 @@ typedef enum { NODE_FOR, NODE_WHILE, NODE_SELECT, + NODE_NESTED, NODE_OPER_POS, NODE_OPER_NEG, NODE_OPER_ASS, @@ -43,6 +44,7 @@ typedef struct Node Node; struct Node { NodeType type; Node *next; + String text; Node *key;