Looking good

This commit is contained in:
2025-08-04 15:36:59 +02:00
parent 71968d2b59
commit 9f96f1ffaa
8 changed files with 1123 additions and 669 deletions
+4 -4
View File
@@ -1,5 +1,5 @@
let a = 5
let b = 5
if a == b: print "a and b are the same\n"
else print "they are not the same!\n"
fun a(name)
<a>My name is \(name)</a>
a("Francesco")
-46
View File
@@ -1,46 +0,0 @@
let title = "My Website"
let posts = [
{
name: "Post Title 1",
date: "1 Jan 2025",
comments: [
{ author: "User 1", date: "1 Jan 2025", content: "This is a comment" },
{ author: "User 2", date: "2 Jan 2025", content: "Second comment" },
]
},
{
name: "Post Title 2",
date: "4 July 2022",
comments: [
{ author: "User 1", date: "1 Jan 2025", content: "This is a comment" },
{ author: "User 2", date: "2 Jan 2025", content: "Second comment" },
]
},
]
fun render_comment(c)
<div class="comment">
<a>\c.author (\c.date)</a>
<p>\c.content</p>
<div class="comment-children">
\for child in c.children:
render_comment(child)
</div>
</div>
<html>
<head>
<title>\title</title>
</head>
<body>
<a>This is regular text</a>
\for post in posts:
<div class="post">
<a>\post.title (\post.date)</a>
\for comment in post.comments:
render_comment(comment)
</div>
</body>
</html>
+846 -529
View File
File diff suppressed because it is too large Load Diff
+10 -2
View File
@@ -6,6 +6,13 @@
enum {
OPCODE_NOPE = 0x00,
OPCODE_EXIT = 0x23,
OPCODE_GROUP = 0x25,
OPCODE_GPOP = 0x26,
OPCODE_GPRINT = 0x27,
OPCODE_GTRUNC = 0x28,
OPCODE_GCOALESCE = 0x29,
OPCODE_GOVERWRITE = 0x2A,
OPCODE_GPACK = 0x2B,
OPCODE_PUSHI = 0x01,
OPCODE_PUSHF = 0x02,
OPCODE_PUSHS = 0x03,
@@ -28,7 +35,6 @@ enum {
OPCODE_JUMP = 0x13,
OPCODE_JIFP = 0x14,
OPCODE_CALL = 0x15,
OPCODE_VARS = 0x22,
OPCODE_RET = 0x16,
OPCODE_APPEND = 0x17,
OPCODE_INSERT1 = 0x18,
@@ -47,7 +53,9 @@ typedef struct {
int errlen;
} AssembleResult;
void print_program(Program p);
int parse_program_header(Program p, String *code, String *data, char *errbuf, int errmax);
void print_program(Program program);
char *print_instruction(char *p, char *data);
AssembleResult assemble(Node *root, Arena *arena, char *errbuf, int errmax);
#endif // WL_ASSEMBLE_INCLUDED
+201 -75
View File
@@ -9,6 +9,7 @@
#define FRAME_LIMIT 128
#define EVAL_STACK_LIMIT 128
#define GROUP_LIMIT 128
#define HEAP_BASE 0xFEEDBEEFFEEDBEEF
@@ -84,8 +85,8 @@ typedef struct {
} StringValue;
typedef struct {
int base;
int return_off;
int group;
int return_addr;
} Frame;
typedef struct {
@@ -100,12 +101,15 @@ typedef struct {
int errmax;
int errlen;
int frame_depth;
int num_frames;
Frame frames[FRAME_LIMIT];
int eval_depth;
Value eval_stack[EVAL_STACK_LIMIT];
int num_groups;
int groups[GROUP_LIMIT];
} Eval;
#define VALUE_NONE ((Value) 0)
@@ -224,7 +228,7 @@ Value make_float(Eval *e, float x)
return ((Value) v) | 7;
}
Value make_str(Eval *e, String x)
Value make_str(Eval *e, String x) // TODO: This should reuse the string contents when possible
{
StringValue *v = alloc(e->a, (int) sizeof(StringValue) + x.len, 8);
if (v == NULL) {
@@ -276,6 +280,8 @@ b32 valeq(Value a, Value b);
int map_select(Eval *e, Value map, Value key, Value *val)
{
(void) e;
MapValue *p = get_map(map);
MapItems *batch = &p->head;
while (batch) {
@@ -319,8 +325,37 @@ int map_insert(Eval *e, Value map, Value key, Value val)
return 0;
}
Value *array_select(Eval *e, Value array, uint32_t key)
void value_print(Value v);
void map_print(Value v)
{
printf("{ ");
MapValue *p = get_map(v);
MapItems *batch = &p->head;
while (batch) {
int num = ITEMS_PER_MAP_BATCH;
if (batch->next == NULL)
num = p->tail_count;
for (int i = 0; i < num; i++) {
value_print(batch->keys[i]);
printf(": ");
value_print(batch->items[i]);
printf(", ");
}
batch = batch->next;
}
printf("}");
}
Value *array_select(Eval *e, Value array, int key)
{
(void) e;
ArrayValue *p = get_array(array);
ArrayItems *batch = &p->head;
int cursor = 0;
@@ -362,6 +397,25 @@ int array_append(Eval *e, Value array, Value val)
return 0;
}
void array_print(Value v)
{
ArrayValue *p = get_array(v);
ArrayItems *batch = &p->head;
int cursor = 0;
while (batch) {
int num = ITEMS_PER_MAP_BATCH;
if (batch->next == NULL)
num = p->tail_count;
for (int i = 0; i < num; i++)
value_print(batch->items[i]);
batch = batch->next;
cursor += num;
}
}
b32 valeq(Value a, Value b)
{
Type t1 = type_of(a);
@@ -438,9 +492,58 @@ b32 valgrt(Value a, Value b)
return false;
}
void value_print(Value v)
{
switch (type_of(v)) {
case TYPE_NONE:
printf("none");
break;
case TYPE_BOOL:
printf(v == VALUE_TRUE ? "true" : "false");
break;
case TYPE_INT:
printf("%" LLD, get_int(v));
break;
case TYPE_FLOAT:
printf("%lf", get_float(v));
break;
case TYPE_MAP:
map_print(v);
break;
case TYPE_ARRAY:
array_print(v);
break;
case TYPE_STRING:
{
String s = get_str(v);
printf("%.*s", s.len, s.ptr);
}
break;
case TYPE_ERROR:
printf("error");
break;
}
fflush(stdout);
}
int step(Eval *e)
{
uint8_t opcode = e->code.ptr[e->off++];
uint8_t opcode = e->code.ptr[e->off];
/*
printf("%-3d: ", e->off);
print_instruction(e->code.ptr + e->off, e->data.ptr);
printf("\n");
*/
e->off++;
switch (opcode) {
case OPCODE_NOPE:
@@ -455,6 +558,77 @@ int step(Eval *e)
}
break;
case OPCODE_GROUP:
{
e->groups[e->num_groups++] = e->eval_depth;
}
break;
case OPCODE_GPOP:
{
int group = e->groups[--e->num_groups];
e->eval_depth = group;
}
break;
case OPCODE_GPRINT:
{
for (int i = e->groups[e->num_groups-1]; i < e->eval_depth; i++)
value_print(e->eval_stack[i]);
}
break;
case OPCODE_GCOALESCE:
{
e->num_groups--;
}
break;
case OPCODE_GTRUNC:
{
uint32_t num;
memcpy(&num, (uint8_t*) e->code.ptr + e->off, sizeof(uint32_t));
e->off += (int) sizeof(uint32_t);
int group_size = e->eval_depth - e->groups[e->num_groups-1];
if (group_size < (int) num) {
for (int i = 0; i < (int) num - group_size; i++)
e->eval_stack[e->eval_depth + i] = VALUE_NONE;
}
e->eval_depth = e->groups[e->num_groups-1] + num;
}
break;
case OPCODE_GOVERWRITE:
{
int current = e->groups[e->num_groups-1];
int parent = e->groups[e->num_groups-2];
int current_size = e->eval_depth - current;
for (int i = 0; i < current_size; i++)
e->eval_stack[parent + i] = e->eval_stack[current + i];
e->num_groups--;
e->eval_depth = parent + current_size;
}
break;
case OPCODE_GPACK:
{
Value array = make_array(e);
if (array == VALUE_ERROR)
return -1;
for (int i = e->groups[e->num_groups-1]; i < e->eval_depth; i++)
array_append(e, array, e->eval_stack[i]);
e->eval_depth = e->groups[--e->num_groups];
e->eval_stack[e->eval_depth++] = array;
}
break;
case OPCODE_PUSHN:
{
e->eval_stack[e->eval_depth++] = VALUE_NONE;
@@ -510,7 +684,10 @@ int step(Eval *e)
memcpy(&idx, (uint8_t*) e->code.ptr + e->off, sizeof(uint8_t));
e->off += sizeof(uint8_t);
e->eval_stack[e->eval_depth++] = e->eval_stack[e->frames[e->frame_depth-1].base + idx];
int group = e->frames[e->num_frames-1].group;
Value v = e->eval_stack[e->groups[group] + idx];
e->eval_stack[e->eval_depth++] = v;
}
break;
@@ -542,6 +719,7 @@ int step(Eval *e)
case OPCODE_POP:
{
assert(e->num_groups == 0 || e->eval_depth > e->groups[e->num_groups-1]);
e->eval_depth--;
}
break;
@@ -889,8 +1067,8 @@ int step(Eval *e)
memcpy(&x, (uint8_t*) e->code.ptr + e->off, (int) sizeof(x));
e->off += (int) sizeof(x);
Frame *f = &e->frames[e->frame_depth-1];
e->eval_stack[f->base + x] = e->eval_stack[--e->eval_depth];
Frame *f = &e->frames[e->num_frames-1];
e->eval_stack[e->groups[f->group] + x] = e->eval_stack[--e->eval_depth];
}
break;
@@ -923,50 +1101,23 @@ int step(Eval *e)
case OPCODE_CALL:
{
uint8_t num;
memcpy(&num, (uint8_t*) e->code.ptr + e->off, sizeof(uint8_t));
e->off += (int) sizeof(uint8_t);
uint32_t off;
memcpy(&off, (uint8_t*) e->code.ptr + e->off, sizeof(uint32_t));
e->off += (int) sizeof(uint32_t);
// Push a dummy value for the return value
e->eval_stack[e->eval_depth++] = VALUE_NONE;
if (e->frame_depth == FRAME_LIMIT) {
if (e->num_frames == FRAME_LIMIT) {
eval_report(e, "Frame limit reached");
return -1;
}
Frame *f = &e->frames[e->frame_depth++];
f->base = e->eval_depth;
f->return_off = e->off;
e->frames[e->num_frames++] = (Frame) {.return_addr=e->off, .group=e->num_groups-1};
e->off = off;
}
break;
case OPCODE_VARS:
{
uint32_t num;
memcpy(&num, e->code.ptr + e->off, sizeof(uint32_t));
e->off += sizeof(uint32_t);
e->eval_depth += num;
}
break;
case OPCODE_RET:
{
Frame *f = &e->frames[--e->frame_depth];
assert(e->eval_depth > f->base);
Value r = e->eval_stack[--e->eval_depth];
e->off = f->return_off;
e->eval_depth = f->base;
e->eval_stack[e->eval_depth-1] = r;
e->off = e->frames[--e->num_frames].return_addr;
}
break;
@@ -1076,18 +1227,7 @@ int step(Eval *e)
case OPCODE_PRINT:
{
Value v = e->eval_stack[e->eval_depth-1];
switch (type_of(v)) {
case TYPE_NONE : printf("none"); break;
case TYPE_BOOL : printf(v == VALUE_TRUE ? "true" : "false"); break;
case TYPE_INT : printf("%" LLD, get_int(v)); break;
case TYPE_FLOAT : printf("%lf", get_float(v)); break;
case TYPE_MAP : printf("map"); break;
case TYPE_ARRAY : printf("array"); break;
case TYPE_STRING: printf("%.*s", get_str(v).len, get_str(v).ptr); break;
case TYPE_ERROR : printf("error"); break;
}
fflush(stdout);
value_print(v);
}
break;
@@ -1101,42 +1241,27 @@ int step(Eval *e)
int eval(Program p, Arena *a, char *errbuf, int errmax)
{
if (p.len < 3 * sizeof(uint32_t)) {
snprintf(errbuf, errmax, "Invalid program");
return -1;
}
uint32_t magic;
uint32_t code_size;
uint32_t data_size;
memcpy(&magic, p.ptr + 0, sizeof(uint32_t));
memcpy(&code_size, p.ptr + 4, sizeof(uint32_t));
memcpy(&data_size, p.ptr + 8, sizeof(uint32_t));
String code;
String data;
if (magic != 0xFEEDBEEF) {
snprintf(errbuf, errmax, "Invalid program");
int ret = parse_program_header(p, &code, &data, errbuf, errmax);
if (ret < 0)
return -1;
}
if (code_size + data_size + 3 * sizeof(uint32_t) != p.len) {
snprintf(errbuf, errmax, "Invalid program");
return -1;
}
Eval e = {
.code = { p.ptr + 3 * sizeof(uint32_t), code_size },
.data = { p.ptr + 3 * sizeof(uint32_t) + code_size, data_size },
.code=code,
.data=data,
.off=0,
.a=a,
.errbuf=errbuf,
.errmax=errmax,
.errlen=0,
.frame_depth=0,
.num_frames=0,
.eval_depth=0,
.num_groups=0,
};
Frame *f = &e.frames[e.frame_depth++];
f->base = 0;
f->return_off = 0;
e.frames[e.num_frames++] = (Frame) { 0, 0 };
for (;;) {
int ret = step(&e);
@@ -1144,5 +1269,6 @@ int eval(Program p, Arena *a, char *errbuf, int errmax)
if (ret == 1) break;
}
e.num_frames--;
return 0;
}
+3 -3
View File
@@ -25,8 +25,8 @@ int main(void)
return -1;
}
//print_node(parse_result.node);
//printf("\n");
print_node(parse_result.node);
printf("\n");
AssembleResult assemble_result = assemble(parse_result.node, &a, err, COUNT(err));
if (assemble_result.errlen) {
@@ -34,7 +34,7 @@ int main(void)
return -1;
}
//print_program(assemble_result.program);
print_program(assemble_result.program);
ret = eval(assemble_result.program, &a, err, COUNT(err));
if (ret < 0) {
+57 -8
View File
@@ -203,8 +203,19 @@ Node *alloc_node(Parser *p)
Token next_token(Parser *p)
{
while (p->s.cur < p->s.len && is_space(p->s.src[p->s.cur]))
p->s.cur++;
for (;;) {
while (p->s.cur < p->s.len && is_space(p->s.src[p->s.cur]))
p->s.cur++;
if (!consume_str(&p->s, S("<!--")))
break;
while (p->s.cur < p->s.len) {
if (consume_str(&p->s, S("-->")))
break;
p->s.cur++;
}
}
if (p->s.cur == p->s.len)
return (Token) { .type=TOKEN_END };
@@ -406,6 +417,7 @@ Token next_token_or_newline(Parser *p)
enum {
IGNORE_GRT = 1 << 0,
IGNORE_LSS = 1 << 1,
IGNORE_DIV = 1 << 2,
};
Node *parse_stmt(Parser *p, int opflags);
@@ -429,6 +441,7 @@ Node *parse_html(Parser *p)
Node *param_head;
Node **param_tail = &param_head;
b32 no_body = false;
for (;;) {
int param_offset = p->s.cur;
@@ -437,8 +450,20 @@ Node *parse_html(Parser *p)
Node *attr_value;
t = next_token(p);
if (t.type == TOKEN_OPER_GRT)
break;
if (t.type == TOKEN_OPER_DIV) {
t = next_token(p);
if (t.type != TOKEN_OPER_GRT) {
parser_report(p, "Invalid token '/' inside an HTML tag");
return NULL;
}
no_body = true;
break;
}
if (t.type != TOKEN_IDENT) {
parser_report(p, "Invalid token inside HTML tag");
return NULL;
@@ -449,7 +474,7 @@ Node *parse_html(Parser *p)
t = next_token(p);
if (t.type == TOKEN_OPER_ASS) {
attr_value = parse_expr(p, IGNORE_GRT);
attr_value = parse_expr(p, IGNORE_GRT | IGNORE_DIV);
if (attr_value == NULL)
return NULL;
@@ -476,13 +501,26 @@ Node *parse_html(Parser *p)
Node *head;
Node **tail = &head;
for (;;) {
if (!no_body) for (;;) {
for (;;) {
int off = p->s.cur;
while (p->s.cur < p->s.len && p->s.src[p->s.cur] != '<' && p->s.src[p->s.cur] != '\\')
p->s.cur++;
for (;;) {
while (p->s.cur < p->s.len && p->s.src[p->s.cur] != '<' && p->s.src[p->s.cur] != '\\')
p->s.cur++;
if (!consume_str(&p->s, S("<!--")))
break;
while (p->s.cur < p->s.len) {
if (consume_str(&p->s, S("-->")))
break;
p->s.cur++;
}
}
if (p->s.cur > off) {
@@ -715,9 +753,13 @@ int precedence(Token t, int flags)
return 3;
case TOKEN_OPER_MUL:
case TOKEN_OPER_DIV:
case TOKEN_OPER_MOD:
return 3;
return 4;
case TOKEN_OPER_DIV:
if (flags & IGNORE_DIV)
return -1;
return 4;
default:
break;
@@ -1481,6 +1523,13 @@ void print_node(Node *node)
{
switch (node->type) {
case NODE_PRINT:
{
printf("print ");
print_node(node->left);
}
break;
case NODE_BLOCK:
{
printf("{");