Ejemplo n.º 1
0
int Levels_levelForOp(Levels *self, char *messageName, IoSymbol *messageSymbol, IoMessage *msg)
{
	IoObject *value = IoMap_rawAt(self->operatorTable, messageSymbol);

	if (!value)
	{
		return -1;
	}

	if (ISNUMBER(value))
	{
		int precedence = IoNumber_asInt((IoNumber*)value);
		if (precedence < 0 || precedence >= IO_OP_MAX_LEVEL)
		{
			IoState_error_(IoObject_state(msg), msg, "compile error: Precedence for operators must be between 0 and %d. Precedence was %d.", IO_OP_MAX_LEVEL - 1, precedence);
		}

		return precedence;
	}
	else
	{
		IoState_error_(IoObject_state(msg), msg, "compile error: Value for '%s' in Message OperatorTable operators is not a number. Values in the OperatorTable operators are numbers which indicate the precedence of the operator.", messageName);
		return -1; // The C compiler does not know that IoState_error_() will never return.
	}
}
Ejemplo n.º 2
0
IoObject *IoCertificate_attributes(IoCertificate *self, IoObject *locals, IoMessage *m)
{
	IoObject *map = IoObject_new(IoObject_state(self));
	const EVP_PKEY *pkey = X509_extract_key(X509(self));
	int i;
	for(i = 0; i < EVP_PKEY_get_attr_count(pkey); i++)
	{
		IoList *list = IoList_new(IoObject_state(self));
		X509_ATTRIBUTE *attr = EVP_PKEY_get_attr(pkey, i);
		const char *key = (const char *)OBJ_nid2ln(OBJ_obj2nid(X509_ATTRIBUTE_get0_object(attr)));
		int j;
		for(j = 0; j < X509_ATTRIBUTE_count(attr); j++)
		{
			ASN1_TYPE *attrType = X509_ATTRIBUTE_get0_type(attr, j);
			ASN1_OBJECT *attrData = X509_ATTRIBUTE_get0_data(attr, j, attrType->type, NULL);
			//consider switching on attrType instead; 
			//really, that would be wiser, so that dates, 
			//numbers, etc can be happy
			/*
			switch(attrType->type) {
				case V_ASN1_OCTET_STRING:
			...
			*/
			int len = i2t_ASN1_OBJECT(NULL, 0, attrData);
			char *value = calloc(len, sizeof(char));
			i2t_ASN1_OBJECT(value, len, attrData);
			IoList_rawAppend_(list, IoSeq_newWithCString_(IoObject_state(self), value));
		}
		IoObject_setSlot_to_(map, IOSYMBOL(key), list);
	}
	return map;
}
Ejemplo n.º 3
0
void IoDrawStuffKeyboardFunc(int key)
{
    //printf("IoDrawStuffKeyboardFunc\n");
    IoState_pushRetainPool(IoObject_state(proto));
    IoMessage_setCachedArg_toInt_(DATA(proto)->keyboardMessage, 0, key);    
    IoDrawStuff_tryCallback(proto, DATA(proto)->keyboardMessage);
    IoState_popRetainPool(IoObject_state(proto));
}
Ejemplo n.º 4
0
void IoDrawStuffStopFunc(void)
{
    //printf("IoDrawStuffStopFunc\n");
    IoState_pushRetainPool(IoObject_state(proto));
    
    IoDrawStuff_tryCallback(proto, DATA(proto)->stopMessage);
    IoState_popRetainPool(IoObject_state(proto));
}
Ejemplo n.º 5
0
void IoDrawStuffStepFunc(int pause)
{
    //printf("IoDrawStuffStepFunc\n");
    IoState_pushRetainPool(IoObject_state(proto));
    IoMessage_setCachedArg_toInt_(DATA(proto)->stepMessage, 0, pause);    
    IoDrawStuff_tryCallback(proto, DATA(proto)->stepMessage);
    IoState_popRetainPool(IoObject_state(proto));
}
Ejemplo n.º 6
0
IoObject *IoCertificate_nameToObject(IoObject *self, X509_NAME *xname)
{
	IoObject *map = IoObject_new(IoObject_state(self));
	int i;
	for(i = 0; i < X509_NAME_entry_count(xname); i++)
	{
		X509_NAME_ENTRY *entry = X509_NAME_get_entry(xname, i);
		const char *key = (const char *)OBJ_nid2ln(OBJ_obj2nid(X509_NAME_ENTRY_get_object(entry)));
		const char *value = (const char *)ASN1_STRING_data(X509_NAME_ENTRY_get_data(entry));
		IoObject_setSlot_to_(map, IOSYMBOL(key), IoSeq_newWithCString_(IoObject_state(self), value));
	}
	return map;
}
Ejemplo n.º 7
0
IoCFFIArray *IoCFFIArray_with(IoCFFIArray *self, IoObject *locals, IoMessage *m)
{
	IoCFFIDataType *type;
	int size, i;
	ffi_type *item_type;
	IoCFFIArray *o = IOCLONE(self);

	IoState_on_doCString_withLabel_(IoObject_state(o), o, "init", "IoCFFIArray_with");

	type = IOCLONE(IoMessage_locals_valueArgAt_(m, locals, 0));
	IoObject_setSlot_to_(o, IOSYMBOL("arrayType"), type);

	size = IoMessage_locals_intArgAt_(m, locals, 1);
	DATA(o)->arraySize = size;

	item_type = IoCFFIDataType_ffiType(type);
	DATA(o)->itemSize = item_type->size;

	// Fake libffi to think we are a Struct
	DATA(o)->ffiType.size = 0;
	DATA(o)->ffiType.alignment = 0;
	DATA(o)->ffiType.type = FFI_TYPE_STRUCT;
	DATA(o)->ffiType.elements = io_calloc(size + 1, sizeof(ffi_type *));
	DATA(o)->needToFreeFFIType = 1;
	for ( i = 0 ; i < size ; i++ ) {
		DATA(o)->ffiType.elements[i] = item_type;
	}
	DATA(o)->ffiType.elements[size] = NULL;

	ffi_cif cif;
	ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 0, &(DATA(o)->ffiType), NULL);

	return o;
}
Ejemplo n.º 8
0
void IoUserInit(IoObject *context)
{
	IoState *self = IoObject_state((IoObject *)context);

	IoObject_setSlot_to_(context, SIOSYMBOL("User"), IoUser_proto(self));

}
Ejemplo n.º 9
0
void IoSystemCallInit(IoObject *context)
{
	IoState *self = IoObject_state((IoObject *)context);

	IoObject_setSlot_to_(context, SIOSYMBOL("SystemCall"), IoSystemCall_proto(self));

}
Ejemplo n.º 10
0
void IoVolcanoInit(IoObject *context)
{
	IoState *self = IoObject_state((IoObject *)context);

	IoObject_setSlot_to_(context, SIOSYMBOL("HttpParser"), IoHttpParser_proto(self));

}
Ejemplo n.º 11
0
void IoThreadInit(IoObject *context)
{
	IoState *self = IoObject_state((IoObject *)context);

	IoObject_setSlot_to_(context, SIOSYMBOL("Thread"), IoThread_proto(self));

}
Ejemplo n.º 12
0
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;
}
Ejemplo n.º 13
0
IoObject *IoCertificate_asnTimeToDate(IoCertificate *self, ASN1_TIME *tm)
{
	char *v;
	int gmt=0;
	int i;
	int y=0,M=0,d=0,h=0,m=0,s=0;

	i=tm->length;
	v=(char *)tm->data;

	if (i < 10) return IONIL(self);
	if (v[i-1] == 'Z') gmt=1;
	for (i=0; i<10; i++)
		if ((v[i] > '9') || (v[i] < '0')) return IONIL(self);
	y= (v[0]-'0')*10+(v[1]-'0');
	if (y < 50) y+=100;
	M= (v[2]-'0')*10+(v[3]-'0');
	if ((M > 12) || (M < 1)) return IONIL(self);
	d= (v[4]-'0')*10+(v[5]-'0');
	h= (v[6]-'0')*10+(v[7]-'0');
	m=  (v[8]-'0')*10+(v[9]-'0');
	if (	(v[10] >= '0') && (v[10] <= '9') &&
		(v[11] >= '0') && (v[11] <= '9'))
		s=  (v[10]-'0')*10+(v[11]-'0');
	struct tm ctm;
	ctm.tm_sec = s;
	ctm.tm_min = m;
	ctm.tm_hour = h;
	ctm.tm_mday = d;
	ctm.tm_mon = M-1;
	ctm.tm_year = y;
	ctm.tm_gmtoff = 0;
		
	return IoDate_newWithTime_(IoObject_state(self), timegm(&ctm));
}
Ejemplo n.º 14
0
IoObject *IoCertificate_extensions(IoCertificate *self, IoObject *locals, IoMessage *m)
{
	IoObject *map = IoObject_new(IoObject_state(self));
	int i;
	for(i = 0; i < X509_get_ext_count(X509(self)); i++)
	{
		IoObject *ioext = IoObject_new(IoObject_state(self));
		X509_EXTENSION *ext = X509_get_ext(X509(self), i);
		const char *key = (const char *)OBJ_nid2ln(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
		const char *value = (const char *)ASN1_STRING_data(X509_EXTENSION_get_data(ext));
		int isCritical = X509_EXTENSION_get_critical(ext);
		IoObject_setSlot_to_(ioext, IOSYMBOL("value"), IoSeq_newWithCString_(IoObject_state(self), value));
		IoObject_setSlot_to_(ioext, IOSYMBOL("isCritical"), IONUMBER(isCritical));
		IoObject_setSlot_to_(map, IOSYMBOL(key), ioext);
	}
	return map;
}
Ejemplo n.º 15
0
Archivo: common.c Proyecto: ADTSH/io
int IoSecureSockets_Password_Callback(char *buf, int size, int flag, void *selfPtr)
{
	IoObject *self = (IoObject *)selfPtr;
	IoSeq *passSeq;
	if(flag == 0) //decryption
	{
		passSeq = IoState_on_doCString_withLabel_(IoObject_state(self), self, "fetchDecryptionPassword", "Decryption Password Callback");
	}
	else //encryption
	{
		passSeq = IoState_on_doCString_withLabel_(IoObject_state(self), self, "fetchEncryptionPassword", "Encryption Password Callback");
	}
	char *cpass = CSTRING(passSeq);
	strncpy(buf, cpass, size);
	buf[size-1] = '\0';
	return strlen(buf);	
}
Ejemplo n.º 16
0
IoSecureSocket *IoSecureServer_tlsWrap(IoSecureServer *self, IoObject *locals, IoMessage *msg)
{
	SSL_CTX *ctx = OCTX(self);
	IoSocket *sock = IoMessage_locals_socketArgAt_(msg, locals, 0);
	IoNumber *port = IoObject_getSlot_(sock, IOSYMBOL("port"));
	SSL *ssl = SSL_new(ctx);
	SSL_set_fd(ssl, IoSocket_rawDescriptor(sock));
	set_nonblocking(SSL_get_rbio(ssl));
	set_nonblocking(SSL_get_wbio(ssl));
	SSL_set_accept_state(ssl);
	SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE |
		SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
	IoIPAddress *ioaddr = IoIPAddress_new(IoObject_state(self));
	IPAddress *iaddr = IoIPAddress_rawIPAddress(ioaddr);
	IPAddress_setIp_(iaddr, "0.0.0.0");
	IPAddress_setPort_(iaddr, IoNumber_asLong(port));
	IoSecureSocket *ssock = IoSecureSocket_newWithSSL_IP_(IoObject_state(self), ssl, ioaddr);
	return ssock;
}
Ejemplo n.º 17
0
void IoVector_glInit(IoObject *context)
{
	IoState *state = IoObject_state(context);
	IoObject *self = IoState_protoWithName_(state, "Sequence");

	{
		IoMethodTable methodTable[] = {
		{"glNormal", IoSeq_glNormal},
		{"glTranslate", IoSeq_glTranslate},
		{"glTranslatei", IoSeq_glTranslatei},
		{"glRotate", IoSeq_glRotate},
		{"glScale", IoSeq_glScale},
		{"glUnproject", IoSeq_glUnproject},
		{"glProject", IoSeq_glProject},

		{"glVertex", IoSeq_glVertex},
		{"glColor", IoSeq_glColor},
		{"glClearColor", IoSeq_glClearColor},
		{"drawQuadTo", IoSeq_drawQuadTo},
		{"drawLineLoop", IoSeq_drawLineLoop},
		{"drawLineLoopi", IoSeq_drawLineLoopi},
		{"drawQuad", IoSeq_drawQuad},

		{"red", IoSeq_x},
		{"green", IoSeq_y},
		{"blue", IoSeq_z},
		{"alpha", IoSeq_w},

		{"setRed", IoSeq_setX},
		{"setGreen", IoSeq_setY},
		{"setBlue", IoSeq_setZ},
		{"setAlpha", IoSeq_setW},

		{"drawAsLine", IoSeq_drawAsLine},
		{"drawFilled", IoSeq_drawFilled},

		/*
		{"drawLineTo", IoSeq_drawLineTo},
		{"drawLineLoopTo", IoSeq_drawLineLoopTo},
		*/
		{NULL, NULL},
		};
		IoObject_addMethodTable_(self, methodTable);
	}
}
Ejemplo n.º 18
0
void Levels_attachToTopAndPush(Levels *self, IoMessage *msg, int precedence)
{
	Level *level = NULL;
	{
		Level *top = List_top(self->stack);
		Level_attachAndReplace(top, msg);
	}

	{
		// TODO: Check for overflow of the pool.
		if (self->currentLevel >= IO_OP_MAX_LEVEL)
		{
			IoState_error_(IoObject_state(msg), NULL, "compile error: Overflowed operator stack. Only %d levels of operators currently supported.", IO_OP_MAX_LEVEL-1);
		}

		level = &self->pool[self->currentLevel++];
		Level_setAwaitingFirstArg(level, msg, precedence);
		List_append_(self->stack, level);
	}
}
Ejemplo n.º 19
0
IoObject *IoDrawStuff_tryCallback(IoDrawStuff *self, IoMessage *m)
{
    IoState *state = IoObject_state(proto);
    IoObject *tryCoro = DATA(self)->coroutine;
    IoObject *t = DATA(self)->eventTarget;
    IoObject *result = state->ioNil;
    //printf("IoDrawStuff_tryCallback(self, %p)\n", (void*)m);
    //printf("IoDrawStuff_tryCallback target: %p)\n", (void*)t);

    if(t)
    {
        IoMessage_locals_performOn_(m, t, t);
        if (IoCoroutine_rawException(tryCoro) != state->ioNil)
            IoState_exception_(state, tryCoro);
        
        IoCoroutine_clearStack(tryCoro);
        return IoCoroutine_rawResult(tryCoro);
    }
    return result;
}
Ejemplo n.º 20
0
IoSecureSocket *IoSecureClient_connectionToServer(IoSecureClient *self, IoObject *locals, IoMessage *msg)
{
	SSL_CTX *ctx = OCTX(self);
	char *serverIP = CSTRING(IoMessage_locals_seqArgAt_(msg, locals, 0));
	char *port = CSTRING(IoMessage_locals_seqArgAt_(msg, locals, 1));
	IoSecureSocket *sock = IoSecureSocket_newWithCTX_(IoObject_state(self), ctx);
	if(sock == IONIL(self))
	{
		ERR_print_errors_fp(stderr);
		IoState_error_(IOSTATE, msg, "Error creating SecureSocket");
		return sock;
	}
	if(!IoSecureSocket_createBIO(sock, serverIP, port))
	{
		ERR_print_errors_fp(stderr);
		IoState_error_(IOSTATE, msg, "Error creating BIO for SecureSocket");
		return IONIL(self);
	}
	return sock;
}
Ejemplo n.º 21
0
Archivo: IoBox_gl.c Proyecto: anthem/io
void IoBox_glInit(IoObject *context)
{
	IoState *state = IoObject_state(context);

	IoObject *self = IoState_protoWithInitFunction_(state, IoBox_proto);

	{
		IoMethodTable methodTable[] = {
		{"drawAsRect", IoBox_drawAsRect},
		{"drawAsRectOutline", IoBox_drawAsRectOutline},
		{"scissor", IoBox_scissor},
		//{"scissorToUnion", IoBox_scissorToUnion},
		//{"getScissor", IoBox_getScissor},
		{"glProject", IoBox_glProject},
		{"glUnproject", IoBox_glUnproject},
		{NULL, NULL},
		};

		IoObject_addMethodTable_(self, methodTable);
	}
}
Ejemplo n.º 22
0
IoSymbol *Levels_nameForAssignOperator(Levels *self, IoState *state, IoSymbol *operator, IoSymbol *slotName, IoMessage *msg)
{
	IoObject *value = IoMap_rawAt(self->assignOperatorTable, operator);
	char *operatorString = CSTRING(operator);

	if (value != NULL && ISSYMBOL(value))
	{
		if (strcmp(operatorString, ":=") == 0 && isupper(CSTRING(slotName)[0]))
		{
			return state->setSlotWithTypeSymbol;
		}
		else
		{
			return value;
		}
	}
	else
	{
		IoState_error_(IoObject_state(msg), msg, "compile error: Value for '%s' in Message OperatorTable assignOperators is not a symbol. Values in the OperatorTable assignOperators are symbols which are the name of the operator.", operatorString);
		return NULL; // To keep the compiler happy.
	}
}
Ejemplo n.º 23
0
IoSecureSocket *IoSecureServer_dtlsWrap(IoSecureServer *self, IoObject *locals, IoMessage *msg)
{
	SSL_CTX *ctx = OCTX(self);
	IoSocket *sock = IoObject_getSlot_(self, IOSYMBOL("socket"));
	IoIPAddress *ioip = IoMessage_locals_addressArgAt_(msg, locals, 0);
	IPAddress *ip = IoIPAddress_rawIPAddress(ioip);
	struct sockaddr *addr = IPAddress_sockaddr(ip);
	IoNumber *port = IoObject_getSlot_(sock, IOSYMBOL("port"));
	int fd = IoSocket_rawDescriptor(sock);
	SSL *ssl = SSL_new(ctx);
	BIO *rbio = BIO_new(BIO_s_mem());
	BIO_set_mem_eof_return(rbio, -1);
	BIO *wbio = BIO_new_dgram(fd, BIO_NOCLOSE);
	BIO_dgram_set_peer(wbio, addr);
	SSL_set_bio(ssl, rbio, wbio);
	SSL_set_accept_state(ssl);
	set_nonblocking(wbio);
	SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE |
		SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
	IoSecureSocket *ssock = IoSecureSocket_newWithSSL_IP_(IoObject_state(self), ssl, ioip);
	return ssock;
}
Ejemplo n.º 24
0
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);
	}
}