瀏覽代碼

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

(cherry picked from commit c5da175fd79ecd17752bb2fd8af2b5a65739e58e)
Daniel-Constantin Mierla 3 年之前
父節點
當前提交
150a66f51a

+ 5 - 5
src/modules/app_sqlang/squirrel/include/squirrel.h

@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2003-2017 Alberto Demichelis
+Copyright (c) 2003-2022 Alberto Demichelis
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -65,10 +65,10 @@ struct SQOuter;
 
 #include "sqconfig.h"
 
-#define SQUIRREL_VERSION    _SC("Squirrel 3.1 stable")
-#define SQUIRREL_COPYRIGHT  _SC("Copyright (C) 2003-2017 Alberto Demichelis")
+#define SQUIRREL_VERSION    _SC("Squirrel 3.2 stable")
+#define SQUIRREL_COPYRIGHT  _SC("Copyright (C) 2003-2022 Alberto Demichelis")
 #define SQUIRREL_AUTHOR     _SC("Alberto Demichelis")
-#define SQUIRREL_VERSION_NUMBER 310
+#define SQUIRREL_VERSION_NUMBER 320
 
 #define SQ_VMSTATE_IDLE         0
 #define SQ_VMSTATE_RUNNING      1
@@ -280,7 +280,7 @@ SQUIRREL_API SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQInteger *n
 SQUIRREL_API SQRESULT sq_getclosurename(HSQUIRRELVM v,SQInteger idx);
 SQUIRREL_API SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name);
 SQUIRREL_API SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p);
-SQUIRREL_API SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag);
+SQUIRREL_API SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag,SQBool throwerror);
 SQUIRREL_API SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize);
 SQUIRREL_API SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase);
 SQUIRREL_API SQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx);

+ 7 - 7
src/modules/app_sqlang/squirrel/sqstdlib/sqstdblob.cpp

@@ -14,7 +14,7 @@
 
 #define SETUP_BLOB(v) \
     SQBlob *self = NULL; \
-    { if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) \
+    { if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_BLOB_TYPE_TAG,SQFalse))) \
         return sq_throwerror(v,_SC("invalid type tag"));  } \
     if(!self || !self->IsValid())  \
         return sq_throwerror(v,_SC("the blob is invalid"));
@@ -152,7 +152,7 @@ static SQInteger _blob__cloned(HSQUIRRELVM v)
 {
     SQBlob *other = NULL;
     {
-        if(SQ_FAILED(sq_getinstanceup(v,2,(SQUserPointer*)&other,(SQUserPointer)SQSTD_BLOB_TYPE_TAG)))
+        if(SQ_FAILED(sq_getinstanceup(v,2,(SQUserPointer*)&other,(SQUserPointer)SQSTD_BLOB_TYPE_TAG,SQFalse)))
             return SQ_ERROR;
     }
     //SQBlob *thisone = new SQBlob(other->Len());
@@ -205,8 +205,8 @@ static SQInteger _g_blob_swap2(HSQUIRRELVM v)
 {
     SQInteger i;
     sq_getinteger(v,2,&i);
-    short s=(short)i;
-    sq_pushinteger(v,(s<<8)|((s>>8)&0x00FF));
+    unsigned short s = (unsigned short)i;
+    sq_pushinteger(v, ((s << 8) | ((s >> 8) & 0x00FFu)) & 0xFFFFu);
     return 1;
 }
 
@@ -242,7 +242,7 @@ static const SQRegFunction bloblib_funcs[]={
 SQRESULT sqstd_getblob(HSQUIRRELVM v,SQInteger idx,SQUserPointer *ptr)
 {
     SQBlob *blob;
-    if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG)))
+    if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG,SQTrue)))
         return -1;
     *ptr = blob->GetBuf();
     return SQ_OK;
@@ -251,7 +251,7 @@ SQRESULT sqstd_getblob(HSQUIRRELVM v,SQInteger idx,SQUserPointer *ptr)
 SQInteger sqstd_getblobsize(HSQUIRRELVM v,SQInteger idx)
 {
     SQBlob *blob;
-    if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG)))
+    if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG,SQTrue)))
         return -1;
     return blob->Len();
 }
