void test_ui_sdl_grath() { Sdl_Graph *sdl_grath; allocator_t *allocator = allocator_get_default_alloc(); char *set_str; cjson_t *root, *e, *s; char buf[2048]; root = cjson_create_object();{ cjson_add_item_to_object(root, "Sdl_Graph", e = cjson_create_object());{ cjson_add_string_to_object(e, "name", "alan"); } } set_str = cjson_print(root); sdl_grath = OBJECT_NEW(allocator, Sdl_Graph,set_str); object_dump(sdl_grath, "Sdl_Graph", buf, 2048); dbg_str(DBG_DETAIL,"Sdl_Graph dump: %s",buf); object_destroy(sdl_grath); free(set_str); }
void test_obj_event() { Event *event; allocator_t *allocator = allocator_get_default_alloc(); event = OBJECT_NEW(allocator, Event,""); }
static void * __render_load_text(Sdl_Graph *graph,void *string,void *font,int r, int g, int b, int a) { allocator_t *allocator = ((Obj *)graph)->allocator; Sdl_Text *text; Sdl_Font *f = (Sdl_Font *)font; SDL_Surface* surface = NULL; SDL_Color textColor = {r, g, b, a }; String *content; dbg_str(DBG_DETAIL,"Sdl_Text load text"); text = OBJECT_NEW(allocator, Sdl_Text,""); content = ((Text *)text)->content; content->assign(content,string); surface = TTF_RenderText_Solid(f->ttf_font, ((Text *)text)->content->value, textColor ); if(surface != NULL) { text->texture = SDL_CreateTextureFromSurface(graph->render, surface); text->width = surface->w; text->height = surface->h; dbg_str(DBG_DETAIL,"width =%d height=%d",text->width, text->height); SDL_FreeSurface(surface); } return text; }
static void * __render_load_character(Sdl_Graph *graph,uint32_t code,void *font,int r, int g, int b, int a) { allocator_t *allocator = ((Obj *)graph)->allocator; Character *character; Sdl_Font *f = (Sdl_Font *)font; SDL_Surface* surface = NULL; SDL_Color character_color = {r, g, b, a }; char buf[10] = {0}; /* *dbg_str(DBG_DETAIL,"Sdl_Character load character"); */ character = OBJECT_NEW(allocator, Sdl_Character,""); character->assign(character,code); sprintf(buf,"%c",code); surface = TTF_RenderText_Solid(f->ttf_font, buf, character_color); if(surface != NULL) { ((Sdl_Character *)character)->texture = SDL_CreateTextureFromSurface(graph->render, surface); character->width = surface->w; character->height = surface->h; /* *dbg_str(DBG_DETAIL,"width =%d height=%d",character->width, character->height); */ SDL_FreeSurface(surface); } return character; }
static void *__create_event(Window *window) { allocator_t *allocator = ((Obj *)window)->allocator; dbg_str(DBG_DETAIL,"sdl window create_event"); window->event = OBJECT_NEW(allocator, Sdl_Event,""); }
static void *__create_graph(Window *window, char *graph_type) { allocator_t *allocator = ((Obj *)window)->allocator; dbg_str(DBG_DETAIL,"sdl window create_graph"); window->graph = (Graph *)OBJECT_NEW(allocator, Sdl_Graph,NULL); }
static void *__create_font(Window *window,char *font_name) { allocator_t *allocator = ((Obj *)window)->allocator; dbg_str(DBG_DETAIL,"sdl window create_font"); window->font = OBJECT_NEW(allocator, Sdl_Font,""); window->font->load_font(window->font); }
/* Encode an object, returning the data. */ uint32_t encode_object(uint32_t data, uint32_t devnum) { uint32_t retval; uint8_t otype; otype = DATA_TYPE_DEV(devnum); retval = (otype == TYPE_NONE) ? swap32(data) : OBJECT_NEW(otype, data); return (retval); }
void test_obj_sdl_font() { Font *font; allocator_t *allocator = allocator_get_default_alloc(); int w, h; font = OBJECT_NEW(allocator, Sdl_Font,""); w = font->get_character_width(font,'a'); h = font->get_character_height(font,'a'); dbg_str(DBG_DETAIL,"a's w=%d h=%d", w, h); }
void test_ui_button() { Subject *subject; allocator_t *allocator = allocator_get_default_alloc(); char *set_str; char buf[2048]; set_str = gen_button_setting_str(); subject = OBJECT_NEW(allocator, Button,set_str); object_dump(subject, "Button", buf, 2048); dbg_str(DBG_DETAIL,"Button dump: %s",buf); free(set_str); }
void test_ui_component() { Subject *subject; allocator_t *allocator = allocator_get_default_alloc(); char *set_str; cjson_t *root, *e, *s; char buf[2048]; root = cjson_create_object();{ cjson_add_item_to_object(root, "Component", e = cjson_create_object());{ cjson_add_item_to_object(e, "Subject", s = cjson_create_object());{ cjson_add_number_to_object(s, "x", 1); cjson_add_number_to_object(s, "y", 25); cjson_add_number_to_object(s, "width", 5); cjson_add_number_to_object(s, "height", 125); } cjson_add_string_to_object(e, "name", "alan"); } } set_str = cjson_print(root); /* *subject = OBJECT_ALLOC(allocator,Component); *object_set(subject, "Component", set_str); *dbg_str(DBG_DETAIL,"x=%d y=%d width=%d height=%d",subject->x,subject->y,subject->width,subject->height); */ subject = OBJECT_NEW(allocator, Component,set_str); /* *dbg_str(DBG_DETAIL,"x=%d y=%d width=%d height=%d",subject->x,subject->y,subject->width,subject->height); *dbg_str(DBG_DETAIL,"component nane=%s",((Component *)subject)->name); *subject->move(subject); */ object_dump(subject, "Component", buf, 2048); dbg_str(DBG_DETAIL,"Component dump: %s",buf); free(set_str); }
void test_ui_sdl_window() { Window *window; Graph *g; allocator_t *allocator = allocator_get_default_alloc(); char *set_str; char buf[2048]; set_str = gen_window_setting_str(); window = OBJECT_NEW(allocator, Sdl_Window,set_str); g = window->graph; object_dump(window, "Sdl_Window", buf, 2048); dbg_str(DBG_DETAIL,"Window dump: %s",buf); dbg_str(DBG_DETAIL,"render draw test"); g->render_draw_image(g,0,0,window->background); g->render_present(g); sleep(2); g->render_clear(g); g->render_set_color(g,0xff,0x0,0xff,0xff); g->render_draw_line(g,20,0,50,50); g->render_set_color(g,0xff,0x0,0x0,0xff); g->render_draw_rect(g,20,20,100,100); /* *g->render_fill_rect(g,20,20,100,100); */ g->render_present(g); sleep(5); object_destroy(window); free(set_str); }
static void *__render_load_image(Sdl_Graph *graph,void *path) { Sdl_Image *image; allocator_t *allocator = ((Obj *)graph)->allocator; dbg_str(DBG_DETAIL,"SDL Graph render_load_image"); image = OBJECT_NEW(allocator, Sdl_Image,""); ((Image *)image)->path->assign(((Image *)image)->path,path); if(image->surface == NULL) { image->load_image((Image *)image); } if(image->surface != NULL) { image->texture = SDL_CreateTextureFromSurface(graph->render, image->surface); image->width = image->surface->w; image->height = image->surface->h; SDL_FreeSurface(image->surface); image->surface = NULL; } return image; }
void test_obj_map() { Map *map; allocator_t *allocator = allocator_get_default_alloc(); char *set_str; cjson_t *root, *e, *s; char buf[2048]; root = cjson_create_object();{ cjson_add_item_to_object(root, "Map", e = cjson_create_object());{ cjson_add_string_to_object(e, "name", "alan"); } } set_str = cjson_print(root); map = OBJECT_NEW(allocator, Map,set_str); object_dump(map, "Map", buf, 2048); dbg_str(OBJ_DETAIL,"Map dump: %s",buf); free(set_str); }
/* * Create runtime and compilation environment and set up it * according to arguments. Executes 'core.yoyo' from standart library * to set up minimal runtime environment and file specified in arguments. * */ int main(int argc, char** argv) { setlocale(LC_ALL, ""); signal(SIGSEGV, Signal_handler); signal(SIGFPE, Signal_handler); YoyoCEnvironment* ycenv = newYoyoCEnvironment(NULL); Environment* env = (Environment*) ycenv; YDebug* debug = NULL; bool dbg = false; env->argv = NULL; env->argc = 0; wchar_t* file = NULL; for (size_t i = 1; i < argc; i++) { char* arg = argv[i]; if (arg[0] == '-' && strlen(arg) > 1) { arg++; if (arg[0] == '-') { /* Arguments like --... (e.g. --debug) */ arg++; if (strcmp(arg, "debug") == 0) dbg = true; else if (strcmp(arg, "help") == 0) { printf("Yoyo v"VERSION" - tiny dynamic language.\n" "View code examples in repository\n" "Use:\n\tyoyo [OPTIONS] FILE arg1 arg2 ...\n" "Options:\n" "\t--debug - execute in debug mode\n" "\t--help - display brief help\n" "\t--version - display project version\n" "\t-Ppath - add path to file search path\n" "\t-Dkey=value - define key\n" "Most useful keys:\n" "\tystd - specify standart library location\n" "\tobjects = hash/tree - specify used object implementation\n" "\tIntPool - specify integer pool size(Strongly affects on memory use and performance)\n" "\tIntCache - specify integer cache size(Strongly affects on memory use and performance)\n" "\tworkdir - specify working directory\n" "\nAuthor: Eugene Protopopov <*****@*****.**>\n" "License: Program, standart library and examples are distributed under the terms of GNU GPLv3 or any later version.\n" "Program repo: https://github.com/protopopov1122/Yoyo"); exit(0); } else if (strcmp(arg, "version") == 0) { printf("v"VERSION"\n"); exit(0); } } else if (arg[0] == 'D') { /* Environment variable definitions. * Format: -Dkey=value */ arg++; char* key = NULL; char* value = NULL; size_t key_len = 0; size_t value_len = 0; while (*arg != '=' && *arg != '\0') { key = realloc(key, sizeof(char) * (++key_len)); key[key_len - 1] = *(arg++); } key = realloc(key, sizeof(char) * (++key_len)); key[key_len - 1] = '\0'; while (*arg != '\0') { arg++; value = realloc(value, sizeof(char) * (++value_len)); value[value_len - 1] = *arg; } wchar_t* wkey = calloc(1, sizeof(wchar_t) * (strlen(key) + 1)); wchar_t* wvalue = calloc(1, sizeof(wchar_t) * (strlen(value != NULL ? value : "none") + 1)); mbstowcs(wkey, key, strlen(key)); mbstowcs(wvalue, value != NULL ? value : "none", strlen(value != NULL ? value : "none")); env->define(env, wkey, wvalue); free(wkey); free(wvalue); free(key); free(value); } else if (arg[0] == 'P') { /*Runtime path definitions. * Format: -Ppath*/ arg++; wchar_t* wpath = malloc(sizeof(wchar_t) * (strlen(arg) + 1)); mbstowcs(wpath, arg, strlen(arg)); wpath[strlen(arg)] = L'\0'; env->addPath(env, wpath); free(wpath); } } else { /* If file to execute is not defined, then current * argument is file. Else it is an argument to * yoyo program. */ if (file == NULL) { file = malloc(sizeof(wchar_t) * (strlen(arg) + 1)); mbstowcs(file, arg, strlen(arg)); file[strlen(arg)] = L'\0'; } else { wchar_t* warg = malloc(sizeof(wchar_t) * (strlen(arg) + 1)); mbstowcs(warg, arg, strlen(arg)); warg[strlen(arg)] = L'\0'; env->argc++; env->argv = realloc(env->argv, sizeof(wchar_t*) * env->argc); env->argv[env->argc - 1] = warg; } } } /* Adds minimal path: working directory(by default is '.') and * standart library directory(by default is working directory). */ wchar_t* workdir = env->getDefined(env, L"workdir"); wchar_t* libdir = env->getDefined(env, L"ystd"); workdir = workdir == NULL ? L"." : workdir; char* mbs_wd = calloc(1, sizeof(wchar_t) * (wcslen(workdir) + 1)); wcstombs(mbs_wd, workdir, sizeof(wchar_t) * wcslen(workdir)); chdir(mbs_wd); free(mbs_wd); env->addPath(env, workdir); env->addPath(env, libdir == NULL ? YSTD_PATH : libdir); if (env->getDefined(env, L"objects")==NULL) env->define(env, L"objects", OBJ_TYPE); #ifdef GCGenerational if (env->getDefined(env, L"GCPlain")==NULL) env->define(env, L"GCGenerational", L""); #endif JitCompiler* jit = NULL; if (env->getDefined(env, L"yjit")!=NULL) { wchar_t* wcs = env->getDefined(env, L"yjit"); char* mbs = calloc(1, sizeof(wchar_t)*(wcslen(wcs)+1)); wcstombs(mbs, wcs, sizeof(wchar_t) * wcslen(wcs)); void* handle = dlopen(mbs, RTLD_NOW); if (handle!=NULL) { void* ptr = dlsym(handle, "getYoyoJit"); if (ptr!=NULL) { JitGetter* getter_ptr = (JitGetter*) &ptr; JitGetter getter = *getter_ptr; jit = getter(); } else fprintf(env->err_stream, "%s\n", dlerror()); } else fprintf(env->err_stream, "%s\n", dlerror()); free(mbs); } YRuntime* runtime = newRuntime(env, NULL); ycenv->bytecode = newBytecode(&runtime->symbols); ycenv->preprocess_bytecode = true; bool dumpcode = env->getDefined(env, L"dumpcode"); ycenv->analyze_bytecode = dumpcode || jit != NULL; if (dbg) debug = newDefaultDebugger(ycenv->bytecode); OBJECT_NEW(runtime->global_scope, L"sys", Yoyo_SystemObject(ycenv->bytecode, yoyo_thread(runtime)), yoyo_thread(runtime)); int32_t pid = -1; bool exectime = env->getDefined(env, L"exectime") != NULL; /* Executes specified file only if 'core.yoyo' is found and valid */ if (Yoyo_interpret_file(ycenv->bytecode, runtime, L"core.yoyo") != -1) { runtime->debugger = debug; if (file != NULL) { clock_t start = clock(); pid = Yoyo_interpret_file(ycenv->bytecode, runtime, file); if (exectime) printf("Execution time: %lf\n", (double) (clock() - start) / CLOCKS_PER_SEC); free(file); } else { Yoyo_interpret_file(ycenv->bytecode, runtime, L"repl.yoyo"); } } if (dumpcode) { for (size_t i = 0; i < ycenv->bytecode->procedure_count; i++) { if (ycenv->bytecode->procedures[i] == NULL) continue; ProcedureStats* stats = ycenv->bytecode->procedures[i]->stats; if (stats != NULL) print_stats(stats); } } if (env->getDefined(env, L"testjit") != NULL) { if (pid != -1 && jit != NULL) { ycenv->bytecode->procedures[pid]->compiled = jit->compile(jit, ycenv->bytecode->procedures[pid], ycenv->bytecode); clock_t start = clock(); invoke(pid, ycenv->bytecode, runtime->global_scope, NULL, yoyo_thread(runtime)); if (exectime) printf("Execution time: %lf\n", (double) (clock() - start) / CLOCKS_PER_SEC); } } /* Waits all threads to finish and frees resources */ YThread* current_th = yoyo_thread(runtime); current_th->free(current_th); runtime->wait(runtime); runtime->free(runtime); if (debug != NULL) debug->free(debug); if (jit!=NULL) jit->free(jit); exit(EXIT_SUCCESS); }
/*Procedure that interprets current frame bytecode * Uses loop with switch statement.*/ YValue* EXECUTE_PROC(YObject* scope, YThread* th) { ExecutionFrame* frame = (ExecutionFrame*) th->frame; frame->regs[0] = (YValue*) scope; YRuntime* runtime = th->runtime; ILBytecode* bc = frame->bytecode; size_t code_len = frame->proc->code_length; while (frame->pc + 13 <= code_len) { // If runtime is paused then execution should be paused too. if (runtime->state == RuntimePaused) { th->state = ThreadPaused; while (runtime->state == RuntimePaused) YIELD(); th->state = ThreadWorking; } // Decode opcode and arguments uint8_t opcode = frame->proc->code[frame->pc]; int32_t* args = (int32_t*) &(frame->proc->code[frame->pc + 1]); const int32_t iarg0 = args[0]; const int32_t iarg1 = args[1]; const int32_t iarg2 = args[2]; // Call debugger before each instruction if nescesarry YBreakpoint breakpoint = { .procid = frame->proc->id, .pc = frame->pc }; DEBUG(th->runtime->debugger, instruction, &breakpoint, th); // Interpret opcode // See virtual machine description switch (opcode) { case VM_Halt: break; case VM_LoadConstant: { /*All constants during execution should be stored in pool. * If pool contains constant id, then constant is returned*/ YObject* cpool = th->runtime->Constants.pool; if (cpool->contains(cpool, iarg1, th)) { SET_REGISTER(cpool->get(cpool, iarg1, th), iarg0, th); break; } /*Else it is created, added to pool and returned*/ Constant* cnst = bc->getConstant(bc, iarg1); YValue* val = getNull(th); if (cnst != NULL) { switch (cnst->type) { case IntegerC: val = newInteger(cnst->value.i64, th); break; case FloatC: val = newFloat(cnst->value.fp64, th); break; case StringC: val = newString( bc->getSymbolById(bc, cnst->value.string_id), th); break; case BooleanC: val = newBoolean(cnst->value.boolean, th); break; default: break; } } cpool->put(cpool, iarg1, val, true, th); SET_REGISTER(val, iarg0, th); } break; case VM_LoadInteger: { /*Load integer from argument directly to register*/ YValue* val = newInteger(iarg1, th); SET_REGISTER(val, iarg0, th); } break; case VM_Copy: { /*Copy register value to another*/ SET_REGISTER(getRegister(iarg1, th), iarg0, th); } break; case VM_Push: { /*Push register value to stack*/ push(getRegister(iarg0, th), th); } break; case VM_PushInteger: { push(newInteger(iarg0, th), th); } break; /*Next instructions load values from two registers, * perform polymorph binary operation and * save result to third register*/ case VM_Add: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.add_operation(v1, v2, th), iarg0, th); } break; case VM_Subtract: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.subtract_operation(v1, v2, th), iarg0, th); } break; case VM_Multiply: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.multiply_operation(v1, v2, th), iarg0, th); } break; case VM_Divide: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.divide_operation(v1, v2, th), iarg0, th); } break; case VM_Modulo: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.modulo_operation(v1, v2, th), iarg0, th); } break; case VM_Power: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.power_operation(v1, v2, th), iarg0, th); } break; case VM_ShiftRight: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.shr_operation(v1, v2, th), iarg0, th); } break; case VM_ShiftLeft: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.shl_operation(v1, v2, th), iarg0, th); } break; case VM_And: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.and_operation(v1, v2, th), iarg0, th); } break; case VM_Or: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.or_operation(v1, v2, th), iarg0, th); } break; case VM_Xor: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(v1->type->oper.xor_operation(v1, v2, th), iarg0, th); } break; case VM_Compare: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); SET_REGISTER(newInteger(v1->type->oper.compare(v1, v2, th), th), iarg0, th); } break; case VM_Test: { /*Take an integer from register and * check if certain bit is 1 or 0*/ YValue* arg = getRegister(iarg1, th); if (arg->type == &th->runtime->IntType) { int64_t i = ((YInteger*) arg)->value; YValue* res = newBoolean((i & iarg2) != 0, th); SET_REGISTER(res, iarg0, th); } else SET_REGISTER(getNull(th), iarg0, th); } break; case VM_FastCompare: { YValue* v1 = getRegister(iarg0, th); YValue* v2 = getRegister(iarg1, th); int i = v1->type->oper.compare(v1, v2, th); YValue* res = newBoolean((i & iarg2) != 0, th); SET_REGISTER(res, iarg0, th); } break; /*These instruction perform polymorph unary operations*/ case VM_Negate: { YValue* v1 = getRegister(iarg1, th); SET_REGISTER(v1->type->oper.negate_operation(v1, th), iarg0, th); } break; case VM_Not: { YValue* v1 = getRegister(iarg1, th); SET_REGISTER(v1->type->oper.not_operation(v1, th), iarg0, th); } break; case VM_Increment: { YValue* v1 = getRegister(iarg1, th); if (v1->type == &th->runtime->IntType) { int64_t i = getInteger(v1, th); i++; SET_REGISTER(newInteger(i, th), iarg0, th); } else if (v1->type==&th->runtime->FloatType) { double i = getFloat(v1, th); i++; SET_REGISTER(newFloat(i, th), iarg0, th); } else { SET_REGISTER(v1, iarg0, th); } } break; case VM_Decrement: { YValue* v1 = getRegister(iarg1, th); if (v1->type == &th->runtime->IntType) { int64_t i = getInteger(v1, th); i--; SET_REGISTER(newInteger(i, th), iarg0, th); } else if (v1->type==&th->runtime->FloatType) { double i = getFloat(v1, th); i--; SET_REGISTER(newFloat(i, th), iarg0, th); } else { SET_REGISTER(v1, iarg0, th); } } break; case VM_Call: { /*Invoke lambda from register. * Arguments stored in stack. * Argument count passed as argument*/ size_t argc = (size_t) popInt(th); /* YValue** args = malloc(sizeof(YValue*) * argc); for (size_t i = argc - 1; i < argc; i--) args[i] = pop(th);*/ YValue** args = &((ExecutionFrame*) th->frame)->stack[((ExecutionFrame*) th->frame)->stack_offset] - argc; ((ExecutionFrame*) th->frame)->stack_offset -= argc; YValue* val = getRegister(iarg1, th); YObject* scope = NULL; if (iarg2 != -1) { YValue* scl = getRegister(iarg2, th); if (scl->type == &th->runtime->ObjectType) scope = (YObject*) scl; else { scope = th->runtime->newObject(NULL, th); OBJECT_NEW(scope, L"value", scl, th); } } if (val->type == &th->runtime->LambdaType) { YLambda* l = (YLambda*) val; SET_REGISTER(invokeLambda(l, scope, args, argc, th), iarg0, th); } else { throwException(L"CallingNotALambda", NULL, 0, th); SET_REGISTER(getNull(th), iarg0, th); } //free(args); } break; case VM_Return: { /*Verify register value to be some type(if defined) * and return it. Execution has been ended*/ YValue* ret = getRegister(iarg0, th); if (((ExecutionFrame*) th->frame)->retType != NULL && !((ExecutionFrame*) th->frame)->retType->verify( ((ExecutionFrame*) th->frame)->retType, ret, th)) { wchar_t* wstr = toString(ret, th); throwException(L"Wrong return type", &wstr, 1, th); free(wstr); return getNull(th); } return ret; } case VM_NewObject: { /*Create object with parent(if defined)*/ YValue* p = getRegister(iarg1, th); if (iarg1 != -1 && p->type == &th->runtime->ObjectType) { YObject* obj = th->runtime->newObject((YObject*) p, th); SET_REGISTER((YValue*) obj, iarg0, th); } else SET_REGISTER((YValue*) th->runtime->newObject(NULL, th), iarg0, th); } break; case VM_NewArray: { /*Create empty array*/ SET_REGISTER((YValue*) newArray(th), iarg0, th); } break; case VM_NewLambda: { /*Create lambda. Lambda signature is stored in stack. * It is popped and formed as signature*/ // Check if lambda is vararg YValue* vmeth = pop(th); bool meth = (vmeth->type == &th->runtime->BooleanType) ? ((YBoolean*) vmeth)->value : false; YValue* vvararg = pop(th); bool vararg = (vvararg->type == &th->runtime->BooleanType) ? ((YBoolean*) vvararg)->value : false; // Get argument count and types size_t argc = (size_t) popInt(th); int32_t* argids = calloc(1, sizeof(int32_t) * argc); YoyoType** argTypes = calloc(1, sizeof(YoyoType*) * argc); for (size_t i = argc - 1; i < argc; i--) { argids[i] = (int32_t) popInt(th); YValue* val = pop(th); if (val->type == &th->runtime->DeclarationType) argTypes[i] = (YoyoType*) val; else argTypes[i] = val->type->TypeConstant; } // Get lambda return type YValue* retV = pop(th); YoyoType* retType = NULL; if (retV->type == &th->runtime->DeclarationType) retType = (YoyoType*) retV; else retType = retV->type->TypeConstant; // Get lambda scope from argument and create // lambda signature and lambda YValue* sp = getRegister(iarg2, th); if (sp->type == &th->runtime->ObjectType) { YObject* scope = (YObject*) sp; YLambda* lmbd = newProcedureLambda(iarg1, bc, scope, argids, newLambdaSignature(meth, argc, vararg, argTypes, retType, th), th); SET_REGISTER((YValue*) lmbd, iarg0, th); } else SET_REGISTER(getNull(th), iarg0, th); // Free allocated resources free(argids); free(argTypes); } break; case VM_NewOverload: { /*Pop lambdas from stack and * create overloaded lambda*/ // Pop lambda count and lambdas size_t count = (size_t) iarg1; YLambda** lambdas = malloc(sizeof(YLambda*) * count); for (size_t i = 0; i < count; i++) { YValue* val = pop(th); if (val->type == &th->runtime->LambdaType) lambdas[i] = (YLambda*) val; else lambdas[i] = NULL; } // If default lambda is defined then get it YLambda* defLmbd = NULL; if (iarg2 != -1) { YValue* val = getRegister(iarg2, th); if (val->type == &th->runtime->LambdaType) defLmbd = (YLambda*) val; } // Create overloaded lambda SET_REGISTER( (YValue*) newOverloadedLambda(lambdas, count, defLmbd, th), iarg0, th); // Free allocated resources free(lambdas); } break; case VM_NewComplexObject: { /*Pop mixin objects from stack and create complex object*/ // Get mixin count and pop mixins size_t count = (size_t) iarg2; YObject** mixins = malloc(sizeof(YObject*) * count); for (size_t i = 0; i < count; i++) { YValue* val = pop(th); if (val->type == &th->runtime->ObjectType) mixins[i] = (YObject*) val; else mixins[i] = NULL; } // Get base object YValue* basev = getRegister(iarg1, th); YObject* base = NULL; if (basev->type == &th->runtime->ObjectType) base = (YObject*) basev; else base = th->runtime->newObject(NULL, th); // Create complex object and free allocated resources SET_REGISTER((YValue*) newComplexObject(base, mixins, count, th), iarg0, th); free(mixins); } break; case VM_GetField: { /*Read value property and store it in register*/ YValue* val = getRegister(iarg1, th); if (val->type->oper.readProperty != NULL) { SET_REGISTER(val->type->oper.readProperty(iarg2, val, th), iarg0, th); } else SET_REGISTER(getNull(th), iarg0, th); } break; case VM_SetField: { /*Set objects field*/ YValue* val = getRegister(iarg0, th); if (val->type == &th->runtime->ObjectType) { YObject* obj = (YObject*) val; obj->put(obj, iarg1, getRegister(iarg2, th), false, th); } } break; case VM_NewField: { /*Create new field in object*/ YValue* val = getRegister(iarg0, th); if (val->type == &th->runtime->ObjectType) { YObject* obj = (YObject*) val; obj->put(obj, iarg1, getRegister(iarg2, th), true, th); } } break; case VM_DeleteField: { /*Delete field from object*/ YValue* val = getRegister(iarg0, th); if (val->type == &th->runtime->ObjectType) { YObject* obj = (YObject*) val; obj->remove(obj, iarg1, th); } } break; case VM_ArrayGet: { /*Get index from value. If can't then throw exception*/ YValue* val = getRegister(iarg1, th); YValue* val2 = getRegister(iarg2, th); // If value is array, but index is integer then // reads array element at index if (val->type == &th->runtime->ArrayType && val2->type == &th->runtime->IntType) { YArray* arr = (YArray*) val; size_t index = (size_t) ((YInteger*) val2)->value; SET_REGISTER(arr->get(arr, index, th), iarg0, th); } else if (val->type->oper.readIndex != NULL) { // Else calls readIndex on type(if readIndex is defined) SET_REGISTER(val->type->oper.readIndex(val, val2, th), iarg0, th); } else { throwException(L"AccesingNotAnArray", NULL, 0, th); SET_REGISTER(getNull(th), iarg0, th); } } break; case VM_ArraySet: { /*Set value to other value on index. If can't throw exception*/ YValue* val = getRegister(iarg0, th); YValue* val2 = getRegister(iarg1, th); // If value if array, but index is integer // then assigns value to an array if (val->type == &th->runtime->ArrayType && val2->type == &th->runtime->IntType) { YArray* arr = (YArray*) val; size_t index = (size_t) ((YInteger*) val2)->value; arr->set(arr, index, getRegister(iarg2, th), th); } else if (val->type->oper.readIndex != NULL) { // Else calls writeIndex on type(if writeIndex is defined) val->type->oper.writeIndex(val, val2, getRegister(iarg2, th), th); } else { throwException(L"ModifyingNotAnArray", NULL, 0, th); } } break; case VM_ArrayDelete: { /*If value is array but index is integer set array index * else throw an exception*/ YValue* val = getRegister(iarg0, th); YValue* val2 = getRegister(iarg1, th); if (val->type == &th->runtime->ArrayType && val2->type == &th->runtime->IntType) { YArray* arr = (YArray*) val; size_t index = (size_t) ((YInteger*) val2)->value; arr->remove(arr, index, th); } else if (val->type->oper.removeIndex !=NULL) { val->type->oper.removeIndex(val, val2, th); } else { throwException(L"ModifyingNotAnArray", NULL, 0, th); } } break; case VM_Goto: { /*Get label id from argument, get label address and jump*/ uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } break; case VM_GotoIfTrue: { /*Get label id from argument, get label address and jump * if condition is true*/ YValue* bln = getRegister(iarg1, th); if (bln->type == &th->runtime->BooleanType && ((YBoolean*) bln)->value) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } } break; case VM_GotoIfFalse: { /*Get label id from argument, get label address and jump * if condition is false*/ YValue* bln = getRegister(iarg1, th); if (bln->type == &th->runtime->BooleanType && !((YBoolean*) bln)->value) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } } break; case VM_Jump: { /*Goto to an address*/ frame->pc = iarg0; continue; } break; case VM_JumpIfTrue: { /*Goto to an address if condition is true*/ YValue* bln = getRegister(iarg1, th); if (bln->type == &th->runtime->BooleanType && ((YBoolean*) bln)->value) { frame->pc = iarg0; continue; } } break; case VM_JumpIfFalse: { /*Goto to an address if condition is false*/ YValue* bln = getRegister(iarg1, th); if (bln->type == &th->runtime->BooleanType && !((YBoolean*) bln)->value) { frame->pc = iarg0; continue; } } break; case VM_Throw: { /*Throw an exception*/ th->exception = newException(getRegister(iarg0, th), th); } break; case VM_Catch: { /*Save current exception in register and * set exception NULL*/ SET_REGISTER(th->exception, iarg0, th); th->exception = NULL; } break; case VM_OpenCatch: { /*Add next catch address to frame catch stack. * If exception is thrown then catch address being * popped from stack and interpreter * jump to it*/ CatchBlock* cb = malloc(sizeof(CatchBlock)); cb->prev = frame->catchBlock; cb->pc = iarg0; frame->catchBlock = cb; } break; case VM_CloseCatch: { /*Remove catch address from frame catch stack*/ CatchBlock* cb = frame->catchBlock; frame->catchBlock = cb->prev; free(cb); } break; case VM_Nop: { /*Does nothing*/ } break; case VM_Swap: { /*Swap two register values*/ YValue* r1 = getRegister(iarg0, th); YValue* r2 = getRegister(iarg1, th); SET_REGISTER(r1, iarg1, th); SET_REGISTER(r2, iarg0, th); } break; case VM_Subsequence: { /*Get subsequence from value if subseq method * is defined*/ YValue* reg = getRegister(iarg0, th); YValue* tfrom = getRegister(iarg1, th); YValue* tto = getRegister(iarg2, th); if (tfrom->type == &th->runtime->IntType&& tto->type == &th->runtime->IntType&& reg->type->oper.subseq!=NULL) { size_t from = (size_t) ((YInteger*) tfrom)->value; size_t to = (size_t) ((YInteger*) tto)->value; SET_REGISTER(reg->type->oper.subseq(reg, from, to, th), iarg0, th); } else SET_REGISTER(getNull(th), iarg0, th); } break; case VM_Iterator: { /*Get iterator from value if it is iterable*/ YValue* v = getRegister(iarg1, th); if (v->type->oper.iterator != NULL) { SET_REGISTER((YValue*) v->type->oper.iterator(v, th), iarg0, th);\ } else { SET_REGISTER(getNull(th), iarg0, th); } } break; case VM_Iterate: { /*If iterator has next value than get it and save * to register. If iterator doesn't has next value * then jump to a label*/ YValue* v = getRegister(iarg1, th); YValue* value = NULL; if (v->type->oper.iterator != NULL) { YoyoIterator* iter = v->type->oper.iterator(v, th); if (iter->hasNext(iter, th)) value = iter->next(iter, th); } if (value == NULL) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg2)->value; frame->pc = addr; } else SET_REGISTER(value, iarg0, th); } break; case VM_NewInterface: { /*Build new interface*/ YoyoAttribute* attrs = calloc(1, sizeof(YoyoAttribute) * iarg2); // Pop interface parents YoyoInterface** parents = calloc(1, sizeof(YoyoInterface*) * iarg1); for (int32_t i = 0; i < iarg1; i++) { YValue* val = pop(th); YoyoType* type = NULL; if (val->type == &th->runtime->DeclarationType) type = (YoyoType*) val; else type = val->type->TypeConstant; parents[i] = type->type == InterfaceDT ? (YoyoInterface*) type : NULL; } // Pop interface fields for (int32_t i = 0; i < iarg2; i++) { attrs[i].id = popInt(th); YValue* val = pop(th); YoyoType* type = NULL; if (val->type == &th->runtime->DeclarationType) type = (YoyoType*) val; else type = val->type->TypeConstant; attrs[i].type = type; } // Build interface and free allocated resources SET_REGISTER( (YValue*) newInterface(parents, (size_t) iarg1, attrs, (size_t) iarg2, th), iarg0, th); free(attrs); free(parents); } break; case VM_ChangeType: { /*Change field type*/ YValue* val = getRegister(iarg2, th); YoyoType* type = NULL; if (val->type == &th->runtime->DeclarationType) type = (YoyoType*) val; else type = val->type->TypeConstant; YValue* o = getRegister(iarg0, th); if (o->type == &th->runtime->ObjectType) { YObject* obj = (YObject*) o; obj->setType(obj, iarg1, type, th); } } break; case VM_GotoIfEquals: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_EQUALS) != 0) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } } break; case VM_JumpIfEquals: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_EQUALS) != 0) { frame->pc = iarg0; continue; } } break; case VM_GotoIfNotEquals: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_NOT_EQUALS) != 0) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } } break; case VM_JumpIfNotEquals: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_NOT_EQUALS) != 0) { frame->pc = iarg0; continue; } } break; case VM_GotoIfGreater: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_GREATER) != 0) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } } break; case VM_JumpIfGreater: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_GREATER) != 0) { frame->pc = iarg0; continue; } } break; case VM_GotoIfLesser: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_LESSER) != 0) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } } break; case VM_JumpIfLesser: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_LESSER) != 0) { frame->pc = iarg0; continue; } } break; case VM_GotoIfNotLesser: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_GREATER_OR_EQUALS) != 0) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } } break; case VM_JumpIfNotLesser: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_GREATER_OR_EQUALS) != 0) { frame->pc = iarg0; continue; } } break; case VM_GotoIfNotGreater: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_LESSER_OR_EQUALS) != 0) { uint32_t addr = frame->proc->getLabel(frame->proc, iarg0)->value; frame->pc = addr; continue; } } break; case VM_JumpIfNotGreater: { YValue* v1 = getRegister(iarg1, th); YValue* v2 = getRegister(iarg2, th); int cmp = v1->type->oper.compare(v1, v2, th); if ((cmp & COMPARE_LESSER_OR_EQUALS) != 0) { frame->pc = iarg0; continue; } } break; case VM_CheckType: { YValue* value = getRegister(iarg0, th); YValue* tv = getRegister(iarg1, th); YoyoType* type = NULL; if (tv->type == &th->runtime->DeclarationType) type = (YoyoType*) tv; else type = tv->type->TypeConstant; if (!type->verify(type, value, th)) { wchar_t* wcs = getSymbolById(&th->runtime->symbols, iarg2); throwException(L"WrongFieldType", &wcs, 1, th); } } break; } /*If there is an exception then get last catch block * and jump to an address. If catch stack is empty * then return from procedure*/ if (th->exception != NULL) { if (frame->catchBlock != NULL) { frame->pc = frame->proc->getLabel(frame->proc, frame->catchBlock->pc)->value; continue; } else return getNull(th); } frame->pc += 13; } return getNull(th); }