#include "Interpreter.h" optional Interpreter::consume() { tokenIndex++; if (tokenIndex < tokens.size()) return tokens[tokenIndex]; return {}; } optional Interpreter::peek(int offset) { int index = tokenIndex + offset; if (index >= 0 && index < tokens.size()) return tokens[index]; return {}; } void Interpreter::convertToTokens(vector tokenList) { if (debugMode) log.toggleDebugPrint(); tokens = tokenList; log.debug("Alright we got " + to_string(tokens.size()) + " tokens"); while (tokenIndex < static_cast(tokens.size() - 1)) { auto currentToken = consume(); if (!currentToken) break; vector currentInstruction; currentInstruction.push_back(currentToken.value()); // Collect tokens until semicolon while (auto nextToken = peek(1)) { if (nextToken->keyword == keywords::SEMICOLON) { consume(); // consume the semicolon break; } consume(); // consume the peeked token currentInstruction.push_back(nextToken.value()); } // Apply variables to tokens // We start at 1 so we can reassign variables in the execution of code for (int i = 1; i < currentInstruction.size(); i++) { if (currentInstruction[i].type == valtype::STR) { string potentialVarName = get(currentInstruction[i].value.value); auto varIt = variables.find(potentialVarName); if (varIt != variables.end()) { // Replace the token with the variable's value Token newToken; newToken.keyword = keywords::VALUE; newToken.type = varIt->second.type; newToken.value = varIt->second; currentInstruction[i] = newToken; } } } // Do math for (int i = 0; i < currentInstruction.size(); i++) { if (currentInstruction[i].keyword == keywords::ADD || currentInstruction[i].keyword == keywords::SUBTRACT || currentInstruction[i].keyword == keywords::MULTIPLY || currentInstruction[i].keyword == keywords::DIVIDE) { Token newToken; newToken.keyword = keywords::VALUE; if (currentInstruction.size() < i + 1) syntaxError.mathTooFewArgs(); Token before = currentInstruction[i - 1]; Token after = currentInstruction[i + 1]; if (before.type != after.type) syntaxError.mathTypeMismatch(); newToken.type = before.type; if (currentInstruction[i].keyword == keywords::ADD) { if (newToken.type == valtype::INT) { newToken.value.value = get(before.value.value) + get(after.value.value); } else if (newToken.type == valtype::DEC) { newToken.value.value = get(before.value.value) + get(after.value.value); } else if (newToken.type == valtype::STR) { newToken.value.value = get(before.value.value) + get(after.value.value); } else { syntaxError.mathCannotDoOperationOnType("+", "bool"); } } else if (currentInstruction[i].keyword == keywords::SUBTRACT) { if (newToken.type == valtype::INT) { newToken.value.value = get(before.value.value) - get(after.value.value); } else if (newToken.type == valtype::DEC) { newToken.value.value = get(before.value.value) - get(after.value.value); } else { syntaxError.mathCannotDoOperationOnType("-", "bool or string"); } } else if (currentInstruction[i].keyword == keywords::MULTIPLY) { if (newToken.type == valtype::INT) { newToken.value.value = get(before.value.value) * get(after.value.value); } else if (newToken.type == valtype::DEC) { newToken.value.value = get(before.value.value) * get(after.value.value); } else { syntaxError.mathCannotDoOperationOnType("*", "bool or string"); } } else if (currentInstruction[i].keyword == keywords::DIVIDE) { if (newToken.type == valtype::INT) { newToken.value.value = get(before.value.value) / get(after.value.value); } else if (newToken.type == valtype::DEC) { newToken.value.value = get(before.value.value) / get(after.value.value); } else { syntaxError.mathCannotDoOperationOnType("/", "bool or string"); } } else { // Something has gone terribly wrong // We should never reach this point in the code syntaxError.generalError("The math aint mathing"); } // Insert our cool new token and get rid of the boring old stuff currentInstruction[i - 1] = newToken; currentInstruction.erase(currentInstruction.begin() + i); currentInstruction.erase(currentInstruction.begin() + i); i -= 1; } } // Execute the instruction executeCode(currentInstruction); } } 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 (tokens[i].keyword == keywords::PRINT) { i++; if (tokens.size() <= i) break; Token nextToken = tokens[i]; // 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); } } else { syntaxError.fnNotSufficientArgs("print", 1, 1, 0); } } else if (tokens[i].keyword == keywords::EXIT) { i++; if (tokens.size() <= i) break; 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); } } } else if (tokens[i].keyword == keywords::LET) { i++; if (tokens.size() <= i + 2) { 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; newValue.value = get(valueToken.value.value); } else if (typeToken.keyword == keywords::DEC && valueToken.type == valtype::DEC) { newValue.type = valtype::DEC; newValue.value = get(valueToken.value.value); } else if (typeToken.keyword == keywords::STR && valueToken.type == valtype::STR) { newValue.type = valtype::STR; newValue.value = get(valueToken.value.value); } else if (typeToken.keyword == keywords::BOOL && valueToken.type == valtype::BOOL) { newValue.type = valtype::BOOL; newValue.value = get(valueToken.value.value); } else { vector validTypes; if (typeToken.keyword == keywords::INT) validTypes = {"int"}; else if (typeToken.keyword == keywords::DEC) validTypes = {"dec"}; else if (typeToken.keyword == keywords::STR) validTypes = {"str"}; else if (typeToken.keyword == keywords::BOOL) validTypes = {"bool"}; syntaxError.fnTypeMismatch("let", validTypes, valueToken.type, "Variable name is " + varName); continue; } // Store the variable variables[varName] = newValue; } 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..."); if (tokens.size() < i + 1) { syntaxError.mathTooFewArgs(); } string varName = get(tokens[i].value.value); i++; if (variables[varName].type == valtype::INT) { if (tokens[i].keyword == keywords::INCREMENT) { variables[varName].value = get(variables[varName].value) + 1; } else if (tokens[i].keyword == keywords::DECREMENT) { variables[varName].value = get(variables[varName].value) - 1; } else if (tokens[i].keyword == keywords::ADDTO) { if (tokens.size() < i + 1) syntaxError.mathTooFewArgs(); if (tokens[i + 1].value.type != valtype::INT) syntaxError.mathTypeMismatch("Expected an int when adding to an int"); variables[varName].value = get(variables[varName].value) + get(tokens[i + 1].value.value); } else if (tokens[i].keyword == keywords::SUBTRACTFROM) { if (tokens.size() < i + 1) syntaxError.mathTooFewArgs(); if (tokens[i + 1].value.type != valtype::INT) syntaxError.mathTypeMismatch("Expected an int when subtracting from an int"); variables[varName].value = get(variables[varName].value) - get(tokens[i + 1].value.value); } } else if (variables[varName].type == valtype::DEC) { if (tokens[i].keyword == keywords::INCREMENT) { variables[varName].value = get(variables[varName].value) + 1; } else if (tokens[i].keyword == keywords::DECREMENT) { variables[varName].value = get(variables[varName].value) - 1; } else if (tokens[i].keyword == keywords::ADDTO) { if (tokens.size() < i + 1) syntaxError.mathTooFewArgs(); if (tokens[i + 1].value.type != valtype::DEC) syntaxError.mathTypeMismatch("Expected an dec when adding to an dec"); variables[varName].value = get(variables[varName].value) + get(tokens[i + 1].value.value); } else if (tokens[i].keyword == keywords::SUBTRACTFROM) { if (tokens.size() < i + 1) syntaxError.mathTooFewArgs(); if (tokens[i + 1].value.type != valtype::DEC) syntaxError.mathTypeMismatch("Expected an dec when subtracting from an dec"); variables[varName].value = get(variables[varName].value) - get(tokens[i + 1].value.value); } } } else { syntaxError.unknownFn(); } } } }