bug fixed

This commit is contained in:
ValKmjolnir 2021-10-26 22:34:02 +08:00
parent 540aeb73f4
commit 183446d32a
7 changed files with 255 additions and 286 deletions

View File

@ -1,6 +1,6 @@
.PHONY=test .PHONY=test
nasal:main.cpp nasal_ast.h nasal_builtin.h nasal_codegen.h nasal_gc.h nasal_import.h nasal_lexer.h nasal_parse.h nasal_vm.h nasal.h nasal:main.cpp nasal_ast.h nasal_builtin.h nasal_codegen.h nasal_gc.h nasal_import.h nasal_lexer.h nasal_parse.h nasal_vm.h nasal.h
clang++ -std=c++11 -O3 main.cpp -o nasal -fno-exceptions -Wshadow clang++ -std=c++11 -O3 main.cpp -o nasal -fno-exceptions -Wshadow -Wall
test:nasal test:nasal
./nasal test/ascii-art.nas ./nasal test/ascii-art.nas
./nasal -c test/bf.nas ./nasal -c test/bf.nas

View File

@ -1,6 +1,5 @@
#ifndef __NASAL_H__ #ifndef __NASAL_H__
#define __NASAL_H__ #define __NASAL_H__
#pragma GCC optimize(2)
#include <stdint.h> #include <stdint.h>
#include <unistd.h> #include <unistd.h>
@ -20,10 +19,6 @@
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
/*
check if a string can be converted to a number
if this string cannot be converted to a number,it will return nan
*/
inline double hex_to_double(const char* str) inline double hex_to_double(const char* str)
{ {
double ret=0; double ret=0;
@ -104,9 +99,6 @@ double str2num(const char* str)
return is_negative?-ret_num:ret_num; return is_negative?-ret_num:ret_num;
} }
/*
show raw string
*/
std::string raw_string(const std::string& str) std::string raw_string(const std::string& str)
{ {
std::string ret(""); std::string ret("");

View File

@ -66,13 +66,13 @@ const char* ast_name[]=
class nasal_ast class nasal_ast
{ {
private: private:
uint32_t text_line; uint32_t _line;
uint32_t node_type; uint32_t _type;
double node_num; double _num;
std::string node_str; std::string _str;
std::vector<nasal_ast> node_child; std::vector<nasal_ast> _child;
public: public:
nasal_ast(const uint32_t l=0,const uint32_t t=ast_null):text_line(l),node_type(t){} nasal_ast(const uint32_t l=0,const uint32_t t=ast_null):_line(l),_type(t){}
nasal_ast(const nasal_ast&); nasal_ast(const nasal_ast&);
nasal_ast(nasal_ast&&); nasal_ast(nasal_ast&&);
void print(const int); void print(const int);
@ -80,88 +80,88 @@ public:
nasal_ast& operator=(const nasal_ast&); nasal_ast& operator=(const nasal_ast&);
nasal_ast& operator=(nasal_ast&&); nasal_ast& operator=(nasal_ast&&);
nasal_ast& operator[](const int index){return node_child[index];} nasal_ast& operator[](const int index){return _child[index];}
const nasal_ast& operator[](const int index) const {return node_child[index];} const nasal_ast& operator[](const int index) const {return _child[index];}
size_t size() const {return node_child.size();} size_t size() const {return _child.size();}
void add(nasal_ast&& ast){node_child.push_back(std::move(ast));} void add(nasal_ast&& ast){_child.push_back(std::move(ast));}
void add(const nasal_ast& ast){node_child.push_back(ast);} void add(const nasal_ast& ast){_child.push_back(ast);}
void set_line(const uint32_t l){text_line=l;} void set_line(const uint32_t l){_line=l;}
void set_type(const uint32_t t){node_type=t;} void set_type(const uint32_t t){_type=t;}
void set_str(const std::string& s){node_str=s;} void set_str(const std::string& s){_str=s;}
void set_num(const double n){node_num=n;} void set_num(const double n){_num=n;}
inline const uint32_t line() const {return text_line;} inline uint32_t line() const {return _line;}
inline const uint32_t type() const {return node_type;} inline uint32_t type() const {return _type;}
inline const double num() const {return node_num;} inline double num() const {return _num;}
inline const std::string& str() const {return node_str;} inline const std::string& str() const {return _str;}
inline const std::vector<nasal_ast>& child() const {return node_child;} inline const std::vector<nasal_ast>& child() const {return _child;}
inline std::vector<nasal_ast>& child(){return node_child;} inline std::vector<nasal_ast>& child(){return _child;}
}; };
nasal_ast::nasal_ast(const nasal_ast& tmp) nasal_ast::nasal_ast(const nasal_ast& tmp)
{ {
text_line=tmp.text_line; _line=tmp._line;
node_type=tmp.node_type; _type=tmp._type;
node_num =tmp.node_num; _num =tmp._num;
node_str =tmp.node_str; _str =tmp._str;
node_child=tmp.node_child; _child=tmp._child;
} }
nasal_ast::nasal_ast(nasal_ast&& tmp) nasal_ast::nasal_ast(nasal_ast&& tmp)
{ {
text_line=tmp.text_line; _line=tmp._line;
node_type=tmp.node_type; _type=tmp._type;
node_num =tmp.node_num; _num =tmp._num;
node_str.swap(tmp.node_str); _str.swap(tmp._str);
node_child.swap(tmp.node_child); _child.swap(tmp._child);
} }
nasal_ast& nasal_ast::operator=(const nasal_ast& tmp) nasal_ast& nasal_ast::operator=(const nasal_ast& tmp)
{ {
text_line=tmp.text_line; _line=tmp._line;
node_type=tmp.node_type; _type=tmp._type;
node_num=tmp.node_num; _num=tmp._num;
node_str=tmp.node_str; _str=tmp._str;
node_child=tmp.node_child; _child=tmp._child;
return *this; return *this;
} }
nasal_ast& nasal_ast::operator=(nasal_ast&& tmp) nasal_ast& nasal_ast::operator=(nasal_ast&& tmp)
{ {
text_line=tmp.text_line; _line=tmp._line;
node_type=tmp.node_type; _type=tmp._type;
node_num=tmp.node_num; _num=tmp._num;
node_str.swap(tmp.node_str); _str.swap(tmp._str);
node_child.swap(tmp.node_child); _child.swap(tmp._child);
return *this; return *this;
} }
void nasal_ast::clear() void nasal_ast::clear()
{ {
text_line=0; _line=0;
node_num=0; _num=0;
node_str=""; _str="";
node_type=ast_null; _type=ast_null;
node_child.clear(); _child.clear();
} }
void nasal_ast::print(const int depth) void nasal_ast::print(const int depth)
{ {
for(int i=0;i<depth;++i) for(int i=0;i<depth;++i)
std::cout<<"| "; std::cout<<"| ";
std::cout<<ast_name[node_type]; std::cout<<ast_name[_type];
if( if(
node_type==ast_str || _type==ast_str ||
node_type==ast_id || _type==ast_id ||
node_type==ast_default || _type==ast_default ||
node_type==ast_dynamic || _type==ast_dynamic ||
node_type==ast_callh) _type==ast_callh)
std::cout<<":"<<raw_string(node_str); std::cout<<":"<<raw_string(_str);
else if(node_type==ast_num || node_type==ast_file) else if(_type==ast_num || _type==ast_file)
std::cout<<":"<<node_num; std::cout<<":"<<_num;
std::cout<<'\n'; std::cout<<'\n';
for(auto& i:node_child) for(auto& i:_child)
i.print(depth+1); i.print(depth+1);
} }

View File

@ -32,13 +32,13 @@ const uint32_t increment[vm_type_size]=
128 // vm_obj 128 // vm_obj
}; };
// declaration of nasal value type
struct nasal_vec; struct nasal_vec;
struct nasal_hash; struct nasal_hash;
struct nasal_func; struct nasal_func;
struct nasal_obj;
struct nasal_val; struct nasal_val;
// declaration of nasal_ref
struct nasal_ref// 16 bytes struct nasal_ref
{ {
uint8_t type; uint8_t type;
union union
@ -50,43 +50,27 @@ struct nasal_ref// 16 bytes
nasal_ref(const uint8_t t=vm_none):type(t){} nasal_ref(const uint8_t t=vm_none):type(t){}
nasal_ref(const uint8_t t,const double n):type(t){value.num=n;} nasal_ref(const uint8_t t,const double n):type(t){value.num=n;}
nasal_ref(const uint8_t t,nasal_val* n):type(t){value.gcobj=n;} nasal_ref(const uint8_t t,nasal_val* n):type(t){value.gcobj=n;}
nasal_ref(const nasal_ref& nr) nasal_ref(const nasal_ref& nr):type(nr.type),value(nr.value){}
{
type=nr.type;
value=nr.value;
}
nasal_ref(const nasal_ref&& nr)
{
type=nr.type;
value=nr.value;
}
nasal_ref& operator=(const nasal_ref& nr) nasal_ref& operator=(const nasal_ref& nr)
{ {
type=nr.type; type=nr.type;
value=nr.value; value=nr.value;
return *this; return *this;
} }
nasal_ref& operator=(const nasal_ref&& nr)
{
type=nr.type;
value=nr.value;
return *this;
}
bool operator==(const nasal_ref& nr){return type==nr.type && value.gcobj==nr.value.gcobj;} bool operator==(const nasal_ref& nr){return type==nr.type && value.gcobj==nr.value.gcobj;}
bool operator!=(const nasal_ref& nr){return type!=nr.type || value.gcobj!=nr.value.gcobj;} bool operator!=(const nasal_ref& nr){return type!=nr.type || value.gcobj!=nr.value.gcobj;}
// nasal is a weak-type programming language because number and string can be translated to each other // number and string can be translated to each other
double to_number(); double to_number();
std::string to_string(); std::string to_string();
// inline function to get number and pointers, make it easier to read the code
inline double& num (); inline double& num ();
inline std::string* str (); inline std::string* str ();
inline nasal_vec* vec (); inline nasal_vec* vec ();
inline nasal_hash* hash(); inline nasal_hash* hash();
inline nasal_func* func(); inline nasal_func* func();
inline void*& obj (); inline nasal_obj* obj ();
}; };
struct nasal_vec// 24 bytes struct nasal_vec
{ {
std::vector<nasal_ref> elems; std::vector<nasal_ref> elems;
@ -95,7 +79,7 @@ struct nasal_vec// 24 bytes
nasal_ref* get_mem(const int); nasal_ref* get_mem(const int);
}; };
struct nasal_hash// 56 bytes struct nasal_hash
{ {
std::unordered_map<std::string,nasal_ref> elems; std::unordered_map<std::string,nasal_ref> elems;
@ -104,22 +88,30 @@ struct nasal_hash// 56 bytes
nasal_ref* get_mem(const std::string&); nasal_ref* get_mem(const std::string&);
}; };
struct nasal_func// 112 bytes struct nasal_func
{ {
int32_t dynpara; // dynamic parameter name index in hash. int32_t dynpara; // dynamic parameter name index in hash.
uint32_t entry; // pc will set to entry-1 to call this function uint32_t entry; // pc will set to entry-1 to call this function
std::vector<nasal_ref> local; // local scope with default value(nasal_ref) std::vector<nasal_ref> local; // local scope with default value(nasal_ref)
std::vector<nasal_ref> upvalue; // closure std::vector<nasal_ref> upvalue; // closure
std::unordered_map<std::string,int> keys; // parameter name table std::unordered_map<std::string,size_t> keys; // parameter name table
nasal_func():dynpara(-1){} nasal_func():dynpara(-1){}
void clear(); void clear();
}; };
struct nasal_obj
{
uint32_t type;
void* ptr;
nasal_obj():ptr(nullptr){}
void clear();
};
constexpr uint8_t GC_UNCOLLECTED=0; constexpr uint8_t GC_UNCOLLECTED=0;
constexpr uint8_t GC_COLLECTED =1; constexpr uint8_t GC_COLLECTED =1;
constexpr uint8_t GC_FOUND =2; constexpr uint8_t GC_FOUND =2;
struct nasal_val// 16 bytes struct nasal_val
{ {
uint8_t mark; uint8_t mark;
uint8_t type; uint8_t type;
@ -129,14 +121,13 @@ struct nasal_val// 16 bytes
nasal_vec* vec; nasal_vec* vec;
nasal_hash* hash; nasal_hash* hash;
nasal_func* func; nasal_func* func;
void* obj; nasal_obj* obj;
}ptr; }ptr;
nasal_val(uint8_t); nasal_val(uint8_t);
~nasal_val(); ~nasal_val();
}; };
/*functions of nasal_vec*/
nasal_ref nasal_vec::get_val(const int index) nasal_ref nasal_vec::get_val(const int index)
{ {
int size=elems.size(); int size=elems.size();
@ -165,7 +156,7 @@ void nasal_vec::print()
std::cout<<"[]"; std::cout<<"[]";
return; return;
} }
ssize_t iter=0; size_t iter=0;
std::cout<<'['; std::cout<<'[';
for(auto& i:elems) for(auto& i:elems)
{ {
@ -183,10 +174,8 @@ void nasal_vec::print()
std::cout<<",]"[(++iter)==elems.size()]; std::cout<<",]"[(++iter)==elems.size()];
} }
--depth; --depth;
return;
} }
/*functions of nasal_hash*/
nasal_ref nasal_hash::get_val(const std::string& key) nasal_ref nasal_hash::get_val(const std::string& key)
{ {
if(elems.count(key)) if(elems.count(key))
@ -259,20 +248,23 @@ void nasal_hash::print()
std::cout<<",}"[(++iter)==elems.size()]; std::cout<<",}"[(++iter)==elems.size()];
} }
--depth; --depth;
return;
} }
/*functions of nasal_func*/
void nasal_func::clear() void nasal_func::clear()
{ {
dynpara=-1; dynpara=-1;
local.clear(); local.clear();
upvalue.clear(); upvalue.clear();
keys.clear(); keys.clear();
return;
} }
/*functions of nasal_val*/ void nasal_obj::clear()
{
if(ptr)
free(ptr);
ptr=nullptr;
}
nasal_val::nasal_val(uint8_t val_type) nasal_val::nasal_val(uint8_t val_type)
{ {
mark=GC_COLLECTED; mark=GC_COLLECTED;
@ -283,9 +275,8 @@ nasal_val::nasal_val(uint8_t val_type)
case vm_vec: ptr.vec=new nasal_vec; break; case vm_vec: ptr.vec=new nasal_vec; break;
case vm_hash: ptr.hash=new nasal_hash; break; case vm_hash: ptr.hash=new nasal_hash; break;
case vm_func: ptr.func=new nasal_func; break; case vm_func: ptr.func=new nasal_func; break;
case vm_obj: ptr.obj=nullptr; break; case vm_obj: ptr.obj=new nasal_obj; break;
} }
return;
} }
nasal_val::~nasal_val() nasal_val::~nasal_val()
{ {
@ -295,22 +286,16 @@ nasal_val::~nasal_val()
case vm_vec: delete ptr.vec; break; case vm_vec: delete ptr.vec; break;
case vm_hash: delete ptr.hash; break; case vm_hash: delete ptr.hash; break;
case vm_func: delete ptr.func; break; case vm_func: delete ptr.func; break;
case vm_obj: case vm_obj: delete ptr.obj; break;
if(ptr.obj)
free(ptr.obj);
break;
} }
ptr.obj=nullptr;
type=vm_nil; type=vm_nil;
return;
} }
/* functions of nasal_ref */
double nasal_ref::to_number() double nasal_ref::to_number()
{ {
if(type==vm_str) if(type==vm_str)
return str2num(str()->c_str()); return str2num(str()->c_str());
return num(); return value.num;
} }
std::string nasal_ref::to_string() std::string nasal_ref::to_string()
{ {
@ -325,17 +310,17 @@ inline std::string* nasal_ref::str (){return value.gcobj->ptr.str; }
inline nasal_vec* nasal_ref::vec (){return value.gcobj->ptr.vec; } inline nasal_vec* nasal_ref::vec (){return value.gcobj->ptr.vec; }
inline nasal_hash* nasal_ref::hash(){return value.gcobj->ptr.hash;} inline nasal_hash* nasal_ref::hash(){return value.gcobj->ptr.hash;}
inline nasal_func* nasal_ref::func(){return value.gcobj->ptr.func;} inline nasal_func* nasal_ref::func(){return value.gcobj->ptr.func;}
inline void*& nasal_ref::obj (){return value.gcobj->ptr.obj; } inline nasal_obj* nasal_ref::obj (){return value.gcobj->ptr.obj; }
constexpr uint32_t STACK_MAX_DEPTH=2047;
struct nasal_gc struct nasal_gc
{ {
#define STACK_MAX_DEPTH (4095) nasal_ref zero;
nasal_ref zero; // reserved address of nasal_val,type vm_num, 0 nasal_ref one;
nasal_ref one; // reserved address of nasal_val,type vm_num, 1 nasal_ref nil;
nasal_ref nil; // reserved address of nasal_val,type vm_nil
nasal_ref stack[STACK_MAX_DEPTH+1];// 1 reserved to avoid stack overflow nasal_ref stack[STACK_MAX_DEPTH+1];// 1 reserved to avoid stack overflow
nasal_ref* top; // stack top nasal_ref* top; // stack top
std::vector<nasal_ref> strs; // reserved address for const vm_str std::vector<nasal_ref> strs; // reserved address for const vm_str
std::vector<nasal_val*> memory; // gc memory std::vector<nasal_val*> memory; // gc memory
std::queue<nasal_val*> free_list[vm_type_size]; // gc free list std::queue<nasal_val*> free_list[vm_type_size]; // gc free list
std::vector<nasal_ref> local; std::vector<nasal_ref> local;
@ -393,11 +378,7 @@ void nasal_gc::sweep()
case vm_vec: i->ptr.vec->elems.clear(); break; case vm_vec: i->ptr.vec->elems.clear(); break;
case vm_hash:i->ptr.hash->elems.clear();break; case vm_hash:i->ptr.hash->elems.clear();break;
case vm_func:i->ptr.func->clear(); break; case vm_func:i->ptr.func->clear(); break;
case vm_obj: case vm_obj: i->ptr.obj->clear(); break;
if(i->ptr.obj)
free(i->ptr.obj);
i->ptr.obj=nullptr;
break;
} }
free_list[i->type].push(i); free_list[i->type].push(i);
i->mark=GC_COLLECTED; i->mark=GC_COLLECTED;

View File

@ -144,7 +144,7 @@ void nasal_lexer::die(const char* info)
{ {
++error; ++error;
std::cout<<"[lexer] line "<<line<<" column "<<code.length()<<": \n"<<code<<'\n'; std::cout<<"[lexer] line "<<line<<" column "<<code.length()<<": \n"<<code<<'\n';
for(uint32_t i=0;i<code.size()-1;++i) for(int i=0;i<(int)code.size()-1;++i)
std::cout<<char(" \t"[code[i]=='\t']); std::cout<<char(" \t"[code[i]=='\t']);
std::cout<<'^'<<info<<'\n'; std::cout<<'^'<<info<<'\n';
} }
@ -259,7 +259,10 @@ std::string nasal_lexer::str_gen()
} }
// check if this string ends with a " or ' // check if this string ends with a " or '
if(ptr++>=size) if(ptr++>=size)
{
die("get EOF when generating string."); die("get EOF when generating string.");
return str;
}
code+=res[ptr-1]; code+=res[ptr-1];
if(begin=='`' && str.length()!=1) if(begin=='`' && str.length()!=1)
die("\'`\' is used for string that includes one character."); die("\'`\' is used for string that includes one character.");

