diff --git a/include/ground.h b/include/ground.h index 753a553..21b0b4e 100644 --- a/include/ground.h +++ b/include/ground.h @@ -336,6 +336,23 @@ struct GroundBytecode { GroundBytecodeHeap heap; }; + +// --- Internal Ground components, avoid use outside of Ground --- + +enum GroundExecutionResultType { + _GER_CONTINUE, _GER_JUMP, _GER_RETURN, _GER_END +}; + +struct GroundExecutionResult { + enum GroundExecutionResultType type; + union { + GroundBytecodeValue value; + GroundSize line; + GroundInt end; + } as; +}; + + // // INTERFACE // @@ -428,6 +445,8 @@ struct _Ground { GroundState (*State) (GroundState* in); GroundIdentifier* (*Identifier) (GroundIdentifier* in); + + GroundBytecodeValue (*BytecodeValue) (GroundBytecodeValue* in); } Copy; struct { @@ -481,11 +500,11 @@ struct _Ground { void (*save) (GroundBytecode* bytecode, const char* path); GroundBytecode (*load) (const char* path); struct { - void (*execute) (GroundBytecodeProgram* program, GroundBytecodeHeap* heap); - void (*optimise) (GroundBytecodeProgram* program); + GroundBytecodeValue (*execute) (GroundBytecodeProgram* program, GroundBytecodeHeap* heap); + void (*optimise) (GroundBytecodeProgram* program); } Program; struct { - int64_t (*execute) (GroundBytecodeInstruction* instruction, GroundBytecodeHeap* heap); + struct GroundExecutionResult (*execute) (GroundBytecodeInstruction* instruction, GroundBytecodeHeap* heap); } Instruction; struct { void (*set) (GroundBytecodeHeap* heap, GroundSize idx, GroundValue value); diff --git a/meson.build b/meson.build index e2bbb59..29c92c7 100644 --- a/meson.build +++ b/meson.build @@ -25,6 +25,8 @@ sources = files( 'src/Copy/Identifier.c', + 'src/Copy/BytecodeValue.c', + 'src/Free/Function.c', 'src/Free/List.c', 'src/Free/Object.c', diff --git a/src/Bytecode/Instruction/execute.c b/src/Bytecode/Instruction/execute.c index 28db9bd..3aad2ec 100644 --- a/src/Bytecode/Instruction/execute.c +++ b/src/Bytecode/Instruction/execute.c @@ -9,6 +9,11 @@ #define HEAP_GET(heap, idx) (&(heap)->heap[(idx)]) #define HEAP_SET(heap, idx, val) ((heap)->heap[(idx)] = (val)) +#define CONTINUE (struct GroundExecutionResult) { _GER_CONTINUE } +#define JUMP(idx) (struct GroundExecutionResult) { .type = _GER_JUMP, .as.line = idx } +#define END(res) (struct GroundExecutionResult) { .type = _GER_END, .as.end = res } +#define RETURN(val) (struct GroundExecutionResult) { .type = _GER_RETURN, .as.value = val } + static void printValue(GroundBytecodeValue* val) { switch (val->type.type) { case GroundType_Int: @@ -32,7 +37,7 @@ static void printValue(GroundBytecodeValue* val) { } } -int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction, GroundBytecodeHeap* heap) { +struct GroundExecutionResult _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction, GroundBytecodeHeap* heap) { static const void* jumpTable[] = { &&IF, &&JUMP, &&END, @@ -55,67 +60,67 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction IF: { GroundBytecodeValue* cond = HEAP_GET(heap, instruction->args.at[0]); if (cond->as.Bool) { - return instruction->args.at[1]; + return JUMP(instruction->args.at[1]); } - return -1; + return CONTINUE; } JUMP: { - return instruction->args.at[0]; + return JUMP(instruction->args.at[0]); } END: { - return -2; + return END( HEAP_GET(heap, instruction->args.at[0])->as.Int ); } INPUT: { char* input = linenoise(""); HEAP_SET(heap, instruction->args.at[0], Ground.New.BytecodeValue(Ground.New.Value.String(Ground.New.String(input)))); free(input); - return -1; + return CONTINUE; } PRINT: { for (GroundSize i = 0; i < instruction->args.len; i++) { printValue(HEAP_GET(heap, instruction->args.at[i])); } - return -1; + return CONTINUE; } PRINTLN: { for (GroundSize i = 0; i < instruction->args.len; i++) { printValue(HEAP_GET(heap, instruction->args.at[i])); } printf("\n"); - return -1; + return CONTINUE; } SET: { HEAP_SET(heap, instruction->args.at[0], *HEAP_GET(heap, instruction->args.at[1])); - return -1; + return CONTINUE; } GETTYPE: { Ground.Log.Warning("GETTYPE is deprecated"); - return -1; + return CONTINUE; } EXISTS: { Ground.Log.Warning("EXISTS is deprecated"); - return -1; + return CONTINUE; } SETLIST: { - return -1; + return CONTINUE; } SETLISTAT: { - return -1; + return CONTINUE; } GETLISTAT: { - return -1; + return CONTINUE; } GETLISTSIZE: { - return -1; + return CONTINUE; } LISTAPPEND: { - return -1; + return CONTINUE; } GETSTRSIZE: { - return -1; + return CONTINUE; } GETSTRCHARAT: { - return -1; + return CONTINUE; } ADD: { GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]); @@ -186,7 +191,7 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction break; } } - return -1; + return CONTINUE; } SUBTRACT: { GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]); @@ -236,7 +241,7 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction break; } } - return -1; + return CONTINUE; } MULTIPLY: { GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]); @@ -286,7 +291,7 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction break; } } - return -1; + return CONTINUE; } DIVIDE: { GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]); @@ -336,7 +341,7 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction break; } } - return -1; + return CONTINUE; } EQUAL: { GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]); @@ -407,7 +412,7 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction break; } } - return -1; + return CONTINUE; } INEQUAL: { GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]); @@ -478,11 +483,11 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction break; } } - return -1; + return CONTINUE; } NOT: { HEAP_SET(heap, instruction->args.at[1], Ground.New.BytecodeValue(Ground.New.Value.Bool(!HEAP_GET(heap, instruction->args.at[0])->as.Bool))); - return -1; + return CONTINUE; } GREATER: { GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]); @@ -529,7 +534,7 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction break; } } - return -1; + return CONTINUE; } LESSER: { GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]); @@ -576,7 +581,7 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction break; } } - return -1; + return CONTINUE; } AND: { GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]); @@ -585,7 +590,7 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction *final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Bool && right->as.Bool)); - return -1; + return CONTINUE; } OR: { GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]); @@ -594,7 +599,7 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction *final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Bool || right->as.Bool)); - return -1; + return CONTINUE; } XOR: { GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]); @@ -603,13 +608,13 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction *final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Bool != right->as.Bool)); - return -1; + return CONTINUE; } NEG: { - return -1; + return CONTINUE; } SHIFT: { - return -1; + return CONTINUE; } STOI: { GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[1]); @@ -624,7 +629,7 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction Ground.Log.Error("Failed converting string to double"); } - return -1; + return CONTINUE; } STOD: { GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[1]); @@ -639,7 +644,7 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction Ground.Log.Error("Failed converting string to double"); } - return -1; + return CONTINUE; } ITOC: { GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[1]); @@ -647,7 +652,7 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction *final = Ground.New.BytecodeValue(Ground.New.Value.Char((char)in->as.Int)); - return -1; + return CONTINUE; } CTOI: { GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[1]); @@ -655,7 +660,7 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction *final = Ground.New.BytecodeValue(Ground.New.Value.Int((int64_t)in->as.Char)); - return -1; + return CONTINUE; } TOSTRING: { GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[1]); @@ -682,7 +687,7 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction } case GroundType_String: { *in = Ground.New.BytecodeValue(Ground.New.Value.String(final->as.String)); - return -1; + return CONTINUE; } default: { @@ -694,76 +699,120 @@ int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction *in = Ground.New.BytecodeValue(Ground.New.Value.String(Ground.New.String(buf))); - return -1; + return CONTINUE; } FUN: { - // no-op - return -1; + // make a copy of the current state and attach it to the function + GroundBytecodeFunction* function = &HEAP_GET(heap, instruction->args.at[0])->as.Function; + + if (function->closure == NULL) {} + + return CONTINUE; } RETURN: { - return -1; + return RETURN( *HEAP_GET(heap, instruction->args.at[0]) ); } ENDFUN: { // no-op - return -1; + return CONTINUE; } CALL: { - return -1; + // call !function $value... &returnIdx + GroundBytecodeFunction* function = &HEAP_GET(heap, instruction->args.at[0])->as.Function; + + if (function->isNativeFunction) { + // TODO implement calling native functions + return CONTINUE; + } + + if (function->closure == NULL) { + Ground.Log.Error("unexpected NULL closure in Ground.Bytecode.Instruction.execute"); + Ground.Flags.error = true; + return CONTINUE; + } + + // amount of captured variables + amount of function args + GroundSize heapSize = function->closure->len + function->args.count; + + GroundBytecodeHeap newHeap = { malloc(sizeof(GroundBytecodeValue) * heapSize), heapSize, heapSize }; + if (newHeap.heap == NULL) { + Ground.Log.Error("malloc failed in Ground.Bytecode.Instruction.execute"); + Ground.Flags.error = true; + return CONTINUE; + } + + // load function arguments into the heap + for (GroundSize i = 0; i < function->args.count; i++) { + newHeap.heap[i] = Ground.Copy.BytecodeValue(HEAP_GET(heap, i + 1)); // +1 because arg 1 is where fn args start + } + + // function arguments are the first indexes, copy after + for (GroundSize i = function->args.count; i < newHeap.len; i++) { + newHeap.heap[i] = Ground.Copy.BytecodeValue(&function->closure->heap[i]); + } + + // Now we run the thingy + GroundBytecodeValue result = Ground.Bytecode.Program.execute(function->program.ground, &newHeap); + + // And store the result + HEAP_SET(heap, instruction->args.at[instruction->args.len - 1], result); + + return CONTINUE; } CALLMETHOD: { - return -1; + return CONTINUE; } STRUCT: { // no-op - return -1; + return CONTINUE; } ENDSTRUCT: { // no-op - return -1; + return CONTINUE; } INIT: { - return -1; + return CONTINUE; } GETFIELD: { - return -1; + return CONTINUE; } SETFIELD: { - return -1; + return CONTINUE; } USE: { - return -1; + return CONTINUE; } EXTERN: { - return -1; + return CONTINUE; } CREATELABEL: { // no-op - return -1; + return CONTINUE; } PAUSE: { - return -1; + return CONTINUE; } DROP: { GroundBytecodeValue* in = HEAP_GET(heap, instruction->args.at[0]); Ground.Free.BytecodeValue(in); *in = Ground.New.BytecodeValue(Ground.New.Value.Int(0)); - return -1; + return CONTINUE; } LICENSE: { - return -1; + return CONTINUE; } ERRORCMD: { - return -1; + return CONTINUE; } THROW: { - return -1; + return CONTINUE; } CATCH: { - return -1; + return CONTINUE; } Ground.Log.Error("operation fell through in Ground.Instruction.execute()"); Ground.Flags.error = true; - return -1; + return CONTINUE; } diff --git a/src/Bytecode/Program/execute.c b/src/Bytecode/Program/execute.c index c7e5ac6..09df625 100644 --- a/src/Bytecode/Program/execute.c +++ b/src/Bytecode/Program/execute.c @@ -1,18 +1,22 @@ #include "../../../include/ground.h" #include -void _GroundBytecodeProgramExecute(GroundBytecodeProgram* program, GroundBytecodeHeap* heap) { +GroundBytecodeValue _GroundBytecodeProgramExecute(GroundBytecodeProgram* program, GroundBytecodeHeap* heap) { GroundSize i = 0; while (i < program->len) { - int64_t status = Ground.Bytecode.Instruction.execute(&program->at[i], heap); + struct GroundExecutionResult status = Ground.Bytecode.Instruction.execute(&program->at[i], heap); if (Ground.Flags.error) { - return; + return Ground.New.BytecodeValue(Ground.New.Value.Int(1)); } - switch (status) { - case -1: i++; break; - case -2: return; - default: i = status; break; + switch (status.type) { + + case _GER_CONTINUE: i++; break; + case _GER_RETURN: return status.as.value; + case _GER_JUMP: i = status.as.line; break; + case _GER_END: exit(status.as.end); + } } + return Ground.New.BytecodeValue(Ground.New.Value.Int(0)); } diff --git a/src/Copy/BytecodeValue.c b/src/Copy/BytecodeValue.c new file mode 100644 index 0000000..3cd2a09 --- /dev/null +++ b/src/Copy/BytecodeValue.c @@ -0,0 +1,22 @@ +#include "../../include/ground.h" + +GroundBytecodeValue _GroundCopyBytecodeValue(GroundBytecodeValue* value) { + GroundBytecodeValue newValue = *value; + switch (value->type.type) { + case GroundType_Int: + case GroundType_Double: + case GroundType_Bool: + case GroundType_Char: + break; + + case GroundType_String: { + newValue.as.String = Ground.Copy.String(&value->as.String); + break; + } + + // TODO: Implement copying for everything else + default: break; + } + + return newValue; +} diff --git a/src/libmain.c b/src/libmain.c index 28645a5..73eb3e6 100644 --- a/src/libmain.c +++ b/src/libmain.c @@ -66,6 +66,8 @@ GroundState _GroundCopyState(GroundState* in); GroundIdentifier* _GroundCopyIdentifier(GroundIdentifier* identifier); +GroundBytecodeValue _GroundCopyBytecodeValue(GroundBytecodeValue* value); + void _GroundListAppend(GroundList* list, GroundValue value); @@ -99,10 +101,10 @@ void _GroundLogWarning(const char* message); void _GroundLogPrintErrors(); -void _GroundBytecodeProgramExecute(GroundBytecodeProgram* program, GroundBytecodeHeap* heap); +GroundBytecodeValue _GroundBytecodeProgramExecute(GroundBytecodeProgram* program, GroundBytecodeHeap* heap); void _GroundBytecodeProgramOptimise(GroundBytecodeProgram* program); -int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction, GroundBytecodeHeap* heap); +struct GroundExecutionResult _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction, GroundBytecodeHeap* heap); void _GroundBytecodeSave(GroundBytecode* bytecode, const char* path); GroundBytecode _GroundBytecodeLoad(const char* path);