✨ optimize location info gen in codegen
and refactor lib.nas, add multiple native modules
This commit is contained in:
parent
51a0ef6b0c
commit
788e0026c2
|
@ -0,0 +1,64 @@
|
|||
# Nasal Namespace
|
||||
|
||||

|
||||
|
||||
## 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
|
||||
};
|
||||
}();
|
||||
```
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
var libfib=func(){
|
||||
var dl=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
||||
var fib=dl.fib;
|
||||
|
|
|
@ -2,13 +2,6 @@
|
|||
|
||||
#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) {
|
||||
dump_indent();
|
||||
std::cout << "null" << format_location(node->get_location());
|
||||
|
|
|
@ -39,7 +39,6 @@ private:
|
|||
}
|
||||
|
||||
public:
|
||||
bool visit_file_info(file_info*) override;
|
||||
bool visit_null_expr(null_expr*) override;
|
||||
bool visit_nil_expr(nil_expr*) override;
|
||||
bool visit_number_literal(number_literal*) override;
|
||||
|
|
|
@ -10,10 +10,6 @@ bool ast_visitor::visit_call(call* node) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ast_visitor::visit_file_info(file_info* node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ast_visitor::visit_null_expr(null_expr* node) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ class ast_visitor {
|
|||
public:
|
||||
virtual bool visit_expr(expr*);
|
||||
virtual bool visit_call(call*);
|
||||
virtual bool visit_file_info(file_info*);
|
||||
virtual bool visit_null_expr(null_expr*);
|
||||
virtual bool visit_nil_expr(nil_expr*);
|
||||
virtual bool visit_number_literal(number_literal*);
|
||||
|
|
|
@ -9,10 +9,6 @@ void call::accept(ast_visitor* visitor) {
|
|||
visitor->visit_call(this);
|
||||
}
|
||||
|
||||
void file_info::accept(ast_visitor* visitor) {
|
||||
visitor->visit_file_info(this);
|
||||
}
|
||||
|
||||
void null_expr::accept(ast_visitor* visitor) {
|
||||
visitor->visit_null_expr(this);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
enum class expr_type:u32 {
|
||||
ast_null = 0, // null node
|
||||
ast_file_info, // stores file info
|
||||
ast_block, // code block
|
||||
ast_nil, // nil keyword
|
||||
ast_num, // number, basic value type
|
||||
|
@ -84,21 +83,6 @@ public:
|
|||
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 {
|
||||
public:
|
||||
null_expr(const span& location):
|
||||
|
|
|
@ -100,42 +100,44 @@ i32 codegen::upvalue_find(const std::string& name) {
|
|||
return index;
|
||||
}
|
||||
|
||||
void codegen::gen(u8 operation_code, u32 num, u32 line) {
|
||||
code.push_back({operation_code, fileindex, num, line});
|
||||
void codegen::gen(u8 operation_code, u32 num, const span& loc) {
|
||||
code.push_back({operation_code,
|
||||
static_cast<u16>(file_map.at(loc.file)),
|
||||
num, loc.begin_line});
|
||||
}
|
||||
|
||||
void codegen::num_gen(number_literal* node) {
|
||||
f64 num = node->get_number();
|
||||
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) {
|
||||
const auto& str = node->get_content();
|
||||
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) {
|
||||
f64 num = node->get_flag()? 1:0;
|
||||
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) {
|
||||
for(auto child : node->get_elements()) {
|
||||
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) {
|
||||
gen(op_newh, 0, node->get_line());
|
||||
gen(op_newh, 0, node->get_location());
|
||||
for(auto child : node->get_members()) {
|
||||
calc_gen(child->get_value());
|
||||
const auto& field_name = child->get_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();
|
||||
gen(op_newf, 0, node->get_line());
|
||||
gen(op_newf, 0, node->get_location());
|
||||
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
|
||||
// this symbol is only used in local scope(function's scope)
|
||||
|
@ -196,14 +198,14 @@ void codegen::func_gen(function* node) {
|
|||
regist_str(name);
|
||||
switch(tmp->get_parameter_type()) {
|
||||
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;
|
||||
case parameter::param_type::default_parameter:
|
||||
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;
|
||||
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;
|
||||
}
|
||||
add_symbol(name);
|
||||
|
@ -211,7 +213,7 @@ void codegen::func_gen(function* node) {
|
|||
|
||||
code[newf].num = code.size()+1; // entry
|
||||
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();
|
||||
// search symbols first, must use after loading parameters
|
||||
|
@ -244,8 +246,8 @@ void codegen::func_gen(function* node) {
|
|||
|
||||
if (!block->get_expressions().size() ||
|
||||
block->get_expressions().back()->get_type()!=expr_type::ast_ret) {
|
||||
gen(op_pnil, 0, block->get_line());
|
||||
gen(op_ret, 0, block->get_line());
|
||||
gen(op_pnil, 0, block->get_location());
|
||||
gen(op_ret, 0, block->get_location());
|
||||
}
|
||||
code[jmp_ptr].num = code.size();
|
||||
}
|
||||
|
@ -269,7 +271,7 @@ void codegen::call_id(identifier* node) {
|
|||
const auto& name = node->get_name();
|
||||
for(u32 i = 0; builtin[i].name; ++i) {
|
||||
if (builtin[i].name==name) {
|
||||
gen(op_callb, i, node->get_line());
|
||||
gen(op_callb, i, node->get_location());
|
||||
if (local.empty()) {
|
||||
die("should warp native function in local scope",
|
||||
node->get_location());
|
||||
|
@ -279,15 +281,15 @@ void codegen::call_id(identifier* node) {
|
|||
}
|
||||
i32 index;
|
||||
if ((index=local_find(name))>=0) {
|
||||
gen(op_calll, index, node->get_line());
|
||||
gen(op_calll, index, node->get_location());
|
||||
return;
|
||||
}
|
||||
if ((index=upvalue_find(name))>=0) {
|
||||
gen(op_upval, index, node->get_line());
|
||||
gen(op_upval, index, node->get_location());
|
||||
return;
|
||||
}
|
||||
if ((index=global_find(name))>=0) {
|
||||
gen(op_callg, index, node->get_line());
|
||||
gen(op_callg, index, node->get_location());
|
||||
return;
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
|
@ -303,39 +305,39 @@ void codegen::call_vector_gen(call_vector* node) {
|
|||
if (node->get_slices().size()==1 &&
|
||||
!node->get_slices()[0]->get_end()) {
|
||||
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;
|
||||
}
|
||||
gen(op_slcbeg, 0, node->get_line());
|
||||
gen(op_slcbeg, 0, node->get_location());
|
||||
for(auto tmp : node->get_slices()) {
|
||||
if (!tmp->get_end()) {
|
||||
calc_gen(tmp->get_begin());
|
||||
gen(op_slc, 0, tmp->get_line());
|
||||
gen(op_slc, 0, tmp->get_location());
|
||||
} else {
|
||||
calc_gen(tmp->get_begin());
|
||||
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) {
|
||||
if (node->get_argument().size() &&
|
||||
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()) {
|
||||
calc_gen(((hash_pair*)child)->get_value());
|
||||
const auto& field_name = ((hash_pair*)child)->get_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 {
|
||||
for(auto child : node->get_argument()) {
|
||||
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;
|
||||
if ((index=local_find(name))>=0) {
|
||||
gen(op_mcalll, index, node->get_line());
|
||||
gen(op_mcalll, index, node->get_location());
|
||||
return;
|
||||
}
|
||||
if ((index=upvalue_find(name))>=0) {
|
||||
gen(op_mupval, index, node->get_line());
|
||||
gen(op_mupval, index, node->get_location());
|
||||
return;
|
||||
}
|
||||
if ((index=global_find(name))>=0) {
|
||||
gen(op_mcallg, index, node->get_line());
|
||||
gen(op_mcallg, index, node->get_location());
|
||||
return;
|
||||
}
|
||||
die("undefined symbol \"" + name + "\"", node->get_location());
|
||||
|
@ -415,20 +417,20 @@ void codegen::mcall_vec(call_vector* node) {
|
|||
return;
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
const auto& str = node->get_variable_name()->get_name();
|
||||
calc_gen(node->get_value());
|
||||
local.empty()?
|
||||
gen(op_loadg, global_find(str), node->get_line()):
|
||||
gen(op_loadl, local_find(str), node->get_line());
|
||||
gen(op_loadg, global_find(str), node->get_location()):
|
||||
gen(op_loadl, local_find(str), node->get_location());
|
||||
}
|
||||
|
||||
void codegen::multi_def(definition_expr* node) {
|
||||
|
@ -448,21 +450,21 @@ void codegen::multi_def(definition_expr* node) {
|
|||
calc_gen(vals[i]);
|
||||
const auto& name = identifiers[i]->get_name();
|
||||
local.empty()?
|
||||
gen(op_loadg, global_find(name), identifiers[i]->get_line()):
|
||||
gen(op_loadl, local_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_location());
|
||||
}
|
||||
return;
|
||||
}
|
||||
// (var a,b,c) = [0,1,2];
|
||||
calc_gen(node->get_value());
|
||||
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();
|
||||
local.empty()?
|
||||
gen(op_loadg, global_find(name), identifiers[i]->get_line()):
|
||||
gen(op_loadl, local_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_location());
|
||||
}
|
||||
gen(op_pop, 0, node->get_line());
|
||||
gen(op_pop, 0, node->get_location());
|
||||
}
|
||||
|
||||
void codegen::def_gen(definition_expr* node) {
|
||||
|
@ -477,7 +479,7 @@ void codegen::assignment_expression(assignment_expr* node) {
|
|||
case assignment_expr::assign_type::equal:
|
||||
calc_gen(node->get_right());
|
||||
mcall(node->get_left());
|
||||
gen(op_meq, 0, node->get_line());
|
||||
gen(op_meq, 0, node->get_location());
|
||||
break;
|
||||
case assignment_expr::assign_type::add_equal:
|
||||
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());
|
||||
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 {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
regist_num(num);
|
||||
gen(op_addeqc, const_number_map[num], node->get_line());
|
||||
gen(op_addeqc, const_number_map[num], node->get_location());
|
||||
}
|
||||
break;
|
||||
case assignment_expr::assign_type::sub_equal:
|
||||
|
@ -498,11 +500,11 @@ void codegen::assignment_expression(assignment_expr* node) {
|
|||
}
|
||||
mcall(node->get_left());
|
||||
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 {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
regist_num(num);
|
||||
gen(op_subeqc, const_number_map[num], node->get_line());
|
||||
gen(op_subeqc, const_number_map[num], node->get_location());
|
||||
}
|
||||
break;
|
||||
case assignment_expr::assign_type::mult_equal:
|
||||
|
@ -511,11 +513,11 @@ void codegen::assignment_expression(assignment_expr* node) {
|
|||
}
|
||||
mcall(node->get_left());
|
||||
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 {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
regist_num(num);
|
||||
gen(op_muleqc, const_number_map[num], node->get_line());
|
||||
gen(op_muleqc, const_number_map[num], node->get_location());
|
||||
}
|
||||
break;
|
||||
case assignment_expr::assign_type::div_equal:
|
||||
|
@ -524,11 +526,11 @@ void codegen::assignment_expression(assignment_expr* node) {
|
|||
}
|
||||
mcall(node->get_left());
|
||||
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 {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
regist_num(num);
|
||||
gen(op_diveqc, const_number_map[num], node->get_line());
|
||||
gen(op_diveqc, const_number_map[num], node->get_location());
|
||||
}
|
||||
break;
|
||||
case assignment_expr::assign_type::concat_equal:
|
||||
|
@ -537,27 +539,27 @@ void codegen::assignment_expression(assignment_expr* node) {
|
|||
}
|
||||
mcall(node->get_left());
|
||||
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 {
|
||||
const auto& str = ((string_literal*)node->get_right())->get_content();
|
||||
regist_str(str);
|
||||
gen(op_lnkeqc, const_string_map[str], node->get_line());
|
||||
gen(op_lnkeqc, const_string_map[str], node->get_location());
|
||||
}
|
||||
break;
|
||||
case assignment_expr::assign_type::bitwise_and_equal:
|
||||
calc_gen(node->get_right());
|
||||
mcall(node->get_left());
|
||||
gen(op_btandeq, 0, node->get_line());
|
||||
gen(op_btandeq, 0, node->get_location());
|
||||
break;
|
||||
case assignment_expr::assign_type::bitwise_or_equal:
|
||||
calc_gen(node->get_right());
|
||||
mcall(node->get_left());
|
||||
gen(op_btoreq, 0, node->get_line());
|
||||
gen(op_btoreq, 0, node->get_location());
|
||||
break;
|
||||
case assignment_expr::assign_type::bitwise_xor_equal:
|
||||
calc_gen(node->get_right());
|
||||
mcall(node->get_left());
|
||||
gen(op_btxoreq, 0, node->get_line());
|
||||
gen(op_btxoreq, 0, node->get_location());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -581,7 +583,7 @@ void codegen::assignment_statement(assignment_expr* node) {
|
|||
if (code.back().op==op_meq) {
|
||||
code.back().num=1;
|
||||
} else {
|
||||
gen(op_pop, 0, node->get_line());
|
||||
gen(op_pop, 0, node->get_location());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -599,7 +601,7 @@ void codegen::assignment_statement(assignment_expr* node) {
|
|||
} else if (op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) {
|
||||
code.back().op=code.back().op-op_addeqc+op_addecp;
|
||||
} else {
|
||||
gen(op_pop, 0, node->get_line());
|
||||
gen(op_pop, 0, node->get_location());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -630,7 +632,7 @@ void codegen::multi_assign_gen(multi_assign* node) {
|
|||
} else if (code.back().op==op_mcallg) {
|
||||
code.back().op=op_loadg;
|
||||
} else {
|
||||
gen(op_meq, 1, tuple[i]->get_line());
|
||||
gen(op_meq, 1, tuple[i]->get_location());
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -638,7 +640,7 @@ void codegen::multi_assign_gen(multi_assign* node) {
|
|||
calc_gen(node->get_value());
|
||||
auto& tuple = node->get_tuple()->get_elements();
|
||||
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--
|
||||
// and this operation changes local and global value directly
|
||||
mcall(tuple[i]);
|
||||
|
@ -649,35 +651,35 @@ void codegen::multi_assign_gen(multi_assign* node) {
|
|||
} else if (code.back().op==op_mcallg) {
|
||||
code.back().op=op_loadg;
|
||||
} 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) {
|
||||
std::vector<usize> jmp_label;
|
||||
calc_gen(node->get_if_statement()->get_condition());
|
||||
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());
|
||||
if (node->get_elsif_stataments().size() ||
|
||||
node->get_else_statement()) {
|
||||
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();
|
||||
|
||||
for(auto tmp : node->get_elsif_stataments()) {
|
||||
calc_gen(tmp->get_condition());
|
||||
ptr = code.size();
|
||||
gen(op_jf, 0, tmp->get_line());
|
||||
gen(op_jf, 0, tmp->get_location());
|
||||
block_gen(tmp->get_code_block());
|
||||
// the last condition doesn't need to jmp
|
||||
if (tmp!=node->get_elsif_stataments().back() ||
|
||||
node->get_else_statement()) {
|
||||
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();
|
||||
}
|
||||
|
@ -719,10 +721,10 @@ void codegen::while_gen(while_expr* node) {
|
|||
usize loop_ptr = code.size();
|
||||
calc_gen(node->get_condition());
|
||||
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());
|
||||
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();
|
||||
load_continue_break(code.size()-1, code.size());
|
||||
}
|
||||
|
@ -732,17 +734,17 @@ void codegen::for_gen(for_expr* node) {
|
|||
usize jmp_place = code.size();
|
||||
if (node->get_condition()->get_type()==expr_type::ast_null) {
|
||||
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 {
|
||||
calc_gen(node->get_condition());
|
||||
}
|
||||
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());
|
||||
usize continue_place = code.size();
|
||||
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();
|
||||
|
||||
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) {
|
||||
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();
|
||||
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 {
|
||||
gen(op_feach, 0, node->get_line());
|
||||
gen(op_feach, 0, node->get_location());
|
||||
}
|
||||
if (node->get_iterator()->get_name()) { // define a new iterator
|
||||
auto name_node = node->get_iterator()->get_name();
|
||||
const auto& str = name_node->get_name();
|
||||
local.empty()?
|
||||
gen(op_loadg, global_find(str), name_node->get_line()):
|
||||
gen(op_loadl, local_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_location());
|
||||
} else { // use exist variable as the iterator
|
||||
mcall(node->get_iterator()->get_call());
|
||||
if (code.back().op==op_mcallg) {
|
||||
|
@ -772,17 +774,17 @@ void codegen::forei_gen(forei_expr* node) {
|
|||
} else if (code.back().op==op_mupval) {
|
||||
code.back().op=op_loadu;
|
||||
} else {
|
||||
gen(op_meq, 1, node->get_iterator()->get_line());
|
||||
gen(op_meq, 1, node->get_iterator()->get_location());
|
||||
}
|
||||
}
|
||||
++in_loop_level.back();
|
||||
block_gen(node->get_code_block());
|
||||
--in_loop_level.back();
|
||||
gen(op_jmp, ptr, node->get_line());
|
||||
gen(op_jmp, ptr, node->get_location());
|
||||
code[ptr].num=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_line());// pop iterator
|
||||
gen(op_pop, 0, node->get_value()->get_location());// pop vector
|
||||
gen(op_pop, 0, node->get_location());// pop iterator
|
||||
}
|
||||
|
||||
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_ternary:
|
||||
calc_gen(node);
|
||||
gen(op_pop, 0, node->get_line());
|
||||
gen(op_pop, 0, node->get_location());
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
@ -815,33 +817,33 @@ void codegen::statement_generation(expr* node) {
|
|||
void codegen::or_gen(binary_operator* node) {
|
||||
calc_gen(node->get_left());
|
||||
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());
|
||||
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_pnil, 0, node->get_right()->get_line());
|
||||
gen(op_pop, 0, node->get_right()->get_location());
|
||||
gen(op_pnil, 0, node->get_right()->get_location());
|
||||
|
||||
code[label_jump_true_1].num = code[label_jump_true_2].num = code.size();
|
||||
}
|
||||
|
||||
void codegen::and_gen(binary_operator* node) {
|
||||
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();
|
||||
gen(op_jmp, 0, node->get_left()->get_line());
|
||||
gen(op_pop, 0, node->get_right()->get_line()); // jt jumps here
|
||||
gen(op_jmp, 0, node->get_left()->get_location());
|
||||
gen(op_pop, 0, node->get_right()->get_location()); // jt jumps here
|
||||
|
||||
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();
|
||||
gen(op_pop, 0, node->get_right()->get_line());
|
||||
gen(op_pnil, 0, node->get_right()->get_line());
|
||||
gen(op_pop, 0, node->get_right()->get_location());
|
||||
gen(op_pnil, 0, node->get_right()->get_location());
|
||||
// jt jumps here, avoid pop and pnil
|
||||
}
|
||||
|
||||
|
@ -849,11 +851,11 @@ void codegen::unary_gen(unary_operator* node) {
|
|||
calc_gen(node->get_value());
|
||||
switch(node->get_operator_type()) {
|
||||
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:
|
||||
gen(op_lnot, 0, node->get_line()); break;
|
||||
gen(op_lnot, 0, node->get_location()); break;
|
||||
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:
|
||||
calc_gen(node->get_left());
|
||||
calc_gen(node->get_right());
|
||||
gen(op_eq, 0, node->get_line());
|
||||
gen(op_eq, 0, node->get_location());
|
||||
return;
|
||||
case binary_operator::binary_type::cmpneq:
|
||||
calc_gen(node->get_left());
|
||||
calc_gen(node->get_right());
|
||||
gen(op_neq, 0, node->get_line());
|
||||
gen(op_neq, 0, node->get_location());
|
||||
return;
|
||||
case binary_operator::binary_type::bitwise_or:
|
||||
calc_gen(node->get_left());
|
||||
calc_gen(node->get_right());
|
||||
gen(op_btor, 0, node->get_line());
|
||||
gen(op_btor, 0, node->get_location());
|
||||
return;
|
||||
case binary_operator::binary_type::bitwise_xor:
|
||||
calc_gen(node->get_left());
|
||||
calc_gen(node->get_right());
|
||||
gen(op_btxor, 0, node->get_line());
|
||||
gen(op_btxor, 0, node->get_location());
|
||||
return;
|
||||
case binary_operator::binary_type::bitwise_and:
|
||||
calc_gen(node->get_left());
|
||||
calc_gen(node->get_right());
|
||||
gen(op_btand, 0, node->get_line());
|
||||
gen(op_btand, 0, node->get_location());
|
||||
return;
|
||||
default: break;
|
||||
}
|
||||
|
@ -906,99 +908,99 @@ void codegen::binary_gen(binary_operator* node) {
|
|||
calc_gen(node->get_left());
|
||||
if (node->get_right()->get_type()!=expr_type::ast_num) {
|
||||
calc_gen(node->get_right());
|
||||
gen(op_add, 0, node->get_line());
|
||||
gen(op_add, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
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;
|
||||
case binary_operator::binary_type::sub:
|
||||
calc_gen(node->get_left());
|
||||
if (node->get_right()->get_type()!=expr_type::ast_num) {
|
||||
calc_gen(node->get_right());
|
||||
gen(op_sub, 0, node->get_line());
|
||||
gen(op_sub, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
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;
|
||||
case binary_operator::binary_type::mult:
|
||||
calc_gen(node->get_left());
|
||||
if (node->get_right()->get_type()!=expr_type::ast_num) {
|
||||
calc_gen(node->get_right());
|
||||
gen(op_mul, 0, node->get_line());
|
||||
gen(op_mul, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
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;
|
||||
case binary_operator::binary_type::div:
|
||||
calc_gen(node->get_left());
|
||||
if (node->get_right()->get_type()!=expr_type::ast_num) {
|
||||
calc_gen(node->get_right());
|
||||
gen(op_div, 0, node->get_line());
|
||||
gen(op_div, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
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;
|
||||
case binary_operator::binary_type::concat:
|
||||
calc_gen(node->get_left());
|
||||
if (node->get_right()->get_type()!=expr_type::ast_str) {
|
||||
calc_gen(node->get_right());
|
||||
gen(op_lnk, 0, node->get_line());
|
||||
gen(op_lnk, 0, node->get_location());
|
||||
} else {
|
||||
const auto& str = ((string_literal*)node->get_right())->get_content();
|
||||
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;
|
||||
case binary_operator::binary_type::less:
|
||||
calc_gen(node->get_left());
|
||||
if (node->get_right()->get_type()!=expr_type::ast_num) {
|
||||
calc_gen(node->get_right());
|
||||
gen(op_less, 0, node->get_line());
|
||||
gen(op_less, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
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;
|
||||
case binary_operator::binary_type::leq:
|
||||
calc_gen(node->get_left());
|
||||
if (node->get_right()->get_type()!=expr_type::ast_num) {
|
||||
calc_gen(node->get_right());
|
||||
gen(op_leq, 0, node->get_line());
|
||||
gen(op_leq, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
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;
|
||||
case binary_operator::binary_type::grt:
|
||||
calc_gen(node->get_left());
|
||||
if (node->get_right()->get_type()!=expr_type::ast_num) {
|
||||
calc_gen(node->get_right());
|
||||
gen(op_grt, 0, node->get_line());
|
||||
gen(op_grt, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
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;
|
||||
case binary_operator::binary_type::geq:
|
||||
calc_gen(node->get_left());
|
||||
if (node->get_right()->get_type()!=expr_type::ast_num) {
|
||||
calc_gen(node->get_right());
|
||||
gen(op_geq, 0, node->get_line());
|
||||
gen(op_geq, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
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;
|
||||
default: break;
|
||||
|
@ -1008,10 +1010,10 @@ void codegen::binary_gen(binary_operator* node) {
|
|||
void codegen::trino_gen(ternary_operator* node) {
|
||||
calc_gen(node->get_condition());
|
||||
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());
|
||||
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();
|
||||
calc_gen(node->get_right());
|
||||
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) {
|
||||
switch(node->get_type()) {
|
||||
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:
|
||||
num_gen((number_literal*)node); break;
|
||||
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_str:
|
||||
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:
|
||||
cond_gen((condition_expr*)tmp); break;
|
||||
case expr_type::ast_continue:
|
||||
continue_ptr.front().push_back(code.size());
|
||||
gen(op_jmp, 0, tmp->get_line());
|
||||
gen(op_jmp, 0, tmp->get_location());
|
||||
break;
|
||||
case expr_type::ast_break:
|
||||
break_ptr.front().push_back(code.size());
|
||||
gen(op_jmp, 0, tmp->get_line());
|
||||
gen(op_jmp, 0, tmp->get_location());
|
||||
break;
|
||||
case expr_type::ast_while:
|
||||
case expr_type::ast_for:
|
||||
|
@ -1101,16 +1100,20 @@ void codegen::block_gen(code_block* node) {
|
|||
|
||||
void codegen::ret_gen(return_expr* node) {
|
||||
for(u32 i = 0; i<in_loop_level.back(); ++i) {
|
||||
gen(op_pop, 0, node->get_line());
|
||||
gen(op_pop, 0, node->get_line());
|
||||
gen(op_pop, 0, node->get_location());
|
||||
gen(op_pop, 0, node->get_location());
|
||||
}
|
||||
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) {
|
||||
fileindex = 0;
|
||||
file = import.filelist();
|
||||
const auto& file = import.filelist();
|
||||
file_map = {};
|
||||
for(usize i = 0; i<file.size(); ++i) {
|
||||
file_map[file[i]] = i;
|
||||
}
|
||||
|
||||
in_loop_level.push_back(0);
|
||||
|
||||
// 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");
|
||||
|
||||
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
|
||||
gen(op_exit, 0, 0);
|
||||
gen(op_exit, 0, parse.tree()->get_location());
|
||||
|
||||
// size out of bound check
|
||||
if (const_number_table.size()>0xffffff) {
|
||||
|
|
|
@ -22,15 +22,24 @@
|
|||
|
||||
class codegen {
|
||||
private:
|
||||
u16 fileindex;
|
||||
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;
|
||||
|
||||
// constant numbers and strings
|
||||
std::unordered_map<f64, u32> const_number_map;
|
||||
std::unordered_map<std::string, u32> const_string_map;
|
||||
std::vector<f64> const_number_table;
|
||||
std::vector<std::string> const_string_table;
|
||||
|
||||
// generated opcodes
|
||||
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>> break_ptr;
|
||||
|
||||
|
@ -38,6 +47,7 @@ private:
|
|||
// global : max STACK_DEPTH-1 values
|
||||
std::unordered_map<std::string, i32> global;
|
||||
std::unordered_map<std::string, std::unordered_set<std::string>> experimental_namespace;
|
||||
|
||||
// local : max 32768 upvalues 65536 values
|
||||
// but in fact local scope also has less than STACK_DEPTH value
|
||||
std::list<std::unordered_map<std::string, i32>> local;
|
||||
|
@ -56,7 +66,7 @@ private:
|
|||
i32 global_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 str_gen(string_literal*);
|
||||
|
@ -105,7 +115,7 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
codegen(): fileindex(0) {}
|
||||
codegen() = default;
|
||||
const error& compile(parse&, linker&);
|
||||
void print(std::ostream&);
|
||||
void symbol_dump(std::ostream&) const;
|
||||
|
|
|
@ -313,12 +313,15 @@ definition_expr* linker::generate_module_definition(code_block* block) {
|
|||
|
||||
code_block* linker::load(code_block* root, u16 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) {
|
||||
auto tmp = import_nasal_lib();
|
||||
link(tree, tmp);
|
||||
delete tmp;
|
||||
lib_loaded = true;
|
||||
}
|
||||
// load imported modules
|
||||
for(auto i : root->get_expressions()) {
|
||||
if (!import_check(i)) {
|
||||
break;
|
||||
|
@ -327,9 +330,6 @@ code_block* linker::load(code_block* root, u16 fileindex) {
|
|||
tree->add_expression(generate_module_definition(tmp));
|
||||
}
|
||||
// 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);
|
||||
return tree;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# flightgear developer environments simulator (beta)
|
||||
# ValKmjolnir 2022
|
||||
import.std.runtime;
|
||||
|
||||
println("-------------------------------------------------------------");
|
||||
println(" FlightGear simulated-env for developers project, since 2019");
|
||||
|
|
|
@ -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);
|
||||
}
|
77
std/lib.nas
77
std/lib.nas
|
@ -2,6 +2,10 @@
|
|||
# 2019 ValKmjolnir
|
||||
|
||||
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.
|
||||
# this function uses std::cout to output logs.
|
||||
|
@ -327,38 +331,6 @@ var md5 = func(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
|
||||
var fstat = func(filename) {
|
||||
var s = io.stat(filename);
|
||||
|
@ -412,28 +384,6 @@ var bits = {
|
|||
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
|
||||
var D2R = math.pi / 180; # degree to radian
|
||||
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:
|
||||
var bind = func(function, locals, outer_scope = nil) {
|
||||
die("this runtime does not support bind");
|
||||
|
|
100
std/list.nas
100
std/list.nas
|
@ -1,51 +1,77 @@
|
|||
# list.nas
|
||||
# valkmjolnir 2021/3/31
|
||||
var list=func(){
|
||||
var (begin,end)=(nil,nil);
|
||||
return{
|
||||
push_back:func(elem){
|
||||
var tmp={elem:elem,prev:nil,next:nil};
|
||||
if(end!=nil){
|
||||
end.next=tmp;
|
||||
tmp.prev=end;
|
||||
end=tmp;
|
||||
|
||||
var new = func() {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
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;
|
||||
}
|
||||
else
|
||||
begin=end=tmp;
|
||||
len += 1;
|
||||
},
|
||||
pop_back:func(){
|
||||
if(end!=nil)
|
||||
end=end.prev;
|
||||
if(end==nil)
|
||||
begin=nil;
|
||||
else
|
||||
end.next=nil;
|
||||
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;
|
||||
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)
|
||||
front: func() {
|
||||
if (begin!=nil) {
|
||||
return begin.elem;
|
||||
}
|
||||
},
|
||||
back:func(){
|
||||
if(end!=nil)
|
||||
back: func() {
|
||||
if (end!=nil) {
|
||||
return end.elem;
|
||||
}
|
||||
},
|
||||
length: func() {
|
||||
return len;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;}
|
||||
};
|
|
@ -1,9 +1,12 @@
|
|||
# string.nas
|
||||
# ValKmjolnir 2022/10/5
|
||||
|
||||
var join=func(vec){
|
||||
var res="";
|
||||
foreach(var i;vec)
|
||||
res~=i;
|
||||
var join=func(sep, vec){
|
||||
var len = size(vec);
|
||||
var res = "";
|
||||
for(var i = 0; i<len; i+=1) {
|
||||
res ~= vec[i];
|
||||
res ~= (i==len-1? "":sep);
|
||||
}
|
||||
return res;
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
import.module.libmat;
|
||||
import.std.runtime;
|
||||
|
||||
func(){
|
||||
# allocate more spaces
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import.std.runtime;
|
||||
|
||||
var mod=func(n,a){
|
||||
return n-int(n/a)*a;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import.std.runtime;
|
||||
|
||||
var test_func = func(test_processes...) {
|
||||
var test_process_total = maketimestamp();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# hexdump.nas by ValKmjolnir
|
||||
# 2021/8/13
|
||||
import.std.file;
|
||||
import.std.runtime;
|
||||
|
||||
# init
|
||||
var hex=func(){
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import.module.libsock;
|
||||
import.std.json;
|
||||
import.std.runtime;
|
||||
|
||||
var JSON = json.JSON;
|
||||
var socket = libsock.socket;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import.std.process_bar;
|
||||
import.std.runtime;
|
||||
|
||||
var new_map=func(width,height){
|
||||
var tmp=[];
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import.std.process_bar;
|
||||
import.module.libkey;
|
||||
import.std.runtime;
|
||||
|
||||
var is_windows_platform=os.platform()=="windows";
|
||||
var is_macos_platform=os.platform()=="macOS";
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import.std.runtime;
|
||||
|
||||
# basic type
|
||||
nil;
|
||||
2147483647;
|
||||
|
@ -202,6 +204,7 @@ foreach(i;a){
|
|||
;
|
||||
}
|
||||
println(runtime.argv());
|
||||
println(globals.arg);
|
||||
func(a,b,c,d="只有红茶可以吗"){
|
||||
println(a,' ',b,' ',c,' ',d,' true: ',true,' false: ',false);
|
||||
}(c:1919810,b:514,a:114);
|
||||
|
|
|
@ -1,71 +1,6 @@
|
|||
import.module.libkey;
|
||||
|
||||
var list=func(){
|
||||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
import.std.list;
|
||||
import.std.runtime;
|
||||
|
||||
var game=func(x,y){
|
||||
rand(time(0));
|
||||
|
@ -88,7 +23,7 @@ var game=func(x,y){
|
|||
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)+1]);
|
||||
vec[int(x/2)][int(y/3)]=1;
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import.module.libkey;
|
||||
import.std.runtime;
|
||||
|
||||
var color=[
|
||||
"\e[31m","\e[32m","\e[33m","\e[34m","\e[35m","\e[36m",
|
||||
"\e[91m","\e[92m","\e[93m","\e[94m","\e[95m","\e[96m",
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import.std.runtime;
|
||||
|
||||
var os_time=func(){
|
||||
return "[\e[33;1m"~os.time()~"\e[0m] ";
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import.std.runtime;
|
||||
|
||||
var to_lower=func(s){
|
||||
var tmp="";
|
||||
|
|
Loading…
Reference in New Issue