Levels *Levels_new(IoMessage *msg) { Levels *self = io_calloc(1, sizeof(Levels)); IoState *state = IoObject_state(msg); IoSymbol *operatorTableSymbol = IoState_symbolWithCString_(state, "OperatorTable"); // Be ultra flexable, and try to use the first message's operator table. IoObject *opTable = IoObject_rawGetSlot_(msg, operatorTableSymbol); // Otherwise, use Core OperatorTable, and if that doesn't exist, create it. if (opTable == NULL) { // There is a chance the message didn't have it, but the core did---due // to the Core not being part of the message's protos. Use Core // Message's OperatorTable opTable = IoObject_rawGetSlot_(state->core, operatorTableSymbol); // If Core doesn't have an OperatorTable, then create it. if (opTable == NULL) { opTable = IoObject_new(state); IoObject_setSlot_to_(state->core, operatorTableSymbol, opTable); IoObject_setSlot_to_(opTable, IoState_symbolWithCString_(state, "precedenceLevelCount"), IoState_numberWithDouble_(state, IO_OP_MAX_LEVEL)); } } self->operatorTable = getOpTable(opTable, "operators", IoState_createOperatorTable); self->assignOperatorTable = getOpTable(opTable, "assignOperators", IoState_createAssignOperatorTable); self->stack = List_new(); Levels_reset(self); return self; }
IO_METHOD(IoObject, platformVersion) { char platformVersion[256]; /*doc System platformVersion Returns the version id of the OS. */ #if defined(_WIN32) OSVERSIONINFO os; os.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); GetVersionEx(&os); snprintf(platformVersion, sizeof(platformVersion) - 1, "%d.%d", (int)os.dwMajorVersion, (int)os.dwMinorVersion); #elif defined(unix) || defined(__APPLE__) || defined(__NetBSD__) || defined(__OpenBSD__) /* Why Apple and NetBSD don't define 'unix' I'll never know. */ struct utsname os; int ret = uname(&os); if (ret == 0) { snprintf(platformVersion, 256, "%s.%s", os.version, os.release); //sprintf(platformVersion, (size_t)sizeof(platformVersion) - 1, (const char *)os.release); } #endif return IoState_symbolWithCString_(IOSTATE, platformVersion); }
IoCFunction *IoCFunction_newWithFunctionPointer_tag_name_(void *state, IoUserFunction *func, IoTag *typeTag, const char *funcName) { IoCFunction *proto = IoState_protoWithInitFunction_((IoState *)state, IoCFunction_proto); IoCFunction *self = IOCLONE(proto); DATA(self)->typeTag = typeTag; DATA(self)->func = func; DATA(self)->uniqueName = IoState_symbolWithCString_((IoState *)state, funcName); return self; }
IoMessage *IoMessage_newParse(void *state, IoLexer *lexer) { if (IoLexer_errorToken(lexer)) { IoMessage *m; IoSymbol *errorString; // Maybe the nil message could be used here. Or even a NULL. IoSymbol *error = IoState_symbolWithCString_(state, "Error"); m = IoMessage_newWithName_returnsValue_(state, error, error); errorString = IoState_symbolWithCString_((IoState *)state, IoLexer_errorDescription(lexer)); IoLexer_free(lexer); // hack for now - the caller should be responsible for this IoState_error_(state, m, "compile error: %s", CSTRING(errorString)); } if (IoLexer_topType(lexer) == TERMINATOR_TOKEN) { IoLexer_pop(lexer); } if (IoTokenType_isValidMessageName(IoLexer_topType(lexer))) { IoMessage *self = IoMessage_newParseNextMessageChain(state, lexer); if (IoLexer_topType(lexer) != NO_TOKEN) { // TODO: Exception as the end was expected IoState_error_(state, self, "compile error: %s", "unused tokens"); } return self; } return IoMessage_newWithName_returnsValue_(state, IoState_symbolWithCString_((IoState*)state, "nil"), ((IoState*)state)->ioNil ); }
IO_METHOD(IoObject, installPrefix) { char acPath[256]; char root[256]; if( GetModuleFileName( NULL, acPath, 256 ) != 0) { // guaranteed file name of at least one character after path strcpy(( strrchr( acPath, '\\' ) ), "\\..\\"); _fullpath(root,acPath,256); } return IoState_symbolWithCString_(IOSTATE, root); }
IO_METHOD(IoObject, getEnvironmentVariable) { /*doc System getEnvironmentVariable(nameString) Returns a string with the value of the environment variable whose name is specified by nameString. */ IoSymbol *key = IoMessage_locals_symbolArgAt_(m, locals, 0); char *s = getenv(CSTRING(key)); if (!s) { return ((IoState *)IOSTATE)->ioNil; } return IoState_symbolWithCString_(IOSTATE, s); }
IoMap *getOpTable(IoObject *self, const char *slotName, IoMap *create(IoState *state)) { IoSymbol *symbol = IoState_symbolWithCString_(IOSTATE, slotName); IoObject *operators = IoObject_rawGetSlot_(self, symbol); if (operators && ISMAP(operators)) { return operators; } else { // Not strictly correct as if the message has it's own empty // OperatorTable slot, we'll create one for it instead of using // Core Message OperatorTable operators. Oh well. IoMap *result = create(IOSTATE); IoObject_setSlot_to_(self, symbol, result); return result; } }
IoObject *IoCurses_input(IoCurses *self, IoObject *locals, IoMessage *m) { /*doc Curses input(n) Returns user input up to a return, or a maximun of n characters. */ int length = 1; char string[length+1]; if (IoMessage_argCount(m) > 0) { length = IoNumber_asInt(IoMessage_locals_numberArgAt_(m, locals, 0)); } if (innstr(string, length) == ERR) { return IONIL(self); } return IoState_symbolWithCString_(IOSTATE, string); }
IoObject *IoCurses_get(IoCurses *self, IoObject *locals, IoMessage *m) { /*doc Curses get(n) Returns n characters from the terminal. n is optional and defaults to 1. */ int inputCharacterLimit = IO_CURSES_INPUT_BUFFER_LENGTH; char string[inputCharacterLimit]; if (IoMessage_argCount(m) > 0) { IoNumber *number = IoMessage_locals_numberArgAt_(m, locals, 0); inputCharacterLimit = IoNumber_asInt(number); } if (getnstr(string, inputCharacterLimit) == ERR) { return IONIL(self); } return IoState_symbolWithCString_(IOSTATE, string); }
IoMessage *IoMessage_newFromText_label_(void *state, const char *text, const char *label) { IoSymbol *labelSymbol = IoState_symbolWithCString_((IoState *)state, label); return IoMessage_newFromText_labelSymbol_(state, text, labelSymbol); }
IO_METHOD(IoObject, platform) { /*doc System platform Returns a string description of the platform. */ char *platform = "Unknown"; #if defined(__CYGWIN__) platform = "cygwin"; #elif defined(__MINGW32__) platform = "mingw"; #elif defined(_WIN32) OSVERSIONINFO os; os.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); GetVersionEx(&os); switch(os.dwPlatformId) { case VER_PLATFORM_WIN32_WINDOWS: switch(os.dwMinorVersion) { case 0: platform = "Windows 95"; break; case 10: platform = "Windows 98"; break; case 90: platform = "Windows ME"; break; default: platform = "Windows 9X"; break; } break; case VER_PLATFORM_WIN32_NT: if (os.dwMajorVersion == 3 || os.dwMajorVersion == 4) { platform = "Windows NT"; } else if (os.dwMajorVersion == 5) { switch(os.dwMinorVersion) { case 0: platform = "Windows 2000"; break; case 1: platform = "Windows XP"; break; default: platform = "Windows"; break; } } else { platform = "Windows"; } break; default: platform = "Windows"; } #elif defined(unix) || defined(__APPLE__) || defined(__NetBSD__) || defined(__OpenBSD__) /* Why Apple and NetBSD don't define 'unix' I'll never know. */ struct utsname os; int ret = uname(&os); if (ret == 0) { platform = os.sysname; } #endif return IoState_symbolWithCString_(IOSTATE, platform); }
void Levels_attach(Levels *self, IoMessage *msg, List *expressions) { // TODO clean up this method. IoState *state = IoObject_state(msg); IoSymbol *messageSymbol = IoMessage_name(msg); char *messageName = CSTRING(messageSymbol); int precedence = Levels_levelForOp(self, messageName, messageSymbol, msg); int msgArgCount = IoMessage_argCount(msg); /* // o a := b c ; d becomes o setSlot("a", b c) ; d // // a attaching // := msg // b c msg->next */ if (Levels_isAssignOperator(self, messageSymbol)) { Level *currentLevel = Levels_currentLevel(self); IoMessage *attaching = currentLevel->message; IoSymbol *setSlotName; if (attaching == NULL) // := b ; { // Could be handled as, message(:= 42) -> setSlot(nil, 42) IoState_error_(state, msg, "compile error: %s requires a symbol to its left.", messageName); return; } if (IoMessage_argCount(attaching) > 0) // a(1,2,3) := b ; { IoState_error_(state, msg, "compile error: The symbol to the left of %s cannot have arguments.", messageName); return; } if (msgArgCount > 1) // setSlot("a") :=(b, c, d) e ; { IoState_error_(state, msg, "compile error: Assign operator passed multiple arguments, e.g., a := (b, c).", messageName); return; } { // a := b ; IoSymbol *slotName = DATA(attaching)->name; IoSymbol *quotedSlotName = IoSeq_newSymbolWithFormat_(state, "\"%s\"", CSTRING(slotName)); IoMessage *slotNameMessage = IoMessage_newWithName_returnsValue_(state, quotedSlotName, slotName); IoMessage_rawCopySourceLocation(slotNameMessage, attaching); // a := b ; -> a("a") := b ; IoMessage_addArg_(attaching, slotNameMessage); setSlotName = Levels_nameForAssignOperator(self, state, messageSymbol, slotName, msg); } // a("a") := b ; -> setSlot("a") := b ; DATA(attaching)->name = IoObject_addingRef_(attaching, setSlotName); currentLevel->type = ATTACH; if (msgArgCount > 0) // setSlot("a") :=(b c) d e ; { // b c IoMessage *arg = IoMessage_rawArgAt_(msg, 0); if (DATA(msg)->next == NULL || IoMessage_rawIsEOL(DATA(msg)->next)) { IoMessage_addArg_(attaching, arg); } else { // () IoMessage *foo = IoMessage_newWithName_(state, IoState_symbolWithCString_(state, "")); IoMessage_rawCopySourceLocation(foo, attaching); // () -> (b c) IoMessage_addArg_(foo, arg); // (b c) -> (b c) d e ; IoMessage_rawSetNext_(foo, DATA(msg)->next); // setSlot("a") :=(b c) d e ; -> setSlot("a", (b c) d e ;) :=(b c) d e ; IoMessage_addArg_(attaching, foo); } } else // setSlot("a") := b ; { // setSlot("a") := or setSlot("a") := ; IoMessage *mn = DATA(msg)->next; IoSymbol *name = mn ? DATA(mn)->name : NULL; IoSymbol *semi = IoObject_state(msg)->semicolonSymbol; //if (mn == NULL || IoMessage_rawIsEOL(mn)) if (mn == NULL || name == semi) { IoState_error_(state, msg, "compile error: %s must be followed by a value.", messageName); } // setSlot("a") := b c ; -> setSlot("a", b c ;) := b c ; IoMessage_addArg_(attaching, DATA(msg)->next); } // process the value (b c d) later (setSlot("a", b c d) := b c d ;) if (DATA(msg)->next != NULL && !IoMessage_rawIsEOL(DATA(msg)->next)) { List_push_(expressions, DATA(msg)->next); } { IoMessage *last = msg; while (DATA(last)->next != NULL && !IoMessage_rawIsEOL(DATA(last)->next)) { last = DATA(last)->next; } IoMessage_rawSetNext_(attaching, DATA(last)->next); // Continue processing in IoMessage_opShuffle loop IoMessage_rawSetNext_(msg, DATA(last)->next); if (last != msg) { IoMessage_rawSetNext_(last, NULL); } } // make sure b in 1 := b gets executed IoMessage_rawSetCachedResult_(attaching, NULL); } else if (IoMessage_rawIsEOL(msg)) { Levels_popDownTo(self, IO_OP_MAX_LEVEL-1); Level_attachAndReplace(Levels_currentLevel(self), msg); } else if (precedence != -1) // is an operator { if (msgArgCount > 0) { // move arguments off to their own message to make () after operators behave like Cs grouping () IoMessage *brackets = IoMessage_newWithName_(state, IoState_symbolWithCString_(state, "")); IoMessage_rawCopySourceLocation(brackets, msg); List_copy_(IoMessage_rawArgList(brackets), IoMessage_rawArgList(msg)); List_removeAll(IoMessage_rawArgList(msg)); // Insert the brackets message between msg and its next message IoMessage_rawSetNext_(brackets, DATA(msg)->next); IoMessage_rawSetNext_(msg, brackets); } Levels_popDownTo(self, precedence); Levels_attachToTopAndPush(self, msg, precedence); } else { Level_attachAndReplace(Levels_currentLevel(self), msg); } }