Importing libraries

This commit is contained in:
2025-10-29 11:45:58 +00:00
parent db963463b0
commit 7e071a1b01
5 changed files with 101 additions and 5 deletions

View File

@@ -83,8 +83,41 @@ main = func {
}
```
Or this:
```
main func {
dingus(dingus)
}
dingus func {
arg0(arg0)
}
```
<sub>functions are indeed objects >:)</sub>
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!

5
libs/myLib.funk Normal file
View File

@@ -0,0 +1,5 @@
dingle func {
println("this func is dingling")
}
someConstant = "heheheha"

View File

@@ -1,15 +1,21 @@
#include "runner.h"
#include <iostream>
#include <ostream>
#include <fstream>
#include <utility>
#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<std::string, Object> Executor::getVariables() {
return variables;
}
std::map<std::string, Object> globalVariables;
std::optional<ASTNode> Executor::consume() {
if (iterator < code.nodes.size()) {
@@ -121,7 +127,52 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, Objec
}
if (fnName == "import") {
// work on importing modules later
for (Object &object : callArgs) {
ASTValue arg;
if (object.isCustomObject == false && std::holds_alternative<ASTValue>(object.value)) {
arg = std::get<ASTValue>(object.value);
if (arg.type == ValueType::String) {
std::optional<std::string> 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<std::string, Objec
if (variables.find(fnName) != variables.end()) {
if (variables[fnName].isCustomObject) {
if (std::holds_alternative<ASTFunction>(variables[fnName].children["handler"])) {
Executor(std::get<ASTFunction>(variables[fnName].children["handler"]).body, false, {}, callArgs);
Executor(std::get<ASTFunction>(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<ASTFunction>(variables[fnName].value)) {
Executor(std::get<ASTFunction>(variables[fnName].value).body, false, {}, callArgs);
Executor(std::get<ASTFunction>(variables[fnName].value).body, false, globalVariables, callArgs);
}
} else {
@@ -289,6 +340,7 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, Objec
}
}
if (isInitCall) {
Executor(std::get<ASTFunction>(variables[std::string("main")].value).body, false, variables);
globalVariables = variables;
Executor(std::get<ASTFunction>(variables[std::string("main")].value).body, false, globalVariables);
}
}

View File

@@ -37,5 +37,6 @@ class Executor {
std::optional<ASTNode> peek(int ahead = 1);
public:
explicit Executor(ASTCodeBlock in, bool isInitCall = false, std::map<std::string, Object> scopeVals = {}, std::vector<Object> args = {});
std::map<std::string, Object> getVariables();
};

View File

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