🚀 import information output of dbg, vm and codegen

This commit is contained in:
ValKmjolnir 2022-09-11 17:22:00 +08:00
parent 6a6eab8db5
commit aa5b1d3d66
7 changed files with 177 additions and 171 deletions

View File

@ -1,6 +1,9 @@
#ifndef __NASAL_AST_H__ #ifndef __NASAL_AST_H__
#define __NASAL_AST_H__ #define __NASAL_AST_H__
#include <vector>
#include <cstring>
enum ast_node:u32 enum ast_node:u32
{ {
ast_null=0, // null node ast_null=0, // null node
@ -128,14 +131,15 @@ const char* ast_name[]=
class nasal_ast class nasal_ast
{ {
private: private:
u32 _line; u32 node_line;
u32 _column; u32 node_col;
u32 _type; u32 node_type;
f64 _num; f64 node_num;
string _str; string node_str;
std::vector<nasal_ast> _child; std::vector<nasal_ast> node_child;
public: public:
nasal_ast(const u32 l,const u32 c,const u32 t):_line(l),_column(c),_type(t),_num(0){} nasal_ast(const u32 l,const u32 c,const u32 t):
node_line(l),node_col(c),node_type(t),node_num(0){}
nasal_ast(const nasal_ast&); nasal_ast(const nasal_ast&);
nasal_ast(nasal_ast&&); nasal_ast(nasal_ast&&);
void tree(); void tree();
@ -144,74 +148,74 @@ 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[](usize n){return _child[n];} nasal_ast& operator[](usize n){return node_child[n];}
const nasal_ast& operator[](usize n) const {return _child[n];} const nasal_ast& operator[](usize n) const {return node_child[n];}
usize size() const {return _child.size();} usize size() const {return node_child.size();}
void add(nasal_ast&& ast){_child.push_back(std::move(ast));} void add(nasal_ast&& ast){node_child.push_back(std::move(ast));}
void add(const nasal_ast& ast){_child.push_back(ast);} void add(const nasal_ast& ast){node_child.push_back(ast);}
void set_line(const u32 l){_line=l;} void set_line(const u32 l){node_line=l;}
void set_type(const u32 t){_type=t;} void set_type(const u32 t){node_type=t;}
void set_str(const string& s){_str=s;} void set_str(const string& s){node_str=s;}
void set_num(const f64 n){_num=n;} void set_num(const f64 n){node_num=n;}
inline u32 line() const {return _line;} inline u32 line() const {return node_line;}
inline u32 col() const {return _column;} inline u32 col() const {return node_col;}
inline u32 type() const {return _type;} inline u32 type() const {return node_type;}
inline f64 num() const {return _num;} inline f64 num() const {return node_num;}
inline const string& str() const {return _str;} inline const string& str() const {return node_str;}
inline const std::vector<nasal_ast>& child() const {return _child;} inline const std::vector<nasal_ast>& child() const {return node_child;}
inline std::vector<nasal_ast>& child(){return _child;} inline std::vector<nasal_ast>& child(){return node_child;}
}; };
nasal_ast::nasal_ast(const nasal_ast& tmp): nasal_ast::nasal_ast(const nasal_ast& tmp):
_str(tmp._str),_child(tmp._child) node_str(tmp.node_str),node_child(tmp.node_child)
{ {
_line=tmp._line; node_line=tmp.node_line;
_column=tmp._column; node_col=tmp.node_col;
_type=tmp._type; node_type=tmp.node_type;
_num =tmp._num; node_num =tmp.node_num;
} }
nasal_ast::nasal_ast(nasal_ast&& tmp) nasal_ast::nasal_ast(nasal_ast&& tmp)
{ {
_line=tmp._line; node_line=tmp.node_line;
_column=tmp._column; node_col=tmp.node_col;
_type=tmp._type; node_type=tmp.node_type;
_num =tmp._num; node_num =tmp.node_num;
_str.swap(tmp._str); node_str.swap(tmp.node_str);
_child.swap(tmp._child); node_child.swap(tmp.node_child);
} }
nasal_ast& nasal_ast::operator=(const nasal_ast& tmp) nasal_ast& nasal_ast::operator=(const nasal_ast& tmp)
{ {
_line=tmp._line; node_line=tmp.node_line;
_column=tmp._column; node_col=tmp.node_col;
_type=tmp._type; node_type=tmp.node_type;
_num=tmp._num; node_num=tmp.node_num;
_str=tmp._str; node_str=tmp.node_str;
_child=tmp._child; node_child=tmp.node_child;
return *this; return *this;
} }
nasal_ast& nasal_ast::operator=(nasal_ast&& tmp) nasal_ast& nasal_ast::operator=(nasal_ast&& tmp)
{ {
_line=tmp._line; node_line=tmp.node_line;
_column=tmp._column; node_col=tmp.node_col;
_type=tmp._type; node_type=tmp.node_type;
_num=tmp._num; node_num=tmp.node_num;
_str.swap(tmp._str); node_str.swap(tmp.node_str);
_child.swap(tmp._child); node_child.swap(tmp.node_child);
return *this; return *this;
} }
void nasal_ast::clear() void nasal_ast::clear()
{ {
_line=_column=0; node_line=node_col=0;
_num=0; node_num=0;
_str=""; node_str.clear();
_type=ast_null; node_type=ast_null;
_child.clear(); node_child.clear();
} }
void nasal_ast::tree() void nasal_ast::tree()
@ -224,14 +228,16 @@ void nasal_ast::print(u32 depth,bool last,std::vector<string>& indent)
{ {
for(auto& i:indent) for(auto& i:indent)
std::cout<<i; std::cout<<i;
std::cout<<ast_name[_type]; std::cout<<ast_name[node_type];
if(_type==ast_str || _type==ast_id || if(node_type==ast_str ||
_type==ast_default || _type==ast_dynamic || node_type==ast_id ||
_type==ast_callh) node_type==ast_default ||
std::cout<<":"<<rawstr(_str); node_type==ast_dynamic ||
else if(_type==ast_num || _type==ast_file) node_type==ast_callh)
std::cout<<":"<<_num; std::cout<<":"<<rawstr(node_str);
std::cout<<'\n'; else if(node_type==ast_num || node_type==ast_file)
std::cout<<":"<<node_num;
std::cout<<"\n";
if(last && depth) if(last && depth)
indent.back()=" "; indent.back()=" ";
else if(!last && depth) else if(!last && depth)
@ -240,14 +246,14 @@ void nasal_ast::print(u32 depth,bool last,std::vector<string>& indent)
#else #else
indent.back()=""; indent.back()="";
#endif #endif
for(u32 i=0;i<_child.size();++i) for(u32 i=0;i<node_child.size();++i)
{ {
#ifdef _WIN32 #ifdef _WIN32
indent.push_back(i==_child.size()-1?"+-":"|-"); indent.push_back(i==node_child.size()-1?"+-":"|-");
#else #else
indent.push_back(i==_child.size()-1?"└─":"├─"); indent.push_back(i==node_child.size()-1?"└─":"├─");
#endif #endif
_child[i].print(depth+1,i==_child.size()-1,indent); node_child[i].print(depth+1,i==node_child.size()-1,indent);
indent.pop_back(); indent.pop_back();
} }
} }

View File

@ -386,13 +386,7 @@ nas_ref builtin_keys(nas_ref* local,nasal_gc& gc)
} }
nas_ref builtin_die(nas_ref* local,nasal_gc& gc) nas_ref builtin_die(nas_ref* local,nasal_gc& gc)
{ {
nas_ref str=local[1]; return nas_err("error",local[1].tostr());
if(str.type!=vm_str)
return nas_err("die","\"str\" must be string");
std::cerr<<bold_red<<"[vm] error: "
<<bold_white<<str.str()<<'\n'
<<reset;
return {vm_none};
} }
nas_ref builtin_find(nas_ref* local,nasal_gc& gc) nas_ref builtin_find(nas_ref* local,nasal_gc& gc)
{ {

View File

@ -125,66 +125,78 @@ struct opcode
line=tmp.line; line=tmp.line;
return *this; return *this;
} }
void print(const char*,
const f64*,
const string*,
const u32,bool) const;
}; };
void opcode::print(const char* header, class codestream
const f64* constnum,
const string* conststr,
const u32 index,
bool deftnum=false) const
{ {
std::cout<<bold_cyan<<header<<reset<<std::hex<<"0x" private:
<<std::setw(8)<<std::setfill('0')<<index<<": " opcode code;
<<std::setw(2)<<std::setfill('0')<<(u32)op<<" " const u32 index;
<<std::setw(2)<<std::setfill('0')<<((num>>24)&0xff)<<" " const f64* nums;
<<std::setw(2)<<std::setfill('0')<<((num>>16)&0xff)<<" " const string* strs;
<<std::setw(2)<<std::setfill('0')<<((num>>8)&0xff)<<" " const string* files;
<<std::setw(2)<<std::setfill('0')<<(num&0xff) public:
<<" "<<code_table[op]<<" "<<std::dec; codestream(const opcode& c,const u32 i,const f64* n,const string* s,const string* f=nullptr):
switch(op) code(c.op,c.fidx,c.num,c.line),index(i),nums(n),strs(s),files(f){}
friend std::ostream& operator<<(std::ostream& out,const codestream& ins)
{ {
case op_addeq: case op_subeq: case op_muleq: case op_diveq: u8 op=ins.code.op;
case op_lnkeq: case op_meq: u32 num=ins.code.num;
std::cout<<std::hex<<"0x"<<num<<std::dec out<<std::hex<<"0x"
<<" sp-"<<num;break; <<std::setw(8)<<std::setfill('0')<<ins.index<<" "
case op_addeqc:case op_subeqc: case op_muleqc:case op_diveqc: <<std::setw(2)<<std::setfill('0')<<(u32)op<<" "
std::cout<<std::hex<<"0x"<<(num&0x7fffffff)<<std::dec <<std::setw(2)<<std::setfill('0')<<((num>>24)&0xff)<<" "
<<" ("<<constnum[num&0x7fffffff]<<") sp-" <<std::setw(2)<<std::setfill('0')<<((num>>16)&0xff)<<" "
<<(num>>31);break; <<std::setw(2)<<std::setfill('0')<<((num>>8)&0xff)<<" "
case op_lnkeqc: <<std::setw(2)<<std::setfill('0')<<(num&0xff)<<" "
std::cout<<std::hex<<"0x"<<(num&0x7fffffff)<<std::dec<<" (\"" <<code_table[op]<<" "<<std::dec;
<<rawstr(conststr[num&0x7fffffff],16)<<"\") sp-" switch(op)
<<(num>>31);break; {
case op_addc: case op_subc: case op_mulc: case op_divc: case op_addeq: case op_subeq: case op_muleq: case op_diveq:
case op_lessc: case op_leqc: case op_grtc: case op_geqc: case op_lnkeq: case op_meq:
case op_pnum: out<<std::hex<<"0x"<<num<<std::dec
std::cout<<std::hex<<"0x"<<num<<std::dec<<" (" <<" sp-"<<num;break;
<<constnum[num]<<")";break; case op_addeqc:case op_subeqc: case op_muleqc:case op_diveqc:
case op_callvi:case op_newv: case op_callfv: out<<std::hex<<"0x"<<(num&0x7fffffff)<<std::dec
case op_intg: case op_intl: <<" ("<<ins.nums[num&0x7fffffff]<<") sp-"
case op_newf: case op_jmp: case op_jt: case op_jf: <<(num>>31);break;
case op_callg: case op_mcallg: case op_loadg: case op_lnkeqc:
case op_calll: case op_mcalll: case op_loadl: out<<std::hex<<"0x"<<(num&0x7fffffff)<<std::dec<<" (\""
std::cout<<std::hex<<"0x"<<num<<std::dec;break; <<rawstr(ins.strs[num&0x7fffffff],16)<<"\") sp-"
case op_callb: <<(num>>31);break;
std::cout<<std::hex<<"0x"<<num<<" <"<<builtin[num].name case op_addc: case op_subc: case op_mulc: case op_divc:
<<"@0x"<<(u64)builtin[num].func<<std::dec<<">";break; case op_lessc: case op_leqc: case op_grtc: case op_geqc:
case op_upval: case op_mupval: case op_loadu: case op_pnum:
std::cout<<std::hex<<"0x"<<((num>>16)&0xffff) out<<std::hex<<"0x"<<num<<std::dec<<" ("
<<"[0x"<<(num&0xffff)<<"]"<<std::dec;break; <<ins.nums[num]<<")";break;
case op_happ: case op_pstr: case op_callvi:case op_newv: case op_callfv:
case op_lnkc: case op_intg: case op_intl:
case op_callh: case op_mcallh: case op_newf: case op_jmp: case op_jt: case op_jf:
case op_para: case op_deft: case op_dyn: case op_callg: case op_mcallg: case op_loadg:
std::cout<<std::hex<<"0x"<<num<<std::dec case op_calll: case op_mcalll: case op_loadl:
<<" (\""<<rawstr(conststr[num],16)<<"\")";break; out<<std::hex<<"0x"<<num<<std::dec;break;
default:if(deftnum)std::cout<<std::hex<<"0x"<<num<<std::dec;break; case op_callb:
out<<std::hex<<"0x"<<num<<" <"<<builtin[num].name
<<"@0x"<<(u64)builtin[num].func<<std::dec<<">";break;
case op_upval: case op_mupval: case op_loadu:
out<<std::hex<<"0x"<<((num>>16)&0xffff)
<<"[0x"<<(num&0xffff)<<"]"<<std::dec;break;
case op_happ: case op_pstr:
case op_lnkc:
case op_callh: case op_mcallh:
case op_para: case op_deft: case op_dyn:
out<<std::hex<<"0x"<<num<<std::dec
<<" (\""<<rawstr(ins.strs[num],16)<<"\")";break;
default:
if(ins.files)
out<<std::hex<<"0x"<<num<<std::dec;
break;
}
if(ins.files)
out<<" ("<<ins.files[ins.code.fidx]<<":"<<ins.code.line<<")";
return out;
} }
} };
class nasal_codegen class nasal_codegen
{ {
@ -1265,8 +1277,7 @@ void nasal_codegen::singleop(const u32 index)
break; break;
} }
} }
c.print(" ",num_res.data(),str_res.data(),index); std::cout<<" "<<codestream(c,index,num_res.data(),str_res.data())<<"\n";
std::cout<<"\n";
} }
void nasal_codegen::print() void nasal_codegen::print()

