diff --git a/src/interpreter.c b/src/interpreter.c index 056f5f0..2e8c65a 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -136,6 +136,13 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) { 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); @@ -187,6 +194,13 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) { } 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); @@ -225,6 +239,14 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) { 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); @@ -242,7 +264,82 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) { 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); @@ -427,6 +524,10 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) { 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; @@ -453,6 +554,13 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) { } 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); @@ -583,6 +691,27 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) { } 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); @@ -695,27 +824,6 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) { } 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); - } } freeGroundInstruction(in); diff --git a/src/types.c b/src/types.c index 07d0987..d4fb35e 100644 --- a/src/types.c +++ b/src/types.c @@ -1,5 +1,6 @@ #include "types.h" #include +#include GroundValue createIntGroundValue(int64_t in) { GroundValue gv; @@ -309,3 +310,56 @@ void printGroundInstruction(GroundInstruction* gi) { printf(" "); } } + +List createList() { + List list; + list.size = 0; + list.values = malloc(sizeof(GroundValue)); + return list; +} + +void appendToList(List* list, GroundValue value) { + if (list == NULL) { + printf("Expecting a List ptr, got a null pointer instead.\nThis is likely not an error with your Ground program.\nPlease report this issue to https://chsp.au/ground/cground\n"); + exit(EXIT_FAILURE); + } + GroundValue* ptr = realloc(list, (list->size + 1) * sizeof(GroundValue)); + if (ptr == NULL) { + printf("There was an error allocating memory for a list.\nThis is likely not an error with your Ground program.\nPlease report this issue to https://chsp.au/ground/cground\n"); + exit(EXIT_FAILURE); + } + list->size++; + list->values = ptr; + list->values[list->size - 1] = value; +} + +ListAccess getListAt(List* list, int idx) { + if (list == NULL) { + printf("Expecting a List ptr, got a null pointer instead.\nThis is likely not an error with your Ground program.\nPlease report this issue to https://chsp.au/ground/cground\n"); + exit(EXIT_FAILURE); + } + if (idx < list->size) { + ListAccess retval; + retval.value = &list->values[idx]; + retval.status = LIST_OKAY; + return retval; + } else { + ListAccess retval; + retval.value = NULL; + retval.status = LIST_OUT_OF_BOUNDS; + return retval; + } +} + +ListAccessStatus setListAt(List* list, int idx, GroundValue value) { + if (list == NULL) { + printf("Expecting a List ptr, got a null pointer instead.\nThis is likely not an error with your Ground program.\nPlease report this issue to https://chsp.au/ground/cground\n"); + exit(EXIT_FAILURE); + } + if (idx < list->size) { + list->values[idx] = value; + return LIST_OKAY; + } else { + return LIST_OUT_OF_BOUNDS; + } +} diff --git a/src/types.h b/src/types.h index 6bfbad3..1e1b9b8 100644 --- a/src/types.h +++ b/src/types.h @@ -19,6 +19,10 @@ typedef enum GroundArgType { VALUE, VALREF, DIRREF, LINEREF, LABEL, FNREF, TYPEREF } GroundArgType; +typedef enum ListAccessStatus { + LIST_OKAY, LIST_OUT_OF_BOUNDS, LIST_FIXME +} ListAccessStatus; + struct GroundValue; struct List; @@ -43,14 +47,25 @@ typedef struct GroundValue { } GroundValue; /* - * Currently unused. Max, implement this sometime soon. + * Custom data type that stores Ground values. + * Associated functions: + * createList(), appendToList(), getListAt(), setListAt() */ typedef struct List { size_t size; - size_t capacity; GroundValue* values; } List; +/* + * Indicates status when accessing a list. + * Associated functions: + * getListAt() + */ +typedef struct ListAccess { + ListAccessStatus status; + GroundValue* value; +} ListAccess; + /* * Stores arguments for the GroundInstruction struct. * Associated functions: @@ -125,4 +140,17 @@ void addArgToInstruction(GroundInstruction* gi, GroundArg arg); // Prints out a GroundInstruction. void printGroundInstruction(GroundInstruction* gi); +// Creates a Ground list +List createList(); + +// Add item (value) to List (list) +void appendToList(List* list, GroundValue value); + +// Gets item at index (idx) from list (list). If there is an error, it +// will be indicated in the status field. +ListAccess getListAt(List* list, int idx); + +// Sets an item in list (list) at index (idx) to GroundValue (value). +ListAccessStatus setListAt(List* list, int idx, GroundValue value); + #endif