Further work on implementing functions

This commit is contained in:
2025-05-20 15:03:08 +10:00
parent 46e6d7f9da
commit a0b4caa6e8
7 changed files with 95 additions and 18 deletions

View File

@@ -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);

View File

@@ -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 {};
} }

View File

@@ -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);
}; };

View File

@@ -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);
} }

View File

@@ -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 = "");
}; };

View File

@@ -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;
}; };

View File

@@ -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;
} }