#include "parser.h" #include "interpreter.h" #include "compiler.h" #include "types.h" #include #include GroundProgram groundCreateProgram() { return (GroundProgram) { .instructions = malloc(sizeof(GroundInstruction)), .size = 0 }; } void groundAddInstructionToProgram(GroundProgram* program, GroundInstruction instruction) { addInstructionToProgram(program, instruction); } GroundInstruction groundCreateInstruction(GroundInstType type) { return (GroundInstruction) { .type = type, .args.args = malloc(sizeof(GroundArg)), .args.length = 0 }; } void groundAddValueToInstruction(GroundInstruction* inst, GroundValue value) { addArgToInstruction(inst, createValueGroundArg(value)); } void groundAddReferenceToInstruction(GroundInstruction* inst, GroundArg value) { addArgToInstruction(inst, value); } GroundArg groundCreateReference(GroundArgType type, char* ref) { return (GroundArg) { .type = type, .value.refName = ref }; } GroundValue groundCreateValue(GroundValueType type, ...) { va_list args; va_start(args, type); GroundValue gv; switch (type) { case INT: { gv = createIntGroundValue(va_arg(args, int64_t)); break; } case DOUBLE: { gv = createDoubleGroundValue(va_arg(args, double)); break; } case STRING: { gv = createStringGroundValue(va_arg(args, char*)); break; } case CHAR: { gv = createCharGroundValue((char)va_arg(args, int)); break; } case BOOL: { gv = createBoolGroundValue((bool)va_arg(args, int)); break; } case LIST: { gv = createListGroundValue(va_arg(args, List)); break; } case FUNCTION: { gv = createFunctionGroundValue(va_arg(args, GroundFunction*)); break; } case STRUCTVAL: { gv.type = STRUCTVAL; gv.data.structVal = malloc(sizeof(GroundStruct)); *gv.data.structVal = va_arg(args, GroundStruct); break; } case NONE: { gv = createNoneGroundValue(); break; } case CUSTOM: { // CUSTOM values are created from structs GroundStruct* gstruct = va_arg(args, GroundStruct*); gv.type = CUSTOM; gv.data.customVal = malloc(sizeof(GroundObject)); *gv.data.customVal = createObject(*gstruct); // Deep copy the struct definition so it stays valid gv.customType = malloc(sizeof(GroundStruct)); gv.customType->size = gstruct->size; gv.customType->fields = malloc(gstruct->size * sizeof(GroundStructField)); for (size_t i = 0; i < gstruct->size; i++) { strncpy(gv.customType->fields[i].id, gstruct->fields[i].id, 64); gv.customType->fields[i].value = copyGroundValue(&gstruct->fields[i].value); } break; } case ERROR: { // FIXME gv = createNoneGroundValue(); break; } default: { gv = createNoneGroundValue(); break; } } va_end(args); return gv; } GroundValue groundRunProgram(GroundProgram* program) { GroundVariable* variables = NULL; GroundLabel* labels = NULL; GroundScope scope = { .variables = &variables, .labels = &labels, .isMainScope = true }; return interpretGroundProgram(program, &scope); } void groundPrintProgram(GroundProgram* program) { for (size_t i = 0; i < program->size; i++) { printGroundInstruction(&program->instructions[i]); printf("\n"); } } GroundProgram groundParseFile(const char* code) { return parseFile(code); } GroundStruct groundCreateStruct() { GroundStruct gs; gs.size = 0; gs.fields = malloc(sizeof(GroundStructField)); return gs; } void groundAddValueToScope(GroundScope* gs, const char* name, GroundValue value) { addVariable(gs->variables, name, value); } void groundAddFieldToStruct(GroundStruct* gstruct, char* name, GroundValue field) { addFieldToStruct(gstruct, name, field); } GroundFunction* createGroundFunction(); void addArgsToGroundFunction(GroundFunction* function, GroundValueType type, char* name); void groundAddFunctionToStruct(GroundStruct* gstruct, char* name, NativeGroundFunction fn, GroundValueType returnType, int argCount, ...) { GroundFunction* gf = createGroundFunction(); gf->isNative = true; gf->nativeFn = fn; gf->returnType = returnType; va_list args; va_start(args, argCount); for(int i = 0; i < argCount; i++) { GroundValueType type = va_arg(args, GroundValueType); char* argName = va_arg(args, char*); addArgsToGroundFunction(gf, type, argName); } va_end(args); GroundValue gv = createFunctionGroundValue(gf); addFieldToStruct(gstruct, name, gv); } void groundCompileProgram(GroundProgram* program) { #ifdef GROUND_COMPILE_WITH_TRAM compileGroundProgram(program, "program.gexe"); #else (void)program; printf("This version of Ground has been compiled without Tram, so compilation is not supported.\n"); #endif } GroundValue groundRunFunction(GroundFunction* function, size_t argc, ...) { va_list args; va_start(args, argc); if (function == NULL) { return createErrorGroundValue(createGroundError("Null function passed to groundRunFunction", "valueError", NULL, NULL)); } // Seems to crash some functions // GroundScope callScope = copyGroundScope(&function->closure); if (function->isNative) { List argsList = createList(); for (size_t i = 0; i < argc; i++) { appendToList(&argsList, va_arg(args, GroundValue)); } return function->nativeFn(NULL, argsList); } GroundScope callScope = { .labels = malloc(sizeof(GroundLabel*)), .variables = malloc(sizeof(GroundVariable*)), .isMainScope = false }; *callScope.variables = NULL; *callScope.labels = NULL; if (argc != function->argSize) { return createErrorGroundValue(createGroundError("Too few or too many arguments for function", "callError", NULL, NULL)); } for (size_t i = 0; i < argc; i++) { GroundValue gv = va_arg(args, GroundValue); if (checkFnTypes(&gv, &function->args[i]) == false) { return createErrorGroundValue(createGroundError("Mismatched argument type", "callError", NULL, NULL)); } addVariable(callScope.variables, function->args[i].name, gv); } va_end(args); return interpretGroundProgram(&function->program, &callScope); } GroundObjectField* groundFindField(GroundObject head, const char *id) { GroundObjectField* s; HASH_FIND_STR(head.fields, id, s); return s; } GroundVariable* groundFindVariable(GroundScope* gs, const char *id) { GroundVariable* var; HASH_FIND_STR(*gs->variables, id, var); return var; }