View File

@ -113,19 +113,21 @@ void nasal_dbg::callsort(const u64* arr)
void nasal_dbg::stepinfo() void nasal_dbg::stepinfo()
{ {
u32 begin,end;
u32 line=bytecode[pc].line==0?0:bytecode[pc].line-1; u32 line=bytecode[pc].line==0?0:bytecode[pc].line-1;
u32 begin=(line>>3)==0?0:((line>>3)<<3);
u32 end=(1+(line>>3))<<3;
src.load(files[bytecode[pc].fidx]); src.load(files[bytecode[pc].fidx]);
std::cout<<"\nsource code:\n"; std::cout<<"\nsource code:\n";
begin=(line>>3)==0?0:((line>>3)<<3);
end=(1+(line>>3))<<3;
for(u32 i=begin;i<end && i<src.size();++i) for(u32 i=begin;i<end && i<src.size();++i)
std::cout<<bold_cyan<<(i==line?"--> ":" ")<<reset<<src[i]<<"\n"; std::cout<<(i==line?back_white:reset)<<(i==line?"--> ":" ")<<src[i]<<reset<<"\n";
std::cout<<"next bytecode:\n"; std::cout<<"next bytecode:\n";
begin=(pc>>3)==0?0:((pc>>3)<<3); begin=(pc>>3)==0?0:((pc>>3)<<3);
end=(1+(pc>>3))<<3; end=(1+(pc>>3))<<3;
for(u32 i=begin;i<end && bytecode[i].op!=op_exit;++i) for(u32 i=begin;i<end && bytecode[i].op!=op_exit;++i)
bytecodeinfo(i==pc?"--> ":" ",i); std::cout
<<(i==pc?back_white:reset)<<(i==pc?"--> ":" ")
<<codestream(bytecode[i],i,num_table,str_table,files)
<<reset<<"\n";
stackinfo(10); stackinfo(10);
} }

