Files
ground-rewrite/src/Bytecode/Instruction/execute.c

927 lines
34 KiB
C
Raw Normal View History

2026-06-21 14:35:48 +10:00
#include "../../../include/ground.h"
2026-06-25 18:57:53 +10:00
#include "../../linenoise/linenoise.h"
2026-06-21 14:35:48 +10:00
#include <stdint.h>
#include <inttypes.h>
2026-06-24 10:17:58 +10:00
#include <stdio.h>
#include <stdlib.h>
2026-06-21 16:39:05 +10:00
#include <string.h>
#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 }
2026-07-02 11:35:56 +10:00
static void printValue(GroundBytecodeValue* val) {
2026-06-21 16:39:05 +10:00
switch (val->type.type) {
case GroundType_Int:
printf("%" PRId64, val->as.Int);
break;
case GroundType_Double:
printf("%f", val->as.Double);
break;
case GroundType_Bool:
printf(val->as.Bool ? "true" : "false");
break;
case GroundType_Char:
printf("%c", val->as.Char);
break;
case GroundType_String:
printf("%s", val->as.String.cstr);
break;
case GroundType_Function:
printf("<function>");
break;
2026-06-21 16:39:05 +10:00
default:
printf("<fixme opt=%d>", val->type.type);
2026-06-21 16:39:05 +10:00
break;
}
}
2026-06-21 14:35:48 +10:00
struct GroundExecutionResult _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction, GroundBytecodeHeap* heap) {
2026-06-21 14:35:48 +10:00
static const void* jumpTable[] = {
&&IF, &&JUMP, &&END,
&&INPUT, &&PRINT, &&PRINTLN,
&&SET, &&GETTYPE, &&EXISTS,
&&SETLIST, &&SETLISTAT, &&GETLISTAT, &&GETLISTSIZE, &&LISTAPPEND,
&&GETSTRSIZE, &&GETSTRCHARAT,
&&ADD, &&SUBTRACT, &&MULTIPLY, &&DIVIDE,
&&EQUAL, &&INEQUAL, &&NOT, &&GREATER, &&LESSER,
&&AND, &&OR, &&XOR, &&NEG, &&SHIFT,
&&STOI, &&STOD, &&ITOC, &&CTOI, &&TOSTRING,
&&FUN, &&RETURN, &&ENDFUN, &&CALL, &&CALLMETHOD,
&&STRUCT, &&ENDSTRUCT, &&INIT, &&GETFIELD, &&SETFIELD,
&&USE, &&EXTERN, &&CREATELABEL,
&&PAUSE, &&DROP, &&LICENSE, &&ERRORCMD, &&THROW, &&CATCH
};
goto *jumpTable[instruction->type];
IF: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* cond = HEAP_GET(heap, instruction->args.at[0]);
2026-06-21 16:13:00 +10:00
if (cond->as.Bool) {
return JUMP(instruction->args.at[1]);
2026-06-21 16:13:00 +10:00
}
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
JUMP: {
return JUMP(instruction->args.at[0]);
2026-06-21 14:35:48 +10:00
}
END: {
return END( HEAP_GET(heap, instruction->args.at[0])->as.Int );
2026-06-21 14:35:48 +10:00
}
INPUT: {
2026-06-25 18:57:53 +10:00
char* input = linenoise("");
2026-07-02 11:35:56 +10:00
HEAP_SET(heap, instruction->args.at[0], Ground.New.BytecodeValue(Ground.New.Value.String(Ground.New.String(input))));
2026-06-25 18:57:53 +10:00
free(input);
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
PRINT: {
for (GroundSize i = 0; i < instruction->args.len; i++) {
2026-06-21 16:39:05 +10:00
printValue(HEAP_GET(heap, instruction->args.at[i]));
2026-06-21 14:35:48 +10:00
}
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
PRINTLN: {
for (GroundSize i = 0; i < instruction->args.len; i++) {
2026-06-21 16:39:05 +10:00
printValue(HEAP_GET(heap, instruction->args.at[i]));
2026-06-21 14:35:48 +10:00
}
printf("\n");
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
SET: {
2026-06-21 16:39:05 +10:00
HEAP_SET(heap, instruction->args.at[0], *HEAP_GET(heap, instruction->args.at[1]));
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
GETTYPE: {
Ground.Log.Warning("GETTYPE is deprecated");
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
EXISTS: {
Ground.Log.Warning("EXISTS is deprecated");
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
SETLIST: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
SETLISTAT: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
GETLISTAT: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
GETLISTSIZE: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
LISTAPPEND: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
GETSTRSIZE: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
GETSTRCHARAT: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
ADD: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]);
GroundBytecodeValue* left = HEAP_GET(heap, instruction->args.at[0]);
GroundBytecodeValue* right = HEAP_GET(heap, instruction->args.at[1]);
2026-06-21 14:35:48 +10:00
switch (left->type.type) {
case GroundType_Int: {
switch (right->type.type) {
case GroundType_Int: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Int(left->as.Int + right->as.Int));
2026-06-21 14:35:48 +10:00
break;
}
case GroundType_Double: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Double(left->as.Int + right->as.Double));
2026-06-21 14:35:48 +10:00
break;
}
default: {
Ground.Log.Error("invalid add operation in Ground.Instruction.execute()");
Ground.Flags.error = true;
break;
}
}
break;
}
case GroundType_Double: {
switch (right->type.type) {
case GroundType_Int: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Double(left->as.Double + right->as.Int));
2026-06-21 14:35:48 +10:00
break;
}
case GroundType_Double: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Double(left->as.Double + right->as.Double));
2026-06-21 14:35:48 +10:00
break;
}
default: {
Ground.Log.Error("invalid add operation in Ground.Instruction.execute()");
Ground.Flags.error = true;
break;
}
}
break;
}
case GroundType_String: {
switch (right->type.type) {
case GroundType_String: {
2026-06-21 16:39:05 +10:00
GroundSize total = left->as.String.len + right->as.String.len;
char* buf = malloc(total + 1);
2026-06-21 14:35:48 +10:00
if (buf == NULL) {
Ground.Log.Error("malloc failed (instruction ADD{string, string, dirref}) in Ground.Instruction.execute()");
Ground.Flags.error = true;
break;
}
sprintf(buf, "%s%s", left->as.String.cstr, right->as.String.cstr);
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.String(Ground.New.String(buf)));
2026-06-21 14:35:48 +10:00
break;
}
default: {
Ground.Log.Error("invalid add operation in Ground.Instruction.execute()");
Ground.Flags.error = true;
break;
}
}
}
default: {
Ground.Log.Error("invalid add operation in Ground.Instruction.execute()");
Ground.Flags.error = true;
break;
}
}
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
SUBTRACT: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]);
GroundBytecodeValue* left = HEAP_GET(heap, instruction->args.at[0]);
GroundBytecodeValue* right = HEAP_GET(heap, instruction->args.at[1]);
2026-06-21 14:35:48 +10:00
switch (left->type.type) {
case GroundType_Int: {
switch (right->type.type) {
case GroundType_Int: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Int(left->as.Int - right->as.Int));
2026-06-21 14:35:48 +10:00
break;
}
case GroundType_Double: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Double(left->as.Int - right->as.Double));
2026-06-21 14:35:48 +10:00
break;
}
default: {
Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()");
Ground.Flags.error = true;
break;
}
}
break;
}
case GroundType_Double: {
switch (right->type.type) {
case GroundType_Int: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Double(left->as.Double - right->as.Int));
2026-06-21 14:35:48 +10:00
break;
}
case GroundType_Double: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Double(left->as.Double - right->as.Double));
2026-06-21 14:35:48 +10:00
break;
}
default: {
Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()");
Ground.Flags.error = true;
break;
}
}
break;
}
default: {
Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()");
Ground.Flags.error = true;
break;
}
}
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
MULTIPLY: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]);
GroundBytecodeValue* left = HEAP_GET(heap, instruction->args.at[0]);
GroundBytecodeValue* right = HEAP_GET(heap, instruction->args.at[1]);
2026-06-21 14:35:48 +10:00
switch (left->type.type) {
case GroundType_Int: {
switch (right->type.type) {
case GroundType_Int: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Int(left->as.Int * right->as.Int));
2026-06-21 14:35:48 +10:00
break;
}
case GroundType_Double: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Double(left->as.Int * right->as.Double));
2026-06-21 14:35:48 +10:00
break;
}
default: {
Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()");
Ground.Flags.error = true;
break;
}
}
break;
}
case GroundType_Double: {
switch (right->type.type) {
case GroundType_Int: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Double(left->as.Double * right->as.Int));
2026-06-21 14:35:48 +10:00
break;
}
case GroundType_Double: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Double(left->as.Double * right->as.Double));
2026-06-21 14:35:48 +10:00
break;
}
default: {
Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()");
Ground.Flags.error = true;
break;
}
}
break;
}
default: {
Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()");
Ground.Flags.error = true;
break;
}
}
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
DIVIDE: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]);
GroundBytecodeValue* left = HEAP_GET(heap, instruction->args.at[0]);
GroundBytecodeValue* right = HEAP_GET(heap, instruction->args.at[1]);
2026-06-21 14:35:48 +10:00
switch (left->type.type) {
case GroundType_Int: {
switch (right->type.type) {
case GroundType_Int: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Int(left->as.Int / right->as.Int));
2026-06-21 14:35:48 +10:00
break;
}
case GroundType_Double: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Double(left->as.Int / right->as.Double));
2026-06-21 14:35:48 +10:00
break;
}
default: {
Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()");
Ground.Flags.error = true;
break;
}
}
break;
}
case GroundType_Double: {
switch (right->type.type) {
case GroundType_Int: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Double(left->as.Double / right->as.Int));
2026-06-21 14:35:48 +10:00
break;
}
case GroundType_Double: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Double(left->as.Double / right->as.Double));
2026-06-21 14:35:48 +10:00
break;
}
default: {
Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()");
Ground.Flags.error = true;
break;
}
}
break;
}
default: {
Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()");
Ground.Flags.error = true;
break;
}
}
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
EQUAL: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]);
GroundBytecodeValue* left = HEAP_GET(heap, instruction->args.at[0]);
GroundBytecodeValue* right = HEAP_GET(heap, instruction->args.at[1]);
2026-06-21 14:35:48 +10:00
switch (left->type.type) {
case GroundType_Int: {
switch (right->type.type) {
case GroundType_Int: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Int == right->as.Int));
2026-06-21 14:35:48 +10:00
break;
}
case GroundType_Double: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Int == right->as.Double));
2026-06-21 14:35:48 +10:00
break;
}
default: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(false));
2026-06-21 14:35:48 +10:00
break;
}
}
break;
}
case GroundType_Double: {
switch (right->type.type) {
case GroundType_Int: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Double == right->as.Int));
2026-06-21 14:35:48 +10:00
break;
}
case GroundType_Double: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Double == right->as.Double));
2026-06-21 14:35:48 +10:00
break;
}
default: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(false));
2026-06-21 14:35:48 +10:00
break;
}
}
break;
}
case GroundType_Char: {
if (right->type.type == GroundType_Char) {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Char == right->as.Char));
2026-06-21 14:35:48 +10:00
} else {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(false));
2026-06-21 14:35:48 +10:00
}
break;
}
case GroundType_Bool: {
if (right->type.type == GroundType_Bool) {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Bool == right->as.Bool));
2026-06-21 14:35:48 +10:00
} else {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(false));
2026-06-21 14:35:48 +10:00
}
break;
}
case GroundType_String: {
if (right->type.type == GroundType_String) {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(strcmp(left->as.String.cstr, right->as.String.cstr) == 0));
2026-06-21 14:35:48 +10:00
} else {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(false));
2026-06-21 14:35:48 +10:00
}
break;
}
default: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(false));
2026-06-21 14:35:48 +10:00
break;
}
}
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
INEQUAL: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]);
GroundBytecodeValue* left = HEAP_GET(heap, instruction->args.at[0]);
GroundBytecodeValue* right = HEAP_GET(heap, instruction->args.at[1]);
2026-06-21 14:35:48 +10:00
switch (left->type.type) {
case GroundType_Int: {
switch (right->type.type) {
case GroundType_Int: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Int != right->as.Int));
2026-06-21 14:35:48 +10:00
break;
}
case GroundType_Double: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Int != right->as.Double));
2026-06-21 14:35:48 +10:00
break;
}
default: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(true));
2026-06-21 14:35:48 +10:00
break;
}
}
break;
}
case GroundType_Double: {
switch (right->type.type) {
case GroundType_Int: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Double != right->as.Int));
2026-06-21 14:35:48 +10:00
break;
}
case GroundType_Double: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Double != right->as.Double));
2026-06-21 14:35:48 +10:00
break;
}
default: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(true));
2026-06-21 14:35:48 +10:00
break;
}
}
break;
}
case GroundType_Char: {
if (right->type.type == GroundType_Char) {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Char != right->as.Char));
2026-06-21 14:35:48 +10:00
} else {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(true));
2026-06-21 14:35:48 +10:00
}
break;
}
case GroundType_Bool: {
if (right->type.type == GroundType_Bool) {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Bool != right->as.Bool));
2026-06-21 14:35:48 +10:00
} else {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(true));
2026-06-21 14:35:48 +10:00
}
break;
}
case GroundType_String: {
if (right->type.type == GroundType_String) {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(strcmp(left->as.String.cstr, right->as.String.cstr) != 0));
2026-06-21 14:35:48 +10:00
} else {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(true));
2026-06-21 14:35:48 +10:00
}
break;
}
default: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(false));
2026-06-21 14:35:48 +10:00
break;
}
}
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
NOT: {
2026-07-02 11:35:56 +10:00
HEAP_SET(heap, instruction->args.at[1], Ground.New.BytecodeValue(Ground.New.Value.Bool(!HEAP_GET(heap, instruction->args.at[0])->as.Bool)));
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
GREATER: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]);
GroundBytecodeValue* left = HEAP_GET(heap, instruction->args.at[0]);
GroundBytecodeValue* right = HEAP_GET(heap, instruction->args.at[1]);
2026-06-24 10:17:58 +10:00
switch (left->type.type) {
case GroundType_Int: {
switch (right->type.type) {
case GroundType_Int: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Int > right->as.Int));
2026-06-24 10:17:58 +10:00
break;
}
case GroundType_Double: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Int > right->as.Double));
2026-06-24 10:17:58 +10:00
break;
}
default: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(true));
2026-06-24 10:17:58 +10:00
break;
}
}
break;
}
case GroundType_Double: {
switch (right->type.type) {
case GroundType_Int: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Double > right->as.Int));
2026-06-24 10:17:58 +10:00
break;
}
case GroundType_Double: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Double > right->as.Double));
2026-06-24 10:17:58 +10:00
break;
}
default: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(true));
2026-06-24 10:17:58 +10:00
break;
}
}
break;
}
default: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(false));
2026-06-24 10:17:58 +10:00
break;
}
}
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
LESSER: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]);
GroundBytecodeValue* left = HEAP_GET(heap, instruction->args.at[0]);
GroundBytecodeValue* right = HEAP_GET(heap, instruction->args.at[1]);
2026-06-24 10:17:58 +10:00
switch (left->type.type) {
case GroundType_Int: {
switch (right->type.type) {
case GroundType_Int: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Int < right->as.Int));
2026-06-24 10:17:58 +10:00
break;
}
case GroundType_Double: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Int < right->as.Double));
2026-06-24 10:17:58 +10:00
break;
}
default: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(true));
2026-06-24 10:17:58 +10:00
break;
}
}
break;
}
case GroundType_Double: {
switch (right->type.type) {
case GroundType_Int: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Double < right->as.Int));
2026-06-24 10:17:58 +10:00
break;
}
case GroundType_Double: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Double < right->as.Double));
2026-06-24 10:17:58 +10:00
break;
}
default: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(true));
2026-06-24 10:17:58 +10:00
break;
}
}
break;
}
default: {
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(false));
2026-06-24 10:17:58 +10:00
break;
}
}
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
AND: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]);
GroundBytecodeValue* left = HEAP_GET(heap, instruction->args.at[0]);
GroundBytecodeValue* right = HEAP_GET(heap, instruction->args.at[1]);
2026-06-24 10:17:58 +10:00
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Bool && right->as.Bool));
2026-06-24 10:17:58 +10:00
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
OR: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]);
GroundBytecodeValue* left = HEAP_GET(heap, instruction->args.at[0]);
GroundBytecodeValue* right = HEAP_GET(heap, instruction->args.at[1]);
2026-06-24 10:17:58 +10:00
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Bool || right->as.Bool));
2026-06-24 10:17:58 +10:00
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
XOR: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[2]);
GroundBytecodeValue* left = HEAP_GET(heap, instruction->args.at[0]);
GroundBytecodeValue* right = HEAP_GET(heap, instruction->args.at[1]);
2026-06-24 10:17:58 +10:00
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Bool(left->as.Bool != right->as.Bool));
2026-06-24 10:17:58 +10:00
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
NEG: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
SHIFT: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
STOI: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[1]);
GroundBytecodeValue* in = HEAP_GET(heap, instruction->args.at[0]);
2026-06-24 10:17:58 +10:00
char* status = NULL;
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Int(strtoll(in->as.String.cstr, &status, 0)));
2026-06-24 10:17:58 +10:00
if (status != in->as.String.cstr) {
Ground.Flags.error = true;
Ground.Log.Error("Failed converting string to double");
}
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
STOD: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[1]);
GroundBytecodeValue* in = HEAP_GET(heap, instruction->args.at[0]);
2026-06-24 10:17:58 +10:00
char* status = NULL;
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Double(strtod(in->as.String.cstr, &status)));
2026-06-24 10:17:58 +10:00
if (status != in->as.String.cstr) {
Ground.Flags.error = true;
Ground.Log.Error("Failed converting string to double");
}
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
ITOC: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[1]);
GroundBytecodeValue* in = HEAP_GET(heap, instruction->args.at[0]);
2026-06-24 10:17:58 +10:00
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Char((char)in->as.Int));
2026-06-24 10:17:58 +10:00
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
CTOI: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[1]);
GroundBytecodeValue* in = HEAP_GET(heap, instruction->args.at[0]);
2026-06-24 10:17:58 +10:00
2026-07-02 11:35:56 +10:00
*final = Ground.New.BytecodeValue(Ground.New.Value.Int((int64_t)in->as.Char));
2026-06-24 10:17:58 +10:00
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
TOSTRING: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* final = HEAP_GET(heap, instruction->args.at[1]);
GroundBytecodeValue* in = HEAP_GET(heap, instruction->args.at[0]);
2026-06-24 10:17:58 +10:00
char buf[4096];
switch (in->type.type) {
case GroundType_Int: {
snprintf(buf, sizeof(buf), "%" PRId64, in->as.Int);
break;
}
case GroundType_Double: {
snprintf(buf, sizeof(buf), "%f", in->as.Double);
break;
}
case GroundType_Char: {
snprintf(buf, sizeof(buf), "%c", in->as.Char);
break;
}
case GroundType_Bool: {
snprintf(buf, sizeof(buf), in->as.Bool ? "true" : "false");
break;
}
case GroundType_String: {
2026-07-02 11:35:56 +10:00
*in = Ground.New.BytecodeValue(Ground.New.Value.String(final->as.String));
return CONTINUE;
2026-06-24 10:17:58 +10:00
}
default: {
// TODO: implement tostring for complex types
snprintf(buf, sizeof(buf), "<FIXME>");
break;
}
}
2026-07-02 11:35:56 +10:00
*in = Ground.New.BytecodeValue(Ground.New.Value.String(Ground.New.String(buf)));
2026-06-24 10:17:58 +10:00
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
FUN: {
// make a copy of the current state and attach it to the function
GroundBytecodeFunction* function = &HEAP_GET(heap, instruction->args.at[0])->as.Function;
2026-07-03 19:06:40 +10:00
if (function->closure == NULL) {
function->closure = malloc(sizeof(GroundBytecodeHeap));
if (function->closure == NULL) {
Ground.Log.Error("malloc failed in Ground.Bytecode.Instruction.execute");
Ground.Flags.error = true;
return CONTINUE;
}
} else {
free(function->closure->heap);
2026-07-03 19:06:40 +10:00
}
function->closure->capacity = heap->capacity;
function->closure->len = heap->len;
function->closure->heap = malloc(sizeof(GroundBytecodeValue) * heap->capacity);
2026-07-03 19:06:40 +10:00
if (function->closure->heap == NULL) {
2026-07-03 19:06:40 +10:00
Ground.Log.Error("malloc failed in Ground.Bytecode.Instruction.execute");
Ground.Flags.error = true;
return CONTINUE;
2026-07-04 13:27:50 +10:00
} else {
// forget all values in previous closure
for (GroundSize i = 0; i < function->closure->len; i++) {
Ground.Free.BytecodeValue(&function->closure->heap[i]);
}
2026-07-03 19:06:40 +10:00
}
for (GroundSize i = 0; i < heap->len; i++) {
function->closure->heap[i] = Ground.Copy.BytecodeValue(&heap->heap[i]);
2026-07-03 19:06:40 +10:00
}
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
RETURN: {
return RETURN( *HEAP_GET(heap, instruction->args.at[0]) );
2026-06-21 14:35:48 +10:00
}
ENDFUN: {
2026-06-24 10:17:58 +10:00
// no-op
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
CALL: {
// 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, instruction->args.at[i + 1]));
}
// function arguments are the first indexes, copy closure after
for (GroundSize i = function->args.count; i < newHeap.len; i++) {
newHeap.heap[i] = Ground.Copy.BytecodeValue(&function->closure->heap[i - function->args.count]);
}
// 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);
2026-07-04 13:27:50 +10:00
// Clean up the new heap
for (GroundSize i = 0; i < newHeap.len; i++) {
Ground.Free.BytecodeValue(&newHeap.heap[i]);
}
free(newHeap.heap);
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
CALLMETHOD: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
STRUCT: {
2026-06-24 10:17:58 +10:00
// no-op
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
ENDSTRUCT: {
2026-06-24 10:17:58 +10:00
// no-op
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
INIT: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
GETFIELD: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
SETFIELD: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
USE: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
EXTERN: {
// extern "libfile.so" "symbolName" !fnName -returnType -argType...
void* handle = Ground.FFI.openSharedObject(HEAP_GET(heap, instruction->args.at[0])->as.String.cstr);
if (Ground.Flags.error) {
return CONTINUE;
}
void* function = Ground.FFI.getFunction(handle, HEAP_GET(heap, instruction->args.at[0])->as.String.cstr);
if (Ground.Flags.error) {
return CONTINUE;
}
GroundSize argsSize = instruction->args.len - 4; // subtract 4 for libfile, symbol name, fn name, return type
GroundBytecodeFunction bf = {
.isNativeFunction = true,
.closure = NULL,
2026-07-04 19:50:52 +10:00
.program.native = function,
.args = {
.at = malloc(sizeof(GroundFunctionArg) * argsSize),
.capacity = argsSize,
.count = argsSize
},
2026-07-04 19:50:52 +10:00
.returnType = malloc(sizeof(GroundType))
};
2026-07-04 19:50:52 +10:00
if (bf.args.at == NULL || bf.returnType == NULL) {
Ground.Log.Error("malloc failed in Ground.Bytecode.Instruction.execute");
Ground.Flags.error = true;
return CONTINUE;
}
2026-07-04 19:50:52 +10:00
enum GroundTypeType returnTypeType = HEAP_GET(heap, instruction->args.at[3])->type.type;
switch (returnTypeType) {
case GroundType_Struct: {
bf.returnType->type = GroundType_Object;
// TODO implement structs
break;
}
case GroundType_CoreType: {
bf.returnType->type = HEAP_GET(heap, instruction->args.at[3])->as.CoreType;
break;
}
default: {
// should have been caught elsewhere, not really our problem
break;
}
}
for (size_t i = 0; i < argsSize; i++) {
enum GroundTypeType argTypeType = HEAP_GET(heap, instruction->args.at[i + 4])->as.CoreType;
switch (argTypeType) {
case GroundType_Struct: {
bf.args.at[i].as.type.type = GroundType_Object;
// TODO implement structs
break;
}
case GroundType_CoreType: {
bf.args.at[i].as.type.type = HEAP_GET(heap, instruction->args.at[3])->as.CoreType;
break;
}
default: {
// should have been caught elsewhere, not really our problem
break;
}
}
}
2026-07-04 19:50:52 +10:00
GroundBytecodeValue val = {
.type = {GroundType_Function},
.as.Function = bf
};
HEAP_SET(heap, instruction->args.at[3], val);
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
CREATELABEL: {
2026-06-24 10:17:58 +10:00
// no-op
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
PAUSE: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
DROP: {
2026-07-02 11:35:56 +10:00
GroundBytecodeValue* in = HEAP_GET(heap, instruction->args.at[0]);
Ground.Free.BytecodeValue(in);
*in = Ground.New.BytecodeValue(Ground.New.Value.Int(0));
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
LICENSE: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
ERRORCMD: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
THROW: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
CATCH: {
return CONTINUE;
2026-06-21 14:35:48 +10:00
}
Ground.Log.Error("operation fell through in Ground.Instruction.execute()");
Ground.Flags.error = true;
return CONTINUE;
2026-06-21 14:35:48 +10:00
}