optimize location info gen in codegen

and refactor lib.nas, add multiple native modules
This commit is contained in:
ValKmjolnir 2023-07-23 23:57:25 +08:00
parent 51a0ef6b0c
commit 788e0026c2
31 changed files with 477 additions and 356 deletions

64
doc/namespace.md Normal file
View File

@ -0,0 +1,64 @@
# Nasal Namespace
![feigenbaum](./pic/feigenbaum.png)
## Introduction
In this nasal interpreter,
we use this way below to construct namespaces:
- library is linked directly with the script
- module is wraped by a function generated by linker, and return a hash
## Library
Library file is linked with script file directly, like this:
In `std/lib.nas`:
```nasal
var a = 1;
```
In `example.nas`:
```nasal
var b = 1;
```
At the link stage,
in fact we put the ast of two files together to make a new ast,
so the result is equal to:
```nasal
var a = 1;
var b = 1;
```
## Module
Modules is wraped up by a function,
and return a hash, for example:
In `std/example_module.nas`:
```nasal
var a = 1;
```
We analysed this file and generated the ast.
Then we find all the global symbols.
At last we use the information of all the globals symbols in this file to generate a hash to return.
So the result is equal to:
```nasal
var example_module = func {
# source code begin
var a = 1;
# source code end
return {
a: a
};
}();
```

View File

