diff --git a/scripts/small.toy b/scripts/small.toy index 1c8a0e7..fd40910 100644 --- a/scripts/small.toy +++ b/scripts/small.toy @@ -1 +1,4 @@ -; \ No newline at end of file + + + + diff --git a/source/interpreter.c b/source/interpreter.c index b191fd8..d62aa4c 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -310,7 +310,7 @@ static bool execVarDecl(Interpreter* interpreter, bool lng) { return false; } - if (!setScopeVariable(interpreter->scope, identifier, parseIdentifierToValue(interpreter, popLiteralArray(&interpreter->stack)) )) { + if (!setScopeVariable(interpreter->scope, identifier, parseIdentifierToValue(interpreter, popLiteralArray(&interpreter->stack)), false)) { printf("Incorrect type assigned to variable \""); printLiteral(identifier); printf("\"\n"); @@ -338,7 +338,7 @@ static bool execVarAssign(Interpreter* interpreter) { return false; } - if (!setScopeVariable(interpreter->scope, lhs, rhs)) { + if (!setScopeVariable(interpreter->scope, lhs, rhs, true)) { printf("Incorrect type assigned to variable \""); printLiteral(lhs); printf("\"\n"); diff --git a/source/scope.c b/source/scope.c index 90ccb46..65c11ce 100644 --- a/source/scope.c +++ b/source/scope.c @@ -21,6 +21,58 @@ static void freeAncestorChain(Scope* scope) { FREE(Scope, scope); } +//return false if invalid type +static bool checkType(Literal typeLiteral, Literal value) { + //for any types + if (AS_TYPE(typeLiteral).mask == MASK_ANY) { + return true; + } + + //for each type, if a mismatch is found, return false + if ((AS_TYPE(typeLiteral).mask & MASK_BOOLEAN) && !IS_BOOLEAN(value)) { + return false; + } + + if ((AS_TYPE(typeLiteral).mask & MASK_INTEGER) && !IS_INTEGER(value)) { + return false; + } + + if ((AS_TYPE(typeLiteral).mask & MASK_FLOAT) && !IS_FLOAT(value)) { + return false; + } + + if ((AS_TYPE(typeLiteral).mask & MASK_STRING) && !IS_STRING(value)) { + return false; + } + + if ((AS_TYPE(typeLiteral).mask & MASK_ARRAY) && IS_ARRAY(value)) { + //check children + for (int i = 0; i < AS_ARRAY(value)->count; i++) { + if (!checkType(((Literal*)(AS_TYPE(typeLiteral).subtypes))[0], AS_ARRAY(value)->literals[i])) { + return false; + } + } + } + + if ((AS_TYPE(typeLiteral).mask & MASK_DICTIONARY) && IS_DICTIONARY(value)) { + //check children + for (int i = 0; i < AS_DICTIONARY(value)->capacity; i++) { + //only assigned and non-tombstoned keys + if (!IS_NULL(AS_DICTIONARY(value)->entries[i].key)) { + if (checkType(((Literal*)(AS_TYPE(typeLiteral).subtypes))[0], AS_DICTIONARY(value)->entries[i].key)) { + return false; + } + + if (checkType(((Literal*)(AS_TYPE(typeLiteral).subtypes))[1], AS_DICTIONARY(value)->entries[i].value)) { + return false; + } + } + } + } + + return true; +} + //exposed functions Scope* pushScope(Scope* ancestor) { Scope* scope = ALLOCATE(Scope, 1); @@ -44,7 +96,7 @@ Scope* popScope(Scope* scope) { return ret; } -#include + //returns false if error bool declareScopeVariable(Scope* scope, Literal key, Literal type) { //don't redefine a variable within this scope @@ -64,19 +116,30 @@ bool isDelcaredScopeVariable(Scope* scope, Literal key) { } //return false if undefined, or can't be assigned -bool setScopeVariable(Scope* scope, Literal key, Literal value) { +bool setScopeVariable(Scope* scope, Literal key, Literal value, bool constCheck) { //dead end if (scope == NULL) { return false; } - //TODO: type checking - //if it's not in this scope, keep searching up the chain if (!existsLiteralDictionary(&scope->variables, key)) { - return setScopeVariable(scope->ancestor, key, value); + return setScopeVariable(scope->ancestor, key, value, constCheck); } + //type checking + Literal typeLiteral = getLiteralDictionary(&scope->types, key); + + if (!checkType(typeLiteral, value)) { + return false; + } + + //const check + if (constCheck && (AS_TYPE(typeLiteral).mask & MASK_CONST)) { + return false; + } + + //actually assign setLiteralDictionary(&scope->variables, key, value); return true; } diff --git a/source/scope.h b/source/scope.h index 3d9bd65..dddb9b1 100644 --- a/source/scope.h +++ b/source/scope.h @@ -1,5 +1,6 @@ #pragma once +#include "literal_array.h" #include "literal_dictionary.h" typedef struct Scope { @@ -17,6 +18,6 @@ bool declareScopeVariable(Scope* scope, Literal key, Literal type); bool isDelcaredScopeVariable(Scope* scope, Literal key); //return false if undefined -bool setScopeVariable(Scope* scope, Literal key, Literal value); +bool setScopeVariable(Scope* scope, Literal key, Literal value, bool constCheck); bool getScopeVariable(Scope* scope, Literal key, Literal* value);