Further work on functions

This commit is contained in:
2025-05-23 09:26:58 +10:00
parent fe434787e5
commit 80fe4f0aad
5 changed files with 56 additions and 38 deletions

View File

@@ -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. **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 ## 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: If you've got [bob](https://git.maxwellj.xyz/max/bob) installed, make use of the supplied Bobfile by running `bob`. Otherwise, run:

View File

@@ -1,5 +1,7 @@
println "Time to define a function"; println "Time to define a function";
fun str myFunction(int myNum); fun str myFunction(int myNum) {
println myNum;
}
myFunction(3); myFunction(3){};

View File

@@ -21,13 +21,13 @@
optional<Token> Interpreter::consume() { optional<Token> Interpreter::consume() {
tokenIndex++; tokenIndex++;
if (tokenIndex < tokens.size()) return tokens[tokenIndex]; if (tokenIndex < unprocessedTokens.size()) return unprocessedTokens[tokenIndex];
return {}; return {};
} }
optional<Token> Interpreter::peek(int offset) { optional<Token> Interpreter::peek(int offset) {
int index = tokenIndex + offset; int index = tokenIndex + offset;
if (index >= 0 && index < tokens.size()) return tokens[index]; if (index >= 0 && index < unprocessedTokens.size()) return unprocessedTokens[index];
return {}; return {};
} }
@@ -60,10 +60,10 @@ valtype Interpreter::keywordToValtype(keywords in) {
optional<Token> Interpreter::interpret(vector<Token> tokenList, bool isFunction) { optional<Token> Interpreter::interpret(vector<Token> tokenList, bool isFunction) {
if (debugMode) log.toggleDebugPrint(); if (debugMode) log.toggleDebugPrint();
if (isFunction) log.debug("Currently executing code for a function"); if (isFunction) log.debug("Currently executing code for a function");
tokens = tokenList; unprocessedTokens = tokenList;
log.debug("Alright we got " + to_string(tokens.size()) + " tokens"); log.debug("Alright we got " + to_string(unprocessedTokens.size()) + " tokens");
while (tokenIndex < static_cast<int>(tokens.size() - 1)) { while (tokenIndex < static_cast<int>(unprocessedTokens.size() - 1)) {
auto currentToken = consume(); auto currentToken = consume();
if (!currentToken) break; if (!currentToken) break;
@@ -303,47 +303,41 @@ optional<Token> Interpreter::interpret(vector<Token> tokenList, bool isFunction)
// Call functions and assign values // Call functions and assign values
for (int i = 0; i < currentInstruction.size(); i++) { for (int i = 0; i < currentInstruction.size(); i++) {
log.debug("Looking for a function"); log.debug("Looking for a function");
Function empty;
for (int j = 0; j < functionnames.size(); j++) { for (int j = 0; j < functionnames.size(); j++) {
log.debug("There is a function called " + functionnames[j]); log.debug("There is a function called " + functionnames[j]);
//if (tokens[i].type == valtype::STR && functionnames[j] == get<string>(tokens[i].value.value)) log.debug("in theory we should be fine?");
}
if (currentInstruction[i].type == valtype::STR && functions.find(get<string>(currentInstruction[i].value.value)) != functions.end()) {
log.debug("Found a function");
Function fnbuf = functions[get<string>(currentInstruction[i].value.value)]; Function fnbuf = functions[get<string>(currentInstruction[i].value.value)];
i++; i++;
if (currentInstruction[i].keyword != keywords::OPARE) syntaxError.generalError("Expecting a '(' when calling a function"); if (currentInstruction[i].keyword != keywords::OPARE) syntaxError.generalError("Expecting a '(' when calling a function");
i++; i++;
vector<Token> argsForFn; vector<Token> argsForFn;
int argCount = 0; int argCount = 0;
log.debug("Getting arguments for function");
if (currentInstruction[i].keyword != keywords::CPARE) while (currentInstruction[i].keyword != keywords::CPARE) { if (currentInstruction[i].keyword != keywords::CPARE) while (currentInstruction[i].keyword != keywords::CPARE) {
if (i >= currentInstruction.size()) syntaxError.generalError("Expecting a ')' after function arguments"); if (i >= currentInstruction.size()) syntaxError.generalError("Expecting a ')' after function arguments");
if (currentInstruction[i].value.type != fnbuf.arguments[fnbuf.argNames[argCount]]) syntaxError.fnTypeMismatch(get<string>(currentInstruction[i].value.value), {log.getTypeString(fnbuf.arguments[fnbuf.argNames[argCount]])}, currentInstruction[i].value.type); if (currentInstruction[i].value.type != fnbuf.arguments[fnbuf.argNames[argCount]]) syntaxError.fnTypeMismatch(get<string>(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++; i++;
} }
resumePoint.push(tokenIndex); log.debug("Successfully got args");
vector<Token> fnTokens; vector<Token> fnTokens;
int l = 1; log.debug("Running the function");
int m = 0; optional<Token> optionalReturnToken = interpret(fnbuf.instructions, true);
while (l > 0) { Token returnToken;
if (tokens[m].keyword == keywords::OBRAC) l++; if (optionalReturnToken.has_value()) {
if (tokens[m].keyword == keywords::CBRAC) l--; returnToken = optionalReturnToken.value();
if (l < 1) break; } else syntaxError.generalError("Placeholder");
fnTokens.push_back(tokens[m]); log.debug("We have called a function yayayayay");
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");
//tokenIndex = functions[get<string>(currentInstruction[i].value.value)].startToken; //tokenIndex = functions[get<string>(currentInstruction[i].value.value)].startToken;
//if (tokens[i].type == valtype::STR && functionnames[j] == get<string>(tokens[i].value.value)) log.debug("in theory we should be fine?");
} }
} }
// Execute the instruction // Execute the instruction
log.debug("Length of line is " + to_string(lengthOfLine)); log.debug("Length of line is " + to_string(lengthOfLine));
if (isFunction) { if (isFunction) {
optional<Token> returnTokenOptional = executeCode(currentInstruction, true); optional<Token> returnTokenOptional = executeCode(currentInstruction, true);
if (returnTokenOptional.has_value()); if (returnTokenOptional.has_value()) return returnTokenOptional.value();
} }
executeCode(currentInstruction, isFunction); executeCode(currentInstruction, isFunction);
lengthOfLine = 0; lengthOfLine = 0;
@@ -353,6 +347,7 @@ optional<Token> Interpreter::interpret(vector<Token> tokenList, bool isFunction)
optional<Token> Interpreter::executeCode(vector<Token> tokens, bool isFunction) { optional<Token> Interpreter::executeCode(vector<Token> tokens, bool isFunction) {
SyntaxError syntaxError; SyntaxError syntaxError;
if (isFunction) log.debug("Running code for a function");
log.debug("Token length for this expression is " + to_string(tokens.size())); log.debug("Token length for this expression is " + to_string(tokens.size()));
for (int i = 0; i < tokens.size(); i++) { for (int i = 0; i < tokens.size(); i++) {
if (skipScope > 0) { if (skipScope > 0) {
@@ -610,11 +605,24 @@ optional<Token> Interpreter::executeCode(vector<Token> tokens, bool isFunction)
tokenIndex ++; tokenIndex ++;
} }
else log.debug("Function does not require arguments"); else log.debug("Function does not require arguments");
tokenIndex ++; i++;
buf.arguments = valuetypes; 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; 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) { } else if (tokens[i].keyword == keywords::RETURN) {
i++; i++;
if (i >= tokens.size()) syntaxError.fnNotSufficientArgs("return", 1, 1, 0); if (i >= tokens.size()) syntaxError.fnNotSufficientArgs("return", 1, 1, 0);

View File

@@ -29,7 +29,7 @@ private:
stack<int> resumePoint; stack<int> resumePoint;
vector<int> loops; vector<int> loops;
SyntaxError syntaxError; SyntaxError syntaxError;
vector<Token> tokens; vector<Token> unprocessedTokens;
map<string, Value> variables; map<string, Value> variables;
map<string, Function> functions; map<string, Function> functions;
vector<string> functionnames; vector<string> functionnames;

View File

@@ -44,6 +44,8 @@ enum class keywords {
COMMENT COMMENT
}; };
struct Null {};
struct Value; struct Value;
struct List { struct List {
@@ -53,14 +55,7 @@ struct List {
struct Value { struct Value {
valtype type; valtype type;
variant<int, double, string, bool, List> value; variant<int, double, string, bool, List, Null> value;
};
struct Function {
valtype type;
vector<string> argNames;
map<string, valtype> arguments;
int startToken;
}; };
struct Token { struct Token {
@@ -69,6 +64,13 @@ struct Token {
valtype type = valtype::KEYWORD; valtype type = valtype::KEYWORD;
}; };
struct Function {
valtype type;
vector<string> argNames;
map<string, valtype> arguments;
vector<Token> instructions;
};
struct var { struct var {
valtype type; valtype type;
variant<int, double, string, bool> value; variant<int, double, string, bool> value;