More progress on assembler and evaluator
This commit is contained in:
@@ -1,6 +1,4 @@
|
||||
|
||||
func(1, 3, 5);
|
||||
|
||||
title = "My Website";
|
||||
|
||||
posts = [
|
||||
@@ -27,22 +25,21 @@ fun render_comment(c)
|
||||
<a>$c.author; ($c.date;)</a>
|
||||
<p>$c.content;</p>
|
||||
<div class="comment-children">
|
||||
$for child in c.children:
|
||||
$ for child in c.children:
|
||||
render_comment(child);
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<html>
|
||||
export <html>
|
||||
<head>
|
||||
<title>$(title);</title>
|
||||
<title>$title;</title>
|
||||
</head>
|
||||
<body>
|
||||
$for post in posts: {
|
||||
$ for post in posts: {
|
||||
<div class="post">
|
||||
<a>$post.title; ($post.date;)</a>
|
||||
$for comment in post.comments: {
|
||||
$ for comment in post.comments:
|
||||
render_comment(comment);
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</body>
|
||||
|
||||
+407
-87
@@ -2,6 +2,19 @@
|
||||
#include "assemble.h"
|
||||
|
||||
#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 {
|
||||
SCOPE_FUNC,
|
||||
@@ -13,14 +26,122 @@ typedef enum {
|
||||
|
||||
typedef struct {
|
||||
ScopeType type;
|
||||
int var_base;
|
||||
// TODO
|
||||
FunctionCall *calls;
|
||||
} Scope;
|
||||
|
||||
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];
|
||||
|
||||
int strings_len;
|
||||
int strings_cap;
|
||||
char *strings;
|
||||
|
||||
} 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 n = 0;
|
||||
@@ -32,41 +153,85 @@ int count_nodes(Node *head)
|
||||
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) {
|
||||
|
||||
case NODE_FUNC_DECL:
|
||||
{
|
||||
append_u8 (out, OPCODE_JUMP);
|
||||
append_u64(out, xxx);
|
||||
append_u8(&a->out, OPCODE_JUMP);
|
||||
int p1 = append_u32(&a->out, 0);
|
||||
|
||||
// TODO: resolve references
|
||||
|
||||
int arg_count = count_nodes(node->func_args);
|
||||
|
||||
Node *preallocated[32];
|
||||
Node *args = preallocated;
|
||||
if (arg_count > COUNT(preallocated)) {
|
||||
args = malloc(arg_count * sizeof(Node*));
|
||||
if (args == NULL) {
|
||||
// TODO
|
||||
}
|
||||
Node *args[32];
|
||||
if (arg_count > COUNT(args)) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
for (int i = arg_count-1; i >= 0; i--) {
|
||||
append_u8 (out, OPCODE_ASS);
|
||||
append_u64(out, xxx);
|
||||
int idx = declare_var(a, args[i]->sval);
|
||||
if (idx < 0) {
|
||||
// TODO
|
||||
}
|
||||
append_u8(&a->out, OPCODE_SETV);
|
||||
append_u8(&a->out, idx);
|
||||
}
|
||||
|
||||
if (is_expr(node->func_body)) {
|
||||
assemble_node(node->func_body);
|
||||
append_u8(out, OPCODE_RET);
|
||||
assemble_node(a, node->func_body);
|
||||
append_u8(&a->out, OPCODE_RET);
|
||||
} else
|
||||
assemble_node(node->func_body);
|
||||
assemble_node(a, node->func_body);
|
||||
|
||||
append_u8(out, OPCODE_NOPE);
|
||||
|
||||
if (args != preallocated)
|
||||
free(args);
|
||||
patch_with_current_offset(&a->out, p1);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -78,19 +243,50 @@ void assemble_node(Node *node)
|
||||
int arg_count = 0;
|
||||
Node *arg = args;
|
||||
while (arg) {
|
||||
assemble_node(arg);
|
||||
assemble_node(a, arg);
|
||||
arg_count++;
|
||||
arg = arg->next;
|
||||
}
|
||||
|
||||
assemble_node(arg);
|
||||
append_u8(OPCODE_CALL);
|
||||
append_u32(arg_count);
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
if (node->var_value) {
|
||||
assemble_node(a, node->var_value);
|
||||
append_u8(&a->out, OPCODE_SETV);
|
||||
append_u8(&a->out, idx);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -98,9 +294,9 @@ void assemble_node(Node *node)
|
||||
{
|
||||
Node *stmt = node->child;
|
||||
while (stmt) {
|
||||
assemble_node(stmt);
|
||||
assemble_node(a, stmt);
|
||||
if (is_expr(stmt))
|
||||
append_u8(out, OPCODE_POP);
|
||||
append_u8(&a->out, OPCODE_POP);
|
||||
stmt = stmt->next;
|
||||
}
|
||||
}
|
||||
@@ -108,134 +304,258 @@ void assemble_node(Node *node)
|
||||
|
||||
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);
|
||||
append_u32(out, xxx);
|
||||
if (node->right) {
|
||||
|
||||
assemble_node(node->left);
|
||||
assemble_node(a, node->cond);
|
||||
|
||||
if (node->right)
|
||||
assemble_node(node->right);
|
||||
append_u8(&a->out, OPCODE_JIFP);
|
||||
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;
|
||||
|
||||
case NODE_FOR:
|
||||
{
|
||||
assemble_node(node->for_set);
|
||||
assemble_node(a, node->for_set);
|
||||
// TODO
|
||||
}
|
||||
break;
|
||||
|
||||
case NODE_WHILE:
|
||||
break;
|
||||
|
||||
case NODE_SELECT:
|
||||
break;
|
||||
|
||||
case NODE_OPER_POS:
|
||||
assemble_node(node->left);
|
||||
assemble_node(a, node->left);
|
||||
break;
|
||||
|
||||
case NODE_OPER_NEG:
|
||||
assemble_node(node->left);
|
||||
append(out, OPCODE_NEG);
|
||||
break;
|
||||
|
||||
case NODE_OPER_ASS:
|
||||
assemble_node(a, node->left);
|
||||
append_u8(&a->out, OPCODE_NEG);
|
||||
break;
|
||||
|
||||
case NODE_OPER_EQL:
|
||||
assemble_node(node->left);
|
||||
assemble_node(node->right);
|
||||
append(out, OPCODE_EQL);
|
||||
assemble_node(a, node->left);
|
||||
assemble_node(a, node->right);
|
||||
append_u8(&a->out, OPCODE_EQL);
|
||||
break;
|
||||
|
||||
case NODE_OPER_NQL:
|
||||
assemble_node(node->left);
|
||||
assemble_node(node->right);
|
||||
append(out, OPCODE_NQL);
|
||||
assemble_node(a, node->left);
|
||||
assemble_node(a, node->right);
|
||||
append_u8(&a->out, OPCODE_NQL);
|
||||
break;
|
||||
|
||||
case NODE_OPER_LSS:
|
||||
assemble_node(node->left);
|
||||
assemble_node(node->right);
|
||||
append(out, OPCODE_LSS);
|
||||
assemble_node(a, node->left);
|
||||
assemble_node(a, node->right);
|
||||
append_u8(&a->out, OPCODE_LSS);
|
||||
break;
|
||||
|
||||
case NODE_OPER_GRT:
|
||||
assemble_node(node->left);
|
||||
assemble_node(node->right);
|
||||
append(out, OPCODE_GRT);
|
||||
assemble_node(a, node->left);
|
||||
assemble_node(a, node->right);
|
||||
append_u8(&a->out, OPCODE_GRT);
|
||||
break;
|
||||
|
||||
case NODE_OPER_ADD:
|
||||
assemble_node(node->left);
|
||||
assemble_node(node->right);
|
||||
append(out, OPCODE_ADD);
|
||||
assemble_node(a, node->left);
|
||||
assemble_node(a, node->right);
|
||||
append_u8(&a->out, OPCODE_ADD);
|
||||
break;
|
||||
|
||||
case NODE_OPER_SUB:
|
||||
assemble_node(node->left);
|
||||
assemble_node(node->right);
|
||||
append(out, OPCODE_SUB);
|
||||
assemble_node(a, node->left);
|
||||
assemble_node(a, node->right);
|
||||
append_u8(&a->out, OPCODE_SUB);
|
||||
break;
|
||||
|
||||
case NODE_OPER_MUL:
|
||||
assemble_node(node->left);
|
||||
assemble_node(node->right);
|
||||
append(out, OPCODE_MUL);
|
||||
assemble_node(a, node->left);
|
||||
assemble_node(a, node->right);
|
||||
append_u8(&a->out, OPCODE_MUL);
|
||||
break;
|
||||
|
||||
case NODE_OPER_DIV:
|
||||
assemble_node(node->left);
|
||||
assemble_node(node->right);
|
||||
append(out, OPCODE_DIV);
|
||||
assemble_node(a, node->left);
|
||||
assemble_node(a, node->right);
|
||||
append_u8(&a->out, OPCODE_DIV);
|
||||
break;
|
||||
|
||||
case NODE_OPER_MOD:
|
||||
assemble_node(node->left);
|
||||
assemble_node(node->right);
|
||||
append(out, OPCODE_MOD);
|
||||
assemble_node(a, node->left);
|
||||
assemble_node(a, node->right);
|
||||
append_u8(&a->out, OPCODE_MOD);
|
||||
break;
|
||||
|
||||
case NODE_VALUE_INT:
|
||||
append_u8 (out, OPCODE_PUSHI);
|
||||
append_u64(out, node->ival);
|
||||
append_u8(&a->out, OPCODE_PUSHI);
|
||||
append_u64(&a->out, node->ival);
|
||||
break;
|
||||
|
||||
case NODE_VALUE_FLOAT:
|
||||
append_u8 (out, OPCODE_PUSHF);
|
||||
append_f64(out, node->fval);
|
||||
append_u8 (&a->out, OPCODE_PUSHF);
|
||||
append_f64(&a->out, node->dval);
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
case NODE_VALUE_VAR:
|
||||
append_u8 (out, OPCODE_PUSHV);
|
||||
append_u64(out, node->ival);
|
||||
append_u8 (&a->out, OPCODE_PUSHV);
|
||||
append_u64(&a->out, node->ival);
|
||||
break;
|
||||
|
||||
case NODE_VALUE_HTML:
|
||||
TODO;
|
||||
assemble_html_node(a, node);
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
AssembleResult assemble(Node *root)
|
||||
{
|
||||
assemble_node(root);
|
||||
Assembler a = {0};
|
||||
assemble_node(&a, root);
|
||||
append_u8(&a.out, OPCODE_NOPE);
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
+34
-22
@@ -1,27 +1,37 @@
|
||||
#ifndef WL_ASSEMBLE_INCLUDED
|
||||
#define WL_ASSEMBLE_INCLUDED
|
||||
|
||||
#include "parse.h"
|
||||
|
||||
enum {
|
||||
OPCODE_NOPE = 0x00,
|
||||
OPCODE_PUSHI = 0x01,
|
||||
OPCODE_PUSHF = 0x02,
|
||||
OPCODE_PUSHS = 0x03,
|
||||
OPCODE_PUSHV = 0x04,
|
||||
OPCODE_PUSHA = 0x05,
|
||||
OPCODE_PUSHM = 0x06,
|
||||
OPCODE_POP = 0x07,
|
||||
OPCODE_NEG = 0x08,
|
||||
OPCODE_EQL = 0x09,
|
||||
OPCODE_NQL = 0x0A,
|
||||
OPCODE_LSS = 0x0B,
|
||||
OPCODE_GRT = 0x0C,
|
||||
OPCODE_ADD = 0x0D,
|
||||
OPCODE_SUB = 0x0E,
|
||||
OPCODE_MUL = 0x0F,
|
||||
OPCODE_DIV = 0x10,
|
||||
OPCODE_MOD = 0x20,
|
||||
OPCODE_JUMP = 0x30,
|
||||
OPCODE_JIFP = 0x40,
|
||||
OPCODE_CALL = 0x41,
|
||||
OPCODE_RET = 0x42,
|
||||
OPCODE_NOPE = 0x00,
|
||||
OPCODE_PUSHI = 0x01,
|
||||
OPCODE_PUSHF = 0x02,
|
||||
OPCODE_PUSHS = 0x03,
|
||||
OPCODE_PUSHV = 0x04,
|
||||
OPCODE_PUSHA = 0x05,
|
||||
OPCODE_PUSHM = 0x06,
|
||||
OPCODE_POP = 0x07,
|
||||
OPCODE_NEG = 0x08,
|
||||
OPCODE_EQL = 0x09,
|
||||
OPCODE_NQL = 0x0A,
|
||||
OPCODE_LSS = 0x0B,
|
||||
OPCODE_GRT = 0x0C,
|
||||
OPCODE_ADD = 0x0D,
|
||||
OPCODE_SUB = 0x0E,
|
||||
OPCODE_MUL = 0x0F,
|
||||
OPCODE_DIV = 0x10,
|
||||
OPCODE_MOD = 0x11,
|
||||
OPCODE_SETV = 0x12,
|
||||
OPCODE_JUMP = 0x13,
|
||||
OPCODE_JIFP = 0x14,
|
||||
OPCODE_SCALL = 0x15,
|
||||
OPCODE_DCALL = 0x16,
|
||||
OPCODE_RET = 0x17,
|
||||
OPCODE_APPEND = 0x18,
|
||||
OPCODE_INSERT1 = 0x19,
|
||||
OPCODE_INSERT2 = 0x20,
|
||||
OPCODE_SELECT = 0x21,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -34,3 +44,5 @@ typedef struct {
|
||||
} AssembleResult;
|
||||
|
||||
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_IN,
|
||||
TOKEN_KWORD_FUN,
|
||||
TOKEN_KWORD_LET,
|
||||
TOKEN_VALUE_FLOAT,
|
||||
TOKEN_VALUE_INT,
|
||||
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_IN: return S("in");
|
||||
case TOKEN_KWORD_FUN: return S("fun");
|
||||
case TOKEN_KWORD_LET: return S("let");
|
||||
|
||||
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("in"))) return (Token) { .type=TOKEN_KWORD_IN };
|
||||
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 };
|
||||
}
|
||||
|
||||
@@ -1299,6 +1302,49 @@ Node *parse_func_decl(Parser *p, int opflags)
|
||||
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)
|
||||
{
|
||||
Scanner saved = p->s;
|
||||
@@ -1310,6 +1356,9 @@ Node *parse_stmt(Parser *p, int opflags)
|
||||
case TOKEN_KWORD_FUN:
|
||||
return parse_func_decl(p, opflags);
|
||||
|
||||
case TOKEN_KWORD_LET:
|
||||
return parse_var_decl(p, opflags);
|
||||
|
||||
case TOKEN_KWORD_IF:
|
||||
return parse_ifelse_stmt(p, opflags);
|
||||
|
||||
@@ -1611,6 +1660,19 @@ void print_node(Node *node)
|
||||
printf(")");
|
||||
}
|
||||
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_ARG,
|
||||
NODE_FUNC_CALL,
|
||||
NODE_VAR_DECL,
|
||||
NODE_BLOCK,
|
||||
NODE_IFELSE,
|
||||
NODE_FOR,
|
||||
@@ -65,6 +66,9 @@ struct Node {
|
||||
String func_name;
|
||||
Node *func_args;
|
||||
Node *func_body;
|
||||
|
||||
String var_name;
|
||||
Node *var_value;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
||||
Reference in New Issue
Block a user