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
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
./nasal test/ascii-art.nas
./nasal -c test/bf.nas

View File

@ -1,6 +1,5 @@
#ifndef __NASAL_H__
#define __NASAL_H__
#pragma GCC optimize(2)
#include <stdint.h>
#include <unistd.h>
@ -20,10 +19,6 @@
#include <vector>
#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)
{
double ret=0;
@ -104,9 +99,6 @@ double str2num(const char* str)
return is_negative?-ret_num:ret_num;
}
/*
show raw string
*/
std::string raw_string(const std::string& str)
{
std::string ret("");

View File

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

View File

@ -32,13 +32,13 @@ const uint32_t increment[vm_type_size]=
128 // vm_obj
};
// declaration of nasal value type
struct nasal_vec;
struct nasal_hash;
struct nasal_func;
struct nasal_obj;
struct nasal_val;
// declaration of nasal_ref
struct nasal_ref// 16 bytes
struct nasal_ref
{
uint8_t type;
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,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 nasal_ref& nr)
{
type=nr.type;
value=nr.value;
}
nasal_ref(const nasal_ref&& nr)
{
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)
{
type=nr.type;
value=nr.value;
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;}
// 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();
std::string to_string();
// inline function to get number and pointers, make it easier to read the code
inline double& num ();
inline std::string* str ();
inline nasal_vec* vec ();
inline nasal_hash* hash();
inline nasal_func* func();
inline void*& obj ();
inline nasal_obj* obj ();
};
struct nasal_vec// 24 bytes
struct nasal_vec
{
std::vector<nasal_ref> elems;
@ -95,7 +79,7 @@ struct nasal_vec// 24 bytes
nasal_ref* get_mem(const int);
};
struct nasal_hash// 56 bytes
struct nasal_hash
{
std::unordered_map<std::string,nasal_ref> elems;
@ -104,22 +88,30 @@ struct nasal_hash// 56 bytes
nasal_ref* get_mem(const std::string&);
};
struct nasal_func// 112 bytes
struct nasal_func
{
int32_t dynpara; // dynamic parameter name index in hash.
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> 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){}
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_COLLECTED =1;
constexpr uint8_t GC_FOUND =2;
struct nasal_val// 16 bytes
struct nasal_val
{
uint8_t mark;
uint8_t type;
@ -129,14 +121,13 @@ struct nasal_val// 16 bytes
nasal_vec* vec;
nasal_hash* hash;
nasal_func* func;
void* obj;
nasal_obj* obj;
}ptr;
nasal_val(uint8_t);
~nasal_val();
};
/*functions of nasal_vec*/
nasal_ref nasal_vec::get_val(const int index)
{
int size=elems.size();
@ -165,7 +156,7 @@ void nasal_vec::print()
std::cout<<"[]";
return;
}
ssize_t iter=0;
size_t iter=0;
std::cout<<'[';
for(auto& i:elems)
{
@ -183,10 +174,8 @@ void nasal_vec::print()
std::cout<<",]"[(++iter)==elems.size()];
}
--depth;
return;
}
/*functions of nasal_hash*/
nasal_ref nasal_hash::get_val(const std::string& key)
{
if(elems.count(key))
@ -259,20 +248,23 @@ void nasal_hash::print()
std::cout<<",}"[(++iter)==elems.size()];
}
--depth;
return;
}
/*functions of nasal_func*/
void nasal_func::clear()
{
dynpara=-1;
local.clear();
upvalue.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)
{
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_hash: ptr.hash=new nasal_hash; 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()
{
@ -295,22 +286,16 @@ nasal_val::~nasal_val()
case vm_vec: delete ptr.vec; break;
case vm_hash: delete ptr.hash; break;
case vm_func: delete ptr.func; break;
case vm_obj:
if(ptr.obj)
free(ptr.obj);
break;
case vm_obj: delete ptr.obj; break;
}
ptr.obj=nullptr;
type=vm_nil;
return;
}
/* functions of nasal_ref */
double nasal_ref::to_number()
{
if(type==vm_str)
return str2num(str()->c_str());
return num();
return value.num;
}
std::string nasal_ref::to_string()
{
@ -325,14 +310,14 @@ inline std::string* nasal_ref::str (){return value.gcobj->ptr.str; }
inline nasal_vec* nasal_ref::vec (){return value.gcobj->ptr.vec; }
inline nasal_hash* nasal_ref::hash(){return value.gcobj->ptr.hash;}
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
{
#define STACK_MAX_DEPTH (4095)
nasal_ref zero; // reserved address of nasal_val,type vm_num, 0
nasal_ref one; // reserved address of nasal_val,type vm_num, 1
nasal_ref nil; // reserved address of nasal_val,type vm_nil
nasal_ref zero;
nasal_ref one;
nasal_ref nil;
nasal_ref stack[STACK_MAX_DEPTH+1];// 1 reserved to avoid stack overflow
nasal_ref* top; // stack top
std::vector<nasal_ref> strs; // reserved address for const vm_str
@ -393,11 +378,7 @@ void nasal_gc::sweep()
case vm_vec: i->ptr.vec->elems.clear(); break;
case vm_hash:i->ptr.hash->elems.clear();break;
case vm_func:i->ptr.func->clear(); break;
case vm_obj:
if(i->ptr.obj)
free(i->ptr.obj);
i->ptr.obj=nullptr;
break;
case vm_obj: i->ptr.obj->clear(); break;
}
free_list[i->type].push(i);
i->mark=GC_COLLECTED;

View File

@ -144,7 +144,7 @@ void nasal_lexer::die(const char* info)
{
++error;
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<<'^'<<info<<'\n';
}
@ -259,7 +259,10 @@ std::string nasal_lexer::str_gen()
}
// check if this string ends with a " or '
if(ptr++>=size)
{
die("get EOF when generating string.");
return str;
}
code+=res[ptr-1];
if(begin=='`' && str.length()!=1)
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:
// 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)
{
switch(tokens[check_ptr].type)

View File

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