#include "interpreter.h" #include "parser.h" #include "types.h" #include "include/uthash.h" #include #include int currentInstruction = 0; void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where, int whereLine) { printf("Ground runtime error:\n ErrorType: "); switch (error) { case ARG_TYPE_MISMATCH: { printf("ArgTypeMismatch"); break; } case TOO_FEW_ARGS: { printf("TooFewArgs"); break; } case TOO_MANY_ARGS: { printf("TooManyArgs"); break; } case UNKNOWN_LABEL: { printf("UnknownLabel"); break; } case UNKNOWN_VARIABLE: { printf("UnknownVariable"); break; } default: case FIXME: { printf("FIXME (please report issue to https://chsp.au/ground/cground)"); } } printf("\n"); if (what != NULL) { printf(" ErrorContext: %s\n", what); } if (where != NULL) { printf(" ErrorInstruction: "); printGroundInstruction(where); printf("\n"); } if (whereLine > -1) { printf(" ErrorLine: %d\n", whereLine + 1); } exit(1); } GroundLabel* findLabel(GroundLabel* head, const char *id) { GroundLabel *item; HASH_FIND_STR(head, id, item); return item; } void deleteLabel(GroundLabel** head, GroundLabel *item) { HASH_DEL(*head, item); free(item); } void addLabel(GroundLabel **head, const char *id, int data) { GroundLabel* label = findLabel(*head, id); if (label) { deleteLabel(head, label); } GroundLabel* item = malloc(sizeof(GroundLabel)); snprintf(item->id, MAX_ID_LEN, "%s", id); item->lineNum = data; HASH_ADD_STR(*head, id, item); } GroundVariable* findVariable(GroundVariable* head, const char *id) { GroundVariable *item; HASH_FIND_STR(head, id, item); return item; } void deleteVariable(GroundVariable** head, GroundVariable *item) { HASH_DEL(*head, item); free(item); } void addVariable(GroundVariable **head, const char *id, GroundValue data) { GroundVariable* variable = findVariable(*head, id); if (variable) { deleteVariable(head, variable); } GroundVariable* item = malloc(sizeof(GroundVariable)); snprintf(item->id, MAX_ID_LEN, "%s", id); item->value = data; HASH_ADD_STR(*head, id, item); } void interpretGroundProgram(GroundProgram* in) { GroundLabel* labels = NULL; GroundVariable* variables = NULL; GroundScope scope; scope.labels = &labels; scope.variables = &variables; // Preprocess all labels for (int i = 0; i < in->size; i++) { if (in->instructions[i].type == CREATELABEL) { addLabel(scope.labels, in->instructions[i].args.args[0].value.refName, i); } } while (currentInstruction < in->size) { interpretGroundInstruction(in->instructions[currentInstruction], &scope); currentInstruction++; } } void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) { GroundInstruction copied_inst = copyGroundInstruction(&inst); GroundInstruction* in = &copied_inst; // Insert variables prefixed with $ for (int i = 0; i < in->args.length; i++) { if (in->args.args[i].type == VALREF) { GroundVariable* variable = findVariable(*scope->variables, in->args.args[i].value.refName); if (variable) { free(in->args.args[i].value.refName); // Free the strdup'd refName in->args.args[i].value.value = variable->value; in->args.args[i].type = VALUE; } else { runtimeError(UNKNOWN_VARIABLE, NULL, in, currentInstruction); } } } switch (in->type) { // We can safely ignore any CREATELABEL instructions, these have been preprocessed case CREATELABEL: { break; } /* * CONTROL FLOW * These instructions are for controlling how the program is executed. * Instructions: * if, jump, end */ case IF: { if (in->args.length < 2) { runtimeError(TOO_FEW_ARGS, "Expecting 2 arguments", in, currentInstruction); } if (in->args.length > 2) { runtimeError(TOO_MANY_ARGS, "Expecting 2 arguments", in, currentInstruction); } if (in->args.args[0].type != VALUE || in->args.args[0].value.value.type != BOOL) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a bool for arg 0", in, currentInstruction); } if (in->args.args[1].type != LINEREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a LineRef for arg 1", in, currentInstruction); } if (in->args.args[0].value.value.data.boolVal) { GroundLabel* label = findLabel(*scope->labels, in->args.args[1].value.refName); if (label) { currentInstruction = label->lineNum; } else { runtimeError(UNKNOWN_LABEL, NULL, in, currentInstruction); } } break; } case JUMP: { if (in->args.length < 1) { runtimeError(TOO_FEW_ARGS, "Expecting 1 argument", in, currentInstruction); } if (in->args.length > 1) { runtimeError(TOO_MANY_ARGS, "Expecting 1 argument", in, currentInstruction); } if (in->args.args[0].type != LINEREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a LineRef for arg 1", in, currentInstruction); } GroundLabel* label = findLabel(*scope->labels, in->args.args[0].value.refName); if (label) { currentInstruction = label->lineNum; } else { runtimeError(UNKNOWN_LABEL, NULL, in, currentInstruction); } break; } case END: { if (in->args.length < 1 || in->args.args[0].type != VALUE || in->args.args[0].value.value.type != INT) { exit(0); } else { exit(in->args.args[0].value.value.data.intVal); } break; } /* * I/O * These instructions take information from the user, and print it out. * Instructions: * print, println, input */ case PRINT: { if (in->args.length < 1) { runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", in, currentInstruction); } for (int i = 0; i < in->args.length; i++) { if (i != 0) printf(" "); printGroundArg(&in->args.args[i]); } break; } case PRINTLN: { if (in->args.length < 1) { runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", in, currentInstruction); } for (int i = 0; i < in->args.length; i++) { if (i != 0) printf(" "); printGroundArg(&in->args.args[i]); } printf("\n"); break; } case INPUT: { if (in->args.length < 1) { runtimeError(TOO_FEW_ARGS, "Expecting 1 arg", in, currentInstruction); } if (in->args.args[0].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 1", in, currentInstruction); } char buffer[256]; if (fgets(buffer, sizeof(buffer), stdin) != NULL) { buffer[strcspn(buffer, "\n")] = '\0'; addVariable(scope->variables, in->args.args[0].value.refName, createStringGroundValue(buffer)); } else { runtimeError(FIXME, "Failed to read input from console with fgets", in, currentInstruction); } break; } /* * VARIABLES AND LISTS * These instructions are for initializing variables and lists. * Instructions: * set, gettype, exists * WIP Instructions: * setlist, setlistat, getlistat, getlistsize, listappend */ case SET: { if (in->args.length < 2) { runtimeError(TOO_FEW_ARGS, "Expecting 2 args", in, currentInstruction); } if (in->args.length > 2) { runtimeError(TOO_MANY_ARGS, "Expecting 2 args", in, currentInstruction); } if (in->args.args[0].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 1", in, currentInstruction); } if (in->args.args[1].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 2", in, currentInstruction); } addVariable(scope->variables, in->args.args[0].value.refName, in->args.args[1].value.value); break; } case GETTYPE: { if (in->args.length < 2) { runtimeError(TOO_FEW_ARGS, "Expecting 2 args", in, currentInstruction); } if (in->args.length > 2) { runtimeError(TOO_MANY_ARGS, "Expecting 2 args", in, currentInstruction); } if (in->args.args[0].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 1", in, currentInstruction); } if (in->args.args[1].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction); } switch (in->args.args[0].value.value.type) { case INT: { addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("int")); break; } case DOUBLE: { addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("double")); break; } case STRING: { addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("string")); break; } case CHAR: { addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("char")); break; } case BOOL: { addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("bool")); break; } case LIST: { addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("list")); break; } case CUSTOM: { addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("custom")); break; } } break; } case EXISTS: { if (in->args.length < 2) { runtimeError(TOO_FEW_ARGS, "Expecting 2 args", in, currentInstruction); } if (in->args.length > 2) { runtimeError(TOO_MANY_ARGS, "Expecting 2 args", in, currentInstruction); } if (in->args.args[0].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 1", in, currentInstruction); } if (in->args.args[0].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction); } if (findVariable(*scope->variables, in->args.args[0].value.refName)) { addVariable(scope->variables, in->args.args[1].value.refName, createBoolGroundValue(true)); } else { addVariable(scope->variables, in->args.args[1].value.refName, createBoolGroundValue(false)); } break; } /* * MATHS * These instructions allow running mathematical operations on values. * Instructions: * add, subtract, multiply, divide */ case ADD: { if (in->args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction); } if (in->args.length > 3) { runtimeError(TOO_MANY_ARGS, "Expecting 3 args", in, currentInstruction); } if (in->args.args[0].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 1", in, currentInstruction); } if (in->args.args[1].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 2", in, currentInstruction); } if (in->args.args[2].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", in, currentInstruction); } GroundValue* left = &in->args.args[0].value.value; GroundValue* right = &in->args.args[1].value.value; if (left->type == STRING) { if (right->type != STRING) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a String for arg 2", in, currentInstruction); } char* newString = malloc(strlen(left->data.stringVal) + strlen(right->data.stringVal)); strcpy(newString, left->data.stringVal); strcat(newString, right->data.stringVal); addVariable(scope->variables, in->args.args[2].value.refName, createStringGroundValue(newString)); } else if (left->type == INT || left->type == DOUBLE) { if (right->type != INT && right->type != DOUBLE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int or Double for arg 2", in, currentInstruction); } if (left->type == DOUBLE || right->type == DOUBLE) { double result = 0; if (left->type == INT) { result += left->data.intVal; } else if (left->type == DOUBLE) { result += left->data.doubleVal; } if (right->type == INT) { result += right->data.intVal; } else if (right->type == DOUBLE) { result += right->data.doubleVal; } addVariable(scope->variables, in->args.args[2].value.refName, createDoubleGroundValue(result)); } else { int64_t result = left->data.intVal + right->data.intVal; addVariable(scope->variables, in->args.args[2].value.refName, createIntGroundValue(result)); } } else { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int, Double, or String for arg 1", in, currentInstruction); } break; } case SUBTRACT: { if (in->args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction); } if (in->args.length > 3) { runtimeError(TOO_MANY_ARGS, "Expecting 3 args", in, currentInstruction); } if (in->args.args[0].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 1", in, currentInstruction); } if (in->args.args[1].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 2", in, currentInstruction); } if (in->args.args[2].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", in, currentInstruction); } GroundValue* left = &in->args.args[0].value.value; GroundValue* right = &in->args.args[1].value.value; if (left->type == INT || left->type == DOUBLE) { if (right->type != INT && right->type != DOUBLE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int or Double for arg 2", in, currentInstruction); } if (left->type == DOUBLE || right->type == DOUBLE) { double result = 0; if (left->type == INT) { result -= left->data.intVal; } else if (left->type == DOUBLE) { result -= left->data.doubleVal; } if (right->type == INT) { result += right->data.intVal; } else if (right->type == DOUBLE) { result += right->data.doubleVal; } addVariable(scope->variables, in->args.args[2].value.refName, createDoubleGroundValue(result)); } else { int64_t result = left->data.intVal - right->data.intVal; addVariable(scope->variables, in->args.args[2].value.refName, createIntGroundValue(result)); } } else { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int or Double for arg 1", in, currentInstruction); } break; } case MULTIPLY: { if (in->args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction); } if (in->args.length > 3) { runtimeError(TOO_MANY_ARGS, "Expecting 3 args", in, currentInstruction); } if (in->args.args[0].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 1", in, currentInstruction); } if (in->args.args[1].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 2", in, currentInstruction); } if (in->args.args[2].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", in, currentInstruction); } GroundValue* left = &in->args.args[0].value.value; GroundValue* right = &in->args.args[1].value.value; if (left->type == INT || left->type == DOUBLE) { if (right->type != INT && right->type != DOUBLE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int or Double for arg 2", in, currentInstruction); } if (left->type == DOUBLE || right->type == DOUBLE) { double result = 0; if (left->type == INT) { result *= left->data.intVal; } else if (left->type == DOUBLE) { result += left->data.doubleVal; } if (right->type == INT) { result *= right->data.intVal; } else if (right->type == DOUBLE) { result += right->data.doubleVal; } addVariable(scope->variables, in->args.args[2].value.refName, createDoubleGroundValue(result)); } else { int64_t result = left->data.intVal * right->data.intVal; addVariable(scope->variables, in->args.args[2].value.refName, createIntGroundValue(result)); } } else { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int or Double for arg 1", in, currentInstruction); } break; } case DIVIDE: { if (in->args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction); } if (in->args.length > 3) { runtimeError(TOO_MANY_ARGS, "Expecting 3 args", in, currentInstruction); } if (in->args.args[0].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 1", in, currentInstruction); } if (in->args.args[1].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 2", in, currentInstruction); } if (in->args.args[2].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", in, currentInstruction); } GroundValue* left = &in->args.args[0].value.value; GroundValue* right = &in->args.args[1].value.value; if (left->type == INT || left->type == DOUBLE) { if (right->type != INT && right->type != DOUBLE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int or Double for arg 2", in, currentInstruction); } if (right->type == INT && right->data.intVal == 0) { } if (left->type == DOUBLE || right->type == DOUBLE) { double result = 0; if (left->type == INT) { result /= left->data.intVal; } else if (left->type == DOUBLE) { result /= left->data.doubleVal; } if (right->type == INT) { result /= right->data.intVal; } else if (right->type == DOUBLE) { result /= right->data.doubleVal; } addVariable(scope->variables, in->args.args[2].value.refName, createDoubleGroundValue(result)); } else { int64_t result = left->data.intVal / right->data.intVal; addVariable(scope->variables, in->args.args[2].value.refName, createIntGroundValue(result)); } } else { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int or Double for arg 1", in, currentInstruction); } break; } /* * COMPARISONS * Allows comparing values. * Instructions: * equal, inequal, not, greater, lesser */ case EQUAL: { if (in->args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction); } if (in->args.length > 3) { runtimeError(TOO_MANY_ARGS, "Expecting 3 args", in, currentInstruction); } if (in->args.args[0].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 1", in, currentInstruction); } if (in->args.args[1].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 2", in, currentInstruction); } if (in->args.args[2].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", in, currentInstruction); } GroundValue* left = &in->args.args[0].value.value; GroundValue* right = &in->args.args[1].value.value; if (left->type != right->type) { if (left->type == INT && right->type == DOUBLE) { bool cond = (left->data.intVal == right->data.doubleVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); } else if (left->type == DOUBLE && right->type == INT) { bool cond = (left->data.doubleVal == right->data.intVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); } else { addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(false)); } } else { switch (left->type) { case INT: { bool cond = (left->data.intVal == right->data.intVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); break; } case DOUBLE: { bool cond = (left->data.doubleVal == right->data.doubleVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); break; } case STRING: { bool cond = (strcmp(left->data.stringVal, right->data.stringVal) == 0); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); break; } case CHAR: { bool cond = (left->data.charVal == right->data.charVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); break; } case BOOL: { bool cond = (left->data.boolVal == right->data.boolVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); break; } default: { addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(false)); break; } } } break; } case INEQUAL: { if (in->args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction); } if (in->args.length > 3) { runtimeError(TOO_MANY_ARGS, "Expecting 3 args", in, currentInstruction); } if (in->args.args[0].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 1", in, currentInstruction); } if (in->args.args[1].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 2", in, currentInstruction); } if (in->args.args[2].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", in, currentInstruction); } GroundValue* left = &in->args.args[0].value.value; GroundValue* right = &in->args.args[1].value.value; if (left->type != right->type) { if (left->type == INT && right->type == DOUBLE) { bool cond = (left->data.intVal != right->data.doubleVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); } else if (left->type == DOUBLE && right->type == INT) { bool cond = (left->data.doubleVal != right->data.intVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); } else { addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(false)); } } else { switch (left->type) { case INT: { bool cond = (left->data.intVal != right->data.intVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); break; } case DOUBLE: { bool cond = (left->data.doubleVal != right->data.doubleVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); break; } case STRING: { bool cond = (strcmp(left->data.stringVal, right->data.stringVal) != 0); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); break; } case CHAR: { bool cond = (left->data.charVal != right->data.charVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); break; } case BOOL: { bool cond = (left->data.boolVal != right->data.boolVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); break; } default: { addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(true)); break; } } } break; } case NOT: { if (in->args.length < 2) { runtimeError(TOO_FEW_ARGS, "Expecting 2 args", in, currentInstruction); } if (in->args.length > 2) { runtimeError(TOO_MANY_ARGS, "Expecting 2 args", in, currentInstruction); } if (in->args.args[0].type != VALUE && in->args.args[0].value.value.type != BOOL) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Bool for arg 1", in, currentInstruction); } if (in->args.args[1].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction); } bool condition = !in->args.args[1].value.value.data.boolVal; addVariable(scope->variables, in->args.args[1].value.refName, createBoolGroundValue(condition)); } default: { runtimeError(FIXME, "Currently unimplemented instruction", in, currentInstruction); } case GREATER: { if (in->args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction); } if (in->args.length > 3) { runtimeError(TOO_MANY_ARGS, "Expecting 3 args", in, currentInstruction); } if (in->args.args[0].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 1", in, currentInstruction); } if (in->args.args[1].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 2", in, currentInstruction); } if (in->args.args[2].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", in, currentInstruction); } GroundValue* left = &in->args.args[0].value.value; GroundValue* right = &in->args.args[1].value.value; if (left->type != INT && left->type != DOUBLE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int or Double for arg 1", in, currentInstruction); } else if (right->type != INT && right->type != DOUBLE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int or Double for arg 2", in, currentInstruction); } if (left->type != right->type) { if (left->type == INT && right->type == DOUBLE) { bool cond = (left->data.intVal > right->data.doubleVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); } else if (left->type == DOUBLE && right->type == INT) { bool cond = (left->data.doubleVal > right->data.intVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); } else { runtimeError(FIXME, "Uncaught invalid type", in, currentInstruction); } } else { switch (left->type) { case INT: { bool cond = (left->data.intVal > right->data.intVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); break; } case DOUBLE: { bool cond = (left->data.doubleVal > right->data.doubleVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); break; } default: { runtimeError(FIXME, "Uncaught invalid type", in, currentInstruction); break; } } } break; } case LESSER: { if (in->args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction); } if (in->args.length > 3) { runtimeError(TOO_MANY_ARGS, "Expecting 3 args", in, currentInstruction); } if (in->args.args[0].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 1", in, currentInstruction); } if (in->args.args[1].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 2", in, currentInstruction); } if (in->args.args[2].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", in, currentInstruction); } GroundValue* left = &in->args.args[0].value.value; GroundValue* right = &in->args.args[1].value.value; if (left->type != INT && left->type != DOUBLE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int or Double for arg 1", in, currentInstruction); } else if (right->type != INT && right->type != DOUBLE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int or Double for arg 2", in, currentInstruction); } if (left->type != right->type) { if (left->type == INT && right->type == DOUBLE) { bool cond = (left->data.intVal < right->data.doubleVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); } else if (left->type == DOUBLE && right->type == INT) { bool cond = (left->data.doubleVal < right->data.intVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); } else { runtimeError(FIXME, "Uncaught invalid type", in, currentInstruction); } } else { switch (left->type) { case INT: { bool cond = (left->data.intVal < right->data.intVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); break; } case DOUBLE: { bool cond = (left->data.doubleVal < right->data.doubleVal); addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); break; } default: { runtimeError(FIXME, "Uncaught invalid type", in, currentInstruction); break; } } } break; } } freeGroundInstruction(in); }