primitiveEqual(void)
{
	// FloatArrayPlugin>>#primitiveEqual
    sqInt arg;
    float *argPtr;
    sqInt i;
    sqInt length;
    sqInt rcvr;
    float *rcvrPtr;

	arg = stackObjectValue(0);
	rcvr = stackObjectValue(1);
	if (failed()) {
		return null;
	}
	success(isWords(arg));
	success(isWords(rcvr));
	if (failed()) {
		return null;
	}
	pop(2);
	length = stSizeOf(arg);
	if (!(length == (stSizeOf(rcvr)))) {
		return pushBool(0);
	}
	rcvrPtr = ((float *) (firstIndexableField(rcvr)));
	argPtr = ((float *) (firstIndexableField(arg)));
	for (i = 0; i <= (length - 1); i += 1) {
		if (!((rcvrPtr[i]) == (argPtr[i]))) {
			return pushBool(0);
		}
	}
	return pushBool(1);
}
示例#2
0
primitiveEqual(void)
{
    sqInt arg;
    float *argPtr;
    sqInt i;
    sqInt length;
    sqInt rcvr;
    float *rcvrPtr;

	arg = stackValue(0);
	rcvr = stackValue(1);
	if (!((isWords(arg))
		 && (isWords(rcvr)))) {
		return primitiveFail();
	}
	pop(2);
	if (!(((length = stSizeOf(arg))) == (stSizeOf(rcvr)))) {
		return pushBool(0);
	}
	rcvrPtr = ((float *) (firstIndexableField(rcvr)));
	argPtr = ((float *) (firstIndexableField(arg)));
	for (i = 0; i < length; i += 1) {
		if (!((rcvrPtr[i]) == (argPtr[i]))) {
			return pushBool(0);
		}
	}
	return pushBool(1);
}
primitiveFileAtEnd(void)
{
	// FilePlugin>>#primitiveFileAtEnd
    sqInt atEnd;
    SQFile *file;
    sqInt objectPointer;

	/* begin fileValueOf: */
	objectPointer = stackValue(0);
	if (!((isBytes(objectPointer))
		 && ((byteSizeOf(objectPointer)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(objectPointer);
l1:	/* end fileValueOf: */;
	if (!(failed())) {
		atEnd = sqFileAtEnd(file);
	}
	if (!(failed())) {
		pop(2);
		pushBool(atEnd);
	}
}
示例#4
0
primitiveIsPureTranslation(void)
{
    float *matrix;
    sqInt matrix1;

	/* begin loadArgumentMatrix: */
	matrix1 = stackObjectValue(0);
	if (failed()) {
		matrix = null;
		goto l1;
	}
	if (!((isWords(matrix1))
		 && ((slotSizeOf(matrix1)) == 6))) {
		primitiveFail();
		matrix = null;
		goto l1;
	}
	matrix = ((float *) (firstIndexableField(matrix1)));
	l1:	/* end loadArgumentMatrix: */;
	if (failed()) {
		return null;
	}
	pop(1);
	pushBool(((((matrix[0]) == (((float) 1.0))) && ((matrix[1]) == (((float) 0.0)))) && ((matrix[3]) == (((float) 0.0)))) && ((matrix[4]) == (((float) 1.0))));
	return 0;
}
示例#5
0
static char cmdGt( tPSStackItem **topStack, void* /*dummy*/, const char* /*path*/ )
{
	char error = FALSE;
	double bb = popDouble( topStack, &error );
	double aa = popDouble( topStack, &error );

	if( error )
		return FALSE;
	pushBool( topStack, aa > bb );
	return TRUE;
}
示例#6
0
/*
  primitivePluginBrowserReady
  Return true if a connection to the browser
  has been established. Only necessary if some
  sort of asynchronous communications are used.
*/
int display_primitivePluginBrowserReady()
{
    if (inBrowser)
    {
        pop(1);
        pushBool(1);
    }
    else
        primitiveFail();
    return 1;
}
示例#7
0
/*
  primitivePluginRequestState: id
  Return true if the operation was successfully completed.
  Return false if the operation was aborted.
  Return nil if the operation is still in progress.
*/
sqInt display_primitivePluginRequestState()
{
    sqStreamRequest *req;
    int id;

    id= stackIntegerValue(0);
    if (id < 0 || id >= MAX_REQUESTS) return primitiveFail();
    req= requests[id];
    if (!req) return primitiveFail();
    pop(2);
    if (req->state == -1) push(nilObject());
    else pushBool(req->state);
    return 1;
}
primitiveIsOverlayRenderer(void)
{
	// B3DAcceleratorPlugin>>#primitiveIsOverlayRenderer
    sqInt handle;
    sqInt result;

	if (!((methodArgumentCount()) == 1)) {
		return primitiveFail();
	}
	handle = stackIntegerValue(0);
	if (failed()) {
		return null;
	}
	result = b3dxIsOverlayRenderer(handle);
	pop(2);
	return pushBool(result);
}
primitiveEnableDrawRangeChecks(void)
{
	// B3DAcceleratorPlugin>>#primitiveEnableDrawRangeChecks
    sqInt enabled;

	if ((methodArgumentCount()) == 0) {
		pop(1);
		return pushBool(doRangeChecks);
	}
	if ((methodArgumentCount()) == 1) {
		enabled = booleanValueOf(stackValue(0));
		if (failed()) {
			return null;
		}
		doRangeChecks = enabled;
		return pop(1);
	}
}
primitiveHasFileAccess(void)
{
	// FilePlugin>>#primitiveHasFileAccess
    sqInt hasAccess;


	/* If the security plugin can be loaded, use it to check .
	   If not, assume it's ok */

	if (sHFAfn != 0) {

		/* If the security plugin can be loaded, use it to check .
		   If not, assume it's ok */

		hasAccess =  ((sqInt (*)(void))sHFAfn)();
	}
	else {
hasAccess = 1;
	}
	pop(1);
	pushBool(hasAccess);
}
primitiveTextureByteSex(void)
{
	// B3DAcceleratorPlugin>>#primitiveTextureByteSex
    sqInt handle;
    sqInt renderer;
    sqInt result;

	if (!((methodArgumentCount()) == 2)) {
		return primitiveFail();
	}
	handle = stackIntegerValue(0);
	renderer = stackIntegerValue(1);
	if (failed()) {
		return null;
	}
	result = b3dxTextureByteSex(renderer, handle);
	if (result < 0) {
return primitiveFail();
	}
	pop(3);
	return pushBool(result);
}
示例#12
0
primitiveCanWriteImage(void)
{
    pop(1);
    pushBool(ioCanWriteImage());
    return 0;
}
primitiveCanWriteImage(void)
{
	// SecurityPlugin>>#primitiveCanWriteImage
	pop(1);
	pushBool(ioCanWriteImage());
}
示例#14
0
void Operators::doOperator(Context *context, OperatorType oper) {
	Token token1, token2, token3;
	stutskFloat f1, f2;
	stutskInteger i1, i2;
	string s1, s2;

	switch (oper) {
	case OP_ASSIG:
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Variable
		token2 = stack_back_safe();
		stutskStack.pop_back(); // Value
		setVariable(token1, token2); 
		break;
	case OP_ASSIG_REF:
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Variable
		token2 = stack_back_safe();
		stutskStack.pop_back(); // Value
		setVariable(token1, token2, true); 
		break;
	case OP_FUNC:
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Name
		token2 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock
		recurseVariables(token2);
		if (token2.tokenType != T_CODEBLOCK) {
			throw StutskException(ET_ERROR, "Token is not a codeblock");
		}
		else {
			OperatorType dummy;
			string functionName = *giveString(token1);
			if (readOperator(functionName, dummy))
				throw StutskException(ET_ERROR, "Cannot override an operator");
			if (functionName.substr(0,10) == "__builtin_")
				throw StutskException(ET_ERROR, "Cannot override an internal function");
			userFunctions[functionName] = *token2.asTokenList;
		}

		break;
	case OP_UNSET:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		if (token1.tokenType == T_VARIABLE) {
			struct Token::_un_TokenData::_un_VariableData *var = & token1.data.asVariable;
			TokenMap::iterator iter = var->context->variables.find(var->name);
			if (iter != var->context->variables.end())
				var->context->variables.erase(iter);
		}
		else {
			UserFunctionsMap::iterator iter = userFunctions.find(*giveString(token1));
			if (iter != userFunctions.end())
				userFunctions.erase(iter);
		}
		break;
	case OP_DEREF:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		if (token1.tokenType != T_VARIABLE) {
			throw StutskException(ET_ERROR, "Token is not a variable");
		}
		else {
			recurseVariables(token1, true);
			stutskStack.push_back(copy_token(token1));
		}
		break;
	case OP_PLUSPLUS:
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Name
		if (token1.tokenType == T_VARIABLE) {
			switch (giveGCD(token1, f1, i1, s1)) {
			case NT_INVALID:
			case NT_STRING:
				throw StutskException(ET_ERROR,
					"Variable is not a numeric type");
			case NT_INTEGER:
				token2.tokenType = T_INTEGER;
				token2.data.asInteger = i1 + 1;
				setVariable(token1, token2);
				break;
			case NT_FLOAT:
				token2.tokenType = T_FLOAT;
				token2.data.asFloat = f1 + 1.;
				setVariable(token1, token2); 
				break;
			}
		}
		else {
			switch (giveGCD(token1, f1, i1, s1)) {
			case NT_INVALID:
			case NT_STRING:
				throw StutskException(ET_ERROR, "Token is not a numeric type");
			case NT_INTEGER:
				pushInteger(++i1);
				break;
			case NT_FLOAT:
				pushFloat(++f1);
				break;
			}
		}
		break;
	case OP_MINMIN:
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Name
		if (token1.tokenType == T_VARIABLE) {
			switch (giveGCD(token1, f1, i1, s1)) {
			case NT_INVALID:
			case NT_STRING:
				throw StutskException(ET_ERROR,
					"Variable is not a numeric type");
			case NT_INTEGER:
				token2.tokenType = T_INTEGER;
				token2.data.asInteger = i1 - 1;
				setVariable(token1, token2); 
				break;
			case NT_FLOAT:
				token2.tokenType = T_FLOAT;
				token2.data.asFloat = f1 - 1.;
				setVariable(token1, token2); 
				break;
			}
		}
		else {
			switch (giveGCD(token1, f1, i1, s1)) {
			case NT_INVALID:
			case NT_STRING:
				throw StutskException(ET_ERROR, "Token is not a numeric type");
			case NT_INTEGER:
				pushInteger(--i1);
				break;
			case NT_FLOAT:
				pushFloat(--f1);
				break;
			}
		}
		break;
	case OP_PLUS:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		token2 = stack_back_safe();
		stutskStack.pop_back();

		switch (giveGCD(token1, f1, i1, s1)) {
		case NT_STRING:
		case NT_INVALID:
			throw StutskException(ET_ERROR, "Token is not a numeric type");
		case NT_INTEGER:
			switch (giveGCD(token2, f2, i2, s1)) {
			case NT_STRING:
			case NT_INVALID:
				throw StutskException(ET_ERROR, "Token is not a numeric type");
			case NT_INTEGER:
				i1 += i2;
				pushInteger(i1);
				break;
			case NT_FLOAT:
				f2 += i1;
				pushFloat(f2);
				break;
			}
			break;
		case NT_FLOAT:
			f1 += giveFloat(token2);
			pushFloat(f1);
			break;
		}

		break;
	case OP_MINUS:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		token2 = stack_back_safe();
		stutskStack.pop_back();

		switch (giveGCD(token1, f1, i1, s1)) {
		case NT_STRING:
		case NT_INVALID:
			throw StutskException(ET_ERROR, "Token is not a numeric type");
		case NT_INTEGER:
			switch (giveGCD(token2, f2, i2, s1)) {
			case NT_STRING:
			case NT_INVALID:
				throw StutskException(ET_ERROR, "Token is not a numeric type");
			case NT_INTEGER:
				i2 -= i1;
				pushInteger(i2);
				break;
			case NT_FLOAT:
				f2 -= i1;
				pushFloat(f2);
				break;
			}
			break;
		case NT_FLOAT:
			f2 = giveFloat(token2) - f1;
			pushFloat(f2);
			break;
		}

		break;
	case OP_MULTIP:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		token2 = stack_back_safe();
		stutskStack.pop_back();

		switch (giveGCD(token1, f1, i1, s1)) {
		case NT_STRING:
		case NT_INVALID:
			throw StutskException(ET_ERROR, "Token is not a numeric type");
		case NT_INTEGER:
			switch (giveGCD(token2, f2, i2, s1)) {
			case NT_STRING:
			case NT_INVALID:
				throw StutskException(ET_ERROR, "Token is not a numeric type");
			case NT_INTEGER:
				i1 *= i2;
				pushInteger(i1);
				break;
			case NT_FLOAT:
				f2 *= i1;
				pushFloat(f2);
				break;
			}
			break;
		case NT_FLOAT:
			f1 *= giveFloat(token2);
			pushFloat(f1);
			break;
		}
		break;
	case OP_DIV:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		token2 = stack_back_safe();
		stutskStack.pop_back();

		switch (giveGCD(token1, f1, i1, s1)) {
		case NT_STRING:
		case NT_INVALID:
			throw StutskException(ET_ERROR, "Token is not a numeric type");
		case NT_INTEGER:
			if (i1 == 0)
				throw StutskException(ET_ERROR, "Division by zero");
			switch (giveGCD(token2, f2, i2, s1)) {
			case NT_STRING:
			case NT_INVALID:
				throw StutskException(ET_ERROR, "Token is not a numeric type");
			case NT_INTEGER:
				f1 = (stutskFloat)i2 / (stutskFloat)i1;
				pushFloat(f1);
				break;
			case NT_FLOAT:
				f2 /= (stutskFloat)i1;
				pushFloat(f2);
				break;
			}
			break;
		case NT_FLOAT:
			if (f1 == 0.)
				throw StutskException(ET_ERROR, "Division by zero");
			f2 = giveFloat(token2) / f1;
			pushFloat(f2);
			break;
		}
		break;
	case OP_DIVINT:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		token2 = stack_back_safe();
		stutskStack.pop_back();

		switch (giveGCD(token1, f1, i1, s1)) {
		case NT_STRING:
		case NT_INVALID:
			throw StutskException(ET_ERROR, "Token is not a numeric type");
		case NT_INTEGER:
			switch (giveGCD(token2, f2, i2, s1)) {
			case NT_STRING:
			case NT_INVALID:
				throw StutskException(ET_ERROR, "Token is not a numeric type");
			case NT_INTEGER:
				i1 = (stutskInteger)i2 / i1;
				pushInteger(i1);
				break;
			case NT_FLOAT:
				i2 = (stutskInteger)f2 / i1;
				pushInteger(i2);
				break;
			}
			break;
		case NT_FLOAT:
			i2 = giveInteger(token2) / (stutskInteger)f1;
			pushInteger(i2);
			break;
		}
		break;
	case OP_MOD:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		token2 = stack_back_safe();
		stutskStack.pop_back();

		switch (giveGCD(token1, f1, i1, s1)) {
		case NT_STRING:
		case NT_INVALID:
			throw StutskException(ET_ERROR, "Token is not a numeric type");
		case NT_INTEGER:
			switch (giveGCD(token2, f2, i2, s1)) {
			case NT_STRING:
			case NT_INVALID:
				throw StutskException(ET_ERROR, "Token is not a numeric type");
			case NT_INTEGER:
				i1 = (stutskInteger)i2 % i1;
				pushInteger(i1);
				break;
			case NT_FLOAT:
				i2 = (stutskInteger)f2 % i1;
				pushInteger(i2);
				break;
			}
			break;
		case NT_FLOAT:
			i2 = giveInteger(token2) % (stutskInteger)f1;
			pushInteger(i2);
			break;
		}
		break;
	case OP_LESSTHAN:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		token2 = stack_back_safe();
		stutskStack.pop_back();

		pushBool(tokenNumericCompare(token1, token2) == CN_SMALLER);
		break;
	case OP_MORETHAN:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		token2 = stack_back_safe();
		stutskStack.pop_back();

		pushBool(tokenNumericCompare(token1, token2) == CN_LARGER);
		break;
	case OP_LESSTHAN_EQ:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		token2 = stack_back_safe();
		stutskStack.pop_back();

		pushBool(tokenNumericCompare(token1, token2) != CN_LARGER);
		break;
	case OP_MORETHAN_EQ:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		token2 = stack_back_safe();
		stutskStack.pop_back();

		pushBool(tokenNumericCompare(token1, token2) != CN_SMALLER);
		break;
	case OP_EQ:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		token2 = stack_back_safe();
		stutskStack.pop_back();

		pushBool(tokenEqual(token1, token2));	
		break;
	case OP_SAME:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		token2 = stack_back_safe();
		stutskStack.pop_back();
		pushBool(tokenSame(token1, token2));
		break;
	case OP_NOTEQ:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		token2 = stack_back_safe();
		stutskStack.pop_back();

		pushBool(!tokenEqual(token1, token2));	
		break;
	case OP_GLOBAL:
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Variable
		if (token1.tokenType != T_VARIABLE) {
			throw StutskException(ET_ERROR, "Token is not a variable");
		}
		else {
			context->variableScopeMap[token1.data.asVariable.name] = VS_GLOBAL;
		}
		break;
	case OP_AUTO:
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Variable
		if (token1.tokenType != T_VARIABLE) {
			throw StutskException(ET_ERROR, "Token is not a variable");
		}
		else {
			context->variableScopeMap[token1.data.asVariable.name] = VS_AUTO;
		}
		break;
	case OP_STATIC:
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Variable
		if (token1.tokenType != T_VARIABLE) {
			throw StutskException(ET_ERROR, "Token is not a variable");
		}
		else {
			context->variableScopeMap[token1.data.asVariable.name] = VS_STATIC;
		}
		break;
	case OP_FOREVER:
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock
		recurseVariables(token1);
		if (token1.tokenType != T_CODEBLOCK) {
			throw StutskException(ET_ERROR, "Token is not a codeblock");
		}
		else {
			while (true) {
				context->run(*token1.asTokenList, "forever");
				if (exitVar == OP_CONTINUE)
					exitVar = OP_INVALID;
				if (exitVar != OP_INVALID)
					break;
			}
			if (exitVar == OP_BREAK)
				exitVar = OP_INVALID;
		}
		break;
	case OP_FOREACH:
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock
		token2 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock

		recurseVariables(token1);
		if (token1.tokenType != T_CODEBLOCK)
			throw StutskException(ET_ERROR, "Token is not a codeblock");

		recurseVariables(token2);
		if (token2.tokenType == T_ARRAY) {
			for (TokenList::const_iterator it = token2.asTokenList->begin();
				it != token2.asTokenList->end(); ++it) {
					stutskStack.push_back(*it);
					stringstream ss;
					ss << "foreach [" << 
						std::distance(token2.asTokenList->cbegin(), it) << "]";
					context->run(*token1.asTokenList, ss.str());
					if (exitVar == OP_CONTINUE)
						exitVar = OP_INVALID;
					if (exitVar != OP_INVALID)
						break;
			}
		}
		else
			if (token2.tokenType == T_DICTIONARY) {
				for (TokenMap::const_iterator it = token2.asDictionary->begin();
					it != token2.asDictionary->end(); ++it) {
						stutskStack.push_back(it->second);
						StringPtr f = pushString();
						*f =  it->first;

						stringstream ss;
						ss << "foreach [" << it->first << "]";
						context->run(*token1.asTokenList, ss.str());
						if (exitVar == OP_CONTINUE)
							exitVar = OP_INVALID;
						if (exitVar != OP_INVALID)
							break;
				}
			}
			else 
			{
				StringPtr s1_ptr = giveString(token2);
				for (int i = 0; i < (signed)s1_ptr->length(); i++) {
					*pushString() = (*s1_ptr)[i];
					stringstream ss;
					ss << "foreach [" << i << "]";
					context->run(*token1.asTokenList, ss.str());
					if (exitVar == OP_CONTINUE)
						exitVar = OP_INVALID;
					if (exitVar != OP_INVALID)
						break;
				}
			}

			if (exitVar == OP_BREAK)
				exitVar = OP_INVALID;
			break;

	case OP_REPEAT:
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock

		token2 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock

		i1 = giveInteger(token2);
		recurseVariables(token1);

		if (token1.tokenType != T_CODEBLOCK) {
			throw StutskException(ET_ERROR, "Token is not a codeblock");
		}
		else {
			while (i1 > 0) {
				stringstream ss;
				ss << "repeat [" << i1 << "]";
				context->run(*token1.asTokenList, ss.str());
				if (exitVar == OP_CONTINUE)
					exitVar = OP_INVALID;
				if (exitVar != OP_INVALID)
					break;
				i1--;
			}
			if (exitVar == OP_BREAK)
				exitVar = OP_INVALID;
		}
		break;
	case OP_TRY:
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock
		token2 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock
		recurseVariables(token1);
		recurseVariables(token2);
		if ((token2.tokenType != T_CODEBLOCK) ||
			(token2.tokenType != T_CODEBLOCK)) {
				throw StutskException(ET_ERROR, "Token is not a codeblock");
		}
		else {
			try {
				context->run(*token2.asTokenList, "try");
			}
			catch (StutskException &e) {
				*pushString() = e.getMessage();
				pushInteger(e.getLineNumber());
				*pushString() = e.getFileName();

				context->run(*token1.asTokenList, "try");
			}
			catch (std::exception &e) {
				*pushString() = e.what();
				pushInteger(errorToken.lineNum);
				*pushString() = ParseContext::get_by_id(errorToken.context_id).FileName;

				context->run(*token1.asTokenList, "try");
			}
		}
		break;
	case OP_POWER:
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock
		token2 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock
		f1 = pow(giveFloat(token2), giveFloat(token1));
		pushFloat(f1);

		break;
	case OP_THROW:
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Error name
		throw StutskException(ET_CUSTOM, *giveString(token1));
		break;
	case OP_NOT:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		pushBool(!giveBool(token1));
		break;
	case OP_AND:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		token2 = stack_back_safe();
		stutskStack.pop_back();
		pushBool(giveBool(token1) && giveBool(token2));
		break;
	case OP_OR:
		token1 = stack_back_safe();
		stutskStack.pop_back();
		token2 = stack_back_safe();
		stutskStack.pop_back();
		pushBool(giveBool(token1) || giveBool(token2));
		break;
	case OP_IF:
		token2 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock

		recurseVariables(token2);

		if (token2.tokenType != T_CODEBLOCK) {
			throw StutskException(ET_ERROR, "Token is not a codeblock");
		}
		else {
			if (giveBool(token1)) {
				context->run(*token2.asTokenList, "if");
			}
		}
		break;
	case OP_IFELSE:
		token2 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock
		token3 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock

		recurseVariables(token2);
		recurseVariables(token3);

		if ((token2.tokenType != T_CODEBLOCK) ||
			(token3.tokenType != T_CODEBLOCK)) {
				throw StutskException(ET_ERROR, "Token is not a codeblock");
		}
		else {
			if (giveBool(token1)) {
				context->run(*token3.asTokenList, "ifelse");
			}
			else {
				context->run(*token2.asTokenList, "ifelse");
			}
		}
		break;
	case OP_TERNARY:
		token2 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock
		token3 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock

		stutskStack.push_back((giveBool(token1) ? token3 : token2));
		break;
	case OP_CONCAT:
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock
		token2 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock

		// Be careful NOT to recurse variable here because we wouldn't want
		// to overwrite the saved value.

		if (token2.tokenType == T_STRING) // Performance optimization
		{
			token2.asString->append(*giveString(token1));
			stutskStack.push_back(token2);
		}
		else
			// Should be fast enough ...	
			*pushString() = *giveString(token2) + 
			*giveString(token1);

		break;
	case OP_SWITCH:
		token2 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock

		recurseVariables(token2);

		if (token2.tokenType != T_ARRAY)
			throw StutskException(ET_ERROR, "Token is not an array");
		else
		{	
			for (TokenList::iterator it = token2.asTokenList->begin();
				it != token2.asTokenList->end(); ++it) 
			{
				token3 = *it;
				recurseVariables(token3);
				if (token3.tokenType != T_ARRAY)
					throw StutskException(ET_ERROR, "Token is not an array");
				else
				{
					if (token3.asTokenList->size() != 2)
						throw StutskException(ET_ERROR, "Array of wrong length");
					if ((*token3.asTokenList)[1].tokenType != T_CODEBLOCK)
						throw StutskException(ET_ERROR, "Token is not a codeblock");
					if (tokenEqual(token1, (*token3.asTokenList)[0]))
					{
						context->run(*(*token3.asTokenList)[1].asTokenList, "switch");
						break;
					}
				}
			}
		}
		break;
	case OP_BREAK:
	case OP_CONTINUE:
	case OP_HALT:
	case OP_EXIT:
		exitVar = oper;
		break;
	case OP_ARRAY:
		token1 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock
		token2 = stack_back_safe();
		stutskStack.pop_back(); // Codeblock

		recurseVariables(token1);

		if (token2.tokenType == T_VARIABLE) {
			if (token1.tokenType == T_ARRAY) {
				for (TokenList::iterator it = token1.asTokenList->begin();
					it != token1.asTokenList->end(); ++it)
					token2.index.push_back(giveInteger(*it));
			}
			else
				token2.index.push_back(giveInteger(token1));
			stutskStack.push_back(token2);
		}
		else if (token2.tokenType == T_ARRAY) {
			if (token1.tokenType == T_ARRAY) {
				for (TokenList::iterator it = token1.asTokenList->begin();
					it != token1.asTokenList->end(); ++it) {
						i1 = giveInteger(*it);
						if (i1 < 0)
							throw StutskException(ET_ERROR, "Array index underflow");
						if ((signed)token2.asTokenList->size() >= i1 + 1) {
							token2 = (*token2.asTokenList)[i1];
						}
						else
							throw StutskException(ET_ERROR, "Array index overflow");
				}
				stutskStack.push_back(token2);
			}
			else {
				i1 = giveInteger(token1);
				if (i1 < 0)
					throw StutskException(ET_ERROR, "Array index underflow");
				if ((signed)token2.asTokenList->size() >= i1 + 1) {
					stutskStack.push_back((*token2.asTokenList)[i1]);
				}
				else
					throw StutskException(ET_ERROR, "Array index overflow");
			}
		}
		else {
			i1 = giveInteger(token1);
			StringPtr s1_ptr = giveString(token2);
			if (i1 < 0)
				throw StutskException(ET_ERROR, "String index underflow");
			if ((signed)s1_ptr->length() >= i1 + 1) {
				*pushString() = (*s1_ptr)[i1];
			}
			else
				throw StutskException(ET_ERROR, "String index overflow");
		}
	}
}