diff --git a/mx b/mx index ccb8071..04f2300 100755 Binary files a/mx and b/mx differ diff --git a/src/Interpreter.cpp b/src/Interpreter.cpp index 371f825..0870949 100644 --- a/src/Interpreter.cpp +++ b/src/Interpreter.cpp @@ -26,7 +26,7 @@ void Interpreter::convertToTokens(vector tokenList) { // Collect tokens until semicolon while (auto nextToken = peek(1)) { - if (nextToken->keyword == keywords::SEMICOLON) { + if (nextToken->keyword == keywords::SEMICOLON || nextToken->keyword == keywords::OBRAC || nextToken->keyword == keywords::CBRAC) { consume(); // consume the semicolon break; } @@ -123,21 +123,31 @@ void Interpreter::convertToTokens(vector tokenList) { newToken.type = valtype::BOOL; newToken.value.type = valtype::BOOL; if (currentInstruction.size() < i + 1) syntaxError.mathTooFewArgs(); - if (currentInstruction[i - 1].value.type != currentInstruction[i + 1].value.type) syntaxError.mathTypeMismatch(); - log.debug("Comparing stuff"); - if (currentInstruction[i - 1].value.type == valtype::INT) { - if (get(currentInstruction[i - 1].value.value) == get(currentInstruction[i + 1].value.value)) newToken.value.value = true; - else newToken.value.value = false; - } else if (currentInstruction[i - 1].value.type == valtype::DEC) { - if (get(currentInstruction[i - 1].value.value) == get(currentInstruction[i + 1].value.value)) newToken.value.value = true; - else newToken.value.value = false; - } else if (currentInstruction[i - 1].value.type == valtype::STR) { - if (get(currentInstruction[i - 1].value.value) == get(currentInstruction[i + 1].value.value)) newToken.value.value = true; - else newToken.value.value = false; - } else if (currentInstruction[i - 1].value.type == valtype::BOOL) { - if (get(currentInstruction[i - 1].value.value) == get(currentInstruction[i + 1].value.value)) newToken.value.value = true; - else newToken.value.value = false; + if (currentInstruction[i - 1].type != currentInstruction[i + 1].type) syntaxError.mathTypeMismatch(); + log.debug("Comparing values of type: " + to_string(static_cast(currentInstruction[i - 1].type))); + + // Make sure both operands are values + if (currentInstruction[i - 1].keyword != keywords::VALUE || + currentInstruction[i + 1].keyword != keywords::VALUE) { + syntaxError.generalError("Can only compare values"); + return; } + + // Ensure value types are set correctly + if (currentInstruction[i - 1].value.type == valtype::INT) { + newToken.value.value = (get(currentInstruction[i - 1].value.value) == + get(currentInstruction[i + 1].value.value)); + } else if (currentInstruction[i - 1].value.type == valtype::DEC) { + newToken.value.value = (get(currentInstruction[i - 1].value.value) == + get(currentInstruction[i + 1].value.value)); + } else if (currentInstruction[i - 1].value.type == valtype::STR) { + newToken.value.value = (get(currentInstruction[i - 1].value.value) == + get(currentInstruction[i + 1].value.value)); + } else if (currentInstruction[i - 1].value.type == valtype::BOOL) { + newToken.value.value = (get(currentInstruction[i - 1].value.value) == + get(currentInstruction[i + 1].value.value)); + } + currentInstruction[i - 1] = newToken; currentInstruction.erase(currentInstruction.begin() + i); currentInstruction.erase(currentInstruction.begin() + i); @@ -153,6 +163,13 @@ void Interpreter::executeCode(vector tokens) { SyntaxError syntaxError; log.debug("Token length for this expression is " + to_string(tokens.size())); for (int i = 0; i < tokens.size(); i++) { + if (skipScope > 0) { + while (tokens[i].keyword != keywords::CBRAC) { + i++; + } + skipScope --; + return; + } if (tokens[i].keyword == keywords::PRINT) { i++; if (tokens.size() <= i) break; @@ -160,21 +177,21 @@ void Interpreter::executeCode(vector tokens) { // Handle different value types if (nextToken.keyword == keywords::VALUE) { switch (nextToken.type) { - case valtype::INT: - cout << get(nextToken.value.value) << endl; - break; - case valtype::DEC: - cout << get(nextToken.value.value) << endl; - break; - case valtype::STR: - cout << get(nextToken.value.value) << endl; - break; - case valtype::BOOL: - cout << (get(nextToken.value.value) ? "true" : "false") << endl; - break; - default: - vector validTypes = {"int", "dec", "str", "bool"}; - syntaxError.fnTypeMismatch("print", validTypes, nextToken.type); + case valtype::INT: + cout << get(nextToken.value.value) << endl; + break; + case valtype::DEC: + cout << get(nextToken.value.value) << endl; + break; + case valtype::STR: + cout << get(nextToken.value.value) << endl; + break; + case valtype::BOOL: + cout << (get(nextToken.value.value) ? "true" : "false") << endl; + break; + default: + vector validTypes = {"int", "dec", "str", "bool"}; + syntaxError.fnTypeMismatch("print", validTypes, nextToken.type); } } else { syntaxError.fnNotSufficientArgs("print", 1, 1, 0); @@ -185,15 +202,15 @@ void Interpreter::executeCode(vector tokens) { Token nextToken = tokens[i]; if (nextToken.keyword == keywords::VALUE) { switch (nextToken.type) { - case valtype::INT: - exit(get(nextToken.value.value)); - break; - case valtype::DEC: - exit(get(nextToken.value.value)); - break; - default: - vector validTypes = {"int", "dec"}; - syntaxError.fnTypeMismatch("exit", validTypes, nextToken.type); + case valtype::INT: + exit(get(nextToken.value.value)); + break; + case valtype::DEC: + exit(get(nextToken.value.value)); + break; + default: + vector validTypes = {"int", "dec"}; + syntaxError.fnTypeMismatch("exit", validTypes, nextToken.type); } } } else if (tokens[i].keyword == keywords::LET) { @@ -202,23 +219,23 @@ void Interpreter::executeCode(vector tokens) { syntaxError.fnNotSufficientArgs("let", 3, 3, tokens.size() - i); break; } - + Token typeToken = tokens[i]; Token nameToken = tokens[i + 1]; Token valueToken = tokens[i + 2]; i += 2; - + // Validate that we have a valid variable name if (nameToken.type != valtype::STR) { vector validTypes = {"str"}; syntaxError.fnTypeMismatch("let (variable name)", validTypes, nameToken.type); continue; } - + string varName = get(nameToken.value.value); Value newValue; - + // Check the type declaration matches the value if (typeToken.keyword == keywords::INT && valueToken.type == valtype::INT) { newValue.type = valtype::INT; @@ -245,9 +262,20 @@ void Interpreter::executeCode(vector tokens) { syntaxError.fnTypeMismatch("let", validTypes, valueToken.type, "Variable name is " + varName); continue; } - + // Store the variable variables[varName] = newValue; + } else if (tokens[i].keyword == keywords::IF) { + i++; + if (tokens.size() < i) syntaxError.fnNotSufficientArgs("if", 1, 1, 0); + log.debug("IF statement token type: " + to_string(static_cast(tokens[i].type))); + log.debug("IF statement token keyword: " + to_string(static_cast(tokens[i].keyword))); + if (tokens[i].keyword != keywords::VALUE) syntaxError.generalError("if needs a value, not a keyword"); + if (tokens[i].type != valtype::BOOL) syntaxError.comparisonTypeError("in an if statement"); + if (!get(tokens[i].value.value)) { + skipScope ++; + return; + } } else { if (tokens[i].keyword == keywords::VALUE && tokens[i].value.type == valtype::STR && variables.find(get(tokens[i].value.value)) != variables.end()) { log.debug("Manipulating variable..."); @@ -300,7 +328,7 @@ void Interpreter::executeCode(vector tokens) { syntaxError.mathCannotDoOperationOnType("unknown", "any"); } } else { - syntaxError.unknownFn(); + if (tokens[i].keyword != keywords::CBRAC) syntaxError.unknownFn(); } } } diff --git a/src/Interpreter.h b/src/Interpreter.h index fdc887a..843f8a2 100644 --- a/src/Interpreter.h +++ b/src/Interpreter.h @@ -6,6 +6,8 @@ class Interpreter { private: + int skipScope = 0; + int repeatScope = 0; SyntaxError syntaxError; vector tokens; map variables; diff --git a/src/Parser.cpp b/src/Parser.cpp index 68832c5..234daae 100644 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -107,6 +107,8 @@ void Parser::processLines() { else if (ct == "dec") token.keyword = keywords::DEC; else if (ct == "str") token.keyword = keywords::STR; else if (ct == "bool") token.keyword = keywords::BOOL; + else if (ct == "if") token.keyword = keywords::IF; + else if (ct == "while") token.keyword = keywords::WHILE; else if (ct == "{") token.keyword = keywords::OBRAC; else if (ct == "}") token.keyword = keywords::CBRAC; else if (ct == "(") token.keyword = keywords::OPARE; diff --git a/src/SyntaxError.cpp b/src/SyntaxError.cpp index 365ae3b..83030f2 100644 --- a/src/SyntaxError.cpp +++ b/src/SyntaxError.cpp @@ -55,4 +55,9 @@ void SyntaxError::generalError(string notes) { void SyntaxError::cannotCompareDifferentTypes(string notes) { cerr << "ComparisonError: cannot compare two different types" << endl; if (!notes.empty()) cerr << "Notes: " << notes << endl; + exit(1); +} +void SyntaxError::comparisonTypeError(string notes) { + cerr << "ComparisonError: cannot use a non-bool type in an if or while statement" << endl; + if (!notes.empty()) cerr << "Notes: " << notes << endl; } \ No newline at end of file diff --git a/src/SyntaxError.h b/src/SyntaxError.h index 8cc3341..135c7cd 100644 --- a/src/SyntaxError.h +++ b/src/SyntaxError.h @@ -11,5 +11,6 @@ public: void mathTooFewArgs(string notes = ""); void mathCannotDoOperationOnType(string operatorUsed, string type, string notes = ""); void cannotCompareDifferentTypes(string notes = ""); + void comparisonTypeError(string notes = ""); void generalError(string notes = ""); }; \ No newline at end of file