diff --git a/WL.c b/WL.c index 485b39e..7adedd2 100644 --- a/WL.c +++ b/WL.c @@ -71,6 +71,7 @@ int hex_digit_to_int(char c); bool streq(String a, String b); bool streqcase(String a, String b); +String copystr(String s, WL_Arena *a); void *alloc(WL_Arena *a, int len, int align); bool grow_alloc(WL_Arena *a, char *p, int new_len); @@ -171,6 +172,15 @@ bool grow_alloc(WL_Arena *a, char *p, int new_len) return true; } +String copystr(String s, WL_Arena *a) +{ + char *p = alloc(a, s.len, 1); + if (p == NULL) + return (String) { NULL, 0 }; + memcpy(p, s.ptr, s.len); + return (String) { p, s.len }; +} + //////////////////////////////////////////////////////////////////////////////////////// // src/file.h //////////////////////////////////////////////////////////////////////////////////////// @@ -334,9 +344,11 @@ typedef enum { NODE_VAR_DECL, NODE_PRINT, NODE_BLOCK, + NODE_GLOBAL_BLOCK, NODE_IFELSE, NODE_FOR, NODE_WHILE, + NODE_INCLUDE, NODE_SELECT, NODE_NESTED, NODE_OPER_POS, @@ -354,6 +366,9 @@ typedef enum { NODE_VALUE_INT, NODE_VALUE_FLOAT, NODE_VALUE_STR, + NODE_VALUE_NONE, + NODE_VALUE_TRUE, + NODE_VALUE_FALSE, NODE_VALUE_VAR, NODE_VALUE_SYSVAR, NODE_VALUE_HTML, @@ -366,7 +381,6 @@ typedef struct Node Node; struct Node { NodeType type; Node *next; - String text; Node *key; @@ -397,10 +411,15 @@ struct Node { String var_name; Node *var_value; + + String include_path; + Node* include_next; + Node* include_root; }; typedef struct { Node *node; + Node *includes; int errlen; } ParseResult; @@ -436,6 +455,10 @@ typedef enum { TOKEN_KWORD_FUN, TOKEN_KWORD_LET, TOKEN_KWORD_PRINT, + TOKEN_KWORD_NONE, + TOKEN_KWORD_TRUE, + TOKEN_KWORD_FALSE, + TOKEN_KWORD_INCLUDE, TOKEN_VALUE_FLOAT, TOKEN_VALUE_INT, TOKEN_VALUE_STR, @@ -473,11 +496,13 @@ typedef struct { } Token; typedef struct { - Scanner s; - WL_Arena *a; - char *errbuf; - int errmax; - int errlen; + Scanner s; + WL_Arena* a; + char* errbuf; + int errmax; + int errlen; + Node* include_head; + Node** include_tail; } Parser; bool consume_str(Scanner *s, String x) @@ -521,6 +546,10 @@ String tok2str(Token token, char *buf, int max) case TOKEN_KWORD_FUN: return S("fun"); case TOKEN_KWORD_LET: return S("let"); case TOKEN_KWORD_PRINT: return S("print"); + case TOKEN_KWORD_NONE: return S("none"); + case TOKEN_KWORD_TRUE: return S("true"); + case TOKEN_KWORD_FALSE: return S("false"); + case TOKEN_KWORD_INCLUDE: return S("include"); case TOKEN_VALUE_FLOAT: { @@ -655,6 +684,17 @@ Token next_token(Parser *p) if (streq(kword, S("fun"))) return (Token) { .type=TOKEN_KWORD_FUN }; if (streq(kword, S("let"))) return (Token) { .type=TOKEN_KWORD_LET }; if (streq(kword, S("print"))) return (Token) { .type=TOKEN_KWORD_PRINT }; + if (streq(kword, S("none"))) return (Token) { .type=TOKEN_KWORD_NONE }; + if (streq(kword, S("true"))) return (Token) { .type=TOKEN_KWORD_TRUE }; + if (streq(kword, S("false"))) return (Token) { .type=TOKEN_KWORD_FALSE }; + if (streq(kword, S("include"))) return (Token) { .type=TOKEN_KWORD_INCLUDE }; + + kword = copystr(kword, p->a); + if (kword.len == 0) { + parser_report(p, "Out of memory"); + return (Token) { .type=TOKEN_ERROR }; + } + return (Token) { .type=TOKEN_IDENT, .sval=kword }; } @@ -842,8 +882,6 @@ 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]; @@ -859,8 +897,6 @@ Node *parse_html(Parser *p) bool no_body = false; for (;;) { - int param_offset = p->s.cur; - String attr_name; Node *attr_value; @@ -903,7 +939,6 @@ 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; @@ -944,7 +979,6 @@ 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; @@ -1003,7 +1037,6 @@ 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; @@ -1016,8 +1049,6 @@ Node *parse_array(Parser *p) { // Left bracket already consumed - int start = p->s.cur; - Node *head; Node **tail = &head; @@ -1057,7 +1088,6 @@ 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; @@ -1067,8 +1097,6 @@ Node *parse_map(Parser *p) { // Left bracket already consumed - int start = p->s.cur; - Node *head; Node **tail = &head; @@ -1091,7 +1119,6 @@ Node *parse_map(Parser *p) return NULL; key->type = NODE_VALUE_STR; - key->text = t.sval; key->sval = t.sval; } else { @@ -1137,7 +1164,6 @@ 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; @@ -1191,8 +1217,6 @@ bool right_associative(Token t) Node *parse_atom(Parser *p) { - int start = p->s.cur; - Token t = next_token(p); Node *ret; @@ -1208,7 +1232,6 @@ 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; @@ -1226,7 +1249,6 @@ 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; @@ -1240,7 +1262,6 @@ 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; @@ -1254,7 +1275,6 @@ 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; @@ -1268,7 +1288,6 @@ 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; @@ -1282,7 +1301,44 @@ 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; + } + break; + + case TOKEN_KWORD_NONE: + { + Node *node = alloc_node(p); + if (node == NULL) + return NULL; + + node->type = NODE_VALUE_NONE; + node->sval = t.sval; + + ret = node; + } + break; + + case TOKEN_KWORD_TRUE: + { + Node *node = alloc_node(p); + if (node == NULL) + return NULL; + + node->type = NODE_VALUE_TRUE; + node->sval = t.sval; + + ret = node; + } + break; + case TOKEN_KWORD_FALSE: + { + Node *node = alloc_node(p); + if (node == NULL) + return NULL; + + node->type = NODE_VALUE_FALSE; node->sval = t.sval; ret = node; @@ -1316,7 +1372,6 @@ Node *parse_atom(Parser *p) return NULL; parent->type = NODE_NESTED; - parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = node; ret = parent; @@ -1356,7 +1411,6 @@ Node *parse_atom(Parser *p) return NULL; node->type = NODE_VALUE_SYSVAR; - node->text = (String) { p->s.src + start, p->s.cur - start }; node->sval = t.sval; ret = node; @@ -1388,7 +1442,6 @@ 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); @@ -1396,7 +1449,6 @@ 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; @@ -1419,7 +1471,6 @@ 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; @@ -1463,7 +1514,6 @@ 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; @@ -1478,7 +1528,7 @@ Node *parse_atom(Parser *p) return ret; } -Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int start, int flags) +Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int flags) { for (;;) { @@ -1489,8 +1539,6 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int start, int flags break; } - int right_start = p->s.cur; - Node *right = parse_atom(p); if (right == NULL) return NULL; @@ -1509,7 +1557,7 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int start, int flags if (p2 <= p1 && (p1 != p2 || !right_associative(t2))) break; - right = parse_expr_inner(p, right, p1 + (p2 > p1), right_start, flags); + right = parse_expr_inner(p, right, p1 + (p2 > p1), flags); if (right == NULL) return NULL; } @@ -1518,7 +1566,6 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int start, int flags if (parent == NULL) return NULL; - parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = left; parent->right = right; @@ -1546,13 +1593,11 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int start, 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, start, flags); + return parse_expr_inner(p, left, 0, flags); } Node *parse_expr_stmt(Parser *p, int opflags) @@ -1566,8 +1611,6 @@ 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) { parser_report(p, "Missing 'if' keyword before if statement"); @@ -1607,7 +1650,6 @@ 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; @@ -1617,8 +1659,6 @@ 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) { parser_report(p, "Missing 'for' keyword at the start of a for statement"); @@ -1671,7 +1711,6 @@ 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; @@ -1682,8 +1721,6 @@ 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) { parser_report(p, "Missing keyword 'while' at the start of a while statement"); @@ -1709,7 +1746,6 @@ 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; @@ -1718,8 +1754,6 @@ Node *parse_while_stmt(Parser *p, int opflags) Node *parse_block_stmt(Parser *p, bool curly) { - int start = p->s.cur; - if (curly) { Token t = next_token(p); if (t.type != TOKEN_CURLY_OPEN) { @@ -1759,7 +1793,6 @@ Node *parse_block_stmt(Parser *p, bool curly) return NULL; parent->type = NODE_BLOCK; - parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = head; return parent; @@ -1767,8 +1800,6 @@ Node *parse_block_stmt(Parser *p, bool 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) { parser_report(p, "Missing keyword 'fun' at the start of a function declaration"); @@ -1798,8 +1829,6 @@ Node *parse_func_decl(Parser *p, int opflags) for (;;) { - int arg_start = p->s.cur; - t = next_token(p); if (t.type != TOKEN_IDENT) { parser_report(p, "Missing argument name in function declaration"); @@ -1812,7 +1841,6 @@ 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; @@ -1842,7 +1870,6 @@ 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; @@ -1852,8 +1879,6 @@ 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) { parser_report(p, "Missing keyword 'let' at the start of a variable declaration"); @@ -1887,7 +1912,6 @@ 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; @@ -1896,8 +1920,6 @@ Node *parse_var_decl(Parser *p, int opflags) Node *parse_print_stmt(Parser *p, int opflags) { - int start = p->s.cur; - Token t = next_token(p); if (t.type != TOKEN_KWORD_PRINT) { parser_report(p, "Missing keyword 'print' at the start of a print statement"); @@ -1913,12 +1935,40 @@ Node *parse_print_stmt(Parser *p, int opflags) return NULL; parent->type = NODE_PRINT; - parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = arg; return parent; } +Node *parse_include_stmt(Parser *p) +{ + Token t = next_token(p); + if (t.type != TOKEN_KWORD_INCLUDE) { + parser_report(p, "Missing keyword 'include' at the start of an include statement"); + return NULL; + } + + t = next_token(p); + if (t.type != TOKEN_VALUE_STR) { + parser_report(p, "Missing file path string after 'include' keyword"); + return NULL; + } + String path = t.sval; + + Node *parent = alloc_node(p); + if (parent == NULL) + return NULL; + + parent->type = NODE_INCLUDE; + parent->include_path = path; + parent->include_root = NULL; + + *p->include_tail = parent; + p->include_tail = &parent->include_next; + + return parent; +} + Node *parse_stmt(Parser *p, int opflags) { Scanner saved = p->s; @@ -1927,6 +1977,9 @@ Node *parse_stmt(Parser *p, int opflags) switch (t.type) { + case TOKEN_KWORD_INCLUDE: + return parse_include_stmt(p); + case TOKEN_KWORD_PRINT: return parse_print_stmt(p, opflags); @@ -1959,6 +2012,18 @@ void print_node(Node *node) { switch (node->type) { + case NODE_VALUE_NONE: + printf("none"); + break; + + case NODE_VALUE_TRUE: + printf("true"); + break; + + case NODE_VALUE_FALSE: + printf("false"); + break; + case NODE_NESTED: { printf("("); @@ -2268,6 +2333,18 @@ void print_node(Node *node) //printf(";"); } break; + + case NODE_INCLUDE: + { + printf("include \"%.*s\"", + node->include_path.len, + node->include_path.ptr); + } + break; + + default: + printf("(invalid node type %x)", node->type); + break; } } @@ -2281,12 +2358,17 @@ ParseResult parse(String src, WL_Arena *a, char *errbuf, int errmax) .errlen=0, }; + p.include_tail = &p.include_head; + Node *node = parse_block_stmt(&p, false); - if (node == NULL) - return (ParseResult) { NULL, p.errlen }; + return (ParseResult) { .node=NULL, .includes=NULL, .errlen=p.errlen }; - return (ParseResult) { node, -1 }; + assert(node->type == NODE_BLOCK); + node->type = NODE_GLOBAL_BLOCK; + + *p.include_tail = NULL; + return (ParseResult) { .node=node, .includes=p.include_head, .errlen=-1 }; } //////////////////////////////////////////////////////////////////////////////////////// @@ -2342,6 +2424,8 @@ enum { OPCODE_SYSVAR = 0x2C, OPCODE_SYSCALL = 0x2D, OPCODE_FOR = 0x2E, + OPCODE_PUSHT = 0x2F, + OPCODE_PUSHFL = 0x30, }; typedef struct { @@ -2694,6 +2778,9 @@ bool is_expr(Node *node) case NODE_VALUE_INT: case NODE_VALUE_FLOAT: case NODE_VALUE_STR: + case NODE_VALUE_NONE: + case NODE_VALUE_TRUE: + case NODE_VALUE_FALSE: case NODE_VALUE_VAR: case NODE_VALUE_SYSVAR: case NODE_VALUE_HTML: @@ -3120,6 +3207,24 @@ void assemble_expr(Assembler *a, Node *node, int num_results) } break; + case NODE_VALUE_NONE: + { + append_u8(&a->out, OPCODE_PUSHN); + } + break; + + case NODE_VALUE_TRUE: + { + append_u8(&a->out, OPCODE_PUSHT); + } + break; + + case NODE_VALUE_FALSE: + { + append_u8(&a->out, OPCODE_PUSHFL); + } + break; + case NODE_VALUE_VAR: { String name = node->sval; @@ -3311,6 +3416,13 @@ void assemble_statement(Assembler *a, Node *node, bool pop_expr) { switch (node->type) { + case NODE_INCLUDE: + { + assert(node->include_root); + assemble_statement(a, node->include_root, pop_expr); + } + break; + case NODE_PRINT: { append_u8(&a->out, OPCODE_GROUP); @@ -3389,9 +3501,12 @@ void assemble_statement(Assembler *a, Node *node, bool pop_expr) break; case NODE_BLOCK: + case NODE_GLOBAL_BLOCK: { - int ret = push_scope(a, SCOPE_BLOCK); - if (ret < 0) return; + if (node->type == NODE_BLOCK) { + int ret = push_scope(a, SCOPE_BLOCK); + if (ret < 0) return; + } Node *stmt = node->left; while (stmt) { @@ -3399,8 +3514,10 @@ void assemble_statement(Assembler *a, Node *node, bool pop_expr) stmt = stmt->next; } - ret = pop_scope(a); - if (ret < 0) return; + if (node->type == NODE_BLOCK) { + int ret = pop_scope(a); + if (ret < 0) return; + } } break; @@ -3915,6 +4032,14 @@ char *print_instruction(char *p, char *data) printf("SYSCALL \"%.*s\"", (int) len, (char*) data + off); } break; + + case OPCODE_PUSHT: + printf("PUSHT"); + break; + + case OPCODE_PUSHFL: + printf("PUSHFL"); + break; } return p; @@ -4745,6 +4870,18 @@ int step(WL_State *state) } break; + case OPCODE_PUSHT: + { + state->eval_stack[state->eval_depth++] = VALUE_TRUE; + } + break; + + case OPCODE_PUSHFL: + { + state->eval_stack[state->eval_depth++] = VALUE_FALSE; + } + break; + case OPCODE_PUSHV: { uint8_t idx = read_u8(state); @@ -5847,7 +5984,7 @@ void WL_append(WL_State *state) } //////////////////////////////////////////////////////////////////////////////////////// -// src/public.c +// src/compile.c //////////////////////////////////////////////////////////////////////////////////////// @@ -5855,9 +5992,24 @@ void WL_append(WL_State *state) #include "eval.h" #include "parse.h" #include "assemble.h" -#include "WL.h" +#include "compile.h" #endif +#define FILE_LIMIT 32 + +typedef struct { + String file; + Node* root; + Node* includes; +} CompiledFile; + +struct WL_Compiler { + WL_Arena* arena; + CompiledFile files[FILE_LIMIT]; + int num_files; + String waiting_file; +}; + int WL_streq(WL_String a, char *b, int blen) { if (b == NULL) b = ""; @@ -5873,21 +6025,83 @@ int WL_streq(WL_String a, char *b, int blen) return 1; } -int WL_compile(char *src, int len, WL_Arena arena, WL_Program *program, char *err, int errmax) +WL_Compiler *WL_Compiler_init(WL_Arena *arena) { - if (src == NULL) src = ""; - if (len < 0) len = strlen(src); - - Node *root; - ParseResult pres = parse((String) {src, len}, &arena, err, errmax); - if (pres.node == NULL) - return -1; - root = pres.node; - - AssembleResult ares = assemble(root, &arena, err, errmax); - if (ares.errlen) - return -1; - *program = ares.program; - - return 0; + WL_Compiler *compiler = alloc(arena, (int) sizeof(WL_Compiler), _Alignof(WL_Compiler)); + if (compiler == NULL) + return NULL; + compiler->arena = arena; + compiler->num_files = 0; + compiler->waiting_file = (String) { NULL, 0 }; + return compiler; +} + +void WL_Compiler_free(WL_Compiler *compiler) +{ + (void) compiler; + // TODO +} + +WL_CompileResult WL_compile(WL_Compiler *compiler, WL_String file, WL_String content) +{ + if (compiler->waiting_file.len > 0) + file = (WL_String) { compiler->waiting_file.ptr, compiler->waiting_file.len }; + else { + // TODO: copy file path + // file = strdup(file, compiler->arena) + } + + char err[1<<9]; + ParseResult pres = parse((String) { content.ptr, content.len }, compiler->arena, err, (int) sizeof(err)); + if (pres.node == NULL) { + printf("%s\n", err); // TODO + return (WL_CompileResult) { .type=WL_COMPILE_RESULT_ERROR }; + } + + CompiledFile compiled_file = { + .file = { file.ptr, file.len }, + .root = pres.node, + .includes = pres.includes, + }; + compiler->files[compiler->num_files++] = compiled_file; + + for (int i = 0; i < compiler->num_files; i++) { + + Node *include = compiler->files[i].includes; + while (include) { + + assert(include->type == NODE_INCLUDE); + + if (include->include_root == NULL) { + for (int j = 0; j < compiler->num_files; j++) { + if (streq(include->include_path, compiler->files[j].file)) { + include->include_root = compiler->files[j].root; + break; + } + } + } + + if (include->include_root == NULL) { + + if (compiler->num_files == FILE_LIMIT) { + assert(0); // TODO + } + + // TODO: Make the path relative to the compiled file + + compiler->waiting_file = include->include_path; + return (WL_CompileResult) { .type=WL_COMPILE_RESULT_FILE, .path={ include->include_path.ptr, include->include_path.len } }; + } + + include = include->include_next; + } + } + + AssembleResult ares = assemble(compiler->files[0].root, compiler->arena, err, (int) sizeof(err)); + if (ares.errlen) { + printf("%s\n", err); // TODO + return (WL_CompileResult) { .type=WL_COMPILE_RESULT_ERROR }; + } + + return (WL_CompileResult) { .type=WL_COMPILE_RESULT_DONE, .program=ares.program }; } diff --git a/WL.h b/WL.h index 5e9d879..d806438 100644 --- a/WL.h +++ b/WL.h @@ -4,7 +4,7 @@ // This file was generated automatically. Do not modify directly! //////////////////////////////////////////////////////////////////////////////////////// -// src/public.h +// src/compile.h //////////////////////////////////////////////////////////////////////////////////////// #ifndef WL_PUBLIC_INCLUDED @@ -45,10 +45,27 @@ typedef struct { int cur; } WL_Arena; -int WL_compile (char *src, int len, WL_Arena arena, WL_Program *program, char *err, int errmax); -WL_State *WL_State_init (WL_Arena *a, WL_Program p, char *err, int errmax); -void WL_State_free (WL_State *state); -WL_Result WL_eval (WL_State *state); +typedef struct WL_Compiler WL_Compiler; + +typedef enum { + WL_COMPILE_RESULT_DONE, + WL_COMPILE_RESULT_FILE, + WL_COMPILE_RESULT_ERROR, +} WL_CompileResultType; + +typedef struct { + WL_CompileResultType type; + WL_Program program; + WL_String path; +} WL_CompileResult; + +WL_Compiler* WL_Compiler_init (WL_Arena *arena); +void WL_Compiler_free (WL_Compiler *compiler); +WL_CompileResult WL_compile (WL_Compiler *compiler, WL_String file, WL_String content); +WL_State* WL_State_init (WL_Arena *a, WL_Program p, char *err, int errmax); +void WL_State_free (WL_State *state); +WL_Result WL_eval (WL_State *state); + int WL_streq (WL_String a, char *b, int blen); int WL_peeknone (WL_State *state, int off); int WL_peekint (WL_State *state, int off, long long *x); diff --git a/amalg.py b/amalg.py index 13fac58..8fc8426 100644 --- a/amalg.py +++ b/amalg.py @@ -30,7 +30,7 @@ header = Amalgamator() header.append_text("#ifndef WL_AMALGAMATION\n") header.append_text("#define WL_AMALGAMATION\n") header.append_text(desc) -header.append_file("src/public.h") +header.append_file("src/compile.h") header.append_text("#endif // WL_AMALGAMATION\n") header.save("WL.h") @@ -49,5 +49,5 @@ source.append_file("src/value.h") source.append_file("src/value.c") source.append_file("src/eval.h") source.append_file("src/eval.c") -source.append_file("src/public.c") +source.append_file("src/compile.c") source.save("WL.c") diff --git a/example.wl b/example.wl new file mode 100644 index 0000000..6efd7ce --- /dev/null +++ b/example.wl @@ -0,0 +1 @@ +let ugu = 78 \ No newline at end of file diff --git a/main.c b/main.c index 28cfede..fcac6f7 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include "WL.h" @@ -12,29 +14,64 @@ int main(int argc, char **argv) } char *file = argv[1]; - FILE *f = fopen(file, "rb"); - if (f == NULL) - return -1; - - fseek(f, 0, SEEK_END); - long file_size = ftell(f); - fseek(f, 0, SEEK_SET); - - char *file_data = malloc(file_size); - - fread(file_data, 1, file_size, f); - fclose(f); - char err[1<<9]; char *mem = malloc(1<<20); WL_Arena a = { mem, 1<<20, 0 }; - WL_Program program; - int ret = WL_compile(file_data, file_size, a, &program, err, (int) sizeof(err)); - if (ret < 0) { - printf("%s\n", err); + WL_Compiler *compiler = WL_Compiler_init(&a); + if (compiler == NULL) { + assert(0); // TODO + } + + WL_CompileResult result; + WL_String path = { file, strlen(file) }; + for (int i = 0;; i++) { + + char buf[1<<10]; + if (path.len >= (int) sizeof(buf)) { + assert(0); // TODO + } + memcpy(buf, path.ptr, path.len); + buf[path.len] = '\0'; + + FILE *f = fopen(buf, "rb"); + if (f == NULL) { + printf("File not found '%.*s'\n", path.len, path.ptr); + return -1; + } + + fseek(f, 0, SEEK_END); + long file_size = ftell(f); + fseek(f, 0, SEEK_SET); + + char *file_data = malloc(file_size); + + fread(file_data, 1, file_size, f); + fclose(f); + + result = WL_compile(compiler, path, (WL_String) { file_data, file_size }); + + free(file_data); + + if (result.type == WL_COMPILE_RESULT_ERROR) { + printf("Compilation of '%.*s' failed\n", path.len, path.ptr); + break; + } + + if (result.type == WL_COMPILE_RESULT_DONE) + break; + + assert(result.type == WL_COMPILE_RESULT_FILE); + path = result.path; + } + + WL_Compiler_free(compiler); + + if (result.type == WL_COMPILE_RESULT_ERROR) { + printf("Compilation error\n"); return -1; } + WL_Program program = result.program; WL_State *state = WL_State_init(&a, program, err, (int) sizeof(err)); @@ -71,7 +108,6 @@ int main(int argc, char **argv) } WL_State_free(state); - free(file_data); free(mem); return 0; } diff --git a/main.wl b/main.wl index 9f9ec81..10b3fd8 100644 --- a/main.wl +++ b/main.wl @@ -1,3 +1,7 @@ +include "example.wl" + +ugu + let posts = [ { author: "UserA", diff --git a/src/assemble.c b/src/assemble.c index 7d03332..d8cbedd 100644 --- a/src/assemble.c +++ b/src/assemble.c @@ -332,6 +332,9 @@ bool is_expr(Node *node) case NODE_VALUE_INT: case NODE_VALUE_FLOAT: case NODE_VALUE_STR: + case NODE_VALUE_NONE: + case NODE_VALUE_TRUE: + case NODE_VALUE_FALSE: case NODE_VALUE_VAR: case NODE_VALUE_SYSVAR: case NODE_VALUE_HTML: @@ -758,6 +761,24 @@ void assemble_expr(Assembler *a, Node *node, int num_results) } break; + case NODE_VALUE_NONE: + { + append_u8(&a->out, OPCODE_PUSHN); + } + break; + + case NODE_VALUE_TRUE: + { + append_u8(&a->out, OPCODE_PUSHT); + } + break; + + case NODE_VALUE_FALSE: + { + append_u8(&a->out, OPCODE_PUSHFL); + } + break; + case NODE_VALUE_VAR: { String name = node->sval; @@ -949,6 +970,13 @@ void assemble_statement(Assembler *a, Node *node, bool pop_expr) { switch (node->type) { + case NODE_INCLUDE: + { + assert(node->include_root); + assemble_statement(a, node->include_root, pop_expr); + } + break; + case NODE_PRINT: { append_u8(&a->out, OPCODE_GROUP); @@ -1027,9 +1055,12 @@ void assemble_statement(Assembler *a, Node *node, bool pop_expr) break; case NODE_BLOCK: + case NODE_GLOBAL_BLOCK: { - int ret = push_scope(a, SCOPE_BLOCK); - if (ret < 0) return; + if (node->type == NODE_BLOCK) { + int ret = push_scope(a, SCOPE_BLOCK); + if (ret < 0) return; + } Node *stmt = node->left; while (stmt) { @@ -1037,8 +1068,10 @@ void assemble_statement(Assembler *a, Node *node, bool pop_expr) stmt = stmt->next; } - ret = pop_scope(a); - if (ret < 0) return; + if (node->type == NODE_BLOCK) { + int ret = pop_scope(a); + if (ret < 0) return; + } } break; @@ -1553,7 +1586,15 @@ char *print_instruction(char *p, char *data) printf("SYSCALL \"%.*s\"", (int) len, (char*) data + off); } break; + + case OPCODE_PUSHT: + printf("PUSHT"); + break; + + case OPCODE_PUSHFL: + printf("PUSHFL"); + break; } return p; -} +} \ No newline at end of file diff --git a/src/assemble.h b/src/assemble.h index a8e76c8..dad6d5b 100644 --- a/src/assemble.h +++ b/src/assemble.h @@ -47,6 +47,8 @@ enum { OPCODE_SYSVAR = 0x2C, OPCODE_SYSCALL = 0x2D, OPCODE_FOR = 0x2E, + OPCODE_PUSHT = 0x2F, + OPCODE_PUSHFL = 0x30, }; typedef struct { diff --git a/src/basic.c b/src/basic.c index af2be6c..5747774 100644 --- a/src/basic.c +++ b/src/basic.c @@ -86,4 +86,13 @@ bool grow_alloc(WL_Arena *a, char *p, int new_len) return false; a->cur = new_cur; return true; +} + +String copystr(String s, WL_Arena *a) +{ + char *p = alloc(a, s.len, 1); + if (p == NULL) + return (String) { NULL, 0 }; + memcpy(p, s.ptr, s.len); + return (String) { p, s.len }; } \ No newline at end of file diff --git a/src/basic.h b/src/basic.h index 6e50563..d124327 100644 --- a/src/basic.h +++ b/src/basic.h @@ -35,6 +35,7 @@ int hex_digit_to_int(char c); bool streq(String a, String b); bool streqcase(String a, String b); +String copystr(String s, WL_Arena *a); void *alloc(WL_Arena *a, int len, int align); bool grow_alloc(WL_Arena *a, char *p, int new_len); diff --git a/src/compile.c b/src/compile.c new file mode 100644 index 0000000..82006fe --- /dev/null +++ b/src/compile.c @@ -0,0 +1,118 @@ + +#ifndef WL_AMALGAMATION +#include "eval.h" +#include "parse.h" +#include "assemble.h" +#include "compile.h" +#endif + +#define FILE_LIMIT 32 + +typedef struct { + String file; + Node* root; + Node* includes; +} CompiledFile; + +struct WL_Compiler { + WL_Arena* arena; + CompiledFile files[FILE_LIMIT]; + int num_files; + String waiting_file; +}; + +int WL_streq(WL_String a, char *b, int blen) +{ + if (b == NULL) b = ""; + if (blen < 0) blen = strlen(b); + + if (a.len != blen) + return 0; + + for (int i = 0; i < a.len; i++) + if (a.ptr[i] != b[i]) + return 0; + + return 1; +} + +WL_Compiler *WL_Compiler_init(WL_Arena *arena) +{ + WL_Compiler *compiler = alloc(arena, (int) sizeof(WL_Compiler), _Alignof(WL_Compiler)); + if (compiler == NULL) + return NULL; + compiler->arena = arena; + compiler->num_files = 0; + compiler->waiting_file = (String) { NULL, 0 }; + return compiler; +} + +void WL_Compiler_free(WL_Compiler *compiler) +{ + (void) compiler; + // TODO +} + +WL_CompileResult WL_compile(WL_Compiler *compiler, WL_String file, WL_String content) +{ + if (compiler->waiting_file.len > 0) + file = (WL_String) { compiler->waiting_file.ptr, compiler->waiting_file.len }; + else { + // TODO: copy file path + // file = strdup(file, compiler->arena) + } + + char err[1<<9]; + ParseResult pres = parse((String) { content.ptr, content.len }, compiler->arena, err, (int) sizeof(err)); + if (pres.node == NULL) { + printf("%s\n", err); // TODO + return (WL_CompileResult) { .type=WL_COMPILE_RESULT_ERROR }; + } + + CompiledFile compiled_file = { + .file = { file.ptr, file.len }, + .root = pres.node, + .includes = pres.includes, + }; + compiler->files[compiler->num_files++] = compiled_file; + + for (int i = 0; i < compiler->num_files; i++) { + + Node *include = compiler->files[i].includes; + while (include) { + + assert(include->type == NODE_INCLUDE); + + if (include->include_root == NULL) { + for (int j = 0; j < compiler->num_files; j++) { + if (streq(include->include_path, compiler->files[j].file)) { + include->include_root = compiler->files[j].root; + break; + } + } + } + + if (include->include_root == NULL) { + + if (compiler->num_files == FILE_LIMIT) { + assert(0); // TODO + } + + // TODO: Make the path relative to the compiled file + + compiler->waiting_file = include->include_path; + return (WL_CompileResult) { .type=WL_COMPILE_RESULT_FILE, .path={ include->include_path.ptr, include->include_path.len } }; + } + + include = include->include_next; + } + } + + AssembleResult ares = assemble(compiler->files[0].root, compiler->arena, err, (int) sizeof(err)); + if (ares.errlen) { + printf("%s\n", err); // TODO + return (WL_CompileResult) { .type=WL_COMPILE_RESULT_ERROR }; + } + + return (WL_CompileResult) { .type=WL_COMPILE_RESULT_DONE, .program=ares.program }; +} diff --git a/src/public.h b/src/compile.h similarity index 69% rename from src/public.h rename to src/compile.h index 90c0d77..e5def46 100644 --- a/src/public.h +++ b/src/compile.h @@ -36,10 +36,27 @@ typedef struct { int cur; } WL_Arena; -int WL_compile (char *src, int len, WL_Arena arena, WL_Program *program, char *err, int errmax); -WL_State *WL_State_init (WL_Arena *a, WL_Program p, char *err, int errmax); -void WL_State_free (WL_State *state); -WL_Result WL_eval (WL_State *state); +typedef struct WL_Compiler WL_Compiler; + +typedef enum { + WL_COMPILE_RESULT_DONE, + WL_COMPILE_RESULT_FILE, + WL_COMPILE_RESULT_ERROR, +} WL_CompileResultType; + +typedef struct { + WL_CompileResultType type; + WL_Program program; + WL_String path; +} WL_CompileResult; + +WL_Compiler* WL_Compiler_init (WL_Arena *arena); +void WL_Compiler_free (WL_Compiler *compiler); +WL_CompileResult WL_compile (WL_Compiler *compiler, WL_String file, WL_String content); +WL_State* WL_State_init (WL_Arena *a, WL_Program p, char *err, int errmax); +void WL_State_free (WL_State *state); +WL_Result WL_eval (WL_State *state); + int WL_streq (WL_String a, char *b, int blen); int WL_peeknone (WL_State *state, int off); int WL_peekint (WL_State *state, int off, long long *x); diff --git a/src/eval.c b/src/eval.c index 22efdfb..f719f99 100644 --- a/src/eval.c +++ b/src/eval.c @@ -246,6 +246,18 @@ int step(WL_State *state) } break; + case OPCODE_PUSHT: + { + state->eval_stack[state->eval_depth++] = VALUE_TRUE; + } + break; + + case OPCODE_PUSHFL: + { + state->eval_stack[state->eval_depth++] = VALUE_FALSE; + } + break; + case OPCODE_PUSHV: { uint8_t idx = read_u8(state); diff --git a/src/parse.c b/src/parse.c index 62efabe..241da09 100644 --- a/src/parse.c +++ b/src/parse.c @@ -21,6 +21,10 @@ typedef enum { TOKEN_KWORD_FUN, TOKEN_KWORD_LET, TOKEN_KWORD_PRINT, + TOKEN_KWORD_NONE, + TOKEN_KWORD_TRUE, + TOKEN_KWORD_FALSE, + TOKEN_KWORD_INCLUDE, TOKEN_VALUE_FLOAT, TOKEN_VALUE_INT, TOKEN_VALUE_STR, @@ -58,11 +62,13 @@ typedef struct { } Token; typedef struct { - Scanner s; - WL_Arena *a; - char *errbuf; - int errmax; - int errlen; + Scanner s; + WL_Arena* a; + char* errbuf; + int errmax; + int errlen; + Node* include_head; + Node** include_tail; } Parser; bool consume_str(Scanner *s, String x) @@ -106,6 +112,10 @@ String tok2str(Token token, char *buf, int max) case TOKEN_KWORD_FUN: return S("fun"); case TOKEN_KWORD_LET: return S("let"); case TOKEN_KWORD_PRINT: return S("print"); + case TOKEN_KWORD_NONE: return S("none"); + case TOKEN_KWORD_TRUE: return S("true"); + case TOKEN_KWORD_FALSE: return S("false"); + case TOKEN_KWORD_INCLUDE: return S("include"); case TOKEN_VALUE_FLOAT: { @@ -240,6 +250,17 @@ Token next_token(Parser *p) if (streq(kword, S("fun"))) return (Token) { .type=TOKEN_KWORD_FUN }; if (streq(kword, S("let"))) return (Token) { .type=TOKEN_KWORD_LET }; if (streq(kword, S("print"))) return (Token) { .type=TOKEN_KWORD_PRINT }; + if (streq(kword, S("none"))) return (Token) { .type=TOKEN_KWORD_NONE }; + if (streq(kword, S("true"))) return (Token) { .type=TOKEN_KWORD_TRUE }; + if (streq(kword, S("false"))) return (Token) { .type=TOKEN_KWORD_FALSE }; + if (streq(kword, S("include"))) return (Token) { .type=TOKEN_KWORD_INCLUDE }; + + kword = copystr(kword, p->a); + if (kword.len == 0) { + parser_report(p, "Out of memory"); + return (Token) { .type=TOKEN_ERROR }; + } + return (Token) { .type=TOKEN_IDENT, .sval=kword }; } @@ -427,8 +448,6 @@ 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]; @@ -444,8 +463,6 @@ Node *parse_html(Parser *p) bool no_body = false; for (;;) { - int param_offset = p->s.cur; - String attr_name; Node *attr_value; @@ -488,7 +505,6 @@ 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; @@ -529,7 +545,6 @@ 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; @@ -588,7 +603,6 @@ 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; @@ -601,8 +615,6 @@ Node *parse_array(Parser *p) { // Left bracket already consumed - int start = p->s.cur; - Node *head; Node **tail = &head; @@ -642,7 +654,6 @@ 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; @@ -652,8 +663,6 @@ Node *parse_map(Parser *p) { // Left bracket already consumed - int start = p->s.cur; - Node *head; Node **tail = &head; @@ -676,7 +685,6 @@ Node *parse_map(Parser *p) return NULL; key->type = NODE_VALUE_STR; - key->text = t.sval; key->sval = t.sval; } else { @@ -722,7 +730,6 @@ 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; @@ -776,8 +783,6 @@ bool right_associative(Token t) Node *parse_atom(Parser *p) { - int start = p->s.cur; - Token t = next_token(p); Node *ret; @@ -793,7 +798,6 @@ 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; @@ -811,7 +815,6 @@ 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; @@ -825,7 +828,6 @@ 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; @@ -839,7 +841,6 @@ 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; @@ -853,7 +854,6 @@ 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; @@ -867,7 +867,44 @@ 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; + } + break; + + case TOKEN_KWORD_NONE: + { + Node *node = alloc_node(p); + if (node == NULL) + return NULL; + + node->type = NODE_VALUE_NONE; + node->sval = t.sval; + + ret = node; + } + break; + + case TOKEN_KWORD_TRUE: + { + Node *node = alloc_node(p); + if (node == NULL) + return NULL; + + node->type = NODE_VALUE_TRUE; + node->sval = t.sval; + + ret = node; + } + break; + case TOKEN_KWORD_FALSE: + { + Node *node = alloc_node(p); + if (node == NULL) + return NULL; + + node->type = NODE_VALUE_FALSE; node->sval = t.sval; ret = node; @@ -901,7 +938,6 @@ Node *parse_atom(Parser *p) return NULL; parent->type = NODE_NESTED; - parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = node; ret = parent; @@ -941,7 +977,6 @@ Node *parse_atom(Parser *p) return NULL; node->type = NODE_VALUE_SYSVAR; - node->text = (String) { p->s.src + start, p->s.cur - start }; node->sval = t.sval; ret = node; @@ -973,7 +1008,6 @@ 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); @@ -981,7 +1015,6 @@ 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; @@ -1004,7 +1037,6 @@ 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; @@ -1048,7 +1080,6 @@ 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; @@ -1063,7 +1094,7 @@ Node *parse_atom(Parser *p) return ret; } -Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int start, int flags) +Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int flags) { for (;;) { @@ -1074,8 +1105,6 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int start, int flags break; } - int right_start = p->s.cur; - Node *right = parse_atom(p); if (right == NULL) return NULL; @@ -1094,7 +1123,7 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int start, int flags if (p2 <= p1 && (p1 != p2 || !right_associative(t2))) break; - right = parse_expr_inner(p, right, p1 + (p2 > p1), right_start, flags); + right = parse_expr_inner(p, right, p1 + (p2 > p1), flags); if (right == NULL) return NULL; } @@ -1103,7 +1132,6 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int start, int flags if (parent == NULL) return NULL; - parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = left; parent->right = right; @@ -1131,13 +1159,11 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int start, 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, start, flags); + return parse_expr_inner(p, left, 0, flags); } Node *parse_expr_stmt(Parser *p, int opflags) @@ -1151,8 +1177,6 @@ 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) { parser_report(p, "Missing 'if' keyword before if statement"); @@ -1192,7 +1216,6 @@ 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; @@ -1202,8 +1225,6 @@ 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) { parser_report(p, "Missing 'for' keyword at the start of a for statement"); @@ -1256,7 +1277,6 @@ 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; @@ -1267,8 +1287,6 @@ 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) { parser_report(p, "Missing keyword 'while' at the start of a while statement"); @@ -1294,7 +1312,6 @@ 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; @@ -1303,8 +1320,6 @@ Node *parse_while_stmt(Parser *p, int opflags) Node *parse_block_stmt(Parser *p, bool curly) { - int start = p->s.cur; - if (curly) { Token t = next_token(p); if (t.type != TOKEN_CURLY_OPEN) { @@ -1344,7 +1359,6 @@ Node *parse_block_stmt(Parser *p, bool curly) return NULL; parent->type = NODE_BLOCK; - parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = head; return parent; @@ -1352,8 +1366,6 @@ Node *parse_block_stmt(Parser *p, bool 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) { parser_report(p, "Missing keyword 'fun' at the start of a function declaration"); @@ -1383,8 +1395,6 @@ Node *parse_func_decl(Parser *p, int opflags) for (;;) { - int arg_start = p->s.cur; - t = next_token(p); if (t.type != TOKEN_IDENT) { parser_report(p, "Missing argument name in function declaration"); @@ -1397,7 +1407,6 @@ 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; @@ -1427,7 +1436,6 @@ 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; @@ -1437,8 +1445,6 @@ 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) { parser_report(p, "Missing keyword 'let' at the start of a variable declaration"); @@ -1472,7 +1478,6 @@ 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; @@ -1481,8 +1486,6 @@ Node *parse_var_decl(Parser *p, int opflags) Node *parse_print_stmt(Parser *p, int opflags) { - int start = p->s.cur; - Token t = next_token(p); if (t.type != TOKEN_KWORD_PRINT) { parser_report(p, "Missing keyword 'print' at the start of a print statement"); @@ -1498,12 +1501,40 @@ Node *parse_print_stmt(Parser *p, int opflags) return NULL; parent->type = NODE_PRINT; - parent->text = (String) { p->s.src + start, p->s.cur - start }; parent->left = arg; return parent; } +Node *parse_include_stmt(Parser *p) +{ + Token t = next_token(p); + if (t.type != TOKEN_KWORD_INCLUDE) { + parser_report(p, "Missing keyword 'include' at the start of an include statement"); + return NULL; + } + + t = next_token(p); + if (t.type != TOKEN_VALUE_STR) { + parser_report(p, "Missing file path string after 'include' keyword"); + return NULL; + } + String path = t.sval; + + Node *parent = alloc_node(p); + if (parent == NULL) + return NULL; + + parent->type = NODE_INCLUDE; + parent->include_path = path; + parent->include_root = NULL; + + *p->include_tail = parent; + p->include_tail = &parent->include_next; + + return parent; +} + Node *parse_stmt(Parser *p, int opflags) { Scanner saved = p->s; @@ -1512,6 +1543,9 @@ Node *parse_stmt(Parser *p, int opflags) switch (t.type) { + case TOKEN_KWORD_INCLUDE: + return parse_include_stmt(p); + case TOKEN_KWORD_PRINT: return parse_print_stmt(p, opflags); @@ -1544,6 +1578,18 @@ void print_node(Node *node) { switch (node->type) { + case NODE_VALUE_NONE: + printf("none"); + break; + + case NODE_VALUE_TRUE: + printf("true"); + break; + + case NODE_VALUE_FALSE: + printf("false"); + break; + case NODE_NESTED: { printf("("); @@ -1853,6 +1899,18 @@ void print_node(Node *node) //printf(";"); } break; + + case NODE_INCLUDE: + { + printf("include \"%.*s\"", + node->include_path.len, + node->include_path.ptr); + } + break; + + default: + printf("(invalid node type %x)", node->type); + break; } } @@ -1866,10 +1924,15 @@ ParseResult parse(String src, WL_Arena *a, char *errbuf, int errmax) .errlen=0, }; + p.include_tail = &p.include_head; + Node *node = parse_block_stmt(&p, false); - if (node == NULL) - return (ParseResult) { NULL, p.errlen }; + return (ParseResult) { .node=NULL, .includes=NULL, .errlen=p.errlen }; - return (ParseResult) { node, -1 }; + assert(node->type == NODE_BLOCK); + node->type = NODE_GLOBAL_BLOCK; + + *p.include_tail = NULL; + return (ParseResult) { .node=node, .includes=p.include_head, .errlen=-1 }; } diff --git a/src/parse.h b/src/parse.h index bf5bd77..3136f26 100644 --- a/src/parse.h +++ b/src/parse.h @@ -13,9 +13,11 @@ typedef enum { NODE_VAR_DECL, NODE_PRINT, NODE_BLOCK, + NODE_GLOBAL_BLOCK, NODE_IFELSE, NODE_FOR, NODE_WHILE, + NODE_INCLUDE, NODE_SELECT, NODE_NESTED, NODE_OPER_POS, @@ -33,6 +35,9 @@ typedef enum { NODE_VALUE_INT, NODE_VALUE_FLOAT, NODE_VALUE_STR, + NODE_VALUE_NONE, + NODE_VALUE_TRUE, + NODE_VALUE_FALSE, NODE_VALUE_VAR, NODE_VALUE_SYSVAR, NODE_VALUE_HTML, @@ -45,7 +50,6 @@ typedef struct Node Node; struct Node { NodeType type; Node *next; - String text; Node *key; @@ -76,10 +80,15 @@ struct Node { String var_name; Node *var_value; + + String include_path; + Node* include_next; + Node* include_root; }; typedef struct { Node *node; + Node *includes; int errlen; } ParseResult; diff --git a/src/public.c b/src/public.c deleted file mode 100644 index d8c6f92..0000000 --- a/src/public.c +++ /dev/null @@ -1,41 +0,0 @@ - -#ifndef WL_AMALGAMATION -#include "eval.h" -#include "parse.h" -#include "assemble.h" -#include "WL.h" -#endif - -int WL_streq(WL_String a, char *b, int blen) -{ - if (b == NULL) b = ""; - if (blen < 0) blen = strlen(b); - - if (a.len != blen) - return 0; - - for (int i = 0; i < a.len; i++) - if (a.ptr[i] != b[i]) - return 0; - - return 1; -} - -int WL_compile(char *src, int len, WL_Arena arena, WL_Program *program, char *err, int errmax) -{ - if (src == NULL) src = ""; - if (len < 0) len = strlen(src); - - Node *root; - ParseResult pres = parse((String) {src, len}, &arena, err, errmax); - if (pres.node == NULL) - return -1; - root = pres.node; - - AssembleResult ares = assemble(root, &arena, err, errmax); - if (ares.errlen) - return -1; - *program = ares.program; - - return 0; -} \ No newline at end of file