int main(int argc, char *argv[]) { VM *vm = vm_create(hello, sizeof(hello), 0); vm_exec(vm, 0, false); vm_free(vm); // int t1 = (clock() / (CLOCKS_PER_SEC / 1000)); vm = vm_create(loop, sizeof(loop), 2); vm_exec(vm, 0, false); vm_print_data(vm->globals, vm->nglobals); vm_free(vm); // int t2 = (clock() / (CLOCKS_PER_SEC / 1000)); vm = vm_create(factorial, sizeof(factorial), 0); vm_exec(vm, 23, false); vm_free(vm); vm = vm_create(f, sizeof(f), 0); vm_exec(vm, 0, false); vm_free(vm); // printf("duration = %d ms\n", (t2 - t1)); return 0; }
int main(int argc, char **argv) { FILE *file = NULL; char *code = (char *) malloc(BUFFER_LEN); size_t code_len = 0; size_t bytes_read = 0; if (argc >= 2) { file = fopen(argv[1], "r"); } else { file = stdin; } if (file == NULL) { fputs("Must provide a file as the first argument, or piped into stdin.", stderr); exit(1); } while (bytes_read = fread((code + code_len), 1, BUFFER_LEN, file)) { code_len += bytes_read; code = (char *) realloc(code, code_len + BUFFER_LEN); } vm_init( vm_exec(code); fclose(file); }
int repl(){ char *a = calloc(1, 1000 * sizeof(char)); xenon_stack_vector stack; stack.size = 1000; while(1){ stack.vector = calloc(1, 1000 * sizeof(xenon_stack_item)); printf("Xenon> "); input(a, 1000); if(strcmp(a, ".exit") == 0){ return 0; } char *b = preprocessor(a); mpc_ast_t *ast = parse("stdin", b); free(b); if(ast != NULL){ stack.cursor = 0; mpc_ast_print(ast); //vm_add_opcode_to_stack(&stack, HALT); tree_walker(ast, stack); vm_add_opcode_to_stack(&stack, CONST); vm_add_int_to_stack(&stack, 10); printf("%i\n", stack.cursor); VM *vm = vm_create(stack, 0); mpc_ast_delete(ast); vm_exec(vm, 0, false); vm_free(vm); } if(stack.vector != NULL){ free(stack.vector); } } free(a); return 0; }
void vm_run(int at) { pcounter = at; while(running) { vm_exec(); } }
int main(int argc, char *argv[]) { FILE *f = fopen(argv[1], "r"); if ( f!=NULL ) { VM *vm = vm_load(f); vm_exec(vm, false); } return 0; }
VALUE rb_iseq_eval_main(VALUE iseqval) { rb_thread_t *th = GET_THREAD(); VALUE val; volatile VALUE tmp; vm_set_main_stack(th, iseqval); val = vm_exec(th); tmp = iseqval; /* prohibit tail call optimization */ return val; }
static inline VALUE invoke_block_from_c(rb_thread_t *th, const rb_block_t *block, VALUE self, int argc, const VALUE *argv, const rb_block_t *blockptr, const NODE *cref) { if (SPECIAL_CONST_P(block->iseq)) return Qnil; else if (BUILTIN_TYPE(block->iseq) != T_NODE) { const rb_iseq_t *iseq = block->iseq; const rb_control_frame_t *cfp; rb_control_frame_t *ncfp; int i, opt_pc, arg_size = iseq->arg_size; int type = block_proc_is_lambda(block->proc) ? VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK; rb_vm_set_finish_env(th); cfp = th->cfp; CHECK_STACK_OVERFLOW(cfp, argc + iseq->stack_max); for (i=0; i<argc; i++) { cfp->sp[i] = argv[i]; } opt_pc = vm_yield_setup_args(th, iseq, argc, cfp->sp, blockptr, type == VM_FRAME_MAGIC_LAMBDA); ncfp = vm_push_frame(th, iseq, type, self, GC_GUARDED_PTR(block->dfp), iseq->iseq_encoded + opt_pc, cfp->sp + arg_size, block->lfp, iseq->local_size - arg_size); ncfp->me = th->passed_me; th->passed_me = 0; th->passed_block = blockptr; if (cref) { th->cfp->dfp[-1] = (VALUE)cref; } return vm_exec(th); } else { return vm_yield_with_cfunc(th, block, self, argc, argv, blockptr); } }
/** * Runs the specified Gunderscript "exported" function. * instance: an instance of Gunderscript. * entryPoint: the name of an entryPoint function to run. * entryPointLen: the length of entryPoint in chars. * returns: true if a success, and false if an error occurs. */ GSAPI bool gunderscript_function(Gunderscript * instance, char * entryPoint, size_t entryPointLen) { VMFunc * function; /* get compiler function definitions */ function = vm_function(instance->vm, entryPoint, entryPointLen); if(function == NULL) { return false; } /* execute function in the virtual machine */ if(!vm_exec(instance->vm, vm_bytecode(instance->vm), vm_bytecode_size(instance->vm), function->index, function->numArgs + function->numVars)) { return false; } return true; }
vm_var *vm_exec_exprs(l_vm *vm, vm_map *scope, l_p_expr **exprs, int exprc) { vm_var *ret = vm->var_none; for (int i = 0; i < exprc; ++i) { ret = vm_exec(vm, scope, exprs[i]); if (ret->type == VAR_TYPE_ERROR) { ret->refs += 1; l_vm_cleanup(vm); ret->refs -= 1; l_vm_cleanup_add(vm, ret); return ret; } } ret->refs += 1; l_vm_cleanup(vm); ret->refs -= 1; l_vm_cleanup_add(vm, ret); return ret; }
int main(int argc, char *argv[]) { cunit_setup = setup; cunit_teardown = teardown; char samplesdir[2000]; char samplesfile[2000]; char* wichruntime = getenv("WICHRUNTIME"); // set in intellij "test_vm_samples" environment variable config area if ( wichruntime==NULL ) { fprintf(stderr, "environment variable WICHRUNTIME not set to root of runtime area\n"); return -1; } strcpy(samplesdir, wichruntime); strcat(samplesdir, "/vm/test/samples"); struct dirent *dp; DIR *dir = opendir(samplesdir); if ( dir!=NULL ) { dp = readdir(dir); while (dp != NULL) { char *filename = dp->d_name; if ( strstr(filename, ".wasm")!=NULL ) { printf("loading %s\n", filename); strcpy(samplesfile, samplesdir); strcat(samplesfile, "/"); strcat(samplesfile, filename); FILE *f = fopen(samplesfile, "r"); VM *vm = vm_load(f); vm_exec(vm, false); fclose(f); } dp = readdir(dir); } closedir(dir); } else { fprintf(stderr, "can't find samples dir\n"); } return 0; }
void lisp_main(char *file) { FILE *fp; if((fp=fopen(file,"r")) == NULL){ printf("file open error\n"); exit(0); } cons_t *root = Cons_New(); token_t *lex_buf = (token_t *)malloc(sizeof(token_t)); //--Lexer startLex(lex_buf,fp); //dumpLexer(lex_buf); //--Parser parse(lex_buf,root); dumpCons_t(root); //debug //--eval //printf("\n--answer:%d\n",eval(root)); //AST //--run printf("\n"); bytecode_t *bytecode = Bytecode_New(); hash_table_t *hash = HashTable_init(); int esp = 1; //value_t st[1024]; compile(root,bytecode,hash); vm_exec(bytecode,esp,hash,0); HashTable_free(hash); Bytecode_free(bytecode); token_free(lex_buf); freeCons_t(root); fclose(fp); }
static int exec(int using_readline) { jmp_buf buf; if (loop_frame_list == NULL) { loop_frame_list = new_array(); } val_t null_value; null_value.ptr = NULL; loop_frame_push(&buf, null_value); if (setjmp(buf) == 0) { val_t val = vm_exec(memory + current_index, stack_value); if (!IS_NULL(val) && using_readline) { print_return_value(val); printf("\n"); } loop_frame_t *frame = loop_frame_pop(); FREE(frame); return 0; } else { cstack_cons_cell_clear(); environment_clear(); return 1; } }
int shell (int argc, char* args[]) { FILE* file = NULL; table = (void**)(vm_exec(NULL, NULL).ptr); gc_init(); new_func_data_table(); new_global_environment(); exception_init(); if (argc > 1){ file = fopen(args[1],"r"); if (!file) { EXCEPTION("Script not found!!\n"); exit(1); } } init_first(); set_static_mtds(); void *handler = dlopen("libreadline" K_OSDLLEXT, RTLD_LAZY); void *f = (handler != NULL) ? dlsym(handler, "readline") : NULL; myreadline = (f != NULL) ? (char* (*)(const char*))f : NULL; f = (handler != NULL) ? dlsym(handler, "add_history") : NULL; myadd_history = (f != NULL) ? (int (*)(const char*))f : _add_history; int i = 0; while (bootstrap_functions[i] != NULL) { split_and_exec(2, args, (char*)bootstrap_functions[i]); i++; } if (argc > 1){ shell_file(argc, args, file); } else { shell_readline(argc, args); } func_data_table_free(); opline_free(); gc_end(); return 0; }
void lisp_repl() { char *line; using_history(); hash_table_t *hash = HashTable_init(); int esp = 1; while((line = readline("Sukima>")) != NULL) { add_history(line); token_t *lex_buf = (token_t *)malloc(sizeof(token_t)); token_t *lex_current = lex_buf; lex_current = lex(lex_current,line,strlen(line)); lex_current->type = TY_EOL; //dumpLexer(lex_buf); cons_t *root = Cons_New(); parse(lex_buf,root); dumpCons_t(root); //debug printf("\n"); bytecode_t *bytecode = Bytecode_New(); //value_t st[128]; compile(root,bytecode,hash); vm_exec(bytecode,esp,hash,0); Bytecode_free(bytecode); token_free(lex_buf); freeCons_t(root); free(line); } HashTable_free(hash); }
/*RHO static*/ VALUE eval_string_with_cref(VALUE self, VALUE src, VALUE scope, NODE *cref, const char *file, int line) { int state; VALUE result = Qundef; VALUE envval; rb_binding_t *bind = 0; rb_thread_t *th = GET_THREAD(); rb_env_t *env = NULL; rb_block_t block; volatile int parse_in_eval; volatile int mild_compile_error; if (file == 0) { file = rb_sourcefile(); line = rb_sourceline(); } parse_in_eval = th->parse_in_eval; mild_compile_error = th->mild_compile_error; PUSH_TAG(); if ((state = EXEC_TAG()) == 0) { rb_iseq_t *iseq; volatile VALUE iseqval; if (scope != Qnil) { if (rb_obj_is_kind_of(scope, rb_cBinding)) { GetBindingPtr(scope, bind); envval = bind->env; } else { rb_raise(rb_eTypeError, "wrong argument type %s (expected Binding)", rb_obj_classname(scope)); } GetEnvPtr(envval, env); th->base_block = &env->block; } else { rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp); if (cfp != 0) { block = *RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp); th->base_block = █ th->base_block->self = self; th->base_block->iseq = cfp->iseq; /* TODO */ } else { rb_raise(rb_eRuntimeError, "Can't eval on top of Fiber or Thread"); } } //RHO if ( TYPE(src) != T_STRING ){ iseqval = src; }else //RHO { /* make eval iseq */ th->parse_in_eval++; th->mild_compile_error++; iseqval = rb_iseq_compile(src, rb_str_new2(file), INT2FIX(line)); th->mild_compile_error--; th->parse_in_eval--; } vm_set_eval_stack(th, iseqval, cref); th->base_block = 0; if (0) { /* for debug */ printf("%s\n", RSTRING_PTR(rb_iseq_disasm(iseqval))); } /* save new env */ GetISeqPtr(iseqval, iseq); if (bind && iseq->local_size > 0) { bind->env = rb_vm_make_env_object(th, th->cfp); } /* kick */ CHECK_STACK_OVERFLOW(th->cfp, iseq->stack_max); result = vm_exec(th); } POP_TAG(); th->mild_compile_error = mild_compile_error; th->parse_in_eval = parse_in_eval; if (state) { if (state == TAG_RAISE) { VALUE errinfo = th->errinfo; if (strcmp(file, "(eval)") == 0) { VALUE mesg, errat, bt2; extern VALUE rb_get_backtrace(VALUE info); ID id_mesg; CONST_ID(id_mesg, "mesg"); errat = rb_get_backtrace(errinfo); mesg = rb_attr_get(errinfo, id_mesg); if (!NIL_P(errat) && TYPE(errat) == T_ARRAY && (bt2 = vm_backtrace(th, -2), RARRAY_LEN(bt2) > 0)) { if (!NIL_P(mesg) && TYPE(mesg) == T_STRING && !RSTRING_LEN(mesg)) { if (OBJ_FROZEN(mesg)) { VALUE m = rb_str_cat(rb_str_dup(RARRAY_PTR(errat)[0]), ": ", 2); rb_ivar_set(errinfo, id_mesg, rb_str_append(m, mesg)); } else { rb_str_update(mesg, 0, 0, rb_str_new2(": ")); rb_str_update(mesg, 0, 0, RARRAY_PTR(errat)[0]); } } RARRAY_PTR(errat)[0] = RARRAY_PTR(bt2)[0]; } } rb_exc_raise(errinfo); } JUMP_TAG(state); } return result; }
static inline VALUE vm_call0(rb_thread_t * th, VALUE klass, VALUE recv, VALUE id, ID oid, int argc, const VALUE *argv, const NODE *body, int nosuper) { VALUE val; rb_block_t *blockptr = 0; if (0) printf("id: %s, nd: %s, argc: %d, passed: %p\n", rb_id2name(id), ruby_node_name(nd_type(body)), argc, (void *)th->passed_block); if (th->passed_block) { blockptr = th->passed_block; th->passed_block = 0; } again: switch (nd_type(body)) { case RUBY_VM_METHOD_NODE:{ rb_control_frame_t *reg_cfp; VALUE iseqval = (VALUE)body->nd_body; int i; rb_vm_set_finish_env(th); reg_cfp = th->cfp; CHECK_STACK_OVERFLOW(reg_cfp, argc + 1); *reg_cfp->sp++ = recv; for (i = 0; i < argc; i++) { *reg_cfp->sp++ = argv[i]; } vm_setup_method(th, reg_cfp, argc, blockptr, 0, iseqval, recv); val = vm_exec(th); break; } case NODE_CFUNC: { EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass); { rb_control_frame_t *reg_cfp = th->cfp; rb_control_frame_t *cfp = vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1); cfp->method_id = oid; cfp->method_class = klass; val = call_cfunc(body->nd_cfnc, recv, body->nd_argc, argc, argv); if (reg_cfp != th->cfp + 1) { SDR2(reg_cfp); SDR2(th->cfp-5); rb_bug("cfp consistency error - call0"); th->cfp = reg_cfp; } vm_pop_frame(th); } EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass); break; } case NODE_ATTRSET:{ if (argc != 1) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); } val = rb_ivar_set(recv, body->nd_vid, argv[0]); break; } case NODE_IVAR: { if (argc != 0) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); } val = rb_attr_get(recv, body->nd_vid); break; } case NODE_BMETHOD:{ val = vm_call_bmethod(th, oid, body->nd_cval, recv, klass, argc, (VALUE *)argv, blockptr); break; } case NODE_ZSUPER:{ klass = RCLASS_SUPER(klass); if (!klass || !(body = rb_method_node(klass, id))) { return method_missing(recv, id, argc, argv, 0); } RUBY_VM_CHECK_INTS(); nosuper = CALL_SUPER; body = body->nd_body; goto again; } default: rb_bug("unsupported: vm_call0(%s)", ruby_node_name(nd_type(body))); } RUBY_VM_CHECK_INTS(); return val; }
vm_var *vm_exec(l_vm *vm, vm_map *scope, l_p_expr *expr) { vm->currline = expr->line; switch (expr->type) { case EXPR_EMPTY: return vm->var_none; case EXPR_GROUP: { vm_var *var = vm_exec(vm, scope, expr->expression.expr_group->expr); l_vm_cleanup_add(vm, var); return var; } case EXPR_FUNC_CALL: { l_p_expr_func_call *e = expr->expression.func_call; vm_var *func = vm_exec(vm, scope, e->func); l_vm_cleanup_add(vm, func); l_p_comma_expr_list *exprs = e->arg_list; // Create arguments array vm_var_array *args = malloc(sizeof(*args)); vm_var_array_init(args, VAR_TYPE_NONE); for (int i = 0; i < exprs->expressionc; ++i) { vm_var *val = vm_exec(vm, scope, exprs->expressions[i]); vm_var_array_set(args, i, val); } // Execute function if it's a function if (func->type == VAR_TYPE_FUNCTION) { vm_var *var = vm_var_function_exec( vm, func->var.function, args, NULL, e->infix); l_vm_cleanup_add(vm, var); vm_var_array_free(args); free(args); return var; } // Instantiate and create contsructor if it's an object with $init // and it isn't an instance of a class, or call $call otherwise else if (func->type == VAR_TYPE_OBJECT) { // Find $init if it's not an instance vm_var *init; if (!func->var.object.instance) init = vm_map_lookup_r(func->map, "$init"); // If we didn't find init, or it's an instance, run $call if ( func->var.object.instance || init == NULL) { // Find $call vm_var *call = vm_map_lookup_r(func->map, "$call"); if (call == NULL || call->type != VAR_TYPE_FUNCTION) return l_vm_error(vm, "Expected callable"); // Call vm_var *ret = vm_var_function_exec( vm, call->var.function, args, func, 0); l_vm_cleanup_add(vm, ret); vm_var_array_free(args); free(args); return ret; } if (init->type != VAR_TYPE_FUNCTION) return l_vm_error(vm, "Expected callable"); // Create new object vm_var *obj = vm_var_create(VAR_TYPE_OBJECT); obj->var.object.instance = 1; obj->map->parent = func->map; vm_map_increfs(func->map); l_vm_cleanup_add(vm, obj); // Call vm_var *ret = vm_var_function_exec( vm, init->var.function, args, obj, 0); l_vm_cleanup_add(vm, ret); vm_var_array_free(args); free(args); return obj; } // Error if neither else { return l_vm_error(vm, "Expected callable"); } } case EXPR_OBJECT_LOOKUP: { l_p_expr_object_lookup *e = expr->expression.object_lookup; vm_var *obj = vm_exec(vm, scope, e->obj); vm_var *var = vm_map_lookup_r(obj->map, e->key); l_vm_cleanup_add(vm, obj); if (var != NULL) l_vm_cleanup_add(vm, var); if (var == NULL) { return vm->var_none; } else if ( var->type == VAR_TYPE_FUNCTION && var->var.function->self == NULL) { vm_var_function *func = malloc(sizeof(*func)); vm_var_function_init_self(func, var->var.function, obj); vm_var *v = vm_var_create(VAR_TYPE_FUNCTION); v->var.function = func; l_vm_cleanup_add(vm, v); return v; } else { return var; } } case EXPR_ARRAY_LOOKUP: { l_p_expr_array_lookup *e = expr->expression.array_lookup; vm_var *obj = vm_exec(vm, scope, e->arr); vm_var *key = vm_exec(vm, scope, e->key); l_vm_cleanup_add(vm, obj); l_vm_cleanup_add(vm, key); if (obj->type == VAR_TYPE_ARRAY) { vm_var_array *arr = obj->var.array; if (key->type != VAR_TYPE_NUMBER) return l_vm_error(vm, "Expected number in array lookup"); vm_var_array_prepare(arr); int num = (int)key->var.number; if (num >= arr->varc) return l_vm_error(vm, "Array index out of bounds"); vm_var *var = arr->vars[num]; if (var != NULL) l_vm_cleanup_add(vm, var); if (var == NULL) return vm->var_none; else return var; } // TODO: object lookup else if ( key->type == VAR_TYPE_ARRAY && key->var.array->type == VAR_TYPE_CHAR) { return l_vm_error(vm, "Object lookup with [] is not implemented"); } else { return l_vm_error(vm, "Confusing array/object lookup"); } } case EXPR_ASSIGNMENT: { l_p_expr_assignment *e = expr->expression.assignment; vm_var *val = vm_exec(vm, scope, e->val); l_vm_cleanup_add(vm, val); l_p_expr *ekey = e->key; if (ekey->type == EXPR_OBJECT_LOOKUP) { l_p_expr_object_lookup *ol = ekey->expression.object_lookup; vm_var *obj = vm_exec(vm, scope, ol->obj); l_vm_cleanup_add(vm, obj); if (vm_map_set(obj->map, ol->key, val) == -1) return l_vm_error(vm, "Scope is immutable"); } else if (ekey->type == EXPR_ARRAY_LOOKUP) { l_p_expr_array_lookup *al = ekey->expression.array_lookup; vm_var *arr = vm_exec(vm, scope, al->arr); vm_var *key = vm_exec(vm, scope, al->key); l_vm_cleanup_add(vm, arr); l_vm_cleanup_add(vm, key); if (arr->type == VAR_TYPE_ARRAY && key->type == VAR_TYPE_NUMBER) { vm_var_array_prepare(arr->var.array); int ret = vm_var_array_set( arr->var.array, (int)(key->var.number), val); if (ret == -1) return l_vm_error(vm, "Can't insert value into array"); } else if ( key->type == VAR_TYPE_ARRAY && key->var.array->type == VAR_TYPE_CHAR) { char *k = ""; // TODO: char array to string conversion if (vm_map_set(arr->map, k, val)) return l_vm_error(vm, "Scope is immutable"); } else { return l_vm_error(vm, "Confusing array/object assignment"); } } else if (ekey->type == EXPR_VARIABLE) { if (vm_map_replace_r(scope, ekey->expression.variable->name, val) == -1) return l_vm_error(vm, "Variable isn't defined"); } else { return l_vm_error(vm, "Invalid assignment"); } return val; } case EXPR_DECLARATION: { l_p_expr_assignment *e = expr->expression.assignment; vm_var *val = vm_exec(vm, scope, e->val); l_vm_cleanup_add(vm, val); l_p_expr *ekey = e->key; if (ekey->type != EXPR_VARIABLE) return l_vm_error(vm, "Invalid declaration"); char *key = ekey->expression.variable->name; if (vm_map_define(scope, key, val) == -1) return l_vm_error(vm, "Variable already exists"); return vm->var_none; } case EXPR_FUNCTION: { l_p_expr_function *e = expr->expression.function; vm_var_function *func = malloc(sizeof(*func)); vm_var_function_init_scope(func, scope); if (e->arg_definition != NULL) { func->argnames = e->arg_definition->names; func->argnamec = e->arg_definition->namec; } func->exprs = e->expr_list->expressions; func->exprc = e->expr_list->expressionc; vm_var *var = vm_var_create(VAR_TYPE_FUNCTION); var->var.function = func; vm_var_function_increfs(func); l_vm_cleanup_add(vm, var); return var; } case EXPR_OBJECT_LITERAL: { l_p_expr_object_literal *e = expr->expression.object_literal; vm_var *var = vm_var_create(VAR_TYPE_OBJECT); l_vm_cleanup_add(vm, var); for (int i = 0; i < e->exprc; ++i) { vm_var *val = vm_exec(vm, scope, e->exprs[i]); if (vm_map_set(var->map, e->names[i], val) == -1) return l_vm_error(vm, "Scope is immutable"); } return var; } case EXPR_ARRAY_LITERAL: { l_p_expr_array_literal *al = expr->expression.array_literal; l_p_comma_expr_list *e = al->expr_list; vm_var_array *arr = malloc(sizeof(*arr)); vm_var_array_init(arr, VAR_TYPE_NONE); for (int i = 0; i < e->expressionc; ++i) { vm_var *val = vm_exec(vm, scope, e->expressions[i]); vm_var_array_set(arr, i, val); } vm_var *var = vm_var_create(VAR_TYPE_ARRAY); var->var.array = arr; l_vm_cleanup_add(vm, var); return var; } case EXPR_STRING_LITERAL: { l_p_expr_string_literal *sl = expr->expression.string_literal; vm_var_array *arr = malloc(sizeof(*arr)); vm_var_array_init(arr, VAR_TYPE_CHAR); arr->ready = 0; arr->strcache = malloc(strlen(sl->string) + 1); strcpy(arr->strcache, sl->string); vm_var *var = vm_var_create(VAR_TYPE_ARRAY); var->var.array = arr; l_vm_cleanup_add(vm, var); return var; } case EXPR_NUM_LITERAL: { vm_var *var = vm_var_create(VAR_TYPE_NUMBER); var->var.number = expr->expression.num_literal->number; l_vm_cleanup_add(vm, var); return var; } case EXPR_VARIABLE: { char *key = expr->expression.variable->name; vm_var *var = vm_map_lookup_r(scope, key); if (var != NULL) l_vm_cleanup_add(vm, var); if (var == NULL) return vm->var_none; else return var; } } return vm->var_none; }