@@ -267,7 +267,7 @@ SQUserPointer sqstd_createblob(HSQUIRRELVM v, SQInteger size)
         sq_pushinteger(v,size); //size
         SQBlob *blob = NULL;
         if(SQ_SUCCEEDED(sq_call(v,2,SQTrue,SQFalse))
-            && SQ_SUCCEEDED(sq_getinstanceup(v,-1,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) {
+            && SQ_SUCCEEDED(sq_getinstanceup(v,-1,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG,SQTrue))) {
             sq_remove(v,-2);
             return blob->GetBuf();
         }

+ 2 - 2
src/modules/app_sqlang/squirrel/sqstdlib/sqstdio.cpp

@@ -154,7 +154,7 @@ static SQInteger _file_constructor(HSQUIRRELVM v)
 static SQInteger _file_close(HSQUIRRELVM v)
 {
     SQFile *self = NULL;
-    if(SQ_SUCCEEDED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_FILE_TYPE_TAG))
+    if(SQ_SUCCEEDED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_FILE_TYPE_TAG, SQTrue))
         && self != NULL)
     {
         self->Close();
@@ -200,7 +200,7 @@ SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own)
 SQRESULT sqstd_getfile(HSQUIRRELVM v, SQInteger idx, SQFILE *file)
 {
     SQFile *fileobj = NULL;
-    if(SQ_SUCCEEDED(sq_getinstanceup(v,idx,(SQUserPointer*)&fileobj,(SQUserPointer)SQSTD_FILE_TYPE_TAG))) {
+    if(SQ_SUCCEEDED(sq_getinstanceup(v,idx,(SQUserPointer*)&fileobj,(SQUserPointer)SQSTD_FILE_TYPE_TAG,SQFalse))) {
         *file = fileobj->GetHandle();
         return SQ_OK;
     }

+ 1 - 1
src/modules/app_sqlang/squirrel/sqstdlib/sqstdstream.cpp

@@ -11,7 +11,7 @@
 
 #define SETUP_STREAM(v) \
     SQStream *self = NULL; \
-    if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)((SQUnsignedInteger)SQSTD_STREAM_TYPE_TAG)))) \
+    if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)((SQUnsignedInteger)SQSTD_STREAM_TYPE_TAG),SQFalse))) \
         return sq_throwerror(v,_SC("invalid type tag")); \
     if(!self || !self->IsValid())  \
         return sq_throwerror(v,_SC("the stream is invalid"));

+ 28 - 14
src/modules/app_sqlang/squirrel/sqstdlib/sqstdstring.cpp

@@ -12,6 +12,8 @@
 #define MAX_WFORMAT_LEN 3
 #define ADDITIONAL_FORMAT_SPACE (100*sizeof(SQChar))
 
