✨ native functions can be loaded from differen tables
This commit is contained in:
parent
fd7472b737
commit
227197996d
1
makefile
1
makefile
|
@ -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 .
|
||||||
|
|
||||||
|
|
|
@ -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}
|
||||||
|
};
|
|
@ -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[];
|
||||||
|
|
|
@ -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}
|
||||||
};
|
};
|
|
@ -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[];
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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[] = {
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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[] = {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue