Further work on implementing functions
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
println "Time to define a function";
|
println "Time to define a function";
|
||||||
|
|
||||||
fun str myFunction(int myNum);
|
fun str myFunction(int myNum);
|
||||||
|
|
||||||
|
myFunction(3);
|
||||||
|
@@ -57,8 +57,9 @@ valtype Interpreter::keywordToValtype(keywords in) {
|
|||||||
return valtype::KEYWORD;
|
return valtype::KEYWORD;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::interpret(vector<Token> tokenList) {
|
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");
|
||||||
tokens = tokenList;
|
tokens = tokenList;
|
||||||
log.debug("Alright we got " + to_string(tokens.size()) + " tokens");
|
log.debug("Alright we got " + to_string(tokens.size()) + " tokens");
|
||||||
|
|
||||||
@@ -194,6 +195,7 @@ void Interpreter::interpret(vector<Token> tokenList) {
|
|||||||
i -= 1;
|
i -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect any comparisons and convert
|
// Detect any comparisons and convert
|
||||||
// Start at 1 to avoid having to do more crappy memory safety stuff
|
// Start at 1 to avoid having to do more crappy memory safety stuff
|
||||||
for (int i = 1; i < currentInstruction.size(); i++) {
|
for (int i = 1; i < currentInstruction.size(); i++) {
|
||||||
@@ -210,7 +212,7 @@ void Interpreter::interpret(vector<Token> tokenList) {
|
|||||||
if (currentInstruction[i - 1].keyword != keywords::VALUE ||
|
if (currentInstruction[i - 1].keyword != keywords::VALUE ||
|
||||||
currentInstruction[i + 1].keyword != keywords::VALUE) {
|
currentInstruction[i + 1].keyword != keywords::VALUE) {
|
||||||
syntaxError.generalError("Can only compare values");
|
syntaxError.generalError("Can only compare values");
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure value types are set correctly
|
// Ensure value types are set correctly
|
||||||
@@ -246,7 +248,7 @@ void Interpreter::interpret(vector<Token> tokenList) {
|
|||||||
if (currentInstruction[i - 1].keyword != keywords::VALUE ||
|
if (currentInstruction[i - 1].keyword != keywords::VALUE ||
|
||||||
currentInstruction[i + 1].keyword != keywords::VALUE) {
|
currentInstruction[i + 1].keyword != keywords::VALUE) {
|
||||||
syntaxError.generalError("Can only compare values of");
|
syntaxError.generalError("Can only compare values of");
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure value types are set correctly
|
// Ensure value types are set correctly
|
||||||
@@ -298,14 +300,53 @@ void Interpreter::interpret(vector<Token> tokenList) {
|
|||||||
currentInstruction.insert(currentInstruction.begin() + startIndex, newToken);
|
currentInstruction.insert(currentInstruction.begin() + startIndex, newToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 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<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)];
|
||||||
|
i++;
|
||||||
|
if (currentInstruction[i].keyword != keywords::OPARE) syntaxError.generalError("Expecting a '(' when calling a function");
|
||||||
|
i++;
|
||||||
|
vector<Token> argsForFn;
|
||||||
|
int argCount = 0;
|
||||||
|
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<string>(currentInstruction[i].value.value), {log.getTypeString(fnbuf.arguments[fnbuf.argNames[argCount]])}, currentInstruction[i].value.type);
|
||||||
|
variables[fnbuf.argNames[argCount]] = tokens[i].value;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
resumePoint.push(tokenIndex);
|
||||||
|
vector<Token> 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");
|
||||||
|
//tokenIndex = functions[get<string>(currentInstruction[i].value.value)].startToken;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
// Execute the instruction
|
// Execute the instruction
|
||||||
log.debug("Length of line is " + to_string(lengthOfLine));
|
log.debug("Length of line is " + to_string(lengthOfLine));
|
||||||
executeCode(currentInstruction);
|
executeCode(currentInstruction, isFunction);
|
||||||
lengthOfLine = 0;
|
lengthOfLine = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::executeCode(vector<Token> tokens) {
|
optional<Token> Interpreter::executeCode(vector<Token> tokens, bool isFunction) {
|
||||||
SyntaxError syntaxError;
|
SyntaxError syntaxError;
|
||||||
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++) {
|
||||||
@@ -329,7 +370,7 @@ void Interpreter::executeCode(vector<Token> tokens) {
|
|||||||
if (tokens[i].keyword == keywords::CBRAC) {
|
if (tokens[i].keyword == keywords::CBRAC) {
|
||||||
tokenIndex = loop;
|
tokenIndex = loop;
|
||||||
repeatScope --;
|
repeatScope --;
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tokens[i].keyword == keywords::PRINTLN) {
|
if (tokens[i].keyword == keywords::PRINTLN) {
|
||||||
@@ -504,7 +545,7 @@ void Interpreter::executeCode(vector<Token> tokens) {
|
|||||||
if (tokens[i].type != valtype::BOOL) syntaxError.comparisonTypeError("in an if statement");
|
if (tokens[i].type != valtype::BOOL) syntaxError.comparisonTypeError("in an if statement");
|
||||||
if (!get<bool>(tokens[i].value.value)) {
|
if (!get<bool>(tokens[i].value.value)) {
|
||||||
skipScope ++;
|
skipScope ++;
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
} else if (tokens[i].keyword == keywords::WHILE) {
|
} else if (tokens[i].keyword == keywords::WHILE) {
|
||||||
i++;
|
i++;
|
||||||
@@ -532,36 +573,58 @@ void Interpreter::executeCode(vector<Token> tokens) {
|
|||||||
} else if (tokens[i].keyword == keywords::FUN) {
|
} else if (tokens[i].keyword == keywords::FUN) {
|
||||||
i++;
|
i++;
|
||||||
Function buf;
|
Function buf;
|
||||||
if (keywordToValtype(tokens[i].keyword) == valtype::KEYWORD) syntaxError.generalError("fun needs a defining value for arg 1, not a value. ");
|
if (keywordToValtype(tokens[i].keyword) == valtype::KEYWORD) syntaxError.generalError("fun needs a defining value for arg 1, not a non-value.");
|
||||||
buf.type = keywordToValtype(tokens[i].keyword);
|
buf.type = keywordToValtype(tokens[i].keyword);
|
||||||
i++;
|
i++;
|
||||||
|
tokenIndex ++;
|
||||||
string valName;
|
string valName;
|
||||||
if (tokens[i].value.type == valtype::STR) valName = get<string>(tokens[i].value.value);
|
if (tokens[i].value.type == valtype::STR) valName = get<string>(tokens[i].value.value);
|
||||||
buf.startToken = tokenIndex;
|
functionnames.push_back(valName);
|
||||||
i++;
|
i++;
|
||||||
|
tokenIndex ++;
|
||||||
if (tokens[i].keyword != keywords::OPARE) syntaxError.generalError("This is a placeholder");
|
if (tokens[i].keyword != keywords::OPARE) syntaxError.generalError("This is a placeholder");
|
||||||
i++;
|
i++;
|
||||||
|
tokenIndex ++;
|
||||||
map<string, valtype> valuetypes;
|
map<string, valtype> valuetypes;
|
||||||
while (tokens[i].keyword != keywords::CPARE) {
|
// Get the arguments which we will use in the function
|
||||||
|
if (tokens[i + 1].keyword != keywords::CPARE) while (tokens[i].keyword != keywords::CPARE) {
|
||||||
// We should have a valtype, a name for the variable, and a comma if the thing hasn't ended already
|
// We should have a valtype, a name for the variable, and a comma if the thing hasn't ended already
|
||||||
if (keywordToValtype(tokens[i].keyword) == valtype::KEYWORD) syntaxError.generalError("Another placeholder");
|
if (keywordToValtype(tokens[i].keyword) == valtype::KEYWORD) syntaxError.generalError("Another placeholder");
|
||||||
valtype valbuf = keywordToValtype(tokens[i].keyword);
|
valtype valbuf = keywordToValtype(tokens[i].keyword);
|
||||||
i++;
|
i++;
|
||||||
|
tokenIndex ++;
|
||||||
if (tokens[i].type != valtype::STR) syntaxError.generalError("A third placeholder");
|
if (tokens[i].type != valtype::STR) syntaxError.generalError("A third placeholder");
|
||||||
|
log.debug("This function needs a " + log.getTypeString(valbuf) + " which is accessible as " + get<string>(tokens[i].value.value));
|
||||||
|
buf.argNames.push_back(get<string>(tokens[i].value.value));
|
||||||
valuetypes[get<string>(tokens[i].value.value)] = valbuf;
|
valuetypes[get<string>(tokens[i].value.value)] = valbuf;
|
||||||
i++;
|
i++;
|
||||||
|
tokenIndex ++;
|
||||||
if (tokens[i].keyword == keywords::CPARE) break;
|
if (tokens[i].keyword == keywords::CPARE) break;
|
||||||
if (tokens[i].keyword != keywords::COMMA) syntaxError.generalError("Yet another placeholder");
|
if (tokens[i].keyword != keywords::COMMA) syntaxError.generalError("Yet another placeholder");
|
||||||
i++;
|
i++;
|
||||||
|
tokenIndex ++;
|
||||||
}
|
}
|
||||||
|
else log.debug("Function does not require arguments");
|
||||||
|
tokenIndex ++;
|
||||||
|
buf.arguments = valuetypes;
|
||||||
|
buf.startToken = tokenIndex;
|
||||||
functions[valName] = buf;
|
functions[valName] = buf;
|
||||||
log.debug("Init a function");
|
log.debug("Init a function with name " + valName + " success. Function starts at index " + to_string(buf.startToken));
|
||||||
|
} else if (tokens[i].keyword == keywords::RETURN) {
|
||||||
|
i++;
|
||||||
|
if (i >= tokens.size()) syntaxError.fnNotSufficientArgs("return", 1, 1, 0);
|
||||||
|
if (isFunction){
|
||||||
|
return tokens[i++];
|
||||||
|
} else {
|
||||||
|
if (tokens[i].value.type != valtype::INT) syntaxError.improperReturnType("");
|
||||||
|
exit(get<int>(tokens[i].value.value));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (tokens[i].keyword == keywords::VALUE && tokens[i].value.type == valtype::STR && variables.find(get<string>(tokens[i].value.value)) != variables.end()) {
|
if (tokens[i].keyword == keywords::VALUE && tokens[i].value.type == valtype::STR && variables.find(get<string>(tokens[i].value.value)) != variables.end()) {
|
||||||
log.debug("Manipulating variable...");
|
log.debug("Manipulating variable...");
|
||||||
if (tokens.size() <= i + 2) { // Need at least 3 tokens: variable, operator, value
|
if (tokens.size() <= i + 2) { // Need at least 3 tokens: variable, operator, value
|
||||||
syntaxError.mathTooFewArgs();
|
syntaxError.mathTooFewArgs();
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
string varName = get<string>(tokens[i].value.value);
|
string varName = get<string>(tokens[i].value.value);
|
||||||
i++;
|
i++;
|
||||||
@@ -578,7 +641,7 @@ void Interpreter::executeCode(vector<Token> tokens) {
|
|||||||
default: validTypes = {"unknown"}; break;
|
default: validTypes = {"unknown"}; break;
|
||||||
}
|
}
|
||||||
syntaxError.fnTypeMismatch("assignment", validTypes, valueToken.type);
|
syntaxError.fnTypeMismatch("assignment", validTypes, valueToken.type);
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
variables[varName].value = valueToken.value.value;
|
variables[varName].value = valueToken.value.value;
|
||||||
i++; // Skip the value token since we've processed it
|
i++; // Skip the value token since we've processed it
|
||||||
@@ -613,4 +676,5 @@ void Interpreter::executeCode(vector<Token> tokens) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
@@ -26,22 +26,23 @@ class Interpreter {
|
|||||||
private:
|
private:
|
||||||
int skipScope = 0;
|
int skipScope = 0;
|
||||||
int repeatScope = 0;
|
int repeatScope = 0;
|
||||||
int resumePoint = 0;
|
stack<int> resumePoint;
|
||||||
vector<int> loops;
|
vector<int> loops;
|
||||||
SyntaxError syntaxError;
|
SyntaxError syntaxError;
|
||||||
vector<Token> tokens;
|
vector<Token> tokens;
|
||||||
map<string, Value> variables;
|
map<string, Value> variables;
|
||||||
map<string, Function> functions;
|
map<string, Function> functions;
|
||||||
|
vector<string> functionnames;
|
||||||
Logger log;
|
Logger log;
|
||||||
int loop;
|
int loop;
|
||||||
int lengthOfLine;
|
int lengthOfLine;
|
||||||
int tokenIndex = -1;
|
int tokenIndex = -1;
|
||||||
optional<Token> consume();
|
optional<Token> consume();
|
||||||
optional<Token> peek(int offset = 1);
|
optional<Token> peek(int offset = 1);
|
||||||
void executeCode(vector<Token> tokens);
|
optional<Token> executeCode(vector<Token> tokens, bool isFunction);
|
||||||
valtype keywordToValtype(keywords in);
|
valtype keywordToValtype(keywords in);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void initInterpreter(vector<string> args);
|
void initInterpreter(vector<string> args);
|
||||||
void interpret(vector<Token> tokenList);
|
optional<Token> interpret(vector<Token> tokenList, bool isFunction);
|
||||||
};
|
};
|
||||||
|
@@ -67,7 +67,7 @@ void SyntaxError::mathCannotDoOperationOnType(string operatorUsed, string type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SyntaxError::generalError(string notes) {
|
void SyntaxError::generalError(string notes) {
|
||||||
cerr << "GeneralError: Something went awfully wrong and we don't know why lmao" << endl;
|
cerr << "GeneralError: General error" << endl;
|
||||||
if (!notes.empty()) cerr << "Notes: " << notes << endl;
|
if (!notes.empty()) cerr << "Notes: " << notes << endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,14 @@ void SyntaxError::listOutOfBounds(string notes) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SyntaxError::improperReturnType(string notes) {
|
||||||
|
cerr << "TypeError: Mismatched function return type" << endl;
|
||||||
|
if (!notes.empty()) cerr << "Notes: " << notes << endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
void SyntaxError::comparisonTypeError(string notes) {
|
void SyntaxError::comparisonTypeError(string notes) {
|
||||||
cerr << "ComparisonError: cannot use a non-bool type in an if or while statement" << endl;
|
cerr << "ComparisonError: cannot use a non-bool type in an if or while statement" << endl;
|
||||||
if (!notes.empty()) cerr << "Notes: " << notes << endl;
|
if (!notes.empty()) cerr << "Notes: " << notes << endl;
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@@ -32,5 +32,6 @@ public:
|
|||||||
void comparisonTypeError(string notes = "");
|
void comparisonTypeError(string notes = "");
|
||||||
void listTypeMismatch(string notes = "");
|
void listTypeMismatch(string notes = "");
|
||||||
void listOutOfBounds(string notes = "");
|
void listOutOfBounds(string notes = "");
|
||||||
|
void improperReturnType(string notes = "");
|
||||||
void generalError(string notes = "");
|
void generalError(string notes = "");
|
||||||
};
|
};
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <stack>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@@ -57,6 +58,7 @@ struct Value {
|
|||||||
|
|
||||||
struct Function {
|
struct Function {
|
||||||
valtype type;
|
valtype type;
|
||||||
|
vector<string> argNames;
|
||||||
map<string, valtype> arguments;
|
map<string, valtype> arguments;
|
||||||
int startToken;
|
int startToken;
|
||||||
};
|
};
|
||||||
|
@@ -51,6 +51,6 @@ int main(int argc, char* argv[]) {
|
|||||||
Interpreter interpreter;
|
Interpreter interpreter;
|
||||||
// Convert to tokens and run the code
|
// Convert to tokens and run the code
|
||||||
interpreter.initInterpreter(args.getAllArgs());
|
interpreter.initInterpreter(args.getAllArgs());
|
||||||
interpreter.interpret(parser.getTokens());
|
interpreter.interpret(parser.getTokens(), false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user