+static SQUserPointer rex_typetag = NULL;
+
 static SQBool isfmtchr(SQChar ch)
 {
     switch(ch) {
@@ -247,16 +249,16 @@ static SQInteger _string_rstrip(HSQUIRRELVM v)
 static SQInteger _string_split(HSQUIRRELVM v)
 {
     const SQChar *str,*seps;
-    SQChar *stemp;
+    SQInteger sepsize;
+    SQBool skipempty = SQFalse;
     sq_getstring(v,2,&str);
-    sq_getstring(v,3,&seps);
-    SQInteger sepsize = sq_getsize(v,3);
+    sq_getstringandsize(v,3,&seps,&sepsize);
     if(sepsize == 0) return sq_throwerror(v,_SC("empty separators string"));
-    SQInteger memsize = (sq_getsize(v,2)+1)*sizeof(SQChar);
-    stemp = sq_getscratchpad(v,memsize);
-    memcpy(stemp,str,memsize);
-    SQChar *start = stemp;
-    SQChar *end = stemp;
+    if(sq_gettop(v)>3) {
+        sq_getbool(v,4,&skipempty);
+    }
+    const SQChar *start = str;
+    const SQChar *end = str;
     sq_newarray(v,0);
     while(*end != '\0')
     {
@@ -265,9 +267,10 @@ static SQInteger _string_split(HSQUIRRELVM v)
         {
             if(cur == seps[i])
             {
-                *end = 0;
-                sq_pushstring(v,start,-1);
-                sq_arrayappend(v,-2);
+                if(!skipempty || (end != start)) {
+                    sq_pushstring(v,start,end-start);
+                    sq_arrayappend(v,-2);
+                }
                 start = end + 1;
                 break;
             }
@@ -276,7 +279,7 @@ static SQInteger _string_split(HSQUIRRELVM v)
     }
     if(end != start)
     {
-        sq_pushstring(v,start,-1);
+        sq_pushstring(v,start,end-start);
         sq_arrayappend(v,-2);
     }
     return 1;
@@ -384,7 +387,9 @@ static SQInteger _string_endswith(HSQUIRRELVM v)
 
 #define SETUP_REX(v) \
     SQRex *self = NULL; \
-    sq_getinstanceup(v,1,(SQUserPointer *)&self,0);
+    if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer *)&self,rex_typetag,SQFalse))) { \
+		return sq_throwerror(v,_SC("invalid type tag")); \
+	}
 
 static SQInteger _rexobj_releasehook(SQUserPointer p, SQInteger SQ_UNUSED_ARG(size))
 {
@@ -465,6 +470,13 @@ static SQInteger _regexp_subexpcount(HSQUIRRELVM v)
 
 static SQInteger _regexp_constructor(HSQUIRRELVM v)
 {
+	SQRex *self = NULL;
+	if (SQ_FAILED(sq_getinstanceup(v, 1, (SQUserPointer *)&self, rex_typetag, SQFalse))) {
+		return sq_throwerror(v, _SC("invalid type tag"));
+	}
+	if (self != NULL) {
+		return sq_throwerror(v, _SC("invalid regexp object"));
+	}
     const SQChar *error,*pattern;
     sq_getstring(v,2,&pattern);
     SQRex *rex = sqstd_rex_compile(pattern,&error);
@@ -499,7 +511,7 @@ static const SQRegFunction stringlib_funcs[]={
     _DECL_FUNC(strip,2,_SC(".s")),
     _DECL_FUNC(lstrip,2,_SC(".s")),
     _DECL_FUNC(rstrip,2,_SC(".s")),
-    _DECL_FUNC(split,3,_SC(".ss")),
+    _DECL_FUNC(split,-3,_SC(".ssb")),
     _DECL_FUNC(escape,2,_SC(".s")),
     _DECL_FUNC(startswith,3,_SC(".ss")),
     _DECL_FUNC(endswith,3,_SC(".ss")),
@@ -512,6 +524,8 @@ SQInteger sqstd_register_stringlib(HSQUIRRELVM v)
 {
     sq_pushstring(v,_SC("regexp"),-1);
     sq_newclass(v,SQFalse);
+	rex_typetag = (SQUserPointer)rexobj_funcs;
+	sq_settypetag(v, -1, rex_typetag);
     SQInteger i = 0;
     while(rexobj_funcs[i].name != 0) {
         const SQRegFunction &f = rexobj_funcs[i];

+ 15 - 15
src/modules/app_sqlang/squirrel/squirrel/sqapi.cpp

@@ -807,21 +807,21 @@ SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize)
 }
 
 
-SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag)
-{
-    SQObjectPtr &o = stack_get(v,idx);
-    if(sq_type(o) != OT_INSTANCE) return sq_throwerror(v,_SC("the object is not a class instance"));
-    (*p) = _instance(o)->_userpointer;
-    if(typetag != 0) {
-        SQClass *cl = _instance(o)->_class;
-        do{
-            if(cl->_typetag == typetag)
-                return SQ_OK;
-            cl = cl->_base;
-        }while(cl != NULL);
-        return sq_throwerror(v,_SC("invalid type tag"));
-    }
-    return SQ_OK;
+SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p, SQUserPointer typetag, SQBool throwerror)
+{
+	SQObjectPtr &o = stack_get(v, idx);
+	if (sq_type(o) != OT_INSTANCE) return throwerror ? sq_throwerror(v, _SC("the object is not a class instance")) : SQ_ERROR;
+	(*p) = _instance(o)->_userpointer;
+	if (typetag != 0) {
+		SQClass *cl = _instance(o)->_class;
+		do {
+			if (cl->_typetag == typetag)
+				return SQ_OK;
+			cl = cl->_base;
+		} while (cl != NULL);
+		return throwerror ? sq_throwerror(v, _SC("invalid type tag")) : SQ_ERROR;
+	}
+	return SQ_OK;
 }
 
 SQInteger sq_gettop(HSQUIRRELVM v)

+ 38 - 4
src/modules/app_sqlang/squirrel/squirrel/sqbaselib.cpp

@@ -499,6 +499,32 @@ static SQInteger table_filter(HSQUIRRELVM v)
     return 1;
 }
 
+static SQInteger table_map(HSQUIRRELVM v)
+{
+	SQObject &o = stack_get(v, 1);
+	SQTable *tbl = _table(o);
+	SQInteger nitr, n = 0;
+	SQInteger nitems = tbl->CountUsed();
+	SQObjectPtr ret = SQArray::Create(_ss(v), nitems);
+	SQObjectPtr itr, key, val;
+	while ((nitr = tbl->Next(false, itr, key, val)) != -1) {
+		itr = (SQInteger)nitr;
+
+		v->Push(o);
+		v->Push(key);
+		v->Push(val);
+		if (SQ_FAILED(sq_call(v, 3, SQTrue, SQFalse))) {
+			return SQ_ERROR;
+		}
+		_array(ret)->Set(n, v->GetUp(-1));
+		v->Pop();
+		n++;
+	}
+
+	v->Push(ret);
+	return 1;
+}
+
 #define TABLE_TO_ARRAY_FUNC(_funcname_,_valname_) static SQInteger _funcname_(HSQUIRRELVM v) \
 { \
 	SQObject &o = stack_get(v, 1); \
@@ -536,6 +562,7 @@ const SQRegFunction SQSharedState::_table_default_delegate_funcz[]={
     {_SC("setdelegate"),table_setdelegate,2, _SC(".t|o")},
     {_SC("getdelegate"),table_getdelegate,1, _SC(".")},
     {_SC("filter"),table_filter,2, _SC("tc")},
+	{_SC("map"),table_map,2, _SC("tc") },
 	{_SC("keys"),table_keys,1, _SC("t") },
 	{_SC("values"),table_values,1, _SC("t") },
     {NULL,(SQFUNCTION)0,0,NULL}
@@ -754,7 +781,7 @@ static SQInteger array_find(HSQUIRRELVM v)
 }
 
 
-static bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret)
+static bool _sort_compare(HSQUIRRELVM v, SQArray *arr, SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret)
 {
     if(func < 0) {
         if(!v->ObjCmp(a,b,ret)) return false;
@@ -765,15 +792,21 @@ static bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger
         sq_pushroottable(v);
         v->Push(a);
         v->Push(b);
+		SQObjectPtr *valptr = arr->_values._vals;
+		SQUnsignedInteger precallsize = arr->_values.size();
         if(SQ_FAILED(sq_call(v, 3, SQTrue, SQFalse))) {
             if(!sq_isstring( v->_lasterror))
                 v->Raise_Error(_SC("compare func failed"));
             return false;
         }
-        if(SQ_FAILED(sq_getinteger(v, -1, &ret))) {
+		if(SQ_FAILED(sq_getinteger(v, -1, &ret))) {
             v->Raise_Error(_SC("numeric value expected as return value of the compare function"));
             return false;
         }
+		if (precallsize != arr->_values.size() || valptr != arr->_values._vals) {
+			v->Raise_Error(_SC("array resized during sort operation"));
+			return false;
+		}
         sq_settop(v, top);
         return true;
     }
@@ -792,7 +825,7 @@ static bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteg
             maxChild = root2;
         }
         else {
-            if(!_sort_compare(v,arr->_values[root2],arr->_values[root2 + 1],func,ret))
+            if(!_sort_compare(v,arr,arr->_values[root2],arr->_values[root2 + 1],func,ret))
                 return false;
             if (ret > 0) {
                 maxChild = root2;
@@ -802,7 +835,7 @@ static bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteg
             }
         }
 
-        if(!_sort_compare(v,arr->_values[root],arr->_values[maxChild],func,ret))
+        if(!_sort_compare(v,arr,arr->_values[root],arr->_values[maxChild],func,ret))
             return false;
         if (ret < 0) {
             if (root == maxChild) {
@@ -1116,6 +1149,7 @@ static SQInteger thread_call(HSQUIRRELVM v)
     SQObjectPtr o = stack_get(v,1);
     if(sq_type(o) == OT_THREAD) {
         SQInteger nparams = sq_gettop(v);
+        sq_reservestack(_thread(o), nparams + 3);
         _thread(o)->Push(_thread(o)->_roottable);
         for(SQInteger i = 2; i<(nparams+1); i++)
             sq_move(_thread(o),v,i);

+ 3 - 0
src/modules/app_sqlang/squirrel/squirrel/sqclass.cpp

@@ -61,6 +61,9 @@ bool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr
         _defaultvalues[_member_idx(temp)].val = val;
         return true;
     }
+	if (_members->CountUsed() >= MEMBER_MAX_COUNT) {
+		return false;
+	}
     if(belongs_to_static_table) {
         SQInteger mmidx;
         if((sq_type(val) == OT_CLOSURE || sq_type(val) == OT_NATIVECLOSURE) &&

+ 1 - 0
src/modules/app_sqlang/squirrel/squirrel/sqclass.h

@@ -17,6 +17,7 @@ typedef sqvector<SQClassMember> SQClassMemberVec;
 
 #define MEMBER_TYPE_METHOD 0x01000000
 #define MEMBER_TYPE_FIELD 0x02000000
+#define MEMBER_MAX_COUNT 0x00FFFFFF
 
 #define _ismethod(o) (_integer(o)&MEMBER_TYPE_METHOD)
 #define _isfield(o) (_integer(o)&MEMBER_TYPE_FIELD)

+ 45 - 15
src/modules/app_sqlang/squirrel/squirrel/sqcompiler.cpp

@@ -842,8 +842,8 @@ public:
             _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
             Lex();ParseTableOrClass(_SC(','),_SC('}'));
             break;
-        case TK_FUNCTION: FunctionExp(_token);break;
-        case _SC('@'): FunctionExp(_token,true);break;
+        case TK_FUNCTION: FunctionExp();break;
+        case _SC('@'): FunctionExp(true);break;
         case TK_CLASS: Lex(); ClassExp();break;
         case _SC('-'):
             Lex();
@@ -989,10 +989,15 @@ public:
                 SQInteger tk = _token;
                 Lex();
                 SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor"));
+				_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
+				SQInteger boundtarget = 0xFF;
+				if (_token == _SC('[')) {
+					boundtarget = ParseBindEnv();
+				}
                 Expect(_SC('('));
-                _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
-                CreateFunction(id);
-                _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
+                
+                CreateFunction(id, boundtarget);
+                _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, boundtarget);
                                 }
                                 break;
             case _SC('['):
@@ -1034,11 +1039,15 @@ public:
         SQObject varname;
         Lex();
         if( _token == TK_FUNCTION) {
+			SQInteger boundtarget = 0xFF;
             Lex();
-            varname = Expect(TK_IDENTIFIER);
+			varname = Expect(TK_IDENTIFIER);
+			if (_token == _SC('[')) {
+				boundtarget = ParseBindEnv();
+			}
             Expect(_SC('('));
-            CreateFunction(varname,false);
-            _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
+            CreateFunction(varname,0xFF,false);
+            _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, boundtarget);
             _fs->PopTarget();
             _fs->PushLocalVariable(varname);
             return;
@@ -1310,9 +1319,13 @@ public:
             _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
             if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
         }
+		SQInteger boundtarget = 0xFF;
+		if (_token == _SC('[')) {
+			boundtarget = ParseBindEnv();
+		}
         Expect(_SC('('));
-        CreateFunction(id);
-        _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
+        CreateFunction(id, boundtarget);
+        _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, boundtarget);
         EmitDerefOp(_OP_NEWSLOT);
         _fs->PopTarget();
     }
@@ -1438,12 +1451,26 @@ public:
             END_SCOPE();
         }
     }
