Browse Source

Merge pull request #1 from albertodemichelis/master

Sync
Sandu Liviu Catalin 7 years ago
parent
commit
68d7c7f516

+ 11 - 6
CMakeLists.txt

@@ -4,8 +4,13 @@ else()
   cmake_minimum_required(VERSION 2.8)
 endif()
 
+option(DISABLE_STATIC "Avoid building/installing static libraries.")
+option(LONG_OUTPUT_NAMES "Use longer names for binaries and libraries: squirrel3 (not sq).")
+
 set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}" CACHE PATH "")
-set(CMAKE_BUILD_TYPE "Release" CACHE STRING "")
+if (NOT CMAKE_BUILD_TYPE)
+  set(CMAKE_BUILD_TYPE "Release")
+endif ()
 
 project(squirrel C CXX)
 
@@ -40,12 +45,12 @@ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
   add_definitions(-D_SQ64)
 endif()
 
-if(NOT DEFINED SQ_DISABLE_INSTALLER)
-  if(NOT DEFINED INSTALL_BIN_DIR)
+if(NOT SQ_DISABLE_INSTALLER)
+  if(NOT INSTALL_BIN_DIR)
     set(INSTALL_BIN_DIR bin)
   endif()
 
-  if(NOT DEFINED INSTALL_LIB_DIR)
+  if(NOT INSTALL_LIB_DIR)
     set(INSTALL_LIB_DIR lib)
   endif()
 endif()
@@ -54,11 +59,11 @@ add_subdirectory(squirrel)
 add_subdirectory(sqstdlib)
 add_subdirectory(sq)
 
-if(NOT WIN32 AND NOT DEFINED DISABLE_DYNAMIC)
+if(NOT WIN32 AND NOT DISABLE_DYNAMIC)
   set_target_properties(squirrel sqstdlib PROPERTIES SOVERSION 0 VERSION 0.0.0)
 endif()
 
-if(DEFINED INSTALL_INC_DIR)
+if(INSTALL_INC_DIR)
   set(SQ_PUB_HEADERS include/sqconfig.h
                      include/sqstdaux.h
                      include/sqstdblob.h

+ 19 - 3
doc/source/reference/api/calls.rst

@@ -87,9 +87,28 @@ reset the last error in the virtual machine to null
 resumes the generator at the top position of the stack.
 
 
+.. _sq_tailcall:
 
+.. c:function:: SQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams)
 
+	:param HSQUIRRELVM v: the target VM
+    :param SQInteger params: number of parameters of the function
 
+	Calls a closure and removes the caller function from the call stack.
+	This function must be invoke from a native closure and 
+	he return value of sq_tailcall must be returned by the caller function(see example).
+	
+*.eg*
+
+::
+
+    SQInteger tailcall_something_example(HSQUIRRELVM v)
+    {
+		//push closure and parameters here
+		... 
+        return sq_tailcall(v,2);
+    }
+	
 .. _sq_throwerror:
 
 .. c:function:: SQRESULT sq_throwerror(HSQUIRRELVM v, const SQChar * err)
@@ -101,9 +120,6 @@ resumes the generator at the top position of the stack.
 sets the last error in the virtual machine and returns the value that has to be returned by a native closure in order to trigger an exception in the virtual machine.
 
 
-
-
-
 .. _sq_throwobject:
 
 .. c:function:: SQRESULT sq_throwobject(HSQUIRRELVM v)

+ 4 - 4
doc/source/reference/api/object_creation_and_handling.rst

