diff --git a/README.md b/README.md index 84b38c8..a9662ec 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![Iodine programming language logo](https://git.maxwellj.xyz/iodine/iodine/raw/commit/a782c09f913ecc38df7a84665f305e4ea89fb7d7/branding/Iodine_250px.png) +![Iodine programming language logo](https://chookspace.com/iodine/iodine/raw/branch/master/branding/Iodine_250px.png) # Iodine - a statically typed, interpreted language diff --git a/examples/args.io b/examples/args.io deleted file mode 100644 index c38f1b2..0000000 --- a/examples/args.io +++ /dev/null @@ -1 +0,0 @@ -println args; diff --git a/examples/list.io b/examples/list.io new file mode 100644 index 0000000..722e29e --- /dev/null +++ b/examples/list.io @@ -0,0 +1 @@ +printlist ["This is an element in the list" "And this is another" "Oh look another list element" "How fun!"]; diff --git a/src/Interpreter.cpp b/src/Interpreter.cpp index a318963..65929f0 100644 --- a/src/Interpreter.cpp +++ b/src/Interpreter.cpp @@ -249,6 +249,34 @@ void Interpreter::interpret(vector tokenList) { i -= 1; } } + // Find lists and create list objects + for (int i = 0; i < currentInstruction.size(); i++) { + if (currentInstruction[i].keyword == keywords::OSQUA) { + log.debug("Making a list"); + int startIndex = i; + currentInstruction.erase(currentInstruction.begin() + i); + List buf; + buf.type = currentInstruction[i].value.type; + while (currentInstruction[i].keyword != keywords::CSQUA) { + if (buf.type == currentInstruction[i].value.type) { + buf.value.push_back(currentInstruction[i].value); + currentInstruction.erase(currentInstruction.begin() + i); + } else { + syntaxError.listTypeMismatch(); + } + } + currentInstruction.erase(currentInstruction.begin() + i); + Value newValue; + newValue.type = valtype::LIST; + newValue.value = buf; + Token newToken; + newToken.type = valtype::LIST; + newToken.value.type = valtype::LIST; + newToken.value.value = buf; + newToken.keyword = keywords::LIST; + currentInstruction.insert(currentInstruction.begin() + startIndex, newToken); + } + } // Execute the instruction log.debug("Length of line is " + to_string(lengthOfLine)); executeCode(currentInstruction); @@ -285,7 +313,7 @@ void Interpreter::executeCode(vector tokens) { } if (tokens[i].keyword == keywords::PRINTLN) { i++; - if (tokens.size() <= i) break; + if (tokens.size() <= i) syntaxError.fnNotSufficientArgs("println", 1, 1, 0); Token nextToken = tokens[i]; // Handle different value types if (nextToken.keyword == keywords::VALUE) { @@ -307,7 +335,7 @@ void Interpreter::executeCode(vector tokens) { syntaxError.fnTypeMismatch("println", validTypes, nextToken.type); } } else { - syntaxError.fnNotSufficientArgs("println", 1, 1, 0); + syntaxError.fnTypeMismatch("println", {}, nextToken.type); } } else if (tokens[i].keyword == keywords::PRINT) { i++; @@ -335,6 +363,39 @@ void Interpreter::executeCode(vector tokens) { } else { syntaxError.fnNotSufficientArgs("print", 1, 1, 0); } + } else if (tokens[i].keyword == keywords::PRINTLIST) { + i++; + if (tokens.size() <= i) syntaxError.fnNotSufficientArgs("printlist", 1, 1, 0); + Token nextToken = tokens[i]; + log.debug("Printing a list. Type of next token is " + log.getTypeString(nextToken.value.type)); + if (nextToken.keyword == keywords::LIST && nextToken.type == valtype::LIST) { + List list = get(nextToken.value.value); + log.debug("List obtained"); + if (list.value[0].type == valtype::INT) { + for (int j = 0; j < list.value.size(); j++) { + cout << get(list.value[j].value) << ", "; + } + } + else if (list.value[0].type == valtype::DEC) { + for (int j = 0; j < list.value.size(); j++) { + cout << get(list.value[j].value) << ", "; + } + } + else if (list.value[0].type == valtype::STR) { + for (int j = 0; j < list.value.size(); j++) { + cout << get(list.value[j].value) << ", "; + } + } + else if (list.value[0].type == valtype::BOOL) { + for (int j = 0; j < list.value.size(); j++) { + cout << (get(list.value[j].value) ? "true" : "false") << ", "; + } + } + cout << endl; + } else { + syntaxError.fnTypeMismatch("printlist", {}, valtype::UNKNOWN); + } + break; } else if (tokens[i].keyword == keywords::EXIT) { i++; if (tokens.size() <= i) break; diff --git a/src/Logger.cpp b/src/Logger.cpp index 8e82785..84c55d2 100644 --- a/src/Logger.cpp +++ b/src/Logger.cpp @@ -52,3 +52,25 @@ void Logger::debug(string in) { if (isDebug) cout << "Debug: " + in + "\n"; writeToLog("Debug", in); } + +string Logger::getTypeString(valtype in) { + switch (in) { + case valtype::STR: + return "string"; + case valtype::INT: + return "int"; + case valtype::DEC: + return "dec"; + case valtype::BOOL: + return "bool"; + case valtype::LIST: + return "list"; + case valtype::KEYWORD: + return "keyword"; + case valtype::UNKNOWN: + return "unknown"; + default: + return "unknown"; + } + return "error"; +} diff --git a/src/Logger.h b/src/Logger.h index 6677f82..57ee35c 100644 --- a/src/Logger.h +++ b/src/Logger.h @@ -32,4 +32,5 @@ public: void fatalError(string in, int code); void info(string in); void debug(string in); + string getTypeString(valtype in); }; diff --git a/src/Parser.cpp b/src/Parser.cpp index db6490b..d1a496f 100644 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -72,7 +72,7 @@ void Parser::parseLines(string in, Logger log) { } terms.push_back(termBuffer); termBuffer.clear(); - } else if ((c == ',' || c == '{' || c == '}' || c == '(' || c == ')') && !isString) { + } else if ((c == ',' || c == '{' || c == '}' || c == '(' || c == ')' || c == '[' || c == ']') && !isString) { if (!buffer.empty()) { termBuffer.push_back(buffer); buffer.clear(); @@ -120,6 +120,7 @@ void Parser::processLines() { else if (ct == "let") token.keyword = keywords::LET; else if (ct == "print") token.keyword = keywords::PRINT; else if (ct == "println") token.keyword = keywords::PRINTLN; + else if (ct == "printlist") token.keyword = keywords::PRINTLIST; else if (ct == "input") token.keyword = keywords::INPUT; else if (ct == "return") token.keyword = keywords::RETURN; else if (ct == "exit") token.keyword = keywords::EXIT; diff --git a/src/SyntaxError.cpp b/src/SyntaxError.cpp index b0de60b..1af1c1d 100644 --- a/src/SyntaxError.cpp +++ b/src/SyntaxError.cpp @@ -30,7 +30,8 @@ void SyntaxError::fnTypeMismatch(string function, vector validTypes, val else if (typeGiven == valtype::DEC) cerr << "dec"; else if (typeGiven == valtype::STR) cerr << "str"; else if (typeGiven == valtype::BOOL) cerr << "bool"; - else cerr << "unknown"; + else if (typeGiven == valtype::LIST) cerr << "list"; + else cerr << "other or unknown"; cerr << "' instead" << endl; if (!notes.empty()) cerr << "Notes: " << notes << endl; exit(1); @@ -75,6 +76,12 @@ void SyntaxError::cannotCompareDifferentTypes(string notes) { if (!notes.empty()) cerr << "Notes: " << notes << endl; exit(1); } +void SyntaxError::listTypeMismatch(string notes) { + cerr << "TypeError: List type mismatch" << endl; + if (!notes.empty()) cerr << "Notes: " << notes << endl; + exit(1); +} + void SyntaxError::comparisonTypeError(string notes) { cerr << "ComparisonError: cannot use a non-bool type in an if or while statement" << endl; if (!notes.empty()) cerr << "Notes: " << notes << endl; diff --git a/src/SyntaxError.h b/src/SyntaxError.h index 8178aa3..397aa95 100644 --- a/src/SyntaxError.h +++ b/src/SyntaxError.h @@ -30,5 +30,6 @@ public: void mathCannotDoOperationOnType(string operatorUsed, string type, string notes = ""); void cannotCompareDifferentTypes(string notes = ""); void comparisonTypeError(string notes = ""); + void listTypeMismatch(string notes = ""); void generalError(string notes = ""); }; diff --git a/src/common.h b/src/common.h index 4630639..7a222ba 100644 --- a/src/common.h +++ b/src/common.h @@ -38,8 +38,8 @@ enum class keywords { ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, LESS, GREATER, EQLESS, EQGREATER, INCREMENT, DECREMENT, - PRINT, PRINTLN, LET, INPUT, EXIT, - VALUE, SEMICOLON, VARIABLE, + PRINT, PRINTLN, PRINTLIST, LET, INPUT, EXIT, + VALUE, LIST, SEMICOLON, VARIABLE, COMMENT };