#include #include #include #include #include "interpreter.h" #include "inter_builtins.h" #include "util.h" int namehash(const char *name,int mod){ int h=0; for(int i=0;name[i];i++)h+=name[i]; return h%mod; } #define VMAP_HASHSZ (61) typedef struct Vllist{ char *name; AST *value; struct Vllist *next; } Vllist; typedef struct Scope{ Vllist *vmap[VMAP_HASHSZ]; struct Scope *next; } Scope; typedef struct Symbolstore{ int sz,len; char **syms; } Symbolstore; struct InterState{ Scope *scope; Symbolstore ss; }; Scope* scope_make(void){ Scope *scope=malloc(1,Scope); memset(scope->vmap,0,VMAP_HASHSZ*sizeof(Vllist*)); scope->next=NULL; return scope; } InterState* inter_make(void){ InterState *is=malloc(1,InterState); is->scope=scope_make(); is->ss.sz=16; is->ss.len=0; is->ss.syms=malloc(is->ss.sz,char*); return is; } static void scope_destroy(Scope *scope,bool recursive){ do { for(int i=0;ivmap[i]){ Vllist *ll=scope->vmap[i]; free(ll->name); ast_free(ll->value); scope->vmap[i]=ll->next; free(ll); } } Scope *next=scope->next; free(scope); scope=next; } while(recursive&&scope); } void inter_destroy(InterState *is){ assert(is); scope_destroy(is->scope,true); for(int i=0;iss.len;i++)free(is->ss.syms[i]); free(is->ss.syms); } static void intern_symbols(InterState *is,AST *ast){ switch(ast->type){ case AST_LIST: for(int i=0;ili.len;i++)intern_symbols(is,ast->li.nodes[i]); break; case AST_SYMBOL:{ if(ast->sy.symid>=0&&ast->sy.symidss.len&&strcmp(ast->sy.name,is->ss.syms[ast->sy.symid])==0){ break; } int i; for(i=0;iss.len;i++){ if(strcmp(is->ss.syms[i],ast->sy.name)==0)break; } if(iss.len){ ast->sy.symid=i; break; } if(is->ss.len==is->ss.sz){ is->ss.sz*=2; is->ss.syms=realloc(is->ss.syms,is->ss.sz,char*); } is->ss.syms[is->ss.len++]=copystring(ast->sy.name); break; } case AST_QUOTED: intern_symbols(is,ast->qu.ast); break; case AST_WORD: case AST_NUMBER: case AST_STRING: break; default: assert(false); } } static const AST* find_var(const InterState *is,const char *name){ int h=namehash(name,VMAP_HASHSZ); for(const Scope *scope=is->scope;scope;scope=scope->next){ for(const Vllist *ll=scope->vmap[h];ll;ll=ll->next){ if(strcmp(name,ll->name)==0)return ll->value; } } return NULL; } InterRet ir_ast(AST *ast){ InterRet ir={ast,NULL}; return ir; } InterRet ir_err(char *errstr){ InterRet ir={NULL,errstr}; return ir; } InterRet ir_err_c(const char *errstr){ return ir_err(copystring(errstr)); } static char* replace_arguments(AST *ast,int nargs,AST **args){ switch(ast->type){ case AST_LIST: for(int i=0;ili.len;i++){ replace_arguments(ast->li.nodes[i],nargs,args); } break; case AST_LAMBDAARG:{ assert(ast->ar.idx>=0); if(ast->ar.idx>=nargs){ return copystring("Too few arguments passed to lambda function"); } AST *copy=ast_copy(args[ast->ar.idx]); memcpy(ast,copy,sizeof(AST)); break; } case AST_QUOTED: replace_arguments(ast->qu.ast,nargs,args); break; case AST_LAMBDA: case AST_WORD: case AST_NUMBER: case AST_STRING: case AST_SYMBOL: break; default: assert(false); } return NULL; } InterRet interpret(InterState *is,const AST *ast){ //fprintf(stderr,"Interpreting %s\n",ast_stringify(ast)); switch(ast->type){ case AST_LIST:{ if(ast->li.len==0){ return ir_ast(ast_copy(ast)); } assert(ast->li.len>0); AST *nodes[ast->li.len]; for(int i=0;ili.len;i++){ InterRet ir=interpret(is,ast->li.nodes[i]);; if(ir.errstr){ while(i-->0)ast_free(nodes[i]); return ir; } nodes[i]=ir.ast; } if(nodes[0]->type!=AST_LAMBDA){ return ir_err_c("First node in evaluated list not a function"); } /*AST *temp=ast_list(ast->li.len,nodes); char *ss=ast_stringify(temp); free(temp); fprintf(stderr,"Function call: %s\n",ss); free(ss);*/ if(nodes[0]->la.body){ char *errstr=replace_arguments(nodes[0]->la.body,ast->li.len-1,nodes+1); if(errstr)return ir_err(errstr); return interpret(is,nodes[0]->la.body); } InterRet ir=nodes[0]->la.cfunc(is,ast->li.len-1,nodes+1); for(int i=0;ili.len;i++)ast_free(nodes[i]); return ir; } case AST_SYMBOL: return ir_ast(ast_copy(ast)); case AST_WORD:{ const AST *cv=find_var(is,ast->wo.word); if(cv)return ir_ast(ast_copy(cv)); char *errstr; asprintf(&errstr,"Unknown variable '%s'",ast->wo.word); if(!errstr)outofmem(); return ir_err(errstr); } case AST_NUMBER: return ir_ast(ast_copy(ast)); case AST_STRING: return ir_ast(ast_copy(ast)); case AST_QUOTED: return ir_ast(ast_copy(ast->qu.ast)); default: assert(false); } } void inter_assign(InterState *is,const char *name,AST *ast){ assert(is->scope); int h=namehash(name,VMAP_HASHSZ); Vllist *ll=malloc(1,Vllist); ll->name=copystring(name); ll->value=ast; ll->next=is->scope->vmap[h]; is->scope->vmap[h]=ll; } void inter_register(InterState *is,const char *name,lambdafunc_t cfunc){ inter_assign(is,name,ast_lambda(cfunc,NULL)); } void inter_register_prelude(InterState *is){ inter_register(is,"do",builtin_do); inter_register(is,"?",builtin_if); inter_register(is,"if",builtin_if); inter_register(is,"print",builtin_print); inter_register(is,"=",builtin_equals); inter_register(is,">",builtin_greater); inter_register(is,">=",builtin_greaterequals); inter_register(is,"<",builtin_less); inter_register(is,"<=",builtin_lessequals); inter_register(is,"equals",builtin_equals); inter_register(is,"greater",builtin_greater); inter_register(is,"greaterequals",builtin_greaterequals); inter_register(is,"less",builtin_less); inter_register(is,"lessequals",builtin_lessequals); inter_register(is,"+",builtin_sum); inter_register(is,"-",builtin_difference); inter_register(is,"*",builtin_product); inter_register(is,"/",builtin_quotient); inter_register(is,"%",builtin_remainder); inter_register(is,"sum",builtin_sum); inter_register(is,"difference",builtin_difference); inter_register(is,"product",builtin_product); inter_register(is,"quotient",builtin_quotient); inter_register(is,"remainder",builtin_remainder); inter_register(is,"define",builtin_define); } InterRet inter_runcode(InterState *is,AST *ast){ intern_symbols(is,ast); return interpret(is,ast); }