@@ -66,12 +66,12 @@ pushes the value of a class or instance member using a member handle (see sq_get
 
 .. _sq_getclosureinfo:
 
-.. c:function:: SQRESULT sq_getclosureinfo(HSQUIRRELVM v, SQInteger idx, SQUnsignedInteger * nparams, SQUnsignedInteger * nfreevars)
+.. c:function:: SQRESULT sq_getclosureinfo(HSQUIRRELVM v, SQInteger idx, SQInteger * nparams, SQInteger * nfreevars)
 
     :param HSQUIRRELVM v: the target VM
     :param SQInteger idx: index of the target closure
-    :param SQUnsignedInteger * nparams: a pointer to an unsigned integer that will store the number of parameters
-    :param SQUnsignedInteger * nfreevars: a pointer to an unsigned integer that will store the number of free variables
+    :param SQInteger * nparams: a pointer to an integer that will store the number of parameters
+    :param SQInteger * nfreevars: a pointer to an integer that will store the number of free variables
     :returns: an SQRESULT
 
 retrieves number of parameters and number of freevariables from a squirrel closure.
@@ -355,7 +355,7 @@ creates a new array and pushes it in the stack
     :param SQBool hasbase: if the parameter is true the function expects a base class on top of the stack.
     :returns: a SQRESULT
 
-creates a new class object. If the parameter 'hasbase' is different than 0, the function pops a class from the stack and inherits the new created class from it.
+creates a new class object. If the parameter 'hasbase' is different than 0, the function pops a class from the stack and inherits the new created class from it. The new class is pushed in the stack.
 
 
 

+ 1 - 1
doc/source/reference/api/object_manipulation.rst

@@ -164,7 +164,7 @@ pops a key from the stack and delete the slot indexed by it from the table at po
     :param HSQUIRRELVM v: the target VM
     :param SQInteger idx: index of the target object in the stack
     :returns: a SQRESULT
-    :remarks: this call will invokes the delegation system like a normal dereference it only works on tables, arrays and userdata; if the function fails, nothing will be pushed in the stack.
+    :remarks: this call will invokes the delegation system like a normal dereference it only works on tables, arrays, classes, instances and userdata; if the function fails, nothing will be pushed in the stack.
 
 pops a key from the stack and performs a get operation on the object at the position idx in the stack; and pushes the result in the stack.
 

+ 8 - 8
doc/source/reference/embedding/build_configuration.rst

@@ -13,19 +13,19 @@ Unicode
 .. index:: single: Unicode
 
 By default Squirrel strings are plain 8-bits ASCII characters; however if the symbol
-'SQUNICODE' is defined the VM, compiler and API will use 16-bits characters (UCS2).
+'SQUNICODE' is defined the VM, compiler and API will use 16-bit characters (UCS2).
 
 .. _squirrel_64bits:
 
----------------------------------
-Squirrel on 64 bits architectures
----------------------------------
+--------------------------------
+Squirrel on 64-bit architectures
+--------------------------------
 
 .. index::
-    single: Squirrel on 64 bits architectures
+    single: Squirrel on 64-bit architectures
     single: 64 bits
 
-Squirrel can be compiled on 64 bits architectures by defining '_SQ64' in the C++
+Squirrel can be compiled on 64-bit architectures by defining '_SQ64' in the C++
 preprocessor. This flag should be defined in any project that includes 'squirrel.h'.
 
 .. _userdata_alignment:
@@ -38,7 +38,7 @@ Userdata Alignment
 
 Both class instances and userdatas can have a buffer associated to them.
 Squirrel specifies the alignment(in bytes) through the preprocessor defining 'SQ_ALIGNMENT'.
-By default SQ_ALIGNMENT is defined as 4 for 32 bits builds and 8 for 64bits builds and builds that use 64bits floats.
+By default SQ_ALIGNMENT is defined as 4 for 32-bit builds and 8 for 64-bit builds and builds that use 64-bit floats.
 It is possible to override the value of SQ_ALIGNMENT respecting the following rules.
 SQ_ALIGNMENT shall be less than or equal to SQ_MALLOC alignments, and it shall be power of 2.
 
@@ -53,7 +53,7 @@ Stand-alone VM without compiler
 
 .. index:: single: Stand-alone VM without compiler
 
-Squirrel's VM can be compiled without it's compiler by defining 'NO_COMPILER' in the C++ preprocessor.
+Squirrel's VM can be compiled without its compiler by defining 'NO_COMPILER' in the C++ preprocessor.
 When 'NO_COMPILER' is defined all function related to the compiler (eg. sq_compile) will fail. Other functions
 that conditionally load precompiled bytecode or compile a file (eg. sqstd_dofile) will only work with
 precompiled bytecode.

+ 1 - 1
doc/source/reference/embedding/calling_a_function.rst

@@ -16,7 +16,7 @@ parameter is > 0. ::
     sq_pushinteger(v,1);
     sq_pushfloat(v,2.0);
     sq_pushstring(v,"three",-1);
-    sq_call(v,4,SQFalse);
+    sq_call(v,4,SQFalse,SQFalse);
     sq_pop(v,2); //pops the roottable and the function
 
 this is equivalent to the following Squirrel code::

+ 1 - 1
doc/source/reference/embedding/compiling_a_script.rst

@@ -8,7 +8,7 @@ You can compile a Squirrel script with the function *sq_compile*.::
 
     typedef SQInteger (*SQLEXREADFUNC)(SQUserPointer userdata);
 
-    SQRESULT sq_compile(HSQUIRRELVM v,SQREADFUNC read,SQUserPointer p,
+    SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,
                 const SQChar *sourcename,SQBool raiseerror);
 
 In order to compile a script is necessary for the host application to implement a reader

+ 2 - 1
doc/source/reference/embedding/creating_a_c_function.rst

@@ -99,7 +99,8 @@ Here an example of how to register a function::
     {
         sq_pushroottable(v);
         sq_pushstring(v,fname,-1);
-        sq_newclosure(v,f,0,0); //create a new function
+        sq_newclosure(v,f,0); //create a new function
         sq_newslot(v,-3,SQFalse);
         sq_pop(v,1); //pops the root table
+        return 0;
     }

+ 2 - 2
doc/source/reference/embedding/references_from_c.rst

@@ -11,11 +11,11 @@ The object can be also re-pushed in the VM stack using sq_pushobject().::
 
     HSQOBJECT obj;
 
-    sq_resetobject(v,&obj) //initialize the handle
+    sq_resetobject(&obj); //initialize the handle
     sq_getstackobj(v,-2,&obj); //retrieve an object handle from the pos -2
     sq_addref(v,&obj); //adds a reference to the object
 
     ... //do stuff
 
-    sq_pushobject(v,&obj); //push the object in the stack
+    sq_pushobject(v,obj); //push the object in the stack
     sq_release(v,&obj); //relese the object

+ 18 - 13
doc/source/reference/language/builtin_functions.rst

@@ -53,9 +53,9 @@ returns the const table of the VM.
 
 sets the const table of the VM; returns the previous const table.
 
-.. js:function:: assert(exp)
+.. js:function:: assert(exp, [message])
 
-throws an exception if exp is null
+throws an exception if exp is null or false. Throws "assertion failed" string by default, or message if specified.
 
 .. js:function:: print(x)
 
@@ -279,7 +279,7 @@ tries to get a value from the slot 'key' without employing delegation
 
 .. js:function:: table.rawset(key,val)
 
-Sets the slot 'key' with the value 'val' without employing delegation. If the slot does not exists, it will be created.
+Sets the slot 'key' with the value 'val' without employing delegation. If the slot does not exists, it will be created. Returns table itself.
 
 
 .. js:function:: table.rawdelete()
@@ -304,7 +304,7 @@ Tries to invoke the _tostring metamethod. If that fails, it returns "(table : po
 
 .. js:function:: table.clear()
 
-removes all the slots from the table
+removes all the slots from the table. Returns table itself.
 
 
 .. js:function:: table.setdelegate(table)
@@ -316,6 +316,11 @@ Sets the delegate of the table. To remove a delegate, 'null' must be passed to t
 
 returns the table's delegate or null if no delegate was set.
 
+
+.. js:function:: table.filter(func(key,val))
+
+Creates a new table with all values that pass the test implemented by the provided function. In detail, it creates a new table, invokes the specified function for each key-value pair in the original table; if the function returns 'true', then the value is added to the newly created table at the same key.
+
 ^^^^^^
 Array
 ^^^^^^
@@ -327,17 +332,17 @@ returns the length of the array
 
 .. js:function:: array.append(val)
 
-appends the value 'val' at the end of the array
+appends the value 'val' at the end of the array. Returns array itself.
 
 
 .. js:function:: array.push(val)
 
-appends the value 'val' at the end of the array
+appends the value 'val' at the end of the array. Returns array itself.
 
 
 .. js:function:: array.extend(array)
 
-Extends the array by appending all the items in the given array.
+Extends the array by appending all the items in the given array. Returns array itself.
 
 
 .. js:function:: array.pop()
@@ -352,22 +357,22 @@ returns the value of the array with the higher index
 
 .. js:function:: array.insert(idx,val)
 
-inserts the value 'val' at the position 'idx' in the array
+inserts the value 'val' at the position 'idx' in the array. Returns array itself.
 
 
 .. js:function:: array.remove(idx)
 
-removes the value at the position 'idx' in the array
+removes the value at the position 'idx' in the array and returns its value.
 
 
 .. js:function:: array.resize(size,[fill])
 
-Resizes the array. If the optional parameter 'fill' is specified, its value will be used to fill the new array's slots when the size specified is bigger than the previous size. If the fill parameter is omitted, null is used instead.
+Resizes the array. If the optional parameter 'fill' is specified, its value will be used to fill the new array's slots when the size specified is bigger than the previous size. If the fill parameter is omitted, null is used instead. Returns array itself.
 
 
 .. js:function:: array.sort([compare_func])
 
-Sorts the array. A custom compare function can be optionally passed. The function prototype as to be the following.::
+Sorts the array in-place. A custom compare function can be optionally passed. The function prototype as to be the following.::
 
     function custom_compare(a,b)
     {
@@ -380,11 +385,11 @@ a more compact version of a custom compare can be written using a lambda express
 
     arr.sort(@(a,b) a <=> b);
 
-
+Returns array itself.
 
 .. js:function:: array.reverse()
 
-reverse the elements of the array in place
+reverse the elements of the array in place. Returns array itself.
 
 
 .. js:function:: array.slice(start,[end])

+ 2 - 1
include/squirrel.h

@@ -276,7 +276,7 @@ SQUIRREL_API void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK ho
 SQUIRREL_API SQRELEASEHOOK sq_getreleasehook(HSQUIRRELVM v,SQInteger idx);
 SQUIRREL_API SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize);
 SQUIRREL_API SQRESULT sq_getfunctioninfo(HSQUIRRELVM v,SQInteger level,SQFunctionInfo *fi);
-SQUIRREL_API SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger *nparams,SQUnsignedInteger *nfreevars);
+SQUIRREL_API SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQInteger *nparams,SQInteger *nfreevars);
 SQUIRREL_API SQRESULT sq_getclosurename(HSQUIRRELVM v,SQInteger idx);
 SQUIRREL_API SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name);
 SQUIRREL_API SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p);
