|  | @@ -16,12 +16,12 @@ static void sError(Script* sc, const char* format, ...) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static bool sPrinter(Object* o) {
 | 
	
		
			
				|  |  |      switch(o->type) {
 | 
	
		
			
				|  |  | -        case OT_INT: printf("%d\n", o->data.intValue); return false;
 | 
	
		
			
				|  |  | -        case OT_FLOAT: printf("%.2f\n", o->data.floatValue); return false;
 | 
	
		
			
				|  |  | -        case OT_CONST_STRING: printf("%s\n", o->data.stringValue); return false;
 | 
	
		
			
				|  |  | +        case OT_INT: printf("%d\n", o->as.intValue); return false;
 | 
	
		
			
				|  |  | +        case OT_FLOAT: printf("%.2f\n", o->as.floatValue); return false;
 | 
	
		
			
				|  |  | +        case OT_CONST_STRING: printf("%s\n", o->as.stringValue); return false;
 | 
	
		
			
				|  |  |          case OT_NULL: printf("null\n"); return false;
 | 
	
		
			
				|  |  |          case OT_BOOL:
 | 
	
		
			
				|  |  | -            printf(o->data.intValue ? "true\n" : "false\n");
 | 
	
		
			
				|  |  | +            printf(o->as.intValue ? "true\n" : "false\n");
 | 
	
		
			
				|  |  |              return false;
 | 
	
		
			
				|  |  |          case OT_ARRAY: printf("array\n"); return false;
 | 
	
		
			
				|  |  |          default: return true;
 | 
	
	
		
			
				|  | @@ -94,12 +94,12 @@ static Object* sPeek(Script* sc) {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static bool sPushInt(Script* sc, int value) {
 | 
	
		
			
				|  |  | -    Object o = {.type = OT_INT, .data.intValue = value};
 | 
	
		
			
				|  |  | +    Object o = {.type = OT_INT, .as.intValue = value};
 | 
	
		
			
				|  |  |      return sPush(sc, &o);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void sPushFloat(Script* sc, float value) {
 | 
	
		
			
				|  |  | -    Object o = {.type = OT_FLOAT, .data.floatValue = value};
 | 
	
		
			
				|  |  | +    Object o = {.type = OT_FLOAT, .as.floatValue = value};
 | 
	
		
			
				|  |  |      sPush(sc, &o);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -109,14 +109,14 @@ static void sPushNull(Script* sc) {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void sPushBool(Script* sc, bool value) {
 | 
	
		
			
				|  |  | -    Object o = {.type = OT_BOOL, .data.intValue = value};
 | 
	
		
			
				|  |  | +    Object o = {.type = OT_BOOL, .as.intValue = value};
 | 
	
		
			
				|  |  |      sPush(sc, &o);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void sPushReference(Script* sc, int pointer, int index) {
 | 
	
		
			
				|  |  |      Object o = {.type = OT_REFERENCE,
 | 
	
		
			
				|  |  | -                .data.reference.pointer = pointer,
 | 
	
		
			
				|  |  | -                .data.reference.index = index};
 | 
	
		
			
				|  |  | +                .as.reference.pointer = pointer,
 | 
	
		
			
				|  |  | +                .as.reference.index = index};
 | 
	
		
			
				|  |  |      sPush(sc, &o);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -137,7 +137,7 @@ static void sPopVars(Script* sc) {
 | 
	
		
			
				|  |  |      int value = 0;
 | 
	
		
			
				|  |  |      Object o;
 | 
	
		
			
				|  |  |      if(sReadInt(sc, &value) && !sPop(sc, &o) && sCheckType(sc, &o, OT_INT)) {
 | 
	
		
			
				|  |  | -        sc->stackVarIndex = o.data.intValue;
 | 
	
		
			
				|  |  | +        sc->stackVarIndex = o.as.intValue;
 | 
	
		
			
				|  |  |          if(sc->stackIndex < value) {
 | 
	
		
			
				|  |  |              sError(sc, "stack underflow on line %d", sc->line);
 | 
	
		
			
				|  |  |          } else {
 | 
	
	
		
			
				|  | @@ -157,13 +157,13 @@ static void sReferenceFromArray(Script* sc) {
 | 
	
		
			
				|  |  |      int value = 0;
 | 
	
		
			
				|  |  |      Object o;
 | 
	
		
			
				|  |  |      if(sReadInt(sc, &value) && !sPop(sc, &o) && sCheckType(sc, &o, OT_INT)) {
 | 
	
		
			
				|  |  | -        sPushReference(sc, value, o.data.intValue);
 | 
	
		
			
				|  |  | +        sPushReference(sc, value, o.as.intValue);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static Object* sDereference(Script* sc, Object* reference) {
 | 
	
		
			
				|  |  | -    int pointer = reference->data.reference.pointer;
 | 
	
		
			
				|  |  | -    int index = reference->data.reference.index;
 | 
	
		
			
				|  |  | +    int pointer = reference->as.reference.pointer;
 | 
	
		
			
				|  |  | +    int index = reference->as.reference.index;
 | 
	
		
			
				|  |  |      if(pointer == -1) {
 | 
	
		
			
				|  |  |          if(index < 0 || index >= sc->stackIndex) {
 | 
	
		
			
				|  |  |              sError(sc, "variable reference index exceeds stack on line %d",
 | 
	
	
		
			
				|  | @@ -214,13 +214,13 @@ static void sSet(Script* sc) {
 | 
	
		
			
				|  |  |  static void sAllocateArray(Script* sc) {
 | 
	
		
			
				|  |  |      Object length;
 | 
	
		
			
				|  |  |      if(!sPop(sc, &length) && sCheckType(sc, &length, OT_INT)) {
 | 
	
		
			
				|  |  | -        if(length.data.intValue < 0) {
 | 
	
		
			
				|  |  | +        if(length.as.intValue < 0) {
 | 
	
		
			
				|  |  |              sError(sc, "negative array length on line %d", sc->line);
 | 
	
		
			
				|  |  |              return;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          Object o = {.type = OT_ARRAY,
 | 
	
		
			
				|  |  | -                    .data.intValue =
 | 
	
		
			
				|  |  | -                        aAllocate(&sc->allocator, length.data.intValue)};
 | 
	
		
			
				|  |  | +                    .as.intValue =
 | 
	
		
			
				|  |  | +                        aAllocate(&sc->allocator, length.as.intValue)};
 | 
	
		
			
				|  |  |          sPush(sc, &o);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -228,7 +228,7 @@ static void sAllocateArray(Script* sc) {
 | 
	
		
			
				|  |  |  static void sArrayLength(Script* sc) {
 | 
	
		
			
				|  |  |      Object* o = sPopAndDereference(sc);
 | 
	
		
			
				|  |  |      if(o != NULL && sCheckType(sc, o, OT_ARRAY)) {
 | 
	
		
			
				|  |  | -        int arrayPointer = o->data.intValue;
 | 
	
		
			
				|  |  | +        int arrayPointer = o->as.intValue;
 | 
	
		
			
				|  |  |          if(arrayPointer < 0 || arrayPointer >= sc->allocator.capacity) {
 | 
	
		
			
				|  |  |              sError(sc, "array pointer is out of range on line %d\n", sc->line);
 | 
	
		
			
				|  |  |              return;
 | 
	
	
		
			
				|  | @@ -241,9 +241,9 @@ static void sPreChange(Script* sc, int change) {
 | 
	
		
			
				|  |  |      Object* o = sPopAndDereference(sc);
 | 
	
		
			
				|  |  |      if(o != NULL) {
 | 
	
		
			
				|  |  |          if(o->type == OT_INT) {
 | 
	
		
			
				|  |  | -            o->data.intValue += change;
 | 
	
		
			
				|  |  | +            o->as.intValue += change;
 | 
	
		
			
				|  |  |          } else if(o->type == OT_FLOAT) {
 | 
	
		
			
				|  |  | -            o->data.floatValue += change;
 | 
	
		
			
				|  |  | +            o->as.floatValue += change;
 | 
	
		
			
				|  |  |          } else {
 | 
	
		
			
				|  |  |              sError(sc, "variable is '%s' not a number on line %d",
 | 
	
		
			
				|  |  |                     oGetName(o->type), sc->line);
 | 
	
	
		
			
				|  | @@ -266,10 +266,10 @@ static void sPostChange(Script* sc, int change) {
 | 
	
		
			
				|  |  |      if(o != NULL) {
 | 
	
		
			
				|  |  |          if(o->type == OT_INT) {
 | 
	
		
			
				|  |  |              sPush(sc, o);
 | 
	
		
			
				|  |  | -            o->data.intValue += change;
 | 
	
		
			
				|  |  | +            o->as.intValue += change;
 | 
	
		
			
				|  |  |          } else if(o->type == OT_FLOAT) {
 | 
	
		
			
				|  |  |              sPush(sc, o);
 | 
	
		
			
				|  |  | -            o->data.floatValue += change;
 | 
	
		
			
				|  |  | +            o->as.floatValue += change;
 | 
	
		
			
				|  |  |          } else {
 | 
	
		
			
				|  |  |              sError(sc, "variable is '%s' not a number on line %d",
 | 
	
		
			
				|  |  |                     oGetName(o->type), sc->line);
 | 
	
	
		
			
				|  | @@ -307,7 +307,7 @@ static void sPushCodeString(Script* sc) {
 | 
	
		
			
				|  |  |      if(sReadInt(sc, &value)) {
 | 
	
		
			
				|  |  |          char* s = (char*)(sc->code->code + sc->readIndex);
 | 
	
		
			
				|  |  |          sc->readIndex += value;
 | 
	
		
			
				|  |  | -        Object o = {.type = OT_CONST_STRING, .data.stringValue = s};
 | 
	
		
			
				|  |  | +        Object o = {.type = OT_CONST_STRING, .as.stringValue = s};
 | 
	
		
			
				|  |  |          sPush(sc, &o);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -318,13 +318,13 @@ static void sPushCodeString(Script* sc) {
 | 
	
		
			
				|  |  |          if(sPop(sc, o) || sPop(sc, o + 1)) {                                   \
 | 
	
		
			
				|  |  |              return;                                                            \
 | 
	
		
			
				|  |  |          } else if(o[0].type == OT_INT && o[1].type == OT_INT) {                \
 | 
	
		
			
				|  |  | -            check sPush##typeA(sc, o[1].data.intValue op o[0].data.intValue);  \
 | 
	
		
			
				|  |  | +            check sPush##typeA(sc, o[1].as.intValue op o[0].as.intValue);      \
 | 
	
		
			
				|  |  |          } else if(o[0].type == OT_INT && o[1].type == OT_FLOAT) {              \
 | 
	
		
			
				|  |  | -            sPush##typeB(sc, o[1].data.floatValue op o[0].data.intValue);      \
 | 
	
		
			
				|  |  | +            sPush##typeB(sc, o[1].as.floatValue op o[0].as.intValue);          \
 | 
	
		
			
				|  |  |          } else if(o[0].type == OT_FLOAT && o[1].type == OT_INT) {              \
 | 
	
		
			
				|  |  | -            sPush##typeB(sc, o[1].data.intValue op o[0].data.floatValue);      \
 | 
	
		
			
				|  |  | +            sPush##typeB(sc, o[1].as.intValue op o[0].as.floatValue);          \
 | 
	
		
			
				|  |  |          } else if(o[0].type == OT_FLOAT && o[1].type == OT_FLOAT) {            \
 | 
	
		
			
				|  |  | -            sPush##typeB(sc, o[1].data.floatValue op o[0].data.floatValue);    \
 | 
	
		
			
				|  |  | +            sPush##typeB(sc, o[1].as.floatValue op o[0].as.floatValue);        \
 | 
	
		
			
				|  |  |          } else {                                                               \
 | 
	
		
			
				|  |  |              sError(sc, "object is not a number on line %d", sc->line);         \
 | 
	
		
			
				|  |  |          }                                                                      \
 | 
	
	
		
			
				|  | @@ -336,12 +336,12 @@ static void sPushCodeString(Script* sc) {
 | 
	
		
			
				|  |  |          Object o[2];                                                           \
 | 
	
		
			
				|  |  |          if(!sPop(sc, o) && !sPop(sc, o + 1) && sCheckType(sc, o, OT_INT) &&    \
 | 
	
		
			
				|  |  |             sCheckType(sc, o + 1, OT_INT)) {                                    \
 | 
	
		
			
				|  |  | -            check sPushInt(sc, o[1].data.intValue op o[0].data.intValue);      \
 | 
	
		
			
				|  |  | +            check sPushInt(sc, o[1].as.intValue op o[0].as.intValue);          \
 | 
	
		
			
				|  |  |          }                                                                      \
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  #define INT_OP(op) CHECKED_INT_OP(, op)
 | 
	
		
			
				|  |  |  #define ZERO_CHECK(op)                                                         \
 | 
	
		
			
				|  |  | -    if(o[0].data.intValue == 0) {                                              \
 | 
	
		
			
				|  |  | +    if(o[0].as.intValue == 0) {                                                \
 | 
	
		
			
				|  |  |          sError(sc, op " by 0 on line %d", sc->line);                           \
 | 
	
		
			
				|  |  |          return;                                                                \
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -353,9 +353,9 @@ static void sInvertSign(Script* sc) {
 | 
	
		
			
				|  |  |      if(o == NULL) {
 | 
	
		
			
				|  |  |          return;
 | 
	
		
			
				|  |  |      } else if(o->type == OT_INT) {
 | 
	
		
			
				|  |  | -        o->data.intValue = -o->data.intValue;
 | 
	
		
			
				|  |  | +        o->as.intValue = -o->as.intValue;
 | 
	
		
			
				|  |  |      } else if(o->type == OT_FLOAT) {
 | 
	
		
			
				|  |  | -        o->data.floatValue = -o->data.floatValue;
 | 
	
		
			
				|  |  | +        o->as.floatValue = -o->as.floatValue;
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |          sError(sc, "object is not a number on line %d", sc->line);
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -366,15 +366,15 @@ static void sEqual(Script* sc) {
 | 
	
		
			
				|  |  |      if(sPop(sc, o) || sPop(sc, o + 1)) {
 | 
	
		
			
				|  |  |          return;
 | 
	
		
			
				|  |  |      } else if(o[0].type == OT_INT && o[1].type == OT_INT) {
 | 
	
		
			
				|  |  | -        sPushBool(sc, o[0].data.intValue == o[1].data.intValue);
 | 
	
		
			
				|  |  | +        sPushBool(sc, o[0].as.intValue == o[1].as.intValue);
 | 
	
		
			
				|  |  |      } else if(o[0].type == OT_INT && o[1].type == OT_FLOAT) {
 | 
	
		
			
				|  |  | -        sPushBool(sc, o[0].data.intValue == o[1].data.floatValue);
 | 
	
		
			
				|  |  | +        sPushBool(sc, o[0].as.intValue == o[1].as.floatValue);
 | 
	
		
			
				|  |  |      } else if(o[0].type == OT_FLOAT && o[1].type == OT_INT) {
 | 
	
		
			
				|  |  | -        sPushBool(sc, o[0].data.floatValue == o[1].data.intValue);
 | 
	
		
			
				|  |  | +        sPushBool(sc, o[0].as.floatValue == o[1].as.intValue);
 | 
	
		
			
				|  |  |      } else if(o[0].type == OT_FLOAT && o[1].type == OT_FLOAT) {
 | 
	
		
			
				|  |  | -        sPushBool(sc, o[0].data.floatValue == o[1].data.floatValue);
 | 
	
		
			
				|  |  | +        sPushBool(sc, o[0].as.floatValue == o[1].as.floatValue);
 | 
	
		
			
				|  |  |      } else if(o[0].type == OT_BOOL && o[1].type == OT_BOOL) {
 | 
	
		
			
				|  |  | -        sPushBool(sc, o[0].data.intValue == o[1].data.intValue);
 | 
	
		
			
				|  |  | +        sPushBool(sc, o[0].as.intValue == o[1].as.intValue);
 | 
	
		
			
				|  |  |      } else if(o[0].type == OT_NULL && o[1].type == OT_NULL) {
 | 
	
		
			
				|  |  |          sPushBool(sc, true);
 | 
	
		
			
				|  |  |      } else {
 | 
	
	
		
			
				|  | @@ -385,14 +385,14 @@ static void sEqual(Script* sc) {
 | 
	
		
			
				|  |  |  static void sNot(Script* sc) {
 | 
	
		
			
				|  |  |      Object* o = sPeek(sc);
 | 
	
		
			
				|  |  |      if(o != NULL && sCheckType(sc, o, OT_BOOL)) {
 | 
	
		
			
				|  |  | -        o->data.intValue = !o->data.intValue;
 | 
	
		
			
				|  |  | +        o->as.intValue = !o->as.intValue;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void sBitNot(Script* sc) {
 | 
	
		
			
				|  |  |      Object* o = sPeek(sc);
 | 
	
		
			
				|  |  |      if(o != NULL && sCheckType(sc, o, OT_INT)) {
 | 
	
		
			
				|  |  | -        o->data.intValue = ~o->data.intValue;
 | 
	
		
			
				|  |  | +        o->as.intValue = ~o->as.intValue;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -400,7 +400,7 @@ static void sAnd(Script* sc) {
 | 
	
		
			
				|  |  |      Object o[2];
 | 
	
		
			
				|  |  |      if(!sPop(sc, o) && !sPop(sc, o + 1) && sCheckType(sc, o, OT_BOOL) &&
 | 
	
		
			
				|  |  |         sCheckType(sc, o + 1, OT_BOOL)) {
 | 
	
		
			
				|  |  | -        sPushBool(sc, o[0].data.intValue && o[1].data.intValue);
 | 
	
		
			
				|  |  | +        sPushBool(sc, o[0].as.intValue && o[1].as.intValue);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -408,7 +408,7 @@ static void sOr(Script* sc) {
 | 
	
		
			
				|  |  |      Object o[2];
 | 
	
		
			
				|  |  |      if(!sPop(sc, o) && !sPop(sc, o + 1) && sCheckType(sc, o, OT_BOOL) &&
 | 
	
		
			
				|  |  |         sCheckType(sc, o + 1, OT_BOOL)) {
 | 
	
		
			
				|  |  | -        sPushBool(sc, o[0].data.intValue || o[1].data.intValue);
 | 
	
		
			
				|  |  | +        sPushBool(sc, o[0].as.intValue || o[1].as.intValue);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -442,7 +442,7 @@ static void sGoSub(Script* sc) {
 | 
	
		
			
				|  |  |                     sc->line);
 | 
	
		
			
				|  |  |              return;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        sc->stack[returnStackIndex].data.intValue = sc->readIndex;
 | 
	
		
			
				|  |  | +        sc->stack[returnStackIndex].as.intValue = sc->readIndex;
 | 
	
		
			
				|  |  |          sc->readIndex = gotoIndex;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -451,7 +451,7 @@ static void sIfGoTo(Script* sc) {
 | 
	
		
			
				|  |  |      int gotoIndex;
 | 
	
		
			
				|  |  |      Object o;
 | 
	
		
			
				|  |  |      if(sReadInt(sc, &gotoIndex) && !sPop(sc, &o) &&
 | 
	
		
			
				|  |  | -       sCheckType(sc, &o, OT_BOOL) && !o.data.intValue) {
 | 
	
		
			
				|  |  | +       sCheckType(sc, &o, OT_BOOL) && !o.as.intValue) {
 | 
	
		
			
				|  |  |          sc->readIndex = gotoIndex;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -463,7 +463,7 @@ static void sSetReturn(Script* sc) {
 | 
	
		
			
				|  |  |  static void sReturn(Script* sc) {
 | 
	
		
			
				|  |  |      Object o;
 | 
	
		
			
				|  |  |      if(!sPop(sc, &o) && sCheckType(sc, &o, OT_INT)) {
 | 
	
		
			
				|  |  | -        sc->readIndex = o.data.intValue;
 | 
	
		
			
				|  |  | +        sc->readIndex = o.as.intValue;
 | 
	
		
			
				|  |  |          if(sc->returnValue.type != OT_VOID) {
 | 
	
		
			
				|  |  |              sPush(sc, &sc->returnValue);
 | 
	
		
			
				|  |  |              sc->returnValue.type = OT_VOID;
 | 
	
	
		
			
				|  | @@ -569,7 +569,7 @@ void sSetPrinter(ObjectPrinter p) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void sMark(Script* sc, Object* o) {
 | 
	
		
			
				|  |  |      if(o->type == OT_ARRAY) {
 | 
	
		
			
				|  |  | -        Array* a = sc->allocator.data + o->data.intValue;
 | 
	
		
			
				|  |  | +        Array* a = sc->allocator.data + o->as.intValue;
 | 
	
		
			
				|  |  |          a->marked = true;
 | 
	
		
			
				|  |  |          for(int i = 0; i < a->length; i++) {
 | 
	
		
			
				|  |  |              sMark(sc, a->data + i);
 |