native functions can be loaded from differen tables

This commit is contained in:
ValKmjolnir 2023-07-29 23:45:44 +08:00
parent fd7472b737
commit 227197996d
13 changed files with 110 additions and 70 deletions

View File

@ -84,7 +84,6 @@ build/nasal_ast.o: \
build/nasal_builtin.o: \ build/nasal_builtin.o: \
src/nasal.h\ src/nasal.h\
src/nasal_gc.h\ src/nasal_gc.h\
src/fg_props.h\
src/nasal_builtin.h src/nasal_builtin.cpp | build 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 . $(CXX) -std=$(STD) -c -O3 src/nasal_builtin.cpp -fno-exceptions -fPIC -o build/nasal_builtin.o -I .

View File

@ -28,4 +28,9 @@ var builtin_logprint(var* local, gc& ngc) {
} }
out << "\n"; out << "\n";
return nil; return nil;
} }
nasal_builtin_table flight_gear_native[] = {
{"_logprint", builtin_logprint},
{nullptr, nullptr}
};

View File

@ -2,6 +2,7 @@
#include "nasal.h" #include "nasal.h"
#include "nasal_gc.h" #include "nasal_gc.h"
#include "nasal_builtin.h"
#define SG_LOG_BULK 1 #define SG_LOG_BULK 1
#define SG_LOG_DEBUG 2 #define SG_LOG_DEBUG 2
@ -12,4 +13,6 @@
#define SG_DEV_ALERT 8 #define SG_DEV_ALERT 8
#define SG_MANDATORY_INFO 9 #define SG_MANDATORY_INFO 9
var builtin_logprint(var*, gc&); var builtin_logprint(var*, gc&);
extern nasal_builtin_table flight_gear_native[];

View File