@@ -332,6 +332,7 @@ 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);
+SQUIRREL_API SQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams);
 
 /*raw object handling*/
 SQUIRREL_API SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po);

+ 8 - 8
sq/CMakeLists.txt

@@ -1,34 +1,34 @@
-if(NOT DEFINED DISABLE_DYNAMIC)
+if(NOT DISABLE_DYNAMIC)
   if(CMAKE_COMPILER_IS_GNUCXX)
     set_source_files_properties(sq.c PROPERTIES COMPILE_FLAGS -std=c99)
   endif()
   add_executable(sq sq.c)
   set_target_properties(sq PROPERTIES LINKER_LANGUAGE C)
   target_link_libraries(sq squirrel sqstdlib)
-  if(NOT DEFINED SQ_DISABLE_INSTALLER)
+  if(NOT SQ_DISABLE_INSTALLER)
     install(TARGETS sq RUNTIME DESTINATION ${INSTALL_BIN_DIR})
   endif()
 endif()
 
-if(NOT DEFINED DISABLE_STATIC)
+if(NOT DISABLE_STATIC)
   add_executable(sq_static sq.c)
   set_target_properties(sq_static PROPERTIES LINKER_LANGUAGE C)
   target_link_libraries(sq_static squirrel_static sqstdlib_static)
-  if(NOT DEFINED SQ_DISABLE_INSTALLER)
+  if(NOT SQ_DISABLE_INSTALLER)
     install(TARGETS sq_static RUNTIME DESTINATION ${INSTALL_BIN_DIR})
   endif()
 endif()
 
-if(DEFINED LONG_OUTPUT_NAMES)
-  if(NOT DEFINED DISABLE_DYNAMIC)
+if(LONG_OUTPUT_NAMES)
+  if(NOT DISABLE_DYNAMIC)
     set_target_properties(sq PROPERTIES OUTPUT_NAME squirrel3)
   endif()
 
-  if(NOT DEFINED DISABLE_STATIC)
+  if(NOT DISABLE_STATIC)
     set_target_properties(sq_static PROPERTIES OUTPUT_NAME squirrel3_static)
   endif()
 endif()
 
-if(CMAKE_COMPILER_IS_GNUCXX AND (NOT DEFINED DISABLE_STATIC))
+if(CMAKE_COMPILER_IS_GNUCXX AND NOT DISABLE_STATIC)
   set_target_properties(sq_static PROPERTIES COMPILE_FLAGS "-static -Wl,-static")
 endif()

+ 7 - 7
sqstdlib/CMakeLists.txt

@@ -7,29 +7,29 @@ set(SQSTDLIB_SRC sqstdaux.cpp
                  sqstdstring.cpp
                  sqstdsystem.cpp)
 
-if(NOT DEFINED DISABLE_DYNAMIC)
+if(NOT DISABLE_DYNAMIC)
   add_library(sqstdlib SHARED ${SQSTDLIB_SRC})
   target_link_libraries(sqstdlib squirrel)
-  if(NOT DEFINED SQ_DISABLE_INSTALLER)
+  if(NOT SQ_DISABLE_INSTALLER)
     install(TARGETS sqstdlib RUNTIME DESTINATION ${INSTALL_BIN_DIR}
                              LIBRARY DESTINATION ${INSTALL_LIB_DIR}
                              ARCHIVE DESTINATION ${INSTALL_LIB_DIR})
   endif()
 endif()
 
