Further work on functions
This commit is contained in:
@@ -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:
|
||||||
|
@@ -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){};
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
|
18
src/common.h
18
src/common.h
@@ -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;
|
||||||
|
Reference in New Issue
Block a user