-    void FunctionExp(SQInteger ftype,bool lambda = false)
+	SQInteger ParseBindEnv()
+	{
+		SQInteger boundtarget;
+		Lex();
+		Expression();
+		boundtarget = _fs->TopTarget();
+		Expect(_SC(']'));
+		return boundtarget;
+	}
+    void FunctionExp(bool lambda = false)
     {
-        Lex(); Expect(_SC('('));
+        Lex(); 
+		SQInteger boundtarget = 0xFF;
+		if (_token == _SC('[')) {
+			boundtarget = ParseBindEnv();
+		}
+		Expect(_SC('('));
         SQObjectPtr dummy;
-        CreateFunction(dummy,lambda);
-        _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);
+        CreateFunction(dummy, boundtarget, lambda);
+        _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, boundtarget);
     }
     void ClassExp()
     {
@@ -1508,7 +1535,7 @@ public:
         }
         _es = es;
     }
-    void CreateFunction(SQObject &name,bool lambda = false)
+    void CreateFunction(SQObject &name,SQInteger boundtarget,bool lambda = false)
     {
         SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));
         funcstate->_name = name;
@@ -1542,6 +1569,9 @@ public:
             }
         }
         Expect(_SC(')'));
+		if (boundtarget != 0xFF) {
+			_fs->PopTarget();
+		}
         for(SQInteger n = 0; n < defparams; n++) {
             _fs->PopTarget();
         }