-if(NOT DEFINED DISABLE_STATIC)
+if(NOT DISABLE_STATIC)
   add_library(sqstdlib_static STATIC ${SQSTDLIB_SRC})
-  if(NOT DEFINED SQ_DISABLE_INSTALLER)
+  if(NOT SQ_DISABLE_INSTALLER)
     install(TARGETS sqstdlib_static ARCHIVE DESTINATION ${INSTALL_LIB_DIR})
   endif()
 endif()
 
-if(DEFINED LONG_OUTPUT_NAMES)
-  if(NOT DEFINED DISABLE_DYNAMIC)
+if(LONG_OUTPUT_NAMES)
+  if(NOT DISABLE_DYNAMIC)
     set_target_properties(sqstdlib PROPERTIES OUTPUT_NAME sqstdlib3)
   endif()
 
-  if(NOT DEFINED DISABLE_STATIC)
+  if(NOT DISABLE_STATIC)
     set_target_properties(sqstdlib_static PROPERTIES OUTPUT_NAME sqstdlib3_static)
   endif()
 endif()

+ 4 - 3
sqstdlib/Makefile

@@ -1,6 +1,7 @@
 SQUIRREL= ..
 
 
+CC?= gcc
 OUT?= $(SQUIRREL)/lib/libsqstdlib.a
 INCZ?= -I$(SQUIRREL)/include -I. -Iinclude
 DEFS= $(CC_EXTRA_FLAGS)
@@ -28,16 +29,16 @@ SRCS= \
 
 
 sq32:
-	gcc -O2 -fno-exceptions -fno-rtti -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) $(DEFS)
+	$(CC) -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)
+	$(CC) -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 -fno-exceptions -D_SQ64 -fno-rtti -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) $(DEFS)
+	$(CC) -O2 -m64 -fno-exceptions -D_SQ64 -fno-rtti -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) $(DEFS)
 	ar rc $(OUT) *.o
 	rm *.o

+ 7 - 1
sqstdlib/sqstdblob.cpp

@@ -82,6 +82,12 @@ static SQInteger _blob__get(HSQUIRRELVM v)
 {
     SETUP_BLOB(v);
     SQInteger idx;
+	
+	if ((sq_gettype(v, 2) & SQOBJECT_NUMERIC) == 0)
+	{
+		sq_pushnull(v);
+		return sq_throwobject(v);
+	}
     sq_getinteger(v,2,&idx);
     if(idx < 0 || idx >= self->Len())
         return sq_throwerror(v,_SC("index out of range"));
@@ -168,7 +174,7 @@ static const SQRegFunction _blob_methods[] = {
     _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(_get,2,_SC("x.")),
     _DECL_BLOB_FUNC(_typeof,1,_SC("x")),
     _DECL_BLOB_FUNC(_nexti,2,_SC("x")),
     _DECL_BLOB_FUNC(_cloned,2,_SC("xx")),

+ 1 - 1
sqstdlib/sqstdblobimpl.h

@@ -88,7 +88,7 @@ struct SQBlob : public SQStream
         return 0;
     }
     bool IsValid() {
-        return _buf?true:false;
+        return _size == 0 || _buf?true:false;
     }
     bool EOS() {
         return _ptr == _size;

+ 7 - 7
squirrel/CMakeLists.txt

@@ -11,28 +11,28 @@ set(SQUIRREL_SRC sqapi.cpp
                  sqtable.cpp
                  sqvm.cpp)
 
-if(NOT DEFINED DISABLE_DYNAMIC)
+if(NOT DISABLE_DYNAMIC)
   add_library(squirrel SHARED ${SQUIRREL_SRC})
-  if(NOT DEFINED SQ_DISABLE_INSTALLER)
+  if(NOT SQ_DISABLE_INSTALLER)
     install(TARGETS squirrel RUNTIME DESTINATION ${INSTALL_BIN_DIR}
                          LIBRARY DESTINATION ${INSTALL_LIB_DIR}
                          ARCHIVE DESTINATION ${INSTALL_LIB_DIR})
   endif()
 endif()
 
-if(NOT DEFINED DISABLE_STATIC)
+if(NOT DISABLE_STATIC)
   add_library(squirrel_static STATIC ${SQUIRREL_SRC})
-  if(NOT DEFINED SQ_DISABLE_INSTALLER)
+  if(NOT SQ_DISABLE_INSTALLER)
     install(TARGETS squirrel_static ARCHIVE DESTINATION ${INSTALL_LIB_DIR})
   endif()
 endif()
 
-if(DEFINED LONG_OUTPUT_NAMES)
-  if(NOT DEFINED DISABLE_DYNAMIC)
+if(LONG_OUTPUT_NAMES)
+  if(NOT DISABLE_DYNAMIC)
     set_target_properties(squirrel PROPERTIES OUTPUT_NAME squirrel3)
   endif()
 
-  if(NOT DEFINED DISABLE_STATIC)
+  if(NOT DISABLE_STATIC)
     set_target_properties(squirrel_static PROPERTIES OUTPUT_NAME squirrel3_static)
   endif()
 endif()

+ 4 - 3
squirrel/Makefile

@@ -1,6 +1,7 @@
 SQUIRREL= ..
 
 
+CC?= gcc
 OUT?= $(SQUIRREL)/lib/libsquirrel.a
 INCZ?= -I$(SQUIRREL)/include -I. -Iinclude
 DEFS= $(CC_EXTRA_FLAGS)
@@ -37,16 +38,16 @@ SRCS= \
 
 
 sq32:
-	gcc -O2 -fno-exceptions -fno-rtti -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) $(DEFS)
+	$(CC) -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)
+	$(CC) -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)
+	$(CC) -O2 -m64 -D_SQ64 -fno-exceptions -fno-rtti -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) $(DEFS)
 	ar rc $(OUT) *.o
 	rm *.o

+ 32 - 7
squirrel/sqapi.cpp

@@ -394,21 +394,21 @@ void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars)
     v->Push(SQObjectPtr(nc));
 }
 
-SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger *nparams,SQUnsignedInteger *nfreevars)
+SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQInteger *nparams,SQInteger *nfreevars)
 {
     SQObject o = stack_get(v, idx);
     if(sq_type(o) == OT_CLOSURE) {
         SQClosure *c = _closure(o);
         SQFunctionProto *proto = c->_function;
-        *nparams = (SQUnsignedInteger)proto->_nparameters;
-        *nfreevars = (SQUnsignedInteger)proto->_noutervalues;
+        *nparams = proto->_nparameters;
+        *nfreevars = proto->_noutervalues;
         return SQ_OK;
     }
     else if(sq_type(o) == OT_NATIVECLOSURE)
     {
         SQNativeClosure *c = _nativeclosure(o);
-        *nparams = (SQUnsignedInteger)c->_nparamscheck;
-        *nfreevars = c->_noutervalues;
+        *nparams = c->_nparamscheck;
+        *nfreevars = (SQInteger)c->_noutervalues;
         return SQ_OK;
     }
     return sq_throwerror(v,_SC("the object is not a closure"));
@@ -947,8 +947,11 @@ SQRESULT sq_newmember(HSQUIRRELVM v,SQInteger idx,SQBool bstatic)
     if(sq_type(self) != OT_CLASS) return sq_throwerror(v, _SC("new member only works with classes"));
     SQObjectPtr &key = v->GetUp(-3);
     if(sq_type(key) == OT_NULL) return sq_throwerror(v, _SC("null key"));
-    if(!v->NewSlotA(self,key,v->GetUp(-2),v->GetUp(-1),bstatic?true:false,false))
+    if(!v->NewSlotA(self,key,v->GetUp(-2),v->GetUp(-1),bstatic?true:false,false)) {
+        v->Pop(3);
         return SQ_ERROR;
+    }
+    v->Pop(3);
     return SQ_OK;
 }
 
@@ -958,8 +961,11 @@ SQRESULT sq_rawnewmember(HSQUIRRELVM v,SQInteger idx,SQBool bstatic)
     if(sq_type(self) != OT_CLASS) return sq_throwerror(v, _SC("new member only works with classes"));
     SQObjectPtr &key = v->GetUp(-3);
     if(sq_type(key) == OT_NULL) return sq_throwerror(v, _SC("null key"));
-    if(!v->NewSlotA(self,key,v->GetUp(-2),v->GetUp(-1),bstatic?true:false,true))
+    if(!v->NewSlotA(self,key,v->GetUp(-2),v->GetUp(-1),bstatic?true:false,true)) {
+        v->Pop(3);
         return SQ_ERROR;
+    }
+    v->Pop(3);
     return SQ_OK;
 }
 
@@ -1188,6 +1194,25 @@ SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror)
     return sq_throwerror(v,_SC("call failed"));
 }
 
+SQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams)
+{
+	SQObjectPtr &res = v->GetUp(-(nparams + 1));
+	if (sq_type(res) != OT_CLOSURE) {
+		return sq_throwerror(v, _SC("only closure can be tail called"));
+	}
+	SQClosure *clo = _closure(res);
+	if (clo->_function->_bgenerator)
+	{
+		return sq_throwerror(v, _SC("generators cannot be tail called"));
+	}
+	
+	SQInteger stackbase = (v->_top - nparams) - v->_stackbase;
+	if (!v->TailCall(clo, stackbase, nparams)) {
+		return SQ_ERROR;
+	}
+	return SQ_TAILCALL_FLAG;
+}
+
 SQRESULT sq_suspendvm(HSQUIRRELVM v)
 {
     return v->Suspend();

+ 63 - 13
squirrel/sqbaselib.cpp

@@ -156,7 +156,14 @@ static SQInteger base_getstackinfos(HSQUIRRELVM v)
 static SQInteger base_assert(HSQUIRRELVM v)
 {
     if(SQVM::IsFalse(stack_get(v,2))){
-        return sq_throwerror(v,_SC("assertion failed"));
+        SQInteger top = sq_gettop(v);
+        if (top>2 && SQ_SUCCEEDED(sq_tostring(v,3))) {
+            const SQChar *str = 0;
+            if (SQ_SUCCEEDED(sq_getstring(v,-1,&str))) {
+                return sq_throwerror(v, str);
+            }
+        }
+        return sq_throwerror(v, _SC("assertion failed"));
     }
     return 0;
 }
@@ -283,7 +290,7 @@ static const SQRegFunction base_funcs[]={
     {_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("assert"),base_assert,-2, NULL},
     {_SC("print"),base_print,2, NULL},
     {_SC("error"),base_error,2, NULL},
     {_SC("compilestring"),base_compilestring,-2, _SC(".ss")},
@@ -406,7 +413,7 @@ static SQInteger obj_delegate_weakref(HSQUIRRELVM v)
 
 static SQInteger obj_clear(HSQUIRRELVM v)
 {
-    return sq_clear(v,-1);
+    return SQ_SUCCEEDED(sq_clear(v,-1)) ? 1 : SQ_ERROR;
 }
 
 
@@ -443,7 +450,7 @@ static SQInteger container_rawexists(HSQUIRRELVM v)
 
 static SQInteger container_rawset(HSQUIRRELVM v)
 {
-    return sq_rawset(v,-3);
+    return SQ_SUCCEEDED(sq_rawset(v,-3)) ? 1 : SQ_ERROR;
 }
 
 
@@ -465,6 +472,34 @@ static SQInteger table_getdelegate(HSQUIRRELVM v)
     return SQ_SUCCEEDED(sq_getdelegate(v,-1))?1:SQ_ERROR;
 }
 
+static SQInteger table_filter(HSQUIRRELVM v)
+{
+    SQObject &o = stack_get(v,1);
+    SQTable *tbl = _table(o);
+    SQObjectPtr ret = SQTable::Create(_ss(v),0);
+
+    SQObjectPtr itr, key, val;
+    SQInteger nitr;
+    while((nitr = tbl->Next(false, itr, key, val)) != -1) {
+        itr = (SQInteger)nitr;
+
+        v->Push(o);
+        v->Push(key);
+        v->Push(val);
+        if(SQ_FAILED(sq_call(v,3,SQTrue,SQFalse))) {
+            return SQ_ERROR;
+        }
+        if(!SQVM::IsFalse(v->GetUp(-1))) {
+            _table(ret)->NewSlot(key, val);
+        }
+        v->Pop();
+    }
+
+    v->Push(ret);
+    return 1;
+}
+
+
 const SQRegFunction SQSharedState::_table_default_delegate_funcz[]={
     {_SC("len"),default_delegate_len,1, _SC("t")},
     {_SC("rawget"),container_rawget,2, _SC("t")},
@@ -476,6 +511,7 @@ const SQRegFunction SQSharedState::_table_default_delegate_funcz[]={
     {_SC("clear"),obj_clear,1, _SC(".")},
     {_SC("setdelegate"),table_setdelegate,2, _SC(".t|o")},
     {_SC("getdelegate"),table_getdelegate,1, _SC(".")},
+    {_SC("filter"),table_filter,2, _SC("tc")},
     {NULL,(SQFUNCTION)0,0,NULL}
 };
 
@@ -483,18 +519,19 @@ const SQRegFunction SQSharedState::_table_default_delegate_funcz[]={
 
 static SQInteger array_append(HSQUIRRELVM v)
 {
-    return sq_arrayappend(v,-2);
+    return SQ_SUCCEEDED(sq_arrayappend(v,-2)) ? 1 : SQ_ERROR;
 }
 
 static SQInteger array_extend(HSQUIRRELVM v)
 {
     _array(stack_get(v,1))->Extend(_array(stack_get(v,2)));
-    return 0;
+    sq_pop(v,1);
+    return 1;
 }
 
 static SQInteger array_reverse(HSQUIRRELVM v)
 {
-    return sq_arrayreverse(v,-1);
+    return SQ_SUCCEEDED(sq_arrayreverse(v,-1)) ? 1 : SQ_ERROR;
 }
 
 static SQInteger array_pop(HSQUIRRELVM v)
@@ -519,7 +556,8 @@ static SQInteger array_insert(HSQUIRRELVM v)
     SQObject &val=stack_get(v,3);
     if(!_array(o)->Insert(tointeger(idx),val))
         return sq_throwerror(v,_SC("index out of range"));
-    return 0;
+    sq_pop(v,2);
+    return 1;
 }
 
 static SQInteger array_remove(HSQUIRRELVM v)
@@ -542,10 +580,15 @@ static SQInteger array_resize(HSQUIRRELVM v)
     SQObject &nsize = stack_get(v, 2);
     SQObjectPtr fill;
     if(sq_isnumeric(nsize)) {
+        SQInteger sz = tointeger(nsize);
+        if (sz<0)
+          return sq_throwerror(v, _SC("resizing to negative length"));
+
         if(sq_gettop(v) > 2)
             fill = stack_get(v, 3);
-        _array(o)->Resize(tointeger(nsize),fill);
-        return 0;
+        _array(o)->Resize(sz,fill);
+        sq_settop(v, 1);
+        return 1;
     }
     return sq_throwerror(v, _SC("size must be a number"));
 }
@@ -582,7 +625,8 @@ 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;
+    sq_pop(v,1);
+    return 1;
 }
 
 static SQInteger array_reduce(HSQUIRRELVM v)