@ -1,3 +1,4 @@
var libfib=func(){ var libfib=func(){
var dl=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so")); var dl=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib=dl.fib; var fib=dl.fib;

View File

@ -2,13 +2,6 @@
#include <iostream> #include <iostream>
bool ast_dumper::visit_file_info(file_info* node) {
dump_indent();
std::cout << "file \"" << node->get_file_name() << "\"";
std::cout << format_location(node->get_location());
return true;
}
bool ast_dumper::visit_null_expr(null_expr* node) { bool ast_dumper::visit_null_expr(null_expr* node) {
dump_indent(); dump_indent();
std::cout << "null" << format_location(node->get_location()); std::cout << "null" << format_location(node->get_location());

View File

@ -39,7 +39,6 @@ private:
} }
public: public:
bool visit_file_info(file_info*) override;
bool visit_null_expr(null_expr*) override; bool visit_null_expr(null_expr*) override;
bool visit_nil_expr(nil_expr*) override; bool visit_nil_expr(nil_expr*) override;
bool visit_number_literal(number_literal*) override; bool visit_number_literal(number_literal*) override;

View File

@ -10,10 +10,6 @@ bool ast_visitor::visit_call(call* node) {
return true; return true;
} }
bool ast_visitor::visit_file_info(file_info* node) {
return true;
}
bool ast_visitor::visit_null_expr(null_expr* node) { bool ast_visitor::visit_null_expr(null_expr* node) {
return true; return true;
} }

View File

@ -6,7 +6,6 @@ class ast_visitor {
public: public:
virtual bool visit_expr(expr*); virtual bool visit_expr(expr*);
virtual bool visit_call(call*); virtual bool visit_call(call*);
virtual bool visit_file_info(file_info*);
virtual bool visit_null_expr(null_expr*); virtual bool visit_null_expr(null_expr*);
virtual bool visit_nil_expr(nil_expr*); virtual bool visit_nil_expr(nil_expr*);
virtual bool visit_number_literal(number_literal*); virtual bool visit_number_literal(number_literal*);

View File

@ -9,10 +9,6 @@ void call::accept(ast_visitor* visitor) {
visitor->visit_call(this); visitor->visit_call(this);
} }
void file_info::accept(ast_visitor* visitor) {
visitor->visit_file_info(this);
}
void null_expr::accept(ast_visitor* visitor) { void null_expr::accept(ast_visitor* visitor) {
visitor->visit_null_expr(this); visitor->visit_null_expr(this);
} }

View File

@ -8,7 +8,6 @@
enum class expr_type:u32 { enum class expr_type:u32 {
ast_null = 0, // null node ast_null = 0, // null node
ast_file_info, // stores file info
ast_block, // code block ast_block, // code block
ast_nil, // nil keyword ast_nil, // nil keyword
ast_num, // number, basic value type ast_num, // number, basic value type
@ -84,21 +83,6 @@ public:
virtual void accept(ast_visitor*); virtual void accept(ast_visitor*);
}; };
class file_info:public expr {
private:
uint16_t index;
std::string filename;
public:
file_info(const span& location, uint16_t file_index, const std::string& name):
expr(location, expr_type::ast_file_info),
index(file_index), filename(name) {}
~file_info() = default;
uint16_t get_index() const {return index;}
const std::string& get_file_name() const {return filename;}
void accept(ast_visitor*) override;
};
class null_expr:public expr { class null_expr:public expr {
public: public:
null_expr(const span& location): null_expr(const span& location):

View File

@ -100,42 +100,44 @@ i32 codegen::upvalue_find(const std::string& name) {
return index; return index;
} }
void codegen::gen(u8 operation_code, u32 num, u32 line) { void codegen::gen(u8 operation_code, u32 num, const span& loc) {
code.push_back({operation_code, fileindex, num, line}); code.push_back({operation_code,
static_cast<u16>(file_map.at(loc.file)),
num, loc.begin_line});
} }
void codegen::num_gen(number_literal* node) { void codegen::num_gen(number_literal* node) {
f64 num = node->get_number(); f64 num = node->get_number();
regist_num(num); regist_num(num);
gen(op_pnum,const_number_map.at(num), node->get_line()); gen(op_pnum, const_number_map.at(num), node->get_location());
} }
void codegen::str_gen(string_literal* node) { void codegen::str_gen(string_literal* node) {
const auto& str = node->get_content(); const auto& str = node->get_content();
regist_str(str); regist_str(str);
gen(op_pstr, const_string_map.at(str), node->get_line()); gen(op_pstr, const_string_map.at(str), node->get_location());
} }
void codegen::bool_gen(bool_literal* node) { void codegen::bool_gen(bool_literal* node) {
f64 num = node->get_flag()? 1:0; f64 num = node->get_flag()? 1:0;
regist_num(num); regist_num(num);
gen(op_pnum, const_number_map.at(num), node->get_line()); gen(op_pnum, const_number_map.at(num), node->get_location());
} }
void codegen::vec_gen(vector_expr* node) { void codegen::vec_gen(vector_expr* node) {
for(auto child : node->get_elements()) { for(auto child : node->get_elements()) {
calc_gen(child); calc_gen(child);
} }
gen(op_newv, node->get_elements().size(), node->get_line()); gen(op_newv, node->get_elements().size(), node->get_location());
} }
void codegen::hash_gen(hash_expr* node) { void codegen::hash_gen(hash_expr* node) {
gen(op_newh, 0, node->get_line()); gen(op_newh, 0, node->get_location());
for(auto child : node->get_members()) { for(auto child : node->get_members()) {
calc_gen(child->get_value()); calc_gen(child->get_value());
const auto& field_name = child->get_name(); const auto& field_name = child->get_name();
regist_str(field_name); regist_str(field_name);
gen(op_happ, const_string_map.at(field_name), child->get_line()); gen(op_happ, const_string_map.at(field_name), child->get_location());
} }
} }
@ -175,9 +177,9 @@ void codegen::func_gen(function* node) {
} }
usize newf=code.size(); usize newf=code.size();
gen(op_newf, 0, node->get_line()); gen(op_newf, 0, node->get_location());
usize lsize=code.size(); usize lsize=code.size();
gen(op_intl, 0, node->get_line()); gen(op_intl, 0, node->get_location());
// add special keyword 'me' into symbol table // add special keyword 'me' into symbol table
// this symbol is only used in local scope(function's scope) // this symbol is only used in local scope(function's scope)
@ -196,14 +198,14 @@ void codegen::func_gen(function* node) {
regist_str(name); regist_str(name);
switch(tmp->get_parameter_type()) { switch(tmp->get_parameter_type()) {
case parameter::param_type::normal_parameter: case parameter::param_type::normal_parameter:
gen(op_para, const_string_map.at(name), tmp->get_line()); gen(op_para, const_string_map.at(name), tmp->get_location());
break; break;
case parameter::param_type::default_parameter: case parameter::param_type::default_parameter:
calc_gen(tmp->get_default_value()); calc_gen(tmp->get_default_value());
gen(op_deft, const_string_map.at(name), tmp->get_line()); gen(op_deft, const_string_map.at(name), tmp->get_location());
break; break;
case parameter::param_type::dynamic_parameter: case parameter::param_type::dynamic_parameter:
gen(op_dyn, const_string_map.at(name), tmp->get_line()); gen(op_dyn, const_string_map.at(name), tmp->get_location());
break; break;
} }
add_symbol(name); add_symbol(name);
@ -211,7 +213,7 @@ void codegen::func_gen(function* node) {
code[newf].num = code.size()+1; // entry code[newf].num = code.size()+1; // entry
usize jmp_ptr = code.size(); usize jmp_ptr = code.size();
gen(op_jmp, 0, node->get_line()); gen(op_jmp, 0, node->get_location());
auto block = node->get_code_block(); auto block = node->get_code_block();
// search symbols first, must use after loading parameters // search symbols first, must use after loading parameters
@ -244,8 +246,8 @@ void codegen::func_gen(function* node) {
if (!block->get_expressions().size() || if (!block->get_expressions().size() ||
block->get_expressions().back()->get_type()!=expr_type::ast_ret) { block->get_expressions().back()->get_type()!=expr_type::ast_ret) {
gen(op_pnil, 0, block->get_line()); gen(op_pnil, 0, block->get_location());
gen(op_ret, 0, block->get_line()); gen(op_ret, 0, block->get_location());
} }
code[jmp_ptr].num = code.size(); code[jmp_ptr].num = code.size();
} }
@ -269,7 +271,7 @@ void codegen::call_id(identifier* node) {
const auto& name = node->get_name(); const auto& name = node->get_name();
for(u32 i = 0; builtin[i].name; ++i) { for(u32 i = 0; builtin[i].name; ++i) {
if (builtin[i].name==name) { if (builtin[i].name==name) {
gen(op_callb, i, node->get_line()); gen(op_callb, i, node->get_location());
if (local.empty()) { if (local.empty()) {
die("should warp native function in local scope", die("should warp native function in local scope",
node->get_location()); node->get_location());
@ -279,15 +281,15 @@ void codegen::call_id(identifier* node) {
} }
i32 index; i32 index;
if ((index=local_find(name))>=0) { if ((index=local_find(name))>=0) {
gen(op_calll, index, node->get_line()); gen(op_calll, index, node->get_location());
return; return;
} }
if ((index=upvalue_find(name))>=0) { if ((index=upvalue_find(name))>=0) {
gen(op_upval, index, node->get_line()); gen(op_upval, index, node->get_location());
return; return;
} }
if ((index=global_find(name))>=0) { if ((index=global_find(name))>=0) {
gen(op_callg, index, node->get_line()); gen(op_callg, index, node->get_location());
return; return;
} }
die("undefined symbol \"" + name + "\"", node->get_location()); die("undefined symbol \"" + name + "\"", node->get_location());
@ -295,7 +297,7 @@ void codegen::call_id(identifier* node) {
void codegen::call_hash_gen(call_hash* node) { void codegen::call_hash_gen(call_hash* node) {
regist_str(node->get_field()); regist_str(node->get_field());
gen(op_callh, const_string_map.at(node->get_field()), node->get_line()); gen(op_callh, const_string_map.at(node->get_field()), node->get_location());
} }
void codegen::call_vector_gen(call_vector* node) { void codegen::call_vector_gen(call_vector* node) {
@ -303,39 +305,39 @@ void codegen::call_vector_gen(call_vector* node) {
if (node->get_slices().size()==1 && if (node->get_slices().size()==1 &&
!node->get_slices()[0]->get_end()) { !node->get_slices()[0]->get_end()) {
calc_gen(node->get_slices()[0]->get_begin()); calc_gen(node->get_slices()[0]->get_begin());
gen(op_callv, 0, node->get_slices()[0]->get_line()); gen(op_callv, 0, node->get_slices()[0]->get_location());
return; return;
} }
gen(op_slcbeg, 0, node->get_line()); gen(op_slcbeg, 0, node->get_location());
for(auto tmp : node->get_slices()) { for(auto tmp : node->get_slices()) {
if (!tmp->get_end()) { if (!tmp->get_end()) {
calc_gen(tmp->get_begin()); calc_gen(tmp->get_begin());
gen(op_slc, 0, tmp->get_line()); gen(op_slc, 0, tmp->get_location());
} else { } else {
calc_gen(tmp->get_begin()); calc_gen(tmp->get_begin());
calc_gen(tmp->get_end()); calc_gen(tmp->get_end());
gen(op_slc2, 0, tmp->get_line()); gen(op_slc2, 0, tmp->get_location());
} }
} }
gen(op_slcend, 0, node->get_line()); gen(op_slcend, 0, node->get_location());
} }
void codegen::call_func_gen(call_function* node) { void codegen::call_func_gen(call_function* node) {
if (node->get_argument().size() && if (node->get_argument().size() &&
node->get_argument()[0]->get_type()==expr_type::ast_pair) { node->get_argument()[0]->get_type()==expr_type::ast_pair) {
gen(op_newh, 0, node->get_line()); gen(op_newh, 0, node->get_location());
for(auto child : node->get_argument()) { for(auto child : node->get_argument()) {
calc_gen(((hash_pair*)child)->get_value()); calc_gen(((hash_pair*)child)->get_value());
const auto& field_name = ((hash_pair*)child)->get_name(); const auto& field_name = ((hash_pair*)child)->get_name();
regist_str(field_name); regist_str(field_name);
gen(op_happ, const_string_map.at(field_name), child->get_line()); gen(op_happ, const_string_map.at(field_name), child->get_location());
} }
gen(op_callfh, 0, node->get_line()); gen(op_callfh, 0, node->get_location());
} else { } else {
for(auto child : node->get_argument()) { for(auto child : node->get_argument()) {
calc_gen(child); calc_gen(child);
} }
gen(op_callfv, node->get_argument().size(), node->get_line()); gen(op_callfv, node->get_argument().size(), node->get_location());
} }
} }
@ -390,15 +392,15 @@ void codegen::mcall_id(identifier* node) {
} }
i32 index; i32 index;
if ((index=local_find(name))>=0) { if ((index=local_find(name))>=0) {
gen(op_mcalll, index, node->get_line()); gen(op_mcalll, index, node->get_location());
return; return;
} }
if ((index=upvalue_find(name))>=0) { if ((index=upvalue_find(name))>=0) {
gen(op_mupval, index, node->get_line()); gen(op_mupval, index, node->get_location());
return; return;
} }
if ((index=global_find(name))>=0) { if ((index=global_find(name))>=0) {
gen(op_mcallg, index, node->get_line()); gen(op_mcallg, index, node->get_location());
return; return;
} }
die("undefined symbol \"" + name + "\"", node->get_location()); die("undefined symbol \"" + name + "\"", node->get_location());
@ -415,20 +417,20 @@ void codegen::mcall_vec(call_vector* node) {
return; return;
} }
calc_gen(call->get_begin()); calc_gen(call->get_begin());
gen(op_mcallv, 0, node->get_line()); gen(op_mcallv, 0, node->get_location());
} }
void codegen::mcall_hash(call_hash* node) { void codegen::mcall_hash(call_hash* node) {
regist_str(node->get_field()); regist_str(node->get_field());
gen(op_mcallh, const_string_map.at(node->get_field()), node->get_line()); gen(op_mcallh, const_string_map.at(node->get_field()), node->get_location());
} }
void codegen::single_def(definition_expr* node) { void codegen::single_def(definition_expr* node) {
const auto& str = node->get_variable_name()->get_name(); const auto& str = node->get_variable_name()->get_name();
calc_gen(node->get_value()); calc_gen(node->get_value());
local.empty()? local.empty()?
gen(op_loadg, global_find(str), node->get_line()): gen(op_loadg, global_find(str), node->get_location()):
gen(op_loadl, local_find(str), node->get_line()); gen(op_loadl, local_find(str), node->get_location());
} }
void codegen::multi_def(definition_expr* node) { void codegen::multi_def(definition_expr* node) {
@ -448,21 +450,21 @@ void codegen::multi_def(definition_expr* node) {
calc_gen(vals[i]); calc_gen(vals[i]);
const auto& name = identifiers[i]->get_name(); const auto& name = identifiers[i]->get_name();
local.empty()? local.empty()?
gen(op_loadg, global_find(name), identifiers[i]->get_line()): gen(op_loadg, global_find(name), identifiers[i]->get_location()):
gen(op_loadl, local_find(name), identifiers[i]->get_line()); gen(op_loadl, local_find(name), identifiers[i]->get_location());
} }
return; return;
} }
// (var a,b,c) = [0,1,2]; // (var a,b,c) = [0,1,2];
calc_gen(node->get_value()); calc_gen(node->get_value());
for(usize i = 0; i<size; ++i) { for(usize i = 0; i<size; ++i) {
gen(op_callvi, i, node->get_value()->get_line()); gen(op_callvi, i, node->get_value()->get_location());
const auto& name = identifiers[i]->get_name(); const auto& name = identifiers[i]->get_name();
local.empty()? local.empty()?
gen(op_loadg, global_find(name), identifiers[i]->get_line()): gen(op_loadg, global_find(name), identifiers[i]->get_location()):
gen(op_loadl, local_find(name), identifiers[i]->get_line()); gen(op_loadl, local_find(name), identifiers[i]->get_location());
} }
gen(op_pop, 0, node->get_line()); gen(op_pop, 0, node->get_location());
} }
void codegen::def_gen(definition_expr* node) { void codegen::def_gen(definition_expr* node) {
@ -477,7 +479,7 @@ void codegen::assignment_expression(assignment_expr* node) {
case assignment_expr::assign_type::equal: case assignment_expr::assign_type::equal:
calc_gen(node->get_right()); calc_gen(node->get_right());
mcall(node->get_left()); mcall(node->get_left());
gen(op_meq, 0, node->get_line()); gen(op_meq, 0, node->get_location());
break; break;
case assignment_expr::assign_type::add_equal: case assignment_expr::assign_type::add_equal:
if (node->get_right()->get_type()!=expr_type::ast_num) { if (node->get_right()->get_type()!=expr_type::ast_num) {
@ -485,11 +487,11 @@ void codegen::assignment_expression(assignment_expr* node) {
} }
mcall(node->get_left()); mcall(node->get_left());
if (node->get_right()->get_type()!=expr_type::ast_num) { if (node->get_right()->get_type()!=expr_type::ast_num) {
gen(op_addeq, 0, node->get_line()); gen(op_addeq, 0, node->get_location());
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); regist_num(num);
gen(op_addeqc, const_number_map[num], node->get_line()); gen(op_addeqc, const_number_map[num], node->get_location());
} }
break; break;
case assignment_expr::assign_type::sub_equal: case assignment_expr::assign_type::sub_equal:
@ -498,11 +500,11 @@ void codegen::assignment_expression(assignment_expr* node) {
} }
mcall(node->get_left()); mcall(node->get_left());
if (node->get_right()->get_type()!=expr_type::ast_num) { if (node->get_right()->get_type()!=expr_type::ast_num) {
gen(op_subeq, 0, node->get_line()); gen(op_subeq, 0, node->get_location());
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); regist_num(num);
gen(op_subeqc, const_number_map[num], node->get_line()); gen(op_subeqc, const_number_map[num], node->get_location());
} }
break; break;
case assignment_expr::assign_type::mult_equal: case assignment_expr::assign_type::mult_equal:
@ -511,11 +513,11 @@ void codegen::assignment_expression(assignment_expr* node) {
} }
mcall(node->get_left()); mcall(node->get_left());
if (node->get_right()->get_type()!=expr_type::ast_num) { if (node->get_right()->get_type()!=expr_type::ast_num) {
gen(op_muleq, 0, node->get_line()); gen(op_muleq, 0, node->get_location());
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); regist_num(num);
gen(op_muleqc, const_number_map[num], node->get_line()); gen(op_muleqc, const_number_map[num], node->get_location());
} }
break; break;
case assignment_expr::assign_type::div_equal: case assignment_expr::assign_type::div_equal:
@ -524,11 +526,11 @@ void codegen::assignment_expression(assignment_expr* node) {
} }
mcall(node->get_left()); mcall(node->get_left());
if (node->get_right()->get_type()!=expr_type::ast_num) { if (node->get_right()->get_type()!=expr_type::ast_num) {
gen(op_diveq, 0, node->get_line()); gen(op_diveq, 0, node->get_location());
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); regist_num(num);
gen(op_diveqc, const_number_map[num], node->get_line()); gen(op_diveqc, const_number_map[num], node->get_location());
} }
break; break;
case assignment_expr::assign_type::concat_equal: case assignment_expr::assign_type::concat_equal:
@ -537,27 +539,27 @@ void codegen::assignment_expression(assignment_expr* node) {
} }
mcall(node->get_left()); mcall(node->get_left());
if (node->get_right()->get_type()!=expr_type::ast_str) { if (node->get_right()->get_type()!=expr_type::ast_str) {
gen(op_lnkeq, 0, node->get_line()); gen(op_lnkeq, 0, node->get_location());
} else { } else {
const auto& str = ((string_literal*)node->get_right())->get_content(); const auto& str = ((string_literal*)node->get_right())->get_content();
regist_str(str); regist_str(str);
gen(op_lnkeqc, const_string_map[str], node->get_line()); gen(op_lnkeqc, const_string_map[str], node->get_location());
} }
break; break;
case assignment_expr::assign_type::bitwise_and_equal: case assignment_expr::assign_type::bitwise_and_equal:
calc_gen(node->get_right()); calc_gen(node->get_right());
mcall(node->get_left()); mcall(node->get_left());
gen(op_btandeq, 0, node->get_line()); gen(op_btandeq, 0, node->get_location());
break; break;
case assignment_expr::assign_type::bitwise_or_equal: case assignment_expr::assign_type::bitwise_or_equal:
calc_gen(node->get_right()); calc_gen(node->get_right());
mcall(node->get_left()); mcall(node->get_left());
gen(op_btoreq, 0, node->get_line()); gen(op_btoreq, 0, node->get_location());
break; break;
case assignment_expr::assign_type::bitwise_xor_equal: case assignment_expr::assign_type::bitwise_xor_equal:
calc_gen(node->get_right()); calc_gen(node->get_right());
mcall(node->get_left()); mcall(node->get_left());
gen(op_btxoreq, 0, node->get_line()); gen(op_btxoreq, 0, node->get_location());
break; break;
} }
} }
@ -581,7 +583,7 @@ void codegen::assignment_statement(assignment_expr* node) {
if (code.back().op==op_meq) { if (code.back().op==op_meq) {
code.back().num=1; code.back().num=1;
} else { } else {
gen(op_pop, 0, node->get_line()); gen(op_pop, 0, node->get_location());
} }
} }
break; break;
@ -599,7 +601,7 @@ void codegen::assignment_statement(assignment_expr* node) {
} else if (op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) { } else if (op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) {
code.back().op=code.back().op-op_addeqc+op_addecp; code.back().op=code.back().op-op_addeqc+op_addecp;
} else { } else {
gen(op_pop, 0, node->get_line()); gen(op_pop, 0, node->get_location());
} }
break; break;
} }
@ -630,7 +632,7 @@ void codegen::multi_assign_gen(multi_assign* node) {
} else if (code.back().op==op_mcallg) { } else if (code.back().op==op_mcallg) {
code.back().op=op_loadg; code.back().op=op_loadg;
} else { } else {
gen(op_meq, 1, tuple[i]->get_line()); gen(op_meq, 1, tuple[i]->get_location());
} }
} }
return; return;
@ -638,7 +640,7 @@ void codegen::multi_assign_gen(multi_assign* node) {
calc_gen(node->get_value()); calc_gen(node->get_value());
auto& tuple = node->get_tuple()->get_elements(); auto& tuple = node->get_tuple()->get_elements();
for(i32 i = 0; i<size; ++i) { for(i32 i = 0; i<size; ++i) {
gen(op_callvi, i, node->get_value()->get_line()); gen(op_callvi, i, node->get_value()->get_location());
// multi assign user loadl and loadg to avoid meq's stack-- // multi assign user loadl and loadg to avoid meq's stack--
// and this operation changes local and global value directly // and this operation changes local and global value directly
mcall(tuple[i]); mcall(tuple[i]);
@ -649,35 +651,35 @@ void codegen::multi_assign_gen(multi_assign* node) {
} else if (code.back().op==op_mcallg) { } else if (code.back().op==op_mcallg) {
code.back().op=op_loadg; code.back().op=op_loadg;
} else { } else {
gen(op_meq, 1, tuple[i]->get_line()); gen(op_meq, 1, tuple[i]->get_location());
} }
} }
gen(op_pop, 0, node->get_line()); gen(op_pop, 0, node->get_location());
} }
void codegen::cond_gen(condition_expr* node) { void codegen::cond_gen(condition_expr* node) {
std::vector<usize> jmp_label; std::vector<usize> jmp_label;
calc_gen(node->get_if_statement()->get_condition()); calc_gen(node->get_if_statement()->get_condition());
auto ptr = code.size(); auto ptr = code.size();
gen(op_jf, 0, node->get_if_statement()->get_line()); gen(op_jf, 0, node->get_if_statement()->get_location());
block_gen(node->get_if_statement()->get_code_block()); block_gen(node->get_if_statement()->get_code_block());
if (node->get_elsif_stataments().size() || if (node->get_elsif_stataments().size() ||
node->get_else_statement()) { node->get_else_statement()) {
jmp_label.push_back(code.size()); jmp_label.push_back(code.size());
gen(op_jmp, 0, node->get_if_statement()->get_line()); gen(op_jmp, 0, node->get_if_statement()->get_location());
} }
code[ptr].num = code.size(); code[ptr].num = code.size();
for(auto tmp : node->get_elsif_stataments()) { for(auto tmp : node->get_elsif_stataments()) {
calc_gen(tmp->get_condition()); calc_gen(tmp->get_condition());
ptr = code.size(); ptr = code.size();
gen(op_jf, 0, tmp->get_line()); gen(op_jf, 0, tmp->get_location());
block_gen(tmp->get_code_block()); block_gen(tmp->get_code_block());
// the last condition doesn't need to jmp // the last condition doesn't need to jmp
if (tmp!=node->get_elsif_stataments().back() || if (tmp!=node->get_elsif_stataments().back() ||
node->get_else_statement()) { node->get_else_statement()) {
jmp_label.push_back(code.size()); jmp_label.push_back(code.size());
gen(op_jmp, 0, tmp->get_line()); gen(op_jmp, 0, tmp->get_location());
} }
code[ptr].num=code.size(); code[ptr].num=code.size();
} }
@ -719,10 +721,10 @@ void codegen::while_gen(while_expr* node) {
usize loop_ptr = code.size(); usize loop_ptr = code.size();
calc_gen(node->get_condition()); calc_gen(node->get_condition());
usize condition_ptr = code.size(); usize condition_ptr = code.size();
gen(op_jf, 0, node->get_condition()->get_line()); gen(op_jf, 0, node->get_condition()->get_location());
block_gen(node->get_code_block()); block_gen(node->get_code_block());
gen(op_jmp, loop_ptr, node->get_code_block()->get_line()); gen(op_jmp, loop_ptr, node->get_code_block()->get_location());
code[condition_ptr].num = code.size(); code[condition_ptr].num = code.size();
load_continue_break(code.size()-1, code.size()); load_continue_break(code.size()-1, code.size());
} }
@ -732,17 +734,17 @@ void codegen::for_gen(for_expr* node) {
usize jmp_place = code.size(); usize jmp_place = code.size();
if (node->get_condition()->get_type()==expr_type::ast_null) { if (node->get_condition()->get_type()==expr_type::ast_null) {
regist_num(1); regist_num(1);
gen(op_pnum, const_number_map.at(1), node->get_condition()->get_line()); gen(op_pnum, const_number_map.at(1), node->get_condition()->get_location());
} else { } else {
calc_gen(node->get_condition()); calc_gen(node->get_condition());
} }
usize label_exit = code.size(); usize label_exit = code.size();
gen(op_jf, 0, node->get_condition()->get_line()); gen(op_jf, 0, node->get_condition()->get_location());
block_gen(node->get_code_block()); block_gen(node->get_code_block());
usize continue_place = code.size(); usize continue_place = code.size();
statement_generation(node->get_step()); statement_generation(node->get_step());
gen(op_jmp, jmp_place, node->get_step()->get_line()); gen(op_jmp, jmp_place, node->get_step()->get_location());
code[label_exit].num = code.size(); code[label_exit].num = code.size();
load_continue_break(continue_place, code.size()); load_continue_break(continue_place, code.size());
@ -750,19 +752,19 @@ void codegen::for_gen(for_expr* node) {
void codegen::forei_gen(forei_expr* node) { void codegen::forei_gen(forei_expr* node) {
calc_gen(node->get_value()); calc_gen(node->get_value());
gen(op_cnt, 0, node->get_value()->get_line()); gen(op_cnt, 0, node->get_value()->get_location());
usize ptr = code.size(); usize ptr = code.size();
if (node->get_loop_type()==forei_expr::forei_loop_type::forindex) { if (node->get_loop_type()==forei_expr::forei_loop_type::forindex) {
gen(op_findex, 0, node->get_line()); gen(op_findex, 0, node->get_location());
} else { } else {
gen(op_feach, 0, node->get_line()); gen(op_feach, 0, node->get_location());
} }
if (node->get_iterator()->get_name()) { // define a new iterator if (node->get_iterator()->get_name()) { // define a new iterator
auto name_node = node->get_iterator()->get_name(); auto name_node = node->get_iterator()->get_name();
const auto& str = name_node->get_name(); const auto& str = name_node->get_name();
local.empty()? local.empty()?
gen(op_loadg, global_find(str), name_node->get_line()): gen(op_loadg, global_find(str), name_node->get_location()):
gen(op_loadl, local_find(str), name_node->get_line()); gen(op_loadl, local_find(str), name_node->get_location());
} else { // use exist variable as the iterator } else { // use exist variable as the iterator
mcall(node->get_iterator()->get_call()); mcall(node->get_iterator()->get_call());
if (code.back().op==op_mcallg) { if (code.back().op==op_mcallg) {
@ -772,17 +774,17 @@ void codegen::forei_gen(forei_expr* node) {
} else if (code.back().op==op_mupval) { } else if (code.back().op==op_mupval) {
code.back().op=op_loadu; code.back().op=op_loadu;
} else { } else {
gen(op_meq, 1, node->get_iterator()->get_line()); gen(op_meq, 1, node->get_iterator()->get_location());
} }
} }
++in_loop_level.back(); ++in_loop_level.back();
block_gen(node->get_code_block()); block_gen(node->get_code_block());
--in_loop_level.back(); --in_loop_level.back();
gen(op_jmp, ptr, node->get_line()); gen(op_jmp, ptr, node->get_location());
code[ptr].num=code.size(); code[ptr].num=code.size();
load_continue_break(code.size()-1, code.size()); load_continue_break(code.size()-1, code.size());
gen(op_pop, 0, node->get_value()->get_line());// pop vector gen(op_pop, 0, node->get_value()->get_location());// pop vector
gen(op_pop, 0, node->get_line());// pop iterator gen(op_pop, 0, node->get_location());// pop iterator
} }
void codegen::statement_generation(expr* node) { void codegen::statement_generation(expr* node) {
@ -806,7 +808,7 @@ void codegen::statement_generation(expr* node) {
case expr_type::ast_binary: case expr_type::ast_binary:
case expr_type::ast_ternary: case expr_type::ast_ternary:
calc_gen(node); calc_gen(node);
gen(op_pop, 0, node->get_line()); gen(op_pop, 0, node->get_location());
break; break;
default: break; default: break;
} }
@ -815,33 +817,33 @@ void codegen::statement_generation(expr* node) {
void codegen::or_gen(binary_operator* node) { void codegen::or_gen(binary_operator* node) {
calc_gen(node->get_left()); calc_gen(node->get_left());
usize label_jump_true_1 = code.size(); usize label_jump_true_1 = code.size();
gen(op_jt, 0, node->get_left()->get_line()); gen(op_jt, 0, node->get_left()->get_location());
gen(op_pop, 0, node->get_left()->get_line()); gen(op_pop, 0, node->get_left()->get_location());
calc_gen(node->get_right()); calc_gen(node->get_right());
usize label_jump_true_2 = code.size(); usize label_jump_true_2 = code.size();
gen(op_jt, 0, node->get_right()->get_line()); gen(op_jt, 0, node->get_right()->get_location());
gen(op_pop, 0, node->get_right()->get_line()); gen(op_pop, 0, node->get_right()->get_location());
gen(op_pnil, 0, node->get_right()->get_line()); gen(op_pnil, 0, node->get_right()->get_location());
code[label_jump_true_1].num = code[label_jump_true_2].num = code.size(); code[label_jump_true_1].num = code[label_jump_true_2].num = code.size();
} }
void codegen::and_gen(binary_operator* node) { void codegen::and_gen(binary_operator* node) {
calc_gen(node->get_left()); calc_gen(node->get_left());
gen(op_jt, code.size()+2, node->get_left()->get_line()); gen(op_jt, code.size()+2, node->get_left()->get_location());
usize lable_jump_false = code.size(); usize lable_jump_false = code.size();
gen(op_jmp, 0, node->get_left()->get_line()); gen(op_jmp, 0, node->get_left()->get_location());
gen(op_pop, 0, node->get_right()->get_line()); // jt jumps here gen(op_pop, 0, node->get_right()->get_location()); // jt jumps here
calc_gen(node->get_right()); calc_gen(node->get_right());
gen(op_jt, code.size()+3, node->get_right()->get_line()); gen(op_jt, code.size()+3, node->get_right()->get_location());
code[lable_jump_false].num = code.size(); code[lable_jump_false].num = code.size();
gen(op_pop, 0, node->get_right()->get_line()); gen(op_pop, 0, node->get_right()->get_location());
gen(op_pnil, 0, node->get_right()->get_line()); gen(op_pnil, 0, node->get_right()->get_location());
// jt jumps here, avoid pop and pnil // jt jumps here, avoid pop and pnil
} }
@ -849,11 +851,11 @@ void codegen::unary_gen(unary_operator* node) {
calc_gen(node->get_value()); calc_gen(node->get_value());
switch(node->get_operator_type()) { switch(node->get_operator_type()) {
case unary_operator::unary_type::negative: case unary_operator::unary_type::negative:
gen(op_usub, 0, node->get_line()); break; gen(op_usub, 0, node->get_location()); break;
case unary_operator::unary_type::logical_not: case unary_operator::unary_type::logical_not:
gen(op_lnot, 0, node->get_line()); break; gen(op_lnot, 0, node->get_location()); break;
case unary_operator::unary_type::bitwise_not: case unary_operator::unary_type::bitwise_not:
gen(op_bnot, 0, node->get_line()); break; gen(op_bnot, 0, node->get_location()); break;
} }
} }
@ -877,27 +879,27 @@ void codegen::binary_gen(binary_operator* node) {
case binary_operator::binary_type::cmpeq: case binary_operator::binary_type::cmpeq:
calc_gen(node->get_left()); calc_gen(node->get_left());
calc_gen(node->get_right()); calc_gen(node->get_right());
gen(op_eq, 0, node->get_line()); gen(op_eq, 0, node->get_location());
return; return;
case binary_operator::binary_type::cmpneq: case binary_operator::binary_type::cmpneq:
calc_gen(node->get_left()); calc_gen(node->get_left());
calc_gen(node->get_right()); calc_gen(node->get_right());
gen(op_neq, 0, node->get_line()); gen(op_neq, 0, node->get_location());
return; return;
case binary_operator::binary_type::bitwise_or: case binary_operator::binary_type::bitwise_or:
calc_gen(node->get_left()); calc_gen(node->get_left());
calc_gen(node->get_right()); calc_gen(node->get_right());
gen(op_btor, 0, node->get_line()); gen(op_btor, 0, node->get_location());
return; return;
case binary_operator::binary_type::bitwise_xor: case binary_operator::binary_type::bitwise_xor:
calc_gen(node->get_left()); calc_gen(node->get_left());
calc_gen(node->get_right()); calc_gen(node->get_right());
gen(op_btxor, 0, node->get_line()); gen(op_btxor, 0, node->get_location());
return; return;
case binary_operator::binary_type::bitwise_and: case binary_operator::binary_type::bitwise_and:
calc_gen(node->get_left()); calc_gen(node->get_left());
calc_gen(node->get_right()); calc_gen(node->get_right());
gen(op_btand, 0, node->get_line()); gen(op_btand, 0, node->get_location());
return; return;
default: break; default: break;
} }
@ -906,99 +908,99 @@ void codegen::binary_gen(binary_operator* node) {
calc_gen(node->get_left()); calc_gen(node->get_left());
if (node->get_right()->get_type()!=expr_type::ast_num) { if (node->get_right()->get_type()!=expr_type::ast_num) {
calc_gen(node->get_right()); calc_gen(node->get_right());
gen(op_add, 0, node->get_line()); gen(op_add, 0, node->get_location());
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); regist_num(num);
gen(op_addc, const_number_map.at(num), node->get_line()); gen(op_addc, const_number_map.at(num), node->get_location());
} }
return; return;
case binary_operator::binary_type::sub: case binary_operator::binary_type::sub:
calc_gen(node->get_left()); calc_gen(node->get_left());
if (node->get_right()->get_type()!=expr_type::ast_num) { if (node->get_right()->get_type()!=expr_type::ast_num) {
calc_gen(node->get_right()); calc_gen(node->get_right());
gen(op_sub, 0, node->get_line()); gen(op_sub, 0, node->get_location());
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); regist_num(num);
gen(op_subc, const_number_map.at(num), node->get_line()); gen(op_subc, const_number_map.at(num), node->get_location());
} }
return; return;
case binary_operator::binary_type::mult: case binary_operator::binary_type::mult:
calc_gen(node->get_left()); calc_gen(node->get_left());
if (node->get_right()->get_type()!=expr_type::ast_num) { if (node->get_right()->get_type()!=expr_type::ast_num) {
calc_gen(node->get_right()); calc_gen(node->get_right());
gen(op_mul, 0, node->get_line()); gen(op_mul, 0, node->get_location());
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); regist_num(num);
gen(op_mulc, const_number_map.at(num), node->get_line()); gen(op_mulc, const_number_map.at(num), node->get_location());
} }
return; return;
case binary_operator::binary_type::div: case binary_operator::binary_type::div:
calc_gen(node->get_left()); calc_gen(node->get_left());
if (node->get_right()->get_type()!=expr_type::ast_num) { if (node->get_right()->get_type()!=expr_type::ast_num) {
calc_gen(node->get_right()); calc_gen(node->get_right());
gen(op_div, 0, node->get_line()); gen(op_div, 0, node->get_location());
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); regist_num(num);
gen(op_divc, const_number_map.at(num), node->get_line()); gen(op_divc, const_number_map.at(num), node->get_location());
} }
return; return;
case binary_operator::binary_type::concat: case binary_operator::binary_type::concat:
calc_gen(node->get_left()); calc_gen(node->get_left());
if (node->get_right()->get_type()!=expr_type::ast_str) { if (node->get_right()->get_type()!=expr_type::ast_str) {
calc_gen(node->get_right()); calc_gen(node->get_right());
gen(op_lnk, 0, node->get_line()); gen(op_lnk, 0, node->get_location());
} else { } else {
const auto& str = ((string_literal*)node->get_right())->get_content(); const auto& str = ((string_literal*)node->get_right())->get_content();
regist_str(str); regist_str(str);
gen(op_lnkc, const_string_map.at(str), node->get_line()); gen(op_lnkc, const_string_map.at(str), node->get_location());
} }
break; break;
case binary_operator::binary_type::less: case binary_operator::binary_type::less:
calc_gen(node->get_left()); calc_gen(node->get_left());
if (node->get_right()->get_type()!=expr_type::ast_num) { if (node->get_right()->get_type()!=expr_type::ast_num) {
calc_gen(node->get_right()); calc_gen(node->get_right());
gen(op_less, 0, node->get_line()); gen(op_less, 0, node->get_location());
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); regist_num(num);
gen(op_lessc, const_number_map.at(num), node->get_line()); gen(op_lessc, const_number_map.at(num), node->get_location());
} }
return; return;
case binary_operator::binary_type::leq: case binary_operator::binary_type::leq:
calc_gen(node->get_left()); calc_gen(node->get_left());
if (node->get_right()->get_type()!=expr_type::ast_num) { if (node->get_right()->get_type()!=expr_type::ast_num) {
calc_gen(node->get_right()); calc_gen(node->get_right());
gen(op_leq, 0, node->get_line()); gen(op_leq, 0, node->get_location());
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); regist_num(num);
gen(op_leqc, const_number_map.at(num), node->get_line()); gen(op_leqc, const_number_map.at(num), node->get_location());
} }
return; return;
case binary_operator::binary_type::grt: case binary_operator::binary_type::grt:
calc_gen(node->get_left()); calc_gen(node->get_left());
if (node->get_right()->get_type()!=expr_type::ast_num) { if (node->get_right()->get_type()!=expr_type::ast_num) {
calc_gen(node->get_right()); calc_gen(node->get_right());
gen(op_grt, 0, node->get_line()); gen(op_grt, 0, node->get_location());
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); regist_num(num);
gen(op_grtc, const_number_map.at(num), node->get_line()); gen(op_grtc, const_number_map.at(num), node->get_location());
} }
return; return;
case binary_operator::binary_type::geq: case binary_operator::binary_type::geq:
calc_gen(node->get_left()); calc_gen(node->get_left());
if (node->get_right()->get_type()!=expr_type::ast_num) { if (node->get_right()->get_type()!=expr_type::ast_num) {
calc_gen(node->get_right()); calc_gen(node->get_right());
gen(op_geq, 0, node->get_line()); gen(op_geq, 0, node->get_location());
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); regist_num(num);
gen(op_geqc, const_number_map.at(num), node->get_line()); gen(op_geqc, const_number_map.at(num), node->get_location());
} }
return; return;
default: break; default: break;
@ -1008,10 +1010,10 @@ void codegen::binary_gen(binary_operator* node) {
void codegen::trino_gen(ternary_operator* node) { void codegen::trino_gen(ternary_operator* node) {
calc_gen(node->get_condition()); calc_gen(node->get_condition());
usize label_jump_false = code.size(); usize label_jump_false = code.size();
gen(op_jf, 0, node->get_condition()->get_line()); gen(op_jf, 0, node->get_condition()->get_location());
calc_gen(node->get_left()); calc_gen(node->get_left());
usize label_jump_to_exit = code.size(); usize label_jump_to_exit = code.size();
gen(op_jmp, 0, node->get_left()->get_line()); gen(op_jmp, 0, node->get_left()->get_location());
code[label_jump_false].num = code.size(); code[label_jump_false].num = code.size();
calc_gen(node->get_right()); calc_gen(node->get_right());
code[label_jump_to_exit].num = code.size(); code[label_jump_to_exit].num = code.size();
@ -1020,7 +1022,7 @@ void codegen::trino_gen(ternary_operator* node) {
void codegen::calc_gen(expr* node) { void codegen::calc_gen(expr* node) {
switch(node->get_type()) { switch(node->get_type()) {
case expr_type::ast_nil: case expr_type::ast_nil:
gen(op_pnil, 0, node->get_line()); break; gen(op_pnil, 0, node->get_location()); break;
case expr_type::ast_num: case expr_type::ast_num:
num_gen((number_literal*)node); break; num_gen((number_literal*)node); break;
case expr_type::ast_str: case expr_type::ast_str:
@ -1064,18 +1066,15 @@ void codegen::block_gen(code_block* node) {
case expr_type::ast_num: case expr_type::ast_num:
case expr_type::ast_str: case expr_type::ast_str:
case expr_type::ast_bool: break; case expr_type::ast_bool: break;
case expr_type::ast_file_info:
// special node type in main block
fileindex = ((file_info*)tmp)->get_index(); break;
case expr_type::ast_cond: case expr_type::ast_cond:
cond_gen((condition_expr*)tmp); break; cond_gen((condition_expr*)tmp); break;
case expr_type::ast_continue: case expr_type::ast_continue:
continue_ptr.front().push_back(code.size()); continue_ptr.front().push_back(code.size());
gen(op_jmp, 0, tmp->get_line()); gen(op_jmp, 0, tmp->get_location());
break; break;
case expr_type::ast_break: case expr_type::ast_break:
break_ptr.front().push_back(code.size()); break_ptr.front().push_back(code.size());
gen(op_jmp, 0, tmp->get_line()); gen(op_jmp, 0, tmp->get_location());
break; break;
case expr_type::ast_while: case expr_type::ast_while:
case expr_type::ast_for: case expr_type::ast_for:
@ -1101,16 +1100,20 @@ void codegen::block_gen(code_block* node) {
void codegen::ret_gen(return_expr* node) { void codegen::ret_gen(return_expr* node) {
for(u32 i = 0; i<in_loop_level.back(); ++i) { for(u32 i = 0; i<in_loop_level.back(); ++i) {
gen(op_pop, 0, node->get_line()); gen(op_pop, 0, node->get_location());
gen(op_pop, 0, node->get_line()); gen(op_pop, 0, node->get_location());
} }
calc_gen(node->get_value()); calc_gen(node->get_value());
gen(op_ret, 0, node->get_line()); gen(op_ret, 0, node->get_location());
} }
const error& codegen::compile(parse& parse, linker& import) { const error& codegen::compile(parse& parse, linker& import) {
fileindex = 0; const auto& file = import.filelist();
file = import.filelist(); file_map = {};
for(usize i = 0; i<file.size(); ++i) {
file_map[file[i]] = i;
}
in_loop_level.push_back(0); in_loop_level.push_back(0);
// add special symbol globals, which is a hash stores all global variables // add special symbol globals, which is a hash stores all global variables
@ -1119,9 +1122,9 @@ const error& codegen::compile(parse& parse, linker& import) {
add_symbol("arg"); add_symbol("arg");
find_symbol(parse.tree()); // search symbols first find_symbol(parse.tree()); // search symbols first
gen(op_intg, global.size(), 0); gen(op_intg, global.size(), parse.tree()->get_location());
block_gen(parse.tree()); // generate main block block_gen(parse.tree()); // generate main block
gen(op_exit, 0, 0); gen(op_exit, 0, parse.tree()->get_location());
// size out of bound check // size out of bound check
if (const_number_table.size()>0xffffff) { if (const_number_table.size()>0xffffff) {

View File

@ -22,15 +22,24 @@
class codegen { class codegen {
private: private:
u16 fileindex;
error err; error err;
std::vector<std::string> file;
// file mapper for file -> index
std::unordered_map<std::string, usize> file_map;
// used for generate pop in return expression
std::vector<u32> in_loop_level; std::vector<u32> in_loop_level;
// constant numbers and strings
std::unordered_map<f64, u32> const_number_map; std::unordered_map<f64, u32> const_number_map;
std::unordered_map<std::string, u32> const_string_map; std::unordered_map<std::string, u32> const_string_map;
std::vector<f64> const_number_table; std::vector<f64> const_number_table;
std::vector<std::string> const_string_table; std::vector<std::string> const_string_table;
// generated opcodes
std::vector<opcode> code; std::vector<opcode> code;
// used to store jmp operands index, to fill the jump address back
std::list<std::vector<i32>> continue_ptr; std::list<std::vector<i32>> continue_ptr;
std::list<std::vector<i32>> break_ptr; std::list<std::vector<i32>> break_ptr;
@ -38,6 +47,7 @@ private:
// global : max STACK_DEPTH-1 values // global : max STACK_DEPTH-1 values
std::unordered_map<std::string, i32> global; std::unordered_map<std::string, i32> global;
std::unordered_map<std::string, std::unordered_set<std::string>> experimental_namespace; std::unordered_map<std::string, std::unordered_set<std::string>> experimental_namespace;
// local : max 32768 upvalues 65536 values // local : max 32768 upvalues 65536 values
// but in fact local scope also has less than STACK_DEPTH value // but in fact local scope also has less than STACK_DEPTH value
std::list<std::unordered_map<std::string, i32>> local; std::list<std::unordered_map<std::string, i32>> local;
@ -56,7 +66,7 @@ private:
i32 global_find(const std::string&); i32 global_find(const std::string&);
i32 upvalue_find(const std::string&); i32 upvalue_find(const std::string&);
void gen(u8, u32, u32); void gen(u8, u32, const span&);
void num_gen(number_literal*); void num_gen(number_literal*);
void str_gen(string_literal*); void str_gen(string_literal*);
@ -105,7 +115,7 @@ public:
} }
public: public:
codegen(): fileindex(0) {} codegen() = default;
const error& compile(parse&, linker&); const error& compile(parse&, linker&);
void print(std::ostream&); void print(std::ostream&);
void symbol_dump(std::ostream&) const; void symbol_dump(std::ostream&) const;

View File

@ -313,12 +313,15 @@ definition_expr* linker::generate_module_definition(code_block* block) {
code_block* linker::load(code_block* root, u16 fileindex) { code_block* linker::load(code_block* root, u16 fileindex) {
auto tree = new code_block({0, 0, 0, 0, files[fileindex]}); auto tree = new code_block({0, 0, 0, 0, files[fileindex]});
// load library, this ast will be linked with root directly
// so no namespace is generated
if (!lib_loaded) { if (!lib_loaded) {
auto tmp = import_nasal_lib(); auto tmp = import_nasal_lib();
link(tree, tmp); link(tree, tmp);
delete tmp; delete tmp;
lib_loaded = true; lib_loaded = true;
} }
// load imported modules
for(auto i : root->get_expressions()) { for(auto i : root->get_expressions()) {
if (!import_check(i)) { if (!import_check(i)) {
break; break;
@ -327,9 +330,6 @@ code_block* linker::load(code_block* root, u16 fileindex) {
tree->add_expression(generate_module_definition(tmp)); tree->add_expression(generate_module_definition(tmp));
} }
// add root to the back of tree // add root to the back of tree
auto file_head = new file_info(
{0, 0, 0, 0, files[fileindex]}, fileindex, files[fileindex]);
tree->add_expression(file_head);
link(tree, root); link(tree, root);
return tree; return tree;
} }

View File

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

68
std/io.nas Normal file
View File

@ -0,0 +1,68 @@
# io.nas
# 2023 by ValKmjolnir
var SEEK_SET = 0;
var SEEK_CUR = 1;
var SEEK_END = 2;
# get content of a file by filename. returns a string.
var readfile = func(filename) {
return __readfile(filename);
}
# input a string as the content of a file.
var fout = func(filename, str) {
return __fout(filename, str);
}
# use C access
var exists = func(filename) {
return __exists(filename);
}
# same as C fopen. open file and get the FILE*.
var open = func(filename, mode = "r") {
return __open(filename, mode);
}
# same as C fclose. close file by FILE*.
var close = func(filehandle) {
return __close(filehandle);
}
# same as C fread. read file by FILE*.
# caution: buf must be a mutable string.use mut("") to get an empty mutable string.
var read = func(filehandle, buf, len) {
return __read(filehandle, buf, len);
}
# same as C fwrite. write file by FILE*.
var write = func(filehandle, str) {
return __write(filehandle, str);
}
# same as C fseek. seek place by FILE*.
var seek = func(filehandle, pos, whence) {
return __seek(filehandle, pos, whence);
}
# same as C ftell.
var tell = func(filehandle) {
return __tell(filehandle);
}
# read file by lines. use FILE*.
# get nil if EOF
var readln = func(filehandle) {
return __readln(filehandle);
}
# same as C stat.
var stat = func(filename) {
return __stat(filename);
}
# same as C feof. check if FILE* gets the end of file(EOF).
var eof = func(filehandle) {
return __eof(filehandle);
}

View File

@ -2,6 +2,10 @@
# 2019 ValKmjolnir # 2019 ValKmjolnir
import.std.coroutine; import.std.coroutine;
import.std.math;
import.std.string;
import.std.io;
import.std.os;
# 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.
@ -327,38 +331,6 @@ var md5 = func(str) {
return __md5(str); return __md5(str);
} }
var io = {
SEEK_SET: 0,
SEEK_CUR: 1,
SEEK_END: 2,
# get content of a file by filename. returns a string.
readfile: func(filename) {return __readfile(filename);},
# input a string as the content of a file.
fout: func(filename, str) {return __fout(filename, str);},
# use C access
exists:func(filename) {return __exists(filename);},
# same as C fopen. open file and get the FILE*.
open: func(filename, mode = "r") {return __open(filename, mode);},
# same as C fclose. close file by FILE*.
close: func(filehandle) {return __close(filehandle);},
# same as C fread. read file by FILE*.
# caution: buf must be a mutable string.use mut("") to get an empty mutable string.
read: func(filehandle, buf, len) {return __read(filehandle, buf, len);},
# same as C fwrite. write file by FILE*.
write: func(filehandle, str) {return __write(filehandle, str);},
# same as C fseek. seek place by FILE*.
seek: func(filehandle, pos, whence) {return __seek(filehandle, pos, whence);},
# same as C ftell.
tell: func(filehandle) {return __tell(filehandle);},
# read file by lines. use FILE*.
# get nil if EOF
readln: func(filehandle) {return __readln(filehandle);},
# same as C stat.
stat: func(filename) {return __stat(filename);},
# same as C feof. check if FILE* gets the end of file(EOF).
eof: func(filehandle) {return __eof(filehandle);}
};
# get file status. using data from io.stat # get file status. using data from io.stat
var fstat = func(filename) { var fstat = func(filename) {
var s = io.stat(filename); var s = io.stat(filename);
@ -412,28 +384,6 @@ var bits = {
buf: func(len) {return __buf;} buf: func(len) {return __buf;}
}; };
# mostly used math functions and special constants, you know.
var math = {
e: 2.7182818284590452354,
pi: 3.14159265358979323846264338327950288,
inf: 1/0,
nan: 0/0,
abs: func(x) {return x>0? x:-x;},
floor: func(x) {return __floor(x);},
pow: func(x, y) {return __pow(x, y);},
sin: func(x) {return __sin(x);},
cos: func(x) {return __cos(x);},
tan: func(x) {return __tan(x);},
exp: func(x) {return __exp(x);},
lg: func(x) {return __lg(x);},
ln: func(x) {return __ln(x);},
sqrt: func(x) {return __sqrt(x);},
atan2: func(x, y) {return __atan2(x, y);},
isnan: func(x) {return __isnan(x);},
max: func(x, y) {return x>y? x:y;},
min: func(x, y) {return x<y? x:y;}
};
# important global constants # important global constants
var D2R = math.pi / 180; # degree to radian var D2R = math.pi / 180; # degree to radian
var R2D = 180 / math.pi; # radian to degree var R2D = 180 / math.pi; # radian to degree
@ -520,25 +470,6 @@ var dylib = {
} }
}; };
# os is used to use or get some os-related info/functions.
# windows/macOS/linux are supported.
var os = {
# get a string that tell which os it runs on.
platform: func() {return __platform;},
time: func() {return __logtime;},
arch: func() {return __arch;}
};
# runtime gives us some functions that we could manage it manually.
var runtime = {
# command line arguments
argv: func() {return globals.arg;},
gc: {
extend: func(type) {return __gcextd;},
info: func() {return __gcinfo;}
}
};
# functions that not supported in this runtime: # functions that not supported in this runtime:
var bind = func(function, locals, outer_scope = nil) { var bind = func(function, locals, outer_scope = nil) {
die("this runtime does not support bind"); die("this runtime does not support bind");

View File

@ -1,51 +1,77 @@
# list.nas # list.nas
# valkmjolnir 2021/3/31 # valkmjolnir 2021/3/31
var list=func(){
var (begin,end)=(nil,nil); var new = func() {
return{ var (begin, end, len) = (nil, nil, 0);
push_back:func(elem){ return {
var tmp={elem:elem,prev:nil,next:nil}; push_back: func(elem) {
if(end!=nil){ var tmp = {
end.next=tmp; elem: elem,
tmp.prev=end; prev: nil,
end=tmp; next: nil
};
if(end!=nil) {
end.next = tmp;
tmp.prev = end;
end = tmp;
} else {
begin = end = tmp;
} }
else len += 1;
begin=end=tmp;
}, },
push_front:func(elem){ push_front: func(elem) {
var tmp={elem:elem,prev:nil,next:nil}; var tmp = {
if(begin!=nil){ elem: elem,
begin.prev=tmp; prev: nil,
tmp.next=begin; next: nil
begin=tmp; };
if (begin!=nil) {
begin.prev = tmp;
tmp.next = begin;
begin = tmp;
} else {
begin = end = tmp;
} }
else len += 1;
begin=end=tmp;
}, },
pop_back:func(){ pop_back: func() {
if(end!=nil) if (end!=nil) {
end=end.prev; end = end.prev;
if(end==nil) }
begin=nil; if (end==nil) {
else begin = nil;
end.next=nil; } else {
end.next = nil;
}
if (len) {
len -= 1;
}
}, },
pop_front:func(){ pop_front: func() {
if(begin!=nil) if (begin!=nil) {
begin=begin.next; begin = begin.next;
if(begin==nil) }
end=nil; if (begin==nil) {
else end = nil;
begin.prev=nil; } else {
begin.prev = nil;
}
if (len) {
len -= 1;
}
}, },
front:func(){ front: func() {
if(begin!=nil) if (begin!=nil) {
return begin.elem; return begin.elem;
}
}, },
back:func(){ back: func() {
if(end!=nil) if (end!=nil) {
return end.elem; return end.elem;
}
}, },
length: func() {
return len;
}
}; };
} }

65
std/math.nas Normal file
View File

@ -0,0 +1,65 @@
# math.nas
# 2023 by ValKmjolnir
# mostly used math functions and special constants, you know.
var e = 2.7182818284590452354;
var pi = 3.14159265358979323846264338327950288;
var inf = 1/0;
var nan = 0/0;
var abs = func(x) {
return x>0? x:-x;
}
var floor = func(x) {
return __floor(x);
}
var pow = func(x, y) {
return __pow(x, y);
}
var sin = func(x) {
return __sin(x);
}
var cos = func(x) {
return __cos(x);
}
var tan = func(x) {
return __tan(x);
}
var exp = func(x) {
return __exp(x);
}
var lg = func(x) {
return __lg(x);
}
var ln = func(x) {
return __ln(x);
}
var sqrt = func(x) {
return __sqrt(x);
}
var atan2 = func(x, y) {
return __atan2(x, y);
}
var isnan = func(x) {
return __isnan(x);
}
var max = func(x, y) {
return x>y? x:y;
}
var min = func(x, y) {
return x<y? x:y;
}

18
std/os.nas Normal file
View File

@ -0,0 +1,18 @@
# os.nas
# 2023 by ValKmjolnir
# os is used to use or get some os-related info/functions.
# windows/macOS/linux are supported.
# get a string that tell which os it runs on.
var platform = func() {
return __platform;
}
var time = func() {
return __logtime;
}
var arch = func() {
return __arch;
}

13
std/runtime.nas Normal file
View File

@ -0,0 +1,13 @@
# runtime.nas
# 2023 by ValKmjolnir
# runtime gives us some functions that we could manage it manually.
# command line arguments
var argv = func() {
return globals.arg;
}
var gc = {
extend: func(type) {return __gcextd;},
info: func() {return __gcinfo;}
};

View File

@ -1,9 +1,12 @@
# string.nas # string.nas
# ValKmjolnir 2022/10/5 # ValKmjolnir 2022/10/5
var join=func(vec){ var join=func(sep, vec){
var res=""; var len = size(vec);
foreach(var i;vec) var res = "";
res~=i; for(var i = 0; i<len; i+=1) {
res ~= vec[i];
res ~= (i==len-1? "":sep);
}
return res; return res;
} }

View File

@ -22,6 +22,7 @@
# 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; import.module.libmat;
import.std.runtime;
func(){ func(){
# allocate more spaces # allocate more spaces

View File

@ -1,3 +1,5 @@
import.std.runtime;
var mod=func(n,a){ var mod=func(n,a){
return n-int(n/a)*a; return n-int(n/a)*a;
} }

View File

@ -1,3 +1,4 @@
import.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,6 +1,7 @@
# hexdump.nas by ValKmjolnir # hexdump.nas by ValKmjolnir
# 2021/8/13 # 2021/8/13
import.std.file; import.std.file;
import.std.runtime;
# init # init
var hex=func(){ var hex=func(){

View File

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

View File

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

View File

@ -1,5 +1,6 @@
import.std.process_bar; import.std.process_bar;
import.module.libkey; import.module.libkey;
import.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,3 +1,5 @@
import.std.runtime;
# basic type # basic type
nil; nil;
2147483647; 2147483647;
@ -202,6 +204,7 @@ foreach(i;a){
; ;
} }
println(runtime.argv()); println(runtime.argv());
println(globals.arg);
func(a,b,c,d="只有红茶可以吗"){ func(a,b,c,d="只有红茶可以吗"){
println(a,' ',b,' ',c,' ',d,' true: ',true,' false: ',false); println(a,' ',b,' ',c,' ',d,' true: ',true,' false: ',false);
}(c:1919810,b:514,a:114); }(c:1919810,b:514,a:114);

View File

@ -1,71 +1,6 @@
import.module.libkey; import.module.libkey;
import.std.list;
var list=func(){ import.std.runtime;
var (begin,end,len)=(nil,nil,0);
return{
push_back:func(elem){
var tmp={
elem:elem,
prev:nil,
next:nil
};
if(end!=nil){
end.next=tmp;
tmp.prev=end;
end=tmp;
}else{
begin=end=tmp;
}
len+=1;
},
push_front:func(elem){
var tmp={
elem:elem,
prev:nil,
next:nil
};
if(begin!=nil){
begin.prev=tmp;
tmp.next=begin;
begin=tmp;
}else{
begin=end=tmp;
}
len+=1;
},
pop_back:func(){
if(end!=nil)
end=end.prev;
if(end==nil)
begin=nil;
else
end.next=nil;
if(len)
len-=1;
},
pop_front:func(){
if(begin!=nil)
begin=begin.next;
if(begin==nil)
end=nil;
else
begin.prev=nil;
if(len)
len-=1;
},
front:func(){
if(begin!=nil)
return begin.elem;
},
back:func(){
if(end!=nil)
return end.elem;
},
length:func(){
return len;
}
};
}
var game=func(x,y){ var game=func(x,y){
rand(time(0)); rand(time(0));
@ -88,7 +23,7 @@ var game=func(x,y){
vec[i][j]=0; vec[i][j]=0;
} }
var snake=list(); var snake = list.new();
snake.push_back([int(x/2),int(y/3)]); snake.push_back([int(x/2),int(y/3)]);
snake.push_back([int(x/2),int(y/3)+1]); snake.push_back([int(x/2),int(y/3)+1]);
vec[int(x/2)][int(y/3)]=1; vec[int(x/2)][int(y/3)]=1;

View File

@ -1,4 +1,6 @@
import.module.libkey; import.module.libkey;
import.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",
"\e[91m","\e[92m","\e[93m","\e[94m","\e[95m","\e[96m", "\e[91m","\e[92m","\e[93m","\e[94m","\e[95m","\e[96m",

View File

@ -1,3 +1,5 @@
import.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,3 +1,4 @@
import.std.runtime;
var to_lower=func(s){ var to_lower=func(s){
var tmp=""; var tmp="";