+ 6 - 5
src/modules/app_sqlang/squirrel/squirrel/sqstring.h

@@ -4,11 +4,12 @@
 
 inline SQHash _hashstr (const SQChar *s, size_t l)
 {
-        SQHash h = (SQHash)l;  /* seed */
-        size_t step = (l>>5)|1;  /* if string is too long, don't hash all its chars */
-        for (; l>=step; l-=step)
-            h = h ^ ((h<<5)+(h>>2)+(unsigned short)*(s++));
-        return h;
+	SQHash h = (SQHash)l;  /* seed */
+	size_t step = (l >> 5) + 1;  /* if string is too long, don't hash all its chars */
+	size_t l1;
+	for (l1 = l; l1 >= step; l1 -= step)
+		h = h ^ ((h << 5) + (h >> 2) + ((unsigned short)s[l1 - 1]));
+	return h;
 }
 
 struct SQString : public SQRefCounted

+ 1 - 1
src/modules/app_sqlang/squirrel/squirrel/sqtable.h

@@ -12,7 +12,7 @@
 
 #define hashptr(p)  ((SQHash)(((SQInteger)p) >> 3))
 
-inline SQHash HashObj(const SQObjectPtr &key)
+inline SQHash HashObj(const SQObject &key)
 {
     switch(sq_type(key)) {
         case OT_STRING:     return _string(key)->_hash;

+ 16 - 3
src/modules/app_sqlang/squirrel/squirrel/sqvm.cpp

@@ -586,7 +586,7 @@ bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr
 
 #define _GUARD(exp) { if(!exp) { SQ_THROW();} }
 
-bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func)
+bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func,SQInteger boundtarget)
 {
     SQInteger nouters;
     SQClosure *closure = SQClosure::Create(_ss(this), func,_table(_roottable)->GetWeakRef(OT_TABLE));
@@ -610,6 +610,19 @@ bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func)
             closure->_defaultparams[i] = _stack._vals[_stackbase + spos];
         }
     }
