|
|
@@ -1,5 +1,12 @@
|
|
|
#include "Code.h"
|
|
|
|
|
|
+#include <stdio.h>
|
|
|
+#include <string.h>
|
|
|
+
|
|
|
+#include "Code.h"
|
|
|
+#include "Constants.h"
|
|
|
+#include "Memory.h"
|
|
|
+
|
|
|
void codeInit(Code* c) {
|
|
|
*c = (Code){};
|
|
|
bufferInit(&c->code);
|
|
|
@@ -7,6 +14,7 @@ void codeInit(Code* c) {
|
|
|
|
|
|
void codeDestroy(Code* c) {
|
|
|
bufferDestroy(&c->code);
|
|
|
+ memoryFree(c->stack);
|
|
|
*c = (Code){};
|
|
|
}
|
|
|
|
|
|
@@ -14,52 +22,181 @@ void codeReset(Code* c) {
|
|
|
bufferReset(&c->code);
|
|
|
}
|
|
|
|
|
|
-bool codePushInstruction(Code* c, Instruction i) {
|
|
|
- return bufferWriteU8(&c->code, i);
|
|
|
+#define POP_VALUE(name) \
|
|
|
+ Value name; \
|
|
|
+ if(iPopValue(c, &name)) \
|
|
|
+ return true
|
|
|
+
|
|
|
+#define INT_VALUE(value) ((Value){.type = VT_INT32, .data = (value)})
|
|
|
+#define CSTRING_VALUE(value) \
|
|
|
+ ((Value){.type = VT_CONSTANT_STRING, .data = (value)})
|
|
|
+
|
|
|
+#define SET_ERROR(format, ...) \
|
|
|
+ snprintf( \
|
|
|
+ c->error.text, sizeof(c->error.text), \
|
|
|
+ format __VA_OPT__(, ) __VA_ARGS__)
|
|
|
+
|
|
|
+[[nodiscard]] static bool codeReadI32(Code* c, i32* i) {
|
|
|
+ return bufferReadI32(&c->code, i);
|
|
|
+}
|
|
|
+
|
|
|
+[[nodiscard]] static const char* codeReadConstantString(Code* c) {
|
|
|
+ return bufferReadString(&c->code);
|
|
|
}
|
|
|
|
|
|
-bool codePushI64(Code* c, i64 i) {
|
|
|
- return bufferWriteI64(&c->code, i);
|
|
|
+static void codeSetPosition(Code* c, size_t pos) {
|
|
|
+ c->code.readIndex = pos;
|
|
|
}
|
|
|
|
|
|
-bool codePushSize(Code* c, size_t i) {
|
|
|
- return bufferWrite(&c->code, &i, sizeof(i));
|
|
|
+static bool iPushValue(Code* c, Value v) {
|
|
|
+ while(c->stackIndex >= c->maxStackSize) {
|
|
|
+ size_t newSize = c->maxStackSize <= 0 ? 16 : (c->maxStackSize * 5) / 4;
|
|
|
+ if(newSize >= MAX_STACK_VALUES) {
|
|
|
+ SET_ERROR("Stack overflow");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ Value* newValues = memoryAllocate(sizeof(Value) * newSize);
|
|
|
+ if(newValues == nullptr) {
|
|
|
+ SET_ERROR("Out of memory for stack");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ memcpy(newValues, c->stack, sizeof(Value) * c->stackIndex);
|
|
|
+ memoryFree(c->stack);
|
|
|
+ c->stack = newValues;
|
|
|
+ c->maxStackSize = newSize;
|
|
|
+ }
|
|
|
+ c->stack[c->stackIndex++] = v;
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
-bool codePushConstantString(Code* c, const char* s) {
|
|
|
- return bufferWriteString(&c->code, s);
|
|
|
+static bool iPopValue(Code* c, Value* v) {
|
|
|
+ if(c->stackIndex <= 0) {
|
|
|
+ SET_ERROR("Pop on empty stack");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ *v = c->stack[--c->stackIndex];
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
-Instruction codeReadInstruction(Code* c) {
|
|
|
- Instruction i = STOP;
|
|
|
- (void)bufferReadU8(&c->code, &i);
|
|
|
- return i;
|
|
|
+static bool iAdd(Code* c) {
|
|
|
+ POP_VALUE(a);
|
|
|
+ POP_VALUE(b);
|
|
|
+ return iPushValue(c, INT_VALUE(a.data + b.data));
|
|
|
}
|
|
|
|
|
|
-bool codeReadI64(Code* c, i64* i) {
|
|
|
- return bufferReadI64(&c->code, i);
|
|
|
+static bool iPushConstantString(Code* c) {
|
|
|
+ const char* s = codeReadConstantString(c);
|
|
|
+ i32 address = (i32)((const u8*)s - c->code.data);
|
|
|
+ return iPushValue(c, CSTRING_VALUE(address));
|
|
|
}
|
|
|
|
|
|
-bool codeReadSize(Code* c, size_t* s) {
|
|
|
- return bufferRead(&c->code, s, sizeof(size_t));
|
|
|
+static bool iPushInt(Code* c) {
|
|
|
+ i32 i = 0;
|
|
|
+ if(codeReadI32(c, &i)) {
|
|
|
+ SET_ERROR("PushInt without value");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return iPushValue(c, INT_VALUE(i));
|
|
|
}
|
|
|
|
|
|
-const char* codeReadConstantString(Code* c) {
|
|
|
- return bufferReadString(&c->code);
|
|
|
+static bool iPrint(Code* c) {
|
|
|
+ POP_VALUE(a);
|
|
|
+ switch(a.type) {
|
|
|
+ case VT_INT32: printf("%d", a.data); break;
|
|
|
+ case VT_CONSTANT_STRING: printf("%s", c->code.data + a.data); break;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+static bool iPrintNewline() {
|
|
|
+ putchar('\n');
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+static bool iJumpIf(Code* c) {
|
|
|
+ POP_VALUE(a);
|
|
|
+ i32 jumpPos = 0;
|
|
|
+ if(codeReadI32(c, &jumpPos)) {
|
|
|
+ SET_ERROR("JumpIf without position");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if(a.data == 0) {
|
|
|
+ codeSetPosition(c, (size_t)jumpPos);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+static bool iReadVariable(Code* c) {
|
|
|
+ i32 address = 0;
|
|
|
+ if(codeReadI32(c, &address)) {
|
|
|
+ SET_ERROR("ReadVariable without address");
|
|
|
+ return true;
|
|
|
+ } else if((size_t)address >= c->stackIndex) {
|
|
|
+ SET_ERROR("ReadVariable with invalid address");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return iPushValue(c, c->stack[address]);
|
|
|
+}
|
|
|
+
|
|
|
+static bool iSetVariable(Code* c) {
|
|
|
+ i32 address = 0;
|
|
|
+ if(codeReadI32(c, &address)) {
|
|
|
+ SET_ERROR("SetVariable without address");
|
|
|
+ return true;
|
|
|
+ } else if((size_t)address >= c->stackIndex) {
|
|
|
+ SET_ERROR("SetVariable with invalid address");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ POP_VALUE(a);
|
|
|
+ c->stack[address] = a;
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+static bool iPushStackVariables(Code* c) {
|
|
|
+ i32 amount = 0;
|
|
|
+ if(codeReadI32(c, &amount)) {
|
|
|
+ SET_ERROR("PushStackVariables without amount");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ Value v = INT_VALUE(0);
|
|
|
+ while(amount > 0) {
|
|
|
+ if(iPushValue(c, v)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ amount--;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
-size_t codeGetWritePosition(const Code* c) {
|
|
|
- return bufferGetWriteIndex(&c->code);
|
|
|
+static bool execute(Code* c, Instruction command) {
|
|
|
+ switch(command) {
|
|
|
+ case ADD: return iAdd(c);
|
|
|
+ case PUSH_CONSTANT_STRING: return iPushConstantString(c);
|
|
|
+ case PUSH_INT64: return iPushInt(c);
|
|
|
+ case PRINT: return iPrint(c);
|
|
|
+ case PRINT_NEWLINE: return iPrintNewline();
|
|
|
+ case JUMP_ON_0: return iJumpIf(c);
|
|
|
+ case READ_VARIABLE: return iReadVariable(c);
|
|
|
+ case SET_VARIABLE: return iSetVariable(c);
|
|
|
+ case PUSH_STACK_VARIABLES: return iPushStackVariables(c);
|
|
|
+ case STOP: return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
-void codeSetWritePosition(Code* c, size_t pos) {
|
|
|
- bufferSetWriteIndex(&c->code, pos);
|
|
|
+void codeRun(Code* c) {
|
|
|
+ while(true) {
|
|
|
+ Instruction i = STOP;
|
|
|
+ if(bufferReadU8(&c->code, &i) || execute(c, i)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-size_t codeGetPosition(const Code* c) {
|
|
|
- return bufferGetReadIndex(&c->code);
|
|
|
+bool codeHasRunError(const Code* code) {
|
|
|
+ return hasError(&code->error);
|
|
|
}
|
|
|
|
|
|
-void codeSetPosition(Code* c, size_t pos) {
|
|
|
- bufferSetReadIndex(&c->code, pos);
|
|
|
+const char* codeGetRunError(const Code* code) {
|
|
|
+ return code->error.text;
|
|
|
}
|