@@ -749,7 +793,8 @@ static SQInteger array_sort(HSQUIRRELVM v)
             return SQ_ERROR;
 
     }
-    return 0;
+    sq_settop(v,1);
+    return 1;
 }
 
 static SQInteger array_slice(HSQUIRRELVM v)
@@ -885,7 +930,12 @@ static SQInteger closure_pcall(HSQUIRRELVM v)
 
 static SQInteger closure_call(HSQUIRRELVM v)
 {
-    return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQTrue))?1:SQ_ERROR;
+	SQObjectPtr &c = stack_get(v, -1);
+	if (sq_type(c) == OT_CLOSURE && (_closure(c)->_function->_bgenerator == false))
+	{
+		return sq_tailcall(v, sq_gettop(v) - 1);
+	}
+	return SQ_SUCCEEDED(sq_call(v, sq_gettop(v) - 1, SQTrue, SQTrue)) ? 1 : SQ_ERROR;
 }
 
 static SQInteger _closure_acall(HSQUIRRELVM v,SQBool raiseerror)

+ 23 - 22
squirrel/sqcompiler.cpp

@@ -443,8 +443,8 @@ public:
             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->SetInstructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
+            _fs->SetInstructionParam(jzpos, 1, endfirstexp - jzpos + 1);
             _fs->SnoozeOpt();
             }
             break;
@@ -482,7 +482,7 @@ public:
             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));
+            _fs->SetInstructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
             _es.etype = EXPR;
             break;
         }else return;
@@ -502,7 +502,7 @@ public:
             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));
+            _fs->SetInstructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
             _es.etype = EXPR;
             break;
             }
@@ -834,7 +834,7 @@ public:
                     _fs->AddInstruction(_OP_APPENDARRAY, array, val, AAT_STACK);
                     key++;
                 }
-                _fs->SetIntructionParam(apos, 1, key);
+                _fs->SetInstructionParam(apos, 1, key);
                 Lex();
             }
             break;
@@ -1002,7 +1002,7 @@ public:
             }
         }
         if(separator == _SC(',')) //hack recognizes a table from the separator
-            _fs->SetIntructionParam(tpos, 1, nkeys);
+            _fs->SetInstructionParam(tpos, 1, nkeys);
         Lex();
     }
     void LocalDeclStatement()
@@ -1092,9 +1092,9 @@ public:
             //Statement(); if(_lex._prevtoken != _SC('}')) OptionalSemicolon();
             IfBlock();
             //END_SCOPE();
-            _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
+            _fs->SetInstructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
         }
-        _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));
+        _fs->SetInstructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));
     }
     void WhileStatement()
     {
@@ -1111,7 +1111,7 @@ public:
 
         END_SCOPE();
         _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
-        _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
+        _fs->SetInstructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
 
         END_BREAKBLE_BLOCK(jmppos);
     }
