Browse code

app_squirrel: updated squirrel interpreter to latest git version (3.2+)

Daniel-Constantin Mierla authored on 08/05/2022 19:35:07
Showing 14 changed files
... ...
@@ -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
... ...
@@ -12,7 +12,7 @@
12 12
 
13 13
 #define hashptr(p)  ((SQHash)(((SQInteger)p) >> 3))
14 14
 
15
-inline SQHash HashObj(const SQObjectPtr &key)
15
+inline SQHash HashObj(const SQObject &key)
16 16
 {
17 17
     switch(sq_type(key)) {
18 18
         case OT_STRING:     return _string(key)->_hash;
... ...
@@ -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);