Importing libraries
This commit is contained in:
33
README.md
33
README.md
@@ -83,8 +83,41 @@ main = func {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Or this:
|
||||||
|
|
||||||
|
```
|
||||||
|
main func {
|
||||||
|
dingus(dingus)
|
||||||
|
}
|
||||||
|
|
||||||
|
dingus func {
|
||||||
|
arg0(arg0)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
<sub>functions are indeed objects >:)</sub>
|
<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
|
## License
|
||||||
|
|
||||||
Funk is licensed to you under the GNU GPL v3.0. Contributions are welcome!
|
Funk is licensed to you under the GNU GPL v3.0. Contributions are welcome!
|
||||||
|
|||||||
5
libs/myLib.funk
Normal file
5
libs/myLib.funk
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
dingle func {
|
||||||
|
println("this func is dingling")
|
||||||
|
}
|
||||||
|
|
||||||
|
someConstant = "heheheha"
|
||||||
@@ -1,15 +1,21 @@
|
|||||||
#include "runner.h"
|
#include "runner.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <ostream>
|
#include <fstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "../parser/parser.h"
|
#include "../parser/parser.h"
|
||||||
|
#include "../lexer/lexer.h"
|
||||||
|
|
||||||
Object::Object(ASTValue value) : value(value) {}
|
Object::Object(ASTValue value) : value(value) {}
|
||||||
Object::Object(ASTFunction function) : value(function) {}
|
Object::Object(ASTFunction function) : value(function) {}
|
||||||
Object::Object() = default;
|
Object::Object() = default;
|
||||||
|
|
||||||
|
std::map<std::string, Object> Executor::getVariables() {
|
||||||
|
return variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, Object> globalVariables;
|
||||||
|
|
||||||
std::optional<ASTNode> Executor::consume() {
|
std::optional<ASTNode> Executor::consume() {
|
||||||
if (iterator < code.nodes.size()) {
|
if (iterator < code.nodes.size()) {
|
||||||
@@ -121,7 +127,52 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, Objec
|
|||||||
|
|
||||||
}
|
}
|
||||||
if (fnName == "import") {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
if (isInitCall) {
|
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.find(fnName) != variables.end()) {
|
||||||
if (variables[fnName].isCustomObject) {
|
if (variables[fnName].isCustomObject) {
|
||||||
if (std::holds_alternative<ASTFunction>(variables[fnName].children["handler"])) {
|
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 {
|
} else {
|
||||||
std::cout << "Object " << fnName << " does not have a handler function" << std::endl;
|
std::cout << "Object " << fnName << " does not have a handler function" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (std::holds_alternative<ASTFunction>(variables[fnName].value)) {
|
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 {
|
} else {
|
||||||
@@ -289,6 +340,7 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, Objec
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isInitCall) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,5 +37,6 @@ class Executor {
|
|||||||
std::optional<ASTNode> peek(int ahead = 1);
|
std::optional<ASTNode> peek(int ahead = 1);
|
||||||
public:
|
public:
|
||||||
explicit Executor(ASTCodeBlock in, bool isInitCall = false, std::map<std::string, Object> scopeVals = {}, std::vector<Object> args = {});
|
explicit Executor(ASTCodeBlock in, bool isInitCall = false, std::map<std::string, Object> scopeVals = {}, std::vector<Object> args = {});
|
||||||
|
std::map<std::string, Object> getVariables();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import("myLib")
|
||||||
|
|
||||||
dingus func {
|
dingus func {
|
||||||
// println is an inbuilt function, you can also use print
|
// println is an inbuilt function, you can also use print
|
||||||
println("you got dingused")
|
println("you got dingused")
|
||||||
@@ -16,6 +18,9 @@ dingus func {
|
|||||||
println(3.14)
|
println(3.14)
|
||||||
println("I am a string!")
|
println("I am a string!")
|
||||||
println(true)
|
println(true)
|
||||||
|
// access things from a library
|
||||||
|
println(myLib::someConstant)
|
||||||
|
myLib::dingle()
|
||||||
}
|
}
|
||||||
|
|
||||||
// main is the entry point of the program, like many other languages
|
// main is the entry point of the program, like many other languages
|
||||||
|
|||||||
Reference in New Issue
Block a user