and now we have variables
This commit is contained in:
parent
da3d9a536b
commit
595aaca18e
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,2 +1,2 @@
|
||||||
.idea
|
.idea
|
||||||
|
main
|
||||||
|
|
98
src/main.cpp
98
src/main.cpp
|
@ -20,8 +20,8 @@ enum class keywords {
|
||||||
ADD, SUBTRACT, MULTIPLY, DIVIDE,
|
ADD, SUBTRACT, MULTIPLY, DIVIDE,
|
||||||
EQUAL, INEQUAL, LESS, GREATER, EQLESS, EQGREATER,
|
EQUAL, INEQUAL, LESS, GREATER, EQLESS, EQGREATER,
|
||||||
INCREMENT, DECREMENT,
|
INCREMENT, DECREMENT,
|
||||||
PRINT, INPUT, EXIT,
|
PRINT, LET, INPUT, EXIT,
|
||||||
VALUE, SEMICOLON
|
VALUE, SEMICOLON, VARIABLE
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Value {
|
struct Value {
|
||||||
|
@ -134,7 +134,7 @@ class Logger {
|
||||||
class SyntaxError {
|
class SyntaxError {
|
||||||
private:
|
private:
|
||||||
public:
|
public:
|
||||||
void fnTypeMismatch(string function, vector<string> validTypes, valtype typeGiven) {
|
void fnTypeMismatch(string function, vector<string> validTypes, valtype typeGiven, string notes = "") {
|
||||||
cout << "TypeError: function type mismatch" << endl;
|
cout << "TypeError: function type mismatch" << endl;
|
||||||
cout << "Function '" << function << "' expected one of the following types: ";
|
cout << "Function '" << function << "' expected one of the following types: ";
|
||||||
for (int i = 0; i < validTypes.size(); i++) {
|
for (int i = 0; i < validTypes.size(); i++) {
|
||||||
|
@ -148,6 +148,17 @@ class SyntaxError {
|
||||||
else if (typeGiven == valtype::BOOL) cout << "bool";
|
else if (typeGiven == valtype::BOOL) cout << "bool";
|
||||||
else cout << "unknown";
|
else cout << "unknown";
|
||||||
cout << "' instead" << endl;
|
cout << "' instead" << endl;
|
||||||
|
if (!notes.empty()) cout << "Notes: " << notes << endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
void fnNotSufficientArgs(string function, int minArgs, int maxArgs, int argsGiven) {
|
||||||
|
cout << "TypeError: function not sufficient arguments" << endl;
|
||||||
|
cout << "Function '" << function << "' expected between " << minArgs << " and " << maxArgs << " arguments, got " << argsGiven << endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
void unknownFn() {
|
||||||
|
cout << "TypeError: unknown function" << endl;
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -257,10 +268,14 @@ class Parser {
|
||||||
if (ct == " ") continue;
|
if (ct == " ") continue;
|
||||||
// Oh boy here we go
|
// Oh boy here we go
|
||||||
else if (ct == "fun") token.keyword = keywords::FUN;
|
else if (ct == "fun") token.keyword = keywords::FUN;
|
||||||
|
else if (ct == "let") token.keyword = keywords::LET;
|
||||||
else if (ct == "print") token.keyword = keywords::PRINT;
|
else if (ct == "print") token.keyword = keywords::PRINT;
|
||||||
else if (ct == "return") token.keyword = keywords::RETURN;
|
else if (ct == "return") token.keyword = keywords::RETURN;
|
||||||
else if (ct == "exit") token.keyword = keywords::EXIT;
|
else if (ct == "exit") token.keyword = keywords::EXIT;
|
||||||
else if (ct == "int") token.keyword = keywords::INT;
|
else if (ct == "int") token.keyword = keywords::INT;
|
||||||
|
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 == "{") token.keyword = keywords::OBRAC;
|
else if (ct == "{") token.keyword = keywords::OBRAC;
|
||||||
else if (ct == "}") token.keyword = keywords::CBRAC;
|
else if (ct == "}") token.keyword = keywords::CBRAC;
|
||||||
else if (ct == "(") token.keyword = keywords::OPARE;
|
else if (ct == "(") token.keyword = keywords::OPARE;
|
||||||
|
@ -314,6 +329,7 @@ class Parser {
|
||||||
class Interpreter {
|
class Interpreter {
|
||||||
private:
|
private:
|
||||||
vector<Token> tokens;
|
vector<Token> tokens;
|
||||||
|
map<string, Value> variables;
|
||||||
Logger log;
|
Logger log;
|
||||||
int tokenIndex = -1;
|
int tokenIndex = -1;
|
||||||
optional<Token> consume() {
|
optional<Token> consume() {
|
||||||
|
@ -348,6 +364,22 @@ class Interpreter {
|
||||||
consume(); // consume the peeked token
|
consume(); // consume the peeked token
|
||||||
currentInstruction.push_back(nextToken.value());
|
currentInstruction.push_back(nextToken.value());
|
||||||
}
|
}
|
||||||
|
// Apply variables to tokens
|
||||||
|
for (int i = 0; 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Execute the instruction
|
// Execute the instruction
|
||||||
executeCode(currentInstruction);
|
executeCode(currentInstruction);
|
||||||
}
|
}
|
||||||
|
@ -375,10 +407,11 @@ class Interpreter {
|
||||||
cout << (get<bool>(nextToken.value.value) ? "true" : "false") << endl;
|
cout << (get<bool>(nextToken.value.value) ? "true" : "false") << endl;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log.error("Unsupported value type");
|
vector<string> validTypes = {"int", "dec", "str", "bool"};
|
||||||
|
syntaxError.fnTypeMismatch("print", validTypes, nextToken.type);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.error("Expected a value after print statement");
|
syntaxError.fnNotSufficientArgs("print", 1, 1, 0);
|
||||||
}
|
}
|
||||||
} else if (tokens[i].keyword == keywords::EXIT) {
|
} else if (tokens[i].keyword == keywords::EXIT) {
|
||||||
i++;
|
i++;
|
||||||
|
@ -397,6 +430,61 @@ class Interpreter {
|
||||||
syntaxError.fnTypeMismatch("exit", validTypes, nextToken.type);
|
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 {
|
||||||
|
syntaxError.unknownFn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user