and now we have variables

This commit is contained in:
Maxwell Jeffress 2025-04-23 19:57:16 +10:00
parent da3d9a536b
commit 595aaca18e
4 changed files with 99 additions and 9 deletions

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
.idea .idea
main

BIN
mx

Binary file not shown.

View File

@ -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();
} }
} }
} }

View File

@ -1,2 +1,4 @@
print "Hello world!"; print "dingusify";
exit fjdskfdkls; let str bingus "heheheha its bingusing time";
print bingus;
exit 0;