#include "../../../include/ground.h" #include "../../linenoise/linenoise.h" #include #include #include #include #include #define HEAP_GET(heap, idx) (&(heap)->heap[(idx)]) #define HEAP_SET(heap, idx, val) ((heap)->heap[(idx)] = (val)) static void printValue(GroundValue* val) { 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; default: printf(""); break; } } int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction, GroundBytecodeHeap* heap) { 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: { GroundValue* cond = HEAP_GET(heap, instruction->args.at[0]); if (cond->as.Bool) { return instruction->args.at[1]; } return -1; } JUMP: { return instruction->args.at[0]; } END: { return -2; } INPUT: { char* input = linenoise(""); HEAP_SET(heap, instruction->args.at[0], Ground.New.Value.String(Ground.New.String(input))); free(input); return -1; } PRINT: { for (GroundSize i = 0; i < instruction->args.len; i++) { printValue(HEAP_GET(heap, instruction->args.at[i])); } return -1; } PRINTLN: { for (GroundSize i = 0; i < instruction->args.len; i++) { printValue(HEAP_GET(heap, instruction->args.at[i])); } printf("\n"); return -1; } SET: { HEAP_SET(heap, instruction->args.at[0], *HEAP_GET(heap, instruction->args.at[1])); return -1; } GETTYPE: { Ground.Log.Warning("GETTYPE is deprecated"); return -1; } EXISTS: { Ground.Log.Warning("EXISTS is deprecated"); return -1; } SETLIST: { return -1; } SETLISTAT: { return -1; } GETLISTAT: { return -1; } GETLISTSIZE: { return -1; } LISTAPPEND: { return -1; } GETSTRSIZE: { return -1; } GETSTRCHARAT: { return -1; } ADD: { GroundValue* final = HEAP_GET(heap, instruction->args.at[2]); GroundValue* left = HEAP_GET(heap, instruction->args.at[0]); GroundValue* right = HEAP_GET(heap, instruction->args.at[1]); switch (left->type.type) { case GroundType_Int: { switch (right->type.type) { case GroundType_Int: { *final = Ground.New.Value.Int(left->as.Int + right->as.Int); break; } case GroundType_Double: { *final = Ground.New.Value.Double(left->as.Int + right->as.Double); 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: { *final = Ground.New.Value.Double(left->as.Double + right->as.Int); break; } case GroundType_Double: { *final = Ground.New.Value.Double(left->as.Double + right->as.Double); 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: { GroundSize total = left->as.String.len + right->as.String.len; char* buf = malloc(total + 1); 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); *final = Ground.New.Value.String(Ground.New.String(buf)); 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 -1; } SUBTRACT: { GroundValue* final = HEAP_GET(heap, instruction->args.at[2]); GroundValue* left = HEAP_GET(heap, instruction->args.at[0]); GroundValue* right = HEAP_GET(heap, instruction->args.at[1]); switch (left->type.type) { case GroundType_Int: { switch (right->type.type) { case GroundType_Int: { *final = Ground.New.Value.Int(left->as.Int - right->as.Int); break; } case GroundType_Double: { *final = Ground.New.Value.Double(left->as.Int - right->as.Double); 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: { *final = Ground.New.Value.Double(left->as.Double - right->as.Int); break; } case GroundType_Double: { *final = Ground.New.Value.Double(left->as.Double - right->as.Double); 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 -1; } MULTIPLY: { GroundValue* final = HEAP_GET(heap, instruction->args.at[2]); GroundValue* left = HEAP_GET(heap, instruction->args.at[0]); GroundValue* right = HEAP_GET(heap, instruction->args.at[1]); switch (left->type.type) { case GroundType_Int: { switch (right->type.type) { case GroundType_Int: { *final = Ground.New.Value.Int(left->as.Int * right->as.Int); break; } case GroundType_Double: { *final = Ground.New.Value.Double(left->as.Int * right->as.Double); 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: { *final = Ground.New.Value.Double(left->as.Double * right->as.Int); break; } case GroundType_Double: { *final = Ground.New.Value.Double(left->as.Double * right->as.Double); 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 -1; } DIVIDE: { GroundValue* final = HEAP_GET(heap, instruction->args.at[2]); GroundValue* left = HEAP_GET(heap, instruction->args.at[0]); GroundValue* right = HEAP_GET(heap, instruction->args.at[1]); switch (left->type.type) { case GroundType_Int: { switch (right->type.type) { case GroundType_Int: { *final = Ground.New.Value.Int(left->as.Int / right->as.Int); break; } case GroundType_Double: { *final = Ground.New.Value.Double(left->as.Int / right->as.Double); 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: { *final = Ground.New.Value.Double(left->as.Double / right->as.Int); break; } case GroundType_Double: { *final = Ground.New.Value.Double(left->as.Double / right->as.Double); 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 -1; } EQUAL: { GroundValue* final = HEAP_GET(heap, instruction->args.at[2]); GroundValue* left = HEAP_GET(heap, instruction->args.at[0]); GroundValue* right = HEAP_GET(heap, instruction->args.at[1]); switch (left->type.type) { case GroundType_Int: { switch (right->type.type) { case GroundType_Int: { *final = Ground.New.Value.Bool(left->as.Int == right->as.Int); break; } case GroundType_Double: { *final = Ground.New.Value.Bool(left->as.Int == right->as.Double); break; } default: { *final = Ground.New.Value.Bool(false); break; } } break; } case GroundType_Double: { switch (right->type.type) { case GroundType_Int: { *final = Ground.New.Value.Bool(left->as.Double == right->as.Int); break; } case GroundType_Double: { *final = Ground.New.Value.Bool(left->as.Double == right->as.Double); break; } default: { *final = Ground.New.Value.Bool(false); break; } } break; } case GroundType_Char: { if (right->type.type == GroundType_Char) { *final = Ground.New.Value.Bool(left->as.Char == right->as.Char); } else { *final = Ground.New.Value.Bool(false); } break; } case GroundType_Bool: { if (right->type.type == GroundType_Bool) { *final = Ground.New.Value.Bool(left->as.Bool == right->as.Bool); } else { *final = Ground.New.Value.Bool(false); } break; } case GroundType_String: { if (right->type.type == GroundType_String) { *final = Ground.New.Value.Bool(strcmp(left->as.String.cstr, right->as.String.cstr) == 0); } else { *final = Ground.New.Value.Bool(false); } break; } default: { *final = Ground.New.Value.Bool(false); break; } } return -1; } INEQUAL: { GroundValue* final = HEAP_GET(heap, instruction->args.at[2]); GroundValue* left = HEAP_GET(heap, instruction->args.at[0]); GroundValue* right = HEAP_GET(heap, instruction->args.at[1]); switch (left->type.type) { case GroundType_Int: { switch (right->type.type) { case GroundType_Int: { *final = Ground.New.Value.Bool(left->as.Int != right->as.Int); break; } case GroundType_Double: { *final = Ground.New.Value.Bool(left->as.Int != right->as.Double); break; } default: { *final = Ground.New.Value.Bool(true); break; } } break; } case GroundType_Double: { switch (right->type.type) { case GroundType_Int: { *final = Ground.New.Value.Bool(left->as.Double != right->as.Int); break; } case GroundType_Double: { *final = Ground.New.Value.Bool(left->as.Double != right->as.Double); break; } default: { *final = Ground.New.Value.Bool(true); break; } } break; } case GroundType_Char: { if (right->type.type == GroundType_Char) { *final = Ground.New.Value.Bool(left->as.Char != right->as.Char); } else { *final = Ground.New.Value.Bool(true); } break; } case GroundType_Bool: { if (right->type.type == GroundType_Bool) { *final = Ground.New.Value.Bool(left->as.Bool != right->as.Bool); } else { *final = Ground.New.Value.Bool(true); } break; } case GroundType_String: { if (right->type.type == GroundType_String) { *final = Ground.New.Value.Bool(strcmp(left->as.String.cstr, right->as.String.cstr) != 0); } else { *final = Ground.New.Value.Bool(true); } break; } default: { *final = Ground.New.Value.Bool(false); break; } } return -1; } NOT: { HEAP_SET(heap, instruction->args.at[1], Ground.New.Value.Bool(!HEAP_GET(heap, instruction->args.at[0])->as.Bool)); return -1; } GREATER: { GroundValue* final = HEAP_GET(heap, instruction->args.at[2]); GroundValue* left = HEAP_GET(heap, instruction->args.at[0]); GroundValue* right = HEAP_GET(heap, instruction->args.at[1]); switch (left->type.type) { case GroundType_Int: { switch (right->type.type) { case GroundType_Int: { *final = Ground.New.Value.Bool(left->as.Int > right->as.Int); break; } case GroundType_Double: { *final = Ground.New.Value.Bool(left->as.Int > right->as.Double); break; } default: { *final = Ground.New.Value.Bool(true); break; } } break; } case GroundType_Double: { switch (right->type.type) { case GroundType_Int: { *final = Ground.New.Value.Bool(left->as.Double > right->as.Int); break; } case GroundType_Double: { *final = Ground.New.Value.Bool(left->as.Double > right->as.Double); break; } default: { *final = Ground.New.Value.Bool(true); break; } } break; } default: { *final = Ground.New.Value.Bool(false); break; } } return -1; } LESSER: { GroundValue* final = HEAP_GET(heap, instruction->args.at[2]); GroundValue* left = HEAP_GET(heap, instruction->args.at[0]); GroundValue* right = HEAP_GET(heap, instruction->args.at[1]); switch (left->type.type) { case GroundType_Int: { switch (right->type.type) { case GroundType_Int: { *final = Ground.New.Value.Bool(left->as.Int < right->as.Int); break; } case GroundType_Double: { *final = Ground.New.Value.Bool(left->as.Int < right->as.Double); break; } default: { *final = Ground.New.Value.Bool(true); break; } } break; } case GroundType_Double: { switch (right->type.type) { case GroundType_Int: { *final = Ground.New.Value.Bool(left->as.Double < right->as.Int); break; } case GroundType_Double: { *final = Ground.New.Value.Bool(left->as.Double < right->as.Double); break; } default: { *final = Ground.New.Value.Bool(true); break; } } break; } default: { *final = Ground.New.Value.Bool(false); break; } } return -1; } AND: { GroundValue* final = HEAP_GET(heap, instruction->args.at[2]); GroundValue* left = HEAP_GET(heap, instruction->args.at[0]); GroundValue* right = HEAP_GET(heap, instruction->args.at[1]); *final = Ground.New.Value.Bool(left->as.Bool && right->as.Bool); return -1; } OR: { GroundValue* final = HEAP_GET(heap, instruction->args.at[2]); GroundValue* left = HEAP_GET(heap, instruction->args.at[0]); GroundValue* right = HEAP_GET(heap, instruction->args.at[1]); *final = Ground.New.Value.Bool(left->as.Bool || right->as.Bool); return -1; } XOR: { GroundValue* final = HEAP_GET(heap, instruction->args.at[2]); GroundValue* left = HEAP_GET(heap, instruction->args.at[0]); GroundValue* right = HEAP_GET(heap, instruction->args.at[1]); *final = Ground.New.Value.Bool(left->as.Bool != right->as.Bool); return -1; } NEG: { return -1; } SHIFT: { return -1; } STOI: { GroundValue* final = HEAP_GET(heap, instruction->args.at[1]); GroundValue* in = HEAP_GET(heap, instruction->args.at[0]); char* status = NULL; *final = Ground.New.Value.Int(strtoll(in->as.String.cstr, &status, 0)); if (status != in->as.String.cstr) { Ground.Flags.error = true; Ground.Log.Error("Failed converting string to double"); } return -1; } STOD: { GroundValue* final = HEAP_GET(heap, instruction->args.at[1]); GroundValue* in = HEAP_GET(heap, instruction->args.at[0]); char* status = NULL; *final = Ground.New.Value.Double(strtod(in->as.String.cstr, &status)); if (status != in->as.String.cstr) { Ground.Flags.error = true; Ground.Log.Error("Failed converting string to double"); } return -1; } ITOC: { GroundValue* final = HEAP_GET(heap, instruction->args.at[1]); GroundValue* in = HEAP_GET(heap, instruction->args.at[0]); *final = Ground.New.Value.Char((char)in->as.Int); return -1; } CTOI: { GroundValue* final = HEAP_GET(heap, instruction->args.at[1]); GroundValue* in = HEAP_GET(heap, instruction->args.at[0]); *final = Ground.New.Value.Int((int64_t)in->as.Char); return -1; } TOSTRING: { GroundValue* final = HEAP_GET(heap, instruction->args.at[1]); GroundValue* in = HEAP_GET(heap, instruction->args.at[0]); 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: { *in = Ground.New.Value.String(final->as.String); return -1; } default: { // TODO: implement tostring for complex types snprintf(buf, sizeof(buf), ""); break; } } *in = Ground.New.Value.String(Ground.New.String(buf)); return -1; } FUN: { // no-op return -1; } RETURN: { return -1; } ENDFUN: { // no-op return -1; } CALL: { return -1; } CALLMETHOD: { return -1; } STRUCT: { // no-op return -1; } ENDSTRUCT: { // no-op return -1; } INIT: { return -1; } GETFIELD: { return -1; } SETFIELD: { return -1; } USE: { return -1; } EXTERN: { return -1; } CREATELABEL: { // no-op return -1; } PAUSE: { return -1; } DROP: { GroundValue* in = HEAP_GET(heap, instruction->args.at[0]); Ground.Free.Value(in); *in = Ground.New.Value.Int(0); return -1; } LICENSE: { return -1; } ERRORCMD: { return -1; } THROW: { return -1; } CATCH: { return -1; } Ground.Log.Error("operation fell through in Ground.Instruction.execute()"); Ground.Flags.error = true; return -1; }