pawengine/src/lang/ast.c
2025-03-13 17:58:19 +01:00

347 lines
9.2 KiB
C

#include <stdbool.h>
#include <stdlib.h>
#include "../log.h"
#include "ast.h"
enum PawVal *op_equals(struct PawAST *ast, enum PawVal *lhs, enum PawVal *rhs) {
if (*lhs == PAW_VAL_BOOL && *rhs == PAW_VAL_BOOL) {
if (*(bool *)val_get_data(lhs) == *(bool *)val_get_data(rhs)) {
return make_pawval_bool(ast->mem, true);
} else {
return make_pawval_bool(ast->mem, false);
}
}
float l;
float r;
if (*lhs == PAW_VAL_FLOAT) {
l = *(float *)val_get_data(lhs);
} else if (*lhs == PAW_VAL_INT) {
l = *(int *)val_get_data(lhs);
}
if (*rhs == PAW_VAL_FLOAT) {
r = *(float *)val_get_data(rhs);
} else if (*rhs == PAW_VAL_INT) {
r = *(int *)val_get_data(rhs);
}
if (l == r) {
return make_pawval_bool(ast->mem, true);
} else {
return make_pawval_bool(ast->mem, false);
}
}
enum PawVal *op_unequals(struct PawAST *ast, enum PawVal *lhs,
enum PawVal *rhs) {
enum PawVal *res = op_equals(ast, lhs, rhs);
*(bool *)val_get_data(res) = !*(bool *)val_get_data(res);
return res;
}
enum PawVal *op_add(struct PawAST *ast, enum PawVal *lhs, enum PawVal *rhs) {
return make_pawval_int(ast->mem,
*(int *)val_get_data(lhs) + *(int *)val_get_data(rhs));
}
enum PawVal *make_pawval_float(struct Mem *mem, float n) {
enum PawVal *val;
val_make(val, float, PAW_VAL_FLOAT);
float *f = val_get_data(val);
*f = n;
return val;
}
enum PawVal *make_pawval_int(struct Mem *mem, int n) {
enum PawVal *val;
val_make(val, int, PAW_VAL_INT);
int *i = (int *)val_get_data(val);
*i = n;
return val;
}
enum PawVal *make_pawval_bool(struct Mem *mem, bool n) {
enum PawVal *val;
val_make(val, bool, PAW_VAL_BOOL);
bool *i = val_get_data(val);
*i = n;
return val;
}
enum PawVal *make_pawval_point(struct Mem *mem, paw_p n) {
enum PawVal *val;
val_make(val, paw_p, PAW_VAL_INT);
paw_p *i = val_get_data(val);
*i = n;
return val;
}
enum PawVal *make_pawval_expr(struct Mem *mem, enum PawVal *lhs,
enum PawVal *rhs, paw_p op) {
enum PawVal *val;
val_make(val, struct PawExpr, PAW_VAL_EXPR);
struct PawExpr *i = val_get_data(val);
i->op = op;
i->lhs = lhs;
i->rhs = rhs;
return val;
*i = (struct PawExpr){
.op = op,
.lhs = lhs,
.rhs = rhs,
};
return val;
}
enum PawVal *make_pawval_func(struct Mem *mem) {
enum PawVal *val;
val_make(val, struct PawFunc, PAW_VAL_FUNC);
struct PawFunc *i = val_get_data(val);
return val;
}
void free_pawval(struct Mem *mem, enum PawVal *val) {
switch (*val) {
case PAW_VAL_FLOAT:
case PAW_VAL_INT:
case PAW_VAL_BOOL:
case PAW_VAL_POINT:
mem_free(mem, val);
break;
case PAW_VAL_FUNC:
crash("todo");
break;
case PAW_VAL_EXPR:;
struct PawExpr *expr = val_get_data(val);
free_pawval(mem, expr->lhs);
free_pawval(mem, expr->rhs);
mem_free(mem, val);
break;
}
}
enum PawCtrl *make_pawctrl_seq(struct Mem *mem) {
enum PawCtrl *ctrl;
ctrl_make(ctrl, struct PawSeq, PAW_CTRL_SEQ);
struct PawSeq *i = ctrl_get_data(ctrl);
dyn_array_create_inplace_mem(&i->seq, mem);
return ctrl;
}
enum PawCtrl *make_pawctrl_call(struct Mem *mem, paw_p addr) {
enum PawCtrl *ctrl;
ctrl_make(ctrl, struct PawCall, PAW_CTRL_CALL);
struct PawCall *i = ctrl_get_data(ctrl);
i->addr = addr;
return ctrl;
}
enum PawCtrl *make_pawctrl_while(struct Mem *mem, enum PawVal *cond,
enum PawCtrl *body) {
enum PawCtrl *ctrl;
ctrl_make(ctrl, struct PawWhile, PAW_CTRL_WHILE);
struct PawWhile *i = ctrl_get_data(ctrl);
i->body = body;
i->cond = cond;
return ctrl;
}
enum PawCtrl *make_pawctrl_asign(struct Mem *mem, enum PawVal *target,
enum PawVal *val) {
enum PawCtrl *ctrl;
ctrl_make(ctrl, struct PawAsign, PAW_CTRL_ASIGN);
struct PawAsign *i = ctrl_get_data(ctrl);
i->lhs = target;
i->rhs = val;
return ctrl;
}
void pawctrl_append(enum PawCtrl *seq, enum PawCtrl *ctrl) {
struct PawSeq *seqval = ctrl_get_data(seq);
dyn_array_append(&seqval->seq, ctrl);
}
void ping_func() { meow("ping"); }
struct PawAST *ast_make() {
struct Mem *mem = make_mem(8192);
struct PawAST *ast = mem_malloc(mem, sizeof(struct PawAST));
ast->mem = mem;
ast->ping_func = ping_func;
ast->prog = make_pawctrl_seq(ast->mem);
dyn_array_create_inplace_mem(&ast->properties, ast->mem);
return ast;
}
enum PawVal *ast_get_property(struct PawAST *ast, char *name) {
for (int i = 0; i < ast->properties.count; i++) {
if (strcmp(ast->properties.items[i].name, name) == 0) {
return ast->properties.items[i].val;
}
}
meow("could not find property %s", name);
return NULL;
}
void ast_insert_property(struct PawAST *ast, char *name, enum PawVal *val) {
dyn_array_append(&ast->properties, ((struct PawProperty){name, val}));
}
struct Stack *stack_make(struct Mem *mem, size_t size) {
struct Stack *stack = mem_malloc(mem, sizeof(struct Stack));
stack->left = mem_malloc(mem, size);
stack->right = stack->left + size;
stack->top = stack->right;
return stack;
}
void stack_pop(struct Stack *stack) {
stack->top = stack->top + sizeof(void *);
if (stack->top > stack->right) {
meow("pop stack is %p:%p:%p", stack->left, stack->top, stack->right);
crash("uuuh am in cellar");
}
}
void stack_push(struct Stack *stack, void *v) {
stack->top = stack->top - sizeof(void *);
if (stack->top < stack->left) {
crash("uuuh am in space");
}
*(void **)stack->top = v;
}
void *stack_poke(struct Stack *stack) { return *(void **)stack->top; }
void *stack_poke2(struct Stack *stack) {
return *(void **)(stack->top + sizeof(void *));
}
void stack_set2(struct Stack *stack, void *v) {
void **n = stack->top + sizeof(void *);
*n = v;
}
void stack_free(struct Stack *stack, struct Mem *mem) {
mem_free(mem, stack->left);
mem_free(mem, stack);
}
void ast_stack_push(struct Stack *stack, enum PawCtrl *ctrl) {
switch (*ctrl) {
case PAW_CTRL_SEQ:
stack_push(stack, NULL);
stack_push(stack, ctrl);
break;
case PAW_CTRL_ASIGN:
case PAW_CTRL_CALL:
case PAW_CTRL_WHILE:
stack_push(stack, ctrl);
break;
}
}
// will no ownership of val is transferred and val will not be touched,
// the caller takes ownership of the returned value which is always a newly
// allocated value
enum PawVal *ast_eval(struct PawAST *ast, enum PawVal *val) {
switch (*val) {
case PAW_VAL_FLOAT:
return make_pawval_float(ast->mem, *(float *)val_get_data(val));
case PAW_VAL_INT:
return make_pawval_int(ast->mem, *(int *)val_get_data(val));
case PAW_VAL_BOOL:
return make_pawval_bool(ast->mem, *(bool *)val_get_data(val));
case PAW_VAL_POINT:
return make_pawval_point(ast->mem, *(void **)val_get_data(val));
case PAW_VAL_FUNC:
meow("todo");
break;
case PAW_VAL_EXPR:;
struct PawExpr *expr = val_get_data(val);
enum PawVal *lhs = ast_eval(ast, expr->lhs);
enum PawVal *rhs = ast_eval(ast, expr->rhs);
enum PawVal *ret = expr->op(ast, lhs, rhs);
free_pawval(ast->mem, lhs);
free_pawval(ast->mem, rhs);
return ret;
break;
}
meow("unreachable");
return NULL;
}
void ast_exec(struct PawAST *ast) {
meow("allocing stack");
struct Stack *stack = stack_make(ast->mem, 2048);
ast_stack_push(stack, ast->prog);
meow("starting exec");
while (stack->top < stack->right) {
enum PawCtrl *ctrl = stack_poke(stack);
switch (*ctrl) {
case PAW_CTRL_SEQ:;
int i = (int64_t)(stack_poke2(stack));
struct PawSeq *seq = ctrl_get_data(ctrl);
if (i >= seq->seq.count) {
stack_pop(stack);
stack_pop(stack);
continue;
}
stack_set2(stack, (void *)(uint64_t)(i + 1));
ast_stack_push(stack, seq->seq.items[i]);
break;
case PAW_CTRL_CALL:;
struct PawCall *call = ctrl_get_data(ctrl);
if (call->addr == ast->ping_func) {
ping_func();
}
stack_pop(stack);
break;
case PAW_CTRL_WHILE:;
struct PawWhile *whle = ctrl_get_data(ctrl);
enum PawVal *ret = ast_eval(ast, whle->cond);
if (*ret != PAW_VAL_BOOL) {
meow("unsuported");
}
bool *v = val_get_data(ret);
if (*v) {
ast_stack_push(stack, whle->body);
} else {
stack_pop(stack);
}
free_pawval(ast->mem, ret);
break;
case PAW_CTRL_ASIGN:;
struct PawAsign *asign = ctrl_get_data(ctrl);
enum PawVal *val = ast_eval(ast, asign->rhs);
if (*val != *asign->lhs) {
crash("woopsie wrong type");
}
switch (*val) {
case PAW_VAL_FLOAT:;
float *ft = val_get_data(asign->lhs);
*ft = *(float *)val_get_data(val);
break;
case PAW_VAL_INT:;
int *it = val_get_data(asign->lhs);
*it = *(int *)val_get_data(val);
break;
case PAW_VAL_BOOL:
bool *bt = val_get_data(asign->lhs);
*bt = *(bool *)val_get_data(val);
break;
case PAW_VAL_POINT:;
paw_p *pt = val_get_data(asign->lhs);
*bt = *(paw_p *)val_get_data(val);
break;
case PAW_VAL_EXPR:
case PAW_VAL_FUNC:
meow("whhooopsie not primitive");
break;
}
free_pawval(ast->mem, val);
stack_pop(stack);
break;
}
}
meow("ending exec");
}