(cherry picked from commit c5da175fd79ecd17752bb2fd8af2b5a65739e58e)
... | ... |
@@ -1,5 +1,5 @@ |
1 | 1 |
/* |
2 |
-Copyright (c) 2003-2017 Alberto Demichelis |
|
2 |
+Copyright (c) 2003-2022 Alberto Demichelis |
|
3 | 3 |
|
4 | 4 |
Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | 5 |
of this software and associated documentation files (the "Software"), to deal |
... | ... |
@@ -65,10 +65,10 @@ struct SQOuter; |
65 | 65 |
|
66 | 66 |
#include "sqconfig.h" |
67 | 67 |
|
68 |
-#define SQUIRREL_VERSION _SC("Squirrel 3.1 stable") |
|
69 |
-#define SQUIRREL_COPYRIGHT _SC("Copyright (C) 2003-2017 Alberto Demichelis") |
|
68 |
+#define SQUIRREL_VERSION _SC("Squirrel 3.2 stable") |
|
69 |
+#define SQUIRREL_COPYRIGHT _SC("Copyright (C) 2003-2022 Alberto Demichelis") |
|
70 | 70 |
#define SQUIRREL_AUTHOR _SC("Alberto Demichelis") |
71 |
-#define SQUIRREL_VERSION_NUMBER 310 |
|
71 |
+#define SQUIRREL_VERSION_NUMBER 320 |
|
72 | 72 |
|
73 | 73 |
#define SQ_VMSTATE_IDLE 0 |
74 | 74 |
#define SQ_VMSTATE_RUNNING 1 |
... | ... |
@@ -280,7 +280,7 @@ SQUIRREL_API SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQInteger *n |
280 | 280 |
SQUIRREL_API SQRESULT sq_getclosurename(HSQUIRRELVM v,SQInteger idx); |
281 | 281 |
SQUIRREL_API SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name); |
282 | 282 |
SQUIRREL_API SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p); |
283 |
-SQUIRREL_API SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag); |
|
283 |
+SQUIRREL_API SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag,SQBool throwerror); |
|
284 | 284 |
SQUIRREL_API SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize); |
285 | 285 |
SQUIRREL_API SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase); |
286 | 286 |
SQUIRREL_API SQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx); |
... | ... |
@@ -14,7 +14,7 @@ |
14 | 14 |
|
15 | 15 |
#define SETUP_BLOB(v) \ |
16 | 16 |
SQBlob *self = NULL; \ |
17 |
- { if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) \ |
|
17 |
+ { if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_BLOB_TYPE_TAG,SQFalse))) \ |
|
18 | 18 |
return sq_throwerror(v,_SC("invalid type tag")); } \ |
19 | 19 |
if(!self || !self->IsValid()) \ |
20 | 20 |
return sq_throwerror(v,_SC("the blob is invalid")); |
... | ... |
@@ -152,7 +152,7 @@ static SQInteger _blob__cloned(HSQUIRRELVM v) |
152 | 152 |
{ |
153 | 153 |
SQBlob *other = NULL; |
154 | 154 |
{ |
155 |
- if(SQ_FAILED(sq_getinstanceup(v,2,(SQUserPointer*)&other,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) |
|
155 |
+ if(SQ_FAILED(sq_getinstanceup(v,2,(SQUserPointer*)&other,(SQUserPointer)SQSTD_BLOB_TYPE_TAG,SQFalse))) |
|
156 | 156 |
return SQ_ERROR; |
157 | 157 |
} |
158 | 158 |
//SQBlob *thisone = new SQBlob(other->Len()); |
... | ... |
@@ -205,8 +205,8 @@ static SQInteger _g_blob_swap2(HSQUIRRELVM v) |
205 | 205 |
{ |
206 | 206 |
SQInteger i; |
207 | 207 |
sq_getinteger(v,2,&i); |
208 |
- short s=(short)i; |
|
209 |
- sq_pushinteger(v,(s<<8)|((s>>8)&0x00FF)); |
|
208 |
+ unsigned short s = (unsigned short)i; |
|
209 |
+ sq_pushinteger(v, ((s << 8) | ((s >> 8) & 0x00FFu)) & 0xFFFFu); |
|
210 | 210 |
return 1; |
211 | 211 |
} |
212 | 212 |
|
... | ... |
@@ -242,7 +242,7 @@ static const SQRegFunction bloblib_funcs[]={ |
242 | 242 |
SQRESULT sqstd_getblob(HSQUIRRELVM v,SQInteger idx,SQUserPointer *ptr) |
243 | 243 |
{ |
244 | 244 |
SQBlob *blob; |
245 |
- if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) |
|
245 |
+ if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG,SQTrue))) |
|
246 | 246 |
return -1; |
247 | 247 |
*ptr = blob->GetBuf(); |
248 | 248 |
return SQ_OK; |
... | ... |
@@ -251,7 +251,7 @@ SQRESULT sqstd_getblob(HSQUIRRELVM v,SQInteger idx,SQUserPointer *ptr) |
251 | 251 |
SQInteger sqstd_getblobsize(HSQUIRRELVM v,SQInteger idx) |
252 | 252 |
{ |
253 | 253 |
SQBlob *blob; |
254 |
- if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) |
|
254 |
+ if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG,SQTrue))) |
|
255 | 255 |
return -1; |
256 | 256 |
return blob->Len(); |
257 | 257 |
} |
... | ... |
@@ -267,7 +267,7 @@ SQUserPointer sqstd_createblob(HSQUIRRELVM v, SQInteger size) |
267 | 267 |
sq_pushinteger(v,size); //size |
268 | 268 |
SQBlob *blob = NULL; |
269 | 269 |
if(SQ_SUCCEEDED(sq_call(v,2,SQTrue,SQFalse)) |
270 |
- && SQ_SUCCEEDED(sq_getinstanceup(v,-1,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) { |
|
270 |
+ && SQ_SUCCEEDED(sq_getinstanceup(v,-1,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG,SQTrue))) { |
|
271 | 271 |
sq_remove(v,-2); |
272 | 272 |
return blob->GetBuf(); |
273 | 273 |
} |
... | ... |
@@ -154,7 +154,7 @@ static SQInteger _file_constructor(HSQUIRRELVM v) |
154 | 154 |
static SQInteger _file_close(HSQUIRRELVM v) |
155 | 155 |
{ |
156 | 156 |
SQFile *self = NULL; |
157 |
- if(SQ_SUCCEEDED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_FILE_TYPE_TAG)) |
|
157 |
+ if(SQ_SUCCEEDED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_FILE_TYPE_TAG, SQTrue)) |
|
158 | 158 |
&& self != NULL) |
159 | 159 |
{ |
160 | 160 |
self->Close(); |
... | ... |
@@ -200,7 +200,7 @@ SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own) |
200 | 200 |
SQRESULT sqstd_getfile(HSQUIRRELVM v, SQInteger idx, SQFILE *file) |
201 | 201 |
{ |
202 | 202 |
SQFile *fileobj = NULL; |
203 |
- if(SQ_SUCCEEDED(sq_getinstanceup(v,idx,(SQUserPointer*)&fileobj,(SQUserPointer)SQSTD_FILE_TYPE_TAG))) { |
|
203 |
+ if(SQ_SUCCEEDED(sq_getinstanceup(v,idx,(SQUserPointer*)&fileobj,(SQUserPointer)SQSTD_FILE_TYPE_TAG,SQFalse))) { |
|
204 | 204 |
*file = fileobj->GetHandle(); |
205 | 205 |
return SQ_OK; |
206 | 206 |
} |
... | ... |
@@ -11,7 +11,7 @@ |
11 | 11 |
|
12 | 12 |
#define SETUP_STREAM(v) \ |
13 | 13 |
SQStream *self = NULL; \ |
14 |
- if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)((SQUnsignedInteger)SQSTD_STREAM_TYPE_TAG)))) \ |
|
14 |
+ if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)((SQUnsignedInteger)SQSTD_STREAM_TYPE_TAG),SQFalse))) \ |
|
15 | 15 |
return sq_throwerror(v,_SC("invalid type tag")); \ |
16 | 16 |
if(!self || !self->IsValid()) \ |
17 | 17 |
return sq_throwerror(v,_SC("the stream is invalid")); |
... | ... |
@@ -12,6 +12,8 @@ |
12 | 12 |
#define MAX_WFORMAT_LEN 3 |
13 | 13 |
#define ADDITIONAL_FORMAT_SPACE (100*sizeof(SQChar)) |
14 | 14 |
|
15 |
+static SQUserPointer rex_typetag = NULL; |
|
16 |
+ |
|
15 | 17 |
static SQBool isfmtchr(SQChar ch) |
16 | 18 |
{ |
17 | 19 |
switch(ch) { |
... | ... |
@@ -247,16 +249,16 @@ static SQInteger _string_rstrip(HSQUIRRELVM v) |
247 | 249 |
static SQInteger _string_split(HSQUIRRELVM v) |
248 | 250 |
{ |
249 | 251 |
const SQChar *str,*seps; |
250 |
- SQChar *stemp; |
|
252 |
+ SQInteger sepsize; |
|
253 |
+ SQBool skipempty = SQFalse; |
|
251 | 254 |
sq_getstring(v,2,&str); |
252 |
- sq_getstring(v,3,&seps); |
|
253 |
- SQInteger sepsize = sq_getsize(v,3); |
|
255 |
+ sq_getstringandsize(v,3,&seps,&sepsize); |
|
254 | 256 |
if(sepsize == 0) return sq_throwerror(v,_SC("empty separators string")); |
255 |
- SQInteger memsize = (sq_getsize(v,2)+1)*sizeof(SQChar); |
|
256 |
- stemp = sq_getscratchpad(v,memsize); |
|
257 |
- memcpy(stemp,str,memsize); |
|
258 |
- SQChar *start = stemp; |
|
259 |
- SQChar *end = stemp; |
|
257 |
+ if(sq_gettop(v)>3) { |
|
258 |
+ sq_getbool(v,4,&skipempty); |
|
259 |
+ } |
|
260 |
+ const SQChar *start = str; |
|
261 |
+ const SQChar *end = str; |
|
260 | 262 |
sq_newarray(v,0); |
261 | 263 |
while(*end != '\0') |
262 | 264 |
{ |
... | ... |
@@ -265,9 +267,10 @@ static SQInteger _string_split(HSQUIRRELVM v) |
265 | 267 |
{ |
266 | 268 |
if(cur == seps[i]) |
267 | 269 |
{ |
268 |
- *end = 0; |
|
269 |
- sq_pushstring(v,start,-1); |
|
270 |
- sq_arrayappend(v,-2); |
|
270 |
+ if(!skipempty || (end != start)) { |
|
271 |
+ sq_pushstring(v,start,end-start); |
|
272 |
+ sq_arrayappend(v,-2); |
|
273 |
+ } |
|
271 | 274 |
start = end + 1; |
272 | 275 |
break; |
273 | 276 |
} |
... | ... |
@@ -276,7 +279,7 @@ static SQInteger _string_split(HSQUIRRELVM v) |
276 | 279 |
} |
277 | 280 |
if(end != start) |
278 | 281 |
{ |
279 |
- sq_pushstring(v,start,-1); |
|
282 |
+ sq_pushstring(v,start,end-start); |
|
280 | 283 |
sq_arrayappend(v,-2); |
281 | 284 |
} |
282 | 285 |
return 1; |
... | ... |
@@ -384,7 +387,9 @@ static SQInteger _string_endswith(HSQUIRRELVM v) |
384 | 387 |
|
385 | 388 |
#define SETUP_REX(v) \ |
386 | 389 |
SQRex *self = NULL; \ |
387 |
- sq_getinstanceup(v,1,(SQUserPointer *)&self,0); |
|
390 |
+ if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer *)&self,rex_typetag,SQFalse))) { \ |
|
391 |
+ return sq_throwerror(v,_SC("invalid type tag")); \ |
|
392 |
+ } |
|
388 | 393 |
|
389 | 394 |
static SQInteger _rexobj_releasehook(SQUserPointer p, SQInteger SQ_UNUSED_ARG(size)) |
390 | 395 |
{ |
... | ... |
@@ -465,6 +470,13 @@ static SQInteger _regexp_subexpcount(HSQUIRRELVM v) |
465 | 470 |
|
466 | 471 |
static SQInteger _regexp_constructor(HSQUIRRELVM v) |
467 | 472 |
{ |
473 |
+ SQRex *self = NULL; |
|
474 |
+ if (SQ_FAILED(sq_getinstanceup(v, 1, (SQUserPointer *)&self, rex_typetag, SQFalse))) { |
|
475 |
+ return sq_throwerror(v, _SC("invalid type tag")); |
|
476 |
+ } |
|
477 |
+ if (self != NULL) { |
|
478 |
+ return sq_throwerror(v, _SC("invalid regexp object")); |
|
479 |
+ } |
|
468 | 480 |
const SQChar *error,*pattern; |
469 | 481 |
sq_getstring(v,2,&pattern); |
470 | 482 |
SQRex *rex = sqstd_rex_compile(pattern,&error); |
... | ... |
@@ -499,7 +511,7 @@ static const SQRegFunction stringlib_funcs[]={ |
499 | 511 |
_DECL_FUNC(strip,2,_SC(".s")), |
500 | 512 |
_DECL_FUNC(lstrip,2,_SC(".s")), |
501 | 513 |
_DECL_FUNC(rstrip,2,_SC(".s")), |
502 |
- _DECL_FUNC(split,3,_SC(".ss")), |
|
514 |
+ _DECL_FUNC(split,-3,_SC(".ssb")), |
|
503 | 515 |
_DECL_FUNC(escape,2,_SC(".s")), |
504 | 516 |
_DECL_FUNC(startswith,3,_SC(".ss")), |
505 | 517 |
_DECL_FUNC(endswith,3,_SC(".ss")), |
... | ... |
@@ -512,6 +524,8 @@ SQInteger sqstd_register_stringlib(HSQUIRRELVM v) |
512 | 524 |
{ |
513 | 525 |
sq_pushstring(v,_SC("regexp"),-1); |
514 | 526 |
sq_newclass(v,SQFalse); |
527 |
+ rex_typetag = (SQUserPointer)rexobj_funcs; |
|
528 |
+ sq_settypetag(v, -1, rex_typetag); |
|
515 | 529 |
SQInteger i = 0; |
516 | 530 |
while(rexobj_funcs[i].name != 0) { |
517 | 531 |
const SQRegFunction &f = rexobj_funcs[i]; |
... | ... |
@@ -807,21 +807,21 @@ SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize) |
807 | 807 |
} |
808 | 808 |
|
809 | 809 |
|
810 |
-SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag) |
|
811 |
-{ |
|
812 |
- SQObjectPtr &o = stack_get(v,idx); |
|
813 |
- if(sq_type(o) != OT_INSTANCE) return sq_throwerror(v,_SC("the object is not a class instance")); |
|
814 |
- (*p) = _instance(o)->_userpointer; |
|
815 |
- if(typetag != 0) { |
|
816 |
- SQClass *cl = _instance(o)->_class; |
|
817 |
- do{ |
|
818 |
- if(cl->_typetag == typetag) |
|
819 |
- return SQ_OK; |
|
820 |
- cl = cl->_base; |
|
821 |
- }while(cl != NULL); |
|
822 |
- return sq_throwerror(v,_SC("invalid type tag")); |
|
823 |
- } |
|
824 |
- return SQ_OK; |
|
810 |
+SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p, SQUserPointer typetag, SQBool throwerror) |
|
811 |
+{ |
|
812 |
+ SQObjectPtr &o = stack_get(v, idx); |
|
813 |
+ if (sq_type(o) != OT_INSTANCE) return throwerror ? sq_throwerror(v, _SC("the object is not a class instance")) : SQ_ERROR; |
|
814 |
+ (*p) = _instance(o)->_userpointer; |
|
815 |
+ if (typetag != 0) { |
|
816 |
+ SQClass *cl = _instance(o)->_class; |
|
817 |
+ do { |
|
818 |
+ if (cl->_typetag == typetag) |
|
819 |
+ return SQ_OK; |
|
820 |
+ cl = cl->_base; |
|
821 |
+ } while (cl != NULL); |
|
822 |
+ return throwerror ? sq_throwerror(v, _SC("invalid type tag")) : SQ_ERROR; |
|
823 |
+ } |
|
824 |
+ return SQ_OK; |
|
825 | 825 |
} |
826 | 826 |
|
827 | 827 |
SQInteger sq_gettop(HSQUIRRELVM v) |
... | ... |
@@ -499,6 +499,32 @@ static SQInteger table_filter(HSQUIRRELVM v) |
499 | 499 |
return 1; |
500 | 500 |
} |
501 | 501 |
|
502 |
+static SQInteger table_map(HSQUIRRELVM v) |
|
503 |
+{ |
|
504 |
+ SQObject &o = stack_get(v, 1); |
|
505 |
+ SQTable *tbl = _table(o); |
|
506 |
+ SQInteger nitr, n = 0; |
|
507 |
+ SQInteger nitems = tbl->CountUsed(); |
|
508 |
+ SQObjectPtr ret = SQArray::Create(_ss(v), nitems); |
|
509 |
+ SQObjectPtr itr, key, val; |
|
510 |
+ while ((nitr = tbl->Next(false, itr, key, val)) != -1) { |
|
511 |
+ itr = (SQInteger)nitr; |
|
512 |
+ |
|
513 |
+ v->Push(o); |
|
514 |
+ v->Push(key); |
|
515 |
+ v->Push(val); |
|
516 |
+ if (SQ_FAILED(sq_call(v, 3, SQTrue, SQFalse))) { |
|
517 |
+ return SQ_ERROR; |
|
518 |
+ } |
|
519 |
+ _array(ret)->Set(n, v->GetUp(-1)); |
|
520 |
+ v->Pop(); |
|
521 |
+ n++; |
|
522 |
+ } |
|
523 |
+ |
|
524 |
+ v->Push(ret); |
|
525 |
+ return 1; |
|
526 |
+} |
|
527 |
+ |
|
502 | 528 |
#define TABLE_TO_ARRAY_FUNC(_funcname_,_valname_) static SQInteger _funcname_(HSQUIRRELVM v) \ |
503 | 529 |
{ \ |
504 | 530 |
SQObject &o = stack_get(v, 1); \ |
... | ... |
@@ -536,6 +562,7 @@ const SQRegFunction SQSharedState::_table_default_delegate_funcz[]={ |
536 | 562 |
{_SC("setdelegate"),table_setdelegate,2, _SC(".t|o")}, |
537 | 563 |
{_SC("getdelegate"),table_getdelegate,1, _SC(".")}, |
538 | 564 |
{_SC("filter"),table_filter,2, _SC("tc")}, |
565 |
+ {_SC("map"),table_map,2, _SC("tc") }, |
|
539 | 566 |
{_SC("keys"),table_keys,1, _SC("t") }, |
540 | 567 |
{_SC("values"),table_values,1, _SC("t") }, |
541 | 568 |
{NULL,(SQFUNCTION)0,0,NULL} |
... | ... |
@@ -754,7 +781,7 @@ static SQInteger array_find(HSQUIRRELVM v) |
754 | 781 |
} |
755 | 782 |
|
756 | 783 |
|
757 |
-static bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret) |
|
784 |
+static bool _sort_compare(HSQUIRRELVM v, SQArray *arr, SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret) |
|
758 | 785 |
{ |
759 | 786 |
if(func < 0) { |
760 | 787 |
if(!v->ObjCmp(a,b,ret)) return false; |
... | ... |
@@ -765,15 +792,21 @@ static bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger |
765 | 792 |
sq_pushroottable(v); |
766 | 793 |
v->Push(a); |
767 | 794 |
v->Push(b); |
795 |
+ SQObjectPtr *valptr = arr->_values._vals; |
|
796 |
+ SQUnsignedInteger precallsize = arr->_values.size(); |
|
768 | 797 |
if(SQ_FAILED(sq_call(v, 3, SQTrue, SQFalse))) { |
769 | 798 |
if(!sq_isstring( v->_lasterror)) |
770 | 799 |
v->Raise_Error(_SC("compare func failed")); |
771 | 800 |
return false; |
772 | 801 |
} |
773 |
- if(SQ_FAILED(sq_getinteger(v, -1, &ret))) { |
|
802 |
+ if(SQ_FAILED(sq_getinteger(v, -1, &ret))) { |
|
774 | 803 |
v->Raise_Error(_SC("numeric value expected as return value of the compare function")); |
775 | 804 |
return false; |
776 | 805 |
} |
806 |
+ if (precallsize != arr->_values.size() || valptr != arr->_values._vals) { |
|
807 |
+ v->Raise_Error(_SC("array resized during sort operation")); |
|
808 |
+ return false; |
|
809 |
+ } |
|
777 | 810 |
sq_settop(v, top); |
778 | 811 |
return true; |
779 | 812 |
} |
... | ... |
@@ -792,7 +825,7 @@ static bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteg |
792 | 825 |
maxChild = root2; |
793 | 826 |
} |
794 | 827 |
else { |
795 |
- if(!_sort_compare(v,arr->_values[root2],arr->_values[root2 + 1],func,ret)) |
|
828 |
+ if(!_sort_compare(v,arr,arr->_values[root2],arr->_values[root2 + 1],func,ret)) |
|
796 | 829 |
return false; |
797 | 830 |
if (ret > 0) { |
798 | 831 |
maxChild = root2; |
... | ... |
@@ -802,7 +835,7 @@ static bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteg |
802 | 835 |
} |
803 | 836 |
} |
804 | 837 |
|
805 |
- if(!_sort_compare(v,arr->_values[root],arr->_values[maxChild],func,ret)) |
|
838 |
+ if(!_sort_compare(v,arr,arr->_values[root],arr->_values[maxChild],func,ret)) |
|
806 | 839 |
return false; |
807 | 840 |
if (ret < 0) { |
808 | 841 |
if (root == maxChild) { |
... | ... |
@@ -1116,6 +1149,7 @@ static SQInteger thread_call(HSQUIRRELVM v) |
1116 | 1149 |
SQObjectPtr o = stack_get(v,1); |
1117 | 1150 |
if(sq_type(o) == OT_THREAD) { |
1118 | 1151 |
SQInteger nparams = sq_gettop(v); |
1152 |
+ sq_reservestack(_thread(o), nparams + 3); |
|
1119 | 1153 |
_thread(o)->Push(_thread(o)->_roottable); |
1120 | 1154 |
for(SQInteger i = 2; i<(nparams+1); i++) |
1121 | 1155 |
sq_move(_thread(o),v,i); |
... | ... |
@@ -61,6 +61,9 @@ bool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr |
61 | 61 |
_defaultvalues[_member_idx(temp)].val = val; |
62 | 62 |
return true; |
63 | 63 |
} |
64 |
+ if (_members->CountUsed() >= MEMBER_MAX_COUNT) { |
|
65 |
+ return false; |
|
66 |
+ } |
|
64 | 67 |
if(belongs_to_static_table) { |
65 | 68 |
SQInteger mmidx; |
66 | 69 |
if((sq_type(val) == OT_CLOSURE || sq_type(val) == OT_NATIVECLOSURE) && |
... | ... |
@@ -17,6 +17,7 @@ typedef sqvector<SQClassMember> SQClassMemberVec; |
17 | 17 |
|
18 | 18 |
#define MEMBER_TYPE_METHOD 0x01000000 |
19 | 19 |
#define MEMBER_TYPE_FIELD 0x02000000 |
20 |
+#define MEMBER_MAX_COUNT 0x00FFFFFF |
|
20 | 21 |
|
21 | 22 |
#define _ismethod(o) (_integer(o)&MEMBER_TYPE_METHOD) |
22 | 23 |
#define _isfield(o) (_integer(o)&MEMBER_TYPE_FIELD) |
... | ... |
@@ -842,8 +842,8 @@ public: |
842 | 842 |
_fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); |
843 | 843 |
Lex();ParseTableOrClass(_SC(','),_SC('}')); |
844 | 844 |
break; |
845 |
- case TK_FUNCTION: FunctionExp(_token);break; |
|
846 |
- case _SC('@'): FunctionExp(_token,true);break; |
|
845 |
+ case TK_FUNCTION: FunctionExp();break; |
|
846 |
+ case _SC('@'): FunctionExp(true);break; |
|
847 | 847 |
case TK_CLASS: Lex(); ClassExp();break; |
848 | 848 |
case _SC('-'): |
849 | 849 |
Lex(); |
... | ... |
@@ -989,10 +989,15 @@ public: |
989 | 989 |
SQInteger tk = _token; |
990 | 990 |
Lex(); |
991 | 991 |
SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor")); |
992 |
+ _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); |
|
993 |
+ SQInteger boundtarget = 0xFF; |
|
994 |
+ if (_token == _SC('[')) { |
|
995 |
+ boundtarget = ParseBindEnv(); |
|
996 |
+ } |
|
992 | 997 |
Expect(_SC('(')); |
993 |
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); |
|
994 |
- CreateFunction(id); |
|
995 |
- _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); |
|
998 |
+ |
|
999 |
+ CreateFunction(id, boundtarget); |
|
1000 |
+ _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, boundtarget); |
|
996 | 1001 |
} |
997 | 1002 |
break; |
998 | 1003 |
case _SC('['): |
... | ... |
@@ -1034,11 +1039,15 @@ public: |
1034 | 1039 |
SQObject varname; |
1035 | 1040 |
Lex(); |
1036 | 1041 |
if( _token == TK_FUNCTION) { |
1042 |
+ SQInteger boundtarget = 0xFF; |
|
1037 | 1043 |
Lex(); |
1038 |
- varname = Expect(TK_IDENTIFIER); |
|
1044 |
+ varname = Expect(TK_IDENTIFIER); |
|
1045 |
+ if (_token == _SC('[')) { |
|
1046 |
+ boundtarget = ParseBindEnv(); |
|
1047 |
+ } |
|
1039 | 1048 |
Expect(_SC('(')); |
1040 |
- CreateFunction(varname,false); |
|
1041 |
- _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); |
|
1049 |
+ CreateFunction(varname,0xFF,false); |
|
1050 |
+ _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, boundtarget); |
|
1042 | 1051 |
_fs->PopTarget(); |
1043 | 1052 |
_fs->PushLocalVariable(varname); |
1044 | 1053 |
return; |
... | ... |
@@ -1310,9 +1319,13 @@ public: |
1310 | 1319 |
_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); |
1311 | 1320 |
if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET); |
1312 | 1321 |
} |
1322 |
+ SQInteger boundtarget = 0xFF; |
|
1323 |
+ if (_token == _SC('[')) { |
|
1324 |
+ boundtarget = ParseBindEnv(); |
|
1325 |
+ } |
|
1313 | 1326 |
Expect(_SC('(')); |
1314 |
- CreateFunction(id); |
|
1315 |
- _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); |
|
1327 |
+ CreateFunction(id, boundtarget); |
|
1328 |
+ _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, boundtarget); |
|
1316 | 1329 |
EmitDerefOp(_OP_NEWSLOT); |
1317 | 1330 |
_fs->PopTarget(); |
1318 | 1331 |
} |
... | ... |
@@ -1438,12 +1451,26 @@ public: |
1438 | 1451 |
END_SCOPE(); |
1439 | 1452 |
} |
1440 | 1453 |
} |
1441 |
- void FunctionExp(SQInteger ftype,bool lambda = false) |
|
1454 |
+ SQInteger ParseBindEnv() |
|
1455 |
+ { |
|
1456 |
+ SQInteger boundtarget; |
|
1457 |
+ Lex(); |
|
1458 |
+ Expression(); |
|
1459 |
+ boundtarget = _fs->TopTarget(); |
|
1460 |
+ Expect(_SC(']')); |
|
1461 |
+ return boundtarget; |
|
1462 |
+ } |
|
1463 |
+ void FunctionExp(bool lambda = false) |
|
1442 | 1464 |
{ |
1443 |
- Lex(); Expect(_SC('(')); |
|
1465 |
+ Lex(); |
|
1466 |
+ SQInteger boundtarget = 0xFF; |
|
1467 |
+ if (_token == _SC('[')) { |
|
1468 |
+ boundtarget = ParseBindEnv(); |
|
1469 |
+ } |
|
1470 |
+ Expect(_SC('(')); |
|
1444 | 1471 |
SQObjectPtr dummy; |
1445 |
- CreateFunction(dummy,lambda); |
|
1446 |
- _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1); |
|
1472 |
+ CreateFunction(dummy, boundtarget, lambda); |
|
1473 |
+ _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, boundtarget); |
|
1447 | 1474 |
} |
1448 | 1475 |
void ClassExp() |
1449 | 1476 |
{ |
... | ... |
@@ -1508,7 +1535,7 @@ public: |
1508 | 1535 |
} |
1509 | 1536 |
_es = es; |
1510 | 1537 |
} |
1511 |
- void CreateFunction(SQObject &name,bool lambda = false) |
|
1538 |
+ void CreateFunction(SQObject &name,SQInteger boundtarget,bool lambda = false) |
|
1512 | 1539 |
{ |
1513 | 1540 |
SQFuncState *funcstate = _fs->PushChildState(_ss(_vm)); |
1514 | 1541 |
funcstate->_name = name; |
... | ... |
@@ -1542,6 +1569,9 @@ public: |
1542 | 1569 |
} |
1543 | 1570 |
} |
1544 | 1571 |
Expect(_SC(')')); |
1572 |
+ if (boundtarget != 0xFF) { |
|
1573 |
+ _fs->PopTarget(); |
|
1574 |
+ } |
|
1545 | 1575 |
for(SQInteger n = 0; n < defparams; n++) { |
1546 | 1576 |
_fs->PopTarget(); |
1547 | 1577 |
} |
... | ... |
@@ -4,11 +4,12 @@ |
4 | 4 |
|
5 | 5 |
inline SQHash _hashstr (const SQChar *s, size_t l) |
6 | 6 |
{ |
7 |
- SQHash h = (SQHash)l; /* seed */ |
|
8 |
- size_t step = (l>>5)|1; /* if string is too long, don't hash all its chars */ |
|
9 |
- for (; l>=step; l-=step) |
|
10 |
- h = h ^ ((h<<5)+(h>>2)+(unsigned short)*(s++)); |
|
11 |
- return h; |
|
7 |
+ SQHash h = (SQHash)l; /* seed */ |
|
8 |
+ size_t step = (l >> 5) + 1; /* if string is too long, don't hash all its chars */ |
|
9 |
+ size_t l1; |
|
10 |
+ for (l1 = l; l1 >= step; l1 -= step) |
|
11 |
+ h = h ^ ((h << 5) + (h >> 2) + ((unsigned short)s[l1 - 1])); |
|
12 |
+ return h; |
|
12 | 13 |
} |
13 | 14 |
|
14 | 15 |
struct SQString : public SQRefCounted |
... | ... |
@@ -586,7 +586,7 @@ bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr |
586 | 586 |
|
587 | 587 |
#define _GUARD(exp) { if(!exp) { SQ_THROW();} } |
588 | 588 |
|
589 |
-bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func) |
|
589 |
+bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func,SQInteger boundtarget) |
|
590 | 590 |
{ |
591 | 591 |
SQInteger nouters; |
592 | 592 |
SQClosure *closure = SQClosure::Create(_ss(this), func,_table(_roottable)->GetWeakRef(OT_TABLE)); |
... | ... |
@@ -610,6 +610,19 @@ bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func) |
610 | 610 |
closure->_defaultparams[i] = _stack._vals[_stackbase + spos]; |
611 | 611 |
} |
612 | 612 |
} |
613 |
+ if (boundtarget != 0xFF) { |
|
614 |
+ SQObjectPtr &val = _stack._vals[_stackbase + boundtarget]; |
|
615 |
+ SQObjectType t = sq_type(val); |
|
616 |
+ if (t == OT_TABLE || t == OT_CLASS || t == OT_INSTANCE || t == OT_ARRAY) { |
|
617 |
+ closure->_env = _refcounted(val)->GetWeakRef(t); |
|
618 |
+ __ObjAddRef(closure->_env); |
|
619 |
+ } |
|
620 |
+ else { |
|
621 |
+ Raise_Error(_SC("cannot bind a %s as environment object"), IdType2Name(t)); |
|
622 |
+ closure->Release(); |
|
623 |
+ return false; |
|
624 |
+ } |
|
625 |
+ } |
|
613 | 626 |
target = closure; |
614 | 627 |
return true; |
615 | 628 |
|
... | ... |
@@ -1003,7 +1016,7 @@ exception_restore: |
1003 | 1016 |
case _OP_CLOSURE: { |
1004 | 1017 |
SQClosure *c = ci->_closure._unVal.pClosure; |
1005 | 1018 |
SQFunctionProto *fp = c->_function; |
1006 |
- if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); } |
|
1019 |
+ if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto,arg2)) { SQ_THROW(); } |
|
1007 | 1020 |
continue; |
1008 | 1021 |
} |
1009 | 1022 |
case _OP_YIELD:{ |
... | ... |
@@ -1323,7 +1336,7 @@ SQInteger SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObj |
1323 | 1336 |
case OT_USERDATA: |
1324 | 1337 |
//delegation |
1325 | 1338 |
if(_delegable(self)->_delegate) { |
1326 |
- if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,0,DONT_FALL_BACK)) return FALLBACK_OK; |
|
1339 |
+ if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest, GET_FLAG_DO_NOT_RAISE_ERROR,DONT_FALL_BACK)) return FALLBACK_OK; |
|
1327 | 1340 |
} |
1328 | 1341 |
else { |
1329 | 1342 |
return FALLBACK_NO_MATCH; |
... | ... |
@@ -103,7 +103,7 @@ public: |
103 | 103 |
_INLINE bool BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); |
104 | 104 |
_INLINE bool NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o1); |
105 | 105 |
_INLINE bool CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res); |
106 |
- bool CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func); |
|
106 |
+ bool CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func, SQInteger boundtarget); |
|
107 | 107 |
bool CLASS_OP(SQObjectPtr &target,SQInteger base,SQInteger attrs); |
108 | 108 |
//return true if the loop is finished |
109 | 109 |
bool FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump); |