View File

@ -17,6 +17,15 @@ struct for_reset
}reset_ter_color; }reset_ter_color;
#endif #endif
std::ostream& back_white(std::ostream& s)
{
#ifdef _WIN32
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0xf0);
#else
s<<"\033[7m";
#endif
return s;
}
std::ostream& bold_red(std::ostream& s) std::ostream& bold_red(std::ostream& s)
{ {
#ifdef _WIN32 #ifdef _WIN32
@ -74,24 +83,19 @@ public:
if(file==f) return; // don't need to load a loaded file if(file==f) return; // don't need to load a loaded file
file=f; file=f;
res.clear(); res.clear();
std::ifstream fin(f,std::ios::binary); std::ifstream in(f,std::ios::binary);
if(fin.fail()) if(in.fail())
{ {
std::cerr<<bold_red<<"src: "<<reset<<"cannot open <"<<f<<">\n"; std::cerr<<bold_red<<"src: "<<reset<<"cannot open <"<<f<<">\n";
std::exit(1); std::exit(1);
} }
string line; string line;
while(!fin.eof()) while(!in.eof())
{ {
std::getline(fin,line); std::getline(in,line);
res.push_back(line); res.push_back(line);
} }
} }
void clear()
{
std::vector<string> tmp;
res.swap(tmp);
}
const string& operator[](usize n){return res[n];} const string& operator[](usize n){return res[n];}
const string& name(){return file;} const string& name(){return file;}
usize size(){return res.size();} usize size(){return res.size();}

