From 8285a11a26d78784f26b76e6bcdfa479f6c1a345 Mon Sep 17 00:00:00 2001 From: faketruth Date: Tue, 8 Nov 2011 01:25:01 +0000 Subject: It's a Squirrel!! In SquirrelBindings.h use #define USE_SQUIRREL 1 to enable squirrel git-svn-id: http://mc-server.googlecode.com/svn/trunk@76 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- squirrel_3_0_1_stable/COMPILE | 41 + squirrel_3_0_1_stable/COPYRIGHT | 21 + squirrel_3_0_1_stable/HISTORY | 422 ++++ squirrel_3_0_1_stable/Makefile | 18 + squirrel_3_0_1_stable/README | 23 + squirrel_3_0_1_stable/include/sqstdaux.h | 16 + squirrel_3_0_1_stable/include/sqstdblob.h | 20 + squirrel_3_0_1_stable/include/sqstdio.h | 53 + squirrel_3_0_1_stable/include/sqstdmath.h | 15 + squirrel_3_0_1_stable/include/sqstdstring.h | 33 + squirrel_3_0_1_stable/include/sqstdsystem.h | 15 + squirrel_3_0_1_stable/include/squirrel.h | 500 +++++ squirrel_3_0_1_stable/sqplus/Makefile | 18 + squirrel_3_0_1_stable/sqplus/SqPlus.cpp | 382 ++++ squirrel_3_0_1_stable/sqplus/SqPlusCallTemplates.h | 337 +++ squirrel_3_0_1_stable/sqplus/SqPlusConst.h | 74 + .../sqplus/SqPlusFunctionCallImpl.h | 114 + squirrel_3_0_1_stable/sqplus/SqPlusOCharBuf.cpp | 61 + squirrel_3_0_1_stable/sqplus/SqPlusOCharBuf.h | 193 ++ squirrel_3_0_1_stable/sqplus/SqPlusOverload.h | 819 +++++++ squirrel_3_0_1_stable/sqplus/SqPlusSetup.h | 129 ++ squirrel_3_0_1_stable/sqplus/SqPlusSmartPointer.h | 141 ++ squirrel_3_0_1_stable/sqplus/SqPlusTypeMask.h | 169 ++ squirrel_3_0_1_stable/sqplus/SqPlusUtf8.cpp | 133 ++ squirrel_3_0_1_stable/sqplus/SqPlusUtf8.h | 15 + .../sqplus/SquirrelBindingsUtils.cpp | 161 ++ .../sqplus/SquirrelBindingsUtils.h | 152 ++ .../sqplus/SquirrelBindingsUtilsWin32.cpp | 31 + .../sqplus/SquirrelBindingsUtilsWin32.h | 41 + squirrel_3_0_1_stable/sqplus/SquirrelObject.cpp | 702 ++++++ squirrel_3_0_1_stable/sqplus/SquirrelObject.h | 256 +++ squirrel_3_0_1_stable/sqplus/SquirrelVM.cpp | 505 +++++ squirrel_3_0_1_stable/sqplus/SquirrelVM.h | 179 ++ squirrel_3_0_1_stable/sqplus/changes.txt | 359 +++ squirrel_3_0_1_stable/sqplus/sqplus.cbp | 190 ++ squirrel_3_0_1_stable/sqplus/sqplus.h | 2327 ++++++++++++++++++++ squirrel_3_0_1_stable/sqplus/sqplus.vcproj | 355 +++ squirrel_3_0_1_stable/sqplus/sqplus.vcxproj | 159 ++ .../sqplus/sqplus.vcxproj.filters | 65 + squirrel_3_0_1_stable/sqplus/sqplus.vcxproj.user | 3 + squirrel_3_0_1_stable/sqplus/sqplus71.vcproj | 235 ++ squirrel_3_0_1_stable/sqplus/sqplusWin32.h | 7 + squirrel_3_0_1_stable/sqstdlib/Makefile | 41 + squirrel_3_0_1_stable/sqstdlib/sqstdaux.cpp | 129 ++ squirrel_3_0_1_stable/sqstdlib/sqstdblob.cpp | 275 +++ squirrel_3_0_1_stable/sqstdlib/sqstdblobimpl.h | 108 + squirrel_3_0_1_stable/sqstdlib/sqstdio.cpp | 419 ++++ squirrel_3_0_1_stable/sqstdlib/sqstdlib.dsp | 131 ++ squirrel_3_0_1_stable/sqstdlib/sqstdmath.cpp | 107 + squirrel_3_0_1_stable/sqstdlib/sqstdrex.cpp | 638 ++++++ squirrel_3_0_1_stable/sqstdlib/sqstdstream.cpp | 336 +++ squirrel_3_0_1_stable/sqstdlib/sqstdstream.h | 18 + squirrel_3_0_1_stable/sqstdlib/sqstdstring.cpp | 378 ++++ squirrel_3_0_1_stable/sqstdlib/sqstdsystem.cpp | 147 ++ squirrel_3_0_1_stable/squirrel.dsw | 77 + squirrel_3_0_1_stable/squirrel/Makefile | 52 + squirrel_3_0_1_stable/squirrel/sqapi.cpp | 1456 ++++++++++++ squirrel_3_0_1_stable/squirrel/sqarray.h | 94 + squirrel_3_0_1_stable/squirrel/sqbaselib.cpp | 1110 ++++++++++ squirrel_3_0_1_stable/squirrel/sqclass.cpp | 213 ++ squirrel_3_0_1_stable/squirrel/sqclass.h | 158 ++ squirrel_3_0_1_stable/squirrel/sqclosure.h | 193 ++ squirrel_3_0_1_stable/squirrel/sqcompiler.cpp | 1504 +++++++++++++ squirrel_3_0_1_stable/squirrel/sqcompiler.h | 77 + squirrel_3_0_1_stable/squirrel/sqdebug.cpp | 116 + squirrel_3_0_1_stable/squirrel/sqfuncproto.h | 154 ++ squirrel_3_0_1_stable/squirrel/sqfuncstate.cpp | 652 ++++++ squirrel_3_0_1_stable/squirrel/sqfuncstate.h | 91 + squirrel_3_0_1_stable/squirrel/sqlexer.cpp | 489 ++++ squirrel_3_0_1_stable/squirrel/sqlexer.h | 47 + squirrel_3_0_1_stable/squirrel/sqmem.cpp | 9 + squirrel_3_0_1_stable/squirrel/sqobject.cpp | 655 ++++++ squirrel_3_0_1_stable/squirrel/sqobject.h | 354 +++ squirrel_3_0_1_stable/squirrel/sqopcodes.h | 132 ++ squirrel_3_0_1_stable/squirrel/sqpcheader.h | 19 + squirrel_3_0_1_stable/squirrel/sqstate.cpp | 648 ++++++ squirrel_3_0_1_stable/squirrel/sqstate.h | 144 ++ squirrel_3_0_1_stable/squirrel/sqstring.h | 31 + squirrel_3_0_1_stable/squirrel/sqtable.cpp | 220 ++ squirrel_3_0_1_stable/squirrel/sqtable.h | 92 + squirrel_3_0_1_stable/squirrel/squirrel.dsp | 302 +++ squirrel_3_0_1_stable/squirrel/squserdata.h | 40 + squirrel_3_0_1_stable/squirrel/squtils.h | 112 + squirrel_3_0_1_stable/squirrel/sqvm.cpp | 1714 ++++++++++++++ squirrel_3_0_1_stable/squirrel/sqvm.h | 208 ++ 85 files changed, 23379 insertions(+) create mode 100644 squirrel_3_0_1_stable/COMPILE create mode 100644 squirrel_3_0_1_stable/COPYRIGHT create mode 100644 squirrel_3_0_1_stable/HISTORY create mode 100644 squirrel_3_0_1_stable/Makefile create mode 100644 squirrel_3_0_1_stable/README create mode 100644 squirrel_3_0_1_stable/include/sqstdaux.h create mode 100644 squirrel_3_0_1_stable/include/sqstdblob.h create mode 100644 squirrel_3_0_1_stable/include/sqstdio.h create mode 100644 squirrel_3_0_1_stable/include/sqstdmath.h create mode 100644 squirrel_3_0_1_stable/include/sqstdstring.h create mode 100644 squirrel_3_0_1_stable/include/sqstdsystem.h create mode 100644 squirrel_3_0_1_stable/include/squirrel.h create mode 100644 squirrel_3_0_1_stable/sqplus/Makefile create mode 100644 squirrel_3_0_1_stable/sqplus/SqPlus.cpp create mode 100644 squirrel_3_0_1_stable/sqplus/SqPlusCallTemplates.h create mode 100644 squirrel_3_0_1_stable/sqplus/SqPlusConst.h create mode 100644 squirrel_3_0_1_stable/sqplus/SqPlusFunctionCallImpl.h create mode 100644 squirrel_3_0_1_stable/sqplus/SqPlusOCharBuf.cpp create mode 100644 squirrel_3_0_1_stable/sqplus/SqPlusOCharBuf.h create mode 100644 squirrel_3_0_1_stable/sqplus/SqPlusOverload.h create mode 100644 squirrel_3_0_1_stable/sqplus/SqPlusSetup.h create mode 100644 squirrel_3_0_1_stable/sqplus/SqPlusSmartPointer.h create mode 100644 squirrel_3_0_1_stable/sqplus/SqPlusTypeMask.h create mode 100644 squirrel_3_0_1_stable/sqplus/SqPlusUtf8.cpp create mode 100644 squirrel_3_0_1_stable/sqplus/SqPlusUtf8.h create mode 100644 squirrel_3_0_1_stable/sqplus/SquirrelBindingsUtils.cpp create mode 100644 squirrel_3_0_1_stable/sqplus/SquirrelBindingsUtils.h create mode 100644 squirrel_3_0_1_stable/sqplus/SquirrelBindingsUtilsWin32.cpp create mode 100644 squirrel_3_0_1_stable/sqplus/SquirrelBindingsUtilsWin32.h create mode 100644 squirrel_3_0_1_stable/sqplus/SquirrelObject.cpp create mode 100644 squirrel_3_0_1_stable/sqplus/SquirrelObject.h create mode 100644 squirrel_3_0_1_stable/sqplus/SquirrelVM.cpp create mode 100644 squirrel_3_0_1_stable/sqplus/SquirrelVM.h create mode 100644 squirrel_3_0_1_stable/sqplus/changes.txt create mode 100644 squirrel_3_0_1_stable/sqplus/sqplus.cbp create mode 100644 squirrel_3_0_1_stable/sqplus/sqplus.h create mode 100644 squirrel_3_0_1_stable/sqplus/sqplus.vcproj create mode 100644 squirrel_3_0_1_stable/sqplus/sqplus.vcxproj create mode 100644 squirrel_3_0_1_stable/sqplus/sqplus.vcxproj.filters create mode 100644 squirrel_3_0_1_stable/sqplus/sqplus.vcxproj.user create mode 100644 squirrel_3_0_1_stable/sqplus/sqplus71.vcproj create mode 100644 squirrel_3_0_1_stable/sqplus/sqplusWin32.h create mode 100644 squirrel_3_0_1_stable/sqstdlib/Makefile create mode 100644 squirrel_3_0_1_stable/sqstdlib/sqstdaux.cpp create mode 100644 squirrel_3_0_1_stable/sqstdlib/sqstdblob.cpp create mode 100644 squirrel_3_0_1_stable/sqstdlib/sqstdblobimpl.h create mode 100644 squirrel_3_0_1_stable/sqstdlib/sqstdio.cpp create mode 100644 squirrel_3_0_1_stable/sqstdlib/sqstdlib.dsp create mode 100644 squirrel_3_0_1_stable/sqstdlib/sqstdmath.cpp create mode 100644 squirrel_3_0_1_stable/sqstdlib/sqstdrex.cpp create mode 100644 squirrel_3_0_1_stable/sqstdlib/sqstdstream.cpp create mode 100644 squirrel_3_0_1_stable/sqstdlib/sqstdstream.h create mode 100644 squirrel_3_0_1_stable/sqstdlib/sqstdstring.cpp create mode 100644 squirrel_3_0_1_stable/sqstdlib/sqstdsystem.cpp create mode 100644 squirrel_3_0_1_stable/squirrel.dsw create mode 100644 squirrel_3_0_1_stable/squirrel/Makefile create mode 100644 squirrel_3_0_1_stable/squirrel/sqapi.cpp create mode 100644 squirrel_3_0_1_stable/squirrel/sqarray.h create mode 100644 squirrel_3_0_1_stable/squirrel/sqbaselib.cpp create mode 100644 squirrel_3_0_1_stable/squirrel/sqclass.cpp create mode 100644 squirrel_3_0_1_stable/squirrel/sqclass.h create mode 100644 squirrel_3_0_1_stable/squirrel/sqclosure.h create mode 100644 squirrel_3_0_1_stable/squirrel/sqcompiler.cpp create mode 100644 squirrel_3_0_1_stable/squirrel/sqcompiler.h create mode 100644 squirrel_3_0_1_stable/squirrel/sqdebug.cpp create mode 100644 squirrel_3_0_1_stable/squirrel/sqfuncproto.h create mode 100644 squirrel_3_0_1_stable/squirrel/sqfuncstate.cpp create mode 100644 squirrel_3_0_1_stable/squirrel/sqfuncstate.h create mode 100644 squirrel_3_0_1_stable/squirrel/sqlexer.cpp create mode 100644 squirrel_3_0_1_stable/squirrel/sqlexer.h create mode 100644 squirrel_3_0_1_stable/squirrel/sqmem.cpp create mode 100644 squirrel_3_0_1_stable/squirrel/sqobject.cpp create mode 100644 squirrel_3_0_1_stable/squirrel/sqobject.h create mode 100644 squirrel_3_0_1_stable/squirrel/sqopcodes.h create mode 100644 squirrel_3_0_1_stable/squirrel/sqpcheader.h create mode 100644 squirrel_3_0_1_stable/squirrel/sqstate.cpp create mode 100644 squirrel_3_0_1_stable/squirrel/sqstate.h create mode 100644 squirrel_3_0_1_stable/squirrel/sqstring.h create mode 100644 squirrel_3_0_1_stable/squirrel/sqtable.cpp create mode 100644 squirrel_3_0_1_stable/squirrel/sqtable.h create mode 100644 squirrel_3_0_1_stable/squirrel/squirrel.dsp create mode 100644 squirrel_3_0_1_stable/squirrel/squserdata.h create mode 100644 squirrel_3_0_1_stable/squirrel/squtils.h create mode 100644 squirrel_3_0_1_stable/squirrel/sqvm.cpp create mode 100644 squirrel_3_0_1_stable/squirrel/sqvm.h (limited to 'squirrel_3_0_1_stable') diff --git a/squirrel_3_0_1_stable/COMPILE b/squirrel_3_0_1_stable/COMPILE new file mode 100644 index 000000000..d032a2f4e --- /dev/null +++ b/squirrel_3_0_1_stable/COMPILE @@ -0,0 +1,41 @@ +Squirrel 3.0 stable +-------------------------------------------------------- +What is in this distribution? + +squirrel + static library implementing the compiler and interpreter of the language + +sqstdlib + the standard utility libraries + +sq + stand alone interpreter + +doc + The manual + +etc + a minimalistic embedding sample + +samples + samples programs + + +HOW TO COMPILE +--------------------------------------------------------- +GCC USERS +......................................................... +There is a very simple makefile that compiles all libraries and exes +from the root of the project run 'make' + +for 32 bits systems + + $ make + +for 64 bits systems + + $ make sq64 + +VISUAL C++ USERS +......................................................... +Open squirrel.dsw from the root project directory and build(dho!) \ No newline at end of file diff --git a/squirrel_3_0_1_stable/COPYRIGHT b/squirrel_3_0_1_stable/COPYRIGHT new file mode 100644 index 000000000..40bea1615 --- /dev/null +++ b/squirrel_3_0_1_stable/COPYRIGHT @@ -0,0 +1,21 @@ +Copyright (c) 2003-2011 Alberto Demichelis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------- +END OF COPYRIGHT diff --git a/squirrel_3_0_1_stable/HISTORY b/squirrel_3_0_1_stable/HISTORY new file mode 100644 index 000000000..d16ae44cc --- /dev/null +++ b/squirrel_3_0_1_stable/HISTORY @@ -0,0 +1,422 @@ +***version 3.0.1 stable*** +-added # as alternative symbol for "line comment"(mostly useful for shell scripts) +-added sq_throwobject() to throw an arbitrary object from the C API +-added alignement flag for userdata types, SQ_ALIGNMENT (thx Shigemasa) +-added rawset() and rawget() to class and instance default delegate +-changed bytecode format now ensures matching integer size and float size +-now inherited classes also inherit userdatasize +-added SQUIRREL_VERSION_NUMBER in squirrel.h and _versionnumber_ global symbol +-fixed sq_getmemberhandle +-fixed sq_getrefcount +-refactored some sqstdio code +-refactored some clone code +-refactored some stuff in the string lib +-added -s and -fno-exceptions in GCC makefile(better performance when using GCC) + +***2011-03-13 *** +***version 3.0 stable*** +-added sq_getcallee() +-sq_getfreevariable() also works for native closures +-minior optimizations +-removed several warning when compiling with GCC 4.x +-fixed some errors in the documentation +-fixed bug when using SQUSEDOUBLE and 32bits intengers +-fixed bug when invoking generators with closure.call() (thx huntercool) + +***2010-12-19 *** +***version 3.0 release candidate 1(RC 1)*** +-improved metamethods error handling +-added parameter 'isstatic' to _newmember metamethod(thx G.Meyer) +-added sq_getrefcount() to return number of refences from C++(thx G.Meyer) + +***2010-11-07 *** +***version 3.0 beta 3*** +-license changed to "MIT license" +-added sq_resurrectunreachable() and resurrectunreachable() +-added callee() built in function, returns the current running closure +-added thread.getstackinfos() +-added sq_objtouserpointer() +-added sq_newtableex() +-various refactoring and optimizations +-fixed several 64bits issues regarding integer to string conversions +-fixed some bugs when SQUSEDOUBLE is used in 32bits systems + +***2010-08-18 *** +***version 3.0 beta 2.1*** +-fixed bug in class constructor +-fixed bug in compound arith + +***2010-08-12 *** +***version 3.0 beta 2*** +-class methods can be added or replaced after the class as been instantiated +-JSON compliant table syntax, this is currently an experimental feature (thx atai) +-sq_getsize() now returns userdatasize for classes and instances +-now setroottable() and setconsttable() return the previous value of the respective table +-fixed bug in compound arith operators when used on a free variable (thx ellon) +-fixed some x64 minor bugs +-fixed minor bug in the compiler +-refactored some VM internals +-documented sq_getmemberhandle, sq_getbyhandle, sq_setbyhandle to set and get value from classes + +***2009-11-15 *** +***version 3.0 beta 1*** +-various refactoring and optimizations +-fixed bug in free variables (thx mokehehe) +-fixed bug in functions with default parameters (thx ara & Yexo) +-fixed bug in exception handling +-improved error propagation in _set and _get metamethods ( and 'throw null' for clean failure) +-added sq_getmemberhandle, sq_getbyhandle, sq_setbyhandle to set and get value from classes + +***2009-06-30 *** +***version 3.0 alpha 2*** +-added real free variables(thx Paul Ruizendaal) +-added refactored function call implementation and compiler(thx Paul Ruizendaal) +-added sq_getfunctioninfo +-added compile time flag SQUSEDOUBLE to use double precision floats +-added global slot _floatsize_ int the base lib to recognize single precision and double precision builds +-sq_wakeupvm can now resume the vm with an exception +-added sqstd_format +-now blobs can be cloned +-generators can now be instantiated by calling sq_call() or closure.call() +-fixed debughook bug +-fixed cooroutine error propagation + +***2008-07-23 *** +***version 3.0 alpha 1*** +-first branch from 2.x source tree +-added 'base' keyword +-removed 'delegate' keyword +-now compiled scripts are vararg functions +-added setdelegate() and getdelegate() table builtin methods +-added <=> 3 ways compare operator +-added lambda expression @(a,b) a + b +-added local function statement +-added array built-in map(),reduce(),apply(),filter() and find() +-generators hold only a weak reference of the enviroment object +-removed 'vargv' and 'vargc' keywords +-now var args are passed as an array called vargv(as a paramter) +-removed 'parent' keyword +-added class getbase() built in method +-instanceof doesn't throw an exception if the left expression is not a class +-lexical scoping for free variables(free variables are no longer in the second parameter list) +-sq_setprintfunc accept error func +-sq_geterrorfunc() +-added sq_arrayremove() and sq_arrayinsert() +-error() built in function(works like print but prints using the errorfunc) +-added native debug hook + +***2008-02-17 *** +***version 2.2 stable*** +-added _newslot metamethod in classes +-added enums added constants +-added sq_pushconsttable, sq_setconsttable +-added default param +-added octal literals(thx Dinosaur) +-fixed debug hook, 'calls' and 'returns' are properly notified in the same number. +-fixed a coroutine bug + +***2007-07-29 *** +***version 2.1.2 stable*** +-new behaviour for generators iteration using foreach +now when a generator is iterated by foreach the value returned by a 'return val' statement +will terminate the iteration but will not be returned as foreach iteration +-added sq_setclassudsize() +-added sq_clear() +-added table.clear(), array.clear() +-fixed sq_cmp() (thx jyuill) +-fixed minor bugs + +***2006-08-21 *** +***version 2.1.1 stable*** +-vm refactoring +-optimized internal function memory layout +-new global symbol _version_ (is the version string) +-code size optimization for float literals(on 32bits float builts) +-now the raw ref API(sq_addref etc...) is fully reentrant. +-fixed a bug in sq_getdelegate() now pushes null if the object doesn't have a delegate(thx MatzeB) +-improved C reference performances in NO_GARBAGE_COLLECTOR builds +-sq_getlocal() now enumerates also outer values. +-fixed regexp library for GCC users. + +***2006-03-19 *** +***version 2.1 stable*** +-added static class fields, new keyword static +-added 64bits architecture support +-added global slot _intsize_ int the base lib to recognize 32bits and 64bits builds +-added functions with fixed environment, closure.bindenv() built-in function +-all types except userdata and null implement the tostring() method +-string concatenation now invokes metamethod _tostring +-new metamethods for class objects _newmember and _inherited +-sq_call() sq_resume() sq_wakeupvm() have a new signature +-new C referencing implementation(scales more with the amount of references) +-refactored hash table +-new api functions sq_newslot(),sq_tobool(),sq_getbase(), sq_instanceof(), sq_bindenv() +-the api func sq_createslot was deprecated but still supported in form of C macro on top of sq_newslot +-sq_setreleasehook() now also works for classes +-stream.readstr() and stream.writestr() have been deprecated(this affects file and blob) +-fixed squirrel.h undeclared api calls +-fixed few minor bugs +-SQChar is now defined as wchar_t +-removed warning when building with -Wall -pedantic for GCC users +-added new std io function writeclosuretofile() +-added new std string functions strip(),rstrip(),lstrip() and split() +-regular expressions operators (+,*) now have more POSIX greedyness behaviour +-class constructors are now invoked as normal functions + +***2005-10-02 *** +***version 2.0.5 stable*** +-fixed some 64bits incompatibilities (thx sarge) +-fixed minor bug in the stdlib format() function (thx Rick) +-fixed a bug in dofile() that was preventing to compile empty files +-added new API sq_poptop() & sq_getfreevariable() +-some performance improvements + +***2005-08-14 *** +***version 2.0.4 stable*** +-weak references and related API calls +-added sq_objtobool() +-class instances memory policies improved(1 mem allocation for the whole instance) +-typetags are now declared as SQUserPointer instead of unsigned int +-first pass for 64bits compatibility +-fixed minor bug in the stdio stream +-fixed a bug in format() +-fixed bug in string.tointeger() and string.tofloat() + +***2005-06-24 *** +***version 2.0.3 stable*** +-dofile() and loadfile() in the iolib now can decode ASCII, UTF8 files UCS2 big-endian and little-endian +-sq_setparamscheck() : now typemesk can check for null +-added string escape sequence \xhhhh +-fixed some C++ standard incompatibilities + +***2005-05-15 *** +***version 2.0.2 stable*** +-performances improvements (expecially for GCC users) +-removed all dependencies from C++ exception handling +-various bugfixes + +***2005-04-12 *** +***version 2.0.1 stable*** +-various bugfixes +-sq_setparamscheck() now allows spaces in the typemask + +***2005-04-03 *** +***version 2.0 stable*** +-added API sq_gettypetag() +-added built-in function to the bool type(tointeger, tostring etc...) + +***2005-02-27 *** +***version 2.0 release candidate 1(RC 1)*** +-added API sq_reseterror() +-modified sq_release() +-now class instances can be cloned +-various bufixes + +***2005-01-26 *** +***version 2.0 beta 1*** +-added bool type +-class properties can be redefined in a derived class +-added ops *= /= and %= +-new syntax for class attributes declaration instead of ( and ) +-increased the max number of literals per function from 65535 to 16777215 +-now free variables have proper lexical scoping +-added API sq_createinstance(), sq_pushbool(), sq_getbool() +-added built-in function type() +-added built-in function obj.rawin(key) in table,class and instance +-sq_rawget() and sq_rawset() now work also on classes and instances +-the VM no longer uses C++ exception handling (more suitable for embedded devices) +-various bufixes + +***2004-12-21 *** +***version 2.0 alpha 2*** +-globals scoping changed, now if :: is omitted the VM automatically falls back on the root table +-various bufixes +-added class level attributes + +***2004-12-12 *** +***version 2.0 alpha 1*** +-codebase branch from version 1.x +-added classes +-added functions with variable number of parameters(vargc & vargv and the ...) +-0 and 0.0 are now considered 'false' by all conditional statements(if,while,for,?,do-while) +-added new api functions sq_newclass() sq_setinstanceup() sq_getinstanceup() sq_getattributes() sq_setattributes() +-modified api sq_settypetag() + +***2004-11-01 *** +***version 1.0 stable*** +-fixed some minor bug +-improved operator 'delete' performances +-added scientific notation for float numbers( eg. 2.e16 or 2.e-2) + +***2004-08-30 *** +***version 1.0 release candidate 2(RC 2)*** +-fixed bug in the vm(thx Pierre Renaux) +-fixed bug in the optimizer(thx Pierre Renaux) +-fixed some bug in the documentation(thx JD) +-added new api functions for raw object handling +-removed nested multiline comments +-reduced memory footprint in C references + +***2004-08-23 *** +***version 1.0 release candidate 1(RC 1)*** +-fixed division by zero +-the 'in' operator and obj.rawget() do not query the default delegate anymore +-added function sq_getprintfunc() +-added new standard library 'auxlib'(implements default error handlers) + +***2004-07-12 *** +***version 1.0 beta 4*** +-fixed a bug in the integer.tochar() built-in method +-fixed unary minus operator +-fixed bug in dofile() +-fixed inconsistency between != and == operators(on float/integer comparison) +-added javascript style unsigned right shift operator '>>>' +-added array(size) constructor built-in function +-array.resize(size,[fill]) built-in function accepts an optional 'fill' value +-improved debug API, added sq_getclosureinfo() and sq_setnativeclosurename() + +***2004-05-23 *** +***version 1.0 beta 3*** +-minor vm bug fixes +-string allocation is now faster +-tables and array memory usage is now less conservative(they shrink) +-added regular expression routines in the standard library +-The 'c' expression now accepts only 1 character(thx irbrian) +-multiline strings <[ ]> have been substituted with C# style verbatim strings (eg. @"string") +-added new keyword 'parent' for accessing the delegate of tables and unserdata +-The metamethod '_clone' has been renamed '_cloned' +-the _delslot metamethod's behaviour and prototype have been changed +-new default function in the integer and float object 'tochar()' +-the built-in function chcode2string has been removed +-the default method [table].getdelegate() has been removed +-new api sq_rawdeleteslot() +-new table built-in method rawdelete(key) +-the dynamic mudule loading has been removed from the standard distribution +-some optimizations in the VM + +***2004-04-21 *** +***version 1.0 beta 2*** +-minor compiler/parser bug fixes +-sq_newclosure has a different prototype, the "paramscheck" of paramter has been moved to the new function sq_setparamscheck() +-sq_setparamscheck allows to add automatic parameters type checking in native closures +-sq_compile() lost the lineinfo parameter +-new api sq_enabledebuginfo() globally sets compiler's debug info generation +-added consistency check on bytecode serialization +-fixed += operator, now works on strings like + +-added global slot in the base lib _charsize_ to recognize unicode builds from ascii builds runtime +-added registry table +-new api call sq_pushregistrytable() +-added type tag to the userdata type sq_settypetag() +-sq_getuserdata now queries the userdata typetag +-the built in function collect_garbage() as been renamed collectgarbage() for consistency reasons +-new standard libraries(sqlibs are now obsolete) + +***2004-02-20 *** +***version 1.0 beta 1*** +-fixed a bug in the compiler (thanks Martin Kofler) +-fixed bug in the switch case statement +-fixed the _unm metamethod +-fixed minor bugs in the API +-fixed automatic stack resizing +-first beta version + first pass code clean up in the VM and base lib + first pass code coverege test has been done on VM and built-in lib +-new VM creation API sq_open() sq_close() (sq_newvm and sq_releasevm are now obsolete) +-new api allows to specifiy a "print" function to output text(sq_printfunc) +-added some small optimizations +-new cooperative multi-threading capabilities in the base library(coroutines), VMs are now a built in type("thread") +-new built in functions have been added for manipulating the new "thread" type +-friend virtual machines share the same root table, error handler and debug hook by default +-new compile time options + +***2004-01-19 *** +***version 0.9 alpha*** +-fixed a garbage collection bug +-fixed some API bugs(thanks to Joshua Jensen) +-fixed tail calls (in the version 0.8 the tail call optimization was erroneously disabled) +-new function parameters semantic, now passing a wrong number of parameters generates an exception +-native closures have now a built in parameter number checking +-sq_rawget and sq_rawset now work also on arrays +-sq_getsize now woks also on userdata +-the userdata release hook prototype is changed(now passes the size of the userdata) +-the lexer reader function now returns an integer instead of a char that allows better error checking on the input(thx Joshua Jensen) +-faster compiler +-try/catch blocks do not cause any runtime memory allocation anymore + +***2003-12-06 *** +***version 0.8 alpha*** +-fixed a bug that was preventing to have callable userdata throught the metamethod _call +-fixed a garbage collection bug +-fixed == operator now can compare correctly different types +-new built in method getstackinfos(level) +-improved line informations precision for the debug hook +-new api call sq_compilebuffer() +-new built-in api function compilestring() +-new syntactic sugar for function declarations inside tables +-the debug API has been finalized + +***2003-11-17 *** +***version 0.7 alpha*** +-fixed critical bug SQInteger the tail call system +-fixed bug in the continue statement code generation +-fixed func call param issue(thanks to Rewoonenco Andrew) +-added _delslot metamethod(thanks to Rewoonenco Andrew) +-new multiline string expression ( delimited by <[ and ]> ) +-normal strings ("") do not allow embedded new line anymore +-reduced vm memory footprint(C refs are shared between friend VMs) +-new api method sq_deleteslot() +-new debug hook event 'r' is triggered when a function returns + +***2003-11-04 *** +***version 0.6 alpha*** +-fixed switch statement(was executing the default case after a break) +-sq_call() doesn't pop the closure (just the params) +-the vm execution can be suspended from the C API anytime (micro-threads) +-new api calls sq_suspendvm() sq_wakeupvm() sq_getvmstate() and sq_reservestack() + +***2003-10-13 *** +***version 0.5 alpha*** +-fixed some minor bug +-tested with non ASCII identifiers in unicode mode(I've tried chinese chars) +-added built-in function string.find() +-the built-in function array.sort() optionally accepts a cmp(a,b) function +-the debug hook function now has a new prototype debug_hook(event_type,sourcefile,line,functionname) +-fixed some debug info imprecision + +***2003-10-01 *** +***version 0.4 alpha*** +-faster VM +-sq_call will pop arguments and closure also in case of failure +-fixed a bug in sq_remove +-now the VM detects delegation cycles(and throws an exception) +-new operators ++ and -- +-new operator ',' comma operator +-fixed some expression precedence issue +-fixed bug in sq_arraypop + +***2003-09-15 *** +***version 0.3 alpha*** +-fixed a bug in array::insert() +-optional Unicode core(define SQUNICODE or _UNICODE on Win32) +-sq_compiler uses a new reader function SQLEXREADFUNC +-the debug hook passes 'l' instead of 'line' for line callbacks + and 'c' instead of 'call' for call callbacks +-new array.extend() bulit-in function +-new API sq_clone() + +***2003-09-10 *** +***version 0.2 pre-alpha*** +-new completely reentrant VM (sq_open and sq_close are now obsolete) +-sq_newvm() has a new prototype +-allocators are now global and linked in the VM +-_newslot meta method added +-rawset creates a slot if doesn't exists +-the compiler error callback pass the vm handle(thanks Pierre Renaux) +-sq_setforeignptr() sq_getforeingptr() are now public +-sq_resume() now is possible to resume generators from C +-sq_getlasterror() retrieve the last thrown error +-improved docs + +***2003-09-06 *** +***version 0.1 pre-alpha*** +first release diff --git a/squirrel_3_0_1_stable/Makefile b/squirrel_3_0_1_stable/Makefile new file mode 100644 index 000000000..8218f5bfa --- /dev/null +++ b/squirrel_3_0_1_stable/Makefile @@ -0,0 +1,18 @@ + +SQUIRREL=. +MAKE=make + +sq32: + cd squirrel; $(MAKE) + cd sqstdlib; $(MAKE) + cd sq; $(MAKE) + +sqprof: + cd squirrel; $(MAKE) sqprof + cd sqstdlib; $(MAKE) sqprof + cd sq; $(MAKE) sqprof + +sq64: + cd squirrel; $(MAKE) sq64 + cd sqstdlib; $(MAKE) sq64 + cd sq; $(MAKE) sq64 diff --git a/squirrel_3_0_1_stable/README b/squirrel_3_0_1_stable/README new file mode 100644 index 000000000..803b26aa1 --- /dev/null +++ b/squirrel_3_0_1_stable/README @@ -0,0 +1,23 @@ +The programming language SQUIRREL 3.0 stable + +-------------------------------------------------- +The project has been compiled and run on Windows(x86 and x64) and +Linux(x86 and x64) and Solaris(x86 and x64). + +Has been tested with the following compilers: + MS Visual C++ 6.0,7.0,7.1,8.0,9.0,10.0 (32 and 64bits) + MinGW gcc 3.2 (mingw special 20020817-1) + Cygnus gcc 3.2 + Linux gcc 3.2.3 + Linux gcc 4.0.0 (x86 & 64bits) + Solaris gcc 4.0.0 (x86 & 64bits) + + +Feedback and suggestions are appreciated +project page - http://www.squirrel-lang.org +community forums - http://forum.squirrel-lang.org +wiki - http://wiki.squirrel-lang.org +author - alberto@demichelis.net + +END OF README + diff --git a/squirrel_3_0_1_stable/include/sqstdaux.h b/squirrel_3_0_1_stable/include/sqstdaux.h new file mode 100644 index 000000000..b90034823 --- /dev/null +++ b/squirrel_3_0_1_stable/include/sqstdaux.h @@ -0,0 +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_ */ diff --git a/squirrel_3_0_1_stable/include/sqstdblob.h b/squirrel_3_0_1_stable/include/sqstdblob.h new file mode 100644 index 000000000..eda4cc9c5 --- /dev/null +++ b/squirrel_3_0_1_stable/include/sqstdblob.h @@ -0,0 +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, 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/squirrel_3_0_1_stable/include/sqstdio.h b/squirrel_3_0_1_stable/include/sqstdio.h new file mode 100644 index 000000000..1174201a9 --- /dev/null +++ b/squirrel_3_0_1_stable/include/sqstdio.h @@ -0,0 +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 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/squirrel_3_0_1_stable/include/sqstdmath.h b/squirrel_3_0_1_stable/include/sqstdmath.h new file mode 100644 index 000000000..420f2ce67 --- /dev/null +++ b/squirrel_3_0_1_stable/include/sqstdmath.h @@ -0,0 +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_*/ diff --git a/squirrel_3_0_1_stable/include/sqstdstring.h b/squirrel_3_0_1_stable/include/sqstdstring.h new file mode 100644 index 000000000..771c2f658 --- /dev/null +++ b/squirrel_3_0_1_stable/include/sqstdstring.h @@ -0,0 +1,33 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_STRING_H_ +#define _SQSTD_STRING_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +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_format(HSQUIRRELVM v,SQInteger nformatstringidx,SQInteger *outlen,SQChar **output); + +SQUIRREL_API SQRESULT sqstd_register_stringlib(HSQUIRRELVM v); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*_SQSTD_STRING_H_*/ diff --git a/squirrel_3_0_1_stable/include/sqstdsystem.h b/squirrel_3_0_1_stable/include/sqstdsystem.h new file mode 100644 index 000000000..daefa0fd5 --- /dev/null +++ b/squirrel_3_0_1_stable/include/sqstdsystem.h @@ -0,0 +1,15 @@ +/* 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/squirrel_3_0_1_stable/include/squirrel.h b/squirrel_3_0_1_stable/include/squirrel.h new file mode 100644 index 000000000..baaaf39c5 --- /dev/null +++ b/squirrel_3_0_1_stable/include/squirrel.h @@ -0,0 +1,500 @@ +/* +Copyright (c) 2003-2011 Alberto Demichelis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#ifndef _SQUIRREL_H_ +#define _SQUIRREL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef SQUIRREL_API +#define SQUIRREL_API extern +#endif + +#if (defined(_WIN64) || defined(_LP64)) +#ifndef _SQ64 +#define _SQ64 +#endif +#endif + +#ifdef _SQ64 + +#ifdef _MSC_VER +typedef __int64 SQInteger; +typedef unsigned __int64 SQUnsignedInteger; +typedef unsigned __int64 SQHash; /*should be the same size of a pointer*/ +#else +typedef long long SQInteger; +typedef unsigned long long SQUnsignedInteger; +typedef unsigned long long SQHash; /*should be the same size of a pointer*/ +#endif +typedef int SQInt32; +typedef unsigned int SQUnsignedInteger32; +#else +typedef int SQInteger; +typedef int SQInt32; /*must be 32 bits(also on 64bits processors)*/ +typedef unsigned int SQUnsignedInteger32; /*must be 32 bits(also on 64bits processors)*/ +typedef unsigned int SQUnsignedInteger; +typedef unsigned int SQHash; /*should be the same size of a pointer*/ +#endif + + +#ifdef SQUSEDOUBLE +typedef double SQFloat; +#else +typedef float SQFloat; +#endif + +#if defined(SQUSEDOUBLE) && !defined(_SQ64) || !defined(SQUSEDOUBLE) && defined(_SQ64) +#ifdef _MSC_VER +typedef __int64 SQRawObjectVal; //must be 64bits +#else +typedef long long SQRawObjectVal; //must be 64bits +#endif +#define SQ_OBJECT_RAWINIT() { _unVal.raw = 0; } +#else +typedef SQUnsignedInteger SQRawObjectVal; //is 32 bits on 32 bits builds and 64 bits otherwise +#define SQ_OBJECT_RAWINIT() +#endif + +#ifndef SQ_ALIGNMENT // SQ_ALIGNMENT shall be less than or equal to SQ_MALLOC alignments, and its value shall be power of 2. +#if defined(SQUSEDOUBLE) || defined(_SQ64) +#define SQ_ALIGNMENT 8 +#else +#define SQ_ALIGNMENT 4 +#endif +#endif + +typedef void* SQUserPointer; +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; +struct SQOuter; + +#ifdef _UNICODE +#define SQUNICODE +#endif + +#ifdef SQUNICODE +#if (defined(_MSC_VER) && _MSC_VER >= 1400) // 1400 = VS8 + +#if !defined(_NATIVE_WCHAR_T_DEFINED) //this is if the compiler considers wchar_t as native type +#define wchar_t unsigned short +#endif + +#else +typedef unsigned short wchar_t; +#endif + +typedef wchar_t SQChar; +#define _SC(a) L##a +#define scstrcmp wcscmp +#define scsprintf swprintf +#define scstrlen wcslen +#define scstrtod wcstod +#ifdef _SQ64 +#define scstrtol _wcstoi64 +#else +#define scstrtol wcstol +#endif +#define scatoi _wtoi +#define scstrtoul wcstoul +#define scvsprintf vswprintf +#define scstrstr wcsstr +#define scisspace iswspace +#define scisdigit iswdigit +#define scisxdigit iswxdigit +#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 +#ifdef _SQ64 +#ifdef _MSC_VER +#define scstrtol _strtoi64 +#else +#define scstrtol strtoll +#endif +#else +#define scstrtol strtol +#endif +#define scatoi atoi +#define scstrtoul strtoul +#define scvsprintf vsprintf +#define scstrstr strstr +#define scisspace isspace +#define scisdigit isdigit +#define scisxdigit isxdigit +#define sciscntrl iscntrl +#define scisalpha isalpha +#define scisalnum isalnum +#define scprintf printf +#define MAX_CHAR 0xFF +#endif + +#ifdef _SQ64 +#define _PRINT_INT_PREC _SC("ll") +#define _PRINT_INT_FMT _SC("%lld") +#else +#define _PRINT_INT_FMT _SC("%d") +#endif + +#define SQUIRREL_VERSION _SC("Squirrel 3.0.1 stable") +#define SQUIRREL_COPYRIGHT _SC("Copyright (C) 2003-2011 Alberto Demichelis") +#define SQUIRREL_AUTHOR _SC("Alberto Demichelis") +#define SQUIRREL_VERSION_NUMBER 301 + +#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 +#define _RT_OUTER 0x00020000 + +typedef enum tagSQObjectType{ + 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), + OT_OUTER = (_RT_OUTER|SQOBJECT_REF_COUNTED) //internal usage only +}SQObjectType; + +#define ISREFCOUNTED(t) (t&SQOBJECT_REF_COUNTED) + + +typedef union tagSQObjectValue +{ + struct SQTable *pTable; + struct SQArray *pArray; + struct SQClosure *pClosure; + struct SQOuter *pOuter; + 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; + SQRawObjectVal raw; +}SQObjectValue; + + +typedef struct tagSQObject +{ + SQObjectType _type; + SQObjectValue _unVal; +}SQObject; + +typedef struct tagSQMemberHandle{ + SQBool _static; + SQInteger _index; +}SQMemberHandle; + +typedef struct tagSQStackInfos{ + const SQChar* funcname; + const SQChar* source; + SQInteger line; +}SQStackInfos; + +typedef struct SQVM* HSQUIRRELVM; +typedef SQObject HSQOBJECT; +typedef SQMemberHandle HSQMEMBERHANDLE; +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 void (*SQDEBUGHOOK)(HSQUIRRELVM /*v*/, SQInteger /*type*/, const SQChar * /*sourcename*/, SQInteger /*line*/, const SQChar * /*funcname*/); +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; + +typedef struct tagSQFunctionInfo { + SQUserPointer funcid; + const SQChar *name; + const SQChar *source; +}SQFunctionInfo; + +/*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,SQPRINTFUNCTION errfunc); +SQUIRREL_API SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v); +SQUIRREL_API SQPRINTFUNCTION sq_geterrorfunc(HSQUIRRELVM v); +SQUIRREL_API SQRESULT sq_suspendvm(HSQUIRRELVM v); +SQUIRREL_API SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval,SQBool raiseerror,SQBool throwerror); +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 enable); +SQUIRREL_API void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable); +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 SQRESULT 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_newtableex(HSQUIRRELVM v,SQInteger initialcapacity); +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 SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx); +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 SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQBool sq_instanceof(HSQUIRRELVM v); +SQUIRREL_API SQRESULT sq_tostring(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b); +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_getfunctioninfo(HSQUIRRELVM v,SQInteger idx,SQFunctionInfo *fi); +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_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize); +SQUIRREL_API SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase); +SQUIRREL_API SQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx); +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); +SQUIRREL_API SQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t); +SQUIRREL_API SQRESULT sq_getmemberhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle); +SQUIRREL_API SQRESULT sq_getbyhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle); +SQUIRREL_API SQRESULT sq_setbyhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle); + +/*object manipulation*/ +SQUIRREL_API void sq_pushroottable(HSQUIRRELVM v); +SQUIRREL_API void sq_pushregistrytable(HSQUIRRELVM v); +SQUIRREL_API void sq_pushconsttable(HSQUIRRELVM v); +SQUIRREL_API SQRESULT sq_setroottable(HSQUIRRELVM v); +SQUIRREL_API SQRESULT sq_setconsttable(HSQUIRRELVM v); +SQUIRREL_API SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic); +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_arrayremove(HSQUIRRELVM v,SQInteger idx,SQInteger itemidx); +SQUIRREL_API SQRESULT sq_arrayinsert(HSQUIRRELVM v,SQInteger idx,SQInteger destpos); +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); +SQUIRREL_API SQRESULT sq_clear(HSQUIRRELVM v,SQInteger idx); + +/*calls*/ +SQUIRREL_API SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror); +SQUIRREL_API SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror); +SQUIRREL_API const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx); +SQUIRREL_API SQRESULT sq_getcallee(HSQUIRRELVM v); +SQUIRREL_API const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval); +SQUIRREL_API SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err); +SQUIRREL_API SQRESULT sq_throwobject(HSQUIRRELVM v); +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 SQUnsignedInteger sq_getrefcount(HSQUIRRELVM v,HSQOBJECT *po); +SQUIRREL_API void sq_resetobject(HSQOBJECT *po); +SQUIRREL_API const SQChar *sq_objtostring(const HSQOBJECT *o); +SQUIRREL_API SQBool sq_objtobool(const HSQOBJECT *o); +SQUIRREL_API SQInteger sq_objtointeger(const HSQOBJECT *o); +SQUIRREL_API SQFloat sq_objtofloat(const HSQOBJECT *o); +SQUIRREL_API SQUserPointer sq_objtouserpointer(const HSQOBJECT *o); +SQUIRREL_API SQRESULT sq_getobjtypetag(const HSQOBJECT *o,SQUserPointer * typetag); + +/*GC*/ +SQUIRREL_API SQInteger sq_collectgarbage(HSQUIRRELVM v); +SQUIRREL_API SQRESULT sq_resurrectunreachable(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); +SQUIRREL_API void sq_setnativedebughook(HSQUIRRELVM v,SQDEBUGHOOK hook); + +/*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) + +/* deprecated */ +#define sq_createslot(v,n) sq_newslot(v,n,SQFalse) + +#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/squirrel_3_0_1_stable/sqplus/Makefile b/squirrel_3_0_1_stable/sqplus/Makefile new file mode 100644 index 000000000..1bef39832 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/Makefile @@ -0,0 +1,18 @@ +SQUIRREL= .. + +OUT= $(SQUIRREL)/lib/libsqplus.a +INCDIRS= -I$(SQUIRREL)/include -I. -Iinclude + +ALLSRCS = $(wildcard *.cpp) +WIN32SRCS = $(wildcard *Win32*) +SRCS = $(filter-out $(WIN32SRCS),$(ALLSRCS)) + +sqplus: +# g++ -fno-rtti -c $(SRCS) $(INCDIRS) + g++ -O3 -fno-rtti -Os -c $(SRCS) $(INCDIRS) + ar rc $(OUT) *.o + rm *.o + + +#g++ -O3 -fno-rtti -Os -c $(SRCS) $(INCDIRS) +#g++ -ggdb -fno-rtti -c $(SRCS) $(INCDIRS) diff --git a/squirrel_3_0_1_stable/sqplus/SqPlus.cpp b/squirrel_3_0_1_stable/sqplus/SqPlus.cpp new file mode 100644 index 000000000..a2eaacb72 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SqPlus.cpp @@ -0,0 +1,382 @@ +#include "sqplus.h" +#include + +#ifdef SQPLUS_SMARTPOINTER_OPT +#define SQPLUS_SMARTPOINTER_CPP_DECLARATION +#include "SqPlusSmartPointer.h" +#endif + +namespace SqPlus { + +static int getVarInfo(StackHandler & sa,VarRefPtr & vr) { + HSQOBJECT htable = sa.GetObjectHandle(1); + SquirrelObject table(htable); + const SQChar * el = sa.GetString(2); + ScriptStringVar256 varNameTag; + getVarNameTag(varNameTag,sizeof(varNameTag),el); + SQUserPointer data=0; + if (!table.RawGetUserData(varNameTag,&data)) { + return sa.ThrowError(_SC("getVarInfo: Could not retrieve UserData")); // Results in variable not being found error. + } + vr = (VarRefPtr)data; + return SQ_OK; +} // getVarInfo + +static int getInstanceVarInfo(StackHandler & sa,VarRefPtr & vr,SQUserPointer & data) { + HSQOBJECT ho = sa.GetObjectHandle(1); + SquirrelObject instance(ho); + const SQChar * el = sa.GetString(2); + ScriptStringVar256 varNameTag; + getVarNameTag(varNameTag,sizeof(varNameTag),el); + SQUserPointer ivrData=0; + if (!instance.RawGetUserData(varNameTag,&ivrData)) { + return sa.ThrowError(_SC("getInstanceVarInfo: Could not retrieve UserData")); // Results in variable not being found error. + } + vr = (VarRefPtr)ivrData; + + char * up; + if (!(vr->m_access & (VAR_ACCESS_STATIC|VAR_ACCESS_CONSTANT))) { + SQUserPointer typetag; + instance.GetTypeTag(&typetag); + +#if defined(SQ_USE_CLASS_INHERITANCE) + if (typetag != vr->instanceType) { + SquirrelObject typeTable = instance.GetValue(SQ_CLASS_OBJECT_TABLE_NAME); + up = (char *)typeTable.GetUserPointer(INT((size_t)vr->instanceType)); // 64-bit compatible version. + if (!up) { + throw SquirrelError(_SC("Invalid Instance Type")); + } + } else { + up = (char *)instance.GetInstanceUP(0); + } // if + +#elif defined(SQ_USE_CLASS_INHERITANCE_SIMPLE) + ClassTypeBase *ctb = (ClassTypeBase*)vr->instanceType; + up = (char *)instance.GetInstanceUP(0); + // Walk base classes until type tag match, adjust for inheritence offset + while(ctb && typetag!=ctb) { + up = (char*)up - ctb->m_offset; + ctb = ctb->m_pbase; + } + if (!ctb) { + throw SquirrelError(_SC("Invalid Instance Type")); + } +#else + up = (char *)instance.GetInstanceUP(0); +#endif + +#ifdef SQPLUS_SMARTPOINTER_OPT +#define SQPLUS_SMARTPOINTER_INSTANCE_VARINFO +#include "SqPlusSmartPointer.h" +#endif + + up += (size_t)vr->offsetOrAddrOrConst; // Offset + } else { + up = (char *)vr->offsetOrAddrOrConst; // Address + } // if + data = up; + return SQ_OK; +} // getInstanceVarInfo + + +// If not static/global, message can (and will) disappear before arriving at catch (G++) +static ScriptStringVar256 g_msg_throw; + +static int setVar(StackHandler & sa,VarRef * vr,void * data) { + if (vr->m_access & (VAR_ACCESS_READ_ONLY|VAR_ACCESS_CONSTANT)) { + const SQChar * el = sa.GetString(2); + SCSNPRINTF(g_msg_throw.s,sizeof(g_msg_throw),_SC("setVar(): Cannot write to constant: %s"),el); + throw SquirrelError(g_msg_throw.s); + } // if + switch (vr->m_type) { + case TypeInfo::TypeID: { + INT * val = (INT *)data; // Address + if (val) { + INT v = sa.GetInt(3); + // Support for different int sizes + switch( vr->m_size ) { + case 1: v = (*(char*)val = (char)v); break; + case 2: v = (*(short*)val = (short)v); break; +#ifdef _SQ64 + case 4: v = (*(int*)val = (int)v); break; +#endif + default: *val = v; + } + return sa.Return(v); + } // if + break; + } // case + case TypeInfo::TypeID: { + unsigned * val = (unsigned *)data; // Address + if (val) { + *val = sa.GetInt(3); + return sa.Return(static_cast(*val)); + } // if + break; + } // case + case TypeInfo::TypeID: { + FLOAT * val = (FLOAT *)data; // Address + if (val) { + *val = sa.GetFloat(3); + return sa.Return(*val); + } // if + break; + } // case + case TypeInfo::TypeID: { + bool * val = (bool *)data; // Address + if (val) { + *val = sa.GetBool(3) ? true : false; + return sa.Return(*val); + } // if + break; + } // case + case VAR_TYPE_INSTANCE: { + HSQUIRRELVM v = sa.GetVMPtr(); + SQUserPointer src = sa.GetInstanceUp(3,(SQUserPointer)vr->varType); // Effectively performs: ClassType<>::type() == ClassType<>(). + if (!src) { + throw SquirrelError(_SC("INSTANCE type assignment mismatch")); + } + vr->varType->vgetCopyFunc()(data,src); + return 0; + } + case TypeInfo::TypeID: { + const SQChar * el = sa.GetString(2); + SCSNPRINTF(g_msg_throw.s,sizeof(g_msg_throw),_SC("setVar(): Cannot write to an SQUserPointer: %s"),el); + throw SquirrelError(g_msg_throw.s); + } // case + case TypeInfo::TypeID: { + ScriptStringVarBase * val = (ScriptStringVarBase *)data; // Address + if (val) { + const SQChar * strVal = sa.GetString(3); + if (strVal) { + *val = strVal; + return sa.Return(val->s); + } // if + } // if + break; + } // case +#if defined(SQPLUS_SUPPORT_STD_STRING) && !defined(SQUNICODE) + case TypeInfo::TypeID: { + std::string *val = (std::string*)data; // Address + if (val) { + const SQChar *strVal = sa.GetString(3); + if (strVal) { + *val = strVal; + return sa.Return(val->c_str()); + } // if + } // if + break; + } // case +#endif + } // switch + return SQ_ERROR; +} // setVar + +static int getVar(StackHandler & sa,VarRef * vr,void * data) { + switch (vr->m_type) { + case TypeInfo::TypeID: { + if (!(vr->m_access & VAR_ACCESS_CONSTANT)) { + if (data) { + INT v; + // Support for different int sizes + switch( vr->m_size ){ + case 1: v = *(char*)data; break; + case 2: v = *(short*)data; break; +#ifdef _SQ64 + case 4: v = *(int*)data; break; +#endif + default: v = *(INT*)data; + } + return sa.Return(v); + } // if + } else { + INT * val = (INT *)&data; // Constant value + return sa.Return(*val); + } // if + break; + } // case + case TypeInfo::TypeID: { + if (!(vr->m_access & VAR_ACCESS_CONSTANT)) { + unsigned * val = (unsigned *)data; // Address + if (val){ + return sa.Return(static_cast(*val)); + } + } else { + unsigned * val = (unsigned *)&data; // Constant value + return sa.Return(static_cast(*val)); + } // if + break; + } // case + case TypeInfo::TypeID: { + if (!(vr->m_access & VAR_ACCESS_CONSTANT)) { + FLOAT * val = (FLOAT *)data; // Address + if (val) { + return sa.Return(*val); + } // if + } else { + FLOAT * val = (FLOAT *)&data; // Constant value + return sa.Return(*val); + } // if + break; + } // case + case TypeInfo::TypeID: { + if (!(vr->m_access & VAR_ACCESS_CONSTANT)) { + bool * val = (bool *)data; // Address + if (val) { + return sa.Return(*val); + } // if + } else { + bool * val = (bool *)&data; // Constant value + return sa.Return(*val); + } // if + break; + } // case + case VAR_TYPE_INSTANCE: + if (!CreateNativeClassInstance(sa.GetVMPtr(),vr->varType->GetTypeName(),data,0)) { // data = address. Allocates memory. + SCSNPRINTF(g_msg_throw.s,sizeof(g_msg_throw),_SC("getVar(): Could not create instance: %s"),vr->varType->GetTypeName()); + throw SquirrelError(g_msg_throw.s); + } // if + return 1; + case TypeInfo::TypeID: + return sa.Return(data); // The address of member variable, not the variable itself. + case TypeInfo::TypeID: { + if (!(vr->m_access & VAR_ACCESS_CONSTANT)) { + ScriptStringVarBase * val = (ScriptStringVarBase *)data; // Address + if (val) { + return sa.Return(val->s); + } // if + } else { + throw SquirrelError(_SC("getVar(): Invalid type+access: 'ScriptStringVarBase' with VAR_ACCESS_CONSTANT (use VAR_ACCESS_READ_ONLY instead)")); + } + break; + } // case + case TypeInfo::TypeID: { + if (!(vr->m_access & VAR_ACCESS_CONSTANT)) { + if( vr->m_access==VAR_ACCESS_READ_WRITE ) + throw SquirrelError(_SC("getVar(): Invalid type+access: 'const SQChar *' without VAR_ACCESS_CONSTANT")); + // It is OK to read from a SQChar* if requested + return sa.Return(*(const SQChar **)data); // Address + } else { + return sa.Return((const SQChar *)data); // Address + } + break; + } // case +#ifdef SQPLUS_SUPPORT_STD_STRING + case TypeInfo::TypeID: { + if (!(vr->m_access & VAR_ACCESS_CONSTANT)) { + std::string *val = (std::string *)data; // Address + if (val) { + return sa.Return(val->c_str()); + } + } else { + throw SquirrelError(_SC("getVar(): Invalid type+access: 'std::string' with VAR_ACCESS_CONSTANT (use VAR_ACCESS_READ_ONLY instead)")); + } + break; + } // case +#endif + } // switch + return SQ_ERROR; +} // getVar + +// === Global Vars === + +int setVarFunc(HSQUIRRELVM v) { + SquirrelVM::Init(v); // For handling multi-VM setting right + StackHandler sa(v); + if (sa.GetType(1) == OT_TABLE) { + VarRefPtr vr; + int res = getVarInfo(sa,vr); + if (res != SQ_OK) return res; + return setVar(sa,vr,vr->offsetOrAddrOrConst); + } // if + return SQ_ERROR; +} // setVarFunc + +int getVarFunc(HSQUIRRELVM v) { + SquirrelVM::Init(v); // For handling multi-VM setting right + StackHandler sa(v); + if (sa.GetType(1) == OT_TABLE) { + VarRefPtr vr; + int res = getVarInfo(sa,vr); + if (res != SQ_OK) return res; + return getVar(sa,vr,vr->offsetOrAddrOrConst); + } // if + return SQ_ERROR; +} // getVarFunc + +// === Instance Vars === + +int setInstanceVarFunc(HSQUIRRELVM v) { + SquirrelVM::Init(v); // For handling multi-VM setting right + StackHandler sa(v); + if (sa.GetType(1) == OT_INSTANCE) { + VarRefPtr vr; + void * data; + int res = getInstanceVarInfo(sa,vr,data); + if (res != SQ_OK) return res; + return setVar(sa,vr,data); + } // if + return SQ_ERROR; +} // setInstanceVarFunc + +int getInstanceVarFunc(HSQUIRRELVM v) { + SquirrelVM::Init(v); // For handling multi-VM setting right + StackHandler sa(v); + if (sa.GetType(1) == OT_INSTANCE) { + VarRefPtr vr; + void * data; + int res = getInstanceVarInfo(sa,vr,data); + if (res != SQ_OK) return res; + return getVar(sa,vr,data); + } // if + return SQ_ERROR; +} // getInstanceVarFunc + +// === Classes === + +BOOL CreateClass(HSQUIRRELVM v,SquirrelObject & newClass,SQUserPointer classType,const SQChar * name,const SQChar * baseName) { + int n = 0; + int oldtop = sq_gettop(v); + sq_pushroottable(v); + sq_pushstring(v,name,-1); + if (baseName) { + sq_pushstring(v,baseName,-1); + if (SQ_FAILED(sq_get(v,-3))) { // Make sure the base exists if specified by baseName. + sq_settop(v,oldtop); + return FALSE; + } // if + } // if + if (SQ_FAILED(sq_newclass(v,baseName ? 1 : 0))) { // Will inherit from base class on stack from sq_get() above. + sq_settop(v,oldtop); + return FALSE; + } // if + newClass.AttachToStackObject(-1); + sq_settypetag(v,-1,classType); + sq_createslot(v,-3); + sq_pop(v,1); + return TRUE; +} // CreateClass + +SquirrelObject RegisterClassType(HSQUIRRELVM v,const SQChar * scriptClassName,SQUserPointer classType,SQFUNCTION constructor) { + SquirrelVM::Init(v); // For handling multi-VM setting right + int top = sq_gettop(v); + SquirrelObject newClass; + if (CreateClass(v,newClass,classType,scriptClassName)) { + SquirrelVM::CreateFunction(newClass,constructor,_SC("constructor")); + } // if + sq_settop(v,top); + return newClass; +} // RegisterClassType + + +/////////////////////////////////////////////////////////////////////////// +// GCC sometimes has problems with finding inline functions at link time +// (that also have a template definition). To solve the problem, +// non-inlines goes here. +#ifdef GCC_INLINE_WORKAROUND +# include "SqPlusFunctionCallImpl.h" +#endif // GCC_INLINE_WORKAROUND +/////////////////////////////////////////////////////////////////////////// + +} // namespace SqPlus + diff --git a/squirrel_3_0_1_stable/sqplus/SqPlusCallTemplates.h b/squirrel_3_0_1_stable/sqplus/SqPlusCallTemplates.h new file mode 100644 index 000000000..75e4887c5 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SqPlusCallTemplates.h @@ -0,0 +1,337 @@ + +// This file is included multiple times, with varying options - No header guard. + +// Include this file to generate Call templates with or without these options: +// - SQPLUS_APPLY_CONST - const qualifier after functions signature (const func / member func) +// - SQPLUS_APPLY_CDECL - qualifier before class name (MSVC specific calling convention) + +#undef CONST_QUAL +#undef CALL_QUAL + +#ifdef SQPLUS_APPLY_CONST + #define CONST_QUAL const +#else + #define CONST_QUAL +#endif + +#ifdef SQPLUS_APPLY_CDECL + #define CALL_QUAL __cdecl +#else + #define CALL_QUAL +#endif + + +#ifdef SQPLUS_CALL_MFUNC_RET0 + + // Include this file again, with __cdecl also (Visual C++ specific) + #if defined(SQPLUS_ENABLE_CDECL_MEMBER_FUNCTIONS) && !defined(SQPLUS_APPLY_CDECL) + #define SQPLUS_APPLY_CDECL + #include "SqPlusCallTemplates.h" + #undef CALL_QUAL + #define CALL_QUAL + #endif + + template + static int Call(Callee & callee,RT (CALL_QUAL Callee::*func)() CONST_QUAL,HSQUIRRELVM v,int /*index*/) { + RT ret = (callee.*func)(); + Push(v,ret); + return 1; + } + + template + static int Call(Callee & callee,RT (CALL_QUAL Callee::*func)(P1) CONST_QUAL,HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + RT ret = (callee.*func)( + Get(TypeWrapper(),v,index + 0) + ); + Push(v,ret); + return 1; + } + + template + static int Call(Callee & callee,RT (CALL_QUAL Callee::*func)(P1,P2) CONST_QUAL,HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + RT ret = (callee.*func)( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1) + ); + Push(v,ret); + return 1; + } + + template + static int Call(Callee & callee,RT (CALL_QUAL Callee::*func)(P1,P2,P3) CONST_QUAL,HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + RT ret = (callee.*func)( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2) + ); + Push(v,ret); + return 1; + } + + template + static int Call(Callee & callee,RT (CALL_QUAL Callee::*func)(P1,P2,P3,P4) CONST_QUAL,HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + RT ret = (callee.*func)( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3) + ); + Push(v,ret); + return 1; + } + + template + static int Call(Callee & callee,RT (CALL_QUAL Callee::*func)(P1,P2,P3,P4,P5) CONST_QUAL,HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + RT ret = (callee.*func)( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4) + ); + Push(v,ret); + return 1; + } + + template + static int Call(Callee & callee,RT (CALL_QUAL Callee::*func)(P1,P2,P3,P4,P5,P6) CONST_QUAL,HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + sq_argassert(6,index + 5); + RT ret = (callee.*func)( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4), + Get(TypeWrapper(),v,index + 5) + ); + Push(v,ret); + return 1; + } + + template + static int Call(Callee & callee,RT (CALL_QUAL Callee::*func)(P1,P2,P3,P4,P5,P6,P7) CONST_QUAL,HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + sq_argassert(6,index + 5); + sq_argassert(7,index + 6); + RT ret = (callee.*func)( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4), + Get(TypeWrapper(),v,index + 5), + Get(TypeWrapper(),v,index + 6) + ); + Push(v,ret); + return 1; + } +#undef SQPLUS_CALL_MFUNC_RET0 +#endif // SQPLUS_CALL_MFUNC_RET0 + + +#ifdef SQPLUS_CALL_MFUNC_NORET + + // Include this very same thing with __cdecl also + #if defined(SQPLUS_ENABLE_CDECL_MEMBER_FUNCTIONS) && !defined(SQPLUS_APPLY_CDECL) + #define SQPLUS_APPLY_CDECL + #include "SqPlusCallTemplates.h" + #undef CALL_QUAL + #define CALL_QUAL + #endif + + // === Member function calls === + + template + static int Call(Callee & callee,void (CALL_QUAL Callee::*func)() CONST_QUAL, HSQUIRRELVM,int /*index*/) { + (callee.*func)(); + return 0; + } + + template + static int Call(Callee & callee,void (CALL_QUAL Callee::*func)(P1) CONST_QUAL, HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + (callee.*func)( + Get(TypeWrapper(),v,index + 0) + ); + return 0; + } + + template + static int Call(Callee & callee,void (CALL_QUAL Callee::*func)(P1,P2) CONST_QUAL, HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + (callee.*func)( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1) + ); + return 0; + } + + template + static int Call(Callee & callee,void (CALL_QUAL Callee::*func)(P1,P2,P3) CONST_QUAL, HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + (callee.*func)( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2) + ); + return 0; + } + + template + static int Call(Callee & callee,void (CALL_QUAL Callee::*func)(P1,P2,P3,P4) CONST_QUAL, HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + (callee.*func)( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3) + ); + return 0; + } + + template + static int Call(Callee & callee,void (CALL_QUAL Callee::*func)(P1,P2,P3,P4,P5) CONST_QUAL, HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + (callee.*func)( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4) + ); + return 0; + } + + template + static int Call(Callee & callee,void (CALL_QUAL Callee::*func)(P1,P2,P3,P4,P5,P6) CONST_QUAL, HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + sq_argassert(6,index + 5); + (callee.*func)( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4), + Get(TypeWrapper(),v,index + 5) + ); + return 0; + } + + template + static int Call(Callee & callee,void (CALL_QUAL Callee::*func)(P1,P2,P3,P4,P5,P6,P7) CONST_QUAL, HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + sq_argassert(6,index + 5); + sq_argassert(7,index + 6); + (callee.*func)( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4), + Get(TypeWrapper(),v,index + 5), + Get(TypeWrapper(),v,index + 6) + ); + return 0; + } +#undef SQPLUS_CALL_MFUNC_NORET +#endif // SQPLUS_CALL_MFUNC_NORET + + +#ifdef SQPLUS_CALL_MFUNC_RET1 + + // Include this very same thing with __cdecl also + #if defined(SQPLUS_ENABLE_CDECL_MEMBER_FUNCTIONS) && !defined(SQPLUS_APPLY_CDECL) + #define SQPLUS_APPLY_CDECL + #include "SqPlusCallTemplates.h" + #undef CALL_QUAL + #define CALL_QUAL + #endif + + template + int Call(Callee & callee, RT (CALL_QUAL Callee::*func)() CONST_QUAL, HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(callee,func,v,index); + } + + template + int Call(Callee & callee,RT (CALL_QUAL Callee::*func)(P1) CONST_QUAL, HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(callee,func,v,index); + } + + template + int Call(Callee & callee,RT (CALL_QUAL Callee::*func)(P1,P2) CONST_QUAL, HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(callee,func,v,index); + } + + template + int Call(Callee & callee,RT (CALL_QUAL Callee::*func)(P1,P2,P3) CONST_QUAL, HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(callee,func,v,index); + } + + template + int Call(Callee & callee,RT (CALL_QUAL Callee::*func)(P1,P2,P3,P4) CONST_QUAL, HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(callee,func,v,index); + } + + template + int Call(Callee & callee,RT (CALL_QUAL Callee::*func)(P1,P2,P3,P4,P5) CONST_QUAL, HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(callee,func,v,index); + } + + template + int Call(Callee & callee,RT (CALL_QUAL Callee::*func)(P1,P2,P3,P4,P5,P6) CONST_QUAL, HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(callee,func,v,index); + } + + template + int Call(Callee & callee,RT (CALL_QUAL Callee::*func)(P1,P2,P3,P4,P5,P6,P7) CONST_QUAL, HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(callee,func,v,index); + } + +#undef SQPLUS_CALL_MFUNC_RET1 +#endif // SQPLUS_CALL_MFUNC_RET1 + +// We will be reusing these symbols later +#undef SQPLUS_APPLY_CDECL +#undef SQPLUS_APPLY_CONST diff --git a/squirrel_3_0_1_stable/sqplus/SqPlusConst.h b/squirrel_3_0_1_stable/sqplus/SqPlusConst.h new file mode 100644 index 000000000..0fd6b72ae --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SqPlusConst.h @@ -0,0 +1,74 @@ +// SqPlusConst.h +// SqPlus constant type and constant member function support created by Simon Michelmore. +// Modular integration 11/14/05 jcs. + +#ifdef SQPLUS_DECLARE_INSTANCE_TYPE_CONST +#undef SQPLUS_DECLARE_INSTANCE_TYPE_CONST + +// Kamaitati's NULL_INSTANCE support. 5/28/06 jcs + +#ifdef SQPLUS_SUPPORT_NULL_INSTANCES + +#define DECLARE_INSTANCE_TYPE_NAME_CONST_BASE(TYPE,NAME) \ +inline bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return GetInstance(v,idx) != NULL; } \ +inline const TYPE & Get(TypeWrapper,HSQUIRRELVM v,int idx) { return *GetInstance(v,idx); } + +// Ordinary case +#define DECLARE_INSTANCE_TYPE_NAME_CONST(TYPE,NAME) \ + DECLARE_INSTANCE_TYPE_NAME_(TYPE,NAME) \ + namespace SqPlus { \ + DECLARE_INSTANCE_TYPE_NAME_CONST_BASE(TYPE,NAME) \ + template<> inline void Push(HSQUIRRELVM v,const TYPE * value) { \ + if (!value) sq_pushnull(v); \ + else if (!CreateNativeClassInstance(v,GetTypeName(*value),(TYPE*)value,0)) \ + throw SquirrelError(_SC("Push(): could not create INSTANCE (check registration name)")); } \ + template<> inline void Push(HSQUIRRELVM v,const TYPE & value) { if (!CreateCopyInstance(v,GetTypeName(value),value)) throw SquirrelError(_SC("Push(): could not create INSTANCE copy (check registration name)")); } \ + } // nameSpace SqPlus + +// Case for custom Push implementation (covariant return type) +#define DECLARE_INSTANCE_TYPE_NAME_CONST_CUSTOM(TYPE,NAME) \ + DECLARE_INSTANCE_TYPE_NAME_CUSTOM_(TYPE,NAME) \ + namespace SqPlus { \ + DECLARE_INSTANCE_TYPE_NAME_CONST_BASE(TYPE,NAME) \ + template<> void Push(HSQUIRRELVM v,const TYPE * value); \ + template<> void Push(HSQUIRRELVM v,const TYPE & value); \ + } // nameSpace SqPlus + + +#else + +#define DECLARE_INSTANCE_TYPE_NAME_CONST(TYPE,NAME) \ + DECLARE_INSTANCE_TYPE_NAME_(TYPE,NAME) \ + namespace SqPlus { \ + template<> inline void Push(HSQUIRRELVM v,const TYPE * value) { if (!CreateNativeClassInstance(v,GetTypeName(*value),(TYPE*)value,0)) throw SquirrelError(_SC("Push(): could not create INSTANCE (check registration name)")); } \ + template<> inline void Push(HSQUIRRELVM v,const TYPE & value) { if (!CreateCopyInstance(v,GetTypeName(value),value)) throw SquirrelError(_SC("Push(): could not create INSTANCE copy (check registration name)")); } \ + template<> inline bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return GetInstance(v,idx) != NULL; } \ + template<> inline const TYPE & Get(TypeWrapper,HSQUIRRELVM v,int idx) { return *GetInstance(v,idx); } \ + } // nameSpace SqPlus + +#endif + +#define DECLARE_INSTANCE_TYPE(TYPE) DECLARE_INSTANCE_TYPE_NAME_CONST(TYPE,TYPE) +#define DECLARE_INSTANCE_TYPE_NAME(TYPE,NAME) DECLARE_INSTANCE_TYPE_NAME_CONST(TYPE,NAME) +#define DECLARE_INSTANCE_TYPE_CUSTOM(TYPE) DECLARE_INSTANCE_TYPE_NAME_CONST_CUSTOM(TYPE,TYPE) +#define DECLARE_INSTANCE_TYPE_NAME_CUSTOM(TYPE,NAME) DECLARE_INSTANCE_TYPE_NAME_CONST_CUSTOM(TYPE,NAME) +#endif + +#define SQPLUS_APPLY_CONST +#include "SqPlusCallTemplates.h" + + +#ifdef SQ_REG_CONST_STATIC_VAR +#undef SQ_REG_CONST_STATIC_VAR +template +SQClassDefBase & staticVar(const VarType * pvar,const SQChar * name,VarAccessType access=VAR_ACCESS_READ_ONLY) { + struct CV { + const VarType * var; + } cv; // Cast Variable helper. + cv.var = pvar; + RegisterInstanceVariable(newClass,ClassType::type(),*(VarType **)&cv,name,VarAccessType(access|VAR_ACCESS_STATIC)); + return *this; +} // staticVar +#endif + +// SqPlusConst.h diff --git a/squirrel_3_0_1_stable/sqplus/SqPlusFunctionCallImpl.h b/squirrel_3_0_1_stable/sqplus/SqPlusFunctionCallImpl.h new file mode 100644 index 000000000..c0752a7f3 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SqPlusFunctionCallImpl.h @@ -0,0 +1,114 @@ +#ifndef _SQPLUS_FUNCTION_CALL_IMPL_H_ +#define _SQPLUS_FUNCTION_CALL_IMPL_H_ + +#ifdef GCC_INLINE_WORKAROUND +# define SQINLINE +#else +# define SQINLINE inline +#endif + +SQINLINE void Push(HSQUIRRELVM v,char value) { sq_pushinteger(v,value); } +SQINLINE void Push(HSQUIRRELVM v,unsigned char value) { sq_pushinteger(v,value); } +SQINLINE void Push(HSQUIRRELVM v,short value) { sq_pushinteger(v,value); } +SQINLINE void Push(HSQUIRRELVM v,unsigned short value) { sq_pushinteger(v,value); } +SQINLINE void Push(HSQUIRRELVM v,int value) { sq_pushinteger(v,value); } +SQINLINE void Push(HSQUIRRELVM v,unsigned int value) { sq_pushinteger(v,value); } +SQINLINE void Push(HSQUIRRELVM v,long value) { sq_pushinteger(v,value); } +SQINLINE void Push(HSQUIRRELVM v,unsigned long value) { sq_pushinteger(v,value); } +SQINLINE void Push(HSQUIRRELVM v,double value) { sq_pushfloat(v,(FLOAT)value); } +SQINLINE void Push(HSQUIRRELVM v,float value) { sq_pushfloat(v,(FLOAT)value); } +SQINLINE void Push(HSQUIRRELVM v,const SQChar * value) { sq_pushstring(v,value,-1); } +SQINLINE void Push(HSQUIRRELVM v,SQChar * value) { sq_pushstring(v,value,-1); } +SQINLINE void Push(HSQUIRRELVM v,const SquirrelNull &) { sq_pushnull(v); } +SQINLINE void Push(HSQUIRRELVM v,SQFUNCTION value) { sq_pushuserpointer(v,(void*)value); } +SQINLINE void Push(HSQUIRRELVM v,SQAnythingPtr value) { sq_pushuserpointer(v,(void*)value); } // Cast to SQAnythingPtr instead of void * if USE_ARGUMENT_DEPENDANT_OVERLOADS can't be used by your compiler. +SQINLINE void Push(HSQUIRRELVM v,SquirrelObject & so) { sq_pushobject(v,so.GetObjectHandle()); } + +#ifdef USE_ARGUMENT_DEPENDANT_OVERLOADS +#ifdef _MSC_VER +#pragma warning (disable:4675) // Disable warning: "resolved overload was found by argument-dependent lookup" when class/struct pointers are used as function arguments. +#endif +// === BEGIN Argument Dependent Overloads === +SQINLINE void Push(HSQUIRRELVM v,bool value) { sq_pushbool(v,value); } // Pass bool as int if USE_ARGUMENT_DEPENDANT_OVERLOADS can't be used by your compiler. +SQINLINE void Push(HSQUIRRELVM v,const void * value) { sq_pushuserpointer(v,(void*)value); } // Pass SQAnythingPtr instead of void * " " +SQINLINE void Push(HSQUIRRELVM v,const SQUserPointer & value) { sq_pushuserpointer(v,(void*)value); } +// === END Argument Dependent Overloads === +#endif + +#define SQPLUS_CHECK_GET(res) if (!SQ_SUCCEEDED(res)) throw SquirrelError(_SC("sq_get*() failed (type error)")) + +//SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return sq_gettype(v,idx) == OT_BOOL; } +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return true; } // All types can be cast to bool +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return sq_gettype(v,idx) == OT_INTEGER; } +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v, int idx) { return sq_gettype(v,idx) == OT_INTEGER; } +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return sq_gettype(v,idx) == OT_INTEGER; } +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return sq_gettype(v,idx) == OT_INTEGER; } +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return sq_gettype(v,idx) == OT_INTEGER; } +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return sq_gettype(v,idx) == OT_INTEGER; } +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return sq_gettype(v,idx) == OT_INTEGER; } +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return sq_gettype(v,idx) == OT_INTEGER; } +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { int type = sq_gettype(v,idx); return type == OT_FLOAT; } +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { int type = sq_gettype(v,idx); return type == OT_FLOAT; } +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return sq_gettype(v,idx) == OT_STRING; } +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return sq_gettype(v,idx) == OT_STRING; } +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return true; } // See Get() for HSQUIRRELVM below (v is always present). +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return sq_gettype(v,idx) == OT_USERPOINTER; } +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return true; } // See sq_getstackobj(): always returns true. + +SQINLINE void Get(TypeWrapper,HSQUIRRELVM v,int) {} +//SQINLINE bool Get(TypeWrapper,HSQUIRRELVM v,int idx) { SQBool b; SQPLUS_CHECK_GET(sq_getbool(v,idx,&b)); return b != 0; } +SQINLINE char Get(TypeWrapper,HSQUIRRELVM v,int idx) { INT i; SQPLUS_CHECK_GET(sq_getinteger(v,idx,&i)); return static_cast(i); } +SQINLINE unsigned char Get(TypeWrapper,HSQUIRRELVM v,int idx) { INT i; SQPLUS_CHECK_GET(sq_getinteger(v,idx,&i)); return static_cast(i); } +SQINLINE short Get(TypeWrapper,HSQUIRRELVM v,int idx) { INT i; SQPLUS_CHECK_GET(sq_getinteger(v,idx,&i)); return static_cast(i); } +SQINLINE unsigned short Get(TypeWrapper,HSQUIRRELVM v,int idx) { INT i; SQPLUS_CHECK_GET(sq_getinteger(v,idx,&i)); return static_cast(i); } +SQINLINE int Get(TypeWrapper,HSQUIRRELVM v,int idx) { INT i; SQPLUS_CHECK_GET(sq_getinteger(v,idx,&i)); return i; } +SQINLINE unsigned int Get(TypeWrapper,HSQUIRRELVM v,int idx) { INT i; SQPLUS_CHECK_GET(sq_getinteger(v,idx,&i)); return static_cast(i); } +SQINLINE long Get(TypeWrapper,HSQUIRRELVM v,int idx) { INT i; SQPLUS_CHECK_GET(sq_getinteger(v,idx,&i)); return static_cast(i); } +SQINLINE unsigned long Get(TypeWrapper,HSQUIRRELVM v,int idx) { INT i; SQPLUS_CHECK_GET(sq_getinteger(v,idx,&i)); return static_cast(i); } +SQINLINE float Get(TypeWrapper,HSQUIRRELVM v,int idx) { FLOAT f; SQPLUS_CHECK_GET(sq_getfloat(v,idx,&f)); return f; } +SQINLINE double Get(TypeWrapper,HSQUIRRELVM v,int idx) { FLOAT f; SQPLUS_CHECK_GET(sq_getfloat(v,idx,&f)); return static_cast(f); } +SQINLINE const SQChar * Get(TypeWrapper,HSQUIRRELVM v,int idx) { const SQChar * s; SQPLUS_CHECK_GET(sq_getstring(v,idx,&s)); return s; } +SQINLINE SquirrelNull Get(TypeWrapper,HSQUIRRELVM v,int idx) { (void)v, (void)idx; return SquirrelNull(); } +SQINLINE void * Get(TypeWrapper,HSQUIRRELVM v,int idx) { SQUserPointer p; SQPLUS_CHECK_GET(sq_getuserpointer(v,idx,&p)); return p; } +SQINLINE HSQUIRRELVM Get(TypeWrapper,HSQUIRRELVM v,int /*idx*/) { sq_poptop(v); return v; } // sq_poptop(v): remove UserData from stack so GetParamCount() matches normal behavior. +SQINLINE SquirrelObject Get(TypeWrapper,HSQUIRRELVM v,int idx) { HSQOBJECT o; SQPLUS_CHECK_GET(sq_getstackobj(v,idx,&o)); return SquirrelObject(o); } + +SQINLINE bool Get(TypeWrapper,HSQUIRRELVM v,int idx){ + switch( sq_gettype(v,idx) ){ + case OT_NULL:{ return false; } + case OT_BOOL:{ SQBool b; SQPLUS_CHECK_GET(sq_getbool(v,idx,&b)); return b != 0; } + case OT_INTEGER:{ INT i; SQPLUS_CHECK_GET(sq_getinteger(v,idx,&i)); return i != 0; } + case OT_FLOAT:{ FLOAT f; SQPLUS_CHECK_GET(sq_getfloat(v,idx,&f)); return f != (FLOAT)0.0; } + default: return true; } } + +#ifdef SQPLUS_AUTOCONVERT_OTHER_CHAR +SQINLINE void Push(HSQUIRRELVM v, const SQOtherChar *value){ SQDefCharBuf cb(value); sq_pushstring(v,(const SQChar*)cb,-1); } +SQINLINE void Push(HSQUIRRELVM v, SQOtherChar *value){ SQDefCharBuf cb(value); sq_pushstring(v,(const SQChar*)cb,-1); } +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return sq_gettype(v,idx) == OT_STRING; } +SQINLINE bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return sq_gettype(v,idx) == OT_STRING; } +/*SQINLINE SQOtherChar* Get(TypeWrapper,HSQUIRRELVM v,int idx) { + const SQChar *s; SQPLUS_CHECK_GET(sq_getstring(v,idx,&s)); + static SQOthCharBuf ocb[SQPLUS_AUTOCONVERT_MAX_INSTANCES]; static int st_buf_cnt; + return ocb[st_buf_cnt++%SQPLUS_AUTOCONVERT_MAX_INSTANCES].Set(s); }*/ +SQINLINE SQOthCharBuf Get(TypeWrapper,HSQUIRRELVM v,int idx) { const SQChar * s; SQPLUS_CHECK_GET(sq_getstring(v,idx,&s)); return SQOthCharBuf(s); } +#endif // SQPLUS_AUTOCONVERT_OTHER_CHAR + +#if defined(SQPLUS_SUPPORT_STD_STRING) && !defined(SQUNICODE) +SQINLINE void Push(HSQUIRRELVM v,const std::string& value) { sq_pushstring(v,value.c_str(),-1); } +SQINLINE bool Match(TypeWrapper, HSQUIRRELVM v, int idx) { return sq_gettype(v,idx) == OT_STRING; } +SQINLINE std::string Get(TypeWrapper,HSQUIRRELVM v,int idx) { const SQChar * s; SQPLUS_CHECK_GET(sq_getstring(v,idx,&s)); return std::string(s); } +#endif // defined(SQPLUS_SUPPORT_STD_STRING) && !defined(SQUNICODE) + +// Added jflanglois suggestion, 8/20/06. jcs +#ifdef SQPLUS_SUPPORT_SQ_STD_STRING +typedef std::basic_string sq_std_string; +SQINLINE void Push(HSQUIRRELVM v,const sq_std_string & value) { sq_pushstring(v,value.c_str(),-1); } +SQINLINE bool Match(TypeWrapper, HSQUIRRELVM v, int idx) { return sq_gettype(v,idx) == OT_STRING; } +SQINLINE sq_std_string Get(TypeWrapper,HSQUIRRELVM v,int idx) { const SQChar * s; SQPLUS_CHECK_GET(sq_getstring(v,idx,&s)); return sq_std_string(s); } +#endif + +// Specialization to support void return type. +SQINLINE void GetRet(TypeWrapper,HSQUIRRELVM v,int idx) { sq_pop(v,2); } + +#endif // _SQPLUS_FUNCTION_CALL_IMPL_H_ + diff --git a/squirrel_3_0_1_stable/sqplus/SqPlusOCharBuf.cpp b/squirrel_3_0_1_stable/sqplus/SqPlusOCharBuf.cpp new file mode 100644 index 000000000..4a0bd2a9b --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SqPlusOCharBuf.cpp @@ -0,0 +1,61 @@ + +#include "sqplus.h" +#include "SqPlusOCharBuf.h" + +#include + +// Conversion functions, between char* string and wchar_t* strings. + +int ol_strlen(const wchar_t* pwc){ return (int)wcslen(pwc); } +int ol_buflen(const wchar_t* pwc){ return (int)wcslen(pwc); } +int ol_charlen(const wchar_t* pwc){ return 1; } +//int ol_charlen(const wchar_t pwc){ return 1; } +int ol_char(const wchar_t* pwc){ return (int)*pwc; } +bool ol_writechar(wchar_t*& pwc, int ch){ *pwc=(wchar_t)ch; pwc++; return true; } + +int ol_buflen(const char* pc){ return (int)strlen(pc); } + +#if SQPLUS_USE_LATIN1==1 + // Convert to 8-bit LATIN1 char set. The only thing to do is convert chars out of range to '?' + int ol_strlen(const char* pc){ return (int)strlen(pc); } + int ol_charlen(const char* pc){ return 1; } + //int ol_charlen(int pc){ return 1; } + int ol_char(const char* pc){ return (int)*(unsigned char*)pc; } + bool ol_writechar(char*& pc, int ch){ *pc=(char)(ch>255?'?':ch); pc++; return true; } +#else + #include "SqPlusUtf8.h" + // Convert to 8-Bit UTF8 encoding. Some more work here. + int ol_strlen(const char* pc){ return sqplus_utf8_strlen(pc); } + int ol_charlen(const char* pc){ return sqplus_utf8_len_first(pc); } + //int ol_charlen(int ch){ char buf[8]; return sqplus_wchar_to_utf8(buf,ch,8); } + int ol_char(const char* pc){ int chr=-1; sqplus_utf8_to_wchar(&chr,pc); return chr; } + bool ol_writechar(char*& pc, int ch) { + int l=sqplus_wchar_to_utf8(pc,ch,8); + if(l>0){ + pc += l; + return true; + } + else return false; + } +#endif + + +#ifdef SQUNICODE + // SQChar is wchar_t, convert to/from to either Latin1 or UTF8 + SQDefCharBuf CH2SQ( const char* ps ){ + return SQDefCharBuf(ps); + } + SQOthCharBuf SQ2CH( const wchar_t* pws ){ + return SQOthCharBuf(pws); + } +#else + // SQChar is char, convert to/from wchar_t + SQDefCharBuf WC2SQ( const wchar_t* pws ){ + return SQDefCharBuf(pws); + } + SQOthCharBuf SQ2WC( const char* ps ){ + return SQOthCharBuf(ps); + } +#endif + + diff --git a/squirrel_3_0_1_stable/sqplus/SqPlusOCharBuf.h b/squirrel_3_0_1_stable/sqplus/SqPlusOCharBuf.h new file mode 100644 index 000000000..c27e7c803 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SqPlusOCharBuf.h @@ -0,0 +1,193 @@ + +#ifndef SQPLUS_OCHARBUF_H +#define SQPLUS_OCHARBUF_H + +// Conversion routines between different character encodings, to be used in +// Push/Get/Match handlers of SqPlus. It enables using both of char* and +// wchar_t* as function arguments. +// +// When converting from wchar_t to char, the choice is between using a Latin1 +// or a UTF8 representation in 8-bit mode. This is probably most useful if +// Squirrel is compiled in ANSI mode and the app uses some wchar_t strings +// (UNICODE mode on Win32). +// + +// A char is either +// - A Latin1 character (first code page, coincides with Unicode points 0..255) +// - Part of an UTF8 character +// +// Note: SQUTF8 requires Squirrel sources that have been patched for UTF8 strings +// internally (when converting function arguments). + +#ifndef SQUTF8 + // Default to Latin1 conversion + //#undef SQPLUS_USE_LATIN1 + #ifndef SQPLUS_USE_LATIN1 + #define SQPLUS_USE_LATIN1 1 + #endif +#else + // Using Squirrel with internal UTF8 string encoding + //#undef SQPLUS_USE_LATIN1 + #ifndef SQPLUS_USE_LATIN1 + #define SQPLUS_USE_LATIN1 0 + #endif +#endif + + +// The various ol_... functions sets up for a conversion scheme +// that can be used in both wchar_t => char and char => wchar_t. +int ol_strlen(const wchar_t* pwc); +int ol_buflen(const wchar_t* pwc); +int ol_charlen(const wchar_t* pwc); +int ol_char(const wchar_t* pwc); +bool ol_writechar(wchar_t*& pwc, int ch); + +int ol_strlen(const char* pc); +int ol_buflen(const char* pc); +int ol_charlen(const char* pc); +int ol_char(const char* pc); +bool ol_writechar(char*& pc, int ch); + +#ifdef SQUNICODE + // SQChar is wchar_t, convert to/from either Latin1 or UTF8 + typedef char SQOtherChar; +#else + // SQChar is char, convert to/from wchar_t + typedef wchar_t SQOtherChar; +#endif + + +// Buffer to hold a string and release it in destructor. +// SQT is input character type +// SQOT is the opposite type of SQChar +// If 'try_borrow' is set, it will not allocate a new buffer when no +// conversion is done, it will just keep the input pointer (beware). +template +struct SQCharBufImpl { + + // Allocate a buffer from string of same type + SQCharBufImpl(const SQT *poc=NULL, bool try_borrow=true ) : m_poc(0), m_own(false) { + Init( poc, try_borrow ); + } + + // This does conversion from other char type + SQCharBufImpl(const SQOT *ps, bool try_borrow=false ) : m_poc(0), m_own(false) { + Init( ps ); // Cannot borrow pointer when doing conversion + } + + void Init( const SQT *poc, bool try_borrow ){ + m_own = !try_borrow; + if( try_borrow ){ + m_poc = (SQT*)poc; + } + else { + int sl = poc ? ol_buflen(poc) : 0; + if( poc ){ + m_poc = poc ? new SQT[sl+1] : NULL; + if( m_poc ) memcpy( m_poc, poc, (sl+1)*sizeof(SQT) ); + } + else + m_poc = NULL; + } + } + + void Init( const SQOT *ps ){ + m_own = true; + if( ps ){ + int sl = ps ? ol_strlen(ps) : 0; // Length of string in characters (not bytes) + int scl = 0; // Length of converted string in char/wchar_t count + // How much storage needed? + if( !use_latin1 && sizeof(SQT) UTF8 + const SQOT *ps1 = ps; // It is wchar_t* here + SQT tmp_buf[8]; + SQT *ptmp; + while( *ps1 ){ + ptmp = tmp_buf; + if( ol_writechar(ptmp,*ps1++) ) + scl += ol_charlen(tmp_buf); + else + scl++; + } + } + else scl = sl; // Converting to wchar_t or Latin1, keep length + + m_poc = new SQT[scl+1]; + if( !m_poc ) return; + + // Convert + SQT *poc = m_poc; + while( *ps ){ + ol_writechar( poc, ol_char(ps) ); + ps += ol_charlen(ps); + } + *poc = 0; // Terminating zero + } + else + m_poc = NULL; + } + + ~SQCharBufImpl(){ Release(); } + + void Release( ){ + if(m_poc && m_own ) + delete [] m_poc; + m_poc = NULL; + } + + SQT* Set( const SQOT *ps ){ + Release( ); + Init( ps ); + return m_poc; + } + + operator SQT*() const { return m_poc; } + + SQCharBufImpl& operator = (const SQT *ps){ + Release(); + Init( ps, false ); + return *this; + } + + SQCharBufImpl& operator = (const SQOT *ps){ + Release(); + Init( ps ); + return *this; + } + + // Move string from other here - Note: Empties the input argument (other) + SQCharBufImpl& operator = (const SQCharBufImpl& other){ + Release(); + m_poc = other.m_poc; + m_own = other.m_own; + SQT **psqt = (SQT**)&other.m_poc; + *psqt = NULL; + return *this; + } + +protected: + SQT *m_poc; + bool m_own; +}; + +typedef SQCharBufImpl SQOthCharBuf; +typedef SQCharBufImpl SQDefCharBuf; +typedef SQCharBufImpl SQWCharBuf; +typedef SQCharBufImpl SQACharBuf; + +#ifdef SQUNICODE + // SQChar is wchar_t, convert to/from to either Latin1 or UTF8 + #define WC2SQ(s) s + #define SQ2WC(s) s + SQDefCharBuf CH2SQ( const char* ps ); + SQOthCharBuf SQ2CH( const wchar_t* pws ); +#else + // SQChar is char, convert to/from wchar_t + SQDefCharBuf WC2SQ( const wchar_t* pws ); + SQOthCharBuf SQ2WC( const char* pws ); + #define CH2SQ(s) s + #define SQ2CH(s) s +#endif + +#endif // SQPLUS_CHARBUF_H + diff --git a/squirrel_3_0_1_stable/sqplus/SqPlusOverload.h b/squirrel_3_0_1_stable/sqplus/SqPlusOverload.h new file mode 100644 index 000000000..e205de366 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SqPlusOverload.h @@ -0,0 +1,819 @@ +// SqPlusOverload.h +// SqPlus function overloading support created by Katsuaki Kawachi. +// +// Const member function fixed Tegan +// from http://squirrel-lang.org/forums/thread/2160.aspx + +#ifdef SQPLUS_OVERLOAD_RELEASE_HOOK +#undef SQPLUS_OVERLOAD_RELEASE_HOOK + + // These end up int ClassType now + static inline int destruct(SQUserPointer up, SQInteger size) { + if (up) { + static_cast(up)->~T(); + sq_free(up, size); + } + return 0; + } + + static inline SQRELEASEHOOK &release(void) { + static SQRELEASEHOOK hook = ClassType::destruct; + return hook; + } + + void releaseHook(SQRELEASEHOOK releaseHook) { + release() = releaseHook; + //return *this; + } + + static inline SQRELEASEHOOK &getReleaseHook(void) { + return release(); + } + +#endif // SQPLUS_OVERLOAD_RELEASE_HOOK + + +#ifdef SQPLUS_OVERLOAD_DECLARATION +#undef SQPLUS_OVERLOAD_DECLARATION + +template struct Arg; + +#endif // SQPLUS_OVERLOAD_DECLARATION + + +#ifdef SQPLUS_OVERLOAD_IMPLEMENTATION +#undef SQPLUS_OVERLOAD_IMPLEMENTATION +private: + class SQFuncHolder { + private: + template + class FlexArray { + protected: + SquirrelObject array; + public: + FlexArray(int size = 0) { + this->resize(size); + } + int size(void) const { + return array.Len(); + } + void resize(int newSize) { + if (this->size() == 0) { + array = SquirrelVM::CreateArray(newSize); + } else { + array.ArrayResize(newSize); + } + } + void push_back(const T &t) { + this->set(this->size(), t); + } + void set(int index, const T &t) { + get(index) = t; + } + T &get(int index) { + if (index >= array.Len()) { + resize(index + 1); + } + SQUserPointer up = array.GetUserPointer(index); + if (!up) { + up = sq_newuserdata(SquirrelVM::GetVMPtr(), sizeof(T)); + new(static_cast(up)) T; + array.SetUserPointer(index, up); + } + return *static_cast(up); + } + }; + /* + storage of wrapped C++ functions + */ + typedef SQInteger(*WrappedFunction)(HSQUIRRELVM, bool, int); + typedef FlexArray SQWrappedFuncArray; + typedef FlexArray SQWrappedFuncArray2 ; + typedef FlexArray SQWrappedFuncArray3 ; + + struct MemberHolder { + static SQWrappedFuncArray &funcs(int functionIndex, + int paramCount) { + static SQWrappedFuncArray3 funcs; + return funcs.get(paramCount).get(functionIndex); + } + }; + struct StaticHolder { + static SQWrappedFuncArray &funcs(int functionIndex, + int paramCount) { + static SQWrappedFuncArray3 funcs; + return funcs.get(paramCount).get(functionIndex); + } + }; + struct ConstructorHolder { + static SQWrappedFuncArray &funcs(int paramCount) { + static SQWrappedFuncArray2 funcs; + return funcs.get(paramCount); + } + }; + + /* + wrapper for C++ functions + */ + template struct MemberDispatcher { + static inline FlexArray &mfunc(void) { + static FlexArray mfunc; + return mfunc; + } + static inline SQInteger + dispatch(HSQUIRRELVM v, bool execute, int functionIndex) { + return execute ? + Call(*GetInstance(v, 1), + mfunc().get(functionIndex), v, 2) : + Arg::argTypeDistance(v); + } + }; + template struct StaticDispatcher { + static inline FlexArray &sfunc(void) { + static FlexArray sfunc; + return sfunc; + } + static inline SQInteger + dispatch(HSQUIRRELVM v, bool execute, int functionIndex) { + return execute ? + Call(sfunc().get(functionIndex), v, 2) : + Arg::argTypeDistance(v); + } + }; + template struct Constructor { + static inline Cfunc &cfunc(void) { + static Cfunc cfunc = 0; + return cfunc; + } + static inline SQInteger + construct(HSQUIRRELVM v, bool execute, int) { + return execute ? + Call(cfunc(), v, 2) : + Arg::argTypeDistance(v); + } + }; + + // search and call an overloaded function on runtime + static inline SQInteger + call(SQWrappedFuncArray &funcs, HSQUIRRELVM v, int functionIndex = 0) { + bool ambiguous = false; + int imin = -1; + int dmin = INT_MAX; + for (int i = 0, size = funcs.size(); i < size; ++i) { + // FIXME: to be refactored + const int d = (**funcs.get(i))(v, false, functionIndex); + if (d == 0) { // complete match + imin = i; + ambiguous = false; + goto SQPLUS_OVERLOAD_CALL_IMMEDIATE_EXECUTION; + } else if (0 < d && d < dmin) { + dmin = d; + imin = i; + ambiguous = false; + } else if (d == dmin) { + ambiguous = true; + } + } + + if (ambiguous) { + return sq_throwerror( + v, _SC("Call of overloaded function is ambiguous") + ); + } else if (imin == -1) { + return sq_throwerror( + v, _SC("No match for given arguments") + ); + } + + SQPLUS_OVERLOAD_CALL_IMMEDIATE_EXECUTION: + // FIXME: to be refactored + return (**funcs.get(imin))(v, true, functionIndex); + } + + public: + template static inline void + addMemberFunc(int functionIndex, Mfunc mfunc) { + MemberHolder::funcs(functionIndex, Arg::num()).push_back( + &MemberDispatcher::dispatch + ); + MemberDispatcher::mfunc().set(functionIndex, mfunc); + } + template static inline void + addStaticFunc(int functionIndex, Sfunc sfunc) { + StaticHolder::funcs(functionIndex, Arg::num()).push_back( + &StaticDispatcher::dispatch + ); + StaticDispatcher::sfunc().set(functionIndex, sfunc); + } + template static inline void + addConstructor(Cfunc cfunc) { + ConstructorHolder::funcs(Arg::num()).push_back( + &Constructor::construct + ); + Constructor::cfunc() = cfunc; + } + + static inline SQInteger + memberCall(int paramCount, HSQUIRRELVM v, int functionIndex) { + return call(MemberHolder::funcs(functionIndex, paramCount), + v, functionIndex); + } + static inline SQInteger + staticCall(int paramCount, HSQUIRRELVM v, int functionIndex) { + return call(StaticHolder::funcs(functionIndex, paramCount), + v, functionIndex); + } + static inline SQInteger + constructorCall(int paramCount, HSQUIRRELVM v, int) { + return call(ConstructorHolder::funcs(paramCount), v); + } + }; // class SQFuncHolder + + + struct FunctionNameEnumerator { + SquirrelObject names; + FunctionNameEnumerator(void) : names(SquirrelVM::CreateTable()) {} + int index(const SQChar *n) { + int i; + SquirrelObject v = names.GetValue(n); + if (v.IsNull()) { + i = names.Len(); + names.SetValue(n, i); + } else { + i = v.ToInteger(); + } + return i; + } + }; + + FunctionNameEnumerator overloadedMemberNames; + FunctionNameEnumerator overloadedStaticMemberNames; + + static SquirrelObject & + functionIndexHolders(HSQUIRRELVM v) { + static SquirrelObject indexHolders; + if (indexHolders.IsNull()) { + sq_newtable(v); + indexHolders.AttachToStackObject(-1); + sq_pop(v, 1); + } + return indexHolders; + } + + template + static SquirrelObject & + indexHolder(HSQUIRRELVM v) { + static SquirrelObject holder; + if (holder.IsNull()) { + sq_pushobject(v, functionIndexHolders(v).GetObjectHandle()); + sq_pushinteger(v, N); + if (SQ_OK == sq_rawget(v, -2)) { + holder.AttachToStackObject(-1); + sq_pop(v, 3); + } else { + sq_pushinteger(v, N); + sq_newtable(v); + holder.AttachToStackObject(-1); + sq_rawset(v, -3); + sq_pop(v, 1); + } + } + return holder; + } + + template + class SQOverloader { + private: + static inline SQInteger switcher(HSQUIRRELVM v, + int(*caller)(int, HSQUIRRELVM, int), + int fidx) { + return (*caller)(StackHandler(v).GetParamCount() - 1, + v, + fidx); + } + + static inline SQInteger memberSwitcher(HSQUIRRELVM v) { + SQInteger fidx; + sq_pushobject(v, indexHolder<0>(v).GetObjectHandle()); + sq_push(v, 0); // native closure + sq_rawget(v, -2); + sq_getinteger(v, -1, &fidx); + sq_pop(v, 2); + return switcher(v, SQFuncHolder::memberCall, fidx); + } + static inline SQInteger staticSwitcher(HSQUIRRELVM v) { + SQInteger fidx; + sq_pushobject(v, indexHolder<1>(v).GetObjectHandle()); + sq_push(v, 0); // native closure + sq_rawget(v, -2); + sq_getinteger(v, -1, &fidx); + sq_pop(v, 2); + return switcher(v, SQFuncHolder::staticCall, fidx); + } + static inline SQInteger constructorSwitcher(HSQUIRRELVM v) { + return switcher(v, SQFuncHolder::constructorCall, 0); + } + + public: + static inline void addMemberFunc(SQClassDefBase *def, + Func mfunc, + const SQChar *name) { + const int fidx = def->overloadedMemberNames.index(name); + SQFuncHolder::addMemberFunc(fidx, mfunc); + def->staticFuncVarArgs(memberSwitcher, name); + + HSQUIRRELVM v = def->v; + // get closure + sq_pushobject(v, def->newClass.GetObjectHandle()); + sq_pushstring(v, name, -1); + sq_rawget(v, -2); + // holder[closure] = fidx + sq_pushobject(v, indexHolder<0>(v).GetObjectHandle()); + sq_push(v, -2); + sq_pushinteger(v, fidx); + sq_rawset(v, -3); + // + sq_pop(v, 3); + } + + static inline void addOperatorFunc(SQClassDefBase *def, + Func ofunc, + const SQChar *name) { + if (Arg::num() != 1) { + //assert(false && + // "Cannot add this function as operator (argc != 1)"); + abort(); + } + SQChar proxy[256]; + scsprintf(proxy, _SC("overloaded%s"), name); + + addMemberFunc(def, ofunc, proxy); + + SQChar script[512]; + scsprintf(script, _SC("%s.%s<-function(o){return %s.%s(o);}"), + def->name, name, def->name, proxy); + SquirrelVM::RunScript(SquirrelVM::CompileBuffer(script)); + } + + static inline void addStaticFunc(SQClassDefBase *def, + Func sfunc, + const SQChar *name) { + const int fidx = def->overloadedStaticMemberNames.index(name); + SQFuncHolder::addStaticFunc(fidx, sfunc); + def->staticFuncVarArgs(staticSwitcher, name); + + HSQUIRRELVM v = def->v; + // get closure + sq_pushobject(v, def->newClass.GetObjectHandle()); + sq_pushstring(v, name, -1); + sq_rawget(v, -2); + + // holder[closure] = fidx + sq_pushobject(v, indexHolder<1>(v).GetObjectHandle()); + sq_push(v, -2); + sq_pushinteger(v, fidx); + sq_rawset(v, -3); + // + sq_pop(v, 3); + } + template + static inline void addConstructor(SQClassDefBase *def, + Cfunc cfunc) { + SQFuncHolder::addConstructor(cfunc); + def->staticFuncVarArgs(constructorSwitcher, _SC("constructor")); + } + static inline void addGlobalFunc(SQClassDefBase *def, + Func gfunc, + const SQChar *name) { + const int fidx = def->overloadedStaticMemberNames.index(name); + SQFuncHolder::addStaticFunc(fidx, gfunc); + SquirrelVM::CreateFunctionGlobal(staticSwitcher, name, _SC("*")); + + HSQUIRRELVM v = def->v; + // get closure + sq_pushroottable(v); + sq_pushstring(v, name, -1); + sq_rawget(v, -2); + + // holder[closure] = fidx + sq_pushobject(v, indexHolder<1>(v).GetObjectHandle()); + sq_push(v, -2); + sq_pushinteger(v, fidx); + sq_rawset(v, -3); + // + sq_pop(v, 3); + } + }; + +public: + template + SQClassDefBase &overloadFunc(Mfunc mfunc, const SQChar *n) { + SQOverloader::addMemberFunc(this, mfunc, n); + return *this; + } + template + SQClassDefBase &overloadOperator(Ofunc ofunc, const SQChar *n){ + SQOverloader::addOperatorFunc(this, ofunc, n); + return *this; + } + template + SQClassDefBase &overloadStaticFunc(Sfunc sfunc, + const SQChar *n) { + SQOverloader::addStaticFunc(this, sfunc, n); + return *this; + } + template + SQClassDefBase &overloadConstructor(void) { + SQOverloader::addConstructor(this, &Arg::create); + return *this; + } + template + SQClassDefBase &overloadConstructor(Cfunc cfunc) { + SQOverloader::addConstructor(this, cfunc); + return *this; + } + template + SQClassDefBase &overloadGlobalFunc(Gfunc gfunc, + const SQChar *n) { + SQOverloader::addGlobalFunc(this, gfunc, n); + return *this; + } + + +#endif // SQPLUS_OVERLOAD_IMPLEMENTATION + + + +#ifdef SQPLUS_OVERLOAD_FUNCTIONS +#undef SQPLUS_OVERLOAD_FUNCTIONS + +struct GlobalFuncOverloader {}; +static inline SQClassDefBase &globalFuncOverloader(void) +{ + static SQClassDefBase fo(_SC("GlobalFuncOverloader")); + return fo; +} + +template void +OverloadGlobal(Gfunc gfunc, const SQChar *n) +{ + globalFuncOverloader().overloadGlobalFunc(gfunc, n); +} + +template struct CheckInstance { + template struct unref {typedef T type;}; + template struct unref {typedef T type;}; + template struct unref {typedef T type;}; + template struct unref {typedef T type;}; + template struct unref {typedef T type;}; + + /* + d = -1 : not in hierarchy + d = 0 : same + d > 0 : similar (o is d-th subclass of TYPE) + */ + static inline int distance(HSQUIRRELVM v, int index) { + HSQOBJECT o; + sq_resetobject(&o); + sq_getstackobj(v, index, &o); + + const int top = sq_gettop(v); + sq_pushroottable(v); + + // Check plain object type + int d = -1; + if (Match(TypeWrapper(), v, index)) { + d = 0; + + // Check instance type hierarchy + if (sq_type(o) == OT_INSTANCE) { + SQUserPointer dsttype = + ClassType::type>::type(); + + SQUserPointer argtype; + for (sq_getclass(v, index); + sq_gettypetag(v, -1, &argtype) == SQ_OK; + sq_getbase(v, -1)) { + if (argtype == dsttype) { + goto SQPLUS_OVERLOAD_DISTANCE_IMMEDIATE_RETURN; + } + ++d; + } + d = -1; // no matching type found + } + } + SQPLUS_OVERLOAD_DISTANCE_IMMEDIATE_RETURN: + sq_settop(v, top); + return d; + } +}; + + +template +struct Arg { + static inline int num(void) {return 0;} + static inline int argTypeDistance(HSQUIRRELVM) { + return 0; + } +}; + +template +struct Arg { + static inline int num(void) {return 1;} + static inline int argTypeDistance(HSQUIRRELVM v) { + return Arg::argTypeDistance(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 2;} + static inline int argTypeDistance(HSQUIRRELVM v) { + return Arg::argTypeDistance(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 3;} + static inline int argTypeDistance(HSQUIRRELVM v) { + return Arg::argTypeDistance(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 4;} + static inline int argTypeDistance(HSQUIRRELVM v) { + return Arg::argTypeDistance(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 5;} + static inline int argTypeDistance(HSQUIRRELVM v) { + return Arg::argTypeDistance(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 6;} + static inline int argTypeDistance(HSQUIRRELVM v) { + return Arg::argTypeDistance(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 7;} + static inline int argTypeDistance(HSQUIRRELVM v) { + return Arg::argTypeDistance(v); + } +}; + +#ifdef SQPLUS_CONST_OPT +template +struct Arg { + static inline int num(void) {return 0;} + static inline int argTypeDistance(HSQUIRRELVM) { + return 0; + } +}; + +template +struct Arg { + static inline int num(void) {return 1;} + static inline int argTypeDistance(HSQUIRRELVM v) { + return Arg::argTypeDistance(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 2;} + static inline int argTypeDistance(HSQUIRRELVM v) { + return Arg::argTypeDistance(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 3;} + static inline int argTypeDistance(HSQUIRRELVM v) { + return Arg::argTypeDistance(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 4;} + static inline int argTypeDistance(HSQUIRRELVM v) { + return Arg::argTypeDistance(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 5;} + static inline int argTypeDistance(HSQUIRRELVM v) { + return Arg::argTypeDistance(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 6;} + static inline int argTypeDistance(HSQUIRRELVM v) { + return Arg::argTypeDistance(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 7;} + static inline int argTypeDistance(HSQUIRRELVM v) { + return Arg::argTypeDistance(v); + } +}; +#endif + +static inline int classAllocationError(HSQUIRRELVM v) { + return sq_throwerror(v, _SC("Failed to allocate memory")); +} + +template +struct Arg { + static inline int num(void) {return 0;} + static inline int argTypeDistance(HSQUIRRELVM) {return 0;} + static inline int create(void) { + HSQUIRRELVM v = SquirrelVM::GetVMPtr(); + R *r = static_cast(sq_malloc(sizeof(R))); + return r ? + PostConstruct(v, new(r) R, + ClassType::getReleaseHook()) : + classAllocationError(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 1;} + static inline int argTypeDistance(HSQUIRRELVM v) { + int s, r; + r = 0; + s = CheckInstance::distance(v, 2); if (s < 0) {return -1;} r += s; + return r; + } + static inline int create(A1 a1) { + HSQUIRRELVM v = SquirrelVM::GetVMPtr(); + R *r = static_cast(sq_malloc(sizeof(R))); + return r ? + PostConstruct(v, new(r) R(a1), + ClassType::getReleaseHook()) : + classAllocationError(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 2;} + static inline int argTypeDistance(HSQUIRRELVM v) { + int s, r; + r = 0; + s = CheckInstance::distance(v, 2); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 3); if (s < 0) {return -1;} r += s; + return r; + } + static inline int create(A1 a1, A2 a2) { + HSQUIRRELVM v = SquirrelVM::GetVMPtr(); + R *r = static_cast(sq_malloc(sizeof(R))); + return r ? + PostConstruct(v, new(r) R(a1, a2), + ClassType::getReleaseHook()) : + classAllocationError(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 3;} + static inline int argTypeDistance(HSQUIRRELVM v) { + int s, r; + r = 0; + s = CheckInstance::distance(v, 2); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 3); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 4); if (s < 0) {return -1;} r += s; + return r; + } + static inline int create(A1 a1, A2 a2, A3 a3) { + HSQUIRRELVM v = SquirrelVM::GetVMPtr(); + R *r = static_cast(sq_malloc(sizeof(R))); + return r ? + PostConstruct(v, new(r) R(a1, a2, a3), + ClassType::getReleaseHook()) : + classAllocationError(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 4;} + static inline int argTypeDistance(HSQUIRRELVM v) { + int s, r; + r = 0; + s = CheckInstance::distance(v, 2); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 3); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 4); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 5); if (s < 0) {return -1;} r += s; + return r; + } + static inline int create(A1 a1, A2 a2, A3 a3, A4 a4) { + HSQUIRRELVM v = SquirrelVM::GetVMPtr(); + R *r = static_cast(sq_malloc(sizeof(R))); + return r ? + PostConstruct(v, new(r) R(a1, a2, a3, a4), + ClassType::getReleaseHook()) : + classAllocationError(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 5;} + static inline int argTypeDistance(HSQUIRRELVM v) { + int s, r; + r = 0; + s = CheckInstance::distance(v, 2); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 3); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 4); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 5); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 6); if (s < 0) {return -1;} r += s; + return r; + } + static inline int create(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { + HSQUIRRELVM v = SquirrelVM::GetVMPtr(); + R *r = static_cast(sq_malloc(sizeof(R))); + return r ? + PostConstruct(v, new(r) R(a1, a2, a3, a4, a5), + ClassType::getReleaseHook()) : + classAllocationError(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 6;} + static inline int argTypeDistance(HSQUIRRELVM v) { + int s, r; + r = 0; + s = CheckInstance::distance(v, 2); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 3); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 4); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 5); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 6); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 7); if (s < 0) {return -1;} r += s; + return r; + } + static inline int create(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { + HSQUIRRELVM v = SquirrelVM::GetVMPtr(); + R *r = static_cast(sq_malloc(sizeof(R))); + return r ? + PostConstruct(v, new(r) R(a1, a2, a3, a4, a5, a6), + ClassType::getReleaseHook()) : + classAllocationError(v); + } +}; + +template +struct Arg { + static inline int num(void) {return 7;} + static inline int argTypeDistance(HSQUIRRELVM v) { + int s, r; + r = 0; + s = CheckInstance::distance(v, 2); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 3); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 4); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 5); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 6); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 7); if (s < 0) {return -1;} r += s; + s = CheckInstance::distance(v, 8); if (s < 0) {return -1;} r += s; + return r; + } + static inline int create(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) { + HSQUIRRELVM v = SquirrelVM::GetVMPtr(); + R *r = static_cast(sq_malloc(sizeof(R))); + return r ? + PostConstruct(v, new(r) R(a1, a2, a3, a4, a5, a6, a7), + ClassType::getReleaseHook()) : + classAllocationError(v); + } +}; +#endif // SQPLUS_OVERLOAD_FUNCTIONS + +// SqPlusOverload.h + +// Local Variables: +// mode: c++ +// End: diff --git a/squirrel_3_0_1_stable/sqplus/SqPlusSetup.h b/squirrel_3_0_1_stable/sqplus/SqPlusSetup.h new file mode 100644 index 000000000..372e63f69 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SqPlusSetup.h @@ -0,0 +1,129 @@ +#ifndef SQPLUSSETUP_H +#define SQPLUSSETUP_H + +// Setup file for SqPlus. +// Comment / uncomment / define options below. + + +// Inheritance in Squirrel allows one class to inherit a base class's +// functions and variables. +// +// Variables are merged: if Derived has a var name 'val' and Base has +// a var of the same name, the resulting var 'val' will take Derived's +// initialization value. +// +// Functions are not merged, and can be called via Squirrel scoping rules. +// +// Define SQ_USE_CLASS_INHERITANCE to enable class inheritance support +// (requires slightly more memory and adds some CPU overhead). +// +// Can also be useful for debugging, as class type information is +// checked before dispatching instance function calls and before +// accessing instance member variables. +#define SQ_USE_CLASS_INHERITANCE + + +// This is a new C++ template based inheritence scheme that uses no +// additional memory per instance. To support offset between "this" +// pointer in base and derived class, use a second class in: +// SQClassDef< MyClass, MyBaseClass >. +// NOTE: For new code SQ_USE_CLASS_INHERITANCE_SIMPLE is more +// efficient than above method. +//#define SQ_USE_CLASS_INHERITANCE_SIMPLE + +// === Instance type info support === +#define SQ_SUPPORT_INSTANCE_TYPE_INFO + +// === Constant argument and constant member function support === +// Define SQPLUS_CONST_OPT before including SqPlus.h for constant +// argument + constant member function support. +#define SQPLUS_CONST_OPT + + +// === Uncomment to support smart pointer === +// Define SQPLUS_SMARTPOINTER_OPT before including SqPlus.h for +// smartpointer member function + variable support +//#define SQPLUS_SMARTPOINTER_OPT + + +// === Function overloading support === +#define SQPLUS_OVERLOAD_OPT + +// === Uncomment to support std::string === +// Requires that Squirrel is compiled with SQChar == char +//#define SQPLUS_SUPPORT_STD_STRING + +// === Uncomment to support typedef std::basic_string sq_std_string === +#define SQPLUS_SUPPORT_SQ_STD_STRING + +// === Uncomment to support NULL INSTANCE arguments === +#define SQPLUS_SUPPORT_NULL_INSTANCES + +// === Uncomment to disable copying of class instances === +// If classes being exposed have private or protected constructors +// one cannot do assign (=) in template functions. +//#define SQPLUS_DISABLE_COPY_INSTANCES + + +// === Auto generating typemasks for registered functions === +// This is useful when using Squirrel interactively +//#define SQPLUS_ENABLE_AUTO_TYPEMASK + +// === Uncomment to generate a typeof function for each class === +// This is mostly for displaying function help from inside a Squirrel prompt +//#define SQPLUS_ENABLE_TYPEOF + +// === Uncomment to skip sq_argassert() === +//#define SQ_SKIP_ARG_ASSERT + +// === GCC Inline template fix === +// Can solve problems when linking if GCC has problems with inline functions +//#define GCC_INLINE_WORKAROUND + + +// === MSVC cdecl member functions === +// Enable binding member functions with __cdecl calling convention under MSVC. +// Mostly useful when linking with binaries from other compilers. +#ifdef _MSC_VER +//#define SQPLUS_ENABLE_CDECL_MEMBER_FUNCTIONS +#endif + + +// === Generic Push/Pop/Match handlers === +// This enables using a 'fallback' set of Push/Get/Match that operates +// on class level (not on template level). This opens for handling all +// members of a certain class hierarchy using the same function +// GenPush/GenGet/GenMatch overrides (provided the hierarchy has some +// run-time type mechanism to use). They are used whenever an exact +// template match is not found. +//#define SQPLUS_USE_GENERIC_HANDLERS + + +// === Sandbox VM === +// This enables giving one VM the role of 'sandbox' VM where scripts +// of unknown origin may execute and not have access to any SqPlus +// registered functions. All normal VMs have full access to script +// functions, but the one given in SetSandboxVm() can only use std +// Squirrel functions. +//#define SQPLUS_USE_SANDBOX_VM + + +#if defined(SQPLUS_SUPPORT_STD_STRING) || defined(SQPLUS_SUPPORT_SQ_STD_STRING) +# include +#endif + + +// === Conversion of arguments from opposite char type ( char <=> wchar_t ) === +// Converts strings to opposite encoding in Push/Get handlers (UTF8 / Latin1) +#define SQPLUS_AUTOCONVERT_OTHER_CHAR + +// === Whether 8 bit chars are treated as Latin1(1) or UTF8(0) === +// (leave undefined for undefined for automatic handling) +#define SQPLUS_USE_LATIN1 1 + +// === Include system library bindings when creating VM:s in SquirrelVM::Init() === +// Define to bind to system lib when VM:s are created automatically in +// SquirrelVM::Init() +//#define SQPLUS_SQUIRRELVM_WITH_SYSTEMLIB + +#endif // SQPLUSSETUP_H diff --git a/squirrel_3_0_1_stable/sqplus/SqPlusSmartPointer.h b/squirrel_3_0_1_stable/sqplus/SqPlusSmartPointer.h new file mode 100644 index 000000000..34996ffd8 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SqPlusSmartPointer.h @@ -0,0 +1,141 @@ +// SqPlusSmartPointer.h +// SqPlus smart pointer member function support created by James Whitworth. +// Modular integration 07/11/07 James Whitworth. +// you must define the function: +// unsigned char* getSmartPointerPointee(unsigned char*) { +// return &(MySmartPointer->pointee); +// } +// somewhere in your program so it can correctly lookup member variables on the class pointed to +// by your smart pointer. + +#ifdef SQPLUS_SMARTPOINTER_ACCESSTYPE +#undef SQPLUS_SMARTPOINTER_ACCESSTYPE +enum VarAccessType {VAR_ACCESS_READ_WRITE=0,VAR_ACCESS_READ_ONLY=1<<0,VAR_ACCESS_CONSTANT=1<<1,VAR_ACCESS_STATIC=1<<2,VAR_ACCESS_SMARTPOINTER=1<<3}; +#endif // #ifdef SQPLUS_SMARTPOINTER_ACCESSTYPE + +#ifdef SQPLUS_SMARTPOINTER_REGISTER_VARIABLE +#undef SQPLUS_SMARTPOINTER_REGISTER_VARIABLE +// classType is the type of the member variable's containing class. +template +void +RegisterSmartInstanceVariable(SquirrelObject & so, + ClassTypeBase *classType, + T *var, + const SQChar *scriptVarName, + VarAccessType access = VAR_ACCESS_READ_WRITE) +{ + VarRef *pvr = createVarRef(so,scriptVarName); + + // var must be passed in as &obj->var, where obj = 0 + // (the address is the offset), or as static/global address. + void *offsetOrAddrOrConst = static_cast(var); + *pvr = VarRef(offsetOrAddrOrConst, + TypeInfo(), + classType, + ClassType::type(), + sizeof(*var), + access); + pvr->m_access |= VAR_ACCESS_SMARTPOINTER; + createInstanceSetGetHandlers(so); +} +#endif // #ifdef SQPLUS_SMARTPOINTER_REGISTER_VARIABLE + +#ifdef SQPLUS_SMARTPOINTER_DISPATCH +#undef SQPLUS_SMARTPOINTER_DISPATCH +template +class DirectCallSmartInstanceMemberFunction { +public: + static inline int Dispatch(HSQUIRRELVM v) { + DirectCallInstanceFuncPicker p(v); + if (!p.instance || !p.func) { + sq_throwerror(v, _SC("Invalid Instance Type")); + } + Pointee *pointeeInstance = static_cast(p.instance->get()); + return + !pointeeInstance ? sq_throwerror(v, _SC("SmartPointer Pointee NULL")) : + Call(*pointeeInstance, *(p.func), v, 2); + } +}; +#endif // #ifdef SQPLUS_SMARTPOINTER_DISPATCH + +#ifdef SQPLUS_SMARTPOINTER_DIRECT_CLOSURE +#undef SQPLUS_SMARTPOINTER_DIRECT_CLOSURE + +template +inline void sq_pushdirectsmartinstanceclosure(HSQUIRRELVM v,const Callee & callee,const Pointee & pointee,Func func,SQUnsignedInteger nupvalues) { + unsigned char * up = (unsigned char *)sq_newuserdata(v,sizeof(func)); // Also pushed on stack. + memcpy(up,&func,sizeof(func)); + sq_newclosure(v,DirectCallSmartInstanceMemberFunction::Dispatch,nupvalues+1); +} // sq_pushdirectinstanceclosure + +#endif // #ifdef SQPLUS_SMARTPOINTER_DIRECT_CLOSURE + +#ifdef SQPLUS_SMARTPOINTER_REGISTER_INSTANCE +#undef SQPLUS_SMARTPOINTER_REGISTER_INSTANCE + +template +inline void RegisterSmartInstance(HSQUIRRELVM v,HSQOBJECT hclass,Callee & callee,Pointee & pointee,Func func,const SQChar * name) { + sq_pushobject(v,hclass); + sq_pushstring(v,name,-1); + sq_pushdirectsmartinstanceclosure(v,callee,pointee,func,0); + sq_createslot(v,-3); + sq_poptop(v); // Remove hclass. +} // RegisterInstance + +#endif // #ifdef SQPLUS_SMARTPOINTER_REGISTER_INSTANCE + +#ifdef SQPLUS_SMARTPOINTER_CLASS_DEF_FUNC +#undef SQPLUS_SMARTPOINTER_CLASS_DEF_FUNC + + // Register a smartpointer member function. + template + SQClassDefBase & smartFunc(Func pfunc,const SQChar * name) { + RegisterSmartInstance(v,newClass.GetObjectHandle(),*(TClassType *)0,*(Pointee *)0,pfunc,name); + return *this; + } // func + +#endif // #ifdef SQPLUS_SMARTPOINTER_CLASS_DEF_FUNC + +#ifdef SQPLUS_SMARTPOINTER_CLASS_DEF_VAR +#undef SQPLUS_SMARTPOINTER_CLASS_DEF_VAR + + // Register a member variable. + template + SQClassDefBase & smartVar(VarType Pointee::* pvar,const SQChar * name,VarAccessType access=VAR_ACCESS_READ_WRITE) { + struct CV { + VarType Pointee::* var; + } cv; // Cast Variable helper. + cv.var = pvar; + RegisterSmartInstanceVariable(newClass,ClassType::type(),*(VarType **)&cv,name,access); + return *this; + } // var + + // Register a member variable as a UserPointer (read only). + template + SQClassDefBase & smartVarAsUserPointer(VarType Pointee::* pvar,const SQChar * name) { + struct CV { + VarType Pointee::* var; + } cv; // Cast Variable helper. + cv.var = pvar; + RegisterSmartInstanceVariable(newClass,ClassType::type(),*(SQAnything **)&cv,name,VAR_ACCESS_READ_ONLY); + return *this; + } // varAsUserPointer + +#endif // #ifdef SQPLUS_SMARTPOINTER_CLASS_DEF_VAR + + +#ifdef SQPLUS_SMARTPOINTER_CPP_DECLARATION +#undef SQPLUS_SMARTPOINTER_CPP_DECLARATION +extern unsigned char* getSmartPointerPointee(unsigned char*); +#endif + +#ifdef SQPLUS_SMARTPOINTER_INSTANCE_VARINFO +#undef SQPLUS_SMARTPOINTER_INSTANCE_VARINFO + if(vr->m_access & VAR_ACCESS_SMARTPOINTER) { + up = reinterpret_cast( + getSmartPointerPointee(reinterpret_cast(up)) + ); + } +#endif // #ifdef SQPLUS_SMARTPOINTER_CPP_DECLARATION + +// SqPlusSmartPointer.h diff --git a/squirrel_3_0_1_stable/sqplus/SqPlusTypeMask.h b/squirrel_3_0_1_stable/sqplus/SqPlusTypeMask.h new file mode 100644 index 000000000..975a51a1f --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SqPlusTypeMask.h @@ -0,0 +1,169 @@ + +// File to automatically generate a typemask for a function + +// Will generate type masks that accepts Instance pointer or null +#ifndef SQPLUS_ACCEPT_NULL_INSTANCE + #define SQPLUS_ACCEPT_NULL_INSTANCE +#endif + +// Macros to reduce typing: (P1), (P1,P2), (P1,P2,P3), ... +#define P_0 +#define P_1 P1 +#define P_2 P_1,P2 +#define P_3 P_2,P3 +#define P_4 P_3,P4 +#define P_5 P_4,P5 +#define P_6 P_5,P6 +#define P_7 P_6,P7 + +// Macros to reduce typing: (typename P1), (typename P1,typename P2), ... +#define PTN_0 +#define PTN_1 typename P1 +#define PTN_2 PTN_1,typename P2 +#define PTN_3 PTN_2,typename P3 +#define PTN_4 PTN_3,typename P4 +#define PTN_5 PTN_4,typename P5 +#define PTN_6 PTN_5,typename P6 +#define PTN_7 PTN_6,typename P7 + +// Include a comma first in list: ,typename P1,typename P2 +#define PTNC_0 +#define PTNC_1 ,PTN_1 +#define PTNC_2 ,PTN_2 +#define PTNC_3 ,PTN_3 +#define PTNC_4 ,PTN_4 +#define PTNC_5 ,PTN_5 +#define PTNC_6 ,PTN_6 +#define PTNC_7 ,PTN_7 + +#ifdef SQUNICODE +#define scstrcpy wcscpy +#else +#define scstrcpy strcpy +#endif + +inline const SQChar* strappchar(SQChar *buf, SQChar *in, SQChar ch){ + int l=scstrlen(in); + scstrcpy(buf,in); + buf[l] = ch; +#ifdef SQPLUS_ACCEPT_NULL_INSTANCE + if( ch=='x' ){ + buf[++l] = '|'; // Also accept NULL pointers + buf[++l] = 'o'; + } +#endif + buf[l+1] = 0; + return buf; +} + +template +struct sqTypeMask { }; + + +// Return type not included in type mask, delegate to void case + +// Base case, no arguments +template +struct sqTypeMask { + static const SQChar *Get(){ + static SQChar buf[64]; + //buf[0] = _SC('t'); + //buf[1] = 0; + //strcpy(buf,"t|x"); // Accept both instance and table, we don't use param anyway + buf[0] = _SC('.'); // Accept anything (not used) + buf[1] = 0; + return buf; + } +}; + +// Recursive case, peel of one arg at each level +#define DECLARE_RT_SQTYPEMASK(N,M) \ +template \ +struct sqTypeMask { \ + static const SQChar *Get(){ \ + static SQChar buf[10]; \ + return strappchar(buf, (SQChar*)sqTypeMask::Get(), \ + (SQChar)TypeInfo::TypeMask); \ + } \ +}; + +DECLARE_RT_SQTYPEMASK(1,0) +DECLARE_RT_SQTYPEMASK(2,1) +DECLARE_RT_SQTYPEMASK(3,2) +DECLARE_RT_SQTYPEMASK(4,3) +DECLARE_RT_SQTYPEMASK(5,4) +DECLARE_RT_SQTYPEMASK(6,5) +DECLARE_RT_SQTYPEMASK(7,6) + + +// Difference to above is that 1st param is instance instead of table + +#define DECLARE_RT_MEMBER_SQTYPEMASK(N,QUAL) \ +template \ +struct sqTypeMask { \ + static const SQChar *Get(){ \ + SQChar *buf = (SQChar*)sqTypeMask::Get(); \ + buf[0] = _SC('x'); \ + return buf; \ + } \ +}; + +// buf[1] = 0; \ + +DECLARE_RT_MEMBER_SQTYPEMASK(0,) +DECLARE_RT_MEMBER_SQTYPEMASK(1,) +DECLARE_RT_MEMBER_SQTYPEMASK(2,) +DECLARE_RT_MEMBER_SQTYPEMASK(3,) +DECLARE_RT_MEMBER_SQTYPEMASK(4,) +DECLARE_RT_MEMBER_SQTYPEMASK(5,) +DECLARE_RT_MEMBER_SQTYPEMASK(6,) +DECLARE_RT_MEMBER_SQTYPEMASK(7,) + +DECLARE_RT_MEMBER_SQTYPEMASK(0,const) +DECLARE_RT_MEMBER_SQTYPEMASK(1,const) +DECLARE_RT_MEMBER_SQTYPEMASK(2,const) +DECLARE_RT_MEMBER_SQTYPEMASK(3,const) +DECLARE_RT_MEMBER_SQTYPEMASK(4,const) +DECLARE_RT_MEMBER_SQTYPEMASK(5,const) +DECLARE_RT_MEMBER_SQTYPEMASK(6,const) +DECLARE_RT_MEMBER_SQTYPEMASK(7,const) + + +#ifdef _MSC_VER + +// Difference to above is we're using __cdecl calling convention here +// Only makes sense for MSVC where member functions can have different +// calling conventions (__cdecl or __thiscall) + +#define DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(N,QUAL) \ +template \ +struct sqTypeMask { \ + static const SQChar *Get(){ \ + SQChar *buf = (SQChar*)sqTypeMask::Get(); \ + buf[0] = _SC('x'); \ + return buf; \ + } \ +}; + +// buf[1] = 0; \ + +DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(0,) +DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(1,) +DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(2,) +DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(3,) +DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(4,) +DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(5,) +DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(6,) +DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(7,) + +DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(0,const) +DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(1,const) +DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(2,const) +DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(3,const) +DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(4,const) +DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(5,const) +DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(6,const) +DECLARE_RT_MEMBER_SQTYPEMASK_CDECL(7,const) + +#endif // _MSC_VER + diff --git a/squirrel_3_0_1_stable/sqplus/SqPlusUtf8.cpp b/squirrel_3_0_1_stable/sqplus/SqPlusUtf8.cpp new file mode 100644 index 000000000..7505e9928 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SqPlusUtf8.cpp @@ -0,0 +1,133 @@ + +/////////////////////////////////////////////////////////////////////// +// Simple conversion routines, to, from UTF8 and full Unicode character +// (using int). +// + +// Only when needed +#if !defined(SQPLUS_USE_LATIN1) || SQPLUS_USE_LATIN1==0 + +static char g_utf8_length[256]; +static int g_did_init_length; + +void sqplus_init_utf8_lengths() { + // Fill in lengths in array above + for( int lb=0; lb<256; lb++ ){ + int l = -1; + if( !(lb&0x80) ) l=1; + else if( (lb&0xE0)==0xC0 ) l=2; + else if( (lb&0xF0)==0xE0 ) l=3; + else if( (lb&0xF8)==0xF0 ) l=4; + else if( (lb&0xFC)==0xF8 ) l=5; + else if( (lb&0xFE)==0xFC ) l=6; + g_utf8_length[lb] = l; + } + g_did_init_length = 1; +} + +// Length of a UTF8 encoded Unicode character +int sqplus_utf8_len(int lead_byte){ + if( !(lead_byte&0x80) ) return 1; // Special case, make faster + if( !g_did_init_length ) + sqplus_init_utf8_lengths(); + + return g_utf8_length[(unsigned char)lead_byte]; +} + +int sqplus_utf8_len_first(const char* pc){ + int lb = *(unsigned char*)pc; + if( !(lb&0x80) ) return 1; // Special case, make faster + if( !g_did_init_length ) + sqplus_init_utf8_lengths(); + + int l = g_utf8_length[(unsigned char)lb]; + if( l>0 ) return l; + + // Invalid UTF8 lead byte. Look for next valid character. + const char *pc1 = pc+1; + while( ((*pc1)&0xC0)==0x80 ) + pc1++; + return int(pc1 - pc); +} + + +// Length of a UTF8 encoded Unicode string (number of Unicode characters) +int sqplus_utf8_strlen(const char *str) { + if( !str ) return 0; + int l, tl=0; + while( *str ){ + l = sqplus_utf8_len_first(str); + str += l; + tl++; + } + return tl; +} + +// Convert one UTF8 encoded character to Unicode point +int sqplus_utf8_to_wchar(int *result, const char *string){ + int res=-1; + + // Assume argument pointers to be OK + unsigned char ch = *string; + int l = sqplus_utf8_len(ch); + + if( l<1 ) return -1; + int wc = l>1 ? (ch&(0x7F>>l)) : ch; + while( l>1 ){ + wc = (wc<<6) + (*++string & 0x3F); + l--; + } + *result = wc; + + return 0; +} + +// Convert one Unicode point to UTF8 encoded version. +// Checks if output fits in 1/4/6 bytes buffer. +int sqplus_wchar_to_utf8(char *s, int wc, int size){ + if( size<1 ) return -1; + if( (unsigned int)wc>=0x80000000 ) return -2; + + // Single byte case + if( wc<0x80 ){ + *s = (char)wc; + //*s = (char)wc&0x7F; + return 1; + } + if( size<4 ) return -3; + + // Two or more UTF8 bytes + int p = 1; // Index of last UTF8 byte + if( wc>0x7FF ){ // 11 bits + // Three or more UTF8 bytes + p++; // p>=2 + if( wc>0xFFFF ){ // 16 bits + // Four or more UTF8 bytes + p++; // p>=3 + if( wc>0x1FFFFF ){ // 21 bits + // Five or more UTF8 bytes + if( size<6 ) return -3; + p++; // p>=4 UTF8 bytes + if( wc>0x3FFFFFF ){ // 26 bits + // Six UTF8 bytes + p++; // p>=5 + if( (unsigned int)wc>(unsigned int)0x7FFFFFF ){ // 31 bits + // Would need 7 UTF8 bytes. Not supported. + return -10; + } + s[p-4] = 0x80 | ((wc>>24)&0x3F); // Bit 24..29 + } + s[p-3] = 0x80 | ((wc>>18)&0x3F); // Bit 18..23 + } + s[p-2] = 0x80 | ((wc>>12)&0x3F); // Bit 12..17 + } + s[p-1] = 0x80 | ((wc>>6)&0x3F); // Bit 6..11 + } + s[p] = 0x80 | (wc&0x3F); // Bit 0..5 + s[0] = (0xFC << (5-p)) | (wc>>(p*6)); + + return p+1; +} + +#endif // #if !defined(SQPLUS_USE_LATIN1) || SQPLUS_USE_LATIN1==0 + diff --git a/squirrel_3_0_1_stable/sqplus/SqPlusUtf8.h b/squirrel_3_0_1_stable/sqplus/SqPlusUtf8.h new file mode 100644 index 000000000..b0c14aa36 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SqPlusUtf8.h @@ -0,0 +1,15 @@ +#ifndef SQPLUSUTF8_H +#define SQPLUSUTF8_H + +#if defined(SQUTF8) || SQPLUS_USE_LATIN1!=1 + +// Simple Unicode <-> UTF8 conversion routines +//int sqplus_utf8_len(char lead_byte); +int sqplus_utf8_len_first(const char *str); +int sqplus_utf8_strlen(const char *str); +int sqplus_utf8_to_wchar(int *result, const char *string); +int sqplus_wchar_to_utf8(char *s, int wc, int size); + +#endif // defined(SQUTF8) || SQPLUS_USE_LATIN1!=1 + +#endif // SQPLUSUTF8_H diff --git a/squirrel_3_0_1_stable/sqplus/SquirrelBindingsUtils.cpp b/squirrel_3_0_1_stable/sqplus/SquirrelBindingsUtils.cpp new file mode 100644 index 000000000..cd337961c --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SquirrelBindingsUtils.cpp @@ -0,0 +1,161 @@ +#include "sqplus.h" + +BOOL CreateStaticNamespace(HSQUIRRELVM v,ScriptNamespaceDecl *sn) +{ + int n = 0; + sq_pushroottable(v); + sq_pushstring(v,sn->name,-1); + sq_newtable(v); + const ScriptClassMemberDecl *members = sn->members; + const ScriptClassMemberDecl *m = NULL; + while(members[n].name) { + m = &members[n]; + sq_pushstring(v,m->name,-1); + sq_newclosure(v,m->func,0); + sq_setparamscheck(v,m->params,m->typemask); + sq_setnativeclosurename(v,-1,m->name); + sq_createslot(v,-3); + n++; + } + const ScriptConstantDecl *consts = sn->constants; + const ScriptConstantDecl *c = NULL; + n = 0; + while(consts[n].name) { + c = &consts[n]; + sq_pushstring(v,c->name,-1); + switch(c->type) { + case OT_STRING: sq_pushstring(v,c->val.s,-1);break; + case OT_INTEGER: sq_pushinteger(v,c->val.i);break; + case OT_FLOAT: sq_pushfloat(v,c->val.f);break; + } + sq_createslot(v,-3); + n++; + } + if(sn->delegate) { + const ScriptClassMemberDecl *members = sn->delegate; + const ScriptClassMemberDecl *m = NULL; + sq_newtable(v); + while(members[n].name) { + m = &members[n]; + sq_pushstring(v,m->name,-1); + sq_newclosure(v,m->func,0); + sq_setparamscheck(v,m->params,m->typemask); + sq_setnativeclosurename(v,-1,m->name); + sq_createslot(v,-3); + n++; + } + sq_setdelegate(v,-2); + } + sq_createslot(v,-3); + sq_pop(v,1); + + return TRUE; +} + +BOOL CreateClass(HSQUIRRELVM v,SquirrelClassDecl *cd) +{ + int n = 0; + int oldtop = sq_gettop(v); + sq_pushroottable(v); + sq_pushstring(v,cd->name,-1); + if(cd->base) { + sq_pushstring(v,cd->base,-1); + if(SQ_FAILED(sq_get(v,-3))) { // Make sure the base exists if specified by cd->base name. + sq_settop(v,oldtop); + return FALSE; + } + } + if(SQ_FAILED(sq_newclass(v,cd->base?1:0))) { // Will inherit from base class on stack from sq_get() above. + sq_settop(v,oldtop); + return FALSE; + } +// sq_settypetag(v,-1,(unsigned int)cd); +#ifdef _WIN32 +#pragma warning(disable : 4311) +#endif + sq_settypetag(v,-1,reinterpret_cast(cd)); + const ScriptClassMemberDecl *members = cd->members; + const ScriptClassMemberDecl *m = NULL; + if (members) { + while(members[n].name) { + m = &members[n]; + sq_pushstring(v,m->name,-1); + sq_newclosure(v,m->func,0); + sq_setparamscheck(v,m->params,m->typemask); + sq_setnativeclosurename(v,-1,m->name); + sq_createslot(v,-3); + n++; + } + } // if + sq_createslot(v,-3); + sq_pop(v,1); + return TRUE; +} + +BOOL CreateNativeClassInstance(HSQUIRRELVM v, + const SQChar *classname, + SQUserPointer ud, + SQRELEASEHOOK hook) +{ + // If we don't do this, SquirrelVM keeps an old pointer around and this + // will be used by SquirrelObject. That crashes when using several VMs. + SquirrelVM::Init( v ); + + int oldtop = sq_gettop(v); + sq_pushroottable(v); + sq_pushstring(v,classname,-1); + if(SQ_FAILED(sq_rawget(v,-2))){ //Get the class (created with sq_newclass()). + sq_settop(v,oldtop); + return FALSE; + } + //sq_pushroottable(v); + if(SQ_FAILED(sq_createinstance(v,-1))) { + sq_settop(v,oldtop); + return FALSE; + } + +#ifdef SQ_USE_CLASS_INHERITANCE + HSQOBJECT ho; + sq_getstackobj(v, -1, &ho); // OT_INSTANCE + SquirrelObject instance(ho); + SqPlus::PopulateAncestry(v, instance, ud); +#endif + + sq_remove(v,-3); //removes the root table + sq_remove(v,-2); //removes the class + if(SQ_FAILED(sq_setinstanceup(v,-1,ud))) { + sq_settop(v,oldtop); + return FALSE; + } + sq_setreleasehook(v,-1,hook); + return TRUE; +} + + + +// Create native class instance and leave on stack. +BOOL CreateConstructNativeClassInstance(HSQUIRRELVM v,const SQChar * className) { + int oldtop = sq_gettop(v); + sq_pushroottable(v); + sq_pushstring(v,className,-1); + if (SQ_FAILED(sq_rawget(v,-2))) { // Get the class (created with sq_newclass()). + sq_settop(v,oldtop); + return FALSE; + } // if +#if 0 + sq_remove(v,-3); // Remove the root table. + sq_push(v,1); // Push the 'this'. +#else // Kamaitati's change. 5/28/06 jcs. + sq_remove(v,-2); // Remove the root table. + sq_pushroottable(v); // Push the 'this'. +#endif + if (SQ_FAILED(sq_call(v,1,SQTrue,SQ_CALL_RAISE_ERROR))) { // Call ClassName(): creates new instance and calls constructor (instead of sq_createinstance() where constructor is not called). + sq_settop(v,oldtop); + return FALSE; + } // if + sq_remove(v,-2); // Remove the class. + // int newtop = sq_gettop(v); + return TRUE; +} // CreateConstructNativeClassInstance + + diff --git a/squirrel_3_0_1_stable/sqplus/SquirrelBindingsUtils.h b/squirrel_3_0_1_stable/sqplus/SquirrelBindingsUtils.h new file mode 100644 index 000000000..11ab4be54 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SquirrelBindingsUtils.h @@ -0,0 +1,152 @@ +#ifndef SQUIRREL_BINDINGS_UTILS_H +#define SQUIRREL_BINDINGS_UTILS_H + +struct ScriptClassMemberDecl { + const SQChar *name; + SQFUNCTION func; + int params; + const SQChar *typemask; +}; + +struct SquirrelClassDecl { + const SQChar *name; + const SQChar *base; + const ScriptClassMemberDecl *members; +}; + +struct ScriptConstantDecl { + const SQChar *name; + SQObjectType type; + union value { + value(float v){ f = v; } + value(int v){ i = v; } + value(long int v){ li = v; } + value(const SQChar *v){ s = v; } + float f; + int i; + long int li; + const SQChar *s; + } val; +}; + +struct ScriptNamespaceDecl { + const SQChar *name; + const ScriptClassMemberDecl *members; + const ScriptConstantDecl *constants; + const ScriptClassMemberDecl *delegate; +}; + +#define _BEGIN_CLASS(classname) \ + int __##classname##__typeof(HSQUIRRELVM v) \ + { \ + sq_pushstring(v,_SC(#classname),-1); \ + return 1; \ + } \ + struct ScriptClassMemberDecl __##classname##_members[] = { \ + {_SC("_typeof"),__##classname##__typeof,1,NULL}, + +#define _BEGIN_NAMESPACE(xnamespace) struct ScriptClassMemberDecl __##xnamespace##_members[] = { +#define _BEGIN_NAMESPACE_CONSTANTS(xnamespace) {NULL,NULL,0,NULL}}; \ + struct ScriptConstantDecl __##xnamespace##_constants[] = { + +#define _BEGIN_DELEGATE(xnamespace) struct ScriptClassMemberDecl __##xnamespace##_delegate[] = { +#define _DELEGATE(xnamespace) __##xnamespace##_delegate +#define _END_DELEGATE(classname) {NULL,NULL,NULL,NULL}}; + +#define _CONSTANT(name,type,val) {_SC(#name),type,val}, +#define _CONSTANT_IMPL(name,type) {_SC(#name),type,name}, + +#define _MEMBER_FUNCTION(classname,name,nparams,typemask) \ + {_SC(#name),__##classname##_##name,nparams,typemask}, + +#define _END_NAMESPACE(classname,delegate) {NULL,OT_NULL,0}}; \ +struct ScriptNamespaceDecl __##classname##_decl = { \ + _SC(#classname), __##classname##_members,__##classname##_constants,delegate }; + +#define _END_CLASS(classname) {NULL,NULL,0,NULL}}; \ +struct SquirrelClassDecl __##classname##_decl = { \ + _SC(#classname), NULL, __##classname##_members }; + + +#define _END_CLASS_INHERITANCE(classname,base) {NULL,NULL,NULL,NULL}}; \ +struct SquirrelClassDecl __##classname##_decl = { \ + _SC(#classname), _SC(#base), __##classname##_members }; + +#define _MEMBER_FUNCTION_IMPL(classname,name) \ + int __##classname##_##name(HSQUIRRELVM v) + +#define _INIT_STATIC_NAMESPACE(classname) CreateStaticNamespace(SquirrelVM::GetVMPtr(),&__##classname##_decl); +#define _INIT_CLASS(classname)CreateClass(SquirrelVM::GetVMPtr(),&__##classname##_decl); + +#define _DECL_STATIC_NAMESPACE(xnamespace) extern struct ScriptNamespaceDecl __##xnamespace##_decl; +#define _DECL_CLASS(classname) extern struct SquirrelClassDecl __##classname##_decl; + +#define _CHECK_SELF(cppclass,scriptclass) \ + cppclass *self = NULL; \ + if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)&__##scriptclass##_decl))) { \ + return sq_throwerror(v,_SC("invalid instance type"));\ + } + +#define _CHECK_INST_PARAM(pname,idx,cppclass,scriptclass) \ + cppclass *pname = NULL; \ + if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer*)&pname,(SQUserPointer)&__##scriptclass##_decl))) { \ + return sq_throwerror(v,_SC("invalid instance type"));\ + } \ + +#define _CHECK_INST_PARAM_BREAK(pname,idx,cppclass,scriptclass) \ + cppclass *pname = NULL; \ + if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer*)&pname,(SQUserPointer)&__##scriptclass##_decl))) { \ + break; \ + } \ + +#define _CLASS_TAG(classname) ((unsigned int)&__##classname##_decl) + + +#define _DECL_NATIVE_CONSTRUCTION(classname,cppclass) \ + BOOL push_##classname(cppclass &quat); \ + SquirrelObject new_##classname(cppclass &quat); + +#define _IMPL_NATIVE_CONSTRUCTION(classname,cppclass) \ +static int classname##_release_hook(SQUserPointer p, int size) \ +{ \ + if(p) { \ + cppclass *pv = (cppclass *)p; \ + delete pv; \ + } \ + return 0; \ +} \ +BOOL push_##classname(cppclass &quat) \ +{ \ + cppclass *newquat = new cppclass; \ + *newquat = quat; \ + if(!CreateNativeClassInstance(SquirrelVM::GetVMPtr(),_SC(#classname),newquat,classname##_release_hook)) { \ + delete newquat; \ + return FALSE; \ + } \ + return TRUE; \ +} \ +SquirrelObject new_##classname(cppclass &quat) \ +{ \ + SquirrelObject ret; \ + if(push_##classname(quat)) { \ + ret.AttachToStackObject(-1); \ + sq_pop(SquirrelVM::GetVMPtr(),1); \ + } \ + return ret; \ +} \ +int construct_##classname(cppclass *p) \ +{ \ + sq_setinstanceup(SquirrelVM::GetVMPtr(),1,p); \ + sq_setreleasehook(SquirrelVM::GetVMPtr(),1,classname##_release_hook); \ + return 1; \ +} + +BOOL CreateStaticClass(HSQUIRRELVM v,SquirrelClassDecl *cd); +BOOL CreateStaticNamespace(HSQUIRRELVM v,ScriptNamespaceDecl *sn); +BOOL CreateClass(HSQUIRRELVM v,SquirrelClassDecl *cd); +BOOL InitScriptClasses(HSQUIRRELVM v); +BOOL CreateNativeClassInstance(HSQUIRRELVM v,const SQChar *classname,SQUserPointer ud,SQRELEASEHOOK hook); +BOOL CreateConstructNativeClassInstance(HSQUIRRELVM v,const SQChar * className); + +#endif // SQUIRREL_BINDINGS_UTILS_H + diff --git a/squirrel_3_0_1_stable/sqplus/SquirrelBindingsUtilsWin32.cpp b/squirrel_3_0_1_stable/sqplus/SquirrelBindingsUtilsWin32.cpp new file mode 100644 index 000000000..dd3f850ca --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SquirrelBindingsUtilsWin32.cpp @@ -0,0 +1,31 @@ +#include "sqplus.h" + +//#include "SquirrelObject.h" +//#include "SquirrelVM.h" +#include "SquirrelBindingsUtilsWin32.h" + +int refcounted_release_hook(SQUserPointer p, int size) +{ + IUnknown *pRC = (IUnknown*)p; + pRC->Release(); + return 0; +} + +static BOOL __CreateRefCountedInstance(HSQUIRRELVM v,const SQChar *classname,IUnknown *pRC,SQRELEASEHOOK hook) +{ + if(!CreateNativeClassInstance(v,classname,pRC,hook)) return FALSE; + return TRUE; +} + +int construct_RefCounted(IUnknown *p) +{ + sq_setinstanceup(SquirrelVM::GetVMPtr(),1,p); + sq_setreleasehook(SquirrelVM::GetVMPtr(),1,refcounted_release_hook); + return 1; +} + + +BOOL CreateRefCountedInstance(HSQUIRRELVM v,const SQChar *classname,IUnknown *pRC) +{ + return __CreateRefCountedInstance(v,classname,pRC,refcounted_release_hook); +} diff --git a/squirrel_3_0_1_stable/sqplus/SquirrelBindingsUtilsWin32.h b/squirrel_3_0_1_stable/sqplus/SquirrelBindingsUtilsWin32.h new file mode 100644 index 000000000..3f3358422 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SquirrelBindingsUtilsWin32.h @@ -0,0 +1,41 @@ +#ifndef SQUIRREL_BINDINGS_UTILS_WIN32_H +#define SQUIRREL_BINDINGS_UTILS_WIN32_H + +#ifndef _INC_WINDOWS +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include +#endif +#ifndef __IUnknown_INTERFACE_DEFINED__ +#include +#endif + +#ifndef SQUIRREL_BINDINGS_UTILS_H +#include "SquirrelBindingsUtils.h" +#endif + +#define _DECLARE_REFCOUNTED_NEW(cppclass,classname) \ + SquirrelObject new_##classname(cppclass *ptr) { \ + if(CreateRefCountedInstance(SquirrelVM::GetVMPtr(),_SC(#classname),ptr)) { \ + HSQOBJECT o; \ + sq_getstackobj(SquirrelVM::GetVMPtr(),-1,&o); \ + SquirrelObject tmp = o; \ + sq_pop(SquirrelVM::GetVMPtr(),1); \ + return tmp; \ + } \ + return SquirrelObject() ; \ + } + +#define _RETURN_REFCOUNTED_INSTANCE(classname,ptr) \ + if(!CreateRefCountedInstance(SquirrelVM::GetVMPtr(),_SC(#classname),ptr)) { \ + return sa.ThrowError(_SC("cannot create the class instance")); \ + } \ + return 1; + +BOOL CreateRefCountedInstance(HSQUIRRELVM v,const SQChar *classname,IUnknown *pRC); +BOOL CreateRefCountedInstanceChached(HSQUIRRELVM v,const SQChar *classname,IUnknown *pRC); +int refcounted_release_hook(SQUserPointer p, int size); +int construct_RefCounted(IUnknown *p); + +#endif // SQUIRREL_BINDINGS_UTILS_WIN32_H + diff --git a/squirrel_3_0_1_stable/sqplus/SquirrelObject.cpp b/squirrel_3_0_1_stable/sqplus/SquirrelObject.cpp new file mode 100644 index 000000000..58d43bbed --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SquirrelObject.cpp @@ -0,0 +1,702 @@ +#include "sqplus.h" + +SquirrelObject::SquirrelObject(void) +{ + sq_resetobject(&_o); +} + +SquirrelObject::~SquirrelObject() +{ + Reset(); +} + +SquirrelObject::SquirrelObject(const SquirrelObject &o) +{ + _o = o._o; + sq_addref(SquirrelVM::_VM,&_o); +} + +SquirrelObject::SquirrelObject(HSQOBJECT o) +{ + _o = o; + sq_addref(SquirrelVM::_VM,&_o); +} + +void SquirrelObject::Reset(void) { + if(SquirrelVM::_VM) + sq_release(SquirrelVM::_VM,&_o); + else if( _o._type!=OT_NULL && _o._unVal.pRefCounted ) + printf( "SquirrelObject::~SquirrelObject - Cannot release\n" ); + sq_resetobject(&_o); +} // SquirrelObject::Reset + +SquirrelObject SquirrelObject::Clone() +{ + SquirrelObject ret; + if(GetType() == OT_TABLE || GetType() == OT_ARRAY) + { + sq_pushobject(SquirrelVM::_VM,_o); + sq_clone(SquirrelVM::_VM,-1); + ret.AttachToStackObject(-1); + sq_pop(SquirrelVM::_VM,2); + } + return ret; + +} + +SquirrelObject & SquirrelObject::operator =(const SquirrelObject &o) +{ + //HSQOBJECT t; + //t = o._o; + //sq_addref(SquirrelVM::_VM,&t); + sq_addref(SquirrelVM::_VM, (HSQOBJECT*)&o._o); + sq_release(SquirrelVM::_VM,&_o); + //_o = t; + _o = o._o; + return *this; +} + +SquirrelObject & SquirrelObject::operator =(HSQOBJECT ho) +{ + sq_addref(SquirrelVM::_VM,&ho); + sq_release(SquirrelVM::_VM,&_o); + _o = ho; + return *this; +} + +SquirrelObject & SquirrelObject::operator =(int n) +{ + sq_pushinteger(SquirrelVM::_VM,n); + AttachToStackObject(-1); + sq_pop(SquirrelVM::_VM,1); + return *this; +} + +#include +#include "../squirrel/sqstate.h" +#include "../squirrel/sqvm.h" + +SquirrelObject & SquirrelObject::operator =(HSQUIRRELVM v) +{ + if( v && SquirrelVM::_VM ){ + SquirrelVM::_VM->Push(v); + AttachToStackObject(-1); + sq_poptop(SquirrelVM::_VM); + } + else Reset(); + return *this; +} + +bool SquirrelObject::operator == (const SquirrelObject &o) +{ + bool cmp = false; + HSQUIRRELVM v = SquirrelVM::GetVMPtr(); + int oldtop = sq_gettop(v); + + sq_pushobject(v, GetObjectHandle()); + sq_pushobject(v, o.GetObjectHandle()); + if(sq_cmp(v) == 0) + cmp = true; + + sq_settop(v, oldtop); + return cmp; +} + +bool SquirrelObject::CompareUserPointer( const SquirrelObject &o ) +{ + if( _o._type == o.GetObjectHandle()._type ) + if( _o._unVal.pUserPointer == o.GetObjectHandle()._unVal.pUserPointer ) + return true; + + return false; +} + +void SquirrelObject::ArrayAppend(const SquirrelObject &o) +{ + if(sq_isarray(_o)) { + sq_pushobject(SquirrelVM::_VM,_o); + sq_pushobject(SquirrelVM::_VM,o._o); + sq_arrayappend(SquirrelVM::_VM,-2); + sq_pop(SquirrelVM::_VM,1); + } +} + +void SquirrelObject::AttachToStackObject(int idx) +{ + HSQOBJECT t; + sq_getstackobj(SquirrelVM::_VM,idx,&t); + sq_addref(SquirrelVM::_VM,&t); + sq_release(SquirrelVM::_VM,&_o); + _o = t; +} + +BOOL SquirrelObject::SetDelegate(SquirrelObject &obj) +{ + if(obj.GetType() == OT_TABLE || + obj.GetType() == OT_NULL) { + switch(_o._type) { + case OT_USERDATA: + case OT_TABLE: + sq_pushobject(SquirrelVM::_VM,_o); + sq_pushobject(SquirrelVM::_VM,obj._o); + if(SQ_SUCCEEDED(sq_setdelegate(SquirrelVM::_VM,-2))) { + sq_pop(SquirrelVM::_VM,1); + return TRUE; + } + sq_pop(SquirrelVM::_VM,1); + break; + } + } + return FALSE; +} + +SquirrelObject SquirrelObject::GetDelegate() +{ + SquirrelObject ret; + if(_o._type == OT_TABLE || _o._type == OT_USERDATA) + { + int top = sq_gettop(SquirrelVM::_VM); + sq_pushobject(SquirrelVM::_VM,_o); + sq_getdelegate(SquirrelVM::_VM,-1); + ret.AttachToStackObject(-1); + sq_settop(SquirrelVM::_VM,top); +// sq_pop(SquirrelVM::_VM,2); + } + return ret; +} + +BOOL SquirrelObject::IsNull() const +{ + return sq_isnull(_o); +} + +BOOL SquirrelObject::IsNumeric() const +{ + return sq_isnumeric(_o); +} + +int SquirrelObject::Len() const +{ + int ret = 0; + if(sq_isarray(_o) || sq_istable(_o) || sq_isstring(_o)) { + sq_pushobject(SquirrelVM::_VM,_o); + ret = sq_getsize(SquirrelVM::_VM,-1); + sq_pop(SquirrelVM::_VM,1); + } + return ret; +} + +#define _SETVALUE_INT_BEGIN \ + BOOL ret = FALSE; \ + int top = sq_gettop(SquirrelVM::_VM); \ + sq_pushobject(SquirrelVM::_VM,_o); \ + sq_pushinteger(SquirrelVM::_VM,key); + +#define _SETVALUE_INT_END \ + if(SQ_SUCCEEDED(sq_rawset(SquirrelVM::_VM,-3))) { \ + ret = TRUE; \ + } \ + sq_settop(SquirrelVM::_VM,top); \ + return ret; + +BOOL SquirrelObject::SetValue(INT key,const SquirrelObject &val) +{ + _SETVALUE_INT_BEGIN + sq_pushobject(SquirrelVM::_VM,val._o); + _SETVALUE_INT_END +} + +BOOL SquirrelObject::SetValue(INT key,INT n) +{ + _SETVALUE_INT_BEGIN + sq_pushinteger(SquirrelVM::_VM,n); + _SETVALUE_INT_END +} + +BOOL SquirrelObject::SetValue(INT key,FLOAT f) +{ + _SETVALUE_INT_BEGIN + sq_pushfloat(SquirrelVM::_VM,f); + _SETVALUE_INT_END +} + +BOOL SquirrelObject::SetValue(INT key,const SQChar *s) +{ + _SETVALUE_INT_BEGIN + sq_pushstring(SquirrelVM::_VM,s,-1); + _SETVALUE_INT_END +} + +BOOL SquirrelObject::SetValue(INT key,bool b) +{ + _SETVALUE_INT_BEGIN + sq_pushbool(SquirrelVM::_VM,b); + _SETVALUE_INT_END +} + +BOOL SquirrelObject::SetValue(const SquirrelObject &key,const SquirrelObject &val) +{ + BOOL ret = FALSE; + int top = sq_gettop(SquirrelVM::_VM); + sq_pushobject(SquirrelVM::_VM,_o); + sq_pushobject(SquirrelVM::_VM,key._o); + sq_pushobject(SquirrelVM::_VM,val._o); + if(SQ_SUCCEEDED(sq_rawset(SquirrelVM::_VM,-3))) { + ret = TRUE; + } + sq_settop(SquirrelVM::_VM,top); + return ret; +} + +#define _SETVALUE_STR_BEGIN \ + BOOL ret = FALSE; \ + int top = sq_gettop(SquirrelVM::_VM); \ + sq_pushobject(SquirrelVM::_VM,_o); \ + sq_pushstring(SquirrelVM::_VM,key,-1); + +#define _SETVALUE_STR_END \ + if(SQ_SUCCEEDED(sq_rawset(SquirrelVM::_VM,-3))) { \ + ret = TRUE; \ + } \ + sq_settop(SquirrelVM::_VM,top); \ + return ret; + +BOOL SquirrelObject::SetValue(const SQChar *key,const SquirrelObject &val) +{ + _SETVALUE_STR_BEGIN + sq_pushobject(SquirrelVM::_VM,val._o); + _SETVALUE_STR_END +} + +BOOL SquirrelObject::SetValue(const SQChar *key,INT n) +{ + _SETVALUE_STR_BEGIN + sq_pushinteger(SquirrelVM::_VM,n); + _SETVALUE_STR_END +} + +BOOL SquirrelObject::SetValue(const SQChar *key,FLOAT f) +{ + _SETVALUE_STR_BEGIN + sq_pushfloat(SquirrelVM::_VM,f); + _SETVALUE_STR_END +} + +BOOL SquirrelObject::SetValue(const SQChar *key,const SQChar *s) +{ + _SETVALUE_STR_BEGIN + sq_pushstring(SquirrelVM::_VM,s,-1); + _SETVALUE_STR_END +} + +BOOL SquirrelObject::SetValue(const SQChar *key,bool b) +{ + _SETVALUE_STR_BEGIN + sq_pushbool(SquirrelVM::_VM,b); + _SETVALUE_STR_END +} + +// === BEGIN User Pointer, User Data === + +BOOL SquirrelObject::SetUserPointer(const SQChar * key,SQUserPointer up) { + _SETVALUE_STR_BEGIN + sq_pushuserpointer(SquirrelVM::_VM,up); + _SETVALUE_STR_END +} // SquirrelObject::SetUserPointer + +SQUserPointer SquirrelObject::GetUserPointer(const SQChar * key) { + SQUserPointer ret = NULL; + if (GetSlot(key)) { + sq_getuserpointer(SquirrelVM::_VM,-1,&ret); + sq_pop(SquirrelVM::_VM,1); + } // if + sq_pop(SquirrelVM::_VM,1); + return ret; +} // SquirrelObject::GetUserPointer + +BOOL SquirrelObject::SetUserPointer(INT key,SQUserPointer up) { + _SETVALUE_INT_BEGIN + sq_pushuserpointer(SquirrelVM::_VM,up); + _SETVALUE_INT_END +} // SquirrelObject::SetUserPointer + +SQUserPointer SquirrelObject::GetUserPointer(INT key) { + SQUserPointer ret = NULL; + if (GetSlot(key)) { + sq_getuserpointer(SquirrelVM::_VM,-1,&ret); + sq_pop(SquirrelVM::_VM,1); + } // if + sq_pop(SquirrelVM::_VM,1); + return ret; +} // SquirrelObject::GetUserPointer + +// === User Data === + +BOOL SquirrelObject::NewUserData(const SQChar * key,INT size,SQUserPointer * typetag) { + _SETVALUE_STR_BEGIN + sq_newuserdata(SquirrelVM::_VM,size); + if (typetag) { + sq_settypetag(SquirrelVM::_VM,-1,typetag); + } // if + _SETVALUE_STR_END +} // SquirrelObject::NewUserData + +BOOL SquirrelObject::GetUserData(const SQChar * key,SQUserPointer * data,SQUserPointer * typetag) { + BOOL ret = false; + if (GetSlot(key)) { + sq_getuserdata(SquirrelVM::_VM,-1,data,typetag); + sq_pop(SquirrelVM::_VM,1); + ret = true; + } // if + sq_pop(SquirrelVM::_VM,1); + return ret; +} // SquirrelObject::GetUserData + +BOOL SquirrelObject::RawGetUserData(const SQChar * key,SQUserPointer * data,SQUserPointer * typetag) { + BOOL ret = false; + if (RawGetSlot(key)) { + sq_getuserdata(SquirrelVM::_VM,-1,data,typetag); + sq_pop(SquirrelVM::_VM,1); + ret = true; + } // if + sq_pop(SquirrelVM::_VM,1); + return ret; +} // SquirrelObject::RawGetUserData + +// === END User Pointer === + +// === BEGIN Arrays === + +BOOL SquirrelObject::ArrayResize(INT newSize) { +// int top = sq_gettop(SquirrelVM::_VM); + sq_pushobject(SquirrelVM::_VM,GetObjectHandle()); + BOOL res = sq_arrayresize(SquirrelVM::_VM,-1,newSize) == SQ_OK; + sq_pop(SquirrelVM::_VM,1); +// sq_settop(SquirrelVM::_VM,top); + return res; +} // SquirrelObject::ArrayResize + +BOOL SquirrelObject::ArrayExtend(INT amount) { + int newLen = Len()+amount; + return ArrayResize(newLen); +} // SquirrelObject::ArrayExtend + +BOOL SquirrelObject::ArrayReverse(void) { + sq_pushobject(SquirrelVM::_VM,GetObjectHandle()); + BOOL res = sq_arrayreverse(SquirrelVM::_VM,-1) == SQ_OK; + sq_pop(SquirrelVM::_VM,1); + return res; +} // SquirrelObject::ArrayReverse + +SquirrelObject SquirrelObject::ArrayPop(SQBool returnPoppedVal) { + SquirrelObject ret; + int top = sq_gettop(SquirrelVM::_VM); + sq_pushobject(SquirrelVM::_VM,GetObjectHandle()); + if (sq_arraypop(SquirrelVM::_VM,-1,returnPoppedVal) == SQ_OK) { + if (returnPoppedVal) { + ret.AttachToStackObject(-1); + } // if + } // if + sq_settop(SquirrelVM::_VM,top); + return ret; +} // SquirrelObject::ArrayPop + +// === END Arrays === + +SQObjectType SquirrelObject::GetType() +{ + return _o._type; +} + +BOOL SquirrelObject::GetSlot(INT key) const +{ + sq_pushobject(SquirrelVM::_VM,_o); + sq_pushinteger(SquirrelVM::_VM,key); + if(SQ_SUCCEEDED(sq_get(SquirrelVM::_VM,-2))) { + return TRUE; + } + + return FALSE; +} + + +SquirrelObject SquirrelObject::GetValue(INT key)const +{ + SquirrelObject ret; + if(GetSlot(key)) { + ret.AttachToStackObject(-1); + sq_pop(SquirrelVM::_VM,1); + } + sq_pop(SquirrelVM::_VM,1); + return ret; +} + +FLOAT SquirrelObject::GetFloat(INT key) const +{ + FLOAT ret = 0.0f; + if(GetSlot(key)) { + sq_getfloat(SquirrelVM::_VM,-1,&ret); + sq_pop(SquirrelVM::_VM,1); + } + sq_pop(SquirrelVM::_VM,1); + return ret; +} + +INT SquirrelObject::GetInt(INT key) const +{ + INT ret = 0; + if(GetSlot(key)) { + sq_getinteger(SquirrelVM::_VM,-1,&ret); + sq_pop(SquirrelVM::_VM,1); + } + sq_pop(SquirrelVM::_VM,1); + return ret; +} + +const SQChar *SquirrelObject::GetString(INT key) const +{ + const SQChar *ret = NULL; + if(GetSlot(key)) { + sq_getstring(SquirrelVM::_VM,-1,&ret); + sq_pop(SquirrelVM::_VM,1); + } + sq_pop(SquirrelVM::_VM,1); + return ret; +} + +bool SquirrelObject::GetBool(INT key) const +{ + SQBool ret = FALSE; + if(GetSlot(key)) { + sq_getbool(SquirrelVM::_VM,-1,&ret); + sq_pop(SquirrelVM::_VM,1); + } + sq_pop(SquirrelVM::_VM,1); + return ret?true:false; +} + +BOOL SquirrelObject::Exists(const SQChar *key) const +{ + if(GetSlot(key)) { + sq_pop(SquirrelVM::_VM,2); + return TRUE; + } else { + sq_pop(SquirrelVM::_VM,1); + return FALSE; + } +} +//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +BOOL SquirrelObject::GetSlot(const SQChar *name) const +{ + sq_pushobject(SquirrelVM::_VM,_o); + sq_pushstring(SquirrelVM::_VM,name,-1); + if(SQ_SUCCEEDED(sq_get(SquirrelVM::_VM,-2))) { + return TRUE; + } + + return FALSE; +} + +BOOL SquirrelObject::RawGetSlot(const SQChar *name) const { + sq_pushobject(SquirrelVM::_VM,_o); + sq_pushstring(SquirrelVM::_VM,name,-1); + if(SQ_SUCCEEDED(sq_rawget(SquirrelVM::_VM,-2))) { + return TRUE; + } + return FALSE; +} // SquirrelObject::RawGetSlot + +SquirrelObject SquirrelObject::GetValue(const SQChar *key)const +{ + SquirrelObject ret; + if(GetSlot(key)) { + ret.AttachToStackObject(-1); + sq_pop(SquirrelVM::_VM,1); + } + sq_pop(SquirrelVM::_VM,1); + return ret; +} + +FLOAT SquirrelObject::GetFloat(const SQChar *key) const +{ + FLOAT ret = 0.0f; + if(GetSlot(key)) { + sq_getfloat(SquirrelVM::_VM,-1,&ret); + sq_pop(SquirrelVM::_VM,1); + } + sq_pop(SquirrelVM::_VM,1); + return ret; +} + +INT SquirrelObject::GetInt(const SQChar *key) const +{ + INT ret = 0; + if(GetSlot(key)) { + sq_getinteger(SquirrelVM::_VM,-1,&ret); + sq_pop(SquirrelVM::_VM,1); + } + sq_pop(SquirrelVM::_VM,1); + return ret; +} + +const SQChar *SquirrelObject::GetString(const SQChar *key) const +{ + const SQChar *ret = NULL; + if(GetSlot(key)) { + sq_getstring(SquirrelVM::_VM,-1,&ret); + sq_pop(SquirrelVM::_VM,1); + } + sq_pop(SquirrelVM::_VM,1); + return ret; +} + +bool SquirrelObject::GetBool(const SQChar *key) const +{ + SQBool ret = FALSE; + if(GetSlot(key)) { + sq_getbool(SquirrelVM::_VM,-1,&ret); + sq_pop(SquirrelVM::_VM,1); + } + sq_pop(SquirrelVM::_VM,1); + return ret?true:false; +} + +SQUserPointer SquirrelObject::GetInstanceUP(SQUserPointer tag) const +{ + SQUserPointer up; + sq_pushobject(SquirrelVM::_VM,_o); + if (SQ_FAILED(sq_getinstanceup(SquirrelVM::_VM,-1,(SQUserPointer*)&up,tag))) { + sq_reseterror(SquirrelVM::_VM); + up = NULL; + } // if + sq_pop(SquirrelVM::_VM,1); + return up; +} + +BOOL SquirrelObject::SetInstanceUP(SQUserPointer up) +{ + if(!sq_isinstance(_o)) return FALSE; + sq_pushobject(SquirrelVM::_VM,_o); + sq_setinstanceup(SquirrelVM::_VM,-1,up); + sq_pop(SquirrelVM::_VM,1); + return TRUE; +} + +SquirrelObject SquirrelObject::GetAttributes(const SQChar *key) +{ + SquirrelObject ret; + int top = sq_gettop(SquirrelVM::_VM); + sq_pushobject(SquirrelVM::_VM,_o); + if(key) + sq_pushstring(SquirrelVM::_VM,key,-1); + else + sq_pushnull(SquirrelVM::_VM); + if(SQ_SUCCEEDED(sq_getattributes(SquirrelVM::_VM,-2))) { + ret.AttachToStackObject(-1); + } + sq_settop(SquirrelVM::_VM,top); + return ret; +} + +BOOL SquirrelObject::BeginIteration() +{ + if(!sq_istable(_o) && !sq_isarray(_o) && !sq_isclass(_o)) + return FALSE; + sq_pushobject(SquirrelVM::_VM,_o); + sq_pushnull(SquirrelVM::_VM); + return TRUE; +} + +BOOL SquirrelObject::Next(SquirrelObject &key,SquirrelObject &val) +{ + if(SQ_SUCCEEDED(sq_next(SquirrelVM::_VM,-2))) { + key.AttachToStackObject(-2); + val.AttachToStackObject(-1); + sq_pop(SquirrelVM::_VM,2); + return TRUE; + } + return FALSE; +} + +BOOL SquirrelObject::GetTypeTag(SQUserPointer * typeTag) { + if (SQ_SUCCEEDED(sq_getobjtypetag(&_o,typeTag))) { + return TRUE; + } // if + return FALSE; +} // SquirrelObject::GetTypeTag + +const SQChar * SquirrelObject::GetTypeName(const SQChar * key) { +#if 1 + // This version will work even if SQ_SUPPORT_INSTANCE_TYPE_INFO is not enabled. + SqPlus::ScriptStringVar256 varNameTag; + SqPlus::getVarNameTag(varNameTag,sizeof(varNameTag),key); + SQUserPointer data=0; + if (!RawGetUserData(varNameTag,&data)) { + return NULL; + } // if + SqPlus::VarRefPtr vr = (SqPlus::VarRefPtr)data; + return vr->varType->GetTypeName(); +#else // This version will only work if SQ_SUPPORT_INSTANCE_TYPE_INFO is enabled. + SquirrelObject so = GetValue(key); + if (so.IsNull()) return NULL; + return so.GetTypeName(); +#endif +} // SquirrelObject::GetTypeName + +const SQChar * SquirrelObject::GetTypeName(INT key) { + SquirrelObject so = GetValue(key); + if (so.IsNull()) return NULL; + return so.GetTypeName(); +} // SquirrelObject::GetTypeName + +const SQChar * SquirrelObject::GetTypeName(void) { + SQUserPointer typeTag=NULL; + if (SQ_SUCCEEDED(sq_getobjtypetag(&_o,&typeTag))) { + SquirrelObject typeTable = SquirrelVM::GetRootTable().GetValue(SQ_PLUS_TYPE_TABLE); + if (typeTable.IsNull()) { + return NULL; // Not compiled with SQ_SUPPORT_INSTANCE_TYPE_INFO enabled. + } // if + return typeTable.GetString(INT((size_t)typeTag)); + } // if + return NULL; +} // SquirrelObject::GetTypeName + +SquirrelObject SquirrelObject::GetBase(void) +{ + SquirrelObject ret; + sq_pushobject(SquirrelVM::_VM,_o); + sq_getbase(SquirrelVM::_VM,-1); + ret.AttachToStackObject(-1); + sq_pop(SquirrelVM::_VM,2); + + return ret; +} + +const SQChar* SquirrelObject::ToString() +{ + return sq_objtostring(&_o); +} + +SQInteger SquirrelObject::ToInteger() +{ + return sq_objtointeger(&_o); +} + +SQFloat SquirrelObject::ToFloat() +{ + return sq_objtofloat(&_o); +} + +bool SquirrelObject::ToBool() +{ + //<> + return _o._unVal.nInteger?true:false; +} + +void SquirrelObject::EndIteration() +{ + sq_pop(SquirrelVM::_VM,2); +} + diff --git a/squirrel_3_0_1_stable/sqplus/SquirrelObject.h b/squirrel_3_0_1_stable/sqplus/SquirrelObject.h new file mode 100644 index 000000000..647410a74 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SquirrelObject.h @@ -0,0 +1,256 @@ +#ifndef _SQUIRREL_OBJECT_H_ +#define _SQUIRREL_OBJECT_H_ + +class SquirrelObject +{ + friend class SquirrelVM; + +public: + SquirrelObject(); + virtual ~SquirrelObject(); + SquirrelObject(const SquirrelObject & o); + SquirrelObject(HSQOBJECT o); + +#if 1 + template + SquirrelObject(const _ty & val) { sq_resetobject(&_o); Set((_ty &)val); } // Cast away const to avoid compiler SqPlus::Push() match issue. + template + SquirrelObject(_ty & val) { sq_resetobject(&_o); Set(val); } + template + SquirrelObject(_ty * val) { sq_resetobject(&_o); SetByValue(val); } // Set() would also be OK here. SetByValue() to save potential compiler overhead. +#endif + + SquirrelObject & operator = (HSQOBJECT ho); + SquirrelObject & operator = (const SquirrelObject &o); + SquirrelObject & operator = (int n); + SquirrelObject & operator = (HSQUIRRELVM v); + + operator HSQOBJECT& (){ return _o; } + bool operator ==(const SquirrelObject& o); + bool CompareUserPointer(const SquirrelObject& o); + + void AttachToStackObject(int idx); + void Reset(void); // Release (any) reference and reset _o. + SquirrelObject Clone(); + BOOL SetValue(const SquirrelObject &key,const SquirrelObject &val); + + BOOL SetValue(SQInteger key,const SquirrelObject &val); + BOOL SetValue(INT key,bool b); // Compiler treats SQBool as INT. + BOOL SetValue(INT key,INT n); + BOOL SetValue(INT key,FLOAT f); + BOOL SetValue(INT key,const SQChar *s); + + BOOL SetValue(const SQChar *key,const SquirrelObject &val); + BOOL SetValue(const SQChar *key,bool b); + BOOL SetValue(const SQChar *key,INT n); + BOOL SetValue(const SQChar *key,FLOAT f); + BOOL SetValue(const SQChar *key,const SQChar *s); + + BOOL SetUserPointer(const SQChar * key,SQUserPointer up); + SQUserPointer GetUserPointer(const SQChar * key); + BOOL SetUserPointer(INT key,SQUserPointer up); + SQUserPointer GetUserPointer(INT key); + + BOOL NewUserData(const SQChar * key,INT size,SQUserPointer * typetag=0); + BOOL GetUserData(const SQChar * key,SQUserPointer * data,SQUserPointer * typetag=0); + BOOL RawGetUserData(const SQChar * key,SQUserPointer * data,SQUserPointer * typetag=0); + + // === BEGIN Arrays === + + BOOL ArrayResize(INT newSize); + BOOL ArrayExtend(INT amount); + BOOL ArrayReverse(void); + SquirrelObject ArrayPop(SQBool returnPoppedVal=SQTrue); + + void ArrayAppend(const SquirrelObject &o); + + template + BOOL ArrayAppend(T item); + + // === END Arrays === + + BOOL SetInstanceUP(SQUserPointer up); + BOOL IsNull() const; + int IsNumeric() const; + int Len() const; + BOOL SetDelegate(SquirrelObject &obj); + SquirrelObject GetDelegate(); + const SQChar* ToString(); + bool ToBool(); + SQInteger ToInteger(); + SQFloat ToFloat(); + SQUserPointer GetInstanceUP(SQUserPointer tag) const; + SquirrelObject GetValue(const SQChar *key) const; + BOOL Exists(const SQChar *key) const; + FLOAT GetFloat(const SQChar *key) const; + INT GetInt(const SQChar *key) const; + const SQChar *GetString(const SQChar *key) const; + bool GetBool(const SQChar *key) const; + SquirrelObject GetValue(INT key) const; + FLOAT GetFloat(INT key) const; + INT GetInt(INT key) const; + const SQChar *GetString(INT key) const; + bool GetBool(INT key) const; + SquirrelObject GetAttributes(const SQChar *key = NULL); + SQObjectType GetType(); + HSQOBJECT & GetObjectHandle() const {return *(HSQOBJECT*)&_o;} + BOOL BeginIteration(); + BOOL Next(SquirrelObject &key,SquirrelObject &value); + void EndIteration(); + + BOOL GetTypeTag(SQUserPointer * typeTag); + + // === Get the type name of item/object through string key in a table or class. Returns NULL if the type name is not set (not an SqPlus registered type). + const SQChar * GetTypeName(const SQChar * key); + // === Get the type name of item/object through INT key in a table or class. Returns NULL if the type name is not set (not an SqPlus registered type). + const SQChar * GetTypeName(INT key); + // === Get the type name of this object, else return NULL if not an SqPlus registered type. + const SQChar * GetTypeName(void); + + // === Return base class of object using sq_getbase() === + SquirrelObject GetBase(); + + // === BEGIN code suggestion from the Wiki === + // Get any bound type from this SquirrelObject. Note that Squirrel's handling of references and pointers still holds here. + template + _ty Get(void); + + // Set any bound type to this SquirrelObject. Note that Squirrel's handling of references and pointers still holds here. + template + SquirrelObject SetByValue(_ty val); // classes/structs should be passed by ref (below) to avoid an extra copy. + + // Set any bound type to this SquirrelObject. Note that Squirrel's handling of references and pointers still holds here. + template + SquirrelObject &Set(_ty & val); + + // === END code suggestion from the Wiki === + +private: + BOOL GetSlot(const SQChar *name) const; + BOOL RawGetSlot(const SQChar *name) const; + BOOL GetSlot(INT key) const; + HSQOBJECT _o; +}; + +struct StackHandler { + StackHandler(HSQUIRRELVM v) { + _top = sq_gettop(v); + this->v = v; + } + SQFloat GetFloat(int idx) { + SQFloat x = 0.0f; + if(idx > 0 && idx <= _top) { + sq_getfloat(v,idx,&x); + } + return x; + } + SQInteger GetInt(int idx) { + SQInteger x = 0; + if(idx > 0 && idx <= _top) { + sq_getinteger(v,idx,&x); + } + return x; + } + HSQOBJECT GetObjectHandle(int idx) { + HSQOBJECT x; + if(idx > 0 && idx <= _top) { + sq_resetobject(&x); + sq_getstackobj(v,idx,&x); + } + return x; + } + const SQChar *GetString(int idx) + { + const SQChar *x = NULL; + if(idx > 0 && idx <= _top) { + sq_getstring(v,idx,&x); + } + return x; + } + SQUserPointer GetUserPointer(int idx) + { + SQUserPointer x = 0; + if(idx > 0 && idx <= _top) { + sq_getuserpointer(v,idx,&x); + } + return x; + } + SQUserPointer GetInstanceUp(int idx,SQUserPointer tag) + { + SQUserPointer self; + if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer*)&self,tag))) + return NULL; + return self; + } + SQUserPointer GetUserData(int idx,SQUserPointer tag=0) + { + SQUserPointer otag; + SQUserPointer up; + if(idx > 0 && idx <= _top) { + if(SQ_SUCCEEDED(sq_getuserdata(v,idx,&up,&otag))) { + if(tag == otag) + return up; + } + } + return NULL; + } + BOOL GetBool(int idx) + { + SQBool ret; + if(idx > 0 && idx <= _top) { + if(SQ_SUCCEEDED(sq_getbool(v,idx,&ret))) + return ret; + } + return FALSE; + } + int GetType(int idx) + { + if(idx > 0 && idx <= _top) { + return sq_gettype(v,idx); + } + return -1; + } + + int GetParamCount() { + return _top; + } + int Return(const SQChar *s) + { + sq_pushstring(v,s,-1); + return 1; + } + int Return(FLOAT f) + { + sq_pushfloat(v,f); + return 1; + } + int Return(INT i) + { + sq_pushinteger(v,i); + return 1; + } + int Return(bool b) + { + sq_pushbool(v,b); + return 1; + } + int Return(SQUserPointer p) { + sq_pushuserpointer(v,p); + return 1; + } + int Return(SquirrelObject &o) + { + sq_pushobject(v,o.GetObjectHandle()); + return 1; + } + int Return() { return 0; } + int ThrowError(const SQChar *error) { + return sq_throwerror(v,error); + } + HSQUIRRELVM GetVMPtr() { return v; } +private: + int _top; + HSQUIRRELVM v; +}; + +#endif //_SQUIRREL_OBJECT_H_ diff --git a/squirrel_3_0_1_stable/sqplus/SquirrelVM.cpp b/squirrel_3_0_1_stable/sqplus/SquirrelVM.cpp new file mode 100644 index 000000000..2d506d700 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SquirrelVM.cpp @@ -0,0 +1,505 @@ +#include +#include +#include + +#define _DEBUG_DUMP + +#include "sqplus.h" + +#include +#include +#include +#include +#include +#include + + +HSQUIRRELVM SquirrelVM::_VM; +bool SquirrelVM::_no_vm_ref; +int SquirrelVM::_CallState = -1; +SquirrelObject* SquirrelVM::_root; +HSQUIRRELVM SquirrelVM::_sandboxVM; +SquirrelObject SquirrelVM::_vm; + + +// Helper struct to keep track of all SQSharedState:s created by SquirrelVM. +#include "../squirrel/sqpcheader.h" +#include "../squirrel/sqvm.h" +struct SQSharedStateNode { + SQSharedStateNode( SQSharedState* ps ); + ~SQSharedStateNode( ); + SQSharedState* m_ps; + SQSharedStateNode* m_nxt; +}; + +// Linked list of shared states +static SQSharedStateNode* g_sqss_fst; + +SQSharedStateNode::SQSharedStateNode( SQSharedState* ps ) : m_ps(ps), m_nxt(g_sqss_fst) { + g_sqss_fst = this; +} + +SQSharedStateNode::~SQSharedStateNode() { + if(m_ps) sq_delete(m_ps,SQSharedState); + delete m_nxt; +} + +static struct SquirrelVM_ModConstr { + ~SquirrelVM_ModConstr(){ + // Delete any shared states we created + delete g_sqss_fst; + g_sqss_fst = NULL; + } +} g_squirrelvm_mod_constr; + + + +SquirrelError::SquirrelError() +{ + const SQChar *s; + sq_getlasterror(SquirrelVM::_VM); + sq_getstring(SquirrelVM::_VM,-1,&s); + if(s) { + desc = s; + } + else { + desc = _SC("unknown error"); + } +} + + +SquirrelVMSys::~SquirrelVMSys() { + // Must take care to release object with the 'ref' VM + PushRefVM( _vm.GetObjectHandle()._unVal.pThread ); + _vm.Reset(); + PopRefVM(); +} + +void SquirrelVMSys::Set( HSQUIRRELVM v ){ + // Must take care to release object with the 'ref' VM + PushRefVM( v ); + _vm = v; + PopRefVM( ); +} + +void SquirrelVMSys::Set( const SquirrelObject& ov ){ + assert( ov.GetObjectHandle()._type==OT_THREAD ); + // Must take care to release object with the 'ref' VM + PushRefVM( ov.GetObjectHandle()._unVal.pThread ); + _vm = ov; + PopRefVM( ); +} + +SquirrelVMSys::operator HSQUIRRELVM () const { + // Avoid const madness + SquirrelObject *pvm = (SquirrelObject*)&_vm; + assert( pvm->GetObjectHandle()._type==OT_THREAD ); + return pvm->GetObjectHandle()._unVal.pThread; +} + + +// When doing a SquirrelObject assignment, a reference using the current +// VM is done. +HSQUIRRELVM g_VM_pushed; +void SquirrelVMSys::PushRefVM( HSQUIRRELVM v ){ + assert( !g_VM_pushed ); + g_VM_pushed = SquirrelVM::_VM; + SquirrelVM::_VM = v; +} + +void SquirrelVMSys::PopRefVM( ){ + SquirrelVM::_VM = g_VM_pushed; + g_VM_pushed = NULL; +} + + +bool SquirrelVM::Init( HSQUIRRELVM v ){ + if( v && v==_VM ) + return true; + + // Do we have a previous state? + Release( ); + + bool created_new = false; + if( !v ){ + // Create a new VM - a root VM with new SharedState. + v = sq_open(1024); + if( !v ) return false; + // Store the associated shared state in a linked list. The state will only + // be destroyed at app shutdown. Often that is fine, but if using many + // VM:s briefly, this allocation is not optimal. + new SQSharedStateNode( _ss(v) ); + created_new = true; + sq_setprintfunc(v,SquirrelVM::PrintFunc, SquirrelVM::PrintFunc); + sq_pushroottable(v); + sqstd_register_iolib(v); + sqstd_register_bloblib(v); + sqstd_register_mathlib(v); + sqstd_register_stringlib(v); +#ifdef SQPLUS_SQUIRRELVM_WITH_SYSTEMLIB + sqstd_register_systemlib(v); +#endif + sqstd_seterrorhandlers(v); + //TODO error handler, compiler error handler + sq_pop(v,1); + } + + // After this we hold a ref + _no_vm_ref = false; + _VM = v; + _vm = v; + + // In the case where Squirrel is ref counted we currently + // hold two references to the VM (since it is created with + // a ref count of 1). In the GC case, it is outside of the + // chain of valid objects, so it is not referenced. Compensate + // in ref counted case. + if( created_new ) + DropVMRefIfRefCounted( v ); + + return true; +} + +bool SquirrelVM::InitNoRef( HSQUIRRELVM v ){ + if( v && v==_VM ) + return true; + + // Do we have a previous state? + Release( ); + + // Set pointer to this VM, without referencing it + _no_vm_ref = true; + _VM = v; + + return true; +} + +/* +void SquirrelVM::Init( HSQUIRRELVM v ) +{ + if( v && v==_VM ) { + return; + } + + // Do we have a previous state? + Release(); + + if( !v ){ + // Create a new VM and own it + _VM = sq_open(1024); + sq_setprintfunc(_VM,SquirrelVM::PrintFunc); + sq_pushroottable(_VM); + sqstd_register_iolib(_VM); + sqstd_register_bloblib(_VM); + sqstd_register_mathlib(_VM); + sqstd_register_stringlib(_VM); + sqstd_seterrorhandlers(_VM); + //TODO error handler, compiler error handler + sq_pop(_VM,1); + } + else { + _VM = v; + } + // After this we hold a ref + _vm = _VM; +} +*/ + +void SquirrelVM::Release() { + // Release root table object if we have one + if( _root ){ + delete _root; + _root = NULL; + } + + // Release our ref on VM - if we should + if( !_no_vm_ref ) + _vm.Reset(); + + _VM = NULL; +} + +void SquirrelVM::DropVMRefIfRefCounted( HSQUIRRELVM v ){ +#ifdef NO_GARBAGE_COLLECTOR + if( v ){ + SQObject t; + t._unVal.pThread = v; + t._type = OT_THREAD; + sq_release( v, &t ); + } +#endif +} + +BOOL SquirrelVM::Update() +{ + //update remote debugger + return TRUE; +} + +void SquirrelVM::PrintFunc(HSQUIRRELVM v,const SQChar* s,...) +{ + static SQChar temp[2048]; + va_list vl; + va_start(vl, s); + scvsprintf( temp,s, vl); + SCPUTS(temp); + va_end(vl); +} + +SquirrelObject SquirrelVM::CompileScript(const SQChar *s) +{ + SquirrelObject ret; + if(SQ_SUCCEEDED(sqstd_loadfile(_VM,s,1))) { + ret.AttachToStackObject(-1); + sq_pop(_VM,1); + return ret; + } + throw SquirrelError(); +} + +SquirrelObject SquirrelVM::CompileBuffer(const SQChar *s,const SQChar * debugInfo) +{ + SquirrelObject ret; + if(SQ_SUCCEEDED(sq_compilebuffer(_VM,s,(int)scstrlen(s)*sizeof(SQChar),debugInfo,1))) { + ret.AttachToStackObject(-1); + sq_pop(_VM,1); + return ret; + } + throw SquirrelError(); +} + +SquirrelObject SquirrelVM::RunScript(const SquirrelObject &o,SquirrelObject *_this) +{ + SquirrelObject ret; + sq_pushobject(_VM,o._o); + if(_this) { + sq_pushobject(_VM,_this->_o); + } + else { + sq_pushroottable(_VM); + } + if(SQ_SUCCEEDED(sq_call(_VM,1,SQTrue,SQ_CALL_RAISE_ERROR))) { + ret.AttachToStackObject(-1); + sq_pop(_VM,2); + return ret; + } + sq_pop(_VM,1); + throw SquirrelError(); + +} + + +BOOL SquirrelVM::BeginCall(const SquirrelObject &func) +{ + if(_CallState != -1) + return FALSE; + _CallState = 1; + sq_pushobject(_VM,func._o); + sq_pushroottable(_VM); + return TRUE; +} + +BOOL SquirrelVM::BeginCall(const SquirrelObject &func,SquirrelObject &_this) +{ + if(_CallState != -1) + throw SquirrelError(_SC("call already initialized")); + _CallState = 1; + sq_pushobject(_VM,func._o); + sq_pushobject(_VM,_this._o); + return TRUE; +} + +#define _CHECK_CALL_STATE \ + if(_CallState == -1) \ + throw SquirrelError(_SC("call not initialized")); + +void SquirrelVM::PushParam(const SquirrelObject &o) +{ + _CHECK_CALL_STATE + sq_pushobject(_VM,o._o); + _CallState++; +} + +void SquirrelVM::PushParam(const SQChar *s) +{ + _CHECK_CALL_STATE + sq_pushstring(_VM,s,-1); + _CallState++; +} + +void SquirrelVM::PushParam(SQInteger n) +{ + _CHECK_CALL_STATE + sq_pushinteger(_VM,n); + _CallState++; +} + +void SquirrelVM::PushParam(SQFloat f) +{ + _CHECK_CALL_STATE + sq_pushfloat(_VM,f); + _CallState++; +} + +void SquirrelVM::PushParamNull() +{ + _CHECK_CALL_STATE + sq_pushnull(_VM); + _CallState++; +} + +void SquirrelVM::PushParam(SQUserPointer up) +{ + _CHECK_CALL_STATE + sq_pushuserpointer(_VM,up); + _CallState++; +} + +SquirrelObject SquirrelVM::EndCall() +{ + SquirrelObject ret; + if(_CallState >= 0) { + int oldtop = sq_gettop(_VM); + int nparams = _CallState; + _CallState = -1; + if(SQ_SUCCEEDED(sq_call(_VM,nparams,SQTrue,SQ_CALL_RAISE_ERROR))) { + ret.AttachToStackObject(-1); + sq_pop(_VM,2); + }else { + sq_settop(_VM,oldtop-(nparams+1)); + throw SquirrelError(); + } + + } + return ret; +} + +SquirrelObject SquirrelVM::CreateInstance(SquirrelObject &oclass) +{ + SquirrelObject ret; + int oldtop = sq_gettop(_VM); + sq_pushobject(_VM,oclass._o); + if(SQ_FAILED(sq_createinstance(_VM,-1))) { + sq_settop(_VM,oldtop); + throw SquirrelError(); + } + ret.AttachToStackObject(-1); + sq_pop(_VM,2); + return ret; +} + +SquirrelObject SquirrelVM::CreateTable() +{ + SquirrelObject ret; + sq_newtable(_VM); + ret.AttachToStackObject(-1); + sq_pop(_VM,1); + return ret; +} + +SquirrelObject SquirrelVM::CreateString(const SQChar *s) +{ + SquirrelObject ret; + sq_pushstring(_VM,s,-1); + ret.AttachToStackObject(-1); + sq_pop(_VM,1); + return ret; +} + + +SquirrelObject SquirrelVM::CreateArray(int size) +{ + SquirrelObject ret; + sq_newarray(_VM,size); + ret.AttachToStackObject(-1); + sq_pop(_VM,1); + return ret; +} + +SquirrelObject SquirrelVM::CreateFunction(SQFUNCTION func) +{ + SquirrelObject ret; + sq_newclosure(_VM,func,0); + ret.AttachToStackObject(-1); + sq_pop(_VM,1); + return ret; +} + +SquirrelObject SquirrelVM::CreateUserData(int size) { + SquirrelObject ret; + sq_newuserdata(_VM,size); + ret.AttachToStackObject(-1); + sq_pop(_VM,1); + return ret; +} + +const SquirrelObject &SquirrelVM::GetRootTable() +{ + if( !_root ){ + sq_pushroottable(_VM); + _root = new SquirrelObject(); + _root->AttachToStackObject(-1); + sq_pop(_VM,1); + } + return *_root; +} + +void SquirrelVM::PushRootTable(void) { + sq_pushroottable(_VM); +} // SquirrelVM::PushRootTable + +// Creates a function in the table or class currently on the stack. +//void CreateFunction(HSQUIRRELVM v,const SQChar * scriptFuncName,SQFUNCTION func,int numParams=0,const SQChar * typeMask=0) { +SquirrelObject SquirrelVM::CreateFunction(SQFUNCTION func,const SQChar * scriptFuncName,const SQChar * typeMask) { + sq_pushstring(_VM,scriptFuncName,-1); + sq_newclosure(_VM,func,0); + SquirrelObject ret; + ret.AttachToStackObject(-1); + SQChar tm[64]; + SQChar * ptm = tm; + int numParams = SQ_MATCHTYPEMASKSTRING; + if (typeMask) { + if (typeMask[0] == '*') { + ptm = 0; // Variable args: don't check parameters. + numParams = 0; // Clear SQ_MATCHTYPEMASKSTRING (does not mean match 0 params. See sq_setparamscheck()). + } else { + if (SCSNPRINTF(tm,sizeof(tm),_SC("t|y|x%s"),typeMask) < 0) { +// sq_throwerror(_VM,_SC("CreateFunction: typeMask string too long.")); + throw SquirrelError(_SC("CreateFunction: typeMask string too long.")); + } // if + } // if + } else { // Need to check object type on stack: table, class, instance, etc. + SCSNPRINTF(tm,sizeof(tm),_SC("%s"),_SC("t|y|x")); // table, class, instance. +// tm[0] = 't'; +// tm[1] = 0; + } // if +#if 0 + sq_setparamscheck(_VM,numParams+1,ptm); // Parameters are table+args (thus, the +1). +#else + if (ptm) { + sq_setparamscheck(_VM,numParams,ptm); // Determine arg count from type string. + } // if +#endif +#ifdef _DEBUG + sq_setnativeclosurename(_VM,-1,scriptFuncName); // For debugging only. +#endif + sq_createslot(_VM,-3); // Create slot in table or class (assigning function to slot at scriptNameFunc). + return ret; +} // SquirrelVM::CreateFunction + +SquirrelObject SquirrelVM::CreateFunction(SquirrelObject & so,SQFUNCTION func,const SQChar * scriptFuncName,const SQChar * typeMask) { + PushObject(so); + SquirrelObject ret = CreateFunction(func,scriptFuncName,typeMask); + Pop(1); + return ret; +} // SquirrelVM::CreateFunction + +// Create a Global function on the root table. +//void CreateFunctionGlobal(HSQUIRRELVM v,const SQChar * scriptFuncName,SQFUNCTION func,int numParams=0,const SQChar * typeMask=0) { +SquirrelObject SquirrelVM::CreateFunctionGlobal(SQFUNCTION func,const SQChar * scriptFuncName,const SQChar * typeMask) { + PushRootTable(); // Push root table. + // CreateFunction(scriptFuncName,func,numParams,typeMask); + SquirrelObject ret = CreateFunction(func,scriptFuncName,typeMask); + Pop(1); // Pop root table. + return ret; +} // SquirrelVM::CreateFunctionGlobal diff --git a/squirrel_3_0_1_stable/sqplus/SquirrelVM.h b/squirrel_3_0_1_stable/sqplus/SquirrelVM.h new file mode 100644 index 000000000..ee66a2b76 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SquirrelVM.h @@ -0,0 +1,179 @@ +#ifndef _SQUIRREL_VM_H_ +#define _SQUIRREL_VM_H_ + +#include "SquirrelObject.h" + +struct SquirrelError { + SquirrelError(); + SquirrelError(const SQChar* s):desc(s){} + const SQChar *desc; +}; + +// This class can hold a reference to a SquirrelVM. It keeps a Squirrel ref +// to the VM to protect it from being deleted while held. +struct SquirrelVMSys { + SquirrelVMSys() { } + ~SquirrelVMSys(); + + void Set( HSQUIRRELVM v ); + void Set( const SquirrelObject& ov ); + void Reset( ){ _vm.Reset(); } + + SquirrelVMSys& operator = (HSQUIRRELVM v){ Set(v); return *this; } + operator HSQUIRRELVM () const; + +protected: + void PushRefVM(HSQUIRRELVM v); + void PopRefVM(); + SquirrelObject _vm; + friend class SquirrelVM; +}; + +// Notes on creating / destroying SquirrelVM:s: +// +// VM:s created through sq_open are special since they create a new +// SQSharedState. That shared state is later shared by any new thread +// or friend VM. sq_close can be used for closing VM:s created through +// sq_open (but not for friend VMs). +// +// Using squirrel references in SquirrelVMSys and SquirrelVM, one must +// make sure that these are all reset if one calls sq_close manually. +// +// When there are no more references to a VM, it is destroyed automatically, +// but the shared state is not! For VM:s created by SquirrelVM, it keeps +// a list of shared states it has created and will destroy them all on +// app shutdown. + +class SquirrelVM { + friend class SquirrelObject; + friend struct SquirrelError; + friend struct SquirrelVMSys; + +public: + // If a VM is passed as arg here, Init will not alter it. Otherwise + // a new VM is created and initialized. A squirrel reference is kept + // while it is the current VM. + static bool Init( HSQUIRRELVM v=NULL ); + + // Initialize with an externally created VM, without adding a ref + // on it. NOTE: This may not be compatible with Set/GetVMSys as + // we're just working with raw pointers here. + static bool InitNoRef( HSQUIRRELVM v ); + static BOOL IsInitialized(){return _VM == NULL?FALSE:TRUE;} + + static void Release(); // Release ref on VM and reset VM pointer + static void Shutdown(){ Release(); } + static void AppFinalShutdown(); // Call when finally shutting down app + + static BOOL Update(); //debugger and maybe GC later + + static SquirrelObject CompileScript(const SQChar *s); + static SquirrelObject CompileBuffer(const SQChar *s,const SQChar * debugInfo=_SC("console_buffer")); + static SquirrelObject RunScript(const SquirrelObject &o,SquirrelObject *_this = NULL); + + static void PrintFunc(HSQUIRRELVM v,const SQChar* s,...); + + static BOOL BeginCall(const SquirrelObject &func); + static BOOL BeginCall(const SquirrelObject &func,SquirrelObject &_this); + + static void PushParam(const SquirrelObject &o); + static void PushParam(const SQChar *s); + static void PushParam(SQInteger n); + static void PushParam(SQFloat f); + static void PushParam(SQUserPointer up); + static void PushParamNull(); + + static SquirrelObject EndCall(); + static SquirrelObject CreateString(const SQChar *s); + static SquirrelObject CreateTable(); + static SquirrelObject CreateArray(int size); + static SquirrelObject CreateInstance(SquirrelObject &oclass); // oclass is an existing class. Create an 'instance' (OT_INSTANCE) of oclass. + static SquirrelObject CreateFunction(SQFUNCTION func); + static SquirrelObject CreateUserData(int size); + + static const SquirrelObject &GetRootTable(); + static HSQUIRRELVM GetVMPtr() { return _VM; } + + // The sandbox VM ptr is one which cannot access functions bound with + // SqPlus. It is suitable for running non-trusted scripts that can only + // access basic functionality. + static void SetSandboxVMPtr(HSQUIRRELVM v) { + _sandboxVM = v; + } // SetSandboxVMPtr + + static HSQUIRRELVM GetSandboxVMPtr() { + return _sandboxVM; + } // GetSandboxVMPtr + + static void GetVMSys(SquirrelVMSys & vmSys) { + vmSys.Set( _vm ); + } // GetVMSys + + static void SetVMSys(const SquirrelVMSys & vmSys) { + Release(); + HSQUIRRELVM v = (HSQUIRRELVM)vmSys; + if( v ) + Init( v ); + } // SetVMSys + + static void PushValue(INT val) { + sq_pushinteger(_VM,val); + } // PushValue + static void PushValue(FLOAT val) { + sq_pushfloat(_VM,val); + } // PushValue + static void PushValue(bool val) { // Compiler treats SQBool as INT. + sq_pushbool(_VM,val); + } // PushValue + static void PushValue(SQChar * val) { + sq_pushstring(_VM,val,-1); + } // PushValue + static void PushValue(SQUserPointer val) { + sq_pushuserpointer(_VM,val); + } // PushValue + static void PushValue(const SQChar * val) { + sq_pushstring(_VM,val,-1); + } // PushValue + static void PushObject(SquirrelObject & so) { + sq_pushobject(_VM,so._o); + } // PushObject + static void Pop(SQInteger nelemstopop) { + sq_pop(_VM,nelemstopop); + } // Pop + + static void PushRootTable(void); + + // Create/bind a function on the table currently on the stack. + static SquirrelObject CreateFunction(SQFUNCTION func,const SQChar * scriptFuncName,const SQChar * typeMask=0); + // Create/bind a function on the table so. typeMask: standard Squirrel types plus: no typemask means no args, "*" means any type of args. + static SquirrelObject CreateFunction(SquirrelObject & so,SQFUNCTION func,const SQChar * scriptFuncName,const SQChar * typeMask=0); + // Create/bind a function to the root table. typeMask: standard Squirrel types plus: no typemask means no args, "*" means any type of args. + static SquirrelObject CreateFunctionGlobal(SQFUNCTION func,const SQChar * scriptFuncName,const SQChar * typeMask=0); + + // This is a helper to correct a difference in referncing new VM:s in + // ref counted versus garbage collected modes. NOTE: Only use after creating + // a VM with: 1 - sq_open() 2 - Creating a ref to the VM (SquirrelObject) + static void DropVMRefIfRefCounted( HSQUIRRELVM v ); + + +private: + static SquirrelObject _vm; // This is a Squirrel reference to the VM + static HSQUIRRELVM _VM; // The raw C++ pointer + static bool _no_vm_ref; // Set if we only keep the raw C++ pointer and no ref + static int _CallState; + static SquirrelObject * _root; // Cached root table if non NULL + static HSQUIRRELVM _sandboxVM; // The sandbox VM (that cannot use bound functions) +}; + + +template +inline BOOL SquirrelObject::ArrayAppend(T item) { + sq_pushobject(SquirrelVM::_VM,GetObjectHandle()); + SquirrelVM::PushValue(item); + BOOL res = sq_arrayappend(SquirrelVM::_VM,-2) == SQ_OK; + sq_pop(SquirrelVM::_VM,1); + return res; +} // ArrayAppend + +#endif //_SQUIRREL_VM_H_ + diff --git a/squirrel_3_0_1_stable/sqplus/changes.txt b/squirrel_3_0_1_stable/sqplus/changes.txt new file mode 100644 index 000000000..a33f32c2f --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/changes.txt @@ -0,0 +1,359 @@ +2008-07-13 "SQUIRREL2_1_1_sqplus_snapshot_20080713" + + * Released as a snapshot + + +2008-07-06 kawachi + + * Removed testSqPlus2 + + +2008-06-26 arst@users.sf.net + + * SquirrelVM.cpp / SqPlusSetup.h + - Added a new define SQPLUS_SQUIRRELVM_WITH_SYSTEMLIB + (Juggernaut, http://squirrel-lang.org/forums/2585/ShowThread.aspx#2585) + + - Added a new function: + SQClassDefBase::scriptVar(const SQChar* name, int ival, + SQBool static_var=SQFalse) + + It allows for creating either static or ordinary Squirrel class + members from C++ source code. Versions for int/double/const + SQChar*. + + - SquirrelObject::GetBase() - retrieve base class. + (Juggernaut, http://squirrel-lang.org/forums/2585/ShowThread.aspx#2585) + + +2008-06-14 Kazei + + * Fixed memory leak in overloadConstructor + (http://squirrel-lang.org/forums/thread/2516.aspx) + + +2008-05-10 Neimod + + * Fixed for typesafe scripting + (http://squirrel-lang.org/forums/thread/2478.aspx) + + +2008-05-08 arst@users.sf.net + + * sqplus.h/.cpp + + - SQ_USE_CLASS_INHERITANCE_SIMPLE is a new way of handling class + inheritence in SqPlus, relying on a template scheme (see ClassTypeBase + and ClassType). It doesn't use any memory per instance and should + be a bit faster than previous scheme. SqClassDef has been given + a second template argument to account for this: + + struct SQClassDef ... + + - The name of the class (in SqClassDef) can be filled in by SqPlus now, + if Squirrel class name is same as C++ class name: + + SQClasDef("Troll", "Creature").func(...) => + SQClasDef().func(...) + + - Code to handle class types (names, copy funcs, ID tag, ...) has been + collected in ClassTypeBase and ClassType. + + - A new macro to specify that classes should not be copied with default + C++ method: DECLARE_NONCOPY_TYPE(ClassThatCannotBeCopied). + + - Reworked body of repetetive template functions, Moved to + SqPlusCallTemplates.h. Can be included with different qualifiers + (const, cdecl). + + - Support for cdecl member functions (MSVC specific) through: + + SQPLUS_ENABLE_CDECL_MEMBER_FUNCTIONS + + cdecl functions are compatible across compilers, while thiscall + is not. + + - Generic Push/Pop/Match handlers: SQPLUS_USE_GENERIC_HANDLERS + By default, Push/Get/Match handlers are for a single type. This + adds a fallback level, so that `hierarchy wide' handlers can + be used (define for base class and let all derived classes use + just that). + + - For functions that return a pointer to a temporarary (such as + returning a SQDefCharBuf, a template mapper class: + + Temporary::type + + was added. It can hold a temporary value while finishing a + SquirrelFunction call (before returning to C++). + + - Suppressing horrible warnings from Visual C++ about sprintf and related + functions (_CRT_SECURE_NO_DEPRECATE). + + + * SquirrelVM.h/.cpp + + - Changed SquirrelVM and SquirrelVMSys to make them hold a reference + on a SQVM so that ownership can be shared in a defined way. + + - SquirrelVMSys can be used as before to swap the `active' VM. + Now it holds a ref to a VM so that a VM is closed automatically + when switched out and there are no refs to any longer. (To hold a + VM ref in the application, simply use an instance of SquirrelVMSys). + + - NOTE: A VM created through sq_open() comes out with a reference + count of 1. A VM created with sq_newthread() arrives with a ref + count of 0. SquirrelVM will compensate for this. + + - Possibility to store a `sandbox VM'. This VM is not allowed to + access functions / classes bound with SqPlus and so can run more + untrusted scripts. + + - Hopefully these changes will not break current apps. (Note: creating + and keeping correct refs on SQVM involved some difficulties (with ref- + counting and garbage collected Squirrel). The scheme provided here is + (I hope) a working solution.) + + * SquirrelObject.h/.cpp + + - Added: operator = (HSQOBJECT) + + - From forum: (http://squirrel-lang.org/forums/thread/2506.aspx) + (suggested by auron0) + - Added: operator == (const SquirrelObject& o) + - Added: CompareUserPointer(const SquirrelObject& o) + + * SqPlusUTF8.h / .cpp + + - New files for converting strings in arguments (UTF8 <-> wchar_t) + + - Fix for conversion of UTF8 sequence of length 3+ bytes + + + +2008-02-17 PallavNawani + + * BindVariable of std::string + (http://squirrel-lang.org/forums/2370/ShowThread.aspx) + + +2007-10-14 "SQUIRREL2_1_1_sqplus_snapshot_20071014" + + * Fixed const member function overloading by Tegan + (http://squirrel-lang.org/forums/thread/2160.aspx) + + * Updates for missing inline in DECLARE_INSTANCE_TYPE_NAME + (http://squirrel-lang.org/forums/thread/2156.aspx) + + * Fixed resolution in function overloading + (http://squirrel-lang.org/forums/thread/2179.aspx) + + * Added support for operator overloading suggested by Tegan + (http://squirrel-lang.org/forums/thread/2160.aspx) + + +2007-09-27 "SQUIRREL2_1_1_sqplus_snapshot_20070927" + + * Added ats's extensions : + http://squirrel-lang.org/forums/1/2153/ShowThread.aspx + + - GCC_INLINE_WORKAROUND (problems with inline functions with gcc) + - Set/get for short/char members + - Get for const SQChar* + - DECLARE_ENUM_TYPE - Allows enums to be used as arguments + - Support for more customized Push handlers + - SQPLUS_DISABLE_COPY_INSTANCES (disabling automatic use of copy + constructors) + - Support for automatically generate TypeMasks (a template + solution) on function registration + + +2007-08-25 "SQUIRREL2_1_1_sqplus_snapshot_20070825" + + * Added m0pey's smart pointer support : + http://squirrel-lang.org/forums/thread/1982.aspx + + +2007-01-07 "SQUIRREL2_1_1_sqplus_snapshot_20070701" + + * Fixed `returning a pointer of a derived class' problem with gcc + (http://squirrel-lang.org/forums/thread/1875.aspx) based on + http://wiki.squirrel-lang.org/default.aspx/SquirrelWiki/SqPlusNativeCreatedInstancesWithCorrectAncestry.html + + +2007-06/02 "SQUIRREL2_1_1_sqplus_snapshot_20070602" + + * Fix by Sebastien Frippiat: + http://squirrel-lang.org/forums/thread/507.aspx + + +2007-05-27 "SQUIRREL2_1_1_sqplus_snapshot_20070527" + + * Added sqplus/SqPlusOverload.h for function overloading. See + testSqPlus2unit/test_FunctionOverloading.cpp. + + +2007-03-04 "SQUIRREL2_1_1_sqplus_snapshot_20070304" + + * Fixed compilation problem on g++-3.4.4 (cygwin): + http://squirrel-lang.org/forums/thread/1753.aspx + + +2007-02-25 "SQUIRREL2_1_1_sqplus_snapshot_20070225" + + * Fix by Kamaitati: http://squirrel-lang.org/forums/thread/1748.aspx + + * Modified sqplu.h (SquirrelObject::Set<>()) for gcc + + * Added testSqPlus2unit directory for unit testing + + +2006-10-09- "SQUIRREL2_1_1_sqplus_25" + + * Fixed SqPlusConst.h: + http://squirrel-lang.org/forums/thread/1314.aspx, changed + SquirrelObject Get/Set to default to pass-by-reference, where + pass-by-copy requires extra parameter + + +2006-10-08 "SQUIRREL2_1_1_sqplus_24" + + * Added SQClassDefNoConstructor<>: + http://wiki.squirrel-lang.org/default.aspx/SquirrelWiki/SqPlusWithoutAutoDefaultConstructor.html + (allows binding abstract base classes/pure-virtual-interfaces) + + * Added "Squirrel Set/Get objects" + http://wiki.squirrel-lang.org/default.aspx/SquirrelWiki/SqPlusGetSetObjects.html + + +2006-09-30 "SQUIRREL2_1_1_sqplus_23" + + * Fixed return type for sq_std_string Get() + + +2006-08-21 "SQUIRREL2_1_0_sqplus_22" + + * Merged in Squirrel 2.1.1 Stable + + +2006-08-20 "SQUIRREL2_1_0_sqplus_21" + + * Changed code order to be compatible with GCC 4.1.x. + + * Added jflanglois' suggestion for std::basic_string + + +2006-06-27 "SQUIRREL2_1_0_sqplus_20" + + * Added Katsuaki Kawachi's GetInstance()/Match() changes + (http://www.squirrel-lang.org/forums/962/ShowPost.aspx) + + +2006-02-06 "SQUIRREL2_1_0_sqplus_19" + + * Added VS7.1 make/project files with 71 suffix: can be used + alongside VS8 without directory changes + + * Added optional debug string argument to SquirrelVM::CompileBuffer() + + +2006-05-28 "SQUIRREL2_1_0_sqplus_18" + + * Added Kamaitati's changes: bug fix, C++ style inheritance support, + null instance argument support + + +2006-04-25 "SQUIRREL2_1_0_sqplus_17" + + * Changed SquirrelObject::GetInstanceUP() to return NULL and + clear internal error state on invalid instance type request + + * Added SquirrelObject::GetTypeName(const "SQChar" * key), + SquirrelObject::GetTypeName("INT" key) and + SquirrelObject::GetTypeName(). + + * Added SQ_SUPPORT_INSTANCE_TYPE_INFO compile time option + + * Added missing template arguments (7 argument case) + + * Source changes to support VS7.1 and VS8 compilation (standard and + UNICODE builds) + + * Added Code::Blocks project files + + +2006-03-26 "SQUIRREL2_1_0_sqplus_11" + + * Updated make/build files to VS8 (http://msdn.microsoft.com/vstudio/) + + * Source changes for VS8 compilation + + +2006-03-19 "SQUIRREL2_1_0_sqplus_10" + + * Updated to Squirrel 2.1 + + +2006-02-27 "SQUIRREL2_0_5_sqplus_9" + + * Added Ben's changes to implement DECLARE_INSTANCE_TYPE_NAME + (http://www.squirrel-lang.org/forums/635/ShowPost.aspx) + + +2005-12-22 "SQUIRREL2_0_5_sqplus_8" + + * Added GetVMSys() and SetVMSys() to better support multiple VM's + + +2005-11-21 "SQUIRREL2_0_5_sqplus_7" + + * Added modular support for const member functions. Defining + SQPLUS_CONST_OPT before including sqplus.h enables the added + functionality + + * SqPlus tested on Mac OS-X + + +2005-11-03 "SQUIRREL2_0_5_sqplus_6" + + * Fixed inheritance issue: tables added to classes are not newly + created upon instantiation- they must be cloned during + construction (language design) + + * Reworked projects build settings to better allow building all + projects types: Debug, Release, Debug - Unicode, Release - Unicode + + +2005-11-01 "SQUIRREL2_0_5_sqplus_5" + + * Added Unicode support + + +2005-10-23 "SQUIRREL2_0_5_sqplus_4" + + * Added gcc support: + - Added simple GNU Makefiles for gcc + - Minor code changes for gcc compilation + - Tested on RH Linux gcc 3.2.3, Cygwin gcc 3.4.4, and gcc on Sony PSP + (http://www.squirrel-lang.org/forums/420/ShowPost.aspx#420) + + * Added ClassDef::enumInt() for registering enums as ints + (to replace ClassDef::constant((int)myEnum)) + + +2005-10-14 "SQUIRREL2_0_5_sqplus_3" + + * Added support for SquirrelObject as a function argument and return + value. Tables and arrays can be directly accessed without using + the stack. This also makes it possible to return tables, arrays, + classes, and closures for later use at runtime, saving look-up + overhead + + * Added GetRet() for SquirrelFunction<> to ensure proper stack + behavior + + * Added additional error return info to help with debugging + + * Removed unused code + + diff --git a/squirrel_3_0_1_stable/sqplus/sqplus.cbp b/squirrel_3_0_1_stable/sqplus/sqplus.cbp new file mode 100644 index 000000000..ba10ef105 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/sqplus.cbp @@ -0,0 +1,190 @@ + + + + + + + diff --git a/squirrel_3_0_1_stable/sqplus/sqplus.h b/squirrel_3_0_1_stable/sqplus/sqplus.h new file mode 100644 index 000000000..6116d50ec --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/sqplus.h @@ -0,0 +1,2327 @@ +// SqPlus.h +// Created by John Schultz 9/05/05, major update 10/05/05. +// Template function call design from LuaPlusCD by Joshua C. Jensen, +// inspired by luabind which was inspired by boost::python. +// Const argument, const member functions, and Mac OS-X changes by Simon Michelmore. +// DECLARE_INSTANCE_TYPE_NAME changes by Ben (Project5) from http://www.squirrel-lang.org/forums/. +// Added Kamaitati's changes 5/28/06. +// Free for any use. + +#ifndef _SQ_PLUS_H_ +#define _SQ_PLUS_H_ + +#include +#include + +#ifdef __APPLE__ + #include +#else + #include +#endif +#include +#include +#include // For INT_MAX on GCC + +#include "squirrel.h" // Include to get SQUNICODE setting from here +#ifndef _SC + #error No _SC macro - Usually defined in squirrel.h +#endif +// Provide a _sqT(...) macros also (same as _SC but easier to know its for Squirrel) +#ifndef _sqT + #define _sqT _SC +#endif + +// For backward compatibility, define _T if outside of Windows platform. +// (really, _SC() or _sqT() are better, since that leaves us free to run +// Squirrel in ASCII or wchar_t mode, regardless of the app being built). +#if !defined(_WIN32) && !defined(_WIN64) + #ifndef _T + #define _T _SC + #endif +#endif + + +// A comment about strings. We let squirrel.h determine whether to use +// char or wchar_t strings. So here we follow the define SQUNICODE. This +// opens up for using Unicode system calls on Windows while having the script +// engine in ASCII mode, or vice versa. To enable this, also the macro +// _SC("some string") is used instead of _T("some string"). +// +// To handle the case where function parameters are given in the opposite +// character mode (char if SQChar is wchar_t and vice versa), such strings +// can be converted on the fly to the other mode in the function call, if +// the define SQPLUS_AUTOCONVERT_OTHER_CHAR is set below. Buffers are +// allocated and kept around for the duration of the function call. The +// same applies to returned strings of the opposite type. + +#if defined(_MSC_VER) || defined(__BORLANDC__) + #include + #ifndef SQUNICODE + #define SCSNPRINTF _snprintf + #define SCPUTS puts + #else + #define SCSNPRINTF _snwprintf + #define SCPUTS _putws + #endif + #if defined(_MSC_VER) + #ifndef _CRT_SECURE_NO_DEPRECATE + #define _CRT_SECURE_NO_DEPRECATE // Disable warnings around various sprintf + #endif + #pragma warning(disable: 4996) // When above does not work + #endif +#else + #ifdef SQUNICODE + #define SCSNPRINTF _snwprintf + #define SCPUTS _putws + #include // for snprintf + #else + #define SCSNPRINTF snprintf + #include // for snprintf + #define SCPUTS puts + #endif +#endif + + +#ifndef _WINDEF_ + typedef int BOOL; + typedef int INT; + typedef float FLOAT; + #define TRUE 1 + #define FALSE 0 +#endif + +#if 1 +#define SQ_CALL_RAISE_ERROR SQTrue +#else +#define SQ_CALL_RAISE_ERROR SQFalse +#endif + +#include "SquirrelObject.h" +#include "SquirrelVM.h" +#include "SquirrelBindingsUtils.h" + +// All setup defines have moved to its own file +#include "SqPlusSetup.h" + +#ifdef SQPLUS_AUTOCONVERT_OTHER_CHAR +#define SQPLUS_AUTOCONVERT_MAX_INSTANCES 8 // In argument conversion, don't keep more than this alive +#include "SqPlusOCharBuf.h" +#endif + +#if defined(SQPLUS_SUPPORT_STD_STRING) && defined(SQUNICODE) + #ifdef _MSC_VER + #pragma message("std::string and SQChar as wchar_t is not compatible!") + #else + #warning std::string and SQChar as wchar_t is not compatible! + #endif +#endif + + +namespace SqPlus { + +template struct TypeWrapper {}; +struct SquirrelNull {}; +struct SQNoBaseClass {}; // For scripted classes with no base class (or no scripted base class) + +struct SQAnything { void * anything; }; // Needed for binding pointers to variables (cannot dereference void *). +typedef SQAnything * SQAnythingPtr; +typedef SQChar * SQCharPtr; + +// Helper struct to (sometimes) store a temporary return value as another type. +// Useful when returning const char* and other types that require temp allocation. +// For primitive types, it just maps onto itself. +template +struct Temporary { + typedef T type; +}; + +// References are tricky, but they should just be filtered out usually +template +struct SqAssignableRef { + SqAssignableRef( ) : m_pt(0) { } + void operator = (T& tr){ m_pt=&tr; } + operator T& () { return *m_pt; } + T *m_pt; +}; + +template +struct Temporary { + typedef SqAssignableRef type; +}; + + +// === Do not use directly: use one of the predefined sizes below === + +struct ScriptStringVarBase { + const unsigned char MaxLength; // Real length is MaxLength+1. + SQChar s[1]; + ScriptStringVarBase(int _MaxLength) : MaxLength(_MaxLength) {} + operator SQChar * () { return &s[0]; } + operator void * () { return (void *)&s[0]; } + const SQChar * operator = (const SQChar * _s) { + return safeStringCopy(s,_s,MaxLength); + } + // Special safe string copy where MaxLength is 1 less than true buffer length. + // strncpy() pads out nulls for the full length of the buffer specified by MaxLength. + static inline SQChar * safeStringCopy(SQChar * d,const SQChar * s,int MaxLength) { + int i=0; + while (s[i]) { + d[i] = s[i]; + i++; + if (i == MaxLength) break; + } // while + d[i] = 0; // Null terminate. + return d; + } // safeStringCopy +}; + +// === Do not use directly: use one of the predefined sizes below === + +template // MAXLENGTH is max printable characters (trailing NULL is accounted for in ScriptStringVarBase::s[1]). +struct ScriptStringVar : ScriptStringVarBase { + SQChar ps[MAXLENGTH]; + ScriptStringVar() : ScriptStringVarBase(MAXLENGTH) { + s[0] = 0; + } + ScriptStringVar(const SQChar * _s) : ScriptStringVarBase(MAXLENGTH) { + *this = _s; + } + const SQChar * operator = (const SQChar * _s) { + return safeStringCopy(s,_s,MaxLength); + } + const SQChar * operator = (const ScriptStringVar & _s) { + return safeStringCopy(s,_s.s,MaxLength); + } + bool operator == (const ScriptStringVar & _s) { + return _strcmp(s,_s.s) == 0; + } + bool compareCaseInsensitive(const ScriptStringVar & _s) { + return _stricmp(s,_s.s) == 0; + } +}; + +// === Fixed size strings for scripting === + +typedef ScriptStringVar<8> ScriptStringVar8; +typedef ScriptStringVar<16> ScriptStringVar16; +typedef ScriptStringVar<32> ScriptStringVar32; +typedef ScriptStringVar<64> ScriptStringVar64; +typedef ScriptStringVar<128> ScriptStringVar128; +typedef ScriptStringVar<256> ScriptStringVar256; + +// === Script Variable Types === + +enum ScriptVarType { + VAR_TYPE_NONE = -1, + VAR_TYPE_INT = 0, + VAR_TYPE_UINT, + VAR_TYPE_FLOAT, + VAR_TYPE_BOOL, + VAR_TYPE_CONST_STRING, + VAR_TYPE_STRING, + VAR_TYPE_USER_POINTER, + VAR_TYPE_INSTANCE, +#ifdef SQPLUS_SUPPORT_STD_STRING + VAR_TYPE_STD_STRING, +#endif +}; + +template +struct TypeInfo { + const SQChar * typeName; + enum {TypeID=VAR_TYPE_NONE, Size=0, TypeMask='?', IsInstance=0}; +}; + +// === Common Variable Types === + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("int")) {} + enum {TypeID=VAR_TYPE_INT,Size=sizeof(INT),TypeMask='i', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("uint")) {} + enum {TypeID=VAR_TYPE_UINT,Size=sizeof(unsigned), IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("float")) {} + enum {TypeID=VAR_TYPE_FLOAT,Size=sizeof(FLOAT),TypeMask='f', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("bool")) {} + enum {TypeID=VAR_TYPE_BOOL,Size=sizeof(bool),TypeMask='b', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("short")) {} + enum {TypeID=VAR_TYPE_INT,Size=sizeof(short),TypeMask='i', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("char")) {} + enum {TypeID=VAR_TYPE_INT,Size=sizeof(char),TypeMask='i', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("SQUserPointer")) {} + enum {TypeID=VAR_TYPE_USER_POINTER,Size=sizeof(SQUserPointer),TypeMask='u', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("SQUserPointer")) {} + enum {TypeID=VAR_TYPE_USER_POINTER,Size=sizeof(SQUserPointer),TypeMask='u', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(0) {} + enum {TypeID=-1,Size=0,TypeMask=' ', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("const SQChar *")) {} + enum {TypeID=VAR_TYPE_CONST_STRING,Size=sizeof(const SQChar *),TypeMask='s', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +#ifdef SQPLUS_AUTOCONVERT_OTHER_CHAR +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("const SQOtherChar *")) {} + enum {TypeID=VAR_TYPE_CONST_STRING,Size=sizeof(const SQOtherChar *),TypeMask='s', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; +template<> +struct Temporary { + typedef SQOthCharBuf type; +}; +template<> +struct Temporary { + typedef SQOthCharBuf type; +}; +#endif // SQPLUS_AUTOCONVERT_OTHER_CHAR + +// base case: raw pointer +template +struct TypeInfoPtrBase { + const SQChar * typeName; + TypeInfoPtrBase() : typeName(TypeInfo().typeName) {} + enum {TypeID=VAR_TYPE_USER_POINTER,Size=sizeof(T*),TypeMask='u'}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +template +struct TypeInfoPtrBase : public TypeInfo { }; + +// Partial specialization for pointers (to access type without pointer / or instance typeinfo) +template +struct TypeInfo : public TypeInfoPtrBase::IsInstance> { }; + +// Same thing for references +template +struct TypeInfo : public TypeInfoPtrBase::IsInstance> { }; + +#ifdef SQPLUS_SUPPORT_STD_STRING +template<> +struct TypeInfo { + const SQChar *typeName; + TypeInfo() : typeName(_SC("std::string")) {} + enum {TypeID=SqPlus::VAR_TYPE_STD_STRING,Size=sizeof(std::string),TypeMask='s'}; + operator ScriptVarType() {return ScriptVarType(TypeID);} +}; +#endif + +template<> +struct TypeInfo { + const SQChar * typeName; + TypeInfo() : typeName(_SC("ScriptStringVarBase")) {} + enum {TypeID=VAR_TYPE_STRING,Size=sizeof(ScriptStringVarBase),TypeMask='s', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +// === Fixed String Variants === + +template +struct TypeInfo > { + SQChar typeName[24]; + TypeInfo() { scsprintf(typeName,_SC("ScriptStringVar<%d>"),N); } + enum {TypeID=VAR_TYPE_STRING,Size=N*sizeof(ScriptStringVar),TypeMask='s', IsInstance=0}; + operator ScriptVarType() { return ScriptVarType(TypeID); } +}; + +#ifdef SQPLUS_SMARTPOINTER_OPT + #define SQPLUS_SMARTPOINTER_ACCESSTYPE + #include "SqPlusSmartPointer.h" +#else + enum VarAccessType {VAR_ACCESS_READ_WRITE=0,VAR_ACCESS_READ_ONLY=1<<0,VAR_ACCESS_CONSTANT=1<<1,VAR_ACCESS_STATIC=1<<2}; +#endif // SQPLUS_SMARTPOINTER_OPT + +// See VarRef and ClassType<> below: for instance assignment. +typedef void (*CopyVarFunc)(void * dst,void * src); + + +// === Class Type Helper class: returns an ID for each class type and provides base class pointer offset === + +struct ClassTypeBase { + ClassTypeBase() : m_pbase(0), m_name(0), m_offset(0), m_may_have_offset(-1) { } + // Many types cannot have offset, since "this" is the same for all base classes of + // an instance. Detect this, to avoid sum up base offsets all the time. + int MayHaveOffset( ) { + if( m_may_have_offset<0 ){ + if( m_offset ) m_may_have_offset = 1; + else m_may_have_offset = m_pbase ? m_pbase->MayHaveOffset() : 0; + } + return m_may_have_offset; + } + int GetOffsetTo( ClassTypeBase *pbase ){ + if( !m_pbase ) { /*printf("ClassTypeBase::getOffsetTo - Warning - Base type pointer is NULL!\n" );*/ return 0; } + return m_pbase==pbase ? m_offset : m_offset+m_pbase->GetOffsetTo(pbase); + } + virtual CopyVarFunc vgetCopyFunc(void) = 0; + virtual const SQChar* GetTypeName() = 0; + + ClassTypeBase *m_pbase; + const SQChar *m_name; // Name of type + int m_offset; // Adjustment of this pointer between this type and its base class + int m_may_have_offset; // Set to 0 for types that cannot possibly have offset +}; + +// This level handles instance copying in different ways +template +struct ClassTypeCopyImpl; + +// Helper struct to decide if type is copyable or not +template +struct IsCopyable { enum { value=true }; }; + +#define DECLARE_NONCOPY_TYPE_INTERN(TYPE) \ + template<> struct IsCopyable { enum { value=false }; }; + +// Macro to declare a type that should _not_ be copied using ordinary +// c++ copy expresssion: *(T*)pt1 = *(T*)pt2; +#define DECLARE_NONCOPY_TYPE(TYPE) namespace SqPlus { \ + template<> struct IsCopyable { enum { value=false }; }; \ +} + +// Base class to do copying in ordinary C++ way +template +struct ClassTypeCopyImpl : public ClassTypeBase { + static void copy(T * dst,T * src) { + *dst = *src; // This works types with copy ctor / assign operator + } // copy +}; + +// Base class to do copying with memcpy +template +struct ClassTypeCopyImpl : public ClassTypeBase { + static void copy(T * dst,T * src) { + memcpy(dst,src,sizeof(T)); // This works for raw data types + } // copy +}; + +// Base classes to do avoid copying altogether (void case) +template<> +struct ClassTypeCopyImpl : public ClassTypeBase { + static void copy(void * dst,void * src) { } // copy +}; + +template<> +struct ClassTypeCopyImpl : public ClassTypeBase { + static void copy(void * dst,void * src) { } // copy +}; + + +template +struct ClassType : public ClassTypeCopyImpl::value> { + typedef ClassTypeCopyImpl::value> ClassTypeBase; + ClassType( ) { this->m_name=stGetName(); } + + virtual CopyVarFunc vgetCopyFunc(void) { return (CopyVarFunc)&ClassTypeBase::copy; } + virtual const SQChar* GetTypeName(){ return this->m_name; } + + template + void SetBase(TypeWrapper) { + this->m_pbase = ClassType::Get(); + T* pt = reinterpret_cast(this); + this->m_offset = ((char*)pt)-((char*)static_cast(pt)); + } + static ClassType* Get(){ static ClassType st_ct; return &st_ct; } + static ClassTypeBase* type() { return Get(); } + static CopyVarFunc getCopyFunc(void) { return (CopyVarFunc)&ClassTypeBase::copy; } + static const SQChar* stGetName(){ return TypeInfo().typeName; } + + #ifdef SQPLUS_OVERLOAD_OPT + #define SQPLUS_OVERLOAD_RELEASE_HOOK + #include "SqPlusOverload.h" + #endif +}; + + +// === Variable references for script access === + +#define SQ_PLUS_TYPE_TABLE _SC("__SqTypes") + +struct VarRef { + // In this case 'offsetOrAddrOrConst' is simpler than using an anonymous union. + void * offsetOrAddrOrConst; // Instance member variable offset from 'this' pointer base (as size_t), or address if static variable (void *), or constant value. + ScriptVarType m_type; // Variable type (from enum above). + ClassTypeBase* instanceType; // Class type of the containing class instance (for member vars only). + ClassTypeBase* varType; // The class type of the variable itself + short m_size; // ATS: Use for short and char support. For debugging only (size of item when pointer to item is dereferenced). Could be used for variable max string buffer length. + short m_access; // VarAccessType. + + VarRef() : offsetOrAddrOrConst(0), m_type(VAR_TYPE_NONE), instanceType(0/*(SQUserPointer)-1*/), /*copyFunc(0),*/ m_size(0), m_access(VAR_ACCESS_READ_WRITE) {} + VarRef(void * _offsetOrAddrOrConst, ScriptVarType _type, ClassTypeBase* _instanceType, ClassTypeBase* _varType, int _size, VarAccessType _access) : + offsetOrAddrOrConst(_offsetOrAddrOrConst), m_type(_type), instanceType(_instanceType), varType(_varType), m_size(_size), m_access(_access) { +#ifdef SQ_SUPPORT_INSTANCE_TYPE_INFO + SquirrelObject typeTable = SquirrelVM::GetRootTable().GetValue(SQ_PLUS_TYPE_TABLE); + if (typeTable.IsNull()) { + typeTable = SquirrelVM::CreateTable(); + SquirrelObject root = SquirrelVM::GetRootTable(); + root.SetValue(SQ_PLUS_TYPE_TABLE,typeTable); + } // if + typeTable.SetValue(INT((size_t)varType),varType->GetTypeName()); +#endif // SQ_SUPPORT_INSTANCE_TYPE_INFO + } +}; + +typedef VarRef * VarRefPtr; + +// Internal use only. +inline void getVarNameTag(SQChar * buff,INT maxSize,const SQChar * scriptName) { +// assert(maxSize > 3); +#if 1 + SQChar * d = buff; + d[0] = '_'; + d[1] = 'v'; + d = &d[2]; + maxSize -= (2+1); // +1 = space for null. + int pos=0; + while (scriptName[pos] && pos < maxSize) { + d[pos] = scriptName[pos]; + pos++; + } // while + d[pos] = 0; // null terminate. +#else + SCSNPRINTF(buff,maxSize,_SC("_v%s"),scriptName); +#endif +} // getVarNameTag + +// Internal use only. +int setVarFunc(HSQUIRRELVM v); +int getVarFunc(HSQUIRRELVM v); +int setInstanceVarFunc(HSQUIRRELVM v); +int getInstanceVarFunc(HSQUIRRELVM v); + +// === BEGIN Helpers === + +inline void createTableSetGetHandlers(SquirrelObject & so) { + SquirrelObject delegate = so.GetDelegate(); + if (!delegate.Exists(_SC("_set"))) { + delegate = SquirrelVM::CreateTable(); + SquirrelVM::CreateFunction(delegate,setVarFunc,_SC("_set"),_SC("sn|b|s")); // String var name = number(int or float) or bool or string. + SquirrelVM::CreateFunction(delegate,getVarFunc,_SC("_get"),_SC("s")); // String var name. + so.SetDelegate(delegate); + } // if +} // createTableSetGetHandlers + +inline VarRefPtr createVarRef(SquirrelObject & so,const SQChar * scriptVarName) { + VarRefPtr pvr=0; + ScriptStringVar256 scriptVarTagName; getVarNameTag(scriptVarTagName,sizeof(scriptVarTagName),scriptVarName); + if (!so.GetUserData(scriptVarTagName,(SQUserPointer *)&pvr)) { + so.NewUserData(scriptVarTagName,sizeof(*pvr)); + if (!so.GetUserData(scriptVarTagName,(SQUserPointer *)&pvr)) throw SquirrelError(_SC("Could not create UserData.")); + } // if + return pvr; +} // createVarRef + +template +void validateConstantType(T constant) { + switch(TypeInfo()) { + case VAR_TYPE_INT: + case VAR_TYPE_FLOAT: + case VAR_TYPE_BOOL: + case VAR_TYPE_CONST_STRING: + break; + default: + throw SquirrelError(_SC("validateConstantType(): type must be INT, FLOAT, BOOL, or CONST CHAR *.")); + } // case +} // validateConstantType + +inline void createInstanceSetGetHandlers(SquirrelObject & so) { + if (!so.Exists(_SC("_set"))) { + SquirrelVM::CreateFunction(so,setInstanceVarFunc,_SC("_set"),_SC("sn|b|s|x")); // String var name = number(int or float) or bool or string or instance. + SquirrelVM::CreateFunction(so,getInstanceVarFunc,_SC("_get"),_SC("s")); // String var name. + } // if +} // createInstanceSetGetHandlers + +// === END Helpers === + + +// Provide an overridable way of copying / deleting objects +template +struct ObjectCloner { + static T* Clone(T* src){ return new T(src); } + static void Delete(T* dst){ if(dst) delete dst; } +}; + +// specialization for void type +//template<> inline void ClassType::copy(void *dst, void *src) {} +DECLARE_NONCOPY_TYPE_INTERN(void) + + +// === Bind a global or pre-allocated (not instance) class member variable or constant (for tables only (not classes)) === + +template +void BindVariable(SquirrelObject & so,T * var,const SQChar * scriptVarName,VarAccessType access=VAR_ACCESS_READ_WRITE) { + VarRefPtr pvr = createVarRef(so,scriptVarName); + *pvr = VarRef(var,TypeInfo(),NULL,ClassType::type(),sizeof(*var),access); + createTableSetGetHandlers(so); +} // BindVariable + +// === Bind a constant by value: INT, FLOAT, BOOL, or CONST CHAR * (for tables only (not classes)) === + +template +void BindConstant(SquirrelObject & so,T constant,const SQChar * scriptVarName) { + validateConstantType(constant); + VarRefPtr pvr = createVarRef(so,scriptVarName); + struct CV { + T var; + } cv; // Cast Variable helper. + cv.var = constant; + *pvr = VarRef(*(void **)&cv,TypeInfo(),NULL,ClassType::type(),sizeof(constant),VAR_ACCESS_CONSTANT); + createTableSetGetHandlers(so); +} // BindConstant + +template +void BindVariable(T * var,const SQChar * scriptVarName,VarAccessType access=VAR_ACCESS_READ_WRITE) { + SquirrelObject so = SquirrelVM::GetRootTable(); + BindVariable(so,var,scriptVarName,access); +} // BindVariable + +template +void BindConstant(T constant,const SQChar * scriptVarName) { + SquirrelObject so = SquirrelVM::GetRootTable(); + BindConstant(so,constant,scriptVarName); +} // BindConstant + +// === Register a class instance member variable or constant. var argument provides type and offset ( effectively &((ClassType *)0)->var ) === + +// classType is the type of the member variable's containing class. + template +void RegisterInstanceVariable(SquirrelObject & so,ClassTypeBase* classType,T * var,const SQChar * scriptVarName,VarAccessType access=VAR_ACCESS_READ_WRITE) { + VarRef * pvr = createVarRef(so,scriptVarName); + void * offsetOrAddrOrConst = (void *)var; // var must be passed in as &obj->var, where obj = 0 (the address is the offset), or as static/global address. + *pvr = VarRef(offsetOrAddrOrConst,TypeInfo(),classType,ClassType::type(),sizeof(*var),access); + createInstanceSetGetHandlers(so); +} // RegisterInstanceVariable + +#ifdef SQPLUS_SMARTPOINTER_OPT +#define SQPLUS_SMARTPOINTER_REGISTER_VARIABLE +#include "SqPlusSmartPointer.h" +#endif + +template +void RegisterInstanceConstant(SquirrelObject & so,ClassTypeBase *classType,T constant,const SQChar * scriptVarName) { + validateConstantType(constant); + VarRef * pvr = createVarRef(so,scriptVarName); + struct CV { + T var; + size_t pad; + } cv; // Cast Variable helper. + cv.var = constant; + *pvr = VarRef(*(void **)&cv,TypeInfo(),classType,ClassType::type(),sizeof(constant),VAR_ACCESS_CONSTANT); + createInstanceSetGetHandlers(so); +} // RegisterInstanceConstant + +////////////////////////////////////////////////////////////////////////// +/////////// BEGIN Generalized Class/Struct Instance Support ////////////// +////////////////////////////////////////////////////////////////////////// + +// Was previously in SqPlus namespace +//BOOL CreateNativeClassInstance(HSQUIRRELVM v,const SQChar * classname,SQUserPointer ud,SQRELEASEHOOK hook); // In SquirrelBindingUtils.cpp. + +// Create native class instance and leave on stack. +//BOOL CreateConstructNativeClassInstance(HSQUIRRELVM v,const SQChar * className); + +// Create new instance, copy 'classToCopy', and store result on stack. +template +inline BOOL CreateCopyInstance(HSQUIRRELVM v, const SQChar * className,const T & classToCopy) { +#ifndef SQPLUS_DISABLE_COPY_INSTANCES + if (!CreateConstructNativeClassInstance(v,className)) { + return FALSE; + } // if + SQUserPointer up=0; + sq_getinstanceup(v,-1,&up,ClassType::type()); + if (!up) return FALSE; + T * newClass = (T *)up; + *newClass = classToCopy; // Optimized version that uses the copy constructor. + return TRUE; +#else + return FALSE; +#endif +} // CreateCopyInstance + +// Create a new copy of type 'className' and copy 'classToCopy', return result via SquirrelObject. +template +inline SquirrelObject NewClassCopy(HSQUIRRELVM v, const SQChar * className,const T & classToCopy) { + if (CreateCopyInstance(v, className,classToCopy)) { + HSQOBJECT t; + sq_getstackobj(v,-1,&t); + SquirrelObject obj(t); + sq_poptop(v); + return obj; + } else { + throw SquirrelError(_SC("NewClassCopy(): could not create class")); + } // if + return SquirrelObject(); +} // NewClassCopy + +// Return a new class copy on the stack from a varArgs function call. +template +inline int ReturnCopy(HSQUIRRELVM v,const T & classToCopy) { + SquirrelObject so(NewClassCopy(v,GetTypeName(classToCopy),classToCopy)); + return StackHandler(v).Return(so); +} // ReturnCopy + +// Katsuaki Kawachi's GetInstance<> exception change. 6/27/06 jcs + +// Get an instance of type T from the stack at idx (for function calls). +template +T * GetInstance(HSQUIRRELVM v,SQInteger idx) { + SQUserPointer up=0; + if (SQ_FAILED(sq_getinstanceup(v,idx,&up,ClassType::type()))) { + up = 0; + } + if (ExceptionOnError) { // This code block should be compiled out when ExceptionOnError is false. In any case, the compiler should not generate a test condition (include or exclude the enclosed code block). + if (!up) { + throw SquirrelError(_SC("GetInstance: Invalid argument type")); + } + } // if + return (T *)up; +} // GetInstance + + +template void Push(HSQUIRRELVM v, T* pt); +template void Push(HSQUIRRELVM v, T& t); +template bool Match(TypeWrapper, HSQUIRRELVM v, int ix); +template bool Match(TypeWrapper, HSQUIRRELVM v, int ix); +template T &Get(TypeWrapper, HSQUIRRELVM v, int ix); +template T *Get(TypeWrapper, HSQUIRRELVM v, int ix); + + +#ifdef SQPLUS_USE_GENERIC_HANDLERS +// With template specialization, we get Push handlers per 'precise type match' +// This adds a fallback level after that, where we can delegate the work to +// wider C-style functions that can do something for a whole class hierarchy. +// (GenPush, GenGet, GenMatch). + +// This macro allows for a a last generic cast operation before giving control +// to one of GenPush/GenMatch/GenGet. +#ifndef SQPLUS_GEN_CAST + #define SQPLUS_GEN_CAST(TYPE,value) ((TYPE*)value) +#endif + +template void Push(HSQUIRRELVM v, T* pt){ GenPush(v,SQPLUS_GEN_CAST(T,pt)); } +template void Push(HSQUIRRELVM v, T& t){ GenPush(v,SQPLUS_GEN_CAST(T,&t)); } +template bool Match(TypeWrapper, HSQUIRRELVM v, int ix){ + if((ScriptVarType)TypeInfo::TypeID!=VAR_TYPE_NONE) + return GenMatch(SQPLUS_GEN_CAST(T*,0),TypeInfo().typeName,v,ix); + else return false; +} +template bool Match(TypeWrapper, HSQUIRRELVM v, int ix){ + if((ScriptVarType)TypeInfo::TypeID!=VAR_TYPE_NONE) + return GenMatch(SQPLUS_GEN_CAST(T*,0),TypeInfo().typeName,v,ix); + else return false; +} +template T &Get(TypeWrapper, HSQUIRRELVM v, int ix){ + if((ScriptVarType)TypeInfo::TypeID!=VAR_TYPE_NONE) + return *(T*)GenGet(SQPLUS_GEN_CAST(T*,0),TypeInfo().typeName,v,ix); + else return *SQPLUS_GEN_CAST(T,0); +} +template T *Get(TypeWrapper, HSQUIRRELVM v, int ix){ + if((ScriptVarType)TypeInfo::TypeID!=VAR_TYPE_NONE) + return (T*)GenGet(SQPLUS_GEN_CAST(T*,0),TypeInfo().typeName,v,ix); + else return NULL; +} +#endif // SQPLUS_USE_GENERIC_HANDLERS + + +// === BEGIN Function Call Handler Prototypes === + +void Push(HSQUIRRELVM v, char value); +void Push(HSQUIRRELVM v, unsigned char value); +void Push(HSQUIRRELVM v, short value); +void Push(HSQUIRRELVM v, unsigned short value); +void Push(HSQUIRRELVM v, int value); +void Push(HSQUIRRELVM v, unsigned int value); +void Push(HSQUIRRELVM v, long value); +void Push(HSQUIRRELVM v, unsigned long value); +void Push(HSQUIRRELVM v, double value); +void Push(HSQUIRRELVM v, float value); +void Push(HSQUIRRELVM v, const SQChar *value); +void Push(HSQUIRRELVM v, SQChar *value); +void Push(HSQUIRRELVM v, const SquirrelNull &); +void Push(HSQUIRRELVM v, SQFUNCTION value); +void Push(HSQUIRRELVM v, SQAnythingPtr value); // Cast to SQAnythingPtr instead of void * if USE_ARGUMENT_DEPENDANT_OVERLOADS can't be used by your compiler. +void Push(HSQUIRRELVM v, SquirrelObject &so); + +#define USE_ARGUMENT_DEPENDANT_OVERLOADS +#ifdef USE_ARGUMENT_DEPENDANT_OVERLOADS +#ifdef _MSC_VER +#pragma warning(disable:4675) // Disable warning: "resolved overload was found by argument-dependent lookup" when class/struct pointers are used as function arguments. +#endif +// === BEGIN Argument Dependent Overloads === +void Push(HSQUIRRELVM v, bool value); // Pass bool as int if USE_ARGUMENT_DEPENDANT_OVERLOADS can't be used by your compiler. +void Push(HSQUIRRELVM v, const void *value); // Pass SQAnythingPtr instead of void * " " +void Push(HSQUIRRELVM v, const SQUserPointer &value); +// === END Argument Dependent Overloads === +#endif + +#define SQPLUS_CHECK_GET(res) if (!SQ_SUCCEEDED(res)) throw SquirrelError(_SC("sq_get*() failed (type error)")) + +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); // See Get() for HSQUIRRELVM below (v is always present). +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); // See sq_getstackobj(): always returns true. + +void Get(TypeWrapper, HSQUIRRELVM v, int); +bool Get(TypeWrapper, HSQUIRRELVM v, int idx); +char Get(TypeWrapper, HSQUIRRELVM v, int idx); +unsigned char Get(TypeWrapper, HSQUIRRELVM v, int idx); +short Get(TypeWrapper, HSQUIRRELVM v, int idx); +unsigned short Get(TypeWrapper, HSQUIRRELVM v, int idx); +int Get(TypeWrapper, HSQUIRRELVM v, int idx); +unsigned int Get(TypeWrapper, HSQUIRRELVM v, int idx); +long Get(TypeWrapper, HSQUIRRELVM v, int idx); +unsigned long Get(TypeWrapper, HSQUIRRELVM v, int idx); +float Get(TypeWrapper, HSQUIRRELVM v, int idx); +double Get(TypeWrapper, HSQUIRRELVM v, int idx); +const SQChar *Get(TypeWrapper, HSQUIRRELVM v, int idx); +SquirrelNull Get(TypeWrapper, HSQUIRRELVM v, int idx); +void *Get(TypeWrapper, HSQUIRRELVM v, int idx); +HSQUIRRELVM Get(TypeWrapper, HSQUIRRELVM v, int /*idx*/); // sq_poptop(v): remove UserData from stack so GetParamCount() matches normal behavior. +SquirrelObject Get(TypeWrapper, HSQUIRRELVM v, int idx); + +#ifdef SQPLUS_AUTOCONVERT_OTHER_CHAR + void Push(HSQUIRRELVM v, const SQOtherChar *value); + void Push(HSQUIRRELVM v, SQOtherChar *value); + bool Match(TypeWrapper, HSQUIRRELVM v, int idx); + bool Match(TypeWrapper, HSQUIRRELVM v, int idx); + SQOthCharBuf Get(TypeWrapper, HSQUIRRELVM v, int idx); +#endif // SQPLUS_AUTOCONVERT_OTHER_CHAR + +#ifdef SQPLUS_SUPPORT_STD_STRING +void Push(HSQUIRRELVM v, const std::string& value); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +std::string Get(TypeWrapper, HSQUIRRELVM v, int idx); +#endif + +// Added jflanglois suggestion, 8/20/06. jcs +#ifdef SQPLUS_SUPPORT_SQ_STD_STRING +typedef std::basic_string sq_std_string; +void Push(HSQUIRRELVM v,const sq_std_string & value); +bool Match(TypeWrapper, HSQUIRRELVM v, int idx); +sq_std_string Get(TypeWrapper, HSQUIRRELVM v, int idx); +#endif + +// Specialization to support void return type. +void GetRet(TypeWrapper, HSQUIRRELVM v,int idx); + +// GetRet() restores the stack for SquirrelFunction<>() calls. +// Hold on to a reference since return value might be temporary string/instance +template +inline RT GetRet(TypeWrapper,HSQUIRRELVM v,int idx) { + static SquirrelObject st_sq_ret; + static typename Temporary::type st_ret; + st_ret = Get(TypeWrapper(),v,idx); + st_sq_ret.AttachToStackObject(idx); + sq_pop(v,2); // restore stack after function call. + return st_ret; } + +#ifndef GCC_INLINE_WORKAROUND +# include "SqPlusFunctionCallImpl.h" +#endif // GCC_INLINE_WORKAROUND + +// === END Function Call Handlers === + + +// Helper, only implement function bodies +#define IMPLEMENT_ENUM_TYPE(TYPE) namespace SqPlus { \ + bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return Match(TypeWrapper(),v,idx); } \ + TYPE Get(TypeWrapper,HSQUIRRELVM v,int idx) { return (TYPE)Get(TypeWrapper(),v,idx); } \ + void Push(HSQUIRRELVM v,TYPE value) { sq_pushinteger(v,(int)value); } \ +} // nameSpace SqPlus + +// To register simple types (like enums) so they can be used as arguments +// (however, this does not handle enums as return values correctly, since +// we C++ gets problems with references to temporaries) +#define DECLARE_ENUM_TYPE(TYPE) IMPLEMENT_ENUM_TYPE(TYPE) \ +namespace SqPlus { \ + template<> struct TypeInfo : public TypeInfo { }; \ +} // nameSpace SqPlus + +// As above but use when function bodies should not be generated +// (for a header file). +#define PROTOS_ENUM_TYPE(TYPE) namespace SqPlus { \ + bool Match(TypeWrapper,HSQUIRRELVM v,int idx); \ + TYPE Get(TypeWrapper,HSQUIRRELVM v,int idx); \ + void Push(HSQUIRRELVM v,TYPE value); \ + template<> struct TypeInfo : public TypeInfo { }; \ +} // nameSpace SqPlus + + +// NAME and macro changes from Ben's (Project5) forum post. 2/26/06 jcs +// Kamaitati's NULL_INSTANCE support. 5/28/06 jcs + +// ATS: Splitting the macros in different parts to support custom Push implementation (covariant return type) + +#define DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ + inline const SQChar * GetTypeName(const TYPE & n) { return _SC(#NAME); } \ + template<> \ + struct TypeInfo { \ + const SQChar * typeName; \ + TypeInfo() : typeName( _SC(#NAME)) {} \ + enum {TypeID=VAR_TYPE_INSTANCE,Size=sizeof(TYPE),TypeMask='x', IsInstance=1}; \ + operator ScriptVarType() { return ScriptVarType(TypeID); } \ + }; + +#define DECLARE_INSTANCE_TYPEINFO(TYPE) namespace SqPlus { \ + DECLARE_INSTANCE_TYPEINFO_(TYPE,TYPE) \ +} // namespace SqPlus + +#define DECLARE_INSTANCE_TYPEINFO_NAME(TYPE,NAME) namespace SqPlus { \ + DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ +} // namespace SqPlus + + +#ifdef SQPLUS_SUPPORT_NULL_INSTANCES + +// Macro part shared by 'derived' macros +#define DECLARE_INSTANCE_TYPE_BASE_(TYPE,NAME) \ + DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ + template<> inline bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return GetInstance(v,idx) != NULL; } \ + template<> inline bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { \ + return (sq_gettype(v,idx)==OT_NULL) || (GetInstance(v,idx) != NULL); } \ + template<> inline TYPE & Get(TypeWrapper,HSQUIRRELVM v,int idx) { return *GetInstance(v,idx); } \ + template<> inline TYPE * Get(TypeWrapper,HSQUIRRELVM v,int idx) { \ + if (sq_gettype(v,idx)==OT_NULL) return NULL; \ + return GetInstance(v,idx); } + +// Ordinary case +#define DECLARE_INSTANCE_TYPE_NAME_(TYPE,NAME) namespace SqPlus { \ + DECLARE_INSTANCE_TYPE_BASE_(TYPE,NAME) \ + template<> inline void Push(HSQUIRRELVM v,TYPE * value) { \ + if (!value) sq_pushnull(v); \ + else if (!CreateNativeClassInstance(v,GetTypeName(*value),value,0)) \ + throw SquirrelError( _SC( "Push(): could not create INSTANCE (check registration name)")); } \ + template<> inline void Push(HSQUIRRELVM v,TYPE & value) { if (!CreateCopyInstance(v,GetTypeName(value),value)) throw SquirrelError( _SC( "Push(): could not create INSTANCE copy (check registration name)")); } \ +} // nameSpace SqPlus + +// Allows for providing custom Push handlers (protos here, impl must be provided by app) +#define DECLARE_INSTANCE_TYPE_NAME_CUSTOM_(TYPE,NAME) namespace SqPlus { \ + DECLARE_INSTANCE_TYPE_BASE_(TYPE,NAME) \ + template<> void Push(HSQUIRRELVM v,TYPE * value); \ + template<> void Push(HSQUIRRELVM v,TYPE & value); \ +} // nameSpace SqPlus + + +#else + +#define DECLARE_INSTANCE_TYPE_NAME_(TYPE,NAME) namespace SqPlus { \ + DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ + template<> inline void Push(HSQUIRRELVM v,TYPE * value) { if (!CreateNativeClassInstance(v,GetTypeName(*value),value,0)) throw SquirrelError( _SC( "Push(): could not create INSTANCE (check registration name)")); } \ + template<> inline void Push(HSQUIRRELVM v,TYPE & value) { if (!CreateCopyInstance(v,GetTypeName(value),value)) throw SquirrelError( _SC( "Push(): could not create INSTANCE copy (check registration name)")); } \ + template<> inline bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return GetInstance(v,idx) != NULL; } \ + template<> inline bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return GetInstance(v,idx) != NULL; } \ + template<> inline TYPE & Get(TypeWrapper,HSQUIRRELVM v,int idx) { return *GetInstance(v,idx); } \ + template<> inline TYPE * Get(TypeWrapper,HSQUIRRELVM v,int idx) { return GetInstance(v,idx); } \ +} // nameSpace SqPlus + +#endif + +// TYPE or NAME below must match the string name used in SQClassDef<>, otherwise name lookup won't match and Squirrel will throw a "can't create instance" error. +#ifndef SQPLUS_CONST_OPT +#define DECLARE_INSTANCE_TYPE(TYPE) DECLARE_INSTANCE_TYPE_NAME_(TYPE,TYPE) +#define DECLARE_INSTANCE_TYPE_NAME(TYPE,NAME) DECLARE_INSTANCE_TYPE_NAME_(TYPE,NAME) +#define DECLARE_INSTANCE_TYPE_CUSTOM(TYPE) DECLARE_INSTANCE_TYPE_NAME_CUSTOM_(TYPE,TYPE) +#define DECLARE_INSTANCE_TYPE_NAME_CUSTOM(TYPE,NAME) DECLARE_INSTANCE_TYPE_NAME_CUSTOM_(TYPE,NAME) +#else +#define SQPLUS_DECLARE_INSTANCE_TYPE_CONST +#include "SqPlusConst.h" +#endif + +#ifdef SQPLUS_OVERLOAD_OPT +#define SQPLUS_OVERLOAD_DECLARATION +#include "SqPlusOverload.h" +#endif + +// Versions of above for types that aren't copy constructable +#define DECLARE_INSTANCE_TYPEINFO_NOCOPY(TYPE) \ + DECLARE_INSTANCE_TYPEINFO(TYPE) \ + DECLARE_NONCOPY_TYPE(TYPE) + +#define DECLARE_INSTANCE_TYPEINFO_NOCOPY_NAME(TYPE,NAME) namespace SqPlus { \ + DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ + DECLARE_NONCOPY_TYPE(TYPE) + +#define DECLARE_INSTANCE_TYPE_NOCOPY(TYPE) \ + DECLARE_INSTANCE_TYPE(TYPE) \ + DECLARE_NONCOPY_TYPE(TYPE) + +#define DECLARE_INSTANCE_TYPE_NOCOPY_NAME(TYPE,NAME) namespace SqPlus { \ + DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ + DECLARE_NONCOPY_TYPE(TYPE) + + +////////////////////////////////////////////////////////////////////////// +//////////// END Generalized Class/Struct Instance Support /////////////// +////////////////////////////////////////////////////////////////////////// + +#ifndef SQ_SKIP_ARG_ASSERT + #define sq_argassert(arg,_index_) if (!Match(TypeWrapper(),v,_index_)) return sq_throwerror(v,_SC("Incorrect function argument")) +#else + #define sq_argassert(arg,_index_) +#endif + +// === Return value variants === + +template +struct ReturnSpecialization { + + // === Standard Function calls === + + static int Call(RT (*func)(),HSQUIRRELVM v,int /*index*/) { + RT ret = func(); + Push(v,ret); + return 1; + } + + template + static int Call(RT (*func)(P1),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + RT ret = func( + Get(TypeWrapper(),v,index + 0) + ); + Push(v,ret); + return 1; + } + + template + static int Call(RT (*func)(P1,P2),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + RT ret = func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1) + ); + Push(v,ret); + return 1; + } + + template + static int Call(RT (*func)(P1,P2,P3),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + RT ret = func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2) + ); + Push(v,ret); + return 1; + } + + template + static int Call(RT (*func)(P1,P2,P3,P4),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + RT ret = func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3) + ); + Push(v,ret); + return 1; + } + + template + static int Call(RT (*func)(P1,P2,P3,P4,P5),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + RT ret = func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4) + ); + Push(v,ret); + return 1; + } + + template + static int Call(RT (*func)(P1,P2,P3,P4,P5,P6),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + sq_argassert(6,index + 5); + RT ret = func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4), + Get(TypeWrapper(),v,index + 5) + ); + Push(v,ret); + return 1; + } + + template + static int Call(RT (*func)(P1,P2,P3,P4,P5,P6,P7),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + sq_argassert(6,index + 5); + sq_argassert(7,index + 6); + RT ret = func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4), + Get(TypeWrapper(),v,index + 5), + Get(TypeWrapper(),v,index + 6) + ); + Push(v,ret); + return 1; + } + + // === Member Function calls === + + +#define SQPLUS_CALL_MFUNC_RET0 +#include "SqPlusCallTemplates.h" + +#ifdef SQPLUS_CONST_OPT +#define SQPLUS_CALL_MFUNC_RET0 +#include "SqPlusConst.h" +#endif +}; + +// === No return value variants === + +template<> +struct ReturnSpecialization { + + // === Standard function calls === + + static int Call(void (*func)(),HSQUIRRELVM v,int /*index*/) { + (void)v; + func(); + return 0; + } + + template + static int Call(void (*func)(P1),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + func( + Get(TypeWrapper(),v,index + 0) + ); + return 0; + } + + template + static int Call(void (*func)(P1,P2),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1) + ); + return 0; + } + + template + static int Call(void (*func)(P1,P2,P3),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2) + ); + return 0; + } + + template + static int Call(void (*func)(P1,P2,P3,P4),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3) + ); + return 0; + } + + template + static int Call(void (*func)(P1,P2,P3,P4,P5),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4) + ); + return 0; + } + + template + static int Call(void (*func)(P1,P2,P3,P4,P5,P6),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + sq_argassert(6,index + 5); + func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4), + Get(TypeWrapper(),v,index + 5) + ); + return 0; + } + + template + static int Call(void (*func)(P1,P2,P3,P4,P5,P6,P7),HSQUIRRELVM v,int index) { + sq_argassert(1,index + 0); + sq_argassert(2,index + 1); + sq_argassert(3,index + 2); + sq_argassert(4,index + 3); + sq_argassert(5,index + 4); + sq_argassert(6,index + 5); + sq_argassert(7,index + 6); + func( + Get(TypeWrapper(),v,index + 0), + Get(TypeWrapper(),v,index + 1), + Get(TypeWrapper(),v,index + 2), + Get(TypeWrapper(),v,index + 3), + Get(TypeWrapper(),v,index + 4), + Get(TypeWrapper(),v,index + 5), + Get(TypeWrapper(),v,index + 6) + ); + return 0; + } + + // === Member function calls === + + +#define SQPLUS_CALL_MFUNC_NORET +#include "SqPlusCallTemplates.h" + +#ifdef SQPLUS_CONST_OPT +#define SQPLUS_CALL_MFUNC_NORET +#include "SqPlusConst.h" +#endif + +}; + +// === STANDARD Function return value specialized call handlers === + +template +int Call(RT (*func)(),HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(func,v,index); +} + +template +int Call(RT (*func)(P1),HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(func,v,index); +} + +template +int Call(RT (*func)(P1,P2),HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(func,v,index); +} + +template +int Call(RT (*func)(P1,P2,P3),HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(func,v,index); +} + +template +int Call(RT (*func)(P1,P2,P3,P4),HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(func,v,index); +} + +template +int Call(RT (*func)(P1,P2,P3,P4,P5),HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(func,v,index); +} + +template +int Call(RT (*func)(P1,P2,P3,P4,P5,P6),HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(func,v,index); +} + +template +int Call(RT (*func)(P1,P2,P3,P4,P5,P6,P7),HSQUIRRELVM v,int index) { + return ReturnSpecialization::Call(func,v,index); +} + +// === MEMBER Function return value specialized call handlers === + + +#define SQPLUS_CALL_MFUNC_RET1 +#include "SqPlusCallTemplates.h" + +#ifdef SQPLUS_CONST_OPT +#define SQPLUS_CALL_MFUNC_RET1 +#include "SqPlusConst.h" +#endif + +// === Direct Call Standard Function handler === + +template +struct DirectCallFunction { + static inline int Dispatch(HSQUIRRELVM v) { +#ifdef SQPLUS_USE_SANDBOX_VM + if( v==SquirrelVM::GetSandboxVMPtr() ){ + return sq_throwerror(v, _SC("SqPlus: Cannot exec function from sandbox VM")); + } +#endif + StackHandler sa(v); + int paramCount = sa.GetParamCount(); + Func * func = (Func *)sa.GetUserData(paramCount); + return Call(*func,v,2); + } // Dispatch +}; + +// === Direct Call Member Function handler === + +template +class DirectCallMemberFunction { +public: + static inline int Dispatch(HSQUIRRELVM v) { +#ifdef SQPLUS_USE_SANDBOX_VM + if( v==SquirrelVM::GetSandboxVMPtr() ){ + return sq_throwerror(v, _SC("SqPlus: Cannot exec function from sandbox VM")); + } +#endif + StackHandler sa(v); + int paramCount = sa.GetParamCount(); + unsigned char * ud = (unsigned char *)sa.GetUserData(paramCount); + return Call(**(Callee**)ud,*(Func*)(ud + sizeof(Callee*)),v,2); + } // Dispatch +}; + +// === Direct Call Function handlers === + +#define SQ_CLASS_OBJECT_TABLE_NAME _SC("__ot") +#define SQ_CLASS_HIER_ARRAY _SC("__ca") + +template +struct DirectCallInstanceFuncPicker { + Callee *instance; + Func *func; + DirectCallInstanceFuncPicker(HSQUIRRELVM v) { +#ifdef SQPLUS_USE_SANDBOX_VM + if( v==SquirrelVM::GetSandboxVMPtr() ){ + instance = NULL; + func = NULL; + return; + } +#endif + StackHandler sa(v); + instance = static_cast(sa.GetInstanceUp(1, 0)); + const int paramCount = sa.GetParamCount(); + func = static_cast(sa.GetUserData(paramCount)); +#ifdef SQ_USE_CLASS_INHERITANCE + SquirrelObject so(sa.GetObjectHandle(1)); // 'this' + SQUserPointer typetag; so.GetTypeTag(&typetag); + SQUserPointer calleeType = ClassType::type(); + if (typetag != calleeType) { + SquirrelObject typeTable = so.GetValue(SQ_CLASS_OBJECT_TABLE_NAME); + instance = static_cast( + // 64-bit compatible version. + typeTable.GetUserPointer(INT((size_t)ClassType::type())) + ); + } +#elif defined(SQ_USE_CLASS_INHERITANCE_SIMPLE) + SquirrelObject so(sa.GetObjectHandle(1)); // 'this' + ClassTypeBase *instType; so.GetTypeTag((SQUserPointer*)&instType); + ClassTypeBase *calleeType = ClassType::type(); + if (instType!=calleeType && instType->MayHaveOffset() ) { + // instance type is nore derived than callee, adjust pointer + int offset = instType->GetOffsetTo(calleeType); + instance = (Callee*)((char*)instance-offset); + } +#endif + } +}; + +// === Direct Call Instance Member Function handler === +template +class DirectCallInstanceMemberFunction { +public: + static inline int Dispatch(HSQUIRRELVM v) { + DirectCallInstanceFuncPicker p(v); + return p.instance && p.func ? + Call(*(p.instance), *(p.func), v, 2) : + sq_throwerror(v, _SC("Invalid Instance Type")); + } +}; + +// === Direct Call Instance Global Function handler === +template +class DirectCallInstanceGlobalFunction { +public: + static inline int Dispatch(HSQUIRRELVM v) { + DirectCallInstanceFuncPicker p(v); + return p.func ? + Call(*(p.func), v, 1) : + sq_throwerror(v, _SC("Invalid Instance Type")); + } +}; + +// === Direct Call Instance Global Function Var Args handler === +template +class DirectCallInstanceGlobalFunctionVarArgs { +public: + static inline int Dispatch(HSQUIRRELVM v) { + DirectCallInstanceFuncPicker p(v); + return p.func && p.instance ? + (*p.func)(p.instance,v) : + sq_throwerror(v, _SC("Invalid Instance Type")); + } +}; + +// === Direct Call Instance Member Function Variable Argument handler === +template +class DirectCallInstanceMemberFunctionVarArgs { +public: + static inline int Dispatch(HSQUIRRELVM v) { + DirectCallInstanceFuncPicker p(v); + sq_poptop(v); // Remove UserData from stack: so sa.GetParamCount() returns actual param count. + return p.func && p.instance ? + (p.instance->*(*p.func))(v) : + sq_throwerror(v, _SC("Invalid Instance Type")); + } +}; + +#ifdef SQPLUS_SMARTPOINTER_OPT +#define SQPLUS_SMARTPOINTER_DISPATCH +#include "SqPlusSmartPointer.h" +#endif + + +// Code fragment useful for debugging new implementations. +#if 0 +HSQOBJECT ho = sa.GetObjectHandle(paramCount); +SquirrelObject so(ho); +SQObjectType sot = so.GetType(); +#endif + +#ifdef SQPLUS_ENABLE_AUTO_TYPEMASK + #include "SqPlusTypeMask.h" +#endif + +// === Standard function call === + +template +inline void sq_pushdirectclosure(HSQUIRRELVM v,Func func,SQUnsignedInteger nupvalues) { + SQUserPointer up = sq_newuserdata(v,sizeof(func)); // Also pushed on stack. + memcpy(up,&func,sizeof(func)); + sq_newclosure(v,DirectCallFunction::Dispatch,nupvalues+1); +#ifdef SQPLUS_ENABLE_AUTO_TYPEMASK + sq_setparamscheck(v,0,sqTypeMask::Get()); +#endif +} // sq_pushdirectclosure + +// === Fixed Class pointer call (always calls with object pointer that was registered) === + +template +inline void sq_pushdirectclosure(HSQUIRRELVM v,const Callee & callee,Func func,SQUnsignedInteger nupvalues) { + unsigned char * up = (unsigned char *)sq_newuserdata(v,sizeof(Callee*)+sizeof(func)); // Also pushed on stack. + const SQUserPointer pCallee = (SQUserPointer)&callee; + memcpy(up,&pCallee,sizeof(Callee*)); + memcpy(up + sizeof(Callee*),&func,sizeof(func)); + sq_newclosure(v,DirectCallMemberFunction::Dispatch,nupvalues+1); +#ifdef SQPLUS_ENABLE_AUTO_TYPEMASK + sq_setparamscheck(v,0,sqTypeMask::Get()); +#endif +} // sq_pushdirectclosure + +#ifdef SQPLUS_SMARTPOINTER_OPT +#define SQPLUS_SMARTPOINTER_DIRECT_CLOSURE +#include "SqPlusSmartPointer.h" +#endif + +// === Class Instance call: class pointer retrieved from script class instance === + +template +inline void sq_pushdirectinstanceclosure(HSQUIRRELVM v,const Callee & callee,Func func,SQUnsignedInteger nupvalues) { + unsigned char * up = (unsigned char *)sq_newuserdata(v,sizeof(func)); // Also pushed on stack. + memcpy(up,&func,sizeof(func)); + sq_newclosure(v,DirectCallInstanceMemberFunction::Dispatch,nupvalues+1); +#ifdef SQPLUS_ENABLE_AUTO_TYPEMASK + sq_setparamscheck(v,0,sqTypeMask::Get()); +#endif +} // sq_pushdirectinstanceclosure + +// === Global function using this: class pointer retrieved from script class instance === + +template +inline void sq_pushdirectinstanceclosureglobal(HSQUIRRELVM v,const Callee & callee,Func func,SQUnsignedInteger nupvalues) { + unsigned char * up = (unsigned char *)sq_newuserdata(v,sizeof(func)); // Also pushed on stack. + memcpy(up,&func,sizeof(func)); + // Could check that 1st arg of Func is a Callee + sq_newclosure(v,DirectCallInstanceGlobalFunction::Dispatch,nupvalues+1); +#ifdef SQPLUS_ENABLE_AUTO_TYPEMASK + SQChar *tm = (SQChar*)sqTypeMask::Get(); + if( tm ) { + // Censor out the 1st arg, since SqPlus adds that automatically + tm[1] = _SC('x'); //tm[0]; + tm++; + } + sq_setparamscheck(v,0,tm?tm:_SC("")); +#endif +} // sq_pushdirectinstanceclosureglobal + +// === Global function using this: class pointer retrieved from script class instance === + +template +inline void sq_pushdirectinstanceclosureglobalvarargs(HSQUIRRELVM v,const Callee & callee,Func func,SQUnsignedInteger nupvalues) { + unsigned char * up = (unsigned char *)sq_newuserdata(v,sizeof(func)); // Also pushed on stack. + memcpy(up,&func,sizeof(func)); + // Could check that 1st arg of Func is a Callee + sq_newclosure(v,DirectCallInstanceGlobalFunctionVarArgs::Dispatch,nupvalues+1); +#ifdef SQPLUS_ENABLE_AUTO_TYPEMASK + sq_setparamscheck(v,-1,_SC("x")); +#endif +} // sq_pushdirectinstanceclosureglobal + +// === Class Instance call: class pointer retrieved from script class instance (variable arguments) === + +template +inline void sq_pushdirectinstanceclosurevarargs(HSQUIRRELVM v,const Callee & callee,int (Callee::*func)(HSQUIRRELVM),SQUnsignedInteger nupvalues) { + unsigned char * up = (unsigned char *)sq_newuserdata(v,sizeof(func)); // Also pushed on stack. + memcpy(up,&func,sizeof(func)); + typedef int (Callee::*FuncType)(HSQUIRRELVM); + sq_newclosure(v,DirectCallInstanceMemberFunctionVarArgs::Dispatch,nupvalues+1); +} // sq_pushdirectinstanceclosurevarargs + +// === Register a STANDARD function (table or class on stack) === + +template +inline void Register(HSQUIRRELVM v,Func func,const SQChar * name) { + sq_pushstring(v,name,-1); + sq_pushdirectclosure(v,func,0); + sq_createslot(v,-3); // Stack is restored after this call (same state as before Register() call). +} // Register + +// === Register a MEMBER function (table or class on stack) === + +template +inline void Register(HSQUIRRELVM v,Callee & callee,Func func,const SQChar * name) { + sq_pushstring(v,name,-1); + sq_pushdirectclosure(v,callee,func,0); + sq_createslot(v,-3); // Stack is restored after this call (same state as before Register() call). +} // Register + +// === Register a STANDARD global function (root table) === + +template +inline void RegisterGlobal(HSQUIRRELVM v,Func func,const SQChar * name) { + sq_pushroottable(v); + Register(v,func,name); + sq_poptop(v); // Remove root table. +} // RegisterGlobal + +template +inline void RegisterGlobal(Func func,const SQChar * name) { + RegisterGlobal(SquirrelVM::GetVMPtr(),func,name); +} // RegisterGlobal + +// === Register a MEMBER global function (root table) === + +template +inline void RegisterGlobal(HSQUIRRELVM v,Callee & callee,Func func,const SQChar * name) { + sq_pushroottable(v); + Register(v,callee,func,name); + sq_poptop(v); // Remove root table. +} // RegisterGlobal + +template +inline void RegisterGlobal(Callee & callee,Func func,const SQChar * name) { + RegisterGlobal(SquirrelVM::GetVMPtr(),callee,func,name); +} // RegisterGlobal + +// === Register a STANDARD function (hso is table or class) === + +template +inline void Register(HSQUIRRELVM v,HSQOBJECT hso,Func func,const SQChar * name) { + sq_pushobject(v,hso); + Register(v,func,name); + sq_poptop(v); // Remove hso. +} // Register + +// === Register a MEMBER function (hso is table or class) === +// === Fixed Class pointer call (always calls with object pointer that was registered) === + +template +inline void Register(HSQUIRRELVM v,HSQOBJECT hso,Callee & callee,Func func,const SQChar * name) { + sq_pushobject(v,hso); + Register(v,callee,func,name); + sq_poptop(v); // Remove hso. +} // Register + +// === Register an INSTANCE MEMBER function === +// === Class Instance call: class pointer retrieved from script class instance === + +template +inline void RegisterInstance(HSQUIRRELVM v,HSQOBJECT hclass,Callee & callee,Func func,const SQChar * name) { + sq_pushobject(v,hclass); + sq_pushstring(v,name,-1); + sq_pushdirectinstanceclosure(v,callee,func,0); + sq_createslot(v,-3); + sq_poptop(v); // Remove hclass. +} // RegisterInstance + + +// === Register an INSTANCE GLOBAL MEMBER function === +// === Class Instance call: class pointer retrieved from script class instance === +// Allows embedding global func that takes Callee as 1st arg as a member func +template +inline void RegisterInstanceGlobalFunc(HSQUIRRELVM v,HSQOBJECT hclass,Callee & callee,Func func,const SQChar * name) { + sq_pushobject(v,hclass); + sq_pushstring(v,name,-1); + sq_pushdirectinstanceclosureglobal(v,callee,func,0); + sq_createslot(v,-3); + sq_poptop(v); // Remove hclass. +} // RegisterInstanceGlobaFunc + +// === Register an INSTANCE GLOBAL MEMBER WITH VAR ARGS function === +// === Class Instance call: class pointer retrieved from script class instance === +// Allows embedding global func that takes Callee as 1st arg as a member func +template +inline void RegisterInstanceGlobalFuncVarArgs(HSQUIRRELVM v,HSQOBJECT hclass,Callee & callee,Func func,const SQChar * name) { + sq_pushobject(v,hclass); + sq_pushstring(v,name,-1); + sq_pushdirectinstanceclosureglobalvarargs(v,callee,func,0); + sq_createslot(v,-3); + sq_poptop(v); // Remove hclass. +} // RegisterInstanceGlobaFunc + +#ifdef SQPLUS_SMARTPOINTER_OPT +#define SQPLUS_SMARTPOINTER_REGISTER_INSTANCE +#include "SqPlusSmartPointer.h" +#endif + +#ifdef _MSC_VER +#pragma warning(disable : 4995) // Deprecated _snprintf +#endif + +// === Register an INSTANCE MEMBER function Variable Arguments === +// typeMask: "*" means don't check parameters, typeMask=0 means function takes no arguments (and is type checked for that case). +// All the other Squirrel type-masks are passed normally. + +template +inline void RegisterInstanceVarArgs(HSQUIRRELVM v,HSQOBJECT hclass,Callee & callee,int (Callee::*func)(HSQUIRRELVM),const SQChar * name,const SQChar * typeMask=_SC("*")) { + sq_pushobject(v,hclass); + sq_pushstring(v,name,-1); + sq_pushdirectinstanceclosurevarargs(v,callee,func,0); + SQChar tm[64]; + SQChar * ptm = tm; + int numParams = SQ_MATCHTYPEMASKSTRING; + if (typeMask) { + if (typeMask[0] == '*') { + ptm = 0; // Variable args: don't check parameters. +// numParams = 0; // Clear SQ_MATCHTYPEMASKSTRING (does not mean match 0 params. See sq_setparamscheck()). + } else { + if (SCSNPRINTF(tm,sizeof(tm),_SC("x%s"),typeMask) < 0) { // Must be an instance. + throw SquirrelError(_SC("RegisterInstanceVarArgs: typeMask string too long.")); + } // if + } // if + } else { // Need to check object type on stack: table, class, instance, etc. +// _snprintf(tm,sizeof(tm),"x"); // instance. + tm[0] = 'x'; + tm[1] = 0; + } // if + if (ptm) { // If ptm == 0, don't check type. + sq_setparamscheck(v,numParams,ptm); // Determine arg count from type string. + } // if +#ifdef _DEBUG + sq_setnativeclosurename(v,-1,name); // For debugging only. +#endif + sq_createslot(v,-3); + sq_poptop(v); // Remove hclass. +} // RegisterInstanceVarArgs + +#ifdef _MSC_VER +#pragma warning(default : 4995) +#endif + +// === Call Squirrel Functions from C/C++ === +// No type checking is performed for Squirrel functions as Squirrel types are dynamic: +// Incoming types are passed unchanged to Squirrel functions. The parameter count is checked: an exception is thrown if mismatched. +// Return values must match the RT template argument type, else an exception can be thrown on return. + +template +struct SquirrelFunction { + HSQUIRRELVM v; + SquirrelObject object; // Table or class. + SquirrelObject func; + SquirrelFunction() : v(0) {} + SquirrelFunction(HSQUIRRELVM _v,const SquirrelObject & _object,const SquirrelObject & _func) : v(_v), object(_object), func(_func) {} + SquirrelFunction(const SquirrelObject & _object,const SquirrelObject & _func) : v(SquirrelVM::GetVMPtr()), object(_object), func(_func) {} + SquirrelFunction(const SquirrelObject & _object,const SQChar * name) { + v = SquirrelVM::GetVMPtr(); + object = _object; + func = object.GetValue(name); + } + SquirrelFunction(const SQChar * name) { + v = SquirrelVM::GetVMPtr(); + object = SquirrelVM::GetRootTable(); + func = object.GetValue(name); + } + + // Release references and reset internal objects to null. + void reset(void) { + func.Reset(); + object.Reset(); + } // Reset + +#define SQPLUS_CHECK_FNCALL(res) if (!SQ_SUCCEEDED(res)) throw SquirrelError(_SC("SquirrelFunction<> call failed")) + + RT operator()(void) { + sq_pushobject(v,func.GetObjectHandle()); + sq_pushobject(v,object.GetObjectHandle()); + SQPLUS_CHECK_FNCALL(sq_call(v,1,SQTrue,SQ_CALL_RAISE_ERROR)); + return GetRet(TypeWrapper(),v,-1); + } + + template + RT operator()(P1 p1) { + sq_pushobject(v,func.GetObjectHandle()); + sq_pushobject(v,object.GetObjectHandle()); + Push(v,p1); + SQPLUS_CHECK_FNCALL(sq_call(v,2,SQTrue,SQ_CALL_RAISE_ERROR)); + return GetRet(TypeWrapper(),v,-1); + } + + template + RT operator()(P1 p1,P2 p2) { + sq_pushobject(v,func.GetObjectHandle()); + sq_pushobject(v,object.GetObjectHandle()); + Push(v,p1); + Push(v,p2); + SQPLUS_CHECK_FNCALL(sq_call(v,3,SQTrue,SQ_CALL_RAISE_ERROR)); + return GetRet(TypeWrapper(),v,-1); + } + + template + RT operator()(P1 p1,P2 p2,P3 p3) { + sq_pushobject(v,func.GetObjectHandle()); + sq_pushobject(v,object.GetObjectHandle()); + Push(v,p1); + Push(v,p2); + Push(v,p3); + SQPLUS_CHECK_FNCALL(sq_call(v,4,SQTrue,SQ_CALL_RAISE_ERROR)); + return GetRet(TypeWrapper(),v,-1); + } + + template + RT operator()(P1 p1,P2 p2,P3 p3,P4 p4) { + sq_pushobject(v,func.GetObjectHandle()); + sq_pushobject(v,object.GetObjectHandle()); + Push(v,p1); + Push(v,p2); + Push(v,p3); + Push(v,p4); + SQPLUS_CHECK_FNCALL(sq_call(v,5,SQTrue,SQ_CALL_RAISE_ERROR)); + return GetRet(TypeWrapper(),v,-1); + } + + template + RT operator()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5) { + sq_pushobject(v,func.GetObjectHandle()); + sq_pushobject(v,object.GetObjectHandle()); + Push(v,p1); + Push(v,p2); + Push(v,p3); + Push(v,p4); + Push(v,p5); + SQPLUS_CHECK_FNCALL(sq_call(v,6,SQTrue,SQ_CALL_RAISE_ERROR)); + return GetRet(TypeWrapper(),v,-1); + } + + template + RT operator()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6) { + sq_pushobject(v,func.GetObjectHandle()); + sq_pushobject(v,object.GetObjectHandle()); + Push(v,p1); + Push(v,p2); + Push(v,p3); + Push(v,p4); + Push(v,p5); + Push(v,p6); + SQPLUS_CHECK_FNCALL(sq_call(v,7,SQTrue,SQ_CALL_RAISE_ERROR)); + return GetRet(TypeWrapper(),v,-1); + } + + template + RT operator()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7) { + sq_pushobject(v,func.GetObjectHandle()); + sq_pushobject(v,object.GetObjectHandle()); + Push(v,p1); + Push(v,p2); + Push(v,p3); + Push(v,p4); + Push(v,p5); + Push(v,p6); + Push(v,p7); + SQPLUS_CHECK_FNCALL(sq_call(v,8,SQTrue,SQ_CALL_RAISE_ERROR)); + return GetRet(TypeWrapper(),v,-1); + } + +}; + +// === Class/Struct registration === + +#define SQ_DELETE_CLASS(CLASSTYPE) if (up) { CLASSTYPE * self = (CLASSTYPE *)up; delete self;} return 0 +#define SQ_DECLARE_RELEASE(CLASSTYPE) \ + static int release(SQUserPointer up,SQInteger size) { \ + SQ_DELETE_CLASS(CLASSTYPE); \ + } + +template +struct ReleaseClassPtrPtr { + static int release(SQUserPointer up,SQInteger size) { + if (up) { + T ** self = (T **)up; + delete *self; + } // if + return 0; + } // release +}; + +template +struct ReleaseClassPtr { + static int release(SQUserPointer up,SQInteger size) { + if (up) { + T * self = (T *)up; + delete self; + } // if + return 0; + } // release +}; + +BOOL CreateClass(HSQUIRRELVM v,SquirrelObject & newClass,SQUserPointer classType,const SQChar * name,const SQChar * baseName=0); + + +template +inline void PopulateAncestry(HSQUIRRELVM v, + SquirrelObject &instance, + T *newClass) +{ + // 11/2/05: Create a new table for this instance. + SquirrelObject newObjectTable = SquirrelVM::CreateTable(); + // 64-bit compatible version. + newObjectTable.SetUserPointer(INT((size_t)ClassType::type()), newClass); + instance.SetValue(SQ_CLASS_OBJECT_TABLE_NAME, newObjectTable); + + SquirrelObject classHierArray = instance.GetValue(SQ_CLASS_HIER_ARRAY); + INT count = classHierArray.Len(); + + // This will be true when more than one C/C++ class is in the hierarchy. + if (count > 1) { + --count; // Skip the most-derived class. + for (INT i = 0; i < count; i++) { + // Kamaitati's changes for C++ inheritance support. jcs 5/28/06 + SquirrelObject so = classHierArray.GetValue(i); + sq_pushobject(v,so.GetObjectHandle()); + SQUserPointer typeTag; + sq_gettypetag(v,-1,&typeTag); + newObjectTable.SetUserPointer(INT(size_t(typeTag)),newClass); + sq_poptop(v); + } + } +} + + +// Call PostConstruct() at the end of custom constructors. +template +inline int PostConstruct(HSQUIRRELVM v, T *newClass, SQRELEASEHOOK hook) +{ +#ifdef SQ_USE_CLASS_INHERITANCE + StackHandler sa(v); + HSQOBJECT ho = sa.GetObjectHandle(1); // OT_INSTANCE + SquirrelObject instance(ho); + PopulateAncestry(v, instance, newClass); +#endif // SQ_USE_CLASS_INHERITANCE + + sq_setinstanceup(v, 1, newClass); + sq_setreleasehook(v, 1, hook); + return TRUE; +} // PostConstruct + +inline int PostConstructSimple(HSQUIRRELVM v, void *newClass, SQRELEASEHOOK hook){ + sq_setinstanceup(v, 1, newClass); + sq_setreleasehook(v, 1, hook); + return TRUE; +} // PostConstructSimple + + +template +struct ConstructReleaseClass { + static int construct(HSQUIRRELVM v) { + return PostConstruct(v,new T(),release); + } // construct + SQ_DECLARE_RELEASE(T) +}; + +# ifdef SQPLUS_ENABLE_TYPEOF +template +int sq_typeof(HSQUIRRELVM v) { + sq_pushstring(v,TypeInfo().typeName,-1); + return 1; +} +# endif + +// === Helper for RegisterClassType*() === +inline void setupClassHierarchy(SquirrelObject newClass) { + // New member vars cannot be added to instances (OT_INSTANCE): additions must occur on the defining class (OT_CLASS), before any instances are instantiated. + if (!newClass.Exists(SQ_CLASS_OBJECT_TABLE_NAME)) { // Will always get table from most-derived registered class. + SquirrelObject objectTable = SquirrelVM::CreateTable(); + newClass.SetValue(SQ_CLASS_OBJECT_TABLE_NAME,objectTable); // Constructors must add their 'this' pointer indexed by type to this table. See PostConstruct() above. + // 11/2/05: This table will behave as a static global for each instance unless overwritten during construction (see PostConstruct() above). + } // if + SquirrelObject classHierArray; + if (!newClass.Exists(SQ_CLASS_HIER_ARRAY)) { // Will always get table from most-derived registered class. + classHierArray = SquirrelVM::CreateArray(0); // The only constructor called will be the most-derived class: this array contains all classes in the hierarchy to be constructed. + newClass.SetValue(SQ_CLASS_HIER_ARRAY,classHierArray); + } else { + classHierArray = newClass.GetValue(SQ_CLASS_HIER_ARRAY); + } // if + classHierArray.ArrayAppend(newClass); // Add the class to the hierarchy array. The array values will be released and replaced with UserData to free created ancestor classes. +} // setupClassHierarchy + + +template +inline SquirrelObject RegisterClassType(HSQUIRRELVM v,const SQChar * scriptClassName,const SQChar * baseScriptClassName=0) { + int top = sq_gettop(v); + SquirrelObject newClass; + if (CreateClass(v,newClass,(SQUserPointer)ClassType::type(),scriptClassName,baseScriptClassName)) { + SquirrelVM::CreateFunction(newClass,&ConstructReleaseClass::construct,_SC("constructor")); +# ifdef SQ_USE_CLASS_INHERITANCE + setupClassHierarchy(newClass); +# endif +# ifdef SQPLUS_ENABLE_TYPEOF + SquirrelVM::CreateFunction(newClass,&sq_typeof,_SC("_typeof")); +# endif + } // if + sq_settop(v,top); + return newClass; +} // RegisterClassType + +template +inline SquirrelObject RegisterClassTypeNoConstructor(HSQUIRRELVM v,const SQChar * scriptClassName,const SQChar * baseScriptClassName=0) { + int top = sq_gettop(v); + SquirrelObject newClass; + if (CreateClass(v,newClass,(SQUserPointer)ClassType::type(),scriptClassName,baseScriptClassName)) { +# ifdef SQ_USE_CLASS_INHERITANCE + setupClassHierarchy(newClass); +# endif +# ifdef SQPLUS_ENABLE_TYPEOF + SquirrelVM::CreateFunction(newClass,&sq_typeof,_SC("_typeof")); +# endif + } // if + sq_settop(v,top); + return newClass; +} // RegisterClassTypeNoConstructor + + +// === Define and register a C++ class and its members for use with Squirrel === +// Constructors+destructors are automatically created. Custom constructors must use the +// standard SQFUNCTION signature if variable argument types are required (overloads). +// See testSqPlus2.cpp for examples. + +// Do not use SQClassDefBase<> directly, use SQClassDef<> or SQClassDefNoConstructor<>, below. +template +struct SQClassDefBase { + HSQUIRRELVM v; + const SQChar * name; + SquirrelObject newClass; + +#if defined(SQ_USE_CLASS_INHERITANCE) || defined(SQ_USE_CLASS_INHERITANCE_SIMPLE) + const SQChar * base; + // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). + SQClassDefBase(HSQUIRRELVM _v,const SQChar * _name=0,const SQChar * _base=0) : v(_v), name(_name), base(_base) {InitBase();} + // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). + SQClassDefBase(const SQChar * _name=0,const SQChar * _base=0) : v(SquirrelVM::GetVMPtr()), name(_name), base(_base) {InitBase(TypeWrapper());} + template + void InitBase(TypeWrapper){ /*assert(base);*/ ClassType::Get()->SetBase(TypeWrapper()); CheckInitDefaultNames(); } + void InitBase(TypeWrapper){ /*assert(!base);*/ CheckInitDefaultNames(); } + void CheckInitDefaultNames(){ if( !name ) name=TypeInfo().typeName; if( !base ) base=TypeInfo().typeName; } +#else + SQClassDefBase(HSQUIRRELVM _v,const SQChar * _name=0) : v(_v), name(_name) { CheckInitDefaultName(); } + SQClassDefBase(const SQChar * _name=0) : v(SquirrelVM::GetVMPtr()), name(_name) { CheckInitDefaultName(); } + void CheckInitDefaultName(){ if( !name ) name=TypeInfo().typeName; } +#endif + + // Register a member function. + template + SQClassDefBase & func(Func pfunc,const SQChar * name) { + RegisterInstance(v,newClass.GetObjectHandle(),*(TClassType *)0,pfunc,name); + return *this; + } // func + + // Register a global function as a member function (the global takes a Callee*/& as first arg). + template + SQClassDefBase & globMembFunc(Func pfunc,const SQChar * name) { + RegisterInstanceGlobalFunc(v,newClass.GetObjectHandle(),*(TClassType *)0,pfunc,name); + return *this; + } // globMemberFunc + + // Register a global function as a member function (the global takes a Callee*/& as first arg and SQVM* as 2nd). + template + SQClassDefBase & globMembFuncVarArgs(Func pfunc,const SQChar * name) { + RegisterInstanceGlobalFuncVarArgs(v,newClass.GetObjectHandle(),*(TClassType *)0,pfunc,name); + return *this; + } // globMemberFuncVarArgs + +#ifdef SQPLUS_SMARTPOINTER_OPT +#define SQPLUS_SMARTPOINTER_CLASS_DEF_FUNC +#include "SqPlusSmartPointer.h" +#endif + + // Register a variable-argument member function (supports variable+multiple return values). + // typeMask: "*" means don't check parameters, typeMask=0 means function takes no arguments (and is type checked for that case). + // All the other Squirrel type-masks are passed normally. + template + SQClassDefBase & funcVarArgs(Func pfunc,const SQChar * name,const SQChar * typeMask=_SC("*")) { + RegisterInstanceVarArgs(v,newClass.GetObjectHandle(),*(TClassType *)0,pfunc,name,typeMask); + return *this; + } // funcVarArgs + + // === BEGIN static-member+global function registration === + + // === This version is for static member functions only, such as custom constructors where 'this' is not yet valid === + // typeMask: "*" means don't check parameters, typeMask=0 means function takes no arguments (and is type checked for that case). + // All the other Squirrel type-masks are passed normally. + + template + SQClassDefBase & staticFuncVarArgs(Func pfunc,const SQChar * name,const SQChar * typeMask=_SC("*")) { + SquirrelVM::PushObject(newClass); + SquirrelVM::CreateFunction(pfunc,name,typeMask); + SquirrelVM::Pop(1); + return *this; + } // staticFuncVarArgs + + // Register a standard global function (effectively embedding a global function in TClassType's script namespace: does not need or use a 'this' pointer). + template + SQClassDefBase & staticFunc(Func pfunc,const SQChar * name) { + Register(v,newClass.GetObjectHandle(),pfunc,name); + return *this; + } // staticFunc + + // Register a function to a pre-allocated class/struct member function: will use callee's 'this' (effectively embedding a global function in TClassType's script namespace). + template + SQClassDefBase & staticFunc(Callee & callee,Func pfunc,const SQChar * name) { + Register(v,newClass.GetObjectHandle(),callee,pfunc,name); + return *this; + } // staticFunc + + // === END static+global function registration === + + // Register a member variable. + template + SQClassDefBase & var(VarType TClassType::* pvar,const SQChar * name,VarAccessType access=VAR_ACCESS_READ_WRITE) { + struct CV { + VarType TClassType::* var; + } cv; // Cast Variable helper. + cv.var = pvar; + RegisterInstanceVariable(newClass,ClassType::type(),*(VarType **)&cv,name,access); + return *this; + } // var + + // Register a member variable as a UserPointer (read only). + template + SQClassDefBase & varAsUserPointer(VarType TClassType::* pvar,const SQChar * name) { + struct CV { + VarType TClassType::* var; + } cv; // Cast Variable helper. + cv.var = pvar; + RegisterInstanceVariable(newClass,ClassType::type(),*(SQAnything **)&cv,name,VAR_ACCESS_READ_ONLY); + return *this; + } // varAsUserPointer + +#ifdef SQPLUS_SMARTPOINTER_OPT +#define SQPLUS_SMARTPOINTER_CLASS_DEF_VAR +#include "SqPlusSmartPointer.h" +#endif + + template + SQClassDefBase & staticVar(VarType * pvar,const SQChar * name,VarAccessType access=VAR_ACCESS_READ_WRITE) { + struct CV { + VarType * var; + } cv; // Cast Variable helper. + cv.var = pvar; + RegisterInstanceVariable(newClass,ClassType::type(),*(VarType **)&cv,name,VarAccessType(access|VAR_ACCESS_STATIC)); + return *this; + } // staticVar + +#ifdef SQPLUS_CONST_OPT +#define SQ_REG_CONST_STATIC_VAR +#include "SqPlusConst.h" +#endif + + // Member / static member script vars (ordinary Squirrel vars) + SQClassDefBase & scriptVar( const SQChar* name, int ival, SQBool static_var=SQFalse ) { + HSQUIRRELVM v = SquirrelVM::GetVMPtr(); + sq_pushobject(v,newClass.GetObjectHandle()); + sq_pushstring(v,name,-1); + sq_pushinteger(v,ival); + sq_newslot(v,-3,static_var); + sq_pop(v,1); + return *this; + } + + SQClassDefBase & scriptVar( const SQChar* name, double fval, SQBool static_var=SQFalse ) { + HSQUIRRELVM v = SquirrelVM::GetVMPtr(); + sq_pushobject(v,newClass.GetObjectHandle()); + sq_pushstring(v,name,-1); + sq_pushfloat(v,fval); + sq_newslot(v,-3,static_var); + sq_pop(v,1); + return *this; + } + + SQClassDefBase & scriptVar( const SQChar* name, const SQChar* sval, SQBool static_var=SQFalse ) { + HSQUIRRELVM v = SquirrelVM::GetVMPtr(); + sq_pushobject(v,newClass.GetObjectHandle()); + sq_pushstring(v,name,-1); + sq_pushstring(v,sval,-1); + sq_newslot(v,-3,static_var); + sq_pop(v,1); + return *this; + } + + // Register a constant (read-only in script, passed by value (only INT, FLOAT, or BOOL types)). + template + SQClassDefBase & constant(ConstantType constant,const SQChar * name) { + RegisterInstanceConstant(newClass,ClassType::type(),constant,name); + return *this; + } // constant + + // Register an enum as an integer (read-only in script). + SQClassDefBase & enumInt(int constant,const SQChar * name) { + RegisterInstanceConstant(newClass,ClassType::type(),constant,name); + return *this; + } // enumInt + +#ifdef SQPLUS_OVERLOAD_OPT +#define SQPLUS_OVERLOAD_IMPLEMENTATION +#include "SqPlusOverload.h" +#endif +}; + +#ifdef SQPLUS_OVERLOAD_OPT +#define SQPLUS_OVERLOAD_FUNCTIONS +#include "SqPlusOverload.h" +#endif + +template +struct SQClassDef : public SQClassDefBase { + +#if defined(SQ_USE_CLASS_INHERITANCE) || defined(SQ_USE_CLASS_INHERITANCE_SIMPLE) + // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). + SQClassDef(HSQUIRRELVM _v,const SQChar * _name=0,const SQChar * _base=0) : SQClassDefBase(_v,_name,_base) { + SQClassDefBase::newClass = + RegisterClassType( SQClassDefBase::v, + SQClassDefBase::name, + SQClassDefBase::base ); + } + // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). + SQClassDef(const SQChar * _name=0,const SQChar * _base=0) : SQClassDefBase(_name,_base) { + SQClassDefBase::newClass = + RegisterClassType< TClassType>( SQClassDefBase::v, + SQClassDefBase::name, + SQClassDefBase::base ); + } +#else + SQClassDef(HSQUIRRELVM _v,const SQChar * _name=0) : SQClassDefBase(_v,_name) { + SQClassDefBase::newClass = + RegisterClassType(SQClassDefBase::v, + SQClassDefBase::name ); + } + SQClassDef(const SQChar * _name=0) : SQClassDefBase(_name) { + SQClassDefBase::newClass = + RegisterClassType(SQClassDefBase::v, + SQClassDefBase::name ); + } +#endif +}; + +template +struct SQClassDefNoConstructor : public SQClassDefBase { +#if defined(SQ_USE_CLASS_INHERITANCE) || defined(SQ_USE_CLASS_INHERITANCE_SIMPLE) + // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). + SQClassDefNoConstructor(HSQUIRRELVM _v,const SQChar * _name=0,const SQChar * _base=0) : SQClassDefBase(_v,_name,_base) { + SQClassDefBase::newClass = RegisterClassTypeNoConstructor(SQClassDefBase::v,SQClassDefBase::name,SQClassDefBase::base); + } + // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). + SQClassDefNoConstructor(const SQChar * _name=0,const SQChar * _base=0) : SQClassDefBase(_name,_base) { + SQClassDefBase::newClass = RegisterClassTypeNoConstructor(SQClassDefBase::v,SQClassDefBase::name,SQClassDefBase::base); + } +#else + SQClassDefNoConstructor(HSQUIRRELVM _v,const SQChar * _name=0) : SQClassDefBase(_v,_name) { + SQClassDefBase::newClass = RegisterClassTypeNoConstructor(SQClassDefBase::v,SQClassDefBase::name); + } + SQClassDefNoConstructor(const SQChar * _name=0) : SQClassDefBase(_name) { + SQClassDefBase::newClass = RegisterClassTypeNoConstructor(SQClassDefBase::v,SQClassDefBase::name); + } +#endif +}; + + +// === Macros for old style registration. SQClassDef registration is now easier to use (SQ_DECLARE_CLASS() is not needed) === + +#define SQ_DECLARE_CLASS(CLASSNAME) \ +static int _##CLASSNAME##_release(SQUserPointer up,SQInteger size) { \ + if (up) { \ + CLASSNAME * self = (CLASSNAME *)up; \ + delete self; \ + } \ + return 0; \ +} \ +static int _##CLASSNAME##_constructor(HSQUIRRELVM v) { \ + CLASSNAME * pc = new CLASSNAME(); \ + sq_setinstanceup(v,1,pc); \ + sq_setreleasehook(v,1,_##CLASSNAME##_release); \ + return 1; \ +} + +#define SQ_REGISTER_CLASS(CLASSNAME) \ + RegisterClassType(SquirrelVM::GetVMPtr(),_SC(#CLASSNAME),_##CLASSNAME##_constructor) + +#define SQ_REGISTER_INSTANCE(NEWSQCLASS,CCLASS,FUNCNAME) \ + RegisterInstance(SquirrelVM::GetVMPtr(),NEWSQCLASS.GetObjectHandle(),*(CCLASS *)0,&CCLASS::FUNCNAME,_SC(#FUNCNAME)); + +#define SQ_REGISTER_INSTANCE_VARARGS(NEWSQCLASS,CCLASS,FUNCNAME) \ + RegisterInstanceVarArgs(SquirrelVM::GetVMPtr(),NEWSQCLASS.GetObjectHandle(),*(CCLASS *)0,&CCLASS::FUNCNAME,_SC(#FUNCNAME)); + +#define SQ_REGISTER_INSTANCE_VARIABLE(NEWSQCLASS,CCLASS,VARNAME) \ + RegisterInstanceVariable(NEWSQCLASS,&((CCLASS *)0)->VARNAME,_SC(#VARNAME)); + +#if defined(USE_ARGUMENT_DEPENDANT_OVERLOADS) && defined(_MSC_VER) +#pragma warning (default:4675) +#endif + +}; // namespace SqPlus + + +// === BEGIN code suggestion from the Wiki === + +// Get any bound type from this SquirrelObject. Note that Squirrel's +// handling of references and pointers still holds here. +template +inline _ty SquirrelObject::Get(void) { + sq_pushobject(SquirrelVM::_VM,GetObjectHandle()); + _ty val = SqPlus::Get(SqPlus::TypeWrapper<_ty>(),SquirrelVM::_VM,-1); + sq_poptop(SquirrelVM::_VM); + return val; +} + +// Set any bound type to this SquirrelObject. Note that Squirrel's +// handling of references and pointers still holds here. +template +inline SquirrelObject SquirrelObject::SetByValue(_ty val) { // classes/structs should be passed by ref (below) to avoid an extra copy. + SqPlus::Push(SquirrelVM::_VM,val); + AttachToStackObject(-1); + sq_poptop(SquirrelVM::_VM); + return *this; +} + +// Set any bound type to this SquirrelObject. Note that Squirrel's +// handling of references and pointers still holds here. +template +inline SquirrelObject &SquirrelObject::Set(_ty & val) { + SqPlus::Push(SquirrelVM::_VM,val); + AttachToStackObject(-1); + sq_poptop(SquirrelVM::_VM); + return *this; +} + +// === END code suggestion from the Wiki === + +#endif //_SQ_PLUS_H_ diff --git a/squirrel_3_0_1_stable/sqplus/sqplus.vcproj b/squirrel_3_0_1_stable/sqplus/sqplus.vcproj new file mode 100644 index 000000000..fdc22e06b --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/sqplus.vcproj @@ -0,0 +1,355 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/squirrel_3_0_1_stable/sqplus/sqplus.vcxproj b/squirrel_3_0_1_stable/sqplus/sqplus.vcxproj new file mode 100644 index 000000000..fca6ce402 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/sqplus.vcxproj @@ -0,0 +1,159 @@ + + + + + Debug - Unicode + Win32 + + + Debug + Win32 + + + Release - Unicode + Win32 + + + Release + Win32 + + + + {F9811314-C694-49A4-BD87-BA2E7F30D358} + sqplus + Win32Proj + + + + StaticLibrary + Unicode + + + StaticLibrary + Unicode + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(Configuration)\ + $(Configuration)\ + $(Configuration)\ + $(Configuration)\ + $(Configuration)\ + $(Configuration)\ + $(Configuration)\ + $(Configuration)\ + + + + Disabled + ..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ../lib/sqplusD.lib + + + + + ..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ../lib/sqplus.lib + + + + + Disabled + ..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ../lib/sqplusDU.lib + + + + + ..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ../lib/sqplusU.lib + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/squirrel_3_0_1_stable/sqplus/sqplus.vcxproj.filters b/squirrel_3_0_1_stable/sqplus/sqplus.vcxproj.filters new file mode 100644 index 000000000..a61b1ca90 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/sqplus.vcxproj.filters @@ -0,0 +1,65 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/squirrel_3_0_1_stable/sqplus/sqplus.vcxproj.user b/squirrel_3_0_1_stable/sqplus/sqplus.vcxproj.user new file mode 100644 index 000000000..695b5c78b --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/sqplus.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/squirrel_3_0_1_stable/sqplus/sqplus71.vcproj b/squirrel_3_0_1_stable/sqplus/sqplus71.vcproj new file mode 100644 index 000000000..fc3ac5555 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/sqplus71.vcproj @@ -0,0 +1,235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/squirrel_3_0_1_stable/sqplus/sqplusWin32.h b/squirrel_3_0_1_stable/sqplus/sqplusWin32.h new file mode 100644 index 000000000..bf46fd6cf --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/sqplusWin32.h @@ -0,0 +1,7 @@ +#ifndef _SQ_PLUS_WIN32_H_ +#define _SQ_PLUS_WIN32_H_ + +#include "sqplus.h" +#include "SquirrelBindingsUtilsWin32.h" + +#endif //_SQ_PLUS_WIN32_H_ \ No newline at end of file diff --git a/squirrel_3_0_1_stable/sqstdlib/Makefile b/squirrel_3_0_1_stable/sqstdlib/Makefile new file mode 100644 index 000000000..10f6384ea --- /dev/null +++ b/squirrel_3_0_1_stable/sqstdlib/Makefile @@ -0,0 +1,41 @@ +SQUIRREL= .. + + +OUT= $(SQUIRREL)/lib/libsqstdlib.a +INCZ= -I$(SQUIRREL)/include -I. -Iinclude + +OBJS= \ + sqstdblob.o \ + sqstdio.o \ + sqstdstream.o \ + sqstdmath.o \ + sqstdsystem.o \ + sqstdstring.o \ + sqstdaux.o \ + sqstdrex.o + +SRCS= \ + sqstdblob.cpp \ + sqstdio.cpp \ + sqstdstream.cpp \ + sqstdmath.cpp \ + sqstdsystem.cpp \ + sqstdstring.cpp \ + sqstdaux.cpp \ + sqstdrex.cpp + + +sq32: + gcc -O2 -fno-exceptions -fno-rtti -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) + ar rc $(OUT) *.o + rm *.o + +sqprof: + gcc -O2 -pg -fno-exceptions -fno-rtti -pie -gstabs -g3 -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) + ar rc $(OUT) *.o + rm *.o + +sq64: + gcc -O2 -m64 -fno-exceptions -D_SQ64 -fno-rtti -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) + ar rc $(OUT) *.o + rm *.o diff --git a/squirrel_3_0_1_stable/sqstdlib/sqstdaux.cpp b/squirrel_3_0_1_stable/sqstdlib/sqstdaux.cpp new file mode 100644 index 000000000..e115770a8 --- /dev/null +++ b/squirrel_3_0_1_stable/sqstdlib/sqstdaux.cpp @@ -0,0 +1,129 @@ +/* see copyright notice in squirrel.h */ +#include +#include +#include + +void sqstd_printcallstack(HSQUIRRELVM v) +{ + SQPRINTFUNCTION pf = sq_geterrorfunc(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_GENERATOR: + pf(v,_SC("[%s] GENERATOR\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; + case OT_WEAKREF: + pf(v,_SC("[%s] WEAKREF\n"),name); + break; + case OT_BOOL:{ + sq_getinteger(v,-1,&i); + pf(v,_SC("[%s] %s\n"),name,i?_SC("true"):_SC("false")); + } + break; + default: assert(0); break; + } + sq_pop(v,1); + } + } + } +} + +static SQInteger _sqstd_aux_printerror(HSQUIRRELVM v) +{ + SQPRINTFUNCTION pf = sq_geterrorfunc(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_geterrorfunc(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/squirrel_3_0_1_stable/sqstdlib/sqstdblob.cpp b/squirrel_3_0_1_stable/sqstdlib/sqstdblob.cpp new file mode 100644 index 000000000..11b593306 --- /dev/null +++ b/squirrel_3_0_1_stable/sqstdlib/sqstdblob.cpp @@ -0,0 +1,275 @@ +/* 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=(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 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; + self->~SQBlob(); + sq_free(self,sizeof(SQBlob)); + 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); + + SQBlob *b = new (sq_malloc(sizeof(SQBlob)))SQBlob(size); + if(SQ_FAILED(sq_setinstanceup(v,1,b))) { + b->~SQBlob(); + sq_free(b,sizeof(SQBlob)); + return sq_throwerror(v, _SC("cannot create blob")); + } + sq_setreleasehook(v,1,_blob_releasehook); + return 0; +} + +static SQInteger _blob__cloned(HSQUIRRELVM v) +{ + SQBlob *other = NULL; + { + if(SQ_FAILED(sq_getinstanceup(v,2,(SQUserPointer*)&other,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) + return SQ_ERROR; + } + //SQBlob *thisone = new SQBlob(other->Len()); + SQBlob *thisone = new (sq_malloc(sizeof(SQBlob)))SQBlob(other->Len()); + memcpy(thisone->GetBuf(),other->GetBuf(),thisone->Len()); + if(SQ_FAILED(sq_setinstanceup(v,1,thisone))) { + thisone->~SQBlob(); + sq_free(thisone,sizeof(SQBlob)); + return sq_throwerror(v, _SC("cannot clone blob")); + } + 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")), + _DECL_BLOB_FUNC(_cloned,2,_SC("xx")), + {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); + unsigned int t4 = (unsigned int)i; + __swap_dword(&t4); + sq_pushinteger(v,(SQInteger)t4); + return 1; +} + +static SQInteger _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,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,SQFalse)) + && SQ_SUCCEEDED(sq_getinstanceup(v,-1,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) { + 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/squirrel_3_0_1_stable/sqstdlib/sqstdblobimpl.h b/squirrel_3_0_1_stable/sqstdlib/sqstdblobimpl.h new file mode 100644 index 000000000..b2291b73c --- /dev/null +++ b/squirrel_3_0_1_stable/sqstdlib/sqstdblobimpl.h @@ -0,0 +1,108 @@ +/* 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; + } + virtual ~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/squirrel_3_0_1_stable/sqstdlib/sqstdio.cpp b/squirrel_3_0_1_stable/sqstdlib/sqstdio.cpp new file mode 100644 index 000000000..241864bb2 --- /dev/null +++ b/squirrel_3_0_1_stable/sqstdlib/sqstdio.cpp @@ -0,0 +1,419 @@ +/* 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 SQUNICODE + 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,(long)offset,(int)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;} + virtual ~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; + self->~SQFile(); + sq_free(self,sizeof(SQFile)); + 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 (sq_malloc(sizeof(SQFile)))SQFile(newf,owns); + if(SQ_FAILED(sq_setinstanceup(v,1,f))) { + f->~SQFile(); + sq_free(f,sizeof(SQFile)); + 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,SQFalse) )) { + 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_PLAIN(SQUserPointer file) +{ + SQInteger ret; + char c; + if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) ) + return c; + return 0; +} + +#ifdef SQUNICODE +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; +} +#endif + +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_PLAIN; + 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")); + } +#ifdef SQUNICODE + func = _io_file_lexfeed_UTF8; +#else + func = _io_file_lexfeed_PLAIN; +#endif + 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); + if(SQ_SUCCEEDED(sq_call(v,1,retval,SQTrue))) { + 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_writeclosuretofile(HSQUIRRELVM v) +{ + const SQChar *filename; + sq_getstring(v,2,&filename); + if(SQ_SUCCEEDED(sqstd_writeclosuretofile(v,filename))) + 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")), + _DECL_GLOBALIO_FUNC(writeclosuretofile,3,_SC(".sc")), + {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_newslot(v,-3,SQFalse); + sq_pushstring(v,_SC("stdin"),-1); + sqstd_createfile(v,stdin,SQFalse); + sq_newslot(v,-3,SQFalse); + sq_pushstring(v,_SC("stderr"),-1); + sqstd_createfile(v,stderr,SQFalse); + sq_newslot(v,-3,SQFalse); + sq_settop(v,top); + return SQ_OK; +} diff --git a/squirrel_3_0_1_stable/sqstdlib/sqstdlib.dsp b/squirrel_3_0_1_stable/sqstdlib/sqstdlib.dsp new file mode 100644 index 000000000..7453243fe --- /dev/null +++ b/squirrel_3_0_1_stable/sqstdlib/sqstdlib.dsp @@ -0,0 +1,131 @@ +# Microsoft Developer Studio Project File - Name="sqstdlib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=sqstdlib - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "sqstdlib.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "sqstdlib.mak" CFG="sqstdlib - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "sqstdlib - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "sqstdlib - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_LocalPath ".." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "sqstdlib - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x410 /d "NDEBUG" +# ADD RSC /l 0x410 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\lib\sqstdlib.lib" + +!ELSEIF "$(CFG)" == "sqstdlib - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x410 /d "_DEBUG" +# ADD RSC /l 0x410 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\lib\sqstdlib.lib" + +!ENDIF + +# Begin Target + +# Name "sqstdlib - Win32 Release" +# Name "sqstdlib - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\sqstdblob.cpp +# End Source File +# Begin Source File + +SOURCE=.\sqstdio.cpp +# End Source File +# Begin Source File + +SOURCE=.\sqstdmath.cpp +# End Source File +# Begin Source File + +SOURCE=.\sqstdrex.cpp +# End Source File +# Begin Source File + +SOURCE=.\sqstdstream.cpp +# End Source File +# Begin Source File + +SOURCE=.\sqstdstring.cpp +# End Source File +# Begin Source File + +SOURCE=.\sqstdaux.cpp +# End Source File +# Begin Source File + +SOURCE=.\sqstdsystem.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\sqstdblobimpl.h +# End Source File +# Begin Source File + +SOURCE=.\sqstdstream.h +# End Source File +# End Group +# End Target +# End Project diff --git a/squirrel_3_0_1_stable/sqstdlib/sqstdmath.cpp b/squirrel_3_0_1_stable/sqstdlib/sqstdmath.cpp new file mode 100644 index 000000000..ef50359bd --- /dev/null +++ b/squirrel_3_0_1_stable/sqstdlib/sqstdmath.cpp @@ -0,0 +1,107 @@ +/* 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_FAILED(sq_getinteger(v,2,&i))) + return sq_throwerror(v,_SC("invalid param")); + srand((unsigned int)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((int)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}, +}; +#undef _DECL_FUNC + +#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_newslot(v,-3,SQFalse); + i++; + } + sq_pushstring(v,_SC("RAND_MAX"),-1); + sq_pushinteger(v,RAND_MAX); + sq_newslot(v,-3,SQFalse); + sq_pushstring(v,_SC("PI"),-1); + sq_pushfloat(v,(SQFloat)M_PI); + sq_newslot(v,-3,SQFalse); + return SQ_OK; +} diff --git a/squirrel_3_0_1_stable/sqstdlib/sqstdrex.cpp b/squirrel_3_0_1_stable/sqstdlib/sqstdrex.cpp new file mode 100644 index 000000000..921597fed --- /dev/null +++ b/squirrel_3_0_1_stable/sqstdlib/sqstdrex.cpp @@ -0,0 +1,638 @@ +/* see copyright notice in squirrel.h */ +#include +#include +#include +#include +#include + +#ifdef _UINCODE +#define scisprint iswprint +#else +#define scisprint isprint +#endif + +#ifdef _DEBUG +#include + +static const SQChar *g_nnames[] = +{ + _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"), + _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"), + _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"), + _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB") +}; + +#endif + +#define OP_GREEDY (MAX_CHAR+1) // * + ? {n} +#define OP_OR (MAX_CHAR+2) +#define OP_EXPR (MAX_CHAR+3) //parentesis () +#define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:) +#define OP_DOT (MAX_CHAR+5) +#define OP_CLASS (MAX_CHAR+6) +#define OP_CCLASS (MAX_CHAR+7) +#define OP_NCLASS (MAX_CHAR+8) //negates class the [^ +#define OP_RANGE (MAX_CHAR+9) +#define OP_CHAR (MAX_CHAR+10) +#define OP_EOL (MAX_CHAR+11) +#define OP_BOL (MAX_CHAR+12) +#define OP_WB (MAX_CHAR+13) + +#define SQREX_SYMBOL_ANY_CHAR ('.') +#define SQREX_SYMBOL_GREEDY_ONE_OR_MORE ('+') +#define SQREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*') +#define SQREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?') +#define SQREX_SYMBOL_BRANCH ('|') +#define SQREX_SYMBOL_END_OF_STRING ('$') +#define SQREX_SYMBOL_BEGINNING_OF_STRING ('^') +#define SQREX_SYMBOL_ESCAPE_CHAR ('\\') + + +typedef int SQRexNodeType; + +typedef struct tagSQRexNode{ + SQRexNodeType type; + SQInteger left; + SQInteger right; + SQInteger next; +}SQRexNode; + +struct SQRex{ + const SQChar *_eol; + const SQChar *_bol; + const SQChar *_p; + SQInteger _first; + SQInteger _op; + SQRexNode *_nodes; + SQInteger _nallocated; + SQInteger _nsize; + SQInteger _nsubexpr; + SQRexMatch *_matches; + SQInteger _currsubexp; + void *_jmpbuf; + const SQChar **_error; +}; + +static SQInteger sqstd_rex_list(SQRex *exp); + +static SQInteger sqstd_rex_newnode(SQRex *exp, SQRexNodeType type) +{ + SQRexNode n; + n.type = type; + n.next = n.right = n.left = -1; + if(type == OP_EXPR) + n.right = exp->_nsubexpr++; + if(exp->_nallocated < (exp->_nsize + 1)) { + 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; + SQInteger newid = exp->_nsize - 1; + return (SQInteger)newid; +} + +static void sqstd_rex_error(SQRex *exp,const SQChar *error) +{ + if(exp->_error) *exp->_error = error; + longjmp(*((jmp_buf*)exp->_jmpbuf),-1); +} + +static void sqstd_rex_expect(SQRex *exp, SQInteger n){ + if((*exp->_p) != n) + sqstd_rex_error(exp, _SC("expected paren")); + exp->_p++; +} + +static SQChar sqstd_rex_escapechar(SQRex *exp) +{ + if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR){ + exp->_p++; + switch(*exp->_p) { + case 'v': exp->_p++; return '\v'; + case 'n': exp->_p++; return '\n'; + case 't': exp->_p++; return '\t'; + case 'r': exp->_p++; return '\r'; + case 'f': exp->_p++; return '\f'; + default: return (*exp->_p++); + } + } else if(!scisprint(*exp->_p)) sqstd_rex_error(exp,_SC("letter expected")); + return (*exp->_p++); +} + +static SQInteger sqstd_rex_charclass(SQRex *exp,SQInteger classid) +{ + SQInteger n = sqstd_rex_newnode(exp,OP_CCLASS); + exp->_nodes[n].left = classid; + return n; +} + +static SQInteger sqstd_rex_charnode(SQRex *exp,SQBool isclass) +{ + SQChar t; + if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) { + exp->_p++; + switch(*exp->_p) { + case 'n': exp->_p++; return sqstd_rex_newnode(exp,'\n'); + case 't': exp->_p++; return sqstd_rex_newnode(exp,'\t'); + case 'r': exp->_p++; return sqstd_rex_newnode(exp,'\r'); + case 'f': exp->_p++; return sqstd_rex_newnode(exp,'\f'); + case 'v': exp->_p++; return sqstd_rex_newnode(exp,'\v'); + case 'a': case 'A': case 'w': case 'W': case 's': case 'S': + case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': + case 'p': case 'P': case 'l': case 'u': + { + t = *exp->_p; exp->_p++; + return sqstd_rex_charclass(exp,t); + } + case 'b': + case 'B': + if(!isclass) { + SQInteger node = sqstd_rex_newnode(exp,OP_WB); + exp->_nodes[node].left = *exp->_p; + exp->_p++; + return node; + } //else default + default: + t = *exp->_p; exp->_p++; + return sqstd_rex_newnode(exp,t); + } + } + else if(!scisprint(*exp->_p)) { + + sqstd_rex_error(exp,_SC("letter expected")); + } + t = *exp->_p; exp->_p++; + return sqstd_rex_newnode(exp,t); +} +static SQInteger sqstd_rex_class(SQRex *exp) +{ + SQInteger ret = -1; + SQInteger first = -1,chain; + if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){ + ret = sqstd_rex_newnode(exp,OP_NCLASS); + exp->_p++; + }else ret = sqstd_rex_newnode(exp,OP_CLASS); + + if(*exp->_p == ']') sqstd_rex_error(exp,_SC("empty class")); + chain = ret; + while(*exp->_p != ']' && exp->_p != exp->_eol) { + if(*exp->_p == '-' && first != -1){ + SQInteger r; + if(*exp->_p++ == ']') sqstd_rex_error(exp,_SC("unfinished range")); + r = sqstd_rex_newnode(exp,OP_RANGE); + if(exp->_nodes[first].type>*exp->_p) sqstd_rex_error(exp,_SC("invalid range")); + if(exp->_nodes[first].type == OP_CCLASS) sqstd_rex_error(exp,_SC("cannot use character classes in ranges")); + exp->_nodes[r].left = exp->_nodes[first].type; + SQInteger t = sqstd_rex_escapechar(exp); + exp->_nodes[r].right = t; + exp->_nodes[chain].next = r; + chain = r; + first = -1; + } + else{ + if(first!=-1){ + SQInteger c = first; + exp->_nodes[chain].next = c; + chain = c; + first = sqstd_rex_charnode(exp,SQTrue); + } + else{ + first = sqstd_rex_charnode(exp,SQTrue); + } + } + } + if(first!=-1){ + SQInteger c = first; + exp->_nodes[chain].next = c; + chain = c; + first = -1; + } + /* hack? */ + exp->_nodes[ret].left = exp->_nodes[ret].next; + exp->_nodes[ret].next = -1; + return ret; +} + +static SQInteger sqstd_rex_parsenumber(SQRex *exp) +{ + SQInteger ret = *exp->_p-'0'; + SQInteger positions = 10; + exp->_p++; + while(isdigit(*exp->_p)) { + ret = ret*10+(*exp->_p++-'0'); + if(positions==1000000000) sqstd_rex_error(exp,_SC("overflow in numeric constant")); + positions *= 10; + }; + return ret; +} + +static SQInteger sqstd_rex_element(SQRex *exp) +{ + SQInteger ret = -1; + switch(*exp->_p) + { + case '(': { + SQInteger expr; + exp->_p++; + + + if(*exp->_p =='?') { + exp->_p++; + sqstd_rex_expect(exp,':'); + expr = sqstd_rex_newnode(exp,OP_NOCAPEXPR); + } + else + expr = sqstd_rex_newnode(exp,OP_EXPR); + SQInteger newn = sqstd_rex_list(exp); + exp->_nodes[expr].left = newn; + ret = expr; + sqstd_rex_expect(exp,')'); + } + break; + case '[': + exp->_p++; + ret = sqstd_rex_class(exp); + sqstd_rex_expect(exp,']'); + break; + case SQREX_SYMBOL_END_OF_STRING: exp->_p++; ret = sqstd_rex_newnode(exp,OP_EOL);break; + case SQREX_SYMBOL_ANY_CHAR: exp->_p++; ret = sqstd_rex_newnode(exp,OP_DOT);break; + default: + ret = sqstd_rex_charnode(exp,SQFalse); + break; + } + + + SQInteger op; + SQBool isgreedy = SQFalse; + unsigned short p0 = 0, p1 = 0; + switch(*exp->_p){ + case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break; + case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break; + case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = SQTrue; break; + case '{': + exp->_p++; + if(!isdigit(*exp->_p)) sqstd_rex_error(exp,_SC("number expected")); + p0 = (unsigned short)sqstd_rex_parsenumber(exp); + /*******************************/ + switch(*exp->_p) { + case '}': + p1 = p0; exp->_p++; + break; + case ',': + exp->_p++; + p1 = 0xFFFF; + if(isdigit(*exp->_p)){ + p1 = (unsigned short)sqstd_rex_parsenumber(exp); + } + sqstd_rex_expect(exp,'}'); + break; + default: + sqstd_rex_error(exp,_SC(", or } expected")); + } + /*******************************/ + isgreedy = SQTrue; + break; + + } + if(isgreedy) { + SQInteger nnode = sqstd_rex_newnode(exp,OP_GREEDY); + op = OP_GREEDY; + exp->_nodes[nnode].left = ret; + exp->_nodes[nnode].right = ((p0)<<16)|p1; + ret = nnode; + } + + if((*exp->_p != SQREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != SQREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != SQREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) { + SQInteger nnode = sqstd_rex_element(exp); + exp->_nodes[ret].next = nnode; + } + + return ret; +} + +static SQInteger sqstd_rex_list(SQRex *exp) +{ + SQInteger ret=-1,e; + if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) { + exp->_p++; + ret = sqstd_rex_newnode(exp,OP_BOL); + } + e = sqstd_rex_element(exp); + if(ret != -1) { + exp->_nodes[ret].next = e; + } + else ret = e; + + if(*exp->_p == SQREX_SYMBOL_BRANCH) { + SQInteger temp,tright; + exp->_p++; + temp = sqstd_rex_newnode(exp,OP_OR); + exp->_nodes[temp].left = ret; + tright = sqstd_rex_list(exp); + exp->_nodes[temp].right = tright; + ret = temp; + } + return ret; +} + +static SQBool sqstd_rex_matchcclass(SQInteger cclass,SQChar c) +{ + switch(cclass) { + case 'a': return isalpha(c)?SQTrue:SQFalse; + case 'A': return !isalpha(c)?SQTrue:SQFalse; + case 'w': return (isalnum(c) || c == '_')?SQTrue:SQFalse; + case 'W': return (!isalnum(c) && c != '_')?SQTrue:SQFalse; + case 's': return isspace(c)?SQTrue:SQFalse; + case 'S': return !isspace(c)?SQTrue:SQFalse; + case 'd': return isdigit(c)?SQTrue:SQFalse; + case 'D': return !isdigit(c)?SQTrue:SQFalse; + case 'x': return isxdigit(c)?SQTrue:SQFalse; + case 'X': return !isxdigit(c)?SQTrue:SQFalse; + case 'c': return iscntrl(c)?SQTrue:SQFalse; + case 'C': return !iscntrl(c)?SQTrue:SQFalse; + case 'p': return ispunct(c)?SQTrue:SQFalse; + case 'P': return !ispunct(c)?SQTrue:SQFalse; + case 'l': return islower(c)?SQTrue:SQFalse; + case 'u': return isupper(c)?SQTrue:SQFalse; + } + return SQFalse; /*cannot happen*/ +} + +static SQBool sqstd_rex_matchclass(SQRex* exp,SQRexNode *node,SQChar c) +{ + do { + switch(node->type) { + case OP_RANGE: + if(c >= node->left && c <= node->right) return SQTrue; + break; + case OP_CCLASS: + if(sqstd_rex_matchcclass(node->left,c)) return SQTrue; + break; + default: + if(c == node->type)return SQTrue; + } + } while((node->next != -1) && (node = &exp->_nodes[node->next])); + return SQFalse; +} + +static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar *str,SQRexNode *next) +{ + + SQRexNodeType type = node->type; + switch(type) { + case OP_GREEDY: { + //SQRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL; + SQRexNode *greedystop = NULL; + SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0; + const SQChar *s=str, *good = str; + + if(node->next != -1) { + greedystop = &exp->_nodes[node->next]; + } + else { + greedystop = next; + } + + while((nmaches == 0xFFFF || nmaches < p1)) { + + const SQChar *stop; + if(!(s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s,greedystop))) + break; + nmaches++; + good=s; + if(greedystop) { + //checks that 0 matches satisfy the expression(if so skips) + //if not would always stop(for instance if is a '?') + if(greedystop->type != OP_GREEDY || + (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0)) + { + SQRexNode *gnext = NULL; + if(greedystop->next != -1) { + gnext = &exp->_nodes[greedystop->next]; + }else if(next && next->next != -1){ + gnext = &exp->_nodes[next->next]; + } + stop = sqstd_rex_matchnode(exp,greedystop,s,gnext); + if(stop) { + //if satisfied stop it + if(p0 == p1 && p0 == nmaches) break; + else if(nmaches >= p0 && p1 == 0xFFFF) break; + else if(nmaches >= p0 && nmaches <= p1) break; + } + } + } + + if(s >= exp->_eol) + break; + } + if(p0 == p1 && p0 == nmaches) return good; + else if(nmaches >= p0 && p1 == 0xFFFF) return good; + else if(nmaches >= p0 && nmaches <= p1) return good; + return NULL; + } + case OP_OR: { + const SQChar *asd = str; + SQRexNode *temp=&exp->_nodes[node->left]; + while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) { + if(temp->next != -1) + temp = &exp->_nodes[temp->next]; + else + return asd; + } + asd = str; + temp = &exp->_nodes[node->right]; + while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) { + if(temp->next != -1) + temp = &exp->_nodes[temp->next]; + else + return asd; + } + return NULL; + break; + } + case OP_EXPR: + case OP_NOCAPEXPR:{ + SQRexNode *n = &exp->_nodes[node->left]; + const SQChar *cur = str; + SQInteger capture = -1; + if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) { + capture = exp->_currsubexp; + exp->_matches[capture].begin = cur; + exp->_currsubexp++; + } + int tempcap = exp->_currsubexp; + do { + SQRexNode *subnext = NULL; + if(n->next != -1) { + subnext = &exp->_nodes[n->next]; + }else { + subnext = next; + } + if(!(cur = sqstd_rex_matchnode(exp,n,cur,subnext))) { + if(capture != -1){ + exp->_matches[capture].begin = 0; + exp->_matches[capture].len = 0; + } + return NULL; + } + } while((n->next != -1) && (n = &exp->_nodes[n->next])); + + exp->_currsubexp = tempcap; + if(capture != -1) + exp->_matches[capture].len = cur - exp->_matches[capture].begin; + return cur; + } + case OP_WB: + if((str == exp->_bol && !isspace(*str)) + || (str == exp->_eol && !isspace(*(str-1))) + || (!isspace(*str) && isspace(*(str+1))) + || (isspace(*str) && !isspace(*(str+1))) ) { + return (node->left == 'b')?str:NULL; + } + return (node->left == 'b')?NULL:str; + case OP_BOL: + if(str == exp->_bol) return str; + return NULL; + case OP_EOL: + if(str == exp->_eol) return str; + return NULL; + case OP_DOT:{ + *str++; + } + return str; + case OP_NCLASS: + case OP_CLASS: + if(sqstd_rex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?SQTrue:SQFalse):(type == OP_NCLASS?SQTrue:SQFalse)) { + *str++; + return str; + } + return NULL; + case OP_CCLASS: + if(sqstd_rex_matchcclass(node->left,*str)) { + *str++; + return str; + } + return NULL; + default: /* char */ + if(*str != node->type) return NULL; + *str++; + return str; + } + return NULL; +} + +/* public api */ +SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error) +{ + SQRex *exp = (SQRex *)sq_malloc(sizeof(SQRex)); + exp->_eol = exp->_bol = NULL; + exp->_p = pattern; + exp->_nallocated = (SQInteger)scstrlen(pattern) * sizeof(SQChar); + exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode)); + exp->_nsize = 0; + exp->_matches = 0; + exp->_nsubexpr = 0; + exp->_first = sqstd_rex_newnode(exp,OP_EXPR); + exp->_error = error; + exp->_jmpbuf = sq_malloc(sizeof(jmp_buf)); + if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) { + SQInteger res = sqstd_rex_list(exp); + exp->_nodes[exp->_first].left = res; + if(*exp->_p!='\0') + sqstd_rex_error(exp,_SC("unexpected character")); +#ifdef _DEBUG + { + SQInteger nsize,i; + SQRexNode *t; + nsize = exp->_nsize; + t = &exp->_nodes[0]; + scprintf(_SC("\n")); + for(i = 0;i < nsize; i++) { + if(exp->_nodes[i].type>MAX_CHAR) + scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]); + else + scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type); + scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next); + } + scprintf(_SC("\n")); + } +#endif + exp->_matches = (SQRexMatch *) sq_malloc(exp->_nsubexpr * sizeof(SQRexMatch)); + memset(exp->_matches,0,exp->_nsubexpr * sizeof(SQRexMatch)); + } + else{ + sqstd_rex_free(exp); + return NULL; + } + return exp; +} + +void sqstd_rex_free(SQRex *exp) +{ + if(exp) { + if(exp->_nodes) sq_free(exp->_nodes,exp->_nallocated * sizeof(SQRexNode)); + if(exp->_jmpbuf) sq_free(exp->_jmpbuf,sizeof(jmp_buf)); + if(exp->_matches) sq_free(exp->_matches,exp->_nsubexpr * sizeof(SQRexMatch)); + sq_free(exp,sizeof(SQRex)); + } +} + +SQBool sqstd_rex_match(SQRex* exp,const SQChar* text) +{ + const SQChar* res = NULL; + exp->_bol = text; + exp->_eol = text + scstrlen(text); + exp->_currsubexp = 0; + res = sqstd_rex_matchnode(exp,exp->_nodes,text,NULL); + if(res == NULL || res != exp->_eol) + return SQFalse; + return SQTrue; +} + +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; + SQInteger node = exp->_first; + if(text_begin >= text_end) return SQFalse; + exp->_bol = text_begin; + exp->_eol = text_end; + do { + cur = text_begin; + while(node != -1) { + exp->_currsubexp = 0; + cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur,NULL); + if(!cur) + break; + node = exp->_nodes[node].next; + } + *text_begin++; + } while(cur == NULL && text_begin != text_end); + + if(cur == NULL) + return SQFalse; + + --text_begin; + + if(out_begin) *out_begin = text_begin; + if(out_end) *out_end = cur; + return SQTrue; +} + +SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end) +{ + return sqstd_rex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end); +} + +SQInteger sqstd_rex_getsubexpcount(SQRex* exp) +{ + return exp->_nsubexpr; +} + +SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp) +{ + if( n<0 || n >= exp->_nsubexpr) return SQFalse; + *subexp = exp->_matches[n]; + return SQTrue; +} + diff --git a/squirrel_3_0_1_stable/sqstdlib/sqstdstream.cpp b/squirrel_3_0_1_stable/sqstdlib/sqstdstream.cpp new file mode 100644 index 000000000..29fbdd601 --- /dev/null +++ b/squirrel_3_0_1_stable/sqstdlib/sqstdstream.cpp @@ -0,0 +1,336 @@ +/* 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_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 'l': { + SQInteger i; + SAFE_READN(&i, sizeof(i)); + sq_pushinteger(v, i); + } + break; + case 'i': { + SQInt32 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_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 'l': { + SQInteger i; + sq_getinteger(v, 2, &ti); + i = ti; + self->Write(&i, sizeof(SQInteger)); + } + break; + case 'i': { + SQInt32 i; + sq_getinteger(v, 2, &ti); + i = (SQInt32)ti; + self->Write(&i, sizeof(SQInt32)); + } + break; + case 's': { + short s; + sq_getinteger(v, 2, &ti); + s = (short)ti; + self->Write(&s, sizeof(short)); + } + break; + case 'w': { + unsigned short w; + sq_getinteger(v, 2, &ti); + w = (unsigned short)ti; + self->Write(&w, sizeof(unsigned short)); + } + break; + case 'c': { + char c; + sq_getinteger(v, 2, &ti); + c = (char)ti; + self->Write(&c, sizeof(char)); + } + break; + case 'b': { + unsigned char b; + sq_getinteger(v, 2, &ti); + b = (unsigned char)ti; + self->Write(&b, sizeof(unsigned char)); + } + break; + case 'f': { + float f; + sq_getfloat(v, 2, &tf); + f = (float)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; +} + + SQInteger _stream__cloned(HSQUIRRELVM v) + { + return sq_throwerror(v,_SC("this object cannot be cloned")); + } + +static SQRegFunction _stream_methods[] = { + _DECL_STREAM_FUNC(readblob,2,_SC("xn")), + _DECL_STREAM_FUNC(readn,2,_SC("xn")), + _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")), + _DECL_STREAM_FUNC(_cloned,0,NULL), + {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_newslot(v,-3,SQFalse); + i++; + } + sq_newslot(v,-3,SQFalse); + sq_pushroottable(v); + sq_pushstring(v,_SC("stream"),-1); + sq_pushstring(v,_SC("std_stream"),-1); + sq_get(v,-4); + sq_newslot(v,-3,SQFalse); + sq_pop(v,1); + } + else { + sq_pop(v,1); //result + } + sq_pop(v,1); +} + +SQRESULT declare_stream(HSQUIRRELVM v,const SQChar* name,SQUserPointer typetag,const 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_newslot(v,-3,SQFalse); + i++; + } + sq_newslot(v,-3,SQFalse); + 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_newslot(v,-3,SQFalse); + 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_newslot(v,-3,SQFalse); + + sq_settop(v,top); + return SQ_OK; + } + sq_settop(v,top); + return SQ_ERROR; +} diff --git a/squirrel_3_0_1_stable/sqstdlib/sqstdstream.h b/squirrel_3_0_1_stable/sqstdlib/sqstdstream.h new file mode 100644 index 000000000..1595251e7 --- /dev/null +++ b/squirrel_3_0_1_stable/sqstdlib/sqstdstream.h @@ -0,0 +1,18 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_STREAM_H_ +#define _SQSTD_STREAM_H_ + +SQInteger _stream_readblob(HSQUIRRELVM v); +SQInteger _stream_readline(HSQUIRRELVM v); +SQInteger _stream_readn(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,const SQChar* name,SQUserPointer typetag,const SQChar* reg_name,SQRegFunction *methods,SQRegFunction *globals); +#endif /*_SQSTD_STREAM_H_*/ diff --git a/squirrel_3_0_1_stable/sqstdlib/sqstdstring.cpp b/squirrel_3_0_1_stable/sqstdlib/sqstdstring.cpp new file mode 100644 index 000000000..aaa37dfde --- /dev/null +++ b/squirrel_3_0_1_stable/sqstdlib/sqstdstring.cpp @@ -0,0 +1,378 @@ +/* see copyright notice in squirrel.h */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef SQUNICODE +#define scstrchr wcschr +#define scsnprintf wsnprintf +#define scatoi _wtoi +#define scstrtok wcstok +#else +#define scstrchr strchr +#define scsnprintf snprintf +#define scatoi atoi +#define scstrtok strtok +#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; +} + +SQRESULT sqstd_format(HSQUIRRELVM v,SQInteger nformatstringidx,SQInteger *outlen,SQChar **output) +{ + const SQChar *format; + SQChar *dest; + SQChar fmt[MAX_FORMAT_LEN]; + sq_getstring(v,nformatstringidx,&format); + SQInteger allocated = (sq_getsize(v,nformatstringidx)+2)*sizeof(SQChar); + dest = sq_getscratchpad(v,allocated); + SQInteger n = 0,i = 0, nparam = nformatstringidx+1, w = 0; + 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 'o': case 'u': case 'x': case 'X': +#ifdef _SQ64 + { + size_t flen = scstrlen(fmt); + SQInteger fpos = flen - 1; + SQChar f = fmt[fpos]; + SQChar *prec = (SQChar *)_PRINT_INT_PREC; + while(*prec != _SC('\0')) { + fmt[fpos++] = *prec++; + } + fmt[fpos++] = f; + fmt[fpos++] = _SC('\0'); + } +#endif + case 'c': + 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++; + allocated += addlen + sizeof(SQChar); + 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 ++; + } + } + *outlen = i; + dest[i] = '\0'; + *output = dest; + return SQ_OK; +} + +static SQInteger _string_format(HSQUIRRELVM v) +{ + SQChar *dest = NULL; + SQInteger length = 0; + if(SQ_FAILED(sqstd_format(v,2,&length,&dest))) + return -1; + sq_pushstring(v,dest,length); + return 1; +} + +static void __strip_l(const SQChar *str,const SQChar **start) +{ + const SQChar *t = str; + while(((*t) != '\0') && scisspace(*t)){ t++; } + *start = t; +} + +static void __strip_r(const SQChar *str,SQInteger len,const SQChar **end) +{ + if(len == 0) { + *end = str; + return; + } + const SQChar *t = &str[len-1]; + while(t != str && scisspace(*t)) { t--; } + *end = t+1; +} + +static SQInteger _string_strip(HSQUIRRELVM v) +{ + const SQChar *str,*start,*end; + sq_getstring(v,2,&str); + SQInteger len = sq_getsize(v,2); + __strip_l(str,&start); + __strip_r(str,len,&end); + sq_pushstring(v,start,end - start); + return 1; +} + +static SQInteger _string_lstrip(HSQUIRRELVM v) +{ + const SQChar *str,*start; + sq_getstring(v,2,&str); + __strip_l(str,&start); + sq_pushstring(v,start,-1); + return 1; +} + +static SQInteger _string_rstrip(HSQUIRRELVM v) +{ + const SQChar *str,*end; + sq_getstring(v,2,&str); + SQInteger len = sq_getsize(v,2); + __strip_r(str,len,&end); + sq_pushstring(v,str,end - str); + return 1; +} + +static SQInteger _string_split(HSQUIRRELVM v) +{ + const SQChar *str,*seps; + SQChar *stemp,*tok; + sq_getstring(v,2,&str); + sq_getstring(v,3,&seps); + if(sq_getsize(v,3) == 0) return sq_throwerror(v,_SC("empty separators string")); + SQInteger memsize = (sq_getsize(v,2)+1)*sizeof(SQChar); + stemp = sq_getscratchpad(v,memsize); + memcpy(stemp,str,memsize); + tok = scstrtok(stemp,seps); + sq_newarray(v,0); + while( tok != NULL ) { + sq_pushstring(v,tok,-1); + sq_arrayappend(v,-2); + tok = scstrtok( NULL, seps ); + } + 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_pushbool(v,SQTrue); + return 1; + } + sq_pushbool(v,SQFalse); + return 1; +} + +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} +}; +#undef _DECL_REX_FUNC + +#define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_string_##name,nparams,pmask} +static SQRegFunction stringlib_funcs[]={ + _DECL_FUNC(format,-2,_SC(".s")), + _DECL_FUNC(strip,2,_SC(".s")), + _DECL_FUNC(lstrip,2,_SC(".s")), + _DECL_FUNC(rstrip,2,_SC(".s")), + _DECL_FUNC(split,3,_SC(".ss")), + {0,0} +}; +#undef _DECL_FUNC + + +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_newslot(v,-3,SQFalse); + i++; + } + sq_newslot(v,-3,SQFalse); + + 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_newslot(v,-3,SQFalse); + i++; + } + return 1; +} diff --git a/squirrel_3_0_1_stable/sqstdlib/sqstdsystem.cpp b/squirrel_3_0_1_stable/sqstdlib/sqstdsystem.cpp new file mode 100644 index 000000000..40f78d785 --- /dev/null +++ b/squirrel_3_0_1_stable/sqstdlib/sqstdsystem.cpp @@ -0,0 +1,147 @@ +/* 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 it; + SQInteger format = 'l'; + if(sq_gettop(v) > 1) { + sq_getinteger(v,2,&it); + t = it; + 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,0,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} +}; +#undef _DECL_FUNC + +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_newslot(v,-3,SQFalse); + i++; + } + return 1; +} diff --git a/squirrel_3_0_1_stable/squirrel.dsw b/squirrel_3_0_1_stable/squirrel.dsw new file mode 100644 index 000000000..db43df68e --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel.dsw @@ -0,0 +1,77 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "sq"=.\sq\sq.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + . + end source code control +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name sqlibs + End Project Dependency + Begin Project Dependency + Project_Dep_Name squirrel + End Project Dependency + Begin Project Dependency + Project_Dep_Name sqstdlib + End Project Dependency +}}} + +############################################################################### + +Project: "sqstdlib"=.\sqstdlib\sqstdlib.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/squirrel", HAAAAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "squirrel"=.\squirrel\squirrel.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/squirrel", HAAAAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/squirrel", HAAAAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/squirrel_3_0_1_stable/squirrel/Makefile b/squirrel_3_0_1_stable/squirrel/Makefile new file mode 100644 index 000000000..d5de81a96 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/Makefile @@ -0,0 +1,52 @@ +SQUIRREL= .. + + +OUT= $(SQUIRREL)/lib/libsquirrel.a +INCZ= -I$(SQUIRREL)/include -I. -Iinclude +DEFS= +LIB= + +OBJS= \ + sqapi.o \ + sqbaselib.o \ + sqfuncstate.o \ + sqdebug.o \ + sqlexer.o \ + sqobject.o \ + sqcompiler.o \ + sqstate.o \ + sqtable.o \ + sqmem.o \ + sqvm.o \ + sqclass.o + +SRCS= \ + sqapi.cpp \ + sqbaselib.cpp \ + sqfuncstate.cpp \ + sqdebug.cpp \ + sqlexer.cpp \ + sqobject.cpp \ + sqcompiler.cpp \ + sqstate.cpp \ + sqtable.cpp \ + sqmem.cpp \ + sqvm.cpp \ + sqclass.cpp + + + +sq32: + gcc -O2 -fno-exceptions -fno-rtti -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) $(DEFS) + ar rc $(OUT) *.o + rm *.o + +sqprof: + gcc -O2 -pg -fno-exceptions -fno-rtti -pie -gstabs -g3 -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) $(DEFS) + ar rc $(OUT) *.o + rm *.o + +sq64: + gcc -O2 -m64 -D_SQ64 -fno-exceptions -fno-rtti -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) $(DEFS) + ar rc $(OUT) *.o + rm *.o diff --git a/squirrel_3_0_1_stable/squirrel/sqapi.cpp b/squirrel_3_0_1_stable/squirrel/sqapi.cpp new file mode 100644 index 000000000..05338ce23 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqapi.cpp @@ -0,0 +1,1456 @@ +/* + 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_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->_callsstacksize != 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_setnativedebughook(HSQUIRRELVM v,SQDEBUGHOOK hook) +{ + v->_debughook_native = hook; + v->_debughook_closure.Null(); + v->_debughook = hook?true:false; +} + +void sq_setdebughook(HSQUIRRELVM v) +{ + SQObject o = stack_get(v,-1); + if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) { + v->_debughook_closure = o; + v->_debughook_native = NULL; + v->_debughook = !sq_isnull(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; +#ifndef NO_COMPILER + 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; +#else + return sq_throwerror(v,_SC("this is a no compiler build")); +#endif +} + +void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable) +{ + _ss(v)->_debuginfo = enable?true:false; +} + +void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable) +{ + _ss(v)->_notifyallexceptions = enable?true:false; +} + +void sq_addref(HSQUIRRELVM v,HSQOBJECT *po) +{ + if(!ISREFCOUNTED(type(*po))) return; +#ifdef NO_GARBAGE_COLLECTOR + __AddRef(po->_type,po->_unVal); +#else + _ss(v)->_refs_table.AddRef(*po); +#endif +} + +SQUnsignedInteger sq_getrefcount(HSQUIRRELVM v,HSQOBJECT *po) +{ + if(!ISREFCOUNTED(type(*po))) return 0; +#ifdef NO_GARBAGE_COLLECTOR + return po->_unVal.pRefCounted->_uiRef; +#else + return _ss(v)->_refs_table.GetRefCount(*po); +#endif +} + +SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po) +{ + if(!ISREFCOUNTED(type(*po))) return SQTrue; +#ifdef NO_GARBAGE_COLLECTOR + bool ret = (po->_unVal.pRefCounted->_uiRef <= 1) ? SQTrue : SQFalse; + __Release(po->_type,po->_unVal); + return ret; //the ret val doesn't work(and cannot be fixed) +#else + return _ss(v)->_refs_table.Release(*po); +#endif +} + +const SQChar *sq_objtostring(const HSQOBJECT *o) +{ + if(sq_type(*o) == OT_STRING) { + return _stringval(*o); + } + return NULL; +} + +SQInteger sq_objtointeger(const HSQOBJECT *o) +{ + if(sq_isnumeric(*o)) { + return tointeger(*o); + } + return 0; +} + +SQFloat sq_objtofloat(const HSQOBJECT *o) +{ + if(sq_isnumeric(*o)) { + return tofloat(*o); + } + return 0; +} + +SQBool sq_objtobool(const HSQOBJECT *o) +{ + if(sq_isbool(*o)) { + return _integer(*o); + } + return SQFalse; +} + +SQUserPointer sq_objtouserpointer(const HSQOBJECT *o) +{ + if(sq_isuserpointer(*o)) { + return _userpointer(*o); + } + return 0; +} + +void sq_pushnull(HSQUIRRELVM v) +{ + v->PushNull(); +} + +void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len) +{ + if(s) + v->Push(SQObjectPtr(SQString::Create(_ss(v), s, len))); + else v->PushNull(); +} + +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 (SQUserPointer)sq_aligning(ud + 1); +} + +void sq_newtable(HSQUIRRELVM v) +{ + v->Push(SQTable::Create(_ss(v), 0)); +} + +void sq_newtableex(HSQUIRRELVM v,SQInteger initialcapacity) +{ + v->Push(SQTable::Create(_ss(v), initialcapacity)); +} + +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; +} + +SQBool 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))?SQTrue:SQFalse; +} + +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(); + 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(newsize >= 0) { + _array(*arr)->Resize(newsize); + return SQ_OK; + } + return sq_throwerror(v,_SC("negative size")); +} + + +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; +} + +SQRESULT sq_arrayremove(HSQUIRRELVM v,SQInteger idx,SQInteger itemidx) +{ + sq_aux_paramscheck(v, 1); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + return _array(*arr)->Remove(itemidx) ? SQ_OK : sq_throwerror(v,_SC("index out of range")); +} + +SQRESULT sq_arrayinsert(HSQUIRRELVM v,SQInteger idx,SQInteger destpos) +{ + sq_aux_paramscheck(v, 1); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + SQRESULT ret = _array(*arr)->Insert(destpos, v->GetUp(-1)) ? SQ_OK : sq_throwerror(v,_SC("index out of range")); + v->Pop(); + return ret; +} + +void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars) +{ + SQNativeClosure *nc = SQNativeClosure::Create(_ss(v), func,nfreevars); + nc->_nparamscheck = 0; + for(SQUnsignedInteger i = 0; i < nfreevars; i++) { + nc->_outervalues[i] = 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(type(o) == OT_CLOSURE) { + SQClosure *c = _closure(o); + SQFunctionProto *proto = c->_function; + *nparams = (SQUnsignedInteger)proto->_nparameters; + *nfreevars = (SQUnsignedInteger)proto->_noutervalues; + return SQ_OK; + } + else if(type(o) == OT_NATIVECLOSURE) + { + SQNativeClosure *c = _nativeclosure(o); + *nparams = (SQUnsignedInteger)c->_nparamscheck; + *nfreevars = c->_noutervalues; + 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; +} + +SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &o = stack_get(v,idx); + if(!sq_isnativeclosure(o) && + !sq_isclosure(o)) + return sq_throwerror(v,_SC("the target is not a closure")); + SQObjectPtr &env = stack_get(v,-1); + if(!sq_istable(env) && + !sq_isclass(env) && + !sq_isinstance(env)) + return sq_throwerror(v,_SC("invalid environment")); + SQWeakRef *w = _refcounted(env)->GetWeakRef(type(env)); + SQObjectPtr ret; + if(sq_isclosure(o)) { + SQClosure *c = _closure(o)->Clone(); + __ObjRelease(c->_env); + c->_env = w; + __ObjAddRef(c->_env); + if(_closure(o)->_base) { + c->_base = _closure(o)->_base; + __ObjAddRef(c->_base); + } + ret = c; + } + else { //then must be a native closure + SQNativeClosure *c = _nativeclosure(o)->Clone(); + __ObjRelease(c->_env); + c->_env = w; + __ObjAddRef(c->_env); + ret = c; + } + v->Pop(); + v->Push(ret); + return SQ_OK; +} + +SQRESULT sq_clear(HSQUIRRELVM v,SQInteger idx) +{ + SQObject &o=stack_get(v,idx); + switch(type(o)) { + case OT_TABLE: _table(o)->Clear(); break; + case OT_ARRAY: _array(o)->Resize(0); break; + default: + return sq_throwerror(v, _SC("clear only works on table and array")); + break; + + } + return SQ_OK; +} + +void sq_pushroottable(HSQUIRRELVM v) +{ + v->Push(v->_roottable); +} + +void sq_pushregistrytable(HSQUIRRELVM v) +{ + v->Push(_ss(v)->_registry); +} + +void sq_pushconsttable(HSQUIRRELVM v) +{ + v->Push(_ss(v)->_consts); +} + +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")); +} + +SQRESULT sq_setconsttable(HSQUIRRELVM v) +{ + SQObject o = stack_get(v, -1); + if(sq_istable(o)) { + _ss(v)->_consts = o; + v->Pop(); + return SQ_OK; + } + return sq_throwerror(v, _SC("ivalid type, expected table")); +} + +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)); +} + + +SQRESULT sq_tostring(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &o = stack_get(v, idx); + SQObjectPtr res; + if(!v->ToString(o,res)) { + return SQ_ERROR; + } + v->Push(res); + return SQ_OK; +} + +void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b) +{ + SQObjectPtr &o = stack_get(v, idx); + *b = SQVM::IsFalse(o)?SQFalse:SQTrue; +} + +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->PushNull(); + if(!v->Clone(o, stack_get(v, -1))){ + v->Pop(); + return SQ_ERROR; + } + 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; + case OT_INSTANCE: return _instance(o)->_class->_udsize; + case OT_CLASS: return _class(o)->_udsize; + 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(const 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_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize) +{ + SQObjectPtr &o = stack_get(v,idx); + if(type(o) != OT_CLASS) return sq_throwerror(v,_SC("the object is not a class")); + if(_class(o)->_locked) return sq_throwerror(v,_SC("the class is locked")); + _class(o)->_udsize = udsize; + 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_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic) +{ + 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),bstatic?true:false); + 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(); + 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),DONT_FALL_BACK)) { + v->Pop(2); + return SQ_OK; + } + 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(_ss(v), v->GetUp(-2), v->GetUp(-1),false); + 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/class 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) + v->GetUp(-1) = t; + else + v->Pop(); + return SQ_OK; +} + +SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self=stack_get(v,idx); + switch(type(self)){ + case OT_TABLE: + case OT_USERDATA: + if(!_delegable(self)->_delegate){ + v->PushNull(); + break; + } + v->Push(SQObjectPtr(_delegable(self)->_delegate)); + break; + default: return sq_throwerror(v,_SC("wrong type")); break; + } + return SQ_OK; + +} + +SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self=stack_get(v,idx); + if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,DONT_FALL_BACK)) + return SQ_OK; + v->Pop(); + return SQ_ERROR; +} + +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:{ + SQObjectPtr& key = v->GetUp(-1); + if(sq_isnumeric(key)){ + if(_array(self)->Get(tointeger(key),v->GetUp(-1))) { + return SQ_OK; + } + } + else { + v->Pop(); + return sq_throwerror(v,_SC("invalid index type for an array")); + } + } + break; + default: + v->Pop(); + return sq_throwerror(v,_SC("rawget works only on array/table/instance and class")); + } + v->Pop(); + 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->_callsstacksize; + 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=c->_function; + if(func->_noutervalues > (SQInteger)idx) { + v->Push(*_outer(c->_outervalues[idx])->_valptr); + return _stringval(func->_outervalues[idx]._name); + } + idx -= func->_noutervalues; + return func->GetLocal(v,stackbase,idx,(SQInteger)(ci._ip-func->_instructions)-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 SQ_ERROR; +} + +SQRESULT sq_throwobject(HSQUIRRELVM v) +{ + v->_lasterror = v->GetUp(-1); + v->Pop(); + return SQ_ERROR; +} + + +void sq_reseterror(HSQUIRRELVM v) +{ + v->_lasterror.Null(); +} + +void sq_getlasterror(HSQUIRRELVM v) +{ + v->Push(v->_lasterror); +} + +SQRESULT sq_reservestack(HSQUIRRELVM v,SQInteger nsize) +{ + if (((SQUnsignedInteger)v->_top + nsize) > v->_stack.size()) { + if(v->_nmetamethodscall) { + return sq_throwerror(v,_SC("cannot resize stack while in a metamethod")); + } + v->_stack.resize(v->_stack.size() + ((v->_top + nsize) - v->_stack.size())); + } + return SQ_OK; +} + +SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror) +{ + if(type(v->GetUp(-1))==OT_GENERATOR){ + v->PushNull(); //retval + if(!v->Execute(v->GetUp(-2),0,v->_top,v->GetUp(-1),raiseerror,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,SQBool raiseerror) +{ + SQObjectPtr res; + if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res,raiseerror?true:false)){ + + if(!v->_suspended) { + 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,SQBool raiseerror,SQBool throwerror) +{ + SQObjectPtr ret; + if(!v->_suspended) + return sq_throwerror(v,_SC("cannot resume a vm that is not running any code")); + SQInteger target = v->_suspended_target; + if(wakeupret) { + if(target != -1) { + v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval + } + v->Pop(); + } else if(target != -1) { v->GetAt(v->_stackbase+v->_suspended_target).Null(); } + SQObjectPtr dummy; + if(!v->Execute(dummy,-1,-1,ret,raiseerror,throwerror?SQVM::ET_RESUME_THROW_VM : SQVM::ET_RESUME_VM)) { + return SQ_ERROR; + } + 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; + case OT_CLASS: _class(ud)->_hook = hook; break; + default: break; //shutup compiler + } + } +} + +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); + 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 closure; + + 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(!SQClosure::Load(v,up,r,closure)) + return SQ_ERROR; + v->Push(closure); + return SQ_OK; +} + +SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize) +{ + return _ss(v)->GetScratchPad(minsize); +} + +SQRESULT sq_resurrectunreachable(HSQUIRRELVM v) +{ +#ifndef NO_GARBAGE_COLLECTOR + _ss(v)->ResurrectUnreachable(v); + return SQ_OK; +#else + return sq_throwerror(v,_SC("sq_resurrectunreachable requires a garbage collector build")); +#endif +} + +SQInteger sq_collectgarbage(HSQUIRRELVM v) +{ +#ifndef NO_GARBAGE_COLLECTOR + return _ss(v)->CollectGarbage(v); +#else + return -1; +#endif +} + +SQRESULT sq_getcallee(HSQUIRRELVM v) +{ + if(v->_callsstacksize > 1) + { + v->Push(v->_callsstack[v->_callsstacksize - 2]._closure); + return SQ_OK; + } + return sq_throwerror(v,_SC("no closure in the calls stack")); +} + +const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval) +{ + SQObjectPtr &self=stack_get(v,idx); + const SQChar *name = NULL; + switch(type(self)) + { + case OT_CLOSURE:{ + SQClosure *clo = _closure(self); + SQFunctionProto *fp = clo->_function; + if(((SQUnsignedInteger)fp->_noutervalues) > nval) { + v->Push(*(_outer(clo->_outervalues[nval])->_valptr)); + SQOuterVar &ov = fp->_outervalues[nval]; + name = _stringval(ov._name); + } + } + break; + case OT_NATIVECLOSURE:{ + SQNativeClosure *clo = _nativeclosure(self); + if(clo->_noutervalues > nval) { + v->Push(clo->_outervalues[nval]); + name = _SC("@NATIVE"); + } + } + break; + default: break; //shutup compiler + } + return name; +} + +SQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval) +{ + SQObjectPtr &self=stack_get(v,idx); + switch(type(self)) + { + case OT_CLOSURE:{ + SQFunctionProto *fp = _closure(self)->_function; + if(((SQUnsignedInteger)fp->_noutervalues) > nval){ + *(_outer(_closure(self)->_outervalues[nval])->_valptr) = stack_get(v,-1); + } + else return sq_throwerror(v,_SC("invalid free var index")); + } + break; + case OT_NATIVECLOSURE: + if(_nativeclosure(self)->_noutervalues > 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(); + 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_getmemberhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + SQObjectPtr &key = stack_get(v,-1); + SQTable *m = _class(*o)->_members; + SQObjectPtr val; + if(m->Get(key,val)) { + handle->_static = _isfield(val) ? SQFalse : SQTrue; + handle->_index = _member_idx(val); + v->Pop(); + return SQ_OK; + } + return sq_throwerror(v,_SC("wrong index")); +} + +SQRESULT _getmemberbyhandle(HSQUIRRELVM v,SQObjectPtr &self,HSQMEMBERHANDLE *handle,SQObjectPtr *&val) +{ + switch(type(self)) { + case OT_INSTANCE: { + SQInstance *i = _instance(self); + if(handle->_static) { + SQClass *c = i->_class; + val = &c->_methods[handle->_index].val; + } + else { + val = &i->_values[handle->_index]; + + } + } + break; + case OT_CLASS: { + SQClass *c = _class(self); + if(handle->_static) { + val = &c->_methods[handle->_index].val; + } + else { + val = &c->_defaultvalues[handle->_index].val; + } + } + break; + default: + return sq_throwerror(v,_SC("wrong type(expected class or instance)")); + } + return SQ_OK; +} + +SQRESULT sq_getbyhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle) +{ + SQObjectPtr &self = stack_get(v,idx); + SQObjectPtr *val = NULL; + if(SQ_FAILED(_getmemberbyhandle(v,self,handle,val))) { + return SQ_ERROR; + } + v->Push(_realval(*val)); + return SQ_OK; +} + +SQRESULT sq_setbyhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle) +{ + SQObjectPtr &self = stack_get(v,idx); + SQObjectPtr &newval = stack_get(v,-1); + SQObjectPtr *val = NULL; + if(SQ_FAILED(_getmemberbyhandle(v,self,handle,val))) { + return SQ_ERROR; + } + *val = newval; + v->Pop(); + return SQ_OK; +} + +SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + if(_class(*o)->_base) + v->Push(SQObjectPtr(_class(*o)->_base)); + else + v->PushNull(); + return SQ_OK; +} + +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_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t) +{ + SQSharedState *ss = _ss(v); + switch(t) { + case OT_TABLE: v->Push(ss->_table_default_delegate); break; + case OT_ARRAY: v->Push(ss->_array_default_delegate); break; + case OT_STRING: v->Push(ss->_string_default_delegate); break; + case OT_INTEGER: case OT_FLOAT: v->Push(ss->_number_default_delegate); break; + case OT_GENERATOR: v->Push(ss->_generator_default_delegate); break; + case OT_CLOSURE: case OT_NATIVECLOSURE: v->Push(ss->_closure_default_delegate); break; + case OT_THREAD: v->Push(ss->_thread_default_delegate); break; + case OT_CLASS: v->Push(ss->_class_default_delegate); break; + case OT_INSTANCE: v->Push(ss->_instance_default_delegate); break; + case OT_WEAKREF: v->Push(ss->_weakref_default_delegate); break; + default: return sq_throwerror(v,_SC("the type doesn't have a default delegate")); + } + 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")); + } + int faketojump; + if(!v->FOREACH_OP(o,realkey,val,refpos,0,666,faketojump)) + return SQ_ERROR; + if(faketojump != 666) { + 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,SQPRINTFUNCTION errfunc) +{ + _ss(v)->_printfunc = printfunc; + _ss(v)->_errorfunc = errfunc; +} + +SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v) +{ + return _ss(v)->_printfunc; +} + +SQPRINTFUNCTION sq_geterrorfunc(HSQUIRRELVM v) +{ + return _ss(v)->_errorfunc; +} + +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/squirrel_3_0_1_stable/squirrel/sqarray.h b/squirrel_3_0_1_stable/squirrel/sqarray.h new file mode 100644 index 000000000..c3a57abcc --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqarray.h @@ -0,0 +1,94 @@ +/* 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); + SQObjectType GetType() {return OT_ARRAY;} +#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),0); anew->_values.copy(_values); return anew; } + SQInteger Size() const {return _values.size();} + void Resize(SQInteger size) + { + SQObjectPtr _null; + Resize(size,_null); + } + void Resize(SQInteger size,SQObjectPtr &fill) { _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(); } + bool Insert(SQInteger idx,const SQObject &val){ + if(idx < 0 || idx > (SQInteger)_values.size()) + return false; + _values.insert(idx,val); + return true; + } + void ShrinkIfNeeded() { + if(_values.size() <= _values.capacity()>>2) //shrink the array + _values.shrinktofit(); + } + bool Remove(SQInteger idx){ + if(idx < 0 || idx >= (SQInteger)_values.size()) + return false; + _values.remove(idx); + ShrinkIfNeeded(); + return true; + } + void Release() + { + sq_delete(this,SQArray); + } + + SQObjectPtrVec _values; +}; +#endif //_SQARRAY_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqbaselib.cpp b/squirrel_3_0_1_stable/squirrel/sqbaselib.cpp new file mode 100644 index 000000000..1e9ae1445 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqbaselib.cpp @@ -0,0 +1,1110 @@ +/* + 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; + } +} + +static SQInteger base_dummy(HSQUIRRELVM v) +{ + return 0; +} + +#ifndef NO_GARBAGE_COLLECTOR +static SQInteger base_collectgarbage(HSQUIRRELVM v) +{ + sq_pushinteger(v, sq_collectgarbage(v)); + return 1; +} +static SQInteger base_resurectureachable(HSQUIRRELVM v) +{ + sq_resurrectunreachable(v); + return 1; +} +#endif + +static SQInteger base_getroottable(HSQUIRRELVM v) +{ + v->Push(v->_roottable); + return 1; +} + +static SQInteger base_getconsttable(HSQUIRRELVM v) +{ + v->Push(_ss(v)->_consts); + return 1; +} + + +static SQInteger base_setroottable(HSQUIRRELVM v) +{ + SQObjectPtr o = v->_roottable; + if(SQ_FAILED(sq_setroottable(v))) return SQ_ERROR; + v->Push(o); + return 1; +} + +static SQInteger base_setconsttable(HSQUIRRELVM v) +{ + SQObjectPtr o = _ss(v)->_consts; + if(SQ_FAILED(sq_setconsttable(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,SQVM::IsFalse(o)?SQFalse:SQTrue); + return 0; +} + +static SQInteger __getcallstackinfos(HSQUIRRELVM v,SQInteger level) +{ + SQStackInfos si; + SQInteger seq = 0; + const SQChar *name = NULL; + + 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_newslot(v, -3, SQFalse); + sq_pushstring(v, _SC("src"), -1); + sq_pushstring(v, src, -1); + sq_newslot(v, -3, SQFalse); + sq_pushstring(v, _SC("line"), -1); + sq_pushinteger(v, si.line); + sq_newslot(v, -3, SQFalse); + 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_newslot(v, -4, SQFalse); + sq_pop(v, 1); + seq++; + } + sq_newslot(v, -3, SQFalse); + return 1; + } + + return 0; +} +static SQInteger base_getstackinfos(HSQUIRRELVM v) +{ + SQInteger level; + sq_getinteger(v, -1, &level); + return __getcallstackinfos(v,level); +} + +static SQInteger base_assert(HSQUIRRELVM v) +{ + if(SQVM::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_error(HSQUIRRELVM v) +{ + const SQChar *str; + sq_tostring(v,2); + sq_getstring(v,-1,&str); + if(_ss(v)->_errorfunc) _ss(v)->_errorfunc(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 = (_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 SQInteger base_callee(HSQUIRRELVM v) +{ + if(v->_callsstacksize > 1) + { + v->Push(v->_callsstack[v->_callsstacksize - 2]._closure); + return 1; + } + return sq_throwerror(v,_SC("no closure in the calls stack")); +} + +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("getconsttable"),base_getconsttable,1, NULL}, + {_SC("setconsttable"),base_setconsttable,2, NULL}, + {_SC("assert"),base_assert,2, NULL}, + {_SC("print"),base_print,2, NULL}, + {_SC("error"),base_error,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}, + {_SC("callee"),base_callee,0,NULL}, + {_SC("dummy"),base_dummy,0,NULL}, +#ifndef NO_GARBAGE_COLLECTOR + {_SC("collectgarbage"),base_collectgarbage,0, NULL}, + {_SC("resurrectunreachable"),base_resurectureachable,0, NULL}, +#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_newslot(v,-3, SQFalse); + i++; + } + + sq_pushstring(v,_SC("_versionnumber_"),-1); + sq_pushinteger(v,SQUIRREL_VERSION_NUMBER); + sq_newslot(v,-3, SQFalse); + sq_pushstring(v,_SC("_version_"),-1); + sq_pushstring(v,SQUIRREL_VERSION,-1); + sq_newslot(v,-3, SQFalse); + sq_pushstring(v,_SC("_charsize_"),-1); + sq_pushinteger(v,sizeof(SQChar)); + sq_newslot(v,-3, SQFalse); + sq_pushstring(v,_SC("_intsize_"),-1); + sq_pushinteger(v,sizeof(SQInteger)); + sq_newslot(v,-3, SQFalse); + sq_pushstring(v,_SC("_floatsize_"),-1); + sq_pushinteger(v,sizeof(SQFloat)); + sq_newslot(v,-3, SQFalse); + 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->PushNull(); + 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)?(SQInteger)1:(SQInteger)0)); + break; + default: + v->PushNull(); + 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 obj_clear(HSQUIRRELVM v) +{ + return sq_clear(v,-1); +} + + +static SQInteger number_delegate_tochar(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + SQChar c = (SQChar)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 container_rawset(HSQUIRRELVM v) +{ + return sq_rawset(v,-3); +} + + +static SQInteger container_rawget(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_rawget(v,-2))?1:SQ_ERROR; +} + +static SQInteger table_setdelegate(HSQUIRRELVM v) +{ + if(SQ_FAILED(sq_setdelegate(v,-2))) + return SQ_ERROR; + sq_push(v,-1); // -1 because sq_setdelegate pops 1 + return 1; +} + +static SQInteger table_getdelegate(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_getdelegate(v,-1))?1:SQ_ERROR; +} + +SQRegFunction SQSharedState::_table_default_delegate_funcz[]={ + {_SC("len"),default_delegate_len,1, _SC("t")}, + {_SC("rawget"),container_rawget,2, _SC("t")}, + {_SC("rawset"),container_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 }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {_SC("clear"),obj_clear,1, _SC(".")}, + {_SC("setdelegate"),table_setdelegate,2, _SC(".t|o")}, + {_SC("getdelegate"),table_getdelegate,1, _SC(".")}, + {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); + if(!_array(o)->Insert(tointeger(idx),val)) + return sq_throwerror(v,_SC("index out of range")); + 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")); +} + +static SQInteger __map_array(SQArray *dest,SQArray *src,HSQUIRRELVM v) { + SQObjectPtr temp; + SQInteger size = src->Size(); + for(SQInteger n = 0; n < size; n++) { + src->Get(n,temp); + v->Push(src); + v->Push(temp); + if(SQ_FAILED(sq_call(v,2,SQTrue,SQFalse))) { + return SQ_ERROR; + } + dest->Set(n,v->GetUp(-1)); + v->Pop(); + } + return 0; +} + +static SQInteger array_map(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v,1); + SQInteger size = _array(o)->Size(); + SQObjectPtr ret = SQArray::Create(_ss(v),size); + if(SQ_FAILED(__map_array(_array(ret),_array(o),v))) + return SQ_ERROR; + v->Push(ret); + return 1; +} + +static SQInteger array_apply(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v,1); + if(SQ_FAILED(__map_array(_array(o),_array(o),v))) + return SQ_ERROR; + return 0; +} + +static SQInteger array_reduce(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v,1); + SQArray *a = _array(o); + SQInteger size = a->Size(); + if(size == 0) { + return 0; + } + SQObjectPtr res; + a->Get(0,res); + if(size > 1) { + SQObjectPtr other; + for(SQInteger n = 1; n < size; n++) { + a->Get(n,other); + v->Push(o); + v->Push(res); + v->Push(other); + if(SQ_FAILED(sq_call(v,3,SQTrue,SQFalse))) { + return SQ_ERROR; + } + res = v->GetUp(-1); + v->Pop(); + } + } + v->Push(res); + return 1; +} + +static SQInteger array_filter(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v,1); + SQArray *a = _array(o); + SQObjectPtr ret = SQArray::Create(_ss(v),0); + SQInteger size = a->Size(); + SQObjectPtr val; + for(SQInteger n = 0; n < size; n++) { + a->Get(n,val); + v->Push(o); + v->Push(n); + v->Push(val); + if(SQ_FAILED(sq_call(v,3,SQTrue,SQFalse))) { + return SQ_ERROR; + } + if(!SQVM::IsFalse(v->GetUp(-1))) { + _array(ret)->Append(val); + } + v->Pop(); + } + v->Push(ret); + return 1; +} + +static SQInteger array_find(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v,1); + SQObjectPtr &val = stack_get(v,2); + SQArray *a = _array(o); + SQInteger size = a->Size(); + SQObjectPtr temp; + for(SQInteger n = 0; n < size; n++) { + bool res = false; + a->Get(n,temp); + if(SQVM::IsEqual(temp,val,res) && res) { + v->Push(n); + return 1; + } + } + return 0; +} + +//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, SQFalse))) { + if(!sq_isstring( v->_lasterror)) + 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 ( j < 0 ) { + v->Raise_Error( _SC("Invalid qsort, probably compare function defect") ); + return false; + } + 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) +{ + SQInteger func = -1; + SQObjectPtr &o = stack_get(v,1); + //SQObject &funcobj = stack_get(v,2); + if(_array(o)->Size() > 1) { + if(sq_gettop(v) == 2 /*&& 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; + SQInteger alen = _array(o)->Size(); + if(sidx < 0)sidx = alen + sidx; + if(eidx < 0)eidx = alen + eidx; + if(eidx < sidx)return sq_throwerror(v,_SC("wrong indexes")); + if(eidx > alen)return sq_throwerror(v,_SC("slice out of range")); + 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 }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {_SC("clear"),obj_clear,1, _SC(".")}, + {_SC("map"),array_map,2, _SC("ac")}, + {_SC("apply"),array_apply,2, _SC("ac")}, + {_SC("reduce"),array_reduce,2, _SC("ac")}, + {_SC("filter"),array_filter,2, _SC("ac")}, + {_SC("find"),array_find,2, _SC("a.")}, + {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; + SQInteger slen = _string(o)->_len; + if(sidx < 0)sidx = slen + sidx; + if(eidx < 0)eidx = slen + eidx; + if(eidx < sidx) return sq_throwerror(v,_SC("wrong indexes")); + if(eidx > slen) return sq_throwerror(v,_SC("slice out of range")); + v->Push(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(".")}, + {_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(".")}, + {_SC("tochar"),number_delegate_tochar,1, _SC("n|b")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {0,0} +}; + +//CLOSURE DEFAULT DELEGATE////////////////////////// +static SQInteger closure_pcall(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQFalse))?1:SQ_ERROR; +} + +static SQInteger closure_call(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQTrue))?1:SQ_ERROR; +} + +static SQInteger _closure_acall(HSQUIRRELVM v,SQBool raiseerror) +{ + 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,raiseerror))?1:SQ_ERROR; +} + +static SQInteger closure_acall(HSQUIRRELVM v) +{ + return _closure_acall(v,SQTrue); +} + +static SQInteger closure_pacall(HSQUIRRELVM v) +{ + return _closure_acall(v,SQFalse); +} + +static SQInteger closure_bindenv(HSQUIRRELVM v) +{ + if(SQ_FAILED(sq_bindenv(v,1))) + return SQ_ERROR; + return 1; +} + +static SQInteger closure_getinfos(HSQUIRRELVM v) { + SQObject o = stack_get(v,1); + SQTable *res = SQTable::Create(_ss(v),4); + if(type(o) == OT_CLOSURE) { + SQFunctionProto *f = _closure(o)->_function; + SQInteger nparams = f->_nparameters + (f->_varparams?1:0); + SQObjectPtr params = SQArray::Create(_ss(v),nparams); + for(SQInteger n = 0; n_nparameters; n++) { + _array(params)->Set((SQInteger)n,f->_parameters[n]); + } + if(f->_varparams) { + _array(params)->Set(nparams-1,SQString::Create(_ss(v),_SC("..."),-1)); + } + res->NewSlot(SQString::Create(_ss(v),_SC("native"),-1),false); + res->NewSlot(SQString::Create(_ss(v),_SC("name"),-1),f->_name); + res->NewSlot(SQString::Create(_ss(v),_SC("src"),-1),f->_sourcename); + res->NewSlot(SQString::Create(_ss(v),_SC("parameters"),-1),params); + res->NewSlot(SQString::Create(_ss(v),_SC("varargs"),-1),f->_varparams); + } + else { //OT_NATIVECLOSURE + SQNativeClosure *nc = _nativeclosure(o); + res->NewSlot(SQString::Create(_ss(v),_SC("native"),-1),true); + res->NewSlot(SQString::Create(_ss(v),_SC("name"),-1),nc->_name); + res->NewSlot(SQString::Create(_ss(v),_SC("paramscheck"),-1),nc->_nparamscheck); + SQObjectPtr typecheck; + if(nc->_typecheck.size() > 0) { + typecheck = + SQArray::Create(_ss(v), nc->_typecheck.size()); + for(SQUnsignedInteger n = 0; n_typecheck.size(); n++) { + _array(typecheck)->Set((SQInteger)n,nc->_typecheck[n]); + } + } + res->NewSlot(SQString::Create(_ss(v),_SC("typecheck"),-1),typecheck); + } + v->Push(res); + return 1; +} + + +SQRegFunction SQSharedState::_closure_default_delegate_funcz[]={ + {_SC("call"),closure_call,-1, _SC("c")}, + {_SC("pcall"),closure_pcall,-1, _SC("c")}, + {_SC("acall"),closure_acall,2, _SC("ca")}, + {_SC("pacall"),closure_pacall,2, _SC("ca")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {_SC("bindenv"),closure_bindenv,2, _SC("c x|y|t")}, + {_SC("getinfos"),closure_getinfos,1, _SC("c")}, + {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 }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {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,SQFalse))) { + sq_move(v,_thread(o),-1); + sq_pop(_thread(o),1); + return 1; + } + v->_lasterror = _thread(o)->_lasterror; + 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,SQTrue,SQTrue,SQFalse))) { + sq_move(v,thread,-1); + sq_pop(thread,1); //pop retval + if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) { + sq_settop(thread,1); //pop roottable + } + return 1; + } + sq_settop(thread,1); + v->_lasterror = thread->_lasterror; + return SQ_ERROR; + } + return sq_throwerror(v,_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; +} + +static SQInteger thread_getstackinfos(HSQUIRRELVM v) +{ + SQObjectPtr o = stack_get(v,1); + if(type(o) == OT_THREAD) { + SQVM *thread = _thread(o); + SQInteger threadtop = sq_gettop(thread); + SQInteger level; + sq_getinteger(v,-1,&level); + SQRESULT res = __getcallstackinfos(thread,level); + if(SQ_FAILED(res)) + { + sq_settop(thread,threadtop); + if(type(thread->_lasterror) == OT_STRING) { + sq_throwerror(v,_stringval(thread->_lasterror)); + } + else { + sq_throwerror(v,_SC("unknown error")); + } + } + if(res > 0) { + //some result + sq_move(v,thread,-1); + sq_settop(thread,threadtop); + return 1; + } + //no result + sq_settop(thread,threadtop); + return 0; + + } + return sq_throwerror(v,_SC("wrong parameter")); +} + +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 }, + {_SC("getstackinfos"),thread_getstackinfos,2, _SC("vn")}, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {0,0}, +}; + +static SQInteger class_getattributes(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_getattributes(v,-2))?1:SQ_ERROR; +} + +static SQInteger class_setattributes(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_setattributes(v,-3))?1:SQ_ERROR; +} + +static SQInteger class_instance(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_createinstance(v,-1))?1:SQ_ERROR; +} + +static SQInteger class_getbase(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_getbase(v,-1))?1:SQ_ERROR; +} + +SQRegFunction SQSharedState::_class_default_delegate_funcz[] = { + {_SC("getattributes"), class_getattributes, 2, _SC("y.")}, + {_SC("setattributes"), class_setattributes, 3, _SC("y..")}, + {_SC("rawget"),container_rawget,2, _SC("y")}, + {_SC("rawset"),container_rawset,3, _SC("y")}, + {_SC("rawin"),container_rawexists,2, _SC("y")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {_SC("instance"),class_instance,1, _SC("y")}, + {_SC("getbase"),class_getbase,1, _SC("y")}, + {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("rawget"),container_rawget,2, _SC("x")}, + {_SC("rawset"),container_rawset,3, _SC("x")}, + {_SC("rawin"),container_rawexists,2, _SC("x")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {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 }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {0,0} +}; + diff --git a/squirrel_3_0_1_stable/squirrel/sqclass.cpp b/squirrel_3_0_1_stable/squirrel/sqclass.cpp new file mode 100644 index 000000000..1f26cc92f --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqclass.cpp @@ -0,0 +1,213 @@ +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqtable.h" +#include "sqclass.h" +#include "sqfuncproto.h" +#include "sqclosure.h" + + + +SQClass::SQClass(SQSharedState *ss,SQClass *base) +{ + _base = base; + _typetag = 0; + _hook = NULL; + _udsize = 0; + _locked = false; + _constructoridx = -1; + if(_base) { + _constructoridx = _base->_constructoridx; + _udsize = _base->_udsize; + _defaultvalues.copy(base->_defaultvalues); + _methods.copy(base->_methods); + _COPY_VECTOR(_metamethods,base->_metamethods,MT_LAST); + __ObjAddRef(_base); + } + _members = base?base->_members->Clone() : SQTable::Create(ss,0); + __ObjAddRef(_members); + + INIT_CHAIN(); + ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); +} + +void SQClass::Finalize() { + _attributes.Null(); + _defaultvalues.resize(0); + _methods.resize(0); + _NULL_SQOBJECT_VECTOR(_metamethods,MT_LAST); + __ObjRelease(_members); + if(_base) { + __ObjRelease(_base); + } +} + +SQClass::~SQClass() +{ + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + Finalize(); +} + +bool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic) +{ + SQObjectPtr temp; + bool belongs_to_static_table = type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE || bstatic; + if(_locked && !belongs_to_static_table) + 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(belongs_to_static_table) { + SQInteger mmidx; + if((type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) && + (mmidx = ss->GetMetaMethodIdxByName(key)) != -1) { + _metamethods[mmidx] = val; + } + else { + SQObjectPtr theval = val; + if(_base && type(val) == OT_CLOSURE) { + theval = _closure(val)->Clone(); + _closure(theval)->_base = _base; + __ObjAddRef(_base); //ref for the closure + } + if(type(temp) == OT_NULL) { + bool isconstructor; + SQVM::IsEqual(ss->_constructoridx, key, isconstructor); + if(isconstructor) { + _constructoridx = (SQInteger)_methods.size(); + } + SQClassMember m; + m.val = theval; + _members->NewSlot(key,SQObjectPtr(_make_method_idx(_methods.size()))); + _methods.push_back(m); + } + else { + _methods[_member_idx(temp)].val = theval; + } + } + return true; + } + SQClassMember 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; + SQUnsignedInteger 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; + SQUnsignedInteger nvalues = _class->_defaultvalues.size(); + for(SQUnsignedInteger n = 0; n < nvalues; n++) { + new (&_values[n]) SQObjectPtr(i->_values[n]); + } + Init(ss); +} + +void SQInstance::Finalize() +{ + SQUnsignedInteger nvalues = _class->_defaultvalues.size(); + __ObjRelease(_class); + _NULL_SQOBJECT_VECTOR(_values,nvalues); + //for(SQUnsignedInteger i = 0; i < nvalues; i++) { +// _values[i].Null(); +// } +} + +SQInstance::~SQInstance() +{ + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + if(_class){ Finalize(); } //if _class is null it was already finalized by the GC +} + +bool SQInstance::GetMetaMethod(SQVM *v,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/squirrel_3_0_1_stable/squirrel/sqclass.h b/squirrel_3_0_1_stable/squirrel/sqclass.h new file mode 100644 index 000000000..996a3df70 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqclass.h @@ -0,0 +1,158 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQCLASS_H_ +#define _SQCLASS_H_ + +struct SQInstance; + +struct SQClassMember { + SQObjectPtr val; + SQObjectPtr attrs; +}; + +typedef sqvector SQClassMemberVec; + +#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(SQSharedState *ss, const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic); + 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 GetConstructor(SQObjectPtr &ctor) + { + if(_constructoridx != -1) { + ctor = _methods[_constructoridx].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() { + if (_hook) { _hook(_typetag,0);} + sq_delete(this, SQClass); + } + void Finalize(); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable ** ); + SQObjectType GetType() {return OT_CLASS;} +#endif + SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); + SQInstance *CreateInstance(); + SQTable *_members; + SQClass *_base; + SQClassMemberVec _defaultvalues; + SQClassMemberVec _methods; + SQObjectPtr _metamethods[MT_LAST]; + SQObjectPtr _attributes; + SQUserPointer _typetag; + SQRELEASEHOOK _hook; + bool _locked; + SQInteger _constructoridx; + SQInteger _udsize; +}; + +#define calcinstancesize(_theclass_) \ + (_theclass_->_udsize + sq_aligning(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); + if(theclass->_udsize) { + newinst->_userpointer = ((unsigned char *)newinst) + (size - theclass->_udsize); + } + return newinst; + } + SQInstance *Clone(SQSharedState *ss) + { + SQInteger size = calcinstancesize(_class); + SQInstance *newinst = (SQInstance *)SQ_MALLOC(size); + new (newinst) SQInstance(ss, this,size); + if(_class->_udsize) { + newinst->_userpointer = ((unsigned char *)newinst) + (size - _class->_udsize); + } + 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() { + _uiRef++; + if (_hook) { _hook(_userpointer,0);} + _uiRef--; + if(_uiRef > 0) return; + SQInteger size = _memsize; + this->~SQInstance(); + SQ_FREE(this, size); + } + void Finalize(); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable ** ); + SQObjectType GetType() {return OT_INSTANCE;} +#endif + bool InstanceOf(SQClass *trg); + bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res); + + SQClass *_class; + SQUserPointer _userpointer; + SQRELEASEHOOK _hook; + SQInteger _memsize; + SQObjectPtr _values[1]; +}; + +#endif //_SQCLASS_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqclosure.h b/squirrel_3_0_1_stable/squirrel/sqclosure.h new file mode 100644 index 000000000..07b3efcfe --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqclosure.h @@ -0,0 +1,193 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQCLOSURE_H_ +#define _SQCLOSURE_H_ + + +#define _CALC_CLOSURE_SIZE(func) (sizeof(SQClosure) + (func->_noutervalues*sizeof(SQObjectPtr)) + (func->_ndefaultparams*sizeof(SQObjectPtr))) + +struct SQFunctionProto; +struct SQClass; +struct SQClosure : public CHAINABLE_OBJ +{ +private: + SQClosure(SQSharedState *ss,SQFunctionProto *func){_function = func; __ObjAddRef(_function); _base = NULL; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); _env = NULL;} +public: + static SQClosure *Create(SQSharedState *ss,SQFunctionProto *func){ + SQInteger size = _CALC_CLOSURE_SIZE(func); + SQClosure *nc=(SQClosure*)SQ_MALLOC(size); + new (nc) SQClosure(ss,func); + nc->_outervalues = (SQObjectPtr *)(nc + 1); + nc->_defaultparams = &nc->_outervalues[func->_noutervalues]; + _CONSTRUCT_VECTOR(SQObjectPtr,func->_noutervalues,nc->_outervalues); + _CONSTRUCT_VECTOR(SQObjectPtr,func->_ndefaultparams,nc->_defaultparams); + return nc; + } + void Release(){ + SQFunctionProto *f = _function; + SQInteger size = _CALC_CLOSURE_SIZE(f); + _DESTRUCT_VECTOR(SQObjectPtr,f->_noutervalues,_outervalues); + _DESTRUCT_VECTOR(SQObjectPtr,f->_ndefaultparams,_defaultparams); + __ObjRelease(_function); + this->~SQClosure(); + sq_vm_free(this,size); + } + + SQClosure *Clone() + { + SQFunctionProto *f = _function; + SQClosure * ret = SQClosure::Create(_opt_ss(this),f); + ret->_env = _env; + if(ret->_env) __ObjAddRef(ret->_env); + _COPY_VECTOR(ret->_outervalues,_outervalues,f->_noutervalues); + _COPY_VECTOR(ret->_defaultparams,_defaultparams,f->_ndefaultparams); + return ret; + } + ~SQClosure(); + + bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); + static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){ + SQFunctionProto *f = _function; + _NULL_SQOBJECT_VECTOR(_outervalues,f->_noutervalues); + _NULL_SQOBJECT_VECTOR(_defaultparams,f->_ndefaultparams); + } + SQObjectType GetType() {return OT_CLOSURE;} +#endif + SQWeakRef *_env; + SQClass *_base; + SQFunctionProto *_function; + SQObjectPtr *_outervalues; + SQObjectPtr *_defaultparams; +}; + +////////////////////////////////////////////// +struct SQOuter : public CHAINABLE_OBJ +{ + +private: + SQOuter(SQSharedState *ss, SQObjectPtr *outer){_valptr = outer; _next = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); } + +public: + static SQOuter *Create(SQSharedState *ss, SQObjectPtr *outer) + { + SQOuter *nc = (SQOuter*)SQ_MALLOC(sizeof(SQOuter)); + new (nc) SQOuter(ss, outer); + return nc; + } + ~SQOuter() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); } + + void Release() + { + this->~SQOuter(); + sq_vm_free(this,sizeof(SQOuter)); + } + +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize() { _value.Null(); } + SQObjectType GetType() {return OT_OUTER;} +#endif + + SQObjectPtr *_valptr; /* pointer to value on stack, or _value below */ + SQInteger _idx; /* idx in stack array, for relocation */ + SQObjectPtr _value; /* value of outer after stack frame is closed */ + SQOuter *_next; /* pointer to next outer when frame is open */ +}; + +////////////////////////////////////////////// +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,SQInteger target); + bool Resume(SQVM *v,SQObjectPtr &dest); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){_stack.resize(0);_closure.Null();} + SQObjectType GetType() {return OT_GENERATOR;} +#endif + SQObjectPtr _closure; + SQObjectPtrVec _stack; + SQVM::CallInfo _ci; + ExceptionsTraps _etraps; + SQGeneratorState _state; +}; + +#define _CALC_NATVIVECLOSURE_SIZE(noutervalues) (sizeof(SQNativeClosure) + (noutervalues*sizeof(SQObjectPtr))) + +struct SQNativeClosure : public CHAINABLE_OBJ +{ +private: + SQNativeClosure(SQSharedState *ss,SQFUNCTION func){_function=func;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); _env = NULL;} +public: + static SQNativeClosure *Create(SQSharedState *ss,SQFUNCTION func,SQInteger nouters) + { + SQInteger size = _CALC_NATVIVECLOSURE_SIZE(nouters); + SQNativeClosure *nc=(SQNativeClosure*)SQ_MALLOC(size); + new (nc) SQNativeClosure(ss,func); + nc->_outervalues = (SQObjectPtr *)(nc + 1); + nc->_noutervalues = nouters; + _CONSTRUCT_VECTOR(SQObjectPtr,nc->_noutervalues,nc->_outervalues); + return nc; + } + SQNativeClosure *Clone() + { + SQNativeClosure * ret = SQNativeClosure::Create(_opt_ss(this),_function,_noutervalues); + ret->_env = _env; + if(ret->_env) __ObjAddRef(ret->_env); + ret->_name = _name; + _COPY_VECTOR(ret->_outervalues,_outervalues,_noutervalues); + ret->_typecheck.copy(_typecheck); + ret->_nparamscheck = _nparamscheck; + return ret; + } + ~SQNativeClosure() + { + __ObjRelease(_env); + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } + void Release(){ + SQInteger size = _CALC_NATVIVECLOSURE_SIZE(_noutervalues); + _DESTRUCT_VECTOR(SQObjectPtr,_noutervalues,_outervalues); + this->~SQNativeClosure(); + sq_free(this,size); + } + +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize() { _NULL_SQOBJECT_VECTOR(_outervalues,_noutervalues); } + SQObjectType GetType() {return OT_NATIVECLOSURE;} +#endif + SQInteger _nparamscheck; + SQIntVec _typecheck; + SQObjectPtr *_outervalues; + SQUnsignedInteger _noutervalues; + SQWeakRef *_env; + SQFUNCTION _function; + SQObjectPtr _name; +}; + + + +#endif //_SQCLOSURE_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqcompiler.cpp b/squirrel_3_0_1_stable/squirrel/sqcompiler.cpp new file mode 100644 index 000000000..e8c1496c9 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqcompiler.cpp @@ -0,0 +1,1504 @@ +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#ifndef NO_COMPILER +#include +#include +#include "sqopcodes.h" +#include "sqstring.h" +#include "sqfuncproto.h" +#include "sqcompiler.h" +#include "sqfuncstate.h" +#include "sqlexer.h" +#include "sqvm.h" +#include "sqtable.h" + +#define EXPR 1 +#define OBJECT 2 +#define BASE 3 +#define LOCAL 4 +#define OUTER 5 + +struct SQExpState { + SQInteger etype; /* expr. type; one of EXPR, OBJECT, BASE, OUTER or LOCAL */ + SQInteger epos; /* expr. location on stack; -1 for OBJECT and BASE */ + bool donot_get; /* signal not to deref the next value */ +}; + +struct SQScope { + SQInteger outers; + SQInteger stacksize; +}; + +#define BEGIN_SCOPE() SQScope __oldscope__ = _scope; \ + _scope.outers = _fs->_outers; \ + _scope.stacksize = _fs->GetStackSize(); + +#define RESOLVE_OUTERS() if(_fs->GetStackSize() != _scope.stacksize) { \ + if(_fs->CountOuters(_scope.stacksize)) { \ + _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \ + } \ + } + +#define END_SCOPE_NO_CLOSE() { if(_fs->GetStackSize() != _scope.stacksize) { \ + _fs->SetStackSize(_scope.stacksize); \ + } \ + _scope = __oldscope__; \ + } + +#define END_SCOPE() { SQInteger oldouters = _fs->_outers;\ + if(_fs->GetStackSize() != _scope.stacksize) { \ + _fs->SetStackSize(_scope.stacksize); \ + if(oldouters != _fs->_outers) { \ + _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \ + } \ + } \ + _scope = __oldscope__; \ + } + +#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; + _scope.outers = 0; + _scope.stacksize = 0; + 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();} + SQObject Expect(SQInteger tok) + { + + if(_token != tok) { + if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) { + //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->AddParameter(_fs->CreateString(_SC("vargv"))); + _fs->_varparams = true; + _fs->_sourcename = _sourcename; + SQInteger stacksize = _fs->GetStackSize(); + if(setjmp(_errorjmp) == 0) { + Lex(); + while(_token > 0){ + Statement(); + if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon(); + } + _fs->SetStackSize(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(bool closeframe = true) + { + _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(),_fs->GetStackSize()); + } + else{ + if(op == _OP_RETURN && _fs->_traps > 0) + _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0); + _fs->_returnexp = -1; + _fs->AddInstruction(op, 0xFF,0,_fs->GetStackSize()); + } + 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); + } + RESOLVE_OUTERS(); + _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); + } + RESOLVE_OUTERS(); + _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 TK_ENUM: + EnumStatement(); + break; + case _SC('{'):{ + BEGIN_SCOPE(); + Lex(); + Statements(); + Expect(_SC('}')); + if(closeframe) { + END_SCOPE(); + } + else { + END_SCOPE_NO_CLOSE(); + } + } + break; + case TK_TRY: + TryCatchStatement(); + break; + case TK_THROW: + Lex(); + CommaExpr(); + _fs->AddInstruction(_OP_THROW, _fs->PopTarget()); + break; + case TK_CONST: + { + Lex(); + SQObject id = Expect(TK_IDENTIFIER); + Expect('='); + SQObject val = ExpectScalar(); + OptionalSemicolon(); + SQTable *enums = _table(_ss(_vm)->_consts); + SQObjectPtr strongid = id; + enums->NewSlot(strongid,SQObjectPtr(val)); + strongid.Null(); + } + break; + default: + CommaExpr(); + _fs->DiscardTarget(); + //_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, SQInteger etype, SQInteger pos) + { + /* Generate code depending on the expression type */ + switch(etype) { + case LOCAL:{ + SQInteger p2 = _fs->PopTarget(); //src in OP_GET + SQInteger p1 = _fs->PopTarget(); //key in OP_GET + _fs->PushTarget(p1); + //EmitCompArithLocal(tok, p1, p1, p2); + _fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0); + } + break; + case OBJECT: + case BASE: + { + SQInteger val = _fs->PopTarget(); + SQInteger key = _fs->PopTarget(); + SQInteger src = _fs->PopTarget(); + /* _OP_COMPARITH mixes dest obj and source val in the arg1 */ + _fs->AddInstruction(_OP_COMPARITH, _fs->PushTarget(), (src<<16)|val, key, ChooseCompArithCharByToken(tok)); + } + break; + case OUTER: + { + SQInteger val = _fs->TopTarget(); + SQInteger tmp = _fs->PushTarget(); + _fs->AddInstruction(_OP_GETOUTER, tmp, pos); + _fs->AddInstruction(ChooseArithOpByToken(tok), tmp, val, tmp, 0); + _fs->AddInstruction(_OP_SETOUTER, tmp, pos, tmp); + } + break; + } + } + void CommaExpr() + { + for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr()); + } + void Expression() + { + SQExpState es = _es; + _es.etype = EXPR; + _es.epos = -1; + _es.donot_get = false; + 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 = _es.etype; + SQInteger pos = _es.epos; + if(ds == EXPR) Error(_SC("can't assign expression")); + Lex(); Expression(); + + switch(op){ + case TK_NEWSLOT: + if(ds == OBJECT || ds == BASE) + 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 + switch(ds) { + case LOCAL: + { + SQInteger src = _fs->PopTarget(); + SQInteger dst = _fs->TopTarget(); + _fs->AddInstruction(_OP_MOVE, dst, src); + } + break; + case OBJECT: + case BASE: + EmitDerefOp(_OP_SET); + break; + case OUTER: + { + SQInteger src = _fs->PopTarget(); + SQInteger dst = _fs->PushTarget(); + _fs->AddInstruction(_OP_SETOUTER, dst, pos, src); + } + } + break; + case TK_MINUSEQ: + case TK_PLUSEQ: + case TK_MULEQ: + case TK_DIVEQ: + case TK_MODEQ: + EmitCompoundArith(op, ds, pos); + 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; + } + _es = es; + } + template void BIN_EXP(SQOpcode op, T f,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() + { + EqExp(); + for(;;) if(_token == _SC('&')) + {BIN_EXP(_OP_BITW, &SQCompiler::EqExp,BW_AND); + }else return; + } + void EqExp() + { + CompExp(); + for(;;) switch(_token) { + case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::CompExp); break; + case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::CompExp); break; + case TK_3WAYSCMP: BIN_EXP(_OP_CMP, &SQCompiler::CompExp,CMP_3W); break; + default: return; + } + } + void CompExp() + { + ShiftExp(); + for(;;) switch(_token) { + 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; + 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; + } + } + SQOpcode ChooseArithOpByToken(SQInteger tok) + { + switch(tok) { + case TK_PLUSEQ: case '+': return _OP_ADD; + case TK_MINUSEQ: case '-': return _OP_SUB; + case TK_MULEQ: case '*': return _OP_MUL; + case TK_DIVEQ: case '/': return _OP_DIV; + case TK_MODEQ: case '%': return _OP_MOD; + default: assert(0); + } + return _OP_ADD; + } + SQInteger ChooseCompArithCharByToken(SQInteger tok) + { + 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: oper = 0; //shut up compiler + assert(0); break; + }; + return oper; + } + void PlusExp() + { + MultExp(); + for(;;) switch(_token) { + case _SC('+'): case _SC('-'): + BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::MultExp); break; + default: return; + } + } + + void MultExp() + { + PrefixedExpr(); + for(;;) switch(_token) { + case _SC('*'): case _SC('/'): case _SC('%'): + BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::PrefixedExpr); 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(); + + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER))); + if(_es.etype==BASE) { + Emit2ArgsOP(_OP_GET); + pos = _fs->TopTarget(); + _es.etype = EXPR; + _es.epos = pos; + } + else { + if(NeedGet()) { + Emit2ArgsOP(_OP_GET); + } + _es.etype = OBJECT; + } + 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(_es.etype==BASE) { + Emit2ArgsOP(_OP_GET); + pos = _fs->TopTarget(); + _es.etype = EXPR; + _es.epos = pos; + } + else { + if(NeedGet()) { + Emit2ArgsOP(_OP_GET); + } + _es.etype = OBJECT; + } + break; + case TK_MINUSMINUS: + case TK_PLUSPLUS: + { + if(IsEndOfStatement()) return; + SQInteger diff = (_token==TK_MINUSMINUS) ? -1 : 1; + Lex(); + switch(_es.etype) + { + case EXPR: Error(_SC("can't '++' or '--' an expression")); break; + case OBJECT: + case BASE: + Emit2ArgsOP(_OP_PINC, diff); + break; + case LOCAL: { + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, diff); + } + break; + case OUTER: { + SQInteger tmp1 = _fs->PushTarget(); + SQInteger tmp2 = _fs->PushTarget(); + _fs->AddInstruction(_OP_GETOUTER, tmp2, _es.epos); + _fs->AddInstruction(_OP_PINCL, tmp1, tmp2, 0, diff); + _fs->AddInstruction(_OP_SETOUTER, tmp2, _es.epos, tmp2); + _fs->PopTarget(); + } + } + } + return; + break; + case _SC('('): + switch(_es.etype) { + case OBJECT: { + SQInteger key = _fs->PopTarget(); /* location of the key */ + SQInteger table = _fs->PopTarget(); /* location of the object */ + SQInteger closure = _fs->PushTarget(); /* location for the closure */ + SQInteger ttarget = _fs->PushTarget(); /* location for 'this' pointer */ + _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget); + } + break; + case BASE: + //Emit2ArgsOP(_OP_GET); + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); + break; + case OUTER: + _fs->AddInstruction(_OP_GETOUTER, _fs->PushTarget(), _es.epos); + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); + break; + default: + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); + } + _es.etype = EXPR; + Lex(); + FunctionCallArgs(); + break; + default: return; + } + } + } + SQInteger Factor() + { + _es.etype = EXPR; + switch(_token) + { + case TK_STRING_LITERAL: + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1))); + Lex(); + break; + case TK_BASE: + Lex(); + _fs->AddInstruction(_OP_GETBASE, _fs->PushTarget()); + _es.etype = BASE; + _es.epos = _fs->TopTarget(); + return (_es.epos); + break; + case TK_IDENTIFIER: + case TK_CONSTRUCTOR: + case TK_THIS:{ + SQObject id; + SQObject constant; + + 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) { + /* Handle a local variable (includes 'this') */ + _fs->PushTarget(pos); + _es.etype = LOCAL; + _es.epos = pos; + } + + else if((pos = _fs->GetOuterVariable(id)) != -1) { + /* Handle a free var */ + if(NeedGet()) { + _es.epos = _fs->PushTarget(); + _fs->AddInstruction(_OP_GETOUTER, _es.epos, pos); + /* _es.etype = EXPR; already default value */ + } + else { + _es.etype = OUTER; + _es.epos = pos; + } + } + + else if(_fs->IsConstant(id, constant)) { + /* Handle named constant */ + SQObjectPtr constval; + SQObject constid; + if(type(constant) == OT_TABLE) { + Expect('.'); + constid = Expect(TK_IDENTIFIER); + if(!_table(constant)->Get(constid, constval)) { + constval.Null(); + Error(_SC("invalid constant [%s.%s]"), _stringval(id), _stringval(constid)); + } + } + else { + constval = constant; + } + _es.epos = _fs->PushTarget(); + + /* generate direct or literal function depending on size */ + SQObjectType ctype = type(constval); + switch(ctype) { + case OT_INTEGER: EmitLoadConstInt(_integer(constval),_es.epos); break; + case OT_FLOAT: EmitLoadConstFloat(_float(constval),_es.epos); break; + default: _fs->AddInstruction(_OP_LOAD,_es.epos,_fs->GetConstant(constval)); break; + } + _es.etype = EXPR; + } + else { + /* Handle a non-local variable, aka a field. Push the 'this' pointer on + * the virtual stack (always found in offset 0, so no instruction needs to + * be generated), and push the key next. Generate an _OP_LOAD instruction + * for the latter. If we are not using the variable as a dref expr, generate + * the _OP_GET instruction. + */ + _fs->PushTarget(0); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); + if(NeedGet()) { + Emit2ArgsOP(_OP_GET); + } + _es.etype = OBJECT; + } + return _es.epos; + } + break; + case TK_DOUBLE_COLON: // "::" + _fs->AddInstruction(_OP_LOADROOT, _fs->PushTarget()); + _es.etype = OBJECT; + _token = _SC('.'); /* hack: drop into PrefixExpr, case '.'*/ + _es.epos = -1; + return _es.epos; + break; + case TK_NULL: + _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); + Lex(); + break; + case TK_INTEGER: EmitLoadConstInt(_lex._nvalue,-1); Lex(); break; + case TK_FLOAT: EmitLoadConstFloat(_lex._fvalue,-1); 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_NEWOBJ, _fs->PushTarget(),0,0,NOT_ARRAY); + 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, AAT_STACK); + key++; + } + _fs->SetIntructionParam(apos, 1, key); + Lex(); + } + break; + case _SC('{'): + _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); + Lex();ParseTableOrClass(_SC(','),_SC('}')); + break; + case TK_FUNCTION: FunctionExp(_token);break; + case _SC('@'): FunctionExp(_token,true);break; + case TK_CLASS: Lex(); ClassExp();break; + case _SC('-'): + Lex(); + switch(_token) { + case TK_INTEGER: EmitLoadConstInt(-_lex._nvalue,-1); Lex(); break; + case TK_FLOAT: EmitLoadConstFloat(-_lex._fvalue,-1); Lex(); break; + default: UnaryOP(_OP_NEG); + } + break; + case _SC('!'): Lex(); UnaryOP(_OP_NOT); break; + case _SC('~'): + Lex(); + if(_token == TK_INTEGER) { EmitLoadConstInt(~_lex._nvalue,-1); Lex(); break; } + UnaryOP(_OP_BWNOT); + break; + case TK_TYPEOF : Lex() ;UnaryOP(_OP_TYPEOF); break; + case TK_RESUME : Lex(); UnaryOP(_OP_RESUME); break; + case TK_CLONE : Lex(); UnaryOP(_OP_CLONE); break; + case TK_MINUSMINUS : + case TK_PLUSPLUS :PrefixIncDec(_token); break; + case TK_DELETE : DeleteExpr(); break; + case _SC('('): Lex(); CommaExpr(); Expect(_SC(')')); + break; + default: Error(_SC("expression expected")); + } + return -1; + } + void EmitLoadConstInt(SQInteger value,SQInteger target) + { + if(target < 0) { + target = _fs->PushTarget(); + } + if((value & (~((SQInteger)0xFFFFFFFF))) == 0) { //does it fit in 32 bits? + _fs->AddInstruction(_OP_LOADINT, target,value); + } + else { + _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value)); + } + } + void EmitLoadConstFloat(SQFloat value,SQInteger target) + { + if(target < 0) { + target = _fs->PushTarget(); + } + if(sizeof(SQFloat) == sizeof(SQInt32)) { + _fs->AddInstruction(_OP_LOADFLOAT, target,*((SQInt32 *)&value)); + } + else { + _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value)); + } + } + void UnaryOP(SQOpcode op) + { + PrefixedExpr(); + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(op, _fs->PushTarget(), src); + } + bool NeedGet() + { + switch(_token) { + 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 false; + } + return (!_es.donot_get || ( _es.donot_get && (_token == _SC('.') || _token == _SC('[')))); + } + void FunctionCallArgs() + { + SQInteger nargs = 1;//this + while(_token != _SC(')')) { + Expression(); + 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; + bool isstatic = false; + //check if is an attribute + if(separator == ';') { + if(_token == TK_ATTR_OPEN) { + _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); Lex(); + ParseTableOrClass(',',TK_ATTR_CLOSE); + hasattrs = true; + } + if(_token == TK_STATIC) { + isstatic = true; + Lex(); + } + } + 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; + case TK_STRING_LITERAL: //JSON + if(separator == ',') { //only works for tables + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_STRING_LITERAL))); + 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); + unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0); + SQInteger table = _fs->TopTarget(); //<AddInstruction(_OP_NEWSLOT, 0xFF, table, key, val); + } + else { + _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val); //this for classes only as it invokes _newmember + } + } + if(separator == _SC(',')) //hack recognizes a table from the separator + _fs->SetIntructionParam(tpos, 1, nkeys); + Lex(); + } + void LocalDeclStatement() + { + SQObject varname; + Lex(); + if( _token == TK_FUNCTION) { + Lex(); + varname = Expect(TK_IDENTIFIER); + Expect(_SC('(')); + CreateFunction(varname,false); + _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); + _fs->PopTarget(); + _fs->PushLocalVariable(varname); + return; + } + + do { + 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); + if(_token == _SC(',')) Lex(); else break; + } while(1); + } + void IfStatement() + { + SQInteger jmppos; + bool haselse = false; + Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + SQInteger jnepos = _fs->GetCurrentPos(); + BEGIN_SCOPE(); + + Statement(); + // + if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon(); + + END_SCOPE(); + SQInteger endifblock = _fs->GetCurrentPos(); + if(_token == TK_ELSE){ + haselse = true; + BEGIN_SCOPE(); + _fs->AddInstruction(_OP_JMP); + jmppos = _fs->GetCurrentPos(); + Lex(); + Statement(); OptionalSemicolon(); + END_SCOPE(); + _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); + } + _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0)); + } + void WhileStatement() + { + SQInteger jzpos, jmppos; + jmppos = _fs->GetCurrentPos(); + Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); + + BEGIN_BREAKBLE_BLOCK(); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + jzpos = _fs->GetCurrentPos(); + BEGIN_SCOPE(); + + Statement(); + + END_SCOPE(); + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); + _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); + + END_BREAKBLE_BLOCK(jmppos); + } + void DoWhileStatement() + { + Lex(); + SQInteger jmptrg = _fs->GetCurrentPos(); + BEGIN_BREAKBLE_BLOCK() + BEGIN_SCOPE(); + Statement(); + END_SCOPE(); + Expect(TK_WHILE); + SQInteger continuetrg = _fs->GetCurrentPos(); + Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget(), 1); + _fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1); + END_BREAKBLE_BLOCK(continuetrg); + } + void ForStatement() + { + Lex(); + BEGIN_SCOPE(); + 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); + END_SCOPE(); + + 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 + BEGIN_SCOPE(); + //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(); + _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos); + //generate the statement code + BEGIN_BREAKBLE_BLOCK() + Statement(); + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); + _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos); + _fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos); + END_BREAKBLE_BLOCK(foreachpos - 1); + //restore the local variable stack(remove index,val and ref idx) + END_SCOPE(); + } + 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(); + BEGIN_SCOPE(); + Statements(); + END_SCOPE(); + bfirst = false; + } + if(tonextcondjmp != -1) + _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); + if(_token == TK_DEFAULT) { + Lex(); Expect(_SC(':')); + BEGIN_SCOPE(); + Statements(); + END_SCOPE(); + } + 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() + { + SQExpState es; + Lex(); + es = _es; + _es.donot_get = true; + PrefixedExpr(); + if(_es.etype == EXPR) { + Error(_SC("invalid class name")); + } + else if(_es.etype == OBJECT || _es.etype == BASE) { + ClassExp(); + EmitDerefOp(_OP_NEWSLOT); + _fs->PopTarget(); + } + else { + Error(_SC("cannot create a class in a local with the syntax(class )")); + } + _es = es; + } + SQObject ExpectScalar() + { + SQObject val; + val._type = OT_NULL; val._unVal.nInteger = 0; //shut up GCC 4.x + switch(_token) { + case TK_INTEGER: + val._type = OT_INTEGER; + val._unVal.nInteger = _lex._nvalue; + break; + case TK_FLOAT: + val._type = OT_FLOAT; + val._unVal.fFloat = _lex._fvalue; + break; + case TK_STRING_LITERAL: + val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1); + break; + case '-': + Lex(); + switch(_token) + { + case TK_INTEGER: + val._type = OT_INTEGER; + val._unVal.nInteger = -_lex._nvalue; + break; + case TK_FLOAT: + val._type = OT_FLOAT; + val._unVal.fFloat = -_lex._fvalue; + break; + default: + Error(_SC("scalar expected : integer,float")); + } + break; + default: + Error(_SC("scalar expected : integer,float or string")); + } + Lex(); + return val; + } + void EnumStatement() + { + Lex(); + SQObject id = Expect(TK_IDENTIFIER); + Expect(_SC('{')); + + SQObject table = _fs->CreateTable(); + SQInteger nval = 0; + while(_token != _SC('}')) { + SQObject key = Expect(TK_IDENTIFIER); + SQObject val; + if(_token == _SC('=')) { + Lex(); + val = ExpectScalar(); + } + else { + val._type = OT_INTEGER; + val._unVal.nInteger = nval++; + } + _table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val)); + if(_token == ',') Lex(); + } + SQTable *enums = _table(_ss(_vm)->_consts); + SQObjectPtr strongid = id; + enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table)); + strongid.Null(); + Lex(); + } + 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(); + { + BEGIN_SCOPE(); + Statement(); + END_SCOPE(); + } + _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(')')); + { + BEGIN_SCOPE(); + SQInteger ex_target = _fs->PushLocalVariable(exid); + _fs->SetIntructionParam(trappos, 0, ex_target); + Statement(); + _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0); + END_SCOPE(); + } + } + void FunctionExp(SQInteger ftype,bool lambda = false) + { + Lex(); Expect(_SC('(')); + SQObjectPtr dummy; + CreateFunction(dummy,lambda); + _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_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); + ParseTableOrClass(_SC(','),TK_ATTR_CLOSE); + attrs = _fs->TopTarget(); + } + Expect(_SC('{')); + if(attrs != -1) _fs->PopTarget(); + if(base != -1) _fs->PopTarget(); + _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(), base, attrs,NOT_CLASS); + ParseTableOrClass(_SC(';'),_SC('}')); + } + void DeleteExpr() + { + SQExpState es; + Lex(); + es = _es; + _es.donot_get = true; + PrefixedExpr(); + if(_es.etype==EXPR) Error(_SC("can't delete an expression")); + if(_es.etype==OBJECT || _es.etype==BASE) { + Emit2ArgsOP(_OP_DELETE); + } + else { + Error(_SC("cannot delete an (outer) local")); + } + _es = es; + } + void PrefixIncDec(SQInteger token) + { + SQExpState es; + SQInteger diff = (token==TK_MINUSMINUS) ? -1 : 1; + Lex(); + es = _es; + _es.donot_get = true; + PrefixedExpr(); + if(_es.etype==EXPR) { + Error(_SC("can't '++' or '--' an expression")); + } + else if(_es.etype==OBJECT || _es.etype==BASE) { + Emit2ArgsOP(_OP_INC, diff); + } + else if(_es.etype==LOCAL) { + SQInteger src = _fs->TopTarget(); + _fs->AddInstruction(_OP_INCL, src, src, 0, diff); + + } + else if(_es.etype==OUTER) { + SQInteger tmp = _fs->PushTarget(); + _fs->AddInstruction(_OP_GETOUTER, tmp, _es.epos); + _fs->AddInstruction(_OP_INCL, tmp, tmp, 0, diff); + _fs->AddInstruction(_OP_SETOUTER, tmp, _es.epos, tmp); + } + _es = es; + } + void CreateFunction(SQObject &name,bool lambda = false) + { + SQFuncState *funcstate = _fs->PushChildState(_ss(_vm)); + funcstate->_name = name; + SQObject paramname; + funcstate->AddParameter(_fs->CreateString(_SC("this"))); + funcstate->_sourcename = _sourcename; + SQInteger defparams = 0; + while(_token!=_SC(')')) { + if(_token == TK_VARPARAMS) { + if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters")); + funcstate->AddParameter(_fs->CreateString(_SC("vargv"))); + funcstate->_varparams = true; + Lex(); + if(_token != _SC(')')) Error(_SC("expected ')'")); + break; + } + else { + paramname = Expect(TK_IDENTIFIER); + funcstate->AddParameter(paramname); + if(_token == _SC('=')) { + Lex(); + Expression(); + funcstate->AddDefaultParam(_fs->TopTarget()); + defparams++; + } + else { + if(defparams > 0) Error(_SC("expected '='")); + } + if(_token == _SC(',')) Lex(); + else if(_token != _SC(')')) Error(_SC("expected ')' or ','")); + } + } + Expect(_SC(')')); + for(SQInteger n = 0; n < defparams; n++) { + _fs->PopTarget(); + } + + SQFuncState *currchunk = _fs; + _fs = funcstate; + if(lambda) { + Expression(); + _fs->AddInstruction(_OP_RETURN, 1, _fs->PopTarget());} + else { + Statement(false); + } + funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true); + funcstate->AddInstruction(_OP_RETURN, -1); + funcstate->SetStackSize(0); + + SQFunctionProto *func = funcstate->BuildProto(); +#ifdef _DEBUG_DUMP + funcstate->Dump(func); +#endif + _fs = currchunk; + _fs->_functions.push_back(func); + _fs->PopChildState(); + } + 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; + SQExpState _es; + SQScope _scope; + 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); +} + +#endif diff --git a/squirrel_3_0_1_stable/squirrel/sqcompiler.h b/squirrel_3_0_1_stable/squirrel/sqcompiler.h new file mode 100644 index 000000000..fcfd46a99 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqcompiler.h @@ -0,0 +1,77 @@ +/* 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_BASE 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_3WAYSCMP 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 +#define TK_STATIC 322 +#define TK_ENUM 323 +#define TK_CONST 324 + + +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/squirrel_3_0_1_stable/squirrel/sqdebug.cpp b/squirrel_3_0_1_stable/squirrel/sqdebug.cpp new file mode 100644 index 000000000..3cb7b71cd --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqdebug.cpp @@ -0,0 +1,116 @@ +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include +#include "sqvm.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "sqstring.h" + +SQRESULT sq_getfunctioninfo(HSQUIRRELVM v,SQInteger level,SQFunctionInfo *fi) +{ + SQInteger cssize = v->_callsstacksize; + if (cssize > level) { + SQVM::CallInfo &ci = v->_callsstack[cssize-level-1]; + if(sq_isclosure(ci._closure)) { + SQClosure *c = _closure(ci._closure); + SQFunctionProto *proto = c->_function; + fi->funcid = proto; + fi->name = type(proto->_name) == OT_STRING?_stringval(proto->_name):_SC("unknown"); + fi->source = type(proto->_name) == OT_STRING?_stringval(proto->_sourcename):_SC("unknown"); + return SQ_OK; + } + } + return sq_throwerror(v,_SC("the object is not a closure")); +} + +SQRESULT sq_stackinfos(HSQUIRRELVM v, SQInteger level, SQStackInfos *si) +{ + SQInteger cssize = v->_callsstacksize; + 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 = _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; + default: break; //shutup compiler + } + return SQ_OK; + } + return SQ_ERROR; +} + +void SQVM::Raise_Error(const SQChar *s, ...) +{ + va_list vl; + va_start(vl, s); + scvsprintf(_sp(rsl((SQInteger)scstrlen(s)+(NUMBER_MAX_CHAR*2))), s, vl); + va_end(vl); + _lasterror = SQString::Create(_ss(this),_spval,-1); +} + +void SQVM::Raise_Error(const SQObjectPtr &desc) +{ + _lasterror = desc; +} + +SQString *SQVM::PrintObjVal(const SQObjectPtr &o) +{ + switch(type(o)) { + case OT_STRING: return _string(o); + case OT_INTEGER: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)), _PRINT_INT_FMT, _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(const SQObjectPtr &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/squirrel_3_0_1_stable/squirrel/sqfuncproto.h b/squirrel_3_0_1_stable/squirrel/sqfuncproto.h new file mode 100644 index 000000000..cd48aa6df --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqfuncproto.h @@ -0,0 +1,154 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQFUNCTION_H_ +#define _SQFUNCTION_H_ + +#include "sqopcodes.h" + +enum SQOuterType { + otLOCAL = 0, + otOUTER = 1 +}; + +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),_pos(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; + +#define _FUNC_SIZE(ni,nl,nparams,nfuncs,nouters,nlineinf,localinf,defparams) (sizeof(SQFunctionProto) \ + +((ni-1)*sizeof(SQInstruction))+(nl*sizeof(SQObjectPtr)) \ + +(nparams*sizeof(SQObjectPtr))+(nfuncs*sizeof(SQObjectPtr)) \ + +(nouters*sizeof(SQOuterVar))+(nlineinf*sizeof(SQLineInfo)) \ + +(localinf*sizeof(SQLocalVarInfo))+(defparams*sizeof(SQInteger))) + + +struct SQFunctionProto : public CHAINABLE_OBJ +{ +private: + SQFunctionProto(SQSharedState *ss); + ~SQFunctionProto(); + +public: + static SQFunctionProto *Create(SQSharedState *ss,SQInteger ninstructions, + SQInteger nliterals,SQInteger nparameters, + SQInteger nfunctions,SQInteger noutervalues, + SQInteger nlineinfos,SQInteger nlocalvarinfos,SQInteger ndefaultparams) + { + SQFunctionProto *f; + //I compact the whole class and members in a single memory allocation + f = (SQFunctionProto *)sq_vm_malloc(_FUNC_SIZE(ninstructions,nliterals,nparameters,nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams)); + new (f) SQFunctionProto(ss); + f->_ninstructions = ninstructions; + f->_literals = (SQObjectPtr*)&f->_instructions[ninstructions]; + f->_nliterals = nliterals; + f->_parameters = (SQObjectPtr*)&f->_literals[nliterals]; + f->_nparameters = nparameters; + f->_functions = (SQObjectPtr*)&f->_parameters[nparameters]; + f->_nfunctions = nfunctions; + f->_outervalues = (SQOuterVar*)&f->_functions[nfunctions]; + f->_noutervalues = noutervalues; + f->_lineinfos = (SQLineInfo *)&f->_outervalues[noutervalues]; + f->_nlineinfos = nlineinfos; + f->_localvarinfos = (SQLocalVarInfo *)&f->_lineinfos[nlineinfos]; + f->_nlocalvarinfos = nlocalvarinfos; + f->_defaultparams = (SQInteger *)&f->_localvarinfos[nlocalvarinfos]; + f->_ndefaultparams = ndefaultparams; + + _CONSTRUCT_VECTOR(SQObjectPtr,f->_nliterals,f->_literals); + _CONSTRUCT_VECTOR(SQObjectPtr,f->_nparameters,f->_parameters); + _CONSTRUCT_VECTOR(SQObjectPtr,f->_nfunctions,f->_functions); + _CONSTRUCT_VECTOR(SQOuterVar,f->_noutervalues,f->_outervalues); + //_CONSTRUCT_VECTOR(SQLineInfo,f->_nlineinfos,f->_lineinfos); //not required are 2 integers + _CONSTRUCT_VECTOR(SQLocalVarInfo,f->_nlocalvarinfos,f->_localvarinfos); + return f; + } + void Release(){ + _DESTRUCT_VECTOR(SQObjectPtr,_nliterals,_literals); + _DESTRUCT_VECTOR(SQObjectPtr,_nparameters,_parameters); + _DESTRUCT_VECTOR(SQObjectPtr,_nfunctions,_functions); + _DESTRUCT_VECTOR(SQOuterVar,_noutervalues,_outervalues); + //_DESTRUCT_VECTOR(SQLineInfo,_nlineinfos,_lineinfos); //not required are 2 integers + _DESTRUCT_VECTOR(SQLocalVarInfo,_nlocalvarinfos,_localvarinfos); + SQInteger size = _FUNC_SIZE(_ninstructions,_nliterals,_nparameters,_nfunctions,_noutervalues,_nlineinfos,_nlocalvarinfos,_ndefaultparams); + this->~SQFunctionProto(); + sq_vm_free(this,size); + } + + const SQChar* GetLocal(SQVM *v,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop); + SQInteger GetLine(SQInstruction *curr); + bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); + static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){ _NULL_SQOBJECT_VECTOR(_literals,_nliterals); } + SQObjectType GetType() {return OT_FUNCPROTO;} +#endif + SQObjectPtr _sourcename; + SQObjectPtr _name; + SQInteger _stacksize; + bool _bgenerator; + SQInteger _varparams; + + SQInteger _nlocalvarinfos; + SQLocalVarInfo *_localvarinfos; + + SQInteger _nlineinfos; + SQLineInfo *_lineinfos; + + SQInteger _nliterals; + SQObjectPtr *_literals; + + SQInteger _nparameters; + SQObjectPtr *_parameters; + + SQInteger _nfunctions; + SQObjectPtr *_functions; + + SQInteger _noutervalues; + SQOuterVar *_outervalues; + + SQInteger _ndefaultparams; + SQInteger *_defaultparams; + + SQInteger _ninstructions; + SQInstruction _instructions[1]; +}; + +#endif //_SQFUNCTION_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqfuncstate.cpp b/squirrel_3_0_1_stable/squirrel/sqfuncstate.cpp new file mode 100644 index 000000000..9e236c7e7 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqfuncstate.cpp @@ -0,0 +1,652 @@ +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#ifndef NO_COMPILER +#include "sqcompiler.h" +#include "sqstring.h" +#include "sqfuncproto.h" +#include "sqtable.h" +#include "sqopcodes.h" +#include "sqfuncstate.h" + +#ifdef _DEBUG_DUMP +SQInstructionDesc g_InstrDesc[]={ + {_SC("_OP_LINE")}, + {_SC("_OP_LOAD")}, + {_SC("_OP_LOADINT")}, + {_SC("_OP_LOADFLOAT")}, + {_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_ADD")}, + {_SC("_OP_SUB")}, + {_SC("_OP_MUL")}, + {_SC("_OP_DIV")}, + {_SC("_OP_MOD")}, + {_SC("_OP_BITW")}, + {_SC("_OP_RETURN")}, + {_SC("_OP_LOADNULLS")}, + {_SC("_OP_LOADROOT")}, + {_SC("_OP_LOADBOOL")}, + {_SC("_OP_DMOVE")}, + {_SC("_OP_JMP")}, + {_SC("_OP_JCMP")}, + {_SC("_OP_JZ")}, + {_SC("_OP_SETOUTER")}, + {_SC("_OP_GETOUTER")}, + {_SC("_OP_NEWOBJ")}, + {_SC("_OP_APPENDARRAY")}, + {_SC("_OP_COMPARITH")}, + {_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_POSTFOREACH")}, + {_SC("_OP_CLONE")}, + {_SC("_OP_TYPEOF")}, + {_SC("_OP_PUSHTRAP")}, + {_SC("_OP_POPTRAP")}, + {_SC("_OP_THROW")}, + {_SC("_OP_NEWSLOTA")}, + {_SC("_OP_GETBASE")}, + {_SC("_OP_CLOSE")}, + {_SC("_OP_JCMP")} +}; +#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("{") _PRINT_INT_FMT _SC("}"),_integer(o));break; + case OT_BOOL: scprintf(_SC("%s"),_integer(o)?_SC("true"):_SC("false"));break; + default: scprintf(_SC("(%s %p)"),GetTypeName(o),(void*)_rawval(o));break; break; //shut up compiler + } +} + +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; + _outers = 0; + _ss = ss; + +} + +void SQFuncState::Error(const SQChar *err) +{ + _errfunc(_errtarget,err); +} + +#ifdef _DEBUG_DUMP +void SQFuncState::Dump(SQFunctionProto *func) +{ + SQUnsignedInteger n=0,i; + SQInteger si; + 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(si=0;si_nlocalvarinfos;si++){ + SQLocalVarInfo lvi=func->_localvarinfos[si]; + 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_LOADFLOAT) { + scprintf(_SC("[%03d] %15s %d %f %d %d\n"),n,g_InstrDesc[inst.op].name,inst._arg0,*((SQFloat*)&inst._arg1),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 + +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) +{ + 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=(unsigned char)*((SQUnsignedInteger *)&arg0); + _instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&arg1); + _instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&arg2); + _instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&arg3); +} + +void SQFuncState::SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val) +{ + switch(arg){ + case 0:_instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&val);break; + case 1:case 4:_instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&val);break; + case 2:_instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&val);break; + case 3:_instructions[pos]._arg3=(unsigned char)*((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(); +} + +SQInteger SQFuncState::CountOuters(SQInteger stacksize) +{ + SQInteger outers = 0; + SQInteger k = _vlocals.size() - 1; + while(k >= stacksize) { + SQLocalVarInfo &lvi = _vlocals[k]; + k--; + if(lvi._end_op == UINT_MINUS_ONE) { //this means is an outer + outers++; + } + } + return outers; +} + +void SQFuncState::SetStackSize(SQInteger n) +{ + SQInteger size=_vlocals.size(); + while(size>n){ + size--; + SQLocalVarInfo lvi = _vlocals.back(); + if(type(lvi._name)!=OT_NULL){ + if(lvi._end_op == UINT_MINUS_ONE) { //this means is an outer + _outers--; + } + lvi._end_op = GetCurrentPos(); + _localvarinfos.push_back(lvi); + } + _vlocals.pop_back(); + } +} + +bool SQFuncState::IsConstant(const SQObject &name,SQObject &e) +{ + SQObjectPtr val; + if(_table(_sharedstate->_consts)->Get(name,val)) { + e = val; + return true; + } + return false; +} + +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){ + SQLocalVarInfo &lvi = _vlocals[locals-1]; + if(type(lvi._name)==OT_STRING && _string(lvi._name)==_string(name)){ + return locals-1; + } + locals--; + } + return -1; +} + +void SQFuncState::MarkLocalAsOuter(SQInteger pos) +{ + SQLocalVarInfo &lvi = _vlocals[pos]; + lvi._end_op = UINT_MINUS_ONE; + _outers++; +} + +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 _outervalues.size() - 1; + } + } + else { + _parent->MarkLocalAsOuter(pos); + _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otLOCAL)); //local + return _outervalues.size() - 1; + + + } + } + return -1; +} + +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); + if(_lastline!=line) { + _lineinfos.push_back(li); + } + _lastline=line; + } +} + +void SQFuncState::DiscardTarget() +{ + SQInteger discardedtarget = PopTarget(); + SQInteger size = _instructions.size(); + if(size > 0 && _optimization){ + SQInstruction &pi = _instructions[size-1];//previous instruction + switch(pi.op) { + case _OP_SET:case _OP_NEWSLOT:case _OP_SETOUTER:case _OP_CALL: + if(pi._arg0 == discardedtarget) { + pi._arg0 = 0xFF; + } + } + } +} + +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_JZ: + if( pi.op == _OP_CMP && pi._arg1 < 0xFF) { + pi.op = _OP_JCMP; + pi._arg0 = (unsigned char)pi._arg1; + pi._arg1 = i._arg1; + return; + } + case _OP_SET: + case _OP_NEWSLOT: + if(i._arg0 == i._arg3) { + i._arg0 = 0xFF; + } + break; + case _OP_SETOUTER: + if(i._arg0 == i._arg2) { + i._arg0 = 0xFF; + } + break; + case _OP_RETURN: + if( _parent && i._arg0 != MAX_FUNC_STACKSIZE && pi.op == _OP_CALL && _returnexp < size-1) { + pi.op = _OP_TAILCALL; + } else if(pi.op == _OP_CLOSE){ + pi = i; + return; + } + 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: { + SQInteger aat = -1; + switch(pi.op) { + case _OP_LOAD: aat = AAT_LITERAL; break; + case _OP_LOADINT: aat = AAT_INT; break; + case _OP_LOADBOOL: aat = AAT_BOOL; break; + case _OP_LOADFLOAT: aat = AAT_FLOAT; break; + default: break; + } + if(aat != -1 && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){ + pi.op = _OP_APPENDARRAY; + pi._arg0 = i._arg0; + pi._arg1 = pi._arg1; + pi._arg2 = (unsigned char)aat; + pi._arg3 = MAX_FUNC_STACKSIZE; + return; + } + } + break; + case _OP_MOVE: + switch(pi.op) { + case _OP_GET: case _OP_ADD: case _OP_SUB: case _OP_MUL: case _OP_DIV: case _OP_MOD: case _OP_BITW: + case _OP_LOADINT: case _OP_LOADFLOAT: case _OP_LOADBOOL: case _OP_LOAD: + + if(pi._arg0 == i._arg1) + { + pi._arg0 = i._arg0; + _optimization = false; + //_result_elimination = 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,(SQInteger)1); + return ns; +} + +SQObject SQFuncState::CreateTable() +{ + SQObjectPtr nt(SQTable::Create(_sharedstate,0)); + _table(_strings)->NewSlot(nt,(SQInteger)1); + return nt; +} + +SQFunctionProto *SQFuncState::BuildProto() +{ + + SQFunctionProto *f=SQFunctionProto::Create(_ss,_instructions.size(), + _nliterals,_parameters.size(),_functions.size(),_outervalues.size(), + _lineinfos.size(),_localvarinfos.size(),_defaultparams.size()); + + 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; + } + + for(SQUnsignedInteger nf = 0; nf < _functions.size(); nf++) f->_functions[nf] = _functions[nf]; + for(SQUnsignedInteger np = 0; np < _parameters.size(); np++) f->_parameters[np] = _parameters[np]; + for(SQUnsignedInteger no = 0; no < _outervalues.size(); no++) f->_outervalues[no] = _outervalues[no]; + for(SQUnsignedInteger nl = 0; nl < _localvarinfos.size(); nl++) f->_localvarinfos[nl] = _localvarinfos[nl]; + for(SQUnsignedInteger ni = 0; ni < _lineinfos.size(); ni++) f->_lineinfos[ni] = _lineinfos[ni]; + for(SQUnsignedInteger nd = 0; nd < _defaultparams.size(); nd++) f->_defaultparams[nd] = _defaultparams[nd]; + + memcpy(f->_instructions,&_instructions[0],_instructions.size()*sizeof(SQInstruction)); + + 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(); + } +} + +#endif diff --git a/squirrel_3_0_1_stable/squirrel/sqfuncstate.h b/squirrel_3_0_1_stable/squirrel/sqfuncstate.h new file mode 100644 index 000000000..1da13212a --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqfuncstate.h @@ -0,0 +1,91 @@ +/* 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; + SQSharedState *_ss; +}; + + +#endif //_SQFUNCSTATE_H_ + diff --git a/squirrel_3_0_1_stable/squirrel/sqlexer.cpp b/squirrel_3_0_1_stable/squirrel/sqlexer.cpp new file mode 100644 index 000000000..ab17ba619 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqlexer.cpp @@ -0,0 +1,489 @@ +/* + 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(base, TK_BASE); + 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(class,TK_CLASS); + ADD_KEYWORD(extends,TK_EXTENDS); + ADD_KEYWORD(constructor,TK_CONSTRUCTOR); + ADD_KEYWORD(instanceof,TK_INSTANCEOF); + ADD_KEYWORD(true,TK_TRUE); + ADD_KEYWORD(false,TK_FALSE); + ADD_KEYWORD(static,TK_STATIC); + ADD_KEYWORD(enum,TK_ENUM); + ADD_KEYWORD(const,TK_CONST); + + _readf = rg; + _up = up; + _lasttokenline = _currentline = 1; + _currentcolumn = 0; + _prevtoken = -1; + _reached_eof = SQFalse; + 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 = (LexChar)t; + return; + } + _currdata = SQUIRREL_EOB; + _reached_eof = SQTrue; +} + +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(); + } + } +} +void SQLexer::LexLineComment() +{ + do { NEXT(); } while (CUR_CHAR != _SC('\n') && (!IS_EOB())); +} + +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('#'): LexLineComment(); continue; + case _SC('/'): + NEXT(); + switch(CUR_CHAR){ + case _SC('*'): + NEXT(); + LexBlockComment(); + continue; + case _SC('/'): + LexLineComment(); + 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(); + switch(CUR_CHAR) { + case _SC('='): + NEXT(); + if(CUR_CHAR == _SC('>')) { + NEXT(); + RETURN_TOKEN(TK_3WAYSCMP); + } + RETURN_TOKEN(TK_LE) + break; + case _SC('-'): NEXT(); RETURN_TOKEN(TK_NEWSLOT); break; + case _SC('<'): NEXT(); RETURN_TOKEN(TK_SHIFTL); break; + case _SC('/'): NEXT(); RETURN_TOKEN(TK_ATTR_OPEN); break; + } + 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('"')) { + RETURN_TOKEN('@'); + } + 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((int)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; +} + +void LexHexadecimal(const SQChar *s,SQUnsignedInteger *res) +{ + *res = 0; + while(*s != 0) + { + if(scisdigit(*s)) *res = (*res)*16+((*s++)-'0'); + else if(scisxdigit(*s)) *res = (*res)*16+(toupper(*s++)-'A'+10); + else { assert(0); } + } +} + +void LexInteger(const SQChar *s,SQUnsignedInteger *res) +{ + *res = 0; + while(*s != 0) + { + *res = (*res)*10+((*s++)-'0'); + } +} + +SQInteger scisodigit(SQInteger c) { return c >= _SC('0') && c <= _SC('7'); } + +void LexOctal(const SQChar *s,SQUnsignedInteger *res) +{ + *res = 0; + while(*s != 0) + { + if(scisodigit(*s)) *res = (*res)*8+((*s++)-'0'); + else { assert(0); } + } +} + +SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; } + + +#define MAX_HEX_DIGITS (sizeof(SQInteger)*2) +SQInteger SQLexer::ReadNumber() +{ +#define TINT 1 +#define TFLOAT 2 +#define THEX 3 +#define TSCIENTIFIC 4 +#define TOCTAL 5 + SQInteger type = TINT, firstchar = CUR_CHAR; + SQChar *sTemp; + INIT_TEMP_STRING(); + NEXT(); + if(firstchar == _SC('0') && (toupper(CUR_CHAR) == _SC('X') || scisodigit(CUR_CHAR)) ) { + if(scisodigit(CUR_CHAR)) { + type = TOCTAL; + while(scisodigit(CUR_CHAR)) { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + if(scisdigit(CUR_CHAR)) Error(_SC("invalid octal number")); + } + else { + NEXT(); + type = THEX; + while(isxdigit(CUR_CHAR)) { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + if(_longstr.size() > MAX_HEX_DIGITS) Error(_SC("too many digits for an Hex number")); + } + } + else { + APPEND_CHAR((int)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: + LexInteger(&_longstr[0],(SQUnsignedInteger *)&_nvalue); + return TK_INTEGER; + case THEX: + LexHexadecimal(&_longstr[0],(SQUnsignedInteger *)&_nvalue); + return TK_INTEGER; + case TOCTAL: + LexOctal(&_longstr[0],(SQUnsignedInteger *)&_nvalue); + return TK_INTEGER; + } + return 0; +} + +SQInteger SQLexer::ReadID() +{ + SQInteger res; + 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 || res == TK_CONSTRUCTOR) { + _svalue = &_longstr[0]; + } + return res; +} diff --git a/squirrel_3_0_1_stable/squirrel/sqlexer.h b/squirrel_3_0_1_stable/squirrel/sqlexer.h new file mode 100644 index 000000000..d3283c6f7 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqlexer.h @@ -0,0 +1,47 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQLEXER_H_ +#define _SQLEXER_H_ + +#ifdef SQUNICODE +typedef SQChar LexChar; +#else +typedef unsigned char LexChar; +#endif + +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(); + void LexLineComment(); + SQInteger ReadID(); + void Next(); + SQInteger _curtoken; + SQTable *_keywords; + SQBool _reached_eof; +public: + SQInteger _prevtoken; + SQInteger _currentline; + SQInteger _lasttokenline; + SQInteger _currentcolumn; + const SQChar *_svalue; + SQInteger _nvalue; + SQFloat _fvalue; + SQLEXREADFUNC _readf; + SQUserPointer _up; + LexChar _currdata; + SQSharedState *_sharedstate; + sqvector _longstr; + CompilerErrorFunc _errfunc; + void *_errtarget; +}; + +#endif diff --git a/squirrel_3_0_1_stable/squirrel/sqmem.cpp b/squirrel_3_0_1_stable/squirrel/sqmem.cpp new file mode 100644 index 000000000..520f7eb76 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqmem.cpp @@ -0,0 +1,9 @@ +/* + 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/squirrel_3_0_1_stable/squirrel/sqobject.cpp b/squirrel_3_0_1_stable/squirrel/sqobject.cpp new file mode 100644 index 000000000..418a6d656 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqobject.cpp @@ -0,0 +1,655 @@ +/* + 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" + + +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"); + case _RT_OUTER: return _SC("outer"); + default: + return NULL; + } +} + +const SQChar *GetTypeName(const SQObjectPtr &obj1) +{ + return IdType2Name(type(obj1)); +} + +SQString *SQString::Create(SQSharedState *ss,const SQChar *s,SQInteger len) +{ + SQString *str=ADD_STRING(ss,s,len); + return str; +} + +void SQString::Release() +{ + REMOVE_STRING(_sharedstate,this); +} + +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; +} + +SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx) +{ + switch(type(idx)){ + case OT_NULL: + return 0; + case OT_INTEGER: + return (SQUnsignedInteger)_integer(idx); + default: assert(0); break; + } + 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(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) { + if(_delegate) { + return _delegate->Get((*_ss(v)->_metamethods)[mm],res); + } + return false; +} + +bool SQDelegable::SetDelegate(SQTable *mt) +{ + SQTable *temp = mt; + if(temp == this) return false; + 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,SQInteger target) +{ + 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; + + _stack.resize(size); + SQObject _this = v->_stack[v->_stackbase]; + _stack._vals[0] = ISREFCOUNTED(type(_this)) ? SQObjectPtr(_refcounted(_this)->GetWeakRef(type(_this))) : _this; + for(SQInteger n =1; n_stack[v->_stackbase+n]; + } + for(SQInteger j =0; j < size; j++) + { + v->_stack[v->_stackbase+j].Null(); + } + + _ci = *v->ci; + _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,SQObjectPtr &dest) +{ + 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 size = _stack.size(); + SQInteger target = &dest - &(v->_stack._vals[v->_stackbase]); + assert(target>=0 && target<=255); + if(!v->EnterFrame(v->_top, v->_top + size, false)) + return false; + v->ci->_generator = this; + v->ci->_target = (SQInt32)target; + v->ci->_closure = _ci._closure; + v->ci->_ip = _ci._ip; + v->ci->_literals = _ci._literals; + v->ci->_ncalls = _ci._ncalls; + v->ci->_etraps = _ci._etraps; + v->ci->_root = _ci._root; + + + for(SQInteger i=0;i<_ci._etraps;i++) { + v->_etraps.push_back(_etraps.top()); + _etraps.pop_back(); + } + SQObject _this = _stack._vals[0]; + v->_stack[v->_stackbase] = type(_this) == OT_WEAKREF ? _weakref(_this)->_obj : _this; + + for(SQInteger n = 1; n_stack[v->_stackbase+n] = _stack._vals[n]; + _stack._vals[n].Null(); + } + + _state=eRunning; + if (v->_debughook) + v->CallDebugHook(_SC('c')); + + 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=_nlocalvarinfos; + 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 = (SQInteger)(curr-_instructions); + SQInteger line=_lineinfos[0]._line; + SQInteger low = 0; + SQInteger high = _nlineinfos - 1; + SQInteger mid = 0; + while(low <= high) + { + mid = low + ((high - low) >> 1); + SQInteger curop = _lineinfos[mid]._op; + if(curop > op) + { + high = mid - 1; + } + else if(curop < op) { + if(mid < (_nlineinfos - 1) + && _lineinfos[mid + 1]._op >= op) { + break; + } + low = mid + 1; + } + else { //equal + break; + } + } + + line = _lineinfos[mid]._line; + return line; +} + +SQClosure::~SQClosure() +{ + __ObjRelease(_env); + __ObjRelease(_base); + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); +} + +#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,SQUnsignedInteger32 tag) +{ + return SafeWrite(v,write,up,&tag,sizeof(tag)); +} + +bool CheckTag(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQUnsignedInteger32 tag) +{ + SQUnsignedInteger32 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) +{ + SQUnsignedInteger32 _type = (SQUnsignedInteger32)type(o); + _CHECK_IO(SafeWrite(v,write,up,&_type,sizeof(_type))); + 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) +{ + SQUnsignedInteger32 _type; + _CHECK_IO(SafeRead(v,read,up,&_type,sizeof(_type))); + SQObjectType t = (SQObjectType)_type; + 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(WriteTag(v,write,up,sizeof(SQInteger))); + _CHECK_IO(WriteTag(v,write,up,sizeof(SQFloat))); + _CHECK_IO(_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,SQObjectPtr &ret) +{ + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_HEAD)); + _CHECK_IO(CheckTag(v,read,up,sizeof(SQChar))); + _CHECK_IO(CheckTag(v,read,up,sizeof(SQInteger))); + _CHECK_IO(CheckTag(v,read,up,sizeof(SQFloat))); + SQObjectPtr func; + _CHECK_IO(SQFunctionProto::Load(v,up,read,func)); + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_TAIL)); + ret = SQClosure::Create(_ss(v),_funcproto(func)); + return true; +} + +SQFunctionProto::SQFunctionProto(SQSharedState *ss) +{ + _stacksize=0; + _bgenerator=false; + INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); +} + +SQFunctionProto::~SQFunctionProto() +{ + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); +} + +bool SQFunctionProto::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write) +{ + SQInteger i,nliterals = _nliterals,nparameters = _nparameters; + SQInteger noutervalues = _noutervalues,nlocalvarinfos = _nlocalvarinfos; + SQInteger nlineinfos=_nlineinfos,ninstructions = _ninstructions,nfunctions=_nfunctions; + SQInteger ndefaultparams = _ndefaultparams; + _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,&nliterals,sizeof(nliterals))); + _CHECK_IO(SafeWrite(v,write,up,&nparameters,sizeof(nparameters))); + _CHECK_IO(SafeWrite(v,write,up,&noutervalues,sizeof(noutervalues))); + _CHECK_IO(SafeWrite(v,write,up,&nlocalvarinfos,sizeof(nlocalvarinfos))); + _CHECK_IO(SafeWrite(v,write,up,&nlineinfos,sizeof(nlineinfos))); + _CHECK_IO(SafeWrite(v,write,up,&ndefaultparams,sizeof(ndefaultparams))); + _CHECK_IO(SafeWrite(v,write,up,&ninstructions,sizeof(ninstructions))); + _CHECK_IO(SafeWrite(v,write,up,&nfunctions,sizeof(nfunctions))); + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + 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,SQObjectPtr &ret) +{ + SQInteger i, nliterals,nparameters; + SQInteger noutervalues ,nlocalvarinfos ; + SQInteger nlineinfos,ninstructions ,nfunctions,ndefaultparams ; + SQObjectPtr sourcename, name; + 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, &nliterals, sizeof(nliterals))); + _CHECK_IO(SafeRead(v,read,up, &nparameters, sizeof(nparameters))); + _CHECK_IO(SafeRead(v,read,up, &noutervalues, sizeof(noutervalues))); + _CHECK_IO(SafeRead(v,read,up, &nlocalvarinfos, sizeof(nlocalvarinfos))); + _CHECK_IO(SafeRead(v,read,up, &nlineinfos, sizeof(nlineinfos))); + _CHECK_IO(SafeRead(v,read,up, &ndefaultparams, sizeof(ndefaultparams))); + _CHECK_IO(SafeRead(v,read,up, &ninstructions, sizeof(ninstructions))); + _CHECK_IO(SafeRead(v,read,up, &nfunctions, sizeof(nfunctions))); + + + SQFunctionProto *f = SQFunctionProto::Create(_opt_ss(v),ninstructions,nliterals,nparameters, + nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams); + SQObjectPtr proto = f; //gets a ref in case of failure + f->_sourcename = sourcename; + f->_name = name; + + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + + for(i = 0;i < nliterals; i++){ + _CHECK_IO(ReadObject(v, up, read, o)); + f->_literals[i] = o; + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + + for(i = 0; i < nparameters; i++){ + _CHECK_IO(ReadObject(v, up, read, o)); + f->_parameters[i] = o; + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + + for(i = 0; i < noutervalues; 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)); + f->_outervalues[i] = SQOuterVar(name,o, (SQOuterType)type); + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + + for(i = 0; i < nlocalvarinfos; 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))); + f->_localvarinfos[i] = lvi; + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, f->_lineinfos, sizeof(SQLineInfo)*nlineinfos)); + + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, f->_defaultparams, sizeof(SQInteger)*ndefaultparams)); + + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, f->_instructions, sizeof(SQInstruction)*ninstructions)); + + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + for(i = 0; i < nfunctions; i++){ + _CHECK_IO(_funcproto(o)->Load(v, up, read, o)); + f->_functions[i] = o; + } + _CHECK_IO(SafeRead(v,read,up, &f->_stacksize, sizeof(f->_stacksize))); + _CHECK_IO(SafeRead(v,read,up, &f->_bgenerator, sizeof(f->_bgenerator))); + _CHECK_IO(SafeRead(v,read,up, &f->_varparams, sizeof(f->_varparams))); + + ret = f; + 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_closure,chain); + SQSharedState::MarkObject(_roottable, chain); + SQSharedState::MarkObject(temp_reg, chain); + for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); + for(SQInteger k = 0; k < _callsstacksize; k++) SQSharedState::MarkObject(_callsstack[k]._closure, 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< MT_LAST; k++) { + SQSharedState::MarkObject(_metamethods[k], chain); + } + END_MARK() +} + +void SQInstance::Mark(SQCollectable **chain) +{ + START_MARK() + _class->Mark(chain); + SQUnsignedInteger nvalues = _class->_defaultvalues.size(); + 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); + SQSharedState::MarkObject(_closure, chain); + END_MARK() +} + +void SQFunctionProto::Mark(SQCollectable **chain) +{ + START_MARK() + for(SQInteger i = 0; i < _nliterals; i++) SQSharedState::MarkObject(_literals[i], chain); + for(SQInteger k = 0; k < _nfunctions; k++) SQSharedState::MarkObject(_functions[k], chain); + END_MARK() +} + +void SQClosure::Mark(SQCollectable **chain) +{ + START_MARK() + if(_base) _base->Mark(chain); + SQFunctionProto *fp = _function; + fp->Mark(chain); + for(SQInteger i = 0; i < fp->_noutervalues; i++) SQSharedState::MarkObject(_outervalues[i], chain); + for(SQInteger k = 0; k < fp->_ndefaultparams; k++) SQSharedState::MarkObject(_defaultparams[k], chain); + END_MARK() +} + +void SQNativeClosure::Mark(SQCollectable **chain) +{ + START_MARK() + for(SQUnsignedInteger i = 0; i < _noutervalues; i++) SQSharedState::MarkObject(_outervalues[i], chain); + END_MARK() +} + +void SQOuter::Mark(SQCollectable **chain) +{ + START_MARK() + /* If the valptr points to a closed value, that value is alive */ + if(_valptr == &_value) { + SQSharedState::MarkObject(_value, 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/squirrel_3_0_1_stable/squirrel/sqobject.h b/squirrel_3_0_1_stable/squirrel/sqobject.h new file mode 100644 index 000000000..a7d1e1ed3 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqobject.h @@ -0,0 +1,354 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQOBJECT_H_ +#define _SQOBJECT_H_ + +#include "squtils.h" + +#ifdef _SQ64 +#define UINT_MINUS_ONE (0xFFFFFFFFFFFFFFFF) +#else +#define UINT_MINUS_ONE (0xFFFFFFFF) +#endif + +#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_NEWMEMBER=16, + MT_INHERITED=17, + MT_LAST = 18 +}; + +#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 MM_NEWMEMBER _SC("_newmember") +#define MM_INHERITED _SC("_inherited") + + +#define _CONSTRUCT_VECTOR(type,size,ptr) { \ + for(SQInteger n = 0; n < ((SQInteger)size); n++) { \ + new (&ptr[n]) type(); \ + } \ +} + +#define _DESTRUCT_VECTOR(type,size,ptr) { \ + for(SQInteger nl = 0; nl < ((SQInteger)size); nl++) { \ + ptr[nl].~type(); \ + } \ +} + +#define _COPY_VECTOR(dest,src,size) { \ + for(SQInteger _n_ = 0; _n_ < ((SQInteger)size); _n_++) { \ + dest[_n_] = src[_n_]; \ + } \ +} + +#define _NULL_SQOBJECT_VECTOR(vec,size) { \ + for(SQInteger _n_ = 0; _n_ < ((SQInteger)size); _n_++) { \ + vec[_n_].Null(); \ + } \ +} + +#define MINPOWER2 4 + +struct SQRefCounted +{ + SQUnsignedInteger _uiRef; + struct SQWeakRef *_weakref; + SQRefCounted() { _uiRef = 0; _weakref = NULL; } + virtual ~SQRefCounted(); + SQWeakRef *GetWeakRef(SQObjectType type); + 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 _outer(obj) ((obj)._unVal.pOuter) +#define _refcounted(obj) ((obj)._unVal.pRefCounted) +#define _rawval(obj) ((obj)._unVal.raw) + +#define _stringval(obj) (obj)._unVal.pString->_val +#define _userdataval(obj) ((SQUserPointer)sq_aligning((obj)._unVal.pUserData + 1)) + +#define tofloat(num) ((type(num)==OT_INTEGER)?(SQFloat)_integer(num):_float(num)) +#define tointeger(num) ((type(num)==OT_FLOAT)?(SQInteger)_float(num):_integer(num)) +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +#if defined(SQUSEDOUBLE) && !defined(_SQ64) || !defined(SQUSEDOUBLE) && defined(_SQ64) +#define SQ_REFOBJECT_INIT() SQ_OBJECT_RAWINIT() +#else +#define SQ_REFOBJECT_INIT() +#endif + +#define _REF_TYPE_DECL(type,_class,sym) \ + SQObjectPtr(_class * x) \ + { \ + SQ_OBJECT_RAWINIT() \ + _type=type; \ + _unVal.sym = x; \ + assert(_unVal.pTable); \ + _unVal.pRefCounted->_uiRef++; \ + } \ + inline SQObjectPtr& operator=(_class *x) \ + { \ + SQObjectType tOldType; \ + SQObjectValue unOldVal; \ + tOldType=_type; \ + unOldVal=_unVal; \ + _type = type; \ + SQ_REFOBJECT_INIT() \ + _unVal.sym = x; \ + _unVal.pRefCounted->_uiRef++; \ + __Release(tOldType,unOldVal); \ + return *this; \ + } + +#define _SCALAR_TYPE_DECL(type,_class,sym) \ + SQObjectPtr(_class x) \ + { \ + SQ_OBJECT_RAWINIT() \ + _type=type; \ + _unVal.sym = x; \ + } \ + inline SQObjectPtr& operator=(_class x) \ + { \ + __Release(_type,_unVal); \ + _type = type; \ + SQ_OBJECT_RAWINIT() \ + _unVal.sym = x; \ + return *this; \ + } +struct SQObjectPtr : public SQObject +{ + SQObjectPtr() + { + SQ_OBJECT_RAWINIT() + _type=OT_NULL; + _unVal.pUserPointer=NULL; + } + SQObjectPtr(const SQObjectPtr &o) + { + //SQ_OBJECT_RAWINIT() + _type=o._type; + _unVal=o._unVal; + __AddRef(_type,_unVal); + } + SQObjectPtr(const SQObject &o) + { + //SQ_OBJECT_RAWINIT() + _type=o._type; + _unVal=o._unVal; + __AddRef(_type,_unVal); + } + _REF_TYPE_DECL(OT_TABLE,SQTable,pTable) + _REF_TYPE_DECL(OT_CLASS,SQClass,pClass) + _REF_TYPE_DECL(OT_INSTANCE,SQInstance,pInstance) + _REF_TYPE_DECL(OT_ARRAY,SQArray,pArray) + _REF_TYPE_DECL(OT_CLOSURE,SQClosure,pClosure) + _REF_TYPE_DECL(OT_NATIVECLOSURE,SQNativeClosure,pNativeClosure) + _REF_TYPE_DECL(OT_OUTER,SQOuter,pOuter) + _REF_TYPE_DECL(OT_GENERATOR,SQGenerator,pGenerator) + _REF_TYPE_DECL(OT_STRING,SQString,pString) + _REF_TYPE_DECL(OT_USERDATA,SQUserData,pUserData) + _REF_TYPE_DECL(OT_WEAKREF,SQWeakRef,pWeakRef) + _REF_TYPE_DECL(OT_THREAD,SQVM,pThread) + _REF_TYPE_DECL(OT_FUNCPROTO,SQFunctionProto,pFunctionProto) + + _SCALAR_TYPE_DECL(OT_INTEGER,SQInteger,nInteger) + _SCALAR_TYPE_DECL(OT_FLOAT,SQFloat,fFloat) + _SCALAR_TYPE_DECL(OT_USERPOINTER,SQUserPointer,pUserPointer) + + SQObjectPtr(bool bBool) + { + SQ_OBJECT_RAWINIT() + _type = OT_BOOL; + _unVal.nInteger = bBool?1:0; + } + inline SQObjectPtr& operator=(bool b) + { + __Release(_type,_unVal); + SQ_OBJECT_RAWINIT() + _type = OT_BOOL; + _unVal.nInteger = b?1:0; + return *this; + } + + ~SQObjectPtr() + { + __Release(_type,_unVal); + } + + 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; + } + inline void Null() + { + __Release(_type ,_unVal); + _type = OT_NULL; + _unVal.raw = NULL; + } + private: + SQObjectPtr(const SQChar *){} //safety +}; + + +inline void _Swap(SQObject &a,SQObject &b) +{ + SQObjectType tOldType = a._type; + SQObjectValue unOldVal = a._unVal; + a._type = b._type; + a._unVal = b._unVal; + b._type = tOldType; + b._unVal = unOldVal; +} + +///////////////////////////////////////////////////////////////////////////////////// +#ifndef NO_GARBAGE_COLLECTOR +#define MARK_FLAG 0x80000000 +struct SQCollectable : public SQRefCounted { + SQCollectable *_next; + SQCollectable *_prev; + SQSharedState *_sharedstate; + virtual SQObjectType GetType()=0; + 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(SQVM *v,SQMetaMethod mm,SQObjectPtr &res); + SQTable *_delegate; +}; + +SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx); +typedef sqvector SQObjectPtrVec; +typedef sqvector SQIntVec; +const SQChar *GetTypeName(const SQObjectPtr &obj1); +const SQChar *IdType2Name(SQObjectType type); + + + +#endif //_SQOBJECT_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqopcodes.h b/squirrel_3_0_1_stable/squirrel/sqopcodes.h new file mode 100644 index 000000000..4d179812f --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqopcodes.h @@ -0,0 +1,132 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQOPCODES_H_ +#define _SQOPCODES_H_ + +#define MAX_FUNC_STACKSIZE 0xFF +#define MAX_LITERALS ((SQInteger)0x7FFFFFFF) + +enum BitWiseOP { + BW_AND = 0, + BW_OR = 2, + BW_XOR = 3, + BW_SHIFTL = 4, + BW_SHIFTR = 5, + BW_USHIFTR = 6 +}; + +enum CmpOP { + CMP_G = 0, + CMP_GE = 2, + CMP_L = 3, + CMP_LE = 4, + CMP_3W = 5 +}; + +enum NewObjectType { + NOT_TABLE = 0, + NOT_ARRAY = 1, + NOT_CLASS = 2 +}; + +enum AppendArrayType { + AAT_STACK = 0, + AAT_LITERAL = 1, + AAT_INT = 2, + AAT_FLOAT = 3, + AAT_BOOL = 4 +}; + +enum SQOpcode +{ + _OP_LINE= 0x00, + _OP_LOAD= 0x01, + _OP_LOADINT= 0x02, + _OP_LOADFLOAT= 0x03, + _OP_DLOAD= 0x04, + _OP_TAILCALL= 0x05, + _OP_CALL= 0x06, + _OP_PREPCALL= 0x07, + _OP_PREPCALLK= 0x08, + _OP_GETK= 0x09, + _OP_MOVE= 0x0A, + _OP_NEWSLOT= 0x0B, + _OP_DELETE= 0x0C, + _OP_SET= 0x0D, + _OP_GET= 0x0E, + _OP_EQ= 0x0F, + _OP_NE= 0x10, + _OP_ADD= 0x11, + _OP_SUB= 0x12, + _OP_MUL= 0x13, + _OP_DIV= 0x14, + _OP_MOD= 0x15, + _OP_BITW= 0x16, + _OP_RETURN= 0x17, + _OP_LOADNULLS= 0x18, + _OP_LOADROOT= 0x19, + _OP_LOADBOOL= 0x1A, + _OP_DMOVE= 0x1B, + _OP_JMP= 0x1C, + //_OP_JNZ= 0x1D, + _OP_JCMP= 0x1D, + _OP_JZ= 0x1E, + _OP_SETOUTER= 0x1F, + _OP_GETOUTER= 0x20, + _OP_NEWOBJ= 0x21, + _OP_APPENDARRAY= 0x22, + _OP_COMPARITH= 0x23, + _OP_INC= 0x24, + _OP_INCL= 0x25, + _OP_PINC= 0x26, + _OP_PINCL= 0x27, + _OP_CMP= 0x28, + _OP_EXISTS= 0x29, + _OP_INSTANCEOF= 0x2A, + _OP_AND= 0x2B, + _OP_OR= 0x2C, + _OP_NEG= 0x2D, + _OP_NOT= 0x2E, + _OP_BWNOT= 0x2F, + _OP_CLOSURE= 0x30, + _OP_YIELD= 0x31, + _OP_RESUME= 0x32, + _OP_FOREACH= 0x33, + _OP_POSTFOREACH= 0x34, + _OP_CLONE= 0x35, + _OP_TYPEOF= 0x36, + _OP_PUSHTRAP= 0x37, + _OP_POPTRAP= 0x38, + _OP_THROW= 0x39, + _OP_NEWSLOTA= 0x3A, + _OP_GETBASE= 0x3B, + _OP_CLOSE= 0x3C, +}; + +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 = (unsigned char)a0;_arg1 = (SQInt32)a1; + _arg2 = (unsigned char)a2;_arg3 = (unsigned char)a3; + } + + + SQInt32 _arg1; + unsigned char op; + unsigned char _arg0; + unsigned char _arg2; + unsigned char _arg3; +}; + +#include "squtils.h" +typedef sqvector SQInstructionVec; + +#define NEW_SLOT_ATTRIBUTES_FLAG 0x01 +#define NEW_SLOT_STATIC_FLAG 0x02 + +#endif // _SQOPCODES_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqpcheader.h b/squirrel_3_0_1_stable/squirrel/sqpcheader.h new file mode 100644 index 000000000..f0e5cf2df --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqpcheader.h @@ -0,0 +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_ diff --git a/squirrel_3_0_1_stable/squirrel/sqstate.cpp b/squirrel_3_0_1_stable/squirrel/sqstate.cpp new file mode 100644 index 000000000..0bee40661 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqstate.cpp @@ -0,0 +1,648 @@ +/* + 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_((SQInteger)1); +//SQObjectPtr _minusone_((SQInteger)-1); + +SQSharedState::SQSharedState() +{ + _compilererrorhandler = NULL; + _printfunc = NULL; + _errorfunc = NULL; + _debuginfo = false; + _notifyallexceptions = 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,0); + 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 + _stringtable = (SQStringTable*)SQ_MALLOC(sizeof(SQStringTable)); + new (_stringtable) SQStringTable(this); + 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); + newmetamethod(MM_NEWMEMBER); + newmetamethod(MM_INHERITED); + + _constructoridx = SQString::Create(this,_SC("constructor")); + _registry = SQTable::Create(this,0); + _consts = 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(_registry)->Finalize(); + _table(_consts)->Finalize(); + _table(_metamethodsmap)->Finalize(); + _registry.Null(); + _consts.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(); + _refs_table.Finalize(); +#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,SQStringTable); + 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; + case OT_OUTER:_outer(o)->Mark(chain);break; + case OT_FUNCPROTO:_funcproto(o)->Mark(chain);break; + default: break; //shutup compiler + } +} + + +void SQSharedState::RunMark(SQVM *vm,SQCollectable **tchain) +{ + SQVM *vms = _thread(_root_vm); + + vms->Mark(tchain); + + _refs_table.Mark(tchain); + MarkObject(_registry,tchain); + MarkObject(_consts,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); + +} + +SQInteger SQSharedState::ResurrectUnreachable(SQVM *vm) +{ + SQInteger n=0; + SQCollectable *tchain=NULL; + + RunMark(vm,&tchain); + + SQCollectable *resurrected = _gc_chain; + SQCollectable *t = resurrected; + //SQCollectable *nx = NULL; + + _gc_chain = tchain; + + SQArray *ret = NULL; + if(resurrected) { + ret = SQArray::Create(this,0); + SQCollectable *rlast = NULL; + while(t) { + rlast = t; + SQObjectType type = t->GetType(); + if(type != OT_FUNCPROTO && type != OT_OUTER) { + SQObject sqo; + sqo._type = type; + sqo._unVal.pRefCounted = t; + ret->Append(sqo); + } + t = t->_next; + n++; + } + + assert(rlast->_next == NULL); + rlast->_next = _gc_chain; + if(_gc_chain) + { + _gc_chain->_prev = rlast; + } + _gc_chain = resurrected; + } + + t = _gc_chain; + while(t) { + t->UnMark(); + t = t->_next; + } + + if(ret) { + SQObjectPtr temp = ret; + vm->Push(temp); + } + else { + vm->PushNull(); + } + return n; +} + +SQInteger SQSharedState::CollectGarbage(SQVM *vm) +{ + SQInteger n=0; + SQCollectable *tchain=NULL; + + RunMark(vm,&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; + + 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 < size) { + newsize = size + (size>>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; +} + +RefTable::RefTable() +{ + AllocNodes(4); +} + +void RefTable::Finalize() +{ + RefNode *nodes = _nodes; + for(SQUnsignedInteger n = 0; n < _numofslots; n++) { + nodes->obj.Null(); + nodes++; + } +} + +RefTable::~RefTable() +{ + SQ_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode))); +} + +#ifndef NO_GARBAGE_COLLECTOR +void RefTable::Mark(SQCollectable **chain) +{ + RefNode *nodes = (RefNode *)_nodes; + for(SQUnsignedInteger n = 0; n < _numofslots; n++) { + if(type(nodes->obj) != OT_NULL) { + SQSharedState::MarkObject(nodes->obj,chain); + } + nodes++; + } +} +#endif + +void RefTable::AddRef(SQObject &obj) +{ + SQHash mainpos; + RefNode *prev; + RefNode *ref = Get(obj,mainpos,&prev,true); + ref->refs++; +} + +SQUnsignedInteger RefTable::GetRefCount(SQObject &obj) +{ + SQHash mainpos; + RefNode *prev; + RefNode *ref = Get(obj,mainpos,&prev,true); + return ref->refs; +} + + +SQBool RefTable::Release(SQObject &obj) +{ + SQHash mainpos; + RefNode *prev; + RefNode *ref = Get(obj,mainpos,&prev,false); + if(ref) { + if(--ref->refs == 0) { + SQObjectPtr o = ref->obj; + if(prev) { + prev->next = ref->next; + } + else { + _buckets[mainpos] = ref->next; + } + ref->next = _freelist; + _freelist = ref; + _slotused--; + ref->obj.Null(); + //<>test for shrink? + return SQTrue; + } + } + else { + assert(0); + } + return SQFalse; +} + +void RefTable::Resize(SQUnsignedInteger size) +{ + RefNode **oldbucks = _buckets; + RefNode *t = _nodes; + SQUnsignedInteger oldnumofslots = _numofslots; + AllocNodes(size); + //rehash + SQUnsignedInteger nfound = 0; + for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) { + if(type(t->obj) != OT_NULL) { + //add back; + assert(t->refs != 0); + RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj); + nn->refs = t->refs; + t->obj.Null(); + nfound++; + } + t++; + } + assert(nfound == oldnumofslots); + SQ_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode))); +} + +RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj) +{ + RefNode *t = _buckets[mainpos]; + RefNode *newnode = _freelist; + newnode->obj = obj; + _buckets[mainpos] = newnode; + _freelist = _freelist->next; + newnode->next = t; + assert(newnode->refs == 0); + _slotused++; + return newnode; +} + +RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add) +{ + RefNode *ref; + mainpos = ::HashObj(obj)&(_numofslots-1); + *prev = NULL; + for (ref = _buckets[mainpos]; ref; ) { + if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj)) + break; + *prev = ref; + ref = ref->next; + } + if(ref == NULL && add) { + if(_numofslots == _slotused) { + assert(_freelist == 0); + Resize(_numofslots*2); + mainpos = ::HashObj(obj)&(_numofslots-1); + } + ref = Add(mainpos,obj); + } + return ref; +} + +void RefTable::AllocNodes(SQUnsignedInteger size) +{ + RefNode **bucks; + RefNode *nodes; + bucks = (RefNode **)SQ_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode))); + nodes = (RefNode *)&bucks[size]; + RefNode *temp = nodes; + SQUnsignedInteger n; + for(n = 0; n < size - 1; n++) { + bucks[n] = NULL; + temp->refs = 0; + new (&temp->obj) SQObjectPtr; + temp->next = temp+1; + temp++; + } + bucks[n] = NULL; + temp->refs = 0; + new (&temp->obj) SQObjectPtr; + temp->next = NULL; + _freelist = nodes; + _nodes = nodes; + _buckets = bucks; + _slotused = 0; + _numofslots = size; +} +////////////////////////////////////////////////////////////////////////// +//SQStringTable +/* +* 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 +*/ + +SQStringTable::SQStringTable(SQSharedState *ss) +{ + _sharedstate = ss; + AllocNodes(4); + _slotused = 0; +} + +SQStringTable::~SQStringTable() +{ + SQ_FREE(_strings,sizeof(SQString*)*_numofslots); + _strings = NULL; +} + +void SQStringTable::AllocNodes(SQInteger size) +{ + _numofslots = size; + _strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots); + memset(_strings,0,sizeof(SQString*)*_numofslots); +} + +SQString *SQStringTable::Add(const SQChar *news,SQInteger len) +{ + if(len<0) + len = (SQInteger)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; + t->_sharedstate = _sharedstate; + 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 SQStringTable::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 SQStringTable::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/squirrel_3_0_1_stable/squirrel/sqstate.h b/squirrel_3_0_1_stable/squirrel/sqstate.h new file mode 100644 index 000000000..3ed3307d7 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqstate.h @@ -0,0 +1,144 @@ +/* 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 SQStringTable +{ + SQStringTable(SQSharedState*ss); + ~SQStringTable(); + SQString *Add(const SQChar *,SQInteger len); + void Remove(SQString *); +private: + void Resize(SQInteger size); + void AllocNodes(SQInteger size); + SQString **_strings; + SQUnsignedInteger _numofslots; + SQUnsignedInteger _slotused; + SQSharedState *_sharedstate; +}; + +struct RefTable { + struct RefNode { + SQObjectPtr obj; + SQUnsignedInteger refs; + struct RefNode *next; + }; + RefTable(); + ~RefTable(); + void AddRef(SQObject &obj); + SQBool Release(SQObject &obj); + SQUnsignedInteger GetRefCount(SQObject &obj); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); +#endif + void Finalize(); +private: + RefNode *Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add); + RefNode *Add(SQHash mainpos,SQObject &obj); + void Resize(SQUnsignedInteger size); + void AllocNodes(SQUnsignedInteger size); + SQUnsignedInteger _numofslots; + SQUnsignedInteger _slotused; + RefNode *_nodes; + RefNode *_freelist; + RefNode **_buckets; +}; + +#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); + void RunMark(SQVM *vm,SQCollectable **tchain); + SQInteger ResurrectUnreachable(SQVM *vm); + static void MarkObject(SQObjectPtr &o,SQCollectable **chain); +#endif + SQObjectPtrVec *_metamethods; + SQObjectPtr _metamethodsmap; + SQObjectPtrVec *_systemstrings; + SQObjectPtrVec *_types; + SQStringTable *_stringtable; + RefTable _refs_table; + SQObjectPtr _registry; + SQObjectPtr _consts; + 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; + SQPRINTFUNCTION _errorfunc; + bool _debuginfo; + bool _notifyallexceptions; +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_; + +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/squirrel_3_0_1_stable/squirrel/sqstring.h b/squirrel_3_0_1_stable/squirrel/sqstring.h new file mode 100644 index 000000000..235d19059 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqstring.h @@ -0,0 +1,31 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTRING_H_ +#define _SQSTRING_H_ + +inline SQHash _hashstr (const SQChar *s, size_t l) +{ + SQHash h = (SQHash)l; /* seed */ + size_t step = (l>>5)|1; /* if string is too long, don't hash all its chars */ + for (; l>=step; l-=step) + h = h ^ ((h<<5)+(h>>2)+(unsigned short)*(s++)); + return h; +} + +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/squirrel_3_0_1_stable/squirrel/sqtable.cpp b/squirrel_3_0_1_stable/squirrel/sqtable.cpp new file mode 100644 index 000000000..fe3d5f2a1 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqtable.cpp @@ -0,0 +1,220 @@ +/* +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, HashObj(key) & (_numofnodes - 1)); + if (n) { + n->val.Null(); + 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;k_nodes; + _HashNode *src = _nodes; + _HashNode *dst = nt->_nodes; + SQInteger n = 0; + for(n = 0; n < _numofnodes; n++) { + dst->key = src->key; + dst->val = src->val; + if(src->next) { + assert(src->next > basesrc); + dst->next = basedst + (src->next - basesrc); + assert(dst != dst->next); + } + dst++; + src++; + } + assert(_firstfree > basesrc); + assert(_firstfree != NULL); + nt->_firstfree = basedst + (_firstfree - basesrc); +#else + SQInteger ridx=0; + SQObjectPtr key,val; + while((ridx=Next(true,ridx,key,val))!=-1){ + nt->NewSlot(key,val); + } +#endif + nt->SetDelegate(_delegate); + return nt; +} + +bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val) +{ + if(type(key) == OT_NULL) + return false; + _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); + if (n) { + val = _realval(n->val); + return true; + } + return false; +} +bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) +{ + assert(type(key) != OT_NULL); + SQHash h = HashObj(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) { + n = _firstfree; /* get a free place */ + SQHash mph = HashObj(mp->key) & (_numofnodes - 1); + _HashNode *othern; /* main position of colliding node */ + + if (mp > n && (othern = &_nodes[mph]) != mp){ + /* yes; move colliding node into free position */ + while (othern->next != mp){ + assert(othern->next != NULL); + othern = othern->next; /* find previous */ + } + othern->next = n; /* redo the chain with `n' in place of `mp' */ + n->key = mp->key; + n->val = mp->val;/* copy colliding node into free pos. (mp->next also goes) */ + n->next = mp->next; + mp->key.Null(); + mp->val.Null(); + 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 && _firstfree->next == 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, HashObj(key) & (_numofnodes - 1)); + if (n) { + n->val = val; + return true; + } + return false; +} + +void SQTable::_ClearNodes() +{ + for(SQInteger i = 0;i < _numofnodes; i++) { _HashNode &n = _nodes[i]; n.key.Null(); n.val.Null(); } +} + +void SQTable::Finalize() +{ + _ClearNodes(); + SetDelegate(NULL); +} + +void SQTable::Clear() +{ + _ClearNodes(); + _usednodes = 0; + Rehash(true); +} diff --git a/squirrel_3_0_1_stable/squirrel/sqtable.h b/squirrel_3_0_1_stable/squirrel/sqtable.h new file mode 100644 index 000000000..2f6487023 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqtable.h @@ -0,0 +1,92 @@ +/* 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)(((SQInteger)p) >> 3)) + +inline SQHash HashObj(const SQObjectPtr &key) +{ + switch(type(key)) { + case OT_STRING: return _string(key)->_hash; + case OT_FLOAT: return (SQHash)((SQInteger)_float(key)); + case OT_BOOL: case OT_INTEGER: return (SQHash)((SQInteger)_integer(key)); + default: return hashptr(key._unVal.pRefCounted); + } +} + +struct SQTable : public SQDelegable +{ +private: + struct _HashNode + { + _HashNode() { next = NULL; } + 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); + void _ClearNodes(); +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); + SQObjectType GetType() {return OT_TABLE;} +#endif + 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 Clear(); + void Release() + { + sq_delete(this, SQTable); + } + +}; + +#endif //_SQTABLE_H_ diff --git a/squirrel_3_0_1_stable/squirrel/squirrel.dsp b/squirrel_3_0_1_stable/squirrel/squirrel.dsp new file mode 100644 index 000000000..4778b6963 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/squirrel.dsp @@ -0,0 +1,302 @@ +# Microsoft Developer Studio Project File - Name="squirrel" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=squirrel - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "squirrel.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "squirrel.mak" CFG="squirrel - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "squirrel - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "squirrel - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_LocalPath ".." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "squirrel - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "GARBAGE_COLLECTOR" /YX /FD /c +# ADD BASE RSC /l 0x410 /d "NDEBUG" +# ADD RSC /l 0x410 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\lib\squirrel.lib" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x410 /d "_DEBUG" +# ADD RSC /l 0x410 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\lib\squirrel.lib" + +!ENDIF + +# Begin Target + +# Name "squirrel - Win32 Release" +# Name "squirrel - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\sqapi.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqbaselib.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqcompiler.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqdebug.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqfuncstate.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqlexer.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqmem.cpp +# End Source File +# Begin Source File + +SOURCE=.\sqobject.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqstate.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqtable.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqclass.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqvm.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\sqarray.h +# End Source File +# Begin Source File + +SOURCE=.\sqclosure.h +# End Source File +# Begin Source File + +SOURCE=.\sqcompiler.h +# End Source File +# Begin Source File + +SOURCE=.\sqfuncproto.h +# End Source File +# Begin Source File + +SOURCE=.\sqfuncstate.h +# End Source File +# Begin Source File + +SOURCE=.\sqlexer.h +# End Source File +# Begin Source File + +SOURCE=.\sqobject.h +# End Source File +# Begin Source File + +SOURCE=.\sqopcodes.h +# End Source File +# Begin Source File + +SOURCE=.\sqpcheader.h +# End Source File +# Begin Source File + +SOURCE=.\sqstate.h +# End Source File +# Begin Source File + +SOURCE=.\sqstring.h +# End Source File +# Begin Source File + +SOURCE=.\sqtable.h +# End Source File +# Begin Source File + +SOURCE=.\squserdata.h +# End Source File +# Begin Source File + +SOURCE=.\squtils.h +# End Source File +# Begin Source File + +SOURCE=.\sqclass.h +# End Source File +# Begin Source File + +SOURCE=.\sqvm.h +# End Source File +# End Group +# End Target +# End Project diff --git a/squirrel_3_0_1_stable/squirrel/squserdata.h b/squirrel_3_0_1_stable/squirrel/squserdata.h new file mode 100644 index 000000000..dea27ae78 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/squserdata.h @@ -0,0 +1,40 @@ +/* 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(sq_aligning(sizeof(SQUserData))+size); + new (ud) SQUserData(ss); + ud->_size = size; + ud->_typetag = 0; + return ud; + } +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){SetDelegate(NULL);} + SQObjectType GetType(){ return OT_USERDATA;} +#endif + void Release() { + if (_hook) _hook((SQUserPointer)sq_aligning(this + 1),_size); + SQInteger tsize = _size; + this->~SQUserData(); + SQ_FREE(this, sq_aligning(sizeof(SQUserData)) + tsize); + } + + + SQInteger _size; + SQRELEASEHOOK _hook; + SQUserPointer _typetag; + //SQChar _val[1]; +}; + +#endif //_SQUSERDATA_H_ diff --git a/squirrel_3_0_1_stable/squirrel/squtils.h b/squirrel_3_0_1_stable/squirrel/squtils.h new file mode 100644 index 000000000..bff7d24bb --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/squtils.h @@ -0,0 +1,112 @@ +/* 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)); + +#define sq_aligning(v) (((size_t)(v) + (SQ_ALIGNMENT-1)) & (~(SQ_ALIGNMENT-1))) + +//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) + { + if(_size) { + resize(0); //destroys all previous stuff + } + //resize(v._size); + if(v._size > _allocated) { + _realloc(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/squirrel_3_0_1_stable/squirrel/sqvm.cpp b/squirrel_3_0_1_stable/squirrel/sqvm.cpp new file mode 100644 index 000000000..bd8ebcc1a --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqvm.cpp @@ -0,0 +1,1714 @@ +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include +#include +#include "sqopcodes.h" +#include "sqvm.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "sqstring.h" +#include "sqtable.h" +#include "squserdata.h" +#include "sqarray.h" +#include "sqclass.h" + +#define TOP() (_stack._vals[_top-1]) + +bool SQVM::BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2) +{ + SQInteger res; + if((type(o1)|type(o2)) == OT_INTEGER) + { + SQInteger i1 = _integer(o1), i2 = _integer(o2); + 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; +} + +#define _ARITH_(op,trg,o1,o2) \ +{ \ + SQInteger tmask = type(o1)|type(o2); \ + switch(tmask) { \ + case OT_INTEGER: trg = _integer(o1) op _integer(o2);break; \ + case (OT_FLOAT|OT_INTEGER): \ + case (OT_FLOAT): trg = tofloat(o1) op tofloat(o2); break;\ + default: _GUARD(ARITH_OP((#op)[0],trg,o1,o2)); break;\ + } \ +} + +#define _ARITH_NOZERO(op,trg,o1,o2,err) \ +{ \ + SQInteger tmask = type(o1)|type(o2); \ + switch(tmask) { \ + case OT_INTEGER: { SQInteger i2 = _integer(o2); if(i2 == 0) { Raise_Error(err); SQ_THROW(); } trg = _integer(o1) op i2; } break;\ + case (OT_FLOAT|OT_INTEGER): \ + case (OT_FLOAT): trg = tofloat(o1) op tofloat(o2); break;\ + default: _GUARD(ARITH_OP((#op)[0],trg,o1,o2)); break;\ + } \ +} + +bool SQVM::ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2) +{ + SQInteger tmask = type(o1)|type(o2); + switch(tmask) { + case OT_INTEGER:{ + SQInteger res, i1 = _integer(o1), i2 = _integer(o2); + switch(op) { + case '+': res = i1 + i2; break; + case '-': res = i1 - i2; break; + case '/': if(i2 == 0) { Raise_Error(_SC("division by zero")); return false; } + res = i1 / i2; + break; + case '*': res = i1 * i2; break; + case '%': if(i2 == 0) { Raise_Error(_SC("modulo by zero")); return false; } + res = i1 % i2; + break; + default: res = 0xDEADBEEF; + } + trg = res; } + break; + case (OT_FLOAT|OT_INTEGER): + case (OT_FLOAT):{ + SQFloat res, f1 = tofloat(o1), f2 = tofloat(o2); + switch(op) { + case '+': res = f1 + f2; break; + case '-': res = f1 - f2; break; + case '/': res = f1 / f2; break; + case '*': res = f1 * f2; break; + case '%': res = SQFloat(fmod((double)f1,(double)f2)); break; + default: res = 0x0f; + } + trg = res; } + break; + default: + if(op == '+' && (tmask & _RT_STRING)){ + if(!StringCat(o1, o2, trg)) return false; + } + else if(!ArithMetaMethod(op,o1,o2,trg)) { + 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; + _nmetamethodscall = 0; + _lasterror.Null(); + _errorhandler.Null(); + _debughook = false; + _debughook_native = NULL; + _debughook_closure.Null(); + _openouters = NULL; + ci = NULL; + INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); +} + +void SQVM::Finalize() +{ + if(_openouters) CloseOuters(&_stack._vals[0]); + _roottable.Null(); + _lasterror.Null(); + _errorhandler.Null(); + _debughook = false; + _debughook_native = NULL; + _debughook_closure.Null(); + temp_reg.Null(); + _callstackdata.resize(0); + 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; + default: mm = MT_ADD; assert(0); break; //shutup compiler + } + if(is_delegable(o1) && _delegable(o1)->_delegate) { + + SQObjectPtr closure; + if(_delegable(o1)->GetMetaMethod(this, mm, closure)) { + Push(o1);Push(o2); + return CallMetaMethod(closure,mm,2,dest); + } + } + Raise_Error(_SC("arith op %c on between '%s' and '%s'"),op,GetTypeName(o1),GetTypeName(o2)); + 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) { + SQObjectPtr closure; + if(_delegable(o)->GetMetaMethod(this, MT_UNM, closure)) { + Push(o); + if(!CallMetaMethod(closure, MT_UNM, 1, temp_reg)) return false; + _Swap(trg,temp_reg); + return true; + + } + } + default:break; //shutup compiler + } + 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) +{ + SQObjectType t1 = type(o1), t2 = type(o2); + if(t1 == t2){ + if(_rawval(o1)==_rawval(o2))_RET_SUCCEED(0); + SQObjectPtr res; + switch(t1){ + 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: + if(_delegable(o1)->_delegate) { + SQObjectPtr closure; + if(_delegable(o1)->GetMetaMethod(this, MT_CMP, closure)) { + Push(o1);Push(o2); + if(!CallMetaMethod(closure,MT_CMP,2,res)) return false; + } + break; + } + //continues through (no break needed) + default: + _RET_SUCCEED( _userpointer(o1) < _userpointer(o2)?-1:1 ); + } + if(type(res)!=OT_INTEGER) { Raise_CompareError(o1,o2); return false; } + _RET_SUCCEED(_integer(res)); + + } + else{ + if(sq_isnumeric(o1) && sq_isnumeric(o2)){ + if((t1==OT_INTEGER) && (t2==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(t1==OT_NULL) {_RET_SUCCEED(-1);} + else if(t2==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); return true; + case CMP_GE: res = (r >= 0); return true; + case CMP_L: res = (r < 0); return true; + case CMP_LE: res = (r <= 0); return true; + case CMP_3W: res = r; return true; + } + assert(0); + } + return false; +} + +bool SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res) +{ + switch(type(o)) { + case OT_STRING: + res = o; + return true; + 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)),_PRINT_INT_FMT,_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) { + SQObjectPtr closure; + if(_delegable(o)->GetMetaMethod(this, MT_TOSTRING, closure)) { + Push(o); + if(CallMetaMethod(closure,MT_TOSTRING,1,res)) {; + if(type(res) == OT_STRING) + return true; + } + else { + return false; + } + } + } + default: + scsprintf(_sp(rsl(sizeof(void*)+20)),_SC("(%s : 0x%p)"),GetTypeName(o),(void*)_rawval(o)); + } + res = SQString::Create(_ss(this),_spval); + return true; +} + + +bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest) +{ + SQObjectPtr a, b; + if(!ToString(str, a)) return false; + if(!ToString(obj, b)) return false; + SQInteger l = _string(a)->_len , ol = _string(b)->_len; + SQChar *s = _sp(rsl(l + ol + 1)); + memcpy(s, _stringval(a), rsl(l)); + memcpy(s + l, _stringval(b), rsl(ol)); + dest = SQString::Create(_ss(this), _spval, l + ol); + return true; +} + +bool SQVM::TypeOf(const SQObjectPtr &obj1,SQObjectPtr &dest) +{ + if(is_delegable(obj1) && _delegable(obj1)->_delegate) { + SQObjectPtr closure; + if(_delegable(obj1)->GetMetaMethod(this, MT_TYPEOF, closure)) { + Push(obj1); + return CallMetaMethod(closure,MT_TYPEOF,1,dest); + } + } + dest = SQString::Create(_ss(this),GetTypeName(obj1)); + return true; +} + +bool SQVM::Init(SQVM *friendvm, SQInteger stacksize) +{ + _stack.resize(stacksize); + _alloccallsstacksize = 4; + _callstackdata.resize(_alloccallsstacksize); + _callsstacksize = 0; + _callsstack = &_callstackdata[0]; + _stackbase = 0; + _top = 0; + if(!friendvm) + _roottable = SQTable::Create(_ss(this), 0); + else { + _roottable = friendvm->_roottable; + _errorhandler = friendvm->_errorhandler; + _debughook = friendvm->_debughook; + _debughook_native = friendvm->_debughook_native; + _debughook_closure = friendvm->_debughook_closure; + } + + sq_base_register(this); + return true; +} + + +bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQInteger stackbase,bool tailcall) +{ + SQFunctionProto *func = closure->_function; + + SQInteger paramssize = func->_nparameters; + const SQInteger newtop = stackbase + func->_stacksize; + SQInteger nargs = args; + if(func->_varparams) + { + paramssize--; + if (nargs < paramssize) { + Raise_Error(_SC("wrong number of parameters")); + return false; + } + + //dumpstack(stackbase); + SQInteger nvargs = nargs - paramssize; + SQArray *arr = SQArray::Create(_ss(this),nvargs); + SQInteger pbase = stackbase+paramssize; + for(SQInteger n = 0; n < nvargs; n++) { + arr->_values[n] = _stack._vals[pbase]; + _stack._vals[pbase].Null(); + pbase++; + + } + _stack._vals[stackbase+paramssize] = arr; + //dumpstack(stackbase); + } + else if (paramssize != nargs) { + SQInteger ndef = func->_ndefaultparams; + SQInteger diff; + if(ndef && nargs < paramssize && (diff = paramssize - nargs) <= ndef) { + for(SQInteger n = ndef - diff; n < ndef; n++) { + _stack._vals[stackbase + (nargs++)] = closure->_defaultparams[n]; + } + } + else { + Raise_Error(_SC("wrong number of parameters")); + return false; + } + } + + if(closure->_env) { + _stack._vals[stackbase] = closure->_env->_obj; + } + + if(!EnterFrame(stackbase, newtop, tailcall)) return false; + + ci->_closure = closure; + ci->_literals = func->_literals; + ci->_ip = func->_instructions; + ci->_target = (SQInt32)target; + + if (_debughook) { + CallDebugHook(_SC('c')); + } + + if (closure->_function->_bgenerator) { + SQFunctionProto *f = closure->_function; + SQGenerator *gen = SQGenerator::Create(_ss(this), closure); + if(!gen->Yield(this,f->_stacksize)) + return false; + SQObjectPtr temp; + Return(1, target, temp); + STK(target) = gen; + } + + + return true; +} + +bool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval) +{ + SQBool _isroot = ci->_root; + SQInteger callerbase = _stackbase - ci->_prevstkbase; + + if (_debughook) { + for(SQInteger i=0; i_ncalls; i++) { + CallDebugHook(_SC('r')); + } + } + + SQObjectPtr *dest; + if (_isroot) { + dest = &(retval); + } else if (ci->_target == -1) { + dest = NULL; + } else { + dest = &_stack._vals[callerbase + ci->_target]; + } + if (dest) { + if(_arg0 != 0xFF) { + *dest = _stack._vals[_stackbase+_arg1]; + } + else { + dest->Null(); + } + //*dest = (_arg0 != 0xFF) ? _stack._vals[_stackbase+_arg1] : _null_; + } + LeaveFrame(); + return _isroot ? true : false; +} + +#define _RET_ON_FAIL(exp) { if(!exp) return false; } + +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,SQInteger selfidx) +{ + SQObjectPtr tmp, tself = self, tkey = key; + if (!Get(tself, tkey, tmp, false, selfidx)) { return false; } + _RET_ON_FAIL(ARITH_OP( op , target, tmp, incr)) + if (!Set(tself, tkey, target,selfidx)) { return false; } + if (postfix) target = tmp; + return true; +} + +#define arg0 (_i_._arg0) +#define sarg0 ((SQInteger)*((signed char *)&_i_._arg0)) +#define arg1 (_i_._arg1) +#define sarg1 (*((SQInt32 *)&_i_._arg1)) +#define arg2 (_i_._arg2) +#define arg3 (_i_._arg3) +#define sarg3 ((SQInteger)*((signed 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; +} + + +#define _FINISH(howmuchtojump) {jump = howmuchtojump; return true; } +bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr +&o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump) +{ + SQInteger nrefidx; + switch(type(o1)) { + case OT_TABLE: + if((nrefidx = _table(o1)->Next(false,o4, o2, o3)) == -1) _FINISH(exitpos); + o4 = (SQInteger)nrefidx; _FINISH(1); + case OT_ARRAY: + if((nrefidx = _array(o1)->Next(o4, o2, o3)) == -1) _FINISH(exitpos); + o4 = (SQInteger) nrefidx; _FINISH(1); + case OT_STRING: + if((nrefidx = _string(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos); + o4 = (SQInteger)nrefidx; _FINISH(1); + case OT_CLASS: + if((nrefidx = _class(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos); + o4 = (SQInteger)nrefidx; _FINISH(1); + case OT_USERDATA: + case OT_INSTANCE: + if(_delegable(o1)->_delegate) { + SQObjectPtr itr; + SQObjectPtr closure; + if(_delegable(o1)->GetMetaMethod(this, MT_NEXTI, closure)) { + Push(o1); + Push(o4); + if(CallMetaMethod(closure, MT_NEXTI, 2, itr)) { + o4 = o2 = itr; + if(type(itr) == OT_NULL) _FINISH(exitpos); + if(!Get(o1, itr, o3, false, DONT_FALL_BACK)) { + Raise_Error(_SC("_nexti returned an invalid idx")); // cloud be changed + return false; + } + _FINISH(1); + } + else { + return false; + } + } + Raise_Error(_SC("_nexti failed")); + return false; + } + break; + case OT_GENERATOR: + if(_generator(o1)->_state == SQGenerator::eDead) _FINISH(exitpos); + 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, o3); + _FINISH(0); + } + default: + Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1)); + } + return false; //cannot be hit(just to avoid warnings) +} + +#define COND_LITERAL (arg3!=0?ci->_literals[arg1]:STK(arg1)) + +#define SQ_THROW() { goto exception_trap; } + +#define _GUARD(exp) { if(!exp) { SQ_THROW();} } + +bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func) +{ + SQInteger nouters; + SQClosure *closure = SQClosure::Create(_ss(this), func); + if((nouters = func->_noutervalues)) { + for(SQInteger i = 0; i_outervalues[i]; + switch(v._type){ + case otLOCAL: + FindOuter(closure->_outervalues[i], &STK(_integer(v._src))); + break; + case otOUTER: + closure->_outervalues[i] = _closure(ci->_closure)->_outervalues[_integer(v._src)]; + break; + } + } + } + SQInteger ndefparams; + if((ndefparams = func->_ndefaultparams)) { + for(SQInteger i = 0; i < ndefparams; i++) { + SQInteger spos = func->_defaultparams[i]; + closure->_defaultparams[i] = _stack._vals[_stackbase + spos]; + } + } + target = closure; + return true; + +} + + +bool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass,SQInteger attributes) +{ + SQClass *base = NULL; + SQObjectPtr attrs; + if(baseclass != -1) { + 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); + if(type(_class(target)->_metamethods[MT_INHERITED]) != OT_NULL) { + int nparams = 2; + SQObjectPtr ret; + Push(target); Push(attrs); + Call(_class(target)->_metamethods[MT_INHERITED],nparams,_top - nparams, ret, false); + Pop(nparams); + } + _class(target)->_attributes = attrs; + return true; +} + +bool SQVM::IsEqual(const SQObjectPtr &o1,const SQObjectPtr &o2,bool &res) +{ + if(type(o1) == type(o2)) { + res = (_rawval(o1) == _rawval(o2)); + } + else { + if(sq_isnumeric(o1) && sq_isnumeric(o2)) { + res = (tofloat(o1) == tofloat(o2)); + } + else { + res = false; + } + } + return true; +} + +bool SQVM::IsFalse(SQObjectPtr &o) +{ + if(((type(o) & SQOBJECT_CANBEFALSE) + && ( ((type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0))) )) +#if !defined(SQUSEDOUBLE) || (defined(SQUSEDOUBLE) && defined(_SQ64)) + || (_integer(o) == 0) ) //OT_NULL|OT_INTEGER|OT_BOOL +#else + || (((type(o) != OT_FLOAT) && (_integer(o) == 0))) ) //OT_NULL|OT_INTEGER|OT_BOOL +#endif + { + return true; + } + return false; +} + +bool SQVM::Execute(SQObjectPtr &closure, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool raiseerror,ExecutionType et) +{ + if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; } + _nnativecalls++; + AutoDec ad(&_nnativecalls); + SQInteger traps = 0; + CallInfo *prevci = ci; + + switch(et) { + case ET_CALL: { + temp_reg = closure; + if(!StartCall(_closure(temp_reg), _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; + } + if(ci == prevci) { + outres = STK(_top-nargs); + return true; + } + ci->_root = SQTrue; + } + break; + case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, outres); ci->_root = SQTrue; traps += ci->_etraps; break; + case ET_RESUME_VM: + case ET_RESUME_THROW_VM: + traps = _suspended_traps; + ci->_root = _suspended_root; + _suspended = SQFalse; + if(et == ET_RESUME_THROW_VM) { SQ_THROW(); } + 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 (_debughook) CallDebugHook(_SC('l'),arg1); continue; + case _OP_LOAD: TARGET = ci->_literals[arg1]; continue; + case _OP_LOADINT: +#ifndef _SQ64 + TARGET = (SQInteger)arg1; continue; +#else + TARGET = (SQInteger)((SQUnsignedInteger32)arg1); continue; +#endif + case _OP_LOADFLOAT: TARGET = *((SQFloat *)&arg1); continue; + case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue; + case _OP_TAILCALL:{ + SQObjectPtr &t = STK(arg1); + if (type(t) == OT_CLOSURE + && (!_closure(t)->_function->_bgenerator)){ + SQObjectPtr clo = t; + if(_openouters) CloseOuters(&(_stack._vals[_stackbase])); + for (SQInteger i = 0; i < arg3; i++) STK(i) = STK(arg2 + i); + _GUARD(StartCall(_closure(clo), ci->_target, arg3, _stackbase, true)); + continue; + } + } + case _OP_CALL: { + SQObjectPtr clo = STK(arg1); + switch (type(clo)) { + case OT_CLOSURE: + _GUARD(StartCall(_closure(clo), sarg0, arg3, _stackbase+arg2, false)); + continue; + case OT_NATIVECLOSURE: { + bool suspend; + _GUARD(CallNative(_nativeclosure(clo), arg3, _stackbase+arg2, clo,suspend)); + if(suspend){ + _suspended = SQTrue; + _suspended_target = sarg0; + _suspended_root = ci->_root; + _suspended_traps = traps; + outres = clo; + return true; + } + if(sarg0 != -1) { + STK(arg0) = clo; + } + } + continue; + case OT_CLASS:{ + SQObjectPtr inst; + _GUARD(CreateClassInstance(_class(clo),inst,clo)); + if(sarg0 != -1) { + STK(arg0) = inst; + } + SQInteger stkbase; + switch(type(clo)) { + case OT_CLOSURE: + stkbase = _stackbase+arg2; + _stack._vals[stkbase] = inst; + _GUARD(StartCall(_closure(clo), -1, arg3, stkbase, false)); + break; + case OT_NATIVECLOSURE: + bool suspend; + stkbase = _stackbase+arg2; + _stack._vals[stkbase] = inst; + _GUARD(CallNative(_nativeclosure(clo), arg3, stkbase, clo,suspend)); + break; + default: break; //shutup GCC 4.x + } + } + break; + case OT_TABLE: + case OT_USERDATA: + case OT_INSTANCE:{ + SQObjectPtr closure; + if(_delegable(clo)->_delegate && _delegable(clo)->GetMetaMethod(this,MT_CALL,closure)) { + Push(clo); + for (SQInteger i = 0; i < arg3; i++) Push(STK(arg2 + i)); + if(!CallMetaMethod(closure, MT_CALL, arg3+1, clo)) SQ_THROW(); + if(sarg0 != -1) { + STK(arg0) = clo; + } + break; + } + + //Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo)); + //SQ_THROW(); + } + default: + Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo)); + SQ_THROW(); + } + } + continue; + case _OP_PREPCALL: + case _OP_PREPCALLK: { + SQObjectPtr &key = _i_.op == _OP_PREPCALLK?(ci->_literals)[arg1]:STK(arg1); + SQObjectPtr &o = STK(arg2); + if (!Get(o, key, temp_reg,false,arg2)) { + SQ_THROW(); + } + STK(arg3) = o; + _Swap(TARGET,temp_reg);//TARGET = temp_reg; + } + continue; + case _OP_GETK: + if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, false,arg2)) { SQ_THROW();} + _Swap(TARGET,temp_reg);//TARGET = temp_reg; + continue; + case _OP_MOVE: TARGET = STK(arg1); continue; + case _OP_NEWSLOT: + _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),false)); + if(arg0 != 0xFF) 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),arg1)) { SQ_THROW(); } + if (arg0 != 0xFF) TARGET = STK(arg3); + continue; + case _OP_GET: + if (!Get(STK(arg1), STK(arg2), temp_reg, false,arg1)) { SQ_THROW(); } + _Swap(TARGET,temp_reg);//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_ADD: _ARITH_(+,TARGET,STK(arg2),STK(arg1)); continue; + case _OP_SUB: _ARITH_(-,TARGET,STK(arg2),STK(arg1)); continue; + case _OP_MUL: _ARITH_(*,TARGET,STK(arg2),STK(arg1)); continue; + case _OP_DIV: _ARITH_NOZERO(/,TARGET,STK(arg2),STK(arg1),_SC("division by zero")); continue; + case _OP_MOD: ARITH_OP('%',TARGET,STK(arg2),STK(arg1)); continue; + case _OP_BITW: _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue; + case _OP_RETURN: + if((ci)->_generator) { + (ci)->_generator->Kill(); + } + if(Return(arg0, arg1, temp_reg)){ + assert(traps==0); + //outres = temp_reg; + _Swap(outres,temp_reg); + return true; + } + continue; + case _OP_LOADNULLS:{ for(SQInt32 n=0; n < arg1; n++) STK(arg0+n).Null(); }continue; + case _OP_LOADROOT: 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_JCMP: + _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg0),temp_reg)); + if(IsFalse(temp_reg)) ci->_ip+=(sarg1); + continue; + case _OP_JZ: if(IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue; + case _OP_GETOUTER: { + SQClosure *cur_cls = _closure(ci->_closure); + SQOuter *otr = _outer(cur_cls->_outervalues[arg1]); + TARGET = *(otr->_valptr); + } + continue; + case _OP_SETOUTER: { + SQClosure *cur_cls = _closure(ci->_closure); + SQOuter *otr = _outer(cur_cls->_outervalues[arg1]); + *(otr->_valptr) = STK(arg2); + if(arg0 != 0xFF) { + TARGET = STK(arg2); + } + } + continue; + case _OP_NEWOBJ: + switch(arg3) { + case NOT_TABLE: TARGET = SQTable::Create(_ss(this), arg1); continue; + case NOT_ARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue; + case NOT_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue; + default: assert(0); continue; + } + case _OP_APPENDARRAY: + { + SQObject val; + val._unVal.raw = 0; + switch(arg2) { + case AAT_STACK: + val = STK(arg1); break; + case AAT_LITERAL: + val = ci->_literals[arg1]; break; + case AAT_INT: + val._type = OT_INTEGER; +#ifndef _SQ64 + val._unVal.nInteger = (SQInteger)arg1; +#else + val._unVal.nInteger = (SQInteger)((SQUnsignedInteger32)arg1); +#endif + break; + case AAT_FLOAT: + val._type = OT_FLOAT; + val._unVal.fFloat = *((SQFloat *)&arg1); + break; + case AAT_BOOL: + val._type = OT_BOOL; + val._unVal.nInteger = arg1; + break; + default: assert(0); break; + + } + _array(STK(arg0))->Append(val); continue; + } + case _OP_COMPARITH: { + SQInteger selfidx = (((SQUnsignedInteger)arg1&0xFFFF0000)>>16); + _GUARD(DerefInc(arg3, TARGET, STK(selfidx), STK(arg2), STK(arg1&0x0000FFFF), false, selfidx)); + } + continue; + case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false, arg1));} continue; + case _OP_INCL: { + SQObjectPtr &a = STK(arg1); + if(type(a) == OT_INTEGER) { + a._unVal.nInteger = _integer(a) + sarg3; + } + else { + SQObjectPtr o(sarg3); //_GUARD(LOCAL_INC('+',TARGET, STK(arg1), o)); + _ARITH_(+,a,a,o); + } + } continue; + case _OP_PINC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, true, arg1));} continue; + case _OP_PINCL: { + SQObjectPtr &a = STK(arg1); + if(type(a) == OT_INTEGER) { + TARGET = a; + a._unVal.nInteger = _integer(a) + sarg3; + } + else { + 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,DONT_FALL_BACK)?true:false;continue; + case _OP_INSTANCEOF: + if(type(STK(arg1)) != OT_CLASS) + {Raise_Error(_SC("cannot apply instanceof between a %s and a %s"),GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();} + TARGET = (type(STK(arg2)) == OT_INSTANCE) ? (_instance(STK(arg2))->InstanceOf(_class(STK(arg1)))?true:false) : 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)); continue; + case _OP_BWNOT: + if(type(STK(arg1)) == OT_INTEGER) { + SQInteger t = _integer(STK(arg1)); + TARGET = SQInteger(~t); + 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; + if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); } + continue; + } + case _OP_YIELD:{ + if(ci->_generator) { + if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1); + _GUARD(ci->_generator->Yield(this,arg2)); + traps -= ci->_etraps; + if(sarg1 != MAX_FUNC_STACKSIZE) _Swap(STK(arg1),temp_reg);//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, TARGET)); + traps += ci->_etraps; + continue; + case _OP_FOREACH:{ int tojump; + _GUARD(FOREACH_OP(STK(arg0),STK(arg2),STK(arg2+1),STK(arg2+2),arg2,sarg1,tojump)); + ci->_ip += tojump; } + continue; + case _OP_POSTFOREACH: + assert(type(STK(arg0)) == OT_GENERATOR); + if(_generator(STK(arg0))->_state == SQGenerator::eDead) + ci->_ip += (sarg1 - 1); + continue; + case _OP_CLONE: _GUARD(Clone(STK(arg1), TARGET)); continue; + case _OP_TYPEOF: _GUARD(TypeOf(STK(arg1), TARGET)) continue; + case _OP_PUSHTRAP:{ + SQInstruction *_iv = _closure(ci->_closure)->_function->_instructions; + _etraps.push_back(SQExceptionTrap(_top,_stackbase, &_iv[(ci->_ip-_iv)+arg1], arg0)); traps++; + ci->_etraps++; + } + continue; + case _OP_POPTRAP: { + for(SQInteger i = 0; i < arg0; i++) { + _etraps.pop_back(); traps--; + ci->_etraps--; + } + } + continue; + case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); continue; + case _OP_NEWSLOTA: { + bool bstatic = (arg0&NEW_SLOT_STATIC_FLAG)?true:false; + if(type(STK(arg1)) == OT_CLASS) { + if(type(_class(STK(arg1))->_metamethods[MT_NEWMEMBER]) != OT_NULL ) { + Push(STK(arg1)); Push(STK(arg2)); Push(STK(arg3)); + Push((arg0&NEW_SLOT_ATTRIBUTES_FLAG) ? STK(arg2-1) : SQObjectPtr()); + Push(bstatic); + int nparams = 5; + if(Call(_class(STK(arg1))->_metamethods[MT_NEWMEMBER], nparams, _top - nparams, temp_reg,SQFalse)) { + Pop(nparams); + continue; + } + else { + SQ_THROW(); + } + } + } + _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),bstatic)); + if((arg0&NEW_SLOT_ATTRIBUTES_FLAG)) { + _class(STK(arg1))->SetAttributes(STK(arg2),STK(arg2-1)); + } + } + continue; + case _OP_GETBASE:{ + SQClosure *clo = _closure(ci->_closure); + if(clo->_base) { + TARGET = clo->_base; + } + else { + TARGET.Null(); + } + continue; + } + case _OP_CLOSE: + if(_openouters) CloseOuters(&(STK(arg1))); + continue; + } + + } + } +exception_trap: + { + SQObjectPtr currerror = _lasterror; +// dumpstack(_stackbase); +// SQInteger n = 0; + SQInteger last_top = _top; + + if(_ss(this)->_notifyallexceptions || (!traps && raiseerror)) CallErrorHandler(currerror); + + while( ci ) { + if(ci->_etraps > 0) { + SQExceptionTrap &et = _etraps.top(); + ci->_ip = et._ip; + _top = et._stacksize; + _stackbase = et._stackbase; + _stack._vals[_stackbase + et._extarget] = currerror; + _etraps.pop_back(); traps--; ci->_etraps--; + while(last_top >= _top) _stack._vals[last_top--].Null(); + goto exception_restore; + } + else if (_debughook) { + //notify debugger of a "return" + //even if it really an exception unwinding the stack + for(SQInteger i = 0; i < ci->_ncalls; i++) { + CallDebugHook(_SC('r')); + } + } + if(ci->_generator) ci->_generator->Kill(); + bool mustbreak = ci && ci->_root; + LeaveFrame(); + if(mustbreak) break; + } + + _lasterror = currerror; + return false; + } + assert(0); +} + +bool SQVM::CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor) +{ + inst = theclass->CreateInstance(); + if(!theclass->GetConstructor(constructor)) { + constructor.Null(); + } + return true; +} + +void SQVM::CallErrorHandler(SQObjectPtr &error) +{ + if(type(_errorhandler) != OT_NULL) { + SQObjectPtr out; + Push(_roottable); Push(error); + Call(_errorhandler, 2, _top-2, out,SQFalse); + Pop(2); + } +} + + +void SQVM::CallDebugHook(SQInteger type,SQInteger forcedline) +{ + _debughook = false; + SQFunctionProto *func=_closure(ci->_closure)->_function; + if(_debughook_native) { + const SQChar *src = type(func->_sourcename) == OT_STRING?_stringval(func->_sourcename):NULL; + const SQChar *fname = type(func->_name) == OT_STRING?_stringval(func->_name):NULL; + SQInteger line = forcedline?forcedline:func->GetLine(ci->_ip); + _debughook_native(this,type,src,line,fname); + } + else { + SQObjectPtr temp_reg; + SQInteger nparams=5; + Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name); + Call(_debughook_closure,nparams,_top-nparams,temp_reg,SQFalse); + Pop(nparams); + } + _debughook = true; +} + +bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, bool &suspend) +{ + SQInteger nparamscheck = nclosure->_nparamscheck; + SQInteger newtop = newbase + nargs + nclosure->_noutervalues; + + if (_nnativecalls + 1 > MAX_NATIVE_CALLS) { + Raise_Error(_SC("Native stack overflow")); + return false; + } + + if(nparamscheck && (((nparamscheck > 0) && (nparamscheck != nargs)) || + ((nparamscheck < 0) && (nargs < (-nparamscheck))))) + { + Raise_Error(_SC("wrong number of parameters")); + return false; + } + + SQInteger tcs; + SQIntVec &tc = nclosure->_typecheck; + if((tcs = tc.size())) { + for(SQInteger i = 0; i < nargs && i < tcs; i++) { + if((tc._vals[i] != -1) && !(type(_stack._vals[newbase+i]) & tc._vals[i])) { + Raise_ParamTypeError(i,tc._vals[i],type(_stack._vals[newbase+i])); + return false; + } + } + } + + if(!EnterFrame(newbase, newtop, false)) return false; + ci->_closure = nclosure; + + SQInteger outers = nclosure->_noutervalues; + for (SQInteger i = 0; i < outers; i++) { + _stack._vals[newbase+nargs+i] = nclosure->_outervalues[i]; + } + if(nclosure->_env) { + _stack._vals[newbase] = nclosure->_env->_obj; + } + + _nnativecalls++; + SQInteger ret = (nclosure->_function)(this); + _nnativecalls--; + + suspend = false; + if (ret == SQ_SUSPEND_FLAG) { + suspend = true; + } + else if (ret < 0) { + LeaveFrame(); + Raise_Error(_lasterror); + return false; + } + if(ret) { + retval = _stack._vals[_top-1]; + } + else { + retval.Null(); + } + //retval = ret ? _stack._vals[_top-1] : _null_; + LeaveFrame(); + return true; +} + +#define FALLBACK_OK 0 +#define FALLBACK_NO_MATCH 1 +#define FALLBACK_ERROR 2 + +bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw, SQInteger selfidx) +{ + switch(type(self)){ + case OT_TABLE: + if(_table(self)->Get(key,dest))return true; + break; + case OT_ARRAY: + if(sq_isnumeric(key)) { if(_array(self)->Get(tointeger(key),dest)) { return true; } Raise_IdxError(key); return false; } + break; + case OT_INSTANCE: + if(_instance(self)->Get(key,dest)) return true; + break; + case OT_CLASS: + if(_class(self)->Get(key,dest)) return true; + break; + case OT_STRING: + if(sq_isnumeric(key)){ + SQInteger n = tointeger(key); + if(abs((int)n) < _string(self)->_len) { + if(n < 0) n = _string(self)->_len - n; + dest = SQInteger(_stringval(self)[n]); + return true; + } + Raise_IdxError(key); + return false; + } + break; + default:break; //shut up compiler + } + if(!raw) { + switch(FallBackGet(self,key,dest)) { + case FALLBACK_OK: return true; //okie + case FALLBACK_NO_MATCH: break; //keep falling back + case FALLBACK_ERROR: return false; // the metamethod failed + } + if(InvokeDefaultDelegate(self,key,dest)) { + return true; + } + } +//#ifdef ROOT_FALLBACK + if(selfidx == 0) { + if(_table(_roottable)->Get(key,dest)) return true; + } +//#endif + Raise_IdxError(key); + return false; +} + +bool SQVM::InvokeDefaultDelegate(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest) +{ + SQTable *ddel = NULL; + switch(type(self)) { + case OT_CLASS: ddel = _class_ddel; break; + case OT_TABLE: ddel = _table_ddel; break; + case OT_ARRAY: ddel = _array_ddel; break; + case OT_STRING: ddel = _string_ddel; break; + case OT_INSTANCE: ddel = _instance_ddel; break; + case OT_INTEGER:case OT_FLOAT:case OT_BOOL: ddel = _number_ddel; break; + case OT_GENERATOR: ddel = _generator_ddel; break; + case OT_CLOSURE: case OT_NATIVECLOSURE: ddel = _closure_ddel; break; + case OT_THREAD: ddel = _thread_ddel; break; + case OT_WEAKREF: ddel = _weakref_ddel; break; + default: return false; + } + return ddel->Get(key,dest); +} + + +SQInteger SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest) +{ + switch(type(self)){ + case OT_TABLE: + case OT_USERDATA: + //delegation + if(_delegable(self)->_delegate) { + if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,false,DONT_FALL_BACK)) return FALLBACK_OK; + } + else { + return FALLBACK_NO_MATCH; + } + //go through + case OT_INSTANCE: { + SQObjectPtr closure; + if(_delegable(self)->GetMetaMethod(this, MT_GET, closure)) { + Push(self);Push(key); + _nmetamethodscall++; + AutoDec ad(&_nmetamethodscall); + if(Call(closure, 2, _top - 2, dest, SQFalse)) { + Pop(2); + return FALLBACK_OK; + } + else { + if(type(_lasterror) != OT_NULL) { //NULL means "clean failure" (not found) + //error + Pop(2); + return FALLBACK_ERROR; + } + } + } + } + break; + default: break;//shutup GCC 4.x + } + // no metamethod or no fallback type + return FALLBACK_NO_MATCH; +} + +bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,SQInteger selfidx) +{ + switch(type(self)){ + case OT_TABLE: + if(_table(self)->Set(key,val)) return true; + break; + case OT_INSTANCE: + if(_instance(self)->Set(key,val)) return true; + break; + case OT_ARRAY: + if(!sq_isnumeric(key)) { Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); return false; } + if(!_array(self)->Set(tointeger(key),val)) { + Raise_IdxError(key); + return false; + } + return true; + default: + Raise_Error(_SC("trying to set '%s'"),GetTypeName(self)); + return false; + } + + switch(FallBackSet(self,key,val)) { + case FALLBACK_OK: return true; //okie + case FALLBACK_NO_MATCH: break; //keep falling back + case FALLBACK_ERROR: return false; // the metamethod failed + } + if(selfidx == 0) { + if(_table(_roottable)->Set(key,val)) + return true; + } + Raise_IdxError(key); + return false; +} + +SQInteger SQVM::FallBackSet(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val) +{ + switch(type(self)) { + case OT_TABLE: + if(_table(self)->_delegate) { + if(Set(_table(self)->_delegate,key,val,DONT_FALL_BACK)) return FALLBACK_OK; + } + //keps on going + case OT_INSTANCE: + case OT_USERDATA:{ + SQObjectPtr closure; + SQObjectPtr t; + if(_delegable(self)->GetMetaMethod(this, MT_SET, closure)) { + Push(self);Push(key);Push(val); + _nmetamethodscall++; + AutoDec ad(&_nmetamethodscall); + if(Call(closure, 3, _top - 3, t, SQFalse)) { + Pop(3); + return FALLBACK_OK; + } + else { + if(type(_lasterror) != OT_NULL) { //NULL means "clean failure" (not found) + //error + Pop(3); + return FALLBACK_ERROR; + } + } + } + } + break; + default: break;//shutup GCC 4.x + } + // no metamethod or no fallback type + return FALLBACK_NO_MATCH; +} + +bool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target) +{ + SQObjectPtr temp_reg; + SQObjectPtr newobj; + switch(type(self)){ + case OT_TABLE: + newobj = _table(self)->Clone(); + goto cloned_mt; + case OT_INSTANCE: { + newobj = _instance(self)->Clone(_ss(this)); +cloned_mt: + SQObjectPtr closure; + if(_delegable(newobj)->_delegate && _delegable(newobj)->GetMetaMethod(this,MT_CLONED,closure)) { + Push(newobj); + Push(self); + if(!CallMetaMethod(closure,MT_CLONED,2,temp_reg)) + return false; + } + } + target = newobj; + return true; + case OT_ARRAY: + target = _array(self)->Clone(); + return true; + default: + Raise_Error(_SC("cloning a %s"), GetTypeName(self)); + return false; + } +} + +bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic) +{ + 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)) { + SQObjectPtr closure; + if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) { + Push(self);Push(key);Push(val); + if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) { + return false; + } + rawcall = false; + } + else { + rawcall = true; + } + } + } + if(rawcall) _table(self)->NewSlot(key,val); //cannot fail + + break;} + case OT_INSTANCE: { + SQObjectPtr res; + SQObjectPtr closure; + if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) { + Push(self);Push(key);Push(val); + if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) { + return false; + } + break; + } + Raise_Error(_SC("class instances do not support the new slot operator")); + return false; + break;} + case OT_CLASS: + if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) { + 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; + SQObjectPtr closure; + if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_DELSLOT,closure)) { + Push(self);Push(key); + return CallMetaMethod(closure,MT_DELSLOT,2,res); + } + else { + 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,SQBool raiseerror) +{ +#ifdef _DEBUG +SQInteger prevstackbase = _stackbase; +#endif + switch(type(closure)) { + case OT_CLOSURE: + return Execute(closure, nparams, stackbase, outres, raiseerror); + break; + case OT_NATIVECLOSURE:{ + bool suspend; + return CallNative(_nativeclosure(closure), nparams, stackbase, outres,suspend); + + } + break; + case OT_CLASS: { + SQObjectPtr constr; + SQObjectPtr temp; + CreateClassInstance(_class(closure),outres,constr); + if(type(constr) != OT_NULL) { + _stack[stackbase] = outres; + return Call(constr,nparams,stackbase,temp,raiseerror); + } + return true; + } + break; + default: + return false; + } +#ifdef _DEBUG + if(!_suspended) { + assert(_stackbase == prevstackbase); + } +#endif + return true; +} + +bool SQVM::CallMetaMethod(SQObjectPtr &closure,SQMetaMethod mm,SQInteger nparams,SQObjectPtr &outres) +{ + //SQObjectPtr closure; + + _nmetamethodscall++; + if(Call(closure, nparams, _top - nparams, outres, SQFalse)) { + _nmetamethodscall--; + Pop(nparams); + return true; + } + _nmetamethodscall--; + //} + Pop(nparams); + return false; +} + +void SQVM::FindOuter(SQObjectPtr &target, SQObjectPtr *stackindex) +{ + SQOuter **pp = &_openouters; + SQOuter *p; + SQOuter *otr; + + while ((p = *pp) != NULL && p->_valptr >= stackindex) { + if (p->_valptr == stackindex) { + target = SQObjectPtr(p); + return; + } + pp = &p->_next; + } + otr = SQOuter::Create(_ss(this), stackindex); + otr->_next = *pp; + otr->_idx = (stackindex - _stack._vals); + __ObjAddRef(otr); + *pp = otr; + target = SQObjectPtr(otr); +} + +bool SQVM::EnterFrame(SQInteger newbase, SQInteger newtop, bool tailcall) +{ + if( !tailcall ) { + if( _callsstacksize == _alloccallsstacksize ) { + GrowCallStack(); + } + ci = &_callsstack[_callsstacksize++]; + ci->_prevstkbase = (SQInt32)(newbase - _stackbase); + ci->_prevtop = (SQInt32)(_top - _stackbase); + ci->_etraps = 0; + ci->_ncalls = 1; + ci->_generator = NULL; + ci->_root = SQFalse; + } + else { + ci->_ncalls++; + } + + _stackbase = newbase; + _top = newtop; + if(newtop + MIN_STACK_OVERHEAD > (SQInteger)_stack.size()) { + if(_nmetamethodscall) { + Raise_Error(_SC("stack overflow, cannot resize stack while in a metamethod")); + return false; + } + _stack.resize(_stack.size() + (MIN_STACK_OVERHEAD << 2)); + RelocateOuters(); + } + return true; +} + +void SQVM::LeaveFrame() { + SQInteger last_top = _top; + SQInteger last_stackbase = _stackbase; + SQInteger css = --_callsstacksize; + + /* First clean out the call stack frame */ + ci->_closure.Null(); + _stackbase -= ci->_prevstkbase; + _top = _stackbase + ci->_prevtop; + ci = (css) ? &_callsstack[css-1] : NULL; + + if(_openouters) CloseOuters(&(_stack._vals[last_stackbase])); + while (last_top >= _top) { + _stack._vals[last_top--].Null(); + } +} + +void SQVM::RelocateOuters() +{ + SQOuter *p = _openouters; + while (p) { + p->_valptr = _stack._vals + p->_idx; + p = p->_next; + } +} + +void SQVM::CloseOuters(SQObjectPtr *stackindex) { + SQOuter *p; + while ((p = _openouters) != NULL && p->_valptr >= stackindex) { + p->_value = *(p->_valptr); + p->_valptr = &p->_value; + _openouters = p->_next; + __ObjRelease(p); + } +} + +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--; +} + +void SQVM::Pop() { + _stack[--_top].Null(); +} + +void SQVM::Pop(SQInteger n) { + for(SQInteger i = 0; i < n; i++){ + _stack[--_top].Null(); + } +} + +void SQVM::PushNull() { _stack[_top++].Null(); } +void SQVM::Push(const SQObjectPtr &o) { _stack[_top++] = o; } +SQObjectPtr &SQVM::Top() { return _stack[_top-1]; } +SQObjectPtr &SQVM::PopGet() { return _stack[--_top]; } +SQObjectPtr &SQVM::GetUp(SQInteger n) { return _stack[_top+n]; } +SQObjectPtr &SQVM::GetAt(SQInteger n) { return _stack[n]; } + +#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[_callsstacksize-1]; + scprintf(_SC("IP: %p\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 %p"),_generator(obj));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/squirrel_3_0_1_stable/squirrel/sqvm.h b/squirrel_3_0_1_stable/squirrel/sqvm.h new file mode 100644 index 000000000..397dcd9c1 --- /dev/null +++ b/squirrel_3_0_1_stable/squirrel/sqvm.h @@ -0,0 +1,208 @@ +/* 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 15 + +#define SQ_SUSPEND_FLAG -666 +#define DONT_FALL_BACK 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 _INLINE + +#define STK(a) _stack._vals[_stackbase+(a)] +#define TARGET _stack._vals[_stackbase+arg0] + +typedef sqvector ExceptionsTraps; + +struct SQVM : public CHAINABLE_OBJ +{ + struct CallInfo{ + //CallInfo() { _generator = NULL;} + SQInstruction *_ip; + SQObjectPtr *_literals; + SQObjectPtr _closure; + SQGenerator *_generator; + SQInt32 _etraps; + SQInt32 _prevstkbase; + SQInt32 _prevtop; + SQInt32 _target; + SQInt32 _ncalls; + SQBool _root; + }; + +typedef sqvector CallInfoVec; +public: + void DebugHookProxy(SQInteger type, const SQChar * sourcename, SQInteger line, const SQChar * funcname); + static void _DebugHookProxy(HSQUIRRELVM v, SQInteger type, const SQChar * sourcename, SQInteger line, const SQChar * funcname); + enum ExecutionType { ET_CALL, ET_RESUME_GENERATOR, ET_RESUME_VM,ET_RESUME_THROW_VM }; + SQVM(SQSharedState *ss); + ~SQVM(); + bool Init(SQVM *friendvm, SQInteger stacksize); + bool Execute(SQObjectPtr &func, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, SQBool raiseerror, ExecutionType et = ET_CALL); + //starts a native call return when the NATIVE closure returns + bool CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval,bool &suspend); + //starts a SQUIRREL call in the same "Execution loop" + bool StartCall(SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall); + bool CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor); + //call a generic closure pure SQUIRREL or NATIVE + bool Call(SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres,SQBool raiseerror); + 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, SQInteger selfidx); + SQInteger FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest); + bool InvokeDefaultDelegate(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest); + bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, SQInteger selfidx); + SQInteger FallBackSet(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val); + bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val,bool bstatic); + 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); + static bool IsEqual(const SQObjectPtr &o1,const SQObjectPtr &o2,bool &res); + bool ToString(const SQObjectPtr &o,SQObjectPtr &res); + SQString *PrintObjVal(const SQObjectPtr &o); + + + void Raise_Error(const SQChar *s, ...); + void Raise_Error(const SQObjectPtr &desc); + void Raise_IdxError(const SQObjectPtr &o); + void Raise_CompareError(const SQObject &o1, const SQObject &o2); + void Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type); + + void FindOuter(SQObjectPtr &target, SQObjectPtr *stackindex); + void RelocateOuters(); + void CloseOuters(SQObjectPtr *stackindex); + + bool TypeOf(const SQObjectPtr &obj1, SQObjectPtr &dest); + bool CallMetaMethod(SQObjectPtr &closure, 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 CLASS_OP(SQObjectPtr &target,SQInteger base,SQInteger attrs); + //return true if the loop is finished + bool FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump); + //_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,SQInteger arg0); +#ifdef _DEBUG_DUMP + void dumpstack(SQInteger stackbase=-1, bool dumpall = false); +#endif + +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + SQObjectType GetType() {return OT_THREAD;} +#endif + void Finalize(); + void GrowCallStack() { + SQInteger newsize = _alloccallsstacksize*2; + _callstackdata.resize(newsize); + _callsstack = &_callstackdata[0]; + _alloccallsstacksize = newsize; + } + bool EnterFrame(SQInteger newbase, SQInteger newtop, bool tailcall); + void LeaveFrame(); + void Release(){ sq_delete(this,SQVM); } +//////////////////////////////////////////////////////////////////////////// + //stack functions for the api + void Remove(SQInteger n); + + static bool IsFalse(SQObjectPtr &o); + + void Pop(); + void Pop(SQInteger n); + void Push(const SQObjectPtr &o); + void PushNull(); + SQObjectPtr &Top(); + SQObjectPtr &PopGet(); + SQObjectPtr &GetUp(SQInteger n); + SQObjectPtr &GetAt(SQInteger n); + + SQObjectPtrVec _stack; + + SQInteger _top; + SQInteger _stackbase; + SQOuter *_openouters; + SQObjectPtr _roottable; + SQObjectPtr _lasterror; + SQObjectPtr _errorhandler; + + bool _debughook; + SQDEBUGHOOK _debughook_native; + SQObjectPtr _debughook_closure; + + SQObjectPtr temp_reg; + + + CallInfo* _callsstack; + SQInteger _callsstacksize; + SQInteger _alloccallsstacksize; + sqvector _callstackdata; + + ExceptionsTraps _etraps; + CallInfo *ci; + void *_foreignptr; + //VMs sharing the same state + SQSharedState *_sharedstate; + SQInteger _nnativecalls; + SQInteger _nmetamethodscall; + //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)));} + +#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){ \ + SQInteger css = v->_callsstacksize; \ + if(css == v->_alloccallsstacksize) { \ + v->GrowCallStack(); \ + } \ + v->ci = &v->_callsstack[css]; \ + *(v->ci) = nci; \ + v->_callsstacksize++; \ +} + +#define POP_CALLINFO(v){ \ + SQInteger css = --v->_callsstacksize; \ + v->ci->_closure.Null(); \ + v->ci = css?&v->_callsstack[css-1]:NULL; \ +} +#endif //_SQVM_H_ -- cgit v1.2.3