More progress on assembler and evaluator
This commit is contained in:
@@ -1,6 +1,4 @@
|
|||||||
|
|
||||||
func(1, 3, 5);
|
|
||||||
|
|
||||||
title = "My Website";
|
title = "My Website";
|
||||||
|
|
||||||
posts = [
|
posts = [
|
||||||
@@ -27,22 +25,21 @@ fun render_comment(c)
|
|||||||
<a>$c.author; ($c.date;)</a>
|
<a>$c.author; ($c.date;)</a>
|
||||||
<p>$c.content;</p>
|
<p>$c.content;</p>
|
||||||
<div class="comment-children">
|
<div class="comment-children">
|
||||||
$for child in c.children:
|
$ for child in c.children:
|
||||||
render_comment(child);
|
render_comment(child);
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<html>
|
export <html>
|
||||||
<head>
|
<head>
|
||||||
<title>$(title);</title>
|
<title>$title;</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
$for post in posts: {
|
$ for post in posts: {
|
||||||
<div class="post">
|
<div class="post">
|
||||||
<a>$post.title; ($post.date;)</a>
|
<a>$post.title; ($post.date;)</a>
|
||||||
$for comment in post.comments: {
|
$ for comment in post.comments:
|
||||||
render_comment(comment);
|
render_comment(comment);
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+406
-86
@@ -2,6 +2,19 @@
|
|||||||
#include "assemble.h"
|
#include "assemble.h"
|
||||||
|
|
||||||
#define MAX_SCOPES 32
|
#define MAX_SCOPES 32
|
||||||
|
#define MAX_VARS 1024
|
||||||
|
#define MAX_STRING_LITERALS 1024
|
||||||
|
|
||||||
|
typedef struct FunctionCall FunctionCall;
|
||||||
|
struct FunctionCall {
|
||||||
|
FunctionCall *next;
|
||||||
|
String name;
|
||||||
|
int off;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
String name;
|
||||||
|
} Variable;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SCOPE_FUNC,
|
SCOPE_FUNC,
|
||||||
@@ -13,14 +26,122 @@ typedef enum {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ScopeType type;
|
ScopeType type;
|
||||||
|
int var_base;
|
||||||
// TODO
|
// TODO
|
||||||
|
FunctionCall *calls;
|
||||||
} Scope;
|
} Scope;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int depth;
|
char *ptr;
|
||||||
|
int len;
|
||||||
|
int cap;
|
||||||
|
b32 err;
|
||||||
|
} OutputBuffer;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
Arena *a;
|
||||||
|
|
||||||
|
OutputBuffer out;
|
||||||
|
|
||||||
|
int num_vars;
|
||||||
|
Variable vars[MAX_VARS];
|
||||||
|
|
||||||
|
int num_scopes;
|
||||||
Scope scopes[MAX_SCOPES];
|
Scope scopes[MAX_SCOPES];
|
||||||
|
|
||||||
|
int strings_len;
|
||||||
|
int strings_cap;
|
||||||
|
char *strings;
|
||||||
|
|
||||||
} Assembler;
|
} Assembler;
|
||||||
|
|
||||||
|
int add_string_literal(Assembler *a, String str)
|
||||||
|
{
|
||||||
|
if (a->strings_cap - a->strings_len < str.len) {
|
||||||
|
int c = MAX(2 * a->strings_cap, a->strings_len + str.len);
|
||||||
|
char *p = malloc(c);
|
||||||
|
if (p == NULL) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
if (a->strings_cap) {
|
||||||
|
memcpy(p, a->strings, a->strings_len);
|
||||||
|
free(a->strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
a->strings = p;
|
||||||
|
a->strings_cap = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int off = a->strings_len;
|
||||||
|
memcpy(a->strings + a->strings_len, str.ptr, str.len);
|
||||||
|
a->strings_len += str.len;
|
||||||
|
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
|
void append_mem(OutputBuffer *out, void *ptr, int len)
|
||||||
|
{
|
||||||
|
if (out->err)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (out->cap - out->len < len) {
|
||||||
|
|
||||||
|
int new_cap = MAX(512, 2 * out->cap);
|
||||||
|
char *new_ptr = malloc(new_cap);
|
||||||
|
if (new_ptr == NULL) {
|
||||||
|
out->err = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out->cap) {
|
||||||
|
memcpy(new_ptr, out->ptr, out->len);
|
||||||
|
free(out->ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
out->ptr = new_ptr;
|
||||||
|
out->cap = new_cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(out->ptr + out->len, ptr, len);
|
||||||
|
out->len += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void patch_mem(OutputBuffer *out, int off, void *ptr, int len)
|
||||||
|
{
|
||||||
|
if (out->err)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memcpy(out->ptr + off, ptr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int append_u8(OutputBuffer *out, uint8_t x)
|
||||||
|
{
|
||||||
|
int off = out->len;
|
||||||
|
append_mem(out, &x, (int) sizeof(x));
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
|
int append_u32(OutputBuffer *out, uint32_t x)
|
||||||
|
{
|
||||||
|
int off = out->len;
|
||||||
|
append_mem(out, &x, (int) sizeof(x));
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
|
int append_f64(OutputBuffer *out, double x)
|
||||||
|
{
|
||||||
|
int off = out->len;
|
||||||
|
append_mem(out, &x, (int) sizeof(x));
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
|
void patch_with_current_offset(OutputBuffer *out, int off)
|
||||||
|
{
|
||||||
|
uint32_t x = out->len;
|
||||||
|
patch_mem(out, off, &x, (int) sizeof(x));
|
||||||
|
}
|
||||||
|
|
||||||
int count_nodes(Node *head)
|
int count_nodes(Node *head)
|
||||||
{
|
{
|
||||||
int n = 0;
|
int n = 0;
|
||||||
@@ -32,41 +153,85 @@ int count_nodes(Node *head)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void assemble_node(Node *node)
|
int declare_var(Assembler *a, String name)
|
||||||
|
{
|
||||||
|
if (a->num_vars == MAX_VARS)
|
||||||
|
return -1;
|
||||||
|
// TODO: check if the variable exists already
|
||||||
|
int idx = a->num_vars++;
|
||||||
|
a->vars[idx] = (Variable) { name };
|
||||||
|
return idx - a->scopes[a->num_scopes-1].var_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
void assemble_html_node_inner(Assembler *a, Node *node, OutputBuffer *tmp)
|
||||||
|
{
|
||||||
|
append_u8(tmp, '<');
|
||||||
|
append_mem(tmp, node->tagname.ptr, node->tagname.len);
|
||||||
|
|
||||||
|
Node *attr = node->params;
|
||||||
|
while (attr) {
|
||||||
|
append_u8(tmp, ' ');
|
||||||
|
append_mem(tmp, attr->attr_name.ptr, attr->attr_name.len);
|
||||||
|
if (attr->attr_value) {
|
||||||
|
append_u8(tmp, '=');
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
attr = attr->next;
|
||||||
|
}
|
||||||
|
append_u8(tmp, '>');
|
||||||
|
|
||||||
|
Node *child = node->child;
|
||||||
|
while (child) {
|
||||||
|
// TODO
|
||||||
|
child = child->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
append_u8(tmp, '<');
|
||||||
|
append_u8(tmp, '/');
|
||||||
|
append_mem(tmp, node->tagname.ptr, node->tagname.len);
|
||||||
|
append_u8(tmp, '>');
|
||||||
|
}
|
||||||
|
|
||||||
|
void assemble_html_node(Assembler *a, Node *node)
|
||||||
|
{
|
||||||
|
OutputBuffer tmp;
|
||||||
|
assemble_html_node_inner(a, node, &tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void assemble_node(Assembler *a, Node *node)
|
||||||
{
|
{
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
|
|
||||||
case NODE_FUNC_DECL:
|
case NODE_FUNC_DECL:
|
||||||
{
|
{
|
||||||
append_u8 (out, OPCODE_JUMP);
|
append_u8(&a->out, OPCODE_JUMP);
|
||||||
append_u64(out, xxx);
|
int p1 = append_u32(&a->out, 0);
|
||||||
|
|
||||||
|
// TODO: resolve references
|
||||||
|
|
||||||
int arg_count = count_nodes(node->func_args);
|
int arg_count = count_nodes(node->func_args);
|
||||||
|
|
||||||
Node *preallocated[32];
|
Node *args[32];
|
||||||
Node *args = preallocated;
|
if (arg_count > COUNT(args)) {
|
||||||
if (arg_count > COUNT(preallocated)) {
|
|
||||||
args = malloc(arg_count * sizeof(Node*));
|
|
||||||
if (args == NULL) {
|
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = arg_count-1; i >= 0; i--) {
|
for (int i = arg_count-1; i >= 0; i--) {
|
||||||
append_u8 (out, OPCODE_ASS);
|
int idx = declare_var(a, args[i]->sval);
|
||||||
append_u64(out, xxx);
|
if (idx < 0) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
append_u8(&a->out, OPCODE_SETV);
|
||||||
|
append_u8(&a->out, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_expr(node->func_body)) {
|
if (is_expr(node->func_body)) {
|
||||||
assemble_node(node->func_body);
|
assemble_node(a, node->func_body);
|
||||||
append_u8(out, OPCODE_RET);
|
append_u8(&a->out, OPCODE_RET);
|
||||||
} else
|
} else
|
||||||
assemble_node(node->func_body);
|
assemble_node(a, node->func_body);
|
||||||
|
|
||||||
append_u8(out, OPCODE_NOPE);
|
patch_with_current_offset(&a->out, p1);
|
||||||
|
|
||||||
if (args != preallocated)
|
|
||||||
free(args);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -78,19 +243,50 @@ void assemble_node(Node *node)
|
|||||||
int arg_count = 0;
|
int arg_count = 0;
|
||||||
Node *arg = args;
|
Node *arg = args;
|
||||||
while (arg) {
|
while (arg) {
|
||||||
assemble_node(arg);
|
assemble_node(a, arg);
|
||||||
arg_count++;
|
arg_count++;
|
||||||
arg = arg->next;
|
arg = arg->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
assemble_node(arg);
|
|
||||||
append_u8(OPCODE_CALL);
|
|
||||||
append_u32(arg_count);
|
|
||||||
|
|
||||||
if (func->type == NODE_VALUE_VAR) {
|
if (func->type == NODE_VALUE_VAR) {
|
||||||
|
assemble_node(a, arg);
|
||||||
|
append_u8(&a->out, OPCODE_SCALL);
|
||||||
|
append_u8(&a->out, arg_count);
|
||||||
|
int p = append_u32(&a->out, 0);
|
||||||
|
|
||||||
|
FunctionCall *call = alloc(a->a, sizeof(FunctionCall), _Alignof(FunctionCall));
|
||||||
|
if (call == NULL) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
call->name = func->sval;
|
||||||
|
call->off = p;
|
||||||
|
|
||||||
|
Scope *scope = &a->scopes[a->num_scopes-1];
|
||||||
|
|
||||||
|
call->next = scope->calls;
|
||||||
|
scope->calls = call;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
assemble_node(a, func);
|
||||||
|
assemble_node(a, arg);
|
||||||
|
append_u8(&a->out, OPCODE_DCALL);
|
||||||
|
append_u8(&a->out, arg_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NODE_VAR_DECL:
|
||||||
|
{
|
||||||
|
int idx = declare_var(a, node->var_name);
|
||||||
|
if (idx < 0) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node->var_value) {
|
||||||
|
assemble_node(a, node->var_value);
|
||||||
|
append_u8(&a->out, OPCODE_SETV);
|
||||||
|
append_u8(&a->out, idx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -98,9 +294,9 @@ void assemble_node(Node *node)
|
|||||||
{
|
{
|
||||||
Node *stmt = node->child;
|
Node *stmt = node->child;
|
||||||
while (stmt) {
|
while (stmt) {
|
||||||
assemble_node(stmt);
|
assemble_node(a, stmt);
|
||||||
if (is_expr(stmt))
|
if (is_expr(stmt))
|
||||||
append_u8(out, OPCODE_POP);
|
append_u8(&a->out, OPCODE_POP);
|
||||||
stmt = stmt->next;
|
stmt = stmt->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,134 +304,258 @@ void assemble_node(Node *node)
|
|||||||
|
|
||||||
case NODE_IFELSE:
|
case NODE_IFELSE:
|
||||||
{
|
{
|
||||||
assemble_node(node->cond);
|
// If there is no else branch:
|
||||||
|
//
|
||||||
|
// <cond>
|
||||||
|
// JIFP end
|
||||||
|
// <left>
|
||||||
|
// end:
|
||||||
|
// ...
|
||||||
|
//
|
||||||
|
// If there is:
|
||||||
|
//
|
||||||
|
// <cond>
|
||||||
|
// JIFP else
|
||||||
|
// <left>
|
||||||
|
// JUMP end
|
||||||
|
// else:
|
||||||
|
// <right>
|
||||||
|
// end:
|
||||||
|
// ...
|
||||||
|
|
||||||
append_u8 (out, OPCODE_JIFP);
|
if (node->right) {
|
||||||
append_u32(out, xxx);
|
|
||||||
|
|
||||||
assemble_node(node->left);
|
assemble_node(a, node->cond);
|
||||||
|
|
||||||
if (node->right)
|
append_u8(&a->out, OPCODE_JIFP);
|
||||||
assemble_node(node->right);
|
int p1 = append_u32(&a->out, 0);
|
||||||
|
|
||||||
|
assemble_node(a, node->left);
|
||||||
|
|
||||||
|
append_u8(&a->out, OPCODE_JUMP);
|
||||||
|
int p2 = append_u32(&a->out, 0);
|
||||||
|
|
||||||
|
patch_with_current_offset(&a->out, p1);
|
||||||
|
|
||||||
|
assemble_node(a, node->right);
|
||||||
|
|
||||||
|
patch_with_current_offset(&a->out, p2);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
assemble_node(a, node->cond);
|
||||||
|
|
||||||
|
append_u8(&a->out, OPCODE_JIFP);
|
||||||
|
int p1 = append_u32(&a->out, 0);
|
||||||
|
|
||||||
|
assemble_node(a, node->left);
|
||||||
|
|
||||||
|
patch_with_current_offset(&a->out, p1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NODE_WHILE:
|
||||||
|
{
|
||||||
|
// start:
|
||||||
|
// <cond>
|
||||||
|
// JIFP end
|
||||||
|
// <body>
|
||||||
|
// JUMP start
|
||||||
|
// end:
|
||||||
|
// ...
|
||||||
|
|
||||||
|
int start = current_offset(&a->out);
|
||||||
|
|
||||||
|
assemble_node(a, node->cond);
|
||||||
|
|
||||||
|
append_u8(&a->out, OPCODE_JIFP);
|
||||||
|
int p = append_u32(&a->out, 0);
|
||||||
|
|
||||||
|
assemble_node(a, node->left);
|
||||||
|
|
||||||
|
append_u8(&a->out, OPCODE_JUMP);
|
||||||
|
opcode_u32(&a->out, start);
|
||||||
|
|
||||||
|
patch_with_current_offset(&a->out, p);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_FOR:
|
case NODE_FOR:
|
||||||
{
|
{
|
||||||
assemble_node(node->for_set);
|
assemble_node(a, node->for_set);
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_WHILE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NODE_SELECT:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NODE_OPER_POS:
|
case NODE_OPER_POS:
|
||||||
assemble_node(node->left);
|
assemble_node(a, node->left);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_OPER_NEG:
|
case NODE_OPER_NEG:
|
||||||
assemble_node(node->left);
|
assemble_node(a, node->left);
|
||||||
append(out, OPCODE_NEG);
|
append_u8(&a->out, OPCODE_NEG);
|
||||||
break;
|
|
||||||
|
|
||||||
case NODE_OPER_ASS:
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_OPER_EQL:
|
case NODE_OPER_EQL:
|
||||||
assemble_node(node->left);
|
assemble_node(a, node->left);
|
||||||
assemble_node(node->right);
|
assemble_node(a, node->right);
|
||||||
append(out, OPCODE_EQL);
|
append_u8(&a->out, OPCODE_EQL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_OPER_NQL:
|
case NODE_OPER_NQL:
|
||||||
assemble_node(node->left);
|
assemble_node(a, node->left);
|
||||||
assemble_node(node->right);
|
assemble_node(a, node->right);
|
||||||
append(out, OPCODE_NQL);
|
append_u8(&a->out, OPCODE_NQL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_OPER_LSS:
|
case NODE_OPER_LSS:
|
||||||
assemble_node(node->left);
|
assemble_node(a, node->left);
|
||||||
assemble_node(node->right);
|
assemble_node(a, node->right);
|
||||||
append(out, OPCODE_LSS);
|
append_u8(&a->out, OPCODE_LSS);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_OPER_GRT:
|
case NODE_OPER_GRT:
|
||||||
assemble_node(node->left);
|
assemble_node(a, node->left);
|
||||||
assemble_node(node->right);
|
assemble_node(a, node->right);
|
||||||
append(out, OPCODE_GRT);
|
append_u8(&a->out, OPCODE_GRT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_OPER_ADD:
|
case NODE_OPER_ADD:
|
||||||
assemble_node(node->left);
|
assemble_node(a, node->left);
|
||||||
assemble_node(node->right);
|
assemble_node(a, node->right);
|
||||||
append(out, OPCODE_ADD);
|
append_u8(&a->out, OPCODE_ADD);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_OPER_SUB:
|
case NODE_OPER_SUB:
|
||||||
assemble_node(node->left);
|
assemble_node(a, node->left);
|
||||||
assemble_node(node->right);
|
assemble_node(a, node->right);
|
||||||
append(out, OPCODE_SUB);
|
append_u8(&a->out, OPCODE_SUB);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_OPER_MUL:
|
case NODE_OPER_MUL:
|
||||||
assemble_node(node->left);
|
assemble_node(a, node->left);
|
||||||
assemble_node(node->right);
|
assemble_node(a, node->right);
|
||||||
append(out, OPCODE_MUL);
|
append_u8(&a->out, OPCODE_MUL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_OPER_DIV:
|
case NODE_OPER_DIV:
|
||||||
assemble_node(node->left);
|
assemble_node(a, node->left);
|
||||||
assemble_node(node->right);
|
assemble_node(a, node->right);
|
||||||
append(out, OPCODE_DIV);
|
append_u8(&a->out, OPCODE_DIV);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_OPER_MOD:
|
case NODE_OPER_MOD:
|
||||||
assemble_node(node->left);
|
assemble_node(a, node->left);
|
||||||
assemble_node(node->right);
|
assemble_node(a, node->right);
|
||||||
append(out, OPCODE_MOD);
|
append_u8(&a->out, OPCODE_MOD);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_VALUE_INT:
|
case NODE_VALUE_INT:
|
||||||
append_u8 (out, OPCODE_PUSHI);
|
append_u8(&a->out, OPCODE_PUSHI);
|
||||||
append_u64(out, node->ival);
|
append_u64(&a->out, node->ival);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_VALUE_FLOAT:
|
case NODE_VALUE_FLOAT:
|
||||||
append_u8 (out, OPCODE_PUSHF);
|
append_u8 (&a->out, OPCODE_PUSHF);
|
||||||
append_f64(out, node->fval);
|
append_f64(&a->out, node->dval);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_VALUE_STR:
|
case NODE_VALUE_STR:
|
||||||
append_u8 (out, OPCODE_PUSHS);
|
{
|
||||||
append_u64(out, xxx);
|
int off = add_string_literal(a, node->sval);
|
||||||
|
append_u8(&a->out, OPCODE_PUSHS);
|
||||||
|
append_u32(&a->out, off);
|
||||||
|
append_u32(&a->out, node->sval.len);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_VALUE_VAR:
|
case NODE_VALUE_VAR:
|
||||||
append_u8 (out, OPCODE_PUSHV);
|
append_u8 (&a->out, OPCODE_PUSHV);
|
||||||
append_u64(out, node->ival);
|
append_u64(&a->out, node->ival);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_VALUE_HTML:
|
case NODE_VALUE_HTML:
|
||||||
TODO;
|
assemble_html_node(a, node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_VALUE_ARRAY:
|
case NODE_VALUE_ARRAY:
|
||||||
append_u8 (out, OPCODE_PUSHA);
|
{
|
||||||
append_u64(out, xxx);
|
append_u8(&a->out, OPCODE_PUSHA);
|
||||||
|
append_u32(&a->out, count_nodes(node->child));
|
||||||
|
|
||||||
|
Node *child = node->child;
|
||||||
|
while (child) {
|
||||||
|
assemble_node(a, child);
|
||||||
|
append_u8(&a->out, OPCODE_APPEND);
|
||||||
|
child = child->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_VALUE_MAP:
|
case NODE_VALUE_MAP:
|
||||||
append_u8 (out, OPCODE_PUSHM);
|
{
|
||||||
append_u64(out, xxx);
|
append_u8(&a->out, OPCODE_PUSHM);
|
||||||
|
append_u64(&a->out, count_nodes(node->child));
|
||||||
|
|
||||||
|
Node *child = node->child;
|
||||||
|
while (child) {
|
||||||
|
assemble_node(a, child);
|
||||||
|
assemble_node(a, child->key);
|
||||||
|
append_u8(&a->out, OPCODE_INSERT1);
|
||||||
|
child = child->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NODE_SELECT:
|
||||||
|
{
|
||||||
|
Node *set = node->left;
|
||||||
|
Node *key = node->right;
|
||||||
|
|
||||||
|
assemble_node(a, set);
|
||||||
|
assemble_node(a, key);
|
||||||
|
append_u8(&a->out, OPCODE_SELECT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NODE_OPER_ASS:
|
||||||
|
{
|
||||||
|
Node *dst = node->left;
|
||||||
|
Node *src = node->right;
|
||||||
|
|
||||||
|
if (dst->type == NODE_VALUE_VAR) {
|
||||||
|
|
||||||
|
int idx = find_variable(dst->sval);
|
||||||
|
if (idx < 0) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
assemble_node(a, src);
|
||||||
|
append_u8(&a->out, OPCODE_SETV);
|
||||||
|
append_u8(&a->out, idx);
|
||||||
|
|
||||||
|
} else if (dst->type == NODE_SELECT) {
|
||||||
|
|
||||||
|
assemble_node(a, src);
|
||||||
|
assemble_node(a, dst->left);
|
||||||
|
assemble_node(a, dst->right);
|
||||||
|
append_u8(&a->out, OPCODE_INSERT2);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// TODO ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AssembleResult assemble(Node *root)
|
AssembleResult assemble(Node *root)
|
||||||
{
|
{
|
||||||
assemble_node(root);
|
Assembler a = {0};
|
||||||
|
assemble_node(&a, root);
|
||||||
|
append_u8(&a.out, OPCODE_NOPE);
|
||||||
|
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-5
@@ -1,3 +1,7 @@
|
|||||||
|
#ifndef WL_ASSEMBLE_INCLUDED
|
||||||
|
#define WL_ASSEMBLE_INCLUDED
|
||||||
|
|
||||||
|
#include "parse.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
OPCODE_NOPE = 0x00,
|
OPCODE_NOPE = 0x00,
|
||||||
@@ -17,11 +21,17 @@ enum {
|
|||||||
OPCODE_SUB = 0x0E,
|
OPCODE_SUB = 0x0E,
|
||||||
OPCODE_MUL = 0x0F,
|
OPCODE_MUL = 0x0F,
|
||||||
OPCODE_DIV = 0x10,
|
OPCODE_DIV = 0x10,
|
||||||
OPCODE_MOD = 0x20,
|
OPCODE_MOD = 0x11,
|
||||||
OPCODE_JUMP = 0x30,
|
OPCODE_SETV = 0x12,
|
||||||
OPCODE_JIFP = 0x40,
|
OPCODE_JUMP = 0x13,
|
||||||
OPCODE_CALL = 0x41,
|
OPCODE_JIFP = 0x14,
|
||||||
OPCODE_RET = 0x42,
|
OPCODE_SCALL = 0x15,
|
||||||
|
OPCODE_DCALL = 0x16,
|
||||||
|
OPCODE_RET = 0x17,
|
||||||
|
OPCODE_APPEND = 0x18,
|
||||||
|
OPCODE_INSERT1 = 0x19,
|
||||||
|
OPCODE_INSERT2 = 0x20,
|
||||||
|
OPCODE_SELECT = 0x21,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -34,3 +44,5 @@ typedef struct {
|
|||||||
} AssembleResult;
|
} AssembleResult;
|
||||||
|
|
||||||
AssembleResult assemble(Node *root);
|
AssembleResult assemble(Node *root);
|
||||||
|
|
||||||
|
#endif // WL_ASSEMBLE_INCLUDED
|
||||||
+293
@@ -0,0 +1,293 @@
|
|||||||
|
#include "eval.h"
|
||||||
|
|
||||||
|
#define FRAME_LIMIT 128
|
||||||
|
#define EVAL_STACK_LIMIT 128
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
} Frame;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uint64_t i;
|
||||||
|
void* p;
|
||||||
|
} EvalStackItem;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Program p;
|
||||||
|
int off;
|
||||||
|
|
||||||
|
int frame_depth;
|
||||||
|
Frame frames[FRAME_LIMIT];
|
||||||
|
|
||||||
|
int eval_depth;
|
||||||
|
EvalStackItem eval_stack[EVAL_STACK_LIMIT];
|
||||||
|
|
||||||
|
} Eval;
|
||||||
|
|
||||||
|
void step(Eval *e)
|
||||||
|
{
|
||||||
|
uint8_t b = e->p.ptr[e->off++];
|
||||||
|
|
||||||
|
switch (b) {
|
||||||
|
|
||||||
|
case OPCODE_NOPE:
|
||||||
|
// Do nothing
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_PUSHI:
|
||||||
|
{
|
||||||
|
int64_t x;
|
||||||
|
|
||||||
|
memcpy(&x, e->p.ptr + e->off, sizeof(x));
|
||||||
|
e->off += (int) sizeof(x);
|
||||||
|
|
||||||
|
e->eval_stack[e->eval_depth++] = x;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_PUSHF:
|
||||||
|
{
|
||||||
|
double x;
|
||||||
|
|
||||||
|
memcpy(&x, e->p.ptr + e->off, sizeof(x));
|
||||||
|
e->off += (int) sizeof(x);
|
||||||
|
|
||||||
|
e->eval_stack[e->eval_depth++] = x;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_PUSHS:
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_PUSHV:
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_PUSHA:
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_PUSHM:
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_POP:
|
||||||
|
e->eval_depth--;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_NEG:
|
||||||
|
{
|
||||||
|
Value a = e->eval_stack[--e->eval_depth];
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
e->eval_stack[e->eval_depth++] = r;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_EQL:
|
||||||
|
{
|
||||||
|
Value a = e->eval_stack[e->eval_depth-2];
|
||||||
|
Value b = e->eval_stack[e->eval_depth-1];
|
||||||
|
e->eval_depth -= 2;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
e->eval_stack[e->eval_depth++] = r;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_NQL:
|
||||||
|
{
|
||||||
|
Value a = e->eval_stack[e->eval_depth-2];
|
||||||
|
Value b = e->eval_stack[e->eval_depth-1];
|
||||||
|
e->eval_depth -= 2;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
e->eval_stack[e->eval_depth++] = r;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_LSS:
|
||||||
|
{
|
||||||
|
Value a = e->eval_stack[e->eval_depth-2];
|
||||||
|
Value b = e->eval_stack[e->eval_depth-1];
|
||||||
|
e->eval_depth -= 2;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
e->eval_stack[e->eval_depth++] = r;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_GRT:
|
||||||
|
{
|
||||||
|
Value a = e->eval_stack[e->eval_depth-2];
|
||||||
|
Value b = e->eval_stack[e->eval_depth-1];
|
||||||
|
e->eval_depth -= 2;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
e->eval_stack[e->eval_depth++] = r;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_ADD:
|
||||||
|
{
|
||||||
|
Value a = e->eval_stack[e->eval_depth-2];
|
||||||
|
Value b = e->eval_stack[e->eval_depth-1];
|
||||||
|
e->eval_depth -= 2;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
e->eval_stack[e->eval_depth++] = r;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_SUB:
|
||||||
|
{
|
||||||
|
Value a = e->eval_stack[e->eval_depth-2];
|
||||||
|
Value b = e->eval_stack[e->eval_depth-1];
|
||||||
|
e->eval_depth -= 2;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
e->eval_stack[e->eval_depth++] = r;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_MUL:
|
||||||
|
{
|
||||||
|
Value a = e->eval_stack[e->eval_depth-2];
|
||||||
|
Value b = e->eval_stack[e->eval_depth-1];
|
||||||
|
e->eval_depth -= 2;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
e->eval_stack[e->eval_depth++] = r;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_DIV:
|
||||||
|
{
|
||||||
|
Value a = e->eval_stack[e->eval_depth-2];
|
||||||
|
Value b = e->eval_stack[e->eval_depth-1];
|
||||||
|
e->eval_depth -= 2;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
e->eval_stack[e->eval_depth++] = r;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_MOD:
|
||||||
|
{
|
||||||
|
Value a = e->eval_stack[e->eval_depth-2];
|
||||||
|
Value b = e->eval_stack[e->eval_depth-1];
|
||||||
|
e->eval_depth -= 2;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
e->eval_stack[e->eval_depth++] = r;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_SETV:
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_JUMP:
|
||||||
|
{
|
||||||
|
uint32_t x;
|
||||||
|
|
||||||
|
memcpy(&x, e->p.ptr + e->off, (int) sizeof(x));
|
||||||
|
e->off = (int) sizeof(x);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_JIFP:
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_SCALL:
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_DCALL:
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_RET:
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_APPEND:
|
||||||
|
{
|
||||||
|
Value val = e->eval_stack[e->eval_depth-1];
|
||||||
|
Value set = e->eval_stack[e->eval_depth-2];
|
||||||
|
e->eval_depth--;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_INSERT1:
|
||||||
|
{
|
||||||
|
Value key = e->eval_stack[e->eval_depth-1];
|
||||||
|
Value val = e->eval_stack[e->eval_depth-2];
|
||||||
|
Value set = e->eval_stack[e->eval_depth-3];
|
||||||
|
e->eval_depth -= 2;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_INSERT2:
|
||||||
|
{
|
||||||
|
Value key = e->eval_stack[e->eval_depth-1];
|
||||||
|
Value set = e->eval_stack[e->eval_depth-2];
|
||||||
|
Value val = e->eval_stack[e->eval_depth-3];
|
||||||
|
e->eval_depth -= 2;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_SELECT:
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void eval(Program p)
|
||||||
|
{
|
||||||
|
Eval e = { p, 0 };
|
||||||
|
for (;;)
|
||||||
|
step(&e);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef WL_EVAL_INCLUDED
|
||||||
|
#define WL_EVAL_INCLUDED
|
||||||
|
|
||||||
|
#include "assemble.h"
|
||||||
|
|
||||||
|
void eval(Program program);
|
||||||
|
|
||||||
|
#endif // WL_EVAL_INCLUDED
|
||||||
+62
@@ -20,6 +20,7 @@ typedef enum {
|
|||||||
TOKEN_KWORD_FOR,
|
TOKEN_KWORD_FOR,
|
||||||
TOKEN_KWORD_IN,
|
TOKEN_KWORD_IN,
|
||||||
TOKEN_KWORD_FUN,
|
TOKEN_KWORD_FUN,
|
||||||
|
TOKEN_KWORD_LET,
|
||||||
TOKEN_VALUE_FLOAT,
|
TOKEN_VALUE_FLOAT,
|
||||||
TOKEN_VALUE_INT,
|
TOKEN_VALUE_INT,
|
||||||
TOKEN_VALUE_STR,
|
TOKEN_VALUE_STR,
|
||||||
@@ -102,6 +103,7 @@ String tok2str(Token token, char *buf, int max)
|
|||||||
case TOKEN_KWORD_FOR: return S("for");
|
case TOKEN_KWORD_FOR: return S("for");
|
||||||
case TOKEN_KWORD_IN: return S("in");
|
case TOKEN_KWORD_IN: return S("in");
|
||||||
case TOKEN_KWORD_FUN: return S("fun");
|
case TOKEN_KWORD_FUN: return S("fun");
|
||||||
|
case TOKEN_KWORD_LET: return S("let");
|
||||||
|
|
||||||
case TOKEN_VALUE_FLOAT:
|
case TOKEN_VALUE_FLOAT:
|
||||||
{
|
{
|
||||||
@@ -221,6 +223,7 @@ Token next_token(Parser *p)
|
|||||||
if (streq(kword, S("for"))) return (Token) { .type=TOKEN_KWORD_FOR };
|
if (streq(kword, S("for"))) return (Token) { .type=TOKEN_KWORD_FOR };
|
||||||
if (streq(kword, S("in"))) return (Token) { .type=TOKEN_KWORD_IN };
|
if (streq(kword, S("in"))) return (Token) { .type=TOKEN_KWORD_IN };
|
||||||
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 };
|
||||||
return (Token) { .type=TOKEN_IDENT, .sval=kword };
|
return (Token) { .type=TOKEN_IDENT, .sval=kword };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1299,6 +1302,49 @@ Node *parse_func_decl(Parser *p, int opflags)
|
|||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Node *parse_var_decl(Parser *p, int opflags)
|
||||||
|
{
|
||||||
|
Token t = next_token(p);
|
||||||
|
if (t.type != TOKEN_KWORD_LET) {
|
||||||
|
report(p, "Missing keyword 'let' at the start of a variable declaration");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = next_token(p);
|
||||||
|
if (t.type != TOKEN_IDENT) {
|
||||||
|
report(p, "Missing variable name after 'let' keyword");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
String name = t.sval;
|
||||||
|
|
||||||
|
t = next_token(p);
|
||||||
|
|
||||||
|
Node *value = NULL;
|
||||||
|
if (t.type == TOKEN_OPER_ASS) {
|
||||||
|
|
||||||
|
value = parse_expr(p, opflags);
|
||||||
|
if (value == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
t = next_token(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t.type != TOKEN_SEMICOLON) {
|
||||||
|
report(p, "Missing ';' at the end of a variable declaration");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *parent = alloc_node(p);
|
||||||
|
if (parent == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
parent->type = NODE_VAR_DECL;
|
||||||
|
parent->var_name = name;
|
||||||
|
parent->var_value = value;
|
||||||
|
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
Node *parse_stmt(Parser *p, int opflags)
|
Node *parse_stmt(Parser *p, int opflags)
|
||||||
{
|
{
|
||||||
Scanner saved = p->s;
|
Scanner saved = p->s;
|
||||||
@@ -1310,6 +1356,9 @@ Node *parse_stmt(Parser *p, int opflags)
|
|||||||
case TOKEN_KWORD_FUN:
|
case TOKEN_KWORD_FUN:
|
||||||
return parse_func_decl(p, opflags);
|
return parse_func_decl(p, opflags);
|
||||||
|
|
||||||
|
case TOKEN_KWORD_LET:
|
||||||
|
return parse_var_decl(p, opflags);
|
||||||
|
|
||||||
case TOKEN_KWORD_IF:
|
case TOKEN_KWORD_IF:
|
||||||
return parse_ifelse_stmt(p, opflags);
|
return parse_ifelse_stmt(p, opflags);
|
||||||
|
|
||||||
@@ -1611,6 +1660,19 @@ void print_node(Node *node)
|
|||||||
printf(")");
|
printf(")");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_VAR_DECL:
|
||||||
|
{
|
||||||
|
printf("let %.*s",
|
||||||
|
node->var_name.len,
|
||||||
|
node->var_name.ptr);
|
||||||
|
if (node->var_value) {
|
||||||
|
printf(" = ");
|
||||||
|
print_node(node);
|
||||||
|
}
|
||||||
|
printf(";");
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ typedef enum {
|
|||||||
NODE_FUNC_DECL,
|
NODE_FUNC_DECL,
|
||||||
NODE_FUNC_ARG,
|
NODE_FUNC_ARG,
|
||||||
NODE_FUNC_CALL,
|
NODE_FUNC_CALL,
|
||||||
|
NODE_VAR_DECL,
|
||||||
NODE_BLOCK,
|
NODE_BLOCK,
|
||||||
NODE_IFELSE,
|
NODE_IFELSE,
|
||||||
NODE_FOR,
|
NODE_FOR,
|
||||||
@@ -65,6 +66,9 @@ struct Node {
|
|||||||
String func_name;
|
String func_name;
|
||||||
Node *func_args;
|
Node *func_args;
|
||||||
Node *func_body;
|
Node *func_body;
|
||||||
|
|
||||||
|
String var_name;
|
||||||
|
Node *var_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user