diff --git a/.gitignore b/.gitignore index c6ef218..cddd0b3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ .idea - +main diff --git a/mx b/mx index b3f0eb9..8f1f4ba 100755 Binary files a/mx and b/mx differ diff --git a/src/main.cpp b/src/main.cpp index 802fcde..04bfbe4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,8 +20,8 @@ enum class keywords { ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, LESS, GREATER, EQLESS, EQGREATER, INCREMENT, DECREMENT, - PRINT, INPUT, EXIT, - VALUE, SEMICOLON + PRINT, LET, INPUT, EXIT, + VALUE, SEMICOLON, VARIABLE }; struct Value { @@ -134,7 +134,7 @@ class Logger { class SyntaxError { private: public: - void fnTypeMismatch(string function, vector validTypes, valtype typeGiven) { + void fnTypeMismatch(string function, vector validTypes, valtype typeGiven, string notes = "") { cout << "TypeError: function type mismatch" << endl; cout << "Function '" << function << "' expected one of the following types: "; for (int i = 0; i < validTypes.size(); i++) { @@ -148,6 +148,17 @@ class SyntaxError { else if (typeGiven == valtype::BOOL) cout << "bool"; else cout << "unknown"; 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; // Oh boy here we go 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 == "return") token.keyword = keywords::RETURN; else if (ct == "exit") token.keyword = keywords::EXIT; 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::CBRAC; else if (ct == "(") token.keyword = keywords::OPARE; @@ -314,6 +329,7 @@ class Parser { class Interpreter { private: vector tokens; + map variables; Logger log; int tokenIndex = -1; optional consume() { @@ -348,6 +364,22 @@ class Interpreter { consume(); // consume the peeked token 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(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 executeCode(currentInstruction); } @@ -375,10 +407,11 @@ class Interpreter { cout << (get(nextToken.value.value) ? "true" : "false") << endl; break; default: - log.error("Unsupported value type"); + vector validTypes = {"int", "dec", "str", "bool"}; + syntaxError.fnTypeMismatch("print", validTypes, nextToken.type); } } else { - log.error("Expected a value after print statement"); + syntaxError.fnNotSufficientArgs("print", 1, 1, 0); } } else if (tokens[i].keyword == keywords::EXIT) { i++; @@ -397,6 +430,61 @@ class Interpreter { 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 { + syntaxError.unknownFn(); } } } @@ -429,4 +517,4 @@ int main(int argc, char* argv[]) { // Convert to tokens and run the code interpreter.convertToTokens(parser.getTokens()); return 0; -} +} \ No newline at end of file diff --git a/test.mx b/test.mx index c8691f5..e01450c 100644 --- a/test.mx +++ b/test.mx @@ -1,2 +1,4 @@ -print "Hello world!"; -exit fjdskfdkls; +print "dingusify"; +let str bingus "heheheha its bingusing time"; +print bingus; +exit 0;