@@ -1170,10 +1170,11 @@ public:
                 _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();
-
+        if(jzpos>  0) _fs->SetInstructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
+        
         END_BREAKBLE_BLOCK(continuetrg);
+
+		END_SCOPE();
     }
     void ForEachStatement()
     {
@@ -1210,8 +1211,8 @@ public:
         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);
+        _fs->SetInstructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);
+        _fs->SetInstructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos);
         END_BREAKBLE_BLOCK(foreachpos - 1);
         //restore the local variable stack(remove index,val and ref idx)
         _fs->PopTarget();
@@ -1231,7 +1232,7 @@ public:
             if(!bfirst) {
                 _fs->AddInstruction(_OP_JMP, 0, 0);
                 skipcondjmp = _fs->GetCurrentPos();
-                _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
+                _fs->SetInstructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
             }
             //condition
             Lex(); Expression(); Expect(_SC(':'));
@@ -1249,7 +1250,7 @@ public:
 
             //end condition
             if(skipcondjmp != -1) {
-                _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));
+                _fs->SetInstructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));
             }
             tonextcondjmp = _fs->GetCurrentPos();
             BEGIN_SCOPE();
@@ -1258,7 +1259,7 @@ public:
             bfirst = false;
         }
         if(tonextcondjmp != -1)
-            _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
+            _fs->SetInstructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
         if(_token == TK_DEFAULT) {
             Lex(); Expect(_SC(':'));
             BEGIN_SCOPE();
@@ -1402,14 +1403,14 @@ public:
         if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;
         _fs->AddInstruction(_OP_JMP, 0, 0);
         SQInteger jmppos = _fs->GetCurrentPos();
-        _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));
+        _fs->SetInstructionParam(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);
+            _fs->SetInstructionParam(trappos, 0, ex_target);
             Statement();
-            _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
+            _fs->SetInstructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
             END_SCOPE();
         }
     }
@@ -1547,7 +1548,7 @@ public:
             SQInteger pos = funcstate->_unresolvedbreaks.back();
             funcstate->_unresolvedbreaks.pop_back();
             //set the jmp instruction
-            funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);
+            funcstate->SetInstructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);
             ntoresolve--;
         }
     }
@@ -1557,7 +1558,7 @@ public:
             SQInteger pos = funcstate->_unresolvedcontinues.back();
             funcstate->_unresolvedcontinues.pop_back();
             //set the jmp instruction
-            funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0);
+            funcstate->SetInstructionParams(pos, 0, targetpos - pos, 0);
             ntoresolve--;
         }
     }

+ 3 - 3
squirrel/sqfuncstate.cpp

@@ -120,7 +120,7 @@ void SQFuncState::Dump(SQFunctionProto *func)
     scprintf(_SC("SQInstruction sizeof %d\n"),(SQInt32)sizeof(SQInstruction));
     scprintf(_SC("SQObject sizeof %d\n"), (SQInt32)sizeof(SQObject));
     scprintf(_SC("--------------------------------------------------------------------\n"));
-    scprintf(_SC("*****FUNCTION [%s]\n"),type(func->_name)==OT_STRING?_stringval(func->_name):_SC("unknown"));
+    scprintf(_SC("*****FUNCTION [%s]\n"),sq_type(func->_name)==OT_STRING?_stringval(func->_name):_SC("unknown"));
     scprintf(_SC("-----LITERALS\n"));
     SQObjectPtr refidx,key,val;
     SQInteger idx;
@@ -238,7 +238,7 @@ SQInteger SQFuncState::GetConstant(const SQObject &cons)
     return _integer(val);
 }
 
-void SQFuncState::SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3)
+void SQFuncState::SetInstructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3)
 {
     _instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&arg0);
     _instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&arg1);
@@ -246,7 +246,7 @@ void SQFuncState::SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg
     _instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&arg3);
 }
 
-void SQFuncState::SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val)
+void SQFuncState::SetInstructionParam(SQInteger pos,SQInteger arg,SQInteger val)
 {
     switch(arg){
         case 0:_instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&val);break;

+ 2 - 2
squirrel/sqfuncstate.h

@@ -16,8 +16,8 @@ struct SQFuncState
     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);
+    void SetInstructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2=0,SQInteger arg3=0);
+    void SetInstructionParam(SQInteger pos,SQInteger arg,SQInteger val);
     SQInstruction &GetInstruction(SQInteger pos){return _instructions[pos];}
     void PopInstructions(SQInteger size){for(SQInteger i=0;i<size;i++)_instructions.pop_back();}
     void SetStackSize(SQInteger n);

+ 1 - 1
squirrel/sqlexer.cpp

