#include "run.h" #include "ast.h" #include #include // static int valueof(AstNode *a) { // if (a->ty != AST_NUM) { // printf("i need a number\n"); // return -1; // } else { // return a->as.num; // } // } // void run_thing(AstNode *a) { // if (a->ty != AST_LIST) // printf("can only run a list\n"); // else if (a->as.list.len < 3) // printf("need at least 3 elements\n"); // else { // AstNode *fn = &a->as.list.vals[0]; // if (fn->ty != AST_SYMBOL) // printf("first el needs to be symbol\n"); // else if (strcmp(fn->as.str, "+")) // printf("can only run +\n"); // else { // int v1 = valueof(&a->as.list.vals[1]); // int v2 = valueof(&a->as.list.vals[2]); // printf("=> %d\n",v1+v2); // } // } // } int eval (AstNode a); // 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(AstVec l) { CK_LEN("+",l,2); return eval(l.vals[1]) + eval(l.vals[2]); } static int func_id(AstVec l) { CK_LEN("id",l,1); return eval(l.vals[1]); } static int func_minus(AstVec l) { CK_LEN("-",l,2); return eval(l.vals[1]) - eval(l.vals[2]); } static int func_mult(AstVec l) { CK_LEN("*",l,2); return eval(l.vals[1]) * eval(l.vals[2]); } static int func_div(AstVec l) { CK_LEN("/",l,2); return eval(l.vals[1]) / eval(l.vals[2]); } static int func_print(AstVec l) { CK_LEN("print",l,1); int v = eval(l.vals[1]); printf("%d\n",v); return v; } typedef int (*builtin_func)(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 }, { NULL, NULL }, }; static int call_builtin(char *name, AstVec arglist) { for (BuiltinDesc *bd = builtins; bd->name != NULL; bd++) { if (0 == strcmp(bd->name, name)) { return bd->func(arglist); } } printf("couldn't find builtin fn %s\n",name); return 0; } int eval(AstNode a) { switch (a.ty) { case AST_SYMBOL: printf("cant yet read 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(first->as.str, l); break; default: printf("???\n"); return 0; } }