diff --git a/makefile b/makefile index cc9ecfc..7db2e34 100644 --- a/makefile +++ b/makefile @@ -84,7 +84,6 @@ build/nasal_ast.o: \ build/nasal_builtin.o: \ src/nasal.h\ src/nasal_gc.h\ - src/fg_props.h\ src/nasal_builtin.h src/nasal_builtin.cpp | build $(CXX) -std=$(STD) -c -O3 src/nasal_builtin.cpp -fno-exceptions -fPIC -o build/nasal_builtin.o -I . diff --git a/src/fg_props.cpp b/src/fg_props.cpp index 32f470b..206f267 100644 --- a/src/fg_props.cpp +++ b/src/fg_props.cpp @@ -28,4 +28,9 @@ var builtin_logprint(var* local, gc& ngc) { } out << "\n"; return nil; -} \ No newline at end of file +} + +nasal_builtin_table flight_gear_native[] = { + {"_logprint", builtin_logprint}, + {nullptr, nullptr} +}; \ No newline at end of file diff --git a/src/fg_props.h b/src/fg_props.h index 852f3a6..59d136c 100644 --- a/src/fg_props.h +++ b/src/fg_props.h @@ -2,6 +2,7 @@ #include "nasal.h" #include "nasal_gc.h" +#include "nasal_builtin.h" #define SG_LOG_BULK 1 #define SG_LOG_DEBUG 2 @@ -12,4 +13,6 @@ #define SG_DEV_ALERT 8 #define SG_MANDATORY_INFO 9 -var builtin_logprint(var*, gc&); \ No newline at end of file +var builtin_logprint(var*, gc&); + +extern nasal_builtin_table flight_gear_native[]; diff --git a/src/nasal_builtin.cpp b/src/nasal_builtin.cpp index eef53ff..4ceed8e 100644 --- a/src/nasal_builtin.cpp +++ b/src/nasal_builtin.cpp @@ -1,5 +1,4 @@ #include "nasal_builtin.h" -#include "fg_props.h" #include var builtin_print(var* local, gc& ngc) { @@ -1374,6 +1373,5 @@ nasal_builtin_table builtin[] = { {"__gcinfo", builtin_gcinfo}, {"__logtime", builtin_logtime}, {"__ghosttype", builtin_ghosttype}, - {"_logprint", builtin_logprint}, {nullptr, nullptr} }; \ No newline at end of file diff --git a/src/nasal_builtin.h b/src/nasal_builtin.h index 3cd7974..d14d62d 100644 --- a/src/nasal_builtin.h +++ b/src/nasal_builtin.h @@ -134,7 +134,7 @@ var builtin_ghosttype(var*, gc&); // this table must end with {nullptr,nullptr} struct nasal_builtin_table { const char* name; - var (*func)(var*,gc&); + var (*func)(var*, gc&); }; extern nasal_builtin_table builtin[]; diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index b1adddb..b3b7753 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -1,15 +1,30 @@ #include "nasal_codegen.h" +void codegen::load_native_function_table(nasal_builtin_table* table) { + for(usize i = 0; table[i].func; ++i) { + if (native_function_mapper.count(table[i].name)) { + err.err("code", "\"" + std::string(table[i].name) + "\" conflicts."); + continue; + } + native_function.push_back(table[i]); + auto index = native_function_mapper.size(); + native_function_mapper[table[i].name] = index; + } +} + +void codegen::init_native_function() { + load_native_function_table(builtin); + load_native_function_table(flight_gear_native); +} + void codegen::check_id_exist(identifier* node) { const auto& name = node->get_name(); - for(u32 i = 0; builtin[i].name; ++i) { - if (builtin[i].name==name) { - if (local.empty()) { - die("native function used in global scope", - node->get_location()); - } - return; + if (native_function_mapper.count(name)) { + if (local.empty()) { + die("native function should not be used in global scope", + node->get_location()); } + return; } if (local_find(name)>=0) { @@ -269,16 +284,17 @@ void codegen::call_gen(call_expr* node) { 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_location()); - if (local.empty()) { - die("should warp native function in local scope", - node->get_location()); - } - return; + if (native_function_mapper.count(name)) { + gen(op_callb, + static_cast(native_function_mapper.at(name)), + node->get_location()); + if (local.empty()) { + die("should warp native function in local scope", + node->get_location()); } + return; } + i32 index; if ((index=local_find(name))>=0) { gen(op_calll, index, node->get_location()); @@ -384,12 +400,11 @@ void codegen::mcall(expr* node) { void codegen::mcall_id(identifier* node) { const auto& name = node->get_name(); - for(u32 i = 0; builtin[i].name; ++i) { - if (builtin[i].name==name) { - die("cannot modify native function", node->get_location()); - return; - } + if (native_function_mapper.count(name)) { + die("cannot modify native function", node->get_location()); + return; } + i32 index; if ((index=local_find(name))>=0) { gen(op_mcalll, index, node->get_location()); @@ -1114,6 +1129,7 @@ void codegen::ret_gen(return_expr* node) { } const error& codegen::compile(parse& parse, linker& import) { + init_native_function(); const auto& file = import.filelist(); file_map = {}; for(usize i = 0; i #include #include @@ -36,6 +38,12 @@ private: std::vector const_number_table; std::vector const_string_table; + // native functions + std::vector native_function; + std::unordered_map native_function_mapper; + void load_native_function_table(nasal_builtin_table*); + void init_native_function(); + // generated opcodes std::vector code; @@ -108,6 +116,7 @@ private: public: const auto& strs() const {return const_string_table;} const auto& nums() const {return const_number_table;} + const auto& natives() const {return native_function;} const auto& codes() const {return code;} const auto& globals() const {return global;} const auto& get_experimental_namespace() const { diff --git a/src/nasal_dbg.cpp b/src/nasal_dbg.cpp index 66b73f6..cd50eff 100644 --- a/src/nasal_dbg.cpp +++ b/src/nasal_dbg.cpp @@ -91,7 +91,7 @@ void dbg::step_info() { begin = (ctx.pc>>3)==0? 0:((ctx.pc>>3)<<3); end = (1+(ctx.pc>>3))<<3; - codestream::set(cnum, cstr, files); + codestream::set(cnum, cstr, native.data(), files); std::clog << "next bytecode:\n"; for(u32 i = begin; i& argv) { verbose = true; fsize = linker.filelist().size(); - init(gen.strs(), - gen.nums(), - gen.codes(), - gen.globals(), - linker.filelist(), - argv); + init(gen.strs(), gen.nums(), gen.natives(), + gen.codes(), gen.globals(), linker.filelist(), argv); u64 count[op_ret+1] = {0}; typedef void (dbg::*nafunc)(); const nafunc oprs[] = { diff --git a/src/nasal_gc.h b/src/nasal_gc.h index a5c0f7d..539104c 100644 --- a/src/nasal_gc.h +++ b/src/nasal_gc.h @@ -344,7 +344,7 @@ struct gc { context* rctx = nullptr; nas_co* cort = nullptr; // running coroutine - /* temporary space used in builtin/module functions */ + /* temporary space used in native/module functions */ var temp = nil; /* constants and memory pool */ diff --git a/src/nasal_opcode.cpp b/src/nasal_opcode.cpp index f02dee8..00d0e26 100644 --- a/src/nasal_opcode.cpp +++ b/src/nasal_opcode.cpp @@ -26,12 +26,14 @@ const char* opname[] = { }; void codestream::set( - const f64* numbuff, - const std::string* strbuff, - const std::string* filelist) { - nums = numbuff; - strs = strbuff; - files = filelist; + const f64* num_buff, + const std::string* str_buff, + const nasal_builtin_table* native_table_ptr, + const std::string* file_list) { + nums = num_buff; + strs = str_buff; + natives = native_table_ptr; + files = file_list; } void codestream::dump(std::ostream& out) const { @@ -87,8 +89,8 @@ void codestream::dump(std::ostream& out) const { case op_loadl: out << hex << "0x" << num << dec; break; case op_callb: - out << hex << "0x" << num << " <" << builtin[num].name - << "@0x" << (u64)builtin[num].func << dec << ">"; break; + out << hex << "0x" << num << " <" << natives[num].name + << "@0x" << (u64)natives[num].func << dec << ">"; break; case op_upval: case op_mupval: case op_loadu: out << hex << "0x" << ((num>>16)&0xffff) diff --git a/src/nasal_opcode.h b/src/nasal_opcode.h index 0496e6b..d7f93fc 100644 --- a/src/nasal_opcode.h +++ b/src/nasal_opcode.h @@ -57,16 +57,16 @@ enum op_code_type:u8 { op_divecp, // /= const and pop stack top op_lnkecp, // ~= concat const std::string and pop stack top op_meq, // = maybe pop stack top - op_eq, // == - op_neq, // != - op_less, // < - op_leq, // <= - op_grt, // > - op_geq, // >= - op_lessc, // < const - op_leqc, // <= const - op_grtc, // > const - op_geqc, // >= const + op_eq, // == compare operator + op_neq, // != compare operator + op_less, // < compare operator + op_leq, // <= compare operator + op_grt, // > compare operator + op_geq, // >= compare operator + op_lessc, // < const compare operator + op_leqc, // <= const compare operator + op_grtc, // > const compare operator + op_geqc, // >= const compare operator op_pop, // pop a value out of stack top op_jmp, // jump absolute address with no condition op_jt, // used in operator and/or,jmp when condition is true and DO NOT POP @@ -82,8 +82,8 @@ enum op_code_type:u8 { op_callh, // call hash.label op_callfv, // call function(vector as parameters) op_callfh, // call function(hash as parameters) - op_callb, // call builtin-function - op_slcbeg, // begin of slice like: vec[1,2,3:6,0,-1] + op_callb, // call native functions + op_slcbeg, // begin of slice like: vec[1, 2, 3:6, 0, -1] op_slcend, // end of slice op_slc, // slice like vec[1] op_slc2, // slice like vec[nil:10] @@ -111,10 +111,16 @@ private: const u32 index; inline static const f64* nums = nullptr; inline static const std::string* strs = nullptr; + inline static const nasal_builtin_table* natives = nullptr; inline static const std::string* files = nullptr; + public: codestream(const opcode& c, const u32 i): code(c), index(i) {} - static void set(const f64*, const std::string*, const std::string* filelist = nullptr); + static void set( + const f64*, const std::string*, + const nasal_builtin_table*, + const std::string* file_list = nullptr + ); void dump(std::ostream&) const; }; diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index dcf00ee..7ac75e4 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -3,6 +3,7 @@ void vm::init( const std::vector& strs, const std::vector& nums, + const std::vector& natives, const std::vector& code, const std::unordered_map& global, const std::vector& filenames, @@ -13,6 +14,9 @@ void vm::init( bytecode = code.data(); files = filenames.data(); + /* set native functions */ + native = natives; + /* set canary and program counter */ ctx.pc = 0; ctx.localr = nullptr; @@ -98,7 +102,7 @@ void vm::traceback() { std::clog << "trace back (" << (ngc.rctx->stack==stack? "main":"coroutine") << ")\n"; - codestream::set(cnum, cstr, files); + codestream::set(cnum, cstr, native.data(), files); for(u32 p = 0, same = 0, prev = 0xffffffff; !ret.empty(); prev = p, ret.pop()) { if ((p = ret.top())==prev) { ++same; @@ -230,12 +234,8 @@ void vm::run( const std::vector& argv, const bool detail) { verbose = detail; - init(gen.strs(), - gen.nums(), - gen.codes(), - gen.globals(), - linker.filelist(), - argv); + init(gen.strs(), gen.nums(), gen.natives(), + gen.codes(), gen.globals(), linker.filelist(), argv); #ifndef _MSC_VER // using labels as values/computed goto const void* oprs[] = { diff --git a/src/nasal_vm.h b/src/nasal_vm.h index c9ab6d5..92a7a64 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -33,11 +33,13 @@ protected: /* values used for debugger */ const std::string* files = nullptr; // file name list const opcode* bytecode = nullptr; // bytecode buffer address + std::vector native; /* vm initializing function */ void init( const std::vector&, const std::vector&, + const std::vector&, const std::vector&, const std::unordered_map&, const std::vector&, @@ -739,13 +741,13 @@ inline void vm::o_callfh() { } inline void vm::o_callb() { - // reserve place for builtin function return, + // reserve place for native function return, // this code is written for coroutine (++ctx.top)[0] = nil; - // if running a builtin function about coroutine + // if running a native function about coroutine // (top) will be set to another context.top, instead of main_context.top - var tmp = (*builtin[imm[ctx.pc]].func)(ctx.localr, ngc); + var tmp = (*native[imm[ctx.pc]].func)(ctx.localr, ngc); // so we use tmp variable to store this return value // and set it to top[0] later @@ -753,7 +755,7 @@ inline void vm::o_callb() { // if get none, this means errors occurred when calling this native function if (ctx.top[0].type==vm_none) { - die("native function error"); + die("error occurred in native function"); return; } } @@ -780,7 +782,7 @@ inline void vm::o_slc() { var val = (ctx.top--)[0]; var res = ctx.top[-1].vec().get_val(val.tonum()); if (res.type==vm_none) { - die("index "+std::to_string(val.tonum())+" out of range"); + die("index " + std::to_string(val.tonum()) + " out of range"); return; } ctx.top[0].vec().elems.push_back(res); @@ -806,7 +808,8 @@ inline void vm::o_slc2() { } if (num1<-size || num1>=size || num2<-size || num2>=size) { - die("index "+std::to_string(num1)+":"+std::to_string(num2)+" out of range"); + die("index " + std::to_string(num1) + ":" + + std::to_string(num2) + " out of range"); return; } else if (num1<=num2) { for(i32 i = num1; i<=num2; ++i) {