void SC_HID_APIManager::handleElement( int joy_idx, struct hid_device_element * ele, std::atomic<bool> const & shouldBeRunning ){ int status = lockLanguageOrQuit(shouldBeRunning); if (status == EINTR) return; if (status) { postfl("error when locking language (%d)\n", status); return; } if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, s_hidapi->u.classobj ); // set the class HID_API ++g->sp; SetInt(g->sp, joy_idx ); ++g->sp; SetInt(g->sp, ele->index ); ++g->sp; SetInt(g->sp, ele->usage_page ); ++g->sp; SetInt(g->sp, ele->usage ); ++g->sp; SetInt(g->sp, ele->value ); ++g->sp; SetFloat(g->sp, hid_element_map_logical( ele ) ); ++g->sp; SetFloat(g->sp, hid_element_map_physical( ele ) ); ++g->sp; SetInt(g->sp, ele->array_value ); runInterpreter(g, s_hidElementData, 9 ); g->canCallOS = false; } gLangMutex.unlock(); }
void PerformOSCBundle(int inSize, char* inData, PyrObject *replyObj, int inPortNum) { // convert all data to arrays int64 oscTime = OSCtime(inData + 8); double seconds = OSCToElapsedTime(oscTime); VMGlobals *g = gMainVMGlobals; char *data = inData + 16; char* dataEnd = inData + inSize; while (data < dataEnd) { int32 msgSize = OSCint(data); data += sizeof(int32); if (IsBundle(data)) { PerformOSCBundle(msgSize, data, replyObj, inPortNum); } else // is a message { ++g->sp; SetObject(g->sp, g->process); ++g->sp; SetFloat(g->sp, seconds); ++g->sp; SetObject(g->sp, replyObj); ++g->sp; SetInt(g->sp, inPortNum); PyrObject *arrayObj = ConvertOSCMessage(msgSize, data); ++g->sp; SetObject(g->sp, arrayObj); runInterpreter(g, s_recvoscmsg, 5); } data += msgSize; } }
void interpretCmdLine(const char *textbuf, int textlen, char *methodname) { PyrString *string; if (compiledOK) { PyrSlot slot; string = newPyrStringN(gMainVMGlobals->gc, textlen, 0, false); memcpy(string->s, textbuf, textlen); SetObject(&slotRawInterpreter(&gMainVMGlobals->process->interpreter)->cmdLine, string); gMainVMGlobals->gc->GCWrite(slotRawObject(&gMainVMGlobals->process->interpreter), string); SetObject(&slot, gMainVMGlobals->process); //#if __profile__ // ProfilerInit(collectSummary, microsecondsTimeBase, 500, 100); //#endif slotCopy((++gMainVMGlobals->sp), &slot); runInterpreter(gMainVMGlobals, getsym(methodname), 1); //#if __profile__ // ProfilerDump("\pErase2.prof"); // ProfilerTerm(); //#endif } else { postfl("Library has not been compiled successfully.\n"); } }
// pass the remaining command-line arguments to the world void passArguments(int argumentCount, char ** arguments) { mainContext = createMainContext(); exceptionHandlerContext = createExceptionHandlerContext(); // pass all remaining arguments to the script; // place them all directly to the old space since they will live forever OP argumentArray = instantiateClassInOldSpace(ARRAY_OP, argumentCount, 0); for(int index = 0; index < argumentCount; ++index) { int argLength = strlen(arguments[index]); OP argumentString = instantiateClassInOldSpace(STRING_OP, argLength, 0); for(int charIndex = 0; charIndex < argLength; ++charIndex) { storeIndexablePointer(argumentString, charIndex, characterObjectOf(arguments[index][charIndex])); } storeIndexablePointer(argumentArray, index, argumentString); } switchActiveContext(exceptionHandlerContext); activeContextStackPush(argumentArray); sendSelector(OBJECT_ARGUMENTS_SELECTOR_OP, SCRIPTRUNNER_OP, 1); runInterpreter(); mainContext = OBJECT_NIL_OP; exceptionHandlerContext = OBJECT_NIL_OP; }
void PerformOSCBundle(int inSize, char* inData, PyrObject *replyObj) { // convert all data to arrays int64 oscTime = OSCtime(inData + 8); double seconds = OSCToElapsedTime(oscTime); VMGlobals *g = gMainVMGlobals; ++g->sp; SetObject(g->sp, g->process); ++g->sp; SetFloat(g->sp, seconds); ++g->sp; SetObject(g->sp, replyObj); PyrSlot *stackBase = g->sp; char *data = inData + 16; char* dataEnd = inData + inSize; while (data < dataEnd) { int32 msgSize = OSCint(data); data += sizeof(int32); PyrObject *arrayObj = ConvertOSCMessage(msgSize, data); ++g->sp; SetObject(g->sp, arrayObj); data += msgSize; } int numMsgs = g->sp - stackBase; runInterpreter(g, s_recvoscbndl, 3+numMsgs); }
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QFont f("unexistent"); f.setStyleHint(QFont::Monospace); ui->ui_inputPlainTextEdit->setFont(f); ui->ui_outputPlainTextEdit->setFont(f); setCurrentPath(QString()); setModified(false); connect(ui->ui_sourceEditTableWidget, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(cursorPositionChanged(int,int))); connect(ui->ui_sourceEditTableWidget, SIGNAL(textChanged()), this, SLOT(textChanged())); connect(ui->ui_newFileAction, SIGNAL(triggered()), this, SLOT(newFile())); connect(ui->ui_openFileAction, SIGNAL(triggered()), this, SLOT(openFile())); connect(ui->ui_saveFileAction, SIGNAL(triggered()), this, SLOT(saveFile())); connect(ui->ui_saveAsAction, SIGNAL(triggered()), this, SLOT(saveFileAs())); connect(ui->ui_quitAction, SIGNAL(triggered()), this, SLOT(close())); connect(ui->ui_setInterpreterAction, SIGNAL(triggered()), this, SLOT(setInterpreter())); connect(ui->ui_runInterpreterAction, SIGNAL(triggered()), this, SLOT(runInterpreter())); }
SC_DLLEXPORT_C void runLibrary(PyrSymbol* selector) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; try { if (compiledOK) { ++g->sp; SetObject(g->sp, g->process); runInterpreter(g, selector, 1); } else { postfl("Library has not been compiled successfully.\n"); } } catch (std::exception &ex) { PyrMethod *meth = g->method; if (meth) { int ip = slotRawInt8Array(&meth->code) ? g->ip - slotRawInt8Array(&meth->code)->b : -1; post("caught exception in runLibrary %s:%s %3d\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name, ip ); dumpByteCodes(meth); } else { post("caught exception in runLibrary\n"); } error(ex.what()); } catch (...) { postfl("DANGER: OUT of MEMORY. Operation failed.\n"); } g->canCallOS = false; }
void PushQueueEvents_CalibratedValue (){ IOHIDEventStruct event; pRecDevice pCurrentHIDDevice = HIDGetFirstDevice (); int numdevs = gNumberOfHIDDevices; unsigned char result; for(int i=0; i< numdevs; i++){ result = HIDGetEvent(pCurrentHIDDevice, (void*) &event); if(result && compiledOK) { SInt32 value = event.value; int vendorID = pCurrentHIDDevice->vendorID; int productID = pCurrentHIDDevice->productID; int locID = pCurrentHIDDevice->locID; IOHIDElementCookie cookie = (IOHIDElementCookie) event.elementCookie; pRecElement pCurrentHIDElement = HIDGetFirstDeviceElement (pCurrentHIDDevice, kHIDElementTypeAll); // use gElementCookie to find current element while (pCurrentHIDElement && ( (pCurrentHIDElement->cookie) != cookie)) pCurrentHIDElement = HIDGetNextDeviceElement (pCurrentHIDElement, kHIDElementTypeAll); if (pCurrentHIDElement) { value = HIDCalibrateValue(value, pCurrentHIDElement); //find element to calibrate VMGlobals *g = gMainVMGlobals; pthread_mutex_lock (&gLangMutex); g->canCallOS = false; // cannot call the OS ++g->sp; SetObject(g->sp, s_hid->u.classobj); // Set the class HIDService //set arguments: ++g->sp;SetInt(g->sp, vendorID); ++g->sp;SetInt(g->sp, productID); ++g->sp;SetInt(g->sp, locID); ++g->sp;SetInt(g->sp, (int) cookie); ++g->sp;SetInt(g->sp, value); runInterpreter(g, s_hidAction, 6); g->canCallOS = false; // cannot call the OS pthread_mutex_unlock (&gLangMutex); } } /* FIXME: this does not seem to be working! if ( !HIDIsValidDevice(pCurrentHIDDevice) ) { // readError post("HID: read Error\n"); int locID = pCurrentHIDDevice->locID; VMGlobals *g = gMainVMGlobals; pthread_mutex_lock (&gLangMutex); g->canCallOS = false; // cannot call the OS ++g->sp; SetObject(g->sp, s_hid->u.classobj); // Set the class HIDService ++g->sp;SetInt(g->sp, locID); runInterpreter(g, s_readError, 2); g->canCallOS = false; // cannot call the OS pthread_mutex_unlock (&gLangMutex); }*/ pCurrentHIDDevice = HIDGetNextDevice(pCurrentHIDDevice); } }
// create a context that catches unhandled exceptions and prints them OP createExceptionHandlerContext() { switchActiveContext(mainContext); sendSelector(OBJECT_DEFAULT_EXCEPTION_HANDLER_CONTEXT_SELECTOR_OP, SCRIPTRUNNER_OP, 0); runInterpreter(); exceptionHandlerContext = stackPop(mainContext); decrementNamedSmallInteger(exceptionHandlerContext, METHODCONTEXT_PROGRAM_COUNTER); return exceptionHandlerContext; }
void SC_LID::readError() { pthread_mutex_lock(&gLangMutex); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); runInterpreter(g, s_readError, 1); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); }
pascal void OurWordCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon, long inWordPos, short inWordLen) { //post("word done"); pthread_mutex_lock (&gLangMutex); VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, s_speech->u.classobj); //set arguments: ++g->sp; SetInt(g->sp, (int) inRefCon); //src runInterpreter(g, s_speechwordAction, 2); g->canCallOS = false; pthread_mutex_unlock (&gLangMutex); }
static void scCallSysexAction(PyrSymbol* action, int recoverFromUID) { VMGlobals *g = gMainVMGlobals; if(recoverFromUID) { // rebuild the VM so sc won't crash with two following calls ++g->sp; SetObject(g->sp, s_midiin->u.classobj); // Set the class MIDIIn ++g->sp; SetInt(g->sp, recoverFromUID); //src ++g->sp; } PyrInt8Array* sysexArray = newPyrInt8Array(g->gc, (int)gSysexData.size(), 0, true); sysexArray->size = (int)gSysexData.size(); std::copy(gSysexData.begin(), gSysexData.end(), sysexArray->b); SetObject(g->sp, (PyrObject*) sysexArray); // chan argument unneeded as there runInterpreter(g, action, 3 ); // special sysex action in the lang }
void netAddrTcpClientNotifyFunc(void *clientData) { extern bool compiledOK; pthread_mutex_lock(&gLangMutex); if (compiledOK) { PyrObject* netAddrObj = (PyrObject*)clientData; VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, netAddrObj); runInterpreter(g, getsym("prConnectionClosed"), 1); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); }
void PerformOSCMessage(int inSize, char *inData, PyrObject *replyObj, int inPortNum) { PyrObject *arrayObj = ConvertOSCMessage(inSize, inData); // call virtual machine to handle message VMGlobals *g = gMainVMGlobals; ++g->sp; SetObject(g->sp, g->process); ++g->sp; SetFloat(g->sp, elapsedTime()); // time ++g->sp; SetObject(g->sp, replyObj); ++g->sp; SetInt(g->sp, inPortNum); ++g->sp; SetObject(g->sp, arrayObj); runInterpreter(g, s_recvoscmsg, 5); }
void SC_LID::handleEvent(struct input_event& evt) { if (evt.type != EV_SYN) { pthread_mutex_lock(&gLangMutex); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); ++g->sp; SetInt(g->sp, evt.type); ++g->sp; SetInt(g->sp, evt.code); ++g->sp; SetInt(g->sp, evt.value); runInterpreter(g, s_handleEvent, 4); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); } }
pascal void OurSpeechDoneCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon ) { //call action here; // post("text done"); pthread_mutex_lock (&gLangMutex); VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, s_speech->u.classobj); // Set the class //set arguments: ++g->sp;SetInt(g->sp, (int) inRefCon); //src runInterpreter(g, s_speechdoneAction, 2); if(speechStrings[(int) inRefCon] != NULL){ free(speechStrings[(int) inRefCon]); speechStrings[(int) inRefCon] = NULL; } g->canCallOS = false; pthread_mutex_unlock (&gLangMutex); }
static void runShutdown() { //printf("->aboutToCompileLibrary\n"); gLangMutex.lock(); if (compiledOK) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, g->process); runInterpreter(g, s_shutdown, 1); g->canCallOS = false; } gLangMutex.unlock(); //printf("<-aboutToCompileLibrary\n"); }
void aboutToCompileLibrary() { //printf("->aboutToCompileLibrary\n"); pthread_mutex_lock (&gLangMutex); if (compiledOK) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, g->process); runInterpreter(g, s_shutdown, 1); g->canCallOS = false; } pthread_mutex_unlock (&gLangMutex); //printf("<-aboutToCompileLibrary\n"); }
void SC_HID_APIManager::deviceClosed( int joy_idx, struct hid_dev_desc * dd, std::atomic<bool> const & shouldBeRunning ){ int status = lockLanguageOrQuit(shouldBeRunning); if (status == EINTR) return; if (status) { trace("error when locking language (%d)\n", status); return; } if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, s_hidapi->u.classobj ); // set the class HID_API ++g->sp; SetInt(g->sp, joy_idx ); runInterpreter(g, s_hidClosed, 2); g->canCallOS = false; } gLangMutex.unlock(); }
void SerialPort::doneAction() { int status = lockLanguageOrQuit(m_dodone); if (status == EINTR) return; if (status) { postfl("error when locking language (%d)\n", status); return; } PyrSymbol *method = s_doneAction; if (m_obj) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, m_obj); runInterpreter(g, method, 1); g->canCallOS = false; } gLangMutex.unlock(); }
void SC_HID_APIManager::handleDevice( int joy_idx, struct hid_dev_desc * devd, std::atomic<bool> const & shouldBeRunning ){ int status = lockLanguageOrQuit(shouldBeRunning); if (status == EINTR) return; if (status) { postfl("error when locking language (%d)\n", status); return; } if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, s_hidapi->u.classobj ); // set the class HID_API ++g->sp; SetInt(g->sp, joy_idx ); ++g->sp; SetInt(g->sp, devd->device_collection->num_elements ); runInterpreter(g, s_hidDeviceData, 3); g->canCallOS = false; } gLangMutex.unlock(); }
void SerialPort::dataAvailable() { int status = lockLanguageOrQuit(m_running); if (status == EINTR) return; if (status) { postfl("error when locking language (%d)\n", status); return; } PyrSymbol *method = s_dataAvailable; if (m_obj) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, m_obj); runInterpreter(g, method, 1); g->canCallOS = false; } pthread_mutex_unlock (&gLangMutex); }
void compileSucceeded() { compiledOK = !(parseFailed || compileErrors); if (compiledOK) { compiledOK = true; compiledOK = initRuntime(gMainVMGlobals, 128*1024, pyr_pool_runtime); if (compiledOK) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; //++g->sp; SetObject(g->sp, g->process); //runInterpreter(g, s_hardwaresetup, 1); ++g->sp; SetObject(g->sp, g->process); runInterpreter(g, s_startup, 1); g->canCallOS = false; schedRun(); } flushPostBuf(); } }
void* string_popen_thread_func(void *data) { struct sc_process *process = (struct sc_process *)data; FILE *stream = process->stream; pid_t pid = process->pid; char buf[1024]; while (process->postOutput) { char *string = fgets(buf, 1024, stream); if (!string) break; postText(string, strlen(string)); } int res; res = sc_pclose(stream, pid); res = WEXITSTATUS(res); if(process->postOutput) post("RESULT = %d\n", res); free(process); pthread_mutex_lock (&gLangMutex); if(compiledOK) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, class_string); ++g->sp; SetInt(g->sp, res); ++g->sp; SetInt(g->sp, pid); runInterpreter(g, s_unixCmdAction, 3); g->canCallOS = false; } pthread_mutex_unlock (&gLangMutex); return 0; }
// The main bytecode interpreter loop. This is where the magic happens. It is // also, as you can imagine, highly performance critical. Returns `true` if the // fiber completed without error. static bool runInterpreter(WrenVM* vm) { // Hoist these into local variables. They are accessed frequently in the loop // but assigned less frequently. Keeping them in locals and updating them when // a call frame has been pushed or popped gives a large speed boost. register ObjFiber* fiber = vm->fiber; register CallFrame* frame; register Value* stackStart; register uint8_t* ip; register ObjFn* fn; // These macros are designed to only be invoked within this function. #define PUSH(value) (*fiber->stackTop++ = value) #define POP() (*(--fiber->stackTop)) #define DROP() (fiber->stackTop--) #define PEEK() (*(fiber->stackTop - 1)) #define PEEK2() (*(fiber->stackTop - 2)) #define READ_BYTE() (*ip++) #define READ_SHORT() (ip += 2, (ip[-2] << 8) | ip[-1]) // Use this before a CallFrame is pushed to store the local variables back // into the current one. #define STORE_FRAME() frame->ip = ip // Use this after a CallFrame has been pushed or popped to refresh the local // variables. #define LOAD_FRAME() \ frame = &fiber->frames[fiber->numFrames - 1]; \ stackStart = frame->stackStart; \ ip = frame->ip; \ if (frame->fn->type == OBJ_FN) \ { \ fn = (ObjFn*)frame->fn; \ } \ else \ { \ fn = ((ObjClosure*)frame->fn)->fn; \ } // Terminates the current fiber with error string [error]. If another calling // fiber is willing to catch the error, transfers control to it, otherwise // exits the interpreter. #define RUNTIME_ERROR(error) \ do { \ STORE_FRAME(); \ fiber = runtimeError(vm, fiber, error); \ if (fiber == NULL) return false; \ LOAD_FRAME(); \ DISPATCH(); \ } \ while (false) #if WREN_COMPUTED_GOTO // Note that the order of instructions here must exacly match the Code enum // in wren_vm.h or horrendously bad things happen. static void* dispatchTable[] = { &&code_CONSTANT, &&code_NULL, &&code_FALSE, &&code_TRUE, &&code_LOAD_LOCAL_0, &&code_LOAD_LOCAL_1, &&code_LOAD_LOCAL_2, &&code_LOAD_LOCAL_3, &&code_LOAD_LOCAL_4, &&code_LOAD_LOCAL_5, &&code_LOAD_LOCAL_6, &&code_LOAD_LOCAL_7, &&code_LOAD_LOCAL_8, &&code_LOAD_LOCAL, &&code_STORE_LOCAL, &&code_LOAD_UPVALUE, &&code_STORE_UPVALUE, &&code_LOAD_GLOBAL, &&code_STORE_GLOBAL, &&code_LOAD_FIELD_THIS, &&code_STORE_FIELD_THIS, &&code_LOAD_FIELD, &&code_STORE_FIELD, &&code_POP, &&code_CALL_0, &&code_CALL_1, &&code_CALL_2, &&code_CALL_3, &&code_CALL_4, &&code_CALL_5, &&code_CALL_6, &&code_CALL_7, &&code_CALL_8, &&code_CALL_9, &&code_CALL_10, &&code_CALL_11, &&code_CALL_12, &&code_CALL_13, &&code_CALL_14, &&code_CALL_15, &&code_CALL_16, &&code_SUPER_0, &&code_SUPER_1, &&code_SUPER_2, &&code_SUPER_3, &&code_SUPER_4, &&code_SUPER_5, &&code_SUPER_6, &&code_SUPER_7, &&code_SUPER_8, &&code_SUPER_9, &&code_SUPER_10, &&code_SUPER_11, &&code_SUPER_12, &&code_SUPER_13, &&code_SUPER_14, &&code_SUPER_15, &&code_SUPER_16, &&code_JUMP, &&code_LOOP, &&code_JUMP_IF, &&code_AND, &&code_OR, &&code_IS, &&code_CLOSE_UPVALUE, &&code_RETURN, &&code_LIST, &&code_CLOSURE, &&code_CLASS, &&code_METHOD_INSTANCE, &&code_METHOD_STATIC, &&code_END }; #define INTERPRET_LOOP DISPATCH(); #define CASE_CODE(name) code_##name #if WREN_DEBUG_TRACE_INSTRUCTIONS // Prints the stack and instruction before each instruction is executed. #define DISPATCH() \ { \ wrenDebugPrintStack(fiber); \ wrenDebugPrintInstruction(vm, fn, (int)(ip - fn->bytecode)); \ instruction = *ip++; \ goto *dispatchTable[instruction]; \ } #else #define DISPATCH() goto *dispatchTable[instruction = READ_BYTE()]; #endif #else #define INTERPRET_LOOP for (;;) switch (instruction = READ_BYTE()) #define CASE_CODE(name) case CODE_##name #define DISPATCH() break #endif LOAD_FRAME(); Code instruction; INTERPRET_LOOP { CASE_CODE(LOAD_LOCAL_0): CASE_CODE(LOAD_LOCAL_1): CASE_CODE(LOAD_LOCAL_2): CASE_CODE(LOAD_LOCAL_3): CASE_CODE(LOAD_LOCAL_4): CASE_CODE(LOAD_LOCAL_5): CASE_CODE(LOAD_LOCAL_6): CASE_CODE(LOAD_LOCAL_7): CASE_CODE(LOAD_LOCAL_8): PUSH(stackStart[instruction - CODE_LOAD_LOCAL_0]); DISPATCH(); CASE_CODE(LOAD_LOCAL): PUSH(stackStart[READ_BYTE()]); DISPATCH(); CASE_CODE(LOAD_FIELD_THIS): { int field = READ_BYTE(); Value receiver = stackStart[0]; ASSERT(IS_INSTANCE(receiver), "Receiver should be instance."); ObjInstance* instance = AS_INSTANCE(receiver); ASSERT(field < instance->obj.classObj->numFields, "Out of bounds field."); PUSH(instance->fields[field]); DISPATCH(); } CASE_CODE(POP): DROP(); DISPATCH(); CASE_CODE(NULL): PUSH(NULL_VAL); DISPATCH(); CASE_CODE(FALSE): PUSH(FALSE_VAL); DISPATCH(); CASE_CODE(TRUE): PUSH(TRUE_VAL); DISPATCH(); CASE_CODE(CALL_0): CASE_CODE(CALL_1): CASE_CODE(CALL_2): CASE_CODE(CALL_3): CASE_CODE(CALL_4): CASE_CODE(CALL_5): CASE_CODE(CALL_6): CASE_CODE(CALL_7): CASE_CODE(CALL_8): CASE_CODE(CALL_9): CASE_CODE(CALL_10): CASE_CODE(CALL_11): CASE_CODE(CALL_12): CASE_CODE(CALL_13): CASE_CODE(CALL_14): CASE_CODE(CALL_15): CASE_CODE(CALL_16): { // Add one for the implicit receiver argument. int numArgs = instruction - CODE_CALL_0 + 1; int symbol = READ_SHORT(); Value receiver = *(fiber->stackTop - numArgs); ObjClass* classObj = wrenGetClassInline(vm, receiver); // If the class's method table doesn't include the symbol, bail. if (symbol >= classObj->methods.count) { RUNTIME_ERROR(methodNotFound(vm, classObj, symbol)); } Method* method = &classObj->methods.data[symbol]; switch (method->type) { case METHOD_PRIMITIVE: { Value* args = fiber->stackTop - numArgs; // After calling this, the result will be in the first arg slot. switch (method->fn.primitive(vm, fiber, args)) { case PRIM_VALUE: // The result is now in the first arg slot. Discard the other // stack slots. fiber->stackTop -= numArgs - 1; break; case PRIM_ERROR: RUNTIME_ERROR(AS_STRING(args[0])); case PRIM_CALL: STORE_FRAME(); callFunction(fiber, AS_OBJ(args[0]), numArgs); LOAD_FRAME(); break; case PRIM_RUN_FIBER: STORE_FRAME(); fiber = AS_FIBER(args[0]); LOAD_FRAME(); break; } break; } case METHOD_FOREIGN: callForeign(vm, fiber, method->fn.foreign, numArgs); break; case METHOD_BLOCK: STORE_FRAME(); callFunction(fiber, method->fn.obj, numArgs); LOAD_FRAME(); break; case METHOD_NONE: RUNTIME_ERROR(methodNotFound(vm, classObj, symbol)); break; } DISPATCH(); } CASE_CODE(STORE_LOCAL): stackStart[READ_BYTE()] = PEEK(); DISPATCH(); CASE_CODE(CONSTANT): PUSH(fn->constants[READ_SHORT()]); DISPATCH(); CASE_CODE(SUPER_0): CASE_CODE(SUPER_1): CASE_CODE(SUPER_2): CASE_CODE(SUPER_3): CASE_CODE(SUPER_4): CASE_CODE(SUPER_5): CASE_CODE(SUPER_6): CASE_CODE(SUPER_7): CASE_CODE(SUPER_8): CASE_CODE(SUPER_9): CASE_CODE(SUPER_10): CASE_CODE(SUPER_11): CASE_CODE(SUPER_12): CASE_CODE(SUPER_13): CASE_CODE(SUPER_14): CASE_CODE(SUPER_15): CASE_CODE(SUPER_16): { // TODO: Almost completely copied from CALL. Unify somehow. // Add one for the implicit receiver argument. int numArgs = instruction - CODE_SUPER_0 + 1; int symbol = READ_SHORT(); Value receiver = *(fiber->stackTop - numArgs); ObjClass* classObj = wrenGetClassInline(vm, receiver); // Ignore methods defined on the receiver's immediate class. classObj = classObj->superclass; // If the class's method table doesn't include the symbol, bail. if (symbol >= classObj->methods.count) { RUNTIME_ERROR(methodNotFound(vm, classObj, symbol)); } Method* method = &classObj->methods.data[symbol]; switch (method->type) { case METHOD_PRIMITIVE: { Value* args = fiber->stackTop - numArgs; // After calling this, the result will be in the first arg slot. switch (method->fn.primitive(vm, fiber, args)) { case PRIM_VALUE: // The result is now in the first arg slot. Discard the other // stack slots. fiber->stackTop -= numArgs - 1; break; case PRIM_ERROR: RUNTIME_ERROR(AS_STRING(args[0])); case PRIM_CALL: STORE_FRAME(); callFunction(fiber, AS_OBJ(args[0]), numArgs); LOAD_FRAME(); break; case PRIM_RUN_FIBER: STORE_FRAME(); fiber = AS_FIBER(args[0]); LOAD_FRAME(); break; } break; } case METHOD_FOREIGN: callForeign(vm, fiber, method->fn.foreign, numArgs); break; case METHOD_BLOCK: STORE_FRAME(); callFunction(fiber, method->fn.obj, numArgs); LOAD_FRAME(); break; case METHOD_NONE: RUNTIME_ERROR(methodNotFound(vm, classObj, symbol)); break; } DISPATCH(); } CASE_CODE(LOAD_UPVALUE): { Upvalue** upvalues = ((ObjClosure*)frame->fn)->upvalues; PUSH(*upvalues[READ_BYTE()]->value); DISPATCH(); } CASE_CODE(STORE_UPVALUE): { Upvalue** upvalues = ((ObjClosure*)frame->fn)->upvalues; *upvalues[READ_BYTE()]->value = PEEK(); DISPATCH(); } CASE_CODE(LOAD_GLOBAL): PUSH(vm->globals.data[READ_SHORT()]); DISPATCH(); CASE_CODE(STORE_GLOBAL): vm->globals.data[READ_SHORT()] = PEEK(); DISPATCH(); CASE_CODE(STORE_FIELD_THIS): { int field = READ_BYTE(); Value receiver = stackStart[0]; ASSERT(IS_INSTANCE(receiver), "Receiver should be instance."); ObjInstance* instance = AS_INSTANCE(receiver); ASSERT(field < instance->obj.classObj->numFields, "Out of bounds field."); instance->fields[field] = PEEK(); DISPATCH(); } CASE_CODE(LOAD_FIELD): { int field = READ_BYTE(); Value receiver = POP(); ASSERT(IS_INSTANCE(receiver), "Receiver should be instance."); ObjInstance* instance = AS_INSTANCE(receiver); ASSERT(field < instance->obj.classObj->numFields, "Out of bounds field."); PUSH(instance->fields[field]); DISPATCH(); } CASE_CODE(STORE_FIELD): { int field = READ_BYTE(); Value receiver = POP(); ASSERT(IS_INSTANCE(receiver), "Receiver should be instance."); ObjInstance* instance = AS_INSTANCE(receiver); ASSERT(field < instance->obj.classObj->numFields, "Out of bounds field."); instance->fields[field] = PEEK(); DISPATCH(); } CASE_CODE(JUMP): { int offset = READ_SHORT(); ip += offset; DISPATCH(); } CASE_CODE(LOOP): { // Jump back to the top of the loop. int offset = READ_SHORT(); ip -= offset; DISPATCH(); } CASE_CODE(JUMP_IF): { int offset = READ_SHORT(); Value condition = POP(); if (IS_FALSE(condition) || IS_NULL(condition)) ip += offset; DISPATCH(); } CASE_CODE(AND): { int offset = READ_SHORT(); Value condition = PEEK(); if (IS_FALSE(condition) || IS_NULL(condition)) { // Short-circuit the right hand side. ip += offset; } else { // Discard the condition and evaluate the right hand side. DROP(); } DISPATCH(); } CASE_CODE(OR): { int offset = READ_SHORT(); Value condition = PEEK(); if (IS_FALSE(condition) || IS_NULL(condition)) { // Discard the condition and evaluate the right hand side. DROP(); } else { // Short-circuit the right hand side. ip += offset; } DISPATCH(); } CASE_CODE(IS): { Value expected = POP(); if (!IS_CLASS(expected)) { const char* message = "Right operand must be a class."; RUNTIME_ERROR(AS_STRING(wrenNewString(vm, message, strlen(message)))); } ObjClass* actual = wrenGetClass(vm, POP()); bool isInstance = false; // Walk the superclass chain looking for the class. while (actual != NULL) { if (actual == AS_CLASS(expected)) { isInstance = true; break; } actual = actual->superclass; } PUSH(BOOL_VAL(isInstance)); DISPATCH(); } CASE_CODE(CLOSE_UPVALUE): closeUpvalue(fiber); DROP(); DISPATCH(); CASE_CODE(RETURN): { Value result = POP(); fiber->numFrames--; // Close any upvalues still in scope. Value* firstValue = stackStart; while (fiber->openUpvalues != NULL && fiber->openUpvalues->value >= firstValue) { closeUpvalue(fiber); } // If the fiber is complete, end it. if (fiber->numFrames == 0) { // If this is the main fiber, we're done. if (fiber->caller == NULL) return true; // We have a calling fiber to resume. fiber = fiber->caller; // Store the result in the resuming fiber. *(fiber->stackTop - 1) = result; } else { // Store the result of the block in the first slot, which is where the // caller expects it. stackStart[0] = result; // Discard the stack slots for the call frame (leaving one slot for the // result). fiber->stackTop = frame->stackStart + 1; } LOAD_FRAME(); DISPATCH(); } CASE_CODE(LIST): { int numElements = READ_BYTE(); ObjList* list = wrenNewList(vm, numElements); // TODO: Do a straight memcopy. for (int i = 0; i < numElements; i++) { list->elements[i] = *(fiber->stackTop - numElements + i); } // Discard the elements. fiber->stackTop -= numElements; PUSH(OBJ_VAL(list)); DISPATCH(); } CASE_CODE(CLOSURE): { ObjFn* prototype = AS_FN(fn->constants[READ_SHORT()]); ASSERT(prototype->numUpvalues > 0, "Should not create closure for functions that don't need it."); // Create the closure and push it on the stack before creating upvalues // so that it doesn't get collected. ObjClosure* closure = wrenNewClosure(vm, prototype); PUSH(OBJ_VAL(closure)); // Capture upvalues. for (int i = 0; i < prototype->numUpvalues; i++) { bool isLocal = READ_BYTE(); int index = READ_BYTE(); if (isLocal) { // Make an new upvalue to close over the parent's local variable. closure->upvalues[i] = captureUpvalue(vm, fiber, frame->stackStart + index); } else { // Use the same upvalue as the current call frame. closure->upvalues[i] = ((ObjClosure*)frame->fn)->upvalues[index]; } } DISPATCH(); } CASE_CODE(CLASS): { ObjString* name = AS_STRING(PEEK2()); ObjClass* superclass; if (IS_NULL(PEEK())) { // Implicit Object superclass. superclass = vm->objectClass; } else { // TODO: Handle the superclass not being a class object! superclass = AS_CLASS(PEEK()); } int numFields = READ_BYTE(); ObjClass* classObj = wrenNewClass(vm, superclass, numFields, name); // Don't pop the superclass and name off the stack until the subclass is // done being created, to make sure it doesn't get collected. DROP(); DROP(); // Now that we know the total number of fields, make sure we don't // overflow. if (superclass->numFields + numFields > MAX_FIELDS) { char message[70 + MAX_VARIABLE_NAME]; snprintf(message, 70 + MAX_VARIABLE_NAME, "Class '%s' may not have more than %d fields, including inherited " "ones.", name->value, MAX_FIELDS); RUNTIME_ERROR(AS_STRING(wrenNewString(vm, message, strlen(message)))); } PUSH(OBJ_VAL(classObj)); DISPATCH(); } CASE_CODE(METHOD_INSTANCE): CASE_CODE(METHOD_STATIC): { int type = instruction; int symbol = READ_SHORT(); ObjClass* classObj = AS_CLASS(PEEK()); Value method = PEEK2(); bindMethod(vm, type, symbol, classObj, method); DROP(); DROP(); DISPATCH(); } CASE_CODE(END): // A CODE_END should always be preceded by a CODE_RETURN. If we get here, // the compiler generated wrong code. UNREACHABLE(); } // We should only exit this function from an explicit return from CODE_RETURN // or a runtime error. UNREACHABLE(); return false; } WrenInterpretResult wrenInterpret(WrenVM* vm, const char* sourcePath, const char* source) { // TODO: Check for freed VM. ObjFn* fn = wrenCompile(vm, sourcePath, source); if (fn == NULL) return WREN_RESULT_COMPILE_ERROR; WREN_PIN(vm, fn); vm->fiber = wrenNewFiber(vm, (Obj*)fn); WREN_UNPIN(vm); if (runInterpreter(vm)) { return WREN_RESULT_SUCCESS; } else { return WREN_RESULT_RUNTIME_ERROR; } }
/* timer "interrupt" for processing midi data */ static void PMProcessMidi(PtTimestamp timestamp, void *userData) { ScopeMutexLock mulo(&gPmStreamMutex); PmError result; PmEvent buffer; /* just one message at a time */ for( int i = 0 ; i < gNumMIDIInPorts; ++i ) { int pmdid = gMidiInputIndexToPmDevIndex[i]; PmStream* midi_in = gMIDIInStreams[i]; if( midi_in ) { while(result = Pm_Poll(midi_in)) { long Tstatus, data1, data2; if (Pm_Read(midi_in, &buffer, 1) == pmBufferOverflow) continue; // unless there was overflow, we should have a message now Tstatus = Pm_MessageStatus(buffer.message); data1 = Pm_MessageData1(buffer.message); data2 = Pm_MessageData2(buffer.message); // +---------------------------------------------+ // | Lock the interp. mutex and dispatch message | // +---------------------------------------------+ pthread_mutex_lock (&gLangMutex); // it is needed -jamesmcc if (compiledOK) { VMGlobals *g = gMainVMGlobals; uint8 status = static_cast<uint8>(Tstatus & 0xF0); uint8 chan = static_cast<uint8>(Tstatus & 0x0F); g->canCallOS = false; // cannot call the OS ++g->sp; SetObject(g->sp, s_midiin->u.classobj); // Set the class MIDIIn //set arguments: ++g->sp; SetInt(g->sp, pmdid); //src // ++g->sp; SetInt(g->sp, status); //status ++g->sp; SetInt(g->sp, chan); //chan //if(status & 0x80) // set the running status for voice messages //gRunningStatus = ((status >> 4) == 0xF) ? 0 : pkt->data[i]; // keep also additional info switch (status) { case 0x80 : //noteOff ++g->sp; SetInt(g->sp, data1); ++g->sp; SetInt(g->sp, data2); runInterpreter(g, s_midiNoteOffAction, 5); break; case 0x90 : //noteOn ++g->sp; SetInt(g->sp, data1); ++g->sp; SetInt(g->sp, data2); runInterpreter(g, data2 ? s_midiNoteOnAction : s_midiNoteOffAction, 5); break; case 0xA0 : //polytouch ++g->sp; SetInt(g->sp, data1); ++g->sp; SetInt(g->sp, data2); runInterpreter(g, s_midiPolyTouchAction, 5); break; case 0xB0 : //control ++g->sp; SetInt(g->sp, data1); ++g->sp; SetInt(g->sp, data2); runInterpreter(g, s_midiControlAction, 5); break; case 0xC0 : //program ++g->sp; SetInt(g->sp, data1); runInterpreter(g, s_midiProgramAction, 4); break; case 0xD0 : //touch ++g->sp; SetInt(g->sp, data1); runInterpreter(g, s_midiTouchAction, 4); break; case 0xE0 : //bend ++g->sp; SetInt(g->sp, (data2 << 7) | data1); runInterpreter(g, s_midiBendAction, 4); break; /*case 0xF0 : // only the first Pm_Event will carry the 0xF0 byte // sysex message will be terminated by the EOX status byte 0xF7 midiProcessSystemPacket(data1, data2, chan); break; default : // data byte => continuing sysex message if(gRunningStatus && !gSysexFlag) { // handle running status status = gRunningStatus & 0xF0; // accept running status only inside a packet beginning chan = gRunningStatus & 0x0F; // with a valid status byte SetInt(g->sp, chan); --i; //goto L; // parse again with running status set // mv - get next byte } chan = 0; i += midiProcessSystemPacket(pkt, chan); // process sysex packet break; */ } g->canCallOS = false; } pthread_mutex_unlock (&gLangMutex); } } // if (midi_in) } // for loop until numMIDIInPorts }
static int midiProcessSystemPacket(MIDIPacket *pkt, int chan) { int index, data; VMGlobals *g = gMainVMGlobals; switch (chan) { case 7: // added cp: Sysex EOX must be taken into account if first on data packet case 0: { int last_uid = 0; int m = pkt->length; Byte* p_pkt = pkt->data; Byte pktval; while(m--) { pktval = *p_pkt++; if(pktval & 0x80) { // status byte if(pktval == 0xF7) { // end packet gSysexData.push_back(pktval); // add EOX if(gSysexFlag) sysexEnd(last_uid); // if last_uid != 0 rebuild the VM. else sysexEndInvalid(); // invalid 1 byte with only EOX can happen break; } else if(pktval == 0xF0) { // new packet if(gSysexFlag) {// invalid new one/should not happen -- but handle in case // store the last uid value previous to invalid data to rebuild VM after sysexEndInvalid call // since it may call sysexEnd() just after it ! if(slotIntVal(g->sp-1, &last_uid)) { post("error: failed retrieving uid value !"); last_uid = -1; } sysexEndInvalid(); } sysexBegin(); // new sysex in gSysexData.push_back(pktval); // add SOX } else {// abnormal data in middle of sysex packet gSysexData.push_back(pktval); // add it as an abort message sysexEndInvalid(); // flush invalid m = 0; // discard all packet break; } } else if(gSysexFlag) gSysexData.push_back(pktval); // add Byte else // garbage - handle in case - discard it break; } return (pkt->length-m); } break; case 1 : index = pkt->data[1] >> 4; data = pkt->data[1] & 0xf; switch (index) { case 1: case 3: case 5: case 7: { data = data << 4; } } SetInt(g->sp, index); // chan unneeded ++g->sp; SetInt(g->sp, data); // special smpte action in the lang runInterpreter(g, s_midiSMPTEAction, 4 ); return 2; case 2 : //songptr ++g->sp; SetInt(g->sp, (pkt->data[2] << 7) | pkt->data[1]); //val1 runInterpreter(g, s_midiSysrtAction, 4); return 3; case 3 : // song select ++g->sp; SetInt(g->sp, pkt->data[1]); //val1 runInterpreter(g, s_midiSysrtAction, 4); return 2; case 8 : //clock case 10: //start case 11: //continue case 12: //stop case 15: //reset gRunningStatus = 0; // clear running status runInterpreter(g, s_midiSysrtAction, 3); return 1; default: g->sp -= 3; // nevermind break; } return (1); }
static void midiProcessPacket(MIDIPacket *pkt, size_t uid) { //jt if(pkt) { pthread_mutex_lock (&gLangMutex); //dont know if this is really needed/seems to be more stable.. // it is needed -jamesmcc if (compiledOK) { VMGlobals *g = gMainVMGlobals; int i = 0; //cp : changed uint8 to int if packet->length >= 256 bug:(infinite loop) while (i < pkt->length) { uint8 status = pkt->data[i] & 0xF0; uint8 chan = pkt->data[i] & 0x0F; g->canCallOS = false; // cannot call the OS ++g->sp; SetObject(g->sp, s_midiin->u.classobj); // Set the class MIDIIn //set arguments: ++g->sp; SetInt(g->sp, (int)uid); //src // ++g->sp; SetInt(g->sp, status); //status ++g->sp; SetInt(g->sp, chan); //chan if(status & 0x80) // set the running status for voice messages gRunningStatus = ((status >> 4) == 0xF) ? 0 : pkt->data[i]; // keep also additional info L: switch (status) { case 0x80 : //noteOff ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 ++g->sp; SetInt(g->sp, pkt->data[i+2]); //val2 runInterpreter(g, s_midiNoteOffAction, 5); i += 3; break; case 0x90 : //noteOn ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 ++g->sp; SetInt(g->sp, pkt->data[i+2]); //val2 runInterpreter(g, pkt->data[i+2] ? s_midiNoteOnAction : s_midiNoteOffAction, 5); i += 3; break; case 0xA0 : //polytouch ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 ++g->sp; SetInt(g->sp, pkt->data[i+2]); //val2 runInterpreter(g, s_midiPolyTouchAction, 5); i += 3; break; case 0xB0 : //control ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 ++g->sp; SetInt(g->sp, pkt->data[i+2]); //val2 runInterpreter(g, s_midiControlAction, 5); i += 3; break; case 0xC0 : //program ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 runInterpreter(g, s_midiProgramAction, 4); i += 2; break; case 0xD0 : //touch ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 runInterpreter(g, s_midiTouchAction, 4); i += 2; break; case 0xE0 : //bend ++g->sp; SetInt(g->sp, (pkt->data[i+2] << 7) | pkt->data[i+1]); //val1 runInterpreter(g, s_midiBendAction, 4); i += 3; break; case 0xF0 : i += midiProcessSystemPacket(pkt, chan); break; default : // data byte => continuing sysex message if(gRunningStatus && !gSysexFlag) { // modified cp: handling running status. may be we should here status = gRunningStatus & 0xF0; // accept running status only inside a packet beginning chan = gRunningStatus & 0x0F; // with a valid status byte ? SetInt(g->sp, chan); --i; goto L; // parse again with running status set } chan = 0; i += midiProcessSystemPacket(pkt, chan); break; } } g->canCallOS = false; } pthread_mutex_unlock (&gLangMutex); } }