|
@@ -8,9 +8,6 @@
|
|
|
#include "vm/Operation.h"
|
|
|
#include "vm/Script.h"
|
|
|
|
|
|
-static const char* VALUE_TYPE_NAMES[] = {"?", "int", "float", "pointer",
|
|
|
- "array"};
|
|
|
-
|
|
|
void sError(Script* sc, const char* format, ...) {
|
|
|
va_list args;
|
|
|
va_start(args, format);
|
|
@@ -18,9 +15,14 @@ void sError(Script* sc, const char* format, ...) {
|
|
|
va_end(args);
|
|
|
}
|
|
|
|
|
|
+static void sCannotSetValueType(Script* sc) {
|
|
|
+ sError(sc, "cannot set value type");
|
|
|
+}
|
|
|
+
|
|
|
static bool sRead(Script* sc, void* buffer, int length) {
|
|
|
if(sc->readIndex + length > sc->code->length) {
|
|
|
- sError(sc, "cannot read expected %d bytes of data from bytecode");
|
|
|
+ sError(sc, "cannot read expected %d bytes of data from bytecode",
|
|
|
+ length);
|
|
|
return true;
|
|
|
}
|
|
|
memcpy(buffer, sc->code->code + sc->readIndex, (size_t)length);
|
|
@@ -36,15 +38,15 @@ static Operation sReadOperation(Script* sc) {
|
|
|
return (Operation)c;
|
|
|
}
|
|
|
|
|
|
-static Value* sPeekStack(Script* sc, int type) {
|
|
|
+static Value* sPeekStack(Script* sc, ValueType type) {
|
|
|
if(sc->stackIndex <= 0) {
|
|
|
sError(sc, "stack underflow");
|
|
|
return NULL;
|
|
|
}
|
|
|
- int stackType = sc->stack[sc->stackIndex - 1].type;
|
|
|
+ ValueType stackType = vGetType(sc->stack[sc->stackIndex - 1]);
|
|
|
if(stackType != type) {
|
|
|
- sError(sc, "expected %s on stack but got %s", VALUE_TYPE_NAMES[type],
|
|
|
- VALUE_TYPE_NAMES[stackType]);
|
|
|
+ sError(sc, "expected %s on stack but got %s", vtGetName(type),
|
|
|
+ vtGetName(stackType));
|
|
|
return NULL;
|
|
|
}
|
|
|
return sc->stack + (sc->stackIndex - 1);
|
|
@@ -85,7 +87,10 @@ static Value* sPushStack(Script* sc, int values) {
|
|
|
}
|
|
|
Value* v = sc->stack + sc->stackIndex;
|
|
|
for(int i = 0; i < values; i++) {
|
|
|
- v[i].type = VT_NOT_SET;
|
|
|
+ if(vSetType(v + i, VT_NOT_SET)) {
|
|
|
+ sCannotSetValueType(sc);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
}
|
|
|
sc->stackIndex += values;
|
|
|
return v;
|
|
@@ -93,20 +98,20 @@ static Value* sPushStack(Script* sc, int values) {
|
|
|
|
|
|
bool sPushInt32(Script* sc, int32 i) {
|
|
|
Value* v = sPushStack(sc, 1);
|
|
|
- if(v == NULL) {
|
|
|
+ if(vSetType(v, VT_INT)) {
|
|
|
+ sCannotSetValueType(sc);
|
|
|
return true;
|
|
|
}
|
|
|
- v->type = VT_INT;
|
|
|
v->data.intValue = i;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
bool sPushFloat(Script* sc, float f) {
|
|
|
Value* v = sPushStack(sc, 1);
|
|
|
- if(v == NULL) {
|
|
|
+ if(vSetType(v, VT_FLOAT)) {
|
|
|
+ sCannotSetValueType(sc);
|
|
|
return true;
|
|
|
}
|
|
|
- v->type = VT_FLOAT;
|
|
|
v->data.floatValue = f;
|
|
|
return false;
|
|
|
}
|
|
@@ -220,9 +225,9 @@ static void sGoSub(Script* sc) {
|
|
|
if(index < 0 || index >= SCRIPT_STACK_SIZE) {
|
|
|
sError(sc, "invalid gosub offset");
|
|
|
return;
|
|
|
- } else if(sc->stack[index].type != VT_INT) {
|
|
|
+ } else if(vGetType(sc->stack[index]) != VT_INT) {
|
|
|
sError(sc, "gosub expects an int got %s",
|
|
|
- VALUE_TYPE_NAMES[sc->stack[index].type]);
|
|
|
+ vtGetName(vGetType(sc->stack[index])));
|
|
|
return;
|
|
|
}
|
|
|
sc->stack[index].data.intValue = sc->readIndex;
|
|
@@ -305,11 +310,10 @@ static void sNewArray(Script* sc) {
|
|
|
return;
|
|
|
}
|
|
|
Value* p = sPushStack(sc, 1);
|
|
|
- if(p == NULL) {
|
|
|
+ if(vSetType(p, VT_ARRAY) || vSetOffset(p, 0)) {
|
|
|
+ sCannotSetValueType(sc);
|
|
|
return;
|
|
|
}
|
|
|
- p->type = VT_ARRAY;
|
|
|
- p->offset = 0;
|
|
|
p->data.intValue = asAllocate(&sc->arrays, size, length);
|
|
|
if(p->data.intValue == -1) {
|
|
|
sError(sc, "out of memory");
|
|
@@ -339,11 +343,12 @@ static void sDereference(Script* sc) {
|
|
|
return;
|
|
|
}
|
|
|
Value* v = sPushStack(sc, 1);
|
|
|
- if(v != NULL) {
|
|
|
- v->type = VT_POINTER;
|
|
|
- v->offset = ((unsigned int)(address + sc->stackVarIndex)) & 0x0FFFFFFF;
|
|
|
- v->data.intValue = -1;
|
|
|
+ if(vSetType(v, VT_POINTER) ||
|
|
|
+ vSetOffset(v, (uint32)(address + sc->stackVarIndex))) {
|
|
|
+ sCannotSetValueType(sc);
|
|
|
+ return;
|
|
|
}
|
|
|
+ v->data.intValue = -1;
|
|
|
}
|
|
|
|
|
|
static void sGlobalDereference(Script* sc) {
|
|
@@ -352,11 +357,11 @@ static void sGlobalDereference(Script* sc) {
|
|
|
return;
|
|
|
}
|
|
|
Value* v = sPushStack(sc, 1);
|
|
|
- if(v != NULL) {
|
|
|
- v->type = VT_POINTER;
|
|
|
- v->offset = ((unsigned int)address) & 0x0FFFFFFF;
|
|
|
- v->data.intValue = -1;
|
|
|
+ if(vSetType(v, VT_POINTER) || vSetOffset(v, (uint32)address)) {
|
|
|
+ sCannotSetValueType(sc);
|
|
|
+ return;
|
|
|
}
|
|
|
+ v->data.intValue = -1;
|
|
|
}
|
|
|
|
|
|
static void sDuplicateReference(Script* sc) {
|
|
@@ -377,13 +382,15 @@ static void sAddReference(Script* sc) {
|
|
|
}
|
|
|
Value* v = sPeekStack(sc, VT_POINTER);
|
|
|
if(v != NULL) {
|
|
|
- v->offset = ((unsigned int)(v->offset + add * size)) & 0x3FFFFFF;
|
|
|
+ if(vSetOffset(v, vGetOffset(*v) + (uint32)(add * size))) {
|
|
|
+ sCannotSetValueType(sc);
|
|
|
+ }
|
|
|
} else {
|
|
|
sc->error[0] = '\0';
|
|
|
v = sPeekStack(sc, VT_ARRAY);
|
|
|
- if(v != NULL) {
|
|
|
- v->type = VT_POINTER;
|
|
|
- v->offset = ((unsigned int)(v->offset + add * size)) & 0x3FFFFFF;
|
|
|
+ if(vSetType(v, VT_POINTER) ||
|
|
|
+ vSetOffset(v, vGetOffset(*v) + (uint32)(add * size))) {
|
|
|
+ sCannotSetValueType(sc);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -404,16 +411,18 @@ static void sPushStructReference(Script* sc) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static Value* sLoadFromPointer(Script* sc, Value* p, int type) {
|
|
|
+static Value* sLoadFromPointer(Script* sc, Value* p, ValueType wantedType) {
|
|
|
+ uint32 offset = vGetOffset(*p);
|
|
|
if(p->data.intValue < 0) {
|
|
|
- if(p->offset < 0 || p->offset >= SCRIPT_STACK_SIZE) {
|
|
|
+ if(offset >= SCRIPT_STACK_SIZE) {
|
|
|
sError(sc, "load offset overflow");
|
|
|
return NULL;
|
|
|
}
|
|
|
- Value* v = sc->stack + p->offset;
|
|
|
- if(v->type != type && v->type != VT_NOT_SET) {
|
|
|
- sError(sc, "pointer did not point to %s but %s",
|
|
|
- VALUE_TYPE_NAMES[type], VALUE_TYPE_NAMES[v->type]);
|
|
|
+ Value* v = sc->stack + offset;
|
|
|
+ ValueType type = vGetType(*v);
|
|
|
+ if(type != wantedType && type != VT_NOT_SET) {
|
|
|
+ sError(sc, "pointer did not point to %s but %s", vtGetName(type),
|
|
|
+ vtGetName(type));
|
|
|
return NULL;
|
|
|
}
|
|
|
return v;
|
|
@@ -423,12 +432,11 @@ static Value* sLoadFromPointer(Script* sc, Value* p, int type) {
|
|
|
sError(sc, "invalid heap pointer %d", p->data.intValue);
|
|
|
return NULL;
|
|
|
}
|
|
|
- if(p->offset < 0 || p->offset >= a->realLength) {
|
|
|
- sError(sc, "invalid heap pointer offset %d %d", p->offset,
|
|
|
- a->realLength);
|
|
|
+ if((int32)offset >= a->realLength) {
|
|
|
+ sError(sc, "invalid heap pointer offset %u %d", offset, a->realLength);
|
|
|
return NULL;
|
|
|
}
|
|
|
- return a->data + p->offset;
|
|
|
+ return a->data + offset;
|
|
|
}
|
|
|
|
|
|
SnuviArray* sGetArray(Script* sc) {
|
|
@@ -440,7 +448,7 @@ SnuviArray* sGetArray(Script* sc) {
|
|
|
return asGet(&sc->arrays, v->data.intValue);
|
|
|
}
|
|
|
|
|
|
-Value* sPopStructPointer(Script* sc, int type) {
|
|
|
+Value* sPopStructPointer(Script* sc, ValueType type) {
|
|
|
Value* v = sPeekStack(sc, VT_POINTER);
|
|
|
if(v == NULL) {
|
|
|
return NULL;
|
|
@@ -460,10 +468,11 @@ static void sStoreInt32(Script* sc) {
|
|
|
}
|
|
|
sc->stackIndex--;
|
|
|
v = sLoadFromPointer(sc, v, VT_INT);
|
|
|
- if(v != NULL) {
|
|
|
- v->data.intValue = i;
|
|
|
- v->type = VT_INT;
|
|
|
+ if(vSetType(v, VT_INT)) {
|
|
|
+ sCannotSetValueType(sc);
|
|
|
+ return;
|
|
|
}
|
|
|
+ v->data.intValue = i;
|
|
|
}
|
|
|
|
|
|
static void sStoreFloat(Script* sc) {
|
|
@@ -477,10 +486,11 @@ static void sStoreFloat(Script* sc) {
|
|
|
}
|
|
|
sc->stackIndex--;
|
|
|
v = sLoadFromPointer(sc, v, VT_FLOAT);
|
|
|
- if(v != NULL) {
|
|
|
- v->data.floatValue = f;
|
|
|
- v->type = VT_FLOAT;
|
|
|
+ if(vSetType(v, VT_FLOAT)) {
|
|
|
+ sCannotSetValueType(sc);
|
|
|
+ return;
|
|
|
}
|
|
|
+ v->data.floatValue = f;
|
|
|
}
|
|
|
|
|
|
static void sStoreArray(Script* sc) {
|
|
@@ -550,7 +560,7 @@ static void sEqualArrays(Script* sc, bool wanted) {
|
|
|
return;
|
|
|
}
|
|
|
sc->stackIndex--;
|
|
|
- sPushInt32(sc, (a->offset == b->offset &&
|
|
|
+ sPushInt32(sc, (vGetOffset(*a) == vGetOffset(*b) &&
|
|
|
a->data.intValue == b->data.intValue) == wanted);
|
|
|
}
|
|
|
|
|
@@ -574,11 +584,10 @@ static void sPushText(Script* sc) {
|
|
|
return;
|
|
|
}
|
|
|
Value* p = sPushStack(sc, 1);
|
|
|
- if(p == NULL) {
|
|
|
+ if(vSetType(p, VT_ARRAY) || vSetOffset(p, 0)) {
|
|
|
+ sCannotSetValueType(sc);
|
|
|
return;
|
|
|
}
|
|
|
- p->type = VT_ARRAY;
|
|
|
- p->offset = 0;
|
|
|
p->data.intValue = asAllocate(&sc->arrays, 1, length);
|
|
|
if(p->data.intValue == -1) {
|
|
|
sError(sc, "out of memory");
|
|
@@ -594,7 +603,10 @@ static void sPushText(Script* sc) {
|
|
|
}
|
|
|
for(int i = 0; i < length; i++) {
|
|
|
sReadInt32(sc, &(a->data[i].data.intValue));
|
|
|
- a->data[i].type = VT_INT;
|
|
|
+ if(vSetType(a->data + i, VT_INT)) {
|
|
|
+ sCannotSetValueType(sc);
|
|
|
+ return;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -638,18 +650,20 @@ static void sPushAfterChange(Script* sc) {
|
|
|
|
|
|
static void sFloatToInt32(Script* sc) {
|
|
|
Value* v = sPeekStack(sc, VT_FLOAT);
|
|
|
- if(v != NULL) {
|
|
|
- v->data.intValue = (int)v->data.floatValue;
|
|
|
- v->type = VT_INT;
|
|
|
+ if(vSetType(v, VT_INT)) {
|
|
|
+ sCannotSetValueType(sc);
|
|
|
+ return;
|
|
|
}
|
|
|
+ v->data.intValue = (int)v->data.floatValue;
|
|
|
}
|
|
|
|
|
|
static void sInt32ToFloat(Script* sc) {
|
|
|
Value* v = sPeekStack(sc, VT_INT);
|
|
|
- if(v != NULL) {
|
|
|
- v->data.floatValue = (float)v->data.intValue;
|
|
|
- v->type = VT_FLOAT;
|
|
|
+ if(vSetType(v, VT_FLOAT)) {
|
|
|
+ sCannotSetValueType(sc);
|
|
|
+ return;
|
|
|
}
|
|
|
+ v->data.floatValue = (float)v->data.intValue;
|
|
|
}
|
|
|
|
|
|
#define CASE_NUMBER_OP(name, op) \
|