+	if (boundtarget != 0xFF) {
+		SQObjectPtr &val = _stack._vals[_stackbase + boundtarget];
+		SQObjectType t = sq_type(val);
+		if (t == OT_TABLE || t == OT_CLASS || t == OT_INSTANCE || t == OT_ARRAY) {
+			closure->_env = _refcounted(val)->GetWeakRef(t);
+			__ObjAddRef(closure->_env);
+		}
+		else {
+			Raise_Error(_SC("cannot bind a %s as environment object"), IdType2Name(t));
+			closure->Release();
+			return false;
+		}
+	}
     target = closure;
     return true;
 
@@ -1003,7 +1016,7 @@ exception_restore:
             case _OP_CLOSURE: {
                 SQClosure *c = ci->_closure._unVal.pClosure;
                 SQFunctionProto *fp = c->_function;
-                if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); }
+                if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto,arg2)) { SQ_THROW(); }
                 continue;
             }
             case _OP_YIELD:{
@@ -1323,7 +1336,7 @@ SQInteger SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObj
     case OT_USERDATA:
         //delegation
         if(_delegable(self)->_delegate) {
-            if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,0,DONT_FALL_BACK)) return FALLBACK_OK;
+            if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest, GET_FLAG_DO_NOT_RAISE_ERROR,DONT_FALL_BACK)) return FALLBACK_OK;
         }
         else {
             return FALLBACK_NO_MATCH;

+ 1 - 1
src/modules/app_sqlang/squirrel/squirrel/sqvm.h

@@ -103,7 +103,7 @@ public:
     _INLINE bool BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2);
     _INLINE bool NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o1);
     _INLINE bool CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res);
-    bool CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func);
+    bool CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func, SQInteger boundtarget);
     bool CLASS_OP(SQObjectPtr &target,SQInteger base,SQInteger attrs);
     //return true if the loop is finished
     bool FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump);