diff --git a/README.md b/README.md index cb68c09..4e79fe6 100644 --- a/README.md +++ b/README.md @@ -83,8 +83,41 @@ main = func { } ``` +Or this: + +``` +main func { + dingus(dingus) +} + +dingus func { + arg0(arg0) +} +``` + functions are indeed objects >:) +Funk supports importing other libraries written in Funk (FFI libraries will come soon). Use the import function to import those libraries. + +Ensure that the library you are importing is in the directory pointed to by the `FUNK_HOME` environment variable. + +``` +// myCoolLibrary.funk +importedFunction func { + println("The imported function has been called") +} + +importedValue = "Hi there from the library!" + +// main.funk +import("myCoolLibrary") + +main func { + myCoolLibrary::importedFunction() + println(myCoolLibrary::importedValue) +} +``` + ## License Funk is licensed to you under the GNU GPL v3.0. Contributions are welcome! diff --git a/libs/myLib.funk b/libs/myLib.funk new file mode 100644 index 0000000..94408d8 --- /dev/null +++ b/libs/myLib.funk @@ -0,0 +1,5 @@ +dingle func { + println("this func is dingling") +} + +someConstant = "heheheha" \ No newline at end of file diff --git a/src/runner/runner.cpp b/src/runner/runner.cpp index 6d1bd36..3f8a490 100644 --- a/src/runner/runner.cpp +++ b/src/runner/runner.cpp @@ -1,15 +1,21 @@ #include "runner.h" #include -#include +#include #include #include "../parser/parser.h" +#include "../lexer/lexer.h" Object::Object(ASTValue value) : value(value) {} Object::Object(ASTFunction function) : value(function) {} Object::Object() = default; +std::map Executor::getVariables() { + return variables; +} + +std::map globalVariables; std::optional Executor::consume() { if (iterator < code.nodes.size()) { @@ -121,7 +127,52 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map(object.value)) { + arg = std::get(object.value); + if (arg.type == ValueType::String) { + std::optional importName = arg.getString(); + if (importName.has_value()) { + const char* libpathEnv = std::getenv("FUNK_PATH"); + if (libpathEnv == nullptr) { + std::cout << "Error: FUNK_PATH environment variable is not set" << std::endl; + exit(1); + } + std::string libpath = libpathEnv; + // Import the Funk file for this library + std::ifstream file(libpath + "/" + importName.value() + ".funk"); + // Execute the file and capture it's content + if (file.is_open()) { + std::string fc; + std::string buf; + while (std::getline(file, buf)) { + fc += buf + "\n"; + } + Executor importedCode(ASTCodeBlock(Lexer(fc).content)); + for (auto const &[key, val] : importedCode.getVariables()) { + std::string newVarName = importName.value() + "::" + key; + if (isInitCall) { + globalVariables[newVarName] = val; + variables[newVarName] = val; + } else { + variables[newVarName] = val; + } + } + } + } else { + std::cout << "Type mismatch - expecting a string but found something else" << std::endl; + exit(1); + } + } else { + std::cout << "Type mismatch - expecting string for import" << std::endl; + exit(1); + } + } else { + std::cout << "Type mismatch - expecting string for import" << std::endl; + exit(1); + } + } continue; } if (isInitCall) { @@ -268,14 +319,14 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map(variables[fnName].children["handler"])) { - Executor(std::get(variables[fnName].children["handler"]).body, false, {}, callArgs); + Executor(std::get(variables[fnName].children["handler"]).body, false, globalVariables, callArgs); } else { std::cout << "Object " << fnName << " does not have a handler function" << std::endl; exit(1); } } if (std::holds_alternative(variables[fnName].value)) { - Executor(std::get(variables[fnName].value).body, false, {}, callArgs); + Executor(std::get(variables[fnName].value).body, false, globalVariables, callArgs); } } else { @@ -289,6 +340,7 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map(variables[std::string("main")].value).body, false, variables); + globalVariables = variables; + Executor(std::get(variables[std::string("main")].value).body, false, globalVariables); } } \ No newline at end of file diff --git a/src/runner/runner.h b/src/runner/runner.h index 76d2833..368ab78 100644 --- a/src/runner/runner.h +++ b/src/runner/runner.h @@ -37,5 +37,6 @@ class Executor { std::optional peek(int ahead = 1); public: explicit Executor(ASTCodeBlock in, bool isInitCall = false, std::map scopeVals = {}, std::vector args = {}); + std::map getVariables(); }; diff --git a/tests/test.funk b/tests/test.funk index 404da0c..a07d698 100644 --- a/tests/test.funk +++ b/tests/test.funk @@ -1,3 +1,5 @@ +import("myLib") + dingus func { // println is an inbuilt function, you can also use print println("you got dingused") @@ -16,6 +18,9 @@ dingus func { println(3.14) println("I am a string!") println(true) + // access things from a library + println(myLib::someConstant) + myLib::dingle() } // main is the entry point of the program, like many other languages