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;
}
Beispiel #2
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);
}
Beispiel #3
0
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;
}
Beispiel #4
0
void vm_run(int at)
{
	pcounter = at;
	while(running)
	{
		vm_exec();
	}
}
Beispiel #5
0
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;
}
Beispiel #6
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;
}
Beispiel #7
0
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);
    }
}
Beispiel #8
0
/**
 * 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;
}
Beispiel #9
0
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;
}
Beispiel #10
0
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;
}
Beispiel #11
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);
}
Beispiel #12
0
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;
	}
}
Beispiel #13
0
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;
}
Beispiel #14
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);

}
Beispiel #15
0
/*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 = &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;
}
Beispiel #16
0
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;
}
Beispiel #17
0
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;
}