Fixes and added include statement

This commit is contained in:
2025-08-08 11:41:25 +02:00
parent 3c7aafba10
commit acf2ea7b97
16 changed files with 738 additions and 235 deletions
+299 -85
View File
@@ -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,
@@ -474,10 +497,12 @@ typedef struct {
typedef struct {
Scanner s;
WL_Arena *a;
char *errbuf;
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:
{
if (node->type == NODE_BLOCK) {
int ret = push_scope(a, SCOPE_BLOCK);
if (ret < 0) return;
}
Node *stmt = node->left;
while (stmt) {
@@ -3399,9 +3514,11 @@ void assemble_statement(Assembler *a, Node *node, bool pop_expr)
stmt = stmt->next;
}
ret = pop_scope(a);
if (node->type == NODE_BLOCK) {
int ret = pop_scope(a);
if (ret < 0) return;
}
}
break;
case NODE_IFELSE:
@@ -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 };
}
+20 -3
View File
@@ -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);
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);
+2 -2
View File
@@ -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")
+1
View File
@@ -0,0 +1 @@
let ugu = 78
+46 -10
View File
@@ -1,5 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdbool.h>
#include "WL.h"
@@ -12,9 +14,31 @@ int main(int argc, char **argv)
}
char *file = argv[1];
FILE *f = fopen(file, "rb");
if (f == NULL)
char err[1<<9];
char *mem = malloc(1<<20);
WL_Arena a = { mem, 1<<20, 0 };
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);
@@ -25,16 +49,29 @@ int main(int argc, char **argv)
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 };
result = WL_compile(compiler, path, (WL_String) { file_data, file_size });
WL_Program program;
int ret = WL_compile(file_data, file_size, a, &program, err, (int) sizeof(err));
if (ret < 0) {
printf("%s\n", err);
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;
}
+4
View File
@@ -1,3 +1,7 @@
include "example.wl"
ugu
let posts = [
{
author: "UserA",
+42 -1
View File
@@ -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:
{
if (node->type == NODE_BLOCK) {
int ret = push_scope(a, SCOPE_BLOCK);
if (ret < 0) return;
}
Node *stmt = node->left;
while (stmt) {
@@ -1037,9 +1068,11 @@ void assemble_statement(Assembler *a, Node *node, bool pop_expr)
stmt = stmt->next;
}
ret = pop_scope(a);
if (node->type == NODE_BLOCK) {
int ret = pop_scope(a);
if (ret < 0) return;
}
}
break;
case NODE_IFELSE:
@@ -1553,6 +1586,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;
+2
View File
@@ -47,6 +47,8 @@ enum {
OPCODE_SYSVAR = 0x2C,
OPCODE_SYSCALL = 0x2D,
OPCODE_FOR = 0x2E,
OPCODE_PUSHT = 0x2F,
OPCODE_PUSHFL = 0x30,
};
typedef struct {
+9
View File
@@ -87,3 +87,12 @@ bool grow_alloc(WL_Arena *a, char *p, int new_len)
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 };
}
+1
View File
@@ -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);
+118
View File
@@ -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 };
}
+19 -2
View File
@@ -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);
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);
+12
View File
@@ -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);
+128 -65
View File
@@ -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,
@@ -59,10 +63,12 @@ typedef struct {
typedef struct {
Scanner s;
WL_Arena *a;
char *errbuf;
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 };
}
+10 -1
View File
@@ -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;
-41
View File
@@ -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;
}