View File

@ -225,7 +225,7 @@ bool nasal_parse::check_special_call()
{ {
// special call means like this: // special call means like this:
// function_name(a:1,b:2,c:3); // function_name(a:1,b:2,c:3);
uint32_t check_ptr=ptr,curve=1,bracket=0,brace=0,ques=0; uint32_t check_ptr=ptr,curve=1,bracket=0,brace=0;
while(tokens[++check_ptr].type!=tok_eof && curve) while(tokens[++check_ptr].type!=tok_eof && curve)
{ {
switch(tokens[check_ptr].type) switch(tokens[check_ptr].type)

View File

@ -4,22 +4,21 @@
class nasal_vm class nasal_vm
{ {
private: private:
/* reference from nasal_gc */
nasal_ref*& top; // stack top
/* values of nasal_vm */ /* values of nasal_vm */
uint32_t pc; // program counter uint32_t pc; // program counter
uint32_t offset; // used to load default parameter to a new function uint32_t offset; // used to load default parameters to a new function
std::stack<uint32_t> ret; // ptr stack stores address for function to return std::stack<uint32_t> ret; // stack to store return pc
std::stack<nasal_func*> func_stk; // stack to store function,this is used when getting upvalues std::stack<nasal_func*> func_stk; // stack to store function, used to get upvalues
std::stack<int> counter; // iterator stack for forindex/foreach std::stack<int> counter; // iterator stack for forindex/foreach
const double* num_table;// numbers used in process(const calculation) const double* num_table;// const numbers
std::vector<std::string> str_table;// symbols used in process std::vector<std::string> str_table;// const symbols
std::vector<uint32_t> imm; // immediate number std::vector<uint32_t> imm; // immediate number
nasal_ref* mem_addr; // used for mem_call nasal_ref* mem_addr; // used for mem_call
nasal_gc gc; // garbage collector /* garbage collector */
nasal_gc gc;
/* values used for debug */ /* values used for debug */
std::vector<opcode> bytecode; // bytecode std::vector<opcode> bytecode;
std::vector<std::string> files; // files std::vector<std::string> files;
void init( void init(
const std::vector<std::string>&, const std::vector<std::string>&,
@ -116,7 +115,6 @@ private:
void opr_mcallh(); void opr_mcallh();
void opr_ret(); void opr_ret();
public: public:
nasal_vm():top(gc.top){}
~nasal_vm(){clear();} ~nasal_vm(){clear();}
void run( void run(
const nasal_codegen&, const nasal_codegen&,
@ -131,9 +129,9 @@ void nasal_vm::init(
const std::vector<std::string>& filenames) const std::vector<std::string>& filenames)
{ {
gc.init(strs); gc.init(strs);
num_table=nums.data(); // get constant numbers num_table=nums.data();
str_table=strs; // get constant strings & symbols str_table=strs;
files=filenames;// get filenames for debugger files=filenames;
} }
void nasal_vm::clear() void nasal_vm::clear()
{ {
@ -176,8 +174,7 @@ void nasal_vm::traceback()
uint32_t same=0,last=0xffffffff; uint32_t same=0,last=0xffffffff;
for(uint32_t point=0;!ret.empty();last=point,ret.pop()) for(uint32_t point=0;!ret.empty();last=point,ret.pop())
{ {
point=ret.top(); if((point=ret.top())==last)
if(point==last)
{ {
++same; ++same;
continue; continue;
@ -197,9 +194,9 @@ void nasal_vm::stackinfo(const uint32_t limit=10)
printf("vm stack(limit %d):\n",limit); printf("vm stack(limit %d):\n",limit);
uint32_t same=0,global_size=bytecode[0].num; uint32_t same=0,global_size=bytecode[0].num;
nasal_ref last={vm_none,0xffffffff}; nasal_ref last={vm_none,0xffffffff};
for(uint32_t i=0;i<limit && top>=gc.stack+global_size;++i,--top) for(uint32_t i=0;i<limit && gc.top>=gc.stack+global_size;++i,--gc.top)
{ {
if(top[0]==last) if(gc.top[0]==last)
{ {
++same; ++same;
continue; continue;
@ -209,8 +206,8 @@ void nasal_vm::stackinfo(const uint32_t limit=10)
printf("\t... | %d same value(s)\n",same); printf("\t... | %d same value(s)\n",same);
same=0; same=0;
} }
last=top[0]; last=gc.top[0];
valinfo(top[0]); valinfo(gc.top[0]);
} }
if(same) if(same)
printf("\t... | %d same value(s)\n",same); printf("\t... | %d same value(s)\n",same);
@ -298,109 +295,109 @@ inline void nasal_vm::opr_intg()
{ {
// global values store on stack // global values store on stack
for(uint32_t i=0;i<imm[pc];++i) for(uint32_t i=0;i<imm[pc];++i)
(top++)[0].type=vm_nil; (gc.top++)[0].type=vm_nil;
--top;// point to the top --gc.top;// point to the top
} }
inline void nasal_vm::opr_intl() inline void nasal_vm::opr_intl()
{ {
top[0].func()->local.resize(imm[pc],gc.nil); gc.top[0].func()->local.resize(imm[pc],gc.nil);
} }
inline void nasal_vm::opr_loadg() inline void nasal_vm::opr_loadg()
{ {
gc.stack[imm[pc]]=(top--)[0]; gc.stack[imm[pc]]=(gc.top--)[0];
} }
inline void nasal_vm::opr_loadl() inline void nasal_vm::opr_loadl()
{ {
gc.local.back().vec()->elems[imm[pc]]=(top--)[0]; gc.local.back().vec()->elems[imm[pc]]=(gc.top--)[0];
} }
inline void nasal_vm::opr_loadu() inline void nasal_vm::opr_loadu()
{ {
func_stk.top()->upvalue[(imm[pc]>>16)&0xffff].vec()->elems[imm[pc]&0xffff]=(top--)[0]; func_stk.top()->upvalue[(imm[pc]>>16)&0xffff].vec()->elems[imm[pc]&0xffff]=(gc.top--)[0];
} }
inline void nasal_vm::opr_pnum() inline void nasal_vm::opr_pnum()
{ {
(++top)[0]={vm_num,num_table[imm[pc]]}; (++gc.top)[0]={vm_num,num_table[imm[pc]]};
} }
inline void nasal_vm::opr_pone() inline void nasal_vm::opr_pone()
{ {
(++top)[0]={vm_num,(double)1}; (++gc.top)[0]={vm_num,(double)1};
} }
inline void nasal_vm::opr_pzero() inline void nasal_vm::opr_pzero()
{ {
(++top)[0]={vm_num,(double)0}; (++gc.top)[0]={vm_num,(double)0};
} }
inline void nasal_vm::opr_pnil() inline void nasal_vm::opr_pnil()
{ {
(++top)[0].type=vm_nil; (++gc.top)[0].type=vm_nil;
} }
inline void nasal_vm::opr_pstr() inline void nasal_vm::opr_pstr()
{ {
(++top)[0]=gc.strs[imm[pc]]; (++gc.top)[0]=gc.strs[imm[pc]];
} }
inline void nasal_vm::opr_newv() inline void nasal_vm::opr_newv()
{ {
nasal_ref newv=gc.alloc(vm_vec); nasal_ref newv=gc.alloc(vm_vec);
auto& vec=newv.vec()->elems;// top-imm[pc] stores the vector auto& vec=newv.vec()->elems;
vec.resize(imm[pc]); vec.resize(imm[pc]);
// use top-=imm[pc]-1 here will cause error if imm[pc] is 0 // use top-=imm[pc]-1 here will cause error if imm[pc] is 0
top=top-imm[pc]+1; gc.top=gc.top-imm[pc]+1;
for(uint32_t i=0;i<imm[pc];++i) for(uint32_t i=0;i<imm[pc];++i)
vec[i]=top[i]; vec[i]=gc.top[i];
top[0]=newv; gc.top[0]=newv;
} }
inline void nasal_vm::opr_newh() inline void nasal_vm::opr_newh()
{ {
(++top)[0]=gc.alloc(vm_hash); (++gc.top)[0]=gc.alloc(vm_hash);
} }
inline void nasal_vm::opr_newf() inline void nasal_vm::opr_newf()
{ {
offset=1; offset=1;
(++top)[0]=gc.alloc(vm_func); (++gc.top)[0]=gc.alloc(vm_func);
top[0].func()->entry=imm[pc]; gc.top[0].func()->entry=imm[pc];
if(!gc.local.empty()) if(!gc.local.empty())
{ {
top[0].func()->upvalue=func_stk.top()->upvalue; gc.top[0].func()->upvalue=func_stk.top()->upvalue;
top[0].func()->upvalue.push_back(gc.local.back()); gc.top[0].func()->upvalue.push_back(gc.local.back());
} }
} }
inline void nasal_vm::opr_happ() inline void nasal_vm::opr_happ()
{ {
top[-1].hash()->elems[str_table[imm[pc]]]=top[0]; gc.top[-1].hash()->elems[str_table[imm[pc]]]=gc.top[0];
--top; --gc.top;
} }
inline void nasal_vm::opr_para() inline void nasal_vm::opr_para()
{ {
nasal_func* func=top[0].func(); nasal_func* func=gc.top[0].func();
size_t size=func->keys.size(); size_t size=func->keys.size();
func->keys[str_table[imm[pc]]]=size; func->keys[str_table[imm[pc]]]=size;
func->local[offset++]={vm_none}; func->local[offset++]={vm_none};
} }
inline void nasal_vm::opr_defpara() inline void nasal_vm::opr_defpara()
{ {
nasal_ref val=top[0]; nasal_ref val=gc.top[0];
nasal_func* func=(--top)[0].func(); nasal_func* func=(--gc.top)[0].func();
size_t size=func->keys.size(); size_t size=func->keys.size();
func->keys[str_table[imm[pc]]]=size; func->keys[str_table[imm[pc]]]=size;
func->local[offset++]=val; func->local[offset++]=val;
} }
inline void nasal_vm::opr_dynpara() inline void nasal_vm::opr_dynpara()
{ {
top[0].func()->dynpara=imm[pc]; gc.top[0].func()->dynpara=imm[pc];
} }
inline void nasal_vm::opr_unot() inline void nasal_vm::opr_unot()
{ {
nasal_ref val=top[0]; nasal_ref val=gc.top[0];
switch(val.type) switch(val.type)
{ {
case vm_nil:top[0]=gc.zero;break; case vm_nil:gc.top[0]=gc.zero;break;
case vm_num:top[0]=val.num()?gc.zero:gc.one;break; case vm_num:gc.top[0]=val.num()?gc.zero:gc.one;break;
case vm_str: case vm_str:
{ {
double num=str2num(val.str()->c_str()); double num=str2num(val.str()->c_str());
if(std::isnan(num)) if(std::isnan(num))
top[0]=val.str()->empty()?gc.one:gc.zero; gc.top[0]=val.str()->empty()?gc.one:gc.zero;
else else
top[0]=num?gc.zero:gc.one; gc.top[0]=num?gc.zero:gc.one;
} }
break; break;
default:die("unot: incorrect value type");break; default:die("unot: incorrect value type");break;
@ -408,12 +405,12 @@ inline void nasal_vm::opr_unot()
} }
inline void nasal_vm::opr_usub() inline void nasal_vm::opr_usub()
{ {
top[0]={vm_num,-top[0].to_number()}; gc.top[0]={vm_num,-gc.top[0].to_number()};
} }
#define op_calc(type)\ #define op_calc(type)\
nasal_ref val(vm_num,top[-1].to_number() type top[0].to_number());\ nasal_ref val(vm_num,gc.top[-1].to_number() type gc.top[0].to_number());\
(--top)[0]=val; (--gc.top)[0]=val;
inline void nasal_vm::opr_add(){op_calc(+);} inline void nasal_vm::opr_add(){op_calc(+);}
inline void nasal_vm::opr_sub(){op_calc(-);} inline void nasal_vm::opr_sub(){op_calc(-);}
@ -422,13 +419,13 @@ inline void nasal_vm::opr_div(){op_calc(/);}
inline void nasal_vm::opr_lnk() inline void nasal_vm::opr_lnk()
{ {
nasal_ref val=gc.alloc(vm_str); nasal_ref val=gc.alloc(vm_str);
*val.str()=top[-1].to_string()+top[0].to_string(); *val.str()=gc.top[-1].to_string()+gc.top[0].to_string();
(--top)[0]=val; (--gc.top)[0]=val;
} }
#define op_calc_const(type)\ #define op_calc_const(type)\
nasal_ref val(vm_num,top[0].to_number() type num_table[imm[pc]]);\ nasal_ref val(vm_num,gc.top[0].to_number() type num_table[imm[pc]]);\
top[0]=val; gc.top[0]=val;
inline void nasal_vm::opr_addc(){op_calc_const(+);} inline void nasal_vm::opr_addc(){op_calc_const(+);}
inline void nasal_vm::opr_subc(){op_calc_const(-);} inline void nasal_vm::opr_subc(){op_calc_const(-);}
@ -437,13 +434,13 @@ inline void nasal_vm::opr_divc(){op_calc_const(/);}
inline void nasal_vm::opr_lnkc() inline void nasal_vm::opr_lnkc()
{ {
nasal_ref val=gc.alloc(vm_str); nasal_ref val=gc.alloc(vm_str);
*val.str()=top[0].to_string()+str_table[imm[pc]]; *val.str()=gc.top[0].to_string()+str_table[imm[pc]];
top[0]=val; gc.top[0]=val;
} }
#define op_calc_eq(type)\ #define op_calc_eq(type)\
nasal_ref val(vm_num,mem_addr[0].to_number() type top[-1].to_number());\ nasal_ref val(vm_num,mem_addr[0].to_number() type gc.top[-1].to_number());\
(--top)[0]=mem_addr[0]=val; (--gc.top)[0]=mem_addr[0]=val;
inline void nasal_vm::opr_addeq(){op_calc_eq(+);} inline void nasal_vm::opr_addeq(){op_calc_eq(+);}
inline void nasal_vm::opr_subeq(){op_calc_eq(-);} inline void nasal_vm::opr_subeq(){op_calc_eq(-);}
@ -452,13 +449,13 @@ inline void nasal_vm::opr_diveq(){op_calc_eq(/);}
inline void nasal_vm::opr_lnkeq() inline void nasal_vm::opr_lnkeq()
{ {
nasal_ref val=gc.alloc(vm_str); nasal_ref val=gc.alloc(vm_str);
*val.str()=mem_addr[0].to_string()+top[-1].to_string(); *val.str()=mem_addr[0].to_string()+gc.top[-1].to_string();
(--top)[0]=mem_addr[0]=val; (--gc.top)[0]=mem_addr[0]=val;
} }
#define op_calc_eq_const(type)\ #define op_calc_eq_const(type)\
nasal_ref val(vm_num,mem_addr[0].to_number() type num_table[imm[pc]]);\ nasal_ref val(vm_num,mem_addr[0].to_number() type num_table[imm[pc]]);\
top[0]=mem_addr[0]=val; gc.top[0]=mem_addr[0]=val;
inline void nasal_vm::opr_addeqc(){op_calc_eq_const(+);} inline void nasal_vm::opr_addeqc(){op_calc_eq_const(+);}
inline void nasal_vm::opr_subeqc(){op_calc_eq_const(-);} inline void nasal_vm::opr_subeqc(){op_calc_eq_const(-);}
@ -468,47 +465,47 @@ inline void nasal_vm::opr_lnkeqc()
{ {
nasal_ref val=gc.alloc(vm_str); nasal_ref val=gc.alloc(vm_str);
*val.str()=mem_addr[0].to_string()+str_table[imm[pc]]; *val.str()=mem_addr[0].to_string()+str_table[imm[pc]];
top[0]=mem_addr[0]=val; gc.top[0]=mem_addr[0]=val;
} }
inline void nasal_vm::opr_meq() inline void nasal_vm::opr_meq()
{ {
mem_addr[0]=(--top)[0]; mem_addr[0]=(--gc.top)[0];
} }
inline void nasal_vm::opr_eq() inline void nasal_vm::opr_eq()
{ {
nasal_ref val2=top[0]; nasal_ref val2=gc.top[0];
nasal_ref val1=(--top)[0]; nasal_ref val1=(--gc.top)[0];
uint8_t a_type=val1.type; uint8_t a_type=val1.type;
uint8_t b_type=val2.type; uint8_t b_type=val2.type;
if(a_type==vm_nil && b_type==vm_nil) if(a_type==vm_nil && b_type==vm_nil)
top[0]=gc.one; gc.top[0]=gc.one;
else if(a_type==vm_str && b_type==vm_str) else if(a_type==vm_str && b_type==vm_str)
top[0]=(*val1.str()==*val2.str())?gc.one:gc.zero; gc.top[0]=(*val1.str()==*val2.str())?gc.one:gc.zero;
else if(a_type==vm_num || b_type==vm_num) else if(a_type==vm_num || b_type==vm_num)
top[0]=(val1.to_number()==val2.to_number())?gc.one:gc.zero; gc.top[0]=(val1.to_number()==val2.to_number())?gc.one:gc.zero;
else else
top[0]=(val1==val2)?gc.one:gc.zero; gc.top[0]=(val1==val2)?gc.one:gc.zero;
} }
inline void nasal_vm::opr_neq() inline void nasal_vm::opr_neq()
{ {
nasal_ref val2=top[0]; nasal_ref val2=gc.top[0];
nasal_ref val1=(--top)[0]; nasal_ref val1=(--gc.top)[0];
uint8_t a_type=val1.type; uint8_t a_type=val1.type;
uint8_t b_type=val2.type; uint8_t b_type=val2.type;
if(a_type==vm_nil && b_type==vm_nil) if(a_type==vm_nil && b_type==vm_nil)
top[0]=gc.zero; gc.top[0]=gc.zero;
else if(a_type==vm_str && b_type==vm_str) else if(a_type==vm_str && b_type==vm_str)
top[0]=(*val1.str()!=*val2.str())?gc.one:gc.zero; gc.top[0]=(*val1.str()!=*val2.str())?gc.one:gc.zero;
else if(a_type==vm_num || b_type==vm_num) else if(a_type==vm_num || b_type==vm_num)
top[0]=(val1.to_number()!=val2.to_number())?gc.one:gc.zero; gc.top[0]=(val1.to_number()!=val2.to_number())?gc.one:gc.zero;
else else
top[0]=(val1!=val2)?gc.one:gc.zero; gc.top[0]=(val1!=val2)?gc.one:gc.zero;
} }
#define op_cmp(type)\ #define op_cmp(type)\
--top;\ --gc.top;\
top[0]=(top[0].to_number() type top[1].to_number())?gc.one:gc.zero; gc.top[0]=(gc.top[0].to_number() type gc.top[1].to_number())?gc.one:gc.zero;
inline void nasal_vm::opr_less(){op_cmp(<);} inline void nasal_vm::opr_less(){op_cmp(<);}
inline void nasal_vm::opr_leq(){op_cmp(<=);} inline void nasal_vm::opr_leq(){op_cmp(<=);}
@ -516,7 +513,7 @@ inline void nasal_vm::opr_grt(){op_cmp(>);}
inline void nasal_vm::opr_geq(){op_cmp(>=);} inline void nasal_vm::opr_geq(){op_cmp(>=);}
#define op_cmp_const(type)\ #define op_cmp_const(type)\
top[0]=(top[0].to_number() type num_table[imm[pc]])?gc.one:gc.zero; gc.top[0]=(gc.top[0].to_number() type num_table[imm[pc]])?gc.one:gc.zero;
inline void nasal_vm::opr_lessc(){op_cmp_const(<);} inline void nasal_vm::opr_lessc(){op_cmp_const(<);}
inline void nasal_vm::opr_leqc(){op_cmp_const(<=);} inline void nasal_vm::opr_leqc(){op_cmp_const(<=);}
@ -525,7 +522,7 @@ inline void nasal_vm::opr_geqc(){op_cmp_const(>=);}
inline void nasal_vm::opr_pop() inline void nasal_vm::opr_pop()
{ {
--top; --gc.top;
} }
inline void nasal_vm::opr_jmp() inline void nasal_vm::opr_jmp()
{ {
@ -533,19 +530,19 @@ inline void nasal_vm::opr_jmp()
} }
inline void nasal_vm::opr_jt() inline void nasal_vm::opr_jt()
{ {
if(condition(top[0])) if(condition(gc.top[0]))
pc=imm[pc]-1; pc=imm[pc]-1;
} }
inline void nasal_vm::opr_jf() inline void nasal_vm::opr_jf()
{ {
if(!condition(top[0])) if(!condition(gc.top[0]))
pc=imm[pc]-1; pc=imm[pc]-1;
--top; --gc.top;
} }
inline void nasal_vm::opr_counter() inline void nasal_vm::opr_counter()
{ {
counter.push(-1); counter.push(-1);
if(top[0].type!=vm_vec) if(gc.top[0].type!=vm_vec)
die("cnt: must use vector in forindex/foreach"); die("cnt: must use vector in forindex/foreach");
} }
inline void nasal_vm::opr_cntpop() inline void nasal_vm::opr_cntpop()
@ -554,54 +551,54 @@ inline void nasal_vm::opr_cntpop()
} }
inline void nasal_vm::opr_findex() inline void nasal_vm::opr_findex()
{ {
if(++counter.top()>=top[0].vec()->elems.size()) if(++counter.top()>=gc.top[0].vec()->elems.size())
{ {
pc=imm[pc]-1; pc=imm[pc]-1;
return; return;
} }
(++top)[0]={vm_num,(double)counter.top()}; (++gc.top)[0]={vm_num,(double)counter.top()};
} }
inline void nasal_vm::opr_feach() inline void nasal_vm::opr_feach()
{ {
std::vector<nasal_ref>& ref=top[0].vec()->elems; std::vector<nasal_ref>& ref=gc.top[0].vec()->elems;
if(++counter.top()>=ref.size()) if(++counter.top()>=ref.size())
{ {
pc=imm[pc]-1; pc=imm[pc]-1;
return; return;
} }
(++top)[0]=ref[counter.top()]; (++gc.top)[0]=ref[counter.top()];
} }
inline void nasal_vm::opr_callg() inline void nasal_vm::opr_callg()
{ {
(++top)[0]=gc.stack[imm[pc]]; (++gc.top)[0]=gc.stack[imm[pc]];
} }
inline void nasal_vm::opr_calll() inline void nasal_vm::opr_calll()
{ {
(++top)[0]=gc.local.back().vec()->elems[imm[pc]]; (++gc.top)[0]=gc.local.back().vec()->elems[imm[pc]];
} }
inline void nasal_vm::opr_upval() inline void nasal_vm::opr_upval()
{ {
(++top)[0]=func_stk.top()->upvalue[(imm[pc]>>16)&0xffff].vec()->elems[imm[pc]&0xffff]; (++gc.top)[0]=func_stk.top()->upvalue[(imm[pc]>>16)&0xffff].vec()->elems[imm[pc]&0xffff];
} }
inline void nasal_vm::opr_callv() inline void nasal_vm::opr_callv()
{ {
nasal_ref val=top[0]; nasal_ref val=gc.top[0];
nasal_ref vec=(--top)[0]; nasal_ref vec=(--gc.top)[0];
if(vec.type==vm_vec) if(vec.type==vm_vec)
{ {
top[0]=vec.vec()->get_val(val.to_number()); gc.top[0]=vec.vec()->get_val(val.to_number());
if(top[0].type==vm_none) if(gc.top[0].type==vm_none)
die("callv: index out of range:"+std::to_string(val.to_number())); die("callv: index out of range:"+std::to_string(val.to_number()));
} }
else if(vec.type==vm_hash) else if(vec.type==vm_hash)
{ {
if(val.type!=vm_str) if(val.type!=vm_str)
die("callv: must use string as the key"); die("callv: must use string as the key");
top[0]=vec.hash()->get_val(*val.value.gcobj->ptr.str); gc.top[0]=vec.hash()->get_val(*val.str());
if(top[0].type==vm_none) if(gc.top[0].type==vm_none)
die("callv: cannot find member \""+*val.str()+"\" of this hash"); die("callv: cannot find member \""+*val.str()+"\" of this hash");
if(top[0].type==vm_func) if(gc.top[0].type==vm_func)
top[0].func()->local[0]=val;// me gc.top[0].func()->local[0]=val;// 'me'
} }
else if(vec.type==vm_str) else if(vec.type==vm_str)
{ {
@ -610,49 +607,47 @@ inline void nasal_vm::opr_callv()
int str_size=str.length(); int str_size=str.length();
if(num<-str_size || num>=str_size) if(num<-str_size || num>=str_size)
die("callv: index out of range:"+std::to_string(val.to_number())); die("callv: index out of range:"+std::to_string(val.to_number()));
top[0]={vm_num,static_cast<double>(str[num>=0? num:num+str_size])}; gc.top[0]={vm_num,static_cast<double>(str[num>=0? num:num+str_size])};
} }
else else
die("callv: must call a vector/hash/string"); die("callv: must call a vector/hash/string");
} }
inline void nasal_vm::opr_callvi() inline void nasal_vm::opr_callvi()
{ {
nasal_ref val=top[0]; nasal_ref val=gc.top[0];
if(val.type!=vm_vec) if(val.type!=vm_vec)
die("callvi: must use a vector"); die("callvi: must use a vector");
// cannot use operator[],because this may cause overflow // cannot use operator[],because this may cause overflow
(++top)[0]=val.vec()->get_val(imm[pc]); (++gc.top)[0]=val.vec()->get_val(imm[pc]);
if(top[0].type==vm_none) if(gc.top[0].type==vm_none)
die("callvi: index out of range:"+std::to_string(imm[pc])); die("callvi: index out of range:"+std::to_string(imm[pc]));
} }
inline void nasal_vm::opr_callh() inline void nasal_vm::opr_callh()
{ {
nasal_ref val=top[0]; nasal_ref val=gc.top[0];
if(val.type!=vm_hash) if(val.type!=vm_hash)
die("callh: must call a hash"); die("callh: must call a hash");
top[0]=val.hash()->get_val(str_table[imm[pc]]); gc.top[0]=val.hash()->get_val(str_table[imm[pc]]);
if(top[0].type==vm_none) if(gc.top[0].type==vm_none)
die("callh: member \""+str_table[imm[pc]]+"\" does not exist"); die("callh: member \""+str_table[imm[pc]]+"\" does not exist");
if(top[0].type==vm_func) if(gc.top[0].type==vm_func)
top[0].func()->local[0]=val;// me gc.top[0].func()->local[0]=val;// 'me'
} }
inline void nasal_vm::opr_callfv() inline void nasal_vm::opr_callfv()
{ {
uint32_t args_size=imm[pc]; uint32_t args_size=imm[pc];
nasal_ref* args=top-args_size+1; nasal_ref* args=gc.top-args_size+1;
if(args[-1].type!=vm_func) if(args[-1].type!=vm_func)
die("callfv: must call a function"); die("callfv: must call a function");
// push new local scope // push function and new local scope
func_stk.push(args[-1].func()); func_stk.push(args[-1].func());
auto& func=*args[-1].func(); auto& func=*args[-1].func();
gc.local.push_back(gc.alloc(vm_vec)); gc.local.push_back(gc.alloc(vm_vec));
gc.local.back().vec()->elems=func.local; gc.local.back().vec()->elems=func.local;
// load parameters auto& local=gc.local.back().vec()->elems;
auto& closure=gc.local.back().vec()->elems;
uint32_t para_size=func.keys.size(); uint32_t para_size=func.keys.size();
// load arguments // load arguments
@ -662,83 +657,81 @@ inline void nasal_vm::opr_callfv()
// if args_size>para_size,for 0 to args_size will cause corruption // if args_size>para_size,for 0 to args_size will cause corruption
uint32_t min_size=std::min(para_size,args_size); uint32_t min_size=std::min(para_size,args_size);
for(uint32_t i=0;i<min_size;++i) for(uint32_t i=0;i<min_size;++i)
closure[i+1]=args[i]; local[i+1]=args[i];
// load dynamic argument if args_size>=para_size // load dynamic argument if args_size>=para_size
if(func.dynpara>=0) if(func.dynpara>=0)
{ {
nasal_ref vec=gc.alloc(vm_vec); nasal_ref vec=gc.alloc(vm_vec);
for(uint32_t i=para_size;i<args_size;++i) for(uint32_t i=para_size;i<args_size;++i)
vec.vec()->elems.push_back(args[i]); vec.vec()->elems.push_back(args[i]);
closure.back()=vec; local.back()=vec;
} }
top-=args_size;// pop arguments gc.top-=args_size;// pop arguments
ret.push(pc); ret.push(pc);
pc=func.entry-1; pc=func.entry-1;
} }
inline void nasal_vm::opr_callfh() inline void nasal_vm::opr_callfh()
{ {
// get parameter list and function value auto& hash=gc.top[0].hash()->elems;
auto& hash=top[0].hash()->elems; if(gc.top[-1].type!=vm_func)
if(top[-1].type!=vm_func)
die("callfh: must call a function"); die("callfh: must call a function");
// push new local scope // push function and new local scope
func_stk.push(top[-1].func()); func_stk.push(gc.top[-1].func());
auto& func=*top[-1].func(); auto& func=*gc.top[-1].func();
gc.local.push_back(gc.alloc(vm_vec)); gc.local.push_back(gc.alloc(vm_vec));
gc.local.back().vec()->elems=func.local; gc.local.back().vec()->elems=func.local;
// load parameters auto& local=gc.local.back().vec()->elems;
auto& closure=gc.local.back().vec()->elems;
if(func.dynpara>=0) if(func.dynpara>=0)
die("callfh: special call cannot use dynamic argument"); die("callfh: special call cannot use dynamic argument");
for(auto& i:func.keys) for(auto& i:func.keys)
{ {
if(hash.count(i.first)) if(hash.count(i.first))
closure[i.second+1]=hash[i.first]; local[i.second+1]=hash[i.first];
else if(func.local[i.second+1/*1 is reserved for 'me'*/].type==vm_none) else if(func.local[i.second+1/*1 is reserved for 'me'*/].type==vm_none)
die("callfh: lack argument(s): \""+i.first+"\""); die("callfh: lack argument(s): \""+i.first+"\"");
} }
--top;// pop hash --gc.top;// pop hash
ret.push(pc); ret.push(pc);
pc=func.entry-1; pc=func.entry-1;
} }
inline void nasal_vm::opr_callb() inline void nasal_vm::opr_callb()
{ {
(++top)[0]=(*builtin[imm[pc]].func)(gc.local.back().vec()->elems,gc); (++gc.top)[0]=(*builtin[imm[pc]].func)(gc.local.back().vec()->elems,gc);
if(top[0].type==vm_none) if(gc.top[0].type==vm_none)
die("native function error."); die("native function error.");
} }
inline void nasal_vm::opr_slcbegin() inline void nasal_vm::opr_slcbegin()
{ {
// | slice_vector | <-- top[0] // | slice_vector | <-- gc.top[0]
// ---------------- // +--------------+
// | resource_vec | <-- top[-1] // | resource_vec | <-- gc.top[-1]
// ---------------- // +--------------+
(++top)[0]=gc.alloc(vm_vec); (++gc.top)[0]=gc.alloc(vm_vec);
if(top[-1].type!=vm_vec) if(gc.top[-1].type!=vm_vec)
die("slcbegin: must slice a vector"); die("slcbegin: must slice a vector");
} }
inline void nasal_vm::opr_slcend() inline void nasal_vm::opr_slcend()
{ {
top[-1]=top[0]; gc.top[-1]=gc.top[0];
--top; --gc.top;
} }
inline void nasal_vm::opr_slc() inline void nasal_vm::opr_slc()
{ {
nasal_ref val=(top--)[0]; nasal_ref val=(gc.top--)[0];
nasal_ref res=top[-1].vec()->get_val(val.to_number()); nasal_ref res=gc.top[-1].vec()->get_val(val.to_number());
if(res.type==vm_none) if(res.type==vm_none)
die("slc: index out of range:"+std::to_string(val.to_number())); die("slc: index out of range:"+std::to_string(val.to_number()));
top[0].vec()->elems.push_back(res); gc.top[0].vec()->elems.push_back(res);
} }
inline void nasal_vm::opr_slc2() inline void nasal_vm::opr_slc2()
{ {
nasal_ref val2=(top--)[0]; nasal_ref val2=(gc.top--)[0];
nasal_ref val1=(top--)[0]; nasal_ref val1=(gc.top--)[0];
std::vector<nasal_ref>& ref=top[-1].vec()->elems; std::vector<nasal_ref>& ref=gc.top[-1].vec()->elems;
std::vector<nasal_ref>& aim=top[0].vec()->elems; std::vector<nasal_ref>& aim=gc.top[0].vec()->elems;
uint8_t type1=val1.type,type2=val2.type; uint8_t type1=val1.type,type2=val2.type;
int num1=val1.to_number(); int num1=val1.to_number();
@ -767,22 +760,22 @@ inline void nasal_vm::opr_slc2()
inline void nasal_vm::opr_mcallg() inline void nasal_vm::opr_mcallg()
{ {
mem_addr=gc.stack+imm[pc]; mem_addr=gc.stack+imm[pc];
(++top)[0]=mem_addr[0]; (++gc.top)[0]=mem_addr[0];
} }
inline void nasal_vm::opr_mcalll() inline void nasal_vm::opr_mcalll()
{ {
mem_addr=&(gc.local.back().vec()->elems[imm[pc]]); mem_addr=&(gc.local.back().vec()->elems[imm[pc]]);
(++top)[0]=mem_addr[0]; (++gc.top)[0]=mem_addr[0];
} }
inline void nasal_vm::opr_mupval() inline void nasal_vm::opr_mupval()
{ {
mem_addr=&func_stk.top()->upvalue[(imm[pc]>>16)&0xffff].vec()->elems[imm[pc]&0xffff]; mem_addr=&func_stk.top()->upvalue[(imm[pc]>>16)&0xffff].vec()->elems[imm[pc]&0xffff];
(++top)[0]=mem_addr[0]; (++gc.top)[0]=mem_addr[0];
} }
inline void nasal_vm::opr_mcallv() inline void nasal_vm::opr_mcallv()
{ {
nasal_ref val=top[0]; nasal_ref val=gc.top[0];
nasal_ref vec=(--top)[0]; nasal_ref vec=(--gc.top)[0];
if(vec.type==vm_vec) if(vec.type==vm_vec)
{ {
mem_addr=vec.vec()->get_mem(val.to_number()); mem_addr=vec.vec()->get_mem(val.to_number());
@ -807,7 +800,7 @@ inline void nasal_vm::opr_mcallv()
} }
inline void nasal_vm::opr_mcallh() inline void nasal_vm::opr_mcallh()
{ {
nasal_ref hash=top[0]; nasal_ref hash=gc.top[0];
if(hash.type!=vm_hash) if(hash.type!=vm_hash)
die("mcallh: must call a hash"); die("mcallh: must call a hash");
nasal_hash& ref=*hash.hash(); nasal_hash& ref=*hash.hash();
@ -823,13 +816,13 @@ inline void nasal_vm::opr_ret()
{ {
// get nasal_func and set 'me' to nil // get nasal_func and set 'me' to nil
// and rewrite nasal_func with returned value // and rewrite nasal_func with returned value
top[-1].func()->local[0]={vm_nil}; gc.top[-1].func()->local[0]={vm_nil};
--top; --gc.top;
top[0]=top[1]; gc.top[0]=gc.top[1];
func_stk.pop(); // pop function stack func_stk.pop();
gc.local.pop_back(); // pop local scope gc.local.pop_back();
pc=ret.top();ret.pop(); // fetch pc pc=ret.top();ret.pop();
} }
void nasal_vm::run( void nasal_vm::run(
const nasal_codegen& gen, const nasal_codegen& gen,