From: Matthias Braun Date: Thu, 9 Feb 2006 00:23:05 +0000 (+0000) Subject: squirrel update X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=f9b655aacd208ce9959b271bd0d78de3e367d3b9;p=supertux.git squirrel update SVN-Revision: 3049 --- diff --git a/src/squirrel/include/sqstdaux.h b/src/squirrel/include/sqstdaux.h index c16b04373..b90034823 100644 --- a/src/squirrel/include/sqstdaux.h +++ b/src/squirrel/include/sqstdaux.h @@ -1,16 +1,16 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQSTD_AUXLIB_H_ -#define _SQSTD_AUXLIB_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -SQUIRREL_API void sqstd_seterrorhandlers(HSQUIRRELVM v); -SQUIRREL_API void sqstd_printcallstack(HSQUIRRELVM v); - -#ifdef __cplusplus -} /*extern "C"*/ -#endif - -#endif /* _SQSTD_AUXLIB_H_ */ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_AUXLIB_H_ +#define _SQSTD_AUXLIB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +SQUIRREL_API void sqstd_seterrorhandlers(HSQUIRRELVM v); +SQUIRREL_API void sqstd_printcallstack(HSQUIRRELVM v); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /* _SQSTD_AUXLIB_H_ */ diff --git a/src/squirrel/include/sqstdblob.h b/src/squirrel/include/sqstdblob.h index 85c138f0b..eda4cc9c5 100644 --- a/src/squirrel/include/sqstdblob.h +++ b/src/squirrel/include/sqstdblob.h @@ -1,20 +1,20 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQSTDBLOB_H_ -#define _SQSTDBLOB_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -SQUIRREL_API SQUserPointer sqstd_createblob(HSQUIRRELVM v, int size); -SQUIRREL_API SQRESULT sqstd_getblob(HSQUIRRELVM v,int idx,SQUserPointer *ptr); -SQUIRREL_API int sqstd_getblobsize(HSQUIRRELVM v,int idx); - -SQUIRREL_API SQRESULT sqstd_register_bloblib(HSQUIRRELVM v); - -#ifdef __cplusplus -} /*extern "C"*/ -#endif - -#endif /*_SQSTDBLOB_H_*/ - +/* see copyright notice in squirrel.h */ +#ifndef _SQSTDBLOB_H_ +#define _SQSTDBLOB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +SQUIRREL_API SQUserPointer sqstd_createblob(HSQUIRRELVM v, SQInteger size); +SQUIRREL_API SQRESULT sqstd_getblob(HSQUIRRELVM v,SQInteger idx,SQUserPointer *ptr); +SQUIRREL_API SQInteger sqstd_getblobsize(HSQUIRRELVM v,SQInteger idx); + +SQUIRREL_API SQRESULT sqstd_register_bloblib(HSQUIRRELVM v); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*_SQSTDBLOB_H_*/ + diff --git a/src/squirrel/include/sqstdio.h b/src/squirrel/include/sqstdio.h index cbc8069d1..1174201a9 100644 --- a/src/squirrel/include/sqstdio.h +++ b/src/squirrel/include/sqstdio.h @@ -1,55 +1,53 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQSTDIO_H_ -#define _SQSTDIO_H_ - -#ifdef __cplusplus - -#define SQSTD_STREAM_TYPE_TAG 0x80000000 - -struct SQStream { - virtual ~SQStream() {} - - virtual SQInteger Read(void *buffer, SQInteger size) = 0; - virtual SQInteger Write(void *buffer, SQInteger size) = 0; - virtual int Flush() = 0; - virtual long Tell() = 0; - virtual SQInteger Len() = 0; - virtual SQInteger Seek(long offset, int origin) = 0; - virtual bool IsValid() = 0; - virtual bool EOS() = 0; -}; - -extern "C" { -#endif - -#define SQ_SEEK_CUR 0 -#define SQ_SEEK_END 1 -#define SQ_SEEK_SET 2 - -typedef void* SQFILE; - -SQUIRREL_API SQFILE sqstd_fopen(const SQChar *,const SQChar *); -SQUIRREL_API SQInteger sqstd_fread(SQUserPointer, SQInteger, SQInteger, SQFILE); -SQUIRREL_API SQInteger sqstd_fwrite(const SQUserPointer, SQInteger, SQInteger, SQFILE); -SQUIRREL_API SQInteger sqstd_fseek(SQFILE , long , int); -SQUIRREL_API long sqstd_ftell(SQFILE); -SQUIRREL_API SQInteger sqstd_fflush(SQFILE); -SQUIRREL_API SQInteger sqstd_fclose(SQFILE); -SQUIRREL_API SQInteger sqstd_feof(SQFILE); - -SQUIRREL_API SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own); -SQUIRREL_API SQRESULT sqstd_getfile(HSQUIRRELVM v, int idx, SQFILE *file); - -//compiler helpers -SQUIRREL_API SQRESULT sqstd_loadfile(HSQUIRRELVM v,const SQChar *filename,SQBool printerror); -SQUIRREL_API SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool printerror); -SQUIRREL_API SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const SQChar *filename); - -SQUIRREL_API SQRESULT sqstd_register_iolib(HSQUIRRELVM v); - -#ifdef __cplusplus -} /*extern "C"*/ -#endif - -#endif /*_SQSTDIO_H_*/ - +/* see copyright notice in squirrel.h */ +#ifndef _SQSTDIO_H_ +#define _SQSTDIO_H_ + +#ifdef __cplusplus + +#define SQSTD_STREAM_TYPE_TAG 0x80000000 + +struct SQStream { + virtual SQInteger Read(void *buffer, SQInteger size) = 0; + virtual SQInteger Write(void *buffer, SQInteger size) = 0; + virtual SQInteger Flush() = 0; + virtual SQInteger Tell() = 0; + virtual SQInteger Len() = 0; + virtual SQInteger Seek(SQInteger offset, SQInteger origin) = 0; + virtual bool IsValid() = 0; + virtual bool EOS() = 0; +}; + +extern "C" { +#endif + +#define SQ_SEEK_CUR 0 +#define SQ_SEEK_END 1 +#define SQ_SEEK_SET 2 + +typedef void* SQFILE; + +SQUIRREL_API SQFILE sqstd_fopen(const SQChar *,const SQChar *); +SQUIRREL_API SQInteger sqstd_fread(SQUserPointer, SQInteger, SQInteger, SQFILE); +SQUIRREL_API SQInteger sqstd_fwrite(const SQUserPointer, SQInteger, SQInteger, SQFILE); +SQUIRREL_API SQInteger sqstd_fseek(SQFILE , SQInteger , SQInteger); +SQUIRREL_API SQInteger sqstd_ftell(SQFILE); +SQUIRREL_API SQInteger sqstd_fflush(SQFILE); +SQUIRREL_API SQInteger sqstd_fclose(SQFILE); +SQUIRREL_API SQInteger sqstd_feof(SQFILE); + +SQUIRREL_API SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own); +SQUIRREL_API SQRESULT sqstd_getfile(HSQUIRRELVM v, SQInteger idx, SQFILE *file); + +//compiler helpers +SQUIRREL_API SQRESULT sqstd_loadfile(HSQUIRRELVM v,const SQChar *filename,SQBool printerror); +SQUIRREL_API SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool printerror); +SQUIRREL_API SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const SQChar *filename); + +SQUIRREL_API SQRESULT sqstd_register_iolib(HSQUIRRELVM v); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*_SQSTDIO_H_*/ + diff --git a/src/squirrel/include/sqstdmath.h b/src/squirrel/include/sqstdmath.h index 65de6fd72..420f2ce67 100644 --- a/src/squirrel/include/sqstdmath.h +++ b/src/squirrel/include/sqstdmath.h @@ -1,15 +1,15 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQSTD_MATH_H_ -#define _SQSTD_MATH_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -SQUIRREL_API SQRESULT sqstd_register_mathlib(HSQUIRRELVM v); - -#ifdef __cplusplus -} /*extern "C"*/ -#endif - -#endif /*_SQSTD_MATH_H_*/ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_MATH_H_ +#define _SQSTD_MATH_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +SQUIRREL_API SQRESULT sqstd_register_mathlib(HSQUIRRELVM v); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*_SQSTD_MATH_H_*/ diff --git a/src/squirrel/include/sqstdstring.h b/src/squirrel/include/sqstdstring.h index eb7790cea..9db0ffce9 100644 --- a/src/squirrel/include/sqstdstring.h +++ b/src/squirrel/include/sqstdstring.h @@ -1,34 +1,34 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQSTD_STRING_H_ -#define _SQSTD_STRING_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -//#define SQRex_True 1 -//#define SQRex_False 0 - -typedef unsigned int SQRexBool; -typedef struct SQRex SQRex; - -typedef struct { - const SQChar *begin; - int len; -} SQRexMatch; - -SQUIRREL_API SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error); -SQUIRREL_API void sqstd_rex_free(SQRex *exp); -SQUIRREL_API SQBool sqstd_rex_match(SQRex* exp,const SQChar* text); -SQUIRREL_API SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end); -SQUIRREL_API SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end); -SQUIRREL_API int sqstd_rex_getsubexpcount(SQRex* exp); -SQUIRREL_API SQBool sqstd_rex_getsubexp(SQRex* exp, int n, SQRexMatch *subexp); - -SQUIRREL_API SQRESULT sqstd_register_stringlib(HSQUIRRELVM v); - -#ifdef __cplusplus -} /*extern "C"*/ -#endif - -#endif /*_SQSTD_STRING_H_*/ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_STRING_H_ +#define _SQSTD_STRING_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +//#define SQRex_True 1 +//#define SQRex_False 0 + +typedef unsigned int SQRexBool; +typedef struct SQRex SQRex; + +typedef struct { + const SQChar *begin; + SQInteger len; +} SQRexMatch; + +SQUIRREL_API SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error); +SQUIRREL_API void sqstd_rex_free(SQRex *exp); +SQUIRREL_API SQBool sqstd_rex_match(SQRex* exp,const SQChar* text); +SQUIRREL_API SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end); +SQUIRREL_API SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end); +SQUIRREL_API SQInteger sqstd_rex_getsubexpcount(SQRex* exp); +SQUIRREL_API SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp); + +SQUIRREL_API SQRESULT sqstd_register_stringlib(HSQUIRRELVM v); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*_SQSTD_STRING_H_*/ diff --git a/src/squirrel/include/sqstdsystem.h b/src/squirrel/include/sqstdsystem.h index a528f5d7f..daefa0fd5 100644 --- a/src/squirrel/include/sqstdsystem.h +++ b/src/squirrel/include/sqstdsystem.h @@ -1,15 +1,15 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQSTD_SYSTEMLIB_H_ -#define _SQSTD_SYSTEMLIB_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -SQUIRREL_API int sqstd_register_systemlib(HSQUIRRELVM v); - -#ifdef __cplusplus -} /*extern "C"*/ -#endif - -#endif /* _SQSTD_SYSTEMLIB_H_ */ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_SYSTEMLIB_H_ +#define _SQSTD_SYSTEMLIB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +SQUIRREL_API SQInteger sqstd_register_systemlib(HSQUIRRELVM v); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /* _SQSTD_SYSTEMLIB_H_ */ diff --git a/src/squirrel/include/squirrel.h b/src/squirrel/include/squirrel.h index 8f23fb9d6..d301f834e 100644 --- a/src/squirrel/include/squirrel.h +++ b/src/squirrel/include/squirrel.h @@ -1,369 +1,384 @@ -/* -Copyright (c) 2003-2005 Alberto Demichelis - -This software is provided 'as-is', without any -express or implied warranty. In no event will the -authors be held liable for any damages arising from -the use of this software. - -Permission is granted to anyone to use this software -for any purpose, including commercial applications, -and to alter it and redistribute it freely, subject -to the following restrictions: - - 1. The origin of this software must not be - misrepresented; you must not claim that - you wrote the original software. If you - use this software in a product, an - acknowledgment in the product - documentation would be appreciated but is - not required. - - 2. Altered source versions must be plainly - marked as such, and must not be - misrepresented as being the original - software. - - 3. This notice may not be removed or - altered from any source distribution. - -*/ -#ifndef _SQUIRREL_H_ -#define _SQUIRREL_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef SQUIRREL_API -#define SQUIRREL_API extern -#endif - -typedef float SQFloat; -typedef int SQInteger; -typedef void* SQUserPointer; -typedef unsigned int SQBool; -typedef int SQRESULT; - -#define SQTrue 1 -#define SQFalse 0 - - -struct SQVM; -struct SQTable; -struct SQArray; -struct SQString; -struct SQClosure; -struct SQGenerator; -struct SQNativeClosure; -struct SQUserData; -struct SQFunctionProto; -struct SQRefCounted; -struct SQClass; -struct SQInstance; -struct SQDelegable; - -#ifdef _UNICODE -#define SQUNICODE -#endif - -#ifdef SQUNICODE -typedef unsigned short SQChar; -#define _SC(a) L##a -#define scstrcmp wcscmp -#define scsprintf swprintf -#define scstrlen wcslen -#define scstrtod wcstod -#define scatoi _wtoi -#define scstrtoul wcstoul -#define scvsprintf vswprintf -#define scstrstr wcsstr -#define scisspace iswspace -#define scisdigit iswdigit -#define scisalpha iswalpha -#define sciscntrl iswcntrl -#define scisalnum iswalnum -#define scprintf wprintf -#define MAX_CHAR 0xFFFF -#else -typedef char SQChar; -#define _SC(a) a -#define scstrcmp strcmp -#define scsprintf sprintf -#define scstrlen strlen -#define scstrtod strtod -#define scatoi atoi -#define scstrtoul strtoul -#define scvsprintf vsprintf -#define scstrstr strstr -#define scisspace isspace -#define scisdigit isdigit -#define sciscntrl iscntrl -#define scisalpha isalpha -#define scisalnum isalnum -#define scprintf printf -#define MAX_CHAR 0xFF -#endif - -#define SQUIRREL_VERSION _SC("Squirrel 2.0.3 stable") -#define SQUIRREL_COPYRIGHT _SC("Copyright (C) 2003-2005 Alberto Demichelis") -#define SQUIRREL_AUTHOR _SC("Alberto Demichelis") - -#define SQ_VMSTATE_IDLE 0 -#define SQ_VMSTATE_RUNNING 1 -#define SQ_VMSTATE_SUSPENDED 2 - -#define SQUIRREL_EOB 0 -#define SQ_BYTECODE_STREAM_TAG 0xFAFA - -#define SQOBJECT_REF_COUNTED 0x00800000 -#define SQOBJECT_NUMERIC 0x00400000 -#define SQOBJECT_DELEGABLE 0x00200000 -#define SQOBJECT_CANBEFALSE 0x00100000 - -#define SQ_MATCHTYPEMASKSTRING (-99999) - -#define _RT_MASK 0x0000FFFF -#define _RAW_TYPE(type) (type&_RT_MASK) - -#define _RT_NULL 0x00000001 -#define _RT_INTEGER 0x00000002 -#define _RT_FLOAT 0x00000004 -#define _RT_BOOL 0x00000008 -#define _RT_STRING 0x00000010 -#define _RT_TABLE 0x00000020 -#define _RT_ARRAY 0x00000040 -#define _RT_USERDATA 0x00000080 -#define _RT_CLOSURE 0x00000100 -#define _RT_NATIVECLOSURE 0x00000200 -#define _RT_GENERATOR 0x00000400 -#define _RT_USERPOINTER 0x00000800 -#define _RT_THREAD 0x00001000 -#define _RT_FUNCPROTO 0x00002000 -#define _RT_CLASS 0x00004000 -#define _RT_INSTANCE 0x00008000 - -typedef enum { - OT_NULL = (_RT_NULL|SQOBJECT_CANBEFALSE), - OT_INTEGER = (_RT_INTEGER|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE), - OT_FLOAT = (_RT_FLOAT|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE), - OT_BOOL = (_RT_BOOL|SQOBJECT_CANBEFALSE), - OT_STRING = (_RT_STRING|SQOBJECT_REF_COUNTED), - OT_TABLE = (_RT_TABLE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE), - OT_ARRAY = (_RT_ARRAY|SQOBJECT_REF_COUNTED), - OT_USERDATA = (_RT_USERDATA|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE), - OT_CLOSURE = (_RT_CLOSURE|SQOBJECT_REF_COUNTED), - OT_NATIVECLOSURE = (_RT_NATIVECLOSURE|SQOBJECT_REF_COUNTED), - OT_GENERATOR = (_RT_GENERATOR|SQOBJECT_REF_COUNTED), - OT_USERPOINTER = _RT_USERPOINTER, - OT_THREAD = (_RT_THREAD|SQOBJECT_REF_COUNTED) , - OT_FUNCPROTO = (_RT_FUNCPROTO|SQOBJECT_REF_COUNTED), //internal usage only - OT_CLASS = (_RT_CLASS|SQOBJECT_REF_COUNTED), - OT_INSTANCE = (_RT_INSTANCE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE) -}SQObjectType; - -#define ISREFCOUNTED(t) (t&SQOBJECT_REF_COUNTED) - - -typedef union tagSQObjectValue -{ - struct SQTable *pTable; - struct SQArray *pArray; - struct SQClosure *pClosure; - struct SQGenerator *pGenerator; - struct SQNativeClosure *pNativeClosure; - struct SQString *pString; - struct SQUserData *pUserData; - SQInteger nInteger; - SQFloat fFloat; - SQUserPointer pUserPointer; - struct SQFunctionProto *pFunctionProto; - struct SQRefCounted *pRefCounted; - struct SQDelegable *pDelegable; - struct SQVM *pThread; - struct SQClass *pClass; - struct SQInstance *pInstance; -}SQObjectValue; - - -typedef struct tagSQObject -{ - SQObjectValue _unVal; - SQObjectType _type; -}SQObject; - -typedef struct tagSQStackInfos{ - const SQChar* funcname; - const SQChar* source; - int line; -}SQStackInfos; - -typedef struct SQVM* HSQUIRRELVM; -typedef SQObject HSQOBJECT; -typedef int (*SQFUNCTION)(HSQUIRRELVM); -typedef int (*SQRELEASEHOOK)(SQUserPointer,int size); -typedef void (*SQCOMPILERERROR)(HSQUIRRELVM,const SQChar * /*desc*/,const SQChar * /*source*/,int /*line*/,int /*column*/); -typedef void (*SQPRINTFUNCTION)(HSQUIRRELVM,const SQChar * ,...); - -typedef int (*SQWRITEFUNC)(SQUserPointer,SQUserPointer,int); -typedef int (*SQREADFUNC)(SQUserPointer,SQUserPointer,int); - -typedef SQInteger (*SQLEXREADFUNC)(SQUserPointer); - -typedef struct tagSQRegFunction{ - const SQChar *name; - SQFUNCTION f; - int nparamscheck; - const SQChar *typemask; -}SQRegFunction; - -/*vm*/ -SQUIRREL_API HSQUIRRELVM sq_open(int initialstacksize); -SQUIRREL_API HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, int initialstacksize); -SQUIRREL_API void sq_seterrorhandler(HSQUIRRELVM v); -SQUIRREL_API void sq_close(HSQUIRRELVM v); -SQUIRREL_API void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p); -SQUIRREL_API SQUserPointer sq_getforeignptr(HSQUIRRELVM v); -SQUIRREL_API void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc); -SQUIRREL_API SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v); -SQUIRREL_API SQRESULT sq_suspendvm(HSQUIRRELVM v); -SQUIRREL_API SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval); -SQUIRREL_API int sq_getvmstate(HSQUIRRELVM v); - -/*compiler*/ -SQUIRREL_API SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror); -SQUIRREL_API SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,int size,const SQChar *sourcename,SQBool raiseerror); -SQUIRREL_API void sq_enabledebuginfo(HSQUIRRELVM v, SQBool debuginfo); -SQUIRREL_API void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f); - -/*stack operations*/ -SQUIRREL_API void sq_push(HSQUIRRELVM v,int idx); -SQUIRREL_API void sq_pop(HSQUIRRELVM v,int nelemstopop); -SQUIRREL_API void sq_remove(HSQUIRRELVM v,int idx); -SQUIRREL_API int sq_gettop(HSQUIRRELVM v); -SQUIRREL_API void sq_settop(HSQUIRRELVM v,int newtop); -SQUIRREL_API void sq_reservestack(HSQUIRRELVM v,int nsize); -SQUIRREL_API int sq_cmp(HSQUIRRELVM v); -SQUIRREL_API void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,int idx); - -/*object creation handling*/ -SQUIRREL_API SQUserPointer sq_newuserdata(HSQUIRRELVM v,unsigned int size); -SQUIRREL_API void sq_newtable(HSQUIRRELVM v); -SQUIRREL_API void sq_newarray(HSQUIRRELVM v,int size); -SQUIRREL_API void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,unsigned int nfreevars); -SQUIRREL_API SQRESULT sq_setparamscheck(HSQUIRRELVM v,int nparamscheck,const SQChar *typemask); -SQUIRREL_API void sq_pushstring(HSQUIRRELVM v,const SQChar *s,int len); -SQUIRREL_API void sq_pushfloat(HSQUIRRELVM v,SQFloat f); -SQUIRREL_API void sq_pushinteger(HSQUIRRELVM v,SQInteger n); -SQUIRREL_API void sq_pushbool(HSQUIRRELVM v,SQBool b); -SQUIRREL_API void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p); -SQUIRREL_API void sq_pushnull(HSQUIRRELVM v); -SQUIRREL_API SQObjectType sq_gettype(HSQUIRRELVM v,int idx); -SQUIRREL_API SQInteger sq_getsize(HSQUIRRELVM v,int idx); -SQUIRREL_API SQRESULT sq_getstring(HSQUIRRELVM v,int idx,const SQChar **c); -SQUIRREL_API SQRESULT sq_getinteger(HSQUIRRELVM v,int idx,SQInteger *i); -SQUIRREL_API SQRESULT sq_getfloat(HSQUIRRELVM v,int idx,SQFloat *f); -SQUIRREL_API SQRESULT sq_getbool(HSQUIRRELVM v,int idx,SQBool *b); -SQUIRREL_API SQRESULT sq_getthread(HSQUIRRELVM v,int idx,HSQUIRRELVM *thread); -SQUIRREL_API SQRESULT sq_getuserpointer(HSQUIRRELVM v,int idx,SQUserPointer *p); -SQUIRREL_API SQRESULT sq_getuserdata(HSQUIRRELVM v,int idx,SQUserPointer *p,unsigned int *typetag); -SQUIRREL_API SQRESULT sq_settypetag(HSQUIRRELVM v,int idx,unsigned int typetag); -SQUIRREL_API SQRESULT sq_gettypetag(HSQUIRRELVM v,int idx,unsigned int *typetag); -SQUIRREL_API void sq_setreleasehook(HSQUIRRELVM v,int idx,SQRELEASEHOOK hook); -SQUIRREL_API SQChar *sq_getscratchpad(HSQUIRRELVM v,int minsize); -SQUIRREL_API SQRESULT sq_getclosureinfo(HSQUIRRELVM v,int idx,unsigned int *nparams,unsigned int *nfreevars); -SQUIRREL_API SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,int idx,const SQChar *name); -SQUIRREL_API SQRESULT sq_setinstanceup(HSQUIRRELVM v, int idx, SQUserPointer p); -SQUIRREL_API SQRESULT sq_getinstanceup(HSQUIRRELVM v, int idx, SQUserPointer *p,unsigned int typetag); -SQUIRREL_API SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase); -SQUIRREL_API SQRESULT sq_createinstance(HSQUIRRELVM v,int idx); -SQUIRREL_API SQRESULT sq_setattributes(HSQUIRRELVM v,int idx); -SQUIRREL_API SQRESULT sq_getattributes(HSQUIRRELVM v,int idx); -SQUIRREL_API SQRESULT sq_getclass(HSQUIRRELVM v,int idx); - -/*object manipulation*/ -SQUIRREL_API void sq_pushroottable(HSQUIRRELVM v); -SQUIRREL_API void sq_pushregistrytable(HSQUIRRELVM v); -SQUIRREL_API SQRESULT sq_setroottable(HSQUIRRELVM v); -SQUIRREL_API SQRESULT sq_createslot(HSQUIRRELVM v,int idx); -SQUIRREL_API SQRESULT sq_deleteslot(HSQUIRRELVM v,int idx,SQBool pushval); -SQUIRREL_API SQRESULT sq_set(HSQUIRRELVM v,int idx); -SQUIRREL_API SQRESULT sq_get(HSQUIRRELVM v,int idx); -SQUIRREL_API SQRESULT sq_rawget(HSQUIRRELVM v,int idx); -SQUIRREL_API SQRESULT sq_rawset(HSQUIRRELVM v,int idx); -SQUIRREL_API SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,int idx,SQBool pushval); -SQUIRREL_API SQRESULT sq_arrayappend(HSQUIRRELVM v,int idx); -SQUIRREL_API SQRESULT sq_arraypop(HSQUIRRELVM v,int idx,SQBool pushval); -SQUIRREL_API SQRESULT sq_arrayresize(HSQUIRRELVM v,int idx,int newsize); -SQUIRREL_API SQRESULT sq_arrayreverse(HSQUIRRELVM v,int idx); -SQUIRREL_API SQRESULT sq_setdelegate(HSQUIRRELVM v,int idx); -SQUIRREL_API SQRESULT sq_getdelegate(HSQUIRRELVM v,int idx); -SQUIRREL_API SQRESULT sq_clone(HSQUIRRELVM v,int idx); -SQUIRREL_API SQRESULT sq_setfreevariable(HSQUIRRELVM v,int idx,unsigned int nval); -SQUIRREL_API SQRESULT sq_next(HSQUIRRELVM v,int idx); - -/*calls*/ -SQUIRREL_API SQRESULT sq_call(HSQUIRRELVM v,int params,SQBool retval); -SQUIRREL_API SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval); -SQUIRREL_API const SQChar *sq_getlocal(HSQUIRRELVM v,unsigned int level,unsigned int idx); -SQUIRREL_API SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err); -SQUIRREL_API void sq_reseterror(HSQUIRRELVM v); -SQUIRREL_API void sq_getlasterror(HSQUIRRELVM v); - -/*raw object handling*/ -SQUIRREL_API SQRESULT sq_getstackobj(HSQUIRRELVM v,int idx,HSQOBJECT *po); -SQUIRREL_API void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj); -SQUIRREL_API void sq_addref(HSQUIRRELVM v,HSQOBJECT *po); -SQUIRREL_API SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po); -SQUIRREL_API void sq_resetobject(HSQOBJECT *po); -SQUIRREL_API const SQChar *sq_objtostring(HSQOBJECT *o); -SQUIRREL_API SQInteger sq_objtointeger(HSQOBJECT *o); -SQUIRREL_API SQFloat sq_objtofloat(HSQOBJECT *o); - -/*GC*/ -SQUIRREL_API int sq_collectgarbage(HSQUIRRELVM v); - -/*serialization*/ -SQUIRREL_API SQRESULT sq_writeclosure(HSQUIRRELVM vm,SQWRITEFUNC writef,SQUserPointer up); -SQUIRREL_API SQRESULT sq_readclosure(HSQUIRRELVM vm,SQREADFUNC readf,SQUserPointer up); - -/*mem allocation*/ -SQUIRREL_API void *sq_malloc(unsigned int size); -SQUIRREL_API void *sq_realloc(void* p,unsigned int oldsize,unsigned int newsize); -SQUIRREL_API void sq_free(void *p,unsigned int size); - -/*debug*/ -SQUIRREL_API SQRESULT sq_stackinfos(HSQUIRRELVM v,int level,SQStackInfos *si); -SQUIRREL_API void sq_setdebughook(HSQUIRRELVM v); - -/*UTILITY MACRO*/ -#define sq_isnumeric(o) ((o)._type&SQOBJECT_NUMERIC) -#define sq_istable(o) ((o)._type==OT_TABLE) -#define sq_isarray(o) ((o)._type==OT_ARRAY) -#define sq_isfunction(o) ((o)._type==OT_FUNCPROTO) -#define sq_isclosure(o) ((o)._type==OT_CLOSURE) -#define sq_isgenerator(o) ((o)._type==OT_GENERATOR) -#define sq_isnativeclosure(o) ((o)._type==OT_NATIVECLOSURE) -#define sq_isstring(o) ((o)._type==OT_STRING) -#define sq_isinteger(o) ((o)._type==OT_INTEGER) -#define sq_isfloat(o) ((o)._type==OT_FLOAT) -#define sq_isuserpointer(o) ((o)._type==OT_USERPOINTER) -#define sq_isuserdata(o) ((o)._type==OT_USERDATA) -#define sq_isthread(o) ((o)._type==OT_THREAD) -#define sq_isnull(o) ((o)._type==OT_NULL) -#define sq_isclass(o) ((o)._type==OT_CLASS) -#define sq_isinstance(o) ((o)._type==OT_INSTANCE) -#define sq_isbool(o) ((o)._type==OT_BOOL) -#define sq_type(o) ((o)._type) - -#define SQ_OK (0) -#define SQ_ERROR (-1) - -#define SQ_FAILED(res) (res<0) -#define SQ_SUCCEEDED(res) (res>=0) - -#ifdef __cplusplus -} /*extern "C"*/ -#endif - -#endif /*_SQUIRREL_H_*/ +/* +Copyright (c) 2003-2005 Alberto Demichelis + +This software is provided 'as-is', without any +express or implied warranty. In no event will the +authors be held liable for any damages arising from +the use of this software. + +Permission is granted to anyone to use this software +for any purpose, including commercial applications, +and to alter it and redistribute it freely, subject +to the following restrictions: + + 1. The origin of this software must not be + misrepresented; you must not claim that + you wrote the original software. If you + use this software in a product, an + acknowledgment in the product + documentation would be appreciated but is + not required. + + 2. Altered source versions must be plainly + marked as such, and must not be + misrepresented as being the original + software. + + 3. This notice may not be removed or + altered from any source distribution. + +*/ +#ifndef _SQUIRREL_H_ +#define _SQUIRREL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef SQUIRREL_API +#define SQUIRREL_API extern +#endif + +typedef float SQFloat; +typedef int SQInteger; +typedef int SQInt32; //must be 32 bits(also on 64bits processors) +typedef void* SQUserPointer; +typedef unsigned int SQUnsignedInteger; +typedef unsigned int SQHash; //should be the same size of a pointer +typedef SQUnsignedInteger SQBool; +typedef SQInteger SQRESULT; + +#define SQTrue (1) +#define SQFalse (0) + + +struct SQVM; +struct SQTable; +struct SQArray; +struct SQString; +struct SQClosure; +struct SQGenerator; +struct SQNativeClosure; +struct SQUserData; +struct SQFunctionProto; +struct SQRefCounted; +struct SQClass; +struct SQInstance; +struct SQDelegable; + +#ifdef _UNICODE +#define SQUNICODE +#endif + +#ifdef SQUNICODE +typedef unsigned short SQChar; +#define _SC(a) L##a +#define scstrcmp wcscmp +#define scsprintf swprintf +#define scstrlen wcslen +#define scstrtod wcstod +#define scstrtol wcstol +#define scatoi _wtoi +#define scstrtoul wcstoul +#define scvsprintf vswprintf +#define scstrstr wcsstr +#define scisspace iswspace +#define scisdigit iswdigit +#define scisalpha iswalpha +#define sciscntrl iswcntrl +#define scisalnum iswalnum +#define scprintf wprintf +#define MAX_CHAR 0xFFFF +#else +typedef char SQChar; +#define _SC(a) a +#define scstrcmp strcmp +#define scsprintf sprintf +#define scstrlen strlen +#define scstrtod strtod +#define scstrtol strtol +#define scatoi atoi +#define scstrtoul strtoul +#define scvsprintf vsprintf +#define scstrstr strstr +#define scisspace isspace +#define scisdigit isdigit +#define sciscntrl iscntrl +#define scisalpha isalpha +#define scisalnum isalnum +#define scprintf printf +#define MAX_CHAR 0xFF +#endif + +#define SQUIRREL_VERSION _SC("Squirrel 2.0.5 stable") +#define SQUIRREL_COPYRIGHT _SC("Copyright (C) 2003-2005 Alberto Demichelis") +#define SQUIRREL_AUTHOR _SC("Alberto Demichelis") + +#define SQ_VMSTATE_IDLE 0 +#define SQ_VMSTATE_RUNNING 1 +#define SQ_VMSTATE_SUSPENDED 2 + +#define SQUIRREL_EOB 0 +#define SQ_BYTECODE_STREAM_TAG 0xFAFA + +#define SQOBJECT_REF_COUNTED 0x08000000 +#define SQOBJECT_NUMERIC 0x04000000 +#define SQOBJECT_DELEGABLE 0x02000000 +#define SQOBJECT_CANBEFALSE 0x01000000 + +#define SQ_MATCHTYPEMASKSTRING (-99999) + +#define _RT_MASK 0x00FFFFFF +#define _RAW_TYPE(type) (type&_RT_MASK) + +#define _RT_NULL 0x00000001 +#define _RT_INTEGER 0x00000002 +#define _RT_FLOAT 0x00000004 +#define _RT_BOOL 0x00000008 +#define _RT_STRING 0x00000010 +#define _RT_TABLE 0x00000020 +#define _RT_ARRAY 0x00000040 +#define _RT_USERDATA 0x00000080 +#define _RT_CLOSURE 0x00000100 +#define _RT_NATIVECLOSURE 0x00000200 +#define _RT_GENERATOR 0x00000400 +#define _RT_USERPOINTER 0x00000800 +#define _RT_THREAD 0x00001000 +#define _RT_FUNCPROTO 0x00002000 +#define _RT_CLASS 0x00004000 +#define _RT_INSTANCE 0x00008000 +#define _RT_WEAKREF 0x00010000 + +typedef enum { + OT_NULL = (_RT_NULL|SQOBJECT_CANBEFALSE), + OT_INTEGER = (_RT_INTEGER|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE), + OT_FLOAT = (_RT_FLOAT|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE), + OT_BOOL = (_RT_BOOL|SQOBJECT_CANBEFALSE), + OT_STRING = (_RT_STRING|SQOBJECT_REF_COUNTED), + OT_TABLE = (_RT_TABLE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE), + OT_ARRAY = (_RT_ARRAY|SQOBJECT_REF_COUNTED), + OT_USERDATA = (_RT_USERDATA|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE), + OT_CLOSURE = (_RT_CLOSURE|SQOBJECT_REF_COUNTED), + OT_NATIVECLOSURE = (_RT_NATIVECLOSURE|SQOBJECT_REF_COUNTED), + OT_GENERATOR = (_RT_GENERATOR|SQOBJECT_REF_COUNTED), + OT_USERPOINTER = _RT_USERPOINTER, + OT_THREAD = (_RT_THREAD|SQOBJECT_REF_COUNTED) , + OT_FUNCPROTO = (_RT_FUNCPROTO|SQOBJECT_REF_COUNTED), //internal usage only + OT_CLASS = (_RT_CLASS|SQOBJECT_REF_COUNTED), + OT_INSTANCE = (_RT_INSTANCE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE), + OT_WEAKREF = (_RT_WEAKREF|SQOBJECT_REF_COUNTED) +}SQObjectType; + +#define ISREFCOUNTED(t) (t&SQOBJECT_REF_COUNTED) + + +typedef union tagSQObjectValue +{ + struct SQTable *pTable; + struct SQArray *pArray; + struct SQClosure *pClosure; + struct SQGenerator *pGenerator; + struct SQNativeClosure *pNativeClosure; + struct SQString *pString; + struct SQUserData *pUserData; + SQInteger nInteger; + SQFloat fFloat; + SQUserPointer pUserPointer; + struct SQFunctionProto *pFunctionProto; + struct SQRefCounted *pRefCounted; + struct SQDelegable *pDelegable; + struct SQVM *pThread; + struct SQClass *pClass; + struct SQInstance *pInstance; + struct SQWeakRef *pWeakRef; +}SQObjectValue; + + +typedef struct tagSQObject +{ + SQObjectValue _unVal; + SQObjectType _type; +}SQObject; + +typedef struct tagSQStackInfos{ + const SQChar* funcname; + const SQChar* source; + SQInteger line; +}SQStackInfos; + +typedef struct SQVM* HSQUIRRELVM; +typedef SQObject HSQOBJECT; +typedef SQInteger (*SQFUNCTION)(HSQUIRRELVM); +typedef SQInteger (*SQRELEASEHOOK)(SQUserPointer,SQInteger size); +typedef void (*SQCOMPILERERROR)(HSQUIRRELVM,const SQChar * /*desc*/,const SQChar * /*source*/,SQInteger /*line*/,SQInteger /*column*/); +typedef void (*SQPRINTFUNCTION)(HSQUIRRELVM,const SQChar * ,...); + +typedef SQInteger (*SQWRITEFUNC)(SQUserPointer,SQUserPointer,SQInteger); +typedef SQInteger (*SQREADFUNC)(SQUserPointer,SQUserPointer,SQInteger); + +typedef SQInteger (*SQLEXREADFUNC)(SQUserPointer); + +typedef struct tagSQRegFunction{ + const SQChar *name; + SQFUNCTION f; + SQInteger nparamscheck; + const SQChar *typemask; +}SQRegFunction; + +/*vm*/ +SQUIRREL_API HSQUIRRELVM sq_open(SQInteger initialstacksize); +SQUIRREL_API HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize); +SQUIRREL_API void sq_seterrorhandler(HSQUIRRELVM v); +SQUIRREL_API void sq_close(HSQUIRRELVM v); +SQUIRREL_API void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p); +SQUIRREL_API SQUserPointer sq_getforeignptr(HSQUIRRELVM v); +SQUIRREL_API void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc); +SQUIRREL_API SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v); +SQUIRREL_API SQRESULT sq_suspendvm(HSQUIRRELVM v); +SQUIRREL_API SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval); +SQUIRREL_API SQInteger sq_getvmstate(HSQUIRRELVM v); + +/*compiler*/ +SQUIRREL_API SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror); +SQUIRREL_API SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror); +SQUIRREL_API void sq_enabledebuginfo(HSQUIRRELVM v, SQBool debuginfo); +SQUIRREL_API void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f); + +/*stack operations*/ +SQUIRREL_API void sq_push(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API void sq_pop(HSQUIRRELVM v,SQInteger nelemstopop); +SQUIRREL_API void sq_poptop(HSQUIRRELVM v); +SQUIRREL_API void sq_remove(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQInteger sq_gettop(HSQUIRRELVM v); +SQUIRREL_API void sq_settop(HSQUIRRELVM v,SQInteger newtop); +SQUIRREL_API void sq_reservestack(HSQUIRRELVM v,SQInteger nsize); +SQUIRREL_API SQInteger sq_cmp(HSQUIRRELVM v); +SQUIRREL_API void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx); + +/*object creation handling*/ +SQUIRREL_API SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size); +SQUIRREL_API void sq_newtable(HSQUIRRELVM v); +SQUIRREL_API void sq_newarray(HSQUIRRELVM v,SQInteger size); +SQUIRREL_API void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars); +SQUIRREL_API SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask); +SQUIRREL_API void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len); +SQUIRREL_API void sq_pushfloat(HSQUIRRELVM v,SQFloat f); +SQUIRREL_API void sq_pushinteger(HSQUIRRELVM v,SQInteger n); +SQUIRREL_API void sq_pushbool(HSQUIRRELVM v,SQBool b); +SQUIRREL_API void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p); +SQUIRREL_API void sq_pushnull(HSQUIRRELVM v); +SQUIRREL_API SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQInteger sq_getsize(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API void sq_tostring(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c); +SQUIRREL_API SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i); +SQUIRREL_API SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f); +SQUIRREL_API SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b); +SQUIRREL_API SQRESULT sq_getthread(HSQUIRRELVM v,SQInteger idx,HSQUIRRELVM *thread); +SQUIRREL_API SQRESULT sq_getuserpointer(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p); +SQUIRREL_API SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag); +SQUIRREL_API SQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag); +SQUIRREL_API SQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag); +SQUIRREL_API void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook); +SQUIRREL_API SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize); +SQUIRREL_API SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger *nparams,SQUnsignedInteger *nfreevars); +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_newclass(HSQUIRRELVM v,SQBool hasbase); +SQUIRREL_API SQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_setattributes(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API void sq_weakref(HSQUIRRELVM v,SQInteger idx); + +/*object manipulation*/ +SQUIRREL_API void sq_pushroottable(HSQUIRRELVM v); +SQUIRREL_API void sq_pushregistrytable(HSQUIRRELVM v); +SQUIRREL_API SQRESULT sq_setroottable(HSQUIRRELVM v); +SQUIRREL_API SQRESULT sq_createslot(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval); +SQUIRREL_API SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval); +SQUIRREL_API SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQBool pushval); +SQUIRREL_API SQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize); +SQUIRREL_API SQRESULT sq_arrayreverse(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_clone(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval); +SQUIRREL_API SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx); + +/*calls*/ +SQUIRREL_API SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval); +SQUIRREL_API SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval); +SQUIRREL_API const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx); +SQUIRREL_API const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval); +SQUIRREL_API SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err); +SQUIRREL_API void sq_reseterror(HSQUIRRELVM v); +SQUIRREL_API void sq_getlasterror(HSQUIRRELVM v); + +/*raw object handling*/ +SQUIRREL_API SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po); +SQUIRREL_API void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj); +SQUIRREL_API void sq_addref(HSQUIRRELVM v,HSQOBJECT *po); +SQUIRREL_API SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po); +SQUIRREL_API void sq_resetobject(HSQOBJECT *po); +SQUIRREL_API const SQChar *sq_objtostring(HSQOBJECT *o); +SQUIRREL_API SQBool sq_objtobool(HSQOBJECT *o); +SQUIRREL_API SQInteger sq_objtointeger(HSQOBJECT *o); +SQUIRREL_API SQFloat sq_objtofloat(HSQOBJECT *o); + +/*GC*/ +SQUIRREL_API SQInteger sq_collectgarbage(HSQUIRRELVM v); + +/*serialization*/ +SQUIRREL_API SQRESULT sq_writeclosure(HSQUIRRELVM vm,SQWRITEFUNC writef,SQUserPointer up); +SQUIRREL_API SQRESULT sq_readclosure(HSQUIRRELVM vm,SQREADFUNC readf,SQUserPointer up); + +/*mem allocation*/ +SQUIRREL_API void *sq_malloc(SQUnsignedInteger size); +SQUIRREL_API void *sq_realloc(void* p,SQUnsignedInteger oldsize,SQUnsignedInteger newsize); +SQUIRREL_API void sq_free(void *p,SQUnsignedInteger size); + +/*debug*/ +SQUIRREL_API SQRESULT sq_stackinfos(HSQUIRRELVM v,SQInteger level,SQStackInfos *si); +SQUIRREL_API void sq_setdebughook(HSQUIRRELVM v); + +/*UTILITY MACRO*/ +#define sq_isnumeric(o) ((o)._type&SQOBJECT_NUMERIC) +#define sq_istable(o) ((o)._type==OT_TABLE) +#define sq_isarray(o) ((o)._type==OT_ARRAY) +#define sq_isfunction(o) ((o)._type==OT_FUNCPROTO) +#define sq_isclosure(o) ((o)._type==OT_CLOSURE) +#define sq_isgenerator(o) ((o)._type==OT_GENERATOR) +#define sq_isnativeclosure(o) ((o)._type==OT_NATIVECLOSURE) +#define sq_isstring(o) ((o)._type==OT_STRING) +#define sq_isinteger(o) ((o)._type==OT_INTEGER) +#define sq_isfloat(o) ((o)._type==OT_FLOAT) +#define sq_isuserpointer(o) ((o)._type==OT_USERPOINTER) +#define sq_isuserdata(o) ((o)._type==OT_USERDATA) +#define sq_isthread(o) ((o)._type==OT_THREAD) +#define sq_isnull(o) ((o)._type==OT_NULL) +#define sq_isclass(o) ((o)._type==OT_CLASS) +#define sq_isinstance(o) ((o)._type==OT_INSTANCE) +#define sq_isbool(o) ((o)._type==OT_BOOL) +#define sq_isweakref(o) ((o)._type==OT_WEAKREF) +#define sq_type(o) ((o)._type) + +#define SQ_OK (0) +#define SQ_ERROR (-1) + +#define SQ_FAILED(res) (res<0) +#define SQ_SUCCEEDED(res) (res>=0) + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*_SQUIRREL_H_*/ diff --git a/src/squirrel/sqstdlib/sqstdaux.cpp b/src/squirrel/sqstdlib/sqstdaux.cpp index 62a159845..30808ed41 100644 --- a/src/squirrel/sqstdlib/sqstdaux.cpp +++ b/src/squirrel/sqstdlib/sqstdaux.cpp @@ -1,116 +1,116 @@ -/* see copyright notice in squirrel.h */ -#include -#include - -void sqstd_printcallstack(HSQUIRRELVM v) -{ - SQPRINTFUNCTION pf = sq_getprintfunc(v); - if(pf) { - SQStackInfos si; - SQInteger i; - SQFloat f; - const SQChar *s; - int level=1; //1 is to skip this function that is level 0 - const SQChar *name=0; - int seq=0; - pf(v,_SC("\nCALLSTACK\n")); - while(SQ_SUCCEEDED(sq_stackinfos(v,level,&si))) - { - const SQChar *fn=_SC("unknown"); - const SQChar *src=_SC("unknown"); - if(si.funcname)fn=si.funcname; - if(si.source)src=si.source; - pf(v,_SC("*FUNCTION [%s()] %s line [%d]\n"),fn,src,si.line); - level++; - } - level=0; - pf(v,_SC("\nLOCALS\n")); - - for(level=0;level<10;level++){ - seq=0; - while(name=sq_getlocal(v,level,seq)) - { - seq++; - switch(sq_gettype(v,-1)) - { - case OT_NULL: - pf(v,_SC("[%s] NULL\n"),name); - break; - case OT_INTEGER: - sq_getinteger(v,-1,&i); - pf(v,_SC("[%s] %d\n"),name,i); - break; - case OT_FLOAT: - sq_getfloat(v,-1,&f); - pf(v,_SC("[%s] %.14g\n"),name,f); - break; - case OT_USERPOINTER: - pf(v,_SC("[%s] USERPOINTER\n"),name); - break; - case OT_STRING: - sq_getstring(v,-1,&s); - pf(v,_SC("[%s] \"%s\"\n"),name,s); - break; - case OT_TABLE: - pf(v,_SC("[%s] TABLE\n"),name); - break; - case OT_ARRAY: - pf(v,_SC("[%s] ARRAY\n"),name); - break; - case OT_CLOSURE: - pf(v,_SC("[%s] CLOSURE\n"),name); - break; - case OT_NATIVECLOSURE: - pf(v,_SC("[%s] NATIVECLOSURE\n"),name); - break; - case OT_USERDATA: - pf(v,_SC("[%s] USERDATA\n"),name); - break; - case OT_THREAD: - pf(v,_SC("[%s] THREAD\n"),name); - break; - case OT_CLASS: - pf(v,_SC("[%s] CLASS\n"),name); - break; - case OT_INSTANCE: - pf(v,_SC("[%s] INSTANCE\n"),name); - break; - } - sq_pop(v,1); - } - } - } -} - -static int _sqstd_aux_printerror(HSQUIRRELVM v) -{ - SQPRINTFUNCTION pf = sq_getprintfunc(v); - if(pf) { - const SQChar *sErr = 0; - if(sq_gettop(v)>=1) { - if(SQ_SUCCEEDED(sq_getstring(v,2,&sErr))) { - pf(v,_SC("\nAN ERROR HAS OCCURED [%s]\n"),sErr); - } - else{ - pf(v,_SC("\nAN ERROR HAS OCCURED [unknown]\n")); - } - sqstd_printcallstack(v); - } - } - return 0; -} - -void _sqstd_compiler_error(HSQUIRRELVM v,const SQChar *sErr,const SQChar *sSource,int line,int column) -{ - SQPRINTFUNCTION pf = sq_getprintfunc(v); - if(pf) { - pf(v,_SC("ERROR %s line=(%d) column=(%d) [%s]\n"),sErr,line,column,sSource); - } -} - -void sqstd_seterrorhandlers(HSQUIRRELVM v) -{ - sq_setcompilererrorhandler(v,_sqstd_compiler_error); - sq_newclosure(v,_sqstd_aux_printerror,0); - sq_seterrorhandler(v); -} +/* see copyright notice in squirrel.h */ +#include +#include + +void sqstd_printcallstack(HSQUIRRELVM v) +{ + SQPRINTFUNCTION pf = sq_getprintfunc(v); + if(pf) { + SQStackInfos si; + SQInteger i; + SQFloat f; + const SQChar *s; + SQInteger level=1; //1 is to skip this function that is level 0 + const SQChar *name=0; + SQInteger seq=0; + pf(v,_SC("\nCALLSTACK\n")); + while(SQ_SUCCEEDED(sq_stackinfos(v,level,&si))) + { + const SQChar *fn=_SC("unknown"); + const SQChar *src=_SC("unknown"); + if(si.funcname)fn=si.funcname; + if(si.source)src=si.source; + pf(v,_SC("*FUNCTION [%s()] %s line [%d]\n"),fn,src,si.line); + level++; + } + level=0; + pf(v,_SC("\nLOCALS\n")); + + for(level=0;level<10;level++){ + seq=0; + while(name=sq_getlocal(v,level,seq)) + { + seq++; + switch(sq_gettype(v,-1)) + { + case OT_NULL: + pf(v,_SC("[%s] NULL\n"),name); + break; + case OT_INTEGER: + sq_getinteger(v,-1,&i); + pf(v,_SC("[%s] %d\n"),name,i); + break; + case OT_FLOAT: + sq_getfloat(v,-1,&f); + pf(v,_SC("[%s] %.14g\n"),name,f); + break; + case OT_USERPOINTER: + pf(v,_SC("[%s] USERPOINTER\n"),name); + break; + case OT_STRING: + sq_getstring(v,-1,&s); + pf(v,_SC("[%s] \"%s\"\n"),name,s); + break; + case OT_TABLE: + pf(v,_SC("[%s] TABLE\n"),name); + break; + case OT_ARRAY: + pf(v,_SC("[%s] ARRAY\n"),name); + break; + case OT_CLOSURE: + pf(v,_SC("[%s] CLOSURE\n"),name); + break; + case OT_NATIVECLOSURE: + pf(v,_SC("[%s] NATIVECLOSURE\n"),name); + break; + case OT_USERDATA: + pf(v,_SC("[%s] USERDATA\n"),name); + break; + case OT_THREAD: + pf(v,_SC("[%s] THREAD\n"),name); + break; + case OT_CLASS: + pf(v,_SC("[%s] CLASS\n"),name); + break; + case OT_INSTANCE: + pf(v,_SC("[%s] INSTANCE\n"),name); + break; + } + sq_pop(v,1); + } + } + } +} + +static SQInteger _sqstd_aux_printerror(HSQUIRRELVM v) +{ + SQPRINTFUNCTION pf = sq_getprintfunc(v); + if(pf) { + const SQChar *sErr = 0; + if(sq_gettop(v)>=1) { + if(SQ_SUCCEEDED(sq_getstring(v,2,&sErr))) { + pf(v,_SC("\nAN ERROR HAS OCCURED [%s]\n"),sErr); + } + else{ + pf(v,_SC("\nAN ERROR HAS OCCURED [unknown]\n")); + } + sqstd_printcallstack(v); + } + } + return 0; +} + +void _sqstd_compiler_error(HSQUIRRELVM v,const SQChar *sErr,const SQChar *sSource,SQInteger line,SQInteger column) +{ + SQPRINTFUNCTION pf = sq_getprintfunc(v); + if(pf) { + pf(v,_SC("%s line = (%d) column = (%d) : error %s\n"),sSource,line,column,sErr); + } +} + +void sqstd_seterrorhandlers(HSQUIRRELVM v) +{ + sq_setcompilererrorhandler(v,_sqstd_compiler_error); + sq_newclosure(v,_sqstd_aux_printerror,0); + sq_seterrorhandler(v); +} diff --git a/src/squirrel/sqstdlib/sqstdblob.cpp b/src/squirrel/sqstdlib/sqstdblob.cpp index 6dfb760c8..9b0fe5949 100644 --- a/src/squirrel/sqstdlib/sqstdblob.cpp +++ b/src/squirrel/sqstdlib/sqstdblob.cpp @@ -1,255 +1,251 @@ -/* see copyright notice in squirrel.h */ -#include -#include -#include -#include -#include -#include "sqstdstream.h" -#include "sqstdblobimpl.h" - -#define SQSTD_BLOB_TYPE_TAG (SQSTD_STREAM_TYPE_TAG | 0x00000002) - -//Blob - - -#define SETUP_BLOB(v) \ - SQBlob *self = NULL; \ - { if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,SQSTD_BLOB_TYPE_TAG))) \ - return SQ_ERROR; } - - -static int _blob_resize(HSQUIRRELVM v) -{ - SETUP_BLOB(v); - SQInteger size; - sq_getinteger(v,2,&size); - if(!self->Resize(size)) - return sq_throwerror(v,_SC("resize failed")); - return 0; -} - -static void __swap_dword(unsigned int *n) -{ - *n=(unsigned int)(((*n&0xFF000000)>>24) | - ((*n&0x00FF0000)>>8) | - ((*n&0x0000FF00)<<8) | - ((*n&0x000000FF)<<24)); -} - -static void __swap_word(unsigned short *n) -{ - *n=(unsigned short)((*n>>8)&0x00FF)| ((*n<<8)&0xFF00); -} - -static int _blob_swap4(HSQUIRRELVM v) -{ - SETUP_BLOB(v); - int num=(self->Len()-(self->Len()%4))>>2; - unsigned int *t=(unsigned int *)self->GetBuf(); - for(int i = 0; i < num; i++) { - __swap_dword(&t[i]); - } - return 0; -} - -static int _blob_swap2(HSQUIRRELVM v) -{ - SETUP_BLOB(v); - int num=(self->Len()-(self->Len()%2))>>1; - unsigned short *t = (unsigned short *)self->GetBuf(); - for(int i = 0; i < num; i++) { - __swap_word(&t[i]); - } - return 0; -} - -static int _blob__set(HSQUIRRELVM v) -{ - SETUP_BLOB(v); - SQInteger idx,val; - sq_getinteger(v,2,&idx); - sq_getinteger(v,3,&val); - if(idx < 0 || idx >= self->Len()) - return sq_throwerror(v,_SC("index out of range")); - ((unsigned char *)self->GetBuf())[idx] = (unsigned char) val; - sq_push(v,3); - return 1; -} - -static int _blob__get(HSQUIRRELVM v) -{ - SETUP_BLOB(v); - SQInteger idx; - sq_getinteger(v,2,&idx); - if(idx < 0 || idx >= self->Len()) - return sq_throwerror(v,_SC("index out of range")); - sq_pushinteger(v,((unsigned char *)self->GetBuf())[idx]); - return 1; -} - -static int _blob__nexti(HSQUIRRELVM v) -{ - SETUP_BLOB(v); - if(sq_gettype(v,2) == OT_NULL) { - sq_pushinteger(v, 0); - return 1; - } - SQInteger idx; - if(SQ_SUCCEEDED(sq_getinteger(v, 2, &idx))) { - if(idx+1 < self->Len()) { - sq_pushinteger(v, idx+1); - return 1; - } - sq_pushnull(v); - return 1; - } - return sq_throwerror(v,_SC("internal error (_nexti) wrong argument type")); -} - -static int _blob__typeof(HSQUIRRELVM v) -{ - sq_pushstring(v,_SC("blob"),-1); - return 1; -} - -static int _blob_releasehook(SQUserPointer p, int size) -{ - SQBlob *self = (SQBlob*)p; - delete self; - return 1; -} - -static int _blob_constructor(HSQUIRRELVM v) -{ - SQInteger nparam = sq_gettop(v); - SQInteger size = 0; - if(nparam == 2) { - sq_getinteger(v, 2, &size); - } - if(size < 0) return sq_throwerror(v, _SC("cannot create blob with negative size")); - SQBlob *b = new SQBlob(size); - if(SQ_FAILED(sq_setinstanceup(v,1,b))) { - delete b; - return sq_throwerror(v, _SC("cannot create blob with negative size")); - } - sq_setreleasehook(v,1,_blob_releasehook); - return 0; -} - -#define _DECL_BLOB_FUNC(name,nparams,typecheck) {_SC(#name),_blob_##name,nparams,typecheck} -static SQRegFunction _blob_methods[] = { - _DECL_BLOB_FUNC(constructor,-1,_SC("xn")), - _DECL_BLOB_FUNC(resize,2,_SC("xn")), - _DECL_BLOB_FUNC(swap2,1,_SC("x")), - _DECL_BLOB_FUNC(swap4,1,_SC("x")), - _DECL_BLOB_FUNC(_set,3,_SC("xnn")), - _DECL_BLOB_FUNC(_get,2,_SC("xn")), - _DECL_BLOB_FUNC(_typeof,1,_SC("x")), - _DECL_BLOB_FUNC(_nexti,2,_SC("x")), - {0,0,0,0} -}; - - - -//GLOBAL FUNCTIONS - -static int _g_blob_casti2f(HSQUIRRELVM v) -{ - SQInteger i; - sq_getinteger(v,2,&i); - sq_pushfloat(v,*((SQFloat *)&i)); - return 1; -} - -static int _g_blob_castf2i(HSQUIRRELVM v) -{ - SQFloat f; - sq_getfloat(v,2,&f); - sq_pushinteger(v,*((SQInteger *)&f)); - return 1; -} - -static int _g_blob_swap2(HSQUIRRELVM v) -{ - SQInteger i; - sq_getinteger(v,2,&i); - short s=(short)i; - sq_pushinteger(v,(s<<8)|((s>>8)&0x00FF)); - return 1; -} - -static int _g_blob_swap4(HSQUIRRELVM v) -{ - SQInteger i; - sq_getinteger(v,2,&i); - __swap_dword((unsigned int *)&i); - sq_pushinteger(v,i); - return 1; -} - -static int _g_blob_swapfloat(HSQUIRRELVM v) -{ - SQFloat f; - sq_getfloat(v,2,&f); - __swap_dword((unsigned int *)&f); - sq_pushfloat(v,f); - return 1; -} - -#define _DECL_GLOBALBLOB_FUNC(name,nparams,typecheck) {_SC(#name),_g_blob_##name,nparams,typecheck} -static SQRegFunction bloblib_funcs[]={ - _DECL_GLOBALBLOB_FUNC(casti2f,2,_SC(".n")), - _DECL_GLOBALBLOB_FUNC(castf2i,2,_SC(".n")), - _DECL_GLOBALBLOB_FUNC(swap2,2,_SC(".n")), - _DECL_GLOBALBLOB_FUNC(swap4,2,_SC(".n")), - _DECL_GLOBALBLOB_FUNC(swapfloat,2,_SC(".n")), - {0,0} -}; - -SQRESULT sqstd_getblob(HSQUIRRELVM v,int idx,SQUserPointer *ptr) -{ - SQBlob *blob; - if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,SQSTD_BLOB_TYPE_TAG))) - return -1; - *ptr = blob->GetBuf(); - return SQ_OK; -} - -int sqstd_getblobsize(HSQUIRRELVM v,int idx) -{ - SQBlob *blob; - if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,SQSTD_BLOB_TYPE_TAG))) - return -1; - return blob->Len(); -} - -SQUserPointer sqstd_createblob(HSQUIRRELVM v, int size) -{ - int top = sq_gettop(v); -// SQUserPointer p = sq_newuserdata(v, sizeof(SQBlob)); -// sq_setreleasehook(v,-1,_blob_releasehook); -// sq_settypetag(v,-1,SQSTD_BLOB_TYPE_TAG); -// new (p) SQBlob(size); - sq_pushregistrytable(v); - sq_pushstring(v,_SC("std_blob"),-1); - if(SQ_SUCCEEDED(sq_get(v,-2))) { - sq_remove(v,-2); //removes the registry - sq_push(v,1); // push the this - sq_pushinteger(v,size); //size - SQBlob *blob = NULL; - if(SQ_SUCCEEDED(sq_call(v,2,SQTrue)) - && SQ_SUCCEEDED(sq_getinstanceup(v,-1,(SQUserPointer *)&blob,SQSTD_BLOB_TYPE_TAG))) { - sq_remove(v,-2); - sq_remove(v,-2); - return blob->GetBuf(); - } - } - sq_settop(v,top); - return NULL; -} - -SQRESULT sqstd_register_bloblib(HSQUIRRELVM v) -{ - return declare_stream(v,_SC("blob"),SQSTD_BLOB_TYPE_TAG,_SC("std_blob"),_blob_methods,bloblib_funcs); -} - +/* see copyright notice in squirrel.h */ +#include +#include +#include +#include +#include +#include "sqstdstream.h" +#include "sqstdblobimpl.h" + +#define SQSTD_BLOB_TYPE_TAG (SQSTD_STREAM_TYPE_TAG | 0x00000002) + +//Blob + + +#define SETUP_BLOB(v) \ + SQBlob *self = NULL; \ + { if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) \ + return SQ_ERROR; } + + +static SQInteger _blob_resize(HSQUIRRELVM v) +{ + SETUP_BLOB(v); + SQInteger size; + sq_getinteger(v,2,&size); + if(!self->Resize(size)) + return sq_throwerror(v,_SC("resize failed")); + return 0; +} + +static void __swap_dword(unsigned int *n) +{ + *n=(SQUnsignedInteger)(((*n&0xFF000000)>>24) | + ((*n&0x00FF0000)>>8) | + ((*n&0x0000FF00)<<8) | + ((*n&0x000000FF)<<24)); +} + +static void __swap_word(unsigned short *n) +{ + *n=(unsigned short)((*n>>8)&0x00FF)| ((*n<<8)&0xFF00); +} + +static SQInteger _blob_swap4(HSQUIRRELVM v) +{ + SETUP_BLOB(v); + SQInteger num=(self->Len()-(self->Len()%4))>>2; + unsigned int *t=(unsigned int *)self->GetBuf(); + for(SQInteger i = 0; i < num; i++) { + __swap_dword(&t[i]); + } + return 0; +} + +static SQInteger _blob_swap2(HSQUIRRELVM v) +{ + SETUP_BLOB(v); + SQInteger num=(self->Len()-(self->Len()%2))>>1; + unsigned short *t = (unsigned short *)self->GetBuf(); + for(SQInteger i = 0; i < num; i++) { + __swap_word(&t[i]); + } + return 0; +} + +static SQInteger _blob__set(HSQUIRRELVM v) +{ + SETUP_BLOB(v); + SQInteger idx,val; + sq_getinteger(v,2,&idx); + sq_getinteger(v,3,&val); + if(idx < 0 || idx >= self->Len()) + return sq_throwerror(v,_SC("index out of range")); + ((unsigned char *)self->GetBuf())[idx] = (unsigned char) val; + sq_push(v,3); + return 1; +} + +static SQInteger _blob__get(HSQUIRRELVM v) +{ + SETUP_BLOB(v); + SQInteger idx; + sq_getinteger(v,2,&idx); + if(idx < 0 || idx >= self->Len()) + return sq_throwerror(v,_SC("index out of range")); + sq_pushinteger(v,((unsigned char *)self->GetBuf())[idx]); + return 1; +} + +static SQInteger _blob__nexti(HSQUIRRELVM v) +{ + SETUP_BLOB(v); + if(sq_gettype(v,2) == OT_NULL) { + sq_pushinteger(v, 0); + return 1; + } + SQInteger idx; + if(SQ_SUCCEEDED(sq_getinteger(v, 2, &idx))) { + if(idx+1 < self->Len()) { + sq_pushinteger(v, idx+1); + return 1; + } + sq_pushnull(v); + return 1; + } + return sq_throwerror(v,_SC("internal error (_nexti) wrong argument type")); +} + +static SQInteger _blob__typeof(HSQUIRRELVM v) +{ + sq_pushstring(v,_SC("blob"),-1); + return 1; +} + +static SQInteger _blob_releasehook(SQUserPointer p, SQInteger size) +{ + SQBlob *self = (SQBlob*)p; + delete self; + return 1; +} + +static SQInteger _blob_constructor(HSQUIRRELVM v) +{ + SQInteger nparam = sq_gettop(v); + SQInteger size = 0; + if(nparam == 2) { + sq_getinteger(v, 2, &size); + } + if(size < 0) return sq_throwerror(v, _SC("cannot create blob with negative size")); + SQBlob *b = new SQBlob(size); + if(SQ_FAILED(sq_setinstanceup(v,1,b))) { + delete b; + return sq_throwerror(v, _SC("cannot create blob with negative size")); + } + sq_setreleasehook(v,1,_blob_releasehook); + return 0; +} + +#define _DECL_BLOB_FUNC(name,nparams,typecheck) {_SC(#name),_blob_##name,nparams,typecheck} +static SQRegFunction _blob_methods[] = { + _DECL_BLOB_FUNC(constructor,-1,_SC("xn")), + _DECL_BLOB_FUNC(resize,2,_SC("xn")), + _DECL_BLOB_FUNC(swap2,1,_SC("x")), + _DECL_BLOB_FUNC(swap4,1,_SC("x")), + _DECL_BLOB_FUNC(_set,3,_SC("xnn")), + _DECL_BLOB_FUNC(_get,2,_SC("xn")), + _DECL_BLOB_FUNC(_typeof,1,_SC("x")), + _DECL_BLOB_FUNC(_nexti,2,_SC("x")), + {0,0,0,0} +}; + + + +//GLOBAL FUNCTIONS + +static SQInteger _g_blob_casti2f(HSQUIRRELVM v) +{ + SQInteger i; + sq_getinteger(v,2,&i); + sq_pushfloat(v,*((SQFloat *)&i)); + return 1; +} + +static SQInteger _g_blob_castf2i(HSQUIRRELVM v) +{ + SQFloat f; + sq_getfloat(v,2,&f); + sq_pushinteger(v,*((SQInteger *)&f)); + return 1; +} + +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)); + return 1; +} + +static SQInteger _g_blob_swap4(HSQUIRRELVM v) +{ + SQInteger i; + sq_getinteger(v,2,&i); + __swap_dword((SQUnsignedInteger *)&i); + sq_pushinteger(v,i); + return 1; +} + +static SQInteger _g_blob_swapfloat(HSQUIRRELVM v) +{ + SQFloat f; + sq_getfloat(v,2,&f); + __swap_dword((SQUnsignedInteger *)&f); + sq_pushfloat(v,f); + return 1; +} + +#define _DECL_GLOBALBLOB_FUNC(name,nparams,typecheck) {_SC(#name),_g_blob_##name,nparams,typecheck} +static SQRegFunction bloblib_funcs[]={ + _DECL_GLOBALBLOB_FUNC(casti2f,2,_SC(".n")), + _DECL_GLOBALBLOB_FUNC(castf2i,2,_SC(".n")), + _DECL_GLOBALBLOB_FUNC(swap2,2,_SC(".n")), + _DECL_GLOBALBLOB_FUNC(swap4,2,_SC(".n")), + _DECL_GLOBALBLOB_FUNC(swapfloat,2,_SC(".n")), + {0,0} +}; + +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))) + return -1; + *ptr = blob->GetBuf(); + return SQ_OK; +} + +SQInteger sqstd_getblobsize(HSQUIRRELVM v,SQInteger idx) +{ + SQBlob *blob; + if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) + return -1; + return blob->Len(); +} + +SQUserPointer sqstd_createblob(HSQUIRRELVM v, SQInteger size) +{ + SQInteger top = sq_gettop(v); + sq_pushregistrytable(v); + sq_pushstring(v,_SC("std_blob"),-1); + if(SQ_SUCCEEDED(sq_get(v,-2))) { + sq_remove(v,-2); //removes the registry + sq_push(v,1); // push the this + sq_pushinteger(v,size); //size + SQBlob *blob = NULL; + if(SQ_SUCCEEDED(sq_call(v,2,SQTrue)) + && SQ_SUCCEEDED(sq_getinstanceup(v,-1,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) { + sq_remove(v,-2); + sq_remove(v,-2); + return blob->GetBuf(); + } + } + sq_settop(v,top); + return NULL; +} + +SQRESULT sqstd_register_bloblib(HSQUIRRELVM v) +{ + return declare_stream(v,_SC("blob"),(SQUserPointer)SQSTD_BLOB_TYPE_TAG,_SC("std_blob"),_blob_methods,bloblib_funcs); +} + diff --git a/src/squirrel/sqstdlib/sqstdblobimpl.h b/src/squirrel/sqstdlib/sqstdblobimpl.h index 8e1fddb49..b927e7c4e 100644 --- a/src/squirrel/sqstdlib/sqstdblobimpl.h +++ b/src/squirrel/sqstdlib/sqstdblobimpl.h @@ -1,108 +1,108 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQSTD_BLOBIMPL_H_ -#define _SQSTD_BLOBIMPL_H_ - -struct SQBlob : public SQStream -{ - SQBlob(int size) { - _size = size; - _allocated = size; - _buf = (unsigned char *)sq_malloc(size); - memset(_buf, 0, _size); - _ptr = 0; - _owns = true; - } - ~SQBlob() { - sq_free(_buf, _size); - } - SQInteger Write(void *buffer, SQInteger size) { - if(!CanAdvance(size)) { - GrowBufOf(_ptr + size - _size); - } - memcpy(&_buf[_ptr], buffer, size); - _ptr += size; - return size; - } - SQInteger Read(void *buffer,SQInteger size) { - int n = size; - if(!CanAdvance(size)) { - if((_size - _ptr) > 0) - n = _size - _ptr; - else return 0; - } - memcpy(buffer, &_buf[_ptr], n); - _ptr += n; - return n; - } - bool Resize(int n) { - if(!_owns) return false; - if(n != _allocated) { - unsigned char *newbuf = (unsigned char *)sq_malloc(n); - memset(newbuf,0,n); - if(_size > n) - memcpy(newbuf,_buf,n); - else - memcpy(newbuf,_buf,_size); - sq_free(_buf,_allocated); - _buf=newbuf; - _allocated = n; - if(_size > _allocated) - _size = _allocated; - if(_ptr > _allocated) - _ptr = _allocated; - } - return true; - } - bool GrowBufOf(int n) - { - bool ret = true; - if(_size + n > _allocated) { - if(_size + n > _size * 2) - ret = Resize(_size + n); - else - ret = Resize(_size * 2); - } - _size = _size + n; - return ret; - } - bool CanAdvance(int n) { - if(_ptr+n>_size)return false; - return true; - } - SQInteger Seek(long offset, int origin) { - switch(origin) { - case SQ_SEEK_SET: - if(offset >= _size || offset < 0) return -1; - _ptr = offset; - break; - case SQ_SEEK_CUR: - if(_ptr + offset >= _size || _ptr + offset < 0) return -1; - _ptr += offset; - break; - case SQ_SEEK_END: - if(_size + offset >= _size || _size + offset < 0) return -1; - _ptr = _size + offset; - break; - default: return -1; - } - return 0; - } - bool IsValid() { - return _buf?true:false; - } - bool EOS() { - return _ptr == _size; - } - int Flush() { return 0; } - long Tell() { return _ptr; } - SQInteger Len() { return _size; } - SQUserPointer GetBuf(){ return _buf; } -private: - int _size; - int _allocated; - int _ptr; - unsigned char *_buf; - bool _owns; -}; - -#endif //_SQSTD_BLOBIMPL_H_ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_BLOBIMPL_H_ +#define _SQSTD_BLOBIMPL_H_ + +struct SQBlob : public SQStream +{ + SQBlob(SQInteger size) { + _size = size; + _allocated = size; + _buf = (unsigned char *)sq_malloc(size); + memset(_buf, 0, _size); + _ptr = 0; + _owns = true; + } + ~SQBlob() { + sq_free(_buf, _allocated); + } + SQInteger Write(void *buffer, SQInteger size) { + if(!CanAdvance(size)) { + GrowBufOf(_ptr + size - _size); + } + memcpy(&_buf[_ptr], buffer, size); + _ptr += size; + return size; + } + SQInteger Read(void *buffer,SQInteger size) { + SQInteger n = size; + if(!CanAdvance(size)) { + if((_size - _ptr) > 0) + n = _size - _ptr; + else return 0; + } + memcpy(buffer, &_buf[_ptr], n); + _ptr += n; + return n; + } + bool Resize(SQInteger n) { + if(!_owns) return false; + if(n != _allocated) { + unsigned char *newbuf = (unsigned char *)sq_malloc(n); + memset(newbuf,0,n); + if(_size > n) + memcpy(newbuf,_buf,n); + else + memcpy(newbuf,_buf,_size); + sq_free(_buf,_allocated); + _buf=newbuf; + _allocated = n; + if(_size > _allocated) + _size = _allocated; + if(_ptr > _allocated) + _ptr = _allocated; + } + return true; + } + bool GrowBufOf(SQInteger n) + { + bool ret = true; + if(_size + n > _allocated) { + if(_size + n > _size * 2) + ret = Resize(_size + n); + else + ret = Resize(_size * 2); + } + _size = _size + n; + return ret; + } + bool CanAdvance(SQInteger n) { + if(_ptr+n>_size)return false; + return true; + } + SQInteger Seek(SQInteger offset, SQInteger origin) { + switch(origin) { + case SQ_SEEK_SET: + if(offset > _size || offset < 0) return -1; + _ptr = offset; + break; + case SQ_SEEK_CUR: + if(_ptr + offset > _size || _ptr + offset < 0) return -1; + _ptr += offset; + break; + case SQ_SEEK_END: + if(_size + offset > _size || _size + offset < 0) return -1; + _ptr = _size + offset; + break; + default: return -1; + } + return 0; + } + bool IsValid() { + return _buf?true:false; + } + bool EOS() { + return _ptr == _size; + } + SQInteger Flush() { return 0; } + SQInteger Tell() { return _ptr; } + SQInteger Len() { return _size; } + SQUserPointer GetBuf(){ return _buf; } +private: + SQInteger _size; + SQInteger _allocated; + SQInteger _ptr; + unsigned char *_buf; + bool _owns; +}; + +#endif //_SQSTD_BLOBIMPL_H_ diff --git a/src/squirrel/sqstdlib/sqstdio.cpp b/src/squirrel/sqstdlib/sqstdio.cpp index 7534697bc..396d2226c 100644 --- a/src/squirrel/sqstdlib/sqstdio.cpp +++ b/src/squirrel/sqstdlib/sqstdio.cpp @@ -1,400 +1,401 @@ -/* see copyright notice in squirrel.h */ -#include -#include -#include -#include -#include "sqstdstream.h" - -#define SQSTD_FILE_TYPE_TAG (SQSTD_STREAM_TYPE_TAG | 0x00000001) -//basic API -SQFILE sqstd_fopen(const SQChar *filename ,const SQChar *mode) -{ -#ifndef _UNICODE - return (SQFILE)fopen(filename,mode); -#else - return (SQFILE)_wfopen(filename,mode); -#endif -} - -SQInteger sqstd_fread(void* buffer, SQInteger size, SQInteger count, SQFILE file) -{ - return (SQInteger)fread(buffer,size,count,(FILE *)file); -} - -SQInteger sqstd_fwrite(const SQUserPointer buffer, SQInteger size, SQInteger count, SQFILE file) -{ - return (SQInteger)fwrite(buffer,size,count,(FILE *)file); -} - -SQInteger sqstd_fseek(SQFILE file, long offset, int origin) -{ - int realorigin; - switch(origin) { - case SQ_SEEK_CUR: realorigin = SEEK_CUR; break; - case SQ_SEEK_END: realorigin = SEEK_END; break; - case SQ_SEEK_SET: realorigin = SEEK_SET; break; - default: return -1; //failed - } - return fseek((FILE *)file,offset,realorigin); -} - -long sqstd_ftell(SQFILE file) -{ - return ftell((FILE *)file); -} - -SQInteger sqstd_fflush(SQFILE file) -{ - return fflush((FILE *)file); -} - -SQInteger sqstd_fclose(SQFILE file) -{ - return fclose((FILE *)file); -} - -SQInteger sqstd_feof(SQFILE file) -{ - return feof((FILE *)file); -} - -//File -struct SQFile : public SQStream { - SQFile() { _handle = NULL; _owns = false;} - SQFile(SQFILE file, bool owns) { _handle = file; _owns = owns;} - ~SQFile() { Close(); } - bool Open(const SQChar *filename ,const SQChar *mode) { - Close(); - if(_handle = sqstd_fopen(filename,mode)) { - _owns = true; - return true; - } - return false; - } - void Close() { - if(_handle && _owns) { - sqstd_fclose(_handle); - _handle = NULL; - _owns = false; - } - } - SQInteger Read(void *buffer,SQInteger size) { - return sqstd_fread(buffer,1,size,_handle); - } - SQInteger Write(void *buffer,SQInteger size) { - return sqstd_fwrite(buffer,1,size,_handle); - } - int Flush() { - return sqstd_fflush(_handle); - } - long Tell() { - return sqstd_ftell(_handle); - } - SQInteger Len() { - int prevpos=Tell(); - Seek(0,SQ_SEEK_END); - int size=Tell(); - Seek(prevpos,SQ_SEEK_SET); - return size; - } - SQInteger Seek(long offset, int origin) { - return sqstd_fseek(_handle,offset,origin); - } - bool IsValid() { return _handle?true:false; } - bool EOS() { return Tell()==Len()?true:false;} - SQFILE GetHandle() {return _handle;} -private: - SQFILE _handle; - bool _owns; -}; - -static int _file__typeof(HSQUIRRELVM v) -{ - sq_pushstring(v,_SC("file"),-1); - return 1; -} - -static int _file_releasehook(SQUserPointer p, int size) -{ - SQFile *self = (SQFile*)p; - delete self; - return 1; -} - -static int _file_constructor(HSQUIRRELVM v) -{ - const SQChar *filename,*mode; - bool owns = true; - SQFile *f; - SQFILE newf; - if(sq_gettype(v,2) == OT_STRING && sq_gettype(v,3) == OT_STRING) { - sq_getstring(v, 2, &filename); - sq_getstring(v, 3, &mode); - newf = sqstd_fopen(filename, mode); - if(!newf) return sq_throwerror(v, _SC("cannot open file")); - } else if(sq_gettype(v,2) == OT_USERPOINTER) { - owns = !(sq_gettype(v,3) == OT_NULL); - sq_getuserpointer(v,2,&newf); - } else { - return sq_throwerror(v,_SC("wrong parameter")); - } - f = new SQFile(newf,owns); - if(SQ_FAILED(sq_setinstanceup(v,1,f))) { - delete f; - return sq_throwerror(v, _SC("cannot create blob with negative size")); - } - sq_setreleasehook(v,1,_file_releasehook); - return 0; -} - -//bindings -#define _DECL_FILE_FUNC(name,nparams,typecheck) {_SC(#name),_file_##name,nparams,typecheck} -static SQRegFunction _file_methods[] = { - _DECL_FILE_FUNC(constructor,3,_SC("x")), - _DECL_FILE_FUNC(_typeof,1,_SC("x")), - {0,0,0,0}, -}; - - - -SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own) -{ - int top = sq_gettop(v); - sq_pushregistrytable(v); - sq_pushstring(v,_SC("std_file"),-1); - if(SQ_SUCCEEDED(sq_get(v,-2))) { - sq_remove(v,-2); //removes the registry - sq_pushroottable(v); // push the this - sq_pushuserpointer(v,file); //file - if(own){ - sq_pushinteger(v,1); //true - } - else{ - sq_pushnull(v); //false - } - if(SQ_SUCCEEDED( sq_call(v,3,SQTrue) )) { - sq_remove(v,-2); - return SQ_OK; - } - } - sq_settop(v,top); - return SQ_OK; -} - -SQRESULT sqstd_getfile(HSQUIRRELVM v, int idx, SQFILE *file) -{ - SQFile *fileobj = NULL; - if(SQ_SUCCEEDED(sq_getinstanceup(v,idx,(SQUserPointer*)&fileobj,SQSTD_FILE_TYPE_TAG))) { - *file = fileobj->GetHandle(); - return SQ_OK; - } - return sq_throwerror(v,_SC("not a file")); -} - - - -static SQInteger _io_file_lexfeedASCII(SQUserPointer file) -{ - int ret; - char c; - if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) ) - return c; - return 0; -} - -static SQInteger _io_file_lexfeed_UTF8(SQUserPointer file) -{ -#define READ() \ - if(sqstd_fread(&inchar,sizeof(inchar),1,(FILE *)file) != 1) \ - return 0; - - static const int utf8_lengths[16] = - { - 1,1,1,1,1,1,1,1, /* 0000 to 0111 : 1 byte (plain ASCII) */ - 0,0,0,0, /* 1000 to 1011 : not valid */ - 2,2, /* 1100, 1101 : 2 bytes */ - 3, /* 1110 : 3 bytes */ - 4 /* 1111 :4 bytes */ - }; - static unsigned char byte_masks[5] = {0,0,0x1f,0x0f,0x07}; - unsigned char inchar; - int c = 0; - READ(); - c = inchar; - // - if(c >= 0x80) { - int tmp; - int codelen = utf8_lengths[c>>4]; - if(codelen == 0) - return 0; - //"invalid UTF-8 stream"; - tmp = c&byte_masks[codelen]; - for(int n = 0; n < codelen-1; n++) { - tmp<<=6; - READ(); - tmp |= inchar & 0x3F; - } - c = tmp; - } - return c; -} - -static SQInteger _io_file_lexfeed_UCS2_LE(SQUserPointer file) -{ - int ret; - wchar_t c; - if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) ) - return (SQChar)c; - return 0; -} - -static SQInteger _io_file_lexfeed_UCS2_BE(SQUserPointer file) -{ - int ret; - unsigned short c; - if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) ) { - c = ((c>>8)&0x00FF)| ((c<<8)&0xFF00); - return (SQChar)c; - } - return 0; -} - -int file_read(SQUserPointer file,SQUserPointer buf,int size) -{ - int ret; - if( ( ret = sqstd_fread(buf,1,size,(SQFILE)file ))!=0 )return ret; - return -1; -} - -int file_write(SQUserPointer file,SQUserPointer p,int size) -{ - return sqstd_fwrite(p,1,size,(SQFILE)file); -} - -SQRESULT sqstd_loadfile(HSQUIRRELVM v,const SQChar *filename,SQBool printerror) -{ - SQFILE file = sqstd_fopen(filename,_SC("rb")); - int ret; - unsigned short us; - unsigned char uc; - SQLEXREADFUNC func = _io_file_lexfeed_UTF8; - if(file && (ret = sqstd_fread(&us,1,2,file))){ - if(ret != 2) { - sqstd_fclose(file); - return sq_throwerror(v,_SC("io error")); - } - if(us == SQ_BYTECODE_STREAM_TAG) { //BYTECODE - sqstd_fseek(file,0,SQ_SEEK_SET); - if(SQ_SUCCEEDED(sq_readclosure(v,file_read,file))) { - sqstd_fclose(file); - return SQ_OK; - } - } - else { //SCRIPT - switch(us) - { - //gotta swap the next 2 lines on BIG endian machines - case 0xFFFE: func = _io_file_lexfeed_UCS2_BE; break;//UTF-16 little endian; - case 0xFEFF: func = _io_file_lexfeed_UCS2_LE; break;//UTF-16 big endian; - case 0xBBEF: - if(sqstd_fread(&uc,1,sizeof(uc),file) == 0) { - sqstd_fclose(file); - return sq_throwerror(v,_SC("io error")); - } - if(uc != 0xBF) { - sqstd_fclose(file); - return sq_throwerror(v,_SC("Unrecognozed ecoding")); - } - func = _io_file_lexfeed_UTF8; - break;//UTF-8 ; - default: sqstd_fseek(file,0,SQ_SEEK_SET); break; // ascii - } - - if(SQ_SUCCEEDED(sq_compile(v,func,file,filename,printerror))){ - sqstd_fclose(file); - return SQ_OK; - } - } - sqstd_fclose(file); - return SQ_ERROR; - } - return sq_throwerror(v,_SC("cannot open the file")); -} - -SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool printerror) -{ - if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) { - sq_push(v,-2); - int ntop = sq_gettop(v); - if(SQ_SUCCEEDED(sq_call(v,1,retval))) { - sq_remove(v,retval?-2:-1); //removes the closure - return 1; - } - sq_pop(v,1); //removes the closure - } - return SQ_ERROR; -} - -SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const SQChar *filename) -{ - SQFILE file = sqstd_fopen(filename,_SC("wb+")); - if(!file) return sq_throwerror(v,_SC("cannot open the file")); - if(SQ_SUCCEEDED(sq_writeclosure(v,file_write,file))) { - sqstd_fclose(file); - return SQ_OK; - } - sqstd_fclose(file); - return SQ_ERROR; //forward the error -} - -int _g_io_loadfile(HSQUIRRELVM v) -{ - const SQChar *filename; - SQBool printerror = SQFalse; - sq_getstring(v,2,&filename); - if(sq_gettop(v) >= 3) { - sq_getbool(v,3,&printerror); - } - if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) - return 1; - return SQ_ERROR; //propagates the error -} - -int _g_io_dofile(HSQUIRRELVM v) -{ - const SQChar *filename; - SQBool printerror = SQFalse; - sq_getstring(v,2,&filename); - if(sq_gettop(v) >= 3) { - sq_getbool(v,3,&printerror); - } - sq_push(v,1); //repush the this - if(SQ_SUCCEEDED(sqstd_dofile(v,filename,SQTrue,printerror))) - return 1; - return SQ_ERROR; //propagates the error -} - -#define _DECL_GLOBALIO_FUNC(name,nparams,typecheck) {_SC(#name),_g_io_##name,nparams,typecheck} -static SQRegFunction iolib_funcs[]={ - _DECL_GLOBALIO_FUNC(loadfile,-2,_SC(".sb")), - _DECL_GLOBALIO_FUNC(dofile,-2,_SC(".sb")), - {0,0} -}; - -SQRESULT sqstd_register_iolib(HSQUIRRELVM v) -{ - int top = sq_gettop(v); - //create delegate - declare_stream(v,_SC("file"),SQSTD_FILE_TYPE_TAG,_SC("std_file"),_file_methods,iolib_funcs); - sq_pushstring(v,_SC("stdout"),-1); - sqstd_createfile(v,stdout,SQFalse); - sq_createslot(v,-3); - sq_pushstring(v,_SC("stdin"),-1); - sqstd_createfile(v,stdin,SQFalse); - sq_createslot(v,-3); - sq_pushstring(v,_SC("stderr"),-1); - sqstd_createfile(v,stderr,SQFalse); - sq_createslot(v,-3); - sq_settop(v,top); - return SQ_OK; -} +/* see copyright notice in squirrel.h */ +#include +#include +#include +#include +#include "sqstdstream.h" + +#define SQSTD_FILE_TYPE_TAG (SQSTD_STREAM_TYPE_TAG | 0x00000001) +//basic API +SQFILE sqstd_fopen(const SQChar *filename ,const SQChar *mode) +{ +#ifndef _UNICODE + return (SQFILE)fopen(filename,mode); +#else + return (SQFILE)_wfopen(filename,mode); +#endif +} + +SQInteger sqstd_fread(void* buffer, SQInteger size, SQInteger count, SQFILE file) +{ + return (SQInteger)fread(buffer,size,count,(FILE *)file); +} + +SQInteger sqstd_fwrite(const SQUserPointer buffer, SQInteger size, SQInteger count, SQFILE file) +{ + return (SQInteger)fwrite(buffer,size,count,(FILE *)file); +} + +SQInteger sqstd_fseek(SQFILE file, SQInteger offset, SQInteger origin) +{ + SQInteger realorigin; + switch(origin) { + case SQ_SEEK_CUR: realorigin = SEEK_CUR; break; + case SQ_SEEK_END: realorigin = SEEK_END; break; + case SQ_SEEK_SET: realorigin = SEEK_SET; break; + default: return -1; //failed + } + return fseek((FILE *)file,offset,realorigin); +} + +SQInteger sqstd_ftell(SQFILE file) +{ + return ftell((FILE *)file); +} + +SQInteger sqstd_fflush(SQFILE file) +{ + return fflush((FILE *)file); +} + +SQInteger sqstd_fclose(SQFILE file) +{ + return fclose((FILE *)file); +} + +SQInteger sqstd_feof(SQFILE file) +{ + return feof((FILE *)file); +} + +//File +struct SQFile : public SQStream { + SQFile() { _handle = NULL; _owns = false;} + SQFile(SQFILE file, bool owns) { _handle = file; _owns = owns;} + ~SQFile() { Close(); } + bool Open(const SQChar *filename ,const SQChar *mode) { + Close(); + if(_handle = sqstd_fopen(filename,mode)) { + _owns = true; + return true; + } + return false; + } + void Close() { + if(_handle && _owns) { + sqstd_fclose(_handle); + _handle = NULL; + _owns = false; + } + } + SQInteger Read(void *buffer,SQInteger size) { + return sqstd_fread(buffer,1,size,_handle); + } + SQInteger Write(void *buffer,SQInteger size) { + return sqstd_fwrite(buffer,1,size,_handle); + } + SQInteger Flush() { + return sqstd_fflush(_handle); + } + SQInteger Tell() { + return sqstd_ftell(_handle); + } + SQInteger Len() { + SQInteger prevpos=Tell(); + Seek(0,SQ_SEEK_END); + SQInteger size=Tell(); + Seek(prevpos,SQ_SEEK_SET); + return size; + } + SQInteger Seek(SQInteger offset, SQInteger origin) { + return sqstd_fseek(_handle,offset,origin); + } + bool IsValid() { return _handle?true:false; } + bool EOS() { return Tell()==Len()?true:false;} + SQFILE GetHandle() {return _handle;} +private: + SQFILE _handle; + bool _owns; +}; + +static SQInteger _file__typeof(HSQUIRRELVM v) +{ + sq_pushstring(v,_SC("file"),-1); + return 1; +} + +static SQInteger _file_releasehook(SQUserPointer p, SQInteger size) +{ + SQFile *self = (SQFile*)p; + delete self; + return 1; +} + +static SQInteger _file_constructor(HSQUIRRELVM v) +{ + const SQChar *filename,*mode; + bool owns = true; + SQFile *f; + SQFILE newf; + if(sq_gettype(v,2) == OT_STRING && sq_gettype(v,3) == OT_STRING) { + sq_getstring(v, 2, &filename); + sq_getstring(v, 3, &mode); + newf = sqstd_fopen(filename, mode); + if(!newf) return sq_throwerror(v, _SC("cannot open file")); + } else if(sq_gettype(v,2) == OT_USERPOINTER) { + owns = !(sq_gettype(v,3) == OT_NULL); + sq_getuserpointer(v,2,&newf); + } else { + return sq_throwerror(v,_SC("wrong parameter")); + } + f = new SQFile(newf,owns); + if(SQ_FAILED(sq_setinstanceup(v,1,f))) { + delete f; + return sq_throwerror(v, _SC("cannot create blob with negative size")); + } + sq_setreleasehook(v,1,_file_releasehook); + return 0; +} + +//bindings +#define _DECL_FILE_FUNC(name,nparams,typecheck) {_SC(#name),_file_##name,nparams,typecheck} +static SQRegFunction _file_methods[] = { + _DECL_FILE_FUNC(constructor,3,_SC("x")), + _DECL_FILE_FUNC(_typeof,1,_SC("x")), + {0,0,0,0}, +}; + + + +SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own) +{ + SQInteger top = sq_gettop(v); + sq_pushregistrytable(v); + sq_pushstring(v,_SC("std_file"),-1); + if(SQ_SUCCEEDED(sq_get(v,-2))) { + sq_remove(v,-2); //removes the registry + sq_pushroottable(v); // push the this + sq_pushuserpointer(v,file); //file + if(own){ + sq_pushinteger(v,1); //true + } + else{ + sq_pushnull(v); //false + } + if(SQ_SUCCEEDED( sq_call(v,3,SQTrue) )) { + sq_remove(v,-2); + return SQ_OK; + } + } + sq_settop(v,top); + return SQ_OK; +} + +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))) { + *file = fileobj->GetHandle(); + return SQ_OK; + } + return sq_throwerror(v,_SC("not a file")); +} + + + +static SQInteger _io_file_lexfeed_ASCII(SQUserPointer file) +{ + SQInteger ret; + char c; + if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) ) + return c; + return 0; +} + +static SQInteger _io_file_lexfeed_UTF8(SQUserPointer file) +{ +#define READ() \ + if(sqstd_fread(&inchar,sizeof(inchar),1,(FILE *)file) != 1) \ + return 0; + + static const SQInteger utf8_lengths[16] = + { + 1,1,1,1,1,1,1,1, /* 0000 to 0111 : 1 byte (plain ASCII) */ + 0,0,0,0, /* 1000 to 1011 : not valid */ + 2,2, /* 1100, 1101 : 2 bytes */ + 3, /* 1110 : 3 bytes */ + 4 /* 1111 :4 bytes */ + }; + static unsigned char byte_masks[5] = {0,0,0x1f,0x0f,0x07}; + unsigned char inchar; + SQInteger c = 0; + READ(); + c = inchar; + // + if(c >= 0x80) { + SQInteger tmp; + SQInteger codelen = utf8_lengths[c>>4]; + if(codelen == 0) + return 0; + //"invalid UTF-8 stream"; + tmp = c&byte_masks[codelen]; + for(SQInteger n = 0; n < codelen-1; n++) { + tmp<<=6; + READ(); + tmp |= inchar & 0x3F; + } + c = tmp; + } + return c; +} + +static SQInteger _io_file_lexfeed_UCS2_LE(SQUserPointer file) +{ + SQInteger ret; + wchar_t c; + if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) ) + return (SQChar)c; + return 0; +} + +static SQInteger _io_file_lexfeed_UCS2_BE(SQUserPointer file) +{ + SQInteger ret; + unsigned short c; + if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) ) { + c = ((c>>8)&0x00FF)| ((c<<8)&0xFF00); + return (SQChar)c; + } + return 0; +} + +SQInteger file_read(SQUserPointer file,SQUserPointer buf,SQInteger size) +{ + SQInteger ret; + if( ( ret = sqstd_fread(buf,1,size,(SQFILE)file ))!=0 )return ret; + return -1; +} + +SQInteger file_write(SQUserPointer file,SQUserPointer p,SQInteger size) +{ + return sqstd_fwrite(p,1,size,(SQFILE)file); +} + +SQRESULT sqstd_loadfile(HSQUIRRELVM v,const SQChar *filename,SQBool printerror) +{ + SQFILE file = sqstd_fopen(filename,_SC("rb")); + SQInteger ret; + unsigned short us; + unsigned char uc; + SQLEXREADFUNC func = _io_file_lexfeed_ASCII; + if(file){ + ret = sqstd_fread(&us,1,2,file); + if(ret != 2) { + //probably an empty file + us = 0; + } + if(us == SQ_BYTECODE_STREAM_TAG) { //BYTECODE + sqstd_fseek(file,0,SQ_SEEK_SET); + if(SQ_SUCCEEDED(sq_readclosure(v,file_read,file))) { + sqstd_fclose(file); + return SQ_OK; + } + } + else { //SCRIPT + switch(us) + { + //gotta swap the next 2 lines on BIG endian machines + case 0xFFFE: func = _io_file_lexfeed_UCS2_BE; break;//UTF-16 little endian; + case 0xFEFF: func = _io_file_lexfeed_UCS2_LE; break;//UTF-16 big endian; + case 0xBBEF: + if(sqstd_fread(&uc,1,sizeof(uc),file) == 0) { + sqstd_fclose(file); + return sq_throwerror(v,_SC("io error")); + } + if(uc != 0xBF) { + sqstd_fclose(file); + return sq_throwerror(v,_SC("Unrecognozed ecoding")); + } + func = _io_file_lexfeed_UTF8; + break;//UTF-8 ; + default: sqstd_fseek(file,0,SQ_SEEK_SET); break; // ascii + } + + if(SQ_SUCCEEDED(sq_compile(v,func,file,filename,printerror))){ + sqstd_fclose(file); + return SQ_OK; + } + } + sqstd_fclose(file); + return SQ_ERROR; + } + return sq_throwerror(v,_SC("cannot open the file")); +} + +SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool printerror) +{ + if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) { + sq_push(v,-2); + SQInteger ntop = sq_gettop(v); + if(SQ_SUCCEEDED(sq_call(v,1,retval))) { + sq_remove(v,retval?-2:-1); //removes the closure + return 1; + } + sq_pop(v,1); //removes the closure + } + return SQ_ERROR; +} + +SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const SQChar *filename) +{ + SQFILE file = sqstd_fopen(filename,_SC("wb+")); + if(!file) return sq_throwerror(v,_SC("cannot open the file")); + if(SQ_SUCCEEDED(sq_writeclosure(v,file_write,file))) { + sqstd_fclose(file); + return SQ_OK; + } + sqstd_fclose(file); + return SQ_ERROR; //forward the error +} + +SQInteger _g_io_loadfile(HSQUIRRELVM v) +{ + const SQChar *filename; + SQBool printerror = SQFalse; + sq_getstring(v,2,&filename); + if(sq_gettop(v) >= 3) { + sq_getbool(v,3,&printerror); + } + if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) + return 1; + return SQ_ERROR; //propagates the error +} + +SQInteger _g_io_dofile(HSQUIRRELVM v) +{ + const SQChar *filename; + SQBool printerror = SQFalse; + sq_getstring(v,2,&filename); + if(sq_gettop(v) >= 3) { + sq_getbool(v,3,&printerror); + } + sq_push(v,1); //repush the this + if(SQ_SUCCEEDED(sqstd_dofile(v,filename,SQTrue,printerror))) + return 1; + return SQ_ERROR; //propagates the error +} + +#define _DECL_GLOBALIO_FUNC(name,nparams,typecheck) {_SC(#name),_g_io_##name,nparams,typecheck} +static SQRegFunction iolib_funcs[]={ + _DECL_GLOBALIO_FUNC(loadfile,-2,_SC(".sb")), + _DECL_GLOBALIO_FUNC(dofile,-2,_SC(".sb")), + {0,0} +}; + +SQRESULT sqstd_register_iolib(HSQUIRRELVM v) +{ + SQInteger top = sq_gettop(v); + //create delegate + declare_stream(v,_SC("file"),(SQUserPointer)SQSTD_FILE_TYPE_TAG,_SC("std_file"),_file_methods,iolib_funcs); + sq_pushstring(v,_SC("stdout"),-1); + sqstd_createfile(v,stdout,SQFalse); + sq_createslot(v,-3); + sq_pushstring(v,_SC("stdin"),-1); + sqstd_createfile(v,stdin,SQFalse); + sq_createslot(v,-3); + sq_pushstring(v,_SC("stderr"),-1); + sqstd_createfile(v,stderr,SQFalse); + sq_createslot(v,-3); + sq_settop(v,top); + return SQ_OK; +} diff --git a/src/squirrel/sqstdlib/sqstdmath.cpp b/src/squirrel/sqstdlib/sqstdmath.cpp index f6d4d71c3..3d90ee975 100644 --- a/src/squirrel/sqstdlib/sqstdmath.cpp +++ b/src/squirrel/sqstdlib/sqstdmath.cpp @@ -1,105 +1,105 @@ -/* see copyright notice in squirrel.h */ -#include -#include -#include -#include - -#define SINGLE_ARG_FUNC(_funcname) static int math_##_funcname(HSQUIRRELVM v){ \ - SQFloat f; \ - sq_getfloat(v,2,&f); \ - sq_pushfloat(v,(SQFloat)_funcname(f)); \ - return 1; \ -} - -#define TWO_ARGS_FUNC(_funcname) static int math_##_funcname(HSQUIRRELVM v){ \ - SQFloat p1,p2; \ - sq_getfloat(v,2,&p1); \ - sq_getfloat(v,3,&p2); \ - sq_pushfloat(v,(SQFloat)_funcname(p1,p2)); \ - return 1; \ -} - -static int math_srand(HSQUIRRELVM v) -{ - SQInteger i; - if(!sq_getinteger(v,2,&i))return sq_throwerror(v,_SC("invalid param")); - srand(i); - return 0; -} - -static int math_rand(HSQUIRRELVM v) -{ - sq_pushinteger(v,rand()); - return 1; -} - -static int math_abs(HSQUIRRELVM v) -{ - SQInteger n; - sq_getinteger(v,2,&n); - sq_pushinteger(v,(SQInteger)abs(n)); - return 1; -} - -SINGLE_ARG_FUNC(sqrt) -SINGLE_ARG_FUNC(fabs) -SINGLE_ARG_FUNC(sin) -SINGLE_ARG_FUNC(cos) -SINGLE_ARG_FUNC(asin) -SINGLE_ARG_FUNC(acos) -SINGLE_ARG_FUNC(log) -SINGLE_ARG_FUNC(log10) -SINGLE_ARG_FUNC(tan) -SINGLE_ARG_FUNC(atan) -TWO_ARGS_FUNC(atan2) -TWO_ARGS_FUNC(pow) -SINGLE_ARG_FUNC(floor) -SINGLE_ARG_FUNC(ceil) -SINGLE_ARG_FUNC(exp) - -#define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),math_##name,nparams,tycheck} -static SQRegFunction mathlib_funcs[] = { - _DECL_FUNC(sqrt,2,_SC(".n")), - _DECL_FUNC(sin,2,_SC(".n")), - _DECL_FUNC(cos,2,_SC(".n")), - _DECL_FUNC(asin,2,_SC(".n")), - _DECL_FUNC(acos,2,_SC(".n")), - _DECL_FUNC(log,2,_SC(".n")), - _DECL_FUNC(log10,2,_SC(".n")), - _DECL_FUNC(tan,2,_SC(".n")), - _DECL_FUNC(atan,2,_SC(".n")), - _DECL_FUNC(atan2,3,_SC(".nn")), - _DECL_FUNC(pow,3,_SC(".nn")), - _DECL_FUNC(floor,2,_SC(".n")), - _DECL_FUNC(ceil,2,_SC(".n")), - _DECL_FUNC(exp,2,_SC(".n")), - _DECL_FUNC(srand,2,_SC(".n")), - _DECL_FUNC(rand,1,NULL), - _DECL_FUNC(fabs,2,_SC(".n")), - _DECL_FUNC(abs,2,_SC(".n")), - {0,0}, -}; - -#ifndef M_PI -#define M_PI (3.14159265358979323846) -#endif - -SQRESULT sqstd_register_mathlib(HSQUIRRELVM v) -{ - int i=0; - while(mathlib_funcs[i].name!=0) { - sq_pushstring(v,mathlib_funcs[i].name,-1); - sq_newclosure(v,mathlib_funcs[i].f,0); - sq_setparamscheck(v,mathlib_funcs[i].nparamscheck,mathlib_funcs[i].typemask); - sq_setnativeclosurename(v,-1,mathlib_funcs[i].name); - sq_createslot(v,-3); - i++; - } - sq_pushstring(v,_SC("RAND_MAX"),-1); - sq_pushinteger(v,RAND_MAX); - sq_createslot(v,-3); - sq_pushstring(v,_SC("PI"),-1); - sq_pushfloat(v,(SQFloat)M_PI); - sq_createslot(v,-3); - return SQ_OK; -} +/* see copyright notice in squirrel.h */ +#include +#include +#include +#include + +#define SINGLE_ARG_FUNC(_funcname) static SQInteger math_##_funcname(HSQUIRRELVM v){ \ + SQFloat f; \ + sq_getfloat(v,2,&f); \ + sq_pushfloat(v,(SQFloat)_funcname(f)); \ + return 1; \ +} + +#define TWO_ARGS_FUNC(_funcname) static SQInteger math_##_funcname(HSQUIRRELVM v){ \ + SQFloat p1,p2; \ + sq_getfloat(v,2,&p1); \ + sq_getfloat(v,3,&p2); \ + sq_pushfloat(v,(SQFloat)_funcname(p1,p2)); \ + return 1; \ +} + +static SQInteger math_srand(HSQUIRRELVM v) +{ + SQInteger i; + if(!sq_getinteger(v,2,&i))return sq_throwerror(v,_SC("invalid param")); + srand(i); + return 0; +} + +static SQInteger math_rand(HSQUIRRELVM v) +{ + sq_pushinteger(v,rand()); + return 1; +} + +static SQInteger math_abs(HSQUIRRELVM v) +{ + SQInteger n; + sq_getinteger(v,2,&n); + sq_pushinteger(v,(SQInteger)abs(n)); + return 1; +} + +SINGLE_ARG_FUNC(sqrt) +SINGLE_ARG_FUNC(fabs) +SINGLE_ARG_FUNC(sin) +SINGLE_ARG_FUNC(cos) +SINGLE_ARG_FUNC(asin) +SINGLE_ARG_FUNC(acos) +SINGLE_ARG_FUNC(log) +SINGLE_ARG_FUNC(log10) +SINGLE_ARG_FUNC(tan) +SINGLE_ARG_FUNC(atan) +TWO_ARGS_FUNC(atan2) +TWO_ARGS_FUNC(pow) +SINGLE_ARG_FUNC(floor) +SINGLE_ARG_FUNC(ceil) +SINGLE_ARG_FUNC(exp) + +#define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),math_##name,nparams,tycheck} +static SQRegFunction mathlib_funcs[] = { + _DECL_FUNC(sqrt,2,_SC(".n")), + _DECL_FUNC(sin,2,_SC(".n")), + _DECL_FUNC(cos,2,_SC(".n")), + _DECL_FUNC(asin,2,_SC(".n")), + _DECL_FUNC(acos,2,_SC(".n")), + _DECL_FUNC(log,2,_SC(".n")), + _DECL_FUNC(log10,2,_SC(".n")), + _DECL_FUNC(tan,2,_SC(".n")), + _DECL_FUNC(atan,2,_SC(".n")), + _DECL_FUNC(atan2,3,_SC(".nn")), + _DECL_FUNC(pow,3,_SC(".nn")), + _DECL_FUNC(floor,2,_SC(".n")), + _DECL_FUNC(ceil,2,_SC(".n")), + _DECL_FUNC(exp,2,_SC(".n")), + _DECL_FUNC(srand,2,_SC(".n")), + _DECL_FUNC(rand,1,NULL), + _DECL_FUNC(fabs,2,_SC(".n")), + _DECL_FUNC(abs,2,_SC(".n")), + {0,0}, +}; + +#ifndef M_PI +#define M_PI (3.14159265358979323846) +#endif + +SQRESULT sqstd_register_mathlib(HSQUIRRELVM v) +{ + SQInteger i=0; + while(mathlib_funcs[i].name!=0) { + sq_pushstring(v,mathlib_funcs[i].name,-1); + sq_newclosure(v,mathlib_funcs[i].f,0); + sq_setparamscheck(v,mathlib_funcs[i].nparamscheck,mathlib_funcs[i].typemask); + sq_setnativeclosurename(v,-1,mathlib_funcs[i].name); + sq_createslot(v,-3); + i++; + } + sq_pushstring(v,_SC("RAND_MAX"),-1); + sq_pushinteger(v,RAND_MAX); + sq_createslot(v,-3); + sq_pushstring(v,_SC("PI"),-1); + sq_pushfloat(v,(SQFloat)M_PI); + sq_createslot(v,-3); + return SQ_OK; +} diff --git a/src/squirrel/sqstdlib/sqstdrex.c b/src/squirrel/sqstdlib/sqstdrex.c index 534f17da1..e37a58c5d 100644 --- a/src/squirrel/sqstdlib/sqstdrex.c +++ b/src/squirrel/sqstdlib/sqstdrex.c @@ -46,30 +46,30 @@ typedef int SQRexNodeType; typedef struct tagSQRexNode{ SQRexNodeType type; - long left; - long right; - int next; + SQInteger left; + SQInteger right; + SQInteger next; }SQRexNode; struct SQRex{ const SQChar *_eol; const SQChar *_bol; const SQChar *_p; - int _first; - int _op; + SQInteger _first; + SQInteger _op; SQRexNode *_nodes; - int _nallocated; - int _nsize; - int _nsubexpr; + SQInteger _nallocated; + SQInteger _nsize; + SQInteger _nsubexpr; SQRexMatch *_matches; - int _currsubexp; + SQInteger _currsubexp; void *_jmpbuf; const SQChar **_error; }; -static int sqstd_rex_list(SQRex *exp); +static SQInteger sqstd_rex_list(SQRex *exp); -static int sqstd_rex_newnode(SQRex *exp, SQRexNodeType type) +static SQInteger sqstd_rex_newnode(SQRex *exp, SQRexNodeType type) { SQRexNode n; n.type = type; @@ -77,12 +77,12 @@ static int sqstd_rex_newnode(SQRex *exp, SQRexNodeType type) if(type == OP_EXPR) n.right = exp->_nsubexpr++; if(exp->_nallocated < (exp->_nsize + 1)) { - int oldsize = exp->_nallocated; + SQInteger oldsize = exp->_nallocated; exp->_nallocated *= 2; exp->_nodes = (SQRexNode *)sq_realloc(exp->_nodes, oldsize * sizeof(SQRexNode) ,exp->_nallocated * sizeof(SQRexNode)); } exp->_nodes[exp->_nsize++] = n; - return (int)exp->_nsize - 1; + return (SQInteger)exp->_nsize - 1; } static void sqstd_rex_error(SQRex *exp,const SQChar *error) @@ -91,7 +91,7 @@ static void sqstd_rex_error(SQRex *exp,const SQChar *error) longjmp(*((jmp_buf*)exp->_jmpbuf),-1); } -static void sqstd_rex_expect(SQRex *exp, int n){ +static void sqstd_rex_expect(SQRex *exp, SQInteger n){ if((*exp->_p) != n) sqstd_rex_error(exp, _SC("expected paren")); exp->_p++; @@ -125,14 +125,14 @@ static SQChar sqstd_rex_escapechar(SQRex *exp) return (*exp->_p++); } -static int sqstd_rex_charclass(SQRex *exp,int classid) +static SQInteger sqstd_rex_charclass(SQRex *exp,SQInteger classid) { - int n = sqstd_rex_newnode(exp,OP_CCLASS); + SQInteger n = sqstd_rex_newnode(exp,OP_CCLASS); exp->_nodes[n].left = classid; return n; } -static int sqstd_rex_charnode(SQRex *exp,SQBool isclass) +static SQInteger sqstd_rex_charnode(SQRex *exp,SQBool isclass) { if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) { exp->_p++; @@ -153,7 +153,7 @@ static int sqstd_rex_charnode(SQRex *exp,SQBool isclass) case 'b': case 'B': if(!isclass) { - int node = sqstd_rex_newnode(exp,OP_WB); + SQInteger node = sqstd_rex_newnode(exp,OP_WB); exp->_nodes[node].left = *exp->_p; exp->_p++; return node; @@ -167,10 +167,10 @@ static int sqstd_rex_charnode(SQRex *exp,SQBool isclass) } return sqstd_rex_newnode(exp,*exp->_p++); } -static int sqstd_rex_class(SQRex *exp) +static SQInteger sqstd_rex_class(SQRex *exp) { - int ret = -1; - int first = -1,chain; + SQInteger ret = -1; + SQInteger first = -1,chain; if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){ ret = sqstd_rex_newnode(exp,OP_NCLASS); exp->_p++; @@ -183,7 +183,7 @@ static int sqstd_rex_class(SQRex *exp) chain = ret; while(*exp->_p != ']' && exp->_p != exp->_eol) { if(*exp->_p == '-' && first != -1){ - int r; + SQInteger r; if(*exp->_p++ == ']') sqstd_rex_error(exp,_SC("unfinished range")); r = sqstd_rex_newnode(exp,OP_RANGE); if(first>*exp->_p) sqstd_rex_error(exp,_SC("invalid range")); @@ -196,7 +196,7 @@ static int sqstd_rex_class(SQRex *exp) } else{ if(first!=-1){ - int c = first; + SQInteger c = first; exp->_nodes[chain].next = c; chain = c; first = sqstd_rex_charnode(exp,SQTrue); @@ -207,7 +207,7 @@ static int sqstd_rex_class(SQRex *exp) } } if(first!=-1){ - int c = first; + SQInteger c = first; exp->_nodes[chain].next = c; chain = c; first = -1; @@ -218,10 +218,10 @@ static int sqstd_rex_class(SQRex *exp) return ret; } -static int sqstd_rex_parsenumber(SQRex *exp) +static SQInteger sqstd_rex_parsenumber(SQRex *exp) { - int ret = *exp->_p-'0'; - int positions = 10; + SQInteger ret = *exp->_p-'0'; + SQInteger positions = 10; exp->_p++; while(isdigit(*exp->_p)) { ret = ret*10+(*exp->_p++-'0'); @@ -231,13 +231,13 @@ static int sqstd_rex_parsenumber(SQRex *exp) return ret; } -static int sqstd_rex_element(SQRex *exp) +static SQInteger sqstd_rex_element(SQRex *exp) { - int ret; + SQInteger ret; switch(*exp->_p) { case '(': { - int expr; + SQInteger expr; exp->_p++; @@ -266,7 +266,7 @@ static int sqstd_rex_element(SQRex *exp) } /* scope block */ { - int op; + SQInteger op; unsigned short p0 = 0, p1 = 0; switch(*exp->_p){ case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; goto __end; @@ -293,7 +293,7 @@ static int sqstd_rex_element(SQRex *exp) } } __end: { - int nnode = sqstd_rex_newnode(exp,OP_GREEDY); + SQInteger nnode = sqstd_rex_newnode(exp,OP_GREEDY); op = OP_GREEDY; exp->_nodes[nnode].left = ret; exp->_nodes[nnode].right = ((p0)<<16)|p1; @@ -306,9 +306,9 @@ static int sqstd_rex_element(SQRex *exp) return ret; } -static int sqstd_rex_list(SQRex *exp) +static SQInteger sqstd_rex_list(SQRex *exp) { - int ret=-1,e; + SQInteger ret=-1,e; if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) { exp->_p++; ret = sqstd_rex_newnode(exp,OP_BOL); @@ -320,7 +320,7 @@ static int sqstd_rex_list(SQRex *exp) else ret = e; if(*exp->_p == SQREX_SYMBOL_BRANCH) { - int temp; + SQInteger temp; exp->_p++; temp = sqstd_rex_newnode(exp,OP_OR); exp->_nodes[temp].left = ret; @@ -330,7 +330,7 @@ static int sqstd_rex_list(SQRex *exp) return ret; } -static SQBool sqstd_rex_matchcclass(int cclass,SQChar c) +static SQBool sqstd_rex_matchcclass(SQInteger cclass,SQChar c) { switch(cclass) { case 'a': return isalpha(c)?SQTrue:SQFalse; @@ -375,7 +375,7 @@ static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar SQRexNodeType type = node->type; switch(type) { case OP_GREEDY: { - int p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0; + SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0; const SQChar *s=str, *good = str; while((nmaches == 0xFFFF || nmaches < p1) && (s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s))) { @@ -413,7 +413,7 @@ static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar case OP_NOCAPEXPR:{ SQRexNode *n = &exp->_nodes[node->left]; const SQChar *cur = str; - int capture = -1; + SQInteger capture = -1; if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) { capture = exp->_currsubexp; exp->_matches[capture].begin = cur; @@ -477,7 +477,7 @@ SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error) { SQRex *exp = (SQRex *)sq_malloc(sizeof(SQRex)); exp->_p = pattern; - exp->_nallocated = (int)scstrlen(pattern) * sizeof(SQChar); + exp->_nallocated = (SQInteger)scstrlen(pattern) * sizeof(SQChar); exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode)); exp->_nsize = 0; exp->_matches = 0; @@ -491,7 +491,7 @@ SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error) sqstd_rex_error(exp,_SC("unexpected character")); #ifdef _DEBUG { - int nsize,i; + SQInteger nsize,i; SQRexNode *t; nsize = exp->_nsize; t = &exp->_nodes[0]; @@ -541,7 +541,7 @@ SQBool sqstd_rex_match(SQRex* exp,const SQChar* text) SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end) { const SQChar *cur = NULL; - int node = exp->_first; + SQInteger node = exp->_first; if(text_begin >= text_end) return SQFalse; exp->_bol = text_begin; exp->_eol = text_end; @@ -572,12 +572,12 @@ SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, return sqstd_rex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end); } -int sqstd_rex_getsubexpcount(SQRex* exp) +SQInteger sqstd_rex_getsubexpcount(SQRex* exp) { return exp->_nsubexpr; } -SQBool sqstd_rex_getsubexp(SQRex* exp, int n, SQRexMatch *subexp) +SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp) { if( n<0 || n >= exp->_nsubexpr) return SQFalse; *subexp = exp->_matches[n]; diff --git a/src/squirrel/sqstdlib/sqstdstream.cpp b/src/squirrel/sqstdlib/sqstdstream.cpp index fea88f864..a02c0220c 100644 --- a/src/squirrel/sqstdlib/sqstdstream.cpp +++ b/src/squirrel/sqstdlib/sqstdstream.cpp @@ -1,396 +1,396 @@ -/* see copyright notice in squirrel.h */ -#include -#include -#include -#include -#include -#include -#include -#include "sqstdstream.h" -#include "sqstdblobimpl.h" - -#define SETUP_STREAM(v) \ - SQStream *self = NULL; \ - if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,SQSTD_STREAM_TYPE_TAG))) \ - return sq_throwerror(v,_SC("invalid type tag")); \ - if(!self->IsValid()) \ - return sq_throwerror(v,_SC("the stream is invalid")); - -int _stream_readstr(HSQUIRRELVM v) -{ - SETUP_STREAM(v); - SQInteger type = _SC('a'), size = 0; - sq_getinteger(v, 2, &size); - if(size <= 0) return sq_throwerror(v,_SC("invalid size")); - if(sq_gettop(v) > 2) - sq_getinteger(v, 3, &type); - SQChar *dest = NULL; - switch(type) { - case _SC('a'): { - char *temp; - if(self->Read(sq_getscratchpad(v, size+1), size) != size) - return sq_throwerror(v, _SC("io failure")); -#ifdef _UNICODE - temp = (char*) sq_getscratchpad(v, size + (size * sizeof(SQChar))); - dest = (SQChar*) &temp[size]; - size = (SQInteger)mbstowcs(dest, (const char*)temp, size); -#else - temp = (char *) sq_getscratchpad(v, -1); - dest = temp; -#endif - } - break; - case _SC('u'): { - wchar_t *temp; - if(self->Read(sq_getscratchpad(v, (size + 1) * sizeof(wchar_t)),size * sizeof(wchar_t)) != (size * sizeof(wchar_t))) - return sq_throwerror(v, _SC("io failure")); - -#ifdef _UNICODE - temp = (wchar_t*) sq_getscratchpad(v, -1); - dest = (SQChar*) temp; -#else - temp = (wchar_t*) sq_getscratchpad(v,(size * 3) + (size * sizeof(wchar_t))); - dest = (char*) &temp[size]; - size = (SQInteger)wcstombs(dest, (const wchar_t*)temp, size); -#endif - } - break; - default: - return sq_throwerror(v, _SC("invalid coding")); - } - - sq_pushstring(v, dest, size); - return 1; -} - -int _stream_readblob(HSQUIRRELVM v) -{ - SETUP_STREAM(v); - SQUserPointer data,blobp; - SQInteger size,res; - sq_getinteger(v,2,&size); - if(size > self->Len()) { - size = self->Len(); - } - data = sq_getscratchpad(v,size); - res = self->Read(data,size); - if(res <= 0) - return sq_throwerror(v,_SC("no data left to read")); - blobp = sqstd_createblob(v,res); - memcpy(blobp,data,res); - return 1; -} - -#define SAFE_READN(ptr,len) { \ - if(self->Read(ptr,len) != len) return sq_throwerror(v,_SC("io error")); \ - } -int _stream_readn(HSQUIRRELVM v) -{ - SETUP_STREAM(v); - SQInteger format; - sq_getinteger(v, 2, &format); - switch(format) { - case 'i': { - int i; - SAFE_READN(&i, sizeof(i)); - sq_pushinteger(v, i); - } - break; - case 's': { - short s; - SAFE_READN(&s, sizeof(short)); - sq_pushinteger(v, s); - } - break; - case 'w': { - unsigned short w; - SAFE_READN(&w, sizeof(unsigned short)); - sq_pushinteger(v, w); - } - break; - case 'c': { - char c; - SAFE_READN(&c, sizeof(char)); - sq_pushinteger(v, c); - } - break; - case 'b': { - unsigned char c; - SAFE_READN(&c, sizeof(unsigned char)); - sq_pushinteger(v, c); - } - break; - case 'f': { - float f; - SAFE_READN(&f, sizeof(float)); - sq_pushfloat(v, f); - } - break; - case 'd': { - double d; - SAFE_READN(&d, sizeof(double)); - sq_pushfloat(v, (SQFloat)d); - } - break; - default: - return sq_throwerror(v, _SC("invalid format")); - } - return 1; -} - -int _stream_writestr(HSQUIRRELVM v) -{ - SETUP_STREAM(v); - const SQChar *str,*res; - SQInteger trgformat = 'a',len = 0; - sq_getstring(v,2,&str); - len = sq_getsize(v,2); - if(sq_gettop(v)>2) - sq_getinteger(v,3,&trgformat); - switch(trgformat) - { - case 'a': -#ifdef _UNICODE - res = sq_getscratchpad(v,len*3); - len = (SQInteger) wcstombs((char *)res, (const wchar_t*)str, len); -#else - res = str; -#endif - self->Write((void *)res,len); - break; - case 'u': -#ifdef _UNICODE - res = str; -#else - res = sq_getscratchpad(v,len*sizeof(wchar_t)); - len = (SQInteger) mbstowcs((wchar_t*)res, str, len); -#endif - self->Write((void *)res,len*sizeof(wchar_t)); - break; - default: - return sq_throwerror(v,_SC("wrong encoding")); - } - - return 0; -} - -int _stream_writeblob(HSQUIRRELVM v) -{ - SQUserPointer data; - int size; - SETUP_STREAM(v); - if(SQ_FAILED(sqstd_getblob(v,2,&data))) - return sq_throwerror(v,_SC("invalid parameter")); - size = sqstd_getblobsize(v,2); - if(self->Write(data,size) != size) - return sq_throwerror(v,_SC("io error")); - sq_pushinteger(v,size); - return 1; -} - -int _stream_writen(HSQUIRRELVM v) -{ - SETUP_STREAM(v); - SQInteger format, ti; - SQFloat tf; - sq_getinteger(v, 3, &format); - switch(format) { - case 'i': { - int i; - sq_getinteger(v, 2, &ti); - i = ti; - self->Write(&i, sizeof(int)); - } - break; - case 's': { - short s; - sq_getinteger(v, 2, &ti); - s = ti; - self->Write(&s, sizeof(short)); - } - break; - case 'w': { - unsigned short w; - sq_getinteger(v, 2, &ti); - w = ti; - self->Write(&w, sizeof(unsigned short)); - } - break; - case 'c': { - char c; - sq_getinteger(v, 2, &ti); - c = ti; - self->Write(&c, sizeof(char)); - } - break; - case 'b': { - unsigned char b; - sq_getinteger(v, 2, &ti); - b = ti; - self->Write(&b, sizeof(unsigned char)); - } - break; - case 'f': { - float f; - sq_getfloat(v, 2, &tf); - f = tf; - self->Write(&f, sizeof(float)); - } - break; - case 'd': { - double d; - sq_getfloat(v, 2, &tf); - d = tf; - self->Write(&d, sizeof(double)); - } - break; - default: - return sq_throwerror(v, _SC("invalid format")); - } - return 0; -} - -int _stream_seek(HSQUIRRELVM v) -{ - SETUP_STREAM(v); - SQInteger offset, origin = SQ_SEEK_SET; - sq_getinteger(v, 2, &offset); - if(sq_gettop(v) > 2) { - SQInteger t; - sq_getinteger(v, 3, &t); - switch(t) { - case 'b': origin = SQ_SEEK_SET; break; - case 'c': origin = SQ_SEEK_CUR; break; - case 'e': origin = SQ_SEEK_END; break; - default: return sq_throwerror(v,_SC("invalid origin")); - } - } - sq_pushinteger(v, self->Seek(offset, origin)); - return 1; -} - -int _stream_tell(HSQUIRRELVM v) -{ - SETUP_STREAM(v); - sq_pushinteger(v, self->Tell()); - return 1; -} - -int _stream_len(HSQUIRRELVM v) -{ - SETUP_STREAM(v); - sq_pushinteger(v, self->Len()); - return 1; -} - -int _stream_flush(HSQUIRRELVM v) -{ - SETUP_STREAM(v); - if(!self->Flush()) - sq_pushinteger(v, 1); - else - sq_pushnull(v); - return 1; -} - -int _stream_eos(HSQUIRRELVM v) -{ - SETUP_STREAM(v); - if(self->EOS()) - sq_pushinteger(v, 1); - else - sq_pushnull(v); - return 1; -} - -static SQRegFunction _stream_methods[] = { - _DECL_STREAM_FUNC(readstr,-2,_SC("xnn")), - _DECL_STREAM_FUNC(readblob,2,_SC("xn")), - _DECL_STREAM_FUNC(readn,2,_SC("xn")), - _DECL_STREAM_FUNC(writestr,-2,_SC("xsn")), - _DECL_STREAM_FUNC(writeblob,-2,_SC("xx")), - _DECL_STREAM_FUNC(writen,3,_SC("xnn")), - _DECL_STREAM_FUNC(seek,-2,_SC("xnn")), - _DECL_STREAM_FUNC(tell,1,_SC("x")), - _DECL_STREAM_FUNC(len,1,_SC("x")), - _DECL_STREAM_FUNC(eos,1,_SC("x")), - _DECL_STREAM_FUNC(flush,1,_SC("x")), - {0,0} -}; - -void init_streamclass(HSQUIRRELVM v) -{ - sq_pushregistrytable(v); - sq_pushstring(v,_SC("std_stream"),-1); - if(SQ_FAILED(sq_get(v,-2))) { - sq_pushstring(v,_SC("std_stream"),-1); - sq_newclass(v,SQFalse); - sq_settypetag(v,-1,SQSTD_STREAM_TYPE_TAG); - int i = 0; - while(_stream_methods[i].name != 0) { - SQRegFunction &f = _stream_methods[i]; - sq_pushstring(v,f.name,-1); - sq_newclosure(v,f.f,0); - sq_setparamscheck(v,f.nparamscheck,f.typemask); - sq_createslot(v,-3); - i++; - } - sq_createslot(v,-3); - } - else { - sq_pop(v,1); //result - } - sq_pop(v,1); -} - -SQRESULT declare_stream(HSQUIRRELVM v,SQChar* name,int typetag,SQChar* reg_name,SQRegFunction *methods,SQRegFunction *globals) -{ - if(sq_gettype(v,-1) != OT_TABLE) - return sq_throwerror(v,_SC("table expected")); - int top = sq_gettop(v); - //create delegate - init_streamclass(v); - sq_pushregistrytable(v); - sq_pushstring(v,reg_name,-1); - sq_pushstring(v,_SC("std_stream"),-1); - if(SQ_SUCCEEDED(sq_get(v,-3))) { - sq_newclass(v,SQTrue); - sq_settypetag(v,-1,typetag); - int i = 0; - while(methods[i].name != 0) { - SQRegFunction &f = methods[i]; - sq_pushstring(v,f.name,-1); - sq_newclosure(v,f.f,0); - sq_setparamscheck(v,f.nparamscheck,f.typemask); - sq_setnativeclosurename(v,-1,f.name); - sq_createslot(v,-3); - i++; - } - sq_createslot(v,-3); - sq_pop(v,1); - - i = 0; - while(globals[i].name!=0) - { - SQRegFunction &f = globals[i]; - sq_pushstring(v,f.name,-1); - sq_newclosure(v,f.f,0); - sq_setparamscheck(v,f.nparamscheck,f.typemask); - sq_setnativeclosurename(v,-1,f.name); - sq_createslot(v,-3); - i++; - } - //register the class in the target table - sq_pushstring(v,name,-1); - sq_pushregistrytable(v); - sq_pushstring(v,reg_name,-1); - sq_get(v,-2); - sq_remove(v,-2); - sq_createslot(v,-3); - - sq_settop(v,top); - return SQ_OK; - } - sq_settop(v,top); - return SQ_ERROR; -} +/* see copyright notice in squirrel.h */ +#include +#include +#include +#include +#include +#include +#include +#include "sqstdstream.h" +#include "sqstdblobimpl.h" + +#define SETUP_STREAM(v) \ + SQStream *self = NULL; \ + if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_STREAM_TYPE_TAG))) \ + return sq_throwerror(v,_SC("invalid type tag")); \ + if(!self->IsValid()) \ + return sq_throwerror(v,_SC("the stream is invalid")); + +SQInteger _stream_readstr(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + SQInteger type = _SC('a'), size = 0; + sq_getinteger(v, 2, &size); + if(size <= 0) return sq_throwerror(v,_SC("invalid size")); + if(sq_gettop(v) > 2) + sq_getinteger(v, 3, &type); + SQChar *dest = NULL; + switch(type) { + case _SC('a'): { + char *temp; + if(self->Read(sq_getscratchpad(v, size+1), size) != size) + return sq_throwerror(v, _SC("io failure")); +#ifdef _UNICODE + temp = (char*) sq_getscratchpad(v, size + (size * sizeof(SQChar))); + dest = (SQChar*) &temp[size]; + size = (SQInteger)mbstowcs(dest, (const char*)temp, size); +#else + temp = (char *) sq_getscratchpad(v, -1); + dest = temp; +#endif + } + break; + case _SC('u'): { + wchar_t *temp; + if(self->Read(sq_getscratchpad(v, (size + 1) * sizeof(wchar_t)),size * sizeof(wchar_t)) != (size * sizeof(wchar_t))) + return sq_throwerror(v, _SC("io failure")); + +#ifdef _UNICODE + temp = (wchar_t*) sq_getscratchpad(v, -1); + dest = (SQChar*) temp; +#else + temp = (wchar_t*) sq_getscratchpad(v,(size * 3) + (size * sizeof(wchar_t))); + dest = (char*) &temp[size]; + size = (SQInteger)wcstombs(dest, (const wchar_t*)temp, size); +#endif + } + break; + default: + return sq_throwerror(v, _SC("invalid coding")); + } + + sq_pushstring(v, dest, size); + return 1; +} + +SQInteger _stream_readblob(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + SQUserPointer data,blobp; + SQInteger size,res; + sq_getinteger(v,2,&size); + if(size > self->Len()) { + size = self->Len(); + } + data = sq_getscratchpad(v,size); + res = self->Read(data,size); + if(res <= 0) + return sq_throwerror(v,_SC("no data left to read")); + blobp = sqstd_createblob(v,res); + memcpy(blobp,data,res); + return 1; +} + +#define SAFE_READN(ptr,len) { \ + if(self->Read(ptr,len) != len) return sq_throwerror(v,_SC("io error")); \ + } +SQInteger _stream_readn(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + SQInteger format; + sq_getinteger(v, 2, &format); + switch(format) { + case 'i': { + SQInteger i; + SAFE_READN(&i, sizeof(i)); + sq_pushinteger(v, i); + } + break; + case 's': { + short s; + SAFE_READN(&s, sizeof(short)); + sq_pushinteger(v, s); + } + break; + case 'w': { + unsigned short w; + SAFE_READN(&w, sizeof(unsigned short)); + sq_pushinteger(v, w); + } + break; + case 'c': { + char c; + SAFE_READN(&c, sizeof(char)); + sq_pushinteger(v, c); + } + break; + case 'b': { + unsigned char c; + SAFE_READN(&c, sizeof(unsigned char)); + sq_pushinteger(v, c); + } + break; + case 'f': { + float f; + SAFE_READN(&f, sizeof(float)); + sq_pushfloat(v, f); + } + break; + case 'd': { + double d; + SAFE_READN(&d, sizeof(double)); + sq_pushfloat(v, (SQFloat)d); + } + break; + default: + return sq_throwerror(v, _SC("invalid format")); + } + return 1; +} + +SQInteger _stream_writestr(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + const SQChar *str,*res; + SQInteger trgformat = 'a',len = 0; + sq_getstring(v,2,&str); + len = sq_getsize(v,2); + if(sq_gettop(v)>2) + sq_getinteger(v,3,&trgformat); + switch(trgformat) + { + case 'a': +#ifdef _UNICODE + res = sq_getscratchpad(v,len*3); + len = (SQInteger) wcstombs((char *)res, (const wchar_t*)str, len); +#else + res = str; +#endif + self->Write((void *)res,len); + break; + case 'u': +#ifdef _UNICODE + res = str; +#else + res = sq_getscratchpad(v,len*sizeof(wchar_t)); + len = (SQInteger) mbstowcs((wchar_t*)res, str, len); +#endif + self->Write((void *)res,len*sizeof(wchar_t)); + break; + default: + return sq_throwerror(v,_SC("wrong encoding")); + } + + return 0; +} + +SQInteger _stream_writeblob(HSQUIRRELVM v) +{ + SQUserPointer data; + SQInteger size; + SETUP_STREAM(v); + if(SQ_FAILED(sqstd_getblob(v,2,&data))) + return sq_throwerror(v,_SC("invalid parameter")); + size = sqstd_getblobsize(v,2); + if(self->Write(data,size) != size) + return sq_throwerror(v,_SC("io error")); + sq_pushinteger(v,size); + return 1; +} + +SQInteger _stream_writen(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + SQInteger format, ti; + SQFloat tf; + sq_getinteger(v, 3, &format); + switch(format) { + case 'i': { + SQInteger i; + sq_getinteger(v, 2, &ti); + i = ti; + self->Write(&i, sizeof(SQInteger)); + } + break; + case 's': { + short s; + sq_getinteger(v, 2, &ti); + s = ti; + self->Write(&s, sizeof(short)); + } + break; + case 'w': { + unsigned short w; + sq_getinteger(v, 2, &ti); + w = ti; + self->Write(&w, sizeof(unsigned short)); + } + break; + case 'c': { + char c; + sq_getinteger(v, 2, &ti); + c = ti; + self->Write(&c, sizeof(char)); + } + break; + case 'b': { + unsigned char b; + sq_getinteger(v, 2, &ti); + b = ti; + self->Write(&b, sizeof(unsigned char)); + } + break; + case 'f': { + float f; + sq_getfloat(v, 2, &tf); + f = tf; + self->Write(&f, sizeof(float)); + } + break; + case 'd': { + double d; + sq_getfloat(v, 2, &tf); + d = tf; + self->Write(&d, sizeof(double)); + } + break; + default: + return sq_throwerror(v, _SC("invalid format")); + } + return 0; +} + +SQInteger _stream_seek(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + SQInteger offset, origin = SQ_SEEK_SET; + sq_getinteger(v, 2, &offset); + if(sq_gettop(v) > 2) { + SQInteger t; + sq_getinteger(v, 3, &t); + switch(t) { + case 'b': origin = SQ_SEEK_SET; break; + case 'c': origin = SQ_SEEK_CUR; break; + case 'e': origin = SQ_SEEK_END; break; + default: return sq_throwerror(v,_SC("invalid origin")); + } + } + sq_pushinteger(v, self->Seek(offset, origin)); + return 1; +} + +SQInteger _stream_tell(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + sq_pushinteger(v, self->Tell()); + return 1; +} + +SQInteger _stream_len(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + sq_pushinteger(v, self->Len()); + return 1; +} + +SQInteger _stream_flush(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + if(!self->Flush()) + sq_pushinteger(v, 1); + else + sq_pushnull(v); + return 1; +} + +SQInteger _stream_eos(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + if(self->EOS()) + sq_pushinteger(v, 1); + else + sq_pushnull(v); + return 1; +} + +static SQRegFunction _stream_methods[] = { + _DECL_STREAM_FUNC(readstr,-2,_SC("xnn")), + _DECL_STREAM_FUNC(readblob,2,_SC("xn")), + _DECL_STREAM_FUNC(readn,2,_SC("xn")), + _DECL_STREAM_FUNC(writestr,-2,_SC("xsn")), + _DECL_STREAM_FUNC(writeblob,-2,_SC("xx")), + _DECL_STREAM_FUNC(writen,3,_SC("xnn")), + _DECL_STREAM_FUNC(seek,-2,_SC("xnn")), + _DECL_STREAM_FUNC(tell,1,_SC("x")), + _DECL_STREAM_FUNC(len,1,_SC("x")), + _DECL_STREAM_FUNC(eos,1,_SC("x")), + _DECL_STREAM_FUNC(flush,1,_SC("x")), + {0,0} +}; + +void init_streamclass(HSQUIRRELVM v) +{ + sq_pushregistrytable(v); + sq_pushstring(v,_SC("std_stream"),-1); + if(SQ_FAILED(sq_get(v,-2))) { + sq_pushstring(v,_SC("std_stream"),-1); + sq_newclass(v,SQFalse); + sq_settypetag(v,-1,(SQUserPointer)SQSTD_STREAM_TYPE_TAG); + SQInteger i = 0; + while(_stream_methods[i].name != 0) { + SQRegFunction &f = _stream_methods[i]; + sq_pushstring(v,f.name,-1); + sq_newclosure(v,f.f,0); + sq_setparamscheck(v,f.nparamscheck,f.typemask); + sq_createslot(v,-3); + i++; + } + sq_createslot(v,-3); + } + else { + sq_pop(v,1); //result + } + sq_pop(v,1); +} + +SQRESULT declare_stream(HSQUIRRELVM v,SQChar* name,SQUserPointer typetag,SQChar* reg_name,SQRegFunction *methods,SQRegFunction *globals) +{ + if(sq_gettype(v,-1) != OT_TABLE) + return sq_throwerror(v,_SC("table expected")); + SQInteger top = sq_gettop(v); + //create delegate + init_streamclass(v); + sq_pushregistrytable(v); + sq_pushstring(v,reg_name,-1); + sq_pushstring(v,_SC("std_stream"),-1); + if(SQ_SUCCEEDED(sq_get(v,-3))) { + sq_newclass(v,SQTrue); + sq_settypetag(v,-1,typetag); + SQInteger i = 0; + while(methods[i].name != 0) { + SQRegFunction &f = methods[i]; + sq_pushstring(v,f.name,-1); + sq_newclosure(v,f.f,0); + sq_setparamscheck(v,f.nparamscheck,f.typemask); + sq_setnativeclosurename(v,-1,f.name); + sq_createslot(v,-3); + i++; + } + sq_createslot(v,-3); + sq_pop(v,1); + + i = 0; + while(globals[i].name!=0) + { + SQRegFunction &f = globals[i]; + sq_pushstring(v,f.name,-1); + sq_newclosure(v,f.f,0); + sq_setparamscheck(v,f.nparamscheck,f.typemask); + sq_setnativeclosurename(v,-1,f.name); + sq_createslot(v,-3); + i++; + } + //register the class in the target table + sq_pushstring(v,name,-1); + sq_pushregistrytable(v); + sq_pushstring(v,reg_name,-1); + sq_get(v,-2); + sq_remove(v,-2); + sq_createslot(v,-3); + + sq_settop(v,top); + return SQ_OK; + } + sq_settop(v,top); + return SQ_ERROR; +} diff --git a/src/squirrel/sqstdlib/sqstdstream.h b/src/squirrel/sqstdlib/sqstdstream.h index fdb685885..d08fc4c9e 100644 --- a/src/squirrel/sqstdlib/sqstdstream.h +++ b/src/squirrel/sqstdlib/sqstdstream.h @@ -1,20 +1,20 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQSTD_STREAM_H_ -#define _SQSTD_STREAM_H_ - -int _stream_readstr(HSQUIRRELVM v); -int _stream_readblob(HSQUIRRELVM v); -int _stream_readline(HSQUIRRELVM v); -int _stream_readn(HSQUIRRELVM v); -int _stream_writestr(HSQUIRRELVM v); -int _stream_writeblob(HSQUIRRELVM v); -int _stream_writen(HSQUIRRELVM v); -int _stream_seek(HSQUIRRELVM v); -int _stream_tell(HSQUIRRELVM v); -int _stream_len(HSQUIRRELVM v); -int _stream_eos(HSQUIRRELVM v); -int _stream_flush(HSQUIRRELVM v); - -#define _DECL_STREAM_FUNC(name,nparams,typecheck) {_SC(#name),_stream_##name,nparams,typecheck} -SQRESULT declare_stream(HSQUIRRELVM v,SQChar* name,int typetag,SQChar* reg_name,SQRegFunction *methods,SQRegFunction *globals); -#endif /*_SQSTD_STREAM_H_*/ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_STREAM_H_ +#define _SQSTD_STREAM_H_ + +SQInteger _stream_readstr(HSQUIRRELVM v); +SQInteger _stream_readblob(HSQUIRRELVM v); +SQInteger _stream_readline(HSQUIRRELVM v); +SQInteger _stream_readn(HSQUIRRELVM v); +SQInteger _stream_writestr(HSQUIRRELVM v); +SQInteger _stream_writeblob(HSQUIRRELVM v); +SQInteger _stream_writen(HSQUIRRELVM v); +SQInteger _stream_seek(HSQUIRRELVM v); +SQInteger _stream_tell(HSQUIRRELVM v); +SQInteger _stream_len(HSQUIRRELVM v); +SQInteger _stream_eos(HSQUIRRELVM v); +SQInteger _stream_flush(HSQUIRRELVM v); + +#define _DECL_STREAM_FUNC(name,nparams,typecheck) {_SC(#name),_stream_##name,nparams,typecheck} +SQRESULT declare_stream(HSQUIRRELVM v,SQChar* name,SQUserPointer typetag,SQChar* reg_name,SQRegFunction *methods,SQRegFunction *globals); +#endif /*_SQSTD_STREAM_H_*/ diff --git a/src/squirrel/sqstdlib/sqstdstring.cpp b/src/squirrel/sqstdlib/sqstdstring.cpp index 9caef5450..81fc7c207 100644 --- a/src/squirrel/sqstdlib/sqstdstring.cpp +++ b/src/squirrel/sqstdlib/sqstdstring.cpp @@ -1,272 +1,276 @@ -/* see copyright notice in squirrel.h */ -#include -#include -#include -#include -#include -#include - -#ifdef _UNICODE -#define scstrchr wcschr -#define scsnprintf wsnprintf -#define scatoi _wtoi -#else -#define scstrchr strchr -#define scsnprintf snprintf -#define scatoi atoi -#endif -#define MAX_FORMAT_LEN 20 -#define MAX_WFORMAT_LEN 3 -#define ADDITIONAL_FORMAT_SPACE (100*sizeof(SQChar)) - -static int validate_format(HSQUIRRELVM v, SQChar *fmt, const SQChar *src, int n,int &width) -{ - SQChar swidth[MAX_WFORMAT_LEN]; - int wc = 0; - int start = n; - fmt[0] = '%'; - while (scstrchr(_SC("-+ #0"), src[n])) n++; - while (scisdigit(src[n])) { - swidth[wc] = src[n]; - n++; - wc++; - if(wc>=MAX_WFORMAT_LEN) - return sq_throwerror(v,_SC("width format too long")); - } - swidth[wc] = '\0'; - if(wc > 0) { - width = scatoi(swidth); - } - else - width = 0; - if (src[n] == '.') { - n++; - - wc = 0; - while (scisdigit(src[n])) { - swidth[wc] = src[n]; - n++; - wc++; - if(wc>=MAX_WFORMAT_LEN) - return sq_throwerror(v,_SC("precision format too long")); - } - swidth[wc] = '\0'; - if(wc > 0) { - width += scatoi(swidth); - } - } - if (n-start > MAX_FORMAT_LEN ) - return sq_throwerror(v,_SC("format too long")); - memcpy(&fmt[1],&src[start],((n-start)+1)*sizeof(SQChar)); - fmt[(n-start)+2] = '\0'; - return n; -} - -static int _string_format(HSQUIRRELVM v) -{ - const SQChar *format; - SQChar *dest; - SQChar fmt[MAX_FORMAT_LEN]; - sq_getstring(v,2,&format); - int allocated = (sq_getsize(v,2)+1)*sizeof(SQChar); - dest = sq_getscratchpad(v,allocated); - int n = 0,i = 0, nparam = 3, w; - while(format[n] != '\0') { - if(format[n] != '%') { - dest[i++] = format[n]; - n++; - } - else if(format[++n] == '%') { - dest[i++] = '%'; - } - else { - if( nparam > sq_gettop(v) ) - return sq_throwerror(v,_SC("not enough paramters for the given format string")); - n = validate_format(v,fmt,format,n,w); - if(n < 0) return -1; - int addlen = 0; - int valtype = 0; - const SQChar *ts; - SQInteger ti; - SQFloat tf; - switch(format[n]) { - case 's': - if(SQ_FAILED(sq_getstring(v,nparam,&ts))) - return sq_throwerror(v,_SC("string expected for the specified format")); - addlen = (sq_getsize(v,nparam)*sizeof(SQChar))+((w+1)*sizeof(SQChar)); - valtype = 's'; - break; - case 'i': case 'd': case 'c':case 'o': case 'u': case 'x': case 'X': - if(SQ_FAILED(sq_getinteger(v,nparam,&ti))) - return sq_throwerror(v,_SC("integer expected for the specified format")); - addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar)); - valtype = 'i'; - break; - case 'f': case 'g': case 'G': case 'e': case 'E': - if(SQ_FAILED(sq_getfloat(v,nparam,&tf))) - return sq_throwerror(v,_SC("float expected for the specified format")); - addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar)); - valtype = 'f'; - break; - default: - return sq_throwerror(v,_SC("invalid format")); - } - n++; - if((allocated-i) < addlen) - allocated += addlen - (allocated-i); - dest = sq_getscratchpad(v,allocated); - switch(valtype) { - case 's': i += scsprintf(&dest[i],fmt,ts); break; - case 'i': i += scsprintf(&dest[i],fmt,ti); break; - case 'f': i += scsprintf(&dest[i],fmt,tf); break; - }; - nparam ++; - } - } - sq_pushstring(v,dest,i); - return 1; -} - -#define SETUP_REX(v) \ - SQRex *self = NULL; \ - sq_getinstanceup(v,1,(SQUserPointer *)&self,0); - -static int _rexobj_releasehook(SQUserPointer p, int size) -{ - SQRex *self = ((SQRex *)p); - sqstd_rex_free(self); - return 1; -} - -static int _regexp_match(HSQUIRRELVM v) -{ - SETUP_REX(v); - const SQChar *str; - sq_getstring(v,2,&str); - if(sqstd_rex_match(self,str) == SQTrue) - { - sq_pushinteger(v,1); - return 1; - } - return 0; -} - -static void _addrexmatch(HSQUIRRELVM v,const SQChar *str,const SQChar *begin,const SQChar *end) -{ - sq_newtable(v); - sq_pushstring(v,_SC("begin"),-1); - sq_pushinteger(v,begin - str); - sq_rawset(v,-3); - sq_pushstring(v,_SC("end"),-1); - sq_pushinteger(v,end - str); - sq_rawset(v,-3); -} - -static int _regexp_search(HSQUIRRELVM v) -{ - SETUP_REX(v); - const SQChar *str,*begin,*end; - SQInteger start = 0; - sq_getstring(v,2,&str); - if(sq_gettop(v) > 2) sq_getinteger(v,3,&start); - if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) { - _addrexmatch(v,str,begin,end); - return 1; - } - return 0; -} - -static int _regexp_capture(HSQUIRRELVM v) -{ - SETUP_REX(v); - const SQChar *str,*begin,*end; - SQInteger start = 0; - sq_getstring(v,2,&str); - if(sq_gettop(v) > 2) sq_getinteger(v,3,&start); - if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) { - SQInteger n = sqstd_rex_getsubexpcount(self); - SQRexMatch match; - sq_newarray(v,0); - for(SQInteger i = 0;i < n; i++) { - sqstd_rex_getsubexp(self,i,&match); - if(match.len > 0) - _addrexmatch(v,str,match.begin,match.begin+match.len); - else - _addrexmatch(v,str,str,str); //empty match - sq_arrayappend(v,-2); - } - return 1; - } - return 0; -} - -static int _regexp_subexpcount(HSQUIRRELVM v) -{ - SETUP_REX(v); - sq_pushinteger(v,sqstd_rex_getsubexpcount(self)); - return 1; -} - -static int _regexp_constructor(HSQUIRRELVM v) -{ - const SQChar *error,*pattern; - sq_getstring(v,2,&pattern); - SQRex *rex = sqstd_rex_compile(pattern,&error); - if(!rex) return sq_throwerror(v,error); - sq_setinstanceup(v,1,rex); - sq_setreleasehook(v,1,_rexobj_releasehook); - return 0; -} - -static int _regexp__typeof(HSQUIRRELVM v) -{ - sq_pushstring(v,_SC("regexp"),-1); - return 1; -} - -#define _DECL_REX_FUNC(name,nparams,pmask) {_SC(#name),_regexp_##name,nparams,pmask} -static SQRegFunction rexobj_funcs[]={ - _DECL_REX_FUNC(constructor,2,_SC(".s")), - _DECL_REX_FUNC(search,-2,_SC("xsn")), - _DECL_REX_FUNC(match,2,_SC("xs")), - _DECL_REX_FUNC(capture,-2,_SC("xsn")), - _DECL_REX_FUNC(subexpcount,1,_SC("x")), - _DECL_REX_FUNC(_typeof,1,_SC("x")), - {0,0} -}; - -#define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_string_##name,nparams,pmask} -static SQRegFunction stringlib_funcs[]={ - _DECL_FUNC(format,-2,_SC(".s")), - {0,0} -}; - - -int sqstd_register_stringlib(HSQUIRRELVM v) -{ - sq_pushstring(v,_SC("regexp"),-1); - sq_newclass(v,SQFalse); - int i = 0; - while(rexobj_funcs[i].name != 0) { - SQRegFunction &f = rexobj_funcs[i]; - sq_pushstring(v,f.name,-1); - sq_newclosure(v,f.f,0); - sq_setparamscheck(v,f.nparamscheck,f.typemask); - sq_setnativeclosurename(v,-1,f.name); - sq_createslot(v,-3); - i++; - } - sq_createslot(v,-3); - - i = 0; - while(stringlib_funcs[i].name!=0) - { - sq_pushstring(v,stringlib_funcs[i].name,-1); - sq_newclosure(v,stringlib_funcs[i].f,0); - sq_setparamscheck(v,stringlib_funcs[i].nparamscheck,stringlib_funcs[i].typemask); - sq_setnativeclosurename(v,-1,stringlib_funcs[i].name); - sq_createslot(v,-3); - i++; - } - return 1; -} +/* see copyright notice in squirrel.h */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef _UNICODE +#define scstrchr wcschr +#define scsnprintf wsnprintf +#define scatoi _wtoi +#else +#define scstrchr strchr +#define scsnprintf snprintf +#define scatoi atoi +#endif +#define MAX_FORMAT_LEN 20 +#define MAX_WFORMAT_LEN 3 +#define ADDITIONAL_FORMAT_SPACE (100*sizeof(SQChar)) + +static SQInteger validate_format(HSQUIRRELVM v, SQChar *fmt, const SQChar *src, SQInteger n,SQInteger &width) +{ + SQChar swidth[MAX_WFORMAT_LEN]; + SQInteger wc = 0; + SQInteger start = n; + fmt[0] = '%'; + while (scstrchr(_SC("-+ #0"), src[n])) n++; + while (scisdigit(src[n])) { + swidth[wc] = src[n]; + n++; + wc++; + if(wc>=MAX_WFORMAT_LEN) + return sq_throwerror(v,_SC("width format too long")); + } + swidth[wc] = '\0'; + if(wc > 0) { + width = scatoi(swidth); + } + else + width = 0; + if (src[n] == '.') { + n++; + + wc = 0; + while (scisdigit(src[n])) { + swidth[wc] = src[n]; + n++; + wc++; + if(wc>=MAX_WFORMAT_LEN) + return sq_throwerror(v,_SC("precision format too long")); + } + swidth[wc] = '\0'; + if(wc > 0) { + width += scatoi(swidth); + } + } + if (n-start > MAX_FORMAT_LEN ) + return sq_throwerror(v,_SC("format too long")); + memcpy(&fmt[1],&src[start],((n-start)+1)*sizeof(SQChar)); + fmt[(n-start)+2] = '\0'; + return n; +} + +static SQInteger _string_format(HSQUIRRELVM v) +{ + const SQChar *format; + SQChar *dest; + SQChar fmt[MAX_FORMAT_LEN]; + sq_getstring(v,2,&format); + SQInteger allocated = (sq_getsize(v,2)+1)*sizeof(SQChar); + dest = sq_getscratchpad(v,allocated); + SQInteger n = 0,i = 0, nparam = 3, w; + while(format[n] != '\0') { + if(format[n] != '%') { + assert(i < allocated); + dest[i++] = format[n]; + n++; + } + else if(format[n+1] == '%') { //handles %% + dest[i++] = '%'; + n += 2; + } + else { + n++; + if( nparam > sq_gettop(v) ) + return sq_throwerror(v,_SC("not enough paramters for the given format string")); + n = validate_format(v,fmt,format,n,w); + if(n < 0) return -1; + SQInteger addlen = 0; + SQInteger valtype = 0; + const SQChar *ts; + SQInteger ti; + SQFloat tf; + switch(format[n]) { + case 's': + if(SQ_FAILED(sq_getstring(v,nparam,&ts))) + return sq_throwerror(v,_SC("string expected for the specified format")); + addlen = (sq_getsize(v,nparam)*sizeof(SQChar))+((w+1)*sizeof(SQChar)); + valtype = 's'; + break; + case 'i': case 'd': case 'c':case 'o': case 'u': case 'x': case 'X': + if(SQ_FAILED(sq_getinteger(v,nparam,&ti))) + return sq_throwerror(v,_SC("integer expected for the specified format")); + addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar)); + valtype = 'i'; + break; + case 'f': case 'g': case 'G': case 'e': case 'E': + if(SQ_FAILED(sq_getfloat(v,nparam,&tf))) + return sq_throwerror(v,_SC("float expected for the specified format")); + addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar)); + valtype = 'f'; + break; + default: + return sq_throwerror(v,_SC("invalid format")); + } + n++; + if((allocated-i) < addlen) + allocated += addlen; + dest = sq_getscratchpad(v,allocated); + switch(valtype) { + case 's': i += scsprintf(&dest[i],fmt,ts); break; + case 'i': i += scsprintf(&dest[i],fmt,ti); break; + case 'f': i += scsprintf(&dest[i],fmt,tf); break; + }; + nparam ++; + } + } + sq_pushstring(v,dest,i); + return 1; +} + +#define SETUP_REX(v) \ + SQRex *self = NULL; \ + sq_getinstanceup(v,1,(SQUserPointer *)&self,0); + +static SQInteger _rexobj_releasehook(SQUserPointer p, SQInteger size) +{ + SQRex *self = ((SQRex *)p); + sqstd_rex_free(self); + return 1; +} + +static SQInteger _regexp_match(HSQUIRRELVM v) +{ + SETUP_REX(v); + const SQChar *str; + sq_getstring(v,2,&str); + if(sqstd_rex_match(self,str) == SQTrue) + { + sq_pushinteger(v,1); + return 1; + } + return 0; +} + +static void _addrexmatch(HSQUIRRELVM v,const SQChar *str,const SQChar *begin,const SQChar *end) +{ + sq_newtable(v); + sq_pushstring(v,_SC("begin"),-1); + sq_pushinteger(v,begin - str); + sq_rawset(v,-3); + sq_pushstring(v,_SC("end"),-1); + sq_pushinteger(v,end - str); + sq_rawset(v,-3); +} + +static SQInteger _regexp_search(HSQUIRRELVM v) +{ + SETUP_REX(v); + const SQChar *str,*begin,*end; + SQInteger start = 0; + sq_getstring(v,2,&str); + if(sq_gettop(v) > 2) sq_getinteger(v,3,&start); + if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) { + _addrexmatch(v,str,begin,end); + return 1; + } + return 0; +} + +static SQInteger _regexp_capture(HSQUIRRELVM v) +{ + SETUP_REX(v); + const SQChar *str,*begin,*end; + SQInteger start = 0; + sq_getstring(v,2,&str); + if(sq_gettop(v) > 2) sq_getinteger(v,3,&start); + if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) { + SQInteger n = sqstd_rex_getsubexpcount(self); + SQRexMatch match; + sq_newarray(v,0); + for(SQInteger i = 0;i < n; i++) { + sqstd_rex_getsubexp(self,i,&match); + if(match.len > 0) + _addrexmatch(v,str,match.begin,match.begin+match.len); + else + _addrexmatch(v,str,str,str); //empty match + sq_arrayappend(v,-2); + } + return 1; + } + return 0; +} + +static SQInteger _regexp_subexpcount(HSQUIRRELVM v) +{ + SETUP_REX(v); + sq_pushinteger(v,sqstd_rex_getsubexpcount(self)); + return 1; +} + +static SQInteger _regexp_constructor(HSQUIRRELVM v) +{ + const SQChar *error,*pattern; + sq_getstring(v,2,&pattern); + SQRex *rex = sqstd_rex_compile(pattern,&error); + if(!rex) return sq_throwerror(v,error); + sq_setinstanceup(v,1,rex); + sq_setreleasehook(v,1,_rexobj_releasehook); + return 0; +} + +static SQInteger _regexp__typeof(HSQUIRRELVM v) +{ + sq_pushstring(v,_SC("regexp"),-1); + return 1; +} + +#define _DECL_REX_FUNC(name,nparams,pmask) {_SC(#name),_regexp_##name,nparams,pmask} +static SQRegFunction rexobj_funcs[]={ + _DECL_REX_FUNC(constructor,2,_SC(".s")), + _DECL_REX_FUNC(search,-2,_SC("xsn")), + _DECL_REX_FUNC(match,2,_SC("xs")), + _DECL_REX_FUNC(capture,-2,_SC("xsn")), + _DECL_REX_FUNC(subexpcount,1,_SC("x")), + _DECL_REX_FUNC(_typeof,1,_SC("x")), + {0,0} +}; + +#define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_string_##name,nparams,pmask} +static SQRegFunction stringlib_funcs[]={ + _DECL_FUNC(format,-2,_SC(".s")), + {0,0} +}; + + +SQInteger sqstd_register_stringlib(HSQUIRRELVM v) +{ + sq_pushstring(v,_SC("regexp"),-1); + sq_newclass(v,SQFalse); + SQInteger i = 0; + while(rexobj_funcs[i].name != 0) { + SQRegFunction &f = rexobj_funcs[i]; + sq_pushstring(v,f.name,-1); + sq_newclosure(v,f.f,0); + sq_setparamscheck(v,f.nparamscheck,f.typemask); + sq_setnativeclosurename(v,-1,f.name); + sq_createslot(v,-3); + i++; + } + sq_createslot(v,-3); + + i = 0; + while(stringlib_funcs[i].name!=0) + { + sq_pushstring(v,stringlib_funcs[i].name,-1); + sq_newclosure(v,stringlib_funcs[i].f,0); + sq_setparamscheck(v,stringlib_funcs[i].nparamscheck,stringlib_funcs[i].typemask); + sq_setnativeclosurename(v,-1,stringlib_funcs[i].name); + sq_createslot(v,-3); + i++; + } + return 1; +} diff --git a/src/squirrel/sqstdlib/sqstdsystem.cpp b/src/squirrel/sqstdlib/sqstdsystem.cpp index 075a88024..b52f057d2 100644 --- a/src/squirrel/sqstdlib/sqstdsystem.cpp +++ b/src/squirrel/sqstdlib/sqstdsystem.cpp @@ -1,145 +1,145 @@ -/* see copyright notice in squirrel.h */ -#include -#include -#include -#include -#include - -#ifdef SQUNICODE -#include -#define scgetenv _wgetenv -#define scsystem _wsystem -#define scasctime _wasctime -#define scremove _wremove -#define screname _wrename -#else -#define scgetenv getenv -#define scsystem system -#define scasctime asctime -#define scremove remove -#define screname rename -#endif - -static int _system_getenv(HSQUIRRELVM v) -{ - const SQChar *s; - if(SQ_SUCCEEDED(sq_getstring(v,2,&s))){ - sq_pushstring(v,scgetenv(s),-1); - return 1; - } - return 0; -} - - -static int _system_system(HSQUIRRELVM v) -{ - const SQChar *s; - if(SQ_SUCCEEDED(sq_getstring(v,2,&s))){ - sq_pushinteger(v,scsystem(s)); - return 1; - } - return sq_throwerror(v,_SC("wrong param")); -} - - -static int _system_clock(HSQUIRRELVM v) -{ - sq_pushfloat(v,((SQFloat)clock())/(SQFloat)CLOCKS_PER_SEC); - return 1; -} - -static int _system_time(HSQUIRRELVM v) -{ - time_t t; - time(&t); - sq_pushinteger(v,*((SQInteger *)&t)); - return 1; -} - -static int _system_remove(HSQUIRRELVM v) -{ - const SQChar *s; - sq_getstring(v,2,&s); - if(scremove(s)==-1) - return sq_throwerror(v,_SC("remove() failed")); - return 0; -} - -static int _system_rename(HSQUIRRELVM v) -{ - const SQChar *oldn,*newn; - sq_getstring(v,2,&oldn); - sq_getstring(v,3,&newn); - if(screname(oldn,newn)==-1) - return sq_throwerror(v,_SC("rename() failed")); - return 0; -} - -static void _set_integer_slot(HSQUIRRELVM v,const SQChar *name,SQInteger val) -{ - sq_pushstring(v,name,-1); - sq_pushinteger(v,val); - sq_rawset(v,-3); -} - -static int _system_date(HSQUIRRELVM v) -{ - time_t t; - SQInteger format = 'l'; - if(sq_gettop(v) > 1) { - sq_getinteger(v,2,(SQInteger*)&t); - if(sq_gettop(v) > 2) { - sq_getinteger(v,3,(SQInteger*)&format); - } - } - else { - time(&t); - } - tm *date; - if(format == 'u') - date = gmtime(&t); - else - date = localtime(&t); - if(!date) - return sq_throwerror(v,_SC("crt api failure")); - sq_newtable(v); - _set_integer_slot(v, _SC("sec"), date->tm_sec); - _set_integer_slot(v, _SC("min"), date->tm_min); - _set_integer_slot(v, _SC("hour"), date->tm_hour); - _set_integer_slot(v, _SC("day"), date->tm_mday); - _set_integer_slot(v, _SC("month"), date->tm_mon); - _set_integer_slot(v, _SC("year"), date->tm_year+1900); - _set_integer_slot(v, _SC("wday"), date->tm_wday); - _set_integer_slot(v, _SC("yday"), date->tm_yday); - return 1; -} - - - -#define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_system_##name,nparams,pmask} -static SQRegFunction systemlib_funcs[]={ - _DECL_FUNC(getenv,2,_SC(".s")), - _DECL_FUNC(system,2,_SC(".s")), - _DECL_FUNC(clock,1,NULL), - _DECL_FUNC(time,1,NULL), - _DECL_FUNC(date,-1,_SC(".nn")), - _DECL_FUNC(remove,2,_SC(".s")), - _DECL_FUNC(rename,3,_SC(".ss")), - {0,0} -}; - - -int sqstd_register_systemlib(HSQUIRRELVM v) -{ - int i=0; - while(systemlib_funcs[i].name!=0) - { - sq_pushstring(v,systemlib_funcs[i].name,-1); - sq_newclosure(v,systemlib_funcs[i].f,0); - sq_setparamscheck(v,systemlib_funcs[i].nparamscheck,systemlib_funcs[i].typemask); - sq_setnativeclosurename(v,-1,systemlib_funcs[i].name); - sq_createslot(v,-3); - i++; - } - return 1; -} +/* see copyright notice in squirrel.h */ +#include +#include +#include +#include +#include + +#ifdef SQUNICODE +#include +#define scgetenv _wgetenv +#define scsystem _wsystem +#define scasctime _wasctime +#define scremove _wremove +#define screname _wrename +#else +#define scgetenv getenv +#define scsystem system +#define scasctime asctime +#define scremove remove +#define screname rename +#endif + +static SQInteger _system_getenv(HSQUIRRELVM v) +{ + const SQChar *s; + if(SQ_SUCCEEDED(sq_getstring(v,2,&s))){ + sq_pushstring(v,scgetenv(s),-1); + return 1; + } + return 0; +} + + +static SQInteger _system_system(HSQUIRRELVM v) +{ + const SQChar *s; + if(SQ_SUCCEEDED(sq_getstring(v,2,&s))){ + sq_pushinteger(v,scsystem(s)); + return 1; + } + return sq_throwerror(v,_SC("wrong param")); +} + + +static SQInteger _system_clock(HSQUIRRELVM v) +{ + sq_pushfloat(v,((SQFloat)clock())/(SQFloat)CLOCKS_PER_SEC); + return 1; +} + +static SQInteger _system_time(HSQUIRRELVM v) +{ + time_t t; + time(&t); + sq_pushinteger(v,*((SQInteger *)&t)); + return 1; +} + +static SQInteger _system_remove(HSQUIRRELVM v) +{ + const SQChar *s; + sq_getstring(v,2,&s); + if(scremove(s)==-1) + return sq_throwerror(v,_SC("remove() failed")); + return 0; +} + +static SQInteger _system_rename(HSQUIRRELVM v) +{ + const SQChar *oldn,*newn; + sq_getstring(v,2,&oldn); + sq_getstring(v,3,&newn); + if(screname(oldn,newn)==-1) + return sq_throwerror(v,_SC("rename() failed")); + return 0; +} + +static void _set_integer_slot(HSQUIRRELVM v,const SQChar *name,SQInteger val) +{ + sq_pushstring(v,name,-1); + sq_pushinteger(v,val); + sq_rawset(v,-3); +} + +static SQInteger _system_date(HSQUIRRELVM v) +{ + time_t t; + SQInteger format = 'l'; + if(sq_gettop(v) > 1) { + sq_getinteger(v,2,(SQInteger*)&t); + if(sq_gettop(v) > 2) { + sq_getinteger(v,3,(SQInteger*)&format); + } + } + else { + time(&t); + } + tm *date; + if(format == 'u') + date = gmtime(&t); + else + date = localtime(&t); + if(!date) + return sq_throwerror(v,_SC("crt api failure")); + sq_newtable(v); + _set_integer_slot(v, _SC("sec"), date->tm_sec); + _set_integer_slot(v, _SC("min"), date->tm_min); + _set_integer_slot(v, _SC("hour"), date->tm_hour); + _set_integer_slot(v, _SC("day"), date->tm_mday); + _set_integer_slot(v, _SC("month"), date->tm_mon); + _set_integer_slot(v, _SC("year"), date->tm_year+1900); + _set_integer_slot(v, _SC("wday"), date->tm_wday); + _set_integer_slot(v, _SC("yday"), date->tm_yday); + return 1; +} + + + +#define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_system_##name,nparams,pmask} +static SQRegFunction systemlib_funcs[]={ + _DECL_FUNC(getenv,2,_SC(".s")), + _DECL_FUNC(system,2,_SC(".s")), + _DECL_FUNC(clock,1,NULL), + _DECL_FUNC(time,1,NULL), + _DECL_FUNC(date,-1,_SC(".nn")), + _DECL_FUNC(remove,2,_SC(".s")), + _DECL_FUNC(rename,3,_SC(".ss")), + {0,0} +}; + + +SQInteger sqstd_register_systemlib(HSQUIRRELVM v) +{ + SQInteger i=0; + while(systemlib_funcs[i].name!=0) + { + sq_pushstring(v,systemlib_funcs[i].name,-1); + sq_newclosure(v,systemlib_funcs[i].f,0); + sq_setparamscheck(v,systemlib_funcs[i].nparamscheck,systemlib_funcs[i].typemask); + sq_setnativeclosurename(v,-1,systemlib_funcs[i].name); + sq_createslot(v,-3); + i++; + } + return 1; +} diff --git a/src/squirrel/squirrel/sqapi.cpp b/src/squirrel/squirrel/sqapi.cpp index 1234d9958..638280f01 100644 --- a/src/squirrel/squirrel/sqapi.cpp +++ b/src/squirrel/squirrel/sqapi.cpp @@ -1,1077 +1,1143 @@ -/* - see copyright notice in squirrel.h -*/ -#include "sqpcheader.h" -#include "sqvm.h" -#include "sqstring.h" -#include "sqtable.h" -#include "sqarray.h" -#include "sqfuncproto.h" -#include "sqclosure.h" -#include "squserdata.h" -#include "sqcompiler.h" -#include "sqfuncstate.h" -#include "sqclass.h" - -bool sq_aux_gettypedarg(HSQUIRRELVM v,int idx,SQObjectType type,SQObjectPtr **o) -{ - *o = &stack_get(v,idx); - if(type(**o) != type){ - SQObjectPtr oval = v->PrintObjVal(**o); - v->Raise_Error(_SC("wrong argument type, expected '%s' got '%.50s'"),IdType2Name(type),_stringval(oval)); - return false; - } - return true; -} - -#define _GETSAFE_OBJ(v,idx,type,o) { if(!sq_aux_gettypedarg(v,idx,type,&o)) return SQ_ERROR; } - -#define sq_aux_paramscheck(v,count) \ -{ \ - if(sq_gettop(v) < count){ v->Raise_Error(_SC("not enough params in the stack")); return SQ_ERROR; }\ -} - -int sq_aux_throwobject(HSQUIRRELVM v,SQObjectPtr &e) -{ - v->_lasterror = e; - return SQ_ERROR; -} - -int sq_aux_invalidtype(HSQUIRRELVM v,SQObjectType type) -{ - scsprintf(_ss(v)->GetScratchPad(100), _SC("unexpected type %s"), IdType2Name(type)); - return sq_throwerror(v, _ss(v)->GetScratchPad(-1)); -} - -HSQUIRRELVM sq_open(int initialstacksize) -{ - SQSharedState *ss; - SQVM *v; - sq_new(ss, SQSharedState); - ss->Init(); - v = (SQVM *)SQ_MALLOC(sizeof(SQVM)); - new (v) SQVM(ss); - ss->_root_vm = v; - if(v->Init(NULL, initialstacksize)) { - return v; - } else { - sq_delete(v, SQVM); - return NULL; - } - return v; -} - -HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, int initialstacksize) -{ - SQSharedState *ss; - SQVM *v; - ss=_ss(friendvm); - - v= (SQVM *)SQ_MALLOC(sizeof(SQVM)); - new (v) SQVM(ss); - - if(v->Init(friendvm, initialstacksize)) { - friendvm->Push(v); - return v; - } else { - sq_delete(v, SQVM); - return NULL; - } -} - -int sq_getvmstate(HSQUIRRELVM v) -{ - if(v->_suspended) - return SQ_VMSTATE_SUSPENDED; - else { - if(v->_callsstack.size() != 0) return SQ_VMSTATE_RUNNING; - else return SQ_VMSTATE_IDLE; - } -} - -void sq_seterrorhandler(HSQUIRRELVM v) -{ - SQObject o = stack_get(v, -1); - if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) { - v->_errorhandler = o; - v->Pop(); - } -} - -void sq_setdebughook(HSQUIRRELVM v) -{ - SQObject o = stack_get(v,-1); - if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) { - v->_debughook = o; - v->Pop(); - } -} - -void sq_close(HSQUIRRELVM v) -{ - SQSharedState *ss = _ss(v); - _thread(ss->_root_vm)->Finalize(); - sq_delete(ss, SQSharedState); -} - -SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror) -{ - SQObjectPtr o; - if(Compile(v, read, p, sourcename, o, raiseerror?true:false, _ss(v)->_debuginfo)) { - v->Push(SQClosure::Create(_ss(v), _funcproto(o))); - return SQ_OK; - } - return SQ_ERROR; -} - -void sq_enabledebuginfo(HSQUIRRELVM v, SQBool debuginfo) -{ - _ss(v)->_debuginfo = debuginfo?true:false; -} - -void sq_addref(HSQUIRRELVM v,HSQOBJECT *po) -{ - SQObjectPtr refs; - if(!ISREFCOUNTED(type(*po))) return; - if(_table(_ss(v)->_refs_table)->Get(*po, refs)) { - refs = _integer(refs) + 1; - } - else{ - refs = 1; - } - _table(_ss(v)->_refs_table)->NewSlot(*po, refs); -} - -SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po) -{ - SQObjectPtr refs; - if(!ISREFCOUNTED(type(*po))) return SQTrue; - if(_table(_ss(v)->_refs_table)->Get(*po, refs)) { - int n = _integer(refs) - 1; - if(n <= 0) { - _table(_ss(v)->_refs_table)->Remove(*po); - sq_resetobject(po); - } - else { - refs = n;_table(_ss(v)->_refs_table)->Set(*po, refs); - return SQFalse; - } - } - return SQTrue; -} - -const SQChar *sq_objtostring(HSQOBJECT *o) -{ - if(sq_type(*o) == OT_STRING) { - return o->_unVal.pString->_val; - } - return NULL; -} - -SQInteger sq_objtointeger(HSQOBJECT *o) -{ - if(sq_isnumeric(*o)) { - return tointeger(*o); - } - return 0; -} - -SQFloat sq_objtofloat(HSQOBJECT *o) -{ - if(sq_isnumeric(*o)) { - return tofloat(*o); - } - return 0; -} - -void sq_pushnull(HSQUIRRELVM v) -{ - v->Push(_null_); -} - -void sq_pushstring(HSQUIRRELVM v,const SQChar *s,int len) -{ - if(s) - v->Push(SQObjectPtr(SQString::Create(_ss(v), s, len))); - else v->Push(_null_); -} - -void sq_pushinteger(HSQUIRRELVM v,SQInteger n) -{ - v->Push(n); -} - -void sq_pushbool(HSQUIRRELVM v,SQBool b) -{ - v->Push(b?true:false); -} - -void sq_pushfloat(HSQUIRRELVM v,SQFloat n) -{ - v->Push(n); -} - -void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p) -{ - v->Push(p); -} - -SQUserPointer sq_newuserdata(HSQUIRRELVM v,unsigned int size) -{ - SQUserData *ud = SQUserData::Create(_ss(v), size); - v->Push(ud); - return ud->_val; -} - -void sq_newtable(HSQUIRRELVM v) -{ - v->Push(SQTable::Create(_ss(v), 0)); -} - -void sq_newarray(HSQUIRRELVM v,int size) -{ - v->Push(SQArray::Create(_ss(v), size)); -} - -SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase) -{ - SQClass *baseclass = NULL; - if(hasbase) { - SQObjectPtr &base = stack_get(v,-1); - if(type(base) != OT_CLASS) - return sq_throwerror(v,_SC("invalid base type")); - baseclass = _class(base); - } - SQClass *newclass = SQClass::Create(_ss(v), baseclass); - if(baseclass) v->Pop(); - v->Push(newclass); - return SQ_OK; -} - -int sq_instanceof(HSQUIRRELVM v) -{ - SQObjectPtr &inst = stack_get(v,-1); - SQObjectPtr &cl = stack_get(v,-2); - if(type(inst) != OT_INSTANCE || type(cl) != OT_CLASS) - return sq_throwerror(v,_SC("invalid param type")); - return _instance(inst)->InstanceOf(_class(cl))?1:0; -} - -SQRESULT sq_arrayappend(HSQUIRRELVM v,int idx) -{ - sq_aux_paramscheck(v,2); - SQObjectPtr *arr; - _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); - _array(*arr)->Append(v->GetUp(-1)); - v->Pop(1); - return SQ_OK; -} - -SQRESULT sq_arraypop(HSQUIRRELVM v,int idx,SQBool pushval) -{ - sq_aux_paramscheck(v, 1); - SQObjectPtr *arr; - _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); - if(_array(*arr)->Size() > 0) { - if(pushval != 0){ v->Push(_array(*arr)->Top()); } - _array(*arr)->Pop(); - return SQ_OK; - } - return sq_throwerror(v, _SC("empty array")); -} - -SQRESULT sq_arrayresize(HSQUIRRELVM v,int idx,int newsize) -{ - sq_aux_paramscheck(v,1); - SQObjectPtr *arr; - _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); - if(_array(*arr)->Size() > 0) { - _array(*arr)->Resize(newsize); - return SQ_OK; - } - return sq_throwerror(v, _SC("empty array")); -} - -SQRESULT sq_arrayreverse(HSQUIRRELVM v,int idx) -{ - sq_aux_paramscheck(v, 1); - SQObjectPtr *o; - _GETSAFE_OBJ(v, idx, OT_ARRAY,o); - SQArray *arr = _array(*o); - if(arr->Size() > 0) { - SQObjectPtr t; - int size = arr->Size(); - int n = size >> 1; size -= 1; - for(int i = 0; i < n; i++) { - t = arr->_values[i]; - arr->_values[i] = arr->_values[size-i]; - arr->_values[size-i] = t; - } - return SQ_OK; - } - return sq_throwerror(v, _SC("empty array")); -} - -void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,unsigned int nfreevars) -{ - SQNativeClosure *nc = SQNativeClosure::Create(_ss(v), func); - nc->_nparamscheck = 0; - for(unsigned int i = 0; i < nfreevars; i++) { - nc->_outervalues.push_back(v->Top()); - v->Pop(); - } - v->Push(SQObjectPtr(nc)); -} - -SQRESULT sq_getclosureinfo(HSQUIRRELVM v,int idx,unsigned int *nparams,unsigned int *nfreevars) -{ - SQObject o = stack_get(v, idx); - if(sq_isclosure(o)) { - SQClosure *c = _closure(o); - SQFunctionProto *proto = _funcproto(c->_function); - *nparams = (unsigned int)proto->_parameters.size(); - *nfreevars = (unsigned int)c->_outervalues.size(); - return SQ_OK; - } - return sq_throwerror(v,_SC("the object is not a closure")); -} - -SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,int idx,const SQChar *name) -{ - SQObject o = stack_get(v, idx); - if(sq_isnativeclosure(o)) { - SQNativeClosure *nc = _nativeclosure(o); - nc->_name = SQString::Create(_ss(v),name); - return SQ_OK; - } - return sq_throwerror(v,_SC("the object is not a nativeclosure")); -} - -SQRESULT sq_setparamscheck(HSQUIRRELVM v,int nparamscheck,const SQChar *typemask) -{ - SQObject o = stack_get(v, -1); - if(!sq_isnativeclosure(o)) - return sq_throwerror(v, _SC("native closure expected")); - SQNativeClosure *nc = _nativeclosure(o); - nc->_nparamscheck = nparamscheck; - if(typemask) { - SQIntVec res; - if(!CompileTypemask(res, typemask)) - return sq_throwerror(v, _SC("invalid typemask")); - nc->_typecheck.copy(res); - } - else { - nc->_typecheck.resize(0); - } - if(nparamscheck == SQ_MATCHTYPEMASKSTRING) { - nc->_nparamscheck = nc->_typecheck.size(); - } - return SQ_OK; -} - -void sq_pushroottable(HSQUIRRELVM v) -{ - v->Push(v->_roottable); -} - -void sq_pushregistrytable(HSQUIRRELVM v) -{ - v->Push(_ss(v)->_registry); -} - -SQRESULT sq_setroottable(HSQUIRRELVM v) -{ - SQObject o = stack_get(v, -1); - if(sq_istable(o) || sq_isnull(o)) { - v->_roottable = o; - v->Pop(); - return SQ_OK; - } - return sq_throwerror(v, _SC("ivalid type")); -} - -void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p) -{ - v->_foreignptr = p; -} - -SQUserPointer sq_getforeignptr(HSQUIRRELVM v) -{ - return v->_foreignptr; -} - -void sq_push(HSQUIRRELVM v,int idx) -{ - v->Push(stack_get(v, idx)); -} - -SQObjectType sq_gettype(HSQUIRRELVM v,int idx) -{ - return type(stack_get(v, idx)); -} - -SQRESULT sq_getinteger(HSQUIRRELVM v,int idx,SQInteger *i) -{ - SQObjectPtr &o = stack_get(v, idx); - if(sq_isnumeric(o)) { - *i = tointeger(o); - return SQ_OK; - } - return SQ_ERROR; -} - -SQRESULT sq_getfloat(HSQUIRRELVM v,int idx,SQFloat *f) -{ - SQObjectPtr &o = stack_get(v, idx); - if(sq_isnumeric(o)) { - *f = tofloat(o); - return SQ_OK; - } - return SQ_ERROR; -} - -SQRESULT sq_getbool(HSQUIRRELVM v,int idx,SQBool *b) -{ - SQObjectPtr &o = stack_get(v, idx); - if(sq_isbool(o)) { - *b = _integer(o); - return SQ_OK; - } - return SQ_ERROR; -} - -SQRESULT sq_getstring(HSQUIRRELVM v,int idx,const SQChar **c) -{ - SQObjectPtr *o = NULL; - _GETSAFE_OBJ(v, idx, OT_STRING,o); - *c = _stringval(*o); - return SQ_OK; -} - -SQRESULT sq_getthread(HSQUIRRELVM v,int idx,HSQUIRRELVM *thread) -{ - SQObjectPtr *o = NULL; - _GETSAFE_OBJ(v, idx, OT_THREAD,o); - *thread = _thread(*o); - return SQ_OK; -} - -SQRESULT sq_clone(HSQUIRRELVM v,int idx) -{ - SQObjectPtr &o = stack_get(v,idx); - v->Push(_null_); - if(!v->Clone(o, stack_get(v, -1))){ - v->Pop(); - return sq_aux_invalidtype(v, type(o)); - } - return SQ_OK; -} - -SQInteger sq_getsize(HSQUIRRELVM v, int idx) -{ - SQObjectPtr &o = stack_get(v, idx); - SQObjectType type = type(o); - switch(type) { - case OT_STRING: return _string(o)->_len; - case OT_TABLE: return _table(o)->CountUsed(); - case OT_ARRAY: return _array(o)->Size(); - case OT_USERDATA: return _userdata(o)->_size; - default: - return sq_aux_invalidtype(v, type); - } -} - -SQRESULT sq_getuserdata(HSQUIRRELVM v,int idx,SQUserPointer *p,unsigned int *typetag) -{ - SQObjectPtr *o = NULL; - _GETSAFE_OBJ(v, idx, OT_USERDATA,o); - (*p) = _userdataval(*o); - if(typetag) *typetag = _userdata(*o)->_typetag; - return SQ_OK; -} - -SQRESULT sq_settypetag(HSQUIRRELVM v,int idx,unsigned int typetag) -{ - SQObjectPtr &o = stack_get(v,idx); - switch(type(o)) { - case OT_USERDATA: _userdata(o)->_typetag = typetag; break; - case OT_CLASS: _class(o)->_typetag = typetag; break; - default: return sq_throwerror(v,_SC("invalid object type")); - } - return SQ_OK; -} - -SQRESULT sq_gettypetag(HSQUIRRELVM v,int idx,unsigned int *typetag) -{ - SQObjectPtr &o = stack_get(v,idx); - switch(type(o)) { - case OT_USERDATA: *typetag = _userdata(o)->_typetag; break; - case OT_CLASS: *typetag = _class(o)->_typetag; break; - default: return sq_throwerror(v,_SC("invalid object type")); - } - return SQ_OK; -} - -SQRESULT sq_getuserpointer(HSQUIRRELVM v, int idx, SQUserPointer *p) -{ - SQObjectPtr *o = NULL; - _GETSAFE_OBJ(v, idx, OT_USERPOINTER,o); - (*p) = _userpointer(*o); - return SQ_OK; -} - -SQRESULT sq_setinstanceup(HSQUIRRELVM v, int idx, SQUserPointer p) -{ - SQObjectPtr &o = stack_get(v,idx); - if(type(o) != OT_INSTANCE) return sq_throwerror(v,_SC("the object is not a class instance")); - _instance(o)->_userpointer = p; - return SQ_OK; -} - -SQRESULT sq_getinstanceup(HSQUIRRELVM v, int idx, SQUserPointer *p,unsigned int typetag) -{ - SQObjectPtr &o = stack_get(v,idx); - if(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; -} - -int sq_gettop(HSQUIRRELVM v) -{ - return (v->_top) - v->_stackbase; -} - -void sq_settop(HSQUIRRELVM v, int newtop) -{ - int top = sq_gettop(v); - if(top > newtop) - sq_pop(v, top - newtop); - else - while(top < newtop) sq_pushnull(v); -} - -void sq_pop(HSQUIRRELVM v, int nelemstopop) -{ - assert(v->_top >= nelemstopop); - v->Pop(nelemstopop); -} - -void sq_remove(HSQUIRRELVM v, int idx) -{ - v->Remove(idx); -} - -int sq_cmp(HSQUIRRELVM v) -{ - int res; - v->ObjCmp(stack_get(v, -1), stack_get(v, -2),res); - return res; -} - -SQRESULT sq_createslot(HSQUIRRELVM v, int idx) -{ - sq_aux_paramscheck(v, 3); - SQObjectPtr &self = stack_get(v, idx); - if(type(self) == OT_TABLE || type(self) == OT_CLASS) { - SQObjectPtr &key = v->GetUp(-2); - if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key")); - v->NewSlot(self, key, v->GetUp(-1)); - v->Pop(2); - } - return SQ_OK; -} - -SQRESULT sq_deleteslot(HSQUIRRELVM v,int idx,SQBool pushval) -{ - sq_aux_paramscheck(v, 2); - SQObjectPtr *self; - _GETSAFE_OBJ(v, idx, OT_TABLE,self); - SQObjectPtr &key = v->GetUp(-1); - if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key")); - SQObjectPtr res; - if(!v->DeleteSlot(*self, key, res)){ - return SQ_ERROR; - } - if(pushval) v->GetUp(-1) = res; - else v->Pop(1); - return SQ_OK; -} - -SQRESULT sq_set(HSQUIRRELVM v,int idx) -{ - SQObjectPtr &self = stack_get(v, idx); - if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) { - v->Pop(2); - return SQ_OK; - } - v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR; -} - -SQRESULT sq_rawset(HSQUIRRELVM v,int idx) -{ - SQObjectPtr &self = stack_get(v, idx); - if(type(v->GetUp(-2)) == OT_NULL) return sq_throwerror(v, _SC("null key")); - switch(type(self)) { - case OT_TABLE: - _table(self)->NewSlot(v->GetUp(-2), v->GetUp(-1)); - v->Pop(2); - return SQ_OK; - break; - case OT_CLASS: - _class(self)->NewSlot(v->GetUp(-2), v->GetUp(-1)); - v->Pop(2); - return SQ_OK; - break; - case OT_INSTANCE: - if(_instance(self)->Set(v->GetUp(-2), v->GetUp(-1))) { - v->Pop(2); - return SQ_OK; - } - break; - case OT_ARRAY: - if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) { - v->Pop(2); - return SQ_OK; - } - break; - default: - v->Pop(2); - return sq_throwerror(v, _SC("rawset works only on arrays,tables,calsses and instances")); - } - v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR; -} - -SQRESULT sq_setdelegate(HSQUIRRELVM v,int idx) -{ - SQObjectPtr &self = stack_get(v, idx); - SQObjectPtr &mt = v->GetUp(-1); - SQObjectType type = type(self); - switch(type) { - case OT_TABLE: - if(type(mt) == OT_TABLE) { - if(!_table(self)->SetDelegate(_table(mt))) return sq_throwerror(v, _SC("delagate cycle")); v->Pop();} - else if(type(mt)==OT_NULL) { - _table(self)->SetDelegate(NULL); v->Pop(); } - else return sq_aux_invalidtype(v,type); - break; - case OT_USERDATA: - if(type(mt)==OT_TABLE) { - _userdata(self)->SetDelegate(_table(mt)); v->Pop(); } - else if(type(mt)==OT_NULL) { - _userdata(self)->SetDelegate(NULL); v->Pop(); } - else return sq_aux_invalidtype(v, type); - break; - default: - return sq_aux_invalidtype(v, type); - break; - } - return SQ_OK; -} - -SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,int idx,SQBool pushval) -{ - sq_aux_paramscheck(v, 2); - SQObjectPtr *self; - _GETSAFE_OBJ(v, idx, OT_TABLE,self); - SQObjectPtr &key = v->GetUp(-1); - SQObjectPtr t; - if(_table(*self)->Get(key,t)) { - _table(*self)->Remove(key); - } - if(pushval != 0) - if(pushval) v->GetUp(-1) = t; - else - v->Pop(1); - return SQ_OK; -} - -SQRESULT sq_getdelegate(HSQUIRRELVM v,int idx) -{ - SQObjectPtr &self=stack_get(v,idx); - switch(type(self)){ - case OT_TABLE: - if(!_table(self)->_delegate)break; - v->Push(SQObjectPtr(_table(self)->_delegate)); - return SQ_OK; - break; - case OT_USERDATA: - if(!_userdata(self)->_delegate)break; - v->Push(SQObjectPtr(_userdata(self)->_delegate)); - return SQ_OK; - break; - } - return sq_throwerror(v,_SC("wrong type")); -} - -SQRESULT sq_get(HSQUIRRELVM v,int idx) -{ - SQObjectPtr &self=stack_get(v,idx); - if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,false)) - return SQ_OK; - v->Pop(1); - return sq_throwerror(v,_SC("the index doesn't exist")); -} - -SQRESULT sq_rawget(HSQUIRRELVM v,int idx) -{ - SQObjectPtr &self=stack_get(v,idx); - switch(type(self)) { - case OT_TABLE: - if(_table(self)->Get(v->GetUp(-1),v->GetUp(-1))) - return SQ_OK; - break; - case OT_CLASS: - if(_class(self)->Get(v->GetUp(-1),v->GetUp(-1))) - return SQ_OK; - break; - case OT_INSTANCE: - if(_instance(self)->Get(v->GetUp(-1),v->GetUp(-1))) - return SQ_OK; - break; - case OT_ARRAY: - if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,false)) - return SQ_OK; - break; - default: - v->Pop(1); - return sq_throwerror(v,_SC("rawget works only on arrays and tables")); - } - v->Pop(1); - return sq_throwerror(v,_SC("the index doesn't exist")); -} - -SQRESULT sq_getstackobj(HSQUIRRELVM v,int idx,HSQOBJECT *po) -{ - *po=stack_get(v,idx); - return SQ_OK; -} - -const SQChar *sq_getlocal(HSQUIRRELVM v,unsigned int level,unsigned int idx) -{ - unsigned int cstksize=v->_callsstack.size(); - unsigned int lvl=(cstksize-level)-1; - int stackbase=v->_stackbase; - if(lvl_callsstack[(cstksize-i)-1]; - stackbase-=ci._prevstkbase; - } - SQVM::CallInfo &ci=v->_callsstack[lvl]; - if(type(ci._closure)!=OT_CLOSURE) - return NULL; - SQClosure *c=_closure(ci._closure); - SQFunctionProto *func=_funcproto(c->_function); - return func->GetLocal(v,stackbase,idx,(ci._ip-func->_instructions._vals)-1); - } - return NULL; -} - -void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj) -{ - v->Push(SQObjectPtr(obj)); -} - -void sq_resetobject(HSQOBJECT *po) -{ - po->_unVal.pUserPointer=NULL;po->_type=OT_NULL; -} - -SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err) -{ - v->_lasterror=SQString::Create(_ss(v),err); - return -1; -} - -void sq_reseterror(HSQUIRRELVM v) -{ - v->_lasterror = _null_; -} - -void sq_getlasterror(HSQUIRRELVM v) -{ - v->Push(v->_lasterror); -} - -void sq_reservestack(HSQUIRRELVM v,int nsize) -{ - if (((unsigned int)v->_top + nsize) > v->_stack.size()) { - v->_stack.resize(v->_stack.size() + ((v->_top + nsize) - v->_stack.size())); - } -} - -SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval) -{ - if(type(v->GetUp(-1))==OT_GENERATOR){ - v->Push(_null_); //retval - if(!v->Execute(v->GetUp(-2),v->_top,0,v->_top,v->GetUp(-1),SQVM::ET_RESUME_GENERATOR)) - {v->Raise_Error(v->_lasterror); return SQ_ERROR;} - if(!retval) - v->Pop(); - return SQ_OK; - } - return sq_throwerror(v,_SC("only generators can be resumed")); -} - -SQRESULT sq_call(HSQUIRRELVM v,int params,SQBool retval) -{ - SQObjectPtr res; - if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res)){ - v->Pop(params);//pop closure and args - if(retval){ - v->Push(res); return SQ_OK; - } - return SQ_OK; - } - else { - v->Pop(params); - return SQ_ERROR; - } - if(!v->_suspended) - v->Pop(params); - return sq_throwerror(v,_SC("call failed")); -} - -SQRESULT sq_suspendvm(HSQUIRRELVM v) -{ - return v->Suspend(); -} - -SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval) -{ - SQObjectPtr ret; - if(!v->_suspended) - return sq_throwerror(v,_SC("cannot resume a vm that is not running any code")); - if(wakeupret) { - v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval - v->Pop(); - } else v->GetAt(v->_stackbase+v->_suspended_target)=_null_; - if(!v->Execute(_null_,v->_top,-1,-1,ret,SQVM::ET_RESUME_VM)) - return SQ_ERROR; - if(sq_getvmstate(v) == SQ_VMSTATE_IDLE) { - while (v->_top > 1) v->_stack[--v->_top] = _null_; - } - if(retval) - v->Push(ret); - return SQ_OK; -} - -void sq_setreleasehook(HSQUIRRELVM v,int idx,SQRELEASEHOOK hook) -{ - if(sq_gettop(v) >= 1){ - SQObjectPtr &ud=stack_get(v,idx); - switch( type(ud) ) { - case OT_USERDATA: - _userdata(ud)->_hook = hook; - break; - case OT_INSTANCE: - _instance(ud)->_hook = hook; - break; - } - } -} - -void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f) -{ - _ss(v)->_compilererrorhandler = f; -} - -SQRESULT sq_writeclosure(HSQUIRRELVM v,SQWRITEFUNC w,SQUserPointer up) -{ - SQObjectPtr *o = NULL; - _GETSAFE_OBJ(v, -1, OT_CLOSURE,o); - SQClosure *c=_closure(*o); - unsigned short tag = SQ_BYTECODE_STREAM_TAG; - if(w(up,&tag,2) != 2) - return sq_throwerror(v,_SC("io error")); - if(!_closure(*o)->Save(v,up,w)) - return SQ_ERROR; - return SQ_OK; -} - -SQRESULT sq_readclosure(HSQUIRRELVM v,SQREADFUNC r,SQUserPointer up) -{ - SQObjectPtr func=SQFunctionProto::Create(); - SQObjectPtr closure=SQClosure::Create(_ss(v),_funcproto(func)); - unsigned short tag; - if(r(up,&tag,2) != 2) - return sq_throwerror(v,_SC("io error")); - if(tag != SQ_BYTECODE_STREAM_TAG) - return sq_throwerror(v,_SC("invalid stream")); - if(!_closure(closure)->Load(v,up,r)) - return SQ_ERROR; - v->Push(closure); - return SQ_OK; -} - -SQChar *sq_getscratchpad(HSQUIRRELVM v,int minsize) -{ - return _ss(v)->GetScratchPad(minsize); -} - -int sq_collectgarbage(HSQUIRRELVM v) -{ -#ifndef NO_GARBAGE_COLLECTOR - return _ss(v)->CollectGarbage(v); -#else - return -1; -#endif -} - -SQRESULT sq_setfreevariable(HSQUIRRELVM v,int idx,unsigned int nval) -{ - SQObjectPtr &self=stack_get(v,idx); - switch(type(self)) - { - case OT_CLOSURE: - if(_closure(self)->_outervalues.size()>nval){ - _closure(self)->_outervalues[nval]=stack_get(v,-1); - } - else return sq_throwerror(v,_SC("invalid free var index")); - break; - case OT_NATIVECLOSURE: - if(_nativeclosure(self)->_outervalues.size()>nval){ - _nativeclosure(self)->_outervalues[nval]=stack_get(v,-1); - } - else return sq_throwerror(v,_SC("invalid free var index")); - break; - default: - return sq_aux_invalidtype(v,type(self)); - } - v->Pop(1); - return SQ_OK; -} - -SQRESULT sq_setattributes(HSQUIRRELVM v,int idx) -{ - SQObjectPtr *o = NULL; - _GETSAFE_OBJ(v, idx, OT_CLASS,o); - SQObjectPtr &key = stack_get(v,-2); - SQObjectPtr &val = stack_get(v,-1); - SQObjectPtr attrs; - if(type(key) == OT_NULL) { - attrs = _class(*o)->_attributes; - _class(*o)->_attributes = val; - v->Pop(2); - v->Push(attrs); - return SQ_OK; - }else if(_class(*o)->GetAttributes(key,attrs)) { - _class(*o)->SetAttributes(key,val); - v->Pop(2); - v->Push(attrs); - return SQ_OK; - } - return sq_throwerror(v,_SC("wrong index")); -} - -SQRESULT sq_getattributes(HSQUIRRELVM v,int idx) -{ - SQObjectPtr *o = NULL; - _GETSAFE_OBJ(v, idx, OT_CLASS,o); - SQObjectPtr &key = stack_get(v,-1); - SQObjectPtr attrs; - if(type(key) == OT_NULL) { - attrs = _class(*o)->_attributes; - v->Pop(); - v->Push(attrs); - return SQ_OK; - } - else if(_class(*o)->GetAttributes(key,attrs)) { - v->Pop(); - v->Push(attrs); - return SQ_OK; - } - return sq_throwerror(v,_SC("wrong index")); -} - -SQRESULT sq_getclass(HSQUIRRELVM v,int idx) -{ - SQObjectPtr *o = NULL; - _GETSAFE_OBJ(v, idx, OT_INSTANCE,o); - v->Push(SQObjectPtr(_instance(*o)->_class)); - return SQ_OK; -} - -SQRESULT sq_createinstance(HSQUIRRELVM v,int idx) -{ - SQObjectPtr *o = NULL; - _GETSAFE_OBJ(v, idx, OT_CLASS,o); - v->Push(_class(*o)->CreateInstance()); - return SQ_OK; -} - -SQRESULT sq_next(HSQUIRRELVM v,int idx) -{ - SQObjectPtr o=stack_get(v,idx),&refpos = stack_get(v,-1),realkey,val; - if(type(o) == OT_GENERATOR) { - return sq_throwerror(v,_SC("cannot iterate a generator")); - } - bool finished; - if(!v->FOREACH_OP(o,realkey,val,refpos,0,finished)) - return SQ_ERROR; - if(!finished) { - v->Push(realkey); - v->Push(val); - return SQ_OK; - } - return SQ_ERROR; -} - -struct BufState{ - const SQChar *buf; - int ptr; - int size; -}; - -SQInteger buf_lexfeed(SQUserPointer file) -{ - BufState *buf=(BufState*)file; - if(buf->size<(buf->ptr+1)) - return 0; - return buf->buf[buf->ptr++]; -} - -SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,int size,const SQChar *sourcename,SQBool raiseerror) { - BufState buf; - buf.buf = s; - buf.size = size; - buf.ptr = 0; - return sq_compile(v, buf_lexfeed, &buf, sourcename, raiseerror); -} - -void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,int idx) -{ - dest->Push(stack_get(src,idx)); -} - -void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc) -{ - _ss(v)->_printfunc = printfunc; -} - -SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v) -{ - return _ss(v)->_printfunc; -} - -void *sq_malloc(unsigned int size) -{ - return SQ_MALLOC(size); -} - -void *sq_realloc(void* p,unsigned int oldsize,unsigned int newsize) -{ - return SQ_REALLOC(p,oldsize,newsize); -} -void sq_free(void *p,unsigned int size) -{ - SQ_FREE(p,size); -} +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqstring.h" +#include "sqtable.h" +#include "sqarray.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "squserdata.h" +#include "sqcompiler.h" +#include "sqfuncstate.h" +#include "sqclass.h" + +bool sq_aux_gettypedarg(HSQUIRRELVM v,SQInteger idx,SQObjectType type,SQObjectPtr **o) +{ + *o = &stack_get(v,idx); + if(type(**o) != type){ + SQObjectPtr oval = v->PrintObjVal(**o); + v->Raise_Error(_SC("wrong argument type, expected '%s' got '%.50s'"),IdType2Name(type),_stringval(oval)); + return false; + } + return true; +} + +#define _GETSAFE_OBJ(v,idx,type,o) { if(!sq_aux_gettypedarg(v,idx,type,&o)) return SQ_ERROR; } + +#define sq_aux_paramscheck(v,count) \ +{ \ + if(sq_gettop(v) < count){ v->Raise_Error(_SC("not enough params in the stack")); return SQ_ERROR; }\ +} + +SQInteger sq_aux_throwobject(HSQUIRRELVM v,SQObjectPtr &e) +{ + v->_lasterror = e; + return SQ_ERROR; +} + +SQInteger sq_aux_invalidtype(HSQUIRRELVM v,SQObjectType type) +{ + scsprintf(_ss(v)->GetScratchPad(100), _SC("unexpected type %s"), IdType2Name(type)); + return sq_throwerror(v, _ss(v)->GetScratchPad(-1)); +} + +HSQUIRRELVM sq_open(SQInteger initialstacksize) +{ + SQSharedState *ss; + SQVM *v; + sq_new(ss, SQSharedState); + ss->Init(); + v = (SQVM *)SQ_MALLOC(sizeof(SQVM)); + new (v) SQVM(ss); + ss->_root_vm = v; + if(v->Init(NULL, initialstacksize)) { + return v; + } else { + sq_delete(v, SQVM); + return NULL; + } + return v; +} + +HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize) +{ + SQSharedState *ss; + SQVM *v; + ss=_ss(friendvm); + + v= (SQVM *)SQ_MALLOC(sizeof(SQVM)); + new (v) SQVM(ss); + + if(v->Init(friendvm, initialstacksize)) { + friendvm->Push(v); + return v; + } else { + sq_delete(v, SQVM); + return NULL; + } +} + +SQInteger sq_getvmstate(HSQUIRRELVM v) +{ + if(v->_suspended) + return SQ_VMSTATE_SUSPENDED; + else { + if(v->_callsstack.size() != 0) return SQ_VMSTATE_RUNNING; + else return SQ_VMSTATE_IDLE; + } +} + +void sq_seterrorhandler(HSQUIRRELVM v) +{ + SQObject o = stack_get(v, -1); + if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) { + v->_errorhandler = o; + v->Pop(); + } +} + +void sq_setdebughook(HSQUIRRELVM v) +{ + SQObject o = stack_get(v,-1); + if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) { + v->_debughook = o; + v->Pop(); + } +} + +void sq_close(HSQUIRRELVM v) +{ + SQSharedState *ss = _ss(v); + _thread(ss->_root_vm)->Finalize(); + sq_delete(ss, SQSharedState); +} + +SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror) +{ + SQObjectPtr o; + if(Compile(v, read, p, sourcename, o, raiseerror?true:false, _ss(v)->_debuginfo)) { + v->Push(SQClosure::Create(_ss(v), _funcproto(o))); + return SQ_OK; + } + return SQ_ERROR; +} + +void sq_enabledebuginfo(HSQUIRRELVM v, SQBool debuginfo) +{ + _ss(v)->_debuginfo = debuginfo?true:false; +} + +void sq_addref(HSQUIRRELVM v,HSQOBJECT *po) +{ + SQObjectPtr refs; + if(!ISREFCOUNTED(type(*po))) return; + if(_table(_ss(v)->_refs_table)->Get(*po, refs)) { + refs = _integer(refs) + 1; + } + else{ + refs = 1; + } + _table(_ss(v)->_refs_table)->NewSlot(*po, refs); +} + +SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po) +{ + SQObjectPtr refs; + if(!ISREFCOUNTED(type(*po))) return SQTrue; + if(_table(_ss(v)->_refs_table)->Get(*po, refs)) { + SQInteger n = _integer(refs) - 1; + if(n <= 0) { + _table(_ss(v)->_refs_table)->Remove(*po); + sq_resetobject(po); + } + else { + refs = n;_table(_ss(v)->_refs_table)->Set(*po, refs); + return SQFalse; + } + } + return SQTrue; +} + +const SQChar *sq_objtostring(HSQOBJECT *o) +{ + if(sq_type(*o) == OT_STRING) { + return _stringval(*o); + } + return NULL; +} + +SQInteger sq_objtointeger(HSQOBJECT *o) +{ + if(sq_isnumeric(*o)) { + return tointeger(*o); + } + return 0; +} + +SQFloat sq_objtofloat(HSQOBJECT *o) +{ + if(sq_isnumeric(*o)) { + return tofloat(*o); + } + return 0; +} + +SQBool sq_objtobool(HSQOBJECT *o) +{ + if(sq_isbool(*o)) { + return _integer(*o); + } + return SQFalse; +} + +void sq_pushnull(HSQUIRRELVM v) +{ + v->Push(_null_); +} + +void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len) +{ + if(s) + v->Push(SQObjectPtr(SQString::Create(_ss(v), s, len))); + else v->Push(_null_); +} + +void sq_pushinteger(HSQUIRRELVM v,SQInteger n) +{ + v->Push(n); +} + +void sq_pushbool(HSQUIRRELVM v,SQBool b) +{ + v->Push(b?true:false); +} + +void sq_pushfloat(HSQUIRRELVM v,SQFloat n) +{ + v->Push(n); +} + +void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p) +{ + v->Push(p); +} + +SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size) +{ + SQUserData *ud = SQUserData::Create(_ss(v), size); + v->Push(ud); + return ud->_val; +} + +void sq_newtable(HSQUIRRELVM v) +{ + v->Push(SQTable::Create(_ss(v), 0)); +} + +void sq_newarray(HSQUIRRELVM v,SQInteger size) +{ + v->Push(SQArray::Create(_ss(v), size)); +} + +SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase) +{ + SQClass *baseclass = NULL; + if(hasbase) { + SQObjectPtr &base = stack_get(v,-1); + if(type(base) != OT_CLASS) + return sq_throwerror(v,_SC("invalid base type")); + baseclass = _class(base); + } + SQClass *newclass = SQClass::Create(_ss(v), baseclass); + if(baseclass) v->Pop(); + v->Push(newclass); + return SQ_OK; +} + +SQInteger sq_instanceof(HSQUIRRELVM v) +{ + SQObjectPtr &inst = stack_get(v,-1); + SQObjectPtr &cl = stack_get(v,-2); + if(type(inst) != OT_INSTANCE || type(cl) != OT_CLASS) + return sq_throwerror(v,_SC("invalid param type")); + return _instance(inst)->InstanceOf(_class(cl))?1:0; +} + +SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx) +{ + sq_aux_paramscheck(v,2); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + _array(*arr)->Append(v->GetUp(-1)); + v->Pop(1); + return SQ_OK; +} + +SQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQBool pushval) +{ + sq_aux_paramscheck(v, 1); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + if(_array(*arr)->Size() > 0) { + if(pushval != 0){ v->Push(_array(*arr)->Top()); } + _array(*arr)->Pop(); + return SQ_OK; + } + return sq_throwerror(v, _SC("empty array")); +} + +SQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize) +{ + sq_aux_paramscheck(v,1); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + if(_array(*arr)->Size() > 0) { + _array(*arr)->Resize(newsize); + return SQ_OK; + } + return SQ_OK; +} + +SQRESULT sq_arrayreverse(HSQUIRRELVM v,SQInteger idx) +{ + sq_aux_paramscheck(v, 1); + SQObjectPtr *o; + _GETSAFE_OBJ(v, idx, OT_ARRAY,o); + SQArray *arr = _array(*o); + if(arr->Size() > 0) { + SQObjectPtr t; + SQInteger size = arr->Size(); + SQInteger n = size >> 1; size -= 1; + for(SQInteger i = 0; i < n; i++) { + t = arr->_values[i]; + arr->_values[i] = arr->_values[size-i]; + arr->_values[size-i] = t; + } + return SQ_OK; + } + return SQ_OK; +} + +void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars) +{ + SQNativeClosure *nc = SQNativeClosure::Create(_ss(v), func); + nc->_nparamscheck = 0; + for(SQUnsignedInteger i = 0; i < nfreevars; i++) { + nc->_outervalues.push_back(v->Top()); + v->Pop(); + } + v->Push(SQObjectPtr(nc)); +} + +SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger *nparams,SQUnsignedInteger *nfreevars) +{ + SQObject o = stack_get(v, idx); + if(sq_isclosure(o)) { + SQClosure *c = _closure(o); + SQFunctionProto *proto = _funcproto(c->_function); + *nparams = (SQUnsignedInteger)proto->_parameters.size(); + *nfreevars = (SQUnsignedInteger)c->_outervalues.size(); + return SQ_OK; + } + return sq_throwerror(v,_SC("the object is not a closure")); +} + +SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name) +{ + SQObject o = stack_get(v, idx); + if(sq_isnativeclosure(o)) { + SQNativeClosure *nc = _nativeclosure(o); + nc->_name = SQString::Create(_ss(v),name); + return SQ_OK; + } + return sq_throwerror(v,_SC("the object is not a nativeclosure")); +} + +SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask) +{ + SQObject o = stack_get(v, -1); + if(!sq_isnativeclosure(o)) + return sq_throwerror(v, _SC("native closure expected")); + SQNativeClosure *nc = _nativeclosure(o); + nc->_nparamscheck = nparamscheck; + if(typemask) { + SQIntVec res; + if(!CompileTypemask(res, typemask)) + return sq_throwerror(v, _SC("invalid typemask")); + nc->_typecheck.copy(res); + } + else { + nc->_typecheck.resize(0); + } + if(nparamscheck == SQ_MATCHTYPEMASKSTRING) { + nc->_nparamscheck = nc->_typecheck.size(); + } + return SQ_OK; +} + +void sq_pushroottable(HSQUIRRELVM v) +{ + v->Push(v->_roottable); +} + +void sq_pushregistrytable(HSQUIRRELVM v) +{ + v->Push(_ss(v)->_registry); +} + +SQRESULT sq_setroottable(HSQUIRRELVM v) +{ + SQObject o = stack_get(v, -1); + if(sq_istable(o) || sq_isnull(o)) { + v->_roottable = o; + v->Pop(); + return SQ_OK; + } + return sq_throwerror(v, _SC("ivalid type")); +} + +void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p) +{ + v->_foreignptr = p; +} + +SQUserPointer sq_getforeignptr(HSQUIRRELVM v) +{ + return v->_foreignptr; +} + +void sq_push(HSQUIRRELVM v,SQInteger idx) +{ + v->Push(stack_get(v, idx)); +} + +SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx) +{ + return type(stack_get(v, idx)); +} + +void sq_tostring(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &o = stack_get(v, idx); + SQObjectPtr res; + v->ToString(o,res); + v->Push(res); +} + +SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i) +{ + SQObjectPtr &o = stack_get(v, idx); + if(sq_isnumeric(o)) { + *i = tointeger(o); + return SQ_OK; + } + return SQ_ERROR; +} + +SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f) +{ + SQObjectPtr &o = stack_get(v, idx); + if(sq_isnumeric(o)) { + *f = tofloat(o); + return SQ_OK; + } + return SQ_ERROR; +} + +SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b) +{ + SQObjectPtr &o = stack_get(v, idx); + if(sq_isbool(o)) { + *b = _integer(o); + return SQ_OK; + } + return SQ_ERROR; +} + +SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_STRING,o); + *c = _stringval(*o); + return SQ_OK; +} + +SQRESULT sq_getthread(HSQUIRRELVM v,SQInteger idx,HSQUIRRELVM *thread) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_THREAD,o); + *thread = _thread(*o); + return SQ_OK; +} + +SQRESULT sq_clone(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &o = stack_get(v,idx); + v->Push(_null_); + if(!v->Clone(o, stack_get(v, -1))){ + v->Pop(); + return sq_aux_invalidtype(v, type(o)); + } + return SQ_OK; +} + +SQInteger sq_getsize(HSQUIRRELVM v, SQInteger idx) +{ + SQObjectPtr &o = stack_get(v, idx); + SQObjectType type = type(o); + switch(type) { + case OT_STRING: return _string(o)->_len; + case OT_TABLE: return _table(o)->CountUsed(); + case OT_ARRAY: return _array(o)->Size(); + case OT_USERDATA: return _userdata(o)->_size; + default: + return sq_aux_invalidtype(v, type); + } +} + +SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_USERDATA,o); + (*p) = _userdataval(*o); + if(typetag) *typetag = _userdata(*o)->_typetag; + return SQ_OK; +} + +SQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag) +{ + SQObjectPtr &o = stack_get(v,idx); + switch(type(o)) { + case OT_USERDATA: _userdata(o)->_typetag = typetag; break; + case OT_CLASS: _class(o)->_typetag = typetag; break; + default: return sq_throwerror(v,_SC("invalid object type")); + } + return SQ_OK; +} + +SQRESULT sq_getobjtypetag(HSQOBJECT *o,SQUserPointer * typetag) +{ + switch(type(*o)) { + case OT_INSTANCE: *typetag = _instance(*o)->_class->_typetag; break; + case OT_USERDATA: *typetag = _userdata(*o)->_typetag; break; + case OT_CLASS: *typetag = _class(*o)->_typetag; break; + default: return SQ_ERROR; + } + return SQ_OK; +} + +SQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag) +{ + SQObjectPtr &o = stack_get(v,idx); + if(SQ_FAILED(sq_getobjtypetag(&o,typetag))) + return sq_throwerror(v,_SC("invalid object type")); + return SQ_OK; +} + +SQRESULT sq_getuserpointer(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_USERPOINTER,o); + (*p) = _userpointer(*o); + return SQ_OK; +} + +SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p) +{ + SQObjectPtr &o = stack_get(v,idx); + if(type(o) != OT_INSTANCE) return sq_throwerror(v,_SC("the object is not a class instance")); + _instance(o)->_userpointer = p; + return SQ_OK; +} + +SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag) +{ + SQObjectPtr &o = stack_get(v,idx); + if(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; +} + +SQInteger sq_gettop(HSQUIRRELVM v) +{ + return (v->_top) - v->_stackbase; +} + +void sq_settop(HSQUIRRELVM v, SQInteger newtop) +{ + SQInteger top = sq_gettop(v); + if(top > newtop) + sq_pop(v, top - newtop); + else + while(top < newtop) sq_pushnull(v); +} + +void sq_pop(HSQUIRRELVM v, SQInteger nelemstopop) +{ + assert(v->_top >= nelemstopop); + v->Pop(nelemstopop); +} + +void sq_poptop(HSQUIRRELVM v) +{ + assert(v->_top >= 1); + v->Pop(); +} + + +void sq_remove(HSQUIRRELVM v, SQInteger idx) +{ + v->Remove(idx); +} + +SQInteger sq_cmp(HSQUIRRELVM v) +{ + SQInteger res; + v->ObjCmp(stack_get(v, -1), stack_get(v, -2),res); + return res; +} + +SQRESULT sq_createslot(HSQUIRRELVM v, SQInteger idx) +{ + sq_aux_paramscheck(v, 3); + SQObjectPtr &self = stack_get(v, idx); + if(type(self) == OT_TABLE || type(self) == OT_CLASS) { + SQObjectPtr &key = v->GetUp(-2); + if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key")); + v->NewSlot(self, key, v->GetUp(-1)); + v->Pop(2); + } + return SQ_OK; +} + +SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval) +{ + sq_aux_paramscheck(v, 2); + SQObjectPtr *self; + _GETSAFE_OBJ(v, idx, OT_TABLE,self); + SQObjectPtr &key = v->GetUp(-1); + if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key")); + SQObjectPtr res; + if(!v->DeleteSlot(*self, key, res)){ + return SQ_ERROR; + } + if(pushval) v->GetUp(-1) = res; + else v->Pop(1); + return SQ_OK; +} + +SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self = stack_get(v, idx); + if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) { + v->Pop(2); + return SQ_OK; + } + v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR; +} + +SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self = stack_get(v, idx); + if(type(v->GetUp(-2)) == OT_NULL) return sq_throwerror(v, _SC("null key")); + switch(type(self)) { + case OT_TABLE: + _table(self)->NewSlot(v->GetUp(-2), v->GetUp(-1)); + v->Pop(2); + return SQ_OK; + break; + case OT_CLASS: + _class(self)->NewSlot(v->GetUp(-2), v->GetUp(-1)); + v->Pop(2); + return SQ_OK; + break; + case OT_INSTANCE: + if(_instance(self)->Set(v->GetUp(-2), v->GetUp(-1))) { + v->Pop(2); + return SQ_OK; + } + break; + case OT_ARRAY: + if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) { + v->Pop(2); + return SQ_OK; + } + break; + default: + v->Pop(2); + return sq_throwerror(v, _SC("rawset works only on array/table/calsse and instance")); + } + v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR; +} + +SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self = stack_get(v, idx); + SQObjectPtr &mt = v->GetUp(-1); + SQObjectType type = type(self); + switch(type) { + case OT_TABLE: + if(type(mt) == OT_TABLE) { + if(!_table(self)->SetDelegate(_table(mt))) return sq_throwerror(v, _SC("delagate cycle")); v->Pop();} + else if(type(mt)==OT_NULL) { + _table(self)->SetDelegate(NULL); v->Pop(); } + else return sq_aux_invalidtype(v,type); + break; + case OT_USERDATA: + if(type(mt)==OT_TABLE) { + _userdata(self)->SetDelegate(_table(mt)); v->Pop(); } + else if(type(mt)==OT_NULL) { + _userdata(self)->SetDelegate(NULL); v->Pop(); } + else return sq_aux_invalidtype(v, type); + break; + default: + return sq_aux_invalidtype(v, type); + break; + } + return SQ_OK; +} + +SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval) +{ + sq_aux_paramscheck(v, 2); + SQObjectPtr *self; + _GETSAFE_OBJ(v, idx, OT_TABLE,self); + SQObjectPtr &key = v->GetUp(-1); + SQObjectPtr t; + if(_table(*self)->Get(key,t)) { + _table(*self)->Remove(key); + } + if(pushval != 0) + if(pushval) v->GetUp(-1) = t; + else + v->Pop(1); + return SQ_OK; +} + +SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self=stack_get(v,idx); + switch(type(self)){ + case OT_TABLE: + if(!_table(self)->_delegate)break; + v->Push(SQObjectPtr(_table(self)->_delegate)); + return SQ_OK; + break; + case OT_USERDATA: + if(!_userdata(self)->_delegate)break; + v->Push(SQObjectPtr(_userdata(self)->_delegate)); + return SQ_OK; + break; + } + return sq_throwerror(v,_SC("wrong type")); +} + +SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self=stack_get(v,idx); + if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,false)) + return SQ_OK; + v->Pop(1); + return sq_throwerror(v,_SC("the index doesn't exist")); +} + +SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self=stack_get(v,idx); + switch(type(self)) { + case OT_TABLE: + if(_table(self)->Get(v->GetUp(-1),v->GetUp(-1))) + return SQ_OK; + break; + case OT_CLASS: + if(_class(self)->Get(v->GetUp(-1),v->GetUp(-1))) + return SQ_OK; + break; + case OT_INSTANCE: + if(_instance(self)->Get(v->GetUp(-1),v->GetUp(-1))) + return SQ_OK; + break; + case OT_ARRAY: + if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,false)) + return SQ_OK; + break; + default: + v->Pop(1); + return sq_throwerror(v,_SC("rawget works only on array/table/instance and class")); + } + v->Pop(1); + return sq_throwerror(v,_SC("the index doesn't exist")); +} + +SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po) +{ + *po=stack_get(v,idx); + return SQ_OK; +} + +const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx) +{ + SQUnsignedInteger cstksize=v->_callsstack.size(); + SQUnsignedInteger lvl=(cstksize-level)-1; + SQInteger stackbase=v->_stackbase; + if(lvl_callsstack[(cstksize-i)-1]; + stackbase-=ci._prevstkbase; + } + SQVM::CallInfo &ci=v->_callsstack[lvl]; + if(type(ci._closure)!=OT_CLOSURE) + return NULL; + SQClosure *c=_closure(ci._closure); + SQFunctionProto *func=_funcproto(c->_function); + return func->GetLocal(v,stackbase,idx,(ci._ip-func->_instructions._vals)-1); + } + return NULL; +} + +void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj) +{ + v->Push(SQObjectPtr(obj)); +} + +void sq_resetobject(HSQOBJECT *po) +{ + po->_unVal.pUserPointer=NULL;po->_type=OT_NULL; +} + +SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err) +{ + v->_lasterror=SQString::Create(_ss(v),err); + return -1; +} + +void sq_reseterror(HSQUIRRELVM v) +{ + v->_lasterror = _null_; +} + +void sq_getlasterror(HSQUIRRELVM v) +{ + v->Push(v->_lasterror); +} + +void sq_reservestack(HSQUIRRELVM v,SQInteger nsize) +{ + if (((SQUnsignedInteger)v->_top + nsize) > v->_stack.size()) { + v->_stack.resize(v->_stack.size() + ((v->_top + nsize) - v->_stack.size())); + } +} + +SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval) +{ + if(type(v->GetUp(-1))==OT_GENERATOR){ + v->Push(_null_); //retval + if(!v->Execute(v->GetUp(-2),v->_top,0,v->_top,v->GetUp(-1),SQVM::ET_RESUME_GENERATOR)) + {v->Raise_Error(v->_lasterror); return SQ_ERROR;} + if(!retval) + v->Pop(); + return SQ_OK; + } + return sq_throwerror(v,_SC("only generators can be resumed")); +} + +SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval) +{ + SQObjectPtr res; + if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res)){ + v->Pop(params);//pop closure and args + if(retval){ + v->Push(res); return SQ_OK; + } + return SQ_OK; + } + else { + v->Pop(params); + return SQ_ERROR; + } + if(!v->_suspended) + v->Pop(params); + return sq_throwerror(v,_SC("call failed")); +} + +SQRESULT sq_suspendvm(HSQUIRRELVM v) +{ + return v->Suspend(); +} + +SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval) +{ + SQObjectPtr ret; + if(!v->_suspended) + return sq_throwerror(v,_SC("cannot resume a vm that is not running any code")); + if(wakeupret) { + v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval + v->Pop(); + } else v->GetAt(v->_stackbase+v->_suspended_target)=_null_; + if(!v->Execute(_null_,v->_top,-1,-1,ret,SQVM::ET_RESUME_VM)) + return SQ_ERROR; + if(sq_getvmstate(v) == SQ_VMSTATE_IDLE) { + while (v->_top > 1) v->_stack[--v->_top] = _null_; + } + if(retval) + v->Push(ret); + return SQ_OK; +} + +void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook) +{ + if(sq_gettop(v) >= 1){ + SQObjectPtr &ud=stack_get(v,idx); + switch( type(ud) ) { + case OT_USERDATA: + _userdata(ud)->_hook = hook; + break; + case OT_INSTANCE: + _instance(ud)->_hook = hook; + break; + } + } +} + +void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f) +{ + _ss(v)->_compilererrorhandler = f; +} + +SQRESULT sq_writeclosure(HSQUIRRELVM v,SQWRITEFUNC w,SQUserPointer up) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, -1, OT_CLOSURE,o); + SQClosure *c=_closure(*o); + unsigned short tag = SQ_BYTECODE_STREAM_TAG; + if(w(up,&tag,2) != 2) + return sq_throwerror(v,_SC("io error")); + if(!_closure(*o)->Save(v,up,w)) + return SQ_ERROR; + return SQ_OK; +} + +SQRESULT sq_readclosure(HSQUIRRELVM v,SQREADFUNC r,SQUserPointer up) +{ + SQObjectPtr func=SQFunctionProto::Create(); + SQObjectPtr closure=SQClosure::Create(_ss(v),_funcproto(func)); + unsigned short tag; + if(r(up,&tag,2) != 2) + return sq_throwerror(v,_SC("io error")); + if(tag != SQ_BYTECODE_STREAM_TAG) + return sq_throwerror(v,_SC("invalid stream")); + if(!_closure(closure)->Load(v,up,r)) + return SQ_ERROR; + v->Push(closure); + return SQ_OK; +} + +SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize) +{ + return _ss(v)->GetScratchPad(minsize); +} + +SQInteger sq_collectgarbage(HSQUIRRELVM v) +{ +#ifndef NO_GARBAGE_COLLECTOR + return _ss(v)->CollectGarbage(v); +#else + return -1; +#endif +} + +const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval) +{ + SQObjectPtr &self = stack_get(v,idx); + const SQChar *name = NULL; + if(type(self) == OT_CLOSURE) { + if(_closure(self)->_outervalues.size()>nval) { + v->Push(_closure(self)->_outervalues[nval]); + SQFunctionProto *fp = _funcproto(_closure(self)->_function); + SQOuterVar &ov = fp->_outervalues[nval]; + name = _stringval(ov._name); + } + } + return name; +} + +SQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval) +{ + SQObjectPtr &self=stack_get(v,idx); + switch(type(self)) + { + case OT_CLOSURE: + if(_closure(self)->_outervalues.size()>nval){ + _closure(self)->_outervalues[nval]=stack_get(v,-1); + } + else return sq_throwerror(v,_SC("invalid free var index")); + break; + case OT_NATIVECLOSURE: + if(_nativeclosure(self)->_outervalues.size()>nval){ + _nativeclosure(self)->_outervalues[nval]=stack_get(v,-1); + } + else return sq_throwerror(v,_SC("invalid free var index")); + break; + default: + return sq_aux_invalidtype(v,type(self)); + } + v->Pop(1); + return SQ_OK; +} + +SQRESULT sq_setattributes(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + SQObjectPtr &key = stack_get(v,-2); + SQObjectPtr &val = stack_get(v,-1); + SQObjectPtr attrs; + if(type(key) == OT_NULL) { + attrs = _class(*o)->_attributes; + _class(*o)->_attributes = val; + v->Pop(2); + v->Push(attrs); + return SQ_OK; + }else if(_class(*o)->GetAttributes(key,attrs)) { + _class(*o)->SetAttributes(key,val); + v->Pop(2); + v->Push(attrs); + return SQ_OK; + } + return sq_throwerror(v,_SC("wrong index")); +} + +SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + SQObjectPtr &key = stack_get(v,-1); + SQObjectPtr attrs; + if(type(key) == OT_NULL) { + attrs = _class(*o)->_attributes; + v->Pop(); + v->Push(attrs); + return SQ_OK; + } + else if(_class(*o)->GetAttributes(key,attrs)) { + v->Pop(); + v->Push(attrs); + return SQ_OK; + } + return sq_throwerror(v,_SC("wrong index")); +} + +SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_INSTANCE,o); + v->Push(SQObjectPtr(_instance(*o)->_class)); + return SQ_OK; +} + +SQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + v->Push(_class(*o)->CreateInstance()); + return SQ_OK; +} + +void sq_weakref(HSQUIRRELVM v,SQInteger idx) +{ + SQObject &o=stack_get(v,idx); + if(ISREFCOUNTED(type(o))) { + v->Push(_refcounted(o)->GetWeakRef(type(o))); + return; + } + v->Push(o); +} + +SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &o = stack_get(v,idx); + if(type(o) != OT_WEAKREF) { + return sq_throwerror(v,_SC("the object must be a weakref")); + } + v->Push(_weakref(o)->_obj); + return SQ_OK; +} + +SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr o=stack_get(v,idx),&refpos = stack_get(v,-1),realkey,val; + if(type(o) == OT_GENERATOR) { + return sq_throwerror(v,_SC("cannot iterate a generator")); + } + bool finished; + if(!v->FOREACH_OP(o,realkey,val,refpos,0,finished)) + return SQ_ERROR; + if(!finished) { + v->Push(realkey); + v->Push(val); + return SQ_OK; + } + return SQ_ERROR; +} + +struct BufState{ + const SQChar *buf; + SQInteger ptr; + SQInteger size; +}; + +SQInteger buf_lexfeed(SQUserPointer file) +{ + BufState *buf=(BufState*)file; + if(buf->size<(buf->ptr+1)) + return 0; + return buf->buf[buf->ptr++]; +} + +SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror) { + BufState buf; + buf.buf = s; + buf.size = size; + buf.ptr = 0; + return sq_compile(v, buf_lexfeed, &buf, sourcename, raiseerror); +} + +void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx) +{ + dest->Push(stack_get(src,idx)); +} + +void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc) +{ + _ss(v)->_printfunc = printfunc; +} + +SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v) +{ + return _ss(v)->_printfunc; +} + +void *sq_malloc(SQUnsignedInteger size) +{ + return SQ_MALLOC(size); +} + +void *sq_realloc(void* p,SQUnsignedInteger oldsize,SQUnsignedInteger newsize) +{ + return SQ_REALLOC(p,oldsize,newsize); +} +void sq_free(void *p,SQUnsignedInteger size) +{ + SQ_FREE(p,size); +} diff --git a/src/squirrel/squirrel/sqarray.h b/src/squirrel/squirrel/sqarray.h index 7aadbd77d..b463e8162 100644 --- a/src/squirrel/squirrel/sqarray.h +++ b/src/squirrel/squirrel/sqarray.h @@ -1,77 +1,79 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQARRAY_H_ -#define _SQARRAY_H_ - -struct SQArray : public CHAINABLE_OBJ -{ -private: - SQArray(SQSharedState *ss,int nsize){_values.resize(nsize);_uiRef=0;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} - ~SQArray() - { - REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); - } -public: - static SQArray* Create(SQSharedState *ss,int nInitialSize){ - SQArray *newarray=(SQArray*)SQ_MALLOC(sizeof(SQArray)); - new (newarray) SQArray(ss,nInitialSize); - return newarray; - } -#ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); -#endif - void Finalize(){ - _values.resize(0); - } - bool Get(const int nidx,SQObjectPtr &val) - { - if(nidx>=0 && nidx<(int)_values.size()){ - val=_values[nidx]; - return true; - } - else return false; - } - bool Set(const int nidx,const SQObjectPtr &val) - { - if(nidx>=0 && nidx<(int)_values.size()){ - _values[nidx]=val; - return true; - } - else return false; - } - int Next(const SQObjectPtr &refpos,SQObjectPtr &outkey,SQObjectPtr &outval) - { - unsigned int idx=TranslateIndex(refpos); - while(idx<_values.size()){ - //first found - outkey=(SQInteger)idx; - outval=_values[idx]; - //return idx for the next iteration - return ++idx; - } - //nothing to iterate anymore - return -1; - } - SQArray *Clone(){SQArray *anew=Create(_opt_ss(this),Size()); anew->_values.copy(_values); return anew; } - int Size() const {return _values.size();} - void Resize(int size,SQObjectPtr &fill = _null_) { _values.resize(size,fill); ShrinkIfNeeded(); } - void Reserve(int size) { _values.reserve(size); } - void Append(const SQObject &o){_values.push_back(o);} - void Extend(const SQArray *a); - SQObjectPtr &Top(){return _values.top();} - void Pop(){_values.pop_back(); ShrinkIfNeeded(); } - void Insert(const SQObject& idx,const SQObject &val){_values.insert((unsigned int)tointeger(idx),val);} - void ShrinkIfNeeded() { - if(_values.size() <= _values.capacity()>>2) //shrink the array - _values.shrinktofit(); - } - void Remove(unsigned int idx){ - _values.remove(idx); - ShrinkIfNeeded(); - } - void Release() - { - sq_delete(this,SQArray); - } - SQObjectPtrVec _values; -}; -#endif //_SQARRAY_H_ +/* see copyright notice in squirrel.h */ +#ifndef _SQARRAY_H_ +#define _SQARRAY_H_ + +struct SQArray : public CHAINABLE_OBJ +{ +private: + SQArray(SQSharedState *ss,SQInteger nsize){_values.resize(nsize); INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} + ~SQArray() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } +public: + static SQArray* Create(SQSharedState *ss,SQInteger nInitialSize){ + SQArray *newarray=(SQArray*)SQ_MALLOC(sizeof(SQArray)); + new (newarray) SQArray(ss,nInitialSize); + return newarray; + } +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); +#endif + void Finalize(){ + _values.resize(0); + } + bool Get(const SQInteger nidx,SQObjectPtr &val) + { + if(nidx>=0 && nidx<(SQInteger)_values.size()){ + SQObjectPtr &o = _values[nidx]; + val = _realval(o); + return true; + } + else return false; + } + bool Set(const SQInteger nidx,const SQObjectPtr &val) + { + if(nidx>=0 && nidx<(SQInteger)_values.size()){ + _values[nidx]=val; + return true; + } + else return false; + } + SQInteger Next(const SQObjectPtr &refpos,SQObjectPtr &outkey,SQObjectPtr &outval) + { + SQUnsignedInteger idx=TranslateIndex(refpos); + while(idx<_values.size()){ + //first found + outkey=(SQInteger)idx; + SQObjectPtr &o = _values[idx]; + outval = _realval(o); + //return idx for the next iteration + return ++idx; + } + //nothing to iterate anymore + return -1; + } + SQArray *Clone(){SQArray *anew=Create(_opt_ss(this),Size()); anew->_values.copy(_values); return anew; } + SQInteger Size() const {return _values.size();} + void Resize(SQInteger size,SQObjectPtr &fill = _null_) { _values.resize(size,fill); ShrinkIfNeeded(); } + void Reserve(SQInteger size) { _values.reserve(size); } + void Append(const SQObject &o){_values.push_back(o);} + void Extend(const SQArray *a); + SQObjectPtr &Top(){return _values.top();} + void Pop(){_values.pop_back(); ShrinkIfNeeded(); } + void Insert(const SQObject& idx,const SQObject &val){_values.insert((SQUnsignedInteger)tointeger(idx),val);} + void ShrinkIfNeeded() { + if(_values.size() <= _values.capacity()>>2) //shrink the array + _values.shrinktofit(); + } + void Remove(SQUnsignedInteger idx){ + _values.remove(idx); + ShrinkIfNeeded(); + } + void Release() + { + sq_delete(this,SQArray); + } + SQObjectPtrVec _values; +}; +#endif //_SQARRAY_H_ diff --git a/src/squirrel/squirrel/sqbaselib.cpp b/src/squirrel/squirrel/sqbaselib.cpp index 01bce2ce3..674608fcc 100644 --- a/src/squirrel/squirrel/sqbaselib.cpp +++ b/src/squirrel/squirrel/sqbaselib.cpp @@ -1,781 +1,779 @@ -/* - see copyright notice in squirrel.h -*/ -#include "sqpcheader.h" -#include "sqvm.h" -#include "sqstring.h" -#include "sqtable.h" -#include "sqarray.h" -#include "sqfuncproto.h" -#include "sqclosure.h" -#include "sqclass.h" -#include -#include -#include - -bool str2num(const SQChar *s,SQObjectPtr &res) -{ - SQChar *end; - if(scstrstr(s,_SC("."))){ - SQFloat r = SQFloat(scstrtod(s,&end)); - if(s == end) return false; - while (scisspace((*end)) ) end++; - if (*end != _SC('\0')) return false; - res = r; - return true; - } - else{ - const SQChar *t = s; - while(*t != _SC('\0')) if(!scisdigit(*t++)) return false; - res = SQInteger(scatoi(s)); - return true; - } -} - -#ifndef NO_GARBAGE_COLLECTOR -static int base_collectgarbage(HSQUIRRELVM v) -{ - sq_pushinteger(v, sq_collectgarbage(v)); - return 1; -} -#endif - -static int base_getroottable(HSQUIRRELVM v) -{ - v->Push(v->_roottable); - return 1; -} - -static int base_setroottable(HSQUIRRELVM v) -{ - SQObjectPtr &o=stack_get(v,2); - if(SQ_FAILED(sq_setroottable(v))) return SQ_ERROR; - v->Push(o); - return 1; -} - -static int base_seterrorhandler(HSQUIRRELVM v) -{ - sq_seterrorhandler(v); - return 0; -} - -static int base_setdebughook(HSQUIRRELVM v) -{ - sq_setdebughook(v); - return 0; -} - -static int base_enabledebuginfo(HSQUIRRELVM v) -{ - SQObjectPtr &o=stack_get(v,2); - sq_enabledebuginfo(v,(type(o) != OT_NULL)?1:0); - return 0; -} - -static int base_getstackinfos(HSQUIRRELVM v) -{ - SQInteger level; - SQStackInfos si; - int seq = 0; - const SQChar *name = NULL; - sq_getinteger(v, -1, &level); - if (SQ_SUCCEEDED(sq_stackinfos(v, level, &si))) - { - const SQChar *fn = _SC("unknown"); - const SQChar *src = _SC("unknown"); - if(si.funcname)fn = si.funcname; - if(si.source)src = si.source; - sq_newtable(v); - sq_pushstring(v, _SC("func"), -1); - sq_pushstring(v, fn, -1); - sq_createslot(v, -3); - sq_pushstring(v, _SC("src"), -1); - sq_pushstring(v, src, -1); - sq_createslot(v, -3); - sq_pushstring(v, _SC("line"), -1); - sq_pushinteger(v, si.line); - sq_createslot(v, -3); - sq_pushstring(v, _SC("locals"), -1); - sq_newtable(v); - seq=0; - while (name = sq_getlocal(v, level, seq)) { - sq_pushstring(v, name, -1); - sq_push(v, -2); - sq_createslot(v, -4); - sq_pop(v, 1); - seq++; - } - sq_createslot(v, -3); - return 1; - } - - return 0; -} - -static int base_assert(HSQUIRRELVM v) -{ - if(v->IsFalse(stack_get(v,2))){ - return sq_throwerror(v,_SC("assertion failed")); - } - return 0; -} - -static int get_slice_params(HSQUIRRELVM v,int &sidx,int &eidx,SQObjectPtr &o) -{ - int top = sq_gettop(v); - sidx=0; - eidx=0; - o=stack_get(v,1); - SQObjectPtr &start=stack_get(v,2); - if(type(start)!=OT_NULL && sq_isnumeric(start)){ - sidx=tointeger(start); - } - if(top>2){ - SQObjectPtr &end=stack_get(v,3); - if(sq_isnumeric(end)){ - eidx=tointeger(end); - } - } - else { - eidx = sq_getsize(v,1); - } - return 1; -} - -static int base_print(HSQUIRRELVM v) -{ - SQObjectPtr &o=stack_get(v,2); - switch(type(o)){ - case OT_STRING: - if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,_SC("%s"),_stringval(o)); - break; - case OT_INTEGER: - if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,_SC("%d"),_integer(o)); - break; - case OT_FLOAT: - if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,_SC("%.14g"),_float(o)); - break; - default:{ - SQObjectPtr tname; - v->TypeOf(o,tname); - if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,_SC("(%s)"),_stringval(tname)); - } - break; - } - return 0; -} - -static int base_compilestring(HSQUIRRELVM v) -{ - int nargs=sq_gettop(v); - const SQChar *src=NULL,*name=_SC("unnamedbuffer"); - SQInteger 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 int base_newthread(HSQUIRRELVM v) -{ - SQObjectPtr &func = stack_get(v,2); - int stksize = (_funcproto(_closure(func)->_function)->_stacksize << 1) +2; - HSQUIRRELVM newv = sq_newthread(v, (stksize < MIN_STACK_OVERHEAD + 2)? MIN_STACK_OVERHEAD + 2 : stksize); - sq_move(newv,v,-2); - return 1; -} - -static int base_suspend(HSQUIRRELVM v) -{ - return sq_suspendvm(v); -} - -static int base_array(HSQUIRRELVM v) -{ - SQArray *a; - SQObject &size = stack_get(v,2); - if(sq_gettop(v) > 2) { - a = SQArray::Create(_ss(v),0); - a->Resize(tointeger(size),stack_get(v,3)); - } - else { - a = SQArray::Create(_ss(v),tointeger(size)); - } - v->Push(a); - return 1; -} - -static int base_type(HSQUIRRELVM v) -{ - SQObjectPtr &o = stack_get(v,2); - v->Push(SQString::Create(_ss(v),GetTypeName(o),-1)); - return 1; -} - -static SQRegFunction base_funcs[]={ - //generic - {_SC("seterrorhandler"),base_seterrorhandler,2, NULL}, - {_SC("setdebughook"),base_setdebughook,2, NULL}, - {_SC("enabledebuginfo"),base_enabledebuginfo,2, NULL}, - {_SC("getstackinfos"),base_getstackinfos,2, _SC(".n")}, - {_SC("getroottable"),base_getroottable,1, NULL}, - {_SC("setroottable"),base_setroottable,2, NULL}, - {_SC("assert"),base_assert,2, NULL}, - {_SC("print"),base_print,2, NULL}, - {_SC("compilestring"),base_compilestring,-2, _SC(".ss")}, - {_SC("newthread"),base_newthread,2, _SC(".c")}, - {_SC("suspend"),base_suspend,-1, NULL}, - {_SC("array"),base_array,-2, _SC(".n")}, - {_SC("type"),base_type,2, NULL}, -#ifndef NO_GARBAGE_COLLECTOR - {_SC("collectgarbage"),base_collectgarbage,1, _SC("t")}, -#endif - {0,0} -}; - -void sq_base_register(HSQUIRRELVM v) -{ - int 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_createslot(v,-3); - i++; - } - sq_pushstring(v,_SC("_charsize_"),-1); - sq_pushinteger(v,sizeof(SQChar)); - sq_createslot(v,-3); - sq_pop(v,1); -} - -static int default_delegate_len(HSQUIRRELVM v) -{ - v->Push(SQInteger(sq_getsize(v,1))); - return 1; -} - -static int default_delegate_tofloat(HSQUIRRELVM v) -{ - SQObjectPtr &o=stack_get(v,1); - switch(type(o)){ - case OT_STRING:{ - SQObjectPtr res; - if(str2num(_stringval(o),res)){ - v->Push(SQObjectPtr(tofloat(res))); - break; - }} - case OT_INTEGER:case OT_FLOAT: - v->Push(SQObjectPtr(tofloat(o))); - break; - case OT_BOOL: - v->Push(SQObjectPtr((SQFloat)(_integer(o)?1:0))); - break; - default: - v->Push(_null_); - break; - } - return 1; -} - -static int default_delegate_tointeger(HSQUIRRELVM v) -{ - SQObjectPtr &o=stack_get(v,1); - switch(type(o)){ - case OT_STRING:{ - SQObjectPtr res; - if(str2num(_stringval(o),res)){ - v->Push(SQObjectPtr(tointeger(res))); - break; - }} - case OT_INTEGER:case OT_FLOAT: - v->Push(SQObjectPtr(tointeger(o))); - break; - case OT_BOOL: - v->Push(SQObjectPtr(_integer(o)?1:0)); - break; - default: - v->Push(_null_); - break; - } - return 1; -} - -static int default_delegate_tostring(HSQUIRRELVM v) -{ - SQObjectPtr &o=stack_get(v,1); - switch(type(o)){ - case OT_STRING: - v->Push(o); - break; - case OT_INTEGER: - scsprintf(_ss(v)->GetScratchPad(rsl(NUMBER_MAX_CHAR+1)),_SC("%d"),_integer(o)); - v->Push(SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1))); - break; - case OT_FLOAT: - scsprintf(_ss(v)->GetScratchPad(rsl(NUMBER_MAX_CHAR+1)),_SC("%.14g"),_float(o)); - v->Push(SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1))); - break; - case OT_BOOL: - v->Push(SQObjectPtr(SQString::Create(_ss(v),_integer(o)?_SC("true"):_SC("false")))); - break; - default: - v->Push(_null_); - break; - } - return 1; -} - -static int number_delegate_tochar(HSQUIRRELVM v) -{ - SQObject &o=stack_get(v,1); - SQChar c=tointeger(o); - v->Push(SQString::Create(_ss(v),(const SQChar *)&c,1)); - return 1; -} - - -///////////////////////////////////////////////////////////////// -//TABLE DEFAULT DELEGATE - -static int table_rawdelete(HSQUIRRELVM v) -{ - if(SQ_FAILED(sq_rawdeleteslot(v,1,SQTrue))) - return SQ_ERROR; - return 1; -} - - -static int container_rawexists(HSQUIRRELVM v) -{ - if(SQ_SUCCEEDED(sq_rawget(v,-2))) { - sq_pushbool(v,SQTrue); - return 1; - } - sq_pushbool(v,SQFalse); - return 1; -} - -static int table_rawset(HSQUIRRELVM v) -{ - return sq_rawset(v,-3); -} - - -static int table_rawget(HSQUIRRELVM v) -{ - return SQ_SUCCEEDED(sq_rawget(v,-2))?1:SQ_ERROR; -} - -SQRegFunction SQSharedState::_table_default_delegate_funcz[]={ - {_SC("len"),default_delegate_len,1, _SC("t")}, - {_SC("rawget"),table_rawget,2, _SC("t")}, - {_SC("rawset"),table_rawset,3, _SC("t")}, - {_SC("rawdelete"),table_rawdelete,2, _SC("t")}, - {_SC("rawin"),container_rawexists,2, _SC("t")}, - {0,0} -}; - -//ARRAY DEFAULT DELEGATE/////////////////////////////////////// - -static int array_append(HSQUIRRELVM v) -{ - return sq_arrayappend(v,-2); -} - -static int array_extend(HSQUIRRELVM v) -{ - _array(stack_get(v,1))->Extend(_array(stack_get(v,2))); - return 0; -} - -static int array_reverse(HSQUIRRELVM v) -{ - return sq_arrayreverse(v,-1); -} - -static int array_pop(HSQUIRRELVM v) -{ - return SQ_SUCCEEDED(sq_arraypop(v,1,SQTrue))?1:SQ_ERROR; -} - -static int array_top(HSQUIRRELVM v) -{ - SQObject &o=stack_get(v,1); - if(_array(o)->Size()>0){ - v->Push(_array(o)->Top()); - return 1; - } - else return sq_throwerror(v,_SC("top() on a empty array")); -} - -static int array_insert(HSQUIRRELVM v) -{ - SQObject &o=stack_get(v,1); - SQObject &idx=stack_get(v,2); - SQObject &val=stack_get(v,3); - _array(o)->Insert(idx,val); - return 0; -} - -static int array_remove(HSQUIRRELVM v) -{ - SQObject &o = stack_get(v, 1); - SQObject &idx = stack_get(v, 2); - if(!sq_isnumeric(idx)) return sq_throwerror(v, _SC("wrong type")); - SQObjectPtr val; - if(_array(o)->Get(tointeger(idx), val)) { - _array(o)->Remove(tointeger(idx)); - v->Push(val); - return 1; - } - return sq_throwerror(v, _SC("idx out of range")); -} - -static int array_resize(HSQUIRRELVM v) -{ - SQObject &o = stack_get(v, 1); - SQObject &nsize = stack_get(v, 2); - SQObjectPtr fill; - if(sq_isnumeric(nsize)) { - if(sq_gettop(v) > 2) - fill = stack_get(v, 3); - _array(o)->Resize(tointeger(nsize),fill); - return 0; - } - return sq_throwerror(v, _SC("size must be a number")); -} - - -//QSORT ala Sedgewick -bool _qsort_compare(HSQUIRRELVM v,SQObjectPtr &arr,SQObjectPtr &a,SQObjectPtr &b,int func,int &ret) -{ - if(func < 0) { - if(!v->ObjCmp(a,b,ret)) return false; - } - else { - int 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))) { - v->Raise_Error(_SC("compare func failed")); - return false; - } - sq_getinteger(v, -1, &ret); - sq_settop(v, top); - return true; - } - return true; -} -//QSORT ala Sedgewick -bool _qsort(HSQUIRRELVM v,SQObjectPtr &arr, int l, int r,int func) -{ - int i, j; - SQArray *a=_array(arr); - SQObjectPtr pivot,t; - if( l < r ){ - pivot = a->_values[l]; - i = l; j = r+1; - while(1){ - int ret; - do { - ++i; - if(i > r) break; - if(!_qsort_compare(v,arr,a->_values[i],pivot,func,ret)) - return false; - } while( ret <= 0); - do { - --j; - if(!_qsort_compare(v,arr,a->_values[j],pivot,func,ret)) - return false; - } - while( ret > 0 ); - if( i >= j ) break; - t = a->_values[i]; a->_values[i] = a->_values[j]; a->_values[j] = t; - } - t = a->_values[l]; a->_values[l] = a->_values[j]; a->_values[j] = t; - if(!_qsort( v, arr, l, j-1,func)) return false; - if(!_qsort( v, arr, j+1, r,func)) return false; - } - return true; -} - -static int array_sort(HSQUIRRELVM v) -{ - //SQ_TRY { - int func = -1; - SQObjectPtr &o = stack_get(v,1); - SQObject &funcobj = stack_get(v,2); - if(_array(o)->Size() > 1) { - if(type(funcobj) == OT_CLOSURE || type(funcobj) == OT_NATIVECLOSURE) func = 2; - if(!_qsort(v, o, 0, _array(o)->Size()-1, func)) - return SQ_ERROR; - - } - return 0; -} -static int array_slice(HSQUIRRELVM v) -{ - int sidx,eidx; - SQObjectPtr o; - if(get_slice_params(v,sidx,eidx,o)==-1)return -1; - if(sidx<0)sidx=_array(o)->Size()+sidx; - if(eidx<0)eidx=_array(o)->Size()+eidx; - if(eidx <= sidx)return sq_throwerror(v,_SC("wrong indexes")); - SQArray *arr=SQArray::Create(_ss(v),eidx-sidx); - SQObjectPtr t; - int count=0; - for(int i=sidx;iGet(i,t); - arr->Set(count++,t); - } - v->Push(arr); - return 1; - -} - -SQRegFunction SQSharedState::_array_default_delegate_funcz[]={ - {_SC("len"),default_delegate_len,1, _SC("a")}, - {_SC("append"),array_append,2, _SC("a")}, - {_SC("extend"),array_extend,2, _SC("aa")}, - {_SC("push"),array_append,2, _SC("a")}, - {_SC("pop"),array_pop,1, _SC("a")}, - {_SC("top"),array_top,1, _SC("a")}, - {_SC("insert"),array_insert,3, _SC("an")}, - {_SC("remove"),array_remove,2, _SC("an")}, - {_SC("resize"),array_resize,-2, _SC("an")}, - {_SC("reverse"),array_reverse,1, _SC("a")}, - {_SC("sort"),array_sort,-1, _SC("ac")}, - {_SC("slice"),array_slice,-1, _SC("ann")}, - {0,0} -}; - -//STRING DEFAULT DELEGATE////////////////////////// -static int string_slice(HSQUIRRELVM v) -{ - int sidx,eidx; - SQObjectPtr o; - if(SQ_FAILED(get_slice_params(v,sidx,eidx,o)))return -1; - if(sidx<0)sidx=_string(o)->_len+sidx; - if(eidx<0)eidx=_string(o)->_len+eidx; - if(eidxPush(SQString::Create(_ss(v),&_stringval(o)[sidx],eidx-sidx)); - return 1; -} - -static int string_find(HSQUIRRELVM v) -{ - int top,start_idx=0; - const SQChar *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=scstrstr(&str[start_idx],substr); - if(ret){ - sq_pushinteger(v,(int)(ret-str)); - return 1; - } - } - return 0; - } - return sq_throwerror(v,_SC("invalid param")); -} - -#define STRING_TOFUNCZ(func) static int string_##func(HSQUIRRELVM v) \ -{ \ - SQObject str=stack_get(v,1); \ - int len=_string(str)->_len; \ - const SQChar *sThis=_stringval(str); \ - SQChar *sNew=(_ss(v)->GetScratchPad(rsl(len))); \ - for(int i=0;iPush(SQString::Create(_ss(v),sNew,len)); \ - return 1; \ -} - - -STRING_TOFUNCZ(tolower) -STRING_TOFUNCZ(toupper) - -SQRegFunction SQSharedState::_string_default_delegate_funcz[]={ - {_SC("len"),default_delegate_len,1, _SC("s")}, - {_SC("tointeger"),default_delegate_tointeger,1, _SC("s")}, - {_SC("tofloat"),default_delegate_tofloat,1, _SC("s")}, - {_SC("tostring"),default_delegate_tostring,1, _SC("s")}, - {_SC("slice"),string_slice,-1, _SC(" s n n")}, - {_SC("find"),string_find,-2, _SC("s s n ")}, - {_SC("tolower"),string_tolower,1, _SC("s")}, - {_SC("toupper"),string_toupper,1, _SC("s")}, - {0,0} -}; - -//INTEGER DEFAULT DELEGATE////////////////////////// -SQRegFunction SQSharedState::_number_default_delegate_funcz[]={ - {_SC("tointeger"),default_delegate_tointeger,1, _SC("n|b")}, - {_SC("tofloat"),default_delegate_tofloat,1, _SC("n|b")}, - {_SC("tostring"),default_delegate_tostring,1, _SC("n|b")}, - {_SC("tochar"),number_delegate_tochar,1, _SC("n|b")}, - {0,0} -}; - -//CLOSURE DEFAULT DELEGATE////////////////////////// -static int closure_call(HSQUIRRELVM v) -{ - return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue))?1:SQ_ERROR; -} - -static int closure_acall(HSQUIRRELVM v) -{ - SQArray *aparams=_array(stack_get(v,2)); - int nparams=aparams->Size(); - v->Push(stack_get(v,1)); - for(int i=0;iPush(aparams->_values[i]); - return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue))?1:SQ_ERROR; -} - -SQRegFunction SQSharedState::_closure_default_delegate_funcz[]={ - {_SC("call"),closure_call,-1, _SC("c")}, - {_SC("acall"),closure_acall,2, _SC("ca")}, - {0,0} -}; - -//GENERATOR DEFAULT DELEGATE -static int generator_getstatus(HSQUIRRELVM v) -{ - SQObject &o=stack_get(v,1); - switch(_generator(o)->_state){ - case SQGenerator::eSuspended:v->Push(SQString::Create(_ss(v),_SC("suspended")));break; - case SQGenerator::eRunning:v->Push(SQString::Create(_ss(v),_SC("running")));break; - case SQGenerator::eDead:v->Push(SQString::Create(_ss(v),_SC("dead")));break; - } - return 1; -} - -SQRegFunction SQSharedState::_generator_default_delegate_funcz[]={ - {_SC("getstatus"),generator_getstatus,1, _SC("g")}, - {0,0} -}; - -//THREAD DEFAULT DELEGATE - -static int thread_call(HSQUIRRELVM v) -{ - SQObjectPtr o = stack_get(v,1); - if(type(o) == OT_THREAD) { - int nparams = sq_gettop(v); - _thread(o)->Push(_thread(o)->_roottable); - for(int i = 2; i<(nparams+1); i++) - sq_move(_thread(o),v,i); - if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue))) { - sq_move(v,_thread(o),-1); - return 1; - } - return SQ_ERROR; - } - return sq_throwerror(v,_SC("wrong parameter")); -} - -static int thread_wakeup(HSQUIRRELVM v) -{ - SQObjectPtr o = stack_get(v,1); - if(type(o) == OT_THREAD) { - SQVM *thread = _thread(o); - int state = sq_getvmstate(thread); - if(state != SQ_VMSTATE_SUSPENDED) { - switch(state) { - case SQ_VMSTATE_IDLE: - return sq_throwerror(v,_SC("cannot wakeup a idle thread")); - break; - case SQ_VMSTATE_RUNNING: - return sq_throwerror(v,_SC("cannot wakeup a running thread")); - break; - } - } - - int wakeupret = sq_gettop(v)>1?1:0; - if(wakeupret) { - sq_move(thread,v,2); - } - if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,1))) { - sq_move(v,thread,-1); - sq_pop(thread,1); - if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) { - sq_pop(thread,1); - } - return 1; - } - return SQ_ERROR; - } - return sq_throwerror(v,_SC("wrong parameter")); -} - -static int thread_getstatus(HSQUIRRELVM v) -{ - SQObjectPtr &o = stack_get(v,1); - switch(sq_getvmstate(_thread(o))) { - case SQ_VMSTATE_IDLE: - sq_pushstring(v,_SC("idle"),-1); - break; - case SQ_VMSTATE_RUNNING: - sq_pushstring(v,_SC("running"),-1); - break; - case SQ_VMSTATE_SUSPENDED: - sq_pushstring(v,_SC("suspended"),-1); - break; - default: - return sq_throwerror(v,_SC("internal VM error")); - } - return 1; -} - -SQRegFunction SQSharedState::_thread_default_delegate_funcz[] = { - {_SC("call"), thread_call, -1, _SC("v")}, - {_SC("wakeup"), thread_wakeup, -1, _SC("v")}, - {_SC("getstatus"), thread_getstatus, 1, _SC("v")}, - {0,0}, -}; - -static int class_getattributes(HSQUIRRELVM v) -{ - if(SQ_SUCCEEDED(sq_getattributes(v,-2))) - return 1; - return SQ_ERROR; -} - -static int class_setattributes(HSQUIRRELVM v) -{ - if(SQ_SUCCEEDED(sq_setattributes(v,-3))) - return 1; - return SQ_ERROR; -} - -SQRegFunction SQSharedState::_class_default_delegate_funcz[] = { - {_SC("getattributes"), class_getattributes, 2, _SC("y.")}, - {_SC("setattributes"), class_setattributes, 3, _SC("y..")}, - {_SC("rawin"),container_rawexists,2, _SC("y")}, - {0,0} -}; - -static int instance_getclass(HSQUIRRELVM v) -{ - if(SQ_SUCCEEDED(sq_getclass(v,1))) - return 1; - return SQ_ERROR; -} - -SQRegFunction SQSharedState::_instance_default_delegate_funcz[] = { - {_SC("getclass"), instance_getclass, 1, _SC("x")}, - {_SC("rawin"),container_rawexists,2, _SC("x")}, - {0,0} -}; - +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqstring.h" +#include "sqtable.h" +#include "sqarray.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "sqclass.h" +#include +#include +#include + +bool str2num(const SQChar *s,SQObjectPtr &res) +{ + SQChar *end; + if(scstrstr(s,_SC("."))){ + SQFloat r = SQFloat(scstrtod(s,&end)); + if(s == end) return false; + res = r; + return true; + } + else{ + SQInteger r = SQInteger(scstrtol(s,&end,10)); + if(s == end) return false; + res = r; + return true; + } +} + +#ifndef NO_GARBAGE_COLLECTOR +static SQInteger base_collectgarbage(HSQUIRRELVM v) +{ + sq_pushinteger(v, sq_collectgarbage(v)); + return 1; +} +#endif + +static SQInteger base_getroottable(HSQUIRRELVM v) +{ + v->Push(v->_roottable); + return 1; +} + +static SQInteger base_setroottable(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,2); + if(SQ_FAILED(sq_setroottable(v))) return SQ_ERROR; + v->Push(o); + return 1; +} + +static SQInteger base_seterrorhandler(HSQUIRRELVM v) +{ + sq_seterrorhandler(v); + return 0; +} + +static SQInteger base_setdebughook(HSQUIRRELVM v) +{ + sq_setdebughook(v); + return 0; +} + +static SQInteger base_enabledebuginfo(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,2); + sq_enabledebuginfo(v,(type(o) != OT_NULL)?1:0); + return 0; +} + +static SQInteger base_getstackinfos(HSQUIRRELVM v) +{ + SQInteger level; + SQStackInfos si; + SQInteger seq = 0; + const SQChar *name = NULL; + sq_getinteger(v, -1, &level); + if (SQ_SUCCEEDED(sq_stackinfos(v, level, &si))) + { + const SQChar *fn = _SC("unknown"); + const SQChar *src = _SC("unknown"); + if(si.funcname)fn = si.funcname; + if(si.source)src = si.source; + sq_newtable(v); + sq_pushstring(v, _SC("func"), -1); + sq_pushstring(v, fn, -1); + sq_createslot(v, -3); + sq_pushstring(v, _SC("src"), -1); + sq_pushstring(v, src, -1); + sq_createslot(v, -3); + sq_pushstring(v, _SC("line"), -1); + sq_pushinteger(v, si.line); + sq_createslot(v, -3); + sq_pushstring(v, _SC("locals"), -1); + sq_newtable(v); + seq=0; + while (name = sq_getlocal(v, level, seq)) { + sq_pushstring(v, name, -1); + sq_push(v, -2); + sq_createslot(v, -4); + sq_pop(v, 1); + seq++; + } + sq_createslot(v, -3); + return 1; + } + + return 0; +} + +static SQInteger base_assert(HSQUIRRELVM v) +{ + if(v->IsFalse(stack_get(v,2))){ + return sq_throwerror(v,_SC("assertion failed")); + } + return 0; +} + +static SQInteger get_slice_params(HSQUIRRELVM v,SQInteger &sidx,SQInteger &eidx,SQObjectPtr &o) +{ + SQInteger top = sq_gettop(v); + sidx=0; + eidx=0; + o=stack_get(v,1); + SQObjectPtr &start=stack_get(v,2); + if(type(start)!=OT_NULL && sq_isnumeric(start)){ + sidx=tointeger(start); + } + if(top>2){ + SQObjectPtr &end=stack_get(v,3); + if(sq_isnumeric(end)){ + eidx=tointeger(end); + } + } + else { + eidx = sq_getsize(v,1); + } + return 1; +} + +static SQInteger base_print(HSQUIRRELVM v) +{ + const SQChar *str; + sq_tostring(v,2); + sq_getstring(v,-1,&str); + if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,_SC("%s"),str); + return 0; +} + +static SQInteger base_compilestring(HSQUIRRELVM v) +{ + SQInteger nargs=sq_gettop(v); + const SQChar *src=NULL,*name=_SC("unnamedbuffer"); + SQInteger 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 SQInteger base_newthread(HSQUIRRELVM v) +{ + SQObjectPtr &func = stack_get(v,2); + SQInteger stksize = (_funcproto(_closure(func)->_function)->_stacksize << 1) +2; + HSQUIRRELVM newv = sq_newthread(v, (stksize < MIN_STACK_OVERHEAD + 2)? MIN_STACK_OVERHEAD + 2 : stksize); + sq_move(newv,v,-2); + return 1; +} + +static SQInteger base_suspend(HSQUIRRELVM v) +{ + return sq_suspendvm(v); +} + +static SQInteger base_array(HSQUIRRELVM v) +{ + SQArray *a; + SQObject &size = stack_get(v,2); + if(sq_gettop(v) > 2) { + a = SQArray::Create(_ss(v),0); + a->Resize(tointeger(size),stack_get(v,3)); + } + else { + a = SQArray::Create(_ss(v),tointeger(size)); + } + v->Push(a); + return 1; +} + +static SQInteger base_type(HSQUIRRELVM v) +{ + SQObjectPtr &o = stack_get(v,2); + v->Push(SQString::Create(_ss(v),GetTypeName(o),-1)); + return 1; +} + +static SQRegFunction base_funcs[]={ + //generic + {_SC("seterrorhandler"),base_seterrorhandler,2, NULL}, + {_SC("setdebughook"),base_setdebughook,2, NULL}, + {_SC("enabledebuginfo"),base_enabledebuginfo,2, NULL}, + {_SC("getstackinfos"),base_getstackinfos,2, _SC(".n")}, + {_SC("getroottable"),base_getroottable,1, NULL}, + {_SC("setroottable"),base_setroottable,2, NULL}, + {_SC("assert"),base_assert,2, NULL}, + {_SC("print"),base_print,2, NULL}, + {_SC("compilestring"),base_compilestring,-2, _SC(".ss")}, + {_SC("newthread"),base_newthread,2, _SC(".c")}, + {_SC("suspend"),base_suspend,-1, NULL}, + {_SC("array"),base_array,-2, _SC(".n")}, + {_SC("type"),base_type,2, NULL}, +#ifndef NO_GARBAGE_COLLECTOR + {_SC("collectgarbage"),base_collectgarbage,1, _SC("t")}, +#endif + {0,0} +}; + +void sq_base_register(HSQUIRRELVM v) +{ + SQInteger 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_createslot(v,-3); + i++; + } + sq_pushstring(v,_SC("_charsize_"),-1); + sq_pushinteger(v,sizeof(SQChar)); + sq_createslot(v,-3); + sq_pop(v,1); +} + +static SQInteger default_delegate_len(HSQUIRRELVM v) +{ + v->Push(SQInteger(sq_getsize(v,1))); + return 1; +} + +static SQInteger default_delegate_tofloat(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,1); + switch(type(o)){ + case OT_STRING:{ + SQObjectPtr res; + if(str2num(_stringval(o),res)){ + v->Push(SQObjectPtr(tofloat(res))); + break; + }} + return sq_throwerror(v, _SC("cannot convert the string")); + break; + case OT_INTEGER:case OT_FLOAT: + v->Push(SQObjectPtr(tofloat(o))); + break; + case OT_BOOL: + v->Push(SQObjectPtr((SQFloat)(_integer(o)?1:0))); + break; + default: + v->Push(_null_); + break; + } + return 1; +} + +static SQInteger default_delegate_tointeger(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,1); + switch(type(o)){ + case OT_STRING:{ + SQObjectPtr res; + if(str2num(_stringval(o),res)){ + v->Push(SQObjectPtr(tointeger(res))); + break; + }} + return sq_throwerror(v, _SC("cannot convert the string")); + break; + case OT_INTEGER:case OT_FLOAT: + v->Push(SQObjectPtr(tointeger(o))); + break; + case OT_BOOL: + v->Push(SQObjectPtr(_integer(o)?1:0)); + break; + default: + v->Push(_null_); + break; + } + return 1; +} + +static SQInteger default_delegate_tostring(HSQUIRRELVM v) +{ + sq_tostring(v,1); + return 1; +} + +static SQInteger obj_delegate_weakref(HSQUIRRELVM v) +{ + sq_weakref(v,1); + return 1; +} + +static SQInteger number_delegate_tochar(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + SQChar c=tointeger(o); + v->Push(SQString::Create(_ss(v),(const SQChar *)&c,1)); + return 1; +} + + +///////////////////////////////////////////////////////////////// +//TABLE DEFAULT DELEGATE + +static SQInteger table_rawdelete(HSQUIRRELVM v) +{ + if(SQ_FAILED(sq_rawdeleteslot(v,1,SQTrue))) + return SQ_ERROR; + return 1; +} + + +static SQInteger container_rawexists(HSQUIRRELVM v) +{ + if(SQ_SUCCEEDED(sq_rawget(v,-2))) { + sq_pushbool(v,SQTrue); + return 1; + } + sq_pushbool(v,SQFalse); + return 1; +} + +static SQInteger table_rawset(HSQUIRRELVM v) +{ + return sq_rawset(v,-3); +} + + +static SQInteger table_rawget(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_rawget(v,-2))?1:SQ_ERROR; +} + +SQRegFunction SQSharedState::_table_default_delegate_funcz[]={ + {_SC("len"),default_delegate_len,1, _SC("t")}, + {_SC("rawget"),table_rawget,2, _SC("t")}, + {_SC("rawset"),table_rawset,3, _SC("t")}, + {_SC("rawdelete"),table_rawdelete,2, _SC("t")}, + {_SC("rawin"),container_rawexists,2, _SC("t")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {0,0} +}; + +//ARRAY DEFAULT DELEGATE/////////////////////////////////////// + +static SQInteger array_append(HSQUIRRELVM v) +{ + return sq_arrayappend(v,-2); +} + +static SQInteger array_extend(HSQUIRRELVM v) +{ + _array(stack_get(v,1))->Extend(_array(stack_get(v,2))); + return 0; +} + +static SQInteger array_reverse(HSQUIRRELVM v) +{ + return sq_arrayreverse(v,-1); +} + +static SQInteger array_pop(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_arraypop(v,1,SQTrue))?1:SQ_ERROR; +} + +static SQInteger array_top(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + if(_array(o)->Size()>0){ + v->Push(_array(o)->Top()); + return 1; + } + else return sq_throwerror(v,_SC("top() on a empty array")); +} + +static SQInteger array_insert(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + SQObject &idx=stack_get(v,2); + SQObject &val=stack_get(v,3); + _array(o)->Insert(idx,val); + return 0; +} + +static SQInteger array_remove(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v, 1); + SQObject &idx = stack_get(v, 2); + if(!sq_isnumeric(idx)) return sq_throwerror(v, _SC("wrong type")); + SQObjectPtr val; + if(_array(o)->Get(tointeger(idx), val)) { + _array(o)->Remove(tointeger(idx)); + v->Push(val); + return 1; + } + return sq_throwerror(v, _SC("idx out of range")); +} + +static SQInteger array_resize(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v, 1); + SQObject &nsize = stack_get(v, 2); + SQObjectPtr fill; + if(sq_isnumeric(nsize)) { + if(sq_gettop(v) > 2) + fill = stack_get(v, 3); + _array(o)->Resize(tointeger(nsize),fill); + return 0; + } + return sq_throwerror(v, _SC("size must be a number")); +} + + +//QSORT ala Sedgewick +bool _qsort_compare(HSQUIRRELVM v,SQObjectPtr &arr,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret) +{ + if(func < 0) { + if(!v->ObjCmp(a,b,ret)) return false; + } + else { + SQInteger 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))) { + v->Raise_Error(_SC("compare func failed")); + return false; + } + sq_getinteger(v, -1, &ret); + sq_settop(v, top); + return true; + } + return true; +} +//QSORT ala Sedgewick +bool _qsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger l, SQInteger r,SQInteger func) +{ + SQInteger i, j; + SQArray *a=_array(arr); + SQObjectPtr pivot,t; + if( l < r ){ + pivot = a->_values[l]; + i = l; j = r+1; + while(1){ + SQInteger ret; + do { + ++i; + if(i > r) break; + if(!_qsort_compare(v,arr,a->_values[i],pivot,func,ret)) + return false; + } while( ret <= 0); + do { + --j; + if(!_qsort_compare(v,arr,a->_values[j],pivot,func,ret)) + return false; + } + while( ret > 0 ); + if( i >= j ) break; + t = a->_values[i]; a->_values[i] = a->_values[j]; a->_values[j] = t; + } + t = a->_values[l]; a->_values[l] = a->_values[j]; a->_values[j] = t; + if(!_qsort( v, arr, l, j-1,func)) return false; + if(!_qsort( v, arr, j+1, r,func)) return false; + } + return true; +} + +static SQInteger array_sort(HSQUIRRELVM v) +{ + //SQ_TRY { + SQInteger func = -1; + SQObjectPtr &o = stack_get(v,1); + SQObject &funcobj = stack_get(v,2); + if(_array(o)->Size() > 1) { + if(type(funcobj) == OT_CLOSURE || type(funcobj) == OT_NATIVECLOSURE) func = 2; + if(!_qsort(v, o, 0, _array(o)->Size()-1, func)) + return SQ_ERROR; + + } + return 0; +} +static SQInteger array_slice(HSQUIRRELVM v) +{ + SQInteger sidx,eidx; + SQObjectPtr o; + if(get_slice_params(v,sidx,eidx,o)==-1)return -1; + if(sidx<0)sidx=_array(o)->Size()+sidx; + if(eidx<0)eidx=_array(o)->Size()+eidx; + if(eidx <= sidx)return sq_throwerror(v,_SC("wrong indexes")); + SQArray *arr=SQArray::Create(_ss(v),eidx-sidx); + SQObjectPtr t; + SQInteger count=0; + for(SQInteger i=sidx;iGet(i,t); + arr->Set(count++,t); + } + v->Push(arr); + return 1; + +} + +SQRegFunction SQSharedState::_array_default_delegate_funcz[]={ + {_SC("len"),default_delegate_len,1, _SC("a")}, + {_SC("append"),array_append,2, _SC("a")}, + {_SC("extend"),array_extend,2, _SC("aa")}, + {_SC("push"),array_append,2, _SC("a")}, + {_SC("pop"),array_pop,1, _SC("a")}, + {_SC("top"),array_top,1, _SC("a")}, + {_SC("insert"),array_insert,3, _SC("an")}, + {_SC("remove"),array_remove,2, _SC("an")}, + {_SC("resize"),array_resize,-2, _SC("an")}, + {_SC("reverse"),array_reverse,1, _SC("a")}, + {_SC("sort"),array_sort,-1, _SC("ac")}, + {_SC("slice"),array_slice,-1, _SC("ann")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {0,0} +}; + +//STRING DEFAULT DELEGATE////////////////////////// +static SQInteger string_slice(HSQUIRRELVM v) +{ + SQInteger sidx,eidx; + SQObjectPtr o; + if(SQ_FAILED(get_slice_params(v,sidx,eidx,o)))return -1; + if(sidx<0)sidx=_string(o)->_len+sidx; + if(eidx<0)eidx=_string(o)->_len+eidx; + if(eidxPush(SQString::Create(_ss(v),&_stringval(o)[sidx],eidx-sidx)); + return 1; +} + +static SQInteger string_find(HSQUIRRELVM v) +{ + SQInteger top,start_idx=0; + const SQChar *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=scstrstr(&str[start_idx],substr); + if(ret){ + sq_pushinteger(v,(SQInteger)(ret-str)); + return 1; + } + } + return 0; + } + return sq_throwerror(v,_SC("invalid param")); +} + +#define STRING_TOFUNCZ(func) static SQInteger string_##func(HSQUIRRELVM v) \ +{ \ + SQObject str=stack_get(v,1); \ + SQInteger len=_string(str)->_len; \ + const SQChar *sThis=_stringval(str); \ + SQChar *sNew=(_ss(v)->GetScratchPad(rsl(len))); \ + for(SQInteger i=0;iPush(SQString::Create(_ss(v),sNew,len)); \ + return 1; \ +} + + +STRING_TOFUNCZ(tolower) +STRING_TOFUNCZ(toupper) + +SQRegFunction SQSharedState::_string_default_delegate_funcz[]={ + {_SC("len"),default_delegate_len,1, _SC("s")}, + {_SC("tointeger"),default_delegate_tointeger,1, _SC("s")}, + {_SC("tofloat"),default_delegate_tofloat,1, _SC("s")}, + {_SC("tostring"),default_delegate_tostring,1, _SC("s")}, + {_SC("slice"),string_slice,-1, _SC(" s n n")}, + {_SC("find"),string_find,-2, _SC("s s n ")}, + {_SC("tolower"),string_tolower,1, _SC("s")}, + {_SC("toupper"),string_toupper,1, _SC("s")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {0,0} +}; + +//INTEGER DEFAULT DELEGATE////////////////////////// +SQRegFunction SQSharedState::_number_default_delegate_funcz[]={ + {_SC("tointeger"),default_delegate_tointeger,1, _SC("n|b")}, + {_SC("tofloat"),default_delegate_tofloat,1, _SC("n|b")}, + {_SC("tostring"),default_delegate_tostring,1, _SC("n|b")}, + {_SC("tochar"),number_delegate_tochar,1, _SC("n|b")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {0,0} +}; + +//CLOSURE DEFAULT DELEGATE////////////////////////// +static SQInteger closure_call(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue))?1:SQ_ERROR; +} + +static SQInteger closure_acall(HSQUIRRELVM v) +{ + SQArray *aparams=_array(stack_get(v,2)); + SQInteger nparams=aparams->Size(); + v->Push(stack_get(v,1)); + for(SQInteger i=0;iPush(aparams->_values[i]); + return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue))?1:SQ_ERROR; +} + +SQRegFunction SQSharedState::_closure_default_delegate_funcz[]={ + {_SC("call"),closure_call,-1, _SC("c")}, + {_SC("acall"),closure_acall,2, _SC("ca")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {0,0} +}; + +//GENERATOR DEFAULT DELEGATE +static SQInteger generator_getstatus(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + switch(_generator(o)->_state){ + case SQGenerator::eSuspended:v->Push(SQString::Create(_ss(v),_SC("suspended")));break; + case SQGenerator::eRunning:v->Push(SQString::Create(_ss(v),_SC("running")));break; + case SQGenerator::eDead:v->Push(SQString::Create(_ss(v),_SC("dead")));break; + } + return 1; +} + +SQRegFunction SQSharedState::_generator_default_delegate_funcz[]={ + {_SC("getstatus"),generator_getstatus,1, _SC("g")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {0,0} +}; + +//THREAD DEFAULT DELEGATE + +static SQInteger thread_call(HSQUIRRELVM v) +{ + SQObjectPtr o = stack_get(v,1); + if(type(o) == OT_THREAD) { + SQInteger nparams = sq_gettop(v); + _thread(o)->Push(_thread(o)->_roottable); + for(SQInteger i = 2; i<(nparams+1); i++) + sq_move(_thread(o),v,i); + if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue))) { + sq_move(v,_thread(o),-1); + return 1; + } + return SQ_ERROR; + } + return sq_throwerror(v,_SC("wrong parameter")); +} + +static SQInteger thread_wakeup(HSQUIRRELVM v) +{ + SQObjectPtr o = stack_get(v,1); + if(type(o) == OT_THREAD) { + SQVM *thread = _thread(o); + SQInteger state = sq_getvmstate(thread); + if(state != SQ_VMSTATE_SUSPENDED) { + switch(state) { + case SQ_VMSTATE_IDLE: + return sq_throwerror(v,_SC("cannot wakeup a idle thread")); + break; + case SQ_VMSTATE_RUNNING: + return sq_throwerror(v,_SC("cannot wakeup a running thread")); + break; + } + } + + SQInteger wakeupret = sq_gettop(v)>1?1:0; + if(wakeupret) { + sq_move(thread,v,2); + } + if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,1))) { + sq_move(v,thread,-1); + sq_pop(thread,1); + if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) { + sq_pop(thread,1); + } + return 1; + } + return SQ_ERROR; + } + return sq_throwerror(v,_SC("wrong parameter")); +} + +static SQInteger thread_getstatus(HSQUIRRELVM v) +{ + SQObjectPtr &o = stack_get(v,1); + switch(sq_getvmstate(_thread(o))) { + case SQ_VMSTATE_IDLE: + sq_pushstring(v,_SC("idle"),-1); + break; + case SQ_VMSTATE_RUNNING: + sq_pushstring(v,_SC("running"),-1); + break; + case SQ_VMSTATE_SUSPENDED: + sq_pushstring(v,_SC("suspended"),-1); + break; + default: + return sq_throwerror(v,_SC("internal VM error")); + } + return 1; +} + +SQRegFunction SQSharedState::_thread_default_delegate_funcz[] = { + {_SC("call"), thread_call, -1, _SC("v")}, + {_SC("wakeup"), thread_wakeup, -1, _SC("v")}, + {_SC("getstatus"), thread_getstatus, 1, _SC("v")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {0,0}, +}; + +static SQInteger class_getattributes(HSQUIRRELVM v) +{ + if(SQ_SUCCEEDED(sq_getattributes(v,-2))) + return 1; + return SQ_ERROR; +} + +static SQInteger class_setattributes(HSQUIRRELVM v) +{ + if(SQ_SUCCEEDED(sq_setattributes(v,-3))) + return 1; + return SQ_ERROR; +} + +SQRegFunction SQSharedState::_class_default_delegate_funcz[] = { + {_SC("getattributes"), class_getattributes, 2, _SC("y.")}, + {_SC("setattributes"), class_setattributes, 3, _SC("y..")}, + {_SC("rawin"),container_rawexists,2, _SC("y")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {0,0} +}; + +static SQInteger instance_getclass(HSQUIRRELVM v) +{ + if(SQ_SUCCEEDED(sq_getclass(v,1))) + return 1; + return SQ_ERROR; +} + +SQRegFunction SQSharedState::_instance_default_delegate_funcz[] = { + {_SC("getclass"), instance_getclass, 1, _SC("x")}, + {_SC("rawin"),container_rawexists,2, _SC("x")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {0,0} +}; + +static SQInteger weakref_ref(HSQUIRRELVM v) +{ + if(SQ_FAILED(sq_getweakrefval(v,1))) + return SQ_ERROR; + return 1; +} + +SQRegFunction SQSharedState::_weakref_default_delegate_funcz[] = { + {_SC("ref"),weakref_ref,1, _SC("r")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {0,0} +}; + + diff --git a/src/squirrel/squirrel/sqclass.cpp b/src/squirrel/squirrel/sqclass.cpp index 11d40950a..21d600695 100644 --- a/src/squirrel/squirrel/sqclass.cpp +++ b/src/squirrel/squirrel/sqclass.cpp @@ -1,184 +1,190 @@ -/* - see copyright notice in squirrel.h -*/ -#include "sqpcheader.h" -#include "sqvm.h" -#include "sqtable.h" -#include "sqclass.h" -#include "sqclosure.h" - -SQClass::SQClass(SQSharedState *ss,SQClass *base) -{ - _uiRef=0; - _base = base; - _typetag = 0; - _metamethods.resize(MT_LAST); //size it to max size - if(_base) { - _defaultvalues.copy(base->_defaultvalues); - _methods.copy(base->_methods); - _metamethods.copy(base->_metamethods); - __ObjAddRef(_base); - } - _members = base?base->_members->Clone() : SQTable::Create(ss,0); - __ObjAddRef(_members); - _locked = false; - INIT_CHAIN(); - ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); -} - -void SQClass::Finalize() { - _attributes = _null_; - _defaultvalues.resize(0); - _methods.resize(0); - _metamethods.resize(0); - __ObjRelease(_members); - if(_base) { - __ObjRelease(_base); - } -} - -SQClass::~SQClass() -{ - REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); - Finalize(); -} - -bool SQClass::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) -{ - SQObjectPtr temp; - if(_locked) - return false; //the slot already exists - if(_members->Get(key,temp) && type(temp) == OT_INTEGER) //overrides the default value - { - _defaultvalues[_integer(temp)].val = val; - return true; - } - if(type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) { - SQInteger mmidx; - if((mmidx = _sharedstate->GetMetaMethodIdxByName(key)) != -1) { - _metamethods[mmidx] = val; - } - else { - if(type(temp) == OT_NULL) { - SQClassMemeber m; - m.val = val; - _members->NewSlot(key,SQObjectPtr((SQUserPointer)_methods.size())); - _methods.push_back(m); - } - else { - _methods[(int)_userpointer(temp)].val = val; - } - } - return true; - } - SQClassMemeber m; - m.val = val; - _members->NewSlot(key,SQObjectPtr((SQInteger)_defaultvalues.size())); - _defaultvalues.push_back(m); - return true; -} - -SQInstance *SQClass::CreateInstance() -{ - if(!_locked) Lock(); - return SQInstance::Create(_opt_ss(this),this); -} - -int SQClass::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) -{ - SQObjectPtr oval; - int idx = _members->Next(refpos,outkey,oval); - if(idx != -1) { - if(type(oval) != OT_INTEGER) { - outval = _methods[(int)_userpointer(oval)].val; - } - else { - outval = _defaultvalues[_integer(oval)].val; - } - } - return idx; -} - -bool SQClass::SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val) -{ - SQObjectPtr idx; - if(_members->Get(key,idx)) { - if(type(idx) == OT_INTEGER) - _defaultvalues[_integer(idx)].attrs = val; - else - _methods[(int)_userpointer(idx)].attrs = val; - return true; - } - return false; -} - -bool SQClass::GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval) -{ - SQObjectPtr idx; - if(_members->Get(key,idx)) { - outval = (type(idx) == OT_INTEGER?_defaultvalues[_integer(idx)].attrs:_methods[(int)_userpointer(idx)].attrs); - return true; - } - return false; -} - -/////////////////////////////////////////////////////////////////////// -void SQInstance::Init(SQSharedState *ss) -{ - _uiRef = 0; - _userpointer = NULL; - _hook = NULL; - __ObjAddRef(_class); - _delegate = _class->_members; - INIT_CHAIN(); - ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); -} - -SQInstance::SQInstance(SQSharedState *ss, SQClass *c) -{ - _class = c; - _values.resize(_class->_defaultvalues.size()); - for(unsigned int i = 0; i < _class->_defaultvalues.size(); i++) { - _values[i] = _class->_defaultvalues[i].val; - } - Init(ss); -} - -SQInstance::SQInstance(SQSharedState *ss, SQInstance *i) -{ - _class = i->_class; - _values.copy(i->_values); - Init(ss); -} - -void SQInstance::Finalize() -{ - __ObjRelease(_class); - _values.resize(0); -} - -SQInstance::~SQInstance() -{ - REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); - Finalize(); -} - -bool SQInstance::GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res) -{ - if(type(_class->_metamethods[mm]) != OT_NULL) { - res = _class->_metamethods[mm]; - return true; - } - return false; -} - -bool SQInstance::InstanceOf(SQClass *trg) -{ - SQClass *parent = _class; - while(parent != NULL) { - if(parent == trg) - return true; - parent = parent->_base; - } - return false; -} +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqtable.h" +#include "sqclass.h" +#include "sqclosure.h" + +SQClass::SQClass(SQSharedState *ss,SQClass *base) +{ + _base = base; + _typetag = 0; + _metamethods.resize(MT_LAST); //size it to max size + if(_base) { + _defaultvalues.copy(base->_defaultvalues); + _methods.copy(base->_methods); + _metamethods.copy(base->_metamethods); + __ObjAddRef(_base); + } + _members = base?base->_members->Clone() : SQTable::Create(ss,0); + __ObjAddRef(_members); + _locked = false; + INIT_CHAIN(); + ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); +} + +void SQClass::Finalize() { + _attributes = _null_; + _defaultvalues.resize(0); + _methods.resize(0); + _metamethods.resize(0); + __ObjRelease(_members); + if(_base) { + __ObjRelease(_base); + } +} + +SQClass::~SQClass() +{ + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + Finalize(); +} + +bool SQClass::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) +{ + SQObjectPtr temp; + if(_locked) + return false; //the class already has an instance so cannot be modified + if(_members->Get(key,temp) && _isfield(temp)) //overrides the default value + { + _defaultvalues[_member_idx(temp)].val = val; + return true; + } + if(type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) { + SQInteger mmidx; + if((mmidx = _sharedstate->GetMetaMethodIdxByName(key)) != -1) { + _metamethods[mmidx] = val; + } + else { + if(type(temp) == OT_NULL) { + SQClassMemeber m; + m.val = val; + _members->NewSlot(key,SQObjectPtr(_make_method_idx(_methods.size()))); + _methods.push_back(m); + } + else { + _methods[_member_idx(temp)].val = val; + } + } + return true; + } + SQClassMemeber m; + m.val = val; + _members->NewSlot(key,SQObjectPtr(_make_field_idx(_defaultvalues.size()))); + _defaultvalues.push_back(m); + return true; +} + +SQInstance *SQClass::CreateInstance() +{ + if(!_locked) Lock(); + return SQInstance::Create(_opt_ss(this),this); +} + +SQInteger SQClass::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) +{ + SQObjectPtr oval; + SQInteger idx = _members->Next(false,refpos,outkey,oval); + if(idx != -1) { + if(_ismethod(oval)) { + outval = _methods[_member_idx(oval)].val; + } + else { + SQObjectPtr &o = _defaultvalues[_member_idx(oval)].val; + outval = _realval(o); + } + } + return idx; +} + +bool SQClass::SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val) +{ + SQObjectPtr idx; + if(_members->Get(key,idx)) { + if(_isfield(idx)) + _defaultvalues[_member_idx(idx)].attrs = val; + else + _methods[_member_idx(idx)].attrs = val; + return true; + } + return false; +} + +bool SQClass::GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval) +{ + SQObjectPtr idx; + if(_members->Get(key,idx)) { + outval = (_isfield(idx)?_defaultvalues[_member_idx(idx)].attrs:_methods[_member_idx(idx)].attrs); + return true; + } + return false; +} + +/////////////////////////////////////////////////////////////////////// +void SQInstance::Init(SQSharedState *ss) +{ + _userpointer = NULL; + _hook = NULL; + __ObjAddRef(_class); + _delegate = _class->_members; + INIT_CHAIN(); + ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); +} + +SQInstance::SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize) +{ + _memsize = memsize; + _class = c; + _nvalues = _class->_defaultvalues.size(); + for(SQUnsignedInteger n = 0; n < _nvalues; n++) { + new (&_values[n]) SQObjectPtr(_class->_defaultvalues[n].val); + } + Init(ss); +} + +SQInstance::SQInstance(SQSharedState *ss, SQInstance *i, SQInteger memsize) +{ + _memsize = memsize; + _class = i->_class; + _nvalues = _class->_defaultvalues.size(); + for(SQUnsignedInteger n = 0; n < _nvalues; n++) { + new (&_values[n]) SQObjectPtr(i->_values[n]); + } + Init(ss); +} + +void SQInstance::Finalize() +{ + __ObjRelease(_class); + for(SQUnsignedInteger i = 0; i < _nvalues; i++) { + _values[i] = _null_; + } +} + +SQInstance::~SQInstance() +{ + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + Finalize(); +} + +bool SQInstance::GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res) +{ + if(type(_class->_metamethods[mm]) != OT_NULL) { + res = _class->_metamethods[mm]; + return true; + } + return false; +} + +bool SQInstance::InstanceOf(SQClass *trg) +{ + SQClass *parent = _class; + while(parent != NULL) { + if(parent == trg) + return true; + parent = parent->_base; + } + return false; +} diff --git a/src/squirrel/squirrel/sqclass.h b/src/squirrel/squirrel/sqclass.h index 5c12d7e21..3ef4f1940 100644 --- a/src/squirrel/squirrel/sqclass.h +++ b/src/squirrel/squirrel/sqclass.h @@ -1,104 +1,135 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQCLASS_H_ -#define _SQCLASS_H_ - -struct SQInstance; - -struct SQClassMemeber { - SQClassMemeber(){} - SQClassMemeber(const SQClassMemeber &o) { - val = o.val; - attrs = o.attrs; - } - SQObjectPtr val; - SQObjectPtr attrs; -}; - -typedef sqvector SQClassMemeberVec; - -struct SQClass : public CHAINABLE_OBJ -{ - SQClass(SQSharedState *ss,SQClass *base); -public: - static SQClass* Create(SQSharedState *ss,SQClass *base) { - SQClass *newclass = (SQClass *)SQ_MALLOC(sizeof(SQClass)); - new (newclass) SQClass(ss, base); - return newclass; - } - ~SQClass(); - bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val); - bool Get(const SQObjectPtr &key,SQObjectPtr &val) { - if(_members->Get(key,val)) { - val = (type(val) == OT_INTEGER?_defaultvalues[_integer(val)].val:_methods[(int)_userpointer(val)].val); - return true; - } - return false; - } - bool SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val); - bool GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval); - void Lock() { _locked = true; if(_base) _base->Lock(); } - void Release() { sq_delete(this, SQClass); } - void Finalize(); - void Mark(SQCollectable ** ); - int Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); - SQInstance *CreateInstance(); - SQTable *_members; - //SQTable *_properties; - SQClass *_base; - SQClassMemeberVec _defaultvalues; - SQClassMemeberVec _methods; - SQObjectPtrVec _metamethods; - SQObjectPtr _attributes; - unsigned int _typetag; - bool _locked; -}; - -struct SQInstance : public SQDelegable -{ - void Init(SQSharedState *ss); - SQInstance(SQSharedState *ss, SQClass *c); - SQInstance(SQSharedState *ss, SQInstance *c); -public: - static SQInstance* Create(SQSharedState *ss,SQClass *theclass) { - SQInstance *newinst = (SQInstance *)SQ_MALLOC(sizeof(SQInstance)); - new (newinst) SQInstance(ss, theclass); - return newinst; - } - SQInstance *Clone(SQSharedState *ss) - { - SQInstance *newinst = (SQInstance *)SQ_MALLOC(sizeof(SQInstance)); - new (newinst) SQInstance(ss, this); - return newinst; - } - ~SQInstance(); - bool Get(const SQObjectPtr &key,SQObjectPtr &val) { - if(_class->_members->Get(key,val)) { - val = (type(val) == OT_INTEGER?_values[_integer(val)]:_class->_methods[(int)_userpointer(val)].val); - return true; - } - return false; - } - bool Set(const SQObjectPtr &key,const SQObjectPtr &val) { - SQObjectPtr idx; - if(_class->_members->Get(key,idx) && type(idx) == OT_INTEGER) { - _values[_integer(idx)] = val; - return true; - } - return false; - } - void Release() { - if (_hook) { _hook(_userpointer,0);} - sq_delete(this, SQInstance); - } - void Finalize(); - void Mark(SQCollectable ** ); - bool InstanceOf(SQClass *trg); - bool GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res); - - SQClass *_class; - SQUserPointer _userpointer; - SQRELEASEHOOK _hook; - SQObjectPtrVec _values; -}; - -#endif //_SQCLASS_H_ +/* see copyright notice in squirrel.h */ +#ifndef _SQCLASS_H_ +#define _SQCLASS_H_ + +struct SQInstance; + +struct SQClassMemeber { + SQClassMemeber(){} + SQClassMemeber(const SQClassMemeber &o) { + val = o.val; + attrs = o.attrs; + } + SQObjectPtr val; + SQObjectPtr attrs; +}; + +typedef sqvector SQClassMemeberVec; + +#define MEMBER_TYPE_METHOD 0x01000000 +#define MEMBER_TYPE_FIELD 0x02000000 + +#define _ismethod(o) (_integer(o)&MEMBER_TYPE_METHOD) +#define _isfield(o) (_integer(o)&MEMBER_TYPE_FIELD) +#define _make_method_idx(i) ((SQInteger)(MEMBER_TYPE_METHOD|i)) +#define _make_field_idx(i) ((SQInteger)(MEMBER_TYPE_FIELD|i)) +#define _member_type(o) (_integer(o)&0xFF000000) +#define _member_idx(o) (_integer(o)&0x00FFFFFF) + +struct SQClass : public CHAINABLE_OBJ +{ + SQClass(SQSharedState *ss,SQClass *base); +public: + static SQClass* Create(SQSharedState *ss,SQClass *base) { + SQClass *newclass = (SQClass *)SQ_MALLOC(sizeof(SQClass)); + new (newclass) SQClass(ss, base); + return newclass; + } + ~SQClass(); + bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val); + bool Get(const SQObjectPtr &key,SQObjectPtr &val) { + if(_members->Get(key,val)) { + if(_isfield(val)) { + SQObjectPtr &o = _defaultvalues[_member_idx(val)].val; + val = _realval(o); + } + else { + val = _methods[_member_idx(val)].val; + } + return true; + } + return false; + } + bool SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val); + bool GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval); + void Lock() { _locked = true; if(_base) _base->Lock(); } + void Release() { sq_delete(this, SQClass); } + void Finalize(); + void Mark(SQCollectable ** ); + SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); + SQInstance *CreateInstance(); + SQTable *_members; + //SQTable *_properties; + SQClass *_base; + SQClassMemeberVec _defaultvalues; + SQClassMemeberVec _methods; + SQObjectPtrVec _metamethods; + SQObjectPtr _attributes; + SQUserPointer _typetag; + bool _locked; +}; + +#define calcinstancesize(_theclass_) \ + (sizeof(SQInstance)+(sizeof(SQObjectPtr)*(_theclass_->_defaultvalues.size()>0?_theclass_->_defaultvalues.size()-1:0))) +struct SQInstance : public SQDelegable +{ + void Init(SQSharedState *ss); + SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize); + SQInstance(SQSharedState *ss, SQInstance *c, SQInteger memsize); +public: + static SQInstance* Create(SQSharedState *ss,SQClass *theclass) { + + SQInteger size = calcinstancesize(theclass); + SQInstance *newinst = (SQInstance *)SQ_MALLOC(size); + new (newinst) SQInstance(ss, theclass,size); + return newinst; + } + SQInstance *Clone(SQSharedState *ss) + { + SQInteger size = calcinstancesize(_class); + SQInstance *newinst = (SQInstance *)SQ_MALLOC(size); + new (newinst) SQInstance(ss, this,size); + return newinst; + } + ~SQInstance(); + bool Get(const SQObjectPtr &key,SQObjectPtr &val) { + if(_class->_members->Get(key,val)) { + if(_isfield(val)) { + SQObjectPtr &o = _values[_member_idx(val)]; + val = _realval(o); + } + else { + val = _class->_methods[_member_idx(val)].val; + } + return true; + } + return false; + } + bool Set(const SQObjectPtr &key,const SQObjectPtr &val) { + SQObjectPtr idx; + if(_class->_members->Get(key,idx) && _isfield(idx)) { + _values[_member_idx(idx)] = val; + return true; + } + return false; + } + void Release() { + if (_hook) { _hook(_userpointer,0);} + SQInteger size = _memsize; + this->~SQInstance(); + SQ_FREE(this, size); + } + void Finalize(); + void Mark(SQCollectable ** ); + bool InstanceOf(SQClass *trg); + bool GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res); + + SQClass *_class; + SQUserPointer _userpointer; + SQRELEASEHOOK _hook; + SQUnsignedInteger _nvalues; + SQInteger _memsize; + SQObjectPtr _values[1]; +}; + +#endif //_SQCLASS_H_ diff --git a/src/squirrel/squirrel/sqclosure.h b/src/squirrel/squirrel/sqclosure.h index 1ce8d1026..8565621f5 100644 --- a/src/squirrel/squirrel/sqclosure.h +++ b/src/squirrel/squirrel/sqclosure.h @@ -1,101 +1,101 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQCLOSURE_H_ -#define _SQCLOSURE_H_ - -struct SQFunctionProto; - -struct SQClosure : public CHAINABLE_OBJ -{ -private: - SQClosure(SQSharedState *ss,SQFunctionProto *func){_uiRef=0;_function=func; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} -public: - static SQClosure *Create(SQSharedState *ss,SQFunctionProto *func){ - SQClosure *nc=(SQClosure*)SQ_MALLOC(sizeof(SQClosure)); - new (nc) SQClosure(ss,func); - return nc; - } - void Release(){ - sq_delete(this,SQClosure); - } - ~SQClosure() - { - REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); - } - bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); - bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read); -#ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); - void Finalize(){_outervalues.resize(0); } -#endif - SQObjectPtr _function; - SQObjectPtrVec _outervalues; -}; -////////////////////////////////////////////// -struct SQGenerator : public CHAINABLE_OBJ -{ - enum SQGeneratorState{eRunning,eSuspended,eDead}; -private: - SQGenerator(SQSharedState *ss,SQClosure *closure){_uiRef=0;_closure=closure;_state=eRunning;_ci._generator=_null_;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} -public: - static SQGenerator *Create(SQSharedState *ss,SQClosure *closure){ - SQGenerator *nc=(SQGenerator*)SQ_MALLOC(sizeof(SQGenerator)); - new (nc) SQGenerator(ss,closure); - return nc; - } - ~SQGenerator() - { - REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); - } - void Kill(){ - _state=eDead; - _stack.resize(0); - _closure=_null_;} - void Release(){ - sq_delete(this,SQGenerator); - } - bool Yield(SQVM *v); - bool Resume(SQVM *v,int target); -#ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); - void Finalize(){_stack.resize(0);_closure=_null_;} -#endif - SQObjectPtr _closure; - SQObjectPtrVec _stack; - SQObjectPtrVec _vargsstack; - SQVM::CallInfo _ci; - ExceptionsTraps _etraps; - SQGeneratorState _state; -}; - -struct SQNativeClosure : public CHAINABLE_OBJ -{ -private: - SQNativeClosure(SQSharedState *ss,SQFUNCTION func){_uiRef=0;_function=func;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); } -public: - static SQNativeClosure *Create(SQSharedState *ss,SQFUNCTION func) - { - SQNativeClosure *nc=(SQNativeClosure*)SQ_MALLOC(sizeof(SQNativeClosure)); - new (nc) SQNativeClosure(ss,func); - return nc; - } - ~SQNativeClosure() - { - REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); - } - void Release(){ - sq_delete(this,SQNativeClosure); - } -#ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); - void Finalize(){_outervalues.resize(0);} -#endif - SQFUNCTION _function; - SQObjectPtr _name; - SQObjectPtrVec _outervalues; - SQIntVec _typecheck; - int _nparamscheck; -}; - - - -#endif //_SQCLOSURE_H_ +/* see copyright notice in squirrel.h */ +#ifndef _SQCLOSURE_H_ +#define _SQCLOSURE_H_ + +struct SQFunctionProto; + +struct SQClosure : public CHAINABLE_OBJ +{ +private: + SQClosure(SQSharedState *ss,SQFunctionProto *func){_function=func; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} +public: + static SQClosure *Create(SQSharedState *ss,SQFunctionProto *func){ + SQClosure *nc=(SQClosure*)SQ_MALLOC(sizeof(SQClosure)); + new (nc) SQClosure(ss,func); + return nc; + } + void Release(){ + sq_delete(this,SQClosure); + } + ~SQClosure() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } + bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); + bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){_outervalues.resize(0); } +#endif + SQObjectPtr _function; + SQObjectPtrVec _outervalues; +}; +////////////////////////////////////////////// +struct SQGenerator : public CHAINABLE_OBJ +{ + enum SQGeneratorState{eRunning,eSuspended,eDead}; +private: + SQGenerator(SQSharedState *ss,SQClosure *closure){_closure=closure;_state=eRunning;_ci._generator=_null_;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} +public: + static SQGenerator *Create(SQSharedState *ss,SQClosure *closure){ + SQGenerator *nc=(SQGenerator*)SQ_MALLOC(sizeof(SQGenerator)); + new (nc) SQGenerator(ss,closure); + return nc; + } + ~SQGenerator() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } + void Kill(){ + _state=eDead; + _stack.resize(0); + _closure=_null_;} + void Release(){ + sq_delete(this,SQGenerator); + } + bool Yield(SQVM *v); + bool Resume(SQVM *v,SQInteger target); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){_stack.resize(0);_closure=_null_;} +#endif + SQObjectPtr _closure; + SQObjectPtrVec _stack; + SQObjectPtrVec _vargsstack; + SQVM::CallInfo _ci; + ExceptionsTraps _etraps; + SQGeneratorState _state; +}; + +struct SQNativeClosure : public CHAINABLE_OBJ +{ +private: + SQNativeClosure(SQSharedState *ss,SQFUNCTION func){_function=func;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); } +public: + static SQNativeClosure *Create(SQSharedState *ss,SQFUNCTION func) + { + SQNativeClosure *nc=(SQNativeClosure*)SQ_MALLOC(sizeof(SQNativeClosure)); + new (nc) SQNativeClosure(ss,func); + return nc; + } + ~SQNativeClosure() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } + void Release(){ + sq_delete(this,SQNativeClosure); + } +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){_outervalues.resize(0);} +#endif + SQFUNCTION _function; + SQObjectPtr _name; + SQObjectPtrVec _outervalues; + SQIntVec _typecheck; + SQInteger _nparamscheck; +}; + + + +#endif //_SQCLOSURE_H_ diff --git a/src/squirrel/squirrel/sqcompiler.cpp b/src/squirrel/squirrel/sqcompiler.cpp index 1f2072862..ed99a7353 100644 --- a/src/squirrel/squirrel/sqcompiler.cpp +++ b/src/squirrel/squirrel/sqcompiler.cpp @@ -1,1199 +1,1197 @@ -/* - see copyright notice in squirrel.h -*/ -#include "sqpcheader.h" -#include -#include -#include "sqopcodes.h" -#include "sqstring.h" -#include "sqfuncproto.h" -#include "sqcompiler.h" -#include "sqfuncstate.h" -#include "sqlexer.h" -#include "sqvm.h" - -#define DEREF_NO_DEREF -1 -#define DEREF_FIELD -2 - -struct ExpState -{ - ExpState() - { - _deref = DEREF_NO_DEREF; - _freevar = false; - _class_or_delete = false; - _funcarg = false; - } - bool _class_or_delete; - bool _funcarg; - bool _freevar; - int _deref; -}; - -typedef sqvector ExpStateVec; - -#define _exst (_expstates.top()) - -#define BEGIN_BREAKBLE_BLOCK() int __nbreaks__=_fs->_unresolvedbreaks.size(); \ - int __ncontinues__=_fs->_unresolvedcontinues.size(); \ - _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0); - -#define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \ - __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \ - if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \ - if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \ - _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();} - -class SQCompiler -{ -public: - SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo) - { - _vm=v; - _lex.Init(_ss(v), rg, up,ThrowError,this); - _sourcename = SQString::Create(_ss(v), sourcename); - _lineinfo = lineinfo;_raiseerror = raiseerror; - compilererror = NULL; - } - static void ThrowError(void *ud, const SQChar *s) { - SQCompiler *c = (SQCompiler *)ud; - c->Error(s); - } - void Error(const SQChar *s, ...) - { - static SQChar temp[256]; - va_list vl; - va_start(vl, s); - scvsprintf(temp, s, vl); - va_end(vl); - compilererror = temp; - longjmp(_errorjmp,1); - } - void Lex(){ _token = _lex.Lex();} - void PushExpState(){ _expstates.push_back(ExpState()); } - bool IsDerefToken(int tok) - { - switch(tok){ - case _SC('='): case _SC('('): case TK_NEWSLOT: - case TK_MODEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS: return true; - } - return false; - } - ExpState PopExpState() - { - ExpState ret = _expstates.top(); - _expstates.pop_back(); - return ret; - } - SQObject Expect(int tok) - { - - if(_token != tok) { - if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) { - //ret = SQString::Create(_ss(_vm),_SC("constructor")); - //do nothing - } - else { - const SQChar *etypename; - if(tok > 255) { - switch(tok) - { - case TK_IDENTIFIER: - etypename = _SC("IDENTIFIER"); - break; - case TK_STRING_LITERAL: - etypename = _SC("STRING_LITERAL"); - break; - case TK_INTEGER: - etypename = _SC("INTEGER"); - break; - case TK_FLOAT: - etypename = _SC("FLOAT"); - break; - default: - etypename = _lex.Tok2Str(tok); - } - Error(_SC("expected '%s'"), etypename); - } - Error(_SC("expected '%c'"), tok); - } - } - SQObjectPtr ret; - switch(tok) - { - case TK_IDENTIFIER: - ret = _fs->CreateString(_lex._svalue); - break; - case TK_STRING_LITERAL: - ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1); - break; - case TK_INTEGER: - ret = SQObjectPtr(_lex._nvalue); - break; - case TK_FLOAT: - ret = SQObjectPtr(_lex._fvalue); - break; - } - Lex(); - return ret; - } - bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); } - void OptionalSemicolon() - { - if(_token == _SC(';')) { Lex(); return; } - if(!IsEndOfStatement()) { - Error(_SC("end of statement expected (; or lf)")); - } - } - void MoveIfCurrentTargetIsLocal() { - int trg = _fs->TopTarget(); - if(_fs->IsLocal(trg)) { - trg = _fs->PopTarget(); //no pops the target and move it - _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg); - } - } - bool Compile(SQObjectPtr &o) - { - _debugline = 1; - _debugop = 0; - - SQFuncState funcstate(_ss(_vm), SQFunctionProto::Create(), NULL,ThrowError,this); - _funcproto(funcstate._func)->_name = SQString::Create(_ss(_vm), _SC("main")); - _fs = &funcstate; - _fs->AddParameter(_fs->CreateString(_SC("this"))); - _funcproto(_fs->_func)->_sourcename = _sourcename; - int stacksize = _fs->GetStackSize(); - if(setjmp(_errorjmp) == 0) { - Lex(); - while(_token > 0){ - Statement(); - if(_lex._prevtoken != _SC('}')) OptionalSemicolon(); - } - CleanStack(stacksize); - _fs->AddLineInfos(_lex._currentline, _lineinfo, true); - _fs->AddInstruction(_OP_RETURN, 0xFF); - _funcproto(_fs->_func)->_stacksize = _fs->_stacksize; - _fs->SetStackSize(0); - _fs->Finalize(); - o = _fs->_func; -#ifdef _DEBUG_DUMP - _fs->Dump(); -#endif - } - else { - if(_raiseerror && _ss(_vm)->_compilererrorhandler) { - _ss(_vm)->_compilererrorhandler(_vm, compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"), - _lex._currentline, _lex._currentcolumn); - } - _vm->_lasterror = SQString::Create(_ss(_vm), compilererror, -1); - return false; - } - return true; - } - void Statements() - { - while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) { - Statement(); - if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon(); - } - } - void Statement() - { - _fs->AddLineInfos(_lex._currentline, _lineinfo); - switch(_token){ - case _SC(';'): Lex(); break; - case TK_IF: IfStatement(); break; - case TK_WHILE: WhileStatement(); break; - case TK_DO: DoWhileStatement(); break; - case TK_FOR: ForStatement(); break; - case TK_FOREACH: ForEachStatement(); break; - case TK_SWITCH: SwitchStatement(); break; - case TK_LOCAL: LocalDeclStatement(); break; - case TK_RETURN: - case TK_YIELD: { - SQOpcode op; - if(_token == TK_RETURN) { - op = _OP_RETURN; - - } - else { - op = _OP_YIELD; - _funcproto(_fs->_func)->_bgenerator = true; - } - Lex(); - if(!IsEndOfStatement()) { - int retexp = _fs->GetCurrentPos()+1; - CommaExpr(); - if(op == _OP_RETURN && _fs->_traps > 0) - _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0); - _fs->_returnexp = retexp; - _fs->AddInstruction(op, 1, _fs->PopTarget()); - } - else{ - if(op == _OP_RETURN && _fs->_traps > 0) - _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0); - _fs->_returnexp = -1; - _fs->AddInstruction(op, 0xFF); - } - break;} - case TK_BREAK: - if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block")); - if(_fs->_breaktargets.top() > 0){ - _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0); - } - _fs->AddInstruction(_OP_JMP, 0, -1234); - _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos()); - Lex(); - break; - case TK_CONTINUE: - if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block")); - if(_fs->_continuetargets.top() > 0) { - _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0); - } - _fs->AddInstruction(_OP_JMP, 0, -1234); - _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos()); - Lex(); - break; - case TK_FUNCTION: - FunctionStatement(); - break; - case TK_CLASS: - ClassStatement(); - break; - case _SC('{'):{ - int stacksize = _fs->GetStackSize(); - Lex(); - Statements(); - Expect(_SC('}')); - _fs->SetStackSize(stacksize); - } - break; - case TK_TRY: - TryCatchStatement(); - break; - case TK_THROW: - Lex(); - CommaExpr(); - _fs->AddInstruction(_OP_THROW, _fs->PopTarget()); - break; - default: - CommaExpr(); - _fs->PopTarget(); - break; - } - _fs->SnoozeOpt(); - } - void EmitDerefOp(SQOpcode op) - { - int val = _fs->PopTarget(); - int key = _fs->PopTarget(); - int src = _fs->PopTarget(); - _fs->AddInstruction(op,_fs->PushTarget(),src,key,val); - } - void Emit2ArgsOP(SQOpcode op, int p3 = 0) - { - int p2 = _fs->PopTarget(); //src in OP_GET - int p1 = _fs->PopTarget(); //key in OP_GET - _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3); - } - void EmitCompoundArith(int tok,bool deref) - { - int oper; - switch(tok){ - case TK_MINUSEQ: oper = '-'; break; - case TK_PLUSEQ: oper = '+'; break; - case TK_MULEQ: oper = '*'; break; - case TK_DIVEQ: oper = '/'; break; - case TK_MODEQ: oper = '%'; break; - default: assert(0); break; - }; - if(deref) { - int val = _fs->PopTarget(); - int key = _fs->PopTarget(); - int src = _fs->PopTarget(); - //mixes dest obj and source val in the arg1(hack?) - _fs->AddInstruction(_OP_COMPARITH,_fs->PushTarget(),(src<<16)|val,key,oper); - } - else { - Emit2ArgsOP(_OP_COMPARITHL, oper); - } - } - void CommaExpr() - { - for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr()); - } - ExpState Expression(bool funcarg = false) - { - PushExpState(); - _exst._class_or_delete = false; - _exst._funcarg = funcarg; - LogicalOrExp(); - switch(_token) { - case _SC('='): - case TK_NEWSLOT: - case TK_MINUSEQ: - case TK_PLUSEQ: - case TK_MULEQ: - case TK_DIVEQ: - case TK_MODEQ: - { - int op = _token; - int ds = _exst._deref; - bool freevar = _exst._freevar; - if(ds == DEREF_NO_DEREF) Error(_SC("can't assign expression")); - Lex(); Expression(); - - switch(op){ - case TK_NEWSLOT: - if(freevar) Error(_SC("free variables cannot be modified")); - if(ds == DEREF_FIELD) - EmitDerefOp(_OP_NEWSLOT); - else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local - Error(_SC("can't 'create' a local slot")); - break; - case _SC('='): //ASSIGN - if(freevar) Error(_SC("free variables cannot be modified")); - if(ds == DEREF_FIELD) - EmitDerefOp(_OP_SET); - else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local - int p2 = _fs->PopTarget(); //src in OP_GET - int p1 = _fs->TopTarget(); //key in OP_GET - _fs->AddInstruction(_OP_MOVE, p1, p2); - } - break; - case TK_MINUSEQ: - case TK_PLUSEQ: - case TK_MULEQ: - case TK_DIVEQ: - case TK_MODEQ: - EmitCompoundArith(op,ds == DEREF_FIELD); - break; - } - } - break; - case _SC('?'): { - Lex(); - _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); - int jzpos = _fs->GetCurrentPos(); - int trg = _fs->PushTarget(); - Expression(); - int first_exp = _fs->PopTarget(); - if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); - int endfirstexp = _fs->GetCurrentPos(); - _fs->AddInstruction(_OP_JMP, 0, 0); - Expect(_SC(':')); - int jmppos = _fs->GetCurrentPos(); - Expression(); - int second_exp = _fs->PopTarget(); - if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); - _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); - _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1); - _fs->SnoozeOpt(); - } - break; - } - return PopExpState(); - } - void BIN_EXP(SQOpcode op, void (SQCompiler::*f)(void),int op3 = 0) - { - Lex(); (this->*f)(); - int op1 = _fs->PopTarget();int op2 = _fs->PopTarget(); - _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3); - } - void LogicalOrExp() - { - LogicalAndExp(); - for(;;) if(_token == TK_OR) { - int first_exp = _fs->PopTarget(); - int trg = _fs->PushTarget(); - _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0); - int jpos = _fs->GetCurrentPos(); - if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); - Lex(); LogicalOrExp(); - _fs->SnoozeOpt(); - int second_exp = _fs->PopTarget(); - if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); - _fs->SnoozeOpt(); - _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos)); - break; - }else return; - } - void LogicalAndExp() - { - BitwiseOrExp(); - for(;;) switch(_token) { - case TK_AND: { - int first_exp = _fs->PopTarget(); - int trg = _fs->PushTarget(); - _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0); - int jpos = _fs->GetCurrentPos(); - if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); - Lex(); LogicalAndExp(); - _fs->SnoozeOpt(); - int second_exp = _fs->PopTarget(); - if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); - _fs->SnoozeOpt(); - _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos)); - break; - } - case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::BitwiseOrExp); break; - case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::BitwiseOrExp); break; - default: - return; - } - } - void BitwiseOrExp() - { - BitwiseXorExp(); - for(;;) if(_token == _SC('|')) - {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR); - }else return; - } - void BitwiseXorExp() - { - BitwiseAndExp(); - for(;;) if(_token == _SC('^')) - {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR); - }else return; - } - void BitwiseAndExp() - { - CompExp(); - for(;;) if(_token == _SC('&')) - {BIN_EXP(_OP_BITW, &SQCompiler::CompExp,BW_AND); - }else return; - } - void CompExp() - { - ShiftExp(); - for(;;) switch(_token) { - case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::ShiftExp); break; - case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break; - case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break; - case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break; - case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break; - case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::ShiftExp); break; - default: return; - } - } - void ShiftExp() - { - PlusExp(); - for(;;) switch(_token) { - case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break; - case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break; - case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break; - default: return; - } - } - void PlusExp() - { - MultExp(); - for(;;) switch(_token) { - case _SC('+'): case _SC('-'): - BIN_EXP(_OP_ARITH, &SQCompiler::MultExp,_token); break; - default: return; - } - } - - void MultExp() - { - PrefixedExpr(); - for(;;) switch(_token) { - case _SC('*'): case _SC('/'): case _SC('%'): - BIN_EXP(_OP_ARITH, &SQCompiler::PrefixedExpr,_token); break; - default: return; - } - } - //if 'pos' != -1 the previous variable is a local variable - void PrefixedExpr() - { - int pos = Factor(); - for(;;) { - switch(_token) { - case _SC('.'): { - pos = -1; - Lex(); - if(_token == TK_PARENT) { - Lex(); - if(!NeedGet()) - Error(_SC("parent cannot be set")); - int src = _fs->PopTarget(); - _fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), src); - } - else { - _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER))); - if(NeedGet()) Emit2ArgsOP(_OP_GET); - } - _exst._deref = DEREF_FIELD; - _exst._freevar = false; - } - break; - case _SC('['): - if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration")); - Lex(); Expression(); Expect(_SC(']')); - pos = -1; - if(NeedGet()) Emit2ArgsOP(_OP_GET); - _exst._deref = DEREF_FIELD; - _exst._freevar = false; - break; - case TK_MINUSMINUS: - case TK_PLUSPLUS: - if(_exst._deref != DEREF_NO_DEREF && !IsEndOfStatement()) { - int tok = _token; Lex(); - if(pos < 0) - Emit2ArgsOP(_OP_PINC,tok == TK_MINUSMINUS?-1:1); - else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local - int src = _fs->PopTarget(); - _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, tok == TK_MINUSMINUS?-1:1); - } - - } - return; - break; - case _SC('('): - { - if(_exst._deref != DEREF_NO_DEREF) { - if(pos<0) { - int key = _fs->PopTarget(); //key - int table = _fs->PopTarget(); //table etc... - int closure = _fs->PushTarget(); - int ttarget = _fs->PushTarget(); - _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget); - } - else{ - _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); - } - } - else - _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); - _exst._deref = DEREF_NO_DEREF; - Lex(); - FunctionCallArgs(); - } - break; - default: return; - } - } - } - int Factor() - { - switch(_token) - { - case TK_STRING_LITERAL: { - //SQObjectPtr id(SQString::Create(_ss(_vm), _lex._svalue,_lex._longstr.size()-1)); - _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1))); - Lex(); - } - break; - case TK_VARGC: Lex(); _fs->AddInstruction(_OP_VARGC, _fs->PushTarget()); break; - case TK_VARGV: { Lex(); - Expect(_SC('[')); - Expression(); - Expect(_SC(']')); - int src = _fs->PopTarget(); - _fs->AddInstruction(_OP_GETVARGV, _fs->PushTarget(), src); - } - break; - case TK_IDENTIFIER: - case TK_CONSTRUCTOR: - case TK_THIS:{ - _exst._freevar = false; - SQObject id; - switch(_token) { - case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break; - case TK_THIS: id = _fs->CreateString(_SC("this")); break; - case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor")); break; - } - int pos = -1; - Lex(); - if((pos = _fs->GetLocalVariable(id)) == -1) { - //checks if is a free variable - if((pos = _fs->GetOuterVariable(id)) != -1) { - _exst._deref = _fs->PushTarget(); - _fs->AddInstruction(_OP_LOADFREEVAR, _exst._deref ,pos); - _exst._freevar = true; - } else { - _fs->PushTarget(0); - _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); - if(NeedGet()) Emit2ArgsOP(_OP_GET); - _exst._deref = DEREF_FIELD; - } - } - else{ - _fs->PushTarget(pos); - _exst._deref = pos; - } - return _exst._deref; - } - break; - case TK_PARENT: Lex();_fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), 0); break; - case TK_DOUBLE_COLON: // "::" - _fs->AddInstruction(_OP_LOADROOTTABLE, _fs->PushTarget()); - _exst._deref = DEREF_FIELD; - _token = _SC('.'); //hack - return -1; - break; - case TK_NULL: - _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); - Lex(); - break; - case TK_INTEGER: - _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue)); - Lex(); - break; - case TK_FLOAT: - _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue)); - Lex(); - break; - case TK_TRUE: case TK_FALSE: - _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0); - Lex(); - break; - case _SC('['): { - _fs->AddInstruction(_OP_NEWARRAY, _fs->PushTarget()); - int apos = _fs->GetCurrentPos(),key = 0; - Lex(); - while(_token != _SC(']')) { - Expression(); - if(_token == _SC(',')) Lex(); - int val = _fs->PopTarget(); - int array = _fs->TopTarget(); - _fs->AddInstruction(_OP_APPENDARRAY, array, val); - key++; - } - _fs->SetIntructionParam(apos, 1, key); - Lex(); - } - break; - case _SC('{'):{ - _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); - Lex();ParseTableOrClass(_SC(',')); - } - break; - case TK_FUNCTION: FunctionExp(_token);break; - case TK_CLASS: Lex(); ClassExp();break; - case _SC('-'): UnaryOP(_OP_NEG); break; - case _SC('!'): UnaryOP(_OP_NOT); break; - case _SC('~'): UnaryOP(_OP_BWNOT); break; - case TK_TYPEOF : UnaryOP(_OP_TYPEOF); break; - case TK_RESUME : UnaryOP(_OP_RESUME); break; - case TK_CLONE : UnaryOP(_OP_CLONE); break; - case TK_MINUSMINUS : - case TK_PLUSPLUS :PrefixIncDec(_token); break; - case TK_DELETE : DeleteExpr(); break; - case TK_DELEGATE : DelegateExpr(); break; - case _SC('('): Lex(); CommaExpr(); Expect(_SC(')')); - break; - default: Error(_SC("expression expected")); - } - return -1; - } - void UnaryOP(SQOpcode op) - { - Lex(); PrefixedExpr(); - int src = _fs->PopTarget(); - _fs->AddInstruction(op, _fs->PushTarget(), src); - } - bool NeedGet() - { - switch(_token) { - case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_PLUSPLUS: case TK_MINUSMINUS: - case TK_PLUSEQ: case TK_MINUSEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MODEQ: - return false; - } - return (!_exst._class_or_delete) || (_exst._class_or_delete && (_token == _SC('.') || _token == _SC('['))); - } - - void FunctionCallArgs() - { - int nargs = 1;//this - while(_token != _SC(')')) { - Expression(true); - MoveIfCurrentTargetIsLocal(); - nargs++; - if(_token == _SC(',')){ - Lex(); - if(_token == ')') Error(_SC("expression expected, found ')'")); - } - } - Lex(); - for(int i = 0; i < (nargs - 1); i++) _fs->PopTarget(); - int stackbase = _fs->PopTarget(); - int closure = _fs->PopTarget(); - _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs); - } - void ParseTableOrClass(int separator,int terminator = '}') - { - int tpos = _fs->GetCurrentPos(),nkeys = 0; - - while(_token != terminator) { - bool hasattrs = false; - //check if is an attribute - if(separator == ';' && _token == TK_ATTR_OPEN) { - _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex(); - ParseTableOrClass(',',TK_ATTR_CLOSE); - hasattrs = true; - } - switch(_token) { - case TK_FUNCTION: - case TK_CONSTRUCTOR:{ - int tk = _token; - Lex(); - SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor")); - Expect(_SC('(')); - _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); - CreateFunction(id); - _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); - } - break; - case _SC('['): - Lex(); CommaExpr(); Expect(_SC(']')); - Expect(_SC('=')); Expression(); - break; - default : - _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER))); - Expect(_SC('=')); Expression(); - } - - if(_token == separator) Lex();//optional comma/semicolon - nkeys++; - int val = _fs->PopTarget(); - int key = _fs->PopTarget(); - int attrs = hasattrs ? _fs->PopTarget():-1; - assert(hasattrs && attrs == key-1 || !hasattrs); - int table = _fs->TopTarget(); //<AddInstruction(hasattrs?_OP_NEWSLOTA:_OP_NEWSLOT, _fs->PushTarget(), table, key, val); - _fs->PopTarget(); - } - if(separator == _SC(',')) //hack recognizes a table from the separator - _fs->SetIntructionParam(tpos, 1, nkeys); - Lex(); - } - void LocalDeclStatement() - { - SQObject varname; - do { - Lex(); varname = Expect(TK_IDENTIFIER); - if(_token == _SC('=')) { - Lex(); Expression(); - int src = _fs->PopTarget(); - int dest = _fs->PushTarget(); - if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src); - } - else{ - _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); - } - _fs->PopTarget(); - _fs->PushLocalVariable(varname); - - } while(_token == _SC(',')); - } - void IfStatement() - { - int jmppos; - bool haselse = false; - Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); - _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); - int jnepos = _fs->GetCurrentPos(); - int stacksize = _fs->GetStackSize(); - - Statement(); - // - if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon(); - - CleanStack(stacksize); - int endifblock = _fs->GetCurrentPos(); - if(_token == TK_ELSE){ - haselse = true; - stacksize = _fs->GetStackSize(); - _fs->AddInstruction(_OP_JMP); - jmppos = _fs->GetCurrentPos(); - Lex(); - Statement(); OptionalSemicolon(); - CleanStack(stacksize); - _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); - } - _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0)); - } - void WhileStatement() - { - int jzpos, jmppos; - int stacksize = _fs->GetStackSize(); - jmppos = _fs->GetCurrentPos(); - Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); - - BEGIN_BREAKBLE_BLOCK(); - _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); - jzpos = _fs->GetCurrentPos(); - stacksize = _fs->GetStackSize(); - - Statement(); - - CleanStack(stacksize); - _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); - _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); - - END_BREAKBLE_BLOCK(jmppos); - } - void DoWhileStatement() - { - Lex(); - int jzpos = _fs->GetCurrentPos(); - int stacksize = _fs->GetStackSize(); - BEGIN_BREAKBLE_BLOCK() - Statement(); - CleanStack(stacksize); - Expect(TK_WHILE); - int continuetrg = _fs->GetCurrentPos(); - Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); - _fs->AddInstruction(_OP_JNZ, _fs->PopTarget(), jzpos - _fs->GetCurrentPos() - 1); - END_BREAKBLE_BLOCK(continuetrg); - } - void ForStatement() - { - Lex(); - int stacksize = _fs->GetStackSize(); - Expect(_SC('(')); - if(_token == TK_LOCAL) LocalDeclStatement(); - else if(_token != _SC(';')){ - CommaExpr(); - _fs->PopTarget(); - } - Expect(_SC(';')); - _fs->SnoozeOpt(); - int jmppos = _fs->GetCurrentPos(); - int jzpos = -1; - if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); } - Expect(_SC(';')); - _fs->SnoozeOpt(); - int expstart = _fs->GetCurrentPos() + 1; - if(_token != _SC(')')) { - CommaExpr(); - _fs->PopTarget(); - } - Expect(_SC(')')); - _fs->SnoozeOpt(); - int expend = _fs->GetCurrentPos(); - int expsize = (expend - expstart) + 1; - SQInstructionVec exp; - if(expsize > 0) { - for(int i = 0; i < expsize; i++) - exp.push_back(_fs->GetInstruction(expstart + i)); - _fs->PopInstructions(expsize); - } - BEGIN_BREAKBLE_BLOCK() - Statement(); - int continuetrg = _fs->GetCurrentPos(); - if(expsize > 0) { - for(int i = 0; i < expsize; i++) - _fs->AddInstruction(exp[i]); - } - _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0); - if(jzpos> 0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); - CleanStack(stacksize); - - END_BREAKBLE_BLOCK(continuetrg); - } - void ForEachStatement() - { - SQObject idxname, valname; - Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER); - if(_token == _SC(',')) { - idxname = valname; - Lex(); valname = Expect(TK_IDENTIFIER); - } - else{ - idxname = _fs->CreateString(_SC("@INDEX@")); - } - Expect(TK_IN); - - //save the stack size - int stacksize = _fs->GetStackSize(); - //put the table in the stack(evaluate the table expression) - Expression(); Expect(_SC(')')); - int container = _fs->TopTarget(); - //push the index local var - int indexpos = _fs->PushLocalVariable(idxname); - _fs->AddInstruction(_OP_LOADNULLS, indexpos,1); - //push the value local var - int valuepos = _fs->PushLocalVariable(valname); - _fs->AddInstruction(_OP_LOADNULLS, valuepos,1); - //push reference index - int itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@"))); //use invalid id to make it inaccessible - _fs->AddInstruction(_OP_LOADNULLS, itrpos,1); - int jmppos = _fs->GetCurrentPos(); - _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos); - int foreachpos = _fs->GetCurrentPos(); - //generate the statement code - BEGIN_BREAKBLE_BLOCK() - Statement(); - _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); - _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos); - //restore the local variable stack(remove index,val and ref idx) - CleanStack(stacksize); - END_BREAKBLE_BLOCK(foreachpos - 1); - } - void SwitchStatement() - { - Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); - Expect(_SC('{')); - int expr = _fs->TopTarget(); - bool bfirst = true; - int tonextcondjmp = -1; - int skipcondjmp = -1; - int __nbreaks__ = _fs->_unresolvedbreaks.size(); - _fs->_breaktargets.push_back(0); - while(_token == TK_CASE) { - if(!bfirst) { - _fs->AddInstruction(_OP_JMP, 0, 0); - skipcondjmp = _fs->GetCurrentPos(); - _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); - } - //condition - Lex(); Expression(); Expect(_SC(':')); - int trg = _fs->PopTarget(); - _fs->AddInstruction(_OP_EQ, trg, trg, expr); - _fs->AddInstruction(_OP_JZ, trg, 0); - //end condition - if(skipcondjmp != -1) { - _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp)); - } - tonextcondjmp = _fs->GetCurrentPos(); - int stacksize = _fs->GetStackSize(); - Statements(); - _fs->SetStackSize(stacksize); - bfirst = false; - } - if(tonextcondjmp != -1) - _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); - if(_token == TK_DEFAULT) { - Lex(); Expect(_SC(':')); - int stacksize = _fs->GetStackSize(); - Statements(); - _fs->SetStackSize(stacksize); - } - Expect(_SC('}')); - _fs->PopTarget(); - __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__; - if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__); - _fs->_breaktargets.pop_back(); - - } - void FunctionStatement() - { - SQObject id; - Lex(); id = Expect(TK_IDENTIFIER); - _fs->PushTarget(0); - _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); - if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET); - - while(_token == TK_DOUBLE_COLON) { - Lex(); - id = Expect(TK_IDENTIFIER); - _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); - if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET); - } - Expect(_SC('(')); - CreateFunction(id); - _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); - EmitDerefOp(_OP_NEWSLOT); - _fs->PopTarget(); - } - void ClassStatement() - { - ExpState es; - Lex(); PushExpState(); - _exst._class_or_delete = true; - _exst._funcarg = false; - PrefixedExpr(); - es = PopExpState(); - if(es._deref == DEREF_NO_DEREF) Error(_SC("invalid class name")); - if(es._deref == DEREF_FIELD) { - ClassExp(); - EmitDerefOp(_OP_NEWSLOT); - _fs->PopTarget(); - } - else Error(_SC("cannot create a class in a local with the syntax(class )")); - } - void TryCatchStatement() - { - SQObject exid; - Lex(); - _fs->AddInstruction(_OP_PUSHTRAP,0,0); - _fs->_traps++; - if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++; - if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++; - int trappos = _fs->GetCurrentPos(); - Statement(); - _fs->_traps--; - _fs->AddInstruction(_OP_POPTRAP, 1, 0); - if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--; - if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--; - _fs->AddInstruction(_OP_JMP, 0, 0); - int jmppos = _fs->GetCurrentPos(); - _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos)); - Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')')); - int stacksize = _fs->GetStackSize(); - int ex_target = _fs->PushLocalVariable(exid); - _fs->SetIntructionParam(trappos, 0, ex_target); - Statement(); - _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0); - CleanStack(stacksize); - } - void FunctionExp(int ftype) - { - Lex(); Expect(_SC('(')); - CreateFunction(_null_); - _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1); - } - void ClassExp() - { - int base = -1; - int attrs = -1; - if(_token == TK_EXTENDS) { - Lex(); Expression(); - base = _fs->TopTarget(); - } - if(_token == TK_ATTR_OPEN) { - Lex(); - _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); - ParseTableOrClass(_SC(','),TK_ATTR_CLOSE); - attrs = _fs->TopTarget(); - } - Expect(_SC('{')); - if(attrs != -1) _fs->PopTarget(); - if(base != -1) _fs->PopTarget(); - _fs->AddInstruction(_OP_CLASS, _fs->PushTarget(), base, attrs); - ParseTableOrClass(_SC(';')); - } - void DelegateExpr() - { - Lex(); CommaExpr(); - Expect(_SC(':')); - CommaExpr(); - int table = _fs->PopTarget(), delegate = _fs->PopTarget(); - _fs->AddInstruction(_OP_DELEGATE, _fs->PushTarget(), table, delegate); - } - void DeleteExpr() - { - ExpState es; - Lex(); PushExpState(); - _exst._class_or_delete = true; - _exst._funcarg = false; - PrefixedExpr(); - es = PopExpState(); - if(es._deref == DEREF_NO_DEREF) Error(_SC("can't delete an expression")); - if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_DELETE); - else Error(_SC("cannot delete a local")); - } - void PrefixIncDec(int token) - { - ExpState es; - Lex(); PushExpState(); - _exst._class_or_delete = true; - _exst._funcarg = false; - PrefixedExpr(); - es = PopExpState(); - if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_INC,token == TK_MINUSMINUS?-1:1); - else { - int src = _fs->PopTarget(); - _fs->AddInstruction(_OP_INCL, _fs->PushTarget(), src, 0, token == TK_MINUSMINUS?-1:1); - } - } - void CreateFunction(SQObject &name) - { - - SQFuncState *funcstate = _fs->PushChildState(_ss(_vm), SQFunctionProto::Create()); - _funcproto(funcstate->_func)->_name = name; - SQObject paramname; - funcstate->AddParameter(_fs->CreateString(_SC("this"))); - _funcproto(funcstate->_func)->_sourcename = _sourcename; - while(_token!=_SC(')')) { - if(_token == TK_VARPARAMS) { - funcstate->_varparams = true; - Lex(); - if(_token != _SC(')')) Error(_SC("expected ')'")); - break; - } - else { - paramname = Expect(TK_IDENTIFIER); - funcstate->AddParameter(paramname); - if(_token == _SC(',')) Lex(); - else if(_token != _SC(')')) Error(_SC("expected ')' or ','")); - } - } - Expect(_SC(')')); - //outer values - if(_token == _SC(':')) { - Lex(); Expect(_SC('(')); - while(_token != _SC(')')) { - paramname = Expect(TK_IDENTIFIER); - //outers are treated as implicit local variables - funcstate->AddOuterValue(paramname); - if(_token == _SC(',')) Lex(); - else if(_token != _SC(')')) Error(_SC("expected ')' or ','")); - } - Lex(); - } - - SQFuncState *currchunk = _fs; - _fs = funcstate; - Statement(); - funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true); - funcstate->AddInstruction(_OP_RETURN, -1); - funcstate->SetStackSize(0); - _funcproto(_fs->_func)->_stacksize = _fs->_stacksize; - funcstate->Finalize(); -#ifdef _DEBUG_DUMP - funcstate->Dump(); -#endif - _fs = currchunk; - _fs->_functions.push_back(funcstate->_func); - _fs->PopChildState(); - } - void CleanStack(int stacksize) - { - if(_fs->GetStackSize() != stacksize) - _fs->SetStackSize(stacksize); - } - void ResolveBreaks(SQFuncState *funcstate, int ntoresolve) - { - while(ntoresolve > 0) { - int pos = funcstate->_unresolvedbreaks.back(); - funcstate->_unresolvedbreaks.pop_back(); - //set the jmp instruction - funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0); - ntoresolve--; - } - } - void ResolveContinues(SQFuncState *funcstate, int ntoresolve, int targetpos) - { - while(ntoresolve > 0) { - int pos = funcstate->_unresolvedcontinues.back(); - funcstate->_unresolvedcontinues.pop_back(); - //set the jmp instruction - funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0); - ntoresolve--; - } - } -private: - int _token; - SQFuncState *_fs; - SQObjectPtr _sourcename; - SQLexer _lex; - bool _lineinfo; - bool _raiseerror; - int _debugline; - int _debugop; - ExpStateVec _expstates; - SQChar *compilererror; - jmp_buf _errorjmp; - SQVM *_vm; -}; - -bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo) -{ - SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo); - return p.Compile(out); -} +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include +#include +#include "sqopcodes.h" +#include "sqstring.h" +#include "sqfuncproto.h" +#include "sqcompiler.h" +#include "sqfuncstate.h" +#include "sqlexer.h" +#include "sqvm.h" + +#define DEREF_NO_DEREF -1 +#define DEREF_FIELD -2 + +struct ExpState +{ + ExpState() + { + _deref = DEREF_NO_DEREF; + _freevar = false; + _class_or_delete = false; + _funcarg = false; + } + bool _class_or_delete; + bool _funcarg; + bool _freevar; + SQInteger _deref; +}; + +typedef sqvector ExpStateVec; + +#define _exst (_expstates.top()) + +#define BEGIN_BREAKBLE_BLOCK() SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \ + SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \ + _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0); + +#define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \ + __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \ + if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \ + if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \ + _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();} + +class SQCompiler +{ +public: + SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo) + { + _vm=v; + _lex.Init(_ss(v), rg, up,ThrowError,this); + _sourcename = SQString::Create(_ss(v), sourcename); + _lineinfo = lineinfo;_raiseerror = raiseerror; + compilererror = NULL; + } + static void ThrowError(void *ud, const SQChar *s) { + SQCompiler *c = (SQCompiler *)ud; + c->Error(s); + } + void Error(const SQChar *s, ...) + { + static SQChar temp[256]; + va_list vl; + va_start(vl, s); + scvsprintf(temp, s, vl); + va_end(vl); + compilererror = temp; + longjmp(_errorjmp,1); + } + void Lex(){ _token = _lex.Lex();} + void PushExpState(){ _expstates.push_back(ExpState()); } + bool IsDerefToken(SQInteger tok) + { + switch(tok){ + case _SC('='): case _SC('('): case TK_NEWSLOT: + case TK_MODEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS: return true; + } + return false; + } + ExpState PopExpState() + { + ExpState ret = _expstates.top(); + _expstates.pop_back(); + return ret; + } + SQObject Expect(SQInteger tok) + { + + if(_token != tok) { + if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) { + //ret = SQString::Create(_ss(_vm),_SC("constructor")); + //do nothing + } + else { + const SQChar *etypename; + if(tok > 255) { + switch(tok) + { + case TK_IDENTIFIER: + etypename = _SC("IDENTIFIER"); + break; + case TK_STRING_LITERAL: + etypename = _SC("STRING_LITERAL"); + break; + case TK_INTEGER: + etypename = _SC("INTEGER"); + break; + case TK_FLOAT: + etypename = _SC("FLOAT"); + break; + default: + etypename = _lex.Tok2Str(tok); + } + Error(_SC("expected '%s'"), etypename); + } + Error(_SC("expected '%c'"), tok); + } + } + SQObjectPtr ret; + switch(tok) + { + case TK_IDENTIFIER: + ret = _fs->CreateString(_lex._svalue); + break; + case TK_STRING_LITERAL: + ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1); + break; + case TK_INTEGER: + ret = SQObjectPtr(_lex._nvalue); + break; + case TK_FLOAT: + ret = SQObjectPtr(_lex._fvalue); + break; + } + Lex(); + return ret; + } + bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); } + void OptionalSemicolon() + { + if(_token == _SC(';')) { Lex(); return; } + if(!IsEndOfStatement()) { + Error(_SC("end of statement expected (; or lf)")); + } + } + void MoveIfCurrentTargetIsLocal() { + SQInteger trg = _fs->TopTarget(); + if(_fs->IsLocal(trg)) { + trg = _fs->PopTarget(); //no pops the target and move it + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg); + } + } + bool Compile(SQObjectPtr &o) + { + _debugline = 1; + _debugop = 0; + + SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this); + funcstate._name = SQString::Create(_ss(_vm), _SC("main")); + _fs = &funcstate; + _fs->AddParameter(_fs->CreateString(_SC("this"))); + _fs->_sourcename = _sourcename; + SQInteger stacksize = _fs->GetStackSize(); + if(setjmp(_errorjmp) == 0) { + Lex(); + while(_token > 0){ + Statement(); + if(_lex._prevtoken != _SC('}')) OptionalSemicolon(); + } + CleanStack(stacksize); + _fs->AddLineInfos(_lex._currentline, _lineinfo, true); + _fs->AddInstruction(_OP_RETURN, 0xFF); + _fs->SetStackSize(0); + o =_fs->BuildProto(); +#ifdef _DEBUG_DUMP + _fs->Dump(_funcproto(o)); +#endif + } + else { + if(_raiseerror && _ss(_vm)->_compilererrorhandler) { + _ss(_vm)->_compilererrorhandler(_vm, compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"), + _lex._currentline, _lex._currentcolumn); + } + _vm->_lasterror = SQString::Create(_ss(_vm), compilererror, -1); + return false; + } + return true; + } + void Statements() + { + while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) { + Statement(); + if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon(); + } + } + void Statement() + { + _fs->AddLineInfos(_lex._currentline, _lineinfo); + switch(_token){ + case _SC(';'): Lex(); break; + case TK_IF: IfStatement(); break; + case TK_WHILE: WhileStatement(); break; + case TK_DO: DoWhileStatement(); break; + case TK_FOR: ForStatement(); break; + case TK_FOREACH: ForEachStatement(); break; + case TK_SWITCH: SwitchStatement(); break; + case TK_LOCAL: LocalDeclStatement(); break; + case TK_RETURN: + case TK_YIELD: { + SQOpcode op; + if(_token == TK_RETURN) { + op = _OP_RETURN; + + } + else { + op = _OP_YIELD; + _fs->_bgenerator = true; + } + Lex(); + if(!IsEndOfStatement()) { + SQInteger retexp = _fs->GetCurrentPos()+1; + CommaExpr(); + if(op == _OP_RETURN && _fs->_traps > 0) + _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0); + _fs->_returnexp = retexp; + _fs->AddInstruction(op, 1, _fs->PopTarget()); + } + else{ + if(op == _OP_RETURN && _fs->_traps > 0) + _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0); + _fs->_returnexp = -1; + _fs->AddInstruction(op, 0xFF); + } + break;} + case TK_BREAK: + if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block")); + if(_fs->_breaktargets.top() > 0){ + _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0); + } + _fs->AddInstruction(_OP_JMP, 0, -1234); + _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos()); + Lex(); + break; + case TK_CONTINUE: + if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block")); + if(_fs->_continuetargets.top() > 0) { + _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0); + } + _fs->AddInstruction(_OP_JMP, 0, -1234); + _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos()); + Lex(); + break; + case TK_FUNCTION: + FunctionStatement(); + break; + case TK_CLASS: + ClassStatement(); + break; + case _SC('{'):{ + SQInteger stacksize = _fs->GetStackSize(); + Lex(); + Statements(); + Expect(_SC('}')); + _fs->SetStackSize(stacksize); + } + break; + case TK_TRY: + TryCatchStatement(); + break; + case TK_THROW: + Lex(); + CommaExpr(); + _fs->AddInstruction(_OP_THROW, _fs->PopTarget()); + break; + default: + CommaExpr(); + _fs->PopTarget(); + break; + } + _fs->SnoozeOpt(); + } + void EmitDerefOp(SQOpcode op) + { + SQInteger val = _fs->PopTarget(); + SQInteger key = _fs->PopTarget(); + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(op,_fs->PushTarget(),src,key,val); + } + void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0) + { + SQInteger p2 = _fs->PopTarget(); //src in OP_GET + SQInteger p1 = _fs->PopTarget(); //key in OP_GET + _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3); + } + void EmitCompoundArith(SQInteger tok,bool deref) + { + SQInteger oper; + switch(tok){ + case TK_MINUSEQ: oper = '-'; break; + case TK_PLUSEQ: oper = '+'; break; + case TK_MULEQ: oper = '*'; break; + case TK_DIVEQ: oper = '/'; break; + case TK_MODEQ: oper = '%'; break; + default: assert(0); break; + }; + if(deref) { + SQInteger val = _fs->PopTarget(); + SQInteger key = _fs->PopTarget(); + SQInteger src = _fs->PopTarget(); + //mixes dest obj and source val in the arg1(hack?) + _fs->AddInstruction(_OP_COMPARITH,_fs->PushTarget(),(src<<16)|val,key,oper); + } + else { + Emit2ArgsOP(_OP_COMPARITHL, oper); + } + } + void CommaExpr() + { + for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr()); + } + ExpState Expression(bool funcarg = false) + { + PushExpState(); + _exst._class_or_delete = false; + _exst._funcarg = funcarg; + LogicalOrExp(); + switch(_token) { + case _SC('='): + case TK_NEWSLOT: + case TK_MINUSEQ: + case TK_PLUSEQ: + case TK_MULEQ: + case TK_DIVEQ: + case TK_MODEQ: + { + SQInteger op = _token; + SQInteger ds = _exst._deref; + bool freevar = _exst._freevar; + if(ds == DEREF_NO_DEREF) Error(_SC("can't assign expression")); + Lex(); Expression(); + + switch(op){ + case TK_NEWSLOT: + if(freevar) Error(_SC("free variables cannot be modified")); + if(ds == DEREF_FIELD) + EmitDerefOp(_OP_NEWSLOT); + else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local + Error(_SC("can't 'create' a local slot")); + break; + case _SC('='): //ASSIGN + if(freevar) Error(_SC("free variables cannot be modified")); + if(ds == DEREF_FIELD) + EmitDerefOp(_OP_SET); + else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local + SQInteger p2 = _fs->PopTarget(); //src in OP_GET + SQInteger p1 = _fs->TopTarget(); //key in OP_GET + _fs->AddInstruction(_OP_MOVE, p1, p2); + } + break; + case TK_MINUSEQ: + case TK_PLUSEQ: + case TK_MULEQ: + case TK_DIVEQ: + case TK_MODEQ: + EmitCompoundArith(op,ds == DEREF_FIELD); + break; + } + } + break; + case _SC('?'): { + Lex(); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + SQInteger jzpos = _fs->GetCurrentPos(); + SQInteger trg = _fs->PushTarget(); + Expression(); + SQInteger first_exp = _fs->PopTarget(); + if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); + SQInteger endfirstexp = _fs->GetCurrentPos(); + _fs->AddInstruction(_OP_JMP, 0, 0); + Expect(_SC(':')); + SQInteger jmppos = _fs->GetCurrentPos(); + Expression(); + SQInteger second_exp = _fs->PopTarget(); + if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); + _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); + _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1); + _fs->SnoozeOpt(); + } + break; + } + return PopExpState(); + } + void BIN_EXP(SQOpcode op, void (SQCompiler::*f)(void),SQInteger op3 = 0) + { + Lex(); (this->*f)(); + SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget(); + _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3); + } + void LogicalOrExp() + { + LogicalAndExp(); + for(;;) if(_token == TK_OR) { + SQInteger first_exp = _fs->PopTarget(); + SQInteger trg = _fs->PushTarget(); + _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0); + SQInteger jpos = _fs->GetCurrentPos(); + if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); + Lex(); LogicalOrExp(); + _fs->SnoozeOpt(); + SQInteger second_exp = _fs->PopTarget(); + if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); + _fs->SnoozeOpt(); + _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos)); + break; + }else return; + } + void LogicalAndExp() + { + BitwiseOrExp(); + for(;;) switch(_token) { + case TK_AND: { + SQInteger first_exp = _fs->PopTarget(); + SQInteger trg = _fs->PushTarget(); + _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0); + SQInteger jpos = _fs->GetCurrentPos(); + if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); + Lex(); LogicalAndExp(); + _fs->SnoozeOpt(); + SQInteger second_exp = _fs->PopTarget(); + if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); + _fs->SnoozeOpt(); + _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos)); + break; + } + case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::BitwiseOrExp); break; + case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::BitwiseOrExp); break; + default: + return; + } + } + void BitwiseOrExp() + { + BitwiseXorExp(); + for(;;) if(_token == _SC('|')) + {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR); + }else return; + } + void BitwiseXorExp() + { + BitwiseAndExp(); + for(;;) if(_token == _SC('^')) + {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR); + }else return; + } + void BitwiseAndExp() + { + CompExp(); + for(;;) if(_token == _SC('&')) + {BIN_EXP(_OP_BITW, &SQCompiler::CompExp,BW_AND); + }else return; + } + void CompExp() + { + ShiftExp(); + for(;;) switch(_token) { + case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::ShiftExp); break; + case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break; + case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break; + case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break; + case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break; + case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::ShiftExp); break; + default: return; + } + } + void ShiftExp() + { + PlusExp(); + for(;;) switch(_token) { + case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break; + case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break; + case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break; + default: return; + } + } + void PlusExp() + { + MultExp(); + for(;;) switch(_token) { + case _SC('+'): case _SC('-'): + BIN_EXP(_OP_ARITH, &SQCompiler::MultExp,_token); break; + default: return; + } + } + + void MultExp() + { + PrefixedExpr(); + for(;;) switch(_token) { + case _SC('*'): case _SC('/'): case _SC('%'): + BIN_EXP(_OP_ARITH, &SQCompiler::PrefixedExpr,_token); break; + default: return; + } + } + //if 'pos' != -1 the previous variable is a local variable + void PrefixedExpr() + { + SQInteger pos = Factor(); + for(;;) { + switch(_token) { + case _SC('.'): { + pos = -1; + Lex(); + if(_token == TK_PARENT) { + Lex(); + if(!NeedGet()) + Error(_SC("parent cannot be set")); + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), src); + } + else { + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER))); + if(NeedGet()) Emit2ArgsOP(_OP_GET); + } + _exst._deref = DEREF_FIELD; + _exst._freevar = false; + } + break; + case _SC('['): + if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration")); + Lex(); Expression(); Expect(_SC(']')); + pos = -1; + if(NeedGet()) Emit2ArgsOP(_OP_GET); + _exst._deref = DEREF_FIELD; + _exst._freevar = false; + break; + case TK_MINUSMINUS: + case TK_PLUSPLUS: + if(_exst._deref != DEREF_NO_DEREF && !IsEndOfStatement()) { + SQInteger tok = _token; Lex(); + if(pos < 0) + Emit2ArgsOP(_OP_PINC,tok == TK_MINUSMINUS?-1:1); + else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, tok == TK_MINUSMINUS?-1:1); + } + + } + return; + break; + case _SC('('): + { + if(_exst._deref != DEREF_NO_DEREF) { + if(pos<0) { + SQInteger key = _fs->PopTarget(); //key + SQInteger table = _fs->PopTarget(); //table etc... + SQInteger closure = _fs->PushTarget(); + SQInteger ttarget = _fs->PushTarget(); + _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget); + } + else{ + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); + } + } + else + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); + _exst._deref = DEREF_NO_DEREF; + Lex(); + FunctionCallArgs(); + } + break; + default: return; + } + } + } + SQInteger Factor() + { + switch(_token) + { + case TK_STRING_LITERAL: { + //SQObjectPtr id(SQString::Create(_ss(_vm), _lex._svalue,_lex._longstr.size()-1)); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1))); + Lex(); + } + break; + case TK_VARGC: Lex(); _fs->AddInstruction(_OP_VARGC, _fs->PushTarget()); break; + case TK_VARGV: { Lex(); + Expect(_SC('[')); + Expression(); + Expect(_SC(']')); + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(_OP_GETVARGV, _fs->PushTarget(), src); + } + break; + case TK_IDENTIFIER: + case TK_CONSTRUCTOR: + case TK_THIS:{ + _exst._freevar = false; + SQObject id; + switch(_token) { + case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break; + case TK_THIS: id = _fs->CreateString(_SC("this")); break; + case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor")); break; + } + SQInteger pos = -1; + Lex(); + if((pos = _fs->GetLocalVariable(id)) == -1) { + //checks if is a free variable + if((pos = _fs->GetOuterVariable(id)) != -1) { + _exst._deref = _fs->PushTarget(); + _fs->AddInstruction(_OP_LOADFREEVAR, _exst._deref ,pos); + _exst._freevar = true; + } else { + _fs->PushTarget(0); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); + if(NeedGet()) Emit2ArgsOP(_OP_GET); + _exst._deref = DEREF_FIELD; + } + } + else{ + _fs->PushTarget(pos); + _exst._deref = pos; + } + return _exst._deref; + } + break; + case TK_PARENT: Lex();_fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), 0); break; + case TK_DOUBLE_COLON: // "::" + _fs->AddInstruction(_OP_LOADROOTTABLE, _fs->PushTarget()); + _exst._deref = DEREF_FIELD; + _token = _SC('.'); //hack + return -1; + break; + case TK_NULL: + _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); + Lex(); + break; + case TK_INTEGER: + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue)); + Lex(); + break; + case TK_FLOAT: + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue)); + Lex(); + break; + case TK_TRUE: case TK_FALSE: + _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0); + Lex(); + break; + case _SC('['): { + _fs->AddInstruction(_OP_NEWARRAY, _fs->PushTarget()); + SQInteger apos = _fs->GetCurrentPos(),key = 0; + Lex(); + while(_token != _SC(']')) { + Expression(); + if(_token == _SC(',')) Lex(); + SQInteger val = _fs->PopTarget(); + SQInteger array = _fs->TopTarget(); + _fs->AddInstruction(_OP_APPENDARRAY, array, val); + key++; + } + _fs->SetIntructionParam(apos, 1, key); + Lex(); + } + break; + case _SC('{'):{ + _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); + Lex();ParseTableOrClass(_SC(',')); + } + break; + case TK_FUNCTION: FunctionExp(_token);break; + case TK_CLASS: Lex(); ClassExp();break; + case _SC('-'): UnaryOP(_OP_NEG); break; + case _SC('!'): UnaryOP(_OP_NOT); break; + case _SC('~'): UnaryOP(_OP_BWNOT); break; + case TK_TYPEOF : UnaryOP(_OP_TYPEOF); break; + case TK_RESUME : UnaryOP(_OP_RESUME); break; + case TK_CLONE : UnaryOP(_OP_CLONE); break; + case TK_MINUSMINUS : + case TK_PLUSPLUS :PrefixIncDec(_token); break; + case TK_DELETE : DeleteExpr(); break; + case TK_DELEGATE : DelegateExpr(); break; + case _SC('('): Lex(); CommaExpr(); Expect(_SC(')')); + break; + default: Error(_SC("expression expected")); + } + return -1; + } + void UnaryOP(SQOpcode op) + { + Lex(); PrefixedExpr(); + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(op, _fs->PushTarget(), src); + } + bool NeedGet() + { + switch(_token) { + case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_PLUSPLUS: case TK_MINUSMINUS: + case TK_PLUSEQ: case TK_MINUSEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MODEQ: + return false; + } + return (!_exst._class_or_delete) || (_exst._class_or_delete && (_token == _SC('.') || _token == _SC('['))); + } + + void FunctionCallArgs() + { + SQInteger nargs = 1;//this + while(_token != _SC(')')) { + Expression(true); + MoveIfCurrentTargetIsLocal(); + nargs++; + if(_token == _SC(',')){ + Lex(); + if(_token == ')') Error(_SC("expression expected, found ')'")); + } + } + Lex(); + for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget(); + SQInteger stackbase = _fs->PopTarget(); + SQInteger closure = _fs->PopTarget(); + _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs); + } + void ParseTableOrClass(SQInteger separator,SQInteger terminator = '}') + { + SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0; + + while(_token != terminator) { + bool hasattrs = false; + //check if is an attribute + if(separator == ';' && _token == TK_ATTR_OPEN) { + _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex(); + ParseTableOrClass(',',TK_ATTR_CLOSE); + hasattrs = true; + } + switch(_token) { + case TK_FUNCTION: + case TK_CONSTRUCTOR:{ + SQInteger tk = _token; + Lex(); + SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor")); + Expect(_SC('(')); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); + CreateFunction(id); + _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); + } + break; + case _SC('['): + Lex(); CommaExpr(); Expect(_SC(']')); + Expect(_SC('=')); Expression(); + break; + default : + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER))); + Expect(_SC('=')); Expression(); + } + + if(_token == separator) Lex();//optional comma/semicolon + nkeys++; + SQInteger val = _fs->PopTarget(); + SQInteger key = _fs->PopTarget(); + SQInteger attrs = hasattrs ? _fs->PopTarget():-1; + assert(hasattrs && attrs == key-1 || !hasattrs); + SQInteger table = _fs->TopTarget(); //<AddInstruction(hasattrs?_OP_NEWSLOTA:_OP_NEWSLOT, _fs->PushTarget(), table, key, val); + _fs->PopTarget(); + } + if(separator == _SC(',')) //hack recognizes a table from the separator + _fs->SetIntructionParam(tpos, 1, nkeys); + Lex(); + } + void LocalDeclStatement() + { + SQObject varname; + do { + Lex(); varname = Expect(TK_IDENTIFIER); + if(_token == _SC('=')) { + Lex(); Expression(); + SQInteger src = _fs->PopTarget(); + SQInteger dest = _fs->PushTarget(); + if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src); + } + else{ + _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); + } + _fs->PopTarget(); + _fs->PushLocalVariable(varname); + + } while(_token == _SC(',')); + } + void IfStatement() + { + SQInteger jmppos; + bool haselse = false; + Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + SQInteger jnepos = _fs->GetCurrentPos(); + SQInteger stacksize = _fs->GetStackSize(); + + Statement(); + // + if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon(); + + CleanStack(stacksize); + SQInteger endifblock = _fs->GetCurrentPos(); + if(_token == TK_ELSE){ + haselse = true; + stacksize = _fs->GetStackSize(); + _fs->AddInstruction(_OP_JMP); + jmppos = _fs->GetCurrentPos(); + Lex(); + Statement(); OptionalSemicolon(); + CleanStack(stacksize); + _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); + } + _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0)); + } + void WhileStatement() + { + SQInteger jzpos, jmppos; + SQInteger stacksize = _fs->GetStackSize(); + jmppos = _fs->GetCurrentPos(); + Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); + + BEGIN_BREAKBLE_BLOCK(); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + jzpos = _fs->GetCurrentPos(); + stacksize = _fs->GetStackSize(); + + Statement(); + + CleanStack(stacksize); + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); + _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); + + END_BREAKBLE_BLOCK(jmppos); + } + void DoWhileStatement() + { + Lex(); + SQInteger jzpos = _fs->GetCurrentPos(); + SQInteger stacksize = _fs->GetStackSize(); + BEGIN_BREAKBLE_BLOCK() + Statement(); + CleanStack(stacksize); + Expect(TK_WHILE); + SQInteger continuetrg = _fs->GetCurrentPos(); + Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); + _fs->AddInstruction(_OP_JNZ, _fs->PopTarget(), jzpos - _fs->GetCurrentPos() - 1); + END_BREAKBLE_BLOCK(continuetrg); + } + void ForStatement() + { + Lex(); + SQInteger stacksize = _fs->GetStackSize(); + Expect(_SC('(')); + if(_token == TK_LOCAL) LocalDeclStatement(); + else if(_token != _SC(';')){ + CommaExpr(); + _fs->PopTarget(); + } + Expect(_SC(';')); + _fs->SnoozeOpt(); + SQInteger jmppos = _fs->GetCurrentPos(); + SQInteger jzpos = -1; + if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); } + Expect(_SC(';')); + _fs->SnoozeOpt(); + SQInteger expstart = _fs->GetCurrentPos() + 1; + if(_token != _SC(')')) { + CommaExpr(); + _fs->PopTarget(); + } + Expect(_SC(')')); + _fs->SnoozeOpt(); + SQInteger expend = _fs->GetCurrentPos(); + SQInteger expsize = (expend - expstart) + 1; + SQInstructionVec exp; + if(expsize > 0) { + for(SQInteger i = 0; i < expsize; i++) + exp.push_back(_fs->GetInstruction(expstart + i)); + _fs->PopInstructions(expsize); + } + BEGIN_BREAKBLE_BLOCK() + Statement(); + SQInteger continuetrg = _fs->GetCurrentPos(); + if(expsize > 0) { + for(SQInteger i = 0; i < expsize; i++) + _fs->AddInstruction(exp[i]); + } + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0); + if(jzpos> 0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); + CleanStack(stacksize); + + END_BREAKBLE_BLOCK(continuetrg); + } + void ForEachStatement() + { + SQObject idxname, valname; + Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER); + if(_token == _SC(',')) { + idxname = valname; + Lex(); valname = Expect(TK_IDENTIFIER); + } + else{ + idxname = _fs->CreateString(_SC("@INDEX@")); + } + Expect(TK_IN); + + //save the stack size + SQInteger stacksize = _fs->GetStackSize(); + //put the table in the stack(evaluate the table expression) + Expression(); Expect(_SC(')')); + SQInteger container = _fs->TopTarget(); + //push the index local var + SQInteger indexpos = _fs->PushLocalVariable(idxname); + _fs->AddInstruction(_OP_LOADNULLS, indexpos,1); + //push the value local var + SQInteger valuepos = _fs->PushLocalVariable(valname); + _fs->AddInstruction(_OP_LOADNULLS, valuepos,1); + //push reference index + SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@"))); //use invalid id to make it inaccessible + _fs->AddInstruction(_OP_LOADNULLS, itrpos,1); + SQInteger jmppos = _fs->GetCurrentPos(); + _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos); + SQInteger foreachpos = _fs->GetCurrentPos(); + //generate the statement code + BEGIN_BREAKBLE_BLOCK() + Statement(); + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); + _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos); + //restore the local variable stack(remove index,val and ref idx) + CleanStack(stacksize); + END_BREAKBLE_BLOCK(foreachpos - 1); + } + void SwitchStatement() + { + Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); + Expect(_SC('{')); + SQInteger expr = _fs->TopTarget(); + bool bfirst = true; + SQInteger tonextcondjmp = -1; + SQInteger skipcondjmp = -1; + SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size(); + _fs->_breaktargets.push_back(0); + while(_token == TK_CASE) { + if(!bfirst) { + _fs->AddInstruction(_OP_JMP, 0, 0); + skipcondjmp = _fs->GetCurrentPos(); + _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); + } + //condition + Lex(); Expression(); Expect(_SC(':')); + SQInteger trg = _fs->PopTarget(); + _fs->AddInstruction(_OP_EQ, trg, trg, expr); + _fs->AddInstruction(_OP_JZ, trg, 0); + //end condition + if(skipcondjmp != -1) { + _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp)); + } + tonextcondjmp = _fs->GetCurrentPos(); + SQInteger stacksize = _fs->GetStackSize(); + Statements(); + _fs->SetStackSize(stacksize); + bfirst = false; + } + if(tonextcondjmp != -1) + _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); + if(_token == TK_DEFAULT) { + Lex(); Expect(_SC(':')); + SQInteger stacksize = _fs->GetStackSize(); + Statements(); + _fs->SetStackSize(stacksize); + } + Expect(_SC('}')); + _fs->PopTarget(); + __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__; + if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__); + _fs->_breaktargets.pop_back(); + + } + void FunctionStatement() + { + SQObject id; + Lex(); id = Expect(TK_IDENTIFIER); + _fs->PushTarget(0); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); + if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET); + + while(_token == TK_DOUBLE_COLON) { + Lex(); + id = Expect(TK_IDENTIFIER); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); + if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET); + } + Expect(_SC('(')); + CreateFunction(id); + _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); + EmitDerefOp(_OP_NEWSLOT); + _fs->PopTarget(); + } + void ClassStatement() + { + ExpState es; + Lex(); PushExpState(); + _exst._class_or_delete = true; + _exst._funcarg = false; + PrefixedExpr(); + es = PopExpState(); + if(es._deref == DEREF_NO_DEREF) Error(_SC("invalid class name")); + if(es._deref == DEREF_FIELD) { + ClassExp(); + EmitDerefOp(_OP_NEWSLOT); + _fs->PopTarget(); + } + else Error(_SC("cannot create a class in a local with the syntax(class )")); + } + void TryCatchStatement() + { + SQObject exid; + Lex(); + _fs->AddInstruction(_OP_PUSHTRAP,0,0); + _fs->_traps++; + if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++; + if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++; + SQInteger trappos = _fs->GetCurrentPos(); + Statement(); + _fs->_traps--; + _fs->AddInstruction(_OP_POPTRAP, 1, 0); + if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--; + if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--; + _fs->AddInstruction(_OP_JMP, 0, 0); + SQInteger jmppos = _fs->GetCurrentPos(); + _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos)); + Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')')); + SQInteger stacksize = _fs->GetStackSize(); + SQInteger ex_target = _fs->PushLocalVariable(exid); + _fs->SetIntructionParam(trappos, 0, ex_target); + Statement(); + _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0); + CleanStack(stacksize); + } + void FunctionExp(SQInteger ftype) + { + Lex(); Expect(_SC('(')); + CreateFunction(_null_); + _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1); + } + void ClassExp() + { + SQInteger base = -1; + SQInteger attrs = -1; + if(_token == TK_EXTENDS) { + Lex(); Expression(); + base = _fs->TopTarget(); + } + if(_token == TK_ATTR_OPEN) { + Lex(); + _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); + ParseTableOrClass(_SC(','),TK_ATTR_CLOSE); + attrs = _fs->TopTarget(); + } + Expect(_SC('{')); + if(attrs != -1) _fs->PopTarget(); + if(base != -1) _fs->PopTarget(); + _fs->AddInstruction(_OP_CLASS, _fs->PushTarget(), base, attrs); + ParseTableOrClass(_SC(';')); + } + void DelegateExpr() + { + Lex(); CommaExpr(); + Expect(_SC(':')); + CommaExpr(); + SQInteger table = _fs->PopTarget(), delegate = _fs->PopTarget(); + _fs->AddInstruction(_OP_DELEGATE, _fs->PushTarget(), table, delegate); + } + void DeleteExpr() + { + ExpState es; + Lex(); PushExpState(); + _exst._class_or_delete = true; + _exst._funcarg = false; + PrefixedExpr(); + es = PopExpState(); + if(es._deref == DEREF_NO_DEREF) Error(_SC("can't delete an expression")); + if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_DELETE); + else Error(_SC("cannot delete a local")); + } + void PrefixIncDec(SQInteger token) + { + ExpState es; + Lex(); PushExpState(); + _exst._class_or_delete = true; + _exst._funcarg = false; + PrefixedExpr(); + es = PopExpState(); + if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_INC,token == TK_MINUSMINUS?-1:1); + else { + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(_OP_INCL, _fs->PushTarget(), src, 0, token == TK_MINUSMINUS?-1:1); + } + } + void CreateFunction(SQObject &name) + { + + SQFuncState *funcstate = _fs->PushChildState(_ss(_vm)); + funcstate->_name = name; + SQObject paramname; + funcstate->AddParameter(_fs->CreateString(_SC("this"))); + funcstate->_sourcename = _sourcename; + while(_token!=_SC(')')) { + if(_token == TK_VARPARAMS) { + funcstate->_varparams = true; + Lex(); + if(_token != _SC(')')) Error(_SC("expected ')'")); + break; + } + else { + paramname = Expect(TK_IDENTIFIER); + funcstate->AddParameter(paramname); + if(_token == _SC(',')) Lex(); + else if(_token != _SC(')')) Error(_SC("expected ')' or ','")); + } + } + Expect(_SC(')')); + //outer values + if(_token == _SC(':')) { + Lex(); Expect(_SC('(')); + while(_token != _SC(')')) { + paramname = Expect(TK_IDENTIFIER); + //outers are treated as implicit local variables + funcstate->AddOuterValue(paramname); + if(_token == _SC(',')) Lex(); + else if(_token != _SC(')')) Error(_SC("expected ')' or ','")); + } + Lex(); + } + + SQFuncState *currchunk = _fs; + _fs = funcstate; + Statement(); + funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true); + funcstate->AddInstruction(_OP_RETURN, -1); + funcstate->SetStackSize(0); + //_fs->->_stacksize = _fs->_stacksize; + SQFunctionProto *func = funcstate->BuildProto(); +#ifdef _DEBUG_DUMP + funcstate->Dump(func); +#endif + _fs = currchunk; + _fs->_functions.push_back(func); + _fs->PopChildState(); + } + void CleanStack(SQInteger stacksize) + { + if(_fs->GetStackSize() != stacksize) + _fs->SetStackSize(stacksize); + } + void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve) + { + while(ntoresolve > 0) { + SQInteger pos = funcstate->_unresolvedbreaks.back(); + funcstate->_unresolvedbreaks.pop_back(); + //set the jmp instruction + funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0); + ntoresolve--; + } + } + void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos) + { + while(ntoresolve > 0) { + SQInteger pos = funcstate->_unresolvedcontinues.back(); + funcstate->_unresolvedcontinues.pop_back(); + //set the jmp instruction + funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0); + ntoresolve--; + } + } +private: + SQInteger _token; + SQFuncState *_fs; + SQObjectPtr _sourcename; + SQLexer _lex; + bool _lineinfo; + bool _raiseerror; + SQInteger _debugline; + SQInteger _debugop; + ExpStateVec _expstates; + SQChar *compilererror; + jmp_buf _errorjmp; + SQVM *_vm; +}; + +bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo) +{ + SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo); + return p.Compile(out); +} diff --git a/src/squirrel/squirrel/sqcompiler.h b/src/squirrel/squirrel/sqcompiler.h index 595d9c4d0..71dbfa2d0 100644 --- a/src/squirrel/squirrel/sqcompiler.h +++ b/src/squirrel/squirrel/sqcompiler.h @@ -1,74 +1,74 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQCOMPILER_H_ -#define _SQCOMPILER_H_ - -struct SQVM; - -#define TK_IDENTIFIER 258 -#define TK_STRING_LITERAL 259 -#define TK_INTEGER 260 -#define TK_FLOAT 261 -#define TK_DELEGATE 262 -#define TK_DELETE 263 -#define TK_EQ 264 -#define TK_NE 265 -#define TK_LE 266 -#define TK_GE 267 -#define TK_SWITCH 268 -#define TK_ARROW 269 -#define TK_AND 270 -#define TK_OR 271 -#define TK_IF 272 -#define TK_ELSE 273 -#define TK_WHILE 274 -#define TK_BREAK 275 -#define TK_FOR 276 -#define TK_DO 277 -#define TK_NULL 278 -#define TK_FOREACH 279 -#define TK_IN 280 -#define TK_NEWSLOT 281 -#define TK_MODULO 282 -#define TK_LOCAL 283 -#define TK_CLONE 284 -#define TK_FUNCTION 285 -#define TK_RETURN 286 -#define TK_TYPEOF 287 -#define TK_UMINUS 288 -#define TK_PLUSEQ 289 -#define TK_MINUSEQ 290 -#define TK_CONTINUE 291 -#define TK_YIELD 292 -#define TK_TRY 293 -#define TK_CATCH 294 -#define TK_THROW 295 -#define TK_SHIFTL 296 -#define TK_SHIFTR 297 -#define TK_RESUME 298 -#define TK_DOUBLE_COLON 299 -#define TK_CASE 300 -#define TK_DEFAULT 301 -#define TK_THIS 302 -#define TK_PLUSPLUS 303 -#define TK_MINUSMINUS 304 -#define TK_PARENT 305 -#define TK_USHIFTR 306 -#define TK_CLASS 307 -#define TK_EXTENDS 308 -#define TK_CONSTRUCTOR 310 -#define TK_INSTANCEOF 311 -#define TK_VARPARAMS 312 -#define TK_VARGC 313 -#define TK_VARGV 314 -#define TK_TRUE 315 -#define TK_FALSE 316 -#define TK_MULEQ 317 -#define TK_DIVEQ 318 -#define TK_MODEQ 319 -#define TK_ATTR_OPEN 320 -#define TK_ATTR_CLOSE 321 - - -typedef void(*CompilerErrorFunc)(void *ud, const SQChar *s); -bool Compile(SQVM *vm, SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo); -#endif //_SQCOMPILER_H_ +/* see copyright notice in squirrel.h */ +#ifndef _SQCOMPILER_H_ +#define _SQCOMPILER_H_ + +struct SQVM; + +#define TK_IDENTIFIER 258 +#define TK_STRING_LITERAL 259 +#define TK_INTEGER 260 +#define TK_FLOAT 261 +#define TK_DELEGATE 262 +#define TK_DELETE 263 +#define TK_EQ 264 +#define TK_NE 265 +#define TK_LE 266 +#define TK_GE 267 +#define TK_SWITCH 268 +#define TK_ARROW 269 +#define TK_AND 270 +#define TK_OR 271 +#define TK_IF 272 +#define TK_ELSE 273 +#define TK_WHILE 274 +#define TK_BREAK 275 +#define TK_FOR 276 +#define TK_DO 277 +#define TK_NULL 278 +#define TK_FOREACH 279 +#define TK_IN 280 +#define TK_NEWSLOT 281 +#define TK_MODULO 282 +#define TK_LOCAL 283 +#define TK_CLONE 284 +#define TK_FUNCTION 285 +#define TK_RETURN 286 +#define TK_TYPEOF 287 +#define TK_UMINUS 288 +#define TK_PLUSEQ 289 +#define TK_MINUSEQ 290 +#define TK_CONTINUE 291 +#define TK_YIELD 292 +#define TK_TRY 293 +#define TK_CATCH 294 +#define TK_THROW 295 +#define TK_SHIFTL 296 +#define TK_SHIFTR 297 +#define TK_RESUME 298 +#define TK_DOUBLE_COLON 299 +#define TK_CASE 300 +#define TK_DEFAULT 301 +#define TK_THIS 302 +#define TK_PLUSPLUS 303 +#define TK_MINUSMINUS 304 +#define TK_PARENT 305 +#define TK_USHIFTR 306 +#define TK_CLASS 307 +#define TK_EXTENDS 308 +#define TK_CONSTRUCTOR 310 +#define TK_INSTANCEOF 311 +#define TK_VARPARAMS 312 +#define TK_VARGC 313 +#define TK_VARGV 314 +#define TK_TRUE 315 +#define TK_FALSE 316 +#define TK_MULEQ 317 +#define TK_DIVEQ 318 +#define TK_MODEQ 319 +#define TK_ATTR_OPEN 320 +#define TK_ATTR_CLOSE 321 + + +typedef void(*CompilerErrorFunc)(void *ud, const SQChar *s); +bool Compile(SQVM *vm, SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo); +#endif //_SQCOMPILER_H_ diff --git a/src/squirrel/squirrel/sqdebug.cpp b/src/squirrel/squirrel/sqdebug.cpp index 88daf9e6d..9612d06a9 100644 --- a/src/squirrel/squirrel/sqdebug.cpp +++ b/src/squirrel/squirrel/sqdebug.cpp @@ -1,98 +1,98 @@ -/* - see copyright notice in squirrel.h -*/ -#include "sqpcheader.h" -#include -#include "sqvm.h" -#include "sqfuncproto.h" -#include "sqclosure.h" -#include "sqstring.h" - -SQRESULT sq_stackinfos(HSQUIRRELVM v, int level, SQStackInfos *si) -{ - int cssize = v->_callsstack.size(); - if (cssize > level) { - memset(si, 0, sizeof(SQStackInfos)); - SQVM::CallInfo &ci = v->_callsstack[cssize-level-1]; - switch (type(ci._closure)) { - case OT_CLOSURE:{ - SQFunctionProto *func = _funcproto(_closure(ci._closure)->_function); - if (type(func->_name) == OT_STRING) - si->funcname = _stringval(func->_name); - if (type(func->_sourcename) == OT_STRING) - si->source = _stringval(func->_sourcename); - si->line = func->GetLine(ci._ip); - } - break; - case OT_NATIVECLOSURE: - si->source = _SC("NATIVE"); - si->funcname = _SC("unknown"); - if(type(_nativeclosure(ci._closure)->_name) == OT_STRING) - si->funcname = _stringval(_nativeclosure(ci._closure)->_name); - si->line = -1; - break; - } - return SQ_OK; - } - return SQ_ERROR; -} - -void SQVM::Raise_Error(const SQChar *s, ...) -{ - va_list vl; - va_start(vl, s); - scvsprintf(_sp(rsl(scstrlen(s)+(NUMBER_MAX_CHAR*2))), s, vl); - va_end(vl); - _lasterror = SQString::Create(_ss(this),_spval,-1); -} - -void SQVM::Raise_Error(SQObjectPtr &desc) -{ - _lasterror = desc; -} - -SQString *SQVM::PrintObjVal(const SQObject &o) -{ - switch(type(o)) { - case OT_STRING: return _string(o); - case OT_INTEGER: - scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)), _SC("%d"), _integer(o)); - return SQString::Create(_ss(this), _spval); - break; - case OT_FLOAT: - scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)), _SC("%.14g"), _float(o)); - return SQString::Create(_ss(this), _spval); - break; - default: - return SQString::Create(_ss(this), GetTypeName(o)); - } -} - -void SQVM::Raise_IdxError(SQObject &o) -{ - SQObjectPtr oval = PrintObjVal(o); - Raise_Error(_SC("the index '%.50s' does not exist"), _stringval(oval)); -} - -void SQVM::Raise_CompareError(const SQObject &o1, const SQObject &o2) -{ - SQObjectPtr oval1 = PrintObjVal(o1), oval2 = PrintObjVal(o2); - Raise_Error(_SC("comparsion between '%.50s' and '%.50s'"), _stringval(oval1), _stringval(oval2)); -} - - -void SQVM::Raise_ParamTypeError(int nparam,int typemask,int type) -{ - SQObjectPtr exptypes = SQString::Create(_ss(this), _SC(""), -1); - int found = 0; - for(int i=0; i<16; i++) - { - int mask = 0x00000001 << i; - if(typemask & (mask)) { - if(found>0) StringCat(exptypes,SQString::Create(_ss(this), _SC("|"), -1), exptypes); - found ++; - StringCat(exptypes,SQString::Create(_ss(this), IdType2Name((SQObjectType)mask), -1), exptypes); - } - } - Raise_Error(_SC("parameter %d has an invalid type '%s' ; expected: '%s'"), nparam, IdType2Name((SQObjectType)type), _stringval(exptypes)); -} +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include +#include "sqvm.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "sqstring.h" + +SQRESULT sq_stackinfos(HSQUIRRELVM v, SQInteger level, SQStackInfos *si) +{ + SQInteger cssize = v->_callsstack.size(); + if (cssize > level) { + memset(si, 0, sizeof(SQStackInfos)); + SQVM::CallInfo &ci = v->_callsstack[cssize-level-1]; + switch (type(ci._closure)) { + case OT_CLOSURE:{ + SQFunctionProto *func = _funcproto(_closure(ci._closure)->_function); + if (type(func->_name) == OT_STRING) + si->funcname = _stringval(func->_name); + if (type(func->_sourcename) == OT_STRING) + si->source = _stringval(func->_sourcename); + si->line = func->GetLine(ci._ip); + } + break; + case OT_NATIVECLOSURE: + si->source = _SC("NATIVE"); + si->funcname = _SC("unknown"); + if(type(_nativeclosure(ci._closure)->_name) == OT_STRING) + si->funcname = _stringval(_nativeclosure(ci._closure)->_name); + si->line = -1; + break; + } + return SQ_OK; + } + return SQ_ERROR; +} + +void SQVM::Raise_Error(const SQChar *s, ...) +{ + va_list vl; + va_start(vl, s); + scvsprintf(_sp(rsl(scstrlen(s)+(NUMBER_MAX_CHAR*2))), s, vl); + va_end(vl); + _lasterror = SQString::Create(_ss(this),_spval,-1); +} + +void SQVM::Raise_Error(SQObjectPtr &desc) +{ + _lasterror = desc; +} + +SQString *SQVM::PrintObjVal(const SQObject &o) +{ + switch(type(o)) { + case OT_STRING: return _string(o); + case OT_INTEGER: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)), _SC("%d"), _integer(o)); + return SQString::Create(_ss(this), _spval); + break; + case OT_FLOAT: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)), _SC("%.14g"), _float(o)); + return SQString::Create(_ss(this), _spval); + break; + default: + return SQString::Create(_ss(this), GetTypeName(o)); + } +} + +void SQVM::Raise_IdxError(SQObject &o) +{ + SQObjectPtr oval = PrintObjVal(o); + Raise_Error(_SC("the index '%.50s' does not exist"), _stringval(oval)); +} + +void SQVM::Raise_CompareError(const SQObject &o1, const SQObject &o2) +{ + SQObjectPtr oval1 = PrintObjVal(o1), oval2 = PrintObjVal(o2); + Raise_Error(_SC("comparsion between '%.50s' and '%.50s'"), _stringval(oval1), _stringval(oval2)); +} + + +void SQVM::Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type) +{ + SQObjectPtr exptypes = SQString::Create(_ss(this), _SC(""), -1); + SQInteger found = 0; + for(SQInteger i=0; i<16; i++) + { + SQInteger mask = 0x00000001 << i; + if(typemask & (mask)) { + if(found>0) StringCat(exptypes,SQString::Create(_ss(this), _SC("|"), -1), exptypes); + found ++; + StringCat(exptypes,SQString::Create(_ss(this), IdType2Name((SQObjectType)mask), -1), exptypes); + } + } + Raise_Error(_SC("parameter %d has an invalid type '%s' ; expected: '%s'"), nparam, IdType2Name((SQObjectType)type), _stringval(exptypes)); +} diff --git a/src/squirrel/squirrel/sqfuncproto.h b/src/squirrel/squirrel/sqfuncproto.h index 6d9ccc077..b4079b0bf 100644 --- a/src/squirrel/squirrel/sqfuncproto.h +++ b/src/squirrel/squirrel/sqfuncproto.h @@ -1,89 +1,88 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQFUNCTION_H_ -#define _SQFUNCTION_H_ - -#include "sqopcodes.h" - -enum SQOuterType { - otLOCAL = 0, - otSYMBOL = 1, - otOUTER = 2 -}; - -struct SQOuterVar -{ - - SQOuterVar(){} - SQOuterVar(const SQObjectPtr &name,const SQObjectPtr &src,SQOuterType t) - { - _name = name; - _src=src; - _type=t; - } - SQOuterVar(const SQOuterVar &ov) - { - _type=ov._type; - _src=ov._src; - _name=ov._name; - } - SQOuterType _type; - SQObjectPtr _name; - SQObjectPtr _src; -}; - -struct SQLocalVarInfo -{ - SQLocalVarInfo():_start_op(0),_end_op(0){} - SQLocalVarInfo(const SQLocalVarInfo &lvi) - { - _name=lvi._name; - _start_op=lvi._start_op; - _end_op=lvi._end_op; - _pos=lvi._pos; - } - SQObjectPtr _name; - unsigned int _start_op; - unsigned int _end_op; - unsigned int _pos; -}; - -struct SQLineInfo { int _line;int _op; }; - -typedef sqvector SQOuterVarVec; -typedef sqvector SQLocalVarInfoVec; -typedef sqvector SQLineInfoVec; - -struct SQFunctionProto : public SQRefCounted -{ -private: - SQFunctionProto(){ - _uiRef=0; - _stacksize=0; - _bgenerator=false;} -public: - static SQFunctionProto *Create() - { - SQFunctionProto *f; - sq_new(f,SQFunctionProto); - return f; - } - void Release(){ sq_delete(this,SQFunctionProto);} - const SQChar* GetLocal(SQVM *v,unsigned int stackbase,unsigned int nseq,unsigned int nop); - int GetLine(SQInstruction *curr); - bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); - bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read); - SQObjectPtrVec _literals; - SQObjectPtrVec _functions; - SQObjectPtrVec _parameters; - SQOuterVarVec _outervalues; - SQInstructionVec _instructions; - SQObjectPtr _sourcename; - SQObjectPtr _name; - SQLocalVarInfoVec _localvarinfos; - SQLineInfoVec _lineinfos; - int _stacksize; - bool _bgenerator; - bool _varparams; -}; - -#endif //_SQFUNCTION_H_ +/* see copyright notice in squirrel.h */ +#ifndef _SQFUNCTION_H_ +#define _SQFUNCTION_H_ + +#include "sqopcodes.h" + +enum SQOuterType { + otLOCAL = 0, + otSYMBOL = 1, + otOUTER = 2 +}; + +struct SQOuterVar +{ + + SQOuterVar(){} + SQOuterVar(const SQObjectPtr &name,const SQObjectPtr &src,SQOuterType t) + { + _name = name; + _src=src; + _type=t; + } + SQOuterVar(const SQOuterVar &ov) + { + _type=ov._type; + _src=ov._src; + _name=ov._name; + } + SQOuterType _type; + SQObjectPtr _name; + SQObjectPtr _src; +}; + +struct SQLocalVarInfo +{ + SQLocalVarInfo():_start_op(0),_end_op(0){} + SQLocalVarInfo(const SQLocalVarInfo &lvi) + { + _name=lvi._name; + _start_op=lvi._start_op; + _end_op=lvi._end_op; + _pos=lvi._pos; + } + SQObjectPtr _name; + SQUnsignedInteger _start_op; + SQUnsignedInteger _end_op; + SQUnsignedInteger _pos; +}; + +struct SQLineInfo { SQInteger _line;SQInteger _op; }; + +typedef sqvector SQOuterVarVec; +typedef sqvector SQLocalVarInfoVec; +typedef sqvector SQLineInfoVec; + +struct SQFunctionProto : public SQRefCounted +{ +private: + SQFunctionProto(){ + _stacksize=0; + _bgenerator=false;} +public: + static SQFunctionProto *Create() + { + SQFunctionProto *f; + sq_new(f,SQFunctionProto); + return f; + } + void Release(){ sq_delete(this,SQFunctionProto);} + const SQChar* GetLocal(SQVM *v,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop); + SQInteger GetLine(SQInstruction *curr); + bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); + bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read); + SQObjectPtrVec _literals; + SQObjectPtrVec _functions; + SQObjectPtrVec _parameters; + SQOuterVarVec _outervalues; + SQInstructionVec _instructions; + SQObjectPtr _sourcename; + SQObjectPtr _name; + SQLocalVarInfoVec _localvarinfos; + SQLineInfoVec _lineinfos; + SQInteger _stacksize; + bool _bgenerator; + bool _varparams; +}; + +#endif //_SQFUNCTION_H_ diff --git a/src/squirrel/squirrel/sqfuncstate.cpp b/src/squirrel/squirrel/sqfuncstate.cpp index 9823fd38e..9e160267a 100644 --- a/src/squirrel/squirrel/sqfuncstate.cpp +++ b/src/squirrel/squirrel/sqfuncstate.cpp @@ -1,517 +1,544 @@ -/* - see copyright notice in squirrel.h -*/ -#include "sqpcheader.h" -#include "sqcompiler.h" -#include "sqfuncproto.h" -#include "sqstring.h" -#include "sqtable.h" -#include "sqopcodes.h" -#include "sqfuncstate.h" - -#ifdef _DEBUG_DUMP -SQInstructionDesc g_InstrDesc[]={ - {_SC("_OP_LINE")}, - {_SC("_OP_LOAD")}, - {_SC("_OP_TAILCALL")}, - {_SC("_OP_CALL")}, - {_SC("_OP_PREPCALL")}, - {_SC("_OP_PREPCALLK")}, - {_SC("_OP_GETK")}, - {_SC("_OP_MOVE")}, - {_SC("_OP_NEWSLOT")}, - {_SC("_OP_DELETE")}, - {_SC("_OP_SET")}, - {_SC("_OP_GET")}, - {_SC("_OP_EQ")}, - {_SC("_OP_NE")}, - {_SC("_OP_ARITH")}, - {_SC("_OP_BITW")}, - {_SC("_OP_RETURN")}, - {_SC("_OP_LOADNULLS")}, - {_SC("_OP_LOADROOTTABLE")}, - {_SC("_OP_DMOVE")}, - {_SC("_OP_JMP")}, - {_SC("_OP_JNZ")}, - {_SC("_OP_JZ")}, - {_SC("_OP_LOADFREEVAR")}, - {_SC("_OP_VARGC")}, - {_SC("_OP_GETVARGV")}, - {_SC("_OP_NEWTABLE")}, - {_SC("_OP_NEWARRAY")}, - {_SC("_OP_APPENDARRAY")}, - {_SC("_OP_GETPARENT")}, - {_SC("_OP_COMPARITH")}, - {_SC("_OP_COMPARITHL")}, - {_SC("_OP_INC")}, - {_SC("_OP_INCL")}, - {_SC("_OP_PINC")}, - {_SC("_OP_PINCL")}, - {_SC("_OP_CMP")}, - {_SC("_OP_EXISTS")}, - {_SC("_OP_INSTANCEOF")}, - {_SC("_OP_AND")}, - {_SC("_OP_OR")}, - {_SC("_OP_NEG")}, - {_SC("_OP_NOT")}, - {_SC("_OP_BWNOT")}, - {_SC("_OP_CLOSURE")}, - {_SC("_OP_YIELD")}, - {_SC("_OP_RESUME")}, - {_SC("_OP_FOREACH")}, - {_SC("_OP_DELEGATE")}, - {_SC("_OP_CLONE")}, - {_SC("_OP_TYPEOF")}, - {_SC("_OP_PUSHTRAP")}, - {_SC("_OP_POPTRAP")}, - {_SC("_OP_THROW")}, - {_SC("_OP_CLASS")}, - {_SC("_OP_NEWSLOTA")}, - {_SC("_OP_LOADBOOL")} -}; -#endif -void DumpLiteral(SQObjectPtr &o) -{ - switch(type(o)){ - case OT_STRING: scprintf(_SC("\"%s\""),_stringval(o));break; - case OT_FLOAT: scprintf(_SC("{%f}"),_float(o));break; - case OT_INTEGER: scprintf(_SC("{%d}"),_integer(o));break; - } -} - -SQFuncState::SQFuncState(SQSharedState *ss,SQFunctionProto *func,SQFuncState *parent,CompilerErrorFunc efunc,void *ed) -{ - _nliterals = 0; - _literals = SQTable::Create(ss,0); - _strings = SQTable::Create(ss,0); - _sharedstate = ss; - _lastline = 0; - _optimization = true; - _func = func; - _parent = parent; - _stacksize = 0; - _traps = 0; - _returnexp = 0; - _varparams = false; - _errfunc = efunc; - _errtarget = ed; - -} - -void SQFuncState::Error(const SQChar *err) -{ - _errfunc(_errtarget,err); -} - -#ifdef _DEBUG_DUMP -void SQFuncState::Dump() -{ - unsigned int n=0,i; - SQFunctionProto *func=_funcproto(_func); - scprintf(_SC("SQInstruction sizeof %d\n"),sizeof(SQInstruction)); - scprintf(_SC("SQObject sizeof %d\n"),sizeof(SQObject)); - scprintf(_SC("--------------------------------------------------------------------\n")); - scprintf(_SC("*****FUNCTION [%s]\n"),type(func->_name)==OT_STRING?_stringval(func->_name):_SC("unknown")); - scprintf(_SC("-----LITERALS\n")); - SQObjectPtr refidx,key,val; - SQInteger idx; - SQObjectPtrVec templiterals; - templiterals.resize(_nliterals); - while((idx=_table(_literals)->Next(refidx,key,val))!=-1) { - refidx=idx; - templiterals[_integer(val)]=key; - } - for(i=0;i>\n")); - n=0; - for(i=0;i<_parameters.size();i++){ - scprintf(_SC("[%d] "),n); - DumpLiteral(_parameters[i]); - scprintf(_SC("\n")); - n++; - } - scprintf(_SC("-----LOCALS\n")); - for(i=0;i_localvarinfos.size();i++){ - SQLocalVarInfo lvi=func->_localvarinfos[i]; - scprintf(_SC("[%d] %s \t%d %d\n"),lvi._pos,_stringval(lvi._name),lvi._start_op,lvi._end_op); - n++; - } - scprintf(_SC("-----LINE INFO\n")); - for(i=0;i<_lineinfos.size();i++){ - SQLineInfo li=_lineinfos[i]; - scprintf(_SC("op [%d] line [%d] \n"),li._op,li._line); - n++; - } - scprintf(_SC("-----dump\n")); - n=0; - for(i=0;i<_instructions.size();i++){ - SQInstruction &inst=_instructions[i]; - if(inst.op==_OP_LOAD || inst.op==_OP_PREPCALLK || inst.op==_OP_GETK ){ - - int lidx = inst._arg1; - scprintf(_SC("[%03d] %15s %d "),n,g_InstrDesc[inst.op].name,inst._arg0); - if(lidx >= 0xFFFFFFFF) - scprintf(_SC("null")); - else { - int refidx; - SQObjectPtr val,key,refo; - while(((refidx=_table(_literals)->Next(refo,key,val))!= -1) && (_integer(val) != lidx)) { - refo = refidx; - } - DumpLiteral(key); - } - scprintf(_SC(" %d %d \n"),inst._arg2,inst._arg3); - } - else if(inst.op==_OP_ARITH){ - scprintf(_SC("[%03d] %15s %d %d %d %c\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3); - } - else - scprintf(_SC("[%03d] %15s %d %d %d %d\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3); - n++; - } - scprintf(_SC("-----\n")); - scprintf(_SC("stack size[%d]\n"),func->_stacksize); - scprintf(_SC("--------------------------------------------------------------------\n\n")); -} -#endif -/*int SQFuncState::GetStringConstant(SQObjectPtr &cons) -{ - return GetConstant(cons); -}*/ - -int SQFuncState::GetNumericConstant(const SQInteger cons) -{ - return GetConstant(SQObjectPtr(cons)); -} - -int SQFuncState::GetNumericConstant(const SQFloat cons) -{ - return GetConstant(SQObjectPtr(cons)); -} - -int SQFuncState::GetConstant(const SQObject &cons) -{ - int n=0; - SQObjectPtr val; - if(!_table(_literals)->Get(cons,val)) - { - val = _nliterals; - _table(_literals)->NewSlot(cons,val); - _nliterals++; - if(_nliterals > MAX_LITERALS) { - val.Null(); - Error(_SC("internal compiler error: too many literals")); - } - } - return _integer(val); -} - -void SQFuncState::SetIntructionParams(int pos,int arg0,int arg1,int arg2,int arg3) -{ - _instructions[pos]._arg0=*((unsigned int *)&arg0); - _instructions[pos]._arg1=*((unsigned int *)&arg1); - _instructions[pos]._arg2=*((unsigned int *)&arg2); - _instructions[pos]._arg3=*((unsigned int *)&arg3); -} - -void SQFuncState::SetIntructionParam(int pos,int arg,int val) -{ - switch(arg){ - case 0:_instructions[pos]._arg0=*((unsigned int *)&val);break; - case 1:_instructions[pos]._arg1=*((unsigned int *)&val);break; - case 2:_instructions[pos]._arg2=*((unsigned int *)&val);break; - case 3:_instructions[pos]._arg3=*((unsigned int *)&val);break; - case 4:_instructions[pos]._arg1=*((unsigned int *)&val);break; - }; -} - -int SQFuncState::AllocStackPos() -{ - int npos=_vlocals.size(); - _vlocals.push_back(SQLocalVarInfo()); - if(_vlocals.size()>((unsigned int)_stacksize)) { - if(_stacksize>MAX_FUNC_STACKSIZE) Error(_SC("internal compiler error: too many locals")); - _stacksize=_vlocals.size(); - } - return npos; -} - -int SQFuncState::PushTarget(int n) -{ - if(n!=-1){ - _targetstack.push_back(n); - return n; - } - n=AllocStackPos(); - _targetstack.push_back(n); - return n; -} - -int SQFuncState::GetUpTarget(int n){ - return _targetstack[((_targetstack.size()-1)-n)]; -} - -int SQFuncState::TopTarget(){ - return _targetstack.back(); -} -int SQFuncState::PopTarget() -{ - int npos=_targetstack.back(); - SQLocalVarInfo t=_vlocals[_targetstack.back()]; - if(type(t._name)==OT_NULL){ - _vlocals.pop_back(); - } - _targetstack.pop_back(); - return npos; -} - -int SQFuncState::GetStackSize() -{ - return _vlocals.size(); -} - -void SQFuncState::SetStackSize(int n) -{ - int size=_vlocals.size(); - while(size>n){ - size--; - SQLocalVarInfo lvi=_vlocals.back(); - if(type(lvi._name)!=OT_NULL){ - lvi._end_op=GetCurrentPos(); - _localvarinfos.push_back(lvi); - } - _vlocals.pop_back(); - } -} - -bool SQFuncState::IsLocal(unsigned int stkpos) -{ - if(stkpos>=_vlocals.size())return false; - else if(type(_vlocals[stkpos]._name)!=OT_NULL)return true; - return false; -} - -int SQFuncState::PushLocalVariable(const SQObject &name) -{ - int pos=_vlocals.size(); - SQLocalVarInfo lvi; - lvi._name=name; - lvi._start_op=GetCurrentPos()+1; - lvi._pos=_vlocals.size(); - _vlocals.push_back(lvi); - if(_vlocals.size()>((unsigned int)_stacksize))_stacksize=_vlocals.size(); - - return pos; -} - -int SQFuncState::GetLocalVariable(const SQObject &name) -{ - int locals=_vlocals.size(); - while(locals>=1){ - if(type(_vlocals[locals-1]._name)==OT_STRING && _string(_vlocals[locals-1]._name)==_string(name)){ - return locals-1; - } - locals--; - } - return -1; -} - -int SQFuncState::GetOuterVariable(const SQObject &name) -{ - int outers = _outervalues.size(); - for(int i = 0; iGetLocalVariable(name); - if(pos == -1) { - pos = _parent->GetOuterVariable(name); - if(pos != -1) { - _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otOUTER)); //local - return; - } - } - else { - _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otLOCAL)); //local - return; - } - } - _outervalues.push_back(SQOuterVar(name,name,otSYMBOL)); //global -} - -void SQFuncState::AddParameter(const SQObject &name) -{ - PushLocalVariable(name); - _parameters.push_back(name); -} - -void SQFuncState::AddLineInfos(int line,bool lineop,bool force) -{ - if(_lastline!=line || force){ - SQLineInfo li; - li._line=line;li._op=(GetCurrentPos()+1); - if(lineop)AddInstruction(_OP_LINE,0,line); - _lineinfos.push_back(li); - _lastline=line; - } -} - -void SQFuncState::AddInstruction(SQInstruction &i) -{ - int size = _instructions.size(); - if(size > 0 && _optimization){ //simple optimizer - SQInstruction &pi = _instructions[size-1];//previous instruction - switch(i.op) { - case _OP_RETURN: - if( _parent && i._arg0 != MAX_FUNC_STACKSIZE && pi.op == _OP_CALL && _returnexp < size-1) { - pi.op = _OP_TAILCALL; - } - break; - case _OP_GET: - if( pi.op == _OP_LOAD && pi._arg0 == i._arg2 && (!IsLocal(pi._arg0))){ - pi._arg1 = pi._arg1; - pi._arg2 = (unsigned char)i._arg1; - pi.op = _OP_GETK; - pi._arg0 = i._arg0; - - return; - } - break; - case _OP_PREPCALL: - if( pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){ - pi.op = _OP_PREPCALLK; - pi._arg0 = i._arg0; - pi._arg1 = pi._arg1; - pi._arg2 = i._arg2; - pi._arg3 = i._arg3; - return; - } - break; - case _OP_APPENDARRAY: - if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){ - pi.op = _OP_APPENDARRAY; - pi._arg0 = i._arg0; - pi._arg1 = pi._arg1; - pi._arg2 = MAX_FUNC_STACKSIZE; - pi._arg3 = MAX_FUNC_STACKSIZE; - return; - } - break; - case _OP_MOVE: - if((pi.op == _OP_GET || pi.op == _OP_ARITH || pi.op == _OP_BITW) && (pi._arg0 == i._arg1)) - { - pi._arg0 = i._arg0; - _optimization = false; - return; - } - - if(pi.op == _OP_MOVE) - { - pi.op = _OP_DMOVE; - pi._arg2 = i._arg0; - pi._arg3 = (unsigned char)i._arg1; - return; - } - break; - - case _OP_EQ:case _OP_NE: - if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0) )) - { - pi.op = i.op; - pi._arg0 = i._arg0; - pi._arg1 = pi._arg1; - pi._arg2 = i._arg2; - pi._arg3 = MAX_FUNC_STACKSIZE; - return; - } - break; - case _OP_LOADNULLS: - //case _OP_LOADNULL: - if((pi.op == _OP_LOADNULLS && pi._arg0+pi._arg1 == i._arg0)) { - - pi._arg1 = pi._arg1 + 1; - pi.op = _OP_LOADNULLS; - return; - } - break; - case _OP_LINE: - if(pi.op == _OP_LINE) { - _instructions.pop_back(); - _lineinfos.pop_back(); - } - break; - } - } - _optimization = true; - _instructions.push_back(i); -} - -SQObject SQFuncState::CreateString(const SQChar *s,int len) -{ - SQObjectPtr ns(SQString::Create(_sharedstate,s,len)); - _table(_strings)->NewSlot(ns,1); - return ns; -} - -void SQFuncState::Finalize() -{ - SQFunctionProto *f=_funcproto(_func); - f->_literals.resize(_nliterals); - SQObjectPtr refidx,key,val; - SQInteger idx; - while((idx=_table(_literals)->Next(refidx,key,val))!=-1) { - f->_literals[_integer(val)]=key; - refidx=idx; - } - f->_functions.resize(_functions.size()); - f->_functions.copy(_functions); - f->_parameters.resize(_parameters.size()); - f->_parameters.copy(_parameters); - f->_outervalues.resize(_outervalues.size()); - f->_outervalues.copy(_outervalues); - f->_instructions.resize(_instructions.size()); - f->_instructions.copy(_instructions); - f->_localvarinfos.resize(_localvarinfos.size()); - f->_localvarinfos.copy(_localvarinfos); - f->_lineinfos.resize(_lineinfos.size()); - f->_lineinfos.copy(_lineinfos); - f->_varparams = _varparams; -} - -SQFuncState *SQFuncState::PushChildState(SQSharedState *ss,SQFunctionProto *func) -{ - SQFuncState *child = (SQFuncState *)sq_malloc(sizeof(SQFuncState)); - new (child) SQFuncState(ss,func,this,_errfunc,_errtarget); - _childstates.push_back(child); - return child; -} - -void SQFuncState::PopChildState() -{ - SQFuncState *child = _childstates.back(); - sq_delete(child,SQFuncState); - _childstates.pop_back(); -} - -SQFuncState::~SQFuncState() -{ - while(_childstates.size() > 0) - { - PopChildState(); - } -} +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqcompiler.h" +#include "sqfuncproto.h" +#include "sqstring.h" +#include "sqtable.h" +#include "sqopcodes.h" +#include "sqfuncstate.h" + +#ifdef _DEBUG_DUMP +SQInstructionDesc g_InstrDesc[]={ + {_SC("_OP_LINE")}, + {_SC("_OP_LOAD")}, + {_SC("_OP_DLOAD")}, + {_SC("_OP_TAILCALL")}, + {_SC("_OP_CALL")}, + {_SC("_OP_PREPCALL")}, + {_SC("_OP_PREPCALLK")}, + {_SC("_OP_GETK")}, + {_SC("_OP_MOVE")}, + {_SC("_OP_NEWSLOT")}, + {_SC("_OP_DELETE")}, + {_SC("_OP_SET")}, + {_SC("_OP_GET")}, + {_SC("_OP_EQ")}, + {_SC("_OP_NE")}, + {_SC("_OP_ARITH")}, + {_SC("_OP_BITW")}, + {_SC("_OP_RETURN")}, + {_SC("_OP_LOADNULLS")}, + {_SC("_OP_LOADROOTTABLE")}, + {_SC("_OP_LOADBOOL")}, + {_SC("_OP_DMOVE")}, + {_SC("_OP_JMP")}, + {_SC("_OP_JNZ")}, + {_SC("_OP_JZ")}, + {_SC("_OP_LOADFREEVAR")}, + {_SC("_OP_VARGC")}, + {_SC("_OP_GETVARGV")}, + {_SC("_OP_NEWTABLE")}, + {_SC("_OP_NEWARRAY")}, + {_SC("_OP_APPENDARRAY")}, + {_SC("_OP_GETPARENT")}, + {_SC("_OP_COMPARITH")}, + {_SC("_OP_COMPARITHL")}, + {_SC("_OP_INC")}, + {_SC("_OP_INCL")}, + {_SC("_OP_PINC")}, + {_SC("_OP_PINCL")}, + {_SC("_OP_CMP")}, + {_SC("_OP_EXISTS")}, + {_SC("_OP_INSTANCEOF")}, + {_SC("_OP_AND")}, + {_SC("_OP_OR")}, + {_SC("_OP_NEG")}, + {_SC("_OP_NOT")}, + {_SC("_OP_BWNOT")}, + {_SC("_OP_CLOSURE")}, + {_SC("_OP_YIELD")}, + {_SC("_OP_RESUME")}, + {_SC("_OP_FOREACH")}, + {_SC("_OP_DELEGATE")}, + {_SC("_OP_CLONE")}, + {_SC("_OP_TYPEOF")}, + {_SC("_OP_PUSHTRAP")}, + {_SC("_OP_POPTRAP")}, + {_SC("_OP_THROW")}, + {_SC("_OP_CLASS")}, + {_SC("_OP_NEWSLOTA")} +}; +#endif +void DumpLiteral(SQObjectPtr &o) +{ + switch(type(o)){ + case OT_STRING: scprintf(_SC("\"%s\""),_stringval(o));break; + case OT_FLOAT: scprintf(_SC("{%f}"),_float(o));break; + case OT_INTEGER: scprintf(_SC("{%d}"),_integer(o));break; + } +} + +SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed) +{ + _nliterals = 0; + _literals = SQTable::Create(ss,0); + _strings = SQTable::Create(ss,0); + _sharedstate = ss; + _lastline = 0; + _optimization = true; + _parent = parent; + _stacksize = 0; + _traps = 0; + _returnexp = 0; + _varparams = false; + _errfunc = efunc; + _errtarget = ed; + _bgenerator = false; + +} + +void SQFuncState::Error(const SQChar *err) +{ + _errfunc(_errtarget,err); +} + +#ifdef _DEBUG_DUMP +void SQFuncState::Dump(SQFunctionProto *func) +{ + SQUnsignedInteger n=0,i; + scprintf(_SC("SQInstruction sizeof %d\n"),sizeof(SQInstruction)); + scprintf(_SC("SQObject sizeof %d\n"),sizeof(SQObject)); + scprintf(_SC("--------------------------------------------------------------------\n")); + scprintf(_SC("*****FUNCTION [%s]\n"),type(func->_name)==OT_STRING?_stringval(func->_name):_SC("unknown")); + scprintf(_SC("-----LITERALS\n")); + SQObjectPtr refidx,key,val; + SQInteger idx; + SQObjectPtrVec templiterals; + templiterals.resize(_nliterals); + while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) { + refidx=idx; + templiterals[_integer(val)]=key; + } + for(i=0;i>\n")); + n=0; + for(i=0;i<_parameters.size();i++){ + scprintf(_SC("[%d] "),n); + DumpLiteral(_parameters[i]); + scprintf(_SC("\n")); + n++; + } + scprintf(_SC("-----LOCALS\n")); + for(i=0;i_localvarinfos.size();i++){ + SQLocalVarInfo lvi=func->_localvarinfos[i]; + scprintf(_SC("[%d] %s \t%d %d\n"),lvi._pos,_stringval(lvi._name),lvi._start_op,lvi._end_op); + n++; + } + scprintf(_SC("-----LINE INFO\n")); + for(i=0;i<_lineinfos.size();i++){ + SQLineInfo li=_lineinfos[i]; + scprintf(_SC("op [%d] line [%d] \n"),li._op,li._line); + n++; + } + scprintf(_SC("-----dump\n")); + n=0; + for(i=0;i<_instructions.size();i++){ + SQInstruction &inst=_instructions[i]; + if(inst.op==_OP_LOAD || inst.op==_OP_DLOAD || inst.op==_OP_PREPCALLK || inst.op==_OP_GETK ){ + + SQInteger lidx = inst._arg1; + scprintf(_SC("[%03d] %15s %d "),n,g_InstrDesc[inst.op].name,inst._arg0); + if(lidx >= 0xFFFFFFFF) + scprintf(_SC("null")); + else { + SQInteger refidx; + SQObjectPtr val,key,refo; + while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) { + refo = refidx; + } + DumpLiteral(key); + } + if(inst.op != _OP_DLOAD) { + scprintf(_SC(" %d %d \n"),inst._arg2,inst._arg3); + } + else { + scprintf(_SC(" %d "),inst._arg2); + lidx = inst._arg3; + if(lidx >= 0xFFFFFFFF) + scprintf(_SC("null")); + else { + SQInteger refidx; + SQObjectPtr val,key,refo; + while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) { + refo = refidx; + } + DumpLiteral(key); + scprintf(_SC("\n")); + } + } + } + else if(inst.op==_OP_ARITH){ + scprintf(_SC("[%03d] %15s %d %d %d %c\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3); + } + else + scprintf(_SC("[%03d] %15s %d %d %d %d\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3); + n++; + } + scprintf(_SC("-----\n")); + scprintf(_SC("stack size[%d]\n"),func->_stacksize); + scprintf(_SC("--------------------------------------------------------------------\n\n")); +} +#endif + +SQInteger SQFuncState::GetNumericConstant(const SQInteger cons) +{ + return GetConstant(SQObjectPtr(cons)); +} + +SQInteger SQFuncState::GetNumericConstant(const SQFloat cons) +{ + return GetConstant(SQObjectPtr(cons)); +} + +SQInteger SQFuncState::GetConstant(const SQObject &cons) +{ + SQInteger n=0; + SQObjectPtr val; + if(!_table(_literals)->Get(cons,val)) + { + val = _nliterals; + _table(_literals)->NewSlot(cons,val); + _nliterals++; + if(_nliterals > MAX_LITERALS) { + val.Null(); + Error(_SC("internal compiler error: too many literals")); + } + } + return _integer(val); +} + +void SQFuncState::SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3) +{ + _instructions[pos]._arg0=*((SQUnsignedInteger *)&arg0); + _instructions[pos]._arg1=*((SQUnsignedInteger *)&arg1); + _instructions[pos]._arg2=*((SQUnsignedInteger *)&arg2); + _instructions[pos]._arg3=*((SQUnsignedInteger *)&arg3); +} + +void SQFuncState::SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val) +{ + switch(arg){ + case 0:_instructions[pos]._arg0=*((SQUnsignedInteger *)&val);break; + case 1:_instructions[pos]._arg1=*((SQUnsignedInteger *)&val);break; + case 2:_instructions[pos]._arg2=*((SQUnsignedInteger *)&val);break; + case 3:_instructions[pos]._arg3=*((SQUnsignedInteger *)&val);break; + case 4:_instructions[pos]._arg1=*((SQUnsignedInteger *)&val);break; + }; +} + +SQInteger SQFuncState::AllocStackPos() +{ + SQInteger npos=_vlocals.size(); + _vlocals.push_back(SQLocalVarInfo()); + if(_vlocals.size()>((SQUnsignedInteger)_stacksize)) { + if(_stacksize>MAX_FUNC_STACKSIZE) Error(_SC("internal compiler error: too many locals")); + _stacksize=_vlocals.size(); + } + return npos; +} + +SQInteger SQFuncState::PushTarget(SQInteger n) +{ + if(n!=-1){ + _targetstack.push_back(n); + return n; + } + n=AllocStackPos(); + _targetstack.push_back(n); + return n; +} + +SQInteger SQFuncState::GetUpTarget(SQInteger n){ + return _targetstack[((_targetstack.size()-1)-n)]; +} + +SQInteger SQFuncState::TopTarget(){ + return _targetstack.back(); +} +SQInteger SQFuncState::PopTarget() +{ + SQInteger npos=_targetstack.back(); + SQLocalVarInfo t=_vlocals[_targetstack.back()]; + if(type(t._name)==OT_NULL){ + _vlocals.pop_back(); + } + _targetstack.pop_back(); + return npos; +} + +SQInteger SQFuncState::GetStackSize() +{ + return _vlocals.size(); +} + +void SQFuncState::SetStackSize(SQInteger n) +{ + SQInteger size=_vlocals.size(); + while(size>n){ + size--; + SQLocalVarInfo lvi=_vlocals.back(); + if(type(lvi._name)!=OT_NULL){ + lvi._end_op=GetCurrentPos(); + _localvarinfos.push_back(lvi); + } + _vlocals.pop_back(); + } +} + +bool SQFuncState::IsLocal(SQUnsignedInteger stkpos) +{ + if(stkpos>=_vlocals.size())return false; + else if(type(_vlocals[stkpos]._name)!=OT_NULL)return true; + return false; +} + +SQInteger SQFuncState::PushLocalVariable(const SQObject &name) +{ + SQInteger pos=_vlocals.size(); + SQLocalVarInfo lvi; + lvi._name=name; + lvi._start_op=GetCurrentPos()+1; + lvi._pos=_vlocals.size(); + _vlocals.push_back(lvi); + if(_vlocals.size()>((SQUnsignedInteger)_stacksize))_stacksize=_vlocals.size(); + + return pos; +} + +SQInteger SQFuncState::GetLocalVariable(const SQObject &name) +{ + SQInteger locals=_vlocals.size(); + while(locals>=1){ + if(type(_vlocals[locals-1]._name)==OT_STRING && _string(_vlocals[locals-1]._name)==_string(name)){ + return locals-1; + } + locals--; + } + return -1; +} + +SQInteger SQFuncState::GetOuterVariable(const SQObject &name) +{ + SQInteger outers = _outervalues.size(); + for(SQInteger i = 0; iGetLocalVariable(name); + if(pos == -1) { + pos = _parent->GetOuterVariable(name); + if(pos != -1) { + _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otOUTER)); //local + return; + } + } + else { + _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otLOCAL)); //local + return; + } + } + _outervalues.push_back(SQOuterVar(name,name,otSYMBOL)); //global +} + +void SQFuncState::AddParameter(const SQObject &name) +{ + PushLocalVariable(name); + _parameters.push_back(name); +} + +void SQFuncState::AddLineInfos(SQInteger line,bool lineop,bool force) +{ + if(_lastline!=line || force){ + SQLineInfo li; + li._line=line;li._op=(GetCurrentPos()+1); + if(lineop)AddInstruction(_OP_LINE,0,line); + _lineinfos.push_back(li); + _lastline=line; + } +} + +void SQFuncState::AddInstruction(SQInstruction &i) +{ + SQInteger size = _instructions.size(); + if(size > 0 && _optimization){ //simple optimizer + SQInstruction &pi = _instructions[size-1];//previous instruction + switch(i.op) { + case _OP_RETURN: + if( _parent && i._arg0 != MAX_FUNC_STACKSIZE && pi.op == _OP_CALL && _returnexp < size-1) { + pi.op = _OP_TAILCALL; + } + break; + case _OP_GET: + if( pi.op == _OP_LOAD && pi._arg0 == i._arg2 && (!IsLocal(pi._arg0))){ + pi._arg1 = pi._arg1; + pi._arg2 = (unsigned char)i._arg1; + pi.op = _OP_GETK; + pi._arg0 = i._arg0; + + return; + } + break; + case _OP_PREPCALL: + if( pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){ + pi.op = _OP_PREPCALLK; + pi._arg0 = i._arg0; + pi._arg1 = pi._arg1; + pi._arg2 = i._arg2; + pi._arg3 = i._arg3; + return; + } + break; + case _OP_APPENDARRAY: + if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){ + pi.op = _OP_APPENDARRAY; + pi._arg0 = i._arg0; + pi._arg1 = pi._arg1; + pi._arg2 = MAX_FUNC_STACKSIZE; + pi._arg3 = MAX_FUNC_STACKSIZE; + return; + } + break; + case _OP_MOVE: + if((pi.op == _OP_GET || pi.op == _OP_ARITH || pi.op == _OP_BITW) && (pi._arg0 == i._arg1)) + { + pi._arg0 = i._arg0; + _optimization = false; + return; + } + + if(pi.op == _OP_MOVE) + { + pi.op = _OP_DMOVE; + pi._arg2 = i._arg0; + pi._arg3 = (unsigned char)i._arg1; + return; + } + break; + case _OP_LOAD: + if(pi.op == _OP_LOAD && i._arg1 < 256) { + pi.op = _OP_DLOAD; + pi._arg2 = i._arg0; + pi._arg3 = (unsigned char)i._arg1; + return; + } + break; + case _OP_EQ:case _OP_NE: + if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0) )) + { + pi.op = i.op; + pi._arg0 = i._arg0; + pi._arg1 = pi._arg1; + pi._arg2 = i._arg2; + pi._arg3 = MAX_FUNC_STACKSIZE; + return; + } + break; + case _OP_LOADNULLS: + if((pi.op == _OP_LOADNULLS && pi._arg0+pi._arg1 == i._arg0)) { + + pi._arg1 = pi._arg1 + 1; + pi.op = _OP_LOADNULLS; + return; + } + break; + case _OP_LINE: + if(pi.op == _OP_LINE) { + _instructions.pop_back(); + _lineinfos.pop_back(); + } + break; + } + } + _optimization = true; + _instructions.push_back(i); +} + +SQObject SQFuncState::CreateString(const SQChar *s,SQInteger len) +{ + SQObjectPtr ns(SQString::Create(_sharedstate,s,len)); + _table(_strings)->NewSlot(ns,1); + return ns; +} + +SQFunctionProto *SQFuncState::BuildProto() +{ + SQFunctionProto *f=SQFunctionProto::Create(); + f->_literals.resize(_nliterals); + SQObjectPtr refidx,key,val; + SQInteger idx; + + f->_stacksize = _stacksize; + f->_sourcename = _sourcename; + f->_bgenerator = _bgenerator; + f->_name = _name; + + while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) { + f->_literals[_integer(val)]=key; + refidx=idx; + } + + f->_functions.resize(_functions.size()); + f->_functions.copy(_functions); + f->_parameters.resize(_parameters.size()); + f->_parameters.copy(_parameters); + f->_outervalues.resize(_outervalues.size()); + f->_outervalues.copy(_outervalues); + f->_instructions.resize(_instructions.size()); + f->_instructions.copy(_instructions); + f->_localvarinfos.resize(_localvarinfos.size()); + f->_localvarinfos.copy(_localvarinfos); + f->_lineinfos.resize(_lineinfos.size()); + f->_lineinfos.copy(_lineinfos); + f->_varparams = _varparams; + + return f; +} + +SQFuncState *SQFuncState::PushChildState(SQSharedState *ss) +{ + SQFuncState *child = (SQFuncState *)sq_malloc(sizeof(SQFuncState)); + new (child) SQFuncState(ss,this,_errfunc,_errtarget); + _childstates.push_back(child); + return child; +} + +void SQFuncState::PopChildState() +{ + SQFuncState *child = _childstates.back(); + sq_delete(child,SQFuncState); + _childstates.pop_back(); +} + +SQFuncState::~SQFuncState() +{ + while(_childstates.size() > 0) + { + PopChildState(); + } +} diff --git a/src/squirrel/squirrel/sqfuncstate.h b/src/squirrel/squirrel/sqfuncstate.h index 4324eaa0a..c69a2f42d 100644 --- a/src/squirrel/squirrel/sqfuncstate.h +++ b/src/squirrel/squirrel/sqfuncstate.h @@ -1,79 +1,81 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQFUNCSTATE_H_ -#define _SQFUNCSTATE_H_ -/////////////////////////////////// -#include "squtils.h" - -struct SQFuncState -{ - SQFuncState(SQSharedState *ss,SQFunctionProto *func,SQFuncState *parent,CompilerErrorFunc efunc,void *ed); - ~SQFuncState(); -#ifdef _DEBUG_DUMP - void Dump(); -#endif - void Error(const SQChar *err); - SQFuncState *PushChildState(SQSharedState *ss,SQFunctionProto *func); - void PopChildState(); - void AddInstruction(SQOpcode _op,int arg0=0,int arg1=0,int arg2=0,int arg3=0){SQInstruction i(_op,arg0,arg1,arg2,arg3);AddInstruction(i);} - void AddInstruction(SQInstruction &i); - void SetIntructionParams(int pos,int arg0,int arg1,int arg2=0,int arg3=0); - void SetIntructionParam(int pos,int arg,int val); - SQInstruction &GetInstruction(int pos){return _instructions[pos];} - void PopInstructions(int size){for(int i=0;i _childstates; - int GetConstant(const SQObject &cons); -private: - CompilerErrorFunc _errfunc; - void *_errtarget; -}; - - -#endif //_SQFUNCSTATE_H_ - +/* see copyright notice in squirrel.h */ +#ifndef _SQFUNCSTATE_H_ +#define _SQFUNCSTATE_H_ +/////////////////////////////////// +#include "squtils.h" + +struct SQFuncState +{ + SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed); + ~SQFuncState(); +#ifdef _DEBUG_DUMP + void Dump(SQFunctionProto *func); +#endif + void Error(const SQChar *err); + SQFuncState *PushChildState(SQSharedState *ss); + void PopChildState(); + void AddInstruction(SQOpcode _op,SQInteger arg0=0,SQInteger arg1=0,SQInteger arg2=0,SQInteger arg3=0){SQInstruction i(_op,arg0,arg1,arg2,arg3);AddInstruction(i);} + void AddInstruction(SQInstruction &i); + void SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2=0,SQInteger arg3=0); + void SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val); + SQInstruction &GetInstruction(SQInteger pos){return _instructions[pos];} + void PopInstructions(SQInteger size){for(SQInteger i=0;i _childstates; + SQInteger GetConstant(const SQObject &cons); +private: + CompilerErrorFunc _errfunc; + void *_errtarget; +}; + + +#endif //_SQFUNCSTATE_H_ + diff --git a/src/squirrel/squirrel/sqlexer.cpp b/src/squirrel/squirrel/sqlexer.cpp index a0a53f14f..93bd577b6 100644 --- a/src/squirrel/squirrel/sqlexer.cpp +++ b/src/squirrel/squirrel/sqlexer.cpp @@ -1,426 +1,426 @@ -/* - see copyright notice in squirrel.h -*/ -#include "sqpcheader.h" -#include -#include -#include "sqtable.h" -#include "sqstring.h" -#include "sqcompiler.h" -#include "sqlexer.h" - -#define CUR_CHAR (_currdata) -#define RETURN_TOKEN(t) { _prevtoken = _curtoken; _curtoken = t; return t;} -#define IS_EOB() (CUR_CHAR <= SQUIRREL_EOB) -#define NEXT() {Next();_currentcolumn++;} -#define INIT_TEMP_STRING() { _longstr.resize(0);} -#define APPEND_CHAR(c) { _longstr.push_back(c);} -#define TERMINATE_BUFFER() {_longstr.push_back(_SC('\0'));} -#define ADD_KEYWORD(key,id) _keywords->NewSlot( SQString::Create(ss, _SC(#key)) ,SQInteger(id)) - -SQLexer::SQLexer(){} -SQLexer::~SQLexer() -{ - _keywords->Release(); -} - -void SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,CompilerErrorFunc efunc,void *ed) -{ - _errfunc = efunc; - _errtarget = ed; - _sharedstate = ss; - _keywords = SQTable::Create(ss, 26); - ADD_KEYWORD(while, TK_WHILE); - ADD_KEYWORD(do, TK_DO); - ADD_KEYWORD(if, TK_IF); - ADD_KEYWORD(else, TK_ELSE); - ADD_KEYWORD(break, TK_BREAK); - ADD_KEYWORD(continue, TK_CONTINUE); - ADD_KEYWORD(return, TK_RETURN); - ADD_KEYWORD(null, TK_NULL); - ADD_KEYWORD(function, TK_FUNCTION); - ADD_KEYWORD(local, TK_LOCAL); - ADD_KEYWORD(for, TK_FOR); - ADD_KEYWORD(foreach, TK_FOREACH); - ADD_KEYWORD(in, TK_IN); - ADD_KEYWORD(typeof, TK_TYPEOF); - ADD_KEYWORD(delegate, TK_DELEGATE); - ADD_KEYWORD(delete, TK_DELETE); - ADD_KEYWORD(try, TK_TRY); - ADD_KEYWORD(catch, TK_CATCH); - ADD_KEYWORD(throw, TK_THROW); - ADD_KEYWORD(clone, TK_CLONE); - ADD_KEYWORD(yield, TK_YIELD); - ADD_KEYWORD(resume, TK_RESUME); - ADD_KEYWORD(switch, TK_SWITCH); - ADD_KEYWORD(case, TK_CASE); - ADD_KEYWORD(default, TK_DEFAULT); - ADD_KEYWORD(this, TK_THIS); - ADD_KEYWORD(parent,TK_PARENT); - ADD_KEYWORD(class,TK_CLASS); - ADD_KEYWORD(extends,TK_EXTENDS); - ADD_KEYWORD(constructor,TK_CONSTRUCTOR); - ADD_KEYWORD(instanceof,TK_INSTANCEOF); - ADD_KEYWORD(vargc,TK_VARGC); - ADD_KEYWORD(vargv,TK_VARGV); - ADD_KEYWORD(true,TK_TRUE); - ADD_KEYWORD(false,TK_FALSE); - - _readf = rg; - _up = up; - _lasttokenline = _currentline = 1; - _currentcolumn = 0; - _prevtoken = -1; - Next(); -} - -void SQLexer::Error(const SQChar *err) -{ - _errfunc(_errtarget,err); -} - -void SQLexer::Next() -{ - SQInteger t = _readf(_up); - if(t > MAX_CHAR) Error(_SC("Invalid character")); - if(t != 0) { - _currdata = t; - return; - } - _currdata = SQUIRREL_EOB; -} - -const SQChar *SQLexer::Tok2Str(int tok) -{ - SQObjectPtr itr, key, val; - int nitr; - while((nitr = _keywords->Next(itr, key, val)) != -1) { - itr = (SQInteger)nitr; - if(((int)_integer(val)) == tok) - return _stringval(key); - } - return NULL; -} - -void SQLexer::LexBlockComment() -{ - bool done = false; - while(!done) { - switch(CUR_CHAR) { - case _SC('*'): { NEXT(); if(CUR_CHAR == _SC('/')) { done = true; NEXT(); }}; continue; - //case _SC('/'): { NEXT(); if(CUR_CHAR == _SC('*')) { nest++; NEXT(); }}; continue; - case _SC('\n'): _currentline++; NEXT(); continue; - case SQUIRREL_EOB: Error(_SC("missing \"*/\" in comment")); - default: NEXT(); - } - } -} - -int SQLexer::Lex() -{ - _lasttokenline = _currentline; - while(CUR_CHAR != SQUIRREL_EOB) { - switch(CUR_CHAR){ - case _SC('\t'): case _SC('\r'): case _SC(' '): NEXT(); continue; - case _SC('\n'): - _currentline++; - _prevtoken=_curtoken; - _curtoken=_SC('\n'); - NEXT(); - _currentcolumn=1; - continue; - case _SC('/'): - NEXT(); - switch(CUR_CHAR){ - case _SC('*'): - NEXT(); - LexBlockComment(); - continue; - case _SC('/'): - do { NEXT(); } while (CUR_CHAR != _SC('\n') && (!IS_EOB())); - continue; - case _SC('='): - NEXT(); - RETURN_TOKEN(TK_DIVEQ); - continue; - case _SC('>'): - NEXT(); - RETURN_TOKEN(TK_ATTR_CLOSE); - continue; - default: - RETURN_TOKEN('/'); - } - case _SC('='): - NEXT(); - if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('=') } - else { NEXT(); RETURN_TOKEN(TK_EQ); } - case _SC('<'): - NEXT(); - if ( CUR_CHAR == _SC('=') ) { NEXT(); RETURN_TOKEN(TK_LE) } - else if ( CUR_CHAR == _SC('-') ) { NEXT(); RETURN_TOKEN(TK_NEWSLOT); } - else if ( CUR_CHAR == _SC('<') ) { NEXT(); RETURN_TOKEN(TK_SHIFTL); } - else if ( CUR_CHAR == _SC('/') ) { NEXT(); RETURN_TOKEN(TK_ATTR_OPEN); } - //else if ( CUR_CHAR == _SC('[') ) { NEXT(); ReadMultilineString(); RETURN_TOKEN(TK_STRING_LITERAL); } - else { RETURN_TOKEN('<') } - case _SC('>'): - NEXT(); - if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_GE);} - else if(CUR_CHAR == _SC('>')){ - NEXT(); - if(CUR_CHAR == _SC('>')){ - NEXT(); - RETURN_TOKEN(TK_USHIFTR); - } - RETURN_TOKEN(TK_SHIFTR); - } - else { RETURN_TOKEN('>') } - case _SC('!'): - NEXT(); - if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('!')} - else { NEXT(); RETURN_TOKEN(TK_NE); } - case _SC('@'): { - int stype; - NEXT(); - if(CUR_CHAR != _SC('"')) - Error(_SC("string expected")); - if((stype=ReadString('"',true))!=-1) { - RETURN_TOKEN(stype); - } - Error(_SC("error parsing the string")); - } - case _SC('"'): - case _SC('\''): { - int stype; - if((stype=ReadString(CUR_CHAR,false))!=-1){ - RETURN_TOKEN(stype); - } - Error(_SC("error parsing the string")); - } - case _SC('{'): case _SC('}'): case _SC('('): case _SC(')'): case _SC('['): case _SC(']'): - case _SC(';'): case _SC(','): case _SC('?'): case _SC('^'): case _SC('~'): - {int ret = CUR_CHAR; - NEXT(); RETURN_TOKEN(ret); } - case _SC('.'): - NEXT(); - if (CUR_CHAR != _SC('.')){ RETURN_TOKEN('.') } - NEXT(); - if (CUR_CHAR != _SC('.')){ Error(_SC("invalid token '..'")); } - NEXT(); - RETURN_TOKEN(TK_VARPARAMS); - case _SC('&'): - NEXT(); - if (CUR_CHAR != _SC('&')){ RETURN_TOKEN('&') } - else { NEXT(); RETURN_TOKEN(TK_AND); } - case _SC('|'): - NEXT(); - if (CUR_CHAR != _SC('|')){ RETURN_TOKEN('|') } - else { NEXT(); RETURN_TOKEN(TK_OR); } - case _SC(':'): - NEXT(); - if (CUR_CHAR != _SC(':')){ RETURN_TOKEN(':') } - else { NEXT(); RETURN_TOKEN(TK_DOUBLE_COLON); } - case _SC('*'): - NEXT(); - if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MULEQ);} - else RETURN_TOKEN('*'); - case _SC('%'): - NEXT(); - if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MODEQ);} - else RETURN_TOKEN('%'); - case _SC('-'): - NEXT(); - if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MINUSEQ);} - else if (CUR_CHAR == _SC('-')){ NEXT(); RETURN_TOKEN(TK_MINUSMINUS);} - else RETURN_TOKEN('-'); - case _SC('+'): - NEXT(); - if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_PLUSEQ);} - else if (CUR_CHAR == _SC('+')){ NEXT(); RETURN_TOKEN(TK_PLUSPLUS);} - else RETURN_TOKEN('+'); - case SQUIRREL_EOB: - return 0; - default:{ - if (scisdigit(CUR_CHAR)) { - int ret = ReadNumber(); - RETURN_TOKEN(ret); - } - else if (scisalpha(CUR_CHAR) || CUR_CHAR == _SC('_')) { - int t = ReadID(); - RETURN_TOKEN(t); - } - else { - int c = CUR_CHAR; - if (sciscntrl(c)) Error(_SC("unexpected character(control)")); - NEXT(); - RETURN_TOKEN(c); - } - RETURN_TOKEN(0); - } - } - } - return 0; -} - -int SQLexer::GetIDType(SQChar *s) -{ - SQObjectPtr t; - if(_keywords->Get(SQString::Create(_sharedstate, s), t)) { - return int(_integer(t)); - } - return TK_IDENTIFIER; -} - - -int SQLexer::ReadString(int ndelim,bool verbatim) -{ - INIT_TEMP_STRING(); - NEXT(); - if(IS_EOB()) return -1; - for(;;) { - while(CUR_CHAR != ndelim) { - switch(CUR_CHAR) { - case SQUIRREL_EOB: - Error(_SC("unfinished string")); - return -1; - case _SC('\n'): - if(!verbatim) Error(_SC("newline in a constant")); - APPEND_CHAR(CUR_CHAR); NEXT(); - break; - case _SC('\\'): - if(verbatim) { - APPEND_CHAR('\\'); NEXT(); - } - else { - NEXT(); - switch(CUR_CHAR) { - case _SC('x'): NEXT(); { - if(!isxdigit(CUR_CHAR)) Error(_SC("hexadecimal number expected")); - const int maxdigits = 4; - SQChar temp[maxdigits+1]; - int n = 0; - while(isxdigit(CUR_CHAR) && n < maxdigits) { - temp[n] = CUR_CHAR; - n++; - NEXT(); - } - temp[n] = 0; - SQChar *sTemp; - APPEND_CHAR((SQChar)scstrtoul(temp,&sTemp,16)); - } - break; - case _SC('t'): APPEND_CHAR(_SC('\t')); NEXT(); break; - case _SC('a'): APPEND_CHAR(_SC('\a')); NEXT(); break; - case _SC('b'): APPEND_CHAR(_SC('\b')); NEXT(); break; - case _SC('n'): APPEND_CHAR(_SC('\n')); NEXT(); break; - case _SC('r'): APPEND_CHAR(_SC('\r')); NEXT(); break; - case _SC('v'): APPEND_CHAR(_SC('\v')); NEXT(); break; - case _SC('f'): APPEND_CHAR(_SC('\f')); NEXT(); break; - case _SC('0'): APPEND_CHAR(_SC('\0')); NEXT(); break; - case _SC('\\'): APPEND_CHAR(_SC('\\')); NEXT(); break; - case _SC('"'): APPEND_CHAR(_SC('"')); NEXT(); break; - case _SC('\''): APPEND_CHAR(_SC('\'')); NEXT(); break; - default: - Error(_SC("unrecognised escaper char")); - break; - } - } - break; - default: - APPEND_CHAR(CUR_CHAR); - NEXT(); - } - } - NEXT(); - if(verbatim && CUR_CHAR == '"') { //double quotation - APPEND_CHAR(CUR_CHAR); - NEXT(); - } - else { - break; - } - } - TERMINATE_BUFFER(); - int len = _longstr.size()-1; - if(ndelim == _SC('\'')) { - if(len == 0) Error(_SC("empty constant")); - if(len > 1) Error(_SC("constant too long")); - _nvalue = _longstr[0]; - return TK_INTEGER; - } - _svalue = &_longstr[0]; - return TK_STRING_LITERAL; -} - -int isexponent(int c) { return c == 'e' || c=='E'; } - -int SQLexer::ReadNumber() -{ -#define TINT 1 -#define TFLOAT 2 -#define THEX 3 -#define TSCIENTIFIC 4 - int type = TINT, firstchar = CUR_CHAR; - bool isfloat = false; - SQChar *sTemp; - INIT_TEMP_STRING(); - NEXT(); - if(firstchar == _SC('0') && toupper(CUR_CHAR) == _SC('X')) { - NEXT(); - type = THEX; - while(isxdigit(CUR_CHAR)) { - APPEND_CHAR(CUR_CHAR); - NEXT(); - } - if(_longstr.size() > 8) Error(_SC("Hex number over 8 digits")); - } - else { - APPEND_CHAR(firstchar); - while (CUR_CHAR == _SC('.') || scisdigit(CUR_CHAR) || isexponent(CUR_CHAR)) { - if(CUR_CHAR == _SC('.')) type = TFLOAT; - if(isexponent(CUR_CHAR)) { - if(type != TFLOAT) Error(_SC("invalid numeric format")); - type = TSCIENTIFIC; - APPEND_CHAR(CUR_CHAR); - NEXT(); - if(CUR_CHAR == '+' || CUR_CHAR == '-'){ - APPEND_CHAR(CUR_CHAR); - NEXT(); - } - if(!scisdigit(CUR_CHAR)) Error(_SC("exponent expected")); - } - - APPEND_CHAR(CUR_CHAR); - NEXT(); - } - } - TERMINATE_BUFFER(); - switch(type) { - case TSCIENTIFIC: - case TFLOAT: - _fvalue = (SQFloat)scstrtod(&_longstr[0],&sTemp); - return TK_FLOAT; - case TINT: - _nvalue = (SQInteger)scatoi(&_longstr[0]); - return TK_INTEGER; - case THEX: - *((unsigned long *)&_nvalue) = scstrtoul(&_longstr[0],&sTemp,16); - return TK_INTEGER; - } - return 0; -} - -int SQLexer::ReadID() -{ - int res, size = 0; - INIT_TEMP_STRING(); - do { - APPEND_CHAR(CUR_CHAR); - NEXT(); - } while(scisalnum(CUR_CHAR) || CUR_CHAR == _SC('_')); - TERMINATE_BUFFER(); - res = GetIDType(&_longstr[0]); - if(res == TK_IDENTIFIER) { - _svalue = &_longstr[0]; - } - return res; -} +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include +#include +#include "sqtable.h" +#include "sqstring.h" +#include "sqcompiler.h" +#include "sqlexer.h" + +#define CUR_CHAR (_currdata) +#define RETURN_TOKEN(t) { _prevtoken = _curtoken; _curtoken = t; return t;} +#define IS_EOB() (CUR_CHAR <= SQUIRREL_EOB) +#define NEXT() {Next();_currentcolumn++;} +#define INIT_TEMP_STRING() { _longstr.resize(0);} +#define APPEND_CHAR(c) { _longstr.push_back(c);} +#define TERMINATE_BUFFER() {_longstr.push_back(_SC('\0'));} +#define ADD_KEYWORD(key,id) _keywords->NewSlot( SQString::Create(ss, _SC(#key)) ,SQInteger(id)) + +SQLexer::SQLexer(){} +SQLexer::~SQLexer() +{ + _keywords->Release(); +} + +void SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,CompilerErrorFunc efunc,void *ed) +{ + _errfunc = efunc; + _errtarget = ed; + _sharedstate = ss; + _keywords = SQTable::Create(ss, 26); + ADD_KEYWORD(while, TK_WHILE); + ADD_KEYWORD(do, TK_DO); + ADD_KEYWORD(if, TK_IF); + ADD_KEYWORD(else, TK_ELSE); + ADD_KEYWORD(break, TK_BREAK); + ADD_KEYWORD(continue, TK_CONTINUE); + ADD_KEYWORD(return, TK_RETURN); + ADD_KEYWORD(null, TK_NULL); + ADD_KEYWORD(function, TK_FUNCTION); + ADD_KEYWORD(local, TK_LOCAL); + ADD_KEYWORD(for, TK_FOR); + ADD_KEYWORD(foreach, TK_FOREACH); + ADD_KEYWORD(in, TK_IN); + ADD_KEYWORD(typeof, TK_TYPEOF); + ADD_KEYWORD(delegate, TK_DELEGATE); + ADD_KEYWORD(delete, TK_DELETE); + ADD_KEYWORD(try, TK_TRY); + ADD_KEYWORD(catch, TK_CATCH); + ADD_KEYWORD(throw, TK_THROW); + ADD_KEYWORD(clone, TK_CLONE); + ADD_KEYWORD(yield, TK_YIELD); + ADD_KEYWORD(resume, TK_RESUME); + ADD_KEYWORD(switch, TK_SWITCH); + ADD_KEYWORD(case, TK_CASE); + ADD_KEYWORD(default, TK_DEFAULT); + ADD_KEYWORD(this, TK_THIS); + ADD_KEYWORD(parent,TK_PARENT); + ADD_KEYWORD(class,TK_CLASS); + ADD_KEYWORD(extends,TK_EXTENDS); + ADD_KEYWORD(constructor,TK_CONSTRUCTOR); + ADD_KEYWORD(instanceof,TK_INSTANCEOF); + ADD_KEYWORD(vargc,TK_VARGC); + ADD_KEYWORD(vargv,TK_VARGV); + ADD_KEYWORD(true,TK_TRUE); + ADD_KEYWORD(false,TK_FALSE); + + _readf = rg; + _up = up; + _lasttokenline = _currentline = 1; + _currentcolumn = 0; + _prevtoken = -1; + Next(); +} + +void SQLexer::Error(const SQChar *err) +{ + _errfunc(_errtarget,err); +} + +void SQLexer::Next() +{ + SQInteger t = _readf(_up); + if(t > MAX_CHAR) Error(_SC("Invalid character")); + if(t != 0) { + _currdata = t; + return; + } + _currdata = SQUIRREL_EOB; +} + +const SQChar *SQLexer::Tok2Str(SQInteger tok) +{ + SQObjectPtr itr, key, val; + SQInteger nitr; + while((nitr = _keywords->Next(false,itr, key, val)) != -1) { + itr = (SQInteger)nitr; + if(((SQInteger)_integer(val)) == tok) + return _stringval(key); + } + return NULL; +} + +void SQLexer::LexBlockComment() +{ + bool done = false; + while(!done) { + switch(CUR_CHAR) { + case _SC('*'): { NEXT(); if(CUR_CHAR == _SC('/')) { done = true; NEXT(); }}; continue; + case _SC('\n'): _currentline++; NEXT(); continue; + case SQUIRREL_EOB: Error(_SC("missing \"*/\" in comment")); + default: NEXT(); + } + } +} + +SQInteger SQLexer::Lex() +{ + _lasttokenline = _currentline; + while(CUR_CHAR != SQUIRREL_EOB) { + switch(CUR_CHAR){ + case _SC('\t'): case _SC('\r'): case _SC(' '): NEXT(); continue; + case _SC('\n'): + _currentline++; + _prevtoken=_curtoken; + _curtoken=_SC('\n'); + NEXT(); + _currentcolumn=1; + continue; + case _SC('/'): + NEXT(); + switch(CUR_CHAR){ + case _SC('*'): + NEXT(); + LexBlockComment(); + continue; + case _SC('/'): + do { NEXT(); } while (CUR_CHAR != _SC('\n') && (!IS_EOB())); + continue; + case _SC('='): + NEXT(); + RETURN_TOKEN(TK_DIVEQ); + continue; + case _SC('>'): + NEXT(); + RETURN_TOKEN(TK_ATTR_CLOSE); + continue; + default: + RETURN_TOKEN('/'); + } + case _SC('='): + NEXT(); + if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('=') } + else { NEXT(); RETURN_TOKEN(TK_EQ); } + case _SC('<'): + NEXT(); + if ( CUR_CHAR == _SC('=') ) { NEXT(); RETURN_TOKEN(TK_LE) } + else if ( CUR_CHAR == _SC('-') ) { NEXT(); RETURN_TOKEN(TK_NEWSLOT); } + else if ( CUR_CHAR == _SC('<') ) { NEXT(); RETURN_TOKEN(TK_SHIFTL); } + else if ( CUR_CHAR == _SC('/') ) { NEXT(); RETURN_TOKEN(TK_ATTR_OPEN); } + //else if ( CUR_CHAR == _SC('[') ) { NEXT(); ReadMultilineString(); RETURN_TOKEN(TK_STRING_LITERAL); } + else { RETURN_TOKEN('<') } + case _SC('>'): + NEXT(); + if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_GE);} + else if(CUR_CHAR == _SC('>')){ + NEXT(); + if(CUR_CHAR == _SC('>')){ + NEXT(); + RETURN_TOKEN(TK_USHIFTR); + } + RETURN_TOKEN(TK_SHIFTR); + } + else { RETURN_TOKEN('>') } + case _SC('!'): + NEXT(); + if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('!')} + else { NEXT(); RETURN_TOKEN(TK_NE); } + case _SC('@'): { + SQInteger stype; + NEXT(); + if(CUR_CHAR != _SC('"')) + Error(_SC("string expected")); + if((stype=ReadString('"',true))!=-1) { + RETURN_TOKEN(stype); + } + Error(_SC("error parsing the string")); + } + case _SC('"'): + case _SC('\''): { + SQInteger stype; + if((stype=ReadString(CUR_CHAR,false))!=-1){ + RETURN_TOKEN(stype); + } + Error(_SC("error parsing the string")); + } + case _SC('{'): case _SC('}'): case _SC('('): case _SC(')'): case _SC('['): case _SC(']'): + case _SC(';'): case _SC(','): case _SC('?'): case _SC('^'): case _SC('~'): + {SQInteger ret = CUR_CHAR; + NEXT(); RETURN_TOKEN(ret); } + case _SC('.'): + NEXT(); + if (CUR_CHAR != _SC('.')){ RETURN_TOKEN('.') } + NEXT(); + if (CUR_CHAR != _SC('.')){ Error(_SC("invalid token '..'")); } + NEXT(); + RETURN_TOKEN(TK_VARPARAMS); + case _SC('&'): + NEXT(); + if (CUR_CHAR != _SC('&')){ RETURN_TOKEN('&') } + else { NEXT(); RETURN_TOKEN(TK_AND); } + case _SC('|'): + NEXT(); + if (CUR_CHAR != _SC('|')){ RETURN_TOKEN('|') } + else { NEXT(); RETURN_TOKEN(TK_OR); } + case _SC(':'): + NEXT(); + if (CUR_CHAR != _SC(':')){ RETURN_TOKEN(':') } + else { NEXT(); RETURN_TOKEN(TK_DOUBLE_COLON); } + case _SC('*'): + NEXT(); + if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MULEQ);} + else RETURN_TOKEN('*'); + case _SC('%'): + NEXT(); + if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MODEQ);} + else RETURN_TOKEN('%'); + case _SC('-'): + NEXT(); + if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MINUSEQ);} + else if (CUR_CHAR == _SC('-')){ NEXT(); RETURN_TOKEN(TK_MINUSMINUS);} + else RETURN_TOKEN('-'); + case _SC('+'): + NEXT(); + if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_PLUSEQ);} + else if (CUR_CHAR == _SC('+')){ NEXT(); RETURN_TOKEN(TK_PLUSPLUS);} + else RETURN_TOKEN('+'); + case SQUIRREL_EOB: + return 0; + default:{ + if (scisdigit(CUR_CHAR)) { + SQInteger ret = ReadNumber(); + RETURN_TOKEN(ret); + } + else if (scisalpha(CUR_CHAR) || CUR_CHAR == _SC('_')) { + SQInteger t = ReadID(); + RETURN_TOKEN(t); + } + else { + SQInteger c = CUR_CHAR; + if (sciscntrl(c)) Error(_SC("unexpected character(control)")); + NEXT(); + RETURN_TOKEN(c); + } + RETURN_TOKEN(0); + } + } + } + return 0; +} + +SQInteger SQLexer::GetIDType(SQChar *s) +{ + SQObjectPtr t; + if(_keywords->Get(SQString::Create(_sharedstate, s), t)) { + return SQInteger(_integer(t)); + } + return TK_IDENTIFIER; +} + + +SQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim) +{ + INIT_TEMP_STRING(); + NEXT(); + if(IS_EOB()) return -1; + for(;;) { + while(CUR_CHAR != ndelim) { + switch(CUR_CHAR) { + case SQUIRREL_EOB: + Error(_SC("unfinished string")); + return -1; + case _SC('\n'): + if(!verbatim) Error(_SC("newline in a constant")); + APPEND_CHAR(CUR_CHAR); NEXT(); + _currentline++; + break; + case _SC('\\'): + if(verbatim) { + APPEND_CHAR('\\'); NEXT(); + } + else { + NEXT(); + switch(CUR_CHAR) { + case _SC('x'): NEXT(); { + if(!isxdigit(CUR_CHAR)) Error(_SC("hexadecimal number expected")); + const SQInteger maxdigits = 4; + SQChar temp[maxdigits+1]; + SQInteger n = 0; + while(isxdigit(CUR_CHAR) && n < maxdigits) { + temp[n] = CUR_CHAR; + n++; + NEXT(); + } + temp[n] = 0; + SQChar *sTemp; + APPEND_CHAR((SQChar)scstrtoul(temp,&sTemp,16)); + } + break; + case _SC('t'): APPEND_CHAR(_SC('\t')); NEXT(); break; + case _SC('a'): APPEND_CHAR(_SC('\a')); NEXT(); break; + case _SC('b'): APPEND_CHAR(_SC('\b')); NEXT(); break; + case _SC('n'): APPEND_CHAR(_SC('\n')); NEXT(); break; + case _SC('r'): APPEND_CHAR(_SC('\r')); NEXT(); break; + case _SC('v'): APPEND_CHAR(_SC('\v')); NEXT(); break; + case _SC('f'): APPEND_CHAR(_SC('\f')); NEXT(); break; + case _SC('0'): APPEND_CHAR(_SC('\0')); NEXT(); break; + case _SC('\\'): APPEND_CHAR(_SC('\\')); NEXT(); break; + case _SC('"'): APPEND_CHAR(_SC('"')); NEXT(); break; + case _SC('\''): APPEND_CHAR(_SC('\'')); NEXT(); break; + default: + Error(_SC("unrecognised escaper char")); + break; + } + } + break; + default: + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + } + NEXT(); + if(verbatim && CUR_CHAR == '"') { //double quotation + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + else { + break; + } + } + TERMINATE_BUFFER(); + SQInteger len = _longstr.size()-1; + if(ndelim == _SC('\'')) { + if(len == 0) Error(_SC("empty constant")); + if(len > 1) Error(_SC("constant too long")); + _nvalue = _longstr[0]; + return TK_INTEGER; + } + _svalue = &_longstr[0]; + return TK_STRING_LITERAL; +} + +SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; } + +SQInteger SQLexer::ReadNumber() +{ +#define TINT 1 +#define TFLOAT 2 +#define THEX 3 +#define TSCIENTIFIC 4 + SQInteger type = TINT, firstchar = CUR_CHAR; + bool isfloat = false; + SQChar *sTemp; + INIT_TEMP_STRING(); + NEXT(); + if(firstchar == _SC('0') && toupper(CUR_CHAR) == _SC('X')) { + NEXT(); + type = THEX; + while(isxdigit(CUR_CHAR)) { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + if(_longstr.size() > 8) Error(_SC("Hex number over 8 digits")); + } + else { + APPEND_CHAR(firstchar); + while (CUR_CHAR == _SC('.') || scisdigit(CUR_CHAR) || isexponent(CUR_CHAR)) { + if(CUR_CHAR == _SC('.')) type = TFLOAT; + if(isexponent(CUR_CHAR)) { + if(type != TFLOAT) Error(_SC("invalid numeric format")); + type = TSCIENTIFIC; + APPEND_CHAR(CUR_CHAR); + NEXT(); + if(CUR_CHAR == '+' || CUR_CHAR == '-'){ + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + if(!scisdigit(CUR_CHAR)) Error(_SC("exponent expected")); + } + + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + } + TERMINATE_BUFFER(); + switch(type) { + case TSCIENTIFIC: + case TFLOAT: + _fvalue = (SQFloat)scstrtod(&_longstr[0],&sTemp); + return TK_FLOAT; + case TINT: + _nvalue = (SQInteger)scstrtol(&_longstr[0],&sTemp,10); + return TK_INTEGER; + case THEX: + *((SQUnsignedInteger *)&_nvalue) = scstrtoul(&_longstr[0],&sTemp,16); + return TK_INTEGER; + } + return 0; +} + +SQInteger SQLexer::ReadID() +{ + SQInteger res, size = 0; + INIT_TEMP_STRING(); + do { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } while(scisalnum(CUR_CHAR) || CUR_CHAR == _SC('_')); + TERMINATE_BUFFER(); + res = GetIDType(&_longstr[0]); + if(res == TK_IDENTIFIER) { + _svalue = &_longstr[0]; + } + return res; +} diff --git a/src/squirrel/squirrel/sqlexer.h b/src/squirrel/squirrel/sqlexer.h index 918242082..750bbd0df 100644 --- a/src/squirrel/squirrel/sqlexer.h +++ b/src/squirrel/squirrel/sqlexer.h @@ -1,47 +1,47 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQLEXER_H_ -#define _SQLEXER_H_ - -#define MAX_STRING 2024 - - - -struct SQLexer -{ - SQLexer(); - ~SQLexer(); - void Init(SQSharedState *ss,SQLEXREADFUNC rg,SQUserPointer up,CompilerErrorFunc efunc,void *ed); - void Error(const SQChar *err); - int Lex(); - const SQChar *Tok2Str(int tok); -private: - int GetIDType(SQChar *s); - int ReadString(int ndelim,bool verbatim); - int ReadNumber(); - void LexBlockComment(); - int ReadID(); - void Next(); - int _curtoken; - SQTable *_keywords; -public: - int _prevtoken; - int _currentline; - int _lasttokenline; - int _currentcolumn; - const SQChar *_svalue; - SQInteger _nvalue; - SQFloat _fvalue; - SQLEXREADFUNC _readf; - SQUserPointer _up; -#ifdef _UNICODE - SQChar _currdata; -#else - unsigned char _currdata; -#endif - SQSharedState *_sharedstate; - sqvector _longstr; - CompilerErrorFunc _errfunc; - void *_errtarget; -}; - -#endif +/* see copyright notice in squirrel.h */ +#ifndef _SQLEXER_H_ +#define _SQLEXER_H_ + +#define MAX_STRING 2024 + + + +struct SQLexer +{ + SQLexer(); + ~SQLexer(); + void Init(SQSharedState *ss,SQLEXREADFUNC rg,SQUserPointer up,CompilerErrorFunc efunc,void *ed); + void Error(const SQChar *err); + SQInteger Lex(); + const SQChar *Tok2Str(SQInteger tok); +private: + SQInteger GetIDType(SQChar *s); + SQInteger ReadString(SQInteger ndelim,bool verbatim); + SQInteger ReadNumber(); + void LexBlockComment(); + SQInteger ReadID(); + void Next(); + SQInteger _curtoken; + SQTable *_keywords; +public: + SQInteger _prevtoken; + SQInteger _currentline; + SQInteger _lasttokenline; + SQInteger _currentcolumn; + const SQChar *_svalue; + SQInteger _nvalue; + SQFloat _fvalue; + SQLEXREADFUNC _readf; + SQUserPointer _up; +#ifdef _UNICODE + SQChar _currdata; +#else + unsigned char _currdata; +#endif + SQSharedState *_sharedstate; + sqvector _longstr; + CompilerErrorFunc _errfunc; + void *_errtarget; +}; + +#endif diff --git a/src/squirrel/squirrel/sqmem.cpp b/src/squirrel/squirrel/sqmem.cpp index b955a29f0..520f7eb76 100644 --- a/src/squirrel/squirrel/sqmem.cpp +++ b/src/squirrel/squirrel/sqmem.cpp @@ -1,9 +1,9 @@ -/* - see copyright notice in squirrel.h -*/ -#include "sqpcheader.h" -void *sq_vm_malloc(unsigned int size){ return malloc(size); } - -void *sq_vm_realloc(void *p, unsigned int oldsize, unsigned int size){ return realloc(p, size); } - -void sq_vm_free(void *p, unsigned int size){ free(p); } +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +void *sq_vm_malloc(SQUnsignedInteger size){ return malloc(size); } + +void *sq_vm_realloc(void *p, SQUnsignedInteger oldsize, SQUnsignedInteger size){ return realloc(p, size); } + +void sq_vm_free(void *p, SQUnsignedInteger size){ free(p); } diff --git a/src/squirrel/squirrel/sqobject.cpp b/src/squirrel/squirrel/sqobject.cpp index 209c1e5bb..92499c23e 100644 --- a/src/squirrel/squirrel/sqobject.cpp +++ b/src/squirrel/squirrel/sqobject.cpp @@ -1,464 +1,502 @@ -/* - see copyright notice in squirrel.h -*/ -#include "sqpcheader.h" -#include "sqvm.h" -#include "sqstring.h" -#include "sqarray.h" -#include "sqtable.h" -#include "squserdata.h" -#include "sqfuncproto.h" -#include "sqclass.h" -#include "sqclosure.h" - -SQString *SQString::Create(SQSharedState *ss,const SQChar *s,int len) -{ - SQString *str=ADD_STRING(ss,s,len); - str->_sharedstate=ss; - return str; -} - -void SQString::Release() -{ - REMOVE_STRING(_sharedstate,this); -} - -unsigned int TranslateIndex(const SQObjectPtr &idx) -{ - switch(type(idx)){ - case OT_NULL: - return 0; - case OT_INTEGER: - return (unsigned int)_integer(idx); - } - assert(0); - return 0; -} - -bool SQDelegable::GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res) { - if(_delegate) { - return _delegate->Get((*_ss(this)->_metamethods)[mm],res); - } - return false; -} - -bool SQGenerator::Yield(SQVM *v) -{ - if(_state==eSuspended) { v->Raise_Error(_SC("internal vm error, yielding dead generator")); return false;} - if(_state==eDead) { v->Raise_Error(_SC("internal vm error, yielding a dead generator")); return false; } - int size = v->_top-v->_stackbase; - _ci=*v->ci; - _stack.resize(size); - for(int n =0; n_stack[v->_stackbase+n]; - v->_stack[v->_stackbase+n] = _null_; - } - int nvargs = v->ci->_vargs.size; - int vargsbase = v->ci->_vargs.base; - for(int j = nvargs - 1; j >= 0; j--) { - _vargsstack.push_back(v->_vargsstack[vargsbase+j]); - } - _ci._generator=_null_; - for(int i=0;i<_ci._etraps;i++) { - _etraps.push_back(v->_etraps.top()); - v->_etraps.pop_back(); - } - _state=eSuspended; - return true; -} - -bool SQGenerator::Resume(SQVM *v,int target) -{ - int size=_stack.size(); - if(_state==eDead){ v->Raise_Error(_SC("resuming dead generator")); return false; } - if(_state==eRunning){ v->Raise_Error(_SC("resuming active generator")); return false; } - int prevtop=v->_top-v->_stackbase; - PUSH_CALLINFO(v,_ci); - int oldstackbase=v->_stackbase; - v->_stackbase=v->_top; - v->ci->_target=target; - v->ci->_generator=SQObjectPtr(this); - v->ci->_vargs.size = _vargsstack.size(); - - for(int i=0;i<_ci._etraps;i++) { - v->_etraps.push_back(_etraps.top()); - _etraps.pop_back(); - } - for(int n =0; n_stack[v->_stackbase+n] = _stack._vals[n]; - _stack._vals[0] = _null_; - } - while(_vargsstack.size()) { - v->_vargsstack.push_back(_vargsstack.back()); - _vargsstack.pop_back(); - } - v->ci->_vargs.base = v->_vargsstack.size() - v->ci->_vargs.size; - v->_top=v->_stackbase+size; - v->ci->_prevtop=prevtop; - v->ci->_prevstkbase=v->_stackbase-oldstackbase; - _state=eRunning; - return true; -} - -void SQArray::Extend(const SQArray *a){ - int xlen; - if((xlen=a->Size())) - for(int i=0;i_values[i]); -} - -const SQChar* SQFunctionProto::GetLocal(SQVM *vm,unsigned int stackbase,unsigned int nseq,unsigned int nop) -{ - unsigned int nvars=_localvarinfos.size(); - const SQChar *res=NULL; - if(nvars>=nseq){ - for(unsigned int i=0;i=nop) - { - if(nseq==0){ - vm->Push(vm->_stack[stackbase+_localvarinfos[i]._pos]); - res=_stringval(_localvarinfos[i]._name); - break; - } - nseq--; - } - } - } - return res; -} - -int SQFunctionProto::GetLine(SQInstruction *curr) -{ - int op=(curr-_instructions._vals); - int line=_lineinfos[0]._line; - for(unsigned int i=1;i<_lineinfos.size();i++){ - if(_lineinfos[i]._op>=op) - return line; - line=_lineinfos[i]._line; - } - return line; -} - -//#define _ERROR_TRAP() error_trap: -#define _CHECK_IO(exp) { if(!exp)return false; } -bool SafeWrite(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUserPointer dest,int size) -{ - if(write(up,dest,size) != size) { - v->Raise_Error(_SC("io error (write function failure)")); - return false; - } - return true; -} - -bool SafeRead(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQUserPointer dest,int size) -{ - if(size && read(up,dest,size) != size) { - v->Raise_Error(_SC("io error, read function failure, the origin stream could be corrupted/trucated")); - return false; - } - return true; -} - -bool WriteTag(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,int tag) -{ - return SafeWrite(v,write,up,&tag,sizeof(tag)); -} - -bool CheckTag(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,int tag) -{ - int t; - _CHECK_IO(SafeRead(v,read,up,&t,sizeof(t))); - if(t != tag){ - v->Raise_Error(_SC("invalid or corrupted closure stream")); - return false; - } - return true; -} - -bool WriteObject(HSQUIRRELVM v,SQUserPointer up,SQWRITEFUNC write,SQObjectPtr &o) -{ - _CHECK_IO(SafeWrite(v,write,up,&type(o),sizeof(SQObjectType))); - switch(type(o)){ - case OT_STRING: - _CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(SQInteger))); - _CHECK_IO(SafeWrite(v,write,up,_stringval(o),rsl(_string(o)->_len))); - break; - case OT_INTEGER: - _CHECK_IO(SafeWrite(v,write,up,&_integer(o),sizeof(SQInteger)));break; - case OT_FLOAT: - _CHECK_IO(SafeWrite(v,write,up,&_float(o),sizeof(SQFloat)));break; - case OT_NULL: - break; - default: - v->Raise_Error(_SC("cannot serialize a %s"),GetTypeName(o)); - return false; - } - return true; -} - -bool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o) -{ - SQObjectType t; - _CHECK_IO(SafeRead(v,read,up,&t,sizeof(SQObjectType))); - switch(t){ - case OT_STRING:{ - int len; - _CHECK_IO(SafeRead(v,read,up,&len,sizeof(SQInteger))); - _CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(rsl(len)),rsl(len))); - o=SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1),len); - } - break; - case OT_INTEGER:{ - SQInteger i; - _CHECK_IO(SafeRead(v,read,up,&i,sizeof(SQInteger))); o = i; break; - } - case OT_FLOAT:{ - SQFloat f; - _CHECK_IO(SafeRead(v,read,up,&f,sizeof(SQFloat))); o = f; break; - } - case OT_NULL: - o=_null_; - break; - default: - v->Raise_Error(_SC("cannot serialize a %s"),IdType2Name(t)); - return false; - } - return true; -} - -bool SQClosure::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write) -{ - _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_HEAD)); - _CHECK_IO(WriteTag(v,write,up,sizeof(SQChar))); - _CHECK_IO(_funcproto(_function)->Save(v,up,write)); - _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_TAIL)); - return true; -} - -bool SQClosure::Load(SQVM *v,SQUserPointer up,SQREADFUNC read) -{ - _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_HEAD)); - _CHECK_IO(CheckTag(v,read,up,sizeof(SQChar))); - _CHECK_IO(_funcproto(_function)->Load(v,up,read)); - _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_TAIL)); - return true; -} - -bool SQFunctionProto::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write) -{ - int i,nsize=_literals.size(); - _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); - _CHECK_IO(WriteObject(v,up,write,_sourcename)); - _CHECK_IO(WriteObject(v,up,write,_name)); - _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); - _CHECK_IO(SafeWrite(v,write,up,&nsize,sizeof(nsize))); - for(i=0;iSave(v,up,write)); - } - _CHECK_IO(SafeWrite(v,write,up,&_stacksize,sizeof(_stacksize))); - _CHECK_IO(SafeWrite(v,write,up,&_bgenerator,sizeof(_bgenerator))); - _CHECK_IO(SafeWrite(v,write,up,&_varparams,sizeof(_varparams))); - return true; -} - -bool SQFunctionProto::Load(SQVM *v,SQUserPointer up,SQREADFUNC read) -{ - int i, nsize = _literals.size(); - SQObjectPtr o; - _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); - _CHECK_IO(ReadObject(v, up, read, _sourcename)); - _CHECK_IO(ReadObject(v, up, read, _name)); - _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); - _CHECK_IO(SafeRead(v,read,up, &nsize, sizeof(nsize))); - for(i = 0;i < nsize; i++){ - _CHECK_IO(ReadObject(v, up, read, o)); - _literals.push_back(o); - } - _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); - _CHECK_IO(SafeRead(v,read,up, &nsize, sizeof(nsize))); - for(i = 0; i < nsize; i++){ - _CHECK_IO(ReadObject(v, up, read, o)); - _parameters.push_back(o); - } - _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); - _CHECK_IO(SafeRead(v,read,up,&nsize,sizeof(nsize))); - for(i = 0; i < nsize; i++){ - unsigned int type; - SQObjectPtr name; - _CHECK_IO(SafeRead(v,read,up, &type, sizeof(unsigned int))); - _CHECK_IO(ReadObject(v, up, read, o)); - _CHECK_IO(ReadObject(v, up, read, name)); - _outervalues.push_back(SQOuterVar(name,o, (SQOuterType)type)); - } - _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); - _CHECK_IO(SafeRead(v,read,up,&nsize, sizeof(nsize))); - for(i = 0; i < nsize; i++){ - SQLocalVarInfo lvi; - _CHECK_IO(ReadObject(v, up, read, lvi._name)); - _CHECK_IO(SafeRead(v,read,up, &lvi._pos, sizeof(unsigned int))); - _CHECK_IO(SafeRead(v,read,up, &lvi._start_op, sizeof(unsigned int))); - _CHECK_IO(SafeRead(v,read,up, &lvi._end_op, sizeof(unsigned int))); - _localvarinfos.push_back(lvi); - } - _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); - _CHECK_IO(SafeRead(v,read,up, &nsize,sizeof(nsize))); - _lineinfos.resize(nsize); - _CHECK_IO(SafeRead(v,read,up, &_lineinfos[0], sizeof(SQLineInfo)*nsize)); - _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); - _CHECK_IO(SafeRead(v,read,up, &nsize, sizeof(nsize))); - _instructions.resize(nsize); - _CHECK_IO(SafeRead(v,read,up, &_instructions[0], sizeof(SQInstruction)*nsize)); - _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); - _CHECK_IO(SafeRead(v,read,up, &nsize, sizeof(nsize))); - for(i = 0; i < nsize; i++){ - o = SQFunctionProto::Create(); - _CHECK_IO(_funcproto(o)->Load(v, up, read)); - _functions.push_back(o); - } - _CHECK_IO(SafeRead(v,read,up, &_stacksize, sizeof(_stacksize))); - _CHECK_IO(SafeRead(v,read,up, &_bgenerator, sizeof(_bgenerator))); - _CHECK_IO(SafeRead(v,read,up, &_varparams, sizeof(_varparams))); - return true; -} - -#ifndef NO_GARBAGE_COLLECTOR - -#define START_MARK() if(!(_uiRef&MARK_FLAG)){ \ - _uiRef|=MARK_FLAG; - -#define END_MARK() RemoveFromChain(&_sharedstate->_gc_chain, this); \ - AddToChain(chain, this); } - -void SQVM::Mark(SQCollectable **chain) -{ - START_MARK() - SQSharedState::MarkObject(_lasterror,chain); - SQSharedState::MarkObject(_errorhandler,chain); - SQSharedState::MarkObject(_debughook,chain); - SQSharedState::MarkObject(_roottable, chain); - SQSharedState::MarkObject(temp_reg, chain); - for(unsigned int i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); - for(unsigned int j = 0; j < _vargsstack.size(); j++) SQSharedState::MarkObject(_vargsstack[j], chain); - END_MARK() -} - -void SQArray::Mark(SQCollectable **chain) -{ - START_MARK() - int len = _values.size(); - for(int i = 0;i < len; i++) SQSharedState::MarkObject(_values[i], chain); - END_MARK() -} -void SQTable::Mark(SQCollectable **chain) -{ - START_MARK() - if(_delegate) _delegate->Mark(chain); - int len = _numofnodes; - for(int i = 0; i < len; i++){ - SQSharedState::MarkObject(_nodes[i].key, chain); - SQSharedState::MarkObject(_nodes[i].val, chain); - } - END_MARK() -} - -void SQClass::Mark(SQCollectable **chain) -{ - START_MARK() - _members->Mark(chain); - if(_base) _base->Mark(chain); - SQSharedState::MarkObject(_attributes, chain); - for(unsigned int i =0; i< _defaultvalues.size(); i++) { - SQSharedState::MarkObject(_defaultvalues[i].val, chain); - SQSharedState::MarkObject(_defaultvalues[i].attrs, chain); - } - for(unsigned int j =0; j< _methods.size(); j++) { - SQSharedState::MarkObject(_methods[j].val, chain); - SQSharedState::MarkObject(_methods[j].attrs, chain); - } - for(unsigned int k =0; k< _metamethods.size(); k++) { - SQSharedState::MarkObject(_metamethods[k], chain); - } - END_MARK() -} - -void SQInstance::Mark(SQCollectable **chain) -{ - START_MARK() - _class->Mark(chain); - for(unsigned int i =0; i< _values.size(); i++) { - SQSharedState::MarkObject(_values[i], chain); - } - END_MARK() -} - -void SQGenerator::Mark(SQCollectable **chain) -{ - START_MARK() - for(unsigned int i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); - for(unsigned int j = 0; j < _vargsstack.size(); j++) SQSharedState::MarkObject(_vargsstack[j], chain); - SQSharedState::MarkObject(_closure, chain); - END_MARK() -} - -void SQClosure::Mark(SQCollectable **chain) -{ - START_MARK() - for(unsigned int i = 0; i < _outervalues.size(); i++) SQSharedState::MarkObject(_outervalues[i], chain); - END_MARK() -} - -void SQNativeClosure::Mark(SQCollectable **chain) -{ - START_MARK() - for(unsigned int i = 0; i < _outervalues.size(); i++) SQSharedState::MarkObject(_outervalues[i], chain); - END_MARK() -} - -void SQUserData::Mark(SQCollectable **chain){ - START_MARK() - if(_delegate) _delegate->Mark(chain); - END_MARK() -} - -void SQCollectable::UnMark() { _uiRef&=~MARK_FLAG; } - -#endif - +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqstring.h" +#include "sqarray.h" +#include "sqtable.h" +#include "squserdata.h" +#include "sqfuncproto.h" +#include "sqclass.h" +#include "sqclosure.h" + +SQString *SQString::Create(SQSharedState *ss,const SQChar *s,SQInteger len) +{ + SQString *str=ADD_STRING(ss,s,len); + str->_sharedstate=ss; + return str; +} + +void SQString::Release() +{ + REMOVE_STRING(_sharedstate,this); +} + +SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx) +{ + switch(type(idx)){ + case OT_NULL: + return 0; + case OT_INTEGER: + return (SQUnsignedInteger)_integer(idx); + } + assert(0); + return 0; +} + +SQWeakRef *SQRefCounted::GetWeakRef(SQObjectType type) +{ + if(!_weakref) { + sq_new(_weakref,SQWeakRef); + _weakref->_obj._type = type; + _weakref->_obj._unVal.pRefCounted = this; + } + return _weakref; +} + +SQRefCounted::~SQRefCounted() +{ + if(_weakref) { + _weakref->_obj._type = OT_NULL; + _weakref->_obj._unVal.pRefCounted = NULL; + } +} + +void SQWeakRef::Release() { + if(ISREFCOUNTED(_obj._type)) { + _obj._unVal.pRefCounted->_weakref = NULL; + } + sq_delete(this,SQWeakRef); +} + +bool SQDelegable::GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res) { + if(_delegate) { + return _delegate->Get((*_ss(this)->_metamethods)[mm],res); + } + return false; +} + +bool SQDelegable::SetDelegate(SQTable *mt) +{ + SQTable *temp = mt; + while (temp) { + if (temp->_delegate == this) return false; //cycle detected + temp = temp->_delegate; + } + if (mt) __ObjAddRef(mt); + __ObjRelease(_delegate); + _delegate = mt; + return true; +} + +bool SQGenerator::Yield(SQVM *v) +{ + if(_state==eSuspended) { v->Raise_Error(_SC("internal vm error, yielding dead generator")); return false;} + if(_state==eDead) { v->Raise_Error(_SC("internal vm error, yielding a dead generator")); return false; } + SQInteger size = v->_top-v->_stackbase; + _ci=*v->ci; + _stack.resize(size); + for(SQInteger n =0; n_stack[v->_stackbase+n]; + v->_stack[v->_stackbase+n] = _null_; + } + SQInteger nvargs = v->ci->_vargs.size; + SQInteger vargsbase = v->ci->_vargs.base; + for(SQInteger j = nvargs - 1; j >= 0; j--) { + _vargsstack.push_back(v->_vargsstack[vargsbase+j]); + } + _ci._generator=_null_; + for(SQInteger i=0;i<_ci._etraps;i++) { + _etraps.push_back(v->_etraps.top()); + v->_etraps.pop_back(); + } + _state=eSuspended; + return true; +} + +bool SQGenerator::Resume(SQVM *v,SQInteger target) +{ + SQInteger size=_stack.size(); + if(_state==eDead){ v->Raise_Error(_SC("resuming dead generator")); return false; } + if(_state==eRunning){ v->Raise_Error(_SC("resuming active generator")); return false; } + SQInteger prevtop=v->_top-v->_stackbase; + PUSH_CALLINFO(v,_ci); + SQInteger oldstackbase=v->_stackbase; + v->_stackbase=v->_top; + v->ci->_target=target; + v->ci->_generator=SQObjectPtr(this); + v->ci->_vargs.size = _vargsstack.size(); + + for(SQInteger i=0;i<_ci._etraps;i++) { + v->_etraps.push_back(_etraps.top()); + _etraps.pop_back(); + } + for(SQInteger n =0; n_stack[v->_stackbase+n] = _stack._vals[n]; + _stack._vals[0] = _null_; + } + while(_vargsstack.size()) { + v->_vargsstack.push_back(_vargsstack.back()); + _vargsstack.pop_back(); + } + v->ci->_vargs.base = v->_vargsstack.size() - v->ci->_vargs.size; + v->_top=v->_stackbase+size; + v->ci->_prevtop=prevtop; + v->ci->_prevstkbase=v->_stackbase-oldstackbase; + _state=eRunning; + return true; +} + +void SQArray::Extend(const SQArray *a){ + SQInteger xlen; + if((xlen=a->Size())) + for(SQInteger i=0;i_values[i]); +} + +const SQChar* SQFunctionProto::GetLocal(SQVM *vm,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop) +{ + SQUnsignedInteger nvars=_localvarinfos.size(); + const SQChar *res=NULL; + if(nvars>=nseq){ + for(SQUnsignedInteger i=0;i=nop) + { + if(nseq==0){ + vm->Push(vm->_stack[stackbase+_localvarinfos[i]._pos]); + res=_stringval(_localvarinfos[i]._name); + break; + } + nseq--; + } + } + } + return res; +} + +SQInteger SQFunctionProto::GetLine(SQInstruction *curr) +{ + SQInteger op=(curr-_instructions._vals); + SQInteger line=_lineinfos[0]._line; + for(SQUnsignedInteger i=1;i<_lineinfos.size();i++){ + if(_lineinfos[i]._op>=op) + return line; + line=_lineinfos[i]._line; + } + return line; +} + +//#define _ERROR_TRAP() error_trap: +#define _CHECK_IO(exp) { if(!exp)return false; } +bool SafeWrite(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUserPointer dest,SQInteger size) +{ + if(write(up,dest,size) != size) { + v->Raise_Error(_SC("io error (write function failure)")); + return false; + } + return true; +} + +bool SafeRead(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQUserPointer dest,SQInteger size) +{ + if(size && read(up,dest,size) != size) { + v->Raise_Error(_SC("io error, read function failure, the origin stream could be corrupted/trucated")); + return false; + } + return true; +} + +bool WriteTag(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQInteger tag) +{ + return SafeWrite(v,write,up,&tag,sizeof(tag)); +} + +bool CheckTag(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQInteger tag) +{ + SQInteger t; + _CHECK_IO(SafeRead(v,read,up,&t,sizeof(t))); + if(t != tag){ + v->Raise_Error(_SC("invalid or corrupted closure stream")); + return false; + } + return true; +} + +bool WriteObject(HSQUIRRELVM v,SQUserPointer up,SQWRITEFUNC write,SQObjectPtr &o) +{ + _CHECK_IO(SafeWrite(v,write,up,&type(o),sizeof(SQObjectType))); + switch(type(o)){ + case OT_STRING: + _CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(SQInteger))); + _CHECK_IO(SafeWrite(v,write,up,_stringval(o),rsl(_string(o)->_len))); + break; + case OT_INTEGER: + _CHECK_IO(SafeWrite(v,write,up,&_integer(o),sizeof(SQInteger)));break; + case OT_FLOAT: + _CHECK_IO(SafeWrite(v,write,up,&_float(o),sizeof(SQFloat)));break; + case OT_NULL: + break; + default: + v->Raise_Error(_SC("cannot serialize a %s"),GetTypeName(o)); + return false; + } + return true; +} + +bool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o) +{ + SQObjectType t; + _CHECK_IO(SafeRead(v,read,up,&t,sizeof(SQObjectType))); + switch(t){ + case OT_STRING:{ + SQInteger len; + _CHECK_IO(SafeRead(v,read,up,&len,sizeof(SQInteger))); + _CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(rsl(len)),rsl(len))); + o=SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1),len); + } + break; + case OT_INTEGER:{ + SQInteger i; + _CHECK_IO(SafeRead(v,read,up,&i,sizeof(SQInteger))); o = i; break; + } + case OT_FLOAT:{ + SQFloat f; + _CHECK_IO(SafeRead(v,read,up,&f,sizeof(SQFloat))); o = f; break; + } + case OT_NULL: + o=_null_; + break; + default: + v->Raise_Error(_SC("cannot serialize a %s"),IdType2Name(t)); + return false; + } + return true; +} + +bool SQClosure::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write) +{ + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_HEAD)); + _CHECK_IO(WriteTag(v,write,up,sizeof(SQChar))); + _CHECK_IO(_funcproto(_function)->Save(v,up,write)); + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_TAIL)); + return true; +} + +bool SQClosure::Load(SQVM *v,SQUserPointer up,SQREADFUNC read) +{ + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_HEAD)); + _CHECK_IO(CheckTag(v,read,up,sizeof(SQChar))); + _CHECK_IO(_funcproto(_function)->Load(v,up,read)); + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_TAIL)); + return true; +} + +bool SQFunctionProto::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write) +{ + SQInteger i,nsize=_literals.size(); + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(WriteObject(v,up,write,_sourcename)); + _CHECK_IO(WriteObject(v,up,write,_name)); + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeWrite(v,write,up,&nsize,sizeof(nsize))); + for(i=0;iSave(v,up,write)); + } + _CHECK_IO(SafeWrite(v,write,up,&_stacksize,sizeof(_stacksize))); + _CHECK_IO(SafeWrite(v,write,up,&_bgenerator,sizeof(_bgenerator))); + _CHECK_IO(SafeWrite(v,write,up,&_varparams,sizeof(_varparams))); + return true; +} + +bool SQFunctionProto::Load(SQVM *v,SQUserPointer up,SQREADFUNC read) +{ + SQInteger i, nsize = _literals.size(); + SQObjectPtr o; + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(ReadObject(v, up, read, _sourcename)); + _CHECK_IO(ReadObject(v, up, read, _name)); + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, &nsize, sizeof(nsize))); + for(i = 0;i < nsize; i++){ + _CHECK_IO(ReadObject(v, up, read, o)); + _literals.push_back(o); + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, &nsize, sizeof(nsize))); + for(i = 0; i < nsize; i++){ + _CHECK_IO(ReadObject(v, up, read, o)); + _parameters.push_back(o); + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up,&nsize,sizeof(nsize))); + for(i = 0; i < nsize; i++){ + SQUnsignedInteger type; + SQObjectPtr name; + _CHECK_IO(SafeRead(v,read,up, &type, sizeof(SQUnsignedInteger))); + _CHECK_IO(ReadObject(v, up, read, o)); + _CHECK_IO(ReadObject(v, up, read, name)); + _outervalues.push_back(SQOuterVar(name,o, (SQOuterType)type)); + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up,&nsize, sizeof(nsize))); + for(i = 0; i < nsize; i++){ + SQLocalVarInfo lvi; + _CHECK_IO(ReadObject(v, up, read, lvi._name)); + _CHECK_IO(SafeRead(v,read,up, &lvi._pos, sizeof(SQUnsignedInteger))); + _CHECK_IO(SafeRead(v,read,up, &lvi._start_op, sizeof(SQUnsignedInteger))); + _CHECK_IO(SafeRead(v,read,up, &lvi._end_op, sizeof(SQUnsignedInteger))); + _localvarinfos.push_back(lvi); + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, &nsize,sizeof(nsize))); + _lineinfos.resize(nsize); + _CHECK_IO(SafeRead(v,read,up, &_lineinfos[0], sizeof(SQLineInfo)*nsize)); + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, &nsize, sizeof(nsize))); + _instructions.resize(nsize); + _CHECK_IO(SafeRead(v,read,up, &_instructions[0], sizeof(SQInstruction)*nsize)); + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, &nsize, sizeof(nsize))); + for(i = 0; i < nsize; i++){ + o = SQFunctionProto::Create(); + _CHECK_IO(_funcproto(o)->Load(v, up, read)); + _functions.push_back(o); + } + _CHECK_IO(SafeRead(v,read,up, &_stacksize, sizeof(_stacksize))); + _CHECK_IO(SafeRead(v,read,up, &_bgenerator, sizeof(_bgenerator))); + _CHECK_IO(SafeRead(v,read,up, &_varparams, sizeof(_varparams))); + return true; +} + +#ifndef NO_GARBAGE_COLLECTOR + +#define START_MARK() if(!(_uiRef&MARK_FLAG)){ \ + _uiRef|=MARK_FLAG; + +#define END_MARK() RemoveFromChain(&_sharedstate->_gc_chain, this); \ + AddToChain(chain, this); } + +void SQVM::Mark(SQCollectable **chain) +{ + START_MARK() + SQSharedState::MarkObject(_lasterror,chain); + SQSharedState::MarkObject(_errorhandler,chain); + SQSharedState::MarkObject(_debughook,chain); + SQSharedState::MarkObject(_roottable, chain); + SQSharedState::MarkObject(temp_reg, chain); + for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); + for(SQUnsignedInteger j = 0; j < _vargsstack.size(); j++) SQSharedState::MarkObject(_vargsstack[j], chain); + END_MARK() +} + +void SQArray::Mark(SQCollectable **chain) +{ + START_MARK() + SQInteger len = _values.size(); + for(SQInteger i = 0;i < len; i++) SQSharedState::MarkObject(_values[i], chain); + END_MARK() +} +void SQTable::Mark(SQCollectable **chain) +{ + START_MARK() + if(_delegate) _delegate->Mark(chain); + SQInteger len = _numofnodes; + for(SQInteger i = 0; i < len; i++){ + SQSharedState::MarkObject(_nodes[i].key, chain); + SQSharedState::MarkObject(_nodes[i].val, chain); + } + END_MARK() +} + +void SQClass::Mark(SQCollectable **chain) +{ + START_MARK() + _members->Mark(chain); + if(_base) _base->Mark(chain); + SQSharedState::MarkObject(_attributes, chain); + for(SQUnsignedInteger i =0; i< _defaultvalues.size(); i++) { + SQSharedState::MarkObject(_defaultvalues[i].val, chain); + SQSharedState::MarkObject(_defaultvalues[i].attrs, chain); + } + for(SQUnsignedInteger j =0; j< _methods.size(); j++) { + SQSharedState::MarkObject(_methods[j].val, chain); + SQSharedState::MarkObject(_methods[j].attrs, chain); + } + for(SQUnsignedInteger k =0; k< _metamethods.size(); k++) { + SQSharedState::MarkObject(_metamethods[k], chain); + } + END_MARK() +} + +void SQInstance::Mark(SQCollectable **chain) +{ + START_MARK() + _class->Mark(chain); + for(SQUnsignedInteger i =0; i< _nvalues; i++) { + SQSharedState::MarkObject(_values[i], chain); + } + END_MARK() +} + +void SQGenerator::Mark(SQCollectable **chain) +{ + START_MARK() + for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); + for(SQUnsignedInteger j = 0; j < _vargsstack.size(); j++) SQSharedState::MarkObject(_vargsstack[j], chain); + SQSharedState::MarkObject(_closure, chain); + END_MARK() +} + +void SQClosure::Mark(SQCollectable **chain) +{ + START_MARK() + for(SQUnsignedInteger i = 0; i < _outervalues.size(); i++) SQSharedState::MarkObject(_outervalues[i], chain); + END_MARK() +} + +void SQNativeClosure::Mark(SQCollectable **chain) +{ + START_MARK() + for(SQUnsignedInteger i = 0; i < _outervalues.size(); i++) SQSharedState::MarkObject(_outervalues[i], chain); + END_MARK() +} + +void SQUserData::Mark(SQCollectable **chain){ + START_MARK() + if(_delegate) _delegate->Mark(chain); + END_MARK() +} + +void SQCollectable::UnMark() { _uiRef&=~MARK_FLAG; } + +#endif + diff --git a/src/squirrel/squirrel/sqobject.h b/src/squirrel/squirrel/sqobject.h index 9f5823dbf..230ed4c21 100644 --- a/src/squirrel/squirrel/sqobject.h +++ b/src/squirrel/squirrel/sqobject.h @@ -1,299 +1,326 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQOBJECT_H_ -#define _SQOBJECT_H_ - -#include "squtils.h" - -#define SQ_CLOSURESTREAM_HEAD (('S'<<24)|('Q'<<16)|('I'<<8)|('R')) -#define SQ_CLOSURESTREAM_PART (('P'<<24)|('A'<<16)|('R'<<8)|('T')) -#define SQ_CLOSURESTREAM_TAIL (('T'<<24)|('A'<<16)|('I'<<8)|('L')) - -struct SQSharedState; - -enum SQMetaMethod{ - MT_ADD=0, - MT_SUB=1, - MT_MUL=2, - MT_DIV=3, - MT_UNM=4, - MT_MODULO=5, - MT_SET=6, - MT_GET=7, - MT_TYPEOF=8, - MT_NEXTI=9, - MT_CMP=10, - MT_CALL=11, - MT_CLONED=12, - MT_NEWSLOT=13, - MT_DELSLOT=14, - MT_LAST = 15, -}; - -#define MM_ADD _SC("_add") -#define MM_SUB _SC("_sub") -#define MM_MUL _SC("_mul") -#define MM_DIV _SC("_div") -#define MM_UNM _SC("_unm") -#define MM_MODULO _SC("_modulo") -#define MM_SET _SC("_set") -#define MM_GET _SC("_get") -#define MM_TYPEOF _SC("_typeof") -#define MM_NEXTI _SC("_nexti") -#define MM_CMP _SC("_cmp") -#define MM_CALL _SC("_call") -#define MM_CLONED _SC("_cloned") -#define MM_NEWSLOT _SC("_newslot") -#define MM_DELSLOT _SC("_delslot") - -#define MINPOWER2 4 - -struct SQRefCounted -{ - unsigned int _uiRef; - virtual void Release()=0; -}; - -struct SQObjectPtr; - -#define __AddRef(type,unval) if(ISREFCOUNTED(type)) \ - { \ - unval.pRefCounted->_uiRef++; \ - } - -#define __Release(type,unval) if(ISREFCOUNTED(type) && ((--unval.pRefCounted->_uiRef)<=0)) \ - { \ - unval.pRefCounted->Release(); \ - } - -#define __ObjRelease(obj) { \ - if((obj)) { \ - (obj)->_uiRef--; \ - if((obj)->_uiRef == 0) \ - (obj)->Release(); \ - (obj) = NULL; \ - } \ -} - -#define __ObjAddRef(obj) { \ - (obj)->_uiRef++; \ -} - -#define type(obj) ((obj)._type) -#define is_delegable(t) (type(t)&SQOBJECT_DELEGABLE) -#define raw_type(obj) _RAW_TYPE((obj)._type) - -#define _integer(obj) ((obj)._unVal.nInteger) -#define _float(obj) ((obj)._unVal.fFloat) -#define _string(obj) ((obj)._unVal.pString) -#define _table(obj) ((obj)._unVal.pTable) -#define _array(obj) ((obj)._unVal.pArray) -#define _closure(obj) ((obj)._unVal.pClosure) -#define _generator(obj) ((obj)._unVal.pGenerator) -#define _nativeclosure(obj) ((obj)._unVal.pNativeClosure) -#define _userdata(obj) ((obj)._unVal.pUserData) -#define _userpointer(obj) ((obj)._unVal.pUserPointer) -#define _thread(obj) ((obj)._unVal.pThread) -#define _funcproto(obj) ((obj)._unVal.pFunctionProto) -#define _class(obj) ((obj)._unVal.pClass) -#define _instance(obj) ((obj)._unVal.pInstance) -#define _delegable(obj) ((SQDelegable *)(obj)._unVal.pDelegable) -#define _rawval(obj) ((obj)._unVal.pRefCounted) - -#define _stringval(obj) (obj)._unVal.pString->_val -#define _userdataval(obj) (obj)._unVal.pUserData->_val - -#define tofloat(num) ((type(num)==OT_INTEGER)?(SQFloat)_integer(num):_float(num)) -#define tointeger(num) ((type(num)==OT_FLOAT)?(SQInteger)_float(num):_integer(num)) -///////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////// -struct SQObjectPtr : public SQObject -{ - SQObjectPtr() - { - _type=OT_NULL; - _unVal.pUserPointer=NULL; - } - SQObjectPtr(const SQObjectPtr &o) - { - _type=o._type; - _unVal=o._unVal; - __AddRef(_type,_unVal); - } - SQObjectPtr(const SQObject &o) - { - _type=o._type; - _unVal=o._unVal; - __AddRef(_type,_unVal); - } - SQObjectPtr(SQTable *pTable) - { - _type=OT_TABLE; - _unVal.pTable=pTable; - assert(_unVal.pTable); - __AddRef(_type,_unVal); - } - SQObjectPtr(SQClass *pClass) - { - _type=OT_CLASS; - _unVal.pClass=pClass; - assert(_unVal.pClass); - __AddRef(_type,_unVal); - } - SQObjectPtr(SQInstance *pInstance) - { - _type=OT_INSTANCE; - _unVal.pInstance=pInstance; - assert(_unVal.pInstance); - __AddRef(_type,_unVal); - } - SQObjectPtr(SQArray *pArray) - { - _type=OT_ARRAY; - _unVal.pArray=pArray; - assert(_unVal.pArray); - __AddRef(_type,_unVal); - } - SQObjectPtr(SQClosure *pClosure) - { - _type=OT_CLOSURE; - _unVal.pClosure=pClosure; - assert(_unVal.pClosure); - __AddRef(_type,_unVal); - } - SQObjectPtr(SQGenerator *pGenerator) - { - _type=OT_GENERATOR; - _unVal.pGenerator=pGenerator; - assert(_unVal.pGenerator); - __AddRef(_type,_unVal); - } - SQObjectPtr(SQNativeClosure *pNativeClosure) - { - _type=OT_NATIVECLOSURE; - _unVal.pNativeClosure=pNativeClosure; - assert(_unVal.pNativeClosure); - __AddRef(_type,_unVal); - } - SQObjectPtr(SQString *pString) - { - _type=OT_STRING; - _unVal.pString=pString; - assert(_unVal.pString); - __AddRef(_type,_unVal); - } - SQObjectPtr(SQUserData *pUserData) - { - _type=OT_USERDATA; - _unVal.pUserData=pUserData; - assert(_unVal.pUserData); - __AddRef(_type,_unVal); - } - SQObjectPtr(SQVM *pThread) - { - _type=OT_THREAD; - _unVal.pThread=pThread; - assert(_unVal.pThread); - __AddRef(_type,_unVal); - } - SQObjectPtr(SQFunctionProto *pFunctionProto) - { - _type=OT_FUNCPROTO; - _unVal.pFunctionProto=pFunctionProto; - assert(_unVal.pFunctionProto); - __AddRef(_type,_unVal); - } - SQObjectPtr(SQInteger nInteger) - { - _type=OT_INTEGER; - _unVal.nInteger=nInteger; - } - SQObjectPtr(SQFloat fFloat) - { - _type=OT_FLOAT; - _unVal.fFloat=fFloat; - } - SQObjectPtr(bool bBool) - { - _type = OT_BOOL; - _unVal.nInteger = bBool?1:0; - } - SQObjectPtr(SQUserPointer pUserPointer) - { - _type=OT_USERPOINTER; - _unVal.pUserPointer=pUserPointer; - } - ~SQObjectPtr() - { - __Release(_type,_unVal); - } - inline void Null() - { - __Release(_type,_unVal); - _type=OT_NULL; - _unVal.pUserPointer=NULL; - } - inline SQObjectPtr& operator=(const SQObjectPtr& obj) - { - SQObjectType tOldType; - SQObjectValue unOldVal; - tOldType=_type; - unOldVal=_unVal; - _unVal = obj._unVal; - _type = obj._type; - __AddRef(_type,_unVal); - __Release(tOldType,unOldVal); - return *this; - } - inline SQObjectPtr& operator=(const SQObject& obj) - { - SQObjectType tOldType; - SQObjectValue unOldVal; - tOldType=_type; - unOldVal=_unVal; - _unVal = obj._unVal; - _type = obj._type; - __AddRef(_type,_unVal); - __Release(tOldType,unOldVal); - return *this; - } - private: - SQObjectPtr(const SQChar *){} //safety -}; -///////////////////////////////////////////////////////////////////////////////////// -#ifndef NO_GARBAGE_COLLECTOR -#define MARK_FLAG 0x80000000 -struct SQCollectable : public SQRefCounted { - SQCollectable *_next; - SQCollectable *_prev; - SQSharedState *_sharedstate; - virtual void Release()=0; - virtual void Mark(SQCollectable **chain)=0; - void UnMark(); - virtual void Finalize()=0; - static void AddToChain(SQCollectable **chain,SQCollectable *c); - static void RemoveFromChain(SQCollectable **chain,SQCollectable *c); -}; - - -#define ADD_TO_CHAIN(chain,obj) AddToChain(chain,obj) -#define REMOVE_FROM_CHAIN(chain,obj) {if(!(_uiRef&MARK_FLAG))RemoveFromChain(chain,obj);} -#define CHAINABLE_OBJ SQCollectable -#define INIT_CHAIN() {_next=NULL;_prev=NULL;_sharedstate=ss;} -#else - -#define ADD_TO_CHAIN(chain,obj) ((void)0) -#define REMOVE_FROM_CHAIN(chain,obj) ((void)0) -#define CHAINABLE_OBJ SQRefCounted -#define INIT_CHAIN() ((void)0) -#endif - -struct SQDelegable : public CHAINABLE_OBJ { - virtual bool GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res); - SQTable *_delegate; -}; - -unsigned int TranslateIndex(const SQObjectPtr &idx); -typedef sqvector SQObjectPtrVec; -typedef sqvector SQIntVec; - -#endif //_SQOBJECT_H_ +/* see copyright notice in squirrel.h */ +#ifndef _SQOBJECT_H_ +#define _SQOBJECT_H_ + +#include "squtils.h" + +#define SQ_CLOSURESTREAM_HEAD (('S'<<24)|('Q'<<16)|('I'<<8)|('R')) +#define SQ_CLOSURESTREAM_PART (('P'<<24)|('A'<<16)|('R'<<8)|('T')) +#define SQ_CLOSURESTREAM_TAIL (('T'<<24)|('A'<<16)|('I'<<8)|('L')) + +struct SQSharedState; + +enum SQMetaMethod{ + MT_ADD=0, + MT_SUB=1, + MT_MUL=2, + MT_DIV=3, + MT_UNM=4, + MT_MODULO=5, + MT_SET=6, + MT_GET=7, + MT_TYPEOF=8, + MT_NEXTI=9, + MT_CMP=10, + MT_CALL=11, + MT_CLONED=12, + MT_NEWSLOT=13, + MT_DELSLOT=14, + MT_TOSTRING=15, + MT_LAST = 16, +}; + +#define MM_ADD _SC("_add") +#define MM_SUB _SC("_sub") +#define MM_MUL _SC("_mul") +#define MM_DIV _SC("_div") +#define MM_UNM _SC("_unm") +#define MM_MODULO _SC("_modulo") +#define MM_SET _SC("_set") +#define MM_GET _SC("_get") +#define MM_TYPEOF _SC("_typeof") +#define MM_NEXTI _SC("_nexti") +#define MM_CMP _SC("_cmp") +#define MM_CALL _SC("_call") +#define MM_CLONED _SC("_cloned") +#define MM_NEWSLOT _SC("_newslot") +#define MM_DELSLOT _SC("_delslot") +#define MM_TOSTRING _SC("_tostring") + +#define MINPOWER2 4 + +struct SQRefCounted +{ + SQRefCounted() { _uiRef = 0; _weakref = NULL; } + ~SQRefCounted(); + SQWeakRef *GetWeakRef(SQObjectType type); + SQUnsignedInteger _uiRef; + struct SQWeakRef *_weakref; + virtual void Release()=0; +}; + +struct SQWeakRef : SQRefCounted +{ + void Release(); + SQObject _obj; +}; + +#define _realval(o) (type((o)) != OT_WEAKREF?(SQObject)o:_weakref(o)->_obj) + +struct SQObjectPtr; + +#define __AddRef(type,unval) if(ISREFCOUNTED(type)) \ + { \ + unval.pRefCounted->_uiRef++; \ + } + +#define __Release(type,unval) if(ISREFCOUNTED(type) && ((--unval.pRefCounted->_uiRef)<=0)) \ + { \ + unval.pRefCounted->Release(); \ + } + +#define __ObjRelease(obj) { \ + if((obj)) { \ + (obj)->_uiRef--; \ + if((obj)->_uiRef == 0) \ + (obj)->Release(); \ + (obj) = NULL; \ + } \ +} + +#define __ObjAddRef(obj) { \ + (obj)->_uiRef++; \ +} + +#define type(obj) ((obj)._type) +#define is_delegable(t) (type(t)&SQOBJECT_DELEGABLE) +#define raw_type(obj) _RAW_TYPE((obj)._type) + +#define _integer(obj) ((obj)._unVal.nInteger) +#define _float(obj) ((obj)._unVal.fFloat) +#define _string(obj) ((obj)._unVal.pString) +#define _table(obj) ((obj)._unVal.pTable) +#define _array(obj) ((obj)._unVal.pArray) +#define _closure(obj) ((obj)._unVal.pClosure) +#define _generator(obj) ((obj)._unVal.pGenerator) +#define _nativeclosure(obj) ((obj)._unVal.pNativeClosure) +#define _userdata(obj) ((obj)._unVal.pUserData) +#define _userpointer(obj) ((obj)._unVal.pUserPointer) +#define _thread(obj) ((obj)._unVal.pThread) +#define _funcproto(obj) ((obj)._unVal.pFunctionProto) +#define _class(obj) ((obj)._unVal.pClass) +#define _instance(obj) ((obj)._unVal.pInstance) +#define _delegable(obj) ((SQDelegable *)(obj)._unVal.pDelegable) +#define _weakref(obj) ((obj)._unVal.pWeakRef) +#define _refcounted(obj) ((obj)._unVal.pRefCounted) +#define _rawval(obj) ((obj)._unVal.pRefCounted) + +#define _stringval(obj) (obj)._unVal.pString->_val +#define _userdataval(obj) (obj)._unVal.pUserData->_val + +#define tofloat(num) ((type(num)==OT_INTEGER)?(SQFloat)_integer(num):_float(num)) +#define tointeger(num) ((type(num)==OT_FLOAT)?(SQInteger)_float(num):_integer(num)) +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +struct SQObjectPtr : public SQObject +{ + SQObjectPtr() + { + _type=OT_NULL; + _unVal.pUserPointer=NULL; + } + SQObjectPtr(const SQObjectPtr &o) + { + _type=o._type; + _unVal=o._unVal; + __AddRef(_type,_unVal); + } + SQObjectPtr(const SQObject &o) + { + _type=o._type; + _unVal=o._unVal; + __AddRef(_type,_unVal); + } + SQObjectPtr(SQTable *pTable) + { + _type=OT_TABLE; + _unVal.pTable=pTable; + assert(_unVal.pTable); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQClass *pClass) + { + _type=OT_CLASS; + _unVal.pClass=pClass; + assert(_unVal.pClass); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQInstance *pInstance) + { + _type=OT_INSTANCE; + _unVal.pInstance=pInstance; + assert(_unVal.pInstance); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQArray *pArray) + { + _type=OT_ARRAY; + _unVal.pArray=pArray; + assert(_unVal.pArray); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQClosure *pClosure) + { + _type=OT_CLOSURE; + _unVal.pClosure=pClosure; + assert(_unVal.pClosure); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQGenerator *pGenerator) + { + _type=OT_GENERATOR; + _unVal.pGenerator=pGenerator; + assert(_unVal.pGenerator); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQNativeClosure *pNativeClosure) + { + _type=OT_NATIVECLOSURE; + _unVal.pNativeClosure=pNativeClosure; + assert(_unVal.pNativeClosure); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQString *pString) + { + _type=OT_STRING; + _unVal.pString=pString; + assert(_unVal.pString); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQUserData *pUserData) + { + _type=OT_USERDATA; + _unVal.pUserData=pUserData; + assert(_unVal.pUserData); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQVM *pThread) + { + _type=OT_THREAD; + _unVal.pThread=pThread; + assert(_unVal.pThread); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQWeakRef *pWeakRef) + { + _type=OT_WEAKREF; + _unVal.pWeakRef=pWeakRef; + assert(_unVal.pWeakRef); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQFunctionProto *pFunctionProto) + { + _type=OT_FUNCPROTO; + _unVal.pFunctionProto=pFunctionProto; + assert(_unVal.pFunctionProto); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQInteger nInteger) + { + _unVal.pUserPointer=NULL; + _type=OT_INTEGER; + _unVal.nInteger=nInteger; + } + SQObjectPtr(SQFloat fFloat) + { + _unVal.pUserPointer=NULL; + _type=OT_FLOAT; + _unVal.fFloat=fFloat; + } + SQObjectPtr(bool bBool) + { + _unVal.pUserPointer=NULL; + _type = OT_BOOL; + _unVal.nInteger = bBool?1:0; + } + SQObjectPtr(SQUserPointer pUserPointer) + { + _type=OT_USERPOINTER; + _unVal.pUserPointer=pUserPointer; + } + ~SQObjectPtr() + { + __Release(_type,_unVal); + } + inline void Null() + { + __Release(_type,_unVal); + _type=OT_NULL; + _unVal.pUserPointer=NULL; + } + inline SQObjectPtr& operator=(const SQObjectPtr& obj) + { + SQObjectType tOldType; + SQObjectValue unOldVal; + tOldType=_type; + unOldVal=_unVal; + _unVal = obj._unVal; + _type = obj._type; + __AddRef(_type,_unVal); + __Release(tOldType,unOldVal); + return *this; + } + inline SQObjectPtr& operator=(const SQObject& obj) + { + SQObjectType tOldType; + SQObjectValue unOldVal; + tOldType=_type; + unOldVal=_unVal; + _unVal = obj._unVal; + _type = obj._type; + __AddRef(_type,_unVal); + __Release(tOldType,unOldVal); + return *this; + } + private: + SQObjectPtr(const SQChar *){} //safety +}; +///////////////////////////////////////////////////////////////////////////////////// +#ifndef NO_GARBAGE_COLLECTOR +#define MARK_FLAG 0x80000000 +struct SQCollectable : public SQRefCounted { + SQCollectable *_next; + SQCollectable *_prev; + SQSharedState *_sharedstate; + virtual void Release()=0; + virtual void Mark(SQCollectable **chain)=0; + void UnMark(); + virtual void Finalize()=0; + static void AddToChain(SQCollectable **chain,SQCollectable *c); + static void RemoveFromChain(SQCollectable **chain,SQCollectable *c); +}; + + +#define ADD_TO_CHAIN(chain,obj) AddToChain(chain,obj) +#define REMOVE_FROM_CHAIN(chain,obj) {if(!(_uiRef&MARK_FLAG))RemoveFromChain(chain,obj);} +#define CHAINABLE_OBJ SQCollectable +#define INIT_CHAIN() {_next=NULL;_prev=NULL;_sharedstate=ss;} +#else + +#define ADD_TO_CHAIN(chain,obj) ((void)0) +#define REMOVE_FROM_CHAIN(chain,obj) ((void)0) +#define CHAINABLE_OBJ SQRefCounted +#define INIT_CHAIN() ((void)0) +#endif + +struct SQDelegable : public CHAINABLE_OBJ { + bool SetDelegate(SQTable *m); + virtual bool GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res); + SQTable *_delegate; +}; + +SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx); +typedef sqvector SQObjectPtrVec; +typedef sqvector SQIntVec; + +#endif //_SQOBJECT_H_ diff --git a/src/squirrel/squirrel/sqopcodes.h b/src/squirrel/squirrel/sqopcodes.h index dbb7d0c36..f34ca3786 100644 --- a/src/squirrel/squirrel/sqopcodes.h +++ b/src/squirrel/squirrel/sqopcodes.h @@ -1,107 +1,110 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQOPCODES_H_ -#define _SQOPCODES_H_ - -#define MAX_FUNC_STACKSIZE 0xFF -#define MAX_LITERALS 0xFFFFFFFF - -enum BitWiseOP { - BW_AND = 0, - BW_OR = 2, //like ADD - BW_XOR = 3, - BW_SHIFTL = 4, - BW_SHIFTR = 5, - BW_USHIFTR = 6 -}; - -enum CmpOP { - CMP_G = 0, - CMP_GE = 2, //like ADD - CMP_L = 3, - CMP_LE = 4 -}; -enum SQOpcode -{ - _OP_LINE= 0x00, - _OP_LOAD= 0x01, - _OP_TAILCALL= 0x02, - _OP_CALL= 0x03, - _OP_PREPCALL= 0x04, - _OP_PREPCALLK= 0x05, - _OP_GETK= 0x06, - _OP_MOVE= 0x07, - _OP_NEWSLOT= 0x08, - _OP_DELETE= 0x09, - _OP_SET= 0x0A, - _OP_GET= 0x0B, - _OP_EQ= 0x0C, - _OP_NE= 0x0D, - _OP_ARITH= 0x0E, - _OP_BITW= 0x0F, - _OP_RETURN= 0x10, - _OP_LOADNULLS= 0x11, - _OP_LOADROOTTABLE= 0x12, - _OP_DMOVE= 0x13, - _OP_JMP= 0x14, - _OP_JNZ= 0x15, - _OP_JZ= 0x16, - _OP_LOADFREEVAR= 0x17, - _OP_VARGC= 0x18, - _OP_GETVARGV= 0x19, - _OP_NEWTABLE= 0x1A, - _OP_NEWARRAY= 0x1B, - _OP_APPENDARRAY= 0x1C, - _OP_GETPARENT= 0x1D, - _OP_COMPARITH= 0x1E, - _OP_COMPARITHL= 0x1F, - _OP_INC= 0x20, - _OP_INCL= 0x21, - _OP_PINC= 0x22, - _OP_PINCL= 0x23, - _OP_CMP= 0x24, - _OP_EXISTS= 0x25, - _OP_INSTANCEOF= 0x26, - _OP_AND= 0x27, - _OP_OR= 0x28, - _OP_NEG= 0x29, - _OP_NOT= 0x2A, - _OP_BWNOT= 0x2B, - _OP_CLOSURE= 0x2C, - _OP_YIELD= 0x2D, - _OP_RESUME= 0x2E, - _OP_FOREACH= 0x2F, - _OP_DELEGATE= 0x30, - _OP_CLONE= 0x31, - _OP_TYPEOF= 0x32, - _OP_PUSHTRAP= 0x33, - _OP_POPTRAP= 0x34, - _OP_THROW= 0x35, - _OP_CLASS= 0x36, - _OP_NEWSLOTA= 0x37, - _OP_LOADBOOL= 0x38 -}; -struct SQInstructionDesc { - const SQChar *name; -}; - -struct SQInstruction -{ - SQInstruction(){}; - SQInstruction(SQOpcode _op,int a0=0,int a1=0,int a2=0,int a3=0) - { op = _op; - _arg0 = a0;_arg1 = a1; - _arg2 = a2;_arg3 = a3; - } - - - unsigned int _arg1; - unsigned char op; - unsigned char _arg0; - unsigned char _arg2; - unsigned char _arg3; -}; - -#include "squtils.h" -typedef sqvector SQInstructionVec; - -#endif // _SQOPCODES_H_ +/* see copyright notice in squirrel.h */ +#ifndef _SQOPCODES_H_ +#define _SQOPCODES_H_ + +#define MAX_FUNC_STACKSIZE 0xFF +#define MAX_LITERALS 0xFFFFFFFF + +enum BitWiseOP { + BW_AND = 0, + BW_OR = 2, //like ADD + BW_XOR = 3, + BW_SHIFTL = 4, + BW_SHIFTR = 5, + BW_USHIFTR = 6 +}; + +enum CmpOP { + CMP_G = 0, + CMP_GE = 2, //like ADD + CMP_L = 3, + CMP_LE = 4 +}; +enum SQOpcode +{ + _OP_LINE= 0x00, + _OP_LOAD= 0x01, + _OP_DLOAD= 0x02, + _OP_TAILCALL= 0x03, + _OP_CALL= 0x04, + _OP_PREPCALL= 0x05, + _OP_PREPCALLK= 0x06, + _OP_GETK= 0x07, + _OP_MOVE= 0x08, + _OP_NEWSLOT= 0x09, + _OP_DELETE= 0x0A, + _OP_SET= 0x0B, + _OP_GET= 0x0C, + _OP_EQ= 0x0D, + _OP_NE= 0x0E, + _OP_ARITH= 0x0F, + _OP_BITW= 0x10, + _OP_RETURN= 0x11, + _OP_LOADNULLS= 0x12, + _OP_LOADROOTTABLE= 0x13, + _OP_LOADBOOL= 0x14, + _OP_DMOVE= 0x15, + _OP_JMP= 0x16, + _OP_JNZ= 0x17, + _OP_JZ= 0x18, + _OP_LOADFREEVAR= 0x19, + _OP_VARGC= 0x1A, + _OP_GETVARGV= 0x1B, + _OP_NEWTABLE= 0x1C, + _OP_NEWARRAY= 0x1D, + _OP_APPENDARRAY= 0x1E, + _OP_GETPARENT= 0x1F, + _OP_COMPARITH= 0x20, + _OP_COMPARITHL= 0x21, + _OP_INC= 0x22, + _OP_INCL= 0x23, + _OP_PINC= 0x24, + _OP_PINCL= 0x25, + _OP_CMP= 0x26, + _OP_EXISTS= 0x27, + _OP_INSTANCEOF= 0x28, + _OP_AND= 0x29, + _OP_OR= 0x2A, + _OP_NEG= 0x2B, + _OP_NOT= 0x2C, + _OP_BWNOT= 0x2D, + _OP_CLOSURE= 0x2E, + _OP_YIELD= 0x2F, + _OP_RESUME= 0x30, + _OP_FOREACH= 0x31, + _OP_DELEGATE= 0x32, + _OP_CLONE= 0x33, + _OP_TYPEOF= 0x34, + _OP_PUSHTRAP= 0x35, + _OP_POPTRAP= 0x36, + _OP_THROW= 0x37, + _OP_CLASS= 0x38, + _OP_NEWSLOTA= 0x39, + + +}; +struct SQInstructionDesc { + const SQChar *name; +}; + +struct SQInstruction +{ + SQInstruction(){}; + SQInstruction(SQOpcode _op,SQInteger a0=0,SQInteger a1=0,SQInteger a2=0,SQInteger a3=0) + { op = _op; + _arg0 = a0;_arg1 = a1; + _arg2 = a2;_arg3 = a3; + } + + + SQInt32 _arg1; + unsigned char op; + unsigned char _arg0; + unsigned char _arg2; + unsigned char _arg3; +}; + +#include "squtils.h" +typedef sqvector SQInstructionVec; + +#endif // _SQOPCODES_H_ diff --git a/src/squirrel/squirrel/sqpcheader.h b/src/squirrel/squirrel/sqpcheader.h index a3fb037e4..f0e5cf2df 100644 --- a/src/squirrel/squirrel/sqpcheader.h +++ b/src/squirrel/squirrel/sqpcheader.h @@ -1,19 +1,19 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQPCHEADER_H_ -#define _SQPCHEADER_H_ - -#if defined(_MSC_VER) && defined(_DEBUG) -#include -#endif - -#include -#include -#include -#include -#include -//squirrel stuff -#include -#include "sqobject.h" -#include "sqstate.h" - -#endif //_SQPCHEADER_H_ +/* see copyright notice in squirrel.h */ +#ifndef _SQPCHEADER_H_ +#define _SQPCHEADER_H_ + +#if defined(_MSC_VER) && defined(_DEBUG) +#include +#endif + +#include +#include +#include +#include +#include +//squirrel stuff +#include +#include "sqobject.h" +#include "sqstate.h" + +#endif //_SQPCHEADER_H_ diff --git a/src/squirrel/squirrel/sqstate.cpp b/src/squirrel/squirrel/sqstate.cpp index db8e5b28a..e2090953f 100644 --- a/src/squirrel/squirrel/sqstate.cpp +++ b/src/squirrel/squirrel/sqstate.cpp @@ -1,427 +1,431 @@ -/* - see copyright notice in squirrel.h -*/ -#include "sqpcheader.h" -#include "sqopcodes.h" -#include "sqvm.h" -#include "sqfuncproto.h" -#include "sqclosure.h" -#include "sqstring.h" -#include "sqtable.h" -#include "sqarray.h" -#include "squserdata.h" -#include "sqclass.h" - -SQObjectPtr _null_; -SQObjectPtr _true_(true); -SQObjectPtr _false_(false); -SQObjectPtr _one_(1); -SQObjectPtr _minusone_(-1); - -SQSharedState::SQSharedState() -{ - _compilererrorhandler = NULL; - _printfunc = NULL; - _debuginfo = false; -} - -#define newsysstring(s) { \ - _systemstrings->push_back(SQString::Create(this,s)); \ - } - -#define newmetamethod(s) { \ - _metamethods->push_back(SQString::Create(this,s)); \ - _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \ - } - -bool CompileTypemask(SQIntVec &res,const SQChar *typemask) -{ - int i = 0; - - int mask = 0; - while(typemask[i] != 0) { - - switch(typemask[i]){ - case 'o': mask |= _RT_NULL; break; - case 'i': mask |= _RT_INTEGER; break; - case 'f': mask |= _RT_FLOAT; break; - case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break; - case 's': mask |= _RT_STRING; break; - case 't': mask |= _RT_TABLE; break; - case 'a': mask |= _RT_ARRAY; break; - case 'u': mask |= _RT_USERDATA; break; - case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break; - case 'b': mask |= _RT_BOOL; break; - case 'g': mask |= _RT_GENERATOR; break; - case 'p': mask |= _RT_USERPOINTER; break; - case 'v': mask |= _RT_THREAD; break; - case 'x': mask |= _RT_INSTANCE; break; - case 'y': mask |= _RT_CLASS; break; - case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue; - case ' ': i++; continue; //ignores spaces - default: - return false; - } - i++; - if(typemask[i] == '|') { - i++; - if(typemask[i] == 0) - return false; - continue; - } - res.push_back(mask); - mask = 0; - - } - return true; -} - -SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz) -{ - int i=0; - SQTable *t=SQTable::Create(ss,0); - while(funcz[i].name!=0){ - SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f); - nc->_nparamscheck = funcz[i].nparamscheck; - nc->_name = SQString::Create(ss,funcz[i].name); - if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask)) - return NULL; - t->NewSlot(SQString::Create(ss,funcz[i].name),nc); - i++; - } - return t; -} - -void SQSharedState::Init() -{ - _scratchpad=NULL; - _scratchpadsize=0; -#ifndef NO_GARBAGE_COLLECTOR - _gc_chain=NULL; -#endif - sq_new(_stringtable,StringTable); - sq_new(_metamethods,SQObjectPtrVec); - sq_new(_systemstrings,SQObjectPtrVec); - sq_new(_types,SQObjectPtrVec); - _metamethodsmap = SQTable::Create(this,MT_LAST-1); - //adding type strings to avoid memory trashing - //types names - newsysstring(_SC("null")); - newsysstring(_SC("table")); - newsysstring(_SC("array")); - newsysstring(_SC("closure")); - newsysstring(_SC("string")); - newsysstring(_SC("userdata")); - newsysstring(_SC("integer")); - newsysstring(_SC("float")); - newsysstring(_SC("userpointer")); - newsysstring(_SC("function")); - newsysstring(_SC("generator")); - newsysstring(_SC("thread")); - newsysstring(_SC("class")); - newsysstring(_SC("instance")); - newsysstring(_SC("bool")); - //meta methods - newmetamethod(MM_ADD); - newmetamethod(MM_SUB); - newmetamethod(MM_MUL); - newmetamethod(MM_DIV); - newmetamethod(MM_UNM); - newmetamethod(MM_MODULO); - newmetamethod(MM_SET); - newmetamethod(MM_GET); - newmetamethod(MM_TYPEOF); - newmetamethod(MM_NEXTI); - newmetamethod(MM_CMP); - newmetamethod(MM_CALL); - newmetamethod(MM_CLONED); - newmetamethod(MM_NEWSLOT); - newmetamethod(MM_DELSLOT); - - _constructoridx = SQString::Create(this,_SC("constructor")); - _refs_table = SQTable::Create(this,0); - _registry = SQTable::Create(this,0); - _table_default_delegate=CreateDefaultDelegate(this,_table_default_delegate_funcz); - _array_default_delegate=CreateDefaultDelegate(this,_array_default_delegate_funcz); - _string_default_delegate=CreateDefaultDelegate(this,_string_default_delegate_funcz); - _number_default_delegate=CreateDefaultDelegate(this,_number_default_delegate_funcz); - _closure_default_delegate=CreateDefaultDelegate(this,_closure_default_delegate_funcz); - _generator_default_delegate=CreateDefaultDelegate(this,_generator_default_delegate_funcz); - _thread_default_delegate=CreateDefaultDelegate(this,_thread_default_delegate_funcz); - _class_default_delegate=CreateDefaultDelegate(this,_class_default_delegate_funcz); - _instance_default_delegate=CreateDefaultDelegate(this,_instance_default_delegate_funcz); - -} - -SQSharedState::~SQSharedState() -{ - _constructoridx = _null_; - _table(_refs_table)->Finalize(); - _table(_registry)->Finalize(); - _table(_metamethodsmap)->Finalize(); - _refs_table = _null_; - _registry = _null_; - _metamethodsmap = _null_; - while(!_systemstrings->empty()){ - _systemstrings->back()=_null_; - _systemstrings->pop_back(); - } - _thread(_root_vm)->Finalize(); - _root_vm = _null_; - _table_default_delegate=_null_; - _array_default_delegate=_null_; - _string_default_delegate=_null_; - _number_default_delegate=_null_; - _closure_default_delegate=_null_; - _generator_default_delegate=_null_; - _thread_default_delegate=_null_; - _class_default_delegate=_null_; - _instance_default_delegate=_null_; - -#ifndef NO_GARBAGE_COLLECTOR - - - SQCollectable *t=_gc_chain; - SQCollectable *nx=NULL; - while(t){ - t->_uiRef++; - t->Finalize(); - nx=t->_next; - if(--t->_uiRef==0) - t->Release(); - t=nx; - } - assert(_gc_chain==NULL); //just to proove a theory - while(_gc_chain){ - _gc_chain->_uiRef++; - _gc_chain->Release(); - } -#endif - sq_delete(_types,SQObjectPtrVec); - sq_delete(_systemstrings,SQObjectPtrVec); - sq_delete(_metamethods,SQObjectPtrVec); - sq_delete(_stringtable,StringTable); - if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize); -} - - -SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name) -{ - if(type(name) != OT_STRING) - return -1; - SQObjectPtr ret; - if(_table(_metamethodsmap)->Get(name,ret)) { - return _integer(ret); - } - return -1; -} - -#ifndef NO_GARBAGE_COLLECTOR - -void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain) -{ - switch(type(o)){ - case OT_TABLE:_table(o)->Mark(chain);break; - case OT_ARRAY:_array(o)->Mark(chain);break; - case OT_USERDATA:_userdata(o)->Mark(chain);break; - case OT_CLOSURE:_closure(o)->Mark(chain);break; - case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break; - case OT_GENERATOR:_generator(o)->Mark(chain);break; - case OT_THREAD:_thread(o)->Mark(chain);break; - case OT_CLASS:_class(o)->Mark(chain);break; - case OT_INSTANCE:_instance(o)->Mark(chain);break; - } -} - - -int SQSharedState::CollectGarbage(SQVM *vm) -{ - int n=0; - SQCollectable *tchain=NULL; - SQVM *vms=_thread(_root_vm); - - vms->Mark(&tchain); - int x = _table(_thread(_root_vm)->_roottable)->CountUsed(); - MarkObject(_refs_table,&tchain); - MarkObject(_registry,&tchain); - MarkObject(_metamethodsmap,&tchain); - MarkObject(_table_default_delegate,&tchain); - MarkObject(_array_default_delegate,&tchain); - MarkObject(_string_default_delegate,&tchain); - MarkObject(_number_default_delegate,&tchain); - MarkObject(_generator_default_delegate,&tchain); - MarkObject(_thread_default_delegate,&tchain); - MarkObject(_closure_default_delegate,&tchain); - MarkObject(_class_default_delegate,&tchain); - MarkObject(_instance_default_delegate,&tchain); - - SQCollectable *t=_gc_chain; - SQCollectable *nx=NULL; - while(t){ - t->_uiRef++; - t->Finalize(); - nx=t->_next; - if(--t->_uiRef==0) - t->Release(); - t=nx; - n++; - } - - t=tchain; - while(t){ - t->UnMark(); - t=t->_next; - } - _gc_chain=tchain; - int z = _table(_thread(_root_vm)->_roottable)->CountUsed(); - assert(z == x); - return n; -} -#endif - -#ifndef NO_GARBAGE_COLLECTOR -void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c) -{ - c->_prev=NULL; - c->_next=*chain; - if(*chain) (*chain)->_prev=c; - *chain=c; -} - -void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c) -{ - if(c->_prev) c->_prev->_next=c->_next; - else *chain=c->_next; - if(c->_next) - c->_next->_prev=c->_prev; - c->_next=NULL; - c->_prev=NULL; -} -#endif - -SQChar* SQSharedState::GetScratchPad(int size) -{ - int newsize; - if(size>0){ - if(_scratchpadsize>1); - _scratchpad=(SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); - _scratchpadsize=newsize; - - }else if(_scratchpadsize>=(size<<5)){ - newsize=_scratchpadsize>>1; - _scratchpad=(SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); - _scratchpadsize=newsize; - } - } - return _scratchpad; -} - -////////////////////////////////////////////////////////////////////////// -//StringTable -/* -* The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) -* http://www.lua.org/copyright.html#4 -* http://www.lua.org/source/4.0.1/src_lstring.c.html -*/ - -int SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) -{ - int idx = (int)TranslateIndex(refpos); - while(idx < _len){ - outkey = (SQInteger)idx; - outval = SQInteger(_val[idx]); - //return idx for the next iteration - return ++idx; - } - //nothing to iterate anymore - return -1; -} - -StringTable::StringTable() -{ - AllocNodes(4); - _slotused = 0; -} - -StringTable::~StringTable() -{ - SQ_FREE(_strings,sizeof(SQString*)*_numofslots); - _strings=NULL; -} - -void StringTable::AllocNodes(int size) -{ - _numofslots=size; - //_slotused=0; - _strings=(SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots); - memset(_strings,0,sizeof(SQString*)*_numofslots); -} - -SQString *StringTable::Add(const SQChar *news,int len) -{ - if(len<0) - len=scstrlen(news); - unsigned int h=::_hashstr(news,len)&(_numofslots-1); - SQString *s; - for (s = _strings[h]; s; s = s->_next){ - if(s->_len == len && (!memcmp(news,s->_val,rsl(len)))) - return s; //found - } - - SQString *t=(SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString)); - new (t) SQString; - memcpy(t->_val,news,rsl(len)); - t->_val[len]=_SC('\0'); - t->_len=len; - t->_hash=::_hashstr(news,len); - t->_next=_strings[h]; - t->_uiRef=0; - _strings[h]=t; - _slotused++; - if (_slotused > _numofslots) /* too crowded? */ - Resize(_numofslots*2); - return t; -} - -void StringTable::Resize(int size) -{ - int oldsize=_numofslots; - SQString **oldtable=_strings; - AllocNodes(size); - for (int i=0; i_next; - unsigned int h=p->_hash&(_numofslots-1); - p->_next=_strings[h]; - _strings[h] = p; - p=next; - } - } - SQ_FREE(oldtable,oldsize*sizeof(SQString*)); -} - -void StringTable::Remove(SQString *bs) -{ - SQString *s; - SQString *prev=NULL; - unsigned int h=bs->_hash&(_numofslots-1); - - for (s = _strings[h]; s; ){ - if(s == bs){ - if(prev) - prev->_next = s->_next; - else - _strings[h] = s->_next; - _slotused--; - int slen=s->_len; - s->~SQString(); - SQ_FREE(s,sizeof(SQString)+rsl(slen)); - return; - } - prev = s; - s = s->_next; - } - assert(0);//if this fail something is wrong -} +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqopcodes.h" +#include "sqvm.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "sqstring.h" +#include "sqtable.h" +#include "sqarray.h" +#include "squserdata.h" +#include "sqclass.h" + +SQObjectPtr _null_; +SQObjectPtr _true_(true); +SQObjectPtr _false_(false); +SQObjectPtr _one_(1); +SQObjectPtr _minusone_(-1); + +SQSharedState::SQSharedState() +{ + _compilererrorhandler = NULL; + _printfunc = NULL; + _debuginfo = false; +} + +#define newsysstring(s) { \ + _systemstrings->push_back(SQString::Create(this,s)); \ + } + +#define newmetamethod(s) { \ + _metamethods->push_back(SQString::Create(this,s)); \ + _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \ + } + +bool CompileTypemask(SQIntVec &res,const SQChar *typemask) +{ + SQInteger i = 0; + + SQInteger mask = 0; + while(typemask[i] != 0) { + + switch(typemask[i]){ + case 'o': mask |= _RT_NULL; break; + case 'i': mask |= _RT_INTEGER; break; + case 'f': mask |= _RT_FLOAT; break; + case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break; + case 's': mask |= _RT_STRING; break; + case 't': mask |= _RT_TABLE; break; + case 'a': mask |= _RT_ARRAY; break; + case 'u': mask |= _RT_USERDATA; break; + case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break; + case 'b': mask |= _RT_BOOL; break; + case 'g': mask |= _RT_GENERATOR; break; + case 'p': mask |= _RT_USERPOINTER; break; + case 'v': mask |= _RT_THREAD; break; + case 'x': mask |= _RT_INSTANCE; break; + case 'y': mask |= _RT_CLASS; break; + case 'r': mask |= _RT_WEAKREF; break; + case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue; + case ' ': i++; continue; //ignores spaces + default: + return false; + } + i++; + if(typemask[i] == '|') { + i++; + if(typemask[i] == 0) + return false; + continue; + } + res.push_back(mask); + mask = 0; + + } + return true; +} + +SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz) +{ + SQInteger i=0; + SQTable *t=SQTable::Create(ss,0); + while(funcz[i].name!=0){ + SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f); + nc->_nparamscheck = funcz[i].nparamscheck; + nc->_name = SQString::Create(ss,funcz[i].name); + if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask)) + return NULL; + t->NewSlot(SQString::Create(ss,funcz[i].name),nc); + i++; + } + return t; +} + +void SQSharedState::Init() +{ + _scratchpad=NULL; + _scratchpadsize=0; +#ifndef NO_GARBAGE_COLLECTOR + _gc_chain=NULL; +#endif + sq_new(_stringtable,StringTable); + sq_new(_metamethods,SQObjectPtrVec); + sq_new(_systemstrings,SQObjectPtrVec); + sq_new(_types,SQObjectPtrVec); + _metamethodsmap = SQTable::Create(this,MT_LAST-1); + //adding type strings to avoid memory trashing + //types names + newsysstring(_SC("null")); + newsysstring(_SC("table")); + newsysstring(_SC("array")); + newsysstring(_SC("closure")); + newsysstring(_SC("string")); + newsysstring(_SC("userdata")); + newsysstring(_SC("integer")); + newsysstring(_SC("float")); + newsysstring(_SC("userpointer")); + newsysstring(_SC("function")); + newsysstring(_SC("generator")); + newsysstring(_SC("thread")); + newsysstring(_SC("class")); + newsysstring(_SC("instance")); + newsysstring(_SC("bool")); + //meta methods + newmetamethod(MM_ADD); + newmetamethod(MM_SUB); + newmetamethod(MM_MUL); + newmetamethod(MM_DIV); + newmetamethod(MM_UNM); + newmetamethod(MM_MODULO); + newmetamethod(MM_SET); + newmetamethod(MM_GET); + newmetamethod(MM_TYPEOF); + newmetamethod(MM_NEXTI); + newmetamethod(MM_CMP); + newmetamethod(MM_CALL); + newmetamethod(MM_CLONED); + newmetamethod(MM_NEWSLOT); + newmetamethod(MM_DELSLOT); + newmetamethod(MM_TOSTRING); + + _constructoridx = SQString::Create(this,_SC("constructor")); + _refs_table = SQTable::Create(this,0); + _registry = SQTable::Create(this,0); + _table_default_delegate=CreateDefaultDelegate(this,_table_default_delegate_funcz); + _array_default_delegate=CreateDefaultDelegate(this,_array_default_delegate_funcz); + _string_default_delegate=CreateDefaultDelegate(this,_string_default_delegate_funcz); + _number_default_delegate=CreateDefaultDelegate(this,_number_default_delegate_funcz); + _closure_default_delegate=CreateDefaultDelegate(this,_closure_default_delegate_funcz); + _generator_default_delegate=CreateDefaultDelegate(this,_generator_default_delegate_funcz); + _thread_default_delegate=CreateDefaultDelegate(this,_thread_default_delegate_funcz); + _class_default_delegate=CreateDefaultDelegate(this,_class_default_delegate_funcz); + _instance_default_delegate=CreateDefaultDelegate(this,_instance_default_delegate_funcz); + _weakref_default_delegate=CreateDefaultDelegate(this,_weakref_default_delegate_funcz); + +} + +SQSharedState::~SQSharedState() +{ + _constructoridx = _null_; + _table(_refs_table)->Finalize(); + _table(_registry)->Finalize(); + _table(_metamethodsmap)->Finalize(); + _refs_table = _null_; + _registry = _null_; + _metamethodsmap = _null_; + while(!_systemstrings->empty()){ + _systemstrings->back()=_null_; + _systemstrings->pop_back(); + } + _thread(_root_vm)->Finalize(); + _root_vm = _null_; + _table_default_delegate=_null_; + _array_default_delegate=_null_; + _string_default_delegate=_null_; + _number_default_delegate=_null_; + _closure_default_delegate=_null_; + _generator_default_delegate=_null_; + _thread_default_delegate=_null_; + _class_default_delegate=_null_; + _instance_default_delegate=_null_; + _weakref_default_delegate=_null_; + +#ifndef NO_GARBAGE_COLLECTOR + + + SQCollectable *t=_gc_chain; + SQCollectable *nx=NULL; + while(t){ + t->_uiRef++; + t->Finalize(); + nx=t->_next; + if(--t->_uiRef==0) + t->Release(); + t=nx; + } + assert(_gc_chain==NULL); //just to proove a theory + while(_gc_chain){ + _gc_chain->_uiRef++; + _gc_chain->Release(); + } +#endif + sq_delete(_types,SQObjectPtrVec); + sq_delete(_systemstrings,SQObjectPtrVec); + sq_delete(_metamethods,SQObjectPtrVec); + sq_delete(_stringtable,StringTable); + if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize); +} + + +SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name) +{ + if(type(name) != OT_STRING) + return -1; + SQObjectPtr ret; + if(_table(_metamethodsmap)->Get(name,ret)) { + return _integer(ret); + } + return -1; +} + +#ifndef NO_GARBAGE_COLLECTOR + +void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain) +{ + switch(type(o)){ + case OT_TABLE:_table(o)->Mark(chain);break; + case OT_ARRAY:_array(o)->Mark(chain);break; + case OT_USERDATA:_userdata(o)->Mark(chain);break; + case OT_CLOSURE:_closure(o)->Mark(chain);break; + case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break; + case OT_GENERATOR:_generator(o)->Mark(chain);break; + case OT_THREAD:_thread(o)->Mark(chain);break; + case OT_CLASS:_class(o)->Mark(chain);break; + case OT_INSTANCE:_instance(o)->Mark(chain);break; + } +} + + +SQInteger SQSharedState::CollectGarbage(SQVM *vm) +{ + SQInteger n=0; + SQCollectable *tchain=NULL; + SQVM *vms=_thread(_root_vm); + + vms->Mark(&tchain); + SQInteger x = _table(_thread(_root_vm)->_roottable)->CountUsed(); + MarkObject(_refs_table,&tchain); + MarkObject(_registry,&tchain); + MarkObject(_metamethodsmap,&tchain); + MarkObject(_table_default_delegate,&tchain); + MarkObject(_array_default_delegate,&tchain); + MarkObject(_string_default_delegate,&tchain); + MarkObject(_number_default_delegate,&tchain); + MarkObject(_generator_default_delegate,&tchain); + MarkObject(_thread_default_delegate,&tchain); + MarkObject(_closure_default_delegate,&tchain); + MarkObject(_class_default_delegate,&tchain); + MarkObject(_instance_default_delegate,&tchain); + MarkObject(_weakref_default_delegate,&tchain); + + SQCollectable *t=_gc_chain; + SQCollectable *nx=NULL; + while(t){ + t->_uiRef++; + t->Finalize(); + nx=t->_next; + if(--t->_uiRef==0) + t->Release(); + t=nx; + n++; + } + + t=tchain; + while(t){ + t->UnMark(); + t=t->_next; + } + _gc_chain=tchain; + SQInteger z = _table(_thread(_root_vm)->_roottable)->CountUsed(); + assert(z == x); + return n; +} +#endif + +#ifndef NO_GARBAGE_COLLECTOR +void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c) +{ + c->_prev=NULL; + c->_next=*chain; + if(*chain) (*chain)->_prev=c; + *chain=c; +} + +void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c) +{ + if(c->_prev) c->_prev->_next=c->_next; + else *chain=c->_next; + if(c->_next) + c->_next->_prev=c->_prev; + c->_next=NULL; + c->_prev=NULL; +} +#endif + +SQChar* SQSharedState::GetScratchPad(SQInteger size) +{ + SQInteger newsize; + if(size>0){ + if(_scratchpadsize>1); + _scratchpad=(SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); + _scratchpadsize=newsize; + + }else if(_scratchpadsize>=(size<<5)){ + newsize=_scratchpadsize>>1; + _scratchpad=(SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); + _scratchpadsize=newsize; + } + } + return _scratchpad; +} + +////////////////////////////////////////////////////////////////////////// +//StringTable +/* +* The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) +* http://www.lua.org/copyright.html#4 +* http://www.lua.org/source/4.0.1/src_lstring.c.html +*/ + +SQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) +{ + SQInteger idx = (SQInteger)TranslateIndex(refpos); + while(idx < _len){ + outkey = (SQInteger)idx; + outval = SQInteger(_val[idx]); + //return idx for the next iteration + return ++idx; + } + //nothing to iterate anymore + return -1; +} + +StringTable::StringTable() +{ + AllocNodes(4); + _slotused = 0; +} + +StringTable::~StringTable() +{ + SQ_FREE(_strings,sizeof(SQString*)*_numofslots); + _strings=NULL; +} + +void StringTable::AllocNodes(SQInteger size) +{ + _numofslots=size; + //_slotused=0; + _strings=(SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots); + memset(_strings,0,sizeof(SQString*)*_numofslots); +} + +SQString *StringTable::Add(const SQChar *news,SQInteger len) +{ + if(len<0) + len=scstrlen(news); + SQHash h = ::_hashstr(news,len)&(_numofslots-1); + SQString *s; + for (s = _strings[h]; s; s = s->_next){ + if(s->_len == len && (!memcmp(news,s->_val,rsl(len)))) + return s; //found + } + + SQString *t=(SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString)); + new (t) SQString; + memcpy(t->_val,news,rsl(len)); + t->_val[len] = _SC('\0'); + t->_len = len; + t->_hash = ::_hashstr(news,len); + t->_next = _strings[h]; + _strings[h] = t; + _slotused++; + if (_slotused > _numofslots) /* too crowded? */ + Resize(_numofslots*2); + return t; +} + +void StringTable::Resize(SQInteger size) +{ + SQInteger oldsize=_numofslots; + SQString **oldtable=_strings; + AllocNodes(size); + for (SQInteger i=0; i_next; + SQHash h = p->_hash&(_numofslots-1); + p->_next = _strings[h]; + _strings[h] = p; + p = next; + } + } + SQ_FREE(oldtable,oldsize*sizeof(SQString*)); +} + +void StringTable::Remove(SQString *bs) +{ + SQString *s; + SQString *prev=NULL; + SQHash h = bs->_hash&(_numofslots - 1); + + for (s = _strings[h]; s; ){ + if(s == bs){ + if(prev) + prev->_next = s->_next; + else + _strings[h] = s->_next; + _slotused--; + SQInteger slen = s->_len; + s->~SQString(); + SQ_FREE(s,sizeof(SQString) + rsl(slen)); + return; + } + prev = s; + s = s->_next; + } + assert(0);//if this fail something is wrong +} diff --git a/src/squirrel/squirrel/sqstate.h b/src/squirrel/squirrel/sqstate.h index f85e8647d..13aa71949 100644 --- a/src/squirrel/squirrel/sqstate.h +++ b/src/squirrel/squirrel/sqstate.h @@ -1,116 +1,119 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQSTATE_H_ -#define _SQSTATE_H_ - -#include "squtils.h" -#include "sqobject.h" -struct SQString; -struct SQTable; -//max number of character for a printed number -#define NUMBER_MAX_CHAR 50 - -struct StringTable -{ - StringTable(); - ~StringTable(); - //return a string obj if exists - //so when there is a table query, if the string doesn't exists in the global state - //it cannot be in a table so the result will be always null - //SQString *get(const SQChar *news); - SQString *Add(const SQChar *,int len); - void Remove(SQString *); -private: - void Resize(int size); - void AllocNodes(int size); - SQString **_strings; - unsigned int _numofslots; - unsigned int _slotused; -}; - -#define ADD_STRING(ss,str,len) ss->_stringtable->Add(str,len) -#define REMOVE_STRING(ss,bstr) ss->_stringtable->Remove(bstr) - -struct SQObjectPtr; - -struct SQSharedState -{ - SQSharedState(); - ~SQSharedState(); - void Init(); -public: - SQChar* GetScratchPad(int size); - SQInteger GetMetaMethodIdxByName(const SQObjectPtr &name); -#ifndef NO_GARBAGE_COLLECTOR - int CollectGarbage(SQVM *vm); - static void MarkObject(SQObjectPtr &o,SQCollectable **chain); -#endif - SQObjectPtrVec *_metamethods; - SQObjectPtr _metamethodsmap; - SQObjectPtrVec *_systemstrings; - SQObjectPtrVec *_types; - StringTable *_stringtable; - SQObjectPtr _refs_table; - SQObjectPtr _registry; - SQObjectPtr _constructoridx; -#ifndef NO_GARBAGE_COLLECTOR - SQCollectable *_gc_chain; -#endif - SQObjectPtr _root_vm; - SQObjectPtr _table_default_delegate; - static SQRegFunction _table_default_delegate_funcz[]; - SQObjectPtr _array_default_delegate; - static SQRegFunction _array_default_delegate_funcz[]; - SQObjectPtr _string_default_delegate; - static SQRegFunction _string_default_delegate_funcz[]; - SQObjectPtr _number_default_delegate; - static SQRegFunction _number_default_delegate_funcz[]; - SQObjectPtr _generator_default_delegate; - static SQRegFunction _generator_default_delegate_funcz[]; - SQObjectPtr _closure_default_delegate; - static SQRegFunction _closure_default_delegate_funcz[]; - SQObjectPtr _thread_default_delegate; - static SQRegFunction _thread_default_delegate_funcz[]; - SQObjectPtr _class_default_delegate; - static SQRegFunction _class_default_delegate_funcz[]; - SQObjectPtr _instance_default_delegate; - static SQRegFunction _instance_default_delegate_funcz[]; - - SQCOMPILERERROR _compilererrorhandler; - SQPRINTFUNCTION _printfunc; - bool _debuginfo; -private: - SQChar *_scratchpad; - int _scratchpadsize; -}; - -#define _sp(s) (_sharedstate->GetScratchPad(s)) -#define _spval (_sharedstate->GetScratchPad(-1)) - -#define _table_ddel _table(_sharedstate->_table_default_delegate) -#define _array_ddel _table(_sharedstate->_array_default_delegate) -#define _string_ddel _table(_sharedstate->_string_default_delegate) -#define _number_ddel _table(_sharedstate->_number_default_delegate) -#define _generator_ddel _table(_sharedstate->_generator_default_delegate) -#define _closure_ddel _table(_sharedstate->_closure_default_delegate) -#define _thread_ddel _table(_sharedstate->_thread_default_delegate) -#define _class_ddel _table(_sharedstate->_class_default_delegate) -#define _instance_ddel _table(_sharedstate->_instance_default_delegate) - -#ifdef SQUNICODE //rsl REAL STRING LEN -#define rsl(l) ((l)<<1) -#else -#define rsl(l) (l) -#endif - -extern SQObjectPtr _null_; -extern SQObjectPtr _true_; -extern SQObjectPtr _false_; -extern SQObjectPtr _one_; -extern SQObjectPtr _minusone_; - -bool CompileTypemask(SQIntVec &res,const SQChar *typemask); - -void *sq_vm_malloc(unsigned int size); -void *sq_vm_realloc(void *p,unsigned int oldsize,unsigned int size); -void sq_vm_free(void *p,unsigned int size); -#endif //_SQSTATE_H_ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTATE_H_ +#define _SQSTATE_H_ + +#include "squtils.h" +#include "sqobject.h" +struct SQString; +struct SQTable; +//max number of character for a printed number +#define NUMBER_MAX_CHAR 50 + +struct StringTable +{ + StringTable(); + ~StringTable(); + //return a string obj if exists + //so when there is a table query, if the string doesn't exists in the global state + //it cannot be in a table so the result will be always null + //SQString *get(const SQChar *news); + SQString *Add(const SQChar *,SQInteger len); + void Remove(SQString *); +private: + void Resize(SQInteger size); + void AllocNodes(SQInteger size); + SQString **_strings; + SQUnsignedInteger _numofslots; + SQUnsignedInteger _slotused; +}; + +#define ADD_STRING(ss,str,len) ss->_stringtable->Add(str,len) +#define REMOVE_STRING(ss,bstr) ss->_stringtable->Remove(bstr) + +struct SQObjectPtr; + +struct SQSharedState +{ + SQSharedState(); + ~SQSharedState(); + void Init(); +public: + SQChar* GetScratchPad(SQInteger size); + SQInteger GetMetaMethodIdxByName(const SQObjectPtr &name); +#ifndef NO_GARBAGE_COLLECTOR + SQInteger CollectGarbage(SQVM *vm); + static void MarkObject(SQObjectPtr &o,SQCollectable **chain); +#endif + SQObjectPtrVec *_metamethods; + SQObjectPtr _metamethodsmap; + SQObjectPtrVec *_systemstrings; + SQObjectPtrVec *_types; + StringTable *_stringtable; + SQObjectPtr _refs_table; + SQObjectPtr _registry; + SQObjectPtr _constructoridx; +#ifndef NO_GARBAGE_COLLECTOR + SQCollectable *_gc_chain; +#endif + SQObjectPtr _root_vm; + SQObjectPtr _table_default_delegate; + static SQRegFunction _table_default_delegate_funcz[]; + SQObjectPtr _array_default_delegate; + static SQRegFunction _array_default_delegate_funcz[]; + SQObjectPtr _string_default_delegate; + static SQRegFunction _string_default_delegate_funcz[]; + SQObjectPtr _number_default_delegate; + static SQRegFunction _number_default_delegate_funcz[]; + SQObjectPtr _generator_default_delegate; + static SQRegFunction _generator_default_delegate_funcz[]; + SQObjectPtr _closure_default_delegate; + static SQRegFunction _closure_default_delegate_funcz[]; + SQObjectPtr _thread_default_delegate; + static SQRegFunction _thread_default_delegate_funcz[]; + SQObjectPtr _class_default_delegate; + static SQRegFunction _class_default_delegate_funcz[]; + SQObjectPtr _instance_default_delegate; + static SQRegFunction _instance_default_delegate_funcz[]; + SQObjectPtr _weakref_default_delegate; + static SQRegFunction _weakref_default_delegate_funcz[]; + + SQCOMPILERERROR _compilererrorhandler; + SQPRINTFUNCTION _printfunc; + bool _debuginfo; +private: + SQChar *_scratchpad; + SQInteger _scratchpadsize; +}; + +#define _sp(s) (_sharedstate->GetScratchPad(s)) +#define _spval (_sharedstate->GetScratchPad(-1)) + +#define _table_ddel _table(_sharedstate->_table_default_delegate) +#define _array_ddel _table(_sharedstate->_array_default_delegate) +#define _string_ddel _table(_sharedstate->_string_default_delegate) +#define _number_ddel _table(_sharedstate->_number_default_delegate) +#define _generator_ddel _table(_sharedstate->_generator_default_delegate) +#define _closure_ddel _table(_sharedstate->_closure_default_delegate) +#define _thread_ddel _table(_sharedstate->_thread_default_delegate) +#define _class_ddel _table(_sharedstate->_class_default_delegate) +#define _instance_ddel _table(_sharedstate->_instance_default_delegate) +#define _weakref_ddel _table(_sharedstate->_weakref_default_delegate) + +#ifdef SQUNICODE //rsl REAL STRING LEN +#define rsl(l) ((l)<<1) +#else +#define rsl(l) (l) +#endif + +extern SQObjectPtr _null_; +extern SQObjectPtr _true_; +extern SQObjectPtr _false_; +extern SQObjectPtr _one_; +extern SQObjectPtr _minusone_; + +bool CompileTypemask(SQIntVec &res,const SQChar *typemask); + +void *sq_vm_malloc(SQUnsignedInteger size); +void *sq_vm_realloc(void *p,SQUnsignedInteger oldsize,SQUnsignedInteger size); +void sq_vm_free(void *p,SQUnsignedInteger size); +#endif //_SQSTATE_H_ diff --git a/src/squirrel/squirrel/sqstring.h b/src/squirrel/squirrel/sqstring.h index 5061c13f4..29ca9c284 100644 --- a/src/squirrel/squirrel/sqstring.h +++ b/src/squirrel/squirrel/sqstring.h @@ -1,31 +1,31 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQSTRING_H_ -#define _SQSTRING_H_ - -inline unsigned int _hashstr (const SQChar *s, size_t l) -{ - unsigned int h = 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; -} - -struct SQString : public SQRefCounted -{ - SQString(){} - ~SQString(){} -public: - static SQString *Create(SQSharedState *ss, const SQChar *, int len = -1 ); - int Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); - void Release(); - SQSharedState *_sharedstate; - SQString *_next; //chain for the string table - int _len; - int _hash; - SQChar _val[1]; -}; - - - -#endif //_SQSTRING_H_ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTRING_H_ +#define _SQSTRING_H_ + +inline SQHash _hashstr (const SQChar *s, size_t l) +{ + SQHash h = 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; +} + +struct SQString : public SQRefCounted +{ + SQString(){} + ~SQString(){} +public: + static SQString *Create(SQSharedState *ss, const SQChar *, SQInteger len = -1 ); + SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); + void Release(); + SQSharedState *_sharedstate; + SQString *_next; //chain for the string table + SQInteger _len; + SQHash _hash; + SQChar _val[1]; +}; + + + +#endif //_SQSTRING_H_ diff --git a/src/squirrel/squirrel/sqtable.cpp b/src/squirrel/squirrel/sqtable.cpp index 1b4f24467..8eef4b825 100644 --- a/src/squirrel/squirrel/sqtable.cpp +++ b/src/squirrel/squirrel/sqtable.cpp @@ -1,193 +1,172 @@ -/* -see copyright notice in squirrel.h -*/ -#include "sqpcheader.h" -#include "sqvm.h" -#include "sqtable.h" -#include "sqfuncproto.h" -#include "sqclosure.h" - -SQTable::SQTable(SQSharedState *ss,int nInitialSize) -{ - int pow2size=MINPOWER2; - while(nInitialSize>pow2size)pow2size=pow2size<<1; - AllocNodes(pow2size); - _uiRef = 0; - _usednodes = 0; - _delegate = NULL; - INIT_CHAIN(); - ADD_TO_CHAIN(&_sharedstate->_gc_chain,this); -} - -void SQTable::Remove(const SQObjectPtr &key) -{ - _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1)); - if (n) { - n->val = n->key = _null_; - _usednodes--; - Rehash(false); - } -} - -void SQTable::AllocNodes(int nSize) -{ - _HashNode *nodes=(_HashNode *)SQ_MALLOC(sizeof(_HashNode)*nSize); - for(int i=0;i= oldsize-oldsize/4) /* using more than 3/4? */ - AllocNodes(oldsize*2); - else if (nelems <= oldsize/4 && /* less than 1/4? */ - oldsize > MINPOWER2) - AllocNodes(oldsize/2); - else if(force) - AllocNodes(oldsize); - else - return; - _usednodes = 0; - for (int i=0; ikey) != OT_NULL) - NewSlot(old->key,old->val); - } - for(int k=0;kNewSlot(key,val); - } - nt->SetDelegate(_delegate); - return nt; -} - -bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val) -{ - _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1)); - if (n) { - val = n->val; - return true; - } - return false; -} -bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) -{ - unsigned long h = HashKey(key) & (_numofnodes - 1); - _HashNode *n = _Get(key, h); - if (n) { - n->val = val; - return false; - } - _HashNode *mp = &_nodes[h]; - n = mp; - - //key not found I'll insert it - //main pos is not free - - if(type(mp->key)!=OT_NULL) { - - _HashNode *othern; /* main position of colliding node */ - n = _firstfree; /* get a free place */ - if (mp > n && (othern = &_nodes[h]) != mp){ - /* yes; move colliding node into free position */ - while (othern->next != mp) - othern = othern->next; /* find previous */ - othern->next = n; /* redo the chain with `n' in place of `mp' */ - *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ - mp->next = NULL; /* now `mp' is free */ - } - else{ - /* new node will go into free position */ - n->next = mp->next; /* chain new position */ - mp->next = n; - mp = n; - } - } - mp->key = key; - - for (;;) { /* correct `firstfree' */ - if (type(_firstfree->key) == OT_NULL) { - mp->val = val; - _usednodes++; - return true; /* OK; table still has a free place */ - } - else if (_firstfree == _nodes) break; /* cannot decrement from here */ - else (_firstfree)--; - } - Rehash(true); - return NewSlot(key, val); -} - -int SQTable::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) -{ - int idx = (int)TranslateIndex(refpos); - while (idx < _numofnodes) { - if(type(_nodes[idx].key) != OT_NULL) { - //first found - outkey = _nodes[idx].key; - outval = _nodes[idx].val; - //return idx for the next iteration - return ++idx; - } - ++idx; - } - //nothing to iterate anymore - return -1; -} - -bool SQTable::SetDelegate(SQTable *mt) -{ - SQTable *temp = mt; - while (temp) { - if (temp->_delegate == this) return false; //cycle detected - temp = temp->_delegate; - } - if (mt) __ObjAddRef(mt); - __ObjRelease(_delegate); - _delegate = mt; - return true; -} - -bool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val) -{ - _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1)); - if (n) { - n->val = val; - return true; - } - return false; -} - -void SQTable::Finalize() -{ - for(int i = 0;i < _numofnodes; i++) { _nodes[i].key = _null_; _nodes[i].val = _null_; } - SetDelegate(NULL); -} +/* +see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqtable.h" +#include "sqfuncproto.h" +#include "sqclosure.h" + +SQTable::SQTable(SQSharedState *ss,SQInteger nInitialSize) +{ + SQInteger pow2size=MINPOWER2; + while(nInitialSize>pow2size)pow2size=pow2size<<1; + AllocNodes(pow2size); + _usednodes = 0; + _delegate = NULL; + INIT_CHAIN(); + ADD_TO_CHAIN(&_sharedstate->_gc_chain,this); +} + +void SQTable::Remove(const SQObjectPtr &key) +{ + _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1)); + if (n) { + n->val = n->key = _null_; + _usednodes--; + Rehash(false); + } +} + +void SQTable::AllocNodes(SQInteger nSize) +{ + _HashNode *nodes=(_HashNode *)SQ_MALLOC(sizeof(_HashNode)*nSize); + for(SQInteger i=0;i= oldsize-oldsize/4) /* using more than 3/4? */ + AllocNodes(oldsize*2); + else if (nelems <= oldsize/4 && /* less than 1/4? */ + oldsize > MINPOWER2) + AllocNodes(oldsize/2); + else if(force) + AllocNodes(oldsize); + else + return; + _usednodes = 0; + for (SQInteger i=0; ikey) != OT_NULL) + NewSlot(old->key,old->val); + } + for(SQInteger k=0;kNewSlot(key,val); + } + nt->SetDelegate(_delegate); + return nt; +} + +bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val) +{ + _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1)); + if (n) { + val = _realval(n->val); + return true; + } + return false; +} +bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) +{ + SQHash h = HashKey(key) & (_numofnodes - 1); + _HashNode *n = _Get(key, h); + if (n) { + n->val = val; + return false; + } + _HashNode *mp = &_nodes[h]; + n = mp; + + //key not found I'll insert it + //main pos is not free + + if(type(mp->key)!=OT_NULL) { + + _HashNode *othern; /* main position of colliding node */ + n = _firstfree; /* get a free place */ + if (mp > n && (othern = &_nodes[h]) != mp){ + /* yes; move colliding node into free position */ + while (othern->next != mp) + othern = othern->next; /* find previous */ + othern->next = n; /* redo the chain with `n' in place of `mp' */ + *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ + mp->next = NULL; /* now `mp' is free */ + } + else{ + /* new node will go into free position */ + n->next = mp->next; /* chain new position */ + mp->next = n; + mp = n; + } + } + mp->key = key; + + for (;;) { /* correct `firstfree' */ + if (type(_firstfree->key) == OT_NULL) { + mp->val = val; + _usednodes++; + return true; /* OK; table still has a free place */ + } + else if (_firstfree == _nodes) break; /* cannot decrement from here */ + else (_firstfree)--; + } + Rehash(true); + return NewSlot(key, val); +} + +SQInteger SQTable::Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) +{ + SQInteger idx = (SQInteger)TranslateIndex(refpos); + while (idx < _numofnodes) { + if(type(_nodes[idx].key) != OT_NULL) { + //first found + _HashNode &n = _nodes[idx]; + outkey = n.key; + outval = getweakrefs?(SQObject)n.val:_realval(n.val); + //return idx for the next iteration + return ++idx; + } + ++idx; + } + //nothing to iterate anymore + return -1; +} + + +bool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val) +{ + _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1)); + if (n) { + n->val = val; + return true; + } + return false; +} + +void SQTable::Finalize() +{ + for(SQInteger i = 0;i < _numofnodes; i++) { _nodes[i].key = _null_; _nodes[i].val = _null_; } + SetDelegate(NULL); +} diff --git a/src/squirrel/squirrel/sqtable.h b/src/squirrel/squirrel/sqtable.h index 820639c80..141261f92 100644 --- a/src/squirrel/squirrel/sqtable.h +++ b/src/squirrel/squirrel/sqtable.h @@ -1,88 +1,86 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQTABLE_H_ -#define _SQTABLE_H_ -/* -* The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) -* http://www.lua.org/copyright.html#4 -* http://www.lua.org/source/4.0.1/src_ltable.c.html -*/ - -#include "sqstring.h" - -#define hashptr(p) (((unsigned long)(p)) >> 3) - -struct SQTable : public SQDelegable -{ -private: - struct _HashNode - { - SQObjectPtr val; - SQObjectPtr key; - _HashNode *next; - }; - _HashNode *_firstfree; - _HashNode *_nodes; - int _numofnodes; - int _usednodes; - -/////////////////////////// - void AllocNodes(int nSize); - void Rehash(bool force); - SQTable(SQSharedState *ss, int nInitialSize); -public: - static SQTable* Create(SQSharedState *ss,int nInitialSize) - { - SQTable *newtable = (SQTable*)SQ_MALLOC(sizeof(SQTable)); - new (newtable) SQTable(ss, nInitialSize); - newtable->_delegate = NULL; - return newtable; - } - void Finalize(); - SQTable *Clone(); - ~SQTable() - { - SetDelegate(NULL); - REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); - for (int i = 0; i < _numofnodes; i++) _nodes[i].~_HashNode(); - SQ_FREE(_nodes, _numofnodes * sizeof(_HashNode)); - } -#ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); -#endif - inline unsigned long HashKey(const SQObjectPtr &key) - { - switch(type(key)){ - case OT_STRING: return _string(key)->_hash; - case OT_FLOAT: return (unsigned long)((long)_float(key)); - case OT_INTEGER: return (unsigned long)((long)_integer(key)); - default: return hashptr(key._unVal.pRefCounted); - } - } - inline _HashNode *_Get(const SQObjectPtr &key,unsigned long hash) - { - _HashNode *n = &_nodes[hash]; - do{ - if(_rawval(n->key) == _rawval(key) && type(n->key) == type(key)){ - return n; - } - }while(n = n->next); - return NULL; - } - bool Get(const SQObjectPtr &key,SQObjectPtr &val); - void Remove(const SQObjectPtr &key); - bool Set(const SQObjectPtr &key, const SQObjectPtr &val); - //returns true if a new slot has been created false if it was already present - bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val); - int Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); - - int CountUsed(); - void Release() - { - sq_delete(this, SQTable); - } - bool SetDelegate(SQTable *mt); - - -}; - -#endif //_SQTABLE_H_ +/* see copyright notice in squirrel.h */ +#ifndef _SQTABLE_H_ +#define _SQTABLE_H_ +/* +* The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) +* http://www.lua.org/copyright.html#4 +* http://www.lua.org/source/4.0.1/src_ltable.c.html +*/ + +#include "sqstring.h" + +#define hashptr(p) (((SQHash)(p)) >> 3) + +struct SQTable : public SQDelegable +{ +private: + struct _HashNode + { + SQObjectPtr val; + SQObjectPtr key; + _HashNode *next; + }; + _HashNode *_firstfree; + _HashNode *_nodes; + SQInteger _numofnodes; + SQInteger _usednodes; + +/////////////////////////// + void AllocNodes(SQInteger nSize); + void Rehash(bool force); + SQTable(SQSharedState *ss, SQInteger nInitialSize); +public: + static SQTable* Create(SQSharedState *ss,SQInteger nInitialSize) + { + SQTable *newtable = (SQTable*)SQ_MALLOC(sizeof(SQTable)); + new (newtable) SQTable(ss, nInitialSize); + newtable->_delegate = NULL; + return newtable; + } + void Finalize(); + SQTable *Clone(); + ~SQTable() + { + SetDelegate(NULL); + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + for (SQInteger i = 0; i < _numofnodes; i++) _nodes[i].~_HashNode(); + SQ_FREE(_nodes, _numofnodes * sizeof(_HashNode)); + } +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); +#endif + inline SQHash HashKey(const SQObjectPtr &key) + { + switch(type(key)){ + case OT_STRING: return _string(key)->_hash; + case OT_FLOAT: return (SQHash)((SQInteger)_float(key)); + case OT_INTEGER: return (SQHash)((SQInteger)_integer(key)); + default: return hashptr(key._unVal.pRefCounted); + } + } + inline _HashNode *_Get(const SQObjectPtr &key,SQHash hash) + { + _HashNode *n = &_nodes[hash]; + do{ + if(_rawval(n->key) == _rawval(key) && type(n->key) == type(key)){ + return n; + } + }while(n = n->next); + return NULL; + } + bool Get(const SQObjectPtr &key,SQObjectPtr &val); + void Remove(const SQObjectPtr &key); + bool Set(const SQObjectPtr &key, const SQObjectPtr &val); + //returns true if a new slot has been created false if it was already present + bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val); + SQInteger Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); + + SQInteger CountUsed(){ return _usednodes;} + void Release() + { + sq_delete(this, SQTable); + } + +}; + +#endif //_SQTABLE_H_ diff --git a/src/squirrel/squirrel/squserdata.h b/src/squirrel/squirrel/squserdata.h index d9c6d515c..8fe0411ea 100644 --- a/src/squirrel/squirrel/squserdata.h +++ b/src/squirrel/squirrel/squserdata.h @@ -1,45 +1,38 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQUSERDATA_H_ -#define _SQUSERDATA_H_ - -struct SQUserData : SQDelegable -{ - SQUserData(SQSharedState *ss){ _uiRef = 0; _delegate = 0; _hook = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain, this); } - ~SQUserData() - { - REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain, this); - SetDelegate(NULL); - } - static SQUserData* Create(SQSharedState *ss, int size) - { - SQUserData* ud = (SQUserData*)SQ_MALLOC(sizeof(SQUserData)+(size-1)); - new (ud) SQUserData(ss); - ud->_size = size; - ud->_typetag = 0; - return ud; - } -#ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); - void Finalize(){SetDelegate(NULL);} -#endif - void Release() { - if (_hook) _hook(_val,_size); - int tsize = _size - 1; - this->~SQUserData(); - SQ_FREE(this, sizeof(SQUserData) + tsize); - } - void SetDelegate(SQTable *mt) - { - if (mt) __ObjAddRef(mt); - __ObjRelease(_delegate); - _delegate = mt; - } - - - int _size; - SQRELEASEHOOK _hook; - unsigned int _typetag; - SQChar _val[1]; -}; - -#endif //_SQUSERDATA_H_ +/* see copyright notice in squirrel.h */ +#ifndef _SQUSERDATA_H_ +#define _SQUSERDATA_H_ + +struct SQUserData : SQDelegable +{ + SQUserData(SQSharedState *ss){ _delegate = 0; _hook = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain, this); } + ~SQUserData() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain, this); + SetDelegate(NULL); + } + static SQUserData* Create(SQSharedState *ss, SQInteger size) + { + SQUserData* ud = (SQUserData*)SQ_MALLOC(sizeof(SQUserData)+(size-1)); + new (ud) SQUserData(ss); + ud->_size = size; + ud->_typetag = 0; + return ud; + } +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){SetDelegate(NULL);} +#endif + void Release() { + if (_hook) _hook(_val,_size); + SQInteger tsize = _size - 1; + this->~SQUserData(); + SQ_FREE(this, sizeof(SQUserData) + tsize); + } + + SQInteger _size; + SQRELEASEHOOK _hook; + SQUserPointer _typetag; + SQChar _val[1]; +}; + +#endif //_SQUSERDATA_H_ diff --git a/src/squirrel/squirrel/squtils.h b/src/squirrel/squirrel/squtils.h index 71938facc..86456baf4 100644 --- a/src/squirrel/squirrel/squtils.h +++ b/src/squirrel/squirrel/squtils.h @@ -1,104 +1,104 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQUTILS_H_ -#define _SQUTILS_H_ - -#define sq_new(__ptr,__type) {__ptr=(__type *)sq_vm_malloc(sizeof(__type));new (__ptr) __type;} -#define sq_delete(__ptr,__type) {__ptr->~__type();sq_vm_free(__ptr,sizeof(__type));} -#define SQ_MALLOC(__size) sq_vm_malloc(__size); -#define SQ_FREE(__ptr,__size) sq_vm_free(__ptr,__size); -#define SQ_REALLOC(__ptr,__oldsize,__size) sq_vm_realloc(__ptr,__oldsize,__size); - -//sqvector mini vector class, supports objects by value -template class sqvector -{ -public: - sqvector() - { - _vals = NULL; - _size = 0; - _allocated = 0; - } - sqvector(const sqvector& v) - { - copy(v); - } - void copy(const sqvector& v) - { - resize(v._size); - for(unsigned int i = 0; i < v._size; i++) { - new ((void *)&_vals[i]) T(v._vals[i]); - } - _size = v._size; - } - ~sqvector() - { - if(_allocated) { - for(unsigned int i = 0; i < _size; i++) - _vals[i].~T(); - SQ_FREE(_vals, (_allocated * sizeof(T))); - } - } - void reserve(unsigned int newsize) { _realloc(newsize); } - void resize(unsigned int newsize, const T& fill = T()) - { - if(newsize > _allocated) - _realloc(newsize); - if(newsize > _size) { - while(_size < newsize) { - new ((void *)&_vals[_size]) T(fill); - _size++; - } - } - else{ - for(unsigned int i = newsize; i < _size; i++) { - _vals[i].~T(); - } - _size = newsize; - } - } - void shrinktofit() { if(_size > 4) { _realloc(_size); } } - T& top() const { return _vals[_size - 1]; } - inline unsigned int size() const { return _size; } - bool empty() const { return (_size <= 0); } - inline T &push_back(const T& val = T()) - { - if(_allocated <= _size) - _realloc(_size * 2); - return *(new ((void *)&_vals[_size++]) T(val)); - } - inline void pop_back() - { - _size--; _vals[_size].~T(); - } - void insert(unsigned int idx, const T& val) - { - resize(_size + 1); - for(unsigned int i = _size - 1; i > idx; i--) { - _vals[i] = _vals[i - 1]; - } - _vals[idx] = val; - } - void remove(unsigned int idx) - { - _vals[idx].~T(); - if(idx < (_size - 1)) { - memcpy(&_vals[idx], &_vals[idx+1], sizeof(T) * (_size - idx - 1)); - } - _size--; - } - unsigned int capacity() { return _allocated; } - inline T &back() const { return _vals[_size - 1]; } - inline T& operator[](unsigned int pos) const{ return _vals[pos]; } - T* _vals; -private: - void _realloc(unsigned int newsize) - { - newsize = (newsize > 0)?newsize:4; - _vals = (T*)SQ_REALLOC(_vals, _allocated * sizeof(T), newsize * sizeof(T)); - _allocated = newsize; - } - unsigned int _size; - unsigned int _allocated; -}; - -#endif //_SQUTILS_H_ +/* see copyright notice in squirrel.h */ +#ifndef _SQUTILS_H_ +#define _SQUTILS_H_ + +#define sq_new(__ptr,__type) {__ptr=(__type *)sq_vm_malloc(sizeof(__type));new (__ptr) __type;} +#define sq_delete(__ptr,__type) {__ptr->~__type();sq_vm_free(__ptr,sizeof(__type));} +#define SQ_MALLOC(__size) sq_vm_malloc(__size); +#define SQ_FREE(__ptr,__size) sq_vm_free(__ptr,__size); +#define SQ_REALLOC(__ptr,__oldsize,__size) sq_vm_realloc(__ptr,__oldsize,__size); + +//sqvector mini vector class, supports objects by value +template class sqvector +{ +public: + sqvector() + { + _vals = NULL; + _size = 0; + _allocated = 0; + } + sqvector(const sqvector& v) + { + copy(v); + } + void copy(const sqvector& v) + { + resize(v._size); + for(SQUnsignedInteger i = 0; i < v._size; i++) { + new ((void *)&_vals[i]) T(v._vals[i]); + } + _size = v._size; + } + ~sqvector() + { + if(_allocated) { + for(SQUnsignedInteger i = 0; i < _size; i++) + _vals[i].~T(); + SQ_FREE(_vals, (_allocated * sizeof(T))); + } + } + void reserve(SQUnsignedInteger newsize) { _realloc(newsize); } + void resize(SQUnsignedInteger newsize, const T& fill = T()) + { + if(newsize > _allocated) + _realloc(newsize); + if(newsize > _size) { + while(_size < newsize) { + new ((void *)&_vals[_size]) T(fill); + _size++; + } + } + else{ + for(SQUnsignedInteger i = newsize; i < _size; i++) { + _vals[i].~T(); + } + _size = newsize; + } + } + void shrinktofit() { if(_size > 4) { _realloc(_size); } } + T& top() const { return _vals[_size - 1]; } + inline SQUnsignedInteger size() const { return _size; } + bool empty() const { return (_size <= 0); } + inline T &push_back(const T& val = T()) + { + if(_allocated <= _size) + _realloc(_size * 2); + return *(new ((void *)&_vals[_size++]) T(val)); + } + inline void pop_back() + { + _size--; _vals[_size].~T(); + } + void insert(SQUnsignedInteger idx, const T& val) + { + resize(_size + 1); + for(SQUnsignedInteger i = _size - 1; i > idx; i--) { + _vals[i] = _vals[i - 1]; + } + _vals[idx] = val; + } + void remove(SQUnsignedInteger idx) + { + _vals[idx].~T(); + if(idx < (_size - 1)) { + memcpy(&_vals[idx], &_vals[idx+1], sizeof(T) * (_size - idx - 1)); + } + _size--; + } + SQUnsignedInteger capacity() { return _allocated; } + inline T &back() const { return _vals[_size - 1]; } + inline T& operator[](SQUnsignedInteger pos) const{ return _vals[pos]; } + T* _vals; +private: + void _realloc(SQUnsignedInteger newsize) + { + newsize = (newsize > 0)?newsize:4; + _vals = (T*)SQ_REALLOC(_vals, _allocated * sizeof(T), newsize * sizeof(T)); + _allocated = newsize; + } + SQUnsignedInteger _size; + SQUnsignedInteger _allocated; +}; + +#endif //_SQUTILS_H_ diff --git a/src/squirrel/squirrel/sqvm.cpp b/src/squirrel/squirrel/sqvm.cpp index 725cad0c6..3137b0a9c 100644 --- a/src/squirrel/squirrel/sqvm.cpp +++ b/src/squirrel/squirrel/sqvm.cpp @@ -1,1377 +1,1404 @@ -/* - see copyright notice in squirrel.h -*/ -#include "sqpcheader.h" -#include -#include -#include "sqopcodes.h" -#include "sqfuncproto.h" -#include "sqvm.h" -#include "sqclosure.h" -#include "sqstring.h" -#include "sqtable.h" -#include "squserdata.h" -#include "sqarray.h" -#include "sqclass.h" - -#define TOP() (_stack[_top-1]) - -bool SQVM::BW_OP(unsigned int op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2) -{ - SQInteger res; - SQInteger i1 = _integer(o1), i2 = _integer(o2); - if((type(o1)==OT_INTEGER) && (type(o2)==OT_INTEGER)) - { - switch(op) { - case BW_AND: res = i1 & i2; break; - case BW_OR: res = i1 | i2; break; - case BW_XOR: res = i1 ^ i2; break; - case BW_SHIFTL: res = i1 << i2; break; - case BW_SHIFTR: res = i1 >> i2; break; - case BW_USHIFTR:res = (SQInteger)(*((unsigned int*)&i1) >> i2); break; - default: { Raise_Error(_SC("internal vm error bitwise op failed")); return false; } - } - } - else { Raise_Error(_SC("bitwise op between '%s' and '%s'"),GetTypeName(o1),GetTypeName(o2)); return false;} - trg = res; - return true; -} - -bool SQVM::ARITH_OP(unsigned int op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2) -{ - if(sq_isnumeric(o1) && sq_isnumeric(o2)) { - if((type(o1)==OT_INTEGER) && (type(o2)==OT_INTEGER)) { - switch(op) { - case '+': trg = _integer(o1) + _integer(o2); break; - case '-': trg = _integer(o1) - _integer(o2); break; - case '/': if(_integer(o2) == 0) { Raise_Error(_SC("division by zero")); return false; } - trg = _integer(o1) / _integer(o2); - break; - case '*': trg = _integer(o1) * _integer(o2); break; - case '%': trg = _integer(o1) % _integer(o2); break; - } - }else{ - switch(op) { - case '+': trg = tofloat(o1) + tofloat(o2); break; - case '-': trg = tofloat(o1) - tofloat(o2); break; - case '/': trg = tofloat(o1) / tofloat(o2); break; - case '*': trg = tofloat(o1) * tofloat(o2); break; - case '%': trg = SQFloat(fmod((double)tofloat(o1),(double)tofloat(o2))); break; - } - } - } else { - if(op == '+' && (type(o1) == OT_STRING || type(o2) == OT_STRING)){ - if(!StringCat(o1, o2, trg)) return false; - } - else if(!ArithMetaMethod(op,o1,o2,trg)) { - Raise_Error(_SC("arith op %c on between '%s' and '%s'"),op,GetTypeName(o1),GetTypeName(o2)); return false; - } - } - return true; -} - -SQObjectPtr &stack_get(HSQUIRRELVM v,int idx){return ((idx>=0)?(v->GetAt(idx+v->_stackbase-1)):(v->GetUp(idx)));} - -SQVM::SQVM(SQSharedState *ss) -{ - _sharedstate=ss; - _suspended = SQFalse; - _suspended_target=-1; - _suspended_root = SQFalse; - _suspended_traps=-1; - _foreignptr=NULL; - _nnativecalls=0; - _uiRef=0; - _lasterror = _null_; - _errorhandler = _null_; - _debughook = _null_; - INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); -} - -void SQVM::Finalize() -{ - _roottable = _null_; - _lasterror = _null_; - _errorhandler = _null_; - _debughook = _null_; - temp_reg = _null_; - int size=_stack.size(); - for(int i=0;i_gc_chain,this); -} - -bool SQVM::ArithMetaMethod(int op,const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &dest) -{ - SQMetaMethod mm; - switch(op){ - case _SC('+'): mm=MT_ADD; break; - case _SC('-'): mm=MT_SUB; break; - case _SC('/'): mm=MT_DIV; break; - case _SC('*'): mm=MT_MUL; break; - case _SC('%'): mm=MT_MODULO; break; - } - if(is_delegable(o1) && _delegable(o1)->_delegate) { - Push(o1);Push(o2); - return CallMetaMethod(_delegable(o1),mm,2,dest); - } - return false; -} - -bool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o) -{ - - switch(type(o)) { - case OT_INTEGER: - trg = -_integer(o); - return true; - case OT_FLOAT: - trg = -_float(o); - return true; - case OT_TABLE: - case OT_USERDATA: - case OT_INSTANCE: - if(_delegable(o)->_delegate) { - Push(o); - if(CallMetaMethod(_delegable(o), MT_UNM, 1, temp_reg)) { - trg = temp_reg; - return true; - } - } - return true; - - } - Raise_Error(_SC("attempt to negate a %s"), GetTypeName(o)); - return false; -} - -#define _RET_SUCCEED(exp) { result = (exp); return true; } -bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,int &result) -{ - if(type(o1)==type(o2)){ - if(_userpointer(o1)==_userpointer(o2))_RET_SUCCEED(0); - SQObjectPtr res; - switch(type(o1)){ - case OT_STRING: - _RET_SUCCEED(scstrcmp(_stringval(o1),_stringval(o2))); - case OT_INTEGER: - _RET_SUCCEED(_integer(o1)-_integer(o2)); - case OT_FLOAT: - _RET_SUCCEED((_float(o1)<_float(o2))?-1:1); - case OT_TABLE: - case OT_USERDATA: - case OT_INSTANCE: - Push(o1);Push(o2); - if(_delegable(o1)->_delegate)CallMetaMethod(_delegable(o1),MT_CMP,2,res); - break; - } - if(type(res)!=OT_INTEGER) { Raise_CompareError(o1,o2); return false; } - _RET_SUCCEED(_integer(res)); - } - else{ - if(sq_isnumeric(o1) && sq_isnumeric(o2)){ - if((type(o1)==OT_INTEGER) && (type(o2)==OT_FLOAT)) { - if( _integer(o1)==_float(o2) ) { _RET_SUCCEED(0); } - else if( _integer(o1)<_float(o2) ) { _RET_SUCCEED(-1); } - _RET_SUCCEED(1); - } - else{ - if( _float(o1)==_integer(o2) ) { _RET_SUCCEED(0); } - else if( _float(o1)<_integer(o2) ) { _RET_SUCCEED(-1); } - _RET_SUCCEED(1); - } - } - else if(type(o1)==OT_NULL) {_RET_SUCCEED(-1);} - else if(type(o2)==OT_NULL) {_RET_SUCCEED(1);} - else { Raise_CompareError(o1,o2); return false; } - - } - assert(0); - _RET_SUCCEED(0); //cannot happen -} - -bool SQVM::CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res) -{ - int r; - if(ObjCmp(o1,o2,r)) { - switch(op) { - case CMP_G: res = (r > 0)?_true_:_false_; return true; - case CMP_GE: res = (r >= 0)?_true_:_false_; return true; - case CMP_L: res = (r < 0)?_true_:_false_; return true; - case CMP_LE: res = (r <= 0)?_true_:_false_; return true; - - } - assert(0); - } - return false; -} - -bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest) -{ - switch(type(obj)) - { - case OT_STRING: - switch(type(str)){ - case OT_STRING: { - int l=_string(str)->_len,ol=_string(obj)->_len; - SQChar *s=_sp(rsl(l+ol+1)); - memcpy(s,_stringval(str),rsl(l));memcpy(s+l,_stringval(obj),rsl(ol));s[l+ol]=_SC('\0'); - break; - } - case OT_FLOAT: - scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(obj)->_len+1)),_SC("%g%s"),_float(str),_stringval(obj)); - break; - case OT_INTEGER: - scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(obj)->_len+1)),_SC("%d%s"),_integer(str),_stringval(obj)); - break; - default: - Raise_Error(_SC("string concatenation between '%s' and '%s'"),GetTypeName(str),GetTypeName(obj)); - return false; - } - dest=SQString::Create(_ss(this),_spval); - break; - case OT_FLOAT: - scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(str)->_len+1)),_SC("%s%g"),_stringval(str),_float(obj)); - dest=SQString::Create(_ss(this),_spval); - break; - case OT_INTEGER: - scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(str)->_len+1)),_SC("%s%d"),_stringval(str),_integer(obj)); - dest=SQString::Create(_ss(this),_spval); - break; - default: - Raise_Error(_SC("string concatenation between '%s' and '%s'"),GetTypeName(str),GetTypeName(obj)); - return false; - } - return true; -} - -const SQChar *IdType2Name(SQObjectType type) -{ - switch(_RAW_TYPE(type)) - { - case _RT_NULL:return _SC("null"); - case _RT_INTEGER:return _SC("integer"); - case _RT_FLOAT:return _SC("float"); - case _RT_BOOL:return _SC("bool"); - case _RT_STRING:return _SC("string"); - case _RT_TABLE:return _SC("table"); - case _RT_ARRAY:return _SC("array"); - case _RT_GENERATOR:return _SC("generator"); - case _RT_CLOSURE: - case _RT_NATIVECLOSURE: - return _SC("function"); - case _RT_USERDATA: - case _RT_USERPOINTER: - return _SC("userdata"); - case _RT_THREAD: return _SC("thread"); - case _RT_FUNCPROTO: return _SC("function"); - case _RT_CLASS: return _SC("class"); - case _RT_INSTANCE: return _SC("instance"); - default: - return NULL; - } -} - -const SQChar *GetTypeName(const SQObjectPtr &obj1) -{ - return IdType2Name(type(obj1)); -} - -void SQVM::TypeOf(const SQObjectPtr &obj1,SQObjectPtr &dest) -{ - if(is_delegable(obj1) && _delegable(obj1)->_delegate) { - Push(obj1); - if(CallMetaMethod(_delegable(obj1),MT_TYPEOF,1,dest)) - return; - } - dest = SQString::Create(_ss(this),GetTypeName(obj1)); -} - -bool SQVM::Init(SQVM *friendvm, int stacksize) -{ - _stack.resize(stacksize); - _callsstack.reserve(4); - _stackbase = 0; - _top = 0; - if(!friendvm) - _roottable = SQTable::Create(_ss(this), 0); - else { - _roottable = friendvm->_roottable; - _errorhandler = friendvm->_errorhandler; - _debughook = friendvm->_debughook; - } - - sq_base_register(this); - return true; -} - -extern SQInstructionDesc g_InstrDesc[]; - -bool SQVM::StartCall(SQClosure *closure,int target,int nargs,int stackbase,bool tailcall) -{ - SQFunctionProto *func = _funcproto(closure->_function); - //const int outerssize = func->_outervalues.size(); - - const int paramssize = func->_parameters.size(); - const int oldtop = _top; - const int newtop = stackbase + func->_stacksize; - - - if(func->_varparams) - { - if (nargs < paramssize) { - Raise_Error(_SC("wrong number of parameters")); - return false; - } - for(int n = 0; n < nargs - paramssize; n++) { - _vargsstack.push_back(_stack[stackbase+paramssize+n]); - _stack[stackbase+paramssize+n] = _null_; - } - } - else { - if (paramssize != nargs) { - Raise_Error(_SC("wrong number of parameters")); - return false; - } - - } - - if (!tailcall) { - PUSH_CALLINFO(this, CallInfo()); - ci->_etraps = 0; - ci->_prevstkbase = stackbase - _stackbase; - ci->_target = target; - ci->_prevtop = _top - _stackbase; - ci->_ncalls = 1; - ci->_root = SQFalse; - } - else { - ci->_ncalls++; - } - ci->_vargs.size = (nargs - paramssize); - ci->_vargs.base = _vargsstack.size()-(nargs - paramssize); - ci->_closure._unVal.pClosure = closure; - ci->_closure._type = OT_CLOSURE; - ci->_iv = &func->_instructions; - ci->_literals = &func->_literals; - //grows the stack if needed - if (((unsigned int)newtop + (func->_stacksize<<1)) > _stack.size()) { - _stack.resize(_stack.size() + (func->_stacksize<<1)); - } - - _top = newtop; - _stackbase = stackbase; - ci->_ip = ci->_iv->_vals; - return true; -} - -bool SQVM::Return(int _arg0, int _arg1, SQObjectPtr &retval) -{ - if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure)) - for(int i=0;i_ncalls;i++) - CallDebugHook(_SC('r')); - - SQBool broot = ci->_root; - int last_top = _top; - int target = ci->_target; - int oldstackbase = _stackbase; - _stackbase -= ci->_prevstkbase; - _top = _stackbase + ci->_prevtop; - if(ci->_vargs.size) PopVarArgs(ci->_vargs); - POP_CALLINFO(this); - if (broot) { - if (_arg0 != MAX_FUNC_STACKSIZE) retval = _stack[oldstackbase+_arg1]; - else retval = _null_; - } - else { - if (_arg0 != MAX_FUNC_STACKSIZE) - STK(target) = _stack[oldstackbase+_arg1]; - else - STK(target) = _null_; - } - - while (last_top >= _top) _stack[last_top--].Null(); - assert(oldstackbase >= _stackbase); - return broot?true:false; -} - -#define _RET_ON_FAIL(exp) { if(!exp) return false; } - -bool SQVM::LOCAL_INC(int op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr) -{ - _RET_ON_FAIL(ARITH_OP( op , target, a, incr)); - a = target; - return true; -} - -bool SQVM::PLOCAL_INC(int op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr) -{ - SQObjectPtr trg; - _RET_ON_FAIL(ARITH_OP( op , trg, a, incr)); - target = a; - a = trg; - return true; -} - -bool SQVM::DerefInc(int op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix) -{ - SQObjectPtr tmp, tself = self, tkey = key; - if (!Get(tself, tkey, tmp, false, true)) { Raise_IdxError(tkey); return false; } - _RET_ON_FAIL(ARITH_OP( op , target, tmp, incr)) - Set(tself, tkey, target,true); - if (postfix) target = tmp; - return true; -} - -#define arg0 (_i_._arg0) -#define arg1 (_i_._arg1) -#define sarg1 (*((int *)&_i_._arg1)) -#define arg2 (_i_._arg2) -#define arg3 (_i_._arg3) -#define sarg3 (*((char *)&_i_._arg3)) - -SQRESULT SQVM::Suspend() -{ - if (_suspended) - return sq_throwerror(this, _SC("cannot suspend an already suspended vm")); - if (_nnativecalls!=2) - return sq_throwerror(this, _SC("cannot suspend through native calls/metamethods")); - return SQ_SUSPEND_FLAG; -} - -void SQVM::PopVarArgs(VarArgs &vargs) -{ - for(int n = 0; n< vargs.size; n++) - _vargsstack.pop_back(); -} - -#define _FINISH(stoploop) {finished = stoploop; return true; } -bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr -&o3,SQObjectPtr &o4,int arg_2,bool &finished) -{ - int nrefidx; - switch(type(o1)) { - case OT_TABLE: - if((nrefidx = _table(o1)->Next(o4, o2, o3)) == -1) _FINISH(true); - o4 = (SQInteger)nrefidx; _FINISH(false); - case OT_ARRAY: - if((nrefidx = _array(o1)->Next(o4, o2, o3)) == -1) _FINISH(true); - o4 = (SQInteger) nrefidx; _FINISH(false); - case OT_STRING: - if((nrefidx = _string(o1)->Next(o4, o2, o3)) == -1)_FINISH(true); - o4 = (SQInteger)nrefidx; _FINISH(false); - case OT_CLASS: - if((nrefidx = _class(o1)->Next(o4, o2, o3)) == -1)_FINISH(true); - o4 = (SQInteger)nrefidx; _FINISH(false); - case OT_USERDATA: - case OT_INSTANCE: - if(_delegable(o1)->_delegate) { - SQObjectPtr itr; - Push(o1); - Push(o4); - if(CallMetaMethod(_delegable(o1), MT_NEXTI, 2, itr)){ - o4 = o2 = itr; - if(type(itr) == OT_NULL) _FINISH(true); - if(!Get(o1, itr, o3, false,false)) { - Raise_Error(_SC("_nexti returned an invalid idx")); - return false; - } - _FINISH(false); - } - Raise_Error(_SC("_nexti failed")); - return false; - } - break; - case OT_GENERATOR: - if(_generator(o1)->_state == SQGenerator::eDead) _FINISH(true); - if(_generator(o1)->_state == SQGenerator::eSuspended) { - SQInteger idx = 0; - if(type(o4) == OT_INTEGER) { - idx = _integer(o4) + 1; - } - o2 = idx; - o4 = idx; - _generator(o1)->Resume(this, arg_2+1); - _FINISH(false); - } - } - Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1)); - return false; //cannot be hit(just to avoid warnings) -} - -bool SQVM::DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2) -{ - if(type(o1) != OT_TABLE) { Raise_Error(_SC("delegating a '%s'"), GetTypeName(o1)); return false; } - switch(type(o2)) { - case OT_TABLE: - if(!_table(o1)->SetDelegate(_table(o2))){ - Raise_Error(_SC("delegate cycle detected")); - return false; - } - break; - case OT_NULL: - _table(o1)->SetDelegate(NULL); - break; - default: - Raise_Error(_SC("using '%s' as delegate"), GetTypeName(o2)); - return false; - break; - } - trg = o1; - return true; -} -#define COND_LITERAL (arg3!=0?(*ci->_literals)[arg1]:STK(arg1)) - -#define _GUARD(exp) { if(!exp) { Raise_Error(_lasterror); SQ_THROW();} } - -#define SQ_THROW() { goto exception_trap; } - -bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func) -{ - int nouters; - SQClosure *closure = SQClosure::Create(_ss(this), func); - if(nouters = func->_outervalues.size()) { - closure->_outervalues.reserve(nouters); - for(int i = 0; i_outervalues[i]; - switch(v._type){ - case otSYMBOL: - closure->_outervalues.push_back(_null_); - if(!Get(_stack._vals[_stackbase]/*STK(0)*/, v._src, closure->_outervalues.top(), false,true)) - {Raise_IdxError(v._src); return false; } - break; - case otLOCAL: - closure->_outervalues.push_back(_stack._vals[_stackbase+_integer(v._src)]); - break; - case otOUTER: - closure->_outervalues.push_back(_closure(ci->_closure)->_outervalues[_integer(v._src)]); - break; - } - } - } - target = closure; - return true; - -} - -bool SQVM::GETVARGV_OP(SQObjectPtr &target,SQObjectPtr &index,CallInfo *ci) -{ - if(ci->_vargs.size == 0) { - Raise_Error(_SC("the function doesn't have var args")); - return false; - } - if(!sq_isnumeric(index)){ - Raise_Error(_SC("indexing 'vargv' with %s"),GetTypeName(index)); - return false; - } - int idx = tointeger(index); - if(idx < 0 || idx >= ci->_vargs.size){ Raise_Error(_SC("vargv index out of range")); return false; } - target = _vargsstack[ci->_vargs.base+idx]; - return true; -} - -bool SQVM::CLASS_OP(SQObjectPtr &target,int baseclass,int attributes) -{ - SQClass *base = NULL; - SQObjectPtr attrs; - if(baseclass != MAX_LITERALS) { - if(type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error(_SC("trying to inherit from a %s"),GetTypeName(_stack._vals[_stackbase+baseclass])); return false; } - base = _class(_stack._vals[_stackbase + baseclass]); - } - if(attributes != MAX_FUNC_STACKSIZE) { - attrs = _stack._vals[_stackbase+attributes]; - } - target = SQClass::Create(_ss(this),base); - _class(target)->_attributes = attrs; - return true; -} - -bool SQVM::IsFalse(SQObjectPtr &o) -{ - SQObjectType t = type(o); - if((t & SQOBJECT_CANBEFALSE) - && ((t == OT_NULL) || ((t == OT_INTEGER || t == OT_BOOL) && _integer(o) == 0) - || (t == OT_FLOAT && _float(o) == SQFloat(0.0)))) { - return true; - } - return false; -} - -bool SQVM::IsEqual(SQObjectPtr &o1,SQObjectPtr &o2,bool &res) -{ - if(type(o1) == type(o2)) { - res = ((_userpointer(o1) == _userpointer(o2)?true:false)); - } - else { - if(sq_isnumeric(o1) && sq_isnumeric(o2)) { - int cmpres; - if(!ObjCmp(o1, o2,cmpres)) return false; - res = (cmpres == 0); - } - else { - res = false; - } - } - return true; -} - -bool SQVM::Execute(SQObjectPtr &closure, int target, int nargs, int stackbase,SQObjectPtr &outres, ExecutionType et) -{ - if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; } - _nnativecalls++; - AutoDec ad(&_nnativecalls); - int traps = 0; - //temp_reg vars for OP_CALL - int ct_target; - bool ct_tailcall; - - switch(et) { - case ET_CALL: - if(!StartCall(_closure(closure), _top - nargs, nargs, stackbase, false)) { - //call the handler if there are no calls in the stack, if not relies on the previous node - if(ci == NULL) CallErrorHandler(_lasterror); - return false; - } - ci->_root = SQTrue; - break; - case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, target); ci->_root = SQTrue; traps += ci->_etraps; break; - case ET_RESUME_VM: - traps = _suspended_traps; - ci->_root = _suspended_root; - _suspended = SQFalse; - break; - } - -exception_restore: - // - { - for(;;) - { - const SQInstruction &_i_ = *ci->_ip++; - //dumpstack(_stackbase); - //scprintf("\n[%d] %s %d %d %d %d\n",ci->_ip-ci->_iv->_vals,g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3); - switch(_i_.op) - { - case _OP_LINE: - if(type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure)) - CallDebugHook(_SC('l'),arg1); - continue; - case _OP_LOAD: TARGET = (*ci->_literals)[arg1]; continue; - case _OP_TAILCALL: - temp_reg = STK(arg1); - if (type(temp_reg) == OT_CLOSURE){ - ct_tailcall = true; - if(ci->_vargs.size) PopVarArgs(ci->_vargs); - for (int i = 0; i < arg3; i++) STK(i) = STK(arg2 + i); - ct_target = ci->_target; - goto common_call; - } - case _OP_CALL: { - ct_tailcall = false; - ct_target = arg0; - temp_reg = STK(arg1); -common_call: - int last_top = _top; - switch (type(temp_reg)) { - case OT_CLOSURE:{ - _GUARD(StartCall(_closure(temp_reg), ct_target, arg3, ct_tailcall?_stackbase:_stackbase+arg2, ct_tailcall)); - if (_funcproto(_closure(temp_reg)->_function)->_bgenerator) { - SQGenerator *gen = SQGenerator::Create(_ss(this), _closure(temp_reg)); - _GUARD(gen->Yield(this)); - Return(1, ct_target, temp_reg); - STK(ct_target) = gen; - while (last_top >= _top) _stack[last_top--].Null(); - continue; - } - if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure)) - CallDebugHook(_SC('c')); - } - break; - case OT_NATIVECLOSURE: { - bool suspend; - _GUARD(CallNative(_nativeclosure(temp_reg), arg3, _stackbase+arg2, ct_tailcall, temp_reg,suspend)); - if(suspend){ - _suspended = SQTrue; - _suspended_target = ct_target; - _suspended_root = ci->_root; - _suspended_traps = traps; - outres = temp_reg; - return true; - } - STK(ct_target) = temp_reg; - } - break; - case OT_CLASS:{ - _GUARD(CreateClassInstance(_class(temp_reg),arg3,_stackbase+arg2,STK(ct_target))); - } - break; - case OT_TABLE: - case OT_USERDATA: - case OT_INSTANCE: - { - Push(temp_reg); - for (int i = 0; i < arg3; i++) Push(STK(arg2 + i)); - if (_delegable(temp_reg) && CallMetaMethod(_delegable(temp_reg), MT_CALL, arg3+1, temp_reg)){ - STK(ct_target) = temp_reg; - break; - } - Raise_Error(_SC("attempt to call '%s'"), GetTypeName(temp_reg)); - SQ_THROW(); - } - default: - Raise_Error(_SC("attempt to call '%s'"), GetTypeName(temp_reg)); - SQ_THROW(); - } - } - continue; - case _OP_PREPCALL: - if (!Get(STK(arg2), STK(arg1), temp_reg, false,true)) - { Raise_IdxError(STK(arg1)); SQ_THROW(); } - goto common_prepcall; - case _OP_PREPCALLK: - if (!Get(STK(arg2), (*ci->_literals)[arg1], temp_reg,false,true)) { - if(type(STK(arg2)) == OT_CLASS) { //hack? - if(_class_ddel->Get((*ci->_literals)[arg1],temp_reg)) { - STK(arg3) = STK(arg2); - TARGET = temp_reg; - continue; - } - } - { Raise_IdxError((*ci->_literals)[arg1]); SQ_THROW();} - } -common_prepcall: - if(type(STK(arg2)) == OT_CLASS) { - STK(arg3) = STK(0); // this - } - else { - STK(arg3) = STK(arg2); - } - TARGET = temp_reg; - continue; - case _OP_GETK: - if (!Get(STK(arg2), (*ci->_literals)[arg1], temp_reg, false,true)) { Raise_IdxError((*ci->_literals)[arg1]); SQ_THROW();} - TARGET = temp_reg; - continue; - case _OP_MOVE: TARGET = STK(arg1); continue; - case _OP_NEWSLOT: - _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3))); - if(arg0 != arg3) TARGET = STK(arg3); - continue; - case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue; - case _OP_SET: - if (!Set(STK(arg1), STK(arg2), STK(arg3),true)) { Raise_IdxError(STK(arg2)); SQ_THROW(); } - if (arg0 != arg3) TARGET = STK(arg3); - continue; - case _OP_GET: - if (!Get(STK(arg1), STK(arg2), temp_reg, false,true)) { Raise_IdxError(STK(arg2)); SQ_THROW(); } - TARGET = temp_reg; - continue; - case _OP_EQ:{ - bool res; - if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); } - TARGET = res?_true_:_false_; - }continue; - case _OP_NE:{ - bool res; - if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); } - TARGET = (!res)?_true_:_false_; - } continue; - case _OP_ARITH: _GUARD(ARITH_OP( arg3 , temp_reg, STK(arg2), STK(arg1))); TARGET = temp_reg; continue; - case _OP_BITW: _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue; - case _OP_RETURN: - if(type((ci)->_generator) == OT_GENERATOR) { - _generator((ci)->_generator)->Kill(); - } - if(Return(arg0, arg1, temp_reg)){ - assert(traps==0); - outres = temp_reg; - return true; - } - continue; - case _OP_LOADNULLS:{ for(unsigned int n=0;n_ip += (sarg1); continue; - case _OP_JNZ: if(!IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue; - case _OP_JZ: if(IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue; - case _OP_LOADFREEVAR: TARGET = _closure(ci->_closure)->_outervalues[arg1]; continue; - case _OP_VARGC: TARGET = SQInteger(ci->_vargs.size); continue; - case _OP_GETVARGV: - if(!GETVARGV_OP(TARGET,STK(arg1),ci)) { SQ_THROW(); } - continue; - case _OP_NEWTABLE: TARGET = SQTable::Create(_ss(this), arg1); continue; - case _OP_NEWARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue; - case _OP_APPENDARRAY: _array(STK(arg0))->Append(COND_LITERAL); continue; - case _OP_GETPARENT: - switch(type(STK(arg1))) { - case OT_TABLE: - TARGET = _table(STK(arg1))->_delegate?SQObjectPtr(_table(STK(arg1))->_delegate):_null_; - continue; - case OT_CLASS: TARGET = _class(STK(arg1))->_base?_class(STK(arg1))->_base:_null_; - continue; - } - Raise_Error(_SC("the %s type doesn't have a parent slot"), GetTypeName(STK(arg1))); - SQ_THROW(); - continue; - case _OP_COMPARITH: _GUARD(DerefInc(arg3, TARGET, STK((((unsigned int)arg1&0xFFFF0000)>>16)), STK(arg2), STK(arg1&0x0000FFFF), false)); continue; - case _OP_COMPARITHL: _GUARD(LOCAL_INC(arg3, TARGET, STK(arg1), STK(arg2))); continue; - case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false));} continue; - case _OP_INCL: {SQObjectPtr o(sarg3); _GUARD(LOCAL_INC('+',TARGET, STK(arg1), o));} continue; - case _OP_PINC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, true));} continue; - case _OP_PINCL: {SQObjectPtr o(sarg3); _GUARD(PLOCAL_INC('+',TARGET, STK(arg1), o));} continue; - case _OP_CMP: _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET)) continue; - case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, true,false)?_true_:_false_;continue; - case _OP_INSTANCEOF: - if(type(STK(arg1)) != OT_CLASS || type(STK(arg2)) != OT_INSTANCE) - {Raise_Error(_SC("cannot apply instanceof between a %s and a %s"),GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();} - TARGET = _instance(STK(arg2))->InstanceOf(_class(STK(arg1)))?_true_:_false_; - continue; - case _OP_AND: - if(IsFalse(STK(arg2))) { - TARGET = STK(arg2); - ci->_ip += (sarg1); - } - continue; - case _OP_OR: - if(!IsFalse(STK(arg2))) { - TARGET = STK(arg2); - ci->_ip += (sarg1); - } - continue; - case _OP_NEG: _GUARD(NEG_OP(TARGET,STK(arg1))); continue; - case _OP_NOT: TARGET = (IsFalse(STK(arg1))?_true_:_false_); continue; - case _OP_BWNOT: - if(type(STK(arg1)) == OT_INTEGER) { - TARGET = SQInteger(~_integer(STK(arg1))); - continue; - } - Raise_Error(_SC("attempt to perform a bitwise op on a %s"), GetTypeName(STK(arg1))); - SQ_THROW(); - case _OP_CLOSURE: { - SQClosure *c = ci->_closure._unVal.pClosure; - SQFunctionProto *fp = c->_function._unVal.pFunctionProto; - if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); } - continue; - } - case _OP_YIELD:{ - if(type(ci->_generator) == OT_GENERATOR) { - if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1); - _GUARD(_generator(ci->_generator)->Yield(this)); - traps -= ci->_etraps; - if(sarg1 != MAX_FUNC_STACKSIZE) STK(arg1) = temp_reg; - } - else { Raise_Error(_SC("trying to yield a '%s',only genenerator can be yielded"), GetTypeName(ci->_generator)); SQ_THROW();} - if(Return(arg0, arg1, temp_reg)){ - assert(traps==0); - outres = temp_reg; - return true; - } - - } - continue; - case _OP_RESUME: - if(type(STK(arg1)) != OT_GENERATOR){ Raise_Error(_SC("trying to resume a '%s',only genenerator can be resumed"), GetTypeName(STK(arg1))); SQ_THROW();} - _GUARD(_generator(STK(arg1))->Resume(this, arg0)); - traps += ci->_etraps; - continue; - case _OP_FOREACH:{ bool finished; - _GUARD(FOREACH_OP(STK(arg0),STK(arg2),STK(arg2+1),STK(arg2+2),arg2,finished)); - if(finished) ci->_ip += sarg1; } - continue; - case _OP_DELEGATE: _GUARD(DELEGATE_OP(TARGET,STK(arg1),STK(arg2))); continue; - case _OP_CLONE: - if(!Clone(STK(arg1), TARGET)) - { Raise_Error(_SC("cloning a %s"), GetTypeName(STK(arg1))); SQ_THROW();} - continue; - case _OP_TYPEOF: TypeOf(STK(arg1), TARGET); continue; - case _OP_PUSHTRAP: - _etraps.push_back(SQExceptionTrap(_top,_stackbase, &ci->_iv->_vals[(ci->_ip-ci->_iv->_vals)+arg1], arg0)); traps++; - ci->_etraps++; - continue; - case _OP_POPTRAP:{ - for(int i=0; i_etraps--; - }} - continue; - case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); continue; - case _OP_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue; - case _OP_NEWSLOTA: - _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3))); - _class(STK(arg1))->SetAttributes(STK(arg2),STK(arg2-1)); - if(arg0 != arg3) TARGET = STK(arg3); - continue; - } - - } - } -exception_trap: - { - SQObjectPtr currerror = _lasterror; -// dumpstack(_stackbase); - int n = 0; - int last_top = _top; - if(ci) { - if(traps) { - do { - if(ci->_etraps > 0) { - SQExceptionTrap &et = _etraps.top(); - ci->_ip = et._ip; - _top = et._stacksize; - _stackbase = et._stackbase; - _stack[_stackbase+et._extarget] = currerror; - _etraps.pop_back(); traps--; ci->_etraps--; - while(last_top >= _top) _stack[last_top--].Null(); - goto exception_restore; - } - //if is a native closure - if(type(ci->_closure) != OT_CLOSURE && n) - break; - if(type(ci->_generator) == OT_GENERATOR) _generator(ci->_generator)->Kill(); - PopVarArgs(ci->_vargs); - POP_CALLINFO(this); - n++; - }while(_callsstack.size()); - } - //call the hook - CallErrorHandler(currerror); - //remove call stack until a C function is found or the cstack is empty - if(ci) do{ - SQBool exitafterthisone = ci->_root; - if(type(ci->_generator) == OT_GENERATOR) _generator(ci->_generator)->Kill(); - _stackbase -= ci->_prevstkbase; - _top = _stackbase + ci->_prevtop; - PopVarArgs(ci->_vargs); - POP_CALLINFO(this); - if( (ci && type(ci->_closure) != OT_CLOSURE) || exitafterthisone) break; - }while(_callsstack.size()); - - while(last_top >= _top) _stack[last_top--].Null(); - } - _lasterror = currerror; - return false; - } - assert(0); -} - -bool SQVM::CreateClassInstance(SQClass *theclass, int nargs, int stackbase, SQObjectPtr &retval) -{ - SQObjectPtr constr; - SQObjectPtr inst = theclass->CreateInstance(); - _stack[stackbase] = inst; - if(theclass->Get(_ss(this)->_constructoridx,constr)) { - if(!Call(constr,nargs,stackbase,constr)) - return false; - } - retval = inst; - return true; -} - -void SQVM::CallErrorHandler(SQObjectPtr &error) -{ - if(type(_errorhandler) != OT_NULL) { - SQObjectPtr out; - Push(_roottable); Push(error); - Call(_errorhandler, 2, _top-2, out); - Pop(2); - } -} - -void SQVM::CallDebugHook(int type,int forcedline) -{ - SQObjectPtr temp_reg; - int nparams=5; - SQFunctionProto *func=_funcproto(_closure(ci->_closure)->_function); - Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name); - Call(_debughook,nparams,_top-nparams,temp_reg); - Pop(nparams); -} - -bool SQVM::CallNative(SQNativeClosure *nclosure,int nargs,int stackbase,bool tailcall,SQObjectPtr &retval,bool &suspend) -{ - if (_nnativecalls + 1 > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; } - int nparamscheck = nclosure->_nparamscheck; - if(((nparamscheck > 0) && (nparamscheck != nargs)) - || ((nparamscheck < 0) && (nargs < (-nparamscheck)))) { - Raise_Error(_SC("wrong number of parameters")); - return false; - } - - int tcs; - if(tcs = nclosure->_typecheck.size()) { - for(int i = 0; i < nargs && i < tcs; i++) - if((nclosure->_typecheck[i] != -1) && !(type(_stack[stackbase+i]) & nclosure->_typecheck[i])) { - Raise_ParamTypeError(i,nclosure->_typecheck[i],type(_stack[stackbase+i])); - return false; - } - } - _nnativecalls++; - if ((_top + MIN_STACK_OVERHEAD) > (int)_stack.size()) { - _stack.resize(_stack.size() + (MIN_STACK_OVERHEAD<<1)); - } - int oldtop = _top; - int oldstackbase = _stackbase; - _top = stackbase + nargs; - PUSH_CALLINFO(this, CallInfo()); - ci->_etraps = 0; - ci->_closure._unVal.pNativeClosure = nclosure; - ci->_closure._type = OT_NATIVECLOSURE; - ci->_prevstkbase = stackbase - _stackbase; - ci->_ncalls = 1; - _stackbase = stackbase; - //push free variables - int outers = nclosure->_outervalues.size(); - for (int i = 0; i < outers; i++) { - Push(nclosure->_outervalues[i]); - } - ci->_prevtop = (oldtop - oldstackbase); - int ret = (nclosure->_function)(this); - _nnativecalls--; - suspend = false; - if( ret == SQ_SUSPEND_FLAG) suspend = true; - else if (ret < 0) { - _stackbase = oldstackbase; - _top = oldtop; - POP_CALLINFO(this); - Raise_Error(_lasterror); - return false; - } - - if (ret != 0){ retval = TOP(); } - else { retval = _null_; } - _stackbase = oldstackbase; - _top = oldtop; - POP_CALLINFO(this); - return true; -} - -bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw, bool fetchroot) -{ - switch(type(self)){ - case OT_TABLE: - if(_table(self)->Get(key,dest))return true; - break; - case OT_ARRAY: - if(sq_isnumeric(key)){ - return _array(self)->Get(tointeger(key),dest); - } - break; - case OT_INSTANCE: - if(_instance(self)->Get(key,dest)) return true; - break; - } - if(FallBackGet(self,key,dest,raw)) return true; - - if(fetchroot) { - if(_rawval(STK(0)) == _rawval(self) && - type(STK(0)) == type(self)) { - return _table(_roottable)->Get(key,dest); - } - } - return false; -} - -bool SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw) -{ - switch(type(self)){ - case OT_CLASS: - return _class(self)->Get(key,dest); - break; - case OT_TABLE: - case OT_USERDATA: - //delegation - if(_delegable(self)->_delegate) { - if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,raw,false)) - return true; - if(raw)return false; - Push(self);Push(key); - if(CallMetaMethod(_delegable(self),MT_GET,2,dest)) - return true; - } - if(type(self) == OT_TABLE) { - if(raw) return false; - return _table_ddel->Get(key,dest); - } - return false; - break; - case OT_ARRAY: - if(raw)return false; - return _array_ddel->Get(key,dest); - case OT_STRING: - if(sq_isnumeric(key)){ - SQInteger n=tointeger(key); - if(abs(n)<_string(self)->_len){ - if(n<0)n=_string(self)->_len-n; - dest=SQInteger(_stringval(self)[n]); - return true; - } - return false; - } - else { - if(raw)return false; - return _string_ddel->Get(key,dest); - } - break; - case OT_INSTANCE: - if(raw)return false; - Push(self);Push(key); - if(!CallMetaMethod(_delegable(self),MT_GET,2,dest)) { - return _instance_ddel->Get(key,dest); - } - return true; - case OT_INTEGER:case OT_FLOAT:case OT_BOOL: - if(raw)return false; - return _number_ddel->Get(key,dest); - case OT_GENERATOR: - if(raw)return false; - return _generator_ddel->Get(key,dest); - case OT_CLOSURE: case OT_NATIVECLOSURE: - if(raw)return false; - return _closure_ddel->Get(key,dest); - case OT_THREAD: - if(raw)return false; - return _thread_ddel->Get(key,dest); - default:return false; - } - return false; -} - -bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool fetchroot) -{ - switch(type(self)){ - case OT_TABLE: - if(_table(self)->Set(key,val)) - return true; - if(_table(self)->_delegate) { - if(Set(_table(self)->_delegate,key,val,false)) { - return true; - } - } - //keeps going - case OT_USERDATA: - if(_delegable(self)->_delegate) { - SQObjectPtr t; - Push(self);Push(key);Push(val); - if(CallMetaMethod(_delegable(self),MT_SET,3,t)) return true; - } - break; - case OT_INSTANCE:{ - if(_instance(self)->Set(key,val)) - return true; - SQObjectPtr t; - Push(self);Push(key);Push(val); - if(CallMetaMethod(_delegable(self),MT_SET,3,t)) return true; - } - break; - case OT_ARRAY: - if(!sq_isnumeric(key)) {Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); return false; } - return _array(self)->Set(tointeger(key),val); - default: - Raise_Error(_SC("trying to set '%s'"),GetTypeName(self)); - return false; - } - if(fetchroot) { - if(_rawval(STK(0)) == _rawval(self) && - type(STK(0)) == type(self)) { - return _table(_roottable)->Set(key,val); - } - } - return false; -} - -bool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target) -{ - SQObjectPtr temp_reg; - switch(type(self)){ - case OT_TABLE: - target = _table(self)->Clone(); - goto cloned_mt; - case OT_INSTANCE: - target = _instance(self)->Clone(_ss(this)); -cloned_mt: - if(_delegable(target)->_delegate){ - Push(target); - Push(self); - CallMetaMethod(_delegable(target),MT_CLONED,2,temp_reg); - } - return true; - case OT_ARRAY: - target=_array(self)->Clone(); - return true; - default: return false; - } -} - -bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val) -{ - if(type(key) == OT_NULL) { Raise_Error(_SC("null cannot be used as index")); return false; } - switch(type(self)) { - case OT_TABLE: { - bool rawcall = true; - if(_table(self)->_delegate) { - SQObjectPtr res; - if(!_table(self)->Get(key,res)) { - Push(self);Push(key);Push(val); - rawcall = !CallMetaMethod(_table(self),MT_NEWSLOT,3,res); - } - } - if(rawcall) _table(self)->NewSlot(key,val); //cannot fail - - break;} - case OT_CLASS: - if(!_class(self)->NewSlot(key,val)) { - if(_class(self)->_locked) { - Raise_Error(_SC("trying to modify a class that has already been instantiated")); - return false; - } - else { - SQObjectPtr oval = PrintObjVal(key); - Raise_Error(_SC("the property '%s' already exists"),_stringval(oval)); - return false; - } - } - break; - default: - Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); - return false; - break; - } - return true; -} - -bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &res) -{ - switch(type(self)) { - case OT_TABLE: - case OT_INSTANCE: - case OT_USERDATA: { - SQObjectPtr t; - bool handled = false; - if(_delegable(self)->_delegate) { - Push(self);Push(key); - handled = CallMetaMethod(_delegable(self),MT_DELSLOT,2,t); - } - - if(!handled) { - if(type(self) == OT_TABLE) { - if(_table(self)->Get(key,t)) { - _table(self)->Remove(key); - } - else { - Raise_IdxError((SQObject &)key); - return false; - } - } - else { - Raise_Error(_SC("cannot delete a slot from %s"),GetTypeName(self)); - return false; - } - } - res = t; - } - break; - default: - Raise_Error(_SC("attempt to delete a slot from a %s"),GetTypeName(self)); - return false; - } - return true; -} - -bool SQVM::Call(SQObjectPtr &closure,int nparams,int stackbase,SQObjectPtr &outres) -{ -#ifdef _DEBUG -int prevstackbase = _stackbase; -#endif - switch(type(closure)) { - case OT_CLOSURE: - return Execute(closure, _top - nparams, nparams, stackbase,outres); - break; - case OT_NATIVECLOSURE:{ - bool suspend; - return CallNative(_nativeclosure(closure), nparams, stackbase, false, outres,suspend); - - } - break; - case OT_CLASS: - return CreateClassInstance(_class(closure),nparams,stackbase,outres); - break; - default: - return false; - } -#ifdef _DEBUG - if(!_suspended) { - assert(_stackbase == prevstackbase); - } -#endif - return true; -} - -bool SQVM::CallMetaMethod(SQDelegable *del,SQMetaMethod mm,int nparams,SQObjectPtr &outres) -{ - SQObjectPtr closure; - if(del->GetMetaMethod(mm, closure)) { - if(Call(closure, nparams, _top - nparams, outres)) { - Pop(nparams); - return true; - } - } - Pop(nparams); - return false; -} - -void SQVM::Remove(int n) { - n = (n >= 0)?n + _stackbase - 1:_top + n; - for(int i = n; i < _top; i++){ - _stack[i] = _stack[i+1]; - } - _stack[_top] = _null_; - _top--; -} - - -#ifdef _DEBUG_DUMP -void SQVM::dumpstack(int stackbase,bool dumpall) -{ - int size=dumpall?_stack.size():_top; - int n=0; - scprintf(_SC("\n>>>>stack dump<<<<\n")); - CallInfo &ci=_callsstack.back(); - scprintf(_SC("IP: %d\n"),ci._ip); - scprintf(_SC("prev stack base: %d\n"),ci._prevstkbase); - scprintf(_SC("prev top: %d\n"),ci._prevtop); - for(int i=0;i"));else scprintf(_SC(" ")); - scprintf(_SC("[%d]:"),n); - switch(type(obj)){ - case OT_FLOAT: scprintf(_SC("FLOAT %.3f"),_float(obj));break; - case OT_INTEGER: scprintf(_SC("INTEGER %d"),_integer(obj));break; - case OT_BOOL: scprintf(_SC("BOOL %s"),_integer(obj)?"true":"false");break; - case OT_STRING: scprintf(_SC("STRING %s"),_stringval(obj));break; - case OT_NULL: scprintf(_SC("NULL")); break; - case OT_TABLE: scprintf(_SC("TABLE %p[%p]"),_table(obj),_table(obj)->_delegate);break; - case OT_ARRAY: scprintf(_SC("ARRAY %p"),_array(obj));break; - case OT_CLOSURE: scprintf(_SC("CLOSURE [%p]"),_closure(obj));break; - case OT_NATIVECLOSURE: scprintf(_SC("NATIVECLOSURE"));break; - case OT_USERDATA: scprintf(_SC("USERDATA %p[%p]"),_userdataval(obj),_userdata(obj)->_delegate);break; - case OT_GENERATOR: scprintf(_SC("GENERATOR"));break; - case OT_THREAD: scprintf(_SC("THREAD [%p]"),_thread(obj));break; - case OT_USERPOINTER: scprintf(_SC("USERPOINTER %p"),_userpointer(obj));break; - case OT_CLASS: scprintf(_SC("CLASS %p"),_class(obj));break; - case OT_INSTANCE: scprintf(_SC("INSTANCE %p"),_instance(obj));break; - default: - assert(0); - break; - }; - scprintf(_SC("\n")); - ++n; - } -} - -#endif +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include +#include +#include "sqopcodes.h" +#include "sqfuncproto.h" +#include "sqvm.h" +#include "sqclosure.h" +#include "sqstring.h" +#include "sqtable.h" +#include "squserdata.h" +#include "sqarray.h" +#include "sqclass.h" + +#define TOP() (_stack[_top-1]) + +bool SQVM::BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2) +{ + SQInteger res; + SQInteger i1 = _integer(o1), i2 = _integer(o2); + if((type(o1)==OT_INTEGER) && (type(o2)==OT_INTEGER)) + { + switch(op) { + case BW_AND: res = i1 & i2; break; + case BW_OR: res = i1 | i2; break; + case BW_XOR: res = i1 ^ i2; break; + case BW_SHIFTL: res = i1 << i2; break; + case BW_SHIFTR: res = i1 >> i2; break; + case BW_USHIFTR:res = (SQInteger)(*((SQUnsignedInteger*)&i1) >> i2); break; + default: { Raise_Error(_SC("internal vm error bitwise op failed")); return false; } + } + } + else { Raise_Error(_SC("bitwise op between '%s' and '%s'"),GetTypeName(o1),GetTypeName(o2)); return false;} + trg = res; + return true; +} + +bool SQVM::ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2) +{ + if(sq_isnumeric(o1) && sq_isnumeric(o2)) { + if((type(o1)==OT_INTEGER) && (type(o2)==OT_INTEGER)) { + switch(op) { + case '+': trg = _integer(o1) + _integer(o2); break; + case '-': trg = _integer(o1) - _integer(o2); break; + case '/': if(_integer(o2) == 0) { Raise_Error(_SC("division by zero")); return false; } + trg = _integer(o1) / _integer(o2); + break; + case '*': trg = _integer(o1) * _integer(o2); break; + case '%': trg = _integer(o1) % _integer(o2); break; + } + }else{ + switch(op) { + case '+': trg = tofloat(o1) + tofloat(o2); break; + case '-': trg = tofloat(o1) - tofloat(o2); break; + case '/': trg = tofloat(o1) / tofloat(o2); break; + case '*': trg = tofloat(o1) * tofloat(o2); break; + case '%': trg = SQFloat(fmod((double)tofloat(o1),(double)tofloat(o2))); break; + } + } + } else { + if(op == '+' && (type(o1) == OT_STRING || type(o2) == OT_STRING)){ + if(!StringCat(o1, o2, trg)) return false; + } + else if(!ArithMetaMethod(op,o1,o2,trg)) { + Raise_Error(_SC("arith op %c on between '%s' and '%s'"),op,GetTypeName(o1),GetTypeName(o2)); return false; + } + } + return true; +} + +SQVM::SQVM(SQSharedState *ss) +{ + _sharedstate=ss; + _suspended = SQFalse; + _suspended_target=-1; + _suspended_root = SQFalse; + _suspended_traps=-1; + _foreignptr=NULL; + _nnativecalls=0; + _lasterror = _null_; + _errorhandler = _null_; + _debughook = _null_; + INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); +} + +void SQVM::Finalize() +{ + _roottable = _null_; + _lasterror = _null_; + _errorhandler = _null_; + _debughook = _null_; + temp_reg = _null_; + SQInteger size=_stack.size(); + for(SQInteger i=0;i_gc_chain,this); +} + +bool SQVM::ArithMetaMethod(SQInteger op,const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &dest) +{ + SQMetaMethod mm; + switch(op){ + case _SC('+'): mm=MT_ADD; break; + case _SC('-'): mm=MT_SUB; break; + case _SC('/'): mm=MT_DIV; break; + case _SC('*'): mm=MT_MUL; break; + case _SC('%'): mm=MT_MODULO; break; + } + if(is_delegable(o1) && _delegable(o1)->_delegate) { + Push(o1);Push(o2); + return CallMetaMethod(_delegable(o1),mm,2,dest); + } + return false; +} + +bool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o) +{ + + switch(type(o)) { + case OT_INTEGER: + trg = -_integer(o); + return true; + case OT_FLOAT: + trg = -_float(o); + return true; + case OT_TABLE: + case OT_USERDATA: + case OT_INSTANCE: + if(_delegable(o)->_delegate) { + Push(o); + if(CallMetaMethod(_delegable(o), MT_UNM, 1, temp_reg)) { + trg = temp_reg; + return true; + } + } + return true; + + } + Raise_Error(_SC("attempt to negate a %s"), GetTypeName(o)); + return false; +} + +#define _RET_SUCCEED(exp) { result = (exp); return true; } +bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result) +{ + if(type(o1)==type(o2)){ + if(_userpointer(o1)==_userpointer(o2))_RET_SUCCEED(0); + SQObjectPtr res; + switch(type(o1)){ + case OT_STRING: + _RET_SUCCEED(scstrcmp(_stringval(o1),_stringval(o2))); + case OT_INTEGER: + _RET_SUCCEED(_integer(o1)-_integer(o2)); + case OT_FLOAT: + _RET_SUCCEED((_float(o1)<_float(o2))?-1:1); + case OT_TABLE: + case OT_USERDATA: + case OT_INSTANCE: + Push(o1);Push(o2); + if(_delegable(o1)->_delegate)CallMetaMethod(_delegable(o1),MT_CMP,2,res); + break; + } + if(type(res)!=OT_INTEGER) { Raise_CompareError(o1,o2); return false; } + _RET_SUCCEED(_integer(res)); + } + else{ + if(sq_isnumeric(o1) && sq_isnumeric(o2)){ + if((type(o1)==OT_INTEGER) && (type(o2)==OT_FLOAT)) { + if( _integer(o1)==_float(o2) ) { _RET_SUCCEED(0); } + else if( _integer(o1)<_float(o2) ) { _RET_SUCCEED(-1); } + _RET_SUCCEED(1); + } + else{ + if( _float(o1)==_integer(o2) ) { _RET_SUCCEED(0); } + else if( _float(o1)<_integer(o2) ) { _RET_SUCCEED(-1); } + _RET_SUCCEED(1); + } + } + else if(type(o1)==OT_NULL) {_RET_SUCCEED(-1);} + else if(type(o2)==OT_NULL) {_RET_SUCCEED(1);} + else { Raise_CompareError(o1,o2); return false; } + + } + assert(0); + _RET_SUCCEED(0); //cannot happen +} + +bool SQVM::CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res) +{ + SQInteger r; + if(ObjCmp(o1,o2,r)) { + switch(op) { + case CMP_G: res = (r > 0)?_true_:_false_; return true; + case CMP_GE: res = (r >= 0)?_true_:_false_; return true; + case CMP_L: res = (r < 0)?_true_:_false_; return true; + case CMP_LE: res = (r <= 0)?_true_:_false_; return true; + + } + assert(0); + } + return false; +} + +void SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res) +{ + switch(type(o)) { + case OT_STRING: + res = o; + return; + case OT_FLOAT: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),_SC("%g"),_float(o)); + break; + case OT_INTEGER: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),_SC("%d"),_integer(o)); + break; + case OT_BOOL: + scsprintf(_sp(rsl(6)),_integer(o)?_SC("true"):_SC("false")); + break; + case OT_TABLE: + case OT_USERDATA: + case OT_INSTANCE: + if(_delegable(o)->_delegate) { + Push(o); + if(CallMetaMethod(_delegable(o),MT_TOSTRING,1,res)) { + if(type(res) == OT_STRING) + return; + //else keeps going to the default + } + } + default: + scsprintf(_sp(rsl(sizeof(void*)+20)),_SC("(%s : 0x%p)"),GetTypeName(o),_rawval(o)); + } + res = SQString::Create(_ss(this),_spval); + return; +} + + +bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest) +{ + switch(type(obj)) + { + case OT_STRING: + switch(type(str)){ + case OT_STRING: { + SQInteger l=_string(str)->_len,ol=_string(obj)->_len; + SQChar *s=_sp(rsl(l+ol+1)); + memcpy(s,_stringval(str),rsl(l));memcpy(s+l,_stringval(obj),rsl(ol));s[l+ol]=_SC('\0'); + break; + } + case OT_FLOAT: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(obj)->_len+1)),_SC("%g%s"),_float(str),_stringval(obj)); + break; + case OT_INTEGER: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(obj)->_len+1)),_SC("%d%s"),_integer(str),_stringval(obj)); + break; + default: + Raise_Error(_SC("string concatenation between '%s' and '%s'"),GetTypeName(str),GetTypeName(obj)); + return false; + } + dest=SQString::Create(_ss(this),_spval); + break; + case OT_FLOAT: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(str)->_len+1)),_SC("%s%g"),_stringval(str),_float(obj)); + dest=SQString::Create(_ss(this),_spval); + break; + case OT_INTEGER: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(str)->_len+1)),_SC("%s%d"),_stringval(str),_integer(obj)); + dest=SQString::Create(_ss(this),_spval); + break; + default: + Raise_Error(_SC("string concatenation between '%s' and '%s'"),GetTypeName(str),GetTypeName(obj)); + return false; + } + return true; +} + +const SQChar *IdType2Name(SQObjectType type) +{ + switch(_RAW_TYPE(type)) + { + case _RT_NULL:return _SC("null"); + case _RT_INTEGER:return _SC("integer"); + case _RT_FLOAT:return _SC("float"); + case _RT_BOOL:return _SC("bool"); + case _RT_STRING:return _SC("string"); + case _RT_TABLE:return _SC("table"); + case _RT_ARRAY:return _SC("array"); + case _RT_GENERATOR:return _SC("generator"); + case _RT_CLOSURE: + case _RT_NATIVECLOSURE: + return _SC("function"); + case _RT_USERDATA: + case _RT_USERPOINTER: + return _SC("userdata"); + case _RT_THREAD: return _SC("thread"); + case _RT_FUNCPROTO: return _SC("function"); + case _RT_CLASS: return _SC("class"); + case _RT_INSTANCE: return _SC("instance"); + case _RT_WEAKREF: return _SC("weakref"); + default: + return NULL; + } +} + +const SQChar *GetTypeName(const SQObjectPtr &obj1) +{ + return IdType2Name(type(obj1)); +} + +void SQVM::TypeOf(const SQObjectPtr &obj1,SQObjectPtr &dest) +{ + if(is_delegable(obj1) && _delegable(obj1)->_delegate) { + Push(obj1); + if(CallMetaMethod(_delegable(obj1),MT_TYPEOF,1,dest)) + return; + } + dest = SQString::Create(_ss(this),GetTypeName(obj1)); +} + +bool SQVM::Init(SQVM *friendvm, SQInteger stacksize) +{ + _stack.resize(stacksize); + _callsstack.reserve(4); + _stackbase = 0; + _top = 0; + if(!friendvm) + _roottable = SQTable::Create(_ss(this), 0); + else { + _roottable = friendvm->_roottable; + _errorhandler = friendvm->_errorhandler; + _debughook = friendvm->_debughook; + } + + sq_base_register(this); + return true; +} + +extern SQInstructionDesc g_InstrDesc[]; + +bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger nargs,SQInteger stackbase,bool tailcall) +{ + SQFunctionProto *func = _funcproto(closure->_function); + //const SQInteger outerssize = func->_outervalues.size(); + + const SQInteger paramssize = func->_parameters.size(); + const SQInteger oldtop = _top; + const SQInteger newtop = stackbase + func->_stacksize; + + + if (paramssize != nargs) { + if(func->_varparams) + { + if (nargs < paramssize) { + Raise_Error(_SC("wrong number of parameters")); + return false; + } + for(SQInteger n = 0; n < nargs - paramssize; n++) { + _vargsstack.push_back(_stack[stackbase+paramssize+n]); + _stack[stackbase+paramssize+n] = _null_; + } + } + else { + Raise_Error(_SC("wrong number of parameters")); + return false; + } + } + + if (!tailcall) { + PUSH_CALLINFO(this, CallInfo()); + ci->_etraps = 0; + ci->_prevstkbase = stackbase - _stackbase; + ci->_target = target; + ci->_prevtop = _top - _stackbase; + ci->_ncalls = 1; + ci->_root = SQFalse; + } + else { + ci->_ncalls++; + } + ci->_vargs.size = (nargs - paramssize); + ci->_vargs.base = _vargsstack.size()-(nargs - paramssize); + ci->_closure._unVal.pClosure = closure; + ci->_closure._type = OT_CLOSURE; + ci->_iv = &func->_instructions; + ci->_literals = &func->_literals; + //grows the stack if needed + if (((SQUnsignedInteger)newtop + (func->_stacksize<<1)) > _stack.size()) { + _stack.resize(_stack.size() + (func->_stacksize<<1)); + } + + _top = newtop; + _stackbase = stackbase; + ci->_ip = ci->_iv->_vals; + return true; +} + +bool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval) +{ + if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure)) + for(SQInteger i=0;i_ncalls;i++) + CallDebugHook(_SC('r')); + + SQBool broot = ci->_root; + SQInteger last_top = _top; + SQInteger target = ci->_target; + SQInteger oldstackbase = _stackbase; + _stackbase -= ci->_prevstkbase; + _top = _stackbase + ci->_prevtop; + if(ci->_vargs.size) PopVarArgs(ci->_vargs); + POP_CALLINFO(this); + if (broot) { + if (_arg0 != MAX_FUNC_STACKSIZE) retval = _stack[oldstackbase+_arg1]; + else retval = _null_; + } + else { + if (_arg0 != MAX_FUNC_STACKSIZE) + STK(target) = _stack[oldstackbase+_arg1]; + else + STK(target) = _null_; + } + + while (last_top >= _top) _stack[last_top--].Null(); + assert(oldstackbase >= _stackbase); + return broot?true:false; +} + +#define _RET_ON_FAIL(exp) { if(!exp) return false; } + +bool SQVM::LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr) +{ + _RET_ON_FAIL(ARITH_OP( op , target, a, incr)); + a = target; + return true; +} + +bool SQVM::PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr) +{ + SQObjectPtr trg; + _RET_ON_FAIL(ARITH_OP( op , trg, a, incr)); + target = a; + a = trg; + return true; +} + +bool SQVM::DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix) +{ + SQObjectPtr tmp, tself = self, tkey = key; + if (!Get(tself, tkey, tmp, false, true)) { Raise_IdxError(tkey); return false; } + _RET_ON_FAIL(ARITH_OP( op , target, tmp, incr)) + Set(tself, tkey, target,true); + if (postfix) target = tmp; + return true; +} + +#define arg0 (_i_._arg0) +#define arg1 (_i_._arg1) +#define sarg1 (*((SQInteger *)&_i_._arg1)) +#define arg2 (_i_._arg2) +#define arg3 (_i_._arg3) +#define sarg3 (*((char *)&_i_._arg3)) + +SQRESULT SQVM::Suspend() +{ + if (_suspended) + return sq_throwerror(this, _SC("cannot suspend an already suspended vm")); + if (_nnativecalls!=2) + return sq_throwerror(this, _SC("cannot suspend through native calls/metamethods")); + return SQ_SUSPEND_FLAG; +} + +void SQVM::PopVarArgs(VarArgs &vargs) +{ + for(SQInteger n = 0; n< vargs.size; n++) + _vargsstack.pop_back(); +} + +#define _FINISH(stoploop) {finished = stoploop; return true; } +bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr +&o3,SQObjectPtr &o4,SQInteger arg_2,bool &finished) +{ + SQInteger nrefidx; + switch(type(o1)) { + case OT_TABLE: + if((nrefidx = _table(o1)->Next(false,o4, o2, o3)) == -1) _FINISH(true); + o4 = (SQInteger)nrefidx; _FINISH(false); + case OT_ARRAY: + if((nrefidx = _array(o1)->Next(o4, o2, o3)) == -1) _FINISH(true); + o4 = (SQInteger) nrefidx; _FINISH(false); + case OT_STRING: + if((nrefidx = _string(o1)->Next(o4, o2, o3)) == -1)_FINISH(true); + o4 = (SQInteger)nrefidx; _FINISH(false); + case OT_CLASS: + if((nrefidx = _class(o1)->Next(o4, o2, o3)) == -1)_FINISH(true); + o4 = (SQInteger)nrefidx; _FINISH(false); + case OT_USERDATA: + case OT_INSTANCE: + if(_delegable(o1)->_delegate) { + SQObjectPtr itr; + Push(o1); + Push(o4); + if(CallMetaMethod(_delegable(o1), MT_NEXTI, 2, itr)){ + o4 = o2 = itr; + if(type(itr) == OT_NULL) _FINISH(true); + if(!Get(o1, itr, o3, false,false)) { + Raise_Error(_SC("_nexti returned an invalid idx")); + return false; + } + _FINISH(false); + } + Raise_Error(_SC("_nexti failed")); + return false; + } + break; + case OT_GENERATOR: + if(_generator(o1)->_state == SQGenerator::eDead) _FINISH(true); + if(_generator(o1)->_state == SQGenerator::eSuspended) { + SQInteger idx = 0; + if(type(o4) == OT_INTEGER) { + idx = _integer(o4) + 1; + } + o2 = idx; + o4 = idx; + _generator(o1)->Resume(this, arg_2+1); + _FINISH(false); + } + } + Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1)); + return false; //cannot be hit(just to avoid warnings) +} + +bool SQVM::DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2) +{ + if(type(o1) != OT_TABLE) { Raise_Error(_SC("delegating a '%s'"), GetTypeName(o1)); return false; } + switch(type(o2)) { + case OT_TABLE: + if(!_table(o1)->SetDelegate(_table(o2))){ + Raise_Error(_SC("delegate cycle detected")); + return false; + } + break; + case OT_NULL: + _table(o1)->SetDelegate(NULL); + break; + default: + Raise_Error(_SC("using '%s' as delegate"), GetTypeName(o2)); + return false; + break; + } + trg = o1; + return true; +} +#define COND_LITERAL (arg3!=0?(*ci->_literals)[arg1]:STK(arg1)) + +#define _GUARD(exp) { if(!exp) { Raise_Error(_lasterror); SQ_THROW();} } + +#define SQ_THROW() { goto exception_trap; } + +bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func) +{ + SQInteger nouters; + SQClosure *closure = SQClosure::Create(_ss(this), func); + if(nouters = func->_outervalues.size()) { + closure->_outervalues.reserve(nouters); + for(SQInteger i = 0; i_outervalues[i]; + switch(v._type){ + case otSYMBOL: + closure->_outervalues.push_back(_null_); + if(!Get(_stack._vals[_stackbase]/*STK(0)*/, v._src, closure->_outervalues.top(), false,true)) + {Raise_IdxError(v._src); return false; } + break; + case otLOCAL: + closure->_outervalues.push_back(_stack._vals[_stackbase+_integer(v._src)]); + break; + case otOUTER: + closure->_outervalues.push_back(_closure(ci->_closure)->_outervalues[_integer(v._src)]); + break; + } + } + } + target = closure; + return true; + +} + +bool SQVM::GETVARGV_OP(SQObjectPtr &target,SQObjectPtr &index,CallInfo *ci) +{ + if(ci->_vargs.size == 0) { + Raise_Error(_SC("the function doesn't have var args")); + return false; + } + if(!sq_isnumeric(index)){ + Raise_Error(_SC("indexing 'vargv' with %s"),GetTypeName(index)); + return false; + } + SQInteger idx = tointeger(index); + if(idx < 0 || idx >= ci->_vargs.size){ Raise_Error(_SC("vargv index out of range")); return false; } + target = _vargsstack[ci->_vargs.base+idx]; + return true; +} + +bool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass,SQInteger attributes) +{ + SQClass *base = NULL; + SQObjectPtr attrs; + if(baseclass != MAX_LITERALS) { + if(type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error(_SC("trying to inherit from a %s"),GetTypeName(_stack._vals[_stackbase+baseclass])); return false; } + base = _class(_stack._vals[_stackbase + baseclass]); + } + if(attributes != MAX_FUNC_STACKSIZE) { + attrs = _stack._vals[_stackbase+attributes]; + } + target = SQClass::Create(_ss(this),base); + _class(target)->_attributes = attrs; + return true; +} + + + +bool SQVM::IsEqual(SQObjectPtr &o1,SQObjectPtr &o2,bool &res) +{ + if(type(o1) == type(o2)) { + res = ((_userpointer(o1) == _userpointer(o2)?true:false)); + } + else { + if(sq_isnumeric(o1) && sq_isnumeric(o2)) { + SQInteger cmpres; + if(!ObjCmp(o1, o2,cmpres)) return false; + res = (cmpres == 0); + } + else { + res = false; + } + } + return true; +} + +bool SQVM::Execute(SQObjectPtr &closure, SQInteger target, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, ExecutionType et) +{ + if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; } + _nnativecalls++; + AutoDec ad(&_nnativecalls); + SQInteger traps = 0; + //temp_reg vars for OP_CALL + SQInteger ct_target; + bool ct_tailcall; + + switch(et) { + case ET_CALL: + if(!StartCall(_closure(closure), _top - nargs, nargs, stackbase, false)) { + //call the handler if there are no calls in the stack, if not relies on the previous node + if(ci == NULL) CallErrorHandler(_lasterror); + return false; + } + ci->_root = SQTrue; + break; + case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, target); ci->_root = SQTrue; traps += ci->_etraps; break; + case ET_RESUME_VM: + traps = _suspended_traps; + ci->_root = _suspended_root; + _suspended = SQFalse; + break; + } + +exception_restore: + // + { + for(;;) + { + const SQInstruction &_i_ = *ci->_ip++; + //dumpstack(_stackbase); + //scprintf("\n[%d] %s %d %d %d %d\n",ci->_ip-ci->_iv->_vals,g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3); + switch(_i_.op) + { + case _OP_LINE: + if(type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure)) + CallDebugHook(_SC('l'),arg1); + continue; + case _OP_LOAD: TARGET = (*ci->_literals)[arg1]; continue; + case _OP_DLOAD: TARGET = (*ci->_literals)[arg1]; STK(arg2) = (*ci->_literals)[arg3];continue; + case _OP_TAILCALL: + temp_reg = STK(arg1); + if (type(temp_reg) == OT_CLOSURE){ + ct_tailcall = true; + if(ci->_vargs.size) PopVarArgs(ci->_vargs); + for (SQInteger i = 0; i < arg3; i++) STK(i) = STK(arg2 + i); + ct_target = ci->_target; + goto common_call; + } + case _OP_CALL: { + ct_tailcall = false; + ct_target = arg0; + temp_reg = STK(arg1); +common_call: + SQInteger last_top = _top; + switch (type(temp_reg)) { + case OT_CLOSURE:{ + _GUARD(StartCall(_closure(temp_reg), ct_target, arg3, ct_tailcall?_stackbase:_stackbase+arg2, ct_tailcall)); + if (_funcproto(_closure(temp_reg)->_function)->_bgenerator) { + SQGenerator *gen = SQGenerator::Create(_ss(this), _closure(temp_reg)); + _GUARD(gen->Yield(this)); + Return(1, ct_target, temp_reg); + STK(ct_target) = gen; + while (last_top >= _top) _stack[last_top--].Null(); + continue; + } + if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure)) + CallDebugHook(_SC('c')); + } + break; + case OT_NATIVECLOSURE: { + bool suspend; + _GUARD(CallNative(_nativeclosure(temp_reg), arg3, _stackbase+arg2, ct_tailcall, temp_reg,suspend)); + if(suspend){ + _suspended = SQTrue; + _suspended_target = ct_target; + _suspended_root = ci->_root; + _suspended_traps = traps; + outres = temp_reg; + return true; + } + STK(ct_target) = temp_reg; + } + break; + case OT_CLASS:{ + _GUARD(CreateClassInstance(_class(temp_reg),arg3,_stackbase+arg2,STK(ct_target))); + } + break; + case OT_TABLE: + case OT_USERDATA: + case OT_INSTANCE: + { + Push(temp_reg); + for (SQInteger i = 0; i < arg3; i++) Push(STK(arg2 + i)); + if (_delegable(temp_reg) && CallMetaMethod(_delegable(temp_reg), MT_CALL, arg3+1, temp_reg)){ + STK(ct_target) = temp_reg; + break; + } + Raise_Error(_SC("attempt to call '%s'"), GetTypeName(temp_reg)); + SQ_THROW(); + } + default: + Raise_Error(_SC("attempt to call '%s'"), GetTypeName(temp_reg)); + SQ_THROW(); + } + } + continue; + case _OP_PREPCALL: + if (!Get(STK(arg2), STK(arg1), temp_reg, false,true)) + { Raise_IdxError(STK(arg1)); SQ_THROW(); } + goto common_prepcall; + case _OP_PREPCALLK: + if (!Get(STK(arg2), (*ci->_literals)[arg1], temp_reg,false,true)) { + if(type(STK(arg2)) == OT_CLASS) { //hack? + if(_class_ddel->Get((*ci->_literals)[arg1],temp_reg)) { + STK(arg3) = STK(arg2); + TARGET = temp_reg; + continue; + } + } + { Raise_IdxError((*ci->_literals)[arg1]); SQ_THROW();} + } +common_prepcall: + if(type(STK(arg2)) == OT_CLASS) { + STK(arg3) = STK(0); // this + } + else { + STK(arg3) = STK(arg2); + } + TARGET = temp_reg; + continue; + case _OP_GETK: + if (!Get(STK(arg2), (*ci->_literals)[arg1], temp_reg, false,true)) { Raise_IdxError((*ci->_literals)[arg1]); SQ_THROW();} + TARGET = temp_reg; + continue; + case _OP_MOVE: TARGET = STK(arg1); continue; + case _OP_NEWSLOT: + _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3))); + if(arg0 != arg3) TARGET = STK(arg3); + continue; + case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue; + case _OP_SET: + if (!Set(STK(arg1), STK(arg2), STK(arg3),true)) { Raise_IdxError(STK(arg2)); SQ_THROW(); } + if (arg0 != arg3) TARGET = STK(arg3); + continue; + case _OP_GET: + if (!Get(STK(arg1), STK(arg2), temp_reg, false,true)) { Raise_IdxError(STK(arg2)); SQ_THROW(); } + TARGET = temp_reg; + continue; + case _OP_EQ:{ + bool res; + if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); } + TARGET = res?_true_:_false_; + }continue; + case _OP_NE:{ + bool res; + if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); } + TARGET = (!res)?_true_:_false_; + } continue; + case _OP_ARITH: _GUARD(ARITH_OP( arg3 , temp_reg, STK(arg2), STK(arg1))); TARGET = temp_reg; continue; + case _OP_BITW: _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue; + case _OP_RETURN: + if(type((ci)->_generator) == OT_GENERATOR) { + _generator((ci)->_generator)->Kill(); + } + if(Return(arg0, arg1, temp_reg)){ + assert(traps==0); + outres = temp_reg; + return true; + } + continue; + case _OP_LOADNULLS:{ for(SQInt32 n=0; n < arg1; n++) STK(arg0+n) = _null_; }continue; + case _OP_LOADROOTTABLE: TARGET = _roottable; continue; + case _OP_LOADBOOL: TARGET = arg1?_true_:_false_; continue; + case _OP_DMOVE: STK(arg0) = STK(arg1); STK(arg2) = STK(arg3); continue; + case _OP_JMP: ci->_ip += (sarg1); continue; + case _OP_JNZ: if(!IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue; + case _OP_JZ: if(IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue; + case _OP_LOADFREEVAR: TARGET = _closure(ci->_closure)->_outervalues[arg1]; continue; + case _OP_VARGC: TARGET = SQInteger(ci->_vargs.size); continue; + case _OP_GETVARGV: + if(!GETVARGV_OP(TARGET,STK(arg1),ci)) { SQ_THROW(); } + continue; + case _OP_NEWTABLE: TARGET = SQTable::Create(_ss(this), arg1); continue; + case _OP_NEWARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue; + case _OP_APPENDARRAY: _array(STK(arg0))->Append(COND_LITERAL); continue; + case _OP_GETPARENT: + switch(type(STK(arg1))) { + case OT_TABLE: + TARGET = _table(STK(arg1))->_delegate?SQObjectPtr(_table(STK(arg1))->_delegate):_null_; + continue; + case OT_CLASS: TARGET = _class(STK(arg1))->_base?_class(STK(arg1))->_base:_null_; + continue; + } + Raise_Error(_SC("the %s type doesn't have a parent slot"), GetTypeName(STK(arg1))); + SQ_THROW(); + continue; + case _OP_COMPARITH: _GUARD(DerefInc(arg3, TARGET, STK((((SQUnsignedInteger)arg1&0xFFFF0000)>>16)), STK(arg2), STK(arg1&0x0000FFFF), false)); continue; + case _OP_COMPARITHL: _GUARD(LOCAL_INC(arg3, TARGET, STK(arg1), STK(arg2))); continue; + case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false));} continue; + case _OP_INCL: {SQObjectPtr o(sarg3); _GUARD(LOCAL_INC('+',TARGET, STK(arg1), o));} continue; + case _OP_PINC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, true));} continue; + case _OP_PINCL: {SQObjectPtr o(sarg3); _GUARD(PLOCAL_INC('+',TARGET, STK(arg1), o));} continue; + case _OP_CMP: _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET)) continue; + case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, true,false)?_true_:_false_;continue; + case _OP_INSTANCEOF: + if(type(STK(arg1)) != OT_CLASS || type(STK(arg2)) != OT_INSTANCE) + {Raise_Error(_SC("cannot apply instanceof between a %s and a %s"),GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();} + TARGET = _instance(STK(arg2))->InstanceOf(_class(STK(arg1)))?_true_:_false_; + continue; + case _OP_AND: + if(IsFalse(STK(arg2))) { + TARGET = STK(arg2); + ci->_ip += (sarg1); + } + continue; + case _OP_OR: + if(!IsFalse(STK(arg2))) { + TARGET = STK(arg2); + ci->_ip += (sarg1); + } + continue; + case _OP_NEG: _GUARD(NEG_OP(TARGET,STK(arg1))); continue; + case _OP_NOT: TARGET = (IsFalse(STK(arg1))?_true_:_false_); continue; + case _OP_BWNOT: + if(type(STK(arg1)) == OT_INTEGER) { + TARGET = SQInteger(~_integer(STK(arg1))); + continue; + } + Raise_Error(_SC("attempt to perform a bitwise op on a %s"), GetTypeName(STK(arg1))); + SQ_THROW(); + case _OP_CLOSURE: { + SQClosure *c = ci->_closure._unVal.pClosure; + SQFunctionProto *fp = c->_function._unVal.pFunctionProto; + if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); } + continue; + } + case _OP_YIELD:{ + if(type(ci->_generator) == OT_GENERATOR) { + if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1); + _GUARD(_generator(ci->_generator)->Yield(this)); + traps -= ci->_etraps; + if(sarg1 != MAX_FUNC_STACKSIZE) STK(arg1) = temp_reg; + } + else { Raise_Error(_SC("trying to yield a '%s',only genenerator can be yielded"), GetTypeName(ci->_generator)); SQ_THROW();} + if(Return(arg0, arg1, temp_reg)){ + assert(traps==0); + outres = temp_reg; + return true; + } + + } + continue; + case _OP_RESUME: + if(type(STK(arg1)) != OT_GENERATOR){ Raise_Error(_SC("trying to resume a '%s',only genenerator can be resumed"), GetTypeName(STK(arg1))); SQ_THROW();} + _GUARD(_generator(STK(arg1))->Resume(this, arg0)); + traps += ci->_etraps; + continue; + case _OP_FOREACH:{ bool finished; + _GUARD(FOREACH_OP(STK(arg0),STK(arg2),STK(arg2+1),STK(arg2+2),arg2,finished)); + if(finished) ci->_ip += sarg1; } + continue; + case _OP_DELEGATE: _GUARD(DELEGATE_OP(TARGET,STK(arg1),STK(arg2))); continue; + case _OP_CLONE: + if(!Clone(STK(arg1), TARGET)) + { Raise_Error(_SC("cloning a %s"), GetTypeName(STK(arg1))); SQ_THROW();} + continue; + case _OP_TYPEOF: TypeOf(STK(arg1), TARGET); continue; + case _OP_PUSHTRAP: + _etraps.push_back(SQExceptionTrap(_top,_stackbase, &ci->_iv->_vals[(ci->_ip-ci->_iv->_vals)+arg1], arg0)); traps++; + ci->_etraps++; + continue; + case _OP_POPTRAP:{ + for(SQInteger i=0; i_etraps--; + }} + continue; + case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); continue; + case _OP_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue; + case _OP_NEWSLOTA: + _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3))); + _class(STK(arg1))->SetAttributes(STK(arg2),STK(arg2-1)); + if(arg0 != arg3) TARGET = STK(arg3); + continue; + } + + } + } +exception_trap: + { + SQObjectPtr currerror = _lasterror; +// dumpstack(_stackbase); + SQInteger n = 0; + SQInteger last_top = _top; + if(ci) { + if(traps) { + do { + if(ci->_etraps > 0) { + SQExceptionTrap &et = _etraps.top(); + ci->_ip = et._ip; + _top = et._stacksize; + _stackbase = et._stackbase; + _stack[_stackbase+et._extarget] = currerror; + _etraps.pop_back(); traps--; ci->_etraps--; + while(last_top >= _top) _stack[last_top--].Null(); + goto exception_restore; + } + //if is a native closure + if(type(ci->_closure) != OT_CLOSURE && n) + break; + if(type(ci->_generator) == OT_GENERATOR) _generator(ci->_generator)->Kill(); + PopVarArgs(ci->_vargs); + POP_CALLINFO(this); + n++; + }while(_callsstack.size()); + } + //call the hook + CallErrorHandler(currerror); + //remove call stack until a C function is found or the cstack is empty + if(ci) do{ + SQBool exitafterthisone = ci->_root; + if(type(ci->_generator) == OT_GENERATOR) _generator(ci->_generator)->Kill(); + _stackbase -= ci->_prevstkbase; + _top = _stackbase + ci->_prevtop; + PopVarArgs(ci->_vargs); + POP_CALLINFO(this); + if( (ci && type(ci->_closure) != OT_CLOSURE) || exitafterthisone) break; + }while(_callsstack.size()); + + while(last_top >= _top) _stack[last_top--].Null(); + } + _lasterror = currerror; + return false; + } + assert(0); +} + +bool SQVM::CreateClassInstance(SQClass *theclass, SQInteger nargs, SQInteger stackbase, SQObjectPtr &retval) +{ + SQObjectPtr constr; + SQObjectPtr inst = theclass->CreateInstance(); + _stack[stackbase] = inst; + if(theclass->Get(_ss(this)->_constructoridx,constr)) { + if(!Call(constr,nargs,stackbase,constr)) + return false; + } + retval = inst; + return true; +} + +void SQVM::CallErrorHandler(SQObjectPtr &error) +{ + if(type(_errorhandler) != OT_NULL) { + SQObjectPtr out; + Push(_roottable); Push(error); + Call(_errorhandler, 2, _top-2, out); + Pop(2); + } +} + +void SQVM::CallDebugHook(SQInteger type,SQInteger forcedline) +{ + SQObjectPtr temp_reg; + SQInteger nparams=5; + SQFunctionProto *func=_funcproto(_closure(ci->_closure)->_function); + Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name); + Call(_debughook,nparams,_top-nparams,temp_reg); + Pop(nparams); +} + +bool SQVM::CallNative(SQNativeClosure *nclosure,SQInteger nargs,SQInteger stackbase,bool tailcall,SQObjectPtr &retval,bool &suspend) +{ + if (_nnativecalls + 1 > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; } + SQInteger nparamscheck = nclosure->_nparamscheck; + if(((nparamscheck > 0) && (nparamscheck != nargs)) + || ((nparamscheck < 0) && (nargs < (-nparamscheck)))) { + Raise_Error(_SC("wrong number of parameters")); + return false; + } + + SQInteger tcs; + if(tcs = nclosure->_typecheck.size()) { + for(SQInteger i = 0; i < nargs && i < tcs; i++) + if((nclosure->_typecheck[i] != -1) && !(type(_stack[stackbase+i]) & nclosure->_typecheck[i])) { + Raise_ParamTypeError(i,nclosure->_typecheck[i],type(_stack[stackbase+i])); + return false; + } + } + _nnativecalls++; + if ((_top + MIN_STACK_OVERHEAD) > (SQInteger)_stack.size()) { + _stack.resize(_stack.size() + (MIN_STACK_OVERHEAD<<1)); + } + SQInteger oldtop = _top; + SQInteger oldstackbase = _stackbase; + _top = stackbase + nargs; + PUSH_CALLINFO(this, CallInfo()); + ci->_etraps = 0; + ci->_closure._unVal.pNativeClosure = nclosure; + ci->_closure._type = OT_NATIVECLOSURE; + ci->_prevstkbase = stackbase - _stackbase; + ci->_ncalls = 1; + _stackbase = stackbase; + //push free variables + SQInteger outers = nclosure->_outervalues.size(); + for (SQInteger i = 0; i < outers; i++) { + Push(nclosure->_outervalues[i]); + } + ci->_prevtop = (oldtop - oldstackbase); + SQInteger ret = (nclosure->_function)(this); + _nnativecalls--; + suspend = false; + if( ret == SQ_SUSPEND_FLAG) suspend = true; + else if (ret < 0) { + _stackbase = oldstackbase; + _top = oldtop; + POP_CALLINFO(this); + Raise_Error(_lasterror); + return false; + } + + if (ret != 0){ retval = TOP(); } + else { retval = _null_; } + _stackbase = oldstackbase; + _top = oldtop; + POP_CALLINFO(this); + return true; +} + +bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw, bool fetchroot) +{ + switch(type(self)){ + case OT_TABLE: + if(_table(self)->Get(key,dest))return true; + break; + case OT_ARRAY: + if(sq_isnumeric(key)){ + return _array(self)->Get(tointeger(key),dest); + } + break; + case OT_INSTANCE: + if(_instance(self)->Get(key,dest)) return true; + break; + } + if(FallBackGet(self,key,dest,raw)) return true; + + if(fetchroot) { + if(_rawval(STK(0)) == _rawval(self) && + type(STK(0)) == type(self)) { + return _table(_roottable)->Get(key,dest); + } + } + return false; +} + +bool SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw) +{ + switch(type(self)){ + case OT_CLASS: + return _class(self)->Get(key,dest); + break; + case OT_TABLE: + case OT_USERDATA: + //delegation + if(_delegable(self)->_delegate) { + if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,raw,false)) + return true; + if(raw)return false; + Push(self);Push(key); + if(CallMetaMethod(_delegable(self),MT_GET,2,dest)) + return true; + } + if(type(self) == OT_TABLE) { + if(raw) return false; + return _table_ddel->Get(key,dest); + } + return false; + break; + case OT_ARRAY: + if(raw)return false; + return _array_ddel->Get(key,dest); + case OT_STRING: + if(sq_isnumeric(key)){ + SQInteger n=tointeger(key); + if(abs(n)<_string(self)->_len){ + if(n<0)n=_string(self)->_len-n; + dest=SQInteger(_stringval(self)[n]); + return true; + } + return false; + } + else { + if(raw)return false; + return _string_ddel->Get(key,dest); + } + break; + case OT_INSTANCE: + if(raw)return false; + Push(self);Push(key); + if(!CallMetaMethod(_delegable(self),MT_GET,2,dest)) { + return _instance_ddel->Get(key,dest); + } + return true; + case OT_INTEGER:case OT_FLOAT:case OT_BOOL: + if(raw)return false; + return _number_ddel->Get(key,dest); + case OT_GENERATOR: + if(raw)return false; + return _generator_ddel->Get(key,dest); + case OT_CLOSURE: case OT_NATIVECLOSURE: + if(raw)return false; + return _closure_ddel->Get(key,dest); + case OT_THREAD: + if(raw)return false; + return _thread_ddel->Get(key,dest); + case OT_WEAKREF: + if(raw)return false; + return _weakref_ddel->Get(key,dest); + default:return false; + } + return false; +} + +bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool fetchroot) +{ + switch(type(self)){ + case OT_TABLE: + if(_table(self)->Set(key,val)) + return true; + if(_table(self)->_delegate) { + if(Set(_table(self)->_delegate,key,val,false)) { + return true; + } + } + //keeps going + case OT_USERDATA: + if(_delegable(self)->_delegate) { + SQObjectPtr t; + Push(self);Push(key);Push(val); + if(CallMetaMethod(_delegable(self),MT_SET,3,t)) return true; + } + break; + case OT_INSTANCE:{ + if(_instance(self)->Set(key,val)) + return true; + SQObjectPtr t; + Push(self);Push(key);Push(val); + if(CallMetaMethod(_delegable(self),MT_SET,3,t)) return true; + } + break; + case OT_ARRAY: + if(!sq_isnumeric(key)) {Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); return false; } + return _array(self)->Set(tointeger(key),val); + default: + Raise_Error(_SC("trying to set '%s'"),GetTypeName(self)); + return false; + } + if(fetchroot) { + if(_rawval(STK(0)) == _rawval(self) && + type(STK(0)) == type(self)) { + return _table(_roottable)->Set(key,val); + } + } + return false; +} + +bool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target) +{ + SQObjectPtr temp_reg; + switch(type(self)){ + case OT_TABLE: + target = _table(self)->Clone(); + goto cloned_mt; + case OT_INSTANCE: + target = _instance(self)->Clone(_ss(this)); +cloned_mt: + if(_delegable(target)->_delegate){ + Push(target); + Push(self); + CallMetaMethod(_delegable(target),MT_CLONED,2,temp_reg); + } + return true; + case OT_ARRAY: + target=_array(self)->Clone(); + return true; + default: return false; + } +} + +bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val) +{ + if(type(key) == OT_NULL) { Raise_Error(_SC("null cannot be used as index")); return false; } + switch(type(self)) { + case OT_TABLE: { + bool rawcall = true; + if(_table(self)->_delegate) { + SQObjectPtr res; + if(!_table(self)->Get(key,res)) { + Push(self);Push(key);Push(val); + rawcall = !CallMetaMethod(_table(self),MT_NEWSLOT,3,res); + } + } + if(rawcall) _table(self)->NewSlot(key,val); //cannot fail + + break;} + case OT_CLASS: + if(!_class(self)->NewSlot(key,val)) { + if(_class(self)->_locked) { + Raise_Error(_SC("trying to modify a class that has already been instantiated")); + return false; + } + else { + SQObjectPtr oval = PrintObjVal(key); + Raise_Error(_SC("the property '%s' already exists"),_stringval(oval)); + return false; + } + } + break; + default: + Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); + return false; + break; + } + return true; +} + +bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &res) +{ + switch(type(self)) { + case OT_TABLE: + case OT_INSTANCE: + case OT_USERDATA: { + SQObjectPtr t; + bool handled = false; + if(_delegable(self)->_delegate) { + Push(self);Push(key); + handled = CallMetaMethod(_delegable(self),MT_DELSLOT,2,t); + } + + if(!handled) { + if(type(self) == OT_TABLE) { + if(_table(self)->Get(key,t)) { + _table(self)->Remove(key); + } + else { + Raise_IdxError((SQObject &)key); + return false; + } + } + else { + Raise_Error(_SC("cannot delete a slot from %s"),GetTypeName(self)); + return false; + } + } + res = t; + } + break; + default: + Raise_Error(_SC("attempt to delete a slot from a %s"),GetTypeName(self)); + return false; + } + return true; +} + +bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres) +{ +#ifdef _DEBUG +SQInteger prevstackbase = _stackbase; +#endif + switch(type(closure)) { + case OT_CLOSURE: + return Execute(closure, _top - nparams, nparams, stackbase,outres); + break; + case OT_NATIVECLOSURE:{ + bool suspend; + return CallNative(_nativeclosure(closure), nparams, stackbase, false, outres,suspend); + + } + break; + case OT_CLASS: + return CreateClassInstance(_class(closure),nparams,stackbase,outres); + break; + default: + return false; + } +#ifdef _DEBUG + if(!_suspended) { + assert(_stackbase == prevstackbase); + } +#endif + return true; +} + +bool SQVM::CallMetaMethod(SQDelegable *del,SQMetaMethod mm,SQInteger nparams,SQObjectPtr &outres) +{ + SQObjectPtr closure; + if(del->GetMetaMethod(mm, closure)) { + if(Call(closure, nparams, _top - nparams, outres)) { + Pop(nparams); + return true; + } + } + Pop(nparams); + return false; +} + +void SQVM::Remove(SQInteger n) { + n = (n >= 0)?n + _stackbase - 1:_top + n; + for(SQInteger i = n; i < _top; i++){ + _stack[i] = _stack[i+1]; + } + _stack[_top] = _null_; + _top--; +} + + +#ifdef _DEBUG_DUMP +void SQVM::dumpstack(SQInteger stackbase,bool dumpall) +{ + SQInteger size=dumpall?_stack.size():_top; + SQInteger n=0; + scprintf(_SC("\n>>>>stack dump<<<<\n")); + CallInfo &ci=_callsstack.back(); + scprintf(_SC("IP: %d\n"),ci._ip); + scprintf(_SC("prev stack base: %d\n"),ci._prevstkbase); + scprintf(_SC("prev top: %d\n"),ci._prevtop); + for(SQInteger i=0;i"));else scprintf(_SC(" ")); + scprintf(_SC("[%d]:"),n); + switch(type(obj)){ + case OT_FLOAT: scprintf(_SC("FLOAT %.3f"),_float(obj));break; + case OT_INTEGER: scprintf(_SC("INTEGER %d"),_integer(obj));break; + case OT_BOOL: scprintf(_SC("BOOL %s"),_integer(obj)?"true":"false");break; + case OT_STRING: scprintf(_SC("STRING %s"),_stringval(obj));break; + case OT_NULL: scprintf(_SC("NULL")); break; + case OT_TABLE: scprintf(_SC("TABLE %p[%p]"),_table(obj),_table(obj)->_delegate);break; + case OT_ARRAY: scprintf(_SC("ARRAY %p"),_array(obj));break; + case OT_CLOSURE: scprintf(_SC("CLOSURE [%p]"),_closure(obj));break; + case OT_NATIVECLOSURE: scprintf(_SC("NATIVECLOSURE"));break; + case OT_USERDATA: scprintf(_SC("USERDATA %p[%p]"),_userdataval(obj),_userdata(obj)->_delegate);break; + case OT_GENERATOR: scprintf(_SC("GENERATOR"));break; + case OT_THREAD: scprintf(_SC("THREAD [%p]"),_thread(obj));break; + case OT_USERPOINTER: scprintf(_SC("USERPOINTER %p"),_userpointer(obj));break; + case OT_CLASS: scprintf(_SC("CLASS %p"),_class(obj));break; + case OT_INSTANCE: scprintf(_SC("INSTANCE %p"),_instance(obj));break; + case OT_WEAKREF: scprintf(_SC("WEAKERF %p"),_weakref(obj));break; + default: + assert(0); + break; + }; + scprintf(_SC("\n")); + ++n; + } +} + +#endif diff --git a/src/squirrel/squirrel/sqvm.h b/src/squirrel/squirrel/sqvm.h index d46f2a219..00fce00ea 100644 --- a/src/squirrel/squirrel/sqvm.h +++ b/src/squirrel/squirrel/sqvm.h @@ -1,195 +1,203 @@ -/* see copyright notice in squirrel.h */ -#ifndef _SQVM_H_ -#define _SQVM_H_ - -#include "sqopcodes.h" -#include "sqobject.h" -#define MAX_NATIVE_CALLS 100 -#define MIN_STACK_OVERHEAD 10 - -#define SQ_SUSPEND_FLAG -666 -//base lib -void sq_base_register(HSQUIRRELVM v); - -struct SQExceptionTrap{ - SQExceptionTrap() {} - SQExceptionTrap(int ss, int stackbase,SQInstruction *ip, int ex_target){ _stacksize = ss; _stackbase = stackbase; _ip = ip; _extarget = ex_target;} - SQExceptionTrap(const SQExceptionTrap &et) { (*this) = et; } - int _stackbase; - int _stacksize; - SQInstruction *_ip; - int _extarget; -}; - - -#define STK(a) _stack._vals[_stackbase+(a)] -#define TARGET _stack._vals[_stackbase+arg0] - -typedef sqvector ExceptionsTraps; - -struct SQVM : public CHAINABLE_OBJ -{ - struct VarArgs { - VarArgs() { size = 0; base = 0; } - int size; - int base; - }; - - struct CallInfo{ - //CallInfo() {} - //CallInfo(const CallInfo& ci) { } - SQInstructionVec *_iv; - SQObjectPtrVec *_literals; - SQObject _closure; - SQObject _generator; - int _etraps; - int _prevstkbase; - int _prevtop; - int _target; - SQInstruction *_ip; - int _ncalls; - SQBool _root; - VarArgs _vargs; - }; - -typedef sqvector CallInfoVec; -public: - enum ExecutionType { ET_CALL, ET_RESUME_GENERATOR, ET_RESUME_VM }; - SQVM(SQSharedState *ss); - ~SQVM(); - bool Init(SQVM *friendvm, int stacksize); - bool Execute(SQObjectPtr &func, int target, int nargs, int stackbase, SQObjectPtr &outres, ExecutionType et = ET_CALL); - //start a native call return when the NATIVE closure returns(returns true if the vm has been suspended) - bool CallNative(SQNativeClosure *nclosure, int nargs, int stackbase, bool tailcall, SQObjectPtr &retval,bool &suspend); - //start a SQUIRREL call in the same "Execution loop" - bool StartCall(SQClosure *closure, int target, int nargs, int stackbase, bool tailcall); - bool CreateClassInstance(SQClass *theclass, int nargs, int stackbase, SQObjectPtr &retval); - //call a generic closure pure SQUIRREL or NATIVE - bool Call(SQObjectPtr &closure, int nparams, int stackbase, SQObjectPtr &outres); - SQRESULT Suspend(); - - void CallDebugHook(int type,int forcedline=0); - void CallErrorHandler(SQObjectPtr &e); - bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, bool raw, bool fetchroot); - bool FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw); - bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, bool fetchroot); - bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val); - bool DeleteSlot(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &res); - bool Clone(const SQObjectPtr &self, SQObjectPtr &target); - bool ObjCmp(const SQObjectPtr &o1, const SQObjectPtr &o2,int &res); - bool StringCat(const SQObjectPtr &str, const SQObjectPtr &obj, SQObjectPtr &dest); - bool IsEqual(SQObjectPtr &o1,SQObjectPtr &o2,bool &res); - bool IsFalse(SQObjectPtr &o); - SQString *PrintObjVal(const SQObject &o); - - - void Raise_Error(const SQChar *s, ...); - void Raise_Error(SQObjectPtr &desc); - void Raise_IdxError(SQObject &o); - void Raise_CompareError(const SQObject &o1, const SQObject &o2); - void Raise_ParamTypeError(int nparam,int typemask,int type); - - void TypeOf(const SQObjectPtr &obj1, SQObjectPtr &dest); - bool CallMetaMethod(SQDelegable *del, SQMetaMethod mm, int nparams, SQObjectPtr &outres); - bool ArithMetaMethod(int op, const SQObjectPtr &o1, const SQObjectPtr &o2, SQObjectPtr &dest); - bool Return(int _arg0, int _arg1, SQObjectPtr &retval); - //new stuff - inline bool ARITH_OP(unsigned int op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); - inline bool BW_OP(unsigned int 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 GETVARGV_OP(SQObjectPtr &target,SQObjectPtr &idx,CallInfo *ci); - bool CLASS_OP(SQObjectPtr &target,int base,int attrs); - //return true if the loop is finished - bool FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,int arg_2,bool &finished); - bool DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2); - inline bool LOCAL_INC(int op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); - inline bool PLOCAL_INC(int op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); - inline bool DerefInc(int op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix); - void PopVarArgs(VarArgs &vargs); -#ifdef _DEBUG_DUMP - void dumpstack(int stackbase=-1, bool dumpall = false); -#endif - -#ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); -#endif - void Finalize(); - - void Release(){ sq_delete(this,SQVM); } //does nothing -//////////////////////////////////////////////////////////////////////////// - //stack functions for the api - void Remove(int n); - - inline void Pop() { - _stack[--_top] = _null_; - } - - inline void Pop(int n) { - for(int i = 0; i < n; i++){ - _stack[--_top] = _null_; - } - } - - inline void Push(const SQObjectPtr &o) { _stack[_top++] = o; } - inline SQObjectPtr &Top() { return _stack[_top-1]; } - inline SQObjectPtr &PopGet() { return _stack[--_top]; } - inline SQObjectPtr &GetUp(int n) { return _stack[_top+n]; } - inline SQObjectPtr &GetAt(int n) { return _stack[n]; } - - SQObjectPtrVec _stack; - SQObjectPtrVec _vargsstack; - int _top; - int _stackbase; - SQObjectPtr _roottable; - //SQObjectPtr _thrownerror; - SQObjectPtr _lasterror; - SQObjectPtr _errorhandler; - SQObjectPtr _debughook; - - SQObjectPtr temp_reg; - CallInfoVec _callsstack; - ExceptionsTraps _etraps; - CallInfo *ci; - void *_foreignptr; - //VMs sharing the same state - SQSharedState *_sharedstate; - int _nnativecalls; - //suspend infos - SQBool _suspended; - SQBool _suspended_root; - int _suspended_target; - int _suspended_traps; -}; - -struct AutoDec{ - AutoDec(int *n) { _n = n; } - ~AutoDec() { (*_n)--; } - int *_n; -}; - -SQObjectPtr &stack_get(HSQUIRRELVM v, int idx); -const SQChar *GetTypeName(const SQObjectPtr &obj1); -const SQChar *IdType2Name(SQObjectType type); - -#define _ss(_vm_) (_vm_)->_sharedstate - -#ifndef NO_GARBAGE_COLLECTOR -#define _opt_ss(_vm_) (_vm_)->_sharedstate -#else -#define _opt_ss(_vm_) NULL -#endif - -#define PUSH_CALLINFO(v,nci){ \ - v->ci = &v->_callsstack.push_back(nci); \ -} - -#define POP_CALLINFO(v){ \ - v->_callsstack.pop_back(); \ - if(v->_callsstack.size()) \ - v->ci = &v->_callsstack.back() ; \ - else \ - v->ci = NULL; \ -} -#endif //_SQVM_H_ +/* see copyright notice in squirrel.h */ +#ifndef _SQVM_H_ +#define _SQVM_H_ + +#include "sqopcodes.h" +#include "sqobject.h" +#define MAX_NATIVE_CALLS 100 +#define MIN_STACK_OVERHEAD 10 + +#define SQ_SUSPEND_FLAG -666 +//base lib +void sq_base_register(HSQUIRRELVM v); + +struct SQExceptionTrap{ + SQExceptionTrap() {} + SQExceptionTrap(SQInteger ss, SQInteger stackbase,SQInstruction *ip, SQInteger ex_target){ _stacksize = ss; _stackbase = stackbase; _ip = ip; _extarget = ex_target;} + SQExceptionTrap(const SQExceptionTrap &et) { (*this) = et; } + SQInteger _stackbase; + SQInteger _stacksize; + SQInstruction *_ip; + SQInteger _extarget; +}; + + +#define STK(a) _stack._vals[_stackbase+(a)] +#define TARGET _stack._vals[_stackbase+arg0] + +typedef sqvector ExceptionsTraps; + +struct SQVM : public CHAINABLE_OBJ +{ + struct VarArgs { + VarArgs() { size = 0; base = 0; } + SQInteger size; + SQInteger base; + }; + + struct CallInfo{ + CallInfo() { _generator._type = OT_NULL;} + //CallInfo(const CallInfo& ci) { } + SQInstructionVec *_iv; + SQObjectPtrVec *_literals; + SQObject _closure; + SQObject _generator; + SQInteger _etraps; + SQInteger _prevstkbase; + SQInteger _prevtop; + SQInteger _target; + SQInstruction *_ip; + SQInteger _ncalls; + SQBool _root; + VarArgs _vargs; + }; + +typedef sqvector CallInfoVec; +public: + enum ExecutionType { ET_CALL, ET_RESUME_GENERATOR, ET_RESUME_VM }; + SQVM(SQSharedState *ss); + ~SQVM(); + bool Init(SQVM *friendvm, SQInteger stacksize); + bool Execute(SQObjectPtr &func, SQInteger target, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, ExecutionType et = ET_CALL); + //start a native call return when the NATIVE closure returns(returns true if the vm has been suspended) + bool CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger stackbase, bool tailcall, SQObjectPtr &retval,bool &suspend); + //start a SQUIRREL call in the same "Execution loop" + bool StartCall(SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall); + bool CreateClassInstance(SQClass *theclass, SQInteger nargs, SQInteger stackbase, SQObjectPtr &retval); + //call a generic closure pure SQUIRREL or NATIVE + bool Call(SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres); + SQRESULT Suspend(); + + void CallDebugHook(SQInteger type,SQInteger forcedline=0); + void CallErrorHandler(SQObjectPtr &e); + bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, bool raw, bool fetchroot); + bool FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw); + bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, bool fetchroot); + bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val); + bool DeleteSlot(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &res); + bool Clone(const SQObjectPtr &self, SQObjectPtr &target); + bool ObjCmp(const SQObjectPtr &o1, const SQObjectPtr &o2,SQInteger &res); + bool StringCat(const SQObjectPtr &str, const SQObjectPtr &obj, SQObjectPtr &dest); + bool IsEqual(SQObjectPtr &o1,SQObjectPtr &o2,bool &res); + void ToString(const SQObjectPtr &o,SQObjectPtr &res); + SQString *PrintObjVal(const SQObject &o); + + + void Raise_Error(const SQChar *s, ...); + void Raise_Error(SQObjectPtr &desc); + void Raise_IdxError(SQObject &o); + void Raise_CompareError(const SQObject &o1, const SQObject &o2); + void Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type); + + void TypeOf(const SQObjectPtr &obj1, SQObjectPtr &dest); + bool CallMetaMethod(SQDelegable *del, SQMetaMethod mm, SQInteger nparams, SQObjectPtr &outres); + bool ArithMetaMethod(SQInteger op, const SQObjectPtr &o1, const SQObjectPtr &o2, SQObjectPtr &dest); + bool Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval); + //new stuff + inline bool ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); + 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 GETVARGV_OP(SQObjectPtr &target,SQObjectPtr &idx,CallInfo *ci); + 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,bool &finished); + bool DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2); + inline bool LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); + inline bool PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); + inline bool DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix); + void PopVarArgs(VarArgs &vargs); +#ifdef _DEBUG_DUMP + void dumpstack(SQInteger stackbase=-1, bool dumpall = false); +#endif + +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); +#endif + void Finalize(); + + void Release(){ sq_delete(this,SQVM); } //does nothing +//////////////////////////////////////////////////////////////////////////// + //stack functions for the api + void Remove(SQInteger n); + + inline bool IsFalse(SQObjectPtr &o) + { + if((type(o) & SQOBJECT_CANBEFALSE) && ( (type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0)) ) + || (_integer(o) == 0) ) { //OT_NULL|OT_INTEGER|OT_BOOL + return true; + } + return false; + } + inline void Pop() { + _stack[--_top] = _null_; + } + + inline void Pop(SQInteger n) { + for(SQInteger i = 0; i < n; i++){ + _stack[--_top] = _null_; + } + } + + inline void Push(const SQObjectPtr &o) { _stack[_top++] = o; } + inline SQObjectPtr &Top() { return _stack[_top-1]; } + inline SQObjectPtr &PopGet() { return _stack[--_top]; } + inline SQObjectPtr &GetUp(SQInteger n) { return _stack[_top+n]; } + inline SQObjectPtr &GetAt(SQInteger n) { return _stack[n]; } + + SQObjectPtrVec _stack; + SQObjectPtrVec _vargsstack; + SQInteger _top; + SQInteger _stackbase; + SQObjectPtr _roottable; + //SQObjectPtr _thrownerror; + SQObjectPtr _lasterror; + SQObjectPtr _errorhandler; + SQObjectPtr _debughook; + + SQObjectPtr temp_reg; + CallInfoVec _callsstack; + ExceptionsTraps _etraps; + CallInfo *ci; + void *_foreignptr; + //VMs sharing the same state + SQSharedState *_sharedstate; + SQInteger _nnativecalls; + //suspend infos + SQBool _suspended; + SQBool _suspended_root; + SQInteger _suspended_target; + SQInteger _suspended_traps; +}; + +struct AutoDec{ + AutoDec(SQInteger *n) { _n = n; } + ~AutoDec() { (*_n)--; } + SQInteger *_n; +}; + +inline SQObjectPtr &stack_get(HSQUIRRELVM v,SQInteger idx){return ((idx>=0)?(v->GetAt(idx+v->_stackbase-1)):(v->GetUp(idx)));} +const SQChar *GetTypeName(const SQObjectPtr &obj1); +const SQChar *IdType2Name(SQObjectType type); + +#define _ss(_vm_) (_vm_)->_sharedstate + +#ifndef NO_GARBAGE_COLLECTOR +#define _opt_ss(_vm_) (_vm_)->_sharedstate +#else +#define _opt_ss(_vm_) NULL +#endif + +#define PUSH_CALLINFO(v,nci){ \ + v->ci = &v->_callsstack.push_back(nci); \ +} + +#define POP_CALLINFO(v){ \ + v->_callsstack.pop_back(); \ + if(v->_callsstack.size()) \ + v->ci = &v->_callsstack.back() ; \ + else \ + v->ci = NULL; \ +} +#endif //_SQVM_H_