347 lines
9.2 KiB
C
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");
|
|
}
|