Skip to content

Commit

Permalink
⚡ improve import
Browse files Browse the repository at this point in the history
  • Loading branch information
ValKmjolnir committed Nov 1, 2023
1 parent 49f8cef commit 5174551
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 38 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ Use `import("filename.nas")` to get the nasal file including your built-in funct
Also there's another way of importing nasal files, the two way of importing have the same function:

```javascript
import.dirname.dirname.filename;
use dirname.dirname.filename;
import("./dirname/dirname/filename.nas");
```

Expand Down Expand Up @@ -728,7 +728,7 @@ Windows(`.dll`):
Then we write a test nasal file to run this fib function, using `os.platform()` we could write a cross-platform program:
```javascript
import.std.dylib;
use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib = dlhandle.fib;
for(var i = 1; i<30; i+=1)
Expand All @@ -745,7 +745,7 @@ dylib.dlclose(dlhandle.lib);
`dylib.limitcall` is used to get `dlcall` function that has limited parameter size, this function will prove the performance of your code because it does not use `vm_vec` to store the arguments, instead it uses local scope to store them, so this could avoid frequently garbage collecting. And the code above could also be written like this:

```javascript
import.std.dylib;
use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib = dlhandle.fib;
var invoke = dylib.limitcall(1); # this means the called function has only one parameter
Expand Down
6 changes: 3 additions & 3 deletions doc/README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ var print=func(elems...){
当然也有另外一种办法来导入这些nasal文件,下面两种导入方式的效果是一样的:

```javascript
import.dirname.dirname.filename;
use dirname.dirname.filename;
import("./dirname/dirname/filename.nas");
```

Expand Down Expand Up @@ -702,7 +702,7 @@ Windows(`.dll`):
下面例子中`os.platform()`是用来检测当前运行的系统环境的,这样可以实现跨平台:
```javascript
import.std.dylib;
use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib = dlhandle.fib;
for(var i = 1; i<30; i+=1)
Expand All @@ -719,7 +719,7 @@ dylib.dlclose(dlhandle.lib);
`dylib.limitcall`用于获取使用固定长度传参的 `dlcall` 函数,这种函数可以提高你的程序运行效率,因为它不需要用 `vm_vec` 来存储传入参数,而是使用局部作用域来直接存储,从而避免了频繁调用可能导致的频繁垃圾收集。所以上面展示的代码同样可以这样写:

```javascript
import.std.dylib;
use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib = dlhandle.fib;
var invoke = dylib.limitcall(1); # this means the called function has only one parameter
Expand Down
54 changes: 22 additions & 32 deletions src/nasal_import.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,27 +97,27 @@ bool linker::import_check(expr* node) {
if (node->get_type()!=expr_type::ast_call) {
return false;
}
auto tmp = reinterpret_cast<call_expr*>(node);
auto first_expr = tmp->get_first();
auto call_node = reinterpret_cast<call_expr*>(node);
auto first_expr = call_node->get_first();
if (first_expr->get_type()!=expr_type::ast_id) {
return false;
}
if (reinterpret_cast<identifier*>(first_expr)->get_name()!="import") {
return false;
}
if (!tmp->get_calls().size()) {
if (!call_node->get_calls().size()) {
return false;
}

// import("xxx");
if (tmp->get_calls().size()!=1) {
if (call_node->get_calls().size()!=1) {
return false;
}

if (tmp->get_calls()[0]->get_type()!=expr_type::ast_callf) {
if (call_node->get_calls()[0]->get_type()!=expr_type::ast_callf) {
return false;
}
auto func_call = (call_function*)tmp->get_calls()[0];
auto func_call = (call_function*)call_node->get_calls()[0];
if (func_call->get_argument().size()!=1) {
return false;
}
Expand Down Expand Up @@ -171,10 +171,8 @@ code_block* linker::import_regular_file(

// avoid infinite loading loop
filename = find_real_file_path(filename, node->get_location());
if (!filename.length()) {
return new code_block({0, 0, 0, 0, filename});
}
if (used_modules.count(filename)) {
// if get empty string(error) or this file is used before, do not parse
if (!filename.length() || used_modules.count(filename)) {
return new code_block({0, 0, 0, 0, filename});
}

Expand Down Expand Up @@ -286,20 +284,11 @@ std::string linker::generate_module_name(const std::string& file_path) {
"get empty module name from <" + file_path + ">, " +
"will not be easily accessed."
);
return module_name;
}
if (module_name.length() && '0' <= module_name[0] && module_name[0] <= '9') {
err.warn("link",
"get module <" + module_name + "> from <" + file_path + ">, " +
"will not be easily accessed."
);
}
if (module_name.length() && module_name.find(".")!=std::string::npos) {
err.warn("link",
"get module <" + module_name + "> from <" + file_path + ">, " +
"will not be easily accessed."
);
}
if (module_name.length() && module_name.find("-")!=std::string::npos) {
if (std::isdigit(module_name[0]) ||
module_name.find(".")!=std::string::npos ||
module_name.find("-")!=std::string::npos) {
err.warn("link",
"get module <" + module_name + "> from <" + file_path + ">, " +
"will not be easily accessed."
Expand Down Expand Up @@ -358,28 +347,29 @@ code_block* linker::load(code_block* program_root, const std::string& filename)

// load imported modules
std::unordered_set<std::string> used_modules = {};
for(auto& import_ast_node : program_root->get_expressions()) {
if (!import_check(import_ast_node)) {
for(auto& import_node : program_root->get_expressions()) {
if (!import_check(import_node)) {
break;
}
auto module_code_block = import_regular_file(import_ast_node, used_modules);
// this location should not be a reference, may cause use after free!
const auto location = import_ast_node->get_location();
// parse file and get ast
auto module_code_block = import_regular_file(import_node, used_modules);
auto replace_node = new null_expr(import_node->get_location());
// after importing the regular file as module, delete this node
delete import_ast_node;
delete import_node;
// and replace the node with null_expr node
import_ast_node = new null_expr(location);
import_node = replace_node;

// avoid repeatedly importing the same module
const auto& module_path = module_code_block->get_location().file;
if (used_modules.count(module_path)) {
delete module_code_block;
continue;
} else {
used_modules.insert(module_path);
}

// then we generate a function warping the code block,
// and export the necessary global symbols in this code block
// by generate a return statement, with a hashmap return value
used_modules.insert(module_path);
tree->add_expression(generate_module_definition(module_code_block));
}

Expand Down

0 comments on commit 5174551

Please sign in to comment.