rabbit/rabbit/sqbaselib.cpp

1319 lines
34 KiB
C++

/**
* @author Alberto DEMICHELIS
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @copyright 2003-2017, Alberto DEMICHELIS, all right reserved
* @license MPL-2 (see license file)
*/
#include <rabbit/VirtualMachine.hpp>
#include <rabbit/Array.hpp>
#include <rabbit/SharedState.hpp>
#include <rabbit/String.hpp>
#include <rabbit/Table.hpp>
#include <rabbit/Closure.hpp>
#include <rabbit/RegFunction.hpp>
#include <rabbit/NativeClosure.hpp>
#include <rabbit/FunctionProto.hpp>
#include <rabbit/Generator.hpp>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <rabbit/StackInfos.hpp>
static bool str2num(const char *s,rabbit::ObjectPtr &res,int64_t base)
{
char *end;
const char *e = s;
bool iseintbase = base > 13; //to fix error converting hexadecimals with e like 56f0791e
bool isfloat = false;
char c;
while((c = *e) != '\0')
{
if (c == '.' || (!iseintbase && (c == 'E' || c == 'e'))) { //e and E is for scientific notation
isfloat = true;
break;
}
e++;
}
if(isfloat){
float_t r = float_t(strtod(s,&end));
if(s == end) return false;
res = r;
}
else{
int64_t r = int64_t(strtol(s,&end,(int)base));
if(s == end) return false;
res = r;
}
return true;
}
static int64_t base_dummy(rabbit::VirtualMachine* SQ_UNUSED_ARG(v))
{
return 0;
}
static int64_t base_getroottable(rabbit::VirtualMachine* v)
{
v->push(v->_roottable);
return 1;
}
static int64_t base_getconsttable(rabbit::VirtualMachine* v)
{
v->push(_get_shared_state(v)->_consts);
return 1;
}
static int64_t base_setroottable(rabbit::VirtualMachine* v)
{
rabbit::ObjectPtr o = v->_roottable;
if(SQ_FAILED(sq_setroottable(v))) return SQ_ERROR;
v->push(o);
return 1;
}
static int64_t base_setconsttable(rabbit::VirtualMachine* v)
{
rabbit::ObjectPtr o = _get_shared_state(v)->_consts;
if(SQ_FAILED(sq_setconsttable(v))) return SQ_ERROR;
v->push(o);
return 1;
}
static int64_t base_seterrorhandler(rabbit::VirtualMachine* v)
{
sq_seterrorhandler(v);
return 0;
}
static int64_t base_setdebughook(rabbit::VirtualMachine* v)
{
sq_setdebughook(v);
return 0;
}
static int64_t base_enabledebuginfo(rabbit::VirtualMachine* v)
{
rabbit::ObjectPtr &o=stack_get(v,2);
sq_enabledebuginfo(v,rabbit::VirtualMachine::IsFalse(o)?SQFalse:SQTrue);
return 0;
}
static int64_t __getcallstackinfos(rabbit::VirtualMachine* v,int64_t level)
{
rabbit::StackInfos si;
int64_t seq = 0;
const char *name = NULL;
if (SQ_SUCCEEDED(sq_stackinfos(v, level, &si)))
{
const char *fn = "unknown";
const char *src = "unknown";
if(si.funcname)fn = si.funcname;
if(si.source)src = si.source;
sq_newtable(v);
sq_pushstring(v, "func", -1);
sq_pushstring(v, fn, -1);
sq_newslot(v, -3, SQFalse);
sq_pushstring(v, "src", -1);
sq_pushstring(v, src, -1);
sq_newslot(v, -3, SQFalse);
sq_pushstring(v, "line", -1);
sq_pushinteger(v, si.line);
sq_newslot(v, -3, SQFalse);
sq_pushstring(v, "locals", -1);
sq_newtable(v);
seq=0;
while ((name = sq_getlocal(v, level, seq))) {
sq_pushstring(v, name, -1);
sq_push(v, -2);
sq_newslot(v, -4, SQFalse);
sq_pop(v, 1);
seq++;
}
sq_newslot(v, -3, SQFalse);
return 1;
}
return 0;
}
static int64_t base_getstackinfos(rabbit::VirtualMachine* v)
{
int64_t level;
sq_getinteger(v, -1, &level);
return __getcallstackinfos(v,level);
}
static int64_t base_assert(rabbit::VirtualMachine* v)
{
if(rabbit::VirtualMachine::IsFalse(stack_get(v,2))){
int64_t top = sq_gettop(v);
if (top>2 && SQ_SUCCEEDED(sq_tostring(v,3))) {
const char *str = 0;
if (SQ_SUCCEEDED(sq_getstring(v,-1,&str))) {
return sq_throwerror(v, str);
}
}
return sq_throwerror(v, "assertion failed");
}
return 0;
}
static int64_t get_slice_params(rabbit::VirtualMachine* v,int64_t &sidx,int64_t &eidx,rabbit::ObjectPtr &o)
{
int64_t top = sq_gettop(v);
sidx=0;
eidx=0;
o=stack_get(v,1);
if(top>1){
rabbit::ObjectPtr &start=stack_get(v,2);
if( start.isNull() == false
&& start.isNumeric() == true){
sidx=start.toIntegerValue();
}
}
if(top>2){
rabbit::ObjectPtr &end=stack_get(v,3);
if(end.isNumeric() == true){
eidx=end.toIntegerValue();
}
}
else {
eidx = sq_getsize(v,1);
}
return 1;
}
static int64_t base_print(rabbit::VirtualMachine* v)
{
const char *str;
if(SQ_SUCCEEDED(sq_tostring(v,2)))
{
if(SQ_SUCCEEDED(sq_getstring(v,-1,&str))) {
if(_get_shared_state(v)->_printfunc) _get_shared_state(v)->_printfunc(v,"%s",str);
return 0;
}
}
return SQ_ERROR;
}
static int64_t base_error(rabbit::VirtualMachine* v)
{
const char *str;
if(SQ_SUCCEEDED(sq_tostring(v,2)))
{
if(SQ_SUCCEEDED(sq_getstring(v,-1,&str))) {
if(_get_shared_state(v)->_errorfunc) _get_shared_state(v)->_errorfunc(v,"%s",str);
return 0;
}
}
return SQ_ERROR;
}
static int64_t base_compilestring(rabbit::VirtualMachine* v)
{
int64_t nargs=sq_gettop(v);
const char *src=NULL,*name="unnamedbuffer";
int64_t size;
sq_getstring(v,2,&src);
size=sq_getsize(v,2);
if(nargs>2){
sq_getstring(v,3,&name);
}
if(SQ_SUCCEEDED(sq_compilebuffer(v,src,size,name,SQFalse)))
return 1;
else
return SQ_ERROR;
}
static int64_t base_newthread(rabbit::VirtualMachine* v)
{
rabbit::ObjectPtr &func = stack_get(v,2);
int64_t stksize = (func.toClosure()->_function->_stacksize << 1) +2;
rabbit::VirtualMachine* newv = sq_newthread(v, (stksize < MIN_STACK_OVERHEAD + 2)? MIN_STACK_OVERHEAD + 2 : stksize);
sq_move(newv,v,-2);
return 1;
}
static int64_t base_suspend(rabbit::VirtualMachine* v)
{
return sq_suspendvm(v);
}
static int64_t base_array(rabbit::VirtualMachine* v)
{
rabbit::Array *a;
rabbit::Object &size = stack_get(v,2);
if(sq_gettop(v) > 2) {
a = rabbit::Array::create(_get_shared_state(v),0);
a->resize(size.toIntegerValue(),stack_get(v,3));
}
else {
a = rabbit::Array::create(_get_shared_state(v),size.toIntegerValue());
}
v->push(a);
return 1;
}
static int64_t base_type(rabbit::VirtualMachine* v)
{
rabbit::ObjectPtr &o = stack_get(v,2);
v->push(rabbit::String::create(_get_shared_state(v),getTypeName(o),-1));
return 1;
}
static int64_t base_callee(rabbit::VirtualMachine* v)
{
if(v->_callsstacksize > 1)
{
v->push(v->_callsstack[v->_callsstacksize - 2]._closure);
return 1;
}
return sq_throwerror(v,"no closure in the calls stack");
}
static const rabbit::RegFunction base_funcs[]={
//generic
{"seterrorhandler",base_seterrorhandler,2, NULL},
{"setdebughook",base_setdebughook,2, NULL},
{"enabledebuginfo",base_enabledebuginfo,2, NULL},
{"getstackinfos",base_getstackinfos,2, ".n"},
{"getroottable",base_getroottable,1, NULL},
{"setroottable",base_setroottable,2, NULL},
{"getconsttable",base_getconsttable,1, NULL},
{"setconsttable",base_setconsttable,2, NULL},
{"assert",base_assert,-2, NULL},
{"print",base_print,2, NULL},
{"error",base_error,2, NULL},
{"compilestring",base_compilestring,-2, ".ss"},
{"newthread",base_newthread,2, ".c"},
{"suspend",base_suspend,-1, NULL},
{"array",base_array,-2, ".n"},
{"type",base_type,2, NULL},
{"callee",base_callee,0,NULL},
{"dummy",base_dummy,0,NULL},
{NULL,(SQFUNCTION)0,0,NULL}
};
void sq_base_register(rabbit::VirtualMachine* v)
{
int64_t i=0;
sq_pushroottable(v);
while(base_funcs[i].name!=0) {
sq_pushstring(v,base_funcs[i].name,-1);
sq_newclosure(v,base_funcs[i].f,0);
sq_setnativeclosurename(v,-1,base_funcs[i].name);
sq_setparamscheck(v,base_funcs[i].nparamscheck,base_funcs[i].typemask);
sq_newslot(v,-3, SQFalse);
i++;
}
sq_pushstring(v,"_versionnumber_",-1);
sq_pushinteger(v,RABBIT_VERSION_NUMBER);
sq_newslot(v,-3, SQFalse);
sq_pushstring(v,"_version_",-1);
sq_pushstring(v,RABBIT_VERSION,-1);
sq_newslot(v,-3, SQFalse);
sq_pushstring(v,"_charsize_",-1);
sq_pushinteger(v,sizeof(char));
sq_newslot(v,-3, SQFalse);
sq_pushstring(v,"_intsize_",-1);
sq_pushinteger(v,sizeof(int64_t));
sq_newslot(v,-3, SQFalse);
sq_pushstring(v,"_floatsize_",-1);
sq_pushinteger(v,sizeof(float_t));
sq_newslot(v,-3, SQFalse);
sq_pop(v,1);
}
static int64_t default_delegate_len(rabbit::VirtualMachine* v)
{
v->push(int64_t(sq_getsize(v,1)));
return 1;
}
static int64_t default_delegate_tofloat(rabbit::VirtualMachine* v)
{
rabbit::ObjectPtr &o=stack_get(v,1);
switch(o.getType()){
case rabbit::OT_STRING:{
rabbit::ObjectPtr res;
if(str2num(_stringval(o),res,10)){
v->push(rabbit::ObjectPtr(res.toFloatValue()));
break;
}}
return sq_throwerror(v, "cannot convert the string");
break;
case rabbit::OT_INTEGER:
case rabbit::OT_FLOAT:
v->push(rabbit::ObjectPtr(o.toFloatValue()));
break;
case rabbit::OT_BOOL:
v->push(rabbit::ObjectPtr((float_t)(o.toInteger()?1:0)));
break;
default:
v->pushNull();
break;
}
return 1;
}
static int64_t default_delegate_tointeger(rabbit::VirtualMachine* v)
{
rabbit::ObjectPtr &o=stack_get(v,1);
int64_t base = 10;
if(sq_gettop(v) > 1) {
sq_getinteger(v,2,&base);
}
switch(o.getType()){
case rabbit::OT_STRING:{
rabbit::ObjectPtr res;
if(str2num(_stringval(o),res,base)){
v->push(rabbit::ObjectPtr(res.toIntegerValue()));
break;
}}
return sq_throwerror(v, "cannot convert the string");
break;
case rabbit::OT_INTEGER:
case rabbit::OT_FLOAT:
v->push(rabbit::ObjectPtr(o.toIntegerValue()));
break;
case rabbit::OT_BOOL:
v->push(rabbit::ObjectPtr(o.toInteger()?(int64_t)1:(int64_t)0));
break;
default:
v->pushNull();
break;
}
return 1;
}
static int64_t default_delegate_tostring(rabbit::VirtualMachine* v)
{
if(SQ_FAILED(sq_tostring(v,1)))
return SQ_ERROR;
return 1;
}
static int64_t obj_delegate_weakref(rabbit::VirtualMachine* v)
{
sq_weakref(v,1);
return 1;
}
static int64_t obj_clear(rabbit::VirtualMachine* v)
{
return SQ_SUCCEEDED(sq_clear(v,-1)) ? 1 : SQ_ERROR;
}
static int64_t number_delegate_tochar(rabbit::VirtualMachine* v)
{
rabbit::Object &o=stack_get(v,1);
char c = (char)o.toIntegerValue();
v->push(rabbit::String::create(_get_shared_state(v),(const char *)&c,1));
return 1;
}
/////////////////////////////////////////////////////////////////
//TABLE DEFAULT DELEGATE
static int64_t table_rawdelete(rabbit::VirtualMachine* v)
{
if(SQ_FAILED(sq_rawdeleteslot(v,1,SQTrue)))
return SQ_ERROR;
return 1;
}
static int64_t container_rawexists(rabbit::VirtualMachine* v)
{
if(SQ_SUCCEEDED(sq_rawget(v,-2))) {
sq_pushbool(v,SQTrue);
return 1;
}
sq_pushbool(v,SQFalse);
return 1;
}
static int64_t container_rawset(rabbit::VirtualMachine* v)
{
return SQ_SUCCEEDED(sq_rawset(v,-3)) ? 1 : SQ_ERROR;
}
static int64_t container_rawget(rabbit::VirtualMachine* v)
{
return SQ_SUCCEEDED(sq_rawget(v,-2))?1:SQ_ERROR;
}
static int64_t table_setdelegate(rabbit::VirtualMachine* v)
{
if(SQ_FAILED(sq_setdelegate(v,-2)))
return SQ_ERROR;
sq_push(v,-1); // -1 because sq_setdelegate pops 1
return 1;
}
static int64_t table_getdelegate(rabbit::VirtualMachine* v)
{
return SQ_SUCCEEDED(sq_getdelegate(v,-1))?1:SQ_ERROR;
}
static int64_t table_filter(rabbit::VirtualMachine* v)
{
rabbit::Object &o = stack_get(v,1);
rabbit::Table *tbl = o.toTable();
rabbit::ObjectPtr ret = rabbit::Table::create(_get_shared_state(v),0);
rabbit::ObjectPtr itr, key, val;
int64_t nitr;
while((nitr = tbl->next(false, itr, key, val)) != -1) {
itr = (int64_t)nitr;
v->push(o);
v->push(key);
v->push(val);
if(SQ_FAILED(sq_call(v,3,SQTrue,SQFalse))) {
return SQ_ERROR;
}
if(!rabbit::VirtualMachine::IsFalse(v->getUp(-1))) {
ret.toTable()->newSlot(key, val);
}
v->pop();
}
v->push(ret);
return 1;
}
const rabbit::RegFunction rabbit::SharedState::_table_default_delegate_funcz[]={
{"len",default_delegate_len,1, "t"},
{"rawget",container_rawget,2, "t"},
{"rawset",container_rawset,3, "t"},
{"rawdelete",table_rawdelete,2, "t"},
{"rawin",container_rawexists,2, "t"},
{"weakref",obj_delegate_weakref,1, NULL },
{"tostring",default_delegate_tostring,1, "."},
{"clear",obj_clear,1, "."},
{"setdelegate",table_setdelegate,2, ".t|o"},
{"getdelegate",table_getdelegate,1, "."},
{"filter",table_filter,2, "tc"},
{NULL,(SQFUNCTION)0,0,NULL}
};
//ARRAY DEFAULT DELEGATE///////////////////////////////////////
static int64_t array_append(rabbit::VirtualMachine* v)
{
return SQ_SUCCEEDED(sq_arrayappend(v,-2)) ? 1 : SQ_ERROR;
}
static int64_t array_extend(rabbit::VirtualMachine* v)
{
stack_get(v,1).toArray()->extend(stack_get(v,2).toArray());
sq_pop(v,1);
return 1;
}
static int64_t array_reverse(rabbit::VirtualMachine* v)
{
return SQ_SUCCEEDED(sq_arrayreverse(v,-1)) ? 1 : SQ_ERROR;
}
static int64_t array_pop(rabbit::VirtualMachine* v)
{
return SQ_SUCCEEDED(sq_arraypop(v,1,SQTrue))?1:SQ_ERROR;
}
static int64_t array_top(rabbit::VirtualMachine* v)
{
rabbit::Object &o=stack_get(v,1);
if(o.toArray()->size()>0){
v->push(o.toArray()->top());
return 1;
}
else return sq_throwerror(v,"top() on a empty array");
}
static int64_t array_insert(rabbit::VirtualMachine* v)
{
rabbit::Object &o=stack_get(v,1);
rabbit::Object &idx=stack_get(v,2);
rabbit::Object &val=stack_get(v,3);
if(!o.toArray()->insert(idx.toIntegerValue(),val))
return sq_throwerror(v,"index out of range");
sq_pop(v,2);
return 1;
}
static int64_t array_remove(rabbit::VirtualMachine* v)
{
rabbit::Object &o = stack_get(v, 1);
rabbit::Object &idx = stack_get(v, 2);
if(idx.isNumeric() == false) {
return sq_throwerror(v, "wrong type");
}
rabbit::ObjectPtr val;
if(o.toArray()->get(idx.toIntegerValue(), val)) {
o.toArray()->remove(idx.toIntegerValue());
v->push(val);
return 1;
}
return sq_throwerror(v, "idx out of range");
}
static int64_t array_resize(rabbit::VirtualMachine* v)
{
rabbit::Object &o = stack_get(v, 1);
rabbit::Object &nsize = stack_get(v, 2);
rabbit::ObjectPtr fill;
if (nsize.isNumeric() == true) {
int64_t sz = nsize.toIntegerValue();
if (sz<0)
return sq_throwerror(v, "resizing to negative length");
if(sq_gettop(v) > 2)
fill = stack_get(v, 3);
o.toArray()->resize(sz,fill);
sq_settop(v, 1);
return 1;
}
return sq_throwerror(v, "size must be a number");
}
static int64_t __map_array(rabbit::Array *dest,rabbit::Array *src,rabbit::VirtualMachine* v) {
rabbit::ObjectPtr temp;
int64_t size = src->size();
for(int64_t n = 0; n < size; n++) {
src->get(n,temp);
v->push(src);
v->push(temp);
if(SQ_FAILED(sq_call(v,2,SQTrue,SQFalse))) {
return SQ_ERROR;
}
dest->set(n,v->getUp(-1));
v->pop();
}
return 0;
}
static int64_t array_map(rabbit::VirtualMachine* v)
{
rabbit::Object &o = stack_get(v,1);
int64_t size = o.toArray()->size();
rabbit::ObjectPtr ret = rabbit::Array::create(_get_shared_state(v),size);
if(SQ_FAILED(__map_array(ret.toArray(),o.toArray(),v)))
return SQ_ERROR;
v->push(ret);
return 1;
}
static int64_t array_apply(rabbit::VirtualMachine* v)
{
rabbit::Object &o = stack_get(v,1);
if(SQ_FAILED(__map_array(o.toArray(),o.toArray(),v)))
return SQ_ERROR;
sq_pop(v,1);
return 1;
}
static int64_t array_reduce(rabbit::VirtualMachine* v)
{
rabbit::Object &o = stack_get(v,1);
rabbit::Array *a = o.toArray();
int64_t size = a->size();
if(size == 0) {
return 0;
}
rabbit::ObjectPtr res;
a->get(0,res);
if(size > 1) {
rabbit::ObjectPtr other;
for(int64_t n = 1; n < size; n++) {
a->get(n,other);
v->push(o);
v->push(res);
v->push(other);
if(SQ_FAILED(sq_call(v,3,SQTrue,SQFalse))) {
return SQ_ERROR;
}
res = v->getUp(-1);
v->pop();
}
}
v->push(res);
return 1;
}
static int64_t array_filter(rabbit::VirtualMachine* v)
{
rabbit::Object &o = stack_get(v,1);
rabbit::Array *a = o.toArray();
rabbit::ObjectPtr ret = rabbit::Array::create(_get_shared_state(v),0);
int64_t size = a->size();
rabbit::ObjectPtr val;
for(int64_t n = 0; n < size; n++) {
a->get(n,val);
v->push(o);
v->push(n);
v->push(val);
if(SQ_FAILED(sq_call(v,3,SQTrue,SQFalse))) {
return SQ_ERROR;
}
if(!rabbit::VirtualMachine::IsFalse(v->getUp(-1))) {
ret.toArray()->append(val);
}
v->pop();
}
v->push(ret);
return 1;
}
static int64_t array_find(rabbit::VirtualMachine* v)
{
rabbit::Object &o = stack_get(v,1);
rabbit::ObjectPtr &val = stack_get(v,2);
rabbit::Array *a = o.toArray();
int64_t size = a->size();
rabbit::ObjectPtr temp;
for(int64_t n = 0; n < size; n++) {
bool res = false;
a->get(n,temp);
if(rabbit::VirtualMachine::isEqual(temp,val,res) && res) {
v->push(n);
return 1;
}
}
return 0;
}
static bool _sort_compare(rabbit::VirtualMachine* v,rabbit::ObjectPtr &a,rabbit::ObjectPtr &b,int64_t func,int64_t &ret)
{
if(func < 0) {
if(!v->objCmp(a,b,ret)) return false;
}
else {
int64_t top = sq_gettop(v);
sq_push(v, func);
sq_pushroottable(v);
v->push(a);
v->push(b);
if(SQ_FAILED(sq_call(v, 3, SQTrue, SQFalse))) {
if (v->_lasterror.isString() == false) {
v->raise_error("compare func failed");
}
return false;
}
if(SQ_FAILED(sq_getinteger(v, -1, &ret))) {
v->raise_error("numeric value expected as return value of the compare function");
return false;
}
sq_settop(v, top);
return true;
}
return true;
}
static bool _hsort_sift_down(rabbit::VirtualMachine* v,rabbit::Array *arr, int64_t root, int64_t bottom, int64_t func)
{
int64_t maxChild;
int64_t done = 0;
int64_t ret;
int64_t root2;
while (((root2 = root * 2) <= bottom) && (!done))
{
if (root2 == bottom) {
maxChild = root2;
}
else {
if(!_sort_compare(v,(*arr)[root2],(*arr)[root2 + 1],func,ret))
return false;
if (ret > 0) {
maxChild = root2;
}
else {
maxChild = root2 + 1;
}
}
if(!_sort_compare(v,(*arr)[root],(*arr)[maxChild],func,ret))
return false;
if (ret < 0) {
if (root == maxChild) {
v->raise_error("inconsistent compare function");
return false; // We'd be swapping ourselve. The compare function is incorrect
}
_Swap((*arr)[root], (*arr)[maxChild]);
root = maxChild;
}
else {
done = 1;
}
}
return true;
}
static bool _hsort(rabbit::VirtualMachine* v,rabbit::ObjectPtr &arr, int64_t SQ_UNUSED_ARG(l), int64_t SQ_UNUSED_ARG(r),int64_t func)
{
rabbit::Array *a = arr.toArray();
int64_t i;
int64_t array_size = a->size();
for (i = (array_size / 2); i >= 0; i--) {
if(!_hsort_sift_down(v,a, i, array_size - 1,func)) return false;
}
for (i = array_size-1; i >= 1; i--)
{
_Swap((*a)[0],(*a)[i]);
if(!_hsort_sift_down(v,a, 0, i-1,func)) return false;
}
return true;
}
static int64_t array_sort(rabbit::VirtualMachine* v)
{
int64_t func = -1;
rabbit::ObjectPtr &o = stack_get(v,1);
if(o.toArray()->size() > 1) {
if(sq_gettop(v) == 2) func = 2;
if(!_hsort(v, o, 0, o.toArray()->size()-1, func))
return SQ_ERROR;
}
sq_settop(v,1);
return 1;
}
static int64_t array_slice(rabbit::VirtualMachine* v)
{
int64_t sidx,eidx;
rabbit::ObjectPtr o;
if(get_slice_params(v,sidx,eidx,o)==-1)return -1;
int64_t alen = o.toArray()->size();
if(sidx < 0)sidx = alen + sidx;
if(eidx < 0)eidx = alen + eidx;
if(eidx < sidx)return sq_throwerror(v,"wrong indexes");
if(eidx > alen || sidx < 0)return sq_throwerror(v, "slice out of range");
rabbit::Array *arr=rabbit::Array::create(_get_shared_state(v),eidx-sidx);
rabbit::ObjectPtr t;
int64_t count=0;
for(int64_t i=sidx;i<eidx;i++){
o.toArray()->get(i,t);
arr->set(count++,t);
}
v->push(arr);
return 1;
}
const rabbit::RegFunction rabbit::SharedState::_array_default_delegate_funcz[]={
{"len",default_delegate_len,1, "a"},
{"append",array_append,2, "a"},
{"extend",array_extend,2, "aa"},
{"push",array_append,2, "a"},
{"pop",array_pop,1, "a"},
{"top",array_top,1, "a"},
{"insert",array_insert,3, "an"},
{"remove",array_remove,2, "an"},
{"resize",array_resize,-2, "an"},
{"reverse",array_reverse,1, "a"},
{"sort",array_sort,-1, "ac"},
{"slice",array_slice,-1, "ann"},
{"weakref",obj_delegate_weakref,1, NULL },
{"tostring",default_delegate_tostring,1, "."},
{"clear",obj_clear,1, "."},
{"map",array_map,2, "ac"},
{"apply",array_apply,2, "ac"},
{"reduce",array_reduce,2, "ac"},
{"filter",array_filter,2, "ac"},
{"find",array_find,2, "a."},
{NULL,(SQFUNCTION)0,0,NULL}
};
//STRING DEFAULT DELEGATE//////////////////////////
static int64_t string_slice(rabbit::VirtualMachine* v)
{
int64_t sidx,eidx;
rabbit::ObjectPtr o;
if(SQ_FAILED(get_slice_params(v,sidx,eidx,o)))return -1;
int64_t slen = o.toString()->_len;
if(sidx < 0)sidx = slen + sidx;
if(eidx < 0)eidx = slen + eidx;
if(eidx < sidx) return sq_throwerror(v,"wrong indexes");
if(eidx > slen || sidx < 0) return sq_throwerror(v, "slice out of range");
v->push(rabbit::String::create(_get_shared_state(v),&_stringval(o)[sidx],eidx-sidx));
return 1;
}
static int64_t string_find(rabbit::VirtualMachine* v)
{
int64_t top,start_idx=0;
const char *str,*substr,*ret;
if(((top=sq_gettop(v))>1) && SQ_SUCCEEDED(sq_getstring(v,1,&str)) && SQ_SUCCEEDED(sq_getstring(v,2,&substr))){
if(top>2)sq_getinteger(v,3,&start_idx);
if((sq_getsize(v,1)>start_idx) && (start_idx>=0)){
ret=strstr(&str[start_idx],substr);
if(ret){
sq_pushinteger(v,(int64_t)(ret-str));
return 1;
}
}
return 0;
}
return sq_throwerror(v,"invalid param");
}
#define STRING_TOFUNCZ(func) static int64_t string_##func(rabbit::VirtualMachine* v) \
{\
int64_t sidx,eidx; \
rabbit::ObjectPtr str; \
if(SQ_FAILED(get_slice_params(v,sidx,eidx,str)))return -1; \
int64_t slen = str.toString()->_len; \
if(sidx < 0)sidx = slen + sidx; \
if(eidx < 0)eidx = slen + eidx; \
if(eidx < sidx) return sq_throwerror(v,"wrong indexes"); \
if(eidx > slen || sidx < 0) return sq_throwerror(v,"slice out of range"); \
int64_t len=str.toString()->_len; \
const char *sthis=_stringval(str); \
char *snew=(_get_shared_state(v)->getScratchPad(sq_rsl(len))); \
memcpy(snew,sthis,sq_rsl(len));\
for(int64_t i=sidx;i<eidx;i++) snew[i] = func(sthis[i]); \
v->push(rabbit::String::create(_get_shared_state(v),snew,len)); \
return 1; \
}
STRING_TOFUNCZ(tolower)
STRING_TOFUNCZ(toupper)
const rabbit::RegFunction rabbit::SharedState::_string_default_delegate_funcz[]={
{"len",default_delegate_len,1, "s"},
{"tointeger",default_delegate_tointeger,-1, "sn"},
{"tofloat",default_delegate_tofloat,1, "s"},
{"tostring",default_delegate_tostring,1, "."},
{"slice",string_slice,-1, "s n n"},
{"find",string_find,-2, "s s n"},
{"tolower",string_tolower,-1, "s n n"},
{"toupper",string_toupper,-1, "s n n"},
{"weakref",obj_delegate_weakref,1, NULL },
{NULL,(SQFUNCTION)0,0,NULL}
};
//INTEGER DEFAULT DELEGATE//////////////////////////
const rabbit::RegFunction rabbit::SharedState::_number_default_delegate_funcz[]={
{"tointeger",default_delegate_tointeger,1, "n|b"},
{"tofloat",default_delegate_tofloat,1, "n|b"},
{"tostring",default_delegate_tostring,1, "."},
{"tochar",number_delegate_tochar,1, "n|b"},
{"weakref",obj_delegate_weakref,1, NULL },
{NULL,(SQFUNCTION)0,0,NULL}
};
//CLOSURE DEFAULT DELEGATE//////////////////////////
static int64_t closure_pcall(rabbit::VirtualMachine* v)
{
return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQFalse))?1:SQ_ERROR;
}
static int64_t closure_call(rabbit::VirtualMachine* v)
{
rabbit::ObjectPtr &c = stack_get(v, -1);
if ( c.isClosure() == true
&& c.toClosure()->_function->_bgenerator == false) {
return sq_tailcall(v, sq_gettop(v) - 1);
}
return SQ_SUCCEEDED(sq_call(v, sq_gettop(v) - 1, SQTrue, SQTrue)) ? 1 : SQ_ERROR;
}
static int64_t _closure_acall(rabbit::VirtualMachine* v,rabbit::Bool raiseerror)
{
rabbit::Array *aparams=stack_get(v,2).toArray();
int64_t nparams=aparams->size();
v->push(stack_get(v,1));
for(int64_t i=0;i<nparams;i++)v->push((*aparams)[i]);
return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue,raiseerror))?1:SQ_ERROR;
}
static int64_t closure_acall(rabbit::VirtualMachine* v)
{
return _closure_acall(v,SQTrue);
}
static int64_t closure_pacall(rabbit::VirtualMachine* v)
{
return _closure_acall(v,SQFalse);
}
static int64_t closure_bindenv(rabbit::VirtualMachine* v)
{
if(SQ_FAILED(sq_bindenv(v,1)))
return SQ_ERROR;
return 1;
}
static int64_t closure_getroot(rabbit::VirtualMachine* v)
{
if(SQ_FAILED(sq_getclosureroot(v,-1)))
return SQ_ERROR;
return 1;
}
static int64_t closure_setroot(rabbit::VirtualMachine* v)
{
if(SQ_FAILED(sq_setclosureroot(v,-2)))
return SQ_ERROR;
return 1;
}
static int64_t closure_getinfos(rabbit::VirtualMachine* v) {
rabbit::Object o = stack_get(v,1);
rabbit::Table *res = rabbit::Table::create(_get_shared_state(v),4);
if(o.isClosure() == true) {
rabbit::FunctionProto *f = o.toClosure()->_function;
int64_t nparams = f->_nparameters + (f->_varparams?1:0);
rabbit::ObjectPtr params = rabbit::Array::create(_get_shared_state(v),nparams);
rabbit::ObjectPtr defparams = rabbit::Array::create(_get_shared_state(v),f->_ndefaultparams);
for(int64_t n = 0; n<f->_nparameters; n++) {
params.toArray()->set((int64_t)n,f->_parameters[n]);
}
for(int64_t j = 0; j<f->_ndefaultparams; j++) {
defparams.toArray()->set((int64_t)j,o.toClosure()->_defaultparams[j]);
}
if(f->_varparams) {
params.toArray()->set(nparams-1,rabbit::String::create(_get_shared_state(v),"...",-1));
}
res->newSlot(rabbit::String::create(_get_shared_state(v),"native",-1),false);
res->newSlot(rabbit::String::create(_get_shared_state(v),"name",-1),f->_name);
res->newSlot(rabbit::String::create(_get_shared_state(v),"src",-1),f->_sourcename);
res->newSlot(rabbit::String::create(_get_shared_state(v),"parameters",-1),params);
res->newSlot(rabbit::String::create(_get_shared_state(v),"varargs",-1),f->_varparams);
res->newSlot(rabbit::String::create(_get_shared_state(v),"defparams",-1),defparams);
}
else { //rabbit::OT_NATIVECLOSURE
rabbit::NativeClosure *nc = o.toNativeClosure();
res->newSlot(rabbit::String::create(_get_shared_state(v),"native",-1),true);
res->newSlot(rabbit::String::create(_get_shared_state(v),"name",-1),nc->_name);
res->newSlot(rabbit::String::create(_get_shared_state(v),"paramscheck",-1),nc->_nparamscheck);
rabbit::ObjectPtr typecheck;
if(nc->_typecheck.size() > 0) {
typecheck =
rabbit::Array::create(_get_shared_state(v), nc->_typecheck.size());
for(uint64_t n = 0; n<nc->_typecheck.size(); n++) {
typecheck.toArray()->set((int64_t)n,nc->_typecheck[n]);
}
}
res->newSlot(rabbit::String::create(_get_shared_state(v),"typecheck",-1),typecheck);
}
v->push(res);
return 1;
}
const rabbit::RegFunction rabbit::SharedState::_closure_default_delegate_funcz[]={
{"call",closure_call,-1, "c"},
{"pcall",closure_pcall,-1, "c"},
{"acall",closure_acall,2, "ca"},
{"pacall",closure_pacall,2, "ca"},
{"weakref",obj_delegate_weakref,1, NULL },
{"tostring",default_delegate_tostring,1, "."},
{"bindenv",closure_bindenv,2, "c x|y|t"},
{"getinfos",closure_getinfos,1, "c"},
{"getroot",closure_getroot,1, "c"},
{"setroot",closure_setroot,2, "ct"},
{NULL,(SQFUNCTION)0,0,NULL}
};
//GENERATOR DEFAULT DELEGATE
static int64_t generator_getstatus(rabbit::VirtualMachine* v)
{
rabbit::Object &o=stack_get(v,1);
switch(o.toGenerator()->_state){
case rabbit::Generator::eSuspended:v->push(rabbit::String::create(_get_shared_state(v),"suspended"));break;
case rabbit::Generator::eRunning:v->push(rabbit::String::create(_get_shared_state(v),"running"));break;
case rabbit::Generator::eDead:v->push(rabbit::String::create(_get_shared_state(v),"dead"));break;
}
return 1;
}
const rabbit::RegFunction rabbit::SharedState::_generator_default_delegate_funcz[]={
{"getstatus",generator_getstatus,1, "g"},
{"weakref",obj_delegate_weakref,1, NULL },
{"tostring",default_delegate_tostring,1, "."},
{NULL,(SQFUNCTION)0,0,NULL}
};
//THREAD DEFAULT DELEGATE
static int64_t thread_call(rabbit::VirtualMachine* v)
{
rabbit::ObjectPtr o = stack_get(v,1);
if(o.isVirtualMachine() == true) {
int64_t nparams = sq_gettop(v);
o.toVirtualMachine()->push(o.toVirtualMachine()->_roottable);
for(int64_t i = 2; i<(nparams+1); i++)
sq_move(o.toVirtualMachine(),v,i);
if(SQ_SUCCEEDED(sq_call(o.toVirtualMachine(),nparams,SQTrue,SQTrue))) {
sq_move(v,o.toVirtualMachine(),-1);
sq_pop(o.toVirtualMachine(),1);
return 1;
}
v->_lasterror = o.toVirtualMachine()->_lasterror;
return SQ_ERROR;
}
return sq_throwerror(v,"wrong parameter");
}
static int64_t thread_wakeup(rabbit::VirtualMachine* v)
{
rabbit::ObjectPtr o = stack_get(v,1);
if(o.isVirtualMachine() == true) {
rabbit::VirtualMachine *thread = o.toVirtualMachine();
int64_t state = sq_getvmstate(thread);
if(state != SQ_VMSTATE_SUSPENDED) {
switch(state) {
case SQ_VMSTATE_IDLE:
return sq_throwerror(v,"cannot wakeup a idle thread");
break;
case SQ_VMSTATE_RUNNING:
return sq_throwerror(v,"cannot wakeup a running thread");
break;
}
}
int64_t wakeupret = sq_gettop(v)>1?SQTrue:SQFalse;
if(wakeupret) {
sq_move(thread,v,2);
}
if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,SQTrue,SQTrue,SQFalse))) {
sq_move(v,thread,-1);
sq_pop(thread,1); //pop retval
if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) {
sq_settop(thread,1); //pop roottable
}
return 1;
}
sq_settop(thread,1);
v->_lasterror = thread->_lasterror;
return SQ_ERROR;
}
return sq_throwerror(v,"wrong parameter");
}
static int64_t thread_wakeupthrow(rabbit::VirtualMachine* v)
{
rabbit::ObjectPtr o = stack_get(v,1);
if(o.isVirtualMachine() == true) {
rabbit::VirtualMachine *thread = o.toVirtualMachine();
int64_t state = sq_getvmstate(thread);
if(state != SQ_VMSTATE_SUSPENDED) {
switch(state) {
case SQ_VMSTATE_IDLE:
return sq_throwerror(v,"cannot wakeup a idle thread");
break;
case SQ_VMSTATE_RUNNING:
return sq_throwerror(v,"cannot wakeup a running thread");
break;
}
}
sq_move(thread,v,2);
sq_throwobject(thread);
rabbit::Bool rethrow_error = SQTrue;
if(sq_gettop(v) > 2) {
sq_getbool(v,3,&rethrow_error);
}
if(SQ_SUCCEEDED(sq_wakeupvm(thread,SQFalse,SQTrue,SQTrue,SQTrue))) {
sq_move(v,thread,-1);
sq_pop(thread,1); //pop retval
if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) {
sq_settop(thread,1); //pop roottable
}
return 1;
}
sq_settop(thread,1);
if(rethrow_error) {
v->_lasterror = thread->_lasterror;
return SQ_ERROR;
}
return SQ_OK;
}
return sq_throwerror(v,"wrong parameter");
}
static int64_t thread_getstatus(rabbit::VirtualMachine* v)
{
rabbit::ObjectPtr &o = stack_get(v,1);
switch(sq_getvmstate(o.toVirtualMachine())) {
case SQ_VMSTATE_IDLE:
sq_pushstring(v,"idle",-1);
break;
case SQ_VMSTATE_RUNNING:
sq_pushstring(v,"running",-1);
break;
case SQ_VMSTATE_SUSPENDED:
sq_pushstring(v,"suspended",-1);
break;
default:
return sq_throwerror(v,"internal VM error");
}
return 1;
}
static int64_t thread_getstackinfos(rabbit::VirtualMachine* v)
{
rabbit::ObjectPtr o = stack_get(v,1);
if(o.isVirtualMachine() == true) {
rabbit::VirtualMachine *thread = o.toVirtualMachine();
int64_t threadtop = sq_gettop(thread);
int64_t level;
sq_getinteger(v,-1,&level);
rabbit::Result res = __getcallstackinfos(thread,level);
if(SQ_FAILED(res))
{
sq_settop(thread,threadtop);
if(thread->_lasterror.isString() == true) {
sq_throwerror(v,_stringval(thread->_lasterror));
}
else {
sq_throwerror(v,"unknown error");
}
}
if(res > 0) {
//some result
sq_move(v,thread,-1);
sq_settop(thread,threadtop);
return 1;
}
//no result
sq_settop(thread,threadtop);
return 0;
}
return sq_throwerror(v,"wrong parameter");
}
const rabbit::RegFunction rabbit::SharedState::_thread_default_delegate_funcz[] = {
{"call", thread_call, -1, "v"},
{"wakeup", thread_wakeup, -1, "v"},
{"wakeupthrow", thread_wakeupthrow, -2, "v.b"},
{"getstatus", thread_getstatus, 1, "v"},
{"weakref",obj_delegate_weakref,1, NULL },
{"getstackinfos",thread_getstackinfos,2, "vn"},
{"tostring",default_delegate_tostring,1, "."},
{NULL,(SQFUNCTION)0,0,NULL}
};
static int64_t class_getattributes(rabbit::VirtualMachine* v)
{
return SQ_SUCCEEDED(sq_getattributes(v,-2))?1:SQ_ERROR;
}
static int64_t class_setattributes(rabbit::VirtualMachine* v)
{
return SQ_SUCCEEDED(sq_setattributes(v,-3))?1:SQ_ERROR;
}
static int64_t class_instance(rabbit::VirtualMachine* v)
{
return SQ_SUCCEEDED(sq_createinstance(v,-1))?1:SQ_ERROR;
}
static int64_t class_getbase(rabbit::VirtualMachine* v)
{
return SQ_SUCCEEDED(sq_getbase(v,-1))?1:SQ_ERROR;
}
static int64_t class_newmember(rabbit::VirtualMachine* v)
{
int64_t top = sq_gettop(v);
rabbit::Bool bstatic = SQFalse;
if(top == 5)
{
sq_tobool(v,-1,&bstatic);
sq_pop(v,1);
}
if(top < 4) {
sq_pushnull(v);
}
return SQ_SUCCEEDED(sq_newmember(v,-4,bstatic))?1:SQ_ERROR;
}
static int64_t class_rawnewmember(rabbit::VirtualMachine* v)
{
int64_t top = sq_gettop(v);
rabbit::Bool bstatic = SQFalse;
if(top == 5)
{
sq_tobool(v,-1,&bstatic);
sq_pop(v,1);
}
if(top < 4) {
sq_pushnull(v);
}
return SQ_SUCCEEDED(sq_rawnewmember(v,-4,bstatic))?1:SQ_ERROR;
}
const rabbit::RegFunction rabbit::SharedState::_class_default_delegate_funcz[] = {
{"getattributes", class_getattributes, 2, "y."},
{"setattributes", class_setattributes, 3, "y.."},
{"rawget",container_rawget,2, "y"},
{"rawset",container_rawset,3, "y"},
{"rawin",container_rawexists,2, "y"},
{"weakref",obj_delegate_weakref,1, NULL },
{"tostring",default_delegate_tostring,1, "."},
{"instance",class_instance,1, "y"},
{"getbase",class_getbase,1, "y"},
{"newmember",class_newmember,-3, "y"},
{"rawnewmember",class_rawnewmember,-3, "y"},
{NULL,(SQFUNCTION)0,0,NULL}
};
static int64_t instance_getclass(rabbit::VirtualMachine* v)
{
if(SQ_SUCCEEDED(sq_getclass(v,1)))
return 1;
return SQ_ERROR;
}
const rabbit::RegFunction rabbit::SharedState::_instance_default_delegate_funcz[] = {
{"getclass", instance_getclass, 1, "x"},
{"rawget",container_rawget,2, "x"},
{"rawset",container_rawset,3, "x"},
{"rawin",container_rawexists,2, "x"},
{"weakref",obj_delegate_weakref,1, NULL },
{"tostring",default_delegate_tostring,1, "."},
{NULL,(SQFUNCTION)0,0,NULL}
};
static int64_t weakref_ref(rabbit::VirtualMachine* v)
{
if(SQ_FAILED(sq_getweakrefval(v,1)))
return SQ_ERROR;
return 1;
}
const rabbit::RegFunction rabbit::SharedState::_weakref_default_delegate_funcz[] = {
{"ref",weakref_ref,1, "r"},
{"weakref",obj_delegate_weakref,1, NULL },
{"tostring",default_delegate_tostring,1, "."},
{NULL,(SQFUNCTION)0,0,NULL}
};