@ -1,5 +1,4 @@
#include "nasal_builtin.h" #include "nasal_builtin.h"
#include "fg_props.h"
#include <chrono> #include <chrono>
var builtin_print(var* local, gc& ngc) { var builtin_print(var* local, gc& ngc) {
@ -1374,6 +1373,5 @@ nasal_builtin_table builtin[] = {
{"__gcinfo", builtin_gcinfo}, {"__gcinfo", builtin_gcinfo},
{"__logtime", builtin_logtime}, {"__logtime", builtin_logtime},
{"__ghosttype", builtin_ghosttype}, {"__ghosttype", builtin_ghosttype},
{"_logprint", builtin_logprint},
{nullptr, nullptr} {nullptr, nullptr}
}; };

View File

@ -134,7 +134,7 @@ var builtin_ghosttype(var*, gc&);
// this table must end with {nullptr,nullptr} // this table must end with {nullptr,nullptr}
struct nasal_builtin_table { struct nasal_builtin_table {
const char* name; const char* name;
var (*func)(var*,gc&); var (*func)(var*, gc&);
}; };
extern nasal_builtin_table builtin[]; extern nasal_builtin_table builtin[];

View File

@ -1,15 +1,30 @@
#include "nasal_codegen.h" #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) { void codegen::check_id_exist(identifier* node) {
const auto& name = node->get_name(); const auto& name = node->get_name();
for(u32 i = 0; builtin[i].name; ++i) { if (native_function_mapper.count(name)) {
if (builtin[i].name==name) { if (local.empty()) {
if (local.empty()) { die("native function should not be used in global scope",
die("native function used in global scope", node->get_location());
node->get_location());
}
return;
} }
return;
} }
if (local_find(name)>=0) { if (local_find(name)>=0) {
@ -269,16 +284,17 @@ void codegen::call_gen(call_expr* node) {
void codegen::call_id(identifier* node) { 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) { if (native_function_mapper.count(name)) {
if (builtin[i].name==name) { gen(op_callb,
gen(op_callb, i, node->get_location()); static_cast<u32>(native_function_mapper.at(name)),
if (local.empty()) { node->get_location());
die("should warp native function in local scope", if (local.empty()) {
node->get_location()); die("should warp native function in local scope",
} node->get_location());
return;
} }
return;
} }
i32 index; i32 index;
if ((index=local_find(name))>=0) { if ((index=local_find(name))>=0) {
gen(op_calll, index, node->get_location()); gen(op_calll, index, node->get_location());
@ -384,12 +400,11 @@ void codegen::mcall(expr* node) {
void codegen::mcall_id(identifier* node) { void codegen::mcall_id(identifier* node) {
const auto& name = node->get_name(); const auto& name = node->get_name();
for(u32 i = 0; builtin[i].name; ++i) { if (native_function_mapper.count(name)) {
if (builtin[i].name==name) { die("cannot modify native function", node->get_location());
die("cannot modify native function", node->get_location()); return;
return;
}
} }
i32 index; i32 index;
if ((index=local_find(name))>=0) { if ((index=local_find(name))>=0) {
gen(op_mcalll, index, node->get_location()); 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) { const error& codegen::compile(parse& parse, linker& import) {
init_native_function();
const auto& file = import.filelist(); const auto& file = import.filelist();
file_map = {}; file_map = {};
for(usize i = 0; i<file.size(); ++i) { for(usize i = 0; i<file.size(); ++i) {
@ -1175,7 +1191,10 @@ void codegen::print(std::ostream& out) {
} }
// print code // print code
codestream::set(const_number_table.data(), const_string_table.data()); codestream::set(
const_number_table.data(),
const_string_table.data(),
native_function.data());
for(u32 i = 0; i<code.size(); ++i) { for(u32 i = 0; i<code.size(); ++i) {
// print opcode index, opcode name, opcode immediate number // print opcode index, opcode name, opcode immediate number
const auto& c = code[i]; const auto& c = code[i];

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "nasal_err.h" #include "nasal_err.h"
#include "nasal_builtin.h"
#include "nasal_opcode.h" #include "nasal_opcode.h"
#include "nasal_ast.h" #include "nasal_ast.h"
#include "ast_visitor.h" #include "ast_visitor.h"
@ -9,6 +8,9 @@
#include "nasal_parse.h" #include "nasal_parse.h"
#include "nasal_import.h" #include "nasal_import.h"
#include "nasal_builtin.h"
#include "fg_props.h"
#include <iomanip> #include <iomanip>
#include <list> #include <list>
#include <stack> #include <stack>
@ -36,6 +38,12 @@ private:
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;
// native functions
std::vector<nasal_builtin_table> native_function;
std::unordered_map<std::string, usize> native_function_mapper;
void load_native_function_table(nasal_builtin_table*);
void init_native_function();
// generated opcodes // generated opcodes
std::vector<opcode> code; std::vector<opcode> code;
@ -108,6 +116,7 @@ private:
public: public:
const auto& strs() const {return const_string_table;} const auto& strs() const {return const_string_table;}
const auto& nums() const {return const_number_table;} const auto& nums() const {return const_number_table;}
const auto& natives() const {return native_function;}
const auto& codes() const {return code;} const auto& codes() const {return code;}
const auto& globals() const {return global;} const auto& globals() const {return global;}
const auto& get_experimental_namespace() const { const auto& get_experimental_namespace() const {

View File

@ -91,7 +91,7 @@ void dbg::step_info() {
begin = (ctx.pc>>3)==0? 0:((ctx.pc>>3)<<3); begin = (ctx.pc>>3)==0? 0:((ctx.pc>>3)<<3);
end = (1+(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"; std::clog << "next bytecode:\n";
for(u32 i = begin; i<end && bytecode[i].op!=op_exit; ++i) { for(u32 i = begin; i<end && bytecode[i].op!=op_exit; ++i) {
std::clog std::clog
@ -164,12 +164,8 @@ void dbg::run(
const std::vector<std::string>& argv) { const std::vector<std::string>& argv) {
verbose = true; verbose = true;
fsize = linker.filelist().size(); fsize = linker.filelist().size();
init(gen.strs(), init(gen.strs(), gen.nums(), gen.natives(),
gen.nums(), gen.codes(), gen.globals(), linker.filelist(), argv);
gen.codes(),
gen.globals(),
linker.filelist(),
argv);
u64 count[op_ret+1] = {0}; u64 count[op_ret+1] = {0};
typedef void (dbg::*nafunc)(); typedef void (dbg::*nafunc)();
const nafunc oprs[] = { const nafunc oprs[] = {

View File

@ -344,7 +344,7 @@ struct gc {
context* rctx = nullptr; context* rctx = nullptr;
nas_co* cort = nullptr; // running coroutine nas_co* cort = nullptr; // running coroutine
/* temporary space used in builtin/module functions */ /* temporary space used in native/module functions */
var temp = nil; var temp = nil;
/* constants and memory pool */ /* constants and memory pool */

View File

@ -26,12 +26,14 @@ const char* opname[] = {
}; };
void codestream::set( void codestream::set(
const f64* numbuff, const f64* num_buff,
const std::string* strbuff, const std::string* str_buff,
const std::string* filelist) { const nasal_builtin_table* native_table_ptr,
nums = numbuff; const std::string* file_list) {
strs = strbuff; nums = num_buff;
files = filelist; strs = str_buff;
natives = native_table_ptr;
files = file_list;
} }
void codestream::dump(std::ostream& out) const { void codestream::dump(std::ostream& out) const {
@ -87,8 +89,8 @@ void codestream::dump(std::ostream& out) const {
case op_loadl: case op_loadl:
out << hex << "0x" << num << dec; break; out << hex << "0x" << num << dec; break;
case op_callb: case op_callb:
out << hex << "0x" << num << " <" << builtin[num].name out << hex << "0x" << num << " <" << natives[num].name
<< "@0x" << (u64)builtin[num].func << dec << ">"; break; << "@0x" << (u64)natives[num].func << dec << ">"; break;
case op_upval: case op_mupval: case op_upval: case op_mupval:
case op_loadu: case op_loadu:
out << hex << "0x" << ((num>>16)&0xffff) out << hex << "0x" << ((num>>16)&0xffff)

View File

@ -57,16 +57,16 @@ enum op_code_type:u8 {
op_divecp, // /= const and pop stack top op_divecp, // /= const and pop stack top
op_lnkecp, // ~= concat const std::string and pop stack top op_lnkecp, // ~= concat const std::string and pop stack top
op_meq, // = maybe pop stack top op_meq, // = maybe pop stack top
op_eq, // == op_eq, // == compare operator
op_neq, // != op_neq, // != compare operator
op_less, // < op_less, // < compare operator
op_leq, // <= op_leq, // <= compare operator
op_grt, // > op_grt, // > compare operator
op_geq, // >= op_geq, // >= compare operator
op_lessc, // < const op_lessc, // < const compare operator
op_leqc, // <= const op_leqc, // <= const compare operator
op_grtc, // > const op_grtc, // > const compare operator
op_geqc, // >= const op_geqc, // >= const compare operator
op_pop, // pop a value out of stack top op_pop, // pop a value out of stack top
op_jmp, // jump absolute address with no condition op_jmp, // jump absolute address with no condition
op_jt, // used in operator and/or,jmp when condition is true and DO NOT POP 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_callh, // call hash.label
op_callfv, // call function(vector as parameters) op_callfv, // call function(vector as parameters)
op_callfh, // call function(hash as parameters) op_callfh, // call function(hash as parameters)
op_callb, // call builtin-function op_callb, // call native functions
op_slcbeg, // begin of slice like: vec[1,2,3:6,0,-1] op_slcbeg, // begin of slice like: vec[1, 2, 3:6, 0, -1]
op_slcend, // end of slice op_slcend, // end of slice
op_slc, // slice like vec[1] op_slc, // slice like vec[1]
op_slc2, // slice like vec[nil:10] op_slc2, // slice like vec[nil:10]
@ -111,10 +111,16 @@ private:
const u32 index; const u32 index;
inline static const f64* nums = nullptr; inline static const f64* nums = nullptr;
inline static const std::string* strs = nullptr; inline static const std::string* strs = nullptr;
inline static const nasal_builtin_table* natives = nullptr;
inline static const std::string* files = nullptr; inline static const std::string* files = nullptr;
public: public:
codestream(const opcode& c, const u32 i): code(c), index(i) {} 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; void dump(std::ostream&) const;
}; };

View File

@ -3,6 +3,7 @@
void vm::init( void vm::init(
const std::vector<std::string>& strs, const std::vector<std::string>& strs,
const std::vector<f64>& nums, const std::vector<f64>& nums,
const std::vector<nasal_builtin_table>& natives,
const std::vector<opcode>& code, const std::vector<opcode>& code,
const std::unordered_map<std::string, i32>& global, const std::unordered_map<std::string, i32>& global,
const std::vector<std::string>& filenames, const std::vector<std::string>& filenames,
@ -13,6 +14,9 @@ void vm::init(
bytecode = code.data(); bytecode = code.data();
files = filenames.data(); files = filenames.data();
/* set native functions */
native = natives;
/* set canary and program counter */ /* set canary and program counter */
ctx.pc = 0; ctx.pc = 0;
ctx.localr = nullptr; ctx.localr = nullptr;
@ -98,7 +102,7 @@ void vm::traceback() {
std::clog << "trace back (" std::clog << "trace back ("
<< (ngc.rctx->stack==stack? "main":"coroutine") << (ngc.rctx->stack==stack? "main":"coroutine")
<< ")\n"; << ")\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()) { for(u32 p = 0, same = 0, prev = 0xffffffff; !ret.empty(); prev = p, ret.pop()) {
if ((p = ret.top())==prev) { if ((p = ret.top())==prev) {
++same; ++same;
@ -230,12 +234,8 @@ void vm::run(
const std::vector<std::string>& argv, const std::vector<std::string>& argv,
const bool detail) { const bool detail) {
verbose = detail; verbose = detail;
init(gen.strs(), init(gen.strs(), gen.nums(), gen.natives(),
gen.nums(), gen.codes(), gen.globals(), linker.filelist(), argv);
gen.codes(),
gen.globals(),
linker.filelist(),
argv);
#ifndef _MSC_VER #ifndef _MSC_VER
// using labels as values/computed goto // using labels as values/computed goto
const void* oprs[] = { const void* oprs[] = {

View File

@ -33,11 +33,13 @@ protected:
/* values used for debugger */ /* values used for debugger */
const std::string* files = nullptr; // file name list const std::string* files = nullptr; // file name list
const opcode* bytecode = nullptr; // bytecode buffer address const opcode* bytecode = nullptr; // bytecode buffer address
std::vector<nasal_builtin_table> native;
/* vm initializing function */ /* vm initializing function */
void init( void init(
const std::vector<std::string>&, const std::vector<std::string>&,
const std::vector<f64>&, const std::vector<f64>&,
const std::vector<nasal_builtin_table>&,
const std::vector<opcode>&, const std::vector<opcode>&,
const std::unordered_map<std::string, i32>&, const std::unordered_map<std::string, i32>&,
const std::vector<std::string>&, const std::vector<std::string>&,
@ -739,13 +741,13 @@ inline void vm::o_callfh() {
} }
inline void vm::o_callb() { inline void vm::o_callb() {
// reserve place for builtin function return, // reserve place for native function return,
// this code is written for coroutine // this code is written for coroutine
(++ctx.top)[0] = nil; (++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 // (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 // so we use tmp variable to store this return value
// and set it to top[0] later // 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 get none, this means errors occurred when calling this native function
if (ctx.top[0].type==vm_none) { if (ctx.top[0].type==vm_none) {
die("native function error"); die("error occurred in native function");
return; return;
} }
} }
@ -780,7 +782,7 @@ inline void vm::o_slc() {
var val = (ctx.top--)[0]; var val = (ctx.top--)[0];
var res = ctx.top[-1].vec().get_val(val.tonum()); var res = ctx.top[-1].vec().get_val(val.tonum());
if (res.type==vm_none) { 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; return;
} }
ctx.top[0].vec().elems.push_back(res); 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) { 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; return;
} else if (num1<=num2) { } else if (num1<=num2) {
for(i32 i = num1; i<=num2; ++i) { for(i32 i = num1; i<=num2; ++i) {