Fixes and added include statement
This commit is contained in:
@@ -71,6 +71,7 @@ int hex_digit_to_int(char c);
|
|||||||
|
|
||||||
bool streq(String a, String b);
|
bool streq(String a, String b);
|
||||||
bool streqcase(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);
|
void *alloc(WL_Arena *a, int len, int align);
|
||||||
bool grow_alloc(WL_Arena *a, char *p, int new_len);
|
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;
|
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
|
// src/file.h
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -334,9 +344,11 @@ typedef enum {
|
|||||||
NODE_VAR_DECL,
|
NODE_VAR_DECL,
|
||||||
NODE_PRINT,
|
NODE_PRINT,
|
||||||
NODE_BLOCK,
|
NODE_BLOCK,
|
||||||
|
NODE_GLOBAL_BLOCK,
|
||||||
NODE_IFELSE,
|
NODE_IFELSE,
|
||||||
NODE_FOR,
|
NODE_FOR,
|
||||||
NODE_WHILE,
|
NODE_WHILE,
|
||||||
|
NODE_INCLUDE,
|
||||||
NODE_SELECT,
|
NODE_SELECT,
|
||||||
NODE_NESTED,
|
NODE_NESTED,
|
||||||
NODE_OPER_POS,
|
NODE_OPER_POS,
|
||||||
@@ -354,6 +366,9 @@ typedef enum {
|
|||||||
NODE_VALUE_INT,
|
NODE_VALUE_INT,
|
||||||
NODE_VALUE_FLOAT,
|
NODE_VALUE_FLOAT,
|
||||||
NODE_VALUE_STR,
|
NODE_VALUE_STR,
|
||||||
|
NODE_VALUE_NONE,
|
||||||
|
NODE_VALUE_TRUE,
|
||||||
|
NODE_VALUE_FALSE,
|
||||||
NODE_VALUE_VAR,
|
NODE_VALUE_VAR,
|
||||||
NODE_VALUE_SYSVAR,
|
NODE_VALUE_SYSVAR,
|
||||||
NODE_VALUE_HTML,
|
NODE_VALUE_HTML,
|
||||||
@@ -366,7 +381,6 @@ typedef struct Node Node;
|
|||||||
struct Node {
|
struct Node {
|
||||||
NodeType type;
|
NodeType type;
|
||||||
Node *next;
|
Node *next;
|
||||||
String text;
|
|
||||||
|
|
||||||
Node *key;
|
Node *key;
|
||||||
|
|
||||||
@@ -397,10 +411,15 @@ struct Node {
|
|||||||
|
|
||||||
String var_name;
|
String var_name;
|
||||||
Node *var_value;
|
Node *var_value;
|
||||||
|
|
||||||
|
String include_path;
|
||||||
|
Node* include_next;
|
||||||
|
Node* include_root;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Node *node;
|
Node *node;
|
||||||
|
Node *includes;
|
||||||
int errlen;
|
int errlen;
|
||||||
} ParseResult;
|
} ParseResult;
|
||||||
|
|
||||||
@@ -436,6 +455,10 @@ typedef enum {
|
|||||||
TOKEN_KWORD_FUN,
|
TOKEN_KWORD_FUN,
|
||||||
TOKEN_KWORD_LET,
|
TOKEN_KWORD_LET,
|
||||||
TOKEN_KWORD_PRINT,
|
TOKEN_KWORD_PRINT,
|
||||||
|
TOKEN_KWORD_NONE,
|
||||||
|
TOKEN_KWORD_TRUE,
|
||||||
|
TOKEN_KWORD_FALSE,
|
||||||
|
TOKEN_KWORD_INCLUDE,
|
||||||
TOKEN_VALUE_FLOAT,
|
TOKEN_VALUE_FLOAT,
|
||||||
TOKEN_VALUE_INT,
|
TOKEN_VALUE_INT,
|
||||||
TOKEN_VALUE_STR,
|
TOKEN_VALUE_STR,
|
||||||
@@ -474,10 +497,12 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Scanner s;
|
Scanner s;
|
||||||
WL_Arena *a;
|
WL_Arena* a;
|
||||||
char *errbuf;
|
char* errbuf;
|
||||||
int errmax;
|
int errmax;
|
||||||
int errlen;
|
int errlen;
|
||||||
|
Node* include_head;
|
||||||
|
Node** include_tail;
|
||||||
} Parser;
|
} Parser;
|
||||||
|
|
||||||
bool consume_str(Scanner *s, String x)
|
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_FUN: return S("fun");
|
||||||
case TOKEN_KWORD_LET: return S("let");
|
case TOKEN_KWORD_LET: return S("let");
|
||||||
case TOKEN_KWORD_PRINT: return S("print");
|
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:
|
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("fun"))) return (Token) { .type=TOKEN_KWORD_FUN };
|
||||||
if (streq(kword, S("let"))) return (Token) { .type=TOKEN_KWORD_LET };
|
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("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 };
|
return (Token) { .type=TOKEN_IDENT, .sval=kword };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -842,8 +882,6 @@ Node *parse_html(Parser *p)
|
|||||||
{
|
{
|
||||||
// NOTE: The first < was already consumed
|
// NOTE: The first < was already consumed
|
||||||
|
|
||||||
int node_offset = p->s.cur-1;
|
|
||||||
|
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
if (t.type != TOKEN_IDENT) {
|
if (t.type != TOKEN_IDENT) {
|
||||||
char buf[1<<8];
|
char buf[1<<8];
|
||||||
@@ -859,8 +897,6 @@ Node *parse_html(Parser *p)
|
|||||||
bool no_body = false;
|
bool no_body = false;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
int param_offset = p->s.cur;
|
|
||||||
|
|
||||||
String attr_name;
|
String attr_name;
|
||||||
Node *attr_value;
|
Node *attr_value;
|
||||||
|
|
||||||
@@ -903,7 +939,6 @@ Node *parse_html(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
child->type = NODE_HTML_PARAM;
|
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_name = attr_name;
|
||||||
child->attr_value = attr_value;
|
child->attr_value = attr_value;
|
||||||
|
|
||||||
@@ -944,7 +979,6 @@ Node *parse_html(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
child->type = NODE_VALUE_STR;
|
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 };
|
child->sval = (String) { p->s.src + off, p->s.cur - off };
|
||||||
|
|
||||||
*tail = child;
|
*tail = child;
|
||||||
@@ -1003,7 +1037,6 @@ Node *parse_html(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_VALUE_HTML;
|
parent->type = NODE_VALUE_HTML;
|
||||||
parent->text = (String) { p->s.src + node_offset, p->s.cur - node_offset };
|
|
||||||
parent->tagname = tagname;
|
parent->tagname = tagname;
|
||||||
parent->params = param_head;
|
parent->params = param_head;
|
||||||
parent->child = head;
|
parent->child = head;
|
||||||
@@ -1016,8 +1049,6 @@ Node *parse_array(Parser *p)
|
|||||||
{
|
{
|
||||||
// Left bracket already consumed
|
// Left bracket already consumed
|
||||||
|
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Node *head;
|
Node *head;
|
||||||
Node **tail = &head;
|
Node **tail = &head;
|
||||||
|
|
||||||
@@ -1057,7 +1088,6 @@ Node *parse_array(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_VALUE_ARRAY;
|
parent->type = NODE_VALUE_ARRAY;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->child = head;
|
parent->child = head;
|
||||||
|
|
||||||
return parent;
|
return parent;
|
||||||
@@ -1067,8 +1097,6 @@ Node *parse_map(Parser *p)
|
|||||||
{
|
{
|
||||||
// Left bracket already consumed
|
// Left bracket already consumed
|
||||||
|
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Node *head;
|
Node *head;
|
||||||
Node **tail = &head;
|
Node **tail = &head;
|
||||||
|
|
||||||
@@ -1091,7 +1119,6 @@ Node *parse_map(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
key->type = NODE_VALUE_STR;
|
key->type = NODE_VALUE_STR;
|
||||||
key->text = t.sval;
|
|
||||||
key->sval = t.sval;
|
key->sval = t.sval;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -1137,7 +1164,6 @@ Node *parse_map(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_VALUE_MAP;
|
parent->type = NODE_VALUE_MAP;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->child = head;
|
parent->child = head;
|
||||||
|
|
||||||
return parent;
|
return parent;
|
||||||
@@ -1191,8 +1217,6 @@ bool right_associative(Token t)
|
|||||||
|
|
||||||
Node *parse_atom(Parser *p)
|
Node *parse_atom(Parser *p)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
|
|
||||||
Node *ret;
|
Node *ret;
|
||||||
@@ -1208,7 +1232,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_OPER_POS;
|
parent->type = NODE_OPER_POS;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = child;
|
parent->left = child;
|
||||||
|
|
||||||
ret = parent;
|
ret = parent;
|
||||||
@@ -1226,7 +1249,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_OPER_NEG;
|
parent->type = NODE_OPER_NEG;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = child;
|
parent->left = child;
|
||||||
|
|
||||||
ret = parent;
|
ret = parent;
|
||||||
@@ -1240,7 +1262,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
node->type = NODE_VALUE_VAR;
|
node->type = NODE_VALUE_VAR;
|
||||||
node->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
node->sval = t.sval;
|
node->sval = t.sval;
|
||||||
|
|
||||||
ret = node;
|
ret = node;
|
||||||
@@ -1254,7 +1275,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
node->type = NODE_VALUE_INT;
|
node->type = NODE_VALUE_INT;
|
||||||
node->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
node->ival = t.uval;
|
node->ival = t.uval;
|
||||||
|
|
||||||
ret = node;
|
ret = node;
|
||||||
@@ -1268,7 +1288,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
node->type = NODE_VALUE_FLOAT;
|
node->type = NODE_VALUE_FLOAT;
|
||||||
node->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
node->dval = t.dval;
|
node->dval = t.dval;
|
||||||
|
|
||||||
ret = node;
|
ret = node;
|
||||||
@@ -1282,7 +1301,44 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
node->type = NODE_VALUE_STR;
|
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;
|
node->sval = t.sval;
|
||||||
|
|
||||||
ret = node;
|
ret = node;
|
||||||
@@ -1316,7 +1372,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_NESTED;
|
parent->type = NODE_NESTED;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = node;
|
parent->left = node;
|
||||||
|
|
||||||
ret = parent;
|
ret = parent;
|
||||||
@@ -1356,7 +1411,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
node->type = NODE_VALUE_SYSVAR;
|
node->type = NODE_VALUE_SYSVAR;
|
||||||
node->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
node->sval = t.sval;
|
node->sval = t.sval;
|
||||||
|
|
||||||
ret = node;
|
ret = node;
|
||||||
@@ -1388,7 +1442,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
child->type = NODE_VALUE_STR;
|
child->type = NODE_VALUE_STR;
|
||||||
child->text = t.sval;
|
|
||||||
child->sval = t.sval;
|
child->sval = t.sval;
|
||||||
|
|
||||||
Node *parent = alloc_node(p);
|
Node *parent = alloc_node(p);
|
||||||
@@ -1396,7 +1449,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_SELECT;
|
parent->type = NODE_SELECT;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = ret;
|
parent->left = ret;
|
||||||
parent->right = child;
|
parent->right = child;
|
||||||
|
|
||||||
@@ -1419,7 +1471,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_SELECT;
|
parent->type = NODE_SELECT;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = ret;
|
parent->left = ret;
|
||||||
parent->right = child;
|
parent->right = child;
|
||||||
|
|
||||||
@@ -1463,7 +1514,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_FUNC_CALL;
|
parent->type = NODE_FUNC_CALL;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = ret;
|
parent->left = ret;
|
||||||
parent->right = arg_head;
|
parent->right = arg_head;
|
||||||
|
|
||||||
@@ -1478,7 +1528,7 @@ Node *parse_atom(Parser *p)
|
|||||||
return ret;
|
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 (;;) {
|
for (;;) {
|
||||||
|
|
||||||
@@ -1489,8 +1539,6 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int start, int flags
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int right_start = p->s.cur;
|
|
||||||
|
|
||||||
Node *right = parse_atom(p);
|
Node *right = parse_atom(p);
|
||||||
if (right == NULL)
|
if (right == NULL)
|
||||||
return 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)))
|
if (p2 <= p1 && (p1 != p2 || !right_associative(t2)))
|
||||||
break;
|
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)
|
if (right == NULL)
|
||||||
return 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)
|
if (parent == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = left;
|
parent->left = left;
|
||||||
parent->right = right;
|
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)
|
Node *parse_expr(Parser *p, int flags)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Node *left = parse_atom(p);
|
Node *left = parse_atom(p);
|
||||||
if (left == NULL)
|
if (left == NULL)
|
||||||
return 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)
|
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)
|
Node *parse_ifelse_stmt(Parser *p, int opflags)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
if (t.type != TOKEN_KWORD_IF) {
|
if (t.type != TOKEN_KWORD_IF) {
|
||||||
parser_report(p, "Missing 'if' keyword before if statement");
|
parser_report(p, "Missing 'if' keyword before if statement");
|
||||||
@@ -1607,7 +1650,6 @@ Node *parse_ifelse_stmt(Parser *p, int opflags)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_IFELSE;
|
parent->type = NODE_IFELSE;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = if_stmt;
|
parent->left = if_stmt;
|
||||||
parent->right = else_stmt;
|
parent->right = else_stmt;
|
||||||
parent->cond = cond;
|
parent->cond = cond;
|
||||||
@@ -1617,8 +1659,6 @@ Node *parse_ifelse_stmt(Parser *p, int opflags)
|
|||||||
|
|
||||||
Node *parse_for_stmt(Parser *p, int opflags)
|
Node *parse_for_stmt(Parser *p, int opflags)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
if (t.type != TOKEN_KWORD_FOR) {
|
if (t.type != TOKEN_KWORD_FOR) {
|
||||||
parser_report(p, "Missing 'for' keyword at the start of a for statement");
|
parser_report(p, "Missing 'for' keyword at the start of a for statement");
|
||||||
@@ -1671,7 +1711,6 @@ Node *parse_for_stmt(Parser *p, int opflags)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_FOR;
|
parent->type = NODE_FOR;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = body;
|
parent->left = body;
|
||||||
parent->for_var1 = var1;
|
parent->for_var1 = var1;
|
||||||
parent->for_var2 = var2;
|
parent->for_var2 = var2;
|
||||||
@@ -1682,8 +1721,6 @@ Node *parse_for_stmt(Parser *p, int opflags)
|
|||||||
|
|
||||||
Node *parse_while_stmt(Parser *p, int opflags)
|
Node *parse_while_stmt(Parser *p, int opflags)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
if (t.type != TOKEN_KWORD_WHILE) {
|
if (t.type != TOKEN_KWORD_WHILE) {
|
||||||
parser_report(p, "Missing keyword 'while' at the start of a while statement");
|
parser_report(p, "Missing keyword 'while' at the start of a while statement");
|
||||||
@@ -1709,7 +1746,6 @@ Node *parse_while_stmt(Parser *p, int opflags)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_WHILE;
|
parent->type = NODE_WHILE;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = stmt;
|
parent->left = stmt;
|
||||||
parent->cond = cond;
|
parent->cond = cond;
|
||||||
|
|
||||||
@@ -1718,8 +1754,6 @@ Node *parse_while_stmt(Parser *p, int opflags)
|
|||||||
|
|
||||||
Node *parse_block_stmt(Parser *p, bool curly)
|
Node *parse_block_stmt(Parser *p, bool curly)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
if (curly) {
|
if (curly) {
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
if (t.type != TOKEN_CURLY_OPEN) {
|
if (t.type != TOKEN_CURLY_OPEN) {
|
||||||
@@ -1759,7 +1793,6 @@ Node *parse_block_stmt(Parser *p, bool curly)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_BLOCK;
|
parent->type = NODE_BLOCK;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = head;
|
parent->left = head;
|
||||||
|
|
||||||
return parent;
|
return parent;
|
||||||
@@ -1767,8 +1800,6 @@ Node *parse_block_stmt(Parser *p, bool curly)
|
|||||||
|
|
||||||
Node *parse_func_decl(Parser *p, int opflags)
|
Node *parse_func_decl(Parser *p, int opflags)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
if (t.type != TOKEN_KWORD_FUN) {
|
if (t.type != TOKEN_KWORD_FUN) {
|
||||||
parser_report(p, "Missing keyword 'fun' at the start of a function declaration");
|
parser_report(p, "Missing keyword 'fun' at the start of a function declaration");
|
||||||
@@ -1798,8 +1829,6 @@ Node *parse_func_decl(Parser *p, int opflags)
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
int arg_start = p->s.cur;
|
|
||||||
|
|
||||||
t = next_token(p);
|
t = next_token(p);
|
||||||
if (t.type != TOKEN_IDENT) {
|
if (t.type != TOKEN_IDENT) {
|
||||||
parser_report(p, "Missing argument name in function declaration");
|
parser_report(p, "Missing argument name in function declaration");
|
||||||
@@ -1812,7 +1841,6 @@ Node *parse_func_decl(Parser *p, int opflags)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
node->type = NODE_FUNC_ARG;
|
node->type = NODE_FUNC_ARG;
|
||||||
node->text = (String) { p->s.src + arg_start, p->s.cur - arg_start };
|
|
||||||
node->sval = argname;
|
node->sval = argname;
|
||||||
|
|
||||||
*arg_tail = node;
|
*arg_tail = node;
|
||||||
@@ -1842,7 +1870,6 @@ Node *parse_func_decl(Parser *p, int opflags)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_FUNC_DECL;
|
parent->type = NODE_FUNC_DECL;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->func_name = name;
|
parent->func_name = name;
|
||||||
parent->func_args = arg_head;
|
parent->func_args = arg_head;
|
||||||
parent->func_body = body;
|
parent->func_body = body;
|
||||||
@@ -1852,8 +1879,6 @@ Node *parse_func_decl(Parser *p, int opflags)
|
|||||||
|
|
||||||
Node *parse_var_decl(Parser *p, int opflags)
|
Node *parse_var_decl(Parser *p, int opflags)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
if (t.type != TOKEN_KWORD_LET) {
|
if (t.type != TOKEN_KWORD_LET) {
|
||||||
parser_report(p, "Missing keyword 'let' at the start of a variable declaration");
|
parser_report(p, "Missing keyword 'let' at the start of a variable declaration");
|
||||||
@@ -1887,7 +1912,6 @@ Node *parse_var_decl(Parser *p, int opflags)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_VAR_DECL;
|
parent->type = NODE_VAR_DECL;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->var_name = name;
|
parent->var_name = name;
|
||||||
parent->var_value = value;
|
parent->var_value = value;
|
||||||
|
|
||||||
@@ -1896,8 +1920,6 @@ Node *parse_var_decl(Parser *p, int opflags)
|
|||||||
|
|
||||||
Node *parse_print_stmt(Parser *p, int opflags)
|
Node *parse_print_stmt(Parser *p, int opflags)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
if (t.type != TOKEN_KWORD_PRINT) {
|
if (t.type != TOKEN_KWORD_PRINT) {
|
||||||
parser_report(p, "Missing keyword 'print' at the start of a print statement");
|
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;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_PRINT;
|
parent->type = NODE_PRINT;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = arg;
|
parent->left = arg;
|
||||||
|
|
||||||
return parent;
|
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)
|
Node *parse_stmt(Parser *p, int opflags)
|
||||||
{
|
{
|
||||||
Scanner saved = p->s;
|
Scanner saved = p->s;
|
||||||
@@ -1927,6 +1977,9 @@ Node *parse_stmt(Parser *p, int opflags)
|
|||||||
|
|
||||||
switch (t.type) {
|
switch (t.type) {
|
||||||
|
|
||||||
|
case TOKEN_KWORD_INCLUDE:
|
||||||
|
return parse_include_stmt(p);
|
||||||
|
|
||||||
case TOKEN_KWORD_PRINT:
|
case TOKEN_KWORD_PRINT:
|
||||||
return parse_print_stmt(p, opflags);
|
return parse_print_stmt(p, opflags);
|
||||||
|
|
||||||
@@ -1959,6 +2012,18 @@ void print_node(Node *node)
|
|||||||
{
|
{
|
||||||
switch (node->type) {
|
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:
|
case NODE_NESTED:
|
||||||
{
|
{
|
||||||
printf("(");
|
printf("(");
|
||||||
@@ -2268,6 +2333,18 @@ void print_node(Node *node)
|
|||||||
//printf(";");
|
//printf(";");
|
||||||
}
|
}
|
||||||
break;
|
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,
|
.errlen=0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
p.include_tail = &p.include_head;
|
||||||
|
|
||||||
Node *node = parse_block_stmt(&p, false);
|
Node *node = parse_block_stmt(&p, false);
|
||||||
|
|
||||||
if (node == NULL)
|
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_SYSVAR = 0x2C,
|
||||||
OPCODE_SYSCALL = 0x2D,
|
OPCODE_SYSCALL = 0x2D,
|
||||||
OPCODE_FOR = 0x2E,
|
OPCODE_FOR = 0x2E,
|
||||||
|
OPCODE_PUSHT = 0x2F,
|
||||||
|
OPCODE_PUSHFL = 0x30,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -2694,6 +2778,9 @@ bool is_expr(Node *node)
|
|||||||
case NODE_VALUE_INT:
|
case NODE_VALUE_INT:
|
||||||
case NODE_VALUE_FLOAT:
|
case NODE_VALUE_FLOAT:
|
||||||
case NODE_VALUE_STR:
|
case NODE_VALUE_STR:
|
||||||
|
case NODE_VALUE_NONE:
|
||||||
|
case NODE_VALUE_TRUE:
|
||||||
|
case NODE_VALUE_FALSE:
|
||||||
case NODE_VALUE_VAR:
|
case NODE_VALUE_VAR:
|
||||||
case NODE_VALUE_SYSVAR:
|
case NODE_VALUE_SYSVAR:
|
||||||
case NODE_VALUE_HTML:
|
case NODE_VALUE_HTML:
|
||||||
@@ -3120,6 +3207,24 @@ void assemble_expr(Assembler *a, Node *node, int num_results)
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case NODE_VALUE_VAR:
|
||||||
{
|
{
|
||||||
String name = node->sval;
|
String name = node->sval;
|
||||||
@@ -3311,6 +3416,13 @@ void assemble_statement(Assembler *a, Node *node, bool pop_expr)
|
|||||||
{
|
{
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
|
|
||||||
|
case NODE_INCLUDE:
|
||||||
|
{
|
||||||
|
assert(node->include_root);
|
||||||
|
assemble_statement(a, node->include_root, pop_expr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case NODE_PRINT:
|
case NODE_PRINT:
|
||||||
{
|
{
|
||||||
append_u8(&a->out, OPCODE_GROUP);
|
append_u8(&a->out, OPCODE_GROUP);
|
||||||
@@ -3389,9 +3501,12 @@ void assemble_statement(Assembler *a, Node *node, bool pop_expr)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_BLOCK:
|
case NODE_BLOCK:
|
||||||
|
case NODE_GLOBAL_BLOCK:
|
||||||
{
|
{
|
||||||
|
if (node->type == NODE_BLOCK) {
|
||||||
int ret = push_scope(a, SCOPE_BLOCK);
|
int ret = push_scope(a, SCOPE_BLOCK);
|
||||||
if (ret < 0) return;
|
if (ret < 0) return;
|
||||||
|
}
|
||||||
|
|
||||||
Node *stmt = node->left;
|
Node *stmt = node->left;
|
||||||
while (stmt) {
|
while (stmt) {
|
||||||
@@ -3399,9 +3514,11 @@ void assemble_statement(Assembler *a, Node *node, bool pop_expr)
|
|||||||
stmt = stmt->next;
|
stmt = stmt->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = pop_scope(a);
|
if (node->type == NODE_BLOCK) {
|
||||||
|
int ret = pop_scope(a);
|
||||||
if (ret < 0) return;
|
if (ret < 0) return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_IFELSE:
|
case NODE_IFELSE:
|
||||||
@@ -3915,6 +4032,14 @@ char *print_instruction(char *p, char *data)
|
|||||||
printf("SYSCALL \"%.*s\"", (int) len, (char*) data + off);
|
printf("SYSCALL \"%.*s\"", (int) len, (char*) data + off);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPCODE_PUSHT:
|
||||||
|
printf("PUSHT");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_PUSHFL:
|
||||||
|
printf("PUSHFL");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
@@ -4745,6 +4870,18 @@ int step(WL_State *state)
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case OPCODE_PUSHV:
|
||||||
{
|
{
|
||||||
uint8_t idx = read_u8(state);
|
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 "eval.h"
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
#include "assemble.h"
|
#include "assemble.h"
|
||||||
#include "WL.h"
|
#include "compile.h"
|
||||||
#endif
|
#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)
|
int WL_streq(WL_String a, char *b, int blen)
|
||||||
{
|
{
|
||||||
if (b == NULL) b = "";
|
if (b == NULL) b = "";
|
||||||
@@ -5873,21 +6025,83 @@ int WL_streq(WL_String a, char *b, int blen)
|
|||||||
return 1;
|
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 = "";
|
WL_Compiler *compiler = alloc(arena, (int) sizeof(WL_Compiler), _Alignof(WL_Compiler));
|
||||||
if (len < 0) len = strlen(src);
|
if (compiler == NULL)
|
||||||
|
return NULL;
|
||||||
Node *root;
|
compiler->arena = arena;
|
||||||
ParseResult pres = parse((String) {src, len}, &arena, err, errmax);
|
compiler->num_files = 0;
|
||||||
if (pres.node == NULL)
|
compiler->waiting_file = (String) { NULL, 0 };
|
||||||
return -1;
|
return compiler;
|
||||||
root = pres.node;
|
}
|
||||||
|
|
||||||
AssembleResult ares = assemble(root, &arena, err, errmax);
|
void WL_Compiler_free(WL_Compiler *compiler)
|
||||||
if (ares.errlen)
|
{
|
||||||
return -1;
|
(void) compiler;
|
||||||
*program = ares.program;
|
// TODO
|
||||||
|
}
|
||||||
return 0;
|
|
||||||
|
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 };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
// This file was generated automatically. Do not modify directly!
|
// This file was generated automatically. Do not modify directly!
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// src/public.h
|
// src/compile.h
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef WL_PUBLIC_INCLUDED
|
#ifndef WL_PUBLIC_INCLUDED
|
||||||
@@ -45,10 +45,27 @@ typedef struct {
|
|||||||
int cur;
|
int cur;
|
||||||
} WL_Arena;
|
} WL_Arena;
|
||||||
|
|
||||||
int WL_compile (char *src, int len, WL_Arena arena, WL_Program *program, char *err, int errmax);
|
typedef struct WL_Compiler WL_Compiler;
|
||||||
WL_State *WL_State_init (WL_Arena *a, WL_Program p, char *err, int errmax);
|
|
||||||
|
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);
|
void WL_State_free (WL_State *state);
|
||||||
WL_Result WL_eval (WL_State *state);
|
WL_Result WL_eval (WL_State *state);
|
||||||
|
|
||||||
int WL_streq (WL_String a, char *b, int blen);
|
int WL_streq (WL_String a, char *b, int blen);
|
||||||
int WL_peeknone (WL_State *state, int off);
|
int WL_peeknone (WL_State *state, int off);
|
||||||
int WL_peekint (WL_State *state, int off, long long *x);
|
int WL_peekint (WL_State *state, int off, long long *x);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ header = Amalgamator()
|
|||||||
header.append_text("#ifndef WL_AMALGAMATION\n")
|
header.append_text("#ifndef WL_AMALGAMATION\n")
|
||||||
header.append_text("#define WL_AMALGAMATION\n")
|
header.append_text("#define WL_AMALGAMATION\n")
|
||||||
header.append_text(desc)
|
header.append_text(desc)
|
||||||
header.append_file("src/public.h")
|
header.append_file("src/compile.h")
|
||||||
header.append_text("#endif // WL_AMALGAMATION\n")
|
header.append_text("#endif // WL_AMALGAMATION\n")
|
||||||
header.save("WL.h")
|
header.save("WL.h")
|
||||||
|
|
||||||
@@ -49,5 +49,5 @@ source.append_file("src/value.h")
|
|||||||
source.append_file("src/value.c")
|
source.append_file("src/value.c")
|
||||||
source.append_file("src/eval.h")
|
source.append_file("src/eval.h")
|
||||||
source.append_file("src/eval.c")
|
source.append_file("src/eval.c")
|
||||||
source.append_file("src/public.c")
|
source.append_file("src/compile.c")
|
||||||
source.save("WL.c")
|
source.save("WL.c")
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
let ugu = 78
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "WL.h"
|
#include "WL.h"
|
||||||
@@ -12,9 +14,31 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
char *file = argv[1];
|
char *file = argv[1];
|
||||||
|
|
||||||
FILE *f = fopen(file, "rb");
|
char err[1<<9];
|
||||||
if (f == NULL)
|
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;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
long file_size = ftell(f);
|
long file_size = ftell(f);
|
||||||
@@ -25,16 +49,29 @@ int main(int argc, char **argv)
|
|||||||
fread(file_data, 1, file_size, f);
|
fread(file_data, 1, file_size, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
char err[1<<9];
|
result = WL_compile(compiler, path, (WL_String) { file_data, file_size });
|
||||||
char *mem = malloc(1<<20);
|
|
||||||
WL_Arena a = { mem, 1<<20, 0 };
|
|
||||||
|
|
||||||
WL_Program program;
|
free(file_data);
|
||||||
int ret = WL_compile(file_data, file_size, a, &program, err, (int) sizeof(err));
|
|
||||||
if (ret < 0) {
|
if (result.type == WL_COMPILE_RESULT_ERROR) {
|
||||||
printf("%s\n", err);
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
WL_Program program = result.program;
|
||||||
|
|
||||||
WL_State *state = WL_State_init(&a, program, err, (int) sizeof(err));
|
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);
|
WL_State_free(state);
|
||||||
free(file_data);
|
|
||||||
free(mem);
|
free(mem);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
include "example.wl"
|
||||||
|
|
||||||
|
ugu
|
||||||
|
|
||||||
let posts = [
|
let posts = [
|
||||||
{
|
{
|
||||||
author: "UserA",
|
author: "UserA",
|
||||||
|
|||||||
+42
-1
@@ -332,6 +332,9 @@ bool is_expr(Node *node)
|
|||||||
case NODE_VALUE_INT:
|
case NODE_VALUE_INT:
|
||||||
case NODE_VALUE_FLOAT:
|
case NODE_VALUE_FLOAT:
|
||||||
case NODE_VALUE_STR:
|
case NODE_VALUE_STR:
|
||||||
|
case NODE_VALUE_NONE:
|
||||||
|
case NODE_VALUE_TRUE:
|
||||||
|
case NODE_VALUE_FALSE:
|
||||||
case NODE_VALUE_VAR:
|
case NODE_VALUE_VAR:
|
||||||
case NODE_VALUE_SYSVAR:
|
case NODE_VALUE_SYSVAR:
|
||||||
case NODE_VALUE_HTML:
|
case NODE_VALUE_HTML:
|
||||||
@@ -758,6 +761,24 @@ void assemble_expr(Assembler *a, Node *node, int num_results)
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case NODE_VALUE_VAR:
|
||||||
{
|
{
|
||||||
String name = node->sval;
|
String name = node->sval;
|
||||||
@@ -949,6 +970,13 @@ void assemble_statement(Assembler *a, Node *node, bool pop_expr)
|
|||||||
{
|
{
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
|
|
||||||
|
case NODE_INCLUDE:
|
||||||
|
{
|
||||||
|
assert(node->include_root);
|
||||||
|
assemble_statement(a, node->include_root, pop_expr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case NODE_PRINT:
|
case NODE_PRINT:
|
||||||
{
|
{
|
||||||
append_u8(&a->out, OPCODE_GROUP);
|
append_u8(&a->out, OPCODE_GROUP);
|
||||||
@@ -1027,9 +1055,12 @@ void assemble_statement(Assembler *a, Node *node, bool pop_expr)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_BLOCK:
|
case NODE_BLOCK:
|
||||||
|
case NODE_GLOBAL_BLOCK:
|
||||||
{
|
{
|
||||||
|
if (node->type == NODE_BLOCK) {
|
||||||
int ret = push_scope(a, SCOPE_BLOCK);
|
int ret = push_scope(a, SCOPE_BLOCK);
|
||||||
if (ret < 0) return;
|
if (ret < 0) return;
|
||||||
|
}
|
||||||
|
|
||||||
Node *stmt = node->left;
|
Node *stmt = node->left;
|
||||||
while (stmt) {
|
while (stmt) {
|
||||||
@@ -1037,9 +1068,11 @@ void assemble_statement(Assembler *a, Node *node, bool pop_expr)
|
|||||||
stmt = stmt->next;
|
stmt = stmt->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = pop_scope(a);
|
if (node->type == NODE_BLOCK) {
|
||||||
|
int ret = pop_scope(a);
|
||||||
if (ret < 0) return;
|
if (ret < 0) return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_IFELSE:
|
case NODE_IFELSE:
|
||||||
@@ -1553,6 +1586,14 @@ char *print_instruction(char *p, char *data)
|
|||||||
printf("SYSCALL \"%.*s\"", (int) len, (char*) data + off);
|
printf("SYSCALL \"%.*s\"", (int) len, (char*) data + off);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPCODE_PUSHT:
|
||||||
|
printf("PUSHT");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_PUSHFL:
|
||||||
|
printf("PUSHFL");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ enum {
|
|||||||
OPCODE_SYSVAR = 0x2C,
|
OPCODE_SYSVAR = 0x2C,
|
||||||
OPCODE_SYSCALL = 0x2D,
|
OPCODE_SYSCALL = 0x2D,
|
||||||
OPCODE_FOR = 0x2E,
|
OPCODE_FOR = 0x2E,
|
||||||
|
OPCODE_PUSHT = 0x2F,
|
||||||
|
OPCODE_PUSHFL = 0x30,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -87,3 +87,12 @@ bool grow_alloc(WL_Arena *a, char *p, int new_len)
|
|||||||
a->cur = new_cur;
|
a->cur = new_cur;
|
||||||
return true;
|
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 };
|
||||||
|
}
|
||||||
@@ -35,6 +35,7 @@ int hex_digit_to_int(char c);
|
|||||||
|
|
||||||
bool streq(String a, String b);
|
bool streq(String a, String b);
|
||||||
bool streqcase(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);
|
void *alloc(WL_Arena *a, int len, int align);
|
||||||
bool grow_alloc(WL_Arena *a, char *p, int new_len);
|
bool grow_alloc(WL_Arena *a, char *p, int new_len);
|
||||||
|
|||||||
+118
@@ -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 };
|
||||||
|
}
|
||||||
@@ -36,10 +36,27 @@ typedef struct {
|
|||||||
int cur;
|
int cur;
|
||||||
} WL_Arena;
|
} WL_Arena;
|
||||||
|
|
||||||
int WL_compile (char *src, int len, WL_Arena arena, WL_Program *program, char *err, int errmax);
|
typedef struct WL_Compiler WL_Compiler;
|
||||||
WL_State *WL_State_init (WL_Arena *a, WL_Program p, char *err, int errmax);
|
|
||||||
|
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);
|
void WL_State_free (WL_State *state);
|
||||||
WL_Result WL_eval (WL_State *state);
|
WL_Result WL_eval (WL_State *state);
|
||||||
|
|
||||||
int WL_streq (WL_String a, char *b, int blen);
|
int WL_streq (WL_String a, char *b, int blen);
|
||||||
int WL_peeknone (WL_State *state, int off);
|
int WL_peeknone (WL_State *state, int off);
|
||||||
int WL_peekint (WL_State *state, int off, long long *x);
|
int WL_peekint (WL_State *state, int off, long long *x);
|
||||||
+12
@@ -246,6 +246,18 @@ int step(WL_State *state)
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case OPCODE_PUSHV:
|
||||||
{
|
{
|
||||||
uint8_t idx = read_u8(state);
|
uint8_t idx = read_u8(state);
|
||||||
|
|||||||
+128
-65
@@ -21,6 +21,10 @@ typedef enum {
|
|||||||
TOKEN_KWORD_FUN,
|
TOKEN_KWORD_FUN,
|
||||||
TOKEN_KWORD_LET,
|
TOKEN_KWORD_LET,
|
||||||
TOKEN_KWORD_PRINT,
|
TOKEN_KWORD_PRINT,
|
||||||
|
TOKEN_KWORD_NONE,
|
||||||
|
TOKEN_KWORD_TRUE,
|
||||||
|
TOKEN_KWORD_FALSE,
|
||||||
|
TOKEN_KWORD_INCLUDE,
|
||||||
TOKEN_VALUE_FLOAT,
|
TOKEN_VALUE_FLOAT,
|
||||||
TOKEN_VALUE_INT,
|
TOKEN_VALUE_INT,
|
||||||
TOKEN_VALUE_STR,
|
TOKEN_VALUE_STR,
|
||||||
@@ -59,10 +63,12 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Scanner s;
|
Scanner s;
|
||||||
WL_Arena *a;
|
WL_Arena* a;
|
||||||
char *errbuf;
|
char* errbuf;
|
||||||
int errmax;
|
int errmax;
|
||||||
int errlen;
|
int errlen;
|
||||||
|
Node* include_head;
|
||||||
|
Node** include_tail;
|
||||||
} Parser;
|
} Parser;
|
||||||
|
|
||||||
bool consume_str(Scanner *s, String x)
|
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_FUN: return S("fun");
|
||||||
case TOKEN_KWORD_LET: return S("let");
|
case TOKEN_KWORD_LET: return S("let");
|
||||||
case TOKEN_KWORD_PRINT: return S("print");
|
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:
|
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("fun"))) return (Token) { .type=TOKEN_KWORD_FUN };
|
||||||
if (streq(kword, S("let"))) return (Token) { .type=TOKEN_KWORD_LET };
|
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("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 };
|
return (Token) { .type=TOKEN_IDENT, .sval=kword };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,8 +448,6 @@ Node *parse_html(Parser *p)
|
|||||||
{
|
{
|
||||||
// NOTE: The first < was already consumed
|
// NOTE: The first < was already consumed
|
||||||
|
|
||||||
int node_offset = p->s.cur-1;
|
|
||||||
|
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
if (t.type != TOKEN_IDENT) {
|
if (t.type != TOKEN_IDENT) {
|
||||||
char buf[1<<8];
|
char buf[1<<8];
|
||||||
@@ -444,8 +463,6 @@ Node *parse_html(Parser *p)
|
|||||||
bool no_body = false;
|
bool no_body = false;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
int param_offset = p->s.cur;
|
|
||||||
|
|
||||||
String attr_name;
|
String attr_name;
|
||||||
Node *attr_value;
|
Node *attr_value;
|
||||||
|
|
||||||
@@ -488,7 +505,6 @@ Node *parse_html(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
child->type = NODE_HTML_PARAM;
|
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_name = attr_name;
|
||||||
child->attr_value = attr_value;
|
child->attr_value = attr_value;
|
||||||
|
|
||||||
@@ -529,7 +545,6 @@ Node *parse_html(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
child->type = NODE_VALUE_STR;
|
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 };
|
child->sval = (String) { p->s.src + off, p->s.cur - off };
|
||||||
|
|
||||||
*tail = child;
|
*tail = child;
|
||||||
@@ -588,7 +603,6 @@ Node *parse_html(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_VALUE_HTML;
|
parent->type = NODE_VALUE_HTML;
|
||||||
parent->text = (String) { p->s.src + node_offset, p->s.cur - node_offset };
|
|
||||||
parent->tagname = tagname;
|
parent->tagname = tagname;
|
||||||
parent->params = param_head;
|
parent->params = param_head;
|
||||||
parent->child = head;
|
parent->child = head;
|
||||||
@@ -601,8 +615,6 @@ Node *parse_array(Parser *p)
|
|||||||
{
|
{
|
||||||
// Left bracket already consumed
|
// Left bracket already consumed
|
||||||
|
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Node *head;
|
Node *head;
|
||||||
Node **tail = &head;
|
Node **tail = &head;
|
||||||
|
|
||||||
@@ -642,7 +654,6 @@ Node *parse_array(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_VALUE_ARRAY;
|
parent->type = NODE_VALUE_ARRAY;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->child = head;
|
parent->child = head;
|
||||||
|
|
||||||
return parent;
|
return parent;
|
||||||
@@ -652,8 +663,6 @@ Node *parse_map(Parser *p)
|
|||||||
{
|
{
|
||||||
// Left bracket already consumed
|
// Left bracket already consumed
|
||||||
|
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Node *head;
|
Node *head;
|
||||||
Node **tail = &head;
|
Node **tail = &head;
|
||||||
|
|
||||||
@@ -676,7 +685,6 @@ Node *parse_map(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
key->type = NODE_VALUE_STR;
|
key->type = NODE_VALUE_STR;
|
||||||
key->text = t.sval;
|
|
||||||
key->sval = t.sval;
|
key->sval = t.sval;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -722,7 +730,6 @@ Node *parse_map(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_VALUE_MAP;
|
parent->type = NODE_VALUE_MAP;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->child = head;
|
parent->child = head;
|
||||||
|
|
||||||
return parent;
|
return parent;
|
||||||
@@ -776,8 +783,6 @@ bool right_associative(Token t)
|
|||||||
|
|
||||||
Node *parse_atom(Parser *p)
|
Node *parse_atom(Parser *p)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
|
|
||||||
Node *ret;
|
Node *ret;
|
||||||
@@ -793,7 +798,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_OPER_POS;
|
parent->type = NODE_OPER_POS;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = child;
|
parent->left = child;
|
||||||
|
|
||||||
ret = parent;
|
ret = parent;
|
||||||
@@ -811,7 +815,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_OPER_NEG;
|
parent->type = NODE_OPER_NEG;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = child;
|
parent->left = child;
|
||||||
|
|
||||||
ret = parent;
|
ret = parent;
|
||||||
@@ -825,7 +828,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
node->type = NODE_VALUE_VAR;
|
node->type = NODE_VALUE_VAR;
|
||||||
node->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
node->sval = t.sval;
|
node->sval = t.sval;
|
||||||
|
|
||||||
ret = node;
|
ret = node;
|
||||||
@@ -839,7 +841,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
node->type = NODE_VALUE_INT;
|
node->type = NODE_VALUE_INT;
|
||||||
node->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
node->ival = t.uval;
|
node->ival = t.uval;
|
||||||
|
|
||||||
ret = node;
|
ret = node;
|
||||||
@@ -853,7 +854,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
node->type = NODE_VALUE_FLOAT;
|
node->type = NODE_VALUE_FLOAT;
|
||||||
node->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
node->dval = t.dval;
|
node->dval = t.dval;
|
||||||
|
|
||||||
ret = node;
|
ret = node;
|
||||||
@@ -867,7 +867,44 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
node->type = NODE_VALUE_STR;
|
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;
|
node->sval = t.sval;
|
||||||
|
|
||||||
ret = node;
|
ret = node;
|
||||||
@@ -901,7 +938,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_NESTED;
|
parent->type = NODE_NESTED;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = node;
|
parent->left = node;
|
||||||
|
|
||||||
ret = parent;
|
ret = parent;
|
||||||
@@ -941,7 +977,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
node->type = NODE_VALUE_SYSVAR;
|
node->type = NODE_VALUE_SYSVAR;
|
||||||
node->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
node->sval = t.sval;
|
node->sval = t.sval;
|
||||||
|
|
||||||
ret = node;
|
ret = node;
|
||||||
@@ -973,7 +1008,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
child->type = NODE_VALUE_STR;
|
child->type = NODE_VALUE_STR;
|
||||||
child->text = t.sval;
|
|
||||||
child->sval = t.sval;
|
child->sval = t.sval;
|
||||||
|
|
||||||
Node *parent = alloc_node(p);
|
Node *parent = alloc_node(p);
|
||||||
@@ -981,7 +1015,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_SELECT;
|
parent->type = NODE_SELECT;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = ret;
|
parent->left = ret;
|
||||||
parent->right = child;
|
parent->right = child;
|
||||||
|
|
||||||
@@ -1004,7 +1037,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_SELECT;
|
parent->type = NODE_SELECT;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = ret;
|
parent->left = ret;
|
||||||
parent->right = child;
|
parent->right = child;
|
||||||
|
|
||||||
@@ -1048,7 +1080,6 @@ Node *parse_atom(Parser *p)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_FUNC_CALL;
|
parent->type = NODE_FUNC_CALL;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = ret;
|
parent->left = ret;
|
||||||
parent->right = arg_head;
|
parent->right = arg_head;
|
||||||
|
|
||||||
@@ -1063,7 +1094,7 @@ Node *parse_atom(Parser *p)
|
|||||||
return ret;
|
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 (;;) {
|
for (;;) {
|
||||||
|
|
||||||
@@ -1074,8 +1105,6 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int start, int flags
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int right_start = p->s.cur;
|
|
||||||
|
|
||||||
Node *right = parse_atom(p);
|
Node *right = parse_atom(p);
|
||||||
if (right == NULL)
|
if (right == NULL)
|
||||||
return 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)))
|
if (p2 <= p1 && (p1 != p2 || !right_associative(t2)))
|
||||||
break;
|
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)
|
if (right == NULL)
|
||||||
return 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)
|
if (parent == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = left;
|
parent->left = left;
|
||||||
parent->right = right;
|
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)
|
Node *parse_expr(Parser *p, int flags)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Node *left = parse_atom(p);
|
Node *left = parse_atom(p);
|
||||||
if (left == NULL)
|
if (left == NULL)
|
||||||
return 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)
|
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)
|
Node *parse_ifelse_stmt(Parser *p, int opflags)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
if (t.type != TOKEN_KWORD_IF) {
|
if (t.type != TOKEN_KWORD_IF) {
|
||||||
parser_report(p, "Missing 'if' keyword before if statement");
|
parser_report(p, "Missing 'if' keyword before if statement");
|
||||||
@@ -1192,7 +1216,6 @@ Node *parse_ifelse_stmt(Parser *p, int opflags)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_IFELSE;
|
parent->type = NODE_IFELSE;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = if_stmt;
|
parent->left = if_stmt;
|
||||||
parent->right = else_stmt;
|
parent->right = else_stmt;
|
||||||
parent->cond = cond;
|
parent->cond = cond;
|
||||||
@@ -1202,8 +1225,6 @@ Node *parse_ifelse_stmt(Parser *p, int opflags)
|
|||||||
|
|
||||||
Node *parse_for_stmt(Parser *p, int opflags)
|
Node *parse_for_stmt(Parser *p, int opflags)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
if (t.type != TOKEN_KWORD_FOR) {
|
if (t.type != TOKEN_KWORD_FOR) {
|
||||||
parser_report(p, "Missing 'for' keyword at the start of a for statement");
|
parser_report(p, "Missing 'for' keyword at the start of a for statement");
|
||||||
@@ -1256,7 +1277,6 @@ Node *parse_for_stmt(Parser *p, int opflags)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_FOR;
|
parent->type = NODE_FOR;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = body;
|
parent->left = body;
|
||||||
parent->for_var1 = var1;
|
parent->for_var1 = var1;
|
||||||
parent->for_var2 = var2;
|
parent->for_var2 = var2;
|
||||||
@@ -1267,8 +1287,6 @@ Node *parse_for_stmt(Parser *p, int opflags)
|
|||||||
|
|
||||||
Node *parse_while_stmt(Parser *p, int opflags)
|
Node *parse_while_stmt(Parser *p, int opflags)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
if (t.type != TOKEN_KWORD_WHILE) {
|
if (t.type != TOKEN_KWORD_WHILE) {
|
||||||
parser_report(p, "Missing keyword 'while' at the start of a while statement");
|
parser_report(p, "Missing keyword 'while' at the start of a while statement");
|
||||||
@@ -1294,7 +1312,6 @@ Node *parse_while_stmt(Parser *p, int opflags)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_WHILE;
|
parent->type = NODE_WHILE;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = stmt;
|
parent->left = stmt;
|
||||||
parent->cond = cond;
|
parent->cond = cond;
|
||||||
|
|
||||||
@@ -1303,8 +1320,6 @@ Node *parse_while_stmt(Parser *p, int opflags)
|
|||||||
|
|
||||||
Node *parse_block_stmt(Parser *p, bool curly)
|
Node *parse_block_stmt(Parser *p, bool curly)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
if (curly) {
|
if (curly) {
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
if (t.type != TOKEN_CURLY_OPEN) {
|
if (t.type != TOKEN_CURLY_OPEN) {
|
||||||
@@ -1344,7 +1359,6 @@ Node *parse_block_stmt(Parser *p, bool curly)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_BLOCK;
|
parent->type = NODE_BLOCK;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = head;
|
parent->left = head;
|
||||||
|
|
||||||
return parent;
|
return parent;
|
||||||
@@ -1352,8 +1366,6 @@ Node *parse_block_stmt(Parser *p, bool curly)
|
|||||||
|
|
||||||
Node *parse_func_decl(Parser *p, int opflags)
|
Node *parse_func_decl(Parser *p, int opflags)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
if (t.type != TOKEN_KWORD_FUN) {
|
if (t.type != TOKEN_KWORD_FUN) {
|
||||||
parser_report(p, "Missing keyword 'fun' at the start of a function declaration");
|
parser_report(p, "Missing keyword 'fun' at the start of a function declaration");
|
||||||
@@ -1383,8 +1395,6 @@ Node *parse_func_decl(Parser *p, int opflags)
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
int arg_start = p->s.cur;
|
|
||||||
|
|
||||||
t = next_token(p);
|
t = next_token(p);
|
||||||
if (t.type != TOKEN_IDENT) {
|
if (t.type != TOKEN_IDENT) {
|
||||||
parser_report(p, "Missing argument name in function declaration");
|
parser_report(p, "Missing argument name in function declaration");
|
||||||
@@ -1397,7 +1407,6 @@ Node *parse_func_decl(Parser *p, int opflags)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
node->type = NODE_FUNC_ARG;
|
node->type = NODE_FUNC_ARG;
|
||||||
node->text = (String) { p->s.src + arg_start, p->s.cur - arg_start };
|
|
||||||
node->sval = argname;
|
node->sval = argname;
|
||||||
|
|
||||||
*arg_tail = node;
|
*arg_tail = node;
|
||||||
@@ -1427,7 +1436,6 @@ Node *parse_func_decl(Parser *p, int opflags)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_FUNC_DECL;
|
parent->type = NODE_FUNC_DECL;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->func_name = name;
|
parent->func_name = name;
|
||||||
parent->func_args = arg_head;
|
parent->func_args = arg_head;
|
||||||
parent->func_body = body;
|
parent->func_body = body;
|
||||||
@@ -1437,8 +1445,6 @@ Node *parse_func_decl(Parser *p, int opflags)
|
|||||||
|
|
||||||
Node *parse_var_decl(Parser *p, int opflags)
|
Node *parse_var_decl(Parser *p, int opflags)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
if (t.type != TOKEN_KWORD_LET) {
|
if (t.type != TOKEN_KWORD_LET) {
|
||||||
parser_report(p, "Missing keyword 'let' at the start of a variable declaration");
|
parser_report(p, "Missing keyword 'let' at the start of a variable declaration");
|
||||||
@@ -1472,7 +1478,6 @@ Node *parse_var_decl(Parser *p, int opflags)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_VAR_DECL;
|
parent->type = NODE_VAR_DECL;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->var_name = name;
|
parent->var_name = name;
|
||||||
parent->var_value = value;
|
parent->var_value = value;
|
||||||
|
|
||||||
@@ -1481,8 +1486,6 @@ Node *parse_var_decl(Parser *p, int opflags)
|
|||||||
|
|
||||||
Node *parse_print_stmt(Parser *p, int opflags)
|
Node *parse_print_stmt(Parser *p, int opflags)
|
||||||
{
|
{
|
||||||
int start = p->s.cur;
|
|
||||||
|
|
||||||
Token t = next_token(p);
|
Token t = next_token(p);
|
||||||
if (t.type != TOKEN_KWORD_PRINT) {
|
if (t.type != TOKEN_KWORD_PRINT) {
|
||||||
parser_report(p, "Missing keyword 'print' at the start of a print statement");
|
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;
|
return NULL;
|
||||||
|
|
||||||
parent->type = NODE_PRINT;
|
parent->type = NODE_PRINT;
|
||||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
|
||||||
parent->left = arg;
|
parent->left = arg;
|
||||||
|
|
||||||
return parent;
|
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)
|
Node *parse_stmt(Parser *p, int opflags)
|
||||||
{
|
{
|
||||||
Scanner saved = p->s;
|
Scanner saved = p->s;
|
||||||
@@ -1512,6 +1543,9 @@ Node *parse_stmt(Parser *p, int opflags)
|
|||||||
|
|
||||||
switch (t.type) {
|
switch (t.type) {
|
||||||
|
|
||||||
|
case TOKEN_KWORD_INCLUDE:
|
||||||
|
return parse_include_stmt(p);
|
||||||
|
|
||||||
case TOKEN_KWORD_PRINT:
|
case TOKEN_KWORD_PRINT:
|
||||||
return parse_print_stmt(p, opflags);
|
return parse_print_stmt(p, opflags);
|
||||||
|
|
||||||
@@ -1544,6 +1578,18 @@ void print_node(Node *node)
|
|||||||
{
|
{
|
||||||
switch (node->type) {
|
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:
|
case NODE_NESTED:
|
||||||
{
|
{
|
||||||
printf("(");
|
printf("(");
|
||||||
@@ -1853,6 +1899,18 @@ void print_node(Node *node)
|
|||||||
//printf(";");
|
//printf(";");
|
||||||
}
|
}
|
||||||
break;
|
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,
|
.errlen=0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
p.include_tail = &p.include_head;
|
||||||
|
|
||||||
Node *node = parse_block_stmt(&p, false);
|
Node *node = parse_block_stmt(&p, false);
|
||||||
|
|
||||||
if (node == NULL)
|
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
@@ -13,9 +13,11 @@ typedef enum {
|
|||||||
NODE_VAR_DECL,
|
NODE_VAR_DECL,
|
||||||
NODE_PRINT,
|
NODE_PRINT,
|
||||||
NODE_BLOCK,
|
NODE_BLOCK,
|
||||||
|
NODE_GLOBAL_BLOCK,
|
||||||
NODE_IFELSE,
|
NODE_IFELSE,
|
||||||
NODE_FOR,
|
NODE_FOR,
|
||||||
NODE_WHILE,
|
NODE_WHILE,
|
||||||
|
NODE_INCLUDE,
|
||||||
NODE_SELECT,
|
NODE_SELECT,
|
||||||
NODE_NESTED,
|
NODE_NESTED,
|
||||||
NODE_OPER_POS,
|
NODE_OPER_POS,
|
||||||
@@ -33,6 +35,9 @@ typedef enum {
|
|||||||
NODE_VALUE_INT,
|
NODE_VALUE_INT,
|
||||||
NODE_VALUE_FLOAT,
|
NODE_VALUE_FLOAT,
|
||||||
NODE_VALUE_STR,
|
NODE_VALUE_STR,
|
||||||
|
NODE_VALUE_NONE,
|
||||||
|
NODE_VALUE_TRUE,
|
||||||
|
NODE_VALUE_FALSE,
|
||||||
NODE_VALUE_VAR,
|
NODE_VALUE_VAR,
|
||||||
NODE_VALUE_SYSVAR,
|
NODE_VALUE_SYSVAR,
|
||||||
NODE_VALUE_HTML,
|
NODE_VALUE_HTML,
|
||||||
@@ -45,7 +50,6 @@ typedef struct Node Node;
|
|||||||
struct Node {
|
struct Node {
|
||||||
NodeType type;
|
NodeType type;
|
||||||
Node *next;
|
Node *next;
|
||||||
String text;
|
|
||||||
|
|
||||||
Node *key;
|
Node *key;
|
||||||
|
|
||||||
@@ -76,10 +80,15 @@ struct Node {
|
|||||||
|
|
||||||
String var_name;
|
String var_name;
|
||||||
Node *var_value;
|
Node *var_value;
|
||||||
|
|
||||||
|
String include_path;
|
||||||
|
Node* include_next;
|
||||||
|
Node* include_root;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Node *node;
|
Node *node;
|
||||||
|
Node *includes;
|
||||||
int errlen;
|
int errlen;
|
||||||
} ParseResult;
|
} ParseResult;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user