add import logic for use statement

This commit is contained in:
ValKmjolnir 2023-11-01 00:37:02 +08:00
parent 4757dd220a
commit ccbe341dc5
42 changed files with 155 additions and 159 deletions

View File

@ -1,4 +1,4 @@
import.std.dylib; use std.dylib;
var _dl = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so")); var _dl = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));

View File

@ -1,4 +1,4 @@
import.std.dylib; use std.dylib;
var ( var (
kbhit, kbhit,

View File

@ -1,4 +1,4 @@
import.std.dylib; use std.dylib;
var _dl = dylib.dlopen("libmat."~(os.platform()=="windows"?"dll":"so")); var _dl = dylib.dlopen("libmat."~(os.platform()=="windows"?"dll":"so"));

View File

@ -1,4 +1,4 @@
import.std.dylib; use std.dylib;
var socket=func(){ var socket=func(){
var lib=dylib.dlopen("libnasock"~(os.platform()=="windows"?".dll":".so")); var lib=dylib.dlopen("libnasock"~(os.platform()=="windows"?".dll":".so"));

View File

@ -136,7 +136,7 @@ public:
string_literal(const span& location, const std::string& str): string_literal(const span& location, const std::string& str):
expr(location, expr_type::ast_str), content(str) {} expr(location, expr_type::ast_str), content(str) {}
~string_literal() override = default; ~string_literal() override = default;
const std::string get_content() const {return content;} const std::string& get_content() const {return content;}
void accept(ast_visitor*) override; void accept(ast_visitor*) override;
}; };

View File

@ -307,7 +307,7 @@ void codegen::func_gen(function* node) {
void codegen::call_gen(call_expr* node) { void codegen::call_gen(call_expr* node) {
calc_gen(node->get_first()); calc_gen(node->get_first());
if (code.back().op==op_callb) { if (code.size() && code.back().op==op_callb) {
return; return;
} }
for(auto i : node->get_calls()) { for(auto i : node->get_calls()) {
@ -349,6 +349,8 @@ void codegen::call_id(identifier* node) {
return; return;
} }
die("undefined symbol \"" + name + "\"", node->get_location()); die("undefined symbol \"" + name + "\"", node->get_location());
// generation failed, put a push nil operand here to fill the space
emit(op_pnil, index, node->get_location());
} }
void codegen::call_hash_gen(call_hash* node) { void codegen::call_hash_gen(call_hash* node) {

View File

@ -24,19 +24,21 @@ linker::linker():
} }
} }
std::string linker::get_path(call_expr* node) { std::string linker::get_path(expr* node) {
if (node->get_calls()[0]->get_type()==expr_type::ast_callf) { if (node->get_type()==expr_type::ast_use) {
auto tmp = (call_function*)node->get_calls()[0]; auto file_relative_path = std::string(".");
return ((string_literal*)tmp->get_argument()[0])->get_content(); for(auto i : reinterpret_cast<use_stmt*>(node)->get_path()) {
file_relative_path += (is_windows()? "\\":"/") +i->get_name();
}
return file_relative_path + ".nas";
} }
auto fpath = std::string("."); auto call_node = reinterpret_cast<call_expr*>(node);
for(auto i : node->get_calls()) { auto tmp = reinterpret_cast<call_function*>(call_node->get_calls()[0]);
fpath += (is_windows()? "\\":"/") + ((call_hash*)i)->get_field(); auto content = reinterpret_cast<string_literal*>(tmp->get_argument()[0]);
} return content->get_content();
return fpath + ".nas";
} }
std::string linker::find_file( std::string linker::find_real_file_path(
const std::string& filename, const span& location) { const std::string& filename, const span& location) {
// first add file name itself into the file path // first add file name itself into the file path
std::vector<std::string> fpath = {filename}; std::vector<std::string> fpath = {filename};
@ -56,65 +58,58 @@ std::string linker::find_file(
// we will find lib.nas in nasal std directory // we will find lib.nas in nasal std directory
if (filename=="lib.nas") { if (filename=="lib.nas") {
return is_windows()? return is_windows()?
find_file("std\\lib.nas", location): find_real_file_path("std\\lib.nas", location):
find_file("std/lib.nas", location); find_real_file_path("std/lib.nas", location);
} }
if (!show_path) { if (!show_path) {
err.err("link", err.err("link",
"in <" + location.file + ">: " + "in <" + location.file + ">: " +
"cannot find file <" + filename + ">, " + "cannot find file <" + filename + ">, " +
"use <-d> to get detail search path"); "use <-d> to get detail search path"
);
return ""; return "";
} }
std::string paths = ""; auto paths = std::string("");
for(const auto& i : fpath) { for(const auto& i : fpath) {
paths += " -> " + i + "\n"; paths += " -> " + i + "\n";
} }
err.err("link", err.err("link",
"in <" + location.file + ">: " + "in <" + location.file + ">: " +
"cannot find file <" + filename + "> in these paths:\n" + paths); "cannot find file <" + filename + "> in these paths:\n" + paths
);
return ""; return "";
} }
bool linker::import_check(expr* node) { bool linker::import_check(expr* node) {
/* if (node->get_type()==expr_type::ast_use) {
call
|_id:import
|_callh:std
|_callh:file
*/
if (node->get_type()!=expr_type::ast_call) {
return false;
}
auto tmp = (call_expr*)node;
if (tmp->get_first()->get_type()!=expr_type::ast_id) {
return false;
}
if (((identifier*)tmp->get_first())->get_name()!="import") {
return false;
}
if (!tmp->get_calls().size()) {
return false;
}
// import.xxx.xxx;
if (tmp->get_calls()[0]->get_type()==expr_type::ast_callh) {
for(auto i : tmp->get_calls()) {
if (i->get_type()!=expr_type::ast_callh) {
return false;
}
}
return true; return true;
} }
// import("xxx");
if (tmp->get_calls().size()!=1) {
return false;
}
/* /*
call call
|_id:import |_id:import
|_call_func |_call_func
|_string:'filename' |_string:'filename'
*/ */
if (node->get_type()!=expr_type::ast_call) {
return false;
}
auto tmp = reinterpret_cast<call_expr*>(node);
auto first_expr = tmp->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()) {
return false;
}
// import("xxx");
if (tmp->get_calls().size()!=1) {
return false;
}
if (tmp->get_calls()[0]->get_type()!=expr_type::ast_callf) { if (tmp->get_calls()[0]->get_type()!=expr_type::ast_callf) {
return false; return false;
} }
@ -139,17 +134,6 @@ bool linker::exist(const std::string& file) {
return false; return false;
} }
u16 linker::find(const std::string& file) {
for(usize i = 0; i<files.size(); ++i) {
if (files[i]==file) {
return static_cast<u16>(i);
}
}
std::cerr << "unreachable: using this method incorrectly\n";
std::exit(-1);
return UINT16_MAX;
}
bool linker::check_self_import(const std::string& file) { bool linker::check_self_import(const std::string& file) {
for(const auto& i : module_load_stack) { for(const auto& i : module_load_stack) {
if (file==i) { if (file==i) {
@ -176,24 +160,26 @@ void linker::link(code_block* new_tree_root, code_block* old_tree_root) {
old_tree_root->get_expressions().clear(); old_tree_root->get_expressions().clear();
} }
code_block* linker::import_regular_file(call_expr* node) { code_block* linker::import_regular_file(expr* node) {
lexer lex;
parse par;
// get filename // get filename
auto filename = get_path(node); auto filename = get_path(node);
// clear this node
for(auto i : node->get_calls()) { // clear import("xxx/xxx.nas") node
delete i; if (node->get_type()!=expr_type::ast_use) {
auto cast_node = reinterpret_cast<call_expr*>(node);
for(auto i : cast_node->get_calls()) {
delete i;
}
cast_node->get_calls().clear();
const auto& location = cast_node->get_first()->get_location();
delete cast_node->get_first();
cast_node->set_first(new nil_expr(location));
// this will make node to call_expr(nil),
// will not be optimized when generating bytecodes
} }
node->get_calls().clear();
auto location = node->get_first()->get_location();
delete node->get_first();
node->set_first(new nil_expr(location));
// this will make node to call_expr(nil),
// will not be optimized when generating bytecodes
// avoid infinite loading loop // avoid infinite loading loop
filename = find_file(filename, node->get_location()); filename = find_real_file_path(filename, node->get_location());
if (!filename.length()) { if (!filename.length()) {
return new code_block({0, 0, 0, 0, filename}); return new code_block({0, 0, 0, 0, filename});
} }
@ -208,27 +194,27 @@ code_block* linker::import_regular_file(call_expr* node) {
module_load_stack.push_back(filename); module_load_stack.push_back(filename);
// start importing... // start importing...
if (lex.scan(filename).geterr()) { lexer nasal_lexer;
parse nasal_parser;
if (nasal_lexer.scan(filename).geterr()) {
err.err("link", "error occurred when analysing <" + filename + ">"); err.err("link", "error occurred when analysing <" + filename + ">");
return new code_block({0, 0, 0, 0, filename}); return new code_block({0, 0, 0, 0, filename});
} }
if (par.compile(lex).geterr()) { if (nasal_parser.compile(nasal_lexer).geterr()) {
err.err("link", "error occurred when analysing <" + filename + ">"); err.err("link", "error occurred when analysing <" + filename + ">");
return new code_block({0, 0, 0, 0, filename}); return new code_block({0, 0, 0, 0, filename});
} }
// swap result out
auto parse_result = par.swap(nullptr); auto parse_result = nasal_parser.swap(nullptr);
// check if parse result has 'import' // check if parse result has 'import'
auto result = load(parse_result, find(filename)); auto result = load(parse_result, filename);
module_load_stack.pop_back(); module_load_stack.pop_back();
return result; return result;
} }
code_block* linker::import_nasal_lib() { code_block* linker::import_nasal_lib() {
lexer lex; auto filename = find_real_file_path("lib.nas", {0, 0, 0, 0, files[0]});
parse par;
auto filename = find_file("lib.nas", {0, 0, 0, 0, files[0]});
if (!filename.length()) { if (!filename.length()) {
return new code_block({0, 0, 0, 0, filename}); return new code_block({0, 0, 0, 0, filename});
} }
@ -240,22 +226,24 @@ code_block* linker::import_nasal_lib() {
} }
// start importing... // start importing...
if (lex.scan(filename).geterr()) { lexer nasal_lexer;
parse nasal_parser;
if (nasal_lexer.scan(filename).geterr()) {
err.err("link", err.err("link",
"error occurred when analysing library <" + filename + ">" "error occurred when analysing library <" + filename + ">"
); );
return new code_block({0, 0, 0, 0, filename}); return new code_block({0, 0, 0, 0, filename});
} }
if (par.compile(lex).geterr()) { if (nasal_parser.compile(nasal_lexer).geterr()) {
err.err("link", err.err("link",
"error occurred when analysing library <" + filename + ">" "error occurred when analysing library <" + filename + ">"
); );
return new code_block({0, 0, 0, 0, filename}); return new code_block({0, 0, 0, 0, filename});
} }
// swap result out
auto parse_result = par.swap(nullptr); auto parse_result = nasal_parser.swap(nullptr);
// check if library has 'import' (in fact it should not) // check if library has 'import' (in fact it should not)
return load(parse_result, find(filename)); return load(parse_result, filename);
} }
std::string linker::generate_module_name(const std::string& file_path) { std::string linker::generate_module_name(const std::string& file_path) {
@ -314,6 +302,12 @@ std::string linker::generate_module_name(const std::string& file_path) {
"will not be easily accessed." "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."
);
}
return module_name; return module_name;
} }
@ -353,8 +347,8 @@ definition_expr* linker::generate_module_definition(code_block* block) {
return def; return def;
} }
code_block* linker::load(code_block* program_root, u16 fileindex) { code_block* linker::load(code_block* program_root, const std::string& filename) {
auto tree = new code_block({0, 0, 0, 0, files[fileindex]}); auto tree = new code_block({0, 0, 0, 0, filename});
// load library, this ast will be linked with root directly // load library, this ast will be linked with root directly
// so no extra namespace is generated // so no extra namespace is generated
if (!lib_loaded) { if (!lib_loaded) {
@ -370,12 +364,13 @@ code_block* linker::load(code_block* program_root, u16 fileindex) {
if (!import_check(import_ast_node)) { if (!import_check(import_ast_node)) {
break; break;
} }
auto module_code_block = import_regular_file((call_expr*)import_ast_node); auto module_code_block = import_regular_file(import_ast_node);
// this location should not be a reference, may cause use after free!
const auto location = import_ast_node->get_location();
// after importing the regular file as module, delete this node // after importing the regular file as module, delete this node
const auto loc = import_ast_node->get_location();
delete import_ast_node; delete import_ast_node;
// and replace the node with null_expr node // and replace the node with null_expr node
import_ast_node = new null_expr(loc); import_ast_node = new null_expr(location);
// then we generate a function warping the code block, // then we generate a function warping the code block,
// and export the necessary global symbols in this code block // and export the necessary global symbols in this code block
// by generate a return statement, with a hashmap return value // by generate a return statement, with a hashmap return value
@ -397,7 +392,7 @@ const error& linker::link(
// scan root and import files // scan root and import files
// then generate a new ast and return to import_ast // then generate a new ast and return to import_ast
// the main file's index is 0 // the main file's index is 0
auto new_tree_root = load(parse.tree(), 0); auto new_tree_root = load(parse.tree(), self);
auto old_tree_root = parse.swap(new_tree_root); auto old_tree_root = parse.swap(new_tree_root);
delete old_tree_root; delete old_tree_root;
return err; return err;

View File

@ -36,18 +36,17 @@ private:
private: private:
bool import_check(expr*); bool import_check(expr*);
bool exist(const std::string&); bool exist(const std::string&);
u16 find(const std::string&);
bool check_self_import(const std::string&); bool check_self_import(const std::string&);
std::string generate_self_import_path(const std::string&); std::string generate_self_import_path(const std::string&);
void link(code_block*, code_block*); void link(code_block*, code_block*);
std::string get_path(call_expr*); std::string get_path(expr*);
std::string find_file(const std::string&, const span&); std::string find_real_file_path(const std::string&, const span&);
code_block* import_regular_file(call_expr*); code_block* import_regular_file(expr*);
code_block* import_nasal_lib(); code_block* import_nasal_lib();
std::string generate_module_name(const std::string&); std::string generate_module_name(const std::string&);
return_expr* generate_module_return(code_block*); return_expr* generate_module_return(code_block*);
definition_expr* generate_module_definition(code_block*); definition_expr* generate_module_definition(code_block*);
code_block* load(code_block*, u16); code_block* load(code_block*, const std::string&);
public: public:
linker(); linker();

View File

@ -1,6 +1,6 @@
# flightgear developer environments simulator (beta) # flightgear developer environments simulator (beta)
# ValKmjolnir 2022 # ValKmjolnir 2022
import.std.runtime; use std.runtime;
println("-------------------------------------------------------------"); println("-------------------------------------------------------------");
println(" FlightGear simulated-env for developers project, since 2019"); println(" FlightGear simulated-env for developers project, since 2019");

View File

@ -1,13 +1,13 @@
# lib.nas # lib.nas
# 2019 ValKmjolnir # 2019 ValKmjolnir
import.std.coroutine; use std.coroutine;
import.std.math; use std.math;
import.std.string; use std.string;
import.std.io; use std.io;
import.std.os; use std.os;
import.std.bits; use std.bits;
import.std.unix; use std.unix;
# print is used to print all things in nasal, try and see how it works. # print is used to print all things in nasal, try and see how it works.
# this function uses std::cout to output logs. # this function uses std::cout to output logs.

View File

@ -1,5 +1,5 @@
import.std.padding; use std.padding;
import.std.process_bar; use std.process_bar;
var char_ttf=[ var char_ttf=[
[" "," "," "," "," "," "], [" "," "," "," "," "," "],

View File

@ -1,5 +1,5 @@
# Road check and auto pilot by ValKmjolnir # Road check and auto pilot by ValKmjolnir
import.std.fg_env; use std.fg_env;
var props = fg_env.props; var props = fg_env.props;
var geodinfo = fg_env.geodinfo; var geodinfo = fg_env.geodinfo;

View File

@ -1,4 +1,4 @@
import.std.queue; use std.queue;
rand(time(0)); rand(time(0));
var pixel=[' ','#','.','*']; var pixel=[' ','#','.','*'];

View File

@ -1,4 +1,4 @@
import.std.mat; use std.mat;
rand(time(0)); rand(time(0));

View File

@ -1,4 +1,4 @@
import.std.process_bar; use std.process_bar;
var ppm = func(filename, width, height, RGB) { var ppm = func(filename, width, height, RGB) {
# P3 use ASCII number # P3 use ASCII number

View File

@ -1,5 +1,5 @@
import.std.padding; use std.padding;
import.std.file; use std.file;
var source=file.find_all_files_with_extension("./src","cpp","h"); var source=file.find_all_files_with_extension("./src","cpp","h");
sort(source,func(a,b){return cmp(a,b)<0}); sort(source,func(a,b){return cmp(a,b)<0});

View File

@ -21,8 +21,8 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
import.module.libmat; use module.libmat;
import.std.runtime; use std.runtime;
func(){ func(){
# allocate more spaces # allocate more spaces

View File

@ -1,7 +1,7 @@
# coroutine.nas by ValKmjolnir # coroutine.nas by ValKmjolnir
# 2022/5/19 # 2022/5/19
import.std.process_bar; use std.process_bar;
import.std.padding; use std.padding;
if(os.platform()=="windows"){ if(os.platform()=="windows"){
system("chcp 65001"); system("chcp 65001");

View File

@ -1,5 +1,5 @@
import.std.padding; use std.padding;
import.std.process_bar; use std.process_bar;
var mess=func(vec) { var mess=func(vec) {
srand(); srand();

View File

@ -1,4 +1,4 @@
import.std.runtime; use std.runtime;
var mod = math.mod; var mod = math.mod;

View File

@ -1,4 +1,4 @@
import.std.process_bar; use std.process_bar;
var ppm = func(filename, width, height, RGB) { var ppm = func(filename, width, height, RGB) {
# P3 use ASCII number # P3 use ASCII number

View File

@ -1,4 +1,4 @@
import.module.libkey; use module.libkey;
srand(); srand();

View File

@ -1,4 +1,4 @@
import.std.runtime; use std.runtime;
var test_func = func(test_processes...) { var test_func = func(test_processes...) {
var test_process_total = maketimestamp(); var test_process_total = maketimestamp();

View File

@ -1,7 +1,7 @@
# hexdump.nas by ValKmjolnir # hexdump.nas by ValKmjolnir
# 2021/8/13 # 2021/8/13
import.std.file; use std.file;
import.std.runtime; use std.runtime;
# init # init
var hex=func(){ var hex=func(){

View File

@ -1,4 +1,4 @@
import.module.libsock; use module.libsock;
var socket = libsock.socket; var socket = libsock.socket;

View File

@ -1,5 +1,5 @@
import.std.json; use std.json;
import.std.process_bar; use std.process_bar;
var ss = json.stringify({ var ss = json.stringify({
vec:[0,1,2], vec:[0,1,2],

View File

@ -1,6 +1,6 @@
import.module.libsock; use module.libsock;
import.std.json; use std.json;
import.std.runtime; use std.runtime;
var socket = libsock.socket; var socket = libsock.socket;

View File

@ -1,5 +1,5 @@
import.std.process_bar; use std.process_bar;
import.std.runtime; use std.runtime;
var new_map=func(width,height){ var new_map=func(width,height){
var tmp=[]; var tmp=[];

View File

@ -1,6 +1,6 @@
import.test.md5_self; use test.md5_self;
import.std.process_bar; use std.process_bar;
import.std.file; use std.file;
srand(); srand();

View File

@ -1,5 +1,5 @@
import.std.dylib; use std.dylib;
import.module.libfib; use module.libfib;
println(keys(libfib)); println(keys(libfib));
libfib.test_ghost(); libfib.test_ghost();

View File

@ -1,6 +1,6 @@
import.std.process_bar; use std.process_bar;
import.module.libkey; use module.libkey;
import.std.runtime; use std.runtime;
var is_windows_platform=os.platform()=="windows"; var is_windows_platform=os.platform()=="windows";
var is_macos_platform=os.platform()=="macOS"; var is_macos_platform=os.platform()=="macOS";

View File

@ -1,4 +1,4 @@
import.std.process_bar; use std.process_bar;
var ppm = func(filename, width, height, RGB) { var ppm = func(filename, width, height, RGB) {
# P3 use ASCII number # P3 use ASCII number

View File

@ -1,4 +1,4 @@
import.std.runtime; use std.runtime;
# basic type # basic type
nil; nil;

View File

@ -1,5 +1,5 @@
# this will cause error # this will cause error
# import.b; # use b;
println("init a"); println("init a");
var a = "hello"; var a = "hello";

View File

@ -1,3 +1,3 @@
import.a; use a;
println("init b"); println("init b");

View File

@ -1,3 +1,3 @@
import.b; use b;
println("init c"); println("init c");

View File

@ -1,6 +1,6 @@
import.c; use c;
import.a; use a;
import.b; use b;
println(a); println(a);
println(b); println(b);

View File

@ -1,6 +1,6 @@
import.module.libkey; use module.libkey;
import.std.list; use std.list;
import.std.runtime; use std.runtime;
var game=func(x,y){ var game=func(x,y){
rand(time(0)); rand(time(0));

View File

@ -1,5 +1,5 @@
import.module.libkey; use module.libkey;
import.std.runtime; use std.runtime;
var color=[ var color=[
"\e[31m","\e[32m","\e[33m","\e[34m","\e[35m","\e[36m", "\e[31m","\e[32m","\e[33m","\e[34m","\e[35m","\e[36m",

View File

@ -1,4 +1,4 @@
import.std.runtime; use std.runtime;
var os_time=func(){ var os_time=func(){
return "[\e[33;1m"~os.time()~"\e[0m] "; return "[\e[33;1m"~os.time()~"\e[0m] ";

View File

@ -1,4 +1,4 @@
import.std.runtime; use std.runtime;
var to_lower=func(s){ var to_lower=func(s){
var tmp=""; var tmp="";

View File

@ -1,4 +1,4 @@
import.std.file; use std.file;
var tips = func() { var tips = func() {
println("usage:"); println("usage:");