2026-06-21 14:35:48 +10:00
|
|
|
#include "../../../include/ground.h"
|
2026-07-06 14:17:22 +10:00
|
|
|
#ifndef _WIN32
|
2026-06-25 18:57:53 +10:00
|
|
|
#include "../../linenoise/linenoise.h"
|
2026-07-06 14:17:22 +10:00
|
|
|
#endif
|
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>
|
2026-07-05 07:51:15 +10:00
|
|
|
#include <ffi.h>
|
2026-06-21 16:39:05 +10:00
|
|
|
|
|
|
|
|
#define HEAP_GET(heap, idx) (&(heap)->heap[(idx)])
|
|
|
|
|
#define HEAP_SET(heap, idx, val) ((heap)->heap[(idx)] = (val))
|
|
|
|
|
|
2026-07-03 15:14:41 +10:00
|
|
|
#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-05 07:51:15 +10:00
|
|
|
static ffi_type* ffiTypeFromGroundType(GroundType* type) {
|
|
|
|
|
switch (type->type) {
|
|
|
|
|
case GroundType_Int: return &ffi_type_sint64;
|
|
|
|
|
case GroundType_Double: return &ffi_type_double;
|
|
|
|
|
case GroundType_Char: return &ffi_type_schar;
|
|
|
|
|
case GroundType_Bool: return &ffi_type_uint8;
|
|
|
|
|
case GroundType_String: return &ffi_type_pointer;
|
|
|
|
|
default: return &ffi_type_pointer; // FIXME implement stuff for everything else
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-03 15:14:41 +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) {
|
2026-07-03 15:14:41 +10:00
|
|
|
return JUMP(instruction->args.at[1]);
|
2026-06-21 16:13:00 +10:00
|
|
|
}
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
JUMP: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return JUMP(instruction->args.at[0]);
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
END: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return END( HEAP_GET(heap, instruction->args.at[0])->as.Int );
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
INPUT: {
|
2026-07-06 14:17:22 +10:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
// TODO implement line input on Windows
|
|
|
|
|
HEAP_SET(heap, instruction->args.at[0], Ground.New.BytecodeValue(Ground.New.Value.String(Ground.New.String(""))));
|
|
|
|
|
return CONTINUE;
|
|
|
|
|
#else
|
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);
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-07-06 14:17:22 +10:00
|
|
|
#endif
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
PRINT: {
|
|
|
|
|
for (GroundSize i = 0; i < instruction->args.len; i++) {
|
2026-07-08 12:06:18 +10:00
|
|
|
printf("%s ", Ground.Stringify.BytecodeValue(HEAP_GET(heap, instruction->args.at[i])));
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
PRINTLN: {
|
|
|
|
|
for (GroundSize i = 0; i < instruction->args.len; i++) {
|
2026-07-08 12:06:18 +10:00
|
|
|
printf("%s ", Ground.Stringify.BytecodeValue(HEAP_GET(heap, instruction->args.at[i])));
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
printf("\n");
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
SET: {
|
2026-07-04 19:59:00 +10:00
|
|
|
if (instruction->args.at[0] != instruction->args.at[1]) {
|
|
|
|
|
GroundBytecodeValue copy = Ground.Copy.BytecodeValue(HEAP_GET(heap, instruction->args.at[1]));
|
|
|
|
|
Ground.Free.BytecodeValue(&heap->heap[instruction->args.at[0]]);
|
|
|
|
|
HEAP_SET(heap, instruction->args.at[0], copy);
|
|
|
|
|
}
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
GETTYPE: {
|
|
|
|
|
Ground.Log.Warning("GETTYPE is deprecated");
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
EXISTS: {
|
|
|
|
|
Ground.Log.Warning("EXISTS is deprecated");
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
SETLIST: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
SETLISTAT: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
GETLISTAT: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
GETLISTSIZE: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
LISTAPPEND: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
GETSTRSIZE: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
GETSTRCHARAT: {
|
2026-07-03 15:14:41 +10:00
|
|
|
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-07-04 19:59:00 +10:00
|
|
|
free(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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-03 15:14:41 +10:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-03 15:14:41 +10:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-03 15:14:41 +10:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-03 15:14:41 +10:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-03 15:14:41 +10:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-03 15:14:41 +10:00
|
|
|
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)));
|
2026-07-03 15:14:41 +10:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-03 15:14:41 +10:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-03 15:14:41 +10:00
|
|
|
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
|
|
|
|
2026-07-03 15:14:41 +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
|
|
|
|
2026-07-03 15:14:41 +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
|
|
|
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
NEG: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
SHIFT: {
|
2026-07-03 15:14:41 +10:00
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-03 15:14:41 +10:00
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-03 15:14:41 +10:00
|
|
|
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
|
|
|
|
2026-07-03 15:14:41 +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
|
|
|
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
TOSTRING: {
|
2026-07-02 11:35:56 +10:00
|
|
|
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-03 15:14:41 +10:00
|
|
|
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
|
|
|
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
FUN: {
|
2026-07-03 15:14:41 +10:00
|
|
|
// 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;
|
|
|
|
|
}
|
2026-07-04 13:11:01 +10:00
|
|
|
} else {
|
|
|
|
|
free(function->closure->heap);
|
2026-07-03 19:06:40 +10:00
|
|
|
}
|
|
|
|
|
|
2026-07-04 13:11:01 +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
|
|
|
|
2026-07-04 13:11:01 +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++) {
|
2026-07-04 13:11:01 +10:00
|
|
|
function->closure->heap[i] = Ground.Copy.BytecodeValue(&heap->heap[i]);
|
2026-07-03 19:06:40 +10:00
|
|
|
}
|
2026-07-03 15:14:41 +10:00
|
|
|
|
|
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
RETURN: {
|
2026-07-03 15:14:41 +10:00
|
|
|
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
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
CALL: {
|
2026-07-03 15:14:41 +10:00
|
|
|
// call !function $value... &returnIdx
|
|
|
|
|
GroundBytecodeFunction* function = &HEAP_GET(heap, instruction->args.at[0])->as.Function;
|
|
|
|
|
|
|
|
|
|
if (function->isNativeFunction) {
|
2026-07-05 07:51:15 +10:00
|
|
|
|
|
|
|
|
// Ensure we have the right amount and types of arguments first
|
|
|
|
|
if (function->args.count != instruction->args.len - 2) {
|
|
|
|
|
Ground.Log.Error("incorrect amount of arguments for native function in Ground.Bytecode.Instruction.execute");
|
|
|
|
|
Ground.Flags.error = true;
|
|
|
|
|
return CONTINUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ffi_type* argTypes[function->args.count];
|
|
|
|
|
void* args[function->args.count];
|
|
|
|
|
|
|
|
|
|
for (GroundSize i = 0; i < function->args.count; i++) {
|
|
|
|
|
if (function->args.at[i].as.type.type != HEAP_GET(heap, instruction->args.at[i+1])->type.type) {
|
2026-07-05 08:07:50 +10:00
|
|
|
printf("%d != %d\n", function->args.at[i].as.type.type, HEAP_GET(heap, instruction->args.at[i+1])->type.type);
|
2026-07-05 07:51:15 +10:00
|
|
|
Ground.Log.Error("incorrect type of argument for native function in Ground.Bytecode.Instruction.execute");
|
|
|
|
|
Ground.Flags.error = true;
|
|
|
|
|
return CONTINUE;
|
|
|
|
|
}
|
|
|
|
|
argTypes[i] = ffiTypeFromGroundType(&function->args.at[i].as.type);
|
|
|
|
|
switch (HEAP_GET(heap, instruction->args.at[i+1])->type.type) {
|
|
|
|
|
case GroundType_Int: {
|
|
|
|
|
args[i] = &HEAP_GET(heap, instruction->args.at[i+1])->as.Int;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_Double: {
|
|
|
|
|
args[i] = &HEAP_GET(heap, instruction->args.at[i+1])->as.Double;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_Char: {
|
|
|
|
|
args[i] = &HEAP_GET(heap, instruction->args.at[i+1])->as.Char;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_Bool: {
|
|
|
|
|
args[i] = &HEAP_GET(heap, instruction->args.at[i+1])->as.Bool;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_String: {
|
|
|
|
|
args[i] = &HEAP_GET(heap, instruction->args.at[i+1])->as.String.cstr;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
// FIXME implement non-basic types
|
|
|
|
|
args[i] = HEAP_GET(heap, instruction->args.at[i+1]);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ffi_cif cif;
|
|
|
|
|
ffi_status status = ffi_prep_cif(
|
|
|
|
|
&cif, FFI_DEFAULT_ABI, function->args.count, ffiTypeFromGroundType(function->returnType), argTypes
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (status != FFI_OK) {
|
|
|
|
|
Ground.Log.Error("ffi CIF preperation failed in Ground.Bytecode.Instruction.execute");
|
|
|
|
|
Ground.Flags.error = true;
|
|
|
|
|
return CONTINUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
union {
|
|
|
|
|
GroundInt Int;
|
|
|
|
|
GroundDouble Double;
|
|
|
|
|
GroundChar Char;
|
|
|
|
|
GroundBool Bool;
|
|
|
|
|
char* String;
|
|
|
|
|
// TODO more stuff
|
|
|
|
|
} result;
|
|
|
|
|
|
|
|
|
|
ffi_call(&cif, function->program.native, &result, args);
|
|
|
|
|
|
|
|
|
|
// Put return value into the scope
|
|
|
|
|
switch (function->returnType->type) {
|
|
|
|
|
case GroundType_Int: {
|
|
|
|
|
HEAP_SET(heap, instruction->args.at[instruction->args.len - 1], Ground.New.BytecodeValue(Ground.New.Value.Int(result.Int)));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_Char: {
|
|
|
|
|
HEAP_SET(heap, instruction->args.at[instruction->args.len - 1], Ground.New.BytecodeValue(Ground.New.Value.Char(result.Char)));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_Double: {
|
|
|
|
|
HEAP_SET(heap, instruction->args.at[instruction->args.len - 1], Ground.New.BytecodeValue(Ground.New.Value.Double(result.Double)));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_Bool: {
|
|
|
|
|
HEAP_SET(heap, instruction->args.at[instruction->args.len - 1], Ground.New.BytecodeValue(Ground.New.Value.Bool(result.Bool)));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_String: {
|
|
|
|
|
HEAP_SET(heap, instruction->args.at[instruction->args.len - 1], Ground.New.BytecodeValue(Ground.New.Value.String(Ground.New.String(result.String))));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: break; // TODO more types
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-03 15:14:41 +10:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-04 13:11:01 +10:00
|
|
|
// load function arguments into the heap
|
2026-07-03 15:14:41 +10:00
|
|
|
for (GroundSize i = 0; i < function->args.count; i++) {
|
2026-07-04 13:11:01 +10:00
|
|
|
newHeap.heap[i] = Ground.Copy.BytecodeValue(HEAP_GET(heap, instruction->args.at[i + 1]));
|
2026-07-03 15:14:41 +10:00
|
|
|
}
|
|
|
|
|
|
2026-07-04 13:11:01 +10:00
|
|
|
// function arguments are the first indexes, copy closure after
|
2026-07-03 15:14:41 +10:00
|
|
|
for (GroundSize i = function->args.count; i < newHeap.len; i++) {
|
2026-07-04 13:11:01 +10:00
|
|
|
newHeap.heap[i] = Ground.Copy.BytecodeValue(&function->closure->heap[i - function->args.count]);
|
2026-07-03 15:14:41 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now we run the thingy
|
|
|
|
|
GroundBytecodeValue result = Ground.Bytecode.Program.execute(function->program.ground, &newHeap);
|
|
|
|
|
|
2026-07-04 19:59:00 +10:00
|
|
|
// Deep copy the result before freeing the function's heap
|
|
|
|
|
GroundBytecodeValue resultCopy = Ground.Copy.BytecodeValue(&result);
|
2026-07-03 15:14:41 +10:00
|
|
|
|
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);
|
|
|
|
|
|
2026-07-04 19:59:00 +10:00
|
|
|
// And store the result
|
|
|
|
|
HEAP_SET(heap, instruction->args.at[instruction->args.len - 1], resultCopy);
|
|
|
|
|
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
CALLMETHOD: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
STRUCT: {
|
2026-07-06 14:17:22 +10:00
|
|
|
GroundBytecodeStruct* gbs = &HEAP_GET(heap, instruction->args.at[0])->as.Struct;
|
|
|
|
|
// struct &structName &field OP $value &field OP $value &field OP $value...
|
|
|
|
|
// where:
|
|
|
|
|
// &field is the field to initialise
|
|
|
|
|
// OP is a numeric identifier:
|
|
|
|
|
// 0 -> none
|
|
|
|
|
// 1 -> init
|
|
|
|
|
// 2 -> set
|
|
|
|
|
// 3 -> attach closure to function
|
|
|
|
|
// $value is either a type reference (OP=0), a value reference (OP=1), or none (OP=2)
|
|
|
|
|
for (GroundSize i = 1; i < instruction->args.len; i++) {
|
|
|
|
|
GroundSize offset = instruction->args.at[i];
|
|
|
|
|
i++;
|
2026-07-08 12:06:18 +10:00
|
|
|
GroundSize op = instruction->args.at[i];
|
|
|
|
|
switch (op) {
|
2026-07-06 14:17:22 +10:00
|
|
|
case 0: break;
|
|
|
|
|
case 1: {
|
|
|
|
|
i++;
|
|
|
|
|
GroundBytecodeValue* type = HEAP_GET(heap, instruction->args.at[i]);
|
|
|
|
|
switch (type->type.type) {
|
|
|
|
|
case GroundType_Struct: {
|
|
|
|
|
// TODO nested structs
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_CoreType: {
|
|
|
|
|
switch (type->as.CoreType) {
|
|
|
|
|
case GroundType_Int: {
|
|
|
|
|
gbs->values[offset] = Ground.New.BytecodeValue(Ground.New.Value.Int(0));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_Double: {
|
|
|
|
|
gbs->values[offset] = Ground.New.BytecodeValue(Ground.New.Value.Double(0.0));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_String: {
|
|
|
|
|
gbs->values[offset] = Ground.New.BytecodeValue(Ground.New.Value.String(Ground.New.String("")));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_Char: {
|
|
|
|
|
gbs->values[offset] = Ground.New.BytecodeValue(Ground.New.Value.Char(0));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_Bool: {
|
|
|
|
|
gbs->values[offset] = Ground.New.BytecodeValue(Ground.New.Value.Bool(false));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: break; // TODO implement all the other stuff
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 2: {
|
|
|
|
|
i++;
|
|
|
|
|
gbs->values[offset] = Ground.Copy.BytecodeValue(HEAP_GET(heap, instruction->args.at[i]));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 3: {
|
|
|
|
|
GroundBytecodeFunction* function = &gbs->values[offset].as.Function;
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function->closure->capacity = heap->capacity;
|
|
|
|
|
function->closure->len = heap->len;
|
|
|
|
|
function->closure->heap = malloc(sizeof(GroundBytecodeValue) * heap->capacity);
|
|
|
|
|
|
|
|
|
|
if (function->closure->heap == NULL) {
|
|
|
|
|
Ground.Log.Error("malloc failed in Ground.Bytecode.Instruction.execute");
|
|
|
|
|
Ground.Flags.error = true;
|
|
|
|
|
return CONTINUE;
|
|
|
|
|
} else {
|
|
|
|
|
// forget all values in previous closure
|
|
|
|
|
for (GroundSize i = 0; i < function->closure->len; i++) {
|
|
|
|
|
Ground.Free.BytecodeValue(&function->closure->heap[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (GroundSize i = 0; i < heap->len; i++) {
|
|
|
|
|
function->closure->heap[i] = Ground.Copy.BytecodeValue(&heap->heap[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
ENDSTRUCT: {
|
2026-06-24 10:17:58 +10:00
|
|
|
// no-op
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
INIT: {
|
2026-07-06 14:17:22 +10:00
|
|
|
GroundBytecodeValue* type = HEAP_GET(heap, instruction->args.at[1]);
|
|
|
|
|
switch (type->type.type) {
|
|
|
|
|
case GroundType_Struct: {
|
2026-07-08 12:06:18 +10:00
|
|
|
// copy the contents of the struct into the object
|
|
|
|
|
GroundBytecodeObject object = {
|
|
|
|
|
.size = type->as.Struct.size,
|
|
|
|
|
.capacity = type->as.Struct.size,
|
|
|
|
|
.values = malloc(sizeof(GroundBytecodeValue) * type->as.Struct.size)
|
|
|
|
|
};
|
|
|
|
|
for (GroundSize i = 0; i < type->as.Struct.size; i++) {
|
|
|
|
|
object.values[i] = Ground.Copy.BytecodeValue(&type->as.Struct.values[i]);
|
|
|
|
|
}
|
|
|
|
|
HEAP_SET(heap, instruction->args.at[0], ((GroundBytecodeValue) {.as.Object = object, .type = {GroundType_Object}}));
|
2026-07-06 14:17:22 +10:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_CoreType: {
|
|
|
|
|
switch (type->as.CoreType) {
|
|
|
|
|
case GroundType_Int: {
|
|
|
|
|
HEAP_SET(heap, instruction->args.at[0], Ground.New.BytecodeValue(Ground.New.Value.Int(0)));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_Double: {
|
|
|
|
|
HEAP_SET(heap, instruction->args.at[0], Ground.New.BytecodeValue(Ground.New.Value.Double(0.0)));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_String: {
|
|
|
|
|
HEAP_SET(heap, instruction->args.at[0], Ground.New.BytecodeValue(Ground.New.Value.String(Ground.New.String(""))));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_Char: {
|
|
|
|
|
HEAP_SET(heap, instruction->args.at[0], Ground.New.BytecodeValue(Ground.New.Value.Char(0)));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_Bool: {
|
|
|
|
|
HEAP_SET(heap, instruction->args.at[0], Ground.New.BytecodeValue(Ground.New.Value.Bool(false)));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: break; // TODO implement all the other stuff
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-08 12:06:18 +10:00
|
|
|
default: break; // should not be reached
|
2026-07-06 14:17:22 +10:00
|
|
|
}
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
GETFIELD: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
SETFIELD: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
USE: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
EXTERN: {
|
2026-07-04 17:53:14 +10:00
|
|
|
// 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;
|
|
|
|
|
}
|
2026-07-05 07:51:15 +10:00
|
|
|
void* function = Ground.FFI.getFunction(handle, HEAP_GET(heap, instruction->args.at[1])->as.String.cstr);
|
2026-07-04 17:53:14 +10:00
|
|
|
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,
|
2026-07-04 17:53:14 +10:00
|
|
|
.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 17:53:14 +10:00
|
|
|
};
|
2026-07-04 19:50:52 +10:00
|
|
|
if (bf.args.at == NULL || bf.returnType == NULL) {
|
2026-07-04 17:53:14 +10:00
|
|
|
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++) {
|
2026-07-05 08:07:50 +10:00
|
|
|
GroundBytecodeValue* argTypeVal = HEAP_GET(heap, instruction->args.at[i + 4]);
|
|
|
|
|
switch (argTypeVal->type.type) {
|
2026-07-04 19:50:52 +10:00
|
|
|
case GroundType_Struct: {
|
|
|
|
|
bf.args.at[i].as.type.type = GroundType_Object;
|
|
|
|
|
// TODO implement structs
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GroundType_CoreType: {
|
2026-07-05 08:07:50 +10:00
|
|
|
bf.args.at[i].as.type.type = argTypeVal->as.CoreType;
|
2026-07-04 19:50:52 +10:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
// should have been caught elsewhere, not really our problem
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-04 17:53:14 +10:00
|
|
|
}
|
2026-07-04 19:50:52 +10:00
|
|
|
|
|
|
|
|
GroundBytecodeValue val = {
|
|
|
|
|
.type = {GroundType_Function},
|
|
|
|
|
.as.Function = bf
|
|
|
|
|
};
|
|
|
|
|
|
2026-07-05 07:51:15 +10:00
|
|
|
HEAP_SET(heap, instruction->args.at[2], val);
|
2026-07-04 19:50:52 +10:00
|
|
|
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
CREATELABEL: {
|
2026-06-24 10:17:58 +10:00
|
|
|
// no-op
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
PAUSE: {
|
2026-07-03 15:14:41 +10:00
|
|
|
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));
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
LICENSE: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
ERRORCMD: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
THROW: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
CATCH: {
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ground.Log.Error("operation fell through in Ground.Instruction.execute()");
|
|
|
|
|
Ground.Flags.error = true;
|
|
|
|
|
|
2026-07-03 15:14:41 +10:00
|
|
|
return CONTINUE;
|
2026-06-21 14:35:48 +10:00
|
|
|
}
|