+ Right = SpiderScript_CastValueTo(Left->Type, Right);
+ if(Right == ERRPTR)
+ return ERRPTR;
+ }
+ // If statically typed, this should never happen, but catch it anyway
+ else {
+ AST_RuntimeError(Node, "Implicit cast not allowed (from %i to %i)", Right->Type, Left->Type);
+ return ERRPTR;
+ }
+ }
+
+ // NULL Check
+ if( Left == NULL || Right == NULL ) {
+ if(Right && Right != preCastValue) free(Right);
+ return NULL;
+ }
+
+ // Do operation
+ switch(Left->Type)
+ {
+ // String Concatenation
+ case SS_DATATYPE_STRING:
+ switch(Operation)
+ {
+ case NODETYPE_ADD: // Concatenate
+ ret = SpiderScript_StringConcat(Left, Right);
+ break;
+ // TODO: Support python style 'i = %i' % i ?
+ // Might do it via a function call
+ // Implement it via % with an array, but getting past the cast will be fun
+// case NODETYPE_MODULUS:
+// break;
+ // TODO: Support string repititions
+// case NODETYPE_MULTIPLY:
+// break;
+
+ default:
+ AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Operation);
+ ret = ERRPTR;
+ break;
+ }
+ break;
+ // Integer Operations
+ case SS_DATATYPE_INTEGER:
+ if( Left->ReferenceCount == 1 )
+ SpiderScript_ReferenceValue(ret = Left);
+ else
+ ret = SpiderScript_CreateInteger(0);
+ switch(Operation)
+ {
+ case NODETYPE_ADD: ret->Integer = Left->Integer + Right->Integer; break;
+ case NODETYPE_SUBTRACT: ret->Integer = Left->Integer - Right->Integer; break;
+ case NODETYPE_MULTIPLY: ret->Integer = Left->Integer * Right->Integer; break;
+ case NODETYPE_DIVIDE: ret->Integer = Left->Integer / Right->Integer; break;
+ case NODETYPE_MODULO: ret->Integer = Left->Integer % Right->Integer; break;
+ case NODETYPE_BWAND: ret->Integer = Left->Integer & Right->Integer; break;
+ case NODETYPE_BWOR: ret->Integer = Left->Integer | Right->Integer; break;
+ case NODETYPE_BWXOR: ret->Integer = Left->Integer ^ Right->Integer; break;
+ case NODETYPE_BITSHIFTLEFT: ret->Integer = Left->Integer << Right->Integer; break;
+ case NODETYPE_BITSHIFTRIGHT:ret->Integer = Left->Integer >> Right->Integer; break;
+ case NODETYPE_BITROTATELEFT:
+ ret->Integer = (Left->Integer << Right->Integer) | (Left->Integer >> (64-Right->Integer));
+ break;
+ default:
+ AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Operation);
+ SpiderScript_DereferenceValue(ret);
+ ret = ERRPTR;
+ break;
+ }
+ break;
+
+ // Real Numbers
+ case SS_DATATYPE_REAL:
+ if( Left->ReferenceCount == 1 )
+ SpiderScript_ReferenceValue(ret = Left);
+ else
+ ret = SpiderScript_CreateReal(0);
+ switch(Operation)
+ {
+ case NODETYPE_ADD: ret->Real = Left->Real + Right->Real; break;
+ case NODETYPE_SUBTRACT: ret->Real = Left->Real - Right->Real; break;
+ case NODETYPE_MULTIPLY: ret->Real = Left->Real * Right->Real; break;
+ case NODETYPE_DIVIDE: ret->Real = Left->Real / Right->Real; break;
+ default:
+ AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation);
+ SpiderScript_DereferenceValue(ret);
+ ret = ERRPTR;
+ break;
+ }
+ break;
+
+ default:
+ AST_RuntimeError(Node, "BUG - Invalid operation (%i) on type (%i)", Operation, Left->Type);
+ ret = ERRPTR;
+ break;
+ }
+
+ if(Right && Right != preCastValue) free(Right);
+
+ return ret;
+}
+
+/**
+ * \brief Define a variable
+ * \param Block Current block state
+ * \param Type Type of the variable
+ * \param Name Name of the variable
+ * \return Boolean Failure
+ */
+tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value)
+{
+ tAST_Variable *var, *prev = NULL;
+
+ for( var = Block->FirstVar; var; prev = var, var = var->Next )
+ {
+ if( strcmp(var->Name, Name) == 0 ) {
+ AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
+ return ERRPTR;
+ }
+ }
+
+ var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
+ var->Next = NULL;
+ var->Type = Type;
+ var->Object = Value;
+ if(Value) SpiderScript_ReferenceValue(Value);
+ strcpy(var->Name, Name);
+
+ if(prev) prev->Next = var;
+ else Block->FirstVar = var;
+
+ //printf("Defined variable %s (%i)\n", Name, Type);
+
+ return var;
+}
+
+tAST_Variable *Variable_Lookup(tAST_BlockState *Block, tAST_Node *VarNode, int CreateType)
+{
+ tAST_Variable *var = NULL;
+
+ // Speed hack
+ if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
+ var = VarNode->ValueCache;
+ #if TRACE_VAR_LOOKUPS
+ AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
+ VarNode->Variable.Name, var,
+ VarNode->BlockState, VarNode->BlockIdent
+ );
+ #endif
+ }
+ else
+ {
+ tAST_BlockState *bs;
+ for( bs = Block; bs; bs = bs->Parent )
+ {
+ for( var = bs->FirstVar; var; var = var->Next )