|
@@ -21,9 +21,9 @@ static bool sPrinter(Object* o) {
|
|
|
case OT_CONST_STRING: printf("%s\n", o->data.stringValue); return false;
|
|
|
case OT_NULL: printf("null\n"); return false;
|
|
|
case OT_BOOL: printf(o->data.intValue ? "true\n" : "false\n"); return false;
|
|
|
- case OT_VOID: printf("void\n"); return false;
|
|
|
+ case OT_ARRAY: printf("array\n"); return false;
|
|
|
+ default: return true;
|
|
|
}
|
|
|
- return true;
|
|
|
}
|
|
|
|
|
|
static ObjectPrinter printer = sPrinter;
|
|
@@ -109,6 +109,11 @@ static void sPushBool(Script* sc, bool 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};
|
|
|
+ sPush(sc, &o);
|
|
|
+}
|
|
|
+
|
|
|
static void sPushVars(Script* sc) {
|
|
|
int vars = 0;
|
|
|
int offset = 0;
|
|
@@ -135,84 +140,138 @@ static void sPopVars(Script* sc) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void sSet(Script* sc) {
|
|
|
+static void sReferenceFromVar(Script* sc) {
|
|
|
int value = 0;
|
|
|
if(sReadInt(sc, &value)) {
|
|
|
- sPop(sc, sc->stack + value + sc->stackVarIndex);
|
|
|
+ sPushReference(sc, -1, value + sc->stackVarIndex);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void sGet(Script* sc) {
|
|
|
+static void sReferenceFromArray(Script* sc) {
|
|
|
int value = 0;
|
|
|
- if(sReadInt(sc, &value)) {
|
|
|
- sPush(sc, sc->stack + value + sc->stackVarIndex);
|
|
|
+ Object o;
|
|
|
+ if(sReadInt(sc, &value) && !sPop(sc, &o) && sCheckType(sc, &o, OT_INT)) {
|
|
|
+ sPushReference(sc, value, o.data.intValue);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void sPreIncrement(Script* sc) {
|
|
|
- int value = 0;
|
|
|
- if(sReadInt(sc, &value)) {
|
|
|
- Object* o = sc->stack + value + sc->stackVarIndex;
|
|
|
- if(o->type == OT_INT) {
|
|
|
- o->data.intValue++;
|
|
|
- } else if(o->type == OT_FLOAT) {
|
|
|
- o->data.floatValue++;
|
|
|
- } else {
|
|
|
- sError(sc, "variable is not a number on line %d", sc->line);
|
|
|
- return;
|
|
|
+static Object* sDereference(Script* sc, Object* reference) {
|
|
|
+ int pointer = reference->data.reference.pointer;
|
|
|
+ int index = reference->data.reference.index;
|
|
|
+ if(pointer == -1) {
|
|
|
+ if(index < 0 || index >= sc->stackIndex) {
|
|
|
+ sError(sc, "variable reference index exceeds stack on line %d", sc->line);
|
|
|
+ return NULL;
|
|
|
}
|
|
|
+ return sc->stack + index;
|
|
|
+ } else {
|
|
|
+ if(pointer < 0 || pointer >= sc->allocator.capacity) {
|
|
|
+ sError(sc, "array reference pointer is out of range on line %d\n", sc->line);
|
|
|
+ return NULL;
|
|
|
+ } else if(index < 0 || index >= sc->allocator.data[pointer].length) {
|
|
|
+ sError(sc, "array reference index is out of bounds on line %d\n", sc->line);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ return sc->allocator.data[pointer].data + index;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static Object* sPopAndDereference(Script* sc) {
|
|
|
+ Object o;
|
|
|
+ if(!sPop(sc, &o) && sCheckType(sc, &o, OT_REFERENCE)) {
|
|
|
+ return sDereference(sc, &o);
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static void sDereferencePush(Script* sc) {
|
|
|
+ Object* o = sPopAndDereference(sc);
|
|
|
+ if(o != NULL) {
|
|
|
sPush(sc, o);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void sPostIncrement(Script* sc) {
|
|
|
- int value = 0;
|
|
|
- if(sReadInt(sc, &value)) {
|
|
|
- Object* o = sc->stack + value + sc->stackVarIndex;
|
|
|
- if(o->type == OT_INT) {
|
|
|
- sPush(sc, o);
|
|
|
- o->data.intValue++;
|
|
|
- } else if(o->type == OT_FLOAT) {
|
|
|
- sPush(sc, o);
|
|
|
- o->data.floatValue++;
|
|
|
- } else {
|
|
|
- sError(sc, "variable is not a number on line %d", sc->line);
|
|
|
+static void sSet(Script* sc) {
|
|
|
+ Object value;
|
|
|
+ if(sPop(sc, &value)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Object* o = sPopAndDereference(sc);
|
|
|
+ if(o != NULL) {
|
|
|
+ *o = value;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void sAllocateArray(Script* sc) {
|
|
|
+ Object length;
|
|
|
+ if(!sPop(sc, &length) && sCheckType(sc, &length, OT_INT)) {
|
|
|
+ if(length.data.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)};
|
|
|
+ sPush(sc, &o);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void sPreDecrement(Script* sc) {
|
|
|
- int value = 0;
|
|
|
- if(sReadInt(sc, &value)) {
|
|
|
- Object* o = sc->stack + value + sc->stackVarIndex;
|
|
|
+static void sArrayLength(Script* sc) {
|
|
|
+ Object* o = sPopAndDereference(sc);
|
|
|
+ if(o != NULL && sCheckType(sc, o, OT_ARRAY)) {
|
|
|
+ int arrayPointer = o->data.intValue;
|
|
|
+ if(arrayPointer < 0 || arrayPointer >= sc->allocator.capacity) {
|
|
|
+ sError(sc, "array pointer is out of range on line %d\n", sc->line);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ sPushInt(sc, sc->allocator.data[arrayPointer].length);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void sPreChange(Script* sc, int change) {
|
|
|
+ Object* o = sPopAndDereference(sc);
|
|
|
+ if(o != NULL) {
|
|
|
if(o->type == OT_INT) {
|
|
|
- o->data.intValue--;
|
|
|
+ o->data.intValue += change;
|
|
|
} else if(o->type == OT_FLOAT) {
|
|
|
- o->data.floatValue--;
|
|
|
+ o->data.floatValue += change;
|
|
|
} else {
|
|
|
- sError(sc, "variable is not a number on line %d", sc->line);
|
|
|
+ sError(sc, "variable is '%s' not a number on line %d", oGetName(o->type), sc->line);
|
|
|
return;
|
|
|
}
|
|
|
sPush(sc, o);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void sPostDecrement(Script* sc) {
|
|
|
- int value = 0;
|
|
|
- if(sReadInt(sc, &value)) {
|
|
|
- Object* o = sc->stack + value + sc->stackVarIndex;
|
|
|
+static void sPreIncrement(Script* sc) {
|
|
|
+ sPreChange(sc, 1);
|
|
|
+}
|
|
|
+
|
|
|
+static void sPreDecrement(Script* sc) {
|
|
|
+ sPreChange(sc, -1);
|
|
|
+}
|
|
|
+
|
|
|
+static void sPostChange(Script* sc, int change) {
|
|
|
+ Object* o = sPopAndDereference(sc);
|
|
|
+ if(o != NULL) {
|
|
|
if(o->type == OT_INT) {
|
|
|
sPush(sc, o);
|
|
|
- o->data.intValue--;
|
|
|
+ o->data.intValue += change;
|
|
|
} else if(o->type == OT_FLOAT) {
|
|
|
sPush(sc, o);
|
|
|
- o->data.floatValue--;
|
|
|
+ o->data.floatValue += change;
|
|
|
} else {
|
|
|
- sError(sc, "variable is not a number on line %d", sc->line);
|
|
|
+ sError(sc, "variable is '%s' not a number on line %d", oGetName(o->type), sc->line);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void sPostIncrement(Script* sc) {
|
|
|
+ sPostChange(sc, 1);
|
|
|
+}
|
|
|
+
|
|
|
+static void sPostDecrement(Script* sc) {
|
|
|
+ sPostChange(sc, -1);
|
|
|
+}
|
|
|
+
|
|
|
static void sPushCodeInt(Script* sc) {
|
|
|
int value = 0;
|
|
|
if(sReadInt(sc, &value)) {
|
|
@@ -495,7 +554,9 @@ static void sDuplicate(Script* sc) {
|
|
|
}
|
|
|
|
|
|
static void sConsumeInstruction(Script* sc) {
|
|
|
- switch(sReadOperation(sc)) {
|
|
|
+ Operation op = sReadOperation(sc);
|
|
|
+ // printf("Operation: %d\n", op);
|
|
|
+ switch(op) {
|
|
|
case OP_NOTHING: break;
|
|
|
case OP_PUSH_INT: sPushCodeInt(sc); break;
|
|
|
case OP_PUSH_FLOAT: sPushCodeFloat(sc); break;
|
|
@@ -507,7 +568,6 @@ static void sConsumeInstruction(Script* sc) {
|
|
|
case OP_POP_VARS: sPopVars(sc); break;
|
|
|
case OP_POP: sPopEmpty(sc); break;
|
|
|
case OP_SET: sSet(sc); break;
|
|
|
- case OP_GET: sGet(sc); break;
|
|
|
case OP_PRE_INCREMENT: sPreIncrement(sc); break;
|
|
|
case OP_POST_INCREMENT: sPostIncrement(sc); break;
|
|
|
case OP_PRE_DECREMENT: sPreDecrement(sc); break;
|
|
@@ -538,7 +598,13 @@ static void sConsumeInstruction(Script* sc) {
|
|
|
case OP_SET_RETURN: sSetReturn(sc); break;
|
|
|
case OP_RETURN: sReturn(sc); break;
|
|
|
case OP_DUPLICATE: sDuplicate(sc); break;
|
|
|
+ case OP_ALLOCATE_ARRAY: sAllocateArray(sc); break;
|
|
|
+ case OP_ARRAY_LENGTH: sArrayLength(sc); break;
|
|
|
+ case OP_REFERENCE_FROM_VAR: sReferenceFromVar(sc); break;
|
|
|
+ case OP_REFERENCE_FROM_ARRAY: sReferenceFromArray(sc); break;
|
|
|
+ case OP_DEREFERENCE: sDereferencePush(sc); break;
|
|
|
}
|
|
|
+ sCollectGarbage(sc);
|
|
|
}
|
|
|
|
|
|
static bool sHasData(Script* sc) {
|
|
@@ -554,11 +620,13 @@ Script* sInit(ByteCode* code) {
|
|
|
sc->stackIndex = 0;
|
|
|
sc->stackVarIndex = 0;
|
|
|
sc->line = 0;
|
|
|
+ aInit(&sc->allocator);
|
|
|
return sc;
|
|
|
}
|
|
|
|
|
|
void sDelete(Script* sc) {
|
|
|
bcDelete(sc->code);
|
|
|
+ aDelete(&sc->allocator);
|
|
|
free(sc);
|
|
|
}
|
|
|
|
|
@@ -576,6 +644,24 @@ void sSetPrinter(ObjectPrinter p) {
|
|
|
printer = p;
|
|
|
}
|
|
|
|
|
|
+static void sMark(Script* sc, Object* o) {
|
|
|
+ if(o->type == OT_ARRAY) {
|
|
|
+ Array* a = sc->allocator.data + o->data.intValue;
|
|
|
+ a->marked = true;
|
|
|
+ for(int i = 0; i < a->length; i++) {
|
|
|
+ sMark(sc, a->data + i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void sCollectGarbage(Script* sc) {
|
|
|
+ aClearMarker(&sc->allocator);
|
|
|
+ for(int i = 0; i < sc->stackIndex; i++) {
|
|
|
+ sMark(sc, sc->stack + i);
|
|
|
+ }
|
|
|
+ aRemoveUnmarked(&sc->allocator);
|
|
|
+}
|
|
|
+
|
|
|
static void sPrintInt(Script* sc, const char* msg) {
|
|
|
int value = 0;
|
|
|
sReadInt(sc, &value);
|
|
@@ -626,12 +712,11 @@ void sPrintCode(Script* sc) {
|
|
|
case OP_PUSH_VARS: sPrint2Int(sc, "Push Vars"); break;
|
|
|
case OP_POP_VARS: sPrintInt(sc, "Pop Vars"); break;
|
|
|
case OP_POP: puts("Pop"); break;
|
|
|
- case OP_SET: sPrintInt(sc, "Set"); break;
|
|
|
- case OP_GET: sPrintInt(sc, "Get"); break;
|
|
|
- case OP_PRE_INCREMENT: sPrintInt(sc, "Pre Increment"); break;
|
|
|
- case OP_POST_INCREMENT: sPrintInt(sc, "Post Increment"); break;
|
|
|
- case OP_PRE_DECREMENT: sPrintInt(sc, "Pre Decrement"); break;
|
|
|
- case OP_POST_DECREMENT: sPrintInt(sc, "Post Decrement"); break;
|
|
|
+ case OP_SET: puts("Set"); break;
|
|
|
+ case OP_PRE_INCREMENT: puts("Pre Increment"); break;
|
|
|
+ case OP_POST_INCREMENT: puts("Post Increment"); break;
|
|
|
+ case OP_PRE_DECREMENT: puts("Pre Decrement"); break;
|
|
|
+ case OP_POST_DECREMENT: puts("Post Decrement"); break;
|
|
|
case OP_ADD: puts("Add"); break;
|
|
|
case OP_SUB: puts("Sub"); break;
|
|
|
case OP_MUL: puts("Mul"); break;
|
|
@@ -658,6 +743,11 @@ void sPrintCode(Script* sc) {
|
|
|
case OP_SET_RETURN: puts("Set Return"); break;
|
|
|
case OP_RETURN: puts("Return"); break;
|
|
|
case OP_DUPLICATE: puts("Duplicate"); break;
|
|
|
+ case OP_ALLOCATE_ARRAY: puts("Allocate Array"); break;
|
|
|
+ case OP_ARRAY_LENGTH: puts("Array Length"); break;
|
|
|
+ case OP_REFERENCE_FROM_VAR: sPrintInt(sc, "Reference From Var"); break;
|
|
|
+ case OP_REFERENCE_FROM_ARRAY: sPrintInt(sc, "Reference From Array"); break;
|
|
|
+ case OP_DEREFERENCE: puts("Dereference"); break;
|
|
|
}
|
|
|
}
|
|
|
sc->readIndex = oldRead;
|