#include "run.h" #include "ast.h" #include "ht.h" #include #include // return pointer to nth subnode of AST_LIST node *l. // doesn't check that l is a list, or that it has at least n elems. #define NTH(l,n) (&(l)->as.list.vals[(n)]) // n is max index #define CK_LEN(s, l, n) do { if(l.len-1 != n) { \ printf("%s fn requires exactly %d args (%ld provided)",\ s, n, l.len-1); return 0; } } while(0); static int func_plus(Env *s, AstVec l) { CK_LEN("+",l,2); return eval(s, l.vals[1]) + eval(s, l.vals[2]); } static int func_id(Env *s, AstVec l) { CK_LEN("id",l,1); return eval(s, l.vals[1]); } static int func_minus(Env *s, AstVec l) { CK_LEN("-",l,2); return eval(s, l.vals[1]) - eval(s, l.vals[2]); } static int func_mult(Env *s, AstVec l) { CK_LEN("*",l,2); return eval(s, l.vals[1]) * eval(s, l.vals[2]); } static int func_div(Env *s, AstVec l) { CK_LEN("/",l,2); return eval(s, l.vals[1]) / eval(s, l.vals[2]); } static int func_print(Env *s, AstVec l) { CK_LEN("print",l,1); int v = eval(s, l.vals[1]); printf("%d\n",v); return v; } static int func_set(Env *s, AstVec l) { CK_LEN("set", l, 2); if (l.vals[1].ty != AST_SYMBOL) { printf("can only assign to symbols"); return 0; } int v = eval(s, l.vals[2]); printf(" %p set %s %d\n", (void*)s, l.vals[1].as.str, v); ht_put(s, l.vals[1].as.str, v); return v; } static int func_do(Env *s, AstVec l) { for (int i = 1; i < l.len; i++) { eval(s, l.vals[i]); } return 0; } typedef int (*builtin_func)(Env*, AstVec); typedef struct { char *name; builtin_func func; } BuiltinDesc; BuiltinDesc builtins[] = { { "+", func_plus }, { "-", func_minus }, { "*", func_mult }, { "/", func_div }, { "id", func_id }, { "print", func_print }, { "set", func_set }, { "do", func_do }, { NULL, NULL }, }; static int call_builtin(Env *s, char *name, AstVec arglist) { for (BuiltinDesc *bd = builtins; bd->name != NULL; bd++) { if (0 == strcmp(bd->name, name)) { return bd->func(s, arglist); } } printf("couldn't find builtin fn %s\n",name); return 0; } int eval(Env *s, AstNode a) { switch (a.ty) { case AST_SYMBOL:; int v; if (ht_get(s, a.as.str, &v)) { return v; } else { printf("unset variable %s\n",a.as.str); return 0; } break; case AST_NUM: return a.as.num; break; case AST_LIST:; AstVec l = a.as.list; if (l.len < 1) { printf("can't execute empty list\n"); return 0; } AstNode *first = &l.vals[0]; if (first->ty != AST_SYMBOL) { printf("first element of list must be symbol\n"); return 0; } return call_builtin(s, first->as.str, l); break; default: printf("???\n"); return 0; } }