Parcourir la source

array and garbage collector

Kajetan Johannes Hammerle il y a 3 ans
Parent
commit
5de214de95

+ 92 - 0
Allocator.c

@@ -0,0 +1,92 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "Allocator.h"
+
+void aInit(Allocator* a) {
+    a->capacity = 0;
+    a->usedStart = -1;
+    a->freeStart = -1;
+    a->data = NULL;
+}
+
+void aDelete(Allocator* a) {
+    for(int i = a->usedStart; i != -1; i = a->data[i].next) {
+        printf("end Dealloc %d\n", a->data[i].length);
+        free(a->data[i].data);
+    }
+    free(a->data);
+}
+
+static void aInitArray(Array* a, int next) {
+    a->length = 0;
+    a->next = next;
+    a->marked = false;
+    a->data = NULL;
+}
+
+static void aInitArrays(Allocator* a, int start) {
+    for(int i = start; i < a->capacity - 1; i++) {
+        aInitArray(a->data + i, i + 1);
+    }
+    aInitArray(a->data + (a->capacity - 1), -1);
+    a->freeStart = start;
+}
+
+int aAllocate(Allocator* a, int length) {
+    if(a->freeStart == -1) {
+        if(a->data == NULL) {
+            a->capacity = 4;
+            a->data = malloc(sizeof(Array) * a->capacity);
+            aInitArrays(a, 0);
+        } else {
+            int start = a->capacity;
+            a->capacity *= 2;
+            a->data = realloc(a->data, sizeof(Array) * a->capacity);
+            aInitArrays(a, start);
+        }
+    }
+    int index = a->freeStart;
+    Array* array = a->data + index;
+    a->freeStart = array->next;
+
+    array->length = length;
+    array->next = a->usedStart;
+    a->usedStart = index;
+    array->data = malloc(sizeof(Object) * length);
+    for(int i = 0; i < length; i++) {
+        array->data[i].type = OT_NULL;
+    }
+    return index;
+}
+
+void aClearMarker(Allocator* a) {
+    for(int i = a->usedStart; i != -1; i = a->data[i].next) {
+        a->data[i].marked = false;
+    }
+}
+
+void aRemoveUnmarked(Allocator* a) {
+    int prev = -1;
+    int i = a->usedStart;
+    while(i != -1) {
+        int next = a->data[i].next;
+        if(!a->data[i].marked) {
+            free(a->data[i].data);
+
+            if(prev == -1) {
+                a->usedStart = next;
+            } else {
+                a->data[prev].next = next;
+            }
+            a->data[i].next = a->freeStart;
+            a->freeStart = i;
+
+            a->data[i].length = 0;
+            a->data[i].data = NULL;
+        } else {
+            prev = i;
+        }
+        i = next;
+    }
+}

+ 30 - 0
Allocator.h

@@ -0,0 +1,30 @@
+#ifndef ALLOCATOR_H
+#define ALLOCATOR_H
+
+#include <stdbool.h>
+
+#include "Object.h"
+
+typedef struct Array {
+    int length;
+    int next;
+    bool marked;
+    Object* data;
+} Array;
+
+typedef struct Allocator {
+    int capacity;
+    int usedStart;
+    int freeStart;
+    Array* data;
+} Allocator;
+
+void aInit(Allocator* a);
+void aDelete(Allocator* a);
+
+int aAllocate(Allocator* a, int length);
+
+void aClearMarker(Allocator* a);
+void aRemoveUnmarked(Allocator* a);
+
+#endif

+ 64 - 53
Compiler.c

@@ -150,11 +150,6 @@ static const char* cReadString() {
     return literal;
 }
 
-static void cGetVar(const char* var) {
-    cAddOperation(OP_GET);
-    cAddInt(cAddVar(var));
-}
-
 static void cExpression();
 
 static int cCallFunctionArguments() {
@@ -191,29 +186,49 @@ static void cCallFunction(const char* literal, bool noReturn) {
     }
 }
 
