void setupInitialEnvironment(){ globalEnvironmentPut(symbolTableGetOrAdd("a"), newInteger(10)); globalEnvironmentPut(symbolTableGetOrAdd("b"), newInteger(20)); // builtin functions globalEnvironmentPut(symbolTableGetOrAdd("+"), newBuiltinFunction("+", builtin_plus)); globalEnvironmentPut(symbolTableGetOrAdd("-"), newBuiltinFunction("-", builtin_minus)); globalEnvironmentPut(symbolTableGetOrAdd("*"), newBuiltinFunction("*", builtin_times)); globalEnvironmentPut(symbolTableGetOrAdd("/"), newBuiltinFunction("/", builtin_quotient)); globalEnvironmentPut(symbolTableGetOrAdd("eq?"), newBuiltinFunction("eq?", builtin_eqP)); globalEnvironmentPut(symbolTableGetOrAdd("cons?"), newBuiltinFunction("cons?", builtin_consP)); globalEnvironmentPut(symbolTableGetOrAdd("car"), newBuiltinFunction("car", builtin_car)); globalEnvironmentPut(symbolTableGetOrAdd("cdr"), newBuiltinFunction("cdr", builtin_cdr)); globalEnvironmentPut(symbolTableGetOrAdd("cons"), newBuiltinFunction("cons", builtin_cons)); globalEnvironmentPut(symbolTableGetOrAdd("include"), newBuiltinFunction("include", builtin_include)); globalEnvironmentPut(symbolTableGetOrAdd(">"), newBuiltinFunction(">", builtin_gThanNrP)); globalEnvironmentPut(symbolTableGetOrAdd("set-car!"), newBuiltinFunction("set-car!", builtin_set_car)); globalEnvironmentPut(symbolTableGetOrAdd("set-cdr!"), newBuiltinFunction("set-cdr!", builtin_set_cdr)); globalEnvironmentPut(symbolTableGetOrAdd("display"), newBuiltinFunction("display", builtin_display)); globalEnvironmentPut(symbolTableGetOrAdd("write"), newBuiltinFunction("write", builtin_write)); globalEnvironmentPut(symbolTableGetOrAdd("string=?"), newBuiltinFunction("string=?", builtin_eqStringP)); }
object sysPrimitive(int number, object* arguments) { ObjectHandle returnedObject = nilobj; /* someday there will be more here */ switch(number - 150) { case 0: /* do a system() call */ returnedObject = newInteger(system( objectRef(arguments[0]).charPtr())); break; case 1: /* editline, with history support */ { char* command = linenoise_nb(objectRef(arguments[0]).charPtr()); returnedObject = newStString(command); if(command) { linenoiseHistoryAdd(command); free(command); } } break; case 2: /* get last error */ { returnedObject = newStString(gLastError); } break; case 3: /* force garbage collect */ { MemoryManager::Instance()->garbageCollect(); } break; case 4: { returnedObject = newInteger(MemoryManager::Instance()->objectCount()); } break; case 5: { returnedObject = newStString(MemoryManager::Instance()->statsString().c_str()); } break; default: sysError("unknown primitive","sysPrimitive"); } return(returnedObject); }
/* readDeclaration reads a declaration of a class */ static void readClassDeclaration() { object classObj, super, vars; int i, size, instanceTop; object instanceVariables[15]; if (nextToken() != nameconst) sysError("bad file format", "no name in declaration"); classObj = findClass(tokenString); size = 0; if (nextToken() == nameconst) /* read superclass name */ { super = findClass(tokenString); basicAtPut(classObj, superClassInClass, super); size = intValue(basicAt(super, sizeInClass)); nextToken(); } if (token == nameconst) /* read instance var names */ { instanceTop = 0; while (token == nameconst) { instanceVariables[instanceTop++] = newSymbol(tokenString); size++; nextToken(); } vars = newArray(instanceTop); for (i = 0; i < instanceTop; i++) { basicAtPut(vars, i+1, instanceVariables[i]); } basicAtPut(classObj, variablesInClass, vars); } basicAtPut(classObj, sizeInClass, newInteger(size)); }
OBJ readNumber(OBJ inStream, char firstChar, int isNegative){ //printf(YEL "\nreadNumber>" RESET); /* * TO-DO refactor! */ jscheme_int64 *iVal = NULL; char ch; OBJ retVal; // substract the ASCII value of '0' from char to get the actual value between 0 and 9. jscheme_int64 start = (jscheme_int64) firstChar - '0'; if(isNegative) start *= -1; iVal = &start; while( isDigit( ch = nextChar(inStream) )){ //iVal = iVal * 10 + ( (int)ch - '0'); jscheme_int64 ch_val = (jscheme_int64) ch - '0'; if(isNegative){ int mul = __builtin_smull_overflow(*iVal, 10, iVal); int sub = __builtin_ssubl_overflow(*iVal, ch_val, iVal); if( mul || sub ){ if(thisIsTheEnd(inStream)){ prompt_on(); } js_error("readNumber: integer underflow", newInteger(*iVal)); } }else{ int mul = __builtin_smull_overflow(*iVal, 10, iVal); int add = __builtin_saddl_overflow(*iVal, ch_val, iVal); if( mul || add ){ if(thisIsTheEnd(inStream)){ prompt_on(); } js_error("readNumber: integer overflow", newInteger(*iVal)); } } } unreadChar(inStream, ch); retVal = newInteger( *iVal ); return retVal; }
void testFreeingSectors(){ RuntimeErrorValidator * validator = buildErrorSuccessValidator(); Bool aSortingCriteria(int * i , int * x){ return (*i < *x); } Bool equalityCriteria(int * a , int * b){ return (*a == *b); } List lista = createList(NULL , (Bool (*)(void* , void*))equalityCriteria, (Bool (*)(void* , void*))aSortingCriteria); addNode(lista , newInteger(18)); addNode(lista , newInteger(20)); addNode(lista , newInteger(2)); addNode(lista , newInteger(11)); addNode(lista , newInteger(13)); addNode(lista , newInteger(1)); addNode(lista , newInteger(17)); freeSectors("VDA1" , lista , validator); if(hasError(validator)){ error(validator->errorDescription); return ; } }
OBJ builtin_minus(int numArgs){ OBJ theArg; switch (numArgs){ case 0: js_error("(-): at least one arg expected", js_nil); /* NOT REACHED */ case 1: theArg = POP(); if( !ISINTEGER(theArg)){ js_error("(-): non-integer argument", theArg); } return newInteger( -INTVAL(theArg) ); default: theArg = NTH_ARG(numArgs, 0); if( !ISINTEGER(theArg)){ POPN(numArgs); js_error("(-): non-integer argument", theArg); } jscheme_int64 *difference = NULL; jscheme_int64 start = INTVAL(theArg); difference = &start; for(int i = 1; i < numArgs; i++){ OBJ nextArg = NTH_ARG(numArgs, i); if( !ISINTEGER(nextArg)){ POPN(numArgs); js_error("(-): non-integer argument", theArg); } if(__builtin_ssubl_overflow(*difference, INTVAL(nextArg), difference)){ // clean stack POPN(numArgs); js_error("(-): integer overflow", newInteger(*difference)); }; } POPN(numArgs); return newInteger(*difference); } /* NOT REACHED */ return js_nil; }
OBJ builtin_times(int numArgs){ jscheme_int64 *product= NULL; jscheme_int64 start = 1; product = &start; for(int i = 0; i < numArgs; i++){ OBJ theArg = POP(); if( !ISINTEGER(theArg)){ POPN((numArgs - 1) - i); js_error("(*): non-integer argument", theArg); } if(__builtin_smull_overflow(*product,INTVAL(theArg),product)){ // clean stack POPN((numArgs - 1) - i); js_error("(*): integer overflow", newInteger(*product)); } } return newInteger(*product); }
/* readDeclaration reads a declaration of a class */ static void readClassDeclaration() { ObjectHandle classObj, metaObj, vars; std::string className, superName; int i, size, instanceTop; // todo: fixed length variables array! ObjectHandle instanceVariables[15]; // todo: horrible fixed length arrays! char metaClassName[100]; char metaSuperClassName[100]; if (ll.nextToken() != nameconst) sysError("bad file format","no name in declaration"); className = ll.strToken(); if (ll.nextToken() == nameconst) { /* read superclass name */ superName = ll.strToken(); ll.nextToken(); } // todo: sprintf eradication! sprintf(metaClassName, "Meta%s", className.c_str()); if(!superName.empty()) sprintf(metaSuperClassName, "Meta%s", superName.c_str()); else sprintf(metaSuperClassName, "Class"); metaObj = createRawClass(metaClassName, "Class", metaSuperClassName); classObj = createRawClass(className.c_str(), metaClassName, superName.c_str()); classObj->_class = metaObj; // Get the current class size, we'll build on this as // we add instance variables. size = getInteger(classObj->basicAt(sizeInClass)); if (ll.currentToken() == nameconst) { /* read instance var names */ instanceTop = 0; while (ll.currentToken() == nameconst) { instanceVariables[instanceTop++] = createSymbol(ll.strToken().c_str()); size++; ll.nextToken(); } vars = newArray(instanceTop); for (i = 0; i < instanceTop; i++) { vars->basicAtPut(i+1, instanceVariables[i]); } classObj->basicAtPut(variablesInClass, vars); } classObj->basicAtPut(sizeInClass, newInteger(size)); classObj->basicAtPut(methodsInClass, newDictionary(39)); }
/* findClass gets a class object, either by finding it already or making it in addition, it makes sure it has a size, by setting the size to zero if it is nil. */ static object findClass(char *name) { object newobj; newobj = globalSymbol(name); if (newobj == nilobj) newobj = newClass(name); if (basicAt(newobj, sizeInClass) == nilobj) { basicAtPut(newobj, sizeInClass, newInteger(0)); } return newobj; }
/* findClass gets a class object, either by finding it already or making it in addition, it makes sure it has a size, by setting the size to zero if it is nil. */ static ObjectHandle findClass(const char* name) { ObjectHandle newObj; newObj = globalSymbol(name); if (newObj == nilobj) { newObj = createAndRegisterNewClass(name); } if (newObj->basicAt(sizeInClass) == nilobj) { newObj->basicAtPut(sizeInClass, newInteger(0)); } return newObj; }
YArray* Array_find(YArray* arr, YValue* val, YThread* th) { arr->parent.o.linkc++; val->o.linkc++; YArray* out = newArray(th); out->parent.o.linkc++; for (size_t i = 0; i < arr->size(arr, th); i++) { YValue* v = arr->get(arr, i, th); if (CHECK_EQUALS(val, v, th)) out->add(out, newInteger((int64_t) i, th), th); } out->parent.o.linkc--; val->o.linkc--; arr->parent.o.linkc--; return out; }
OBJ builtin_plus(int numArgs){ jscheme_int64 start = 0; jscheme_int64 *sum = NULL; sum = &start; int i; for(i = 0; i < numArgs; i++){ OBJ theArg = POP(); if( !ISINTEGER(theArg)){ POPN((numArgs - 1) - i); js_error("(+): non-integer argument", theArg); } if(__builtin_saddl_overflow( *sum, INTVAL(theArg), sum)){ // clean evalStack POPN((numArgs - 1) - i); js_error("(+): integer overflow", newInteger(*sum)); }; } return newInteger(*sum); }
object sysPrimitive(int number, object * arguments) { object returnedObject; /* someday there will be more here */ switch (number - 150) { case 0: /* do a system() call */ returnedObject = newInteger(system(charPtr(arguments[0]))); break; default: sysError("unknown primitive", "sysPrimitive"); } return (returnedObject); }
YValue* DefaultArray_get(YArray* a, size_t index, YThread* th) { DefaultArray* arr = (DefaultArray*) a; MUTEX_LOCK(&arr->access_mutex); if (index >= arr->size) { YValue* yint = newInteger(index, th); wchar_t* wstr = toString(yint, th); throwException(L"WrongArrayIndex", &wstr, 1, th); free(wstr); MUTEX_UNLOCK(&arr->access_mutex); return getNull(th); } YValue* val = arr->array[index]; MUTEX_UNLOCK(&arr->access_mutex); return val; }
/* readRawDeclaration reads a declaration of a class */ static void readRawClassDeclaration() { ObjectHandle classObj, vars; std::string className, metaName, superName; int i, size, instanceTop; // todo: fixed length variables array! ObjectHandle instanceVariables[15]; if (ll.nextToken() != nameconst) sysError("bad file format","no name in declaration"); className = ll.strToken(); size = 0; if (ll.nextToken() == nameconst) { /* read metaclass name */ metaName = ll.strToken(); ll.nextToken(); } if (ll.currentToken() == nameconst) { /* read superclass name */ superName = ll.strToken(); ll.nextToken(); } classObj = createRawClass(className.c_str(), metaName.c_str(), superName.c_str()); // Get the current class size, we'll build on this as // we add instance variables. size = getInteger(classObj->basicAt(sizeInClass)); if (ll.currentToken() == nameconst) { /* read instance var names */ instanceTop = 0; while (ll.currentToken() == nameconst) { instanceVariables[instanceTop++] = createSymbol(ll.strToken().c_str()); size++; ll.nextToken(); } vars = newArray(instanceTop); for (i = 0; i < instanceTop; i++) { vars->basicAtPut(i+1, instanceVariables[i]); } classObj->basicAtPut(variablesInClass, vars); } classObj->basicAtPut(sizeInClass, newInteger(size)); classObj->basicAtPut(methodsInClass, newDictionary(39)); }
/* * tjoin - Interface for users to call join on their threads in SCAM * * @args - The thread ID to join on */ int tjoin (int args) { int tid = ival(car(args)); // Might garbage collect and then wait with pthread_join T_P(); --WorkingThreads; T_V(); pthread_join(Thread[tid], NULL); // I can now garbage collect again T_P(); ++WorkingThreads; T_V(); return newInteger(tid); }
void DefaultArray_insert(YArray* arr, size_t index, YValue* val, YThread* th) { DefaultArray* array = (DefaultArray*) arr; if (index > array->size) { YValue* yint = newInteger(index, th); wchar_t* wstr = toString(yint, th); throwException(L"WrongArrayIndex", &wstr, 1, th); free(wstr); return; } MUTEX_LOCK(&array->access_mutex); DefaultArray_prepare(array, array->size, th); for (size_t i = array->size - 1; i > index; i--) { array->array[i] = array->array[i - 1]; } array->array[index] = val; MUTEX_UNLOCK(&array->access_mutex); }
static ObjectHandle findClassWithMeta(const char* name, ObjectHandle metaObj) { ObjectHandle newObj, nameObj, methTable; int size; newObj = globalSymbol(name); if (newObj == nilobj) { size = getInteger(metaObj->basicAt(sizeInClass)); newObj = MemoryManager::Instance()->allocObject(size); newObj->_class = metaObj; /* now make name */ nameObj = createSymbol(name); newObj->basicAtPut(nameInClass, nameObj); methTable = newDictionary(39); newObj->basicAtPut(methodsInClass, methTable); newObj->basicAtPut(sizeInClass, newInteger(size)); /* now put in global symbols table */ nameTableInsert(symbols, strHash(name), nameObj, newObj); } return newObj; }
void testListImplementation2(){ Bool equling(int * f1 , int * f2){ return *f1 == *f2; } Bool sorting(int * f1 , int * f2){ return *f1<*f2; } void listing(int * e){ if(e != NULL) logInfo( "linux-commons" , itoa(*e)); } List list = createList(listing , equling , sorting); addNode(list , newInteger(1)); addNode(list , newInteger(2)); addNode(list , newInteger(3)); addNode(list , newInteger(4)); addNode(list , newInteger(5)); addNode(list , newInteger(6)); logInfo("linux-commons" , concatAll(2 , "list size: " , itoa(list->size))); listNodes(list); //otra forma de listar elementos Iterator * iterator = buildIterator(list); while(hasMoreElements(iterator)){ int * element = next(iterator); logInfo("linux-commons" , concatAll(2 , "element: " , itoa(*element))); } }
OBJ builtin_quotient(int numArgs){ #ifdef DEBUG if( DETAILED_TYPES->state) printf(RED "WARNING:" RESET " division is implemented for integers only and will truncate fractions!\n"); #endif OBJ theArg; switch (numArgs){ case 0: js_error("(/): at least one arg expected", js_nil); /* NOT REACHED */ case 1: theArg = POP(); if( !ISINTEGER(theArg)){ js_error("(/): non-integer argument", theArg); /* NOT REACHED */ } if( INTVAL(theArg) == 0){ js_error("(/): division by zero", theArg); /* NOT REACHED */ } return newInteger( 1 / INTVAL(theArg) ); default: theArg = NTH_ARG(numArgs, 0); if( !ISINTEGER(theArg)){ POPN(numArgs); js_error("(/): non-integer argument", theArg); /* NOT REACHED */ } if( INTVAL(theArg) == 0){ for(int i = 1; i < numArgs; i++){ OBJ nextArg = NTH_ARG(numArgs, i); if( !ISINTEGER(nextArg) ){ POPN(numArgs); js_error("(/): non-integer argument", theArg); /* NOT REACHED */ } if( INTVAL(nextArg) == 0){ POPN(numArgs); js_error("(/): division by zero", nextArg); /* NOT REACHED */ } } POPN(numArgs); return newInteger(0); } jscheme_int64 quotient = INTVAL(theArg); for(int i = 1; i < numArgs; i++){ OBJ nextArg = NTH_ARG(numArgs, i); if( !ISINTEGER(nextArg) ){ POPN(numArgs); js_error("(/): non-integer argument", theArg); /* NOT REACHED */ } if( INTVAL(nextArg) == 0){ POPN(numArgs); js_error("(/): division by zero", nextArg); /* NOT REACHED */ } quotient = quotient / INTVAL(nextArg); } POPN(numArgs); return newInteger(quotient); } /* NOT REACHED */ return js_nil; }
/*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); }
/* If there is an error in a thread this will return the thread id */ int getThreadError(int args) { return newInteger(ThreadError); }