From 80fe4f0aad90ef4d6615b3633dcc10046d108563 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Fri, 23 May 2025 09:26:58 +1000 Subject: [PATCH] Further work on functions --- README.md | 6 +++++ examples/function.io | 6 +++-- src/Interpreter.cpp | 62 +++++++++++++++++++++++++------------------- src/Interpreter.h | 2 +- src/common.h | 18 +++++++------ 5 files changed, 56 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 4340fcb..5415901 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,12 @@ Iodine is a programming language with the intention of having the most readable **Iodine is NOT intended for production use at present.** If you build your mission-critical application with Iodine, good luck. Things are going to break very often. +## Quick start + +```bash +bash -c "$(curl -fsSL https://maxwellj.xyz/iodine.sh)" +``` + ## Compiling Iodine If you've got [bob](https://git.maxwellj.xyz/max/bob) installed, make use of the supplied Bobfile by running `bob`. Otherwise, run: diff --git a/examples/function.io b/examples/function.io index da8a143..df9eb51 100644 --- a/examples/function.io +++ b/examples/function.io @@ -1,5 +1,7 @@ println "Time to define a function"; -fun str myFunction(int myNum); +fun str myFunction(int myNum) { + println myNum; +} -myFunction(3); +myFunction(3){}; diff --git a/src/Interpreter.cpp b/src/Interpreter.cpp index 806303e..e2e588f 100644 --- a/src/Interpreter.cpp +++ b/src/Interpreter.cpp @@ -21,13 +21,13 @@ optional Interpreter::consume() { tokenIndex++; - if (tokenIndex < tokens.size()) return tokens[tokenIndex]; + if (tokenIndex < unprocessedTokens.size()) return unprocessedTokens[tokenIndex]; return {}; } optional Interpreter::peek(int offset) { int index = tokenIndex + offset; - if (index >= 0 && index < tokens.size()) return tokens[index]; + if (index >= 0 && index < unprocessedTokens.size()) return unprocessedTokens[index]; return {}; } @@ -60,10 +60,10 @@ valtype Interpreter::keywordToValtype(keywords in) { optional Interpreter::interpret(vector tokenList, bool isFunction) { if (debugMode) log.toggleDebugPrint(); if (isFunction) log.debug("Currently executing code for a function"); - tokens = tokenList; - log.debug("Alright we got " + to_string(tokens.size()) + " tokens"); + unprocessedTokens = tokenList; + log.debug("Alright we got " + to_string(unprocessedTokens.size()) + " tokens"); - while (tokenIndex < static_cast(tokens.size() - 1)) { + while (tokenIndex < static_cast(unprocessedTokens.size() - 1)) { auto currentToken = consume(); if (!currentToken) break; @@ -303,47 +303,41 @@ optional Interpreter::interpret(vector tokenList, bool isFunction) // Call functions and assign values for (int i = 0; i < currentInstruction.size(); i++) { log.debug("Looking for a function"); - Function empty; for (int j = 0; j < functionnames.size(); j++) { log.debug("There is a function called " + functionnames[j]); - //if (tokens[i].type == valtype::STR && functionnames[j] == get(tokens[i].value.value)) log.debug("in theory we should be fine?"); - } - if (currentInstruction[i].type == valtype::STR && functions.find(get(currentInstruction[i].value.value)) != functions.end()) { - log.debug("Found a function"); Function fnbuf = functions[get(currentInstruction[i].value.value)]; i++; if (currentInstruction[i].keyword != keywords::OPARE) syntaxError.generalError("Expecting a '(' when calling a function"); i++; vector argsForFn; int argCount = 0; + log.debug("Getting arguments for function"); if (currentInstruction[i].keyword != keywords::CPARE) while (currentInstruction[i].keyword != keywords::CPARE) { if (i >= currentInstruction.size()) syntaxError.generalError("Expecting a ')' after function arguments"); if (currentInstruction[i].value.type != fnbuf.arguments[fnbuf.argNames[argCount]]) syntaxError.fnTypeMismatch(get(currentInstruction[i].value.value), {log.getTypeString(fnbuf.arguments[fnbuf.argNames[argCount]])}, currentInstruction[i].value.type); - variables[fnbuf.argNames[argCount]] = tokens[i].value; + variables[fnbuf.argNames[argCount]] = currentInstruction[i].value; i++; } - resumePoint.push(tokenIndex); + log.debug("Successfully got args"); vector fnTokens; - int l = 1; - int m = 0; - while (l > 0) { - if (tokens[m].keyword == keywords::OBRAC) l++; - if (tokens[m].keyword == keywords::CBRAC) l--; - if (l < 1) break; - fnTokens.push_back(tokens[m]); - m++; - } - interpret(fnTokens, true); - log.debug("This is a test call for a function. Function won't actually be run yet. If you see this everything is fine"); + log.debug("Running the function"); + optional optionalReturnToken = interpret(fnbuf.instructions, true); + Token returnToken; + if (optionalReturnToken.has_value()) { + returnToken = optionalReturnToken.value(); + } else syntaxError.generalError("Placeholder"); + log.debug("We have called a function yayayayay"); + //tokenIndex = functions[get(currentInstruction[i].value.value)].startToken; + //if (tokens[i].type == valtype::STR && functionnames[j] == get(tokens[i].value.value)) log.debug("in theory we should be fine?"); } } // Execute the instruction log.debug("Length of line is " + to_string(lengthOfLine)); if (isFunction) { optional returnTokenOptional = executeCode(currentInstruction, true); - if (returnTokenOptional.has_value()); + if (returnTokenOptional.has_value()) return returnTokenOptional.value(); } executeCode(currentInstruction, isFunction); lengthOfLine = 0; @@ -353,6 +347,7 @@ optional Interpreter::interpret(vector tokenList, bool isFunction) optional Interpreter::executeCode(vector tokens, bool isFunction) { SyntaxError syntaxError; + if (isFunction) log.debug("Running code for a function"); log.debug("Token length for this expression is " + to_string(tokens.size())); for (int i = 0; i < tokens.size(); i++) { if (skipScope > 0) { @@ -610,11 +605,24 @@ optional Interpreter::executeCode(vector tokens, bool isFunction) tokenIndex ++; } else log.debug("Function does not require arguments"); - tokenIndex ++; + i++; buf.arguments = valuetypes; - buf.startToken = tokenIndex; + log.debug("Gotten arg types for the function"); + //buf.startToken = tokenIndex; + int j = 0; + if (tokens.size() < i + 1) syntaxError.generalError("function needs a body"); + if (tokens[i].keyword != keywords::OBRAC) syntaxError.generalError("function needs a body"); + j++; + tokenIndex++; + log.debug("About to get instructions for function"); + while (j > 0) { + buf.instructions.push_back(tokens[i]); + if (tokens[tokenIndex].keyword == keywords::OBRAC) j++; + if (tokens[tokenIndex].keyword == keywords::CBRAC) j--; + tokenIndex++; + } functions[valName] = buf; - log.debug("Init a function with name " + valName + " success. Function starts at index " + to_string(buf.startToken)); + log.debug("Init a function with name " + valName + " success."); } else if (tokens[i].keyword == keywords::RETURN) { i++; if (i >= tokens.size()) syntaxError.fnNotSufficientArgs("return", 1, 1, 0); diff --git a/src/Interpreter.h b/src/Interpreter.h index 0a1232e..4506632 100644 --- a/src/Interpreter.h +++ b/src/Interpreter.h @@ -29,7 +29,7 @@ private: stack resumePoint; vector loops; SyntaxError syntaxError; - vector tokens; + vector unprocessedTokens; map variables; map functions; vector functionnames; diff --git a/src/common.h b/src/common.h index 130f547..54f15ca 100644 --- a/src/common.h +++ b/src/common.h @@ -44,6 +44,8 @@ enum class keywords { COMMENT }; +struct Null {}; + struct Value; struct List { @@ -53,14 +55,7 @@ struct List { struct Value { valtype type; - variant value; -}; - -struct Function { - valtype type; - vector argNames; - map arguments; - int startToken; + variant value; }; struct Token { @@ -69,6 +64,13 @@ struct Token { valtype type = valtype::KEYWORD; }; +struct Function { + valtype type; + vector argNames; + map arguments; + vector instructions; +}; + struct var { valtype type; variant value;