-static void cPostIncrement(const char* literal) {
-    cAddOperation(OP_POST_INCREMENT);
-    cAddInt(cAddVar(literal));
-}
-
-static void cPostDecrement(const char* literal) {
-    cAddOperation(OP_POST_DECREMENT);
-    cAddInt(cAddVar(literal));
+static void cAddVarOrArrayReference(const char* var) {
+    if(cConsumeTokenIf(T_OPEN_SQUARE_BRACKET)) {
+        cExpression();
+        cAddOperation(OP_REFERENCE_FROM_ARRAY);
+        cAddInt(cAddVar(var));
+        cConsumeToken(T_CLOSE_SQUARE_BRACKET);
+    } else {
+        cAddOperation(OP_REFERENCE_FROM_VAR);
+        cAddInt(cAddVar(var));
+    }
 }
 
 static void cLiteral() {
     const char* literal = cReadString();
     if(cConsumeTokenIf(T_OPEN_BRACKET)) {
         cCallFunction(literal, false);
-    } else if(cConsumeTokenIf(T_INCREMENT)) {
-        cPostIncrement(literal);
+        return;
+    }
+    cAddVarOrArrayReference(literal);
+    if(cConsumeTokenIf(T_INCREMENT)) {
+        cAddOperation(OP_POST_INCREMENT);
     } else if(cConsumeTokenIf(T_DECREMENT)) {
-        cPostDecrement(literal);
+        cAddOperation(OP_POST_DECREMENT);
+    } else if(cConsumeTokenIf(T_POINT)) {
+        cConsumeToken(T_LITERAL);
+        const char* access = cReadString();
+        if(strcmp(access, "length") == 0) {
+            cAddOperation(OP_ARRAY_LENGTH);
+        } else {
+            cError("'%s' not supported after . on line %d", access, line);
+        }
     } else {
-        cGetVar(literal);
+        cAddOperation(OP_DEREFERENCE);
     }
 }
 
+static void cArray() {
+    cConsumeToken(T_OPEN_SQUARE_BRACKET);
+    cExpression();
+    cConsumeToken(T_CLOSE_SQUARE_BRACKET);
+    cAddOperation(OP_ALLOCATE_ARRAY);
+}
+
 static void cPrimary() {
     Token t = cReadTokenAndLine();
     switch(t) {
@@ -228,20 +243,15 @@ static void cPrimary() {
             cConsumeToken(T_CLOSE_BRACKET);
             break;
         case T_LITERAL: cLiteral(); break;
+        case T_ARRAY: cArray(); break;
         default: cUnexpectedToken(t); break;
     }
 }
 
-static void cPreIncrement() {
-    cConsumeToken(T_LITERAL);
-    cAddOperation(OP_PRE_INCREMENT);
-    cAddInt(cAddVar(cReadString()));
-}
-
-static void cPreDecrement() {
+static void cPreChange(Operation op) {
     cConsumeToken(T_LITERAL);
-    cAddOperation(OP_PRE_DECREMENT);
-    cAddInt(cAddVar(cReadString()));
+    cAddVarOrArrayReference(cReadString());
+    cAddOperation(op);
 }
 
 static void cPreUnary() {
@@ -249,9 +259,9 @@ static void cPreUnary() {
         cPrimary();
         cAddOperation(OP_INVERT_SIGN);
     } else if(cConsumeTokenIf(T_INCREMENT)) {
-        cPreIncrement();
+        cPreChange(OP_PRE_INCREMENT);
     } else if(cConsumeTokenIf(T_DECREMENT)) {
-        cPreDecrement();
+        cPreChange(OP_PRE_DECREMENT);
     } else if(cConsumeTokenIf(T_NOT)) {
         int counter = 1;
         while(cConsumeTokenIf(T_NOT)) {
@@ -410,42 +420,43 @@ static void cExpression() {
     cOr();
 }
 
-static void cSetVar(const char* literal) {
-    cExpression();
-    cAddOperation(OP_SET);
-    cAddInt(cAddVar(literal));
-}
-
-static void cOperationSetVar(const char* literal, Operation op) {
-    cGetVar(literal);
+static void cOperationSet(Operation op) {
+    cAddOperation(OP_DUPLICATE);
+    cAddOperation(OP_DEREFERENCE);
     cExpression();
     cAddOperation(op);
     cAddOperation(OP_SET);
-    cAddInt(cAddVar(literal));
 }
 
 static void cLineLiteral() {
     const char* literal = cReadString();
+    if(cConsumeTokenIf(T_OPEN_BRACKET)) {
+        cCallFunction(literal, true);
+        return;
+    }
+    cAddVarOrArrayReference(literal);
     Token t = cReadTokenAndLine();
     switch(t) {
-        case T_SET: cSetVar(literal); break;
-        case T_ADD_SET: cOperationSetVar(literal, OP_ADD); break;
-        case T_SUB_SET: cOperationSetVar(literal, OP_SUB); break;
-        case T_MUL_SET: cOperationSetVar(literal, OP_MUL); break;
-        case T_DIV_SET: cOperationSetVar(literal, OP_DIV); break;
-        case T_MOD_SET: cOperationSetVar(literal, OP_MOD); break;
-        case T_BIT_AND_SET: cOperationSetVar(literal, OP_BIT_AND); break;
-        case T_BIT_OR_SET: cOperationSetVar(literal, OP_BIT_OR); break;
-        case T_BIT_XOR_SET: cOperationSetVar(literal, OP_BIT_XOR); break;
-        case T_LEFT_SHIFT_SET: cOperationSetVar(literal, OP_LEFT_SHIFT); break;
-        case T_RIGHT_SHIFT_SET: cOperationSetVar(literal, OP_RIGHT_SHIFT); break;
-        case T_OPEN_BRACKET: cCallFunction(literal, true); break;
+        case T_SET:
+            cExpression();
+            cAddOperation(OP_SET);
+            break;
+        case T_ADD_SET: cOperationSet(OP_ADD); break;
+        case T_SUB_SET: cOperationSet(OP_SUB); break;
+        case T_MUL_SET: cOperationSet(OP_MUL); break;
+        case T_DIV_SET: cOperationSet(OP_DIV); break;
+        case T_MOD_SET: cOperationSet(OP_MOD); break;
+        case T_BIT_AND_SET: cOperationSet(OP_BIT_AND); break;
+        case T_BIT_OR_SET: cOperationSet(OP_BIT_OR); break;
+        case T_BIT_XOR_SET: cOperationSet(OP_BIT_XOR); break;
+        case T_LEFT_SHIFT_SET: cOperationSet(OP_LEFT_SHIFT); break;
+        case T_RIGHT_SHIFT_SET: cOperationSet(OP_RIGHT_SHIFT); break;
         case T_INCREMENT:
-            cPostIncrement(literal);
+            cAddOperation(OP_POST_INCREMENT);
             cAddOperation(OP_POP);
             break;
         case T_DECREMENT:
-            cPostDecrement(literal);
+            cAddOperation(OP_POST_DECREMENT);
             cAddOperation(OP_POP);
             break;
         default: cUnexpectedToken(t);
@@ -610,11 +621,11 @@ static void cLineExpression(Token t) {
     switch(t) {
         case T_LITERAL: cLineLiteral(); break;
         case T_INCREMENT:
-            cPreIncrement();
+            cPreChange(OP_PRE_INCREMENT);
             cAddOperation(OP_POP);
             break;
         case T_DECREMENT:
-            cPreDecrement();
+            cPreChange(OP_PRE_DECREMENT);
             cAddOperation(OP_POP);
             break;
         default: cUnexpectedToken(t);

+ 2 - 0
Object.c

@@ -8,6 +8,8 @@ const char* oGetName(ObjectType ot) {
         case OT_NULL: return "null";
         case OT_BOOL: return "bool";
         case OT_VOID: return "void";
+        case OT_ARRAY: return "array";
+        case OT_REFERENCE: return "reference";
         default: return "unknown";
     }
 }

+ 16 - 1
Object.h

@@ -1,7 +1,21 @@
 #ifndef OBJECT_H
 #define OBJECT_H
 
-typedef enum ObjectType { OT_INT, OT_FLOAT, OT_CONST_STRING, OT_NULL, OT_BOOL, OT_VOID } ObjectType;
+typedef enum ObjectType {
+    OT_INT,
+    OT_FLOAT,
+    OT_CONST_STRING,
+    OT_NULL,
+    OT_BOOL,
+    OT_VOID,
+    OT_ARRAY,
+    OT_REFERENCE
+} ObjectType;
+
+typedef struct Reference {
+    int pointer;
+    int index;
+} Reference;
 
 typedef struct Object {
     ObjectType type;
@@ -9,6 +23,7 @@ typedef struct Object {
         int intValue;
         float floatValue;
         const char* stringValue;
+        Reference reference;
     } data;
 } Object;
 

+ 6 - 2
Operation.h

@@ -13,7 +13,6 @@ typedef enum Operation {
     OP_POP_VARS,
     OP_POP,
     OP_SET,
-    OP_GET,
     OP_PRE_INCREMENT,
     OP_POST_INCREMENT,
     OP_PRE_DECREMENT,
@@ -43,7 +42,12 @@ typedef enum Operation {
     OP_IF_GOTO,
     OP_SET_RETURN,
     OP_RETURN,
-    OP_DUPLICATE
+    OP_DUPLICATE,
+    OP_ALLOCATE_ARRAY,
+    OP_ARRAY_LENGTH,
+    OP_REFERENCE_FROM_VAR,
+    OP_REFERENCE_FROM_ARRAY,
+    OP_DEREFERENCE,
 } Operation;
 
 #endif

+ 142 - 52
Script.c

@@ -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;

+ 4 - 0
Script.h

@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 
+#include "Allocator.h"
 #include "ByteCode.h"
 #include "Object.h"
 
@@ -18,6 +19,7 @@ typedef struct Script {
     int stackIndex;
     int stackVarIndex;
     int line;
+    Allocator allocator;
 } Script;
 
 Script* sInit(ByteCode* code);
@@ -28,6 +30,8 @@ void sRun(Script* sc);
 typedef bool (*ObjectPrinter)(Object*);
 void sSetPrinter(ObjectPrinter p);
 
+void sCollectGarbage(Script* sc);
+
 void sPrintCode(Script* sc);
 
 #endif

+ 2 - 2
Test.c

@@ -40,9 +40,9 @@ static bool tsPrinter(Object* o) {
         case OT_CONST_STRING: tsPrintToBuffer("%s\n", o->data.stringValue); return false;
         case OT_NULL: tsPrintToBuffer("null\n"); return false;
         case OT_BOOL: tsPrintToBuffer(o->data.intValue ? "true\n" : "false\n"); return false;
-        case OT_VOID: tsPrintToBuffer("void\n"); return false;
+        case OT_ARRAY: tsPrintToBuffer("array\n"); return false;
+        default: return true;
     }
-    return true;
 }
 
 static void tsAppend(const char* s) {

+ 9 - 1
Tokenizer.c

@@ -24,7 +24,8 @@ typedef struct Literal {
 
 Literal LITERALS[] = {{"print", T_PRINT},       {"null", T_NULL},     {"true", T_TRUE},   {"false", T_FALSE},
                       {"function", T_FUNCTION}, {"return", T_RETURN}, {"if", T_IF},       {"else", T_ELSE},
-                      {"while", T_WHILE},       {"for", T_FOR},       {"break", T_BREAK}, {"continue", T_CONTINUE}};
+                      {"while", T_WHILE},       {"for", T_FOR},       {"break", T_BREAK}, {"continue", T_CONTINUE},
+                      {"array", T_ARRAY}};
 const int LITERAL_AMOUNT = sizeof(LITERALS) / sizeof(Literal);
 
 static void tError(const char* format, ...) {
@@ -214,6 +215,9 @@ static bool tParseToken() {
         case '{': return tAddToken(T_OPEN_CURVED_BRACKET);
         case '}': return tAddToken(T_CLOSE_CURVED_BRACKET);
         case '"': return tAddString();
+        case '.': return tAddToken(T_POINT);
+        case '[': return tAddToken(T_OPEN_SQUARE_BRACKET);
+        case ']': return tAddToken(T_CLOSE_SQUARE_BRACKET);
     }
     tError("unknown character on line %d: %c", line, c);
     return false;
@@ -351,6 +355,10 @@ const char* tGetTokenName(Token token) {
         case T_CLOSE_BRACKET: return ")";
         case T_OPEN_CURVED_BRACKET: return "{";
         case T_CLOSE_CURVED_BRACKET: return "}";
+        case T_ARRAY: return "array";
+        case T_POINT: return ".";
+        case T_OPEN_SQUARE_BRACKET: return "[";
+        case T_CLOSE_SQUARE_BRACKET: return "]";
         case T_END: return "end";
     }
     return "Unknown";

+ 4 - 0
Tokenizer.h

@@ -60,6 +60,10 @@ typedef enum Token {
     T_CLOSE_BRACKET,
     T_OPEN_CURVED_BRACKET,
     T_CLOSE_CURVED_BRACKET,
+    T_ARRAY,
+    T_POINT,
+    T_OPEN_SQUARE_BRACKET,
+    T_CLOSE_SQUARE_BRACKET,
     T_END
 } Token;
 

+ 2 - 1
meson.build

@@ -10,7 +10,8 @@ src = [
     'StringIntMap.c',
     'ByteCode.c',
     'FunctionMap.c',
-    'Object.c'
+    'Object.c',
+    'Allocator.c'
 ]
 
 executable('lonely_tiger', 

+ 9 - 0
tests/arrays/alloc

@@ -0,0 +1,9 @@
+a = array[4];
+print a.length;
+a[0] = 5;
+a[1] = true;
+a[2] = "Hi";
+print a[0];
+print a[1];
+print a[2];
+print a[3];

+ 5 - 0
tests/arrays/alloc.out

@@ -0,0 +1,5 @@
+4
+5
+true
+Hi
+null

+ 6 - 0
tests/arrays/and

@@ -0,0 +1,6 @@
+a = array[1];
+a[0] = 7;
+a[0] &= 15;
+print a[0];
+a[0] &= 9;
+print a[0];

+ 2 - 0
tests/arrays/and.out

@@ -0,0 +1,2 @@
+7
+1

+ 8 - 0
tests/arrays/dec

@@ -0,0 +1,8 @@
+a = array[1];
+a[0] = 0;
+a[0]--;
+--a[0];
+print a[0]--;
+print a[0]--;
+print --a[0];
+print --a[0];

+ 4 - 0
tests/arrays/dec.out

@@ -0,0 +1,4 @@
+-2
+-3
+-5
+-6

+ 8 - 0
tests/arrays/inc

@@ -0,0 +1,8 @@
+a = array[1];
+a[0] = 0;
+a[0]++;
+++a[0];
+print a[0]++;
+print a[0]++;
+print ++a[0];
+print ++a[0];

+ 4 - 0
tests/arrays/inc.out

@@ -0,0 +1,4 @@
+2
+3
+5
+6

+ 6 - 0
tests/arrays/or

@@ -0,0 +1,6 @@
+a = array[1];
+a[0] = 0;
+a[0] |= 2;
+print a[0];
+a[0] |= 5;
+print a[0];

+ 2 - 0
tests/arrays/or.out

@@ -0,0 +1,2 @@
+2
+7

+ 31 - 0
tests/arrays/setop

@@ -0,0 +1,31 @@
+a = array[1];
+
+a[0] = 5;
+a[0] += 5;
+a[0] += 10;
+a[0] += 20;
+print a[0];
+
+a[0] = 5;
+a[0] -= 5;
+a[0] -= -10;
+a[0] -= 20;
+print a[0];
+
+a[0] = 5;
+a[0] *= 2;
+a[0] *= 3;
+a[0] *= 4;
+print a[0];
+
+a[0] = 100;
+a[0] /= 2;
+a[0] /= 3;
+a[0] /= 4;
+print a[0];
+
+a[0] = 100;
+a[0] %= 120;
+a[0] %= 90;
+a[0] %= 3;
+print a[0];

+ 5 - 0
tests/arrays/setop.out

@@ -0,0 +1,5 @@
+40
+-10
+120
+4
+1

+ 10 - 0
tests/arrays/shift

@@ -0,0 +1,10 @@
+a = array[1];
+a[0] = 1;
+a[0] <<= 2;
+a[0] <<= 3;
+print a[0];
+
+a[0] = 100;
+a[0] >>= 2;
+a[0] >>= 3;
+print a[0];

+ 2 - 0
tests/arrays/shift.out

@@ -0,0 +1,2 @@
+32
+3

+ 6 - 0
tests/arrays/xor

@@ -0,0 +1,6 @@
+a = array[1];
+a[0] = 0;
+a[0] ^= 2;
+print a[0];
+a[0] ^= 7;
+print a[0];

+ 2 - 0
tests/arrays/xor.out

@@ -0,0 +1,2 @@
+2
+5