@@ -383,7 +383,7 @@ SQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim)
                     break;
                     case _SC('U'):
                     case _SC('u'):  {
-                        const SQInteger maxdigits = x == 'u' ? 4 : 8;
+                        const SQInteger maxdigits = CUR_CHAR == 'u' ? 4 : 8;
                         SQChar temp[8 + 1];
                         ProcessStringHexEscape(temp, maxdigits);
                         SQChar *stemp;

+ 2 - 2
squirrel/sqobject.cpp

@@ -285,7 +285,7 @@ bool SafeWrite(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUserPointer de
     return true;
 }
 
-bool SafeRead(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQUserPointer dest,SQInteger size)
+bool SafeRead(HSQUIRRELVM v,SQREADFUNC 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"));
@@ -299,7 +299,7 @@ bool WriteTag(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUnsignedInteger
     return SafeWrite(v,write,up,&tag,sizeof(tag));
 }
 
-bool CheckTag(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQUnsignedInteger32 tag)
+bool CheckTag(HSQUIRRELVM v,SQREADFUNC read,SQUserPointer up,SQUnsignedInteger32 tag)
 {
     SQUnsignedInteger32 t;
     _CHECK_IO(SafeRead(v,read,up,&t,sizeof(t)));

+ 38 - 12
squirrel/sqvm.cpp

@@ -383,7 +383,8 @@ bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQIntege
     {
         paramssize--;
         if (nargs < paramssize) {
-            Raise_Error(_SC("wrong number of parameters"));
+            Raise_Error(_SC("wrong number of parameters (%d passed, at least %d required)"),
+              (int)nargs, (int)paramssize);
             return false;
         }
 
@@ -409,7 +410,8 @@ bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQIntege
             }
         }
         else {
-            Raise_Error(_SC("wrong number of parameters"));
+            Raise_Error(_SC("wrong number of parameters (%d passed, %d required)"),
+              (int)nargs, (int)paramssize);
             return false;
         }
     }
@@ -744,7 +746,8 @@ exception_restore:
                         continue;
                     case OT_NATIVECLOSURE: {
                         bool suspend;
-                        _GUARD(CallNative(_nativeclosure(clo), arg3, _stackbase+arg2, clo,suspend));
+						bool tailcall;
+                        _GUARD(CallNative(_nativeclosure(clo), arg3, _stackbase+arg2, clo, (SQInt32)sarg0, suspend, tailcall));
                         if(suspend){
                             _suspended = SQTrue;
                             _suspended_target = sarg0;
@@ -753,7 +756,7 @@ exception_restore:
                             outres = clo;
                             return true;
                         }
-                        if(sarg0 != -1) {
+                        if(sarg0 != -1 && !tailcall) {
                             STK(arg0) = clo;
                         }
                                            }
@@ -772,10 +775,10 @@ exception_restore:
                                 _GUARD(StartCall(_closure(clo), -1, arg3, stkbase, false));
                                 break;
                             case OT_NATIVECLOSURE:
-                                bool suspend;
+                                bool dummy;
                                 stkbase = _stackbase+arg2;
                                 _stack._vals[stkbase] = inst;
-                                _GUARD(CallNative(_nativeclosure(clo), arg3, stkbase, clo,suspend));
+                                _GUARD(CallNative(_nativeclosure(clo), arg3, stkbase, clo, -1, dummy, dummy));
                                 break;
                             default: break; //shutup GCC 4.x
                         }
@@ -1139,7 +1142,7 @@ void SQVM::CallDebugHook(SQInteger type,SQInteger forcedline)
     _debughook = true;
 }
 
-bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, bool &suspend)
+bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, SQInt32 target,bool &suspend, bool &tailcall)
 {
     SQInteger nparamscheck = nclosure->_nparamscheck;
     SQInteger newtop = newbase + nargs + nclosure->_noutervalues;
@@ -1169,6 +1172,7 @@ bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newb
 
     if(!EnterFrame(newbase, newtop, false)) return false;
     ci->_closure  = nclosure;
+	ci->_target = target;
 
     SQInteger outers = nclosure->_noutervalues;
     for (SQInteger i = 0; i < outers; i++) {
@@ -1183,7 +1187,12 @@ bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newb
     _nnativecalls--;
 
     suspend = false;
-    if (ret == SQ_SUSPEND_FLAG) {
+	tailcall = false;
+	if (ret == SQ_TAILCALL_FLAG) {
+		tailcall = true;
+		return true;
+	}
+    else if (ret == SQ_SUSPEND_FLAG) {
         suspend = true;
     }
     else if (ret < 0) {
@@ -1202,6 +1211,23 @@ bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newb
     return true;
 }
 
+bool SQVM::TailCall(SQClosure *closure, SQInteger parambase,SQInteger nparams)
+{
+	SQInteger last_top = _top;
+	SQObjectPtr clo = closure;
+	if (ci->_root)
+	{
+		Raise_Error("root calls cannot invoke tailcalls");
+		return false;
+	}
+	for (SQInteger i = 0; i < nparams; i++) STK(i) = STK(parambase + i);
+	bool ret = StartCall(closure, ci->_target, nparams, _stackbase, true);
+	if (last_top >= _top) {
+		_top = last_top;
+	}
+	return ret;
+}
+
 #define FALLBACK_OK         0
 #define FALLBACK_NO_MATCH   1
 #define FALLBACK_ERROR      2
@@ -1334,7 +1360,7 @@ bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr
             return false;
         }
         return true;
-    case OT_USERDATA: break; // must fall back
+  	case OT_USERDATA: break; // must fall back
     default:
         Raise_Error(_SC("trying to set '%s'"),GetTypeName(self));
         return false;
@@ -1551,8 +1577,8 @@ SQInteger prevstackbase = _stackbase;
         return Execute(closure, nparams, stackbase, outres, raiseerror);
         break;
     case OT_NATIVECLOSURE:{
-        bool suspend;
-        return CallNative(_nativeclosure(closure), nparams, stackbase, outres,suspend);
+        bool dummy;
+        return CallNative(_nativeclosure(closure), nparams, stackbase, outres, -1, dummy, dummy);
 
                           }
         break;
@@ -1723,7 +1749,7 @@ void SQVM::dumpstack(SQInteger stackbase,bool dumpall)
         SQObjectPtr &obj=_stack[i];
         if(stackbase==i)scprintf(_SC(">"));else scprintf(_SC(" "));
         scprintf(_SC("[" _PRINT_INT_FMT "]:"),n);
-        switch(type(obj)){
+        switch(sq_type(obj)){
         case OT_FLOAT:          scprintf(_SC("FLOAT %.3f"),_float(obj));break;
         case OT_INTEGER:        scprintf(_SC("INTEGER " _PRINT_INT_FMT),_integer(obj));break;
         case OT_BOOL:           scprintf(_SC("BOOL %s"),_integer(obj)?"true":"false");break;

+ 3 - 1
squirrel/sqvm.h

@@ -8,6 +8,7 @@
 #define MIN_STACK_OVERHEAD 15
 
 #define SQ_SUSPEND_FLAG -666
+#define SQ_TAILCALL_FLAG -777
 #define DONT_FALL_BACK 666
 //#define EXISTS_FALL_BACK -1
 
@@ -56,7 +57,8 @@ public:
     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);
+    bool CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, SQInt32 target, bool &suspend,bool &tailcall);
+	bool TailCall(SQClosure *closure, SQInteger firstparam, SQInteger nparams);
     //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);