View File

@ -723,9 +723,7 @@ void nasal_gc::ctxreserve()
// use to print error log and return error value // use to print error log and return error value
nas_ref nas_err(const string& err_f,const string& info) nas_ref nas_err(const string& err_f,const string& info)
{ {
std::cerr<<bold_red<<"[vm] "<<err_f<<": " std::cerr<<"[vm] "<<err_f<<": "<<info<<"\n";
<<bold_white<<info<<"\n"
<<reset;
return {vm_none}; return {vm_none};
} }
#endif #endif

View File

@ -3,8 +3,7 @@
#include <iomanip> #include <iomanip>
#include <stack> #include <stack>
#include "nasal_codegen.h"
#include "nasal_err.h"
class nasal_vm class nasal_vm
{ {
@ -39,7 +38,6 @@ protected:
/* debug functions */ /* debug functions */
bool detail_info; bool detail_info;
void valinfo(nas_ref&); void valinfo(nas_ref&);
void bytecodeinfo(const char*,const u32);
void traceback(); void traceback();
void stackinfo(const u32); void stackinfo(const u32);
void reginfo(); void reginfo();
@ -200,22 +198,17 @@ void nasal_vm::valinfo(nas_ref& val)
} }
std::cout<<"\n"; std::cout<<"\n";
} }
void nasal_vm::bytecodeinfo(const char* header,const u32 p)
{
const opcode& c=bytecode[p];
c.print(header,num_table,str_table,p,true);
std::cout<<" ("<<files[c.fidx]<<":"<<c.line<<")\n";
}
void nasal_vm::traceback() void nasal_vm::traceback()
{ {
nas_ref* bottom=stack+bytecode[0].num; // bytecode[0] is op_intg /* bytecode[0].num is the global size */
nas_ref* main_ctx_top=gc.stack==stack?top:gc.mctx.top; // if error occurs in coroutine, this works nas_ref* bottom=gc.stack==stack?stack+bytecode[0].num:gc.stack;
nas_ref* ctx_top=gc.stack==stack?top:gc.top;
std::stack<u32> ret; std::stack<u32> ret;
for(nas_ref* i=bottom;i<=main_ctx_top;++i) for(nas_ref* i=bottom;i<=ctx_top;++i)
if(i->type==vm_ret) if(i->type==vm_ret && i->ret()!=0)
ret.push(i->ret()); ret.push(i->ret());
ret.push(pc); // store the position program crashed ret.push(pc); // store the position program crashed
std::cout<<"trace back:\n"; std::cout<<"trace back ("<<(gc.stack==stack?"main":"coroutine")<<")\n";
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)
@ -228,18 +221,18 @@ void nasal_vm::traceback()
<<" 0x"<<std::hex<<std::setw(8)<<std::setfill('0') <<" 0x"<<std::hex<<std::setw(8)<<std::setfill('0')
<<prev<<std::dec<<": "<<same<<" same call(s)\n"; <<prev<<std::dec<<": "<<same<<" same call(s)\n";
same=0; same=0;
bytecodeinfo(" ",p); std::cout<<" "<<codestream(bytecode[p],p,num_table,str_table,files)<<"\n";
} }
// the first called place has no same calls // the first called place has no same calls
} }
void nasal_vm::stackinfo(const u32 limit=10) void nasal_vm::stackinfo(const u32 limit=10)
{ {
/* bytecode[0].num is the global size */ /* bytecode[0].num is the global size */
u32 gsize=gc.stack==stack?bytecode[0].num:0; const u32 gsize=gc.stack==stack?bytecode[0].num:0;
nas_ref* t=top; nas_ref* t=top;
nas_ref* bottom=gc.stack+gsize; nas_ref* bottom=gc.stack+gsize;
std::cout<<"vm stack(0x"<<std::hex<<(u64)bottom<<std::dec std::cout<<"vm stack (0x"<<std::hex<<(u64)bottom<<std::dec
<<"<sp+"<<gsize<<">, limit "<<limit<<", total " <<" <sp+"<<gsize<<">, limit "<<limit<<", total "
<<(t<bottom? 0:(i64)(t-bottom+1))<<")\n"; <<(t<bottom? 0:(i64)(t-bottom+1))<<")\n";
for(u32 i=0;i<limit && t>=bottom;++i,--t) for(u32 i=0;i<limit && t>=bottom;++i,--t)
{ {
@ -251,7 +244,7 @@ void nasal_vm::stackinfo(const u32 limit=10)
} }
void nasal_vm::reginfo() void nasal_vm::reginfo()
{ {
std::cout<<"registers("<<(gc.cort?"coroutine":"main")<<")\n"<<std::hex std::cout<<"registers ("<<(gc.cort?"coroutine":"main")<<")\n"<<std::hex
<<" [ pc ] | pc | 0x"<<pc<<"\n" <<" [ pc ] | pc | 0x"<<pc<<"\n"
<<" [ global ] | addr | 0x"<<(u64)stack<<"\n" <<" [ global ] | addr | 0x"<<(u64)stack<<"\n"
<<" [ localr ] | addr | 0x"<<(u64)localr<<"\n" <<" [ localr ] | addr | 0x"<<(u64)localr<<"\n"
@ -266,7 +259,7 @@ void nasal_vm::gstate()
{ {
if(!bytecode[0].num || stack[0].type==vm_none) // bytecode[0].op is op_intg if(!bytecode[0].num || stack[0].type==vm_none) // bytecode[0].op is op_intg
return; return;
std::cout<<"global(0x"<<std::hex<<(u64)stack<<"<sp+0>)\n"<<std::dec; std::cout<<"global (0x"<<std::hex<<(u64)stack<<" <sp+0>)\n"<<std::dec;
for(u32 i=0;i<bytecode[0].num;++i) for(u32 i=0;i<bytecode[0].num;++i)
{ {
std::cout<<" 0x"<<std::hex<<std::setw(8) std::cout<<" 0x"<<std::hex<<std::setw(8)
@ -279,8 +272,8 @@ void nasal_vm::lstate()
if(!localr || !funcr.func().lsize) if(!localr || !funcr.func().lsize)
return; return;
const u32 lsize=funcr.func().lsize; const u32 lsize=funcr.func().lsize;
std::cout<<"local(0x"<<std::hex<<(u64)localr std::cout<<"local (0x"<<std::hex<<(u64)localr
<<"<sp+"<<(u64)(localr-gc.stack)<<">)\n"<<std::dec; <<" <sp+"<<(u64)(localr-gc.stack)<<">)\n"<<std::dec;
for(u32 i=0;i<lsize;++i) for(u32 i=0;i<lsize;++i)
{ {
std::cout<<" 0x"<<std::hex<<std::setw(8) std::cout<<" 0x"<<std::hex<<std::setw(8)
@ -317,9 +310,7 @@ void nasal_vm::detail()
[[noreturn]] [[noreturn]]
void nasal_vm::die(const string& str) void nasal_vm::die(const string& str)
{ {
std::cout<<bold_red<<"[vm] error: " std::cout<<"[vm] error: "<<str<<"\n";
<<bold_white<<str<<"\n"
<<reset;
traceback(); traceback();
stackinfo(); stackinfo();
if(detail_info) if(detail_info)