bogus/src/Interpreter.cpp

263 lines
13 KiB
C++

#include "Interpreter.h"
optional<Token> Interpreter::consume() {
tokenIndex++;
if (tokenIndex < tokens.size()) return tokens[tokenIndex];
return {};
}
optional<Token> Interpreter::peek(int offset) {
int index = tokenIndex + offset;
if (index >= 0 && index < tokens.size()) return tokens[index];
return {};
}
void Interpreter::convertToTokens(vector<Token> tokenList) {
if (debugMode) log.toggleDebugPrint();
tokens = tokenList;
log.debug("Alright we got " + to_string(tokens.size()) + " tokens");
while (tokenIndex < static_cast<int>(tokens.size() - 1)) {
auto currentToken = consume();
if (!currentToken) break;
vector<Token> 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<string>(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<int>(before.value.value) + get<int>(after.value.value);
}
else if (newToken.type == valtype::DEC) {
newToken.value.value = get<double>(before.value.value) + get<double>(after.value.value);
}
else if (newToken.type == valtype::STR) {
newToken.value.value = get<string>(before.value.value) + get<string>(after.value.value);
} else {
syntaxError.mathCannotDoOperationOnType("+", "bool");
}
}
else if (currentInstruction[i].keyword == keywords::SUBTRACT) {
if (newToken.type == valtype::INT) {
newToken.value.value = get<int>(before.value.value) - get<int>(after.value.value);
}
else if (newToken.type == valtype::DEC) {
newToken.value.value = get<double>(before.value.value) - get<double>(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<int>(before.value.value) * get<int>(after.value.value);
}
else if (newToken.type == valtype::DEC) {
newToken.value.value = get<double>(before.value.value) * get<double>(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<int>(before.value.value) / get<int>(after.value.value);
}
else if (newToken.type == valtype::DEC) {
newToken.value.value = get<double>(before.value.value) / get<double>(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<Token> 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<int>(nextToken.value.value) << endl;
break;
case valtype::DEC:
cout << get<double>(nextToken.value.value) << endl;
break;
case valtype::STR:
cout << get<string>(nextToken.value.value) << endl;
break;
case valtype::BOOL:
cout << (get<bool>(nextToken.value.value) ? "true" : "false") << endl;
break;
default:
vector<string> 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<int>(nextToken.value.value));
break;
case valtype::DEC:
exit(get<double>(nextToken.value.value));
break;
default:
vector<string> 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<string> validTypes = {"str"};
syntaxError.fnTypeMismatch("let (variable name)", validTypes, nameToken.type);
continue;
}
string varName = get<string>(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<int>(valueToken.value.value);
}
else if (typeToken.keyword == keywords::DEC && valueToken.type == valtype::DEC) {
newValue.type = valtype::DEC;
newValue.value = get<double>(valueToken.value.value);
}
else if (typeToken.keyword == keywords::STR && valueToken.type == valtype::STR) {
newValue.type = valtype::STR;
newValue.value = get<string>(valueToken.value.value);
}
else if (typeToken.keyword == keywords::BOOL && valueToken.type == valtype::BOOL) {
newValue.type = valtype::BOOL;
newValue.value = get<bool>(valueToken.value.value);
}
else {
vector<string> 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<string>(tokens[i].value.value)) != variables.end()) {
log.debug("Manipulating variable...");
if (tokens.size() < i + 1) {
syntaxError.mathTooFewArgs();
}
string varName = get<string>(tokens[i].value.value);
i++;
if (variables[varName].type == valtype::INT) {
if (tokens[i].keyword == keywords::INCREMENT) {
variables[varName].value = get<int>(variables[varName].value) + 1;
} else if (tokens[i].keyword == keywords::DECREMENT) {
variables[varName].value = get<int>(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<int>(variables[varName].value) + get<int>(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<int>(variables[varName].value) - get<int>(tokens[i + 1].value.value);
}
} else if (variables[varName].type == valtype::DEC) {
if (tokens[i].keyword == keywords::INCREMENT) {
variables[varName].value = get<double>(variables[varName].value) + 1;
} else if (tokens[i].keyword == keywords::DECREMENT) {
variables[varName].value = get<double>(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<double>(variables[varName].value) + get<double>(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<double>(variables[varName].value) - get<double>(tokens[i + 1].value.value);
}
}
} else {
syntaxError.unknownFn();
}
}
}
}