diff options
-rw-r--r-- | COPYRIGHT | 34 | ||||
-rw-r--r-- | HISTORY | 183 | ||||
-rw-r--r-- | INSTALL | 99 | ||||
-rw-r--r-- | Makefile | 43 | ||||
-rw-r--r-- | README | 39 | ||||
-rw-r--r-- | doc/Makefile | 9 | ||||
-rw-r--r-- | doc/alert.png | bin | 0 -> 1411 bytes | |||
-rw-r--r-- | doc/contents.html | 34 | ||||
-rw-r--r-- | doc/external.png | bin | 0 -> 165 bytes | |||
-rw-r--r-- | doc/lua.1 | 163 | ||||
-rw-r--r-- | doc/lua.html | 172 | ||||
-rw-r--r-- | doc/luac.1 | 136 | ||||
-rw-r--r-- | doc/luac.html | 145 | ||||
-rw-r--r-- | doc/manual.css | 13 | ||||
-rw-r--r-- | doc/manual.html | 1613 | ||||
-rw-r--r-- | doc/osi-certified-72x60.png | bin | 0 -> 3774 bytes | |||
-rw-r--r-- | doc/readme.html | 341 | ||||
-rw-r--r-- | etc/README | 12 | ||||
-rw-r--r-- | etc/all.c | 39 | ||||
-rw-r--r-- | etc/lua.ico | bin | 1078 -> 0 bytes | |||
-rw-r--r-- | etc/lua.pc | 31 | ||||
-rw-r--r-- | etc/min.c | 23 | ||||
-rw-r--r-- | etc/noparser.c | 40 | ||||
-rw-r--r-- | src/Makefile | 79 | ||||
-rw-r--r-- | src/lapi.c | 507 | ||||
-rw-r--r-- | src/lapi.h | 14 | ||||
-rw-r--r-- | src/lauxlib.c | 567 | ||||
-rw-r--r-- | src/lauxlib.h | 27 | ||||
-rw-r--r-- | src/lbaselib.c | 407 | ||||
-rw-r--r-- | src/lbitlib.c | 123 | ||||
-rw-r--r-- | src/lcode.c | 253 | ||||
-rw-r--r-- | src/lcode.h | 13 | ||||
-rw-r--r-- | src/lctype.c | 45 | ||||
-rw-r--r-- | src/lctype.h | 50 | ||||
-rw-r--r-- | src/ldblib.c | 112 | ||||
-rw-r--r-- | src/ldebug.c | 498 | ||||
-rw-r--r-- | src/ldebug.h | 6 | ||||
-rw-r--r-- | src/ldo.c | 564 | ||||
-rw-r--r-- | src/ldo.h | 28 | ||||
-rw-r--r-- | src/ldump.c | 22 | ||||
-rw-r--r-- | src/lfunc.c | 58 | ||||
-rw-r--r-- | src/lfunc.h | 2 | ||||
-rw-r--r-- | src/lgc.c | 832 | ||||
-rw-r--r-- | src/lgc.h | 55 | ||||
-rw-r--r-- | src/linit.c | 49 | ||||
-rw-r--r-- | src/liolib.c | 86 | ||||
-rw-r--r-- | src/llex.c | 191 | ||||
-rw-r--r-- | src/llex.h | 14 | ||||
-rw-r--r-- | src/llimits.h | 96 | ||||
-rw-r--r-- | src/lmathlib.c | 38 | ||||
-rw-r--r-- | src/lmem.c | 41 | ||||
-rw-r--r-- | src/lmem.h | 13 | ||||
-rw-r--r-- | src/loadlib.c | 190 | ||||
-rw-r--r-- | src/lobject.c | 118 | ||||
-rw-r--r-- | src/lobject.h | 111 | ||||
-rw-r--r-- | src/lopcodes.c | 16 | ||||
-rw-r--r-- | src/lopcodes.h | 103 | ||||
-rw-r--r-- | src/loslib.c | 85 | ||||
-rw-r--r-- | src/lparser.c | 371 | ||||
-rw-r--r-- | src/lparser.h | 29 | ||||
-rw-r--r-- | src/lstate.c | 212 | ||||
-rw-r--r-- | src/lstate.h | 114 | ||||
-rw-r--r-- | src/lstring.c | 70 | ||||
-rw-r--r-- | src/lstring.h | 2 | ||||
-rw-r--r-- | src/lstrlib.c | 196 | ||||
-rw-r--r-- | src/ltable.c | 101 | ||||
-rw-r--r-- | src/ltable.h | 11 | ||||
-rw-r--r-- | src/ltablib.c | 120 | ||||
-rw-r--r-- | src/ltm.c | 8 | ||||
-rw-r--r-- | src/ltm.h | 6 | ||||
-rw-r--r-- | src/lua.c | 230 | ||||
-rw-r--r-- | src/lua.h | 189 | ||||
-rw-r--r-- | src/lua.hpp (renamed from etc/lua.hpp) | 0 | ||||
-rw-r--r-- | src/luac.c | 25 | ||||
-rw-r--r-- | src/luaconf.h | 546 | ||||
-rw-r--r-- | src/lualib.h | 23 | ||||
-rw-r--r-- | src/lundump.c | 36 | ||||
-rw-r--r-- | src/lundump.h | 2 | ||||
-rw-r--r-- | src/lvm.c | 519 | ||||
-rw-r--r-- | src/lvm.h | 22 | ||||
-rw-r--r-- | src/lzio.c | 2 | ||||
-rw-r--r-- | src/lzio.h | 5 | ||||
-rw-r--r-- | src/print.c | 41 | ||||
-rw-r--r-- | test/ALL.lua | 26 | ||||
-rw-r--r-- | test/sieve.lua | 2 | ||||
-rw-r--r-- | test/xd.lua | 7 |
86 files changed, 6356 insertions, 5141 deletions
diff --git a/COPYRIGHT b/COPYRIGHT deleted file mode 100644 index 3a53e741..00000000 --- a/COPYRIGHT +++ /dev/null @@ -1,34 +0,0 @@ -Lua License ------------ - -Lua is licensed under the terms of the MIT license reproduced below. -This means that Lua is free software and can be used for both academic -and commercial purposes at absolutely no cost. - -For details and rationale, see http://www.lua.org/license.html . - -=============================================================================== - -Copyright (C) 1994-2008 Lua.org, PUC-Rio. - -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/HISTORY b/HISTORY deleted file mode 100644 index ce0c95bc..00000000 --- a/HISTORY +++ /dev/null @@ -1,183 +0,0 @@ -HISTORY for Lua 5.1 - -* Changes from version 5.0 to 5.1 - ------------------------------- - Language: - + new module system. - + new semantics for control variables of fors. - + new semantics for setn/getn. - + new syntax/semantics for varargs. - + new long strings and comments. - + new `mod' operator (`%') - + new length operator #t - + metatables for all types - API: - + new functions: lua_createtable, lua_get(set)field, lua_push(to)integer. - + user supplies memory allocator (lua_open becomes lua_newstate). - + luaopen_* functions must be called through Lua. - Implementation: - + new configuration scheme via luaconf.h. - + incremental garbage collection. - + better handling of end-of-line in the lexer. - + fully reentrant parser (new Lua function `load') - + better support for 64-bit machines. - + native loadlib support for Mac OS X. - + standard distribution in only one library (lualib.a merged into lua.a) - -* Changes from version 4.0 to 5.0 - ------------------------------- - Language: - + lexical scoping. - + Lua coroutines. - + standard libraries now packaged in tables. - + tags replaced by metatables and tag methods replaced by metamethods, - stored in metatables. - + proper tail calls. - + each function can have its own global table, which can be shared. - + new __newindex metamethod, called when we insert a new key into a table. - + new block comments: --[[ ... ]]. - + new generic for. - + new weak tables. - + new boolean type. - + new syntax "local function". - + (f()) returns the first value returned by f. - + {f()} fills a table with all values returned by f. - + \n ignored in [[\n . - + fixed and-or priorities. - + more general syntax for function definition (e.g. function a.x.y:f()...end). - + more general syntax for function calls (e.g. (print or write)(9)). - + new functions (time/date, tmpfile, unpack, require, load*, etc.). - API: - + chunks are loaded by using lua_load; new luaL_loadfile and luaL_loadbuffer. - + introduced lightweight userdata, a simple "void*" without a metatable. - + new error handling protocol: the core no longer prints error messages; - all errors are reported to the caller on the stack. - + new lua_atpanic for host cleanup. - + new, signal-safe, hook scheme. - Implementation: - + new license: MIT. - + new, faster, register-based virtual machine. - + support for external multithreading and coroutines. - + new and consistent error message format. - + the core no longer needs "stdio.h" for anything (except for a single - use of sprintf to convert numbers to strings). - + lua.c now runs the environment variable LUA_INIT, if present. It can - be "@filename", to run a file, or the chunk itself. - + support for user extensions in lua.c. - sample implementation given for command line editing. - + new dynamic loading library, active by default on several platforms. - + safe garbage-collector metamethods. - + precompiled bytecodes checked for integrity (secure binary dostring). - + strings are fully aligned. - + position capture in string.find. - + read('*l') can read lines with embedded zeros. - -* Changes from version 3.2 to 4.0 - ------------------------------- - Language: - + new "break" and "for" statements (both numerical and for tables). - + uniform treatment of globals: globals are now stored in a Lua table. - + improved error messages. - + no more '$debug': full speed *and* full debug information. - + new read form: read(N) for next N bytes. - + general read patterns now deprecated. - (still available with -DCOMPAT_READPATTERNS.) - + all return values are passed as arguments for the last function - (old semantics still available with -DLUA_COMPAT_ARGRET) - + garbage collection tag methods for tables now deprecated. - + there is now only one tag method for order. - API: - + New API: fully re-entrant, simpler, and more efficient. - + New debug API. - Implementation: - + faster than ever: cleaner virtual machine and new hashing algorithm. - + non-recursive garbage-collector algorithm. - + reduced memory usage for programs with many strings. - + improved treatment for memory allocation errors. - + improved support for 16-bit machines (we hope). - + code now compiles unmodified as both ANSI C and C++. - + numbers in bases other than 10 are converted using strtoul. - + new -f option in Lua to support #! scripts. - + luac can now combine text and binaries. - -* Changes from version 3.1 to 3.2 - ------------------------------- - + redirected all output in Lua's core to _ERRORMESSAGE and _ALERT. - + increased limit on the number of constants and globals per function - (from 2^16 to 2^24). - + debugging info (lua_debug and hooks) moved into lua_state and new API - functions provided to get and set this info. - + new debug lib gives full debugging access within Lua. - + new table functions "foreachi", "sort", "tinsert", "tremove", "getn". - + new io functions "flush", "seek". - -* Changes from version 3.0 to 3.1 - ------------------------------- - + NEW FEATURE: anonymous functions with closures (via "upvalues"). - + new syntax: - - local variables in chunks. - - better scope control with DO block END. - - constructors can now be also written: { record-part; list-part }. - - more general syntax for function calls and lvalues, e.g.: - f(x).y=1 - o:f(x,y):g(z) - f"string" is sugar for f("string") - + strings may now contain arbitrary binary data (e.g., embedded zeros). - + major code re-organization and clean-up; reduced module interdependecies. - + no arbitrary limits on the total number of constants and globals. - + support for multiple global contexts. - + better syntax error messages. - + new traversal functions "foreach" and "foreachvar". - + the default for numbers is now double. - changing it to use floats or longs is easy. - + complete debug information stored in pre-compiled chunks. - + sample interpreter now prompts user when run interactively, and also - handles control-C interruptions gracefully. - -* Changes from version 2.5 to 3.0 - ------------------------------- - + NEW CONCEPT: "tag methods". - Tag methods replace fallbacks as the meta-mechanism for extending the - semantics of Lua. Whereas fallbacks had a global nature, tag methods - work on objects having the same tag (e.g., groups of tables). - Existing code that uses fallbacks should work without change. - + new, general syntax for constructors {[exp] = exp, ... }. - + support for handling variable number of arguments in functions (varargs). - + support for conditional compilation ($if ... $else ... $end). - + cleaner semantics in API simplifies host code. - + better support for writing libraries (auxlib.h). - + better type checking and error messages in the standard library. - + luac can now also undump. - -* Changes from version 2.4 to 2.5 - ------------------------------- - + io and string libraries are now based on pattern matching; - the old libraries are still available for compatibility - + dofile and dostring can now return values (via return statement) - + better support for 16- and 64-bit machines - + expanded documentation, with more examples - -* Changes from version 2.2 to 2.4 - ------------------------------- - + external compiler creates portable binary files that can be loaded faster - + interface for debugging and profiling - + new "getglobal" fallback - + new functions for handling references to Lua objects - + new functions in standard lib - + only one copy of each string is stored - + expanded documentation, with more examples - -* Changes from version 2.1 to 2.2 - ------------------------------- - + functions now may be declared with any "lvalue" as a name - + garbage collection of functions - + support for pipes - -* Changes from version 1.1 to 2.1 - ------------------------------- - + object-oriented support - + fallbacks - + simplified syntax for tables - + many internal improvements - -(end of HISTORY) diff --git a/INSTALL b/INSTALL deleted file mode 100644 index 17eb8aee..00000000 --- a/INSTALL +++ /dev/null @@ -1,99 +0,0 @@ -INSTALL for Lua 5.1 - -* Building Lua - ------------ - Lua is built in the src directory, but the build process can be - controlled from the top-level Makefile. - - Building Lua on Unix systems should be very easy. First do "make" and - see if your platform is listed. If so, just do "make xxx", where xxx - is your platform name. The platforms currently supported are: - aix ansi bsd freebsd generic linux macosx mingw posix solaris - - If your platform is not listed, try the closest one or posix, generic, - ansi, in this order. - - See below for customization instructions and for instructions on how - to build with other Windows compilers. - - If you want to check that Lua has been built correctly, do "make test" - after building Lua. Also, have a look at the example programs in test. - -* Installing Lua - -------------- - Once you have built Lua, you may want to install it in an official - place in your system. In this case, do "make install". The official - place and the way to install files are defined in Makefile. You must - have the right permissions to install files. - - If you want to build and install Lua in one step, do "make xxx install", - where xxx is your platform name. - - If you want to install Lua locally, then do "make local". This will - create directories bin, include, lib, man, and install Lua there as - follows: - - bin: lua luac - include: lua.h luaconf.h lualib.h lauxlib.h lua.hpp - lib: liblua.a - man/man1: lua.1 luac.1 - - These are the only directories you need for development. - - There are man pages for lua and luac, in both nroff and html, and a - reference manual in html in doc, some sample code in test, and some - useful stuff in etc. You don't need these directories for development. - - If you want to install Lua locally, but in some other directory, do - "make install INSTALL_TOP=xxx", where xxx is your chosen directory. - - See below for instructions for Windows and other systems. - -* Customization - ------------- - Three things can be customized by editing a file: - - Where and how to install Lua -- edit Makefile. - - How to build Lua -- edit src/Makefile. - - Lua features -- edit src/luaconf.h. - - You don't actually need to edit the Makefiles because you may set the - relevant variables when invoking make. - - On the other hand, if you need to select some Lua features, you'll need - to edit src/luaconf.h. The edited file will be the one installed, and - it will be used by any Lua clients that you build, to ensure consistency. - - We strongly recommend that you enable dynamic loading. This is done - automatically for all platforms listed above that have this feature - (and also Windows). See src/luaconf.h and also src/Makefile. - -* Building Lua on Windows and other systems - ----------------------------------------- - If you're not using the usual Unix tools, then the instructions for - building Lua depend on the compiler you use. You'll need to create - projects (or whatever your compiler uses) for building the library, - the interpreter, and the compiler, as follows: - - library: lapi.c lcode.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c - lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c - ltable.c ltm.c lundump.c lvm.c lzio.c - lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c - ltablib.c lstrlib.c loadlib.c linit.c - - interpreter: library, lua.c - - compiler: library, luac.c print.c - - If you use Visual Studio .NET, you can use etc/luavs.bat in its - "Command Prompt". - - If all you want is to build the Lua interpreter, you may put all .c files - in a single project, except for luac.c and print.c. Or just use etc/all.c. - - To use Lua as a library in your own programs, you'll need to know how to - create and use libraries with your compiler. - - As mentioned above, you may edit luaconf.h to select some features before - building Lua. - -(end of INSTALL) @@ -1,6 +1,5 @@ -# makefile for installing Lua -# see INSTALL for installation instructions -# see src/Makefile and src/luaconf.h for further customization +# Makefile for installing Lua +# See doc/readme.html for installation and customization instructions. # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= @@ -15,40 +14,41 @@ INSTALL_INC= $(INSTALL_TOP)/include INSTALL_LIB= $(INSTALL_TOP)/lib INSTALL_MAN= $(INSTALL_TOP)/man/man1 # -# You probably want to make INSTALL_LMOD and INSTALL_CMOD consistent with -# LUA_ROOT, LUA_LDIR, and LUA_CDIR in luaconf.h (and also with etc/lua.pc). +# You may want to make INSTALL_LMOD and INSTALL_CMOD consistent with +# LUA_ROOT, LUA_LDIR, and LUA_CDIR in luaconf.h. INSTALL_LMOD= $(INSTALL_TOP)/share/lua/$V INSTALL_CMOD= $(INSTALL_TOP)/lib/lua/$V -# How to install. If your install program does not support "-p", then you -# may have to run ranlib on the installed liblua.a (do "make ranlib"). +# How to install. +# If your install program does not support "-p", then you may have to run +# ranlib on the installed liblua.a. INSTALL= install -p INSTALL_EXEC= $(INSTALL) -m 0755 INSTALL_DATA= $(INSTALL) -m 0644 # -# If you don't have install you can use cp instead. +# If you don't have "install" you can use "cp" instead. # INSTALL= cp -p # INSTALL_EXEC= $(INSTALL) # INSTALL_DATA= $(INSTALL) # Utilities. MKDIR= mkdir -p -RANLIB= ranlib +RM= rm -f -# == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= +# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE ======= # Convenience platforms targets. PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris # What to install. TO_BIN= lua luac -TO_INC= lua.h luaconf.h lualib.h lauxlib.h ../etc/lua.hpp +TO_INC= lua.h luaconf.h lualib.h lauxlib.h lua.hpp TO_LIB= liblua.a TO_MAN= lua.1 luac.1 # Lua version and release. -V= 5.1 -R= 5.1.4 +V= 5.2 +R= $V.0 all: $(PLAT) @@ -65,20 +65,23 @@ install: dummy cd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB) cd doc && $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN) -ranlib: - cd src && cd $(INSTALL_LIB) && $(RANLIB) $(TO_LIB) +uninstall: + cd src && cd $(INSTALL_BIN) && $(RM) $(TO_BIN) + cd src && cd $(INSTALL_INC) && $(RM) $(TO_INC) + cd src && cd $(INSTALL_LIB) && $(RM) $(TO_LIB) + cd doc && cd $(INSTALL_MAN) && $(RM) $(TO_MAN) local: - $(MAKE) install INSTALL_TOP=.. + $(MAKE) install INSTALL_TOP=../install none: @echo "Please do" @echo " make PLATFORM" @echo "where PLATFORM is one of these:" @echo " $(PLATS)" - @echo "See INSTALL for complete instructions." + @echo "See doc/readme.html for complete instructions." -# make may get confused with test/ and INSTALL in a case-insensitive OS +# make may get confused with test/ and install/ in a case-insensitive OS dummy: # echo config parameters @@ -106,8 +109,8 @@ echo: # echo private config parameters pecho: - @echo "V = $(V)" - @echo "R = $(R)" + @echo "V = $V" + @echo "R = $R" @echo "TO_BIN = $(TO_BIN)" @echo "TO_INC = $(TO_INC)" @echo "TO_LIB = $(TO_LIB)" @@ -1,37 +1,4 @@ -README for Lua 5.1 +This is Lua 5.2 (work1), released on 08 Jan 2010. -See INSTALL for installation instructions. -See HISTORY for a summary of changes since the last released version. - -* What is Lua? - ------------ - Lua is a powerful, light-weight programming language designed for extending - applications. Lua is also frequently used as a general-purpose, stand-alone - language. Lua is free software. - - For complete information, visit Lua's web site at http://www.lua.org/ . - For an executive summary, see http://www.lua.org/about.html . - - Lua has been used in many different projects around the world. - For a short list, see http://www.lua.org/uses.html . - -* Availability - ------------ - Lua is freely available for both academic and commercial purposes. - See COPYRIGHT and http://www.lua.org/license.html for details. - Lua can be downloaded at http://www.lua.org/download.html . - -* Installation - ------------ - Lua is implemented in pure ANSI C, and compiles unmodified in all known - platforms that have an ANSI C compiler. In most Unix-like platforms, simply - do "make" with a suitable target. See INSTALL for detailed instructions. - -* Origin - ------ - Lua is developed at Lua.org, a laboratory of the Department of Computer - Science of PUC-Rio (the Pontifical Catholic University of Rio de Janeiro - in Brazil). - For more information about the authors, see http://www.lua.org/authors.html . - -(end of README) +For information about Lua, including installation instructions and +license details, see doc/readme.html. diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 00000000..c9e98b55 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,9 @@ +R= readme +T= $R.txt +H= $R.html + +$T: $H + lynx -dump $? >$@ + +clean: + -rm -f $T diff --git a/doc/alert.png b/doc/alert.png Binary files differnew file mode 100644 index 00000000..49380746 --- /dev/null +++ b/doc/alert.png diff --git a/doc/contents.html b/doc/contents.html index 8e58e18c..beba089f 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -1,7 +1,7 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <HTML> <HEAD> -<TITLE>Lua 5.1 Reference Manual - contents</TITLE> +<TITLE>Lua 5.2 Reference Manual - contents</TITLE> <LINK REL="stylesheet" TYPE="text/css" HREF="lua.css"> <META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1"> <STYLE TYPE="text/css"> @@ -17,29 +17,9 @@ ul { <HR> <H1> <A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="" BORDER=0></A> -Lua 5.1 Reference Manual +Lua 5.2 Reference Manual </H1> -This is an online version of -<BLOCKQUOTE> -<A HREF="http://www.amazon.com/exec/obidos/ASIN/8590379833/lua-indexmanual-20"> -<IMG SRC="cover.png" ALT="" TITLE="buy from Amazon" BORDER=1 ALIGN="left" HSPACE=12> -</A> -<B>Lua 5.1 Reference Manual</B> -<BR>by R. Ierusalimschy, L. H. de Figueiredo, W. Celes -<BR>Lua.org, August 2006 -<BR>ISBN 85-903798-3-3 -<BR><A HREF="http://www.amazon.com/exec/obidos/ASIN/8590379833/lua-indexmanual-20"> -<IMG SRC="amazon.gif" ALT="[Buy from Amazon]" BORDER=0></A> -<BR CLEAR="all"> -</BLOCKQUOTE> -<P> - -Buy a copy of this book and -<A HREF="http://www.lua.org/donations.html">help to support</A> -the Lua project. -<P> - The reference manual is the official definition of the Lua language. For a complete introduction to Lua programming, see the book <A HREF="http://www.lua.org/docs.html#books">Programming in Lua</A>. @@ -50,13 +30,9 @@ For a complete introduction to Lua programming, see the book <A HREF="#contents">contents</A> · <A HREF="#index">index</A> -· -<A HREF="http://www.lua.org/manual/5.1/pt/">português</A> -· -<A HREF="http://www.lua.org/manual/5.1/es/">español</A> <HR> <SMALL> -Copyright © 2006-2008 Lua.org, PUC-Rio. +Copyright © 2006-2010 Lua.org, PUC-Rio. Freely available under the terms of the <a href="http://www.lua.org/license.html#5">Lua license</a>. </SMALL> @@ -489,10 +465,10 @@ Freely available under the terms of the <HR> <SMALL> Last update: -Sat Jan 19 13:24:29 BRST 2008 +Fri Jan 8 16:29:00 BRST 2010 </SMALL> <!-- -Last change: revised for Lua 5.1.3 +Last change: fake for Lua 5.2.0-work1 --> </BODY> diff --git a/doc/external.png b/doc/external.png Binary files differnew file mode 100644 index 00000000..419c06fb --- /dev/null +++ b/doc/external.png diff --git a/doc/lua.1 b/doc/lua.1 deleted file mode 100644 index 24809cc6..00000000 --- a/doc/lua.1 +++ /dev/null @@ -1,163 +0,0 @@ -.\" $Id: lua.man,v 1.11 2006/01/06 16:03:34 lhf Exp $ -.TH LUA 1 "$Date: 2006/01/06 16:03:34 $" -.SH NAME -lua \- Lua interpreter -.SH SYNOPSIS -.B lua -[ -.I options -] -[ -.I script -[ -.I args -] -] -.SH DESCRIPTION -.B lua -is the stand-alone Lua interpreter. -It loads and executes Lua programs, -either in textual source form or -in precompiled binary form. -(Precompiled binaries are output by -.BR luac , -the Lua compiler.) -.B lua -can be used as a batch interpreter and also interactively. -.LP -The given -.I options -(see below) -are executed and then -the Lua program in file -.I script -is loaded and executed. -The given -.I args -are available to -.I script -as strings in a global table named -.BR arg . -If these arguments contain spaces or other characters special to the shell, -then they should be quoted -(but note that the quotes will be removed by the shell). -The arguments in -.B arg -start at 0, -which contains the string -.RI ' script '. -The index of the last argument is stored in -.BR arg.n . -The arguments given in the command line before -.IR script , -including the name of the interpreter, -are available in negative indices in -.BR arg . -.LP -At the very start, -before even handling the command line, -.B lua -executes the contents of the environment variable -.BR LUA_INIT , -if it is defined. -If the value of -.B LUA_INIT -is of the form -.RI '@ filename ', -then -.I filename -is executed. -Otherwise, the string is assumed to be a Lua statement and is executed. -.LP -Options start with -.B '\-' -and are described below. -You can use -.B "'\--'" -to signal the end of options. -.LP -If no arguments are given, -then -.B "\-v \-i" -is assumed when the standard input is a terminal; -otherwise, -.B "\-" -is assumed. -.LP -In interactive mode, -.B lua -prompts the user, -reads lines from the standard input, -and executes them as they are read. -If a line does not contain a complete statement, -then a secondary prompt is displayed and -lines are read until a complete statement is formed or -a syntax error is found. -So, one way to interrupt the reading of an incomplete statement is -to force a syntax error: -adding a -.B ';' -in the middle of a statement is a sure way of forcing a syntax error -(except inside multiline strings and comments; these must be closed explicitly). -If a line starts with -.BR '=' , -then -.B lua -displays the values of all the expressions in the remainder of the -line. The expressions must be separated by commas. -The primary prompt is the value of the global variable -.BR _PROMPT , -if this value is a string; -otherwise, the default prompt is used. -Similarly, the secondary prompt is the value of the global variable -.BR _PROMPT2 . -So, -to change the prompts, -set the corresponding variable to a string of your choice. -You can do that after calling the interpreter -or on the command line -(but in this case you have to be careful with quotes -if the prompt string contains a space; otherwise you may confuse the shell.) -The default prompts are "> " and ">> ". -.SH OPTIONS -.TP -.B \- -load and execute the standard input as a file, -that is, -not interactively, -even when the standard input is a terminal. -.TP -.BI \-e " stat" -execute statement -.IR stat . -You need to quote -.I stat -if it contains spaces, quotes, -or other characters special to the shell. -.TP -.B \-i -enter interactive mode after -.I script -is executed. -.TP -.BI \-l " name" -call -.BI require(' name ') -before executing -.IR script . -Typically used to load libraries. -.TP -.B \-v -show version information. -.SH "SEE ALSO" -.BR luac (1) -.br -http://www.lua.org/ -.SH DIAGNOSTICS -Error messages should be self explanatory. -.SH AUTHORS -R. Ierusalimschy, -L. H. de Figueiredo, -and -W. Celes -.\" EOF diff --git a/doc/lua.html b/doc/lua.html deleted file mode 100644 index 1d435ab0..00000000 --- a/doc/lua.html +++ /dev/null @@ -1,172 +0,0 @@ -<!-- $Id: lua.man,v 1.11 2006/01/06 16:03:34 lhf Exp $ --> -<HTML> -<HEAD> -<TITLE>LUA man page</TITLE> -<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css"> -</HEAD> - -<BODY BGCOLOR="#FFFFFF"> - -<H2>NAME</H2> -lua - Lua interpreter -<H2>SYNOPSIS</H2> -<B>lua</B> -[ -<I>options</I> -] -[ -<I>script</I> -[ -<I>args</I> -] -] -<H2>DESCRIPTION</H2> -<B>lua</B> -is the stand-alone Lua interpreter. -It loads and executes Lua programs, -either in textual source form or -in precompiled binary form. -(Precompiled binaries are output by -<B>luac</B>, -the Lua compiler.) -<B>lua</B> -can be used as a batch interpreter and also interactively. -<P> -The given -<I>options</I> -(see below) -are executed and then -the Lua program in file -<I>script</I> -is loaded and executed. -The given -<I>args</I> -are available to -<I>script</I> -as strings in a global table named -<B>arg</B>. -If these arguments contain spaces or other characters special to the shell, -then they should be quoted -(but note that the quotes will be removed by the shell). -The arguments in -<B>arg</B> -start at 0, -which contains the string -'<I>script</I>'. -The index of the last argument is stored in -<B>arg.n</B>. -The arguments given in the command line before -<I>script</I>, -including the name of the interpreter, -are available in negative indices in -<B>arg</B>. -<P> -At the very start, -before even handling the command line, -<B>lua</B> -executes the contents of the environment variable -<B>LUA_INIT</B>, -if it is defined. -If the value of -<B>LUA_INIT</B> -is of the form -'@<I>filename</I>', -then -<I>filename</I> -is executed. -Otherwise, the string is assumed to be a Lua statement and is executed. -<P> -Options start with -<B>'-'</B> -and are described below. -You can use -<B>'--'</B> -to signal the end of options. -<P> -If no arguments are given, -then -<B>"-v -i"</B> -is assumed when the standard input is a terminal; -otherwise, -<B>"-"</B> -is assumed. -<P> -In interactive mode, -<B>lua</B> -prompts the user, -reads lines from the standard input, -and executes them as they are read. -If a line does not contain a complete statement, -then a secondary prompt is displayed and -lines are read until a complete statement is formed or -a syntax error is found. -So, one way to interrupt the reading of an incomplete statement is -to force a syntax error: -adding a -<B>';'</B> -in the middle of a statement is a sure way of forcing a syntax error -(except inside multiline strings and comments; these must be closed explicitly). -If a line starts with -<B>'='</B>, -then -<B>lua</B> -displays the values of all the expressions in the remainder of the -line. The expressions must be separated by commas. -The primary prompt is the value of the global variable -<B>_PROMPT</B>, -if this value is a string; -otherwise, the default prompt is used. -Similarly, the secondary prompt is the value of the global variable -<B>_PROMPT2</B>. -So, -to change the prompts, -set the corresponding variable to a string of your choice. -You can do that after calling the interpreter -or on the command line -(but in this case you have to be careful with quotes -if the prompt string contains a space; otherwise you may confuse the shell.) -The default prompts are "> " and ">> ". -<H2>OPTIONS</H2> -<P> -<B>-</B> -load and execute the standard input as a file, -that is, -not interactively, -even when the standard input is a terminal. -<P> -<B>-e </B><I>stat</I> -execute statement -<I>stat</I>. -You need to quote -<I>stat </I> -if it contains spaces, quotes, -or other characters special to the shell. -<P> -<B>-i</B> -enter interactive mode after -<I>script</I> -is executed. -<P> -<B>-l </B><I>name</I> -call -<B>require</B>('<I>name</I>') -before executing -<I>script</I>. -Typically used to load libraries. -<P> -<B>-v</B> -show version information. -<H2>SEE ALSO</H2> -<B>luac</B>(1) -<BR> -<A HREF="http://www.lua.org/">http://www.lua.org/</A> -<H2>DIAGNOSTICS</H2> -Error messages should be self explanatory. -<H2>AUTHORS</H2> -R. Ierusalimschy, -L. H. de Figueiredo, -and -W. Celes -<!-- EOF --> -</BODY> -</HTML> diff --git a/doc/luac.1 b/doc/luac.1 deleted file mode 100644 index d8146782..00000000 --- a/doc/luac.1 +++ /dev/null @@ -1,136 +0,0 @@ -.\" $Id: luac.man,v 1.28 2006/01/06 16:03:34 lhf Exp $ -.TH LUAC 1 "$Date: 2006/01/06 16:03:34 $" -.SH NAME -luac \- Lua compiler -.SH SYNOPSIS -.B luac -[ -.I options -] [ -.I filenames -] -.SH DESCRIPTION -.B luac -is the Lua compiler. -It translates programs written in the Lua programming language -into binary files that can be later loaded and executed. -.LP -The main advantages of precompiling chunks are: -faster loading, -protecting source code from accidental user changes, -and -off-line syntax checking. -.LP -Pre-compiling does not imply faster execution -because in Lua chunks are always compiled into bytecodes before being executed. -.B luac -simply allows those bytecodes to be saved in a file for later execution. -.LP -Pre-compiled chunks are not necessarily smaller than the corresponding source. -The main goal in pre-compiling is faster loading. -.LP -The binary files created by -.B luac -are portable only among architectures with the same word size and byte order. -.LP -.B luac -produces a single output file containing the bytecodes -for all source files given. -By default, -the output file is named -.BR luac.out , -but you can change this with the -.B \-o -option. -.LP -In the command line, -you can mix -text files containing Lua source and -binary files containing precompiled chunks. -This is useful to combine several precompiled chunks, -even from different (but compatible) platforms, -into a single precompiled chunk. -.LP -You can use -.B "'\-'" -to indicate the standard input as a source file -and -.B "'\--'" -to signal the end of options -(that is, -all remaining arguments will be treated as files even if they start with -.BR "'\-'" ). -.LP -The internal format of the binary files produced by -.B luac -is likely to change when a new version of Lua is released. -So, -save the source files of all Lua programs that you precompile. -.LP -.SH OPTIONS -Options must be separate. -.TP -.B \-l -produce a listing of the compiled bytecode for Lua's virtual machine. -Listing bytecodes is useful to learn about Lua's virtual machine. -If no files are given, then -.B luac -loads -.B luac.out -and lists its contents. -.TP -.BI \-o " file" -output to -.IR file , -instead of the default -.BR luac.out . -(You can use -.B "'\-'" -for standard output, -but not on platforms that open standard output in text mode.) -The output file may be a source file because -all files are loaded before the output file is written. -Be careful not to overwrite precious files. -.TP -.B \-p -load files but do not generate any output file. -Used mainly for syntax checking and for testing precompiled chunks: -corrupted files will probably generate errors when loaded. -Lua always performs a thorough integrity test on precompiled chunks. -Bytecode that passes this test is completely safe, -in the sense that it will not break the interpreter. -However, -there is no guarantee that such code does anything sensible. -(None can be given, because the halting problem is unsolvable.) -If no files are given, then -.B luac -loads -.B luac.out -and tests its contents. -No messages are displayed if the file passes the integrity test. -.TP -.B \-s -strip debug information before writing the output file. -This saves some space in very large chunks, -but if errors occur when running a stripped chunk, -then the error messages may not contain the full information they usually do. -For instance, -line numbers and names of local variables are lost. -.TP -.B \-v -show version information. -.SH FILES -.TP 15 -.B luac.out -default output file -.SH "SEE ALSO" -.BR lua (1) -.br -http://www.lua.org/ -.SH DIAGNOSTICS -Error messages should be self explanatory. -.SH AUTHORS -L. H. de Figueiredo, -R. Ierusalimschy and -W. Celes -.\" EOF diff --git a/doc/luac.html b/doc/luac.html deleted file mode 100644 index 179ffe82..00000000 --- a/doc/luac.html +++ /dev/null @@ -1,145 +0,0 @@ -<!-- $Id: luac.man,v 1.28 2006/01/06 16:03:34 lhf Exp $ --> -<HTML> -<HEAD> -<TITLE>LUAC man page</TITLE> -<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css"> -</HEAD> - -<BODY BGCOLOR="#FFFFFF"> - -<H2>NAME</H2> -luac - Lua compiler -<H2>SYNOPSIS</H2> -<B>luac</B> -[ -<I>options</I> -] [ -<I>filenames</I> -] -<H2>DESCRIPTION</H2> -<B>luac</B> -is the Lua compiler. -It translates programs written in the Lua programming language -into binary files that can be later loaded and executed. -<P> -The main advantages of precompiling chunks are: -faster loading, -protecting source code from accidental user changes, -and -off-line syntax checking. -<P> -Precompiling does not imply faster execution -because in Lua chunks are always compiled into bytecodes before being executed. -<B>luac</B> -simply allows those bytecodes to be saved in a file for later execution. -<P> -Precompiled chunks are not necessarily smaller than the corresponding source. -The main goal in precompiling is faster loading. -<P> -The binary files created by -<B>luac</B> -are portable only among architectures with the same word size and byte order. -<P> -<B>luac</B> -produces a single output file containing the bytecodes -for all source files given. -By default, -the output file is named -<B>luac.out</B>, -but you can change this with the -<B>-o</B> -option. -<P> -In the command line, -you can mix -text files containing Lua source and -binary files containing precompiled chunks. -This is useful because several precompiled chunks, -even from different (but compatible) platforms, -can be combined into a single precompiled chunk. -<P> -You can use -<B>'-'</B> -to indicate the standard input as a source file -and -<B>'--'</B> -to signal the end of options -(that is, -all remaining arguments will be treated as files even if they start with -<B>'-'</B>). -<P> -The internal format of the binary files produced by -<B>luac</B> -is likely to change when a new version of Lua is released. -So, -save the source files of all Lua programs that you precompile. -<P> -<H2>OPTIONS</H2> -Options must be separate. -<P> -<B>-l</B> -produce a listing of the compiled bytecode for Lua's virtual machine. -Listing bytecodes is useful to learn about Lua's virtual machine. -If no files are given, then -<B>luac</B> -loads -<B>luac.out</B> -and lists its contents. -<P> -<B>-o </B><I>file</I> -output to -<I>file</I>, -instead of the default -<B>luac.out</B>. -(You can use -<B>'-'</B> -for standard output, -but not on platforms that open standard output in text mode.) -The output file may be a source file because -all files are loaded before the output file is written. -Be careful not to overwrite precious files. -<P> -<B>-p</B> -load files but do not generate any output file. -Used mainly for syntax checking and for testing precompiled chunks: -corrupted files will probably generate errors when loaded. -Lua always performs a thorough integrity test on precompiled chunks. -Bytecode that passes this test is completely safe, -in the sense that it will not break the interpreter. -However, -there is no guarantee that such code does anything sensible. -(None can be given, because the halting problem is unsolvable.) -If no files are given, then -<B>luac</B> -loads -<B>luac.out</B> -and tests its contents. -No messages are displayed if the file passes the integrity test. -<P> -<B>-s</B> -strip debug information before writing the output file. -This saves some space in very large chunks, -but if errors occur when running a stripped chunk, -then the error messages may not contain the full information they usually do. -For instance, -line numbers and names of local variables are lost. -<P> -<B>-v</B> -show version information. -<H2>FILES</H2> -<P> -<B>luac.out</B> -default output file -<H2>SEE ALSO</H2> -<B>lua</B>(1) -<BR> -<A HREF="http://www.lua.org/">http://www.lua.org/</A> -<H2>DIAGNOSTICS</H2> -Error messages should be self explanatory. -<H2>AUTHORS</H2> -L. H. de Figueiredo, -R. Ierusalimschy and -W. Celes -<!-- EOF --> -</BODY> -</HTML> diff --git a/doc/manual.css b/doc/manual.css deleted file mode 100644 index eed5afd9..00000000 --- a/doc/manual.css +++ /dev/null @@ -1,13 +0,0 @@ -h3 code { - font-family: inherit ; -} - -pre { - font-size: 105% ; -} - -span.apii { - float: right ; - font-family: inherit ; -} - diff --git a/doc/manual.html b/doc/manual.html index f46f17c8..83d2bb09 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1,39 +1,31 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <html> <head> -<title>Lua 5.1 Reference Manual</title> -<link rel="stylesheet" type="text/css" href="lua.css"> -<link rel="stylesheet" type="text/css" href="manual.css"> -<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1"> +<title>Lua 5.2 Reference Manual</title> +<link rel="stylesheet" href="lua.css"> </head> -<body> +<body bgcolor="#FFFFFF"> <hr> <h1> -<a href="http://www.lua.org/"><img src="logo.gif" alt="" border="0"></a> -Lua 5.1 Reference Manual +<a href="http://www.lua.org/home.html"><img src="logo.gif" alt="[Lua logo]" border="0"></a> +Lua 5.2 Reference Manual </h1> by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes <p> <small> -Copyright © 2006-2008 Lua.org, PUC-Rio. -Freely available under the terms of the -<a href="http://www.lua.org/license.html#5">Lua license</a>. +<a href="http://www.lua.org/copyright.html">Copyright</a> +© 2010 Lua.org, PUC-Rio. All rights reserved. </small> <hr> -<p> - -<a href="contents.html#contents">contents</A> -· -<a href="contents.html#index">index</A> <!-- ====================================================================== --> <p> -<!-- $Id: manual.of,v 1.48 2008/08/18 15:24:20 roberto Exp $ --> +<!-- $Id: manual.of,v 1.53 2010/01/08 18:18:46 roberto Exp roberto $ --> @@ -111,15 +103,19 @@ at the end of this manual. <h2>2.1 - <a name="2.1">Lexical Conventions</a></h2> <p> +Lua is a free-form language. +It ignores spaces (including new lines) and comments +between lexical elements (tokens), +except as delimiters between names and keywords. + + +<p> <em>Names</em> (also called <em>identifiers</em>) in Lua can be any string of letters, digits, and underscores, not beginning with a digit. This coincides with the definition of names in most languages. -(The definition of letter depends on the current locale: -any character considered alphabetic by the current locale -can be used in an identifier.) Identifiers are used to name variables and table fields. @@ -192,10 +188,17 @@ A <em>closing long bracket</em> is defined similarly; for instance, a closing long bracket of level 4 is written as <code>]====]</code>. A long string starts with an opening long bracket of any level and ends at the first closing long bracket of the same level. +It can contain any text except a closing bracket of the proper level. Literals in this bracketed form can run for several lines, do not interpret any escape sequences, and ignore long brackets of any other level. -They can contain anything except a closing bracket of the proper level. +Any kind of end-of-line sequence +(carriage return, newline, carriage return followed by newline, +or newline followed by carriage return) +is converted to a simple newline. +You should not use long strings for non-text data; +Use instead a regular quoted literal with explicit escape sequences +for control characters. <p> @@ -429,20 +432,6 @@ The syntax <code>var.Name</code> is just syntactic sugar for All global variables live as fields in ordinary Lua tables, called <em>environment tables</em> or simply <em>environments</em> (see <a href="#2.9">§2.9</a>). -Each function has its own reference to an environment, -so that all global variables in this function -will refer to this environment table. -When a function is created, -it inherits the environment from the function that created it. -To get the environment table of a Lua function, -you call <a href="#pdf-getfenv"><code>getfenv</code></a>. -To replace it, -you call <a href="#pdf-setfenv"><code>setfenv</code></a>. -(You can only manipulate the environment of C functions -through the debug library; (see <a href="#5.9">§5.9</a>).) - - -<p> An access to a global variable <code>x</code> is equivalent to <code>_env.x</code>, which in turn is equivalent to @@ -450,7 +439,7 @@ which in turn is equivalent to <pre> gettable_event(_env, "x") </pre><p> -where <code>_env</code> is the environment of the running function. +where <code>_env</code> is the current environment (see <a href="#2.9">§2.9</a>). (See <a href="#2.8">§2.8</a> for a complete description of the <code>gettable_event</code> function. This function is not defined or callable in Lua. @@ -862,6 +851,43 @@ The visibility rules for local variables are explained in <a href="#2.6">§2 +<h3>2.4.8 - <a name="2.4.8">Lexical Environments</a></h3> + +<p> +A lexical environment defines a new current environment (see <a href="#2.9">§2.9</a>) +for the code inside its block: + +<pre> + stat ::= <b>in</b> exp <b>do</b> block <b>end</b> +</pre><p> +That is, a lexical environment changes the +table used to resolve all accesses +to global (free) variables inside a block. + + +<p> +Inside a lexical environment, +the result of <code><em>exp</em></code> becomes the current environment. +Expression <code><em>exp</em></code> is evaluated only once in the beginning of +the statement and it is stored in a hidden local variable named +<a name="pdf-(environment)"><code>(environment)</code></a>. +Then, any global variable +(that is, a variable not declared as a local) +<code>var</code> inside <code><em>block</em></code> is accessed as +<code>(environment).<em>var</em></code>. +Moreover, functions defined inside the block also use the +current environment as their environments (see <a href="#2.9">§2.9</a>). + + +<p> +A lexical environment does not shadow local declarations. +That is, any local variable that is visible just before +a lexical environment is still visible inside the environment. + + + + + <h2>2.5 - <a name="2.5">Expressions</a></h2> @@ -1078,7 +1104,7 @@ Otherwise, the "concat" metamethod is called (see <a href="#2.8">§2.8</a>). <h3>2.5.5 - <a name="2.5.5">The Length Operator</a></h3> <p> -The length operator is denoted by the unary operator <code>#</code>. +The length operator is denoted by the unary prefix operator <code>#</code>. The length of a string is its number of bytes (that is, the usual meaning of string length when each character is one byte). @@ -1089,7 +1115,8 @@ The length of a table <code>t</code> is defined to be any integer index <code>n</code> such that <code>t[n]</code> is not <b>nil</b> and <code>t[n+1]</code> is <b>nil</b>; moreover, if <code>t[1]</code> is <b>nil</b>, <code>n</code> can be zero. -For a regular array, with non-nil values from 1 to a given <code>n</code>, +For a regular array, where all non-nil values +have keys from 1 to a given <code>n</code>, its length is exactly that <code>n</code>, the index of its last value. If the array has "holes" @@ -1100,6 +1127,11 @@ directly precedes a <b>nil</b> value the array). +<p> +A program can modify the behavior of the length operator for +any value but strings through metamethods (see <a href="#2.8">§2.8</a>). + + @@ -1237,7 +1269,7 @@ that is, the argument list is a single literal string. <p> -As an exception to the free-format syntax of Lua, +As an exception to the free-form character of Lua, you cannot put a line break before the '<code>(</code>' in a function call. This restriction avoids some ambiguities in the language. If you write @@ -1247,7 +1279,8 @@ If you write (g).x(a) </pre><p> Lua would see that as a single statement, <code>a = f(g).x(a)</code>. -So, if you want two statements, you must add a semi-colon between them. +In this case, if you want two statements, +you must add a semi-colon between them. If you actually want to call <code>f</code>, you must remove the line break before <code>(g)</code>. @@ -1557,6 +1590,8 @@ Tables and full userdata have individual metatables Values of all other types share one single metatable per type; that is, there is one single metatable for all numbers, one for all strings, etc. +By default, a value has no metatable, +but the string library sets a metatable for the string type (see <a href="#5.4">§5.4</a>). <p> @@ -1734,14 +1769,13 @@ the <code>#</code> operation. function len_event (op) if type(op) == "string" then return strlen(op) -- primitive string length - elseif type(op) == "table" then - return #op -- primitive table length else local h = metatable(op).__len if h then - -- call the handler with the operand - return (h(op)) - else -- no handler available: default behavior + return (h(op)) -- call handler with the operand + elseif type(op) == "table" then + return #op -- primitive table length + else -- no handler available: error error(···) end end @@ -1923,23 +1957,24 @@ called when Lua calls a value. <h2>2.9 - <a name="2.9">Environments</a></h2> <p> -Besides metatables, -objects of types thread, function, and userdata -have another table associated with them, -called their <em>environment</em>. +Each function and userdata in Lua +has a table associated with it, +called its <em>environment</em>. Like metatables, environments are regular tables and multiple objects can share the same environment. +>From Lua, +you can manipulate the environment of an object +only through the debug library (see <a href="#5.10">§5.10</a>). <p> -Threads are created sharing the environment of the creating thread. Userdata and C functions are created sharing the environment of the creating C function. Non-nested Lua functions (created by <a href="#pdf-loadfile"><code>loadfile</code></a>, <a href="#pdf-loadstring"><code>loadstring</code></a> or <a href="#pdf-load"><code>load</code></a>) -are created sharing the environment of the creating thread. -Nested Lua functions are created sharing the environment of -the creating Lua function. +are created sharing the global environment. +Nested Lua functions are created sharing the current environment +of where it is defined. <p> @@ -1949,14 +1984,6 @@ a userdata. <p> -Environments associated with threads are called -<em>global environments</em>. -They are used as the default environment for threads and -non-nested Lua functions created by the thread -and can be directly accessed by C code (see <a href="#3.3">§3.3</a>). - - -<p> The environment associated with a C function can be directly accessed by C code (see <a href="#3.3">§3.3</a>). It is used as the default environment for other C functions @@ -1964,20 +1991,15 @@ and userdata created by the function. <p> -Environments associated with Lua functions are used to resolve -all accesses to global variables within the function (see <a href="#2.3">§2.3</a>). -They are used as the default environment for nested Lua functions -created by the function. - - -<p> -You can change the environment of a Lua function or the -running thread by calling <a href="#pdf-setfenv"><code>setfenv</code></a>. -You can get the environment of a Lua function or the running thread -by calling <a href="#pdf-getfenv"><code>getfenv</code></a>. -To manipulate the environment of other objects -(userdata, C functions, other threads) you must -use the C API. +The environment associated with a Lua function is used as the +current environment of all code in the function outside +a lexical environment (see <a href="#2.4.8">§2.4.8</a>). +A lexical environment changes the +current environment inside its scope. +In any case, +the <em>current environment</em> is the table +Lua uses to resolve global variables and to initialize +the environment of nested functions. @@ -2030,6 +2052,16 @@ the speed of memory allocation. <p> +If you set the step multiplier to a very large number +(such as <em>2^30</em>), +the collector behaves like a stop-the-world collector. +If you then set the pause to 200, +the collector behaves as in old Lua versions, +doing a complete collection every time Lua doubles its +memory usage. + + +<p> You can change these numbers by calling <a href="#lua_gc"><code>lua_gc</code></a> in C or <a href="#pdf-collectgarbage"><code>collectgarbage</code></a> in Lua. With these functions you can also control @@ -2107,6 +2139,28 @@ the values in the table are weak. <p> +Userdata with finalizers has a special behavior in weak tables. +When a userdata is a value in a weak table, +it is removed from the table the first time it is collected, +before running its finalizer. +When it is a key, however, +it is removed from the table only when it is really freed, +after running its finalizer. +This behavior allows the finalizer to access values +associated with the userdata through weak tables. + + +<p> +A table with weak keys and strong values +is also called an <em>ephemeron table</em>. +In an ephemeron table, +a value is considered reachable only if its key is reachable. +In particular, +if the only reference to a key comes from its value, +the pair is removed. + + +<p> After you use a table as a metatable, you should not change the value of its <code>__mode</code> field. Otherwise, the weak behavior of the tables controlled by this @@ -2309,7 +2363,7 @@ you are responsible for ensuring consistency. In particular, <em>you are responsible for controlling stack overflow</em>. You can use the function <a href="#lua_checkstack"><code>lua_checkstack</code></a> -to grow the stack size. +to ensure that the stack has extra slots when pushing new elements. <p> @@ -2321,9 +2375,18 @@ unless your code has loops pushing elements onto the stack. <p> +When you call a Lua function +without a fixed number of results (see <a href="#lua_call"><code>lua_call</code></a>), +Lua ensures that the stack has enough size for all results, +but it does not ensure any extra space. +So, before pushing anything in the stack after such a call +you should use <a href="#lua_checkstack"><code>lua_checkstack</code></a>. + + +<p> Most query functions accept as indices any value inside the available stack space, that is, indices up to the maximum stack size -you have set through <a href="#lua_checkstack"><code>lua_checkstack</code></a>. +that you have set through <a href="#lua_checkstack"><code>lua_checkstack</code></a>. Such indices are called <em>acceptable indices</em>. More formally, we define an <em>acceptable index</em> as follows: @@ -2342,8 +2405,7 @@ Note that 0 is never an acceptable index. <p> Unless otherwise noted, -any function that accepts valid indices can also be called with -<em>pseudo-indices</em>, +any function that accepts valid indices also accepts <em>pseudo-indices</em>, which represent some Lua values that are accessible to C code but which are not in the stack. Pseudo-indices are used to access the thread environment, @@ -2353,8 +2415,6 @@ and the upvalues of a C function (see <a href="#3.4">§3.4</a>). <p> -The thread environment (where global variables live) is -always at pseudo-index <a name="pdf-LUA_GLOBALSINDEX"><code>LUA_GLOBALSINDEX</code></a>. The environment of the running C function is always at pseudo-index <a name="pdf-LUA_ENVIRONINDEX"><code>LUA_ENVIRONINDEX</code></a>. @@ -2365,7 +2425,7 @@ you can use regular table operations over an environment table. For instance, to access the value of a global variable, do <pre> - lua_getfield(L, LUA_GLOBALSINDEX, varname); + lua_getfield(L, LUA_ENVIRONINDEX, varname); </pre> @@ -2416,8 +2476,51 @@ or a light userdata with the address of a C object in your code. <p> The integer keys in the registry are used by the reference mechanism, implemented by the auxiliary library, -and therefore should not be used for other purposes. +and by some predefined values. +Therefore, integer keys should not be used for other purposes. + + +<p> +When you create a new Lua state, +its registry comes with some predefined values. +These predefined values are indexed with integer keys +defined as constants in <code>lua.h</code>. +The following constants are defined: + +<ul> +<li><b>LUA_RIDX_MAINTHREAD:</b> At this index the registry has +the main thread of the state. +(The main thread is the one created together with the state.) +</li> +<li><b>LUA_RIDX_CPCALL:</b> At this index the registry has +the <a name="pdf-cpcall"><code>cpcall</code></a> function. +This function allows you to call any +<a href="#lua_CFunction"><code>lua_CFunction</code></a> without creating a closure for it, +therefore preventing an unprotected memory allocation error. + +<p> +The address of the function to be called must be stored in a variable, +whose address is passed as the first argument to <code>cpcall</code>, +as a light userdata. +Note that the light userdata in the first argument should not +point to the function to be called, +but to a variable containing the pointer to the function. +ANSI C does not allow the direct assignment of a function address to +the <code>void*</code> in a light userdata. + + +<p> +Other arguments to <code>cpcall</code> are passed to the called function. +The <code>cpcall</code> function itself should be called with <a href="#lua_pcall"><code>lua_pcall</code></a>, +like any C function. +</li> + +<li><b>LUA_RIDX_GLOBALS:</b> At this index the registry has +the global environment. +This is the C equivalent to the <a href="#pdf-_G"><code>_G</code></a> global variable. +</li> +</ul> @@ -2429,7 +2532,7 @@ Internally, Lua uses the C <code>longjmp</code> facility to handle errors. (You can also choose to use exceptions if you use C++; see file <code>luaconf.h</code>.) When Lua faces any error -(such as memory allocation errors, type errors, syntax errors, +(such as a memory allocation error, type errors, syntax errors, and runtime errors) it <em>raises</em> an error; that is, it does a long jump. @@ -2439,6 +2542,15 @@ any error jumps to the most recent active recover point. <p> +If an error happens outside any protected environment, +Lua calls a <em>panic function</em> (see <a href="#lua_atpanic"><code>lua_atpanic</code></a>) +and then calls <code>abort</code>, +thus exiting the host application. +Your panic function can avoid this exit by +never returning (e.g., doing a long jump). + + +<p> Most functions in the API can throw an error, for instance due to a memory allocation error. The documentation for each function indicates whether @@ -2452,7 +2564,75 @@ Inside a C function you can throw an error by calling <a href="#lua_error"> -<h2>3.7 - <a name="3.7">Functions and Types</a></h2> +<h2>3.7 - <a name="3.7">Handling Yields in C</a></h2> + +<p> +Internally, Lua uses the C <code>longjmp</code> facility to yield a coroutine. +Therefore, if a function <code>foo</code> calls an API function +and this API function yields +(directly or indirectly by calling another function that yields), +Lua cannot return to <code>foo</code> any more, +because the <code>longjmp</code> removes its frame from the C stack. + + +<p> +To avoid this kind of problem, +Lua raises an error whenever it tries to yield accross an API call, +except for three functions: +<a href="#lua_yieldk"><code>lua_yieldk</code></a>, <a href="#lua_callk"><code>lua_callk</code></a>, and <a href="#lua_pcallk"><code>lua_pcallk</code></a>. +All those functions receive a <em>continuation function</em> +(as a parameter called <code>k</code>) to continue execution after an yield. + + +<p> +To explain continuations, +let us set some terminology. +We have a C function called from Lua which we will call +the <em>original function</em>. +This original function may call one of those three functions in the C API, +which we will call the <em>callee function</em>, +that may yield the current thread. +(This will happen when the callee function is <a href="#lua_yieldk"><code>lua_yieldk</code></a>, +or when the callee function is either <a href="#lua_callk"><code>lua_callk</code></a> or <a href="#lua_pcallk"><code>lua_pcallk</code></a> +and the function called by them yields.) + + +<p> +Suppose the running thread yields while executing the callee function. +After the thread resumes, +it eventually will finish running the callee function. +However, +the callee function cannot return to the original function, +because its frame in the C stack was destroyed by the yield. +Instead, Lua calls a <em>continuation function</em>, +which was given as an argument to the callee function. +As the name implies, +the continuation function should continue the task +of the original function. + + +<p> +Lua treats the continuation function as if it was the original function. +The continuation function receives the same Lua stack +from the original function, +in the same state it would be if the callee function had returned. +(For instance, +after a <a href="#lua_callk"><code>lua_callk</code></a> the function and its arguments are +removed from the stack and replaced by the results from the call.) +It also has the same upvalues. +Whatever it returns is handled by Lua as if it was the return +of the original function. + + +<p> +The only difference in the Lua state between the original function +and its continuation is the result of a call to <a href="#lua_getctx"><code>lua_getctx</code></a>. + + + + + +<h2>3.8 - <a name="3.8">Functions and Types</a></h2> <p> Here we list all functions and types from the C API in @@ -2498,18 +2678,48 @@ but not exactly the same. Its arguments are <code>ud</code>, an opaque pointer passed to <a href="#lua_newstate"><code>lua_newstate</code></a>; <code>ptr</code>, a pointer to the block being allocated/reallocated/freed; -<code>osize</code>, the original size of the block; +<code>osize</code>, the original size of the block or some code about what +is being allocated; <code>nsize</code>, the new size of the block. -<code>ptr</code> is <code>NULL</code> if and only if <code>osize</code> is zero. -When <code>nsize</code> is zero, the allocator must return <code>NULL</code>; -if <code>osize</code> is not zero, -it should free the block pointed to by <code>ptr</code>. -When <code>nsize</code> is not zero, the allocator returns <code>NULL</code> -if and only if it cannot fill the request. -When <code>nsize</code> is not zero and <code>osize</code> is zero, -the allocator should behave like <code>malloc</code>. -When <code>nsize</code> and <code>osize</code> are not zero, + + +<p> +When <code>ptr</code> is not <code>NULL</code>, +<code>osize</code> is the previous size of the block +pointed by <code>ptr</code>, +that is, the size given when it was allocated or reallocated. + + +<p> +When <code>ptr</code> is <code>NULL</code>, +<code>osize</code> codes the kind of object that Lua is allocating. +<code>osize</code> is any of +<a href="#pdf-LUA_TSTRING"><code>LUA_TSTRING</code></a>, <a href="#pdf-LUA_TTABLE"><code>LUA_TTABLE</code></a>, <a href="#pdf-LUA_TFUNCTION"><code>LUA_TFUNCTION</code></a>, +<a href="#pdf-LUA_TUSERDATA"><code>LUA_TUSERDATA</code></a>, or <a href="#pdf-LUA_TTHREAD"><code>LUA_TTHREAD</code></a> when (and only when) +Lua is creating a new object of that type. +When <code>osize</code> is some other value, +Lua is allocating memory for something else. + + +<p> +Lua assumes the following behavior from the allocator function: + + +<p> +When <code>nsize</code> is zero: +if <code>ptr</code> is not <code>NULL</code>, +the allocator should free the block pointed to by <code>ptr</code>. +Anyway, the allocator must return <code>NULL</code>. + + +<p> +When <code>nsize</code> is not zero: +if <code>ptr</code> is <code>NULL</code>, +the allocator should behave like <code>malloc</code>; +when <code>ptr</code> is not <code>NULL</code>, the allocator behaves like <code>realloc</code>. +The allocator returns <code>NULL</code> +if and only if it cannot fill the request. Lua assumes that the allocator never fails when <code>osize >= nsize</code>. @@ -2534,6 +2744,9 @@ This code assumes that <code>free(NULL)</code> has no effect and that <code>realloc(NULL, size)</code> is equivalent to <code>malloc(size)</code>. ANSI C ensures both behaviors. +It also assumes that <code>realloc</code> does not fail when shrinking a block. +(ANSI C does not ensure this behavior, +but it seems a safe assumption.) @@ -2544,20 +2757,14 @@ ANSI C ensures both behaviors. <pre>lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);</pre> <p> -Sets a new panic function and returns the old one. +Sets a new panic function and returns the old one (see <a href="#3.6">§3.6</a>). <p> -If an error happens outside any protected environment, -Lua calls a <em>panic function</em> -and then calls <code>exit(EXIT_FAILURE)</code>, -thus exiting the host application. -Your panic function can avoid this exit by -never returning (e.g., doing a long jump). - - -<p> -The panic function can access the error message at the top of the stack. +The panic function should not try to run anything on the failed Lua state. +However, it can still use the debug API (see <a href="#3.9">§3.9</a>) +to gather information about the state. +In particular, the error message is at the top of the stack. @@ -2606,14 +2813,14 @@ equivalent to this Lua code: Here it is in C: <pre> - lua_getfield(L, LUA_GLOBALSINDEX, "f"); /* function to be called */ + lua_getfield(L, LUA_ENVIRONINDEX, "f"); /* function to be called */ lua_pushstring(L, "how"); /* 1st argument */ - lua_getfield(L, LUA_GLOBALSINDEX, "t"); /* table to be indexed */ + lua_getfield(L, LUA_ENVIRONINDEX, "t"); /* table to be indexed */ lua_getfield(L, -1, "x"); /* push result of t.x (2nd arg) */ lua_remove(L, -2); /* remove 't' from the stack */ lua_pushinteger(L, 14); /* 3rd argument */ lua_call(L, 3, 1); /* call 'f' with 3 arguments and 1 result */ - lua_setfield(L, LUA_GLOBALSINDEX, "a"); /* set global 'a' */ + lua_setfield(L, LUA_ENVIRONINDEX, "a"); /* set global 'a' */ </pre><p> Note that the code above is "balanced": at its end, the stack is back to its original configuration. @@ -2623,6 +2830,19 @@ This is considered good programming practice. +<hr><h3><a name="lua_callk"><code>lua_callk</code></a></h3><p> +<span class="apii">[-(nargs + 1), +nresults, <em>e</em>]</span> +<pre>void lua_callk (lua_State *L, int nargs, int nresults, + int ctx, lua_CFunction k);</pre> + +<p> +This function behaves exactly like <a href="#lua_call"><code>lua_call</code></a>, +but allows the called function to yield (see <a href="#3.7">§3.7</a>). + + + + + <hr><h3><a name="lua_CFunction"><code>lua_CFunction</code></a></h3> <pre>typedef int (*lua_CFunction) (lua_State *L);</pre> @@ -2675,12 +2895,15 @@ of numerical arguments and returns their average and sum: <hr><h3><a name="lua_checkstack"><code>lua_checkstack</code></a></h3><p> -<span class="apii">[-0, +0, <em>m</em>]</span> +<span class="apii">[-0, +0, <em>-</em>]</span> <pre>int lua_checkstack (lua_State *L, int extra);</pre> <p> Ensures that there are at least <code>extra</code> free stack slots in the stack. -It returns false if it cannot grow the stack to that size. +It returns false if it cannot grant the request, +because it would cause the stack to be larger than a fixed maximum size +(typically at least a few thousand elements) or +because it cannot allocate memory for the new stack size. This function never shrinks the stack; if the stack is already larger than the new size, it is left unchanged. @@ -2708,6 +2931,33 @@ to avoid growing too large. +<hr><h3><a name="lua_compare"><code>lua_compare</code></a></h3><p> +<span class="apii">[-0, +0, <em>e</em>]</span> +<pre>int lua_compare (lua_State *L, int index1, int index2, int op);</pre> + +<p> +Returns 1 if the value at acceptable index <code>index1</code> satisfies <code>op</code> +when compared with the value at acceptable index <code>index2</code>, +following the semantics of the corresponding Lua operator +(that is, may call metamethods). +Otherwise returns 0. +Also returns 0 if any of the indices is non valid. + + +<p> +The value of <code>op</code> must be one of the following constants: + +<ul> + +<li><b>@<a name="pdf-LUA_OPEQ"><code>LUA_OPEQ</code></a>:</b>compares for equality (<code>==</code>)</li> +<li><b>@<a name="pdf-LUA_OPLT"><code>LUA_OPLT</code></a>:</b>compares for less than (<code><</code>)</li> +<li><b>@<a name="pdf-LUA_OPLE"><code>LUA_OPLE</code></a>:</b>compares for less or equal (<code><=</code>)</li> + +</ul> + + + + <hr><h3><a name="lua_concat"><code>lua_concat</code></a></h3><p> <span class="apii">[-n, +1, <em>e</em>]</span> <pre>void lua_concat (lua_State *L, int n);</pre> @@ -2725,19 +2975,15 @@ Concatenation is performed following the usual semantics of Lua -<hr><h3><a name="lua_cpcall"><code>lua_cpcall</code></a></h3><p> -<span class="apii">[-0, +(0|1), <em>-</em>]</span> -<pre>int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);</pre> +<hr><h3><a name="lua_copy"><code>lua_copy</code></a></h3><p> +<span class="apii">[-0, +0, <em>-</em>]</span> +<pre>void lua_copy (lua_State *L, int fromidx, int toidx);</pre> <p> -Calls the C function <code>func</code> in protected mode. -<code>func</code> starts with only one element in its stack, -a light userdata containing <code>ud</code>. -In case of errors, -<a href="#lua_cpcall"><code>lua_cpcall</code></a> returns the same error codes as <a href="#lua_pcall"><code>lua_pcall</code></a>, -plus the error object on the top of the stack; -otherwise, it returns zero, and does not change the stack. -All values returned by <code>func</code> are discarded. +Moves the element at the valid index <code>fromidx</code> +into the valid index <code>toidx</code> +without shifting any element +(therefore replacing the value at that position). @@ -2788,22 +3034,6 @@ This function does not pop the Lua function from the stack. -<hr><h3><a name="lua_equal"><code>lua_equal</code></a></h3><p> -<span class="apii">[-0, +0, <em>e</em>]</span> -<pre>int lua_equal (lua_State *L, int index1, int index2);</pre> - -<p> -Returns 1 if the two values in acceptable indices <code>index1</code> and -<code>index2</code> are equal, -following the semantics of the Lua <code>==</code> operator -(that is, may call metamethods). -Otherwise returns 0. -Also returns 0 if any of the indices is non valid. - - - - - <hr><h3><a name="lua_error"><code>lua_error</code></a></h3><p> <span class="apii">[-1, +0, <em>v</em>]</span> <pre>int lua_error (lua_State *L);</pre> @@ -2877,6 +3107,11 @@ the collector (see <a href="#2.10">§2.10</a>). The function returns the previous value of the step multiplier. </li> +<li><b><code>LUA_GCISRUNNING</code>:</b> +returns a boolean that tells whether the collector is running +(i.e., not stopped). +</li> + </ul> @@ -2895,6 +3130,42 @@ opaque pointer passed to <a href="#lua_newstate"><code>lua_newstate</code></a>. +<hr><h3><a name="lua_getctx"><code>lua_getctx</code></a></h3><p> +<span class="apii">[-0, +0, <em>-</em>]</span> +<pre>int lua_getctx (lua_State *L, int *ctx);</pre> + +<p> +This function is called by a continuation function (see <a href="#3.7">§3.7</a>) +to retrieve the status of the thread and a context information. + + +<p> +When called in the original function, +<a href="#lua_getctx"><code>lua_getctx</code></a> always returns <a href="#pdf-LUA_OK"><code>LUA_OK</code></a> +and does not change the value of its argument <code>ctx</code>. +When called inside a continuation function, +<a href="#lua_getctx"><code>lua_getctx</code></a> returns <a href="#pdf-LUA_YIELD"><code>LUA_YIELD</code></a> and sets +the value of <code>ctx</code> to be the context information +(the value passed as the <code>ctx</code> argument +to the callee together with the continuation function). + + +<p> +When the callee is <a href="#lua_pcallk"><code>lua_pcallk</code></a>, +Lua may also call its continuation function +to handle errors during the call. +That is, upon an error in the function called by <a href="#lua_pcallk"><code>lua_pcallk</code></a>, +Lua may not return <a href="#lua_pcallk"><code>lua_pcallk</code></a> +but instead may call the continuation function. +In that case, a call to <a href="#lua_getctx"><code>lua_getctx</code></a> will return the error code +(the value that would be returned by <a href="#lua_pcallk"><code>lua_pcallk</code></a>); +the value of <code>ctx</code> will be set to the context information, +as in the case of an yield. + + + + + <hr><h3><a name="lua_getfenv"><code>lua_getfenv</code></a></h3><p> <span class="apii">[-0, +1, <em>-</em>]</span> <pre>void lua_getfenv (lua_State *L, int index);</pre> @@ -2930,7 +3201,7 @@ Pushes onto the stack the value of the global <code>name</code>. It is defined as a macro: <pre> - #define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, s) + #define lua_getglobal(L,s) lua_getfield(L, LUA_ENVIRONINDEX, s) </pre> @@ -3164,17 +3435,14 @@ Returns 1 if the value at the given acceptable index is a userdata -<hr><h3><a name="lua_lessthan"><code>lua_lessthan</code></a></h3><p> -<span class="apii">[-0, +0, <em>e</em>]</span> -<pre>int lua_lessthan (lua_State *L, int index1, int index2);</pre> +<hr><h3><a name="lua_len"><code>lua_len</code></a></h3><p> +<span class="apii">[-0, +1, <em>e</em>]</span> +<pre>void lua_len (lua_State *L, int index);</pre> <p> -Returns 1 if the value at acceptable index <code>index1</code> is smaller -than the value at acceptable index <code>index2</code>, -following the semantics of the Lua <code><</code> operator -(that is, may call metamethods). -Otherwise returns 0. -Also returns 0 if any of the indices is non valid. +Returns the "length" of the value at the given acceptable index; +it is equivalent to the '<code>#</code>' operator in Lua (see <a href="#2.5.5">§2.5.5</a>). +The result is pushed on the stack. @@ -3185,7 +3453,7 @@ Also returns 0 if any of the indices is non valid. <pre>int lua_load (lua_State *L, lua_Reader reader, void *data, - const char *chunkname);</pre> + const char *source);</pre> <p> Loads a Lua chunk. @@ -3197,7 +3465,7 @@ The return values of <a href="#lua_load"><code>lua_load</code></a> are: <ul> -<li><b>0:</b> no errors;</li> +<li><b><a href="#pdf-LUA_OK"><code>LUA_OK</code></a> (0):</b> no errors;</li> <li><b><a name="pdf-LUA_ERRSYNTAX"><code>LUA_ERRSYNTAX</code></a>:</b> syntax error during pre-compilation;</li> @@ -3205,6 +3473,12 @@ syntax error during pre-compilation;</li> <li><b><a href="#pdf-LUA_ERRMEM"><code>LUA_ERRMEM</code></a>:</b> memory allocation error.</li> +<li><b><a href="#pdf-LUA_ERRGCMM"><code>LUA_ERRGCMM</code></a>:</b> +error while running a <code>__gc</code> metamethod. +(This error has no relation with the chunk being loaded. +It is generated by the garbage collector.) +</li> + </ul> <p> @@ -3224,8 +3498,8 @@ The <code>data</code> argument is an opaque value passed to the reader function. <p> -The <code>chunkname</code> argument gives a name to the chunk, -which is used for error messages and in debug information (see <a href="#3.8">§3.8</a>). +The <code>source</code> argument gives a name to the chunk, +which is used for error messages and in debug information (see <a href="#3.9">§3.9</a>). @@ -3236,8 +3510,8 @@ which is used for error messages and in debug information (see <a href="#3.8">&s <pre>lua_State *lua_newstate (lua_Alloc f, void *ud);</pre> <p> -Creates a new, independent state. -Returns <code>NULL</code> if cannot create the state +Creates a new thread running in a new, independent state. +Returns <code>NULL</code> if cannot create the thread/state (due to lack of memory). The argument <code>f</code> is the allocator function; Lua does all memory allocation for this state through this function. @@ -3267,7 +3541,7 @@ It is equivalent to <code>lua_createtable(L, 0, 0)</code>. <p> Creates a new thread, pushes it on the stack, and returns a pointer to a <a href="#lua_State"><code>lua_State</code></a> that represents this new thread. -The new state returned by this function shares with the original state +The new thread returned by this function shares with the original thread all global objects (such as tables), but has an independent execution stack. @@ -3316,7 +3590,7 @@ Lua frees its corresponding memory. <p> Pops a key from the stack, -and pushes a key-value pair from the table at the given index +and pushes a key–value pair from the table at the given index (the "next" pair after the given key). If there are no more elements in the table, then <a href="#lua_next"><code>lua_next</code></a> returns 0 (and pushes nothing). @@ -3356,32 +3630,13 @@ this confuses the next call to <a href="#lua_next"><code>lua_next</code></a>. <p> The type of numbers in Lua. By default, it is double, but that can be changed in <code>luaconf.h</code>. - - -<p> -Through the configuration file you can change +Through this configuration file you can change Lua to operate with another type for numbers (e.g., float or long). -<hr><h3><a name="lua_objlen"><code>lua_objlen</code></a></h3><p> -<span class="apii">[-0, +0, <em>-</em>]</span> -<pre>size_t lua_objlen (lua_State *L, int index);</pre> - -<p> -Returns the "length" of the value at the given acceptable index: -for strings, this is the string length; -for tables, this is the result of the length operator ('<code>#</code>'); -for userdata, this is the size of the block of memory allocated -for the userdata; -for other values, it is 0. - - - - - <hr><h3><a name="lua_pcall"><code>lua_pcall</code></a></h3><p> <span class="apii">[-(nargs + 1), +(nresults|1), <em>-</em>]</span> <pre>int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);</pre> @@ -3424,12 +3679,14 @@ since by then the stack has unwound. <p> -The <a href="#lua_pcall"><code>lua_pcall</code></a> function returns 0 in case of success -or one of the following error codes +The <a href="#lua_pcall"><code>lua_pcall</code></a> function returns one of the following codes (defined in <code>lua.h</code>): <ul> +<li><b><a name="pdf-LUA_OK"><code>LUA_OK</code></a> (0):</b> +success.</li> + <li><b><a name="pdf-LUA_ERRRUN"><code>LUA_ERRRUN</code></a>:</b> a runtime error. </li> @@ -3443,11 +3700,30 @@ For such errors, Lua does not call the error handler function. error while running the error handler function. </li> +<li><b><a name="pdf-LUA_ERRGCMM"><code>LUA_ERRGCMM</code></a>:</b> +error while running a <code>__gc</code> metamethod. +(This error typically has no relation with the function being called. +It is generated by the garbage collector.) +</li> + </ul> +<hr><h3><a name="lua_pcallk"><code>lua_pcallk</code></a></h3><p> +<span class="apii">[-(nargs + 1), +(nresults|1), <em>-</em>]</span> +<pre>int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, + int ctx, lua_CFunction k);</pre> + +<p> +This function behaves exactly like <a href="#lua_pcall"><code>lua_pcall</code></a>, +but allows the called function to yield (see <a href="#3.7">§3.7</a>). + + + + + <hr><h3><a name="lua_pop"><code>lua_pop</code></a></h3><p> <span class="apii">[-n, +0, <em>-</em>]</span> <pre>void lua_pop (lua_State *L, int n);</pre> @@ -3583,7 +3859,7 @@ Pushes a light userdata onto the stack. <p> Userdata represent C values in Lua. -A <em>light userdata</em> represents a pointer. +A <em>light userdata</em> represents a pointer, a <code>void*</code>. It is a value (like a number): you do not create it, it has no individual metatable, and it is not collected (as it was never created). @@ -3609,7 +3885,7 @@ In these cases, it automatically provides the string length. <hr><h3><a name="lua_pushlstring"><code>lua_pushlstring</code></a></h3><p> <span class="apii">[-0, +1, <em>m</em>]</span> -<pre>void lua_pushlstring (lua_State *L, const char *s, size_t len);</pre> +<pre>const char *lua_pushlstring (lua_State *L, const char *s, size_t len);</pre> <p> Pushes the string pointed to by <code>s</code> with size <code>len</code> @@ -3620,6 +3896,10 @@ the function returns. The string can contain embedded zeros. +<p> +Returns a pointer to the internal copy of the string. + + @@ -3647,7 +3927,7 @@ Pushes a number with value <code>n</code> onto the stack. <hr><h3><a name="lua_pushstring"><code>lua_pushstring</code></a></h3><p> <span class="apii">[-0, +1, <em>m</em>]</span> -<pre>void lua_pushstring (lua_State *L, const char *s);</pre> +<pre>const char *lua_pushstring (lua_State *L, const char *s);</pre> <p> Pushes the zero-terminated string pointed to by <code>s</code> @@ -3659,6 +3939,10 @@ The string cannot contain embedded zeros; it is assumed to end at the first zero. +<p> +Returns a pointer to the internal copy of the string. + + @@ -3733,7 +4017,7 @@ Similar to <a href="#lua_gettable"><code>lua_gettable</code></a>, but does a raw <p> Pushes onto the stack the value <code>t[n]</code>, -where <code>t</code> is the value at the given valid index. +where <code>t</code> is the table at the given valid index. The access is raw; that is, it does not invoke metamethods. @@ -3741,6 +4025,23 @@ that is, it does not invoke metamethods. +<hr><h3><a name="lua_rawlen"><code>lua_rawlen</code></a></h3><p> +<span class="apii">[-0, +0, <em>-</em>]</span> +<pre>size_t lua_rawlen (lua_State *L, int index);</pre> + +<p> +Returns the raw "length" of the value at the given acceptable index: +for strings, this is the string length; +for tables, this is the result of the length operator ('<code>#</code>') +with no metamethods; +for userdata, this is the size of the block of memory allocated +for the userdata; +for other values, it is 0. + + + + + <hr><h3><a name="lua_rawset"><code>lua_rawset</code></a></h3><p> <span class="apii">[-2, +0, <em>m</em>]</span> <pre>void lua_rawset (lua_State *L, int index);</pre> @@ -3759,7 +4060,7 @@ Similar to <a href="#lua_settable"><code>lua_settable</code></a>, but does a raw <p> Does the equivalent of <code>t[n] = v</code>, -where <code>t</code> is the value at the given valid index +where <code>t</code> is the table at the given valid index and <code>v</code> is the value at the top of the stack. @@ -3831,9 +4132,10 @@ because a pseudo-index is not an actual stack position. <pre>void lua_replace (lua_State *L, int index);</pre> <p> -Moves the top element into the given position (and pops it), +Moves the top element into the given position without shifting any element -(therefore replacing the value at the given position). +(therefore replacing the value at the given position), +and then pops the top element. @@ -3848,9 +4150,8 @@ Starts and resumes a coroutine in a given thread. <p> -To start a coroutine, you first create a new thread -(see <a href="#lua_newthread"><code>lua_newthread</code></a>); -then you push onto its stack the main function plus any arguments; +To start a coroutine, +you push onto the thread stack the main function plus any arguments; then you call <a href="#lua_resume"><code>lua_resume</code></a>, with <code>narg</code> being the number of arguments. This call returns when the coroutine suspends or finishes its execution. @@ -3858,14 +4159,20 @@ When it returns, the stack contains all values passed to <a href="#lua_yield"><c or all values returned by the body function. <a href="#lua_resume"><code>lua_resume</code></a> returns <a href="#pdf-LUA_YIELD"><code>LUA_YIELD</code></a> if the coroutine yields, -0 if the coroutine finishes its execution +<a href="#pdf-LUA_OK"><code>LUA_OK</code></a> if the coroutine finishes its execution without errors, or an error code in case of errors (see <a href="#lua_pcall"><code>lua_pcall</code></a>). + + +<p> In case of errors, the stack is not unwound, so you can use the debug API over it. The error message is on the top of the stack. -To restart a coroutine, you put on its stack only the values to + + +<p> +To resume a coroutine, you put on its stack only the values to be passed as results from <code>yield</code>, and then call <a href="#lua_resume"><code>lua_resume</code></a>. @@ -3893,7 +4200,7 @@ with user data <code>ud</code>. Pops a table from the stack and sets it as the new environment for the value at the given index. If the value at the given index is -neither a function nor a thread nor a userdata, +neither a function nor a userdata, <a href="#lua_setfenv"><code>lua_setfenv</code></a> returns 0. Otherwise it returns 1. @@ -3930,7 +4237,7 @@ sets it as the new value of global <code>name</code>. It is defined as a macro: <pre> - #define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, s) + #define lua_setglobal(L,s) lua_setfield(L, LUA_ENVIRONINDEX, s) </pre> @@ -4012,8 +4319,9 @@ Returns the status of the thread <code>L</code>. <p> -The status can be 0 for a normal thread, -an error code if the thread finished its execution with an error, +The status can be 0 (<a href="#pdf-LUA_OK"><code>LUA_OK</code></a>) for a normal thread, +an error code if the thread finished the execution +of a <a href="#lua_resume"><code>lua_resume</code></a> with an error, or <a name="pdf-LUA_YIELD"><code>LUA_YIELD</code></a> if the thread is suspended. @@ -4028,10 +4336,10 @@ or <a name="pdf-LUA_YIELD"><code>LUA_YIELD</code></a> if the thread is suspended Converts the Lua value at the given acceptable index to a C boolean value (0 or 1). Like all tests in Lua, -<a href="#lua_toboolean"><code>lua_toboolean</code></a> returns 1 for any Lua value +<a href="#lua_toboolean"><code>lua_toboolean</code></a> returns true for any Lua value different from <b>false</b> and <b>nil</b>; -otherwise it returns 0. -It also returns 0 when called with a non-valid index. +otherwise it returns false. +It also returns false when called with a non-valid index. (If you want to accept only actual boolean values, use <a href="#lua_isboolean"><code>lua_isboolean</code></a> to test the value's type.) @@ -4188,16 +4496,16 @@ or <code>LUA_TNONE</code> for a non-valid index (that is, an index to an "empty" stack position). The types returned by <a href="#lua_type"><code>lua_type</code></a> are coded by the following constants defined in <code>lua.h</code>: -<code>LUA_TNIL</code>, -<code>LUA_TNUMBER</code>, -<code>LUA_TBOOLEAN</code>, -<code>LUA_TSTRING</code>, -<code>LUA_TTABLE</code>, -<code>LUA_TFUNCTION</code>, -<code>LUA_TUSERDATA</code>, -<code>LUA_TTHREAD</code>, +<a name="pdf-LUA_TNIL"><code>LUA_TNIL</code></a>, +<a name="pdf-LUA_TNUMBER"><code>LUA_TNUMBER</code></a>, +<a name="pdf-LUA_TBOOLEAN"><code>LUA_TBOOLEAN</code></a>, +<a name="pdf-LUA_TSTRING"><code>LUA_TSTRING</code></a>, +<a name="pdf-LUA_TTABLE"><code>LUA_TTABLE</code></a>, +<a name="pdf-LUA_TFUNCTION"><code>LUA_TFUNCTION</code></a>, +<a name="pdf-LUA_TUSERDATA"><code>LUA_TUSERDATA</code></a>, +<a name="pdf-LUA_TTHREAD"><code>LUA_TTHREAD</code></a>, and -<code>LUA_TLIGHTUSERDATA</code>. +<a name="pdf-LUA_TLIGHTUSERDATA"><code>LUA_TLIGHTUSERDATA</code></a>. @@ -4215,6 +4523,21 @@ which must be one the values returned by <a href="#lua_type"><code>lua_type</cod +<hr><h3><a name="lua_version"><code>lua_version</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>const lua_Number *lua_version (lua_State *L);</pre> + +<p> +Returns the address of the version number stored in the Lua core. +When called with a valid <a href="#lua_State"><code>lua_State</code></a>, +returns the address of the version used to create that state. +When called with <code>NULL</code>, +returns the address of the version running the call. + + + + + <hr><h3><a name="lua_Writer"><code>lua_Writer</code></a></h3> <pre>typedef int (*lua_Writer) (lua_State *L, const void* p, @@ -4261,6 +4584,22 @@ and pushes them onto the stack <code>to</code>. <pre>int lua_yield (lua_State *L, int nresults);</pre> <p> +This function is equivalent to <a href="#lua_yieldk"><code>lua_yieldk</code></a>, +but it has no continuation (see <a href="#3.7">§3.7</a>). +Therefore, when the thread resumes, +it returns to the function that called +the function calling <code>lua_yield</code>. + + + + + +<hr><h3><a name="lua_yieldk"><code>lua_yieldk</code></a></h3><p> +<span class="apii">[-?, +?, <em>-</em>]</span> +<pre>int lua_yieldk (lua_State *L, int nresults, int ctx, + lua_CFunction k);</pre> + +<p> Yields a coroutine. @@ -4269,21 +4608,34 @@ This function should only be called as the return expression of a C function, as follows: <pre> - return lua_yield (L, nresults); + return lua_yield (L, nresults, i, k); </pre><p> -When a C function calls <a href="#lua_yield"><code>lua_yield</code></a> in that way, +When a C function calls <a href="#lua_yieldk"><code>lua_yieldk</code></a> in that way, the running coroutine suspends its execution, and the call to <a href="#lua_resume"><code>lua_resume</code></a> that started this coroutine returns. The parameter <code>nresults</code> is the number of values from the stack that are passed as results to <a href="#lua_resume"><code>lua_resume</code></a>. +<p> +When the coroutine is resumed again, +Lua calls the given continuation function <code>k</code> to continue +the execution of the C function that yielded (see <a href="#3.7">§3.7</a>). +This continuation function receives the same stack +from the previous function, +with the results removed and +replaced by the arguments passed to <a href="#lua_resume"><code>lua_resume</code></a>. +Moreover, +the continuation function may access the value <code>ctx</code> +by calling <a href="#lua_getctx"><code>lua_getctx</code></a>. -<h2>3.8 - <a name="3.8">The Debug Interface</a></h2> + + +<h2>3.9 - <a name="3.9">The Debug Interface</a></h2> <p> Lua has no built-in debugging facilities. @@ -4303,9 +4655,12 @@ that need "inside information" from the interpreter. const char *what; /* (S) */ const char *source; /* (S) */ int currentline; /* (l) */ - int nups; /* (u) number of upvalues */ int linedefined; /* (S) */ int lastlinedefined; /* (S) */ + unsigned char nups; /* (u) number of upvalues */ + unsigned char nparams; /* (u) number of parameters */ + char isvararg; /* (u) */ + char istailcall; /* (t) */ char short_src[LUA_IDSIZE]; /* (S) */ /* private part */ <em>other fields</em> @@ -4326,10 +4681,15 @@ The fields of <a href="#lua_Debug"><code>lua_Debug</code></a> have the following <ul> <li><b><code>source</code>:</b> -If the function was defined in a string, -then <code>source</code> is that string. -If the function was defined in a file, -then <code>source</code> starts with a '<code>@</code>' followed by the file name. +the source of the chunk that created the function. +If <code>source</code> starts with a '<code>@</code>', +it means that the function was defined in a file where +the file name follows the '<code>@</code>'. +If <code>source</code> starts with a '<code>=</code>', +the rest of it should describe the source in a user-dependent manner. +Otherwise, +the function was defined in a string where +<code>source</code> is that string. </li> <li><b><code>short_src</code>:</b> @@ -4347,10 +4707,7 @@ the line number where the definition of the function ends. <li><b><code>what</code>:</b> the string <code>"Lua"</code> if the function is a Lua function, <code>"C"</code> if it is a C function, -<code>"main"</code> if it is the main part of a chunk, -and <code>"tail"</code> if it was a function that did a tail call. -In the latter case, -Lua has no other information about the function. +<code>"main"</code> if it is the main part of a chunk. </li> <li><b><code>currentline</code>:</b> @@ -4380,10 +4737,25 @@ according to how the function was called. (Lua uses the empty string when no other option seems to apply.) </li> +<li><b><code>istailcall</code>:</b> +true if this function invocation was called by a tail call. +In this case, the caller of this level is not in the stack. +</li> + <li><b><code>nups</code>:</b> the number of upvalues of the function. </li> +<li><b><code>nparams</code>:</b> +the number of fixed parameters of the function +(always 0 for C functions). +</li> + +<li><b><code>isvararg</code>:</b> +whether the function is a vararg function +(always true for C functions). +</li> + </ul> @@ -4441,13 +4813,13 @@ given as argument to a hook (see <a href="#lua_Hook"><code>lua_Hook</code></a>). To get information about a function you push it onto the stack and start the <code>what</code> string with the character '<code>></code>'. (In that case, -<code>lua_getinfo</code> pops the function in the top of the stack.) +<code>lua_getinfo</code> pops the function from the top of the stack.) For instance, to know in which line a function <code>f</code> was defined, you can write the following code: <pre> lua_Debug ar; - lua_getfield(L, LUA_GLOBALSINDEX, "f"); /* get global 'f' */ + lua_getfield(L, LUA_ENVIRONINDEX, "f"); /* get global 'f' */ lua_getinfo(L, ">S", &ar); printf("%d\n", ar.linedefined); </pre> @@ -4470,6 +4842,9 @@ fills in the fields <code>source</code>, <code>short_src</code>, <li><b>'<code>l</code>':</b> fills in the field <code>currentline</code>; </li> +<li><b>'<code>t</code>':</b> fills in the field <code>istailcall</code>; +</li> + <li><b>'<code>u</code>':</b> fills in the field <code>nups</code>; </li> @@ -4589,16 +4964,17 @@ Whenever a hook is called, its <code>ar</code> argument has its field <code>event</code> set to the specific event that triggered the hook. Lua identifies these events with the following constants: <a name="pdf-LUA_HOOKCALL"><code>LUA_HOOKCALL</code></a>, <a name="pdf-LUA_HOOKRET"><code>LUA_HOOKRET</code></a>, -<a name="pdf-LUA_HOOKTAILRET"><code>LUA_HOOKTAILRET</code></a>, <a name="pdf-LUA_HOOKLINE"><code>LUA_HOOKLINE</code></a>, +<a name="pdf-LUA_HOOKTAILCALL"><code>LUA_HOOKTAILCALL</code></a>, <a name="pdf-LUA_HOOKLINE"><code>LUA_HOOKLINE</code></a>, and <a name="pdf-LUA_HOOKCOUNT"><code>LUA_HOOKCOUNT</code></a>. Moreover, for line events, the field <code>currentline</code> is also set. To get the value of any other field in <code>ar</code>, the hook must call <a href="#lua_getinfo"><code>lua_getinfo</code></a>. -For return events, <code>event</code> can be <code>LUA_HOOKRET</code>, -the normal value, or <code>LUA_HOOKTAILRET</code>. -In the latter case, Lua is simulating a return from -a function that did a tail call; -in this case, it is useless to call <a href="#lua_getinfo"><code>lua_getinfo</code></a>. + + +<p> +For call events, <code>event</code> can be <code>LUA_HOOKCALL</code>, +the normal value, or <code>LUA_HOOKTAILCALL</code>, for a tail call; +in this case, there will be no corresponding return event. <p> @@ -4705,6 +5081,29 @@ when the index is greater than the number of upvalues. +<hr><h3><a name="lua_upvalueid"><code>lua_upvalueid</code></a></h3><p> +<span class="apii">[-0, +0, <em>-</em>]</span> +<pre>void *(lua_upvalueid) (lua_State *L, int funcindex, int n);</pre> + +<p> +Returns an unique identifier for the upvalue numbered <code>n</code> +from the closure at index <code>fidx</code>. +Parameters <code>funcindex</code> and <code>n</code> are as in the <a href="#lua_getupvalue"><code>lua_getupvalue</code></a> +(see <a href="#lua_getupvalue"><code>lua_getupvalue</code></a>) +(but <code>n</code> cannot be greater than the number of upvalues). + + +<p> +These unique identifiers allow a program to check whether different +closures share upvalues. +Lua closures that share an upvalue +(that is, that access a same external local variable) +will return identical ids for those upvalue indices. + + + + + <h1>4 - <a name="4">The Auxiliary Library</a></h1> @@ -4728,19 +5127,22 @@ have a prefix <code>luaL_</code>. <p> All functions in the auxiliary library are built on top of the basic API, -and so they provide nothing that cannot be done with this API. +and so they provide nothing that cannot be done with that API. <p> Several functions in the auxiliary library are used to check C function arguments. -Their names are always <code>luaL_check*</code> or <code>luaL_opt*</code>. -All of these functions throw an error if the check is not satisfied. Because the error message is formatted for arguments (e.g., "<code>bad argument #1</code>"), you should not use these functions for other stack values. +<p> +Functions called <code>luaL_check*</code> +always throw an error if the check is not satisfied. + + <h2>4.1 - <a name="4.1">Functions and Types</a></h2> @@ -4938,10 +5340,10 @@ Calls a metamethod. If the object at index <code>obj</code> has a metatable and this metatable has a field <code>e</code>, this function calls this field and passes the object as its only argument. -In this case this function returns 1 and pushes onto the +In this case this function returns true and pushes onto the stack the value returned by the call. If there is no metatable or no metamethod, -this function returns 0 (without pushing any value on the stack). +this function returns false (without pushing any value on the stack). @@ -5064,7 +5466,8 @@ to use strings instead of numbers to select options.) <p> Grows the stack size to <code>top + sz</code> elements, raising an error if the stack cannot grow to that size. -<code>msg</code> is an additional text to go into the error message. +<code>msg</code> is an additional text to go into the error message +(or <code>NULL</code> for no additional text). @@ -5105,7 +5508,24 @@ See <a href="#lua_type"><code>lua_type</code></a> for the encoding of types for <p> Checks whether the function argument <code>narg</code> is a userdata -of the type <code>tname</code> (see <a href="#luaL_newmetatable"><code>luaL_newmetatable</code></a>). +of the type <code>tname</code> (see <a href="#luaL_newmetatable"><code>luaL_newmetatable</code></a>) and +returns the userdata address (see <a href="#lua_touserdata"><code>lua_touserdata</code></a>). + + + + + +<hr><h3><a name="luaL_checkversion"><code>luaL_checkversion</code></a></h3><p> +<span class="apii">[-0, +0, <em>-</em>]</span> +<pre>void *luaL_checkversion (lua_State *L);</pre> + +<p> +Checks whether the core running the call, +the core that created the Lua state, +and the code making the call are all using the same version of Lua. +Also checks whether the core running the call +and the core that created the Lua state +are using the same address space. @@ -5122,15 +5542,15 @@ It is defined as the following macro: <pre> (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0)) </pre><p> -It returns 0 if there are no errors -or 1 in case of errors. +It returns false if there are no errors +or true in case of errors. <hr><h3><a name="luaL_dostring"><code>luaL_dostring</code></a></h3><p> -<span class="apii">[-0, +?, <em>m</em>]</span> +<span class="apii">[-0, +?, <em>-</em>]</span> <pre>int luaL_dostring (lua_State *L, const char *str);</pre> <p> @@ -5140,8 +5560,8 @@ It is defined as the following macro: <pre> (luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0)) </pre><p> -It returns 0 if there are no errors -or 1 in case of errors. +It returns false if there are no errors +or true in case of errors. @@ -5179,7 +5599,7 @@ Pushes onto the stack the field <code>e</code> from the metatable of the object at index <code>obj</code>. If the object does not have a metatable, or if the metatable does not have this field, -returns 0 and pushes nothing. +returns false and pushes nothing. @@ -5214,8 +5634,23 @@ Pushes the resulting string on the stack and returns it. +<hr><h3><a name="luaL_len"><code>luaL_len</code></a></h3><p> +<span class="apii">[-0, +1, <em>e</em>]</span> +<pre>int luaL_len (lua_State *L, int index);</pre> + +<p> +Returns the "length" of the value at the given acceptable index +as a number; +it is equivalent to the '<code>#</code>' operator in Lua (see <a href="#2.5.5">§2.5.5</a>). +Raises an error if the result of the operation is not a number. +(This only may happen through metamethods.) + + + + + <hr><h3><a name="luaL_loadbuffer"><code>luaL_loadbuffer</code></a></h3><p> -<span class="apii">[-0, +1, <em>m</em>]</span> +<span class="apii">[-0, +1, <em>-</em>]</span> <pre>int luaL_loadbuffer (lua_State *L, const char *buff, size_t sz, @@ -5264,7 +5699,7 @@ it does not run it. <hr><h3><a name="luaL_loadstring"><code>luaL_loadstring</code></a></h3><p> -<span class="apii">[-0, +1, <em>m</em>]</span> +<span class="apii">[-0, +1, <em>-</em>]</span> <pre>int luaL_loadstring (lua_State *L, const char *s);</pre> <p> @@ -5314,7 +5749,7 @@ with <code>tname</code> in the registry. Creates a new Lua state. It calls <a href="#lua_newstate"><code>lua_newstate</code></a> with an allocator based on the standard C <code>realloc</code> function -and then sets a panic function (see <a href="#lua_atpanic"><code>lua_atpanic</code></a>) that prints +and then sets a panic function (see <a href="#3.6">§3.6</a>) that prints an error message to the standard error output in case of fatal errors. @@ -5527,8 +5962,10 @@ Opens a library. <p> When called with <code>libname</code> equal to <code>NULL</code>, -it simply registers all functions in the list <code>l</code> +it simply registers all functions in the array <code>l</code> (see <a href="#luaL_Reg"><code>luaL_Reg</code></a>) into the table on the top of the stack. +The pointer <code>l</code> may be <code>NULL</code>, +representing an empty list. <p> @@ -5550,6 +5987,35 @@ on the top of the stack. +<hr><h3><a name="luaL_testudata"><code>luaL_testudata</code></a></h3><p> +<span class="apii">[-0, +0, <em>m</em>]</span> +<pre>void *luaL_testudata (lua_State *L, int narg, const char *tname);</pre> + +<p> +This function works like <a href="#luaL_checkudata"><code>luaL_checkudata</code></a>, +except that, when the test fails, +it returns <code>NULL</code> instead of throwing an error. + + + + + +<hr><h3><a name="luaL_traceback"><code>luaL_traceback</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>luaL_traceback (lua_State *L, lua_State *L1, + const char *msg, int level);</pre> + +<p> +Creates and pushes a traceback of the stack <code>L1</code>. +If <code>msg</code> is not <code>NULL</code> it is appended +at the beginning of the traceback. +The <code>level</code> parameter tells at which level +to start the traceback. + + + + + <hr><h3><a name="luaL_typename"><code>luaL_typename</code></a></h3><p> <span class="apii">[-0, +0, <em>-</em>]</span> <pre>const char *luaL_typename (lua_State *L, int index);</pre> @@ -5561,9 +6027,9 @@ Returns the name of the type of the value at the given index. -<hr><h3><a name="luaL_typerror"><code>luaL_typerror</code></a></h3><p> +<hr><h3><a name="luaL_typeerror"><code>luaL_typeerror</code></a></h3><p> <span class="apii">[-0, +0, <em>v</em>]</span> -<pre>int luaL_typerror (lua_State *L, int narg, const char *tname);</pre> +<pre>int luaL_typeerror (lua_State *L, int narg, const char *tname);</pre> <p> Generates an error with a message like the following: @@ -5645,7 +6111,7 @@ Currently, Lua has the following standard libraries: <ul> -<li>basic library,</li> which includes the coroutine sub-library; +<li>basic library, which includes the coroutine sub-library;</li> <li>package library;</li> @@ -5655,6 +6121,8 @@ Currently, Lua has the following standard libraries: <li>mathematical functions (sin, log, etc.);</li> +<li>bitwise operations;</li> + <li>input and output;</li> <li>operating system facilities;</li> @@ -5678,6 +6146,7 @@ it can open them individually by calling <a name="pdf-luaopen_string"><code>luaopen_string</code></a> (for the string library), <a name="pdf-luaopen_table"><code>luaopen_table</code></a> (for the table library), <a name="pdf-luaopen_math"><code>luaopen_math</code></a> (for the mathematical library), +<a name="pdf-luaopen_bitlib"><code>luaopen_bitlib</code></a> (for the bit library), <a name="pdf-luaopen_io"><code>luaopen_io</code></a> (for the I/O library), <a name="pdf-luaopen_os"><code>luaopen_os</code></a> (for the Operating System library), and <a name="pdf-luaopen_debug"><code>luaopen_debug</code></a> (for the debug library). @@ -5709,7 +6178,7 @@ when absent, it defaults to "assertion failed!" <p> -<hr><h3><a name="pdf-collectgarbage"><code>collectgarbage (opt [, arg])</code></a></h3> +<hr><h3><a name="pdf-collectgarbage"><code>collectgarbage ([opt [, arg]])</code></a></h3> <p> @@ -5718,6 +6187,11 @@ It performs different functions according to its first argument, <code>opt</code <ul> +<li><b>"collect":</b> +performs a full garbage-collection cycle. +This is the default option. +</li> + <li><b>"stop":</b> stops the garbage collector. </li> @@ -5726,12 +6200,16 @@ stops the garbage collector. restarts the garbage collector. </li> -<li><b>"collect":</b> -performs a full garbage-collection cycle. -</li> - <li><b>"count":</b> -returns the total memory in use by Lua (in Kbytes). +returns the total memory in use by Lua (in Kbytes) and +a second value with the total memory in bytes modulo 1024. +The first value has a fractional part, +so the following equality is always true: + +<pre> + k, b = collectgarbage("count") + assert(k*1024 == math.floor(k)*1024 + b) +</pre><p> </li> <li><b>"step":</b> @@ -5755,12 +6233,17 @@ the collector (see <a href="#2.10">§2.10</a>). Returns the previous value for <em>step</em>. </li> +<li><b>"isrunning":</b> +returns a boolean that tells whether the collector is running +(i.e., not stopped). +</li> + </ul> <p> -<hr><h3><a name="pdf-dofile"><code>dofile (filename)</code></a></h3> +<hr><h3><a name="pdf-dofile"><code>dofile ([filename])</code></a></h3> Opens the named file and executes its contents as a Lua chunk. When called without arguments, <code>dofile</code> executes the contents of the standard input (<code>stdin</code>). @@ -5780,7 +6263,7 @@ Function <code>error</code> never returns. <p> Usually, <code>error</code> adds some information about the error position -at the beginning of the message. +at the beginning of the message, if the message is a string. The <code>level</code> argument specifies how to get the error position. With level 1 (the default), the error position is where the <code>error</code> function was called. @@ -5795,25 +6278,10 @@ to the message. <p> <hr><h3><a name="pdf-_G"><code>_G</code></a></h3> A global variable (not a function) that -holds the global environment (that is, <code>_G._G = _G</code>). +holds the global environment (so that <code>_G._G = _G</code>). Lua itself does not use this variable; changing its value does not affect any environment, nor vice-versa. -(Use <a href="#pdf-setfenv"><code>setfenv</code></a> to change environments.) - - - - -<p> -<hr><h3><a name="pdf-getfenv"><code>getfenv ([f])</code></a></h3> -Returns the current environment in use by the function. -<code>f</code> can be a Lua function or a number -that specifies the function at that stack level: -Level 1 is the function calling <code>getfenv</code>. -If the given function is not a Lua function, -or if <code>f</code> is 0, -<code>getfenv</code> returns the global environment. -The default for <code>f</code> is 1. @@ -5837,30 +6305,47 @@ Otherwise, returns the metatable of the given object. <p> -Returns three values: an iterator function, the table <code>t</code>, and 0, +If <code>t</code> has a metamethod <code>__ipairs</code>, +calls it with <code>t</code> as argument and returns the first three +results from the call. + + +<p> +Otherwise, +returns three values: an iterator function, the table <code>t</code>, and 0, so that the construction <pre> for i,v in ipairs(t) do <em>body</em> end </pre><p> will iterate over the pairs (<code>1,t[1]</code>), (<code>2,t[2]</code>), ···, -up to the first integer key absent from the table. +up to the length of the table, +as defined by the length operator (see <a href="#2.5.5">§2.5.5</a>). + +<p> +<hr><h3><a name="pdf-load"><code>load (ld [, source [, mode]])</code></a></h3> + <p> -<hr><h3><a name="pdf-load"><code>load (func [, chunkname])</code></a></h3> +Loads a chunk. <p> -Loads a chunk using function <code>func</code> to get its pieces. -Each call to <code>func</code> must return a string that concatenates +If <code>ld</code> is a function, +calls it repeatedly to get the chunk pieces. +Each call to <code>ld</code> must return a string that concatenates with previous results. A return of an empty string, <b>nil</b>, or no value signals the end of the chunk. <p> +If <code>ld</code> is a string, the chunk is this string. + + +<p> If there are no errors, returns the compiled chunk as a function; otherwise, returns <b>nil</b> plus the error message. @@ -5868,12 +6353,33 @@ The environment of the returned function is the global environment. <p> -<code>chunkname</code> is used as the chunk name for error messages -and debug information. +<code>source</code> is used as the source of the chunk for error messages +and debug information (see <a href="#3.9">§3.9</a>). When absent, it defaults to "<code>=(load)</code>". +<p> +The string <code>mode</code> controls whether the chunk can be text or binary +(that is, a precompiled chunk). +A letter '<code>t</code>' in <code>mode</code> allows a text chunk; +a letter '<code>b</code>' allows a binary chunk. +The default is "<code>bt</code>". + + + + +<p> +<hr><h3><a name="pdf-loadin"><code>loadin (env, ...)</code></a></h3> + + +<p> +This function is similar to <a href="#pdf-load"><code>load</code></a>, +but sets <code>env</code> as the environment +of the created function in case of success. +The parameters after <code>env</code> are similar to those of <a href="#pdf-load"><code>load</code></a>, too. + + <p> @@ -5955,7 +6461,14 @@ In particular, you may clear existing fields. <p> -Returns three values: the <a href="#pdf-next"><code>next</code></a> function, the table <code>t</code>, and <b>nil</b>, +If <code>t</code> has a metamethod <code>__pairs</code>, +calls it with <code>t</code> as argument and returns the first three +results from the call. + + +<p> +Otherwise, +returns three values: the <a href="#pdf-next"><code>next</code></a> function, the table <code>t</code>, and <b>nil</b>, so that the construction <pre> @@ -5972,7 +6485,7 @@ the table during its traversal. <p> -<hr><h3><a name="pdf-pcall"><code>pcall (f, arg1, ···)</code></a></h3> +<hr><h3><a name="pdf-pcall"><code>pcall (f [, arg1, ···])</code></a></h3> <p> @@ -6043,7 +6556,8 @@ This function returns <code>table</code>. <p> If <code>index</code> is a number, -returns all arguments after argument number <code>index</code>. +returns all arguments after argument number <code>index</code>; +a negative number indexes from the end (-1 is the last argument). Otherwise, <code>index</code> must be the string <code>"#"</code>, and <code>select</code> returns the total number of extra arguments it received. @@ -6051,26 +6565,6 @@ and <code>select</code> returns the total number of extra arguments it received. <p> -<hr><h3><a name="pdf-setfenv"><code>setfenv (f, table)</code></a></h3> - - -<p> -Sets the environment to be used by the given function. -<code>f</code> can be a Lua function or a number -that specifies the function at that stack level: -Level 1 is the function calling <code>setfenv</code>. -<code>setfenv</code> returns the given function. - - -<p> -As a special case, when <code>f</code> is 0 <code>setfenv</code> changes -the environment of the running thread. -In this case, <code>setfenv</code> returns no values. - - - - -<p> <hr><h3><a name="pdf-setmetatable"><code>setmetatable (table, metatable)</code></a></h3> @@ -6144,22 +6638,6 @@ and "<code>userdata</code>". <p> -<hr><h3><a name="pdf-unpack"><code>unpack (list [, i [, j]])</code></a></h3> -Returns the elements from the given table. -This function is equivalent to - -<pre> - return list[i], list[i+1], ···, list[j] -</pre><p> -except that the above code can be written only for a fixed number -of elements. -By default, <code>i</code> is 1 and <code>j</code> is the length of the list, -as defined by the length operator (see <a href="#2.5.5">§2.5.5</a>). - - - - -<p> <hr><h3><a name="pdf-_VERSION"><code>_VERSION</code></a></h3> A global variable (not a function) that holds a string containing the current interpreter version. @@ -6169,27 +6647,12 @@ The current contents of this variable is "<code>Lua 5.1</code>". <p> -<hr><h3><a name="pdf-xpcall"><code>xpcall (f, err)</code></a></h3> +<hr><h3><a name="pdf-xpcall"><code>xpcall (f, err [, arg1, ···])</code></a></h3> <p> This function is similar to <a href="#pdf-pcall"><code>pcall</code></a>, -except that you can set a new error handler. - - -<p> -<code>xpcall</code> calls function <code>f</code> in protected mode, -using <code>err</code> as the error handler. -Any error inside <code>f</code> is not propagated; -instead, <code>xpcall</code> catches the error, -calls the <code>err</code> function with the original error object, -and returns a status code. -Its first result is the status code (a boolean), -which is true if the call succeeds without errors. -In this case, <code>xpcall</code> also returns all results from the call, -after this first result. -In case of any error, -<code>xpcall</code> returns <b>false</b> plus the result from <code>err</code>. +except that it sets a new error handler <code>err</code>. @@ -6250,8 +6713,8 @@ If there is any error, <p> -Returns the running coroutine, -or <b>nil</b> when called by the main thread. +Returns the running coroutine plus a boolean, +true when the running coroutine is the main one. @@ -6322,7 +6785,7 @@ Everything else is exported in a table <a name="pdf-package"><code>package</code <p> -Creates a module. +Creates and returns a module. If there is a table in <code>package.loaded[name]</code>, this table is the module. Otherwise, if there is a global table <code>t</code> with the given name, @@ -6334,12 +6797,15 @@ This function also initializes <code>t._NAME</code> with the given name, <code>t._M</code> with the module (<code>t</code> itself), and <code>t._PACKAGE</code> with the package name (the full module name minus last component; see below). -Finally, <code>module</code> sets <code>t</code> as the new environment -of the current function and the new value of <code>package.loaded[name]</code>, +Finally, <code>module</code> sets <code>t</code> as the new value of <code>package.loaded[name]</code>, so that <a href="#pdf-require"><code>require</code></a> returns <code>t</code>. <p> +The <code>module</code> function returns the module table <code>t</code>. + + +<p> If <code>name</code> is a compound name (that is, one with components separated by dots), <code>module</code> creates (or reuses, if they already exist) @@ -6355,6 +6821,12 @@ the module name, where each option is a function to be applied over the module. +<p> +To keep compatibility with old versions of Lua, +<code>module</code> also sets <code>t</code> as the new environment +of the current function. + + <p> @@ -6412,6 +6884,38 @@ then <code>require</code> signals an error. <p> +<hr><h3><a name="pdf-package.config"><code>package.config</code></a></h3> + + +<p> +A string describing some compile-time configurations for packages. +This string is a sequence of lines: + +<ul> + +<li>The first line is the directory separator string. +Default is '<code>\</code>' for Windows and '<code>/</code>' for all other systems.</li> + +<li>The second line is the character that separates templates in a path. +Default is '<code>;</code>'.</li> + +<li>The third line is the string that marks the +substitution points in a template. +Default is '<code>?</code>'.</li> + +<li>The fourth line is a string that, in a path in Windows, +is replaced by the executable's directory. +Default is '<code>!</code>'.</li> + +<li>The fifth line is a mark to ignore all before it when bulding the +<code>luaopen_</code> function name. +Default is '<code>-</code>'.</li> + +</ul> + + + +<p> <hr><h3><a name="pdf-package.cpath"><code>package.cpath</code></a></h3> @@ -6441,6 +6945,12 @@ When you require a module <code>modname</code> and <a href="#pdf-require"><code>require</code></a> simply returns the value stored there. +<p> +This variable is only a reference to the real table; +assignments to this variable do not change the +table used by <a href="#pdf-require"><code>require</code></a>. + + <p> @@ -6471,27 +6981,14 @@ The first searcher simply looks for a loader in the <p> The second searcher looks for a loader as a Lua library, using the path stored at <a href="#pdf-package.path"><code>package.path</code></a>. -A path is a sequence of <em>templates</em> separated by semicolons. -For each template, -the searcher will change each interrogation -mark in the template by <code>filename</code>, -which is the module name with each dot replaced by a -"directory separator" (such as "<code>/</code>" in Unix); -then it will try to open the resulting file name. -So, for instance, if the Lua path is the string - -<pre> - "./?.lua;./?.lc;/usr/local/?/init.lua" -</pre><p> -the search for a Lua file for module <code>foo</code> -will try to open the files -<code>./foo.lua</code>, <code>./foo.lc</code>, and -<code>/usr/local/foo/init.lua</code>, in that order. +The search is done as described in function <a href="#pdf-package.searchpath"><code>package.searchpath</code></a>. <p> The third searcher looks for a loader as a C library, using the path given by the variable <a href="#pdf-package.cpath"><code>package.cpath</code></a>. +Again, +the search is done as described in function <a href="#pdf-package.searchpath"><code>package.searchpath</code></a>. For instance, if the C path is the string @@ -6537,7 +7034,15 @@ with each submodule keeping its original open function. <p> Dynamically links the host program with the C library <code>libname</code>. -Inside this library, looks for a function <code>funcname</code> + + +<p> +If <code>funcname</code> is "<code>*</code>", +then it only links with the library, +making the symbols exported by the library +available to other dynamically linked libraries. +Otherwise, +it looks for a function <code>funcname</code> inside the library and returns this function as a C function. (So, <code>funcname</code> must follow the protocol (see <a href="#lua_CFunction"><code>lua_CFunction</code></a>)). @@ -6549,13 +7054,13 @@ Unlike <a href="#pdf-require"><code>require</code></a>, it does not perform any path searching and does not automatically adds extensions. <code>libname</code> must be the complete file name of the C library, -including if necessary a path and extension. +including if necessary a path and an extension. <code>funcname</code> must be the exact name exported by the C library (which may depend on the C compiler and linker used). <p> -This function is not supported by ANSI C. +This function is not supported by ANSI C. As such, it is only available on some platforms (Windows, Linux, Mac OS X, Solaris, BSD, plus other Unix systems that support the <code>dlfcn</code> standard). @@ -6594,6 +7099,41 @@ A table to store loaders for specific modules <p> +<hr><h3><a name="pdf-package.searchpath"><code>package.searchpath (name, path)</code></a></h3> + + +<p> +Searches for the given <code>name</code> in the given <code>path</code>. + + +<p> +A path is string containing a sequence of +<em>templates</em> separated by semicolons. +For each template, +the function changes each interrogation +mark in the template by <code>name</code>, +and then tries to open the resulting file name. +For instance, if the path is the string + +<pre> + "./?.lua;./?.lc;/usr/local/?/init.lua" +</pre><p> +the search for name <code>foo</code> +will try to open the files +<code>./foo.lua</code>, <code>./foo.lc</code>, and +<code>/usr/local/foo/init.lua</code>, in that order. + + +<p> +Returns the resulting name of the first file that it can +open in read mode (after closing it), +or <b>nil</b> plus an error message if none succeeds. +(This error message lists all file names it tried to open.) + + + + +<p> <hr><h3><a name="pdf-package.seeall"><code>package.seeall (module)</code></a></h3> @@ -7070,6 +7610,16 @@ For instance, the item <code>%b()</code> matches expressions with balanced parentheses. </li> +<li> +<code>%f[<em>set</em>]</code>, a <em>frontier pattern</em>; +such item matches an empty string at any position such that +the next character belongs to <em>set</em> +and the previous character does not belong to <em>set</em>. +The set <em>set</em> is interpreted as previously described. +The beggining and the end of the subject are handled as if +they were the character '<code>\0</code>'. +</li> + </ul> @@ -7161,14 +7711,13 @@ of table <code>t</code>. <p> -<hr><h3><a name="pdf-table.maxn"><code>table.maxn (table)</code></a></h3> +<hr><h3><a name="pdf-table.pack"><code>table.pack (···)</code></a></h3> <p> -Returns the largest positive numerical index of the given table, -or zero if the table has no positive numerical indices. -(To do its job this function does a linear traversal of -the whole table.) +Returns a new table with all parameters stored into +keys 1, 2, etc. +and with a field "<code>n</code>" with the total number of parameters. @@ -7211,6 +7760,22 @@ may have their relative positions changed by the sort. +<p> +<hr><h3><a name="pdf-table.unpack"><code>table.unpack (list [, i [, j]])</code></a></h3> +Returns the elements from the given table. +This function is equivalent to + +<pre> + return list[i], list[i+1], ···, list[j] +</pre><p> +except that the above code can be written only for a fixed number +of elements. +By default, <code>i</code> is 1 and <code>j</code> is the length of the list, +as defined by the length operator (see <a href="#2.5.5">§2.5.5</a>). + + + + @@ -7380,21 +7945,13 @@ Returns <em>m2<sup>e</sup></em> (<code>e</code> should be an integer). <p> -<hr><h3><a name="pdf-math.log"><code>math.log (x)</code></a></h3> +<hr><h3><a name="pdf-math.log"><code>math.log (x [, base])</code></a></h3> <p> -Returns the natural logarithm of <code>x</code>. - - - - -<p> -<hr><h3><a name="pdf-math.log10"><code>math.log10 (x)</code></a></h3> - - -<p> -Returns the base-10 logarithm of <code>x</code>. +Returns the logarithm of <code>x</code> in the given base. +The default for <code>base</code> is $e$ +(so that the function returns the natural logarithm of <code>x</code>). @@ -7551,7 +8108,141 @@ Returns the hyperbolic tangent of <code>x</code>. -<h2>5.7 - <a name="5.7">Input and Output Facilities</a></h2> +<h2>5.7 - <a name="5.7">Bitwise operations</a></h2> + +<p> +This library provides bitwise operations. +It provides all its functions inside the table <a name="pdf-bit"><code>bit</code></a>. +Unless otherwise stated, +all functions accept as arguments and return numbers +in the range <em>[0,2^32 - 1]</em>. +Standard Lua does not use 2-complement representation for numbers, +so in standard Lua (that is, with floating-point numbers) you +cannot use negative numbers with this library. +In particular, -1 is not the same as 0xffffffff. + + +<p> +<hr><h3><a name="pdf-bit.band"><code>bit.band (···)</code></a></h3> + + +<p> +Returns the bitwise and of its operands. + + + + +<p> +<hr><h3><a name="pdf-bit.bnot"><code>bit.bnot (x)</code></a></h3> + + +<p> +Returns the bitwise negation of <code>x</code>. +For any valid <code>x</code>, +the following identity holds: + +<pre> + assert(bit.bnot(x) == 2^32 - 1 - x) +</pre> + + + +<p> +<hr><h3><a name="pdf-bit.bor"><code>bit.bor (···)</code></a></h3> + + +<p> +Returns the bitwise or of its operands. + + + + +<p> +<hr><h3><a name="pdf-bit.brotate"><code>bit.brotate (x, disp)</code></a></h3> + + +<p> +Returns the number <code>x</code> rotated <code>disp</code> bits to the left. +The number <code>disp</code> may be any representable integer. + + +<p> +For any valid displacement, +the following identity holds: + +<pre> + assert(bit.rotate(x, disp) == bit.rotate(x, disp % 32)) +</pre><p> +This allows you to consider that +negative displacements rotate to the right. + + + + +<p> +<hr><h3><a name="pdf-bit.bshift"><code>bit.bshift (x, disp)</code></a></h3> + + +<p> +Returns the number <code>x</code> shifted <code>disp</code> bits to the left. +The number <code>disp</code> may be any representable integer. +Negative displacements shift to the right. +In any direction, vacant bits are filled with zeros. +In particular, +displacements with absolute values higher than +the total number of bits in the representation of <code>x</code> +result in zero (all bits are shifted out). + + +<p> +For positive displacements, +the following equality holds: + +<pre> + assert(bit.bshift(b, disp) == (b * 2^disp) % 2^32) +</pre> + +<p> +For negative displacements, +the following equality holds: + +<pre> + assert(bit.bshift(b, disp) == math.floor(b * 2^disp)) +</pre> + +<p> +This shift operation is what is called logical shift. +For an arithmetic shift, +you should use the arithmetic operators. + + + + +<p> +<hr><h3><a name="pdf-bit.btest"><code>bit.btest (···)</code></a></h3> + + +<p> +Returns a boolean signaling +whether the bitwise and of its operands is different from zero. + + + + +<p> +<hr><h3><a name="pdf-bit.bxor"><code>bit.bxor (···)</code></a></h3> + + +<p> +Returns the bitwise exclusive or of its operands. + + + + + + + +<h2>5.8 - <a name="5.8">Input and Output Facilities</a></h2> <p> The I/O library provides two different styles for file manipulation. @@ -7679,8 +8370,6 @@ The <code>mode</code> string can be any of the following: </ul><p> The <code>mode</code> string can also have a '<code>b</code>' at the end, which is needed in some systems to open the file in binary mode. -This string is exactly what is used in the -standard C function <code>fopen</code>. @@ -7770,6 +8459,11 @@ their handles are garbage collected, but that takes an unpredictable amount of time to happen. +<p> +If <code>file</code> was created with <a href="#pdf-io.popen"><code>io.popen</code></a>, +a sucessful close returns the exit status of the process. + + <p> @@ -7930,12 +8624,17 @@ To write other values, use <a href="#pdf-tostring"><code>tostring</code></a> or <a href="#pdf-string.format"><code>string.format</code></a> before <code>write</code>. +<p> +In case of success, this function returns <code>file</code>. +Otherwise it returns <b>nil</b> plus a string describing the error. + + -<h2>5.8 - <a name="5.8">Operating System Facilities</a></h2> +<h2>5.9 - <a name="5.9">Operating System Facilities</a></h2> <p> This library is implemented through table <a name="pdf-os"><code>os</code></a>. @@ -8023,7 +8722,7 @@ and zero otherwise. <p> -<hr><h3><a name="pdf-os.exit"><code>os.exit ([code])</code></a></h3> +<hr><h3><a name="pdf-os.exit"><code>os.exit ([code [, close])</code></a></h3> <p> @@ -8033,6 +8732,11 @@ to terminate the host program. The default value for <code>code</code> is the success code. +<p> +If the optional second argument <code>close</code> is true, +closes the Lua state before exiting. + + <p> @@ -8156,7 +8860,7 @@ which automatically removes the file when the program ends. -<h2>5.9 - <a name="5.9">The Debug Library</a></h2> +<h2>5.10 - <a name="5.10">The Debug Library</a></h2> <p> This library provides @@ -8236,7 +8940,8 @@ or you can give a number as the value of <code>function</code>, which means the function running at level <code>function</code> of the call stack of the given thread: level 0 is the current function (<code>getinfo</code> itself); -level 1 is the function that called <code>getinfo</code>; +level 1 is the function that called <code>getinfo</code> +(except for tail calls, which do not count on the stack); and so on. If <code>function</code> is a number larger than the number of active functions, then <code>getinfo</code> returns <b>nil</b>. @@ -8362,8 +9067,8 @@ When called without arguments, <p> When the hook is called, its first parameter is a string describing the event that has triggered its call: -<code>"call"</code>, <code>"return"</code> (or <code>"tail return"</code>, -when simulating a return from a tail call), +<code>"call"</code> (or <code>"tail call"</code>), +<code>"return"</code>, <code>"line"</code>, and <code>"count"</code>. For line events, the hook also gets the new line number as its second parameter. @@ -8371,10 +9076,7 @@ Inside a hook, you can call <code>getinfo</code> with level 2 to get more information about the running function (level 0 is the <code>getinfo</code> function, -and level 1 is the hook function), -unless the event is <code>"tail return"</code>. -In this case, Lua is only simulating the return, -and a call to <code>getinfo</code> will return invalid data. +and level 1 is the hook function). @@ -8425,7 +9127,10 @@ Otherwise, it returns the name of the upvalue. <p> -Returns a string with a traceback of the call stack. +If <code>message</code> is present but is not a string, +this function returns <code>message</code> without further processing. +Otherwise, +returns a string with a traceback of the call stack. An optional <code>message</code> string is appended at the beginning of the traceback. An optional <code>level</code> number tells at which level @@ -8529,6 +9234,17 @@ by issuing a different prompt. <p> +In case of unprotected errors in the script, +the interpreter reports the error to the standard error stream. +If the error object is a string, +the interpreter adds a stack traceback to it. +Otherwise, if the error object has a metamethod <code>__tostring</code>, +the interpreter calls this metamethod to produce the final message. +Finally, if the error object is <b>nil</b>, +the interpreter does not report the error. + + +<p> If the global variable <a name="pdf-_PROMPT"><code>_PROMPT</code></a> contains a string, then its value is used as the prompt. Similarly, if the global variable <a name="pdf-_PROMPT2"><code>_PROMPT2</code></a> contains a string, @@ -8577,8 +9293,8 @@ is a more portable solution.) <p> Here we list the incompatibilities that you may find when moving a program -from Lua 5.0 to Lua 5.1. -You can avoid most of the incompatibilities compiling Lua with +from Lua 5.1 to Lua 5.2. +You can avoid some incompatibilities compiling Lua with appropriate options (see file <code>luaconf.h</code>). However, all these compatibility options will be removed in the next version of Lua. @@ -8589,21 +9305,21 @@ all these compatibility options will be removed in the next version of Lua. <ul> <li> -The vararg system changed from the pseudo-argument <code>arg</code> with a -table with the extra arguments to the vararg expression. -(See compile-time option <code>LUA_COMPAT_VARARG</code> in <code>luaconf.h</code>.) +Lua identifiers cannot use locale-dependent letters. </li> <li> -There was a subtle change in the scope of the implicit -variables of the <b>for</b> statement and for the <b>repeat</b> statement. +Doing a step in the garbage collector does not restart the collector +if it has been stopped. </li> <li> -The long string/long comment syntax (<code>[[<em>string</em>]]</code>) -does not allow nesting. -You can use the new syntax (<code>[=[<em>string</em>]=]</code>) in these cases. -(See compile-time option <code>LUA_COMPAT_LSTR</code> in <code>luaconf.h</code>.) +Weak tables with weak keys now perform like <em>ephemeron tables</em>. +</li> + +<li> +Threads do not have individual environments. +All threads share a sinle fixed environment. </li> </ul> @@ -8615,53 +9331,31 @@ You can use the new syntax (<code>[=[<em>string</em>]=]</code>) in these cases. <ul> <li> -Function <code>string.gfind</code> was renamed <a href="#pdf-string.gmatch"><code>string.gmatch</code></a>. -(See compile-time option <code>LUA_COMPAT_GFIND</code> in <code>luaconf.h</code>.) -</li> - -<li> -When <a href="#pdf-string.gsub"><code>string.gsub</code></a> is called with a function as its -third argument, -whenever this function returns <b>nil</b> or <b>false</b> the -replacement string is the whole match, -instead of the empty string. -</li> - -<li> -Function <code>table.setn</code> was deprecated. -Function <code>table.getn</code> corresponds -to the new length operator (<code>#</code>); -use the operator instead of the function. -(See compile-time option <code>LUA_COMPAT_GETN</code> in <code>luaconf.h</code>.) +The debug library is not loaded by default. +You must explicitly require it. </li> <li> -Function <code>loadlib</code> was renamed <a href="#pdf-package.loadlib"><code>package.loadlib</code></a>. -(See compile-time option <code>LUA_COMPAT_LOADLIB</code> in <code>luaconf.h</code>.) +Functions <code>setfenv</code> and <code>getfenv</code> are deprecated. +To set the environment of a Lua function, +use lexical environments or the new function <a href="#pdf-loadin"><code>loadin</code></a>. +(If you really need them, +you may use their equivalents in the debug library.) </li> <li> -Function <code>math.mod</code> was renamed <a href="#pdf-math.fmod"><code>math.fmod</code></a>. -(See compile-time option <code>LUA_COMPAT_MOD</code> in <code>luaconf.h</code>.) +Function <code>math.log10</code> is deprecated. +Use <a href="#pdf-math.log"><code>math.log</code></a> with 10 as its second argument, instead. </li> <li> -Functions <code>table.foreach</code> and <code>table.foreachi</code> are deprecated. -You can use a for loop with <code>pairs</code> or <code>ipairs</code> instead. +Function <code>table.maxn</code> is deprecated. +Write it in Lua if you really need it. </li> <li> -There were substantial changes in function <a href="#pdf-require"><code>require</code></a> due to -the new module system. -However, the new behavior is mostly compatible with the old, -but <code>require</code> gets the path from <a href="#pdf-package.path"><code>package.path</code></a> instead -of from <code>LUA_PATH</code>. -</li> - -<li> -Function <a href="#pdf-collectgarbage"><code>collectgarbage</code></a> has different arguments. -Function <code>gcinfo</code> is deprecated; -use <code>collectgarbage("count")</code> instead. +Function <code>unpack</code> was moved into the table library +and therefore must be called as <a href="#pdf-table.unpack"><code>table.unpack</code></a>. </li> </ul> @@ -8673,36 +9367,38 @@ use <code>collectgarbage("count")</code> instead. <ul> <li> -The <code>luaopen_*</code> functions (to open libraries) -cannot be called directly, -like a regular C function. -They must be called through Lua, -like a Lua function. +Pseudoindex <code>LUA_GLOBALSINDEX</code> was deprecated. +You may use the pseudoindex <a href="#pdf-LUA_ENVIRONINDEX"><code>LUA_ENVIRONINDEX</code></a> instead, +if the C function does not change its standard environment. +Otherwise, you should get the global environment from the registry +(see <a href="#3.5">§3.5</a>). </li> <li> -Function <code>lua_open</code> was replaced by <a href="#lua_newstate"><code>lua_newstate</code></a> to -allow the user to set a memory-allocation function. -You can use <a href="#luaL_newstate"><code>luaL_newstate</code></a> from the standard library to -create a state with a standard allocation function -(based on <code>realloc</code>). +Macros <a href="#lua_getglobal"><code>lua_getglobal</code></a>, <a href="#lua_setglobal"><code>lua_setglobal</code></a>, and <a href="#lua_register"><code>lua_register</code></a> +now operate over the function environment instead of the global +environment. +(This is more consistent with how Lua manipulates global variables.) </li> <li> -Functions <code>luaL_getn</code> and <code>luaL_setn</code> -(from the auxiliary library) are deprecated. -Use <a href="#lua_objlen"><code>lua_objlen</code></a> instead of <code>luaL_getn</code> -and nothing instead of <code>luaL_setn</code>. +<code>luaL_typerror</code> was renamed <a href="#luaL_typeerror"><code>luaL_typeerror</code></a>, +to have a correct spelling. </li> <li> -Function <code>luaL_openlib</code> was replaced by <a href="#luaL_register"><code>luaL_register</code></a>. +Function <code>lua_cpcall</code> is deprecated. +Use the new <code>cpcall</code> function defined in the registry instead +(see <a href="#3.5">§3.5</a>). </li> <li> -Function <code>luaL_checkudata</code> now throws an error when the given value -is not a userdata of the expected type. -(In Lua 5.0 it returned <code>NULL</code>.) +Functions <code>lua_equal</code> and <code>lua_lessthan</code> are deprecated. +Use the new <a href="#lua_compare"><code>lua_compare</code></a> with appropriate options instead. +</li> + +<li> +Function <code>lua_objlen</code> was renamed <a href="#lua_rawlen"><code>lua_rawlen</code></a>. </li> </ul> @@ -8735,7 +9431,8 @@ Here is the complete syntax of Lua in extended BNF. <b>for</b> namelist <b>in</b> explist <b>do</b> block <b>end</b> | <b>function</b> funcname funcbody | <b>local</b> <b>function</b> Name funcbody | - <b>local</b> namelist [`<b>=</b>´ explist] + <b>local</b> namelist [`<b>=</b>´ explist] | + <b>in</b> exp <b>do</b> block <b>end</b> laststat ::= <b>return</b> [explist] | <b>break</b> @@ -8787,15 +9484,5 @@ Here is the complete syntax of Lua in extended BNF. - -<HR> -<SMALL> -Last update: -Mon Aug 18 13:25:46 BRT 2008 -</SMALL> -<!-- -Last change: revised for Lua 5.1.4 ---> - </body></html> diff --git a/doc/osi-certified-72x60.png b/doc/osi-certified-72x60.png Binary files differnew file mode 100644 index 00000000..07df5f6e --- /dev/null +++ b/doc/osi-certified-72x60.png diff --git a/doc/readme.html b/doc/readme.html index 38be6dbb..7640d3af 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -1,7 +1,27 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <HTML> <HEAD> -<TITLE>Lua documentation</TITLE> +<TITLE>Lua 5.2 readme</TITLE> <LINK REL="stylesheet" TYPE="text/css" HREF="lua.css"> +<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1"> +<STYLE TYPE="text/css"> +blockquote, .display { + color: black ; + padding: 8px ; + border: solid #a0a0a0 2px ; + background-color: #EFEFFF ; + margin-left: 0px ; +} + +.review { + color: red ; +} + +.external { + padding-right: 15px; + background: transparent url(external.png) no-repeat center right; +} +</STYLE> </HEAD> <BODY> @@ -9,31 +29,324 @@ <HR> <H1> <A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua" BORDER=0></A> -Documentation +Welcome to Lua 5.2 </H1> -This is the documentation included in the source distribution of Lua 5.1.4. +<A HREF="#about">about</A> +· +<A HREF="#install">installation</A> +· +<A HREF="#changes">changes</A> +· +<A HREF="#license">license</A> +· +<A HREF="contents.html">reference manual</A> +<HR> +<P> -<UL> -<LI><A HREF="contents.html">Reference manual</A> -<LI><A HREF="lua.html">lua man page</A> -<LI><A HREF="luac.html">luac man page</A> -<LI><A HREF="../README">lua/README</A> -<LI><A HREF="../etc/README">lua/etc/README</A> -<LI><A HREF="../test/README">lua/test/README</A> -</UL> +<P> +<IMG SRC="alert.png" ALIGN="absbottom"> +<EM>This is a work version of Lua 5.2. +All details may change in the final version.</EM> + +<H2><A NAME="about">About Lua</A></H2> + +Lua is a powerful, fast, lightweight, embeddable scripting language +developed by a +<A HREF="http://www.lua.org/authors.html">team</A> +at +<A HREF="http://www.puc-rio.br/">PUC-Rio</A>, +the Pontifical Catholic University of Rio de Janeiro in Brazil. +Lua is +<A HREF="#license">free software</A> +used in many products and projects around the world. +<P> Lua's <A HREF="http://www.lua.org/">official web site</A> -contains updated documentation, +provides complete information +about Lua, +including +an +<A HREF="http://www.lua.org/about.html">executive summary</A> +and +updated +<A HREF="http://www.lua.org/docs.html">documentation</A>, especially the -<A HREF="http://www.lua.org/manual/5.1/">reference manual</A>. +<A HREF="http://www.lua.org/manual/5.2/">reference manual</A>, +which may differ slightly from the +<A HREF="contents.html">local copy</A> +distributed in this package. +<P> + +<H2><A NAME="install">Installing Lua</A></H2> +<DIV CLASS="review">how much detail?</DIV><P> + +Lua is distributed in source form. +You need to build it before using it. +This should be straightforward +because +Lua is implemented in pure ANSI C, and compiles unmodified in all known +platforms that have an ANSI C compiler. +Lua also compiles unmodified as C++. +<P> + +The instructions below are for Unix-like platforms. +There are also +<A HREF="#other">instructions for other systems</A>. +See below for +<A HREF="#customization">customization options</A>. +<P> + +<H3>Building Lua</H3> + +In most Unix-like platforms, simply do "make" with a suitable target. +Here are the details. +<P> + +<OL> +<LI> +Open a terminal window and move to +the top-level directory, which is named lua-5.2. +The Makefile there controls both the build process and the installation process. +<P> +<LI> + Do "make" and see if your platform is listed. + The platforms currently supported are: +<BLOCKQUOTE> + aix ansi bsd freebsd generic linux macosx mingw posix solaris +</BLOCKQUOTE> +<P> + If your platform is listed, just do "make xxx", where xxx + is your platform name. +<P> + If your platform is not listed, try the closest one or posix, generic, + ansi, in this order. +<P> +<LI> +The compilation takes only a few moments +and produces three files in the src directory: +lua (the interpreter), +luac (the compiler), +and liblua.a (the library). +<P> +<LI> + If you want to check that Lua has been built correctly, do "make test" + after building Lua. This will run the interpreter on a "hello world" + Lua program from the test directory. + You may want to try other example programs in that directory. +</OL> +<P> + +<H3>Installing Lua</H3> + Once you have built Lua, you may want to install it in an official + place in your system. In this case, do "make install". The official + place and the way to install files are defined in Makefile. You'll + probably need the right permissions to install files. +<P> + + If you want to build and install Lua in one step, do <SPAN CLASS="display">"make xxx install"</SPAN>, + where xxx is your platform name. +<P> + + If you want to install Lua locally, then do "make local". This will + create directories bin, include, lib, man, and install Lua there as + follows: + <SPAN CLASS="review">review!</SPAN> +<P> + +<DL CLASS="display"> +<DT> + bin: +<DD> + lua luac +<DT> + include: +<DD> + lua.h luaconf.h lualib.h lauxlib.h lua.hpp +<DT> + lib: +<DD> + liblua.a +<DT> + man/man1: +<DD> + lua.1 luac.1 +</DL> + + These are the only directories you need for development. +<P> + + There are man pages for + <A HREF="lua.html">lua</A> and + <A HREF="luac.html">luac</A>, in both nroff and html, and a + <A HREF="contents.html">reference manual</A> in html in doc, some sample code in test, and some + useful stuff in etc. You don't need these directories for development. +<P> + + If you want to install Lua locally, but in some other directory, do + "make install INSTALL_TOP=xxx", where xxx is your chosen directory. +<P> + +<H3><A NAME="customization">Customization</A></H3> + Three kinds of things can be customized by editing a file: +<UL> + <LI> Where and how to install Lua – edit Makefile. + <LI> How to build Lua – edit src/Makefile. + <LI> Lua features – edit src/luaconf.h. +</UL> +<P> + + You don't actually need to edit the Makefiles because you may set the + relevant variables in the command line when invoking make. +<P> + + On the other hand, if you need to customize some Lua features, you'll need + to edit src/luaconf.h before building and installing Lua. + The edited file will be the one installed, and + it will be used by any Lua clients that you build, to ensure consistency. +<P> + + We strongly recommend that you enable dynamic loading. This is done + automatically for all platforms listed above that have this feature + and also for Windows. +<P> + +<H3><A NAME="other">Building Lua on other systems</A></H3> + + If you're not using the usual Unix tools, then the instructions for + building Lua depend on the compiler you use. You'll need to create + projects (or whatever your compiler uses) for building the library, + the interpreter, and the compiler, as follows: +<P> +<DL CLASS="display"> +<DT> +library: +<DD> + lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c + lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c + ltable.c ltm.c lundump.c lvm.c lzio.c + lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c + ltablib.c lstrlib.c loadlib.c linit.c +<DT> +interpreter: +<DD> + library, lua.c +<DT> +compiler: +<DD> + library, luac.c print.c +</DL> + + If you use Visual Studio .NET, you can use etc/luavs.bat in its + "Command Prompt". +<P> + + If all you want is to build the Lua interpreter, you may put all .c files + in a single project, except for luac.c and print.c. Or just use etc/all.c. +<P> + + To use Lua as a library in your own programs you'll need to know how to + create and use libraries with your compiler. Moreover, to dynamically load + C libraries for Lua you'll need to know how to create dynamic libraries + and you'll need to make sure that the Lua API functions are accessible to + those dynamic libraries — but you do <EM>not</EM> want to link the Lua library + into each dynamic library. For Unix, we recommend that the Lua library + be linked statically into the host program and its symbols exported for + dynamic linking; src/Makefile does this for the Lua interpreter. + For Windows, we recommend that the Lua library be DLL. +<P> + + As mentioned above, you may edit src/luaconf.h to customize + some features before building Lua. +<P> + +<H2><A NAME="changes">Changes since Lua 5.1</A></H2> +<DIV CLASS="review">incomplete!</DIV><P> + +Here are the main changes in Lua since its last release. +The +<A HREF="contents.html">reference manual</A> +lists the +<A HREF="manual.html#7">incompatibilities</A> that had to be introduced. +<P> + +<H3>Language</H3> +<UL> +<LI> new lexical environments. +<LI> hex escapes in strings. +<LI> tables and strings honor the <CODE>__len</CODE> metamethod. +</UL> + +<H3>Libraries</H3> +<UL> +<LI> new function <CODE>package.searchpath</CODE>. +<LI> new metamethods <CODE>__pairs</CODE> and <CODE>__ipairs</CODE>. +<LI> arguments for function called through <CODE>xpcall</CODE>. +</UL> + +<H3>Implementation</H3> +<UL> +<LI> emergency garbage collector + (core forces a full collection when allocation fails). +<LI> ephemeron tables + (tables with weak keys only visit value when key is accessible) +<LI> handling of non-string error messages. +<LI> udata with finalizers are kept in a separated list for the GC. +<SPAN CLASS="review">relevant?</SPAN> +</UL> + + +<H2><A NAME="license">License</A></H2> +<A HREF="http://www.opensource.org/docs/definition.php"> +<IMG SRC="osi-certified-72x60.png" ALIGN="right" BORDER="0" ALT="[osi certified]" xSTYLE="padding: 40px ;" hspace="10"> +</A> + +Lua is free software licensed under the terms of the +<A HREF="http://www.opensource.org/licenses/mit-license.html">MIT license</A> +reproduced below, +and +can be used for any purpose, including commercial purposes, +at absolutely no cost without having to ask us. + +The only requirement is that if you do use Lua, +then you should give us credit by including the appropriate copyright notice somewhere in your product or its documentation. + +For details and rationale, see +<A HREF="http://www.lua.org/license.html" class="external">this</A>. +<P> + +<BLOCKQUOTE> +Copyright © 1994-2010 Lua.org, PUC-Rio. +<P> + +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: +<P> + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +<P> + +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. +<P> +</BLOCKQUOTE> <P> <HR> <SMALL> Last update: -Tue Aug 12 14:46:07 BRT 2008 +Fri Jan 8 16:41:16 BRST 2010 </SMALL> </BODY> @@ -2,22 +2,12 @@ This directory contains some useful files and code. Unlike the code in ../src, everything here is in the public domain. If any of the makes fail, you're probably not using the same libraries -used to build Lua. Set MYLIBS in Makefile accordingly. +used to build Lua. Set MYLIBS in Makefile or in the command line accordingly. all.c Full Lua interpreter in a single file. Do "make one" for a demo. -lua.hpp - Lua header files for C++ using 'extern "C"'. - -lua.ico - A Lua icon for Windows (and web sites: save as favicon.ico). - Drawn by hand by Markus Gritsch <gritsch@iue.tuwien.ac.at>. - -lua.pc - pkg-config data for Lua - luavs.bat Script to build Lua under "Visual Studio .NET Command Prompt". Run it from the toplevel as etc\luavs.bat. @@ -1,11 +1,31 @@ /* -* all.c -- Lua core, libraries and interpreter in a single file +* all.c -- Lua core, libraries, and interpreter in a single file */ +/* default is to build the full interpreter */ +#ifndef MAKE_LIB +#ifndef MAKE_LUAC +#undef MAKE_LUA +#define MAKE_LUA +#endif +#endif + +/* choose suitable platform-specific features */ +/* some of these may need extra libraries such as -ldl -lreadline -lncurses */ +#if 0 +#define LUA_USE_LINUX +#define LUA_USE_MACOSX +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN +#define LUA_ANSI +#endif + #define luaall_c +/* core -- used by all */ #include "lapi.c" #include "lcode.c" +#include "lctype.c" #include "ldebug.c" #include "ldo.c" #include "ldump.c" @@ -24,15 +44,30 @@ #include "lvm.c" #include "lzio.c" +/* auxiliary library -- used by all */ #include "lauxlib.c" + +/* standard library -- not used by luac */ +#ifndef MAKE_LUAC #include "lbaselib.c" +#include "lbitlib.c" #include "ldblib.c" #include "liolib.c" -#include "linit.c" #include "lmathlib.c" #include "loadlib.c" #include "loslib.c" #include "lstrlib.c" #include "ltablib.c" +#endif +/* lua */ +#ifdef MAKE_LUA +#include "linit.c" #include "lua.c" +#endif + +/* luac */ +#ifdef MAKE_LUAC +#include "print.c" +#include "luac.c" +#endif diff --git a/etc/lua.ico b/etc/lua.ico Binary files differdeleted file mode 100644 index ccbabc4e..00000000 --- a/etc/lua.ico +++ /dev/null diff --git a/etc/lua.pc b/etc/lua.pc deleted file mode 100644 index f52f55b0..00000000 --- a/etc/lua.pc +++ /dev/null @@ -1,31 +0,0 @@ -# lua.pc -- pkg-config data for Lua - -# vars from install Makefile - -# grep '^V=' ../Makefile -V= 5.1 -# grep '^R=' ../Makefile -R= 5.1.4 - -# grep '^INSTALL_.*=' ../Makefile | sed 's/INSTALL_TOP/prefix/' -prefix= /usr/local -INSTALL_BIN= ${prefix}/bin -INSTALL_INC= ${prefix}/include -INSTALL_LIB= ${prefix}/lib -INSTALL_MAN= ${prefix}/man/man1 -INSTALL_LMOD= ${prefix}/share/lua/${V} -INSTALL_CMOD= ${prefix}/lib/lua/${V} - -# canonical vars -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: Lua -Description: An Extensible Extension Language -Version: ${R} -Requires: -Libs: -L${libdir} -llua -lm -Cflags: -I${includedir} - -# (end of lua.pc) @@ -1,39 +1,36 @@ /* * min.c -- a minimal Lua interpreter -* loads stdin only with minimal error handling. -* no interaction, and no standard library, only a "print" function. +* runs one file from the command line or stdin if none given. +* minimal error handling, no traceback, no interaction, no standard library, +* only a "print" function. */ #include <stdio.h> #include "lua.h" #include "lauxlib.h" +#include "lualib.h" static int print(lua_State *L) { int n=lua_gettop(L); int i; + const char *s=""; for (i=1; i<=n; i++) { - if (i>1) printf("\t"); - if (lua_isstring(L,i)) - printf("%s",lua_tostring(L,i)); - else if (lua_isnil(L,i)) - printf("%s","nil"); - else if (lua_isboolean(L,i)) - printf("%s",lua_toboolean(L,i) ? "true" : "false"); - else - printf("%s:%p",luaL_typename(L,i),lua_topointer(L,i)); + printf("%s%s",s,luaL_tolstring(L,i,NULL)); + s="\t"; } printf("\n"); return 0; } -int main(void) +int main(int argc, char *argv[]) { lua_State *L=lua_open(); lua_register(L,"print",print); - if (luaL_dofile(L,NULL)!=0) fprintf(stderr,"%s\n",lua_tostring(L,-1)); + luaL_openlibs(L); + if (luaL_dofile(L,argv[1])!=0) fprintf(stderr,"%s\n",lua_tostring(L,-1)); lua_close(L); return 0; } diff --git a/etc/noparser.c b/etc/noparser.c index 13ba5462..5e0e2031 100644 --- a/etc/noparser.c +++ b/etc/noparser.c @@ -4,16 +4,24 @@ * You'll only be able to load binary files and strings, precompiled with luac. * (Of course, you'll have to build luac with the original parsing modules!) * -* To use this module, simply compile it ("make noparser" does that) and list -* its object file before the Lua libraries. The linker should then not load -* the parsing modules. To try it, do "make luab". +* To use this module, simply compile it and list its object file before the +* Lua libraries. The linker should then not load the parsing modules. * -* If you also want to avoid the dump module (ldump.o), define NODUMP. -* #define NODUMP +* If you want to avoid the dump module or the undump modules, use the +* corresponding #define below. +* +#define NOPARSER +#define NODUMP +#define NOUNDUMP */ +#define NOPARSER + #define LUA_CORE +#include "lua.h" +/* --------------------------------------------------------------- noparser */ +#ifdef NOPARSER #include "llex.h" #include "lparser.h" #include "lzio.h" @@ -22,7 +30,7 @@ LUAI_FUNC void luaX_init (lua_State *L) { UNUSED(L); } -LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { +LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Varlist *varl, const char *name) { UNUSED(z); UNUSED(buff); UNUSED(name); @@ -30,7 +38,9 @@ LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *n lua_error(L); return NULL; } +#endif +/* --------------------------------------------------------------- nodump */ #ifdef NODUMP #include "lundump.h" @@ -39,12 +49,22 @@ LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, UNUSED(w); UNUSED(data); UNUSED(strip); -#if 1 - UNUSED(L); - return 0; -#else lua_pushliteral(L,"dumper not loaded"); lua_error(L); + return 0; +} #endif + +/* --------------------------------------------------------------- noundump */ +#ifdef NOUNDUMP +#include "lundump.h" + +LUAI_FUNC Proto *luaU_undump (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { + UNUSED(z); + UNUSED(buff); + UNUSED(name); + lua_pushliteral(L,"cannot load binary chunks"); + lua_error(L); + return NULL; } #endif diff --git a/src/Makefile b/src/Makefile index e4a3cd61..a3942a5b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,6 +1,5 @@ -# makefile for building Lua -# see ../INSTALL for installation instructions -# see ../Makefile and luaconf.h for further customization +# Makefile for building Lua +# See ../doc/readme.html for installation and customization instructions. # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= @@ -9,25 +8,26 @@ PLAT= none CC= gcc CFLAGS= -O2 -Wall $(MYCFLAGS) +LIBS= -lm $(MYLIBS) + AR= ar rcu RANLIB= ranlib RM= rm -f -LIBS= -lm $(MYLIBS) MYCFLAGS= MYLDFLAGS= MYLIBS= -# == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= +# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE ======= PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris LUA_A= liblua.a -CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \ - lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \ - lundump.o lvm.o lzio.o -LIB_O= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \ - lstrlib.o loadlib.o linit.o +CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \ + lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o \ + ltm.o lundump.o lvm.o lzio.o +LIB_O= lauxlib.o lbaselib.o lbitlib.o ldblib.o liolib.o lmathlib.o loslib.o \ + ltablib.o lstrlib.o loadlib.o linit.o LUA_T= lua LUA_O= lua.o @@ -75,89 +75,90 @@ echo: @echo "MYLIBS = $(MYLIBS)" # convenience targets for popular platforms +ALL= all none: @echo "Please choose a platform:" @echo " $(PLATS)" aix: - $(MAKE) all CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" + $(MAKE) $(ALL) CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" ansi: - $(MAKE) all MYCFLAGS=-DLUA_ANSI + $(MAKE) $(ALL) MYCFLAGS="-DLUA_ANSI" bsd: - $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E" + $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E" freebsd: - $(MAKE) all MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -lreadline" + $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -lreadline" generic: - $(MAKE) all MYCFLAGS= + $(MAKE) $(ALL) MYCFLAGS= linux: - $(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses" + $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -ldl -lreadline -lncurses" macosx: - $(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-lreadline" -# use this on Mac OS X 10.3- -# $(MAKE) all MYCFLAGS=-DLUA_USE_MACOSX + $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_MACOSX" MYLIBS="-lreadline" mingw: $(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \ "AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \ "MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe - $(MAKE) "LUAC_T=luac.exe" luac.exe posix: - $(MAKE) all MYCFLAGS=-DLUA_USE_POSIX + $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_POSIX" solaris: - $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" + $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" # list targets that do not create files (but not all makes understand .PHONY) .PHONY: all $(PLATS) default o a clean depend echo none # DO NOT DELETE -lapi.o: lapi.c lua.h luaconf.h lapi.h lobject.h llimits.h ldebug.h \ - lstate.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h \ - lundump.h lvm.h +lapi.o: lapi.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \ + lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h ltable.h lundump.h \ + lvm.h lauxlib.o: lauxlib.c lua.h luaconf.h lauxlib.h lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h +lbitlib.o: lbitlib.c lua.h luaconf.h lauxlib.h lualib.h lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \ - ltable.h + lstring.h ltable.h +lctype.o: lctype.c lctype.h lua.h luaconf.h llimits.h ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h -ldebug.o: ldebug.c lua.h luaconf.h lapi.h lobject.h llimits.h lcode.h \ - llex.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ +ldebug.o: ldebug.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h \ + ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h ldebug.h ldo.h \ lfunc.h lstring.h lgc.h ltable.h lvm.h -ldo.o: ldo.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ - lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h lstring.h \ - ltable.h lundump.h lvm.h +ldo.o: ldo.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \ + lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h \ + lstring.h ltable.h lundump.h lvm.h ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \ lzio.h lmem.h lundump.h lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h lmem.h \ - lstate.h ltm.h lzio.h + lopcodes.h lstate.h ltm.h lzio.h lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h -llex.o: llex.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h ltm.h \ - lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h +llex.o: llex.c lua.h luaconf.h lctype.h llimits.h ldo.h lobject.h \ + lstate.h ltm.h lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ - ltm.h lzio.h lmem.h ldo.h + ltm.h lzio.h lmem.h ldo.h lgc.h loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h -lobject.o: lobject.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h \ - ltm.h lzio.h lmem.h lstring.h lgc.h lvm.h +lobject.o: lobject.c lua.h luaconf.h lctype.h llimits.h ldebug.h lstate.h \ + lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h lvm.h lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ lfunc.h lstring.h lgc.h ltable.h -lstate.o: lstate.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ - ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h llex.h lstring.h ltable.h +lstate.o: lstate.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h \ + ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h lstring.h \ + ltable.h lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \ ltm.h lzio.h lstring.h lgc.h lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h @@ -1,12 +1,10 @@ /* -** $Id: lapi.c,v 2.55.1.5 2008/07/04 18:41:18 roberto Exp $ +** $Id: lapi.c,v 2.109 2010/01/08 15:16:56 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ -#include <assert.h> -#include <math.h> #include <stdarg.h> #include <string.h> @@ -32,42 +30,47 @@ const char lua_ident[] = - "$Lua: " LUA_RELEASE " " LUA_COPYRIGHT " $\n" - "$Authors: " LUA_AUTHORS " $\n" - "$URL: www.lua.org $\n"; + "$LuaVersion: " LUA_COPYRIGHT " $" + "$LuaAuthors: " LUA_AUTHORS " $"; -#define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base)) +#define api_checkvalidindex(L, i) api_check(L, (i) != luaO_nilobject, \ + "invalid index") -#define api_checkvalidindex(L, i) api_check(L, (i) != luaO_nilobject) - -#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} +static Table *getcurrenv (lua_State *L) { + if (L->ci->previous == NULL) /* no enclosing function? */ + return G(L)->l_gt; /* use global table as environment */ + else { + Closure *func = curr_func(L); + return func->c.env; + } +} -static TValue *index2adr (lua_State *L, int idx) { +static TValue *index2addr (lua_State *L, int idx) { + CallInfo *ci = L->ci; if (idx > 0) { - TValue *o = L->base + (idx - 1); - api_check(L, idx <= L->ci->top - L->base); + TValue *o = ci->func + idx; + api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index"); if (o >= L->top) return cast(TValue *, luaO_nilobject); else return o; } else if (idx > LUA_REGISTRYINDEX) { - api_check(L, idx != 0 && -idx <= L->top - L->base); + api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); return L->top + idx; } else switch (idx) { /* pseudo-indices */ - case LUA_REGISTRYINDEX: return registry(L); + case LUA_REGISTRYINDEX: return &G(L)->l_registry; case LUA_ENVIRONINDEX: { - Closure *func = curr_func(L); - sethvalue(L, &L->env, func->c.env); + sethvalue(L, &L->env, getcurrenv(L)); return &L->env; } - case LUA_GLOBALSINDEX: return gt(L); default: { Closure *func = curr_func(L); - idx = LUA_GLOBALSINDEX - idx; + idx = LUA_ENVIRONINDEX - idx; + api_check(L, idx <= UCHAR_MAX + 1, "upvalue index too large"); return (idx <= func->c.nupvalues) ? &func->c.upvalue[idx-1] : cast(TValue *, luaO_nilobject); @@ -76,32 +79,31 @@ static TValue *index2adr (lua_State *L, int idx) { } -static Table *getcurrenv (lua_State *L) { - if (L->ci == L->base_ci) /* no enclosing function? */ - return hvalue(gt(L)); /* use global table as environment */ - else { - Closure *func = curr_func(L); - return func->c.env; - } -} - - -void luaA_pushobject (lua_State *L, const TValue *o) { - setobj2s(L, L->top, o); - api_incr_top(L); +/* +** to be caled by 'lua_checkstack' in protected mode, to grow stack +** capturing memory errors +*/ +static void growstack (lua_State *L, void *ud) { + int size = *(int *)ud; + luaD_growstack(L, size); } LUA_API int lua_checkstack (lua_State *L, int size) { - int res = 1; + int res; + CallInfo *ci = L->ci; lua_lock(L); - if (size > LUAI_MAXCSTACK || (L->top - L->base + size) > LUAI_MAXCSTACK) - res = 0; /* stack overflow */ - else if (size > 0) { - luaD_checkstack(L, size); - if (L->ci->top < L->top + size) - L->ci->top = L->top + size; + if (L->stack_last - L->top > size) /* stack large enough? */ + res = 1; /* yes; check is OK */ + else { /* no; need to grow stack */ + int inuse = L->top - L->stack + EXTRA_STACK; + if (inuse > LUAI_MAXSTACK - size) /* can grow without overflow? */ + res = 0; /* no */ + else /* try to grow stack */ + res = (luaD_rawrunprotected(L, &growstack, &size) == LUA_OK); } + if (res && ci->top < L->top + size) + ci->top = L->top + size; /* adjust frame top */ lua_unlock(L); return res; } @@ -112,8 +114,8 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { if (from == to) return; lua_lock(to); api_checknelems(from, n); - api_check(from, G(from) == G(to)); - api_check(from, to->ci->top - to->top >= n); + api_check(from, G(from) == G(to), "moving among independent states"); + api_check(from, to->ci->top - to->top >= n, "not enough elements to move"); from->top -= n; for (i = 0; i < n; i++) { setobj2s(to, to->top++, from->top + i); @@ -122,11 +124,6 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { } -LUA_API void lua_setlevel (lua_State *from, lua_State *to) { - to->nCcalls = from->nCcalls; -} - - LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { lua_CFunction old; lua_lock(L); @@ -137,16 +134,10 @@ LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { } -LUA_API lua_State *lua_newthread (lua_State *L) { - lua_State *L1; - lua_lock(L); - luaC_checkGC(L); - L1 = luaE_newthread(L); - setthvalue(L, L->top, L1); - api_incr_top(L); - lua_unlock(L); - luai_userstatethread(L, L1); - return L1; +LUA_API const lua_Number *lua_version (lua_State *L) { + static const lua_Number version = LUA_VERSION_NUM; + if (L == NULL) return &version; + else return G(L)->version; } @@ -157,20 +148,21 @@ LUA_API lua_State *lua_newthread (lua_State *L) { LUA_API int lua_gettop (lua_State *L) { - return cast_int(L->top - L->base); + return cast_int(L->top - (L->ci->func + 1)); } LUA_API void lua_settop (lua_State *L, int idx) { + StkId func = L->ci->func; lua_lock(L); if (idx >= 0) { - api_check(L, idx <= L->stack_last - L->base); - while (L->top < L->base + idx) + api_check(L, idx <= L->stack_last - (func + 1), "new top too large"); + while (L->top < (func + 1) + idx) setnilvalue(L->top++); - L->top = L->base + idx; + L->top = (func + 1) + idx; } else { - api_check(L, -(idx+1) <= (L->top - L->base)); + api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); L->top += idx+1; /* `subtract' index (index is negative) */ } lua_unlock(L); @@ -180,7 +172,7 @@ LUA_API void lua_settop (lua_State *L, int idx) { LUA_API void lua_remove (lua_State *L, int idx) { StkId p; lua_lock(L); - p = index2adr(L, idx); + p = index2addr(L, idx); api_checkvalidindex(L, p); while (++p < L->top) setobjs2s(L, p-1, p); L->top--; @@ -192,7 +184,7 @@ LUA_API void lua_insert (lua_State *L, int idx) { StkId p; StkId q; lua_lock(L); - p = index2adr(L, idx); + p = index2addr(L, idx); api_checkvalidindex(L, p); for (q = L->top; q>p; q--) setobjs2s(L, q, q-1); setobjs2s(L, p, L->top); @@ -200,34 +192,50 @@ LUA_API void lua_insert (lua_State *L, int idx) { } -LUA_API void lua_replace (lua_State *L, int idx) { - StkId o; - lua_lock(L); - /* explicit test for incompatible code */ - if (idx == LUA_ENVIRONINDEX && L->ci == L->base_ci) - luaG_runerror(L, "no calling environment"); - api_checknelems(L, 1); - o = index2adr(L, idx); - api_checkvalidindex(L, o); +static void moveto (lua_State *L, TValue *fr, int idx) { + TValue *to = index2addr(L, idx); + api_checkvalidindex(L, to); if (idx == LUA_ENVIRONINDEX) { Closure *func = curr_func(L); - api_check(L, ttistable(L->top - 1)); - func->c.env = hvalue(L->top - 1); - luaC_barrier(L, func, L->top - 1); + api_check(L, ttistable(fr), "table expected"); + func->c.env = hvalue(fr); + luaC_barrier(L, func, fr); } else { - setobj(L, o, L->top - 1); - if (idx < LUA_GLOBALSINDEX) /* function upvalue? */ - luaC_barrier(L, curr_func(L), L->top - 1); + setobj(L, to, fr); + if (idx < LUA_ENVIRONINDEX) /* function upvalue? */ + luaC_barrier(L, curr_func(L), fr); } + /* LUA_REGISTRYINDEX does not need gc barrier + (collector revisits it before finishing collection) */ +} + + +LUA_API void lua_replace (lua_State *L, int idx) { + lua_lock(L); + /* explicit test for incompatible code */ + if (idx == LUA_ENVIRONINDEX && L->ci->previous == NULL) + luaG_runerror(L, "no calling environment"); + api_checknelems(L, 1); + moveto(L, L->top - 1, idx); L->top--; lua_unlock(L); } +LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { + TValue *fr; + lua_lock(L); + fr = index2addr(L, fromidx); + api_checkvalidindex(L, fr); + moveto(L, fr, toidx); + lua_unlock(L); +} + + LUA_API void lua_pushvalue (lua_State *L, int idx) { lua_lock(L); - setobj2s(L, L->top, index2adr(L, idx)); + setobj2s(L, L->top, index2addr(L, idx)); api_incr_top(L); lua_unlock(L); } @@ -240,7 +248,7 @@ LUA_API void lua_pushvalue (lua_State *L, int idx) { LUA_API int lua_type (lua_State *L, int idx) { - StkId o = index2adr(L, idx); + StkId o = index2addr(L, idx); return (o == luaO_nilobject) ? LUA_TNONE : ttype(o); } @@ -252,14 +260,14 @@ LUA_API const char *lua_typename (lua_State *L, int t) { LUA_API int lua_iscfunction (lua_State *L, int idx) { - StkId o = index2adr(L, idx); + StkId o = index2addr(L, idx); return iscfunction(o); } LUA_API int lua_isnumber (lua_State *L, int idx) { TValue n; - const TValue *o = index2adr(L, idx); + const TValue *o = index2addr(L, idx); return tonumber(o, &n); } @@ -271,48 +279,55 @@ LUA_API int lua_isstring (lua_State *L, int idx) { LUA_API int lua_isuserdata (lua_State *L, int idx) { - const TValue *o = index2adr(L, idx); + const TValue *o = index2addr(L, idx); return (ttisuserdata(o) || ttislightuserdata(o)); } LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { - StkId o1 = index2adr(L, index1); - StkId o2 = index2adr(L, index2); + StkId o1 = index2addr(L, index1); + StkId o2 = index2addr(L, index2); return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : luaO_rawequalObj(o1, o2); } -LUA_API int lua_equal (lua_State *L, int index1, int index2) { - StkId o1, o2; - int i; - lua_lock(L); /* may call tag method */ - o1 = index2adr(L, index1); - o2 = index2adr(L, index2); - i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : equalobj(L, o1, o2); +LUA_API void lua_arith (lua_State *L, int op) { + lua_lock(L); + api_checknelems(L, 2); + if (ttisnumber(L->top - 2) && ttisnumber(L->top - 1)) { + changenvalue(L->top - 2, + luaO_arith(op, nvalue(L->top - 2), nvalue(L->top - 1))); + } + else + luaV_arith(L, L->top - 2, L->top - 2, L->top - 1, op - LUA_OPADD + TM_ADD); + L->top--; lua_unlock(L); - return i; } -LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { +LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { StkId o1, o2; int i; lua_lock(L); /* may call tag method */ - o1 = index2adr(L, index1); - o2 = index2adr(L, index2); - i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 - : luaV_lessthan(L, o1, o2); + o1 = index2addr(L, index1); + o2 = index2addr(L, index2); + if (o1 == luaO_nilobject || o2 == luaO_nilobject) + i = 0; + else switch (op) { + case LUA_OPEQ: i = equalobj(L, o1, o2); break; + case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break; + case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break; + default: api_check(L, 0, "invalid option"); i = 0; + } lua_unlock(L); return i; } - LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { TValue n; - const TValue *o = index2adr(L, idx); + const TValue *o = index2addr(L, idx); if (tonumber(o, &n)) return nvalue(o); else @@ -322,7 +337,7 @@ LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { TValue n; - const TValue *o = index2adr(L, idx); + const TValue *o = index2addr(L, idx); if (tonumber(o, &n)) { lua_Integer res; lua_Number num = nvalue(o); @@ -335,13 +350,13 @@ LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { LUA_API int lua_toboolean (lua_State *L, int idx) { - const TValue *o = index2adr(L, idx); + const TValue *o = index2addr(L, idx); return !l_isfalse(o); } LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { - StkId o = index2adr(L, idx); + StkId o = index2addr(L, idx); if (!ttisstring(o)) { lua_lock(L); /* `luaV_tostring' may create a new string */ if (!luaV_tostring(L, o)) { /* conversion failed? */ @@ -350,7 +365,7 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { return NULL; } luaC_checkGC(L); - o = index2adr(L, idx); /* previous call may reallocate the stack */ + o = index2addr(L, idx); /* previous call may reallocate the stack */ lua_unlock(L); } if (len != NULL) *len = tsvalue(o)->len; @@ -358,32 +373,25 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { } -LUA_API size_t lua_objlen (lua_State *L, int idx) { - StkId o = index2adr(L, idx); +LUA_API size_t lua_rawlen (lua_State *L, int idx) { + StkId o = index2addr(L, idx); switch (ttype(o)) { case LUA_TSTRING: return tsvalue(o)->len; case LUA_TUSERDATA: return uvalue(o)->len; case LUA_TTABLE: return luaH_getn(hvalue(o)); - case LUA_TNUMBER: { - size_t l; - lua_lock(L); /* `luaV_tostring' may create a new string */ - l = (luaV_tostring(L, o) ? tsvalue(o)->len : 0); - lua_unlock(L); - return l; - } default: return 0; } } LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { - StkId o = index2adr(L, idx); + StkId o = index2addr(L, idx); return (!iscfunction(o)) ? NULL : clvalue(o)->c.f; } LUA_API void *lua_touserdata (lua_State *L, int idx) { - StkId o = index2adr(L, idx); + StkId o = index2addr(L, idx); switch (ttype(o)) { case LUA_TUSERDATA: return (rawuvalue(o) + 1); case LUA_TLIGHTUSERDATA: return pvalue(o); @@ -393,13 +401,13 @@ LUA_API void *lua_touserdata (lua_State *L, int idx) { LUA_API lua_State *lua_tothread (lua_State *L, int idx) { - StkId o = index2adr(L, idx); + StkId o = index2addr(L, idx); return (!ttisthread(o)) ? NULL : thvalue(o); } LUA_API const void *lua_topointer (lua_State *L, int idx) { - StkId o = index2adr(L, idx); + StkId o = index2addr(L, idx); switch (ttype(o)) { case LUA_TTABLE: return hvalue(o); case LUA_TFUNCTION: return clvalue(o); @@ -442,20 +450,25 @@ LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { } -LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) { +LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { + TString *ts; lua_lock(L); luaC_checkGC(L); - setsvalue2s(L, L->top, luaS_newlstr(L, s, len)); + ts = luaS_newlstr(L, s, len); + setsvalue2s(L, L->top, ts); api_incr_top(L); lua_unlock(L); + return getstr(ts); } -LUA_API void lua_pushstring (lua_State *L, const char *s) { - if (s == NULL) +LUA_API const char *lua_pushstring (lua_State *L, const char *s) { + if (s == NULL) { lua_pushnil(L); + return NULL; + } else - lua_pushlstring(L, s, strlen(s)); + return lua_pushlstring(L, s, strlen(s)); } @@ -486,8 +499,9 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { Closure *cl; lua_lock(L); - luaC_checkGC(L); api_checknelems(L, n); + api_check(L, n <= UCHAR_MAX, "upvalue index too large"); + luaC_checkGC(L); cl = luaF_newCclosure(L, n, getcurrenv(L)); cl->c.f = fn; L->top -= n; @@ -534,7 +548,7 @@ LUA_API int lua_pushthread (lua_State *L) { LUA_API void lua_gettable (lua_State *L, int idx) { StkId t; lua_lock(L); - t = index2adr(L, idx); + t = index2addr(L, idx); api_checkvalidindex(L, t); luaV_gettable(L, t, L->top - 1, L->top - 1); lua_unlock(L); @@ -543,13 +557,12 @@ LUA_API void lua_gettable (lua_State *L, int idx) { LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { StkId t; - TValue key; lua_lock(L); - t = index2adr(L, idx); + t = index2addr(L, idx); api_checkvalidindex(L, t); - setsvalue(L, &key, luaS_new(L, k)); - luaV_gettable(L, t, &key, L->top); + setsvalue2s(L, L->top, luaS_new(L, k)); api_incr_top(L); + luaV_gettable(L, t, L->top - 1, L->top - 1); lua_unlock(L); } @@ -557,8 +570,8 @@ LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { LUA_API void lua_rawget (lua_State *L, int idx) { StkId t; lua_lock(L); - t = index2adr(L, idx); - api_check(L, ttistable(t)); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); lua_unlock(L); } @@ -567,19 +580,23 @@ LUA_API void lua_rawget (lua_State *L, int idx) { LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { StkId o; lua_lock(L); - o = index2adr(L, idx); - api_check(L, ttistable(o)); - setobj2s(L, L->top, luaH_getnum(hvalue(o), n)); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + setobj2s(L, L->top, luaH_getint(hvalue(o), n)); api_incr_top(L); lua_unlock(L); } LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { + Table *t; lua_lock(L); luaC_checkGC(L); - sethvalue(L, L->top, luaH_new(L, narray, nrec)); + t = luaH_new(L); + sethvalue(L, L->top, t); api_incr_top(L); + if (narray > 0 || nrec > 0) + luaH_resize(L, t, narray, nrec); lua_unlock(L); } @@ -589,7 +606,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { Table *mt = NULL; int res; lua_lock(L); - obj = index2adr(L, objindex); + obj = index2addr(L, objindex); switch (ttype(obj)) { case LUA_TTABLE: mt = hvalue(obj)->metatable; @@ -616,7 +633,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { LUA_API void lua_getfenv (lua_State *L, int idx) { StkId o; lua_lock(L); - o = index2adr(L, idx); + o = index2addr(L, idx); api_checkvalidindex(L, o); switch (ttype(o)) { case LUA_TFUNCTION: @@ -625,9 +642,6 @@ LUA_API void lua_getfenv (lua_State *L, int idx) { case LUA_TUSERDATA: sethvalue(L, L->top, uvalue(o)->env); break; - case LUA_TTHREAD: - setobj2s(L, L->top, gt(thvalue(o))); - break; default: setnilvalue(L->top); break; @@ -646,7 +660,7 @@ LUA_API void lua_settable (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); - t = index2adr(L, idx); + t = index2addr(L, idx); api_checkvalidindex(L, t); luaV_settable(L, t, L->top - 2, L->top - 1); L->top -= 2; /* pop index and value */ @@ -656,14 +670,13 @@ LUA_API void lua_settable (lua_State *L, int idx) { LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { StkId t; - TValue key; lua_lock(L); api_checknelems(L, 1); - t = index2adr(L, idx); + t = index2addr(L, idx); api_checkvalidindex(L, t); - setsvalue(L, &key, luaS_new(L, k)); - luaV_settable(L, t, &key, L->top - 1); - L->top--; /* pop value */ + setsvalue2s(L, L->top++, luaS_new(L, k)); + luaV_settable(L, t, L->top - 1, L->top - 2); + L->top -= 2; /* pop value and key */ lua_unlock(L); } @@ -672,8 +685,8 @@ LUA_API void lua_rawset (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); - t = index2adr(L, idx); - api_check(L, ttistable(t)); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); luaC_barriert(L, hvalue(t), L->top-1); L->top -= 2; @@ -685,9 +698,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, int n) { StkId o; lua_lock(L); api_checknelems(L, 1); - o = index2adr(L, idx); - api_check(L, ttistable(o)); - setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + setobj2t(L, luaH_setint(L, hvalue(o), n), L->top-1); luaC_barriert(L, hvalue(o), L->top-1); L->top--; lua_unlock(L); @@ -699,12 +712,12 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { Table *mt; lua_lock(L); api_checknelems(L, 1); - obj = index2adr(L, objindex); + obj = index2addr(L, objindex); api_checkvalidindex(L, obj); if (ttisnil(L->top - 1)) mt = NULL; else { - api_check(L, ttistable(L->top - 1)); + api_check(L, ttistable(L->top - 1), "table expected"); mt = hvalue(L->top - 1); } switch (ttype(obj)) { @@ -716,8 +729,10 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { } case LUA_TUSERDATA: { uvalue(obj)->metatable = mt; - if (mt) + if (mt) { luaC_objbarrier(L, rawuvalue(obj), mt); + luaC_checkfinalizer(L, rawuvalue(obj)); + } break; } default: { @@ -736,9 +751,9 @@ LUA_API int lua_setfenv (lua_State *L, int idx) { int res = 1; lua_lock(L); api_checknelems(L, 1); - o = index2adr(L, idx); + o = index2addr(L, idx); api_checkvalidindex(L, o); - api_check(L, ttistable(L->top - 1)); + api_check(L, ttistable(L->top - 1), "table expected"); switch (ttype(o)) { case LUA_TFUNCTION: clvalue(o)->c.env = hvalue(L->top - 1); @@ -746,9 +761,6 @@ LUA_API int lua_setfenv (lua_State *L, int idx) { case LUA_TUSERDATA: uvalue(o)->env = hvalue(L->top - 1); break; - case LUA_TTHREAD: - sethvalue(L, gt(thvalue(o)), hvalue(L->top - 1)); - break; default: res = 0; break; @@ -765,21 +777,36 @@ LUA_API int lua_setfenv (lua_State *L, int idx) { */ -#define adjustresults(L,nres) \ - { if (nres == LUA_MULTRET && L->top >= L->ci->top) L->ci->top = L->top; } +#define checkresults(L,na,nr) \ + api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \ + "results from function overflow current stack size") + +LUA_API int lua_getctx (lua_State *L, int *ctx) { + if (L->ci->callstatus & CIST_YIELDED) { + if (ctx) *ctx = L->ci->u.c.ctx; + return L->ci->u.c.status; + } + else return LUA_OK; +} -#define checkresults(L,na,nr) \ - api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na))) - -LUA_API void lua_call (lua_State *L, int nargs, int nresults) { +LUA_API void lua_callk (lua_State *L, int nargs, int nresults, int ctx, + lua_CFunction k) { StkId func; lua_lock(L); + api_check(L, k == NULL || !isLua(L->ci), + "cannot use continuations inside hooks"); api_checknelems(L, nargs+1); checkresults(L, nargs, nresults); func = L->top - (nargs+1); - luaD_call(L, func, nresults); + if (k != NULL && L->nny == 0) { /* need to prepare continuation? */ + L->ci->u.c.k = k; /* save continuation */ + L->ci->u.c.ctx = ctx; /* save context */ + luaD_call(L, func, nresults, 1); /* do the call */ + } + else /* no continuation or no yieldable */ + luaD_call(L, func, nresults, 0); /* just do the call */ adjustresults(L, nresults); lua_unlock(L); } @@ -797,68 +824,55 @@ struct CallS { /* data to `f_call' */ static void f_call (lua_State *L, void *ud) { struct CallS *c = cast(struct CallS *, ud); - luaD_call(L, c->func, c->nresults); + luaD_call(L, c->func, c->nresults, 0); } -LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { +LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, + int ctx, lua_CFunction k) { struct CallS c; int status; ptrdiff_t func; lua_lock(L); + api_check(L, k == NULL || !isLua(L->ci), + "cannot use continuations inside hooks"); api_checknelems(L, nargs+1); checkresults(L, nargs, nresults); if (errfunc == 0) func = 0; else { - StkId o = index2adr(L, errfunc); + StkId o = index2addr(L, errfunc); api_checkvalidindex(L, o); func = savestack(L, o); } c.func = L->top - (nargs+1); /* function to be called */ - c.nresults = nresults; - status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); + if (k == NULL || L->nny > 0) { /* no continuation or no yieldable? */ + c.nresults = nresults; /* do a 'conventional' protected call */ + status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); + } + else { /* prepare continuation (call is already protected by 'resume') */ + CallInfo *ci = L->ci; + ci->u.c.k = k; /* save continuation */ + ci->u.c.ctx = ctx; /* save context */ + /* save information for error recovery */ + ci->u.c.oldtop = savestack(L, c.func); + ci->u.c.old_allowhook = L->allowhook; + ci->u.c.old_errfunc = L->errfunc; + L->errfunc = func; + /* mark that function may do error recovery */ + ci->callstatus |= CIST_YPCALL; + luaD_call(L, c.func, nresults, 1); /* do the call */ + ci->callstatus &= ~CIST_YPCALL; + L->errfunc = ci->u.c.old_errfunc; + status = LUA_OK; /* if it is here, there were no errors */ + } adjustresults(L, nresults); lua_unlock(L); return status; } -/* -** Execute a protected C call. -*/ -struct CCallS { /* data to `f_Ccall' */ - lua_CFunction func; - void *ud; -}; - - -static void f_Ccall (lua_State *L, void *ud) { - struct CCallS *c = cast(struct CCallS *, ud); - Closure *cl; - cl = luaF_newCclosure(L, 0, getcurrenv(L)); - cl->c.f = c->func; - setclvalue(L, L->top, cl); /* push function */ - api_incr_top(L); - setpvalue(L->top, c->ud); /* push only argument */ - api_incr_top(L); - luaD_call(L, L->top - 2, 0); -} - - -LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { - struct CCallS c; - int status; - lua_lock(L); - c.func = func; - c.ud = ud; - status = luaD_pcall(L, f_Ccall, &c, savestack(L, L->top), 0); - lua_unlock(L); - return status; -} - - LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char *chunkname) { ZIO z; @@ -879,7 +893,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) { api_checknelems(L, 1); o = L->top - 1; if (isLfunction(o)) - status = luaU_dump(L, clvalue(o)->l.p, writer, data, 0); + status = luaU_dump(L, getproto(o), writer, data, 0); else status = 1; lua_unlock(L); @@ -911,7 +925,7 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { break; } case LUA_GCCOLLECT: { - luaC_fullgc(L); + luaC_fullgc(L, 0); break; } case LUA_GCCOUNT: { @@ -924,11 +938,9 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { break; } case LUA_GCSTEP: { + lu_mem oldts = g->GCthreshold; lu_mem a = (cast(lu_mem, data) << 10); - if (a <= g->totalbytes) - g->GCthreshold = g->totalbytes - a; - else - g->GCthreshold = 0; + g->GCthreshold = (a <= g->totalbytes) ? g->totalbytes - a : 0; while (g->GCthreshold <= g->totalbytes) { luaC_step(L); if (g->gcstate == GCSpause) { /* end of cycle? */ @@ -936,6 +948,8 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { break; } } + if (oldts == MAX_LUMEM) /* collector was stopped? */ + g->GCthreshold = oldts; /* keep it that way */ break; } case LUA_GCSETPAUSE: { @@ -948,6 +962,10 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { g->gcstepmul = data; break; } + case LUA_GCISRUNNING: { + res = (g->GCthreshold != MAX_LUMEM); + break; + } default: res = -1; /* invalid option */ } lua_unlock(L); @@ -974,8 +992,8 @@ LUA_API int lua_next (lua_State *L, int idx) { StkId t; int more; lua_lock(L); - t = index2adr(L, idx); - api_check(L, ttistable(t)); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); more = luaH_next(L, hvalue(t), L->top - 1); if (more) { api_incr_top(L); @@ -992,8 +1010,7 @@ LUA_API void lua_concat (lua_State *L, int n) { api_checknelems(L, n); if (n >= 2) { luaC_checkGC(L); - luaV_concat(L, n, cast_int(L->top - L->base) - 1); - L->top -= (n-1); + luaV_concat(L, n); } else if (n == 0) { /* push empty string */ setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); @@ -1004,6 +1021,16 @@ LUA_API void lua_concat (lua_State *L, int n) { } +LUA_API void lua_len (lua_State *L, int idx) { + StkId t; + lua_lock(L); + t = index2addr(L, idx); + luaV_objlen(L, L->top, t); + api_incr_top(L); + lua_unlock(L); +} + + LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { lua_Alloc f; lua_lock(L); @@ -1049,7 +1076,7 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val) { Proto *p = f->l.p; if (!(1 <= n && n <= p->sizeupvalues)) return NULL; *val = f->l.upvals[n-1]->v; - return getstr(p->upvalues[n-1]); + return getstr(p->upvalues[n-1].name); } } @@ -1058,7 +1085,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val; lua_lock(L); - name = aux_upvalue(index2adr(L, funcindex), n, &val); + name = aux_upvalue(index2addr(L, funcindex), n, &val); if (name) { setobj2s(L, L->top, val); api_incr_top(L); @@ -1073,7 +1100,7 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { TValue *val; StkId fi; lua_lock(L); - fi = index2adr(L, funcindex); + fi = index2addr(L, funcindex); api_checknelems(L, 1); name = aux_upvalue(fi, n, &val); if (name) { @@ -1085,3 +1112,49 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { return name; } + +static UpVal **getupvalref (lua_State *L, int fidx, int n, Closure **pf) { + Closure *f; + Proto *p; + StkId fi = index2addr(L, fidx); + api_check(L, ttisfunction(fi), "function expected"); + f = clvalue(fi); + api_check(L, !f->c.isC, "Lua function expected"); + p = f->l.p; + api_check(L, (1 <= n && n <= p->sizeupvalues), "invalid upvalue index"); + if (pf) *pf = f; + return &f->l.upvals[n - 1]; /* get its upvalue pointer */ +} + + +LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { + Closure *f; + StkId fi = index2addr(L, fidx); + api_check(L, ttisfunction(fi), "function expected"); + f = clvalue(fi); + if (f->c.isC) { + api_check(L, 1 <= n && n <= f->c.nupvalues, "invalid upvalue index"); + return &f->c.upvalue[n - 1]; + } + else return *getupvalref(L, fidx, n, NULL); +} + + +LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, + int fidx2, int n2) { + Closure *f1; + UpVal **up1 = getupvalref(L, fidx1, n1, &f1); + UpVal **up2 = getupvalref(L, fidx2, n2, NULL); + *up1 = *up2; + luaC_objbarrier(L, f1, *up2); +} + + +#if defined(LUA_COMPAT_CPCALL) +LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { + lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_CPCALL); + lua_pushlightuserdata(L, &func); + lua_pushlightuserdata(L, ud); + return lua_pcall(L, 2, 0, 0); +} +#endif @@ -1,5 +1,5 @@ /* -** $Id: lapi.h,v 2.2.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lapi.h,v 2.7 2009/11/27 15:37:59 roberto Exp $ ** Auxiliary functions from Lua API ** See Copyright Notice in lua.h */ @@ -8,9 +8,17 @@ #define lapi_h -#include "lobject.h" +#include "llimits.h" +#include "lstate.h" +#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ + "stack overflow");} + +#define adjustresults(L,nres) \ + { if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } + +#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ + "not enough elements in the stack") -LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o); #endif diff --git a/src/lauxlib.c b/src/lauxlib.c index 10f14e2c..9972555e 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,11 +1,10 @@ /* -** $Id: lauxlib.c,v 1.159.1.3 2008/01/21 13:20:51 roberto Exp $ +** $Id: lauxlib.c,v 1.196 2009/12/22 15:32:50 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ -#include <ctype.h> #include <errno.h> #include <stdarg.h> #include <stdio.h> @@ -25,9 +24,6 @@ #include "lauxlib.h" -#define FREELIST_REF 0 /* free list of references */ - - /* convert a stack index to positive */ #define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ lua_gettop(L) + (i) + 1) @@ -35,11 +31,131 @@ /* ** {====================================================== -** Error-report functions +** Traceback ** ======================================================= */ +#define LEVELS1 12 /* size of the first part of the stack */ +#define LEVELS2 10 /* size of the second part of the stack */ + + + +/* +** search for 'objidx' in table at index -1. +** return 1 + string at top if find a good name. +*/ +static int findfield (lua_State *L, int objidx, int level) { + int found = 0; + if (level == 0 || !lua_istable(L, -1)) + return 0; /* not found */ + lua_pushnil(L); /* start 'next' loop */ + while (!found && lua_next(L, -2)) { /* for each pair in table */ + if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ + if (lua_rawequal(L, objidx, -1)) { /* found object? */ + lua_pop(L, 1); /* remove value (but keep name) */ + return 1; + } + else if (findfield(L, objidx, level - 1)) { /* try recursively */ + lua_remove(L, -2); /* remove table (but keep name) */ + lua_pushliteral(L, "."); + lua_insert(L, -2); /* place '.' between the two names */ + lua_concat(L, 3); + return 1; + } + } + lua_pop(L, 1); /* remove value */ + } + return 0; /* not found */ +} + + +static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { + int top = lua_gettop(L); + lua_getinfo(L, "f", ar); /* push function */ + lua_pushglobaltable(L); + if (findfield(L, top + 1, 2)) { + lua_copy(L, -1, top + 1); /* move name to proper place */ + lua_pop(L, 2); /* remove pushed values */ + return 1; + } + else { + lua_settop(L, top); /* remove function and global table */ + return 0; + } +} + + +static void pushfuncname (lua_State *L, lua_Debug *ar) { + if (*ar->namewhat != '\0') /* is there a name? */ + lua_pushfstring(L, "function " LUA_QS, ar->name); + else if (*ar->what == 'm') /* main? */ + lua_pushfstring(L, "main chunk"); + else if (*ar->what == 'C' || *ar->what == 't') { + if (pushglobalfuncname(L, ar)) { + lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); + lua_remove(L, -2); /* remove name */ + } + else + lua_pushliteral(L, "?"); + } + else + lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); +} + + +static int countlevels (lua_State *L) { + lua_Debug ar; + int li = 1, le = 1; + /* find an upper bound */ + while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } + /* do a binary search */ + while (li < le) { + int m = (li + le)/2; + if (lua_getstack(L, m, &ar)) li = m + 1; + else le = m; + } + return le - 1; +} + + +LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, + const char *msg, int level) { + lua_Debug ar; + int top = lua_gettop(L); + int numlevels = countlevels(L1); + int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0; + if (msg) lua_pushfstring(L, "%s\n", msg); + lua_pushliteral(L, "stack traceback:"); + while (lua_getstack(L1, level++, &ar)) { + if (level == mark) { /* too many levels? */ + lua_pushliteral(L, "\n\t..."); /* add a '...' */ + level = numlevels - LEVELS2; /* and skip to last ones */ + } + else { + lua_getinfo(L1, "Slnt", &ar); + lua_pushfstring(L, "\n\t%s:", ar.short_src); + if (ar.currentline > 0) + lua_pushfstring(L, "%d:", ar.currentline); + lua_pushliteral(L, " in "); + pushfuncname(L, &ar); + if (ar.istailcall) + lua_pushliteral(L, "\n\t(...tail calls...)"); + lua_concat(L, lua_gettop(L) - top); + } + } + lua_concat(L, lua_gettop(L) - top); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Error-report functions +** ======================================================= +*/ + LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { lua_Debug ar; if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ @@ -48,17 +164,16 @@ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { if (strcmp(ar.namewhat, "method") == 0) { narg--; /* do not count `self' */ if (narg == 0) /* error is in the self argument itself? */ - return luaL_error(L, "calling " LUA_QS " on bad self (%s)", - ar.name, extramsg); + return luaL_error(L, "calling " LUA_QS " on bad self", ar.name); } if (ar.name == NULL) - ar.name = "?"; + ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)", narg, ar.name, extramsg); } -LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { +LUALIB_API int luaL_typeerror (lua_State *L, int narg, const char *tname) { const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, luaL_typename(L, narg)); return luaL_argerror(L, narg, msg); @@ -66,7 +181,7 @@ LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { static void tag_error (lua_State *L, int narg, int tag) { - luaL_typerror(L, narg, lua_typename(L, tag)); + luaL_typeerror(L, narg, lua_typename(L, tag)); } @@ -96,18 +211,11 @@ LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { /* }====================================================== */ -LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, - const char *const lst[]) { - const char *name = (def) ? luaL_optstring(L, narg, def) : - luaL_checkstring(L, narg); - int i; - for (i=0; lst[i]; i++) - if (strcmp(lst[i], name) == 0) - return i; - return luaL_argerror(L, narg, - lua_pushfstring(L, "invalid option " LUA_QS, name)); -} - +/* +** {====================================================== +** Userdata's metatable manipulation +** ======================================================= +*/ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get registry.name */ @@ -121,25 +229,56 @@ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { } -LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { +LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) { void *p = lua_touserdata(L, ud); if (p != NULL) { /* value is a userdata? */ if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ - if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ - lua_pop(L, 2); /* remove both metatables */ - return p; - } + if (!lua_rawequal(L, -1, -2)) /* not the same? */ + p = NULL; /* value is a userdata with wrong metatable */ + lua_pop(L, 2); /* remove both metatables */ + return p; } } - luaL_typerror(L, ud, tname); /* else error */ - return NULL; /* to avoid warnings */ + return NULL; /* value is not a userdata with a metatable */ +} + + +LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { + void *p = luaL_testudata(L, ud, tname); + if (p == NULL) luaL_typeerror(L, ud, tname); + return p; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Argument check functions +** ======================================================= +*/ + +LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, + const char *const lst[]) { + const char *name = (def) ? luaL_optstring(L, narg, def) : + luaL_checkstring(L, narg); + int i; + for (i=0; lst[i]; i++) + if (strcmp(lst[i], name) == 0) + return i; + return luaL_argerror(L, narg, + lua_pushfstring(L, "invalid option " LUA_QS, name)); } -LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) { - if (!lua_checkstack(L, space)) - luaL_error(L, "stack overflow (%s)", mes); +LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { + if (!lua_checkstack(L, space)) { + if (msg) + luaL_error(L, "stack overflow (%s)", msg); + else + luaL_error(L, "stack overflow"); + } } @@ -199,189 +338,9 @@ LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, return luaL_opt(L, luaL_checkinteger, narg, def); } - -LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { - if (!lua_getmetatable(L, obj)) /* no metatable? */ - return 0; - lua_pushstring(L, event); - lua_rawget(L, -2); - if (lua_isnil(L, -1)) { - lua_pop(L, 2); /* remove metatable and metafield */ - return 0; - } - else { - lua_remove(L, -2); /* remove only metatable */ - return 1; - } -} - - -LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { - obj = abs_index(L, obj); - if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ - return 0; - lua_pushvalue(L, obj); - lua_call(L, 1, 1); - return 1; -} - - -LUALIB_API void (luaL_register) (lua_State *L, const char *libname, - const luaL_Reg *l) { - luaI_openlib(L, libname, l, 0); -} - - -static int libsize (const luaL_Reg *l) { - int size = 0; - for (; l->name; l++) size++; - return size; -} - - -LUALIB_API void luaI_openlib (lua_State *L, const char *libname, - const luaL_Reg *l, int nup) { - if (libname) { - int size = libsize(l); - /* check whether lib already exists */ - luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); - lua_getfield(L, -1, libname); /* get _LOADED[libname] */ - if (!lua_istable(L, -1)) { /* not found? */ - lua_pop(L, 1); /* remove previous result */ - /* try global variable (and create one if it does not exist) */ - if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL) - luaL_error(L, "name conflict for module " LUA_QS, libname); - lua_pushvalue(L, -1); - lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ - } - lua_remove(L, -2); /* remove _LOADED table */ - lua_insert(L, -(nup+1)); /* move library table to below upvalues */ - } - for (; l->name; l++) { - int i; - for (i=0; i<nup; i++) /* copy upvalues to the top */ - lua_pushvalue(L, -nup); - lua_pushcclosure(L, l->func, nup); - lua_setfield(L, -(nup+2), l->name); - } - lua_pop(L, nup); /* remove upvalues */ -} - - - -/* -** {====================================================== -** getn-setn: size for arrays -** ======================================================= -*/ - -#if defined(LUA_COMPAT_GETN) - -static int checkint (lua_State *L, int topop) { - int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1; - lua_pop(L, topop); - return n; -} - - -static void getsizes (lua_State *L) { - lua_getfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); - if (lua_isnil(L, -1)) { /* no `size' table? */ - lua_pop(L, 1); /* remove nil */ - lua_newtable(L); /* create it */ - lua_pushvalue(L, -1); /* `size' will be its own metatable */ - lua_setmetatable(L, -2); - lua_pushliteral(L, "kv"); - lua_setfield(L, -2, "__mode"); /* metatable(N).__mode = "kv" */ - lua_pushvalue(L, -1); - lua_setfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); /* store in register */ - } -} - - -LUALIB_API void luaL_setn (lua_State *L, int t, int n) { - t = abs_index(L, t); - lua_pushliteral(L, "n"); - lua_rawget(L, t); - if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */ - lua_pushliteral(L, "n"); /* use it */ - lua_pushinteger(L, n); - lua_rawset(L, t); - } - else { /* use `sizes' */ - getsizes(L); - lua_pushvalue(L, t); - lua_pushinteger(L, n); - lua_rawset(L, -3); /* sizes[t] = n */ - lua_pop(L, 1); /* remove `sizes' */ - } -} - - -LUALIB_API int luaL_getn (lua_State *L, int t) { - int n; - t = abs_index(L, t); - lua_pushliteral(L, "n"); /* try t.n */ - lua_rawget(L, t); - if ((n = checkint(L, 1)) >= 0) return n; - getsizes(L); /* else try sizes[t] */ - lua_pushvalue(L, t); - lua_rawget(L, -2); - if ((n = checkint(L, 2)) >= 0) return n; - return (int)lua_objlen(L, t); -} - -#endif - /* }====================================================== */ - -LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, - const char *r) { - const char *wild; - size_t l = strlen(p); - luaL_Buffer b; - luaL_buffinit(L, &b); - while ((wild = strstr(s, p)) != NULL) { - luaL_addlstring(&b, s, wild - s); /* push prefix */ - luaL_addstring(&b, r); /* push replacement in place of pattern */ - s = wild + l; /* continue after `p' */ - } - luaL_addstring(&b, s); /* push last suffix */ - luaL_pushresult(&b); - return lua_tostring(L, -1); -} - - -LUALIB_API const char *luaL_findtable (lua_State *L, int idx, - const char *fname, int szhint) { - const char *e; - lua_pushvalue(L, idx); - do { - e = strchr(fname, '.'); - if (e == NULL) e = fname + strlen(fname); - lua_pushlstring(L, fname, e - fname); - lua_rawget(L, -2); - if (lua_isnil(L, -1)) { /* no such field? */ - lua_pop(L, 1); /* remove this nil */ - lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ - lua_pushlstring(L, fname, e - fname); - lua_pushvalue(L, -2); - lua_settable(L, -4); /* set new table into field */ - } - else if (!lua_istable(L, -1)) { /* field has a non-table value? */ - lua_pop(L, 2); /* remove table and value */ - return fname; /* return problematic part of the name */ - } - lua_remove(L, -2); /* remove previous table */ - fname = e + 1; - } while (*e == '.'); - return NULL; -} - - - /* ** {====================================================== ** Generic Buffer manipulation @@ -411,9 +370,9 @@ static void adjuststack (luaL_Buffer *B) { if (B->lvl > 1) { lua_State *L = B->L; int toget = 1; /* number of levels to concat */ - size_t toplen = lua_strlen(L, -1); + size_t toplen = lua_rawlen(L, -1); do { - size_t l = lua_strlen(L, -(toget+1)); + size_t l = lua_rawlen(L, -(toget+1)); if (B->lvl - toget + 1 >= LIMIT || toplen > l) { toplen += l; toget++; @@ -470,6 +429,7 @@ LUALIB_API void luaL_addvalue (luaL_Buffer *B) { LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { + luaL_checkstack(L, LIMIT + LUA_MINSTACK, "no space for new buffer"); B->L = L; B->p = B->buffer; B->lvl = 0; @@ -478,6 +438,16 @@ LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { /* }====================================================== */ +/* +** {====================================================== +** Reference system +** ======================================================= +*/ + +/* number of prereserved references (for internal use) */ +#define FREELIST_REF (LUA_RIDX_LAST + 1) /* free list of references */ + + LUALIB_API int luaL_ref (lua_State *L, int t) { int ref; t = abs_index(L, t); @@ -493,8 +463,12 @@ LUALIB_API int luaL_ref (lua_State *L, int t) { lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ } else { /* no free elements */ - ref = (int)lua_objlen(L, t); - ref++; /* create new reference */ + ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ + if (ref == FREELIST_REF) { /* FREELIST_REF not initialized? */ + lua_pushinteger(L, 0); + lua_rawseti(L, t, FREELIST_REF); + ref = FREELIST_REF + 1; + } } lua_rawseti(L, t, ref); return ref; @@ -511,6 +485,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { } } +/* }====================================================== */ /* @@ -534,6 +509,9 @@ static const char *getF (lua_State *L, void *ud, size_t *size) { *size = 1; return "\n"; } + /* 'fread' can return > 0 *and* set the EOF flag. If next call to + 'getF' calls 'fread', terminal may still wait for user input. + The next check avoids this problem. */ if (feof(lf->f)) return NULL; *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); return (*size > 0) ? lf->buff : NULL; @@ -574,7 +552,7 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ if (lf.f == NULL) return errfile(L, "reopen", fnameindex); /* skip eventual `#!...' */ - while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; + while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; lf.extraline = 0; } ungetc(c, lf.f); @@ -615,13 +593,149 @@ LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, } -LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) { +LUALIB_API int luaL_loadstring (lua_State *L, const char *s) { return luaL_loadbuffer(L, s, strlen(s), s); } +/* }====================================================== */ -/* }====================================================== */ + +LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { + if (!lua_getmetatable(L, obj)) /* no metatable? */ + return 0; + lua_pushstring(L, event); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) { + lua_pop(L, 2); /* remove metatable and metafield */ + return 0; + } + else { + lua_remove(L, -2); /* remove only metatable */ + return 1; + } +} + + +LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { + obj = abs_index(L, obj); + if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ + return 0; + lua_pushvalue(L, obj); + lua_call(L, 1, 1); + return 1; +} + + +LUALIB_API int luaL_len (lua_State *L, int idx) { + int l; + lua_len(L, idx); + l = lua_tointeger(L, -1); + if (l == 0 && !lua_isnumber(L, -1)) + luaL_error(L, "object length is not a number"); + lua_pop(L, 1); /* remove object */ + return l; +} + + +LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { + if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */ + switch (lua_type(L, idx)) { + case LUA_TNUMBER: + case LUA_TSTRING: + lua_pushvalue(L, idx); + break; + case LUA_TBOOLEAN: + lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false")); + break; + case LUA_TNIL: + lua_pushliteral(L, "nil"); + break; + default: + lua_pushfstring(L, "%s: %p", luaL_typename(L, idx), + lua_topointer(L, idx)); + break; + } + } + return lua_tolstring(L, -1, len); +} + + +static int libsize (const luaL_Reg *l) { + int size = 0; + for (; l->name; l++) size++; + return size; +} + + +LUALIB_API void luaL_register (lua_State *L, const char *libname, + const luaL_Reg *l) { + luaL_checkversion(L); + if (libname) { + /* check whether lib already exists */ + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); + lua_getfield(L, -1, libname); /* get _LOADED[libname] */ + if (!lua_istable(L, -1)) { /* not found? */ + lua_pop(L, 1); /* remove previous result */ + /* try global variable (and create one if it does not exist) */ + lua_pushglobaltable(L); + if (luaL_findtable(L, 0, libname, libsize(l)) != NULL) + luaL_error(L, "name conflict for module " LUA_QS, libname); + lua_pushvalue(L, -1); + lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ + } + lua_remove(L, -2); /* remove _LOADED table */ + } + if (l == NULL) return; /* nothing to register? */ + for (; l->name; l++) { /* else fill the table with given functions */ + lua_pushcfunction(L, l->func); + lua_setfield(L, -2, l->name); + } +} + + +LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, + const char *r) { + const char *wild; + size_t l = strlen(p); + luaL_Buffer b; + luaL_buffinit(L, &b); + while ((wild = strstr(s, p)) != NULL) { + luaL_addlstring(&b, s, wild - s); /* push prefix */ + luaL_addstring(&b, r); /* push replacement in place of pattern */ + s = wild + l; /* continue after `p' */ + } + luaL_addstring(&b, s); /* push last suffix */ + luaL_pushresult(&b); + return lua_tostring(L, -1); +} + + +LUALIB_API const char *luaL_findtable (lua_State *L, int idx, + const char *fname, int szhint) { + const char *e; + if (idx) lua_pushvalue(L, idx); + do { + e = strchr(fname, '.'); + if (e == NULL) e = fname + strlen(fname); + lua_pushlstring(L, fname, e - fname); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) { /* no such field? */ + lua_pop(L, 1); /* remove this nil */ + lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ + lua_pushlstring(L, fname, e - fname); + lua_pushvalue(L, -2); + lua_settable(L, -4); /* set new table into field */ + } + else if (!lua_istable(L, -1)) { /* field has a non-table value? */ + lua_pop(L, 2); /* remove table and value */ + return fname; /* return problematic part of the name */ + } + lua_remove(L, -2); /* remove previous table */ + fname = e + 1; + } while (*e == '.'); + return NULL; +} static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { @@ -637,10 +751,9 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { static int panic (lua_State *L) { - (void)L; /* to avoid warnings */ fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1)); - return 0; + return 0; /* return to Lua to abort */ } @@ -650,3 +763,13 @@ LUALIB_API lua_State *luaL_newstate (void) { return L; } + +LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver) { + const lua_Number *v = lua_version(L); + if (v != lua_version(NULL)) + luaL_error(L, "multiple Lua VMs detected"); + else if (*v != ver) + luaL_error(L, "version mismatch: app. needs %d, Lua core provides %f", + ver, *v); +} + diff --git a/src/lauxlib.h b/src/lauxlib.h index 34258235..d0143481 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lauxlib.h,v 1.98 2010/01/06 15:14:15 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -15,18 +15,6 @@ #include "lua.h" -#if defined(LUA_COMPAT_GETN) -LUALIB_API int (luaL_getn) (lua_State *L, int t); -LUALIB_API void (luaL_setn) (lua_State *L, int t, int n); -#else -#define luaL_getn(L,i) ((int)lua_objlen(L, i)) -#define luaL_setn(L,i,j) ((void)0) /* no op! */ -#endif - -#if defined(LUA_COMPAT_OPENLIB) -#define luaI_openlib luaL_openlib -#endif - /* extra error code for `luaL_load' */ #define LUA_ERRFILE (LUA_ERRERR+1) @@ -38,6 +26,8 @@ typedef struct luaL_Reg { } luaL_Reg; +LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver); +#define luaL_checkversion(L) luaL_checkversion_(L, LUA_VERSION_NUM) LUALIB_API void (luaI_openlib) (lua_State *L, const char *libname, const luaL_Reg *l, int nup); @@ -45,7 +35,8 @@ LUALIB_API void (luaL_register) (lua_State *L, const char *libname, const luaL_Reg *l); LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); -LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname); +LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len); +LUALIB_API int (luaL_typeerror) (lua_State *L, int narg, const char *tname); LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, size_t *l); @@ -63,6 +54,7 @@ LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); LUALIB_API void (luaL_checkany) (lua_State *L, int narg); LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); +LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname); LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); LUALIB_API void (luaL_where) (lua_State *L, int lvl); @@ -81,6 +73,7 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); LUALIB_API lua_State *(luaL_newstate) (void); +LUALIB_API int luaL_len (lua_State *L, int idx); LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, const char *r); @@ -88,6 +81,8 @@ LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, const char *fname, int szhint); +LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, + const char *msg, int level); @@ -137,9 +132,6 @@ typedef struct luaL_Buffer { ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \ (*(B)->p++ = (char)(c))) -/* compatibility only */ -#define luaL_putchar(B,c) luaL_addchar(B,c) - #define luaL_addsize(B,n) ((B)->p += (n)) LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); @@ -169,6 +161,7 @@ LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); #define luaL_reg luaL_Reg + #endif diff --git a/src/lbaselib.c b/src/lbaselib.c index 2a4c079d..162c06f2 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.191.1.6 2008/02/14 16:46:22 roberto Exp $ +** $Id: lbaselib.c,v 1.235 2009/12/28 16:30:31 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -20,32 +20,25 @@ #include "lualib.h" - - -/* -** If your system does not support `stdout', you can just remove this function. -** If you need, you can define your own `print' function, following this -** model but changing `fputs' to put the strings at a proper place -** (a console window or a log file, for instance). -*/ static int luaB_print (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int i; - lua_getglobal(L, "tostring"); + lua_getfield(L, LUA_ENVIRONINDEX, "tostring"); for (i=1; i<=n; i++) { const char *s; + size_t l; lua_pushvalue(L, -1); /* function to be called */ lua_pushvalue(L, i); /* value to print */ lua_call(L, 1, 1); - s = lua_tostring(L, -1); /* get result */ + s = lua_tolstring(L, -1, &l); /* get result */ if (s == NULL) return luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("print")); - if (i>1) fputs("\t", stdout); - fputs(s, stdout); + if (i>1) luai_writestring("\t", 1); + luai_writestring(s, l); lua_pop(L, 1); /* pop result */ } - fputs("\n", stdout); + luai_writestring("\n", 1); return 0; } @@ -107,13 +100,16 @@ static int luaB_setmetatable (lua_State *L) { luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected"); if (luaL_getmetafield(L, 1, "__metatable")) - luaL_error(L, "cannot change a protected metatable"); + return luaL_error(L, "cannot change a protected metatable"); lua_settop(L, 2); lua_setmetatable(L, 1); return 1; } + +#if defined(LUA_COMPAT_FENV) + static void getfunc (lua_State *L, int opt) { if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); else { @@ -123,40 +119,38 @@ static void getfunc (lua_State *L, int opt) { if (lua_getstack(L, level, &ar) == 0) luaL_argerror(L, 1, "invalid level"); lua_getinfo(L, "f", &ar); - if (lua_isnil(L, -1)) - luaL_error(L, "no function environment for tail call at level %d", - level); } } - static int luaB_getfenv (lua_State *L) { getfunc(L, 1); if (lua_iscfunction(L, -1)) /* is a C function? */ - lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */ + lua_pushglobaltable(L); /* return the global env. */ else lua_getfenv(L, -1); return 1; } - static int luaB_setfenv (lua_State *L) { luaL_checktype(L, 2, LUA_TTABLE); getfunc(L, 0); lua_pushvalue(L, 2); - if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) { - /* change environment of current thread */ - lua_pushthread(L); - lua_insert(L, -2); - lua_setfenv(L, -2); - return 0; - } - else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) - luaL_error(L, - LUA_QL("setfenv") " cannot change environment of given object"); + if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) + return luaL_error(L, + LUA_QL("setfenv") " cannot change environment of given object"); return 1; } +#else + +static int luaB_getfenv (lua_State *L) { + return luaL_error(L, "getfenv/setfenv deprecated"); +} + +#define luaB_setfenv luaB_getfenv + +#endif + static int luaB_rawequal (lua_State *L) { luaL_checkany(L, 1); @@ -185,31 +179,33 @@ static int luaB_rawset (lua_State *L) { static int luaB_gcinfo (lua_State *L) { - lua_pushinteger(L, lua_getgccount(L)); + lua_pushinteger(L, lua_gc(L, LUA_GCCOUNT, 0)); return 1; } static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", - "count", "step", "setpause", "setstepmul", NULL}; + "count", "step", "setpause", "setstepmul", "isrunning", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, - LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; - int o = luaL_checkoption(L, 1, "collect", opts); + LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, + LUA_GCISRUNNING}; + int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; int ex = luaL_optint(L, 2, 0); - int res = lua_gc(L, optsnum[o], ex); - switch (optsnum[o]) { + int res = lua_gc(L, o, ex); + switch (o) { case LUA_GCCOUNT: { int b = lua_gc(L, LUA_GCCOUNTB, 0); lua_pushnumber(L, res + ((lua_Number)b/1024)); - return 1; + lua_pushinteger(L, b); + return 2; } - case LUA_GCSTEP: { + case LUA_GCSTEP: case LUA_GCISRUNNING: { lua_pushboolean(L, res); return 1; } default: { - lua_pushnumber(L, res); + lua_pushinteger(L, res); return 1; } } @@ -223,6 +219,22 @@ static int luaB_type (lua_State *L) { } +static int pairsmeta (lua_State *L, const char *method, int iszero) { + if (!luaL_getmetafield(L, 1, method)) { /* no metamethod? */ + luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */ + lua_pushvalue(L, lua_upvalueindex(1)); /* will return generator, */ + lua_pushvalue(L, 1); /* state, */ + if (iszero) lua_pushinteger(L, 0); /* and initial value */ + else lua_pushnil(L); + } + else { + lua_pushvalue(L, 1); /* argument 'self' to metamethod */ + lua_call(L, 1, 3); /* get 3 values from metamethod */ + } + return 3; +} + + static int luaB_next (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 2); /* create a 2nd argument if there isn't one */ @@ -236,11 +248,7 @@ static int luaB_next (lua_State *L) { static int luaB_pairs (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ - lua_pushvalue(L, 1); /* state, */ - lua_pushnil(L); /* and initial value */ - return 3; + return pairsmeta(L, "__pairs", 0); } @@ -250,21 +258,17 @@ static int ipairsaux (lua_State *L) { i++; /* next value */ lua_pushinteger(L, i); lua_rawgeti(L, 1, i); - return (lua_isnil(L, -1)) ? 0 : 2; + return (lua_isnil(L, -1) && i > luaL_len(L, 1)) ? 0 : 2; } static int luaB_ipairs (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ - lua_pushvalue(L, 1); /* state, */ - lua_pushinteger(L, 0); /* and initial value */ - return 3; + return pairsmeta(L, "__ipairs", 1); } static int load_aux (lua_State *L, int status) { - if (status == 0) /* OK? */ + if (status == LUA_OK) return 1; else { lua_pushnil(L); @@ -274,14 +278,6 @@ static int load_aux (lua_State *L, int status) { } -static int luaB_loadstring (lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - const char *chunkname = luaL_optstring(L, 2, s); - return load_aux(L, luaL_loadbuffer(L, s, l, chunkname)); -} - - static int luaB_loadfile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); return load_aux(L, luaL_loadfile(L, fname)); @@ -289,72 +285,133 @@ static int luaB_loadfile (lua_State *L) { /* +** {====================================================== +** Generic Read function +** ======================================================= +*/ + +static const char *checkrights (lua_State *L, const char *mode, const char *s) { + if (strchr(mode, 'b') == NULL && *s == LUA_SIGNATURE[0]) + return lua_pushstring(L, "attempt to load a binary chunk"); + if (strchr(mode, 't') == NULL && *s != LUA_SIGNATURE[0]) + return lua_pushstring(L, "attempt to load a text chunk"); + return NULL; /* chunk in allowed format */ +} + + +/* +** reserves a slot, above all arguments, to hold a copy of the returned +** string to avoid it being collected while parsed +*/ +#define RESERVEDSLOT 4 + + +/* ** Reader for generic `load' function: `lua_load' uses the ** stack for internal stuff, so the reader cannot change the ** stack top. Instead, it keeps its resulting string in a ** reserved slot inside the stack. */ +typedef struct { /* reader state */ + int f; /* position of reader function on stack */ + const char *mode; /* allowed modes (binary/text) */ +} Readstat; + static const char *generic_reader (lua_State *L, void *ud, size_t *size) { - (void)ud; /* to avoid warnings */ + const char *s; + Readstat *stat = (Readstat *)ud; luaL_checkstack(L, 2, "too many nested functions"); - lua_pushvalue(L, 1); /* get function */ + lua_pushvalue(L, stat->f); /* get function */ lua_call(L, 0, 1); /* call it */ if (lua_isnil(L, -1)) { *size = 0; return NULL; } - else if (lua_isstring(L, -1)) { - lua_replace(L, 3); /* save string in a reserved stack slot */ - return lua_tolstring(L, 3, size); + else if ((s = lua_tostring(L, -1)) != NULL) { + if (stat->mode != NULL) { /* first time? */ + s = checkrights(L, stat->mode, s); /* check mode */ + stat->mode = NULL; /* to avoid further checks */ + if (s) luaL_error(L, s); + } + lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ + return lua_tolstring(L, RESERVEDSLOT, size); + } + else { + luaL_error(L, "reader function must return a string"); + return NULL; /* to avoid warnings */ } - else luaL_error(L, "reader function must return a string"); - return NULL; /* to avoid warnings */ } -static int luaB_load (lua_State *L) { +static int luaB_load_aux (lua_State *L, int farg) { int status; - const char *cname = luaL_optstring(L, 2, "=(load)"); - luaL_checktype(L, 1, LUA_TFUNCTION); - lua_settop(L, 3); /* function, eventual name, plus one reserved slot */ - status = lua_load(L, generic_reader, NULL, cname); + Readstat stat; + size_t l; + const char *s = lua_tolstring(L, farg, &l); + stat.mode = luaL_optstring(L, farg + 2, "bt"); + if (s != NULL) { /* loading a string? */ + const char *chunkname = luaL_optstring(L, farg + 1, s); + status = (checkrights(L, stat.mode, s) != NULL) + || luaL_loadbuffer(L, s, l, chunkname); + } + else { /* loading from a reader function */ + const char *chunkname = luaL_optstring(L, farg + 1, "=(load)"); + luaL_checktype(L, farg, LUA_TFUNCTION); + stat.f = farg; + lua_settop(L, RESERVEDSLOT); /* create reserved slot */ + status = lua_load(L, generic_reader, &stat, chunkname); + } return load_aux(L, status); } +static int luaB_load (lua_State *L) { + return luaB_load_aux(L, 1); +} + + +static int luaB_loadin (lua_State *L) { + int n; + luaL_checktype(L, 1, LUA_TTABLE); + n = luaB_load_aux(L, 2); + if (n == 1) { /* success? */ + lua_pushvalue(L, 1); /* environment for loaded function */ + lua_setfenv(L, -2); + } + return n; +} + + +static int luaB_loadstring (lua_State *L) { + lua_settop(L, 2); + lua_pushliteral(L, "tb"); + return luaB_load(L); /* dostring(s, n) == load(s, n, "tb") */ + +} +/* }====================================================== */ + + +static int dofilecont (lua_State *L) { + return lua_gettop(L) - 1; +} + + static int luaB_dofile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); - int n = lua_gettop(L); - if (luaL_loadfile(L, fname) != 0) lua_error(L); - lua_call(L, 0, LUA_MULTRET); - return lua_gettop(L) - n; + lua_settop(L, 1); + if (luaL_loadfile(L, fname) != LUA_OK) lua_error(L); + lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); + return dofilecont(L); } static int luaB_assert (lua_State *L) { - luaL_checkany(L, 1); if (!lua_toboolean(L, 1)) return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); return lua_gettop(L); } -static int luaB_unpack (lua_State *L) { - int i, e, n; - luaL_checktype(L, 1, LUA_TTABLE); - i = luaL_optint(L, 2, 1); - e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1)); - if (i > e) return 0; /* empty range */ - n = e - i + 1; /* number of elements */ - if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */ - return luaL_error(L, "too many results to unpack"); - lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */ - while (i++ < e) /* push arg[i + 1...e] */ - lua_rawgeti(L, 1, i); - return n; -} - - static int luaB_select (lua_State *L) { int n = lua_gettop(L); if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { @@ -371,11 +428,25 @@ static int luaB_select (lua_State *L) { } +static int pcallcont (lua_State *L) { + int errfunc; /* call has an error function in bottom of the stack */ + int status = lua_getctx(L, &errfunc); + lua_assert(status != LUA_OK); + lua_pushboolean(L, (status == LUA_YIELD)); /* first result (status) */ + if (errfunc) /* came from xpcall? */ + lua_replace(L, 1); /* put first result in place of error function */ + else /* came from pcall */ + lua_insert(L, 1); /* open space for first result */ + return lua_gettop(L); +} + + static int luaB_pcall (lua_State *L) { int status; luaL_checkany(L, 1); - status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); - lua_pushboolean(L, (status == 0)); + status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, pcallcont); + luaL_checkstack(L, 1, NULL); + lua_pushboolean(L, (status == LUA_OK)); lua_insert(L, 1); return lua_gettop(L); /* return status + all results */ } @@ -383,11 +454,14 @@ static int luaB_pcall (lua_State *L) { static int luaB_xpcall (lua_State *L) { int status; - luaL_checkany(L, 2); - lua_settop(L, 2); - lua_insert(L, 1); /* put error function under function to be called */ - status = lua_pcall(L, 0, LUA_MULTRET, 1); - lua_pushboolean(L, (status == 0)); + int n = lua_gettop(L); + luaL_argcheck(L, n >= 2, 2, "value expected"); + lua_pushvalue(L, 1); /* exchange function... */ + lua_copy(L, 2, 1); /* ...and error handler */ + lua_replace(L, 2); + status = lua_pcallk(L, n - 2, LUA_MULTRET, 1, 1, pcallcont); + luaL_checkstack(L, 1, NULL); + lua_pushboolean(L, (status == LUA_OK)); lua_replace(L, 1); return lua_gettop(L); /* return status + all results */ } @@ -395,25 +469,7 @@ static int luaB_xpcall (lua_State *L) { static int luaB_tostring (lua_State *L) { luaL_checkany(L, 1); - if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ - return 1; /* use its value */ - switch (lua_type(L, 1)) { - case LUA_TNUMBER: - lua_pushstring(L, lua_tostring(L, 1)); - break; - case LUA_TSTRING: - lua_pushvalue(L, 1); - break; - case LUA_TBOOLEAN: - lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); - break; - case LUA_TNIL: - lua_pushliteral(L, "nil"); - break; - default: - lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1)); - break; - } + luaL_tolstring(L, 1, NULL); return 1; } @@ -424,7 +480,9 @@ static int luaB_newproxy (lua_State *L) { if (lua_toboolean(L, 1) == 0) return 1; /* no metatable */ else if (lua_isboolean(L, 1)) { - lua_newtable(L); /* create a new metatable `m' ... */ + lua_createtable(L, 0, 1); /* create a new metatable `m' ... */ + lua_pushboolean(L, 1); + lua_setfield(L, -2, "__gc"); /* ... m.__gc = false (HACK!!)... */ lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */ lua_pushboolean(L, 1); lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */ @@ -454,6 +512,7 @@ static const luaL_Reg base_funcs[] = { {"getmetatable", luaB_getmetatable}, {"loadfile", luaB_loadfile}, {"load", luaB_load}, + {"loadin", luaB_loadin}, {"loadstring", luaB_loadstring}, {"next", luaB_next}, {"pcall", luaB_pcall}, @@ -467,7 +526,6 @@ static const luaL_Reg base_funcs[] = { {"tonumber", luaB_tonumber}, {"tostring", luaB_tostring}, {"type", luaB_type}, - {"unpack", luaB_unpack}, {"xpcall", luaB_xpcall}, {NULL, NULL} }; @@ -479,57 +537,25 @@ static const luaL_Reg base_funcs[] = { ** ======================================================= */ -#define CO_RUN 0 /* running */ -#define CO_SUS 1 /* suspended */ -#define CO_NOR 2 /* 'normal' (it resumed another coroutine) */ -#define CO_DEAD 3 - -static const char *const statnames[] = - {"running", "suspended", "normal", "dead"}; - -static int costatus (lua_State *L, lua_State *co) { - if (L == co) return CO_RUN; - switch (lua_status(co)) { - case LUA_YIELD: - return CO_SUS; - case 0: { - lua_Debug ar; - if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ - return CO_NOR; /* it is running */ - else if (lua_gettop(co) == 0) - return CO_DEAD; - else - return CO_SUS; /* initial state */ - } - default: /* some error occured */ - return CO_DEAD; - } -} - - -static int luaB_costatus (lua_State *L) { - lua_State *co = lua_tothread(L, 1); - luaL_argcheck(L, co, 1, "coroutine expected"); - lua_pushstring(L, statnames[costatus(L, co)]); - return 1; -} - - static int auxresume (lua_State *L, lua_State *co, int narg) { - int status = costatus(L, co); - if (!lua_checkstack(co, narg)) - luaL_error(L, "too many arguments to resume"); - if (status != CO_SUS) { - lua_pushfstring(L, "cannot resume %s coroutine", statnames[status]); + int status; + if (!lua_checkstack(co, narg)) { + lua_pushliteral(L, "too many arguments to resume"); + return -1; /* error flag */ + } + if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) { + lua_pushliteral(L, "cannot resume dead coroutine"); return -1; /* error flag */ } lua_xmove(L, co, narg); - lua_setlevel(L, co); status = lua_resume(co, narg); - if (status == 0 || status == LUA_YIELD) { + if (status == LUA_OK || status == LUA_YIELD) { int nres = lua_gettop(co); - if (!lua_checkstack(L, nres + 1)) - luaL_error(L, "too many results to resume"); + if (!lua_checkstack(L, nres + 1)) { + lua_pop(co, nres); /* remove results anyway */ + lua_pushliteral(L, "too many results to resume"); + return -1; /* error flag */ + } lua_xmove(co, L, nres); /* move yielded values */ return nres; } @@ -575,8 +601,7 @@ static int luaB_auxwrap (lua_State *L) { static int luaB_cocreate (lua_State *L) { lua_State *NL = lua_newthread(L); - luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, - "Lua function expected"); + luaL_checktype(L, 1, LUA_TFUNCTION); lua_pushvalue(L, 1); /* move function to top */ lua_xmove(L, NL, 1); /* move function from L to NL */ return 1; @@ -595,13 +620,41 @@ static int luaB_yield (lua_State *L) { } -static int luaB_corunning (lua_State *L) { - if (lua_pushthread(L)) - lua_pushnil(L); /* main thread is not a coroutine */ +static int luaB_costatus (lua_State *L) { + lua_State *co = lua_tothread(L, 1); + luaL_argcheck(L, co, 1, "coroutine expected"); + if (L == co) lua_pushliteral(L, "running"); + else { + switch (lua_status(co)) { + case LUA_YIELD: + lua_pushliteral(L, "suspended"); + break; + case LUA_OK: { + lua_Debug ar; + if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ + lua_pushliteral(L, "normal"); /* it is running */ + else if (lua_gettop(co) == 0) + lua_pushliteral(L, "dead"); + else + lua_pushliteral(L, "suspended"); /* initial state */ + break; + } + default: /* some error occurred */ + lua_pushliteral(L, "dead"); + break; + } + } return 1; } +static int luaB_corunning (lua_State *L) { + int ismain = lua_pushthread(L); + lua_pushboolean(L, ismain); + return 2; +} + + static const luaL_Reg co_funcs[] = { {"create", luaB_cocreate}, {"resume", luaB_coresume}, @@ -625,13 +678,13 @@ static void auxopen (lua_State *L, const char *name, static void base_open (lua_State *L) { /* set global _G */ - lua_pushvalue(L, LUA_GLOBALSINDEX); - lua_setglobal(L, "_G"); + lua_pushglobaltable(L); + lua_setfield(L, LUA_ENVIRONINDEX, "_G"); /* open lib into global table */ luaL_register(L, "_G", base_funcs); lua_pushliteral(L, LUA_VERSION); - lua_setglobal(L, "_VERSION"); /* set global _VERSION */ - /* `ipairs' and `pairs' need auxliliary functions as upvalues */ + lua_setfield(L, LUA_ENVIRONINDEX, "_VERSION"); /* set global _VERSION */ + /* `ipairs' and `pairs' need auxiliary functions as upvalues */ auxopen(L, "ipairs", luaB_ipairs, ipairsaux); auxopen(L, "pairs", luaB_pairs, luaB_next); /* `newproxy' needs a weaktable as upvalue */ @@ -641,11 +694,11 @@ static void base_open (lua_State *L) { lua_pushliteral(L, "kv"); lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ lua_pushcclosure(L, luaB_newproxy, 1); - lua_setglobal(L, "newproxy"); /* set global `newproxy' */ + lua_setfield(L, LUA_ENVIRONINDEX, "newproxy"); /* set global `newproxy' */ } -LUALIB_API int luaopen_base (lua_State *L) { +LUAMOD_API int luaopen_base (lua_State *L) { base_open(L); luaL_register(L, LUA_COLIBNAME, co_funcs); return 2; diff --git a/src/lbitlib.c b/src/lbitlib.c new file mode 100644 index 00000000..5b6a6aae --- /dev/null +++ b/src/lbitlib.c @@ -0,0 +1,123 @@ +/* +** $Id: lbitlib.c,v 1.2 2009/11/24 12:05:44 roberto Exp $ +** Standard library for bitwise operations +** See Copyright Notice in lua.h +*/ + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* number of bits considered when shifting/rotating (must be a power of 2) */ +#define NBITS 32 + + +typedef LUA_INT32 b_int; +typedef unsigned LUA_INT32 b_uint; + + +static b_uint getuintarg (lua_State *L, int arg) { + b_uint r; + lua_Number x = lua_tonumber(L, arg); + if (x == 0) luaL_checktype(L, arg, LUA_TNUMBER); + lua_number2uint(r, x); + return r; +} + + +static b_uint andaux (lua_State *L) { + int i, n = lua_gettop(L); + b_uint r = ~(b_uint)0; + for (i = 1; i <= n; i++) + r &= getuintarg(L, i); + return r; +} + + +static int b_and (lua_State *L) { + b_uint r = andaux(L); + lua_pushnumber(L, lua_uint2number(r)); + return 1; +} + + +static int b_test (lua_State *L) { + b_uint r = andaux(L); + lua_pushboolean(L, r != 0); + return 1; +} + + +static int b_or (lua_State *L) { + int i, n = lua_gettop(L); + b_uint r = 0; + for (i = 1; i <= n; i++) + r |= getuintarg(L, i); + lua_pushnumber(L, lua_uint2number(r)); + return 1; +} + + +static int b_xor (lua_State *L) { + int i, n = lua_gettop(L); + b_uint r = 0; + for (i = 1; i <= n; i++) + r ^= getuintarg(L, i); + lua_pushnumber(L, lua_uint2number(r)); + return 1; +} + + +static int b_not (lua_State *L) { + b_uint r = ~getuintarg(L, 1); + lua_pushnumber(L, lua_uint2number(r)); + return 1; +} + + +static int b_shift (lua_State *L) { + b_uint r = getuintarg(L, 1); + lua_Integer i = luaL_checkinteger(L, 2); + if (i < 0) { /* shift right? */ + i = -i; + if (i >= NBITS) r = 0; + else r >>= i; + } + else { /* shift left */ + if (i >= NBITS) r = 0; + else r <<= i; + } + lua_pushnumber(L, lua_uint2number(r)); + return 1; +} + + +static int b_rotate (lua_State *L) { + b_uint r = getuintarg(L, 1); + lua_Integer i = luaL_checkinteger(L, 2); + i &= (NBITS - 1); /* i = i % NBITS */ + r = (r << i) | (r >> (NBITS - i)); + lua_pushnumber(L, lua_uint2number(r)); + return 1; +} + + +static const luaL_Reg bitlib[] = { + {"band", b_and}, + {"btest", b_test}, + {"bor", b_or}, + {"bxor", b_xor}, + {"bnot", b_not}, + {"bshift", b_shift}, + {"brotate", b_rotate}, + {NULL, NULL} +}; + + + +LUAMOD_API int luaopen_bit (lua_State *L) { + luaL_register(L, LUA_BITLIBNAME, bitlib); + return 1; +} diff --git a/src/lcode.c b/src/lcode.c index cff626b7..4f10e095 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.25.1.3 2007/12/28 15:32:23 roberto Exp $ +** $Id: lcode.c,v 2.42 2009/09/23 20:33:05 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -21,6 +21,7 @@ #include "lobject.h" #include "lopcodes.h" #include "lparser.h" +#include "lstring.h" #include "ltable.h" @@ -35,20 +36,14 @@ static int isnumeral(expdesc *e) { void luaK_nil (FuncState *fs, int from, int n) { Instruction *previous; if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ - if (fs->pc == 0) { /* function start? */ - if (from >= fs->nactvar) - return; /* positions are already clean */ - } - else { - previous = &fs->f->code[fs->pc-1]; - if (GET_OPCODE(*previous) == OP_LOADNIL) { - int pfrom = GETARG_A(*previous); - int pto = GETARG_B(*previous); - if (pfrom <= from && from <= pto+1) { /* can connect both? */ - if (from+n-1 > pto) - SETARG_B(*previous, from+n-1); - return; - } + previous = &fs->f->code[fs->pc-1]; + if (GET_OPCODE(*previous) == OP_LOADNIL) { + int pfrom = GETARG_A(*previous); + int pto = GETARG_B(*previous); + if (pfrom <= from && from <= pto+1) { /* can connect both? */ + if (from+n-1 > pto) + SETARG_B(*previous, from+n-1); + return; } } } @@ -196,6 +191,55 @@ void luaK_concat (FuncState *fs, int *l1, int l2) { } +static int luaK_code (FuncState *fs, Instruction i) { + Proto *f = fs->f; + dischargejpc(fs); /* `pc' will change */ + /* put new instruction in code array */ + luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, + MAX_INT, "opcodes"); + f->code[fs->pc] = i; + /* save corresponding line information */ + luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int, + MAX_INT, "opcodes"); + f->lineinfo[fs->pc] = fs->ls->lastline; + return fs->pc++; +} + + +int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { + lua_assert(getOpMode(o) == iABC); + lua_assert(getBMode(o) != OpArgN || b == 0); + lua_assert(getCMode(o) != OpArgN || c == 0); + lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C); + return luaK_code(fs, CREATE_ABC(o, a, b, c)); +} + + +int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { + lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); + lua_assert(getCMode(o) == OpArgN); + lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx); + return luaK_code(fs, CREATE_ABx(o, a, bc)); +} + + +static int codeextraarg (FuncState *fs, int a) { + lua_assert(a <= MAXARG_Ax); + return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); +} + + +int luaK_codeABxX (FuncState *fs, OpCode o, int reg, int k) { + if (k < MAXARG_Bx) + return luaK_codeABx(fs, o, reg, k + 1); + else { + int p = luaK_codeABx(fs, o, reg, 0); + codeextraarg(fs, k); + return p; + } +} + + void luaK_checkstack (FuncState *fs, int n) { int newstack = fs->freereg + n; if (newstack > fs->f->maxstacksize) { @@ -226,24 +270,29 @@ static void freeexp (FuncState *fs, expdesc *e) { } -static int addk (FuncState *fs, TValue *k, TValue *v) { +static int addk (FuncState *fs, TValue *key, TValue *v) { lua_State *L = fs->L; - TValue *idx = luaH_set(L, fs->h, k); + TValue *idx = luaH_set(L, fs->h, key); Proto *f = fs->f; - int oldsize = f->sizek; + int k, oldsize; if (ttisnumber(idx)) { - lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); - return cast_int(nvalue(idx)); - } - else { /* constant not found; create a new entry */ - setnvalue(idx, cast_num(fs->nk)); - luaM_growvector(L, f->k, fs->nk, f->sizek, TValue, - MAXARG_Bx, "constant table overflow"); - while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); - setobj(L, &f->k[fs->nk], v); - luaC_barrier(L, f, v); - return fs->nk++; + lua_Number n = nvalue(idx); + lua_number2int(k, n); + if (luaO_rawequalObj(&f->k[k], v)) + return k; + /* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0"); + go through and create a new entry for this value */ } + /* constant not found; create a new entry */ + oldsize = f->sizek; + k = fs->nk; + setnvalue(idx, cast_num(k)); + luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); + while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); + setobj(L, &f->k[k], v); + fs->nk++; + luaC_barrier(L, f, v); + return k; } @@ -255,9 +304,20 @@ int luaK_stringK (FuncState *fs, TString *s) { int luaK_numberK (FuncState *fs, lua_Number r) { + int n; + lua_State *L = fs->L; TValue o; setnvalue(&o, r); - return addk(fs, &o, &o); + if (r == 0 || luai_numisnan(NULL, r)) { /* handle -0 and NaN */ + /* use raw representation as key to avoid numeric problems */ + setsvalue(L, L->top, luaS_newlstr(L, (char *)&r, sizeof(r))); + incr_top(L); + n = addk(fs, L->top - 1, &o); + L->top--; + } + else + n = addk(fs, &o, &o); /* regular case */ + return n; } @@ -313,7 +373,7 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { break; } case VGLOBAL: { - e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info); + e->u.s.info = luaK_codeABxX(fs, OP_GETGLOBAL, 0, e->u.s.info); e->k = VRELOCABLE; break; } @@ -352,11 +412,11 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { break; } case VK: { - luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info); + luaK_codek(fs, reg, e->u.s.info); break; } case VKNUM: { - luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval)); + luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval)); break; } case VRELOCABLE: { @@ -444,19 +504,21 @@ void luaK_exp2val (FuncState *fs, expdesc *e) { int luaK_exp2RK (FuncState *fs, expdesc *e) { luaK_exp2val(fs, e); switch (e->k) { - case VKNUM: case VTRUE: case VFALSE: case VNIL: { if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */ - e->u.s.info = (e->k == VNIL) ? nilK(fs) : - (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) : - boolK(fs, (e->k == VTRUE)); + e->u.s.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE)); e->k = VK; return RKASK(e->u.s.info); } else break; } + case VKNUM: { + e->u.s.info = luaK_numberK(fs, e->u.nval); + e->k = VK; + /* go through */ + } case VK: { if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */ return RKASK(e->u.s.info); @@ -483,7 +545,7 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { } case VGLOBAL: { int e = luaK_exp2anyreg(fs, ex); - luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info); + luaK_codeABxX(fs, OP_SETGLOBAL, e, var->u.s.info); break; } case VINDEXED: { @@ -544,15 +606,18 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { pc = NO_JUMP; /* always true; do nothing */ break; } - case VFALSE: { - pc = luaK_jump(fs); /* always jump */ - break; - } case VJMP: { invertjump(fs, e); pc = e->u.s.info; break; } + case VFALSE: { + if (!hasjumps(e)) { + pc = luaK_jump(fs); /* always jump */ + break; + } + /* else go through */ + } default: { pc = jumponcond(fs, e, 0); break; @@ -572,14 +637,17 @@ static void luaK_goiffalse (FuncState *fs, expdesc *e) { pc = NO_JUMP; /* always false; do nothing */ break; } - case VTRUE: { - pc = luaK_jump(fs); /* always jump */ - break; - } case VJMP: { pc = e->u.s.info; break; } + case VTRUE: { + if (!hasjumps(e)) { + pc = luaK_jump(fs); /* always jump */ + break; + } + /* else go through */ + } default: { pc = jumponcond(fs, e, 1); break; @@ -633,26 +701,11 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { - lua_Number v1, v2, r; + lua_Number r; if (!isnumeral(e1) || !isnumeral(e2)) return 0; - v1 = e1->u.nval; - v2 = e2->u.nval; - switch (op) { - case OP_ADD: r = luai_numadd(v1, v2); break; - case OP_SUB: r = luai_numsub(v1, v2); break; - case OP_MUL: r = luai_nummul(v1, v2); break; - case OP_DIV: - if (v2 == 0) return 0; /* do not attempt to divide by 0 */ - r = luai_numdiv(v1, v2); break; - case OP_MOD: - if (v2 == 0) return 0; /* do not attempt to divide by 0 */ - r = luai_nummod(v1, v2); break; - case OP_POW: r = luai_numpow(v1, v2); break; - case OP_UNM: r = luai_numunm(v1); break; - case OP_LEN: return 0; /* no constant folding for 'len' */ - default: lua_assert(0); r = 0; break; - } - if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */ + if ((op == OP_DIV || op == OP_MOD) && e2->u.nval == 0) + return 0; /* do not attempt to divide by 0 */ + r = luaO_arith(op - OP_ADD + LUA_OPADD, e1->u.nval, e2->u.nval); e1->u.nval = r; return 1; } @@ -699,9 +752,12 @@ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; switch (op) { case OPR_MINUS: { - if (!isnumeral(e)) - luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */ - codearith(fs, OP_UNM, e, &e2); + if (isnumeral(e)) /* minus constant? */ + e->u.nval = luai_numunm(NULL, e->u.nval); /* fold it */ + else { + luaK_exp2anyreg(fs, e); + codearith(fs, OP_UNM, e, &e2); + } break; } case OPR_NOT: codenot(fs, e); break; @@ -772,18 +828,19 @@ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { } break; } - case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break; - case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break; - case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break; - case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break; - case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break; - case OPR_POW: codearith(fs, OP_POW, e1, e2); break; - case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break; - case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break; - case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break; - case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break; - case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break; - case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break; + case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: + case OPR_MOD: case OPR_POW: { + codearith(fs, op - OPR_ADD + OP_ADD, e1, e2); + break; + } + case OPR_EQ: case OPR_LT: case OPR_LE: { + codecomp(fs, op - OPR_EQ + OP_EQ, 1, e1, e2); + break; + } + case OPR_NE: case OPR_GT: case OPR_GE: { + codecomp(fs, op - OPR_NE + OP_EQ, 0, e1, e2); + break; + } default: lua_assert(0); } } @@ -794,46 +851,18 @@ void luaK_fixline (FuncState *fs, int line) { } -static int luaK_code (FuncState *fs, Instruction i, int line) { - Proto *f = fs->f; - dischargejpc(fs); /* `pc' will change */ - /* put new instruction in code array */ - luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, - MAX_INT, "code size overflow"); - f->code[fs->pc] = i; - /* save corresponding line information */ - luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int, - MAX_INT, "code size overflow"); - f->lineinfo[fs->pc] = line; - return fs->pc++; -} - - -int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { - lua_assert(getOpMode(o) == iABC); - lua_assert(getBMode(o) != OpArgN || b == 0); - lua_assert(getCMode(o) != OpArgN || c == 0); - return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline); -} - - -int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { - lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); - lua_assert(getCMode(o) == OpArgN); - return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline); -} - - void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; int b = (tostore == LUA_MULTRET) ? 0 : tostore; lua_assert(tostore != 0); if (c <= MAXARG_C) luaK_codeABC(fs, OP_SETLIST, base, b, c); - else { + else if (c <= MAXARG_Ax) { luaK_codeABC(fs, OP_SETLIST, base, b, 0); - luaK_code(fs, cast(Instruction, c), fs->ls->lastline); + codeextraarg(fs, c); } + else + luaX_syntaxerror(fs->ls, "constructor too long"); fs->freereg = base + 1; /* free registers with list values */ } diff --git a/src/lcode.h b/src/lcode.h index b941c607..8ef67e55 100644 --- a/src/lcode.h +++ b/src/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.48.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lcode.h,v 1.52 2009/09/23 20:33:05 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -21,13 +21,13 @@ /* -** grep "ORDER OPR" if you change these enums +** grep "ORDER OPR" if you change these enums (ORDER OP) */ typedef enum BinOpr { OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, OPR_CONCAT, - OPR_NE, OPR_EQ, - OPR_LT, OPR_LE, OPR_GT, OPR_GE, + OPR_EQ, OPR_LT, OPR_LE, + OPR_NE, OPR_GT, OPR_GE, OPR_AND, OPR_OR, OPR_NOBINOPR } BinOpr; @@ -42,8 +42,13 @@ typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; #define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) +#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) + +#define luaK_codek(fs,reg,k) luaK_codeABxX(fs, OP_LOADK, reg, k) + LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); +LUAI_FUNC int luaK_codeABxX (FuncState *fs, OpCode o, int reg, int k); LUAI_FUNC void luaK_fixline (FuncState *fs, int line); LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); diff --git a/src/lctype.c b/src/lctype.c new file mode 100644 index 00000000..b3627f99 --- /dev/null +++ b/src/lctype.c @@ -0,0 +1,45 @@ +/* +** $Id: lctype.c,v 1.8 2009/11/19 19:06:52 roberto Exp $ +** 'ctype' functions for Lua +** See Copyright Notice in lua.h +*/ + +#include <limits.h> + +#include "lctype.h" + +LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { + 0x00, /* EOZ */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x04, 0x04, 0x04, 0x04, 0x05, + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/src/lctype.h b/src/lctype.h new file mode 100644 index 00000000..b43baa79 --- /dev/null +++ b/src/lctype.h @@ -0,0 +1,50 @@ +/* +** $Id: lctype.h,v 1.8 2009/11/19 19:06:52 roberto Exp $ +** 'ctype' functions for Lua +** See Copyright Notice in lua.h +*/ + +#ifndef lctype_h +#define lctype_h + + +#include <limits.h> + +#include "lua.h" + +#include "llimits.h" + + +#define ALPHABIT 0 +#define DIGITBIT 1 +#define PRINTBIT 2 +#define SPACEBIT 3 +#define XDIGITBIT 4 +#define UPPERBIT 5 + + +#define MASK(B) (1 << (B)) + + +/* +** add 1 to char to allow index -1 (EOZ) +*/ +#define testprop(c,p) (luai_ctype_[(c)+1] & (p)) + +/* +** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_' +*/ +#define lislalpha(c) testprop(c, MASK(ALPHABIT)) +#define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT))) +#define lisupper(c) testprop(c, MASK(UPPERBIT)) +#define lisdigit(c) testprop(c, MASK(DIGITBIT)) +#define lisspace(c) testprop(c, MASK(SPACEBIT)) +#define lisprint(c) testprop(c, MASK(PRINTBIT)) +#define lisxdigit(c) testprop(c, MASK(XDIGITBIT)) + + +/* one more entry for 0 and one more for -1 (EOZ) */ +LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2]; + +#endif + diff --git a/src/ldblib.c b/src/ldblib.c index 67de1222..eeaedc1f 100644 --- a/src/ldblib.c +++ b/src/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.104.1.3 2008/01/21 13:11:21 roberto Exp $ +** $Id: ldblib.c,v 1.119 2010/01/06 14:42:35 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -45,6 +45,7 @@ static int db_setmetatable (lua_State *L) { static int db_getfenv (lua_State *L) { + luaL_checkany(L, 1); lua_getfenv(L, 1); return 1; } @@ -72,6 +73,12 @@ static void settabsi (lua_State *L, const char *i, int v) { } +static void settabsb (lua_State *L, const char *i, int v) { + lua_pushboolean(L, v); + lua_setfield(L, -2, i); +} + + static lua_State *getthread (lua_State *L, int *arg) { if (lua_isthread(L, 1)) { *arg = 1; @@ -99,7 +106,7 @@ static int db_getinfo (lua_State *L) { lua_Debug ar; int arg; lua_State *L1 = getthread(L, &arg); - const char *options = luaL_optstring(L, arg+2, "flnSu"); + const char *options = luaL_optstring(L, arg+2, "flnStu"); if (lua_isnumber(L, arg+1)) { if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { lua_pushnil(L); /* level out of range */ @@ -126,19 +133,24 @@ static int db_getinfo (lua_State *L) { } if (strchr(options, 'l')) settabsi(L, "currentline", ar.currentline); - if (strchr(options, 'u')) + if (strchr(options, 'u')) { settabsi(L, "nups", ar.nups); + settabsi(L, "nparams", ar.nparams); + settabsb(L, "isvararg", ar.isvararg); + } if (strchr(options, 'n')) { settabss(L, "name", ar.name); settabss(L, "namewhat", ar.namewhat); } + if (strchr(options, 't')) + settabsb(L, "istailcall", ar.istailcall); if (strchr(options, 'L')) treatstackoption(L, L1, "activelines"); if (strchr(options, 'f')) treatstackoption(L, L1, "func"); return 1; /* return table */ } - + static int db_getlocal (lua_State *L) { int arg; @@ -179,7 +191,6 @@ static int auxupvalue (lua_State *L, int get) { const char *name; int n = luaL_checkint(L, 2); luaL_checktype(L, 1, LUA_TFUNCTION); - if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */ name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); if (name == NULL) return 0; lua_pushstring(L, name); @@ -199,13 +210,40 @@ static int db_setupvalue (lua_State *L) { } +static int checkupval (lua_State *L, int argf, int argnup) { + lua_Debug ar; + int nup = luaL_checkint(L, argnup); + luaL_checktype(L, argf, LUA_TFUNCTION); + lua_pushvalue(L, argf); + lua_getinfo(L, ">u", &ar); + luaL_argcheck(L, 1 <= nup && nup <= ar.nups, argnup, "invalid upvalue index"); + return nup; +} + + +static int db_upvalueid (lua_State *L) { + int n = checkupval(L, 1, 2); + lua_pushlightuserdata(L, lua_upvalueid(L, 1, n)); + return 1; +} + + +static int db_upvaluejoin (lua_State *L) { + int n1 = checkupval(L, 1, 2); + int n2 = checkupval(L, 3, 4); + luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected"); + luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected"); + lua_upvaluejoin(L, 1, n1, 3, n2); + return 0; +} + static const char KEY_HOOK = 'h'; static void hookf (lua_State *L, lua_Debug *ar) { static const char *const hooknames[] = - {"call", "return", "line", "count", "tail return"}; + {"call", "return", "line", "count", "tail call"}; lua_pushlightuserdata(L, (void *)&KEY_HOOK); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushlightuserdata(L, L); @@ -315,58 +353,16 @@ static int db_debug (lua_State *L) { } -#define LEVELS1 12 /* size of the first part of the stack */ -#define LEVELS2 10 /* size of the second part of the stack */ - -static int db_errorfb (lua_State *L) { - int level; - int firstpart = 1; /* still before eventual `...' */ +static int db_traceback (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); - lua_Debug ar; - if (lua_isnumber(L, arg+2)) { - level = (int)lua_tointeger(L, arg+2); - lua_pop(L, 1); - } - else - level = (L == L1) ? 1 : 0; /* level 0 may be this own function */ - if (lua_gettop(L) == arg) - lua_pushliteral(L, ""); - else if (!lua_isstring(L, arg+1)) return 1; /* message is not a string */ - else lua_pushliteral(L, "\n"); - lua_pushliteral(L, "stack traceback:"); - while (lua_getstack(L1, level++, &ar)) { - if (level > LEVELS1 && firstpart) { - /* no more than `LEVELS2' more levels? */ - if (!lua_getstack(L1, level+LEVELS2, &ar)) - level--; /* keep going */ - else { - lua_pushliteral(L, "\n\t..."); /* too many levels */ - while (lua_getstack(L1, level+LEVELS2, &ar)) /* find last levels */ - level++; - } - firstpart = 0; - continue; - } - lua_pushliteral(L, "\n\t"); - lua_getinfo(L1, "Snl", &ar); - lua_pushfstring(L, "%s:", ar.short_src); - if (ar.currentline > 0) - lua_pushfstring(L, "%d:", ar.currentline); - if (*ar.namewhat != '\0') /* is there a name? */ - lua_pushfstring(L, " in function " LUA_QS, ar.name); - else { - if (*ar.what == 'm') /* main? */ - lua_pushfstring(L, " in main chunk"); - else if (*ar.what == 'C' || *ar.what == 't') - lua_pushliteral(L, " ?"); /* C function or tail call */ - else - lua_pushfstring(L, " in function <%s:%d>", - ar.short_src, ar.linedefined); - } - lua_concat(L, lua_gettop(L) - arg); + const char *msg = lua_tostring(L, arg + 1); + if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ + lua_pushvalue(L, arg + 1); /* return it untouched */ + else { + int level = luaL_optint(L, arg + 2, (L == L1) ? 1 : 0); + luaL_traceback(L, L1, msg, level); } - lua_concat(L, lua_gettop(L) - arg); return 1; } @@ -380,17 +376,19 @@ static const luaL_Reg dblib[] = { {"getregistry", db_getregistry}, {"getmetatable", db_getmetatable}, {"getupvalue", db_getupvalue}, + {"upvaluejoin", db_upvaluejoin}, + {"upvalueid", db_upvalueid}, {"setfenv", db_setfenv}, {"sethook", db_sethook}, {"setlocal", db_setlocal}, {"setmetatable", db_setmetatable}, {"setupvalue", db_setupvalue}, - {"traceback", db_errorfb}, + {"traceback", db_traceback}, {NULL, NULL} }; -LUALIB_API int luaopen_debug (lua_State *L) { +LUAMOD_API int luaopen_debug (lua_State *L) { luaL_register(L, LUA_DBLIBNAME, dblib); return 1; } diff --git a/src/ldebug.c b/src/ldebug.c index 50ad3d38..1c18d701 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.29.1.6 2008/05/08 16:56:26 roberto Exp $ +** $Id: ldebug.c,v 2.61 2010/01/06 14:42:35 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -33,20 +33,14 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); -static int currentpc (lua_State *L, CallInfo *ci) { - if (!isLua(ci)) return -1; /* function is not a Lua function? */ - if (ci == L->ci) - ci->savedpc = L->savedpc; - return pcRel(ci->savedpc, ci_func(ci)->l.p); +static int currentpc (CallInfo *ci) { + lua_assert(isLua(ci)); + return pcRel(ci->u.l.savedpc, ci_func(ci)->l.p); } -static int currentline (lua_State *L, CallInfo *ci) { - int pc = currentpc(L, ci); - if (pc < 0) - return -1; /* only active lua functions have current-line information */ - else - return getline(ci_func(ci)->l.p, pc); +static int currentline (CallInfo *ci) { + return getfuncline(ci_func(ci)->l.p, currentpc(ci)); } @@ -58,6 +52,8 @@ LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { mask = 0; func = NULL; } + if (isLua(L->ci)) + L->oldpc = L->ci->u.l.savedpc; L->hook = func; L->basehookcount = count; resethookcount(L); @@ -84,19 +80,13 @@ LUA_API int lua_gethookcount (lua_State *L) { LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { int status; CallInfo *ci; + if (level < 0) return 0; /* invalid (negative) level */ lua_lock(L); - for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) { + for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous) level--; - if (f_isLua(ci)) /* Lua function? */ - level -= ci->tailcalls; /* skip lost tail calls */ - } - if (level == 0 && ci > L->base_ci) { /* level found? */ - status = 1; - ar->i_ci = cast_int(ci - L->base_ci); - } - else if (level < 0) { /* level is of a lost tail call? */ + if (level == 0 && ci != &L->base_ci) { /* level found? */ status = 1; - ar->i_ci = 0; + ar->i_ci = ci; } else status = 0; /* no such level */ lua_unlock(L); @@ -104,43 +94,49 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { } -static Proto *getluaproto (CallInfo *ci) { - return (isLua(ci) ? ci_func(ci)->l.p : NULL); -} - - -static const char *findlocal (lua_State *L, CallInfo *ci, int n) { - const char *name; - Proto *fp = getluaproto(ci); - if (fp && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != NULL) - return name; /* is a local variable in a Lua function */ - else { - StkId limit = (ci == L->ci) ? L->top : (ci+1)->func; - if (limit - ci->base >= n && n > 0) /* is 'n' inside 'ci' stack? */ - return "(*temporary)"; - else - return NULL; +static const char *findlocal (lua_State *L, CallInfo *ci, int n, + StkId *pos) { + const char *name = NULL; + StkId base; + if (isLua(ci)) { + base = ci->u.l.base; + name = luaF_getlocalname(ci_func(ci)->l.p, n, currentpc(ci)); + } + else + base = ci->func + 1; + if (name == NULL) { /* no 'standard' name? */ + StkId limit = (ci == L->ci) ? L->top : ci->next->func; + if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */ + name = "(*temporary)"; /* generic name for any valid slot */ + else { + *pos = base; /* to avoid warnings */ + return NULL; /* no name */ + } } + *pos = base + (n - 1); + return name; } LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { - CallInfo *ci = L->base_ci + ar->i_ci; - const char *name = findlocal(L, ci, n); + StkId pos; + const char *name = findlocal(L, ar->i_ci, n, &pos); lua_lock(L); - if (name) - luaA_pushobject(L, ci->base + (n - 1)); + if (name) { + setobj2s(L, L->top, pos); + api_incr_top(L); + } lua_unlock(L); return name; } LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { - CallInfo *ci = L->base_ci + ar->i_ci; - const char *name = findlocal(L, ci, n); + StkId pos; + const char *name = findlocal(L, ar->i_ci, n, &pos); lua_lock(L); if (name) - setobjs2s(L, ci->base + (n - 1), L->top - 1); + setobjs2s(L, pos, L->top - 1); L->top--; /* pop value */ lua_unlock(L); return name; @@ -164,39 +160,26 @@ static void funcinfo (lua_Debug *ar, Closure *cl) { } -static void info_tailcall (lua_Debug *ar) { - ar->name = ar->namewhat = ""; - ar->what = "tail"; - ar->lastlinedefined = ar->linedefined = ar->currentline = -1; - ar->source = "=(tail call)"; - luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); - ar->nups = 0; -} - - static void collectvalidlines (lua_State *L, Closure *f) { if (f == NULL || f->c.isC) { setnilvalue(L->top); + incr_top(L); } else { - Table *t = luaH_new(L, 0, 0); - int *lineinfo = f->l.p->lineinfo; int i; + int *lineinfo = f->l.p->lineinfo; + Table *t = luaH_new(L); + sethvalue(L, L->top, t); + incr_top(L); for (i=0; i<f->l.p->sizelineinfo; i++) - setbvalue(luaH_setnum(L, t, lineinfo[i]), 1); - sethvalue(L, L->top, t); + setbvalue(luaH_setint(L, t, lineinfo[i]), 1); } - incr_top(L); } static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, Closure *f, CallInfo *ci) { int status = 1; - if (f == NULL) { - info_tailcall(ar); - return status; - } for (; *what; what++) { switch (*what) { case 'S': { @@ -204,11 +187,23 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, break; } case 'l': { - ar->currentline = (ci) ? currentline(L, ci) : -1; + ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1; break; } case 'u': { ar->nups = f->c.nupvalues; + if (f->c.isC) { + ar->isvararg = 1; + ar->nparams = 0; + } + else { + ar->isvararg = f->l.p->is_vararg; + ar->nparams = f->l.p->numparams; + } + break; + } + case 't': { + ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0; break; } case 'n': { @@ -241,15 +236,14 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { f = clvalue(func); L->top--; /* pop function */ } - else if (ar->i_ci != 0) { /* no tail call? */ - ci = L->base_ci + ar->i_ci; + else { + ci = ar->i_ci; lua_assert(ttisfunction(ci->func)); f = clvalue(ci->func); } status = auxgetinfo(L, what, ar, f, ci); if (strchr(what, 'f')) { - if (f == NULL) setnilvalue(L->top); - else setclvalue(L, L->top, f); + setclvalue(L, L->top, f); incr_top(L); } if (strchr(what, 'L')) @@ -261,314 +255,170 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { /* ** {====================================================== -** Symbolic Execution and code checker +** Symbolic Execution ** ======================================================= */ -#define check(x) if (!(x)) return 0; - -#define checkjump(pt,pc) check(0 <= pc && pc < pt->sizecode) - -#define checkreg(pt,reg) check((reg) < (pt)->maxstacksize) - - -static int precheck (const Proto *pt) { - check(pt->maxstacksize <= MAXSTACK); - check(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize); - check(!(pt->is_vararg & VARARG_NEEDSARG) || - (pt->is_vararg & VARARG_HASARG)); - check(pt->sizeupvalues <= pt->nups); - check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0); - check(pt->sizecode > 0 && GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); - return 1; -} - - -#define checkopenop(pt,pc) luaG_checkopenop((pt)->code[(pc)+1]) - -int luaG_checkopenop (Instruction i) { - switch (GET_OPCODE(i)) { - case OP_CALL: - case OP_TAILCALL: - case OP_RETURN: - case OP_SETLIST: { - check(GETARG_B(i) == 0); - return 1; - } - default: return 0; /* invalid instruction after an open call */ - } -} - - -static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) { - switch (mode) { - case OpArgN: check(r == 0); break; - case OpArgU: break; - case OpArgR: checkreg(pt, r); break; - case OpArgK: - check(ISK(r) ? INDEXK(r) < pt->sizek : r < pt->maxstacksize); - break; - } - return 1; +static const char *kname (Proto *p, int c) { + if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) + return svalue(&p->k[INDEXK(c)]); + else + return "?"; } -static Instruction symbexec (const Proto *pt, int lastpc, int reg) { - int pc; - int last; /* stores position of last instruction that changed `reg' */ - last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */ - check(precheck(pt)); +static const char *getobjname (lua_State *L, CallInfo *ci, int reg, + const char **name) { + Proto *p; + int lastpc, pc; + const char *what = NULL; + lua_assert(isLua(ci)); + p = ci_func(ci)->l.p; + lastpc = currentpc(ci); + *name = luaF_getlocalname(p, reg + 1, lastpc); + if (*name) /* is a local? */ + return "local"; + /* else try symbolic execution */ for (pc = 0; pc < lastpc; pc++) { - Instruction i = pt->code[pc]; + Instruction i = p->code[pc]; OpCode op = GET_OPCODE(i); int a = GETARG_A(i); - int b = 0; - int c = 0; - check(op < NUM_OPCODES); - checkreg(pt, a); - switch (getOpMode(op)) { - case iABC: { - b = GETARG_B(i); - c = GETARG_C(i); - check(checkArgMode(pt, b, getBMode(op))); - check(checkArgMode(pt, c, getCMode(op))); + switch (op) { + case OP_GETGLOBAL: { + if (reg == a) { + int g = GETARG_Bx(i); + if (g != 0) g--; + else g = GETARG_Ax(p->code[++pc]); + lua_assert(ttisstring(&p->k[g])); + *name = svalue(&p->k[g]); + what = "global"; + } break; } - case iABx: { - b = GETARG_Bx(i); - if (getBMode(op) == OpArgK) check(b < pt->sizek); + case OP_MOVE: { + if (reg == a) { + int b = GETARG_B(i); /* move from 'b' to 'a' */ + if (b < a) + what = getobjname(L, ci, b, name); /* get name for 'b' */ + else what = NULL; + } break; } - case iAsBx: { - b = GETARG_sBx(i); - if (getBMode(op) == OpArgR) { - int dest = pc+1+b; - check(0 <= dest && dest < pt->sizecode); - if (dest > 0) { - int j; - /* check that it does not jump to a setlist count; this - is tricky, because the count from a previous setlist may - have the same value of an invalid setlist; so, we must - go all the way back to the first of them (if any) */ - for (j = 0; j < dest; j++) { - Instruction d = pt->code[dest-1-j]; - if (!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)) break; - } - /* if 'j' is even, previous value is not a setlist (even if - it looks like one) */ - check((j&1) == 0); - } + case OP_GETTABLE: { + if (reg == a) { + int k = GETARG_C(i); /* key index */ + *name = kname(p, k); + what = "field"; } break; } - } - if (testAMode(op)) { - if (a == reg) last = pc; /* change register `a' */ - } - if (testTMode(op)) { - check(pc+2 < pt->sizecode); /* check skip */ - check(GET_OPCODE(pt->code[pc+1]) == OP_JMP); - } - switch (op) { - case OP_LOADBOOL: { - if (c == 1) { /* does it jump? */ - check(pc+2 < pt->sizecode); /* check its jump */ - check(GET_OPCODE(pt->code[pc+1]) != OP_SETLIST || - GETARG_C(pt->code[pc+1]) != 0); + case OP_GETUPVAL: { + if (reg == a) { + int u = GETARG_B(i); /* upvalue index */ + TString *tn = p->upvalues[u].name; + *name = tn ? getstr(tn) : "?"; + what = "upvalue"; } break; } case OP_LOADNIL: { - if (a <= reg && reg <= b) - last = pc; /* set registers from `a' to `b' */ - break; - } - case OP_GETUPVAL: - case OP_SETUPVAL: { - check(b < pt->nups); - break; - } - case OP_GETGLOBAL: - case OP_SETGLOBAL: { - check(ttisstring(&pt->k[b])); + int b = GETARG_B(i); /* move from 'b' to 'a' */ + if (a <= reg && reg <= b) /* set registers from 'a' to 'b' */ + what = NULL; break; } case OP_SELF: { - checkreg(pt, a+1); - if (reg == a+1) last = pc; - break; - } - case OP_CONCAT: { - check(b < c); /* at least two operands */ - break; - } - case OP_TFORLOOP: { - check(c >= 1); /* at least one result (control variable) */ - checkreg(pt, a+2+c); /* space for results */ - if (reg >= a+2) last = pc; /* affect all regs above its base */ + if (reg == a) { + int k = GETARG_C(i); /* key index */ + *name = kname(p, k); + what = "method"; + } break; } - case OP_FORLOOP: - case OP_FORPREP: - checkreg(pt, a+3); - /* go through */ - case OP_JMP: { - int dest = pc+1+b; - /* not full check and jump is forward and do not skip `lastpc'? */ - if (reg != NO_REG && pc < dest && dest <= lastpc) - pc += b; /* do the jump */ + case OP_TFORCALL: { + if (reg >= a + 2) what = NULL; /* affect all regs above its base */ break; } case OP_CALL: case OP_TAILCALL: { - if (b != 0) { - checkreg(pt, a+b-1); - } - c--; /* c = num. returns */ - if (c == LUA_MULTRET) { - check(checkopenop(pt, pc)); - } - else if (c != 0) - checkreg(pt, a+c-1); - if (reg >= a) last = pc; /* affect all registers above base */ - break; - } - case OP_RETURN: { - b--; /* b = num. returns */ - if (b > 0) checkreg(pt, a+b-1); + if (reg >= a) what = NULL; /* affect all registers above base */ break; } - case OP_SETLIST: { - if (b > 0) checkreg(pt, a + b); - if (c == 0) { - pc++; - check(pc < pt->sizecode - 1); - } - break; - } - case OP_CLOSURE: { - int nup, j; - check(b < pt->sizep); - nup = pt->p[b]->nups; - check(pc + nup < pt->sizecode); - for (j = 1; j <= nup; j++) { - OpCode op1 = GET_OPCODE(pt->code[pc + j]); - check(op1 == OP_GETUPVAL || op1 == OP_MOVE); - } - if (reg != NO_REG) /* tracing? */ - pc += nup; /* do not 'execute' these pseudo-instructions */ + case OP_JMP: { + int b = GETARG_sBx(i); + int dest = pc + 1 + b; + /* jump is forward and do not skip `lastpc'? */ + if (pc < dest && dest <= lastpc) + pc += b; /* do the jump */ break; } - case OP_VARARG: { - check((pt->is_vararg & VARARG_ISVARARG) && - !(pt->is_vararg & VARARG_NEEDSARG)); - b--; - if (b == LUA_MULTRET) check(checkopenop(pt, pc)); - checkreg(pt, a+b-1); + default: + if (testAMode(op) && reg == a) what = NULL; break; - } - default: break; } } - return pt->code[last]; -} - -#undef check -#undef checkjump -#undef checkreg - -/* }====================================================== */ - - -int luaG_checkcode (const Proto *pt) { - return (symbexec(pt, pt->sizecode, NO_REG) != 0); -} - - -static const char *kname (Proto *p, int c) { - if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) - return svalue(&p->k[INDEXK(c)]); - else - return "?"; -} - - -static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos, - const char **name) { - if (isLua(ci)) { /* a Lua function? */ - Proto *p = ci_func(ci)->l.p; - int pc = currentpc(L, ci); - Instruction i; - *name = luaF_getlocalname(p, stackpos+1, pc); - if (*name) /* is a local? */ - return "local"; - i = symbexec(p, pc, stackpos); /* try symbolic execution */ - lua_assert(pc != -1); - switch (GET_OPCODE(i)) { - case OP_GETGLOBAL: { - int g = GETARG_Bx(i); /* global index */ - lua_assert(ttisstring(&p->k[g])); - *name = svalue(&p->k[g]); - return "global"; - } - case OP_MOVE: { - int a = GETARG_A(i); - int b = GETARG_B(i); /* move from `b' to `a' */ - if (b < a) - return getobjname(L, ci, b, name); /* get name for `b' */ - break; - } - case OP_GETTABLE: { - int k = GETARG_C(i); /* key index */ - *name = kname(p, k); - return "field"; - } - case OP_GETUPVAL: { - int u = GETARG_B(i); /* upvalue index */ - *name = p->upvalues ? getstr(p->upvalues[u]) : "?"; - return "upvalue"; - } - case OP_SELF: { - int k = GETARG_C(i); /* key index */ - *name = kname(p, k); - return "method"; - } - default: break; - } - } - return NULL; /* no useful name found */ + return what; } static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { + TMS tm = 0; Instruction i; - if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1)) + if ((ci->callstatus & CIST_TAIL) || !isLua(ci->previous)) return NULL; /* calling function is not Lua (or is unknown) */ - ci--; /* calling function */ - i = ci_func(ci)->l.p->code[currentpc(L, ci)]; - if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || - GET_OPCODE(i) == OP_TFORLOOP) - return getobjname(L, ci, GETARG_A(i), name); - else - return NULL; /* no useful name can be found */ + ci = ci->previous; /* calling function */ + i = ci_func(ci)->l.p->code[currentpc(ci)]; + if (GET_OPCODE(i) == OP_EXTRAARG) /* extra argument? */ + i = ci_func(ci)->l.p->code[currentpc(ci) - 1]; /* get 'real' instruction */ + switch (GET_OPCODE(i)) { + case OP_CALL: + case OP_TAILCALL: + case OP_TFORLOOP: + return getobjname(L, ci, GETARG_A(i), name); + case OP_GETGLOBAL: + case OP_SELF: + case OP_GETTABLE: tm = TM_INDEX; break; + case OP_SETGLOBAL: + case OP_SETTABLE: tm = TM_NEWINDEX; break; + case OP_EQ: tm = TM_EQ; break; + case OP_ADD: tm = TM_ADD; break; + case OP_SUB: tm = TM_SUB; break; + case OP_MUL: tm = TM_MUL; break; + case OP_DIV: tm = TM_DIV; break; + case OP_MOD: tm = TM_MOD; break; + case OP_POW: tm = TM_POW; break; + case OP_UNM: tm = TM_UNM; break; + case OP_LEN: tm = TM_LEN; break; + case OP_LT: tm = TM_LT; break; + case OP_LE: tm = TM_LE; break; + case OP_CONCAT: tm = TM_CONCAT; break; + default: + return NULL; /* else no useful name can be found */ + } + *name = getstr(G(L)->tmname[tm]); + return "metamethod"; } +/* }====================================================== */ + + /* only ANSI way to check whether a pointer points to an array */ static int isinstack (CallInfo *ci, const TValue *o) { StkId p; - for (p = ci->base; p < ci->top; p++) + for (p = ci->u.l.base; p < ci->top; p++) if (o == p) return 1; return 0; } void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { + CallInfo *ci = L->ci; const char *name = NULL; const char *t = luaT_typenames[ttype(o)]; - const char *kind = (isinstack(L->ci, o)) ? - getobjname(L, L->ci, cast_int(o - L->base), &name) : + const char *kind = (isLua(ci) && isinstack(ci, o)) ? + getobjname(L, ci, cast_int(o - ci->u.l.base), &name) : NULL; if (kind) luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", @@ -580,7 +430,7 @@ void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; - lua_assert(!ttisstring(p1) && !ttisnumber(p1)); + lua_assert(!ttisstring(p1) && !ttisnumber(p2)); luaG_typeerror(L, p1, "concatenate"); } @@ -608,8 +458,8 @@ static void addinfo (lua_State *L, const char *msg) { CallInfo *ci = L->ci; if (isLua(ci)) { /* is Lua code? */ char buff[LUA_IDSIZE]; /* add file:line information */ - int line = currentline(L, ci); - luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE); + int line = currentline(ci); + luaO_chunkid(buff, getstr(ci_func(ci)->l.p->source), LUA_IDSIZE); luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); } } @@ -622,7 +472,7 @@ void luaG_errormsg (lua_State *L) { setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top - 1, errfunc); /* push function */ incr_top(L); - luaD_call(L, L->top - 2, 1); /* call it */ + luaD_call(L, L->top - 2, 1, 0); /* call it */ } luaD_throw(L, LUA_ERRRUN); } diff --git a/src/ldebug.h b/src/ldebug.h index ba28a972..545fa345 100644 --- a/src/ldebug.h +++ b/src/ldebug.h @@ -1,5 +1,5 @@ /* -** $Id: ldebug.h,v 2.3.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: ldebug.h,v 2.5 2009/06/10 16:57:53 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ @@ -13,7 +13,7 @@ #define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) -#define getline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0) +#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0) #define resethookcount(L) (L->hookcount = L->basehookcount) @@ -27,7 +27,5 @@ LUAI_FUNC int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC void luaG_runerror (lua_State *L, const char *fmt, ...); LUAI_FUNC void luaG_errormsg (lua_State *L); -LUAI_FUNC int luaG_checkcode (const Proto *pt); -LUAI_FUNC int luaG_checkopenop (Instruction i); #endif @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.38.1.3 2008/01/18 22:31:22 roberto Exp $ +** $Id: ldo.c,v 2.79 2009/12/22 15:32:50 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -14,6 +14,7 @@ #include "lua.h" +#include "lapi.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" @@ -39,6 +40,38 @@ ** ======================================================= */ +/* +** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By +** default, Lua handles errors with exceptions when compiling as +** C++ code, with _longjmp/_setjmp when asked to use them, and with +** longjmp/setjmp otherwise. +*/ +#if !defined(LUAI_THROW) + +#if defined(__cplusplus) +/* C++ exceptions */ +#define LUAI_THROW(L,c) throw(c) +#define LUAI_TRY(L,c,a) \ + try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; } +#define luai_jmpbuf int /* dummy variable */ + +#elif defined(LUA_USE_ULONGJMP) +/* in Unix, try _longjmp/_setjmp (more efficient) */ +#define LUAI_THROW(L,c) _longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf + +#else +/* default handling with long jumps */ +#define LUAI_THROW(L,c) longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf + +#endif + +#endif + + /* chain list of long jump buffers */ struct lua_longjmp { @@ -48,7 +81,7 @@ struct lua_longjmp { }; -void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { +static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { switch (errcode) { case LUA_ERRMEM: { setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); @@ -58,8 +91,7 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); break; } - case LUA_ERRSYNTAX: - case LUA_ERRRUN: { + default: { setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ break; } @@ -68,55 +100,39 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { } -static void restore_stack_limit (lua_State *L) { - lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); - if (L->size_ci > LUAI_MAXCALLS) { /* there was an overflow? */ - int inuse = cast_int(L->ci - L->base_ci); - if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */ - luaD_reallocCI(L, LUAI_MAXCALLS); - } -} - - -static void resetstack (lua_State *L, int status) { - L->ci = L->base_ci; - L->base = L->ci->base; - luaF_close(L, L->base); /* close eventual pending closures */ - luaD_seterrorobj(L, status, L->base); - L->nCcalls = L->baseCcalls; - L->allowhook = 1; - restore_stack_limit(L); - L->errfunc = 0; - L->errorJmp = NULL; -} - - void luaD_throw (lua_State *L, int errcode) { - if (L->errorJmp) { - L->errorJmp->status = errcode; - LUAI_THROW(L, L->errorJmp); + if (L->errorJmp) { /* thread has an error handler? */ + L->errorJmp->status = errcode; /* set status */ + LUAI_THROW(L, L->errorJmp); /* jump to it */ } - else { - L->status = cast_byte(errcode); - if (G(L)->panic) { - resetstack(L, errcode); - lua_unlock(L); - G(L)->panic(L); + else { /* thread has no error handler */ + L->status = cast_byte(errcode); /* mark it as dead */ + if (G(L)->mainthread->errorJmp) { /* main thread has a handler? */ + setobjs2s(L, G(L)->mainthread->top++, L->top - 1); /* copy error obj. */ + luaD_throw(G(L)->mainthread, errcode); /* re-throw in main thread */ + } + else { /* no handler at all; abort */ + if (G(L)->panic) { /* panic function? */ + lua_unlock(L); + G(L)->panic(L); /* call it (last chance to jump out) */ + } + abort(); } - exit(EXIT_FAILURE); } } int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { + unsigned short oldnCcalls = G(L)->nCcalls; struct lua_longjmp lj; - lj.status = 0; + lj.status = LUA_OK; lj.previous = L->errorJmp; /* chain new error handler */ L->errorJmp = &lj; LUAI_TRY(L, &lj, (*f)(L, ud); ); L->errorJmp = lj.previous; /* restore old error handler */ + G(L)->nCcalls = oldnCcalls; return lj.status; } @@ -129,112 +145,126 @@ static void correctstack (lua_State *L, TValue *oldstack) { L->top = (L->top - oldstack) + L->stack; for (up = L->openupval; up != NULL; up = up->gch.next) gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; - for (ci = L->base_ci; ci <= L->ci; ci++) { + for (ci = L->ci; ci != NULL; ci = ci->previous) { ci->top = (ci->top - oldstack) + L->stack; - ci->base = (ci->base - oldstack) + L->stack; ci->func = (ci->func - oldstack) + L->stack; + if (isLua(ci)) + ci->u.l.base = (ci->u.l.base - oldstack) + L->stack; } - L->base = (L->base - oldstack) + L->stack; } +/* some space for error handling */ +#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) + + void luaD_reallocstack (lua_State *L, int newsize) { TValue *oldstack = L->stack; - int realsize = newsize + 1 + EXTRA_STACK; - lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); - luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue); - L->stacksize = realsize; - L->stack_last = L->stack+newsize; + int lim = L->stacksize; + lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); + lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK); + luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue); + for (; lim < newsize; lim++) + setnilvalue(L->stack + lim); /* erase new segment */ + L->stacksize = newsize; + L->stack_last = L->stack + newsize - EXTRA_STACK; correctstack(L, oldstack); } -void luaD_reallocCI (lua_State *L, int newsize) { - CallInfo *oldci = L->base_ci; - luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); - L->size_ci = newsize; - L->ci = (L->ci - oldci) + L->base_ci; - L->end_ci = L->base_ci + L->size_ci - 1; +void luaD_growstack (lua_State *L, int n) { + int size = L->stacksize; + if (size > LUAI_MAXSTACK) /* error after extra size? */ + luaD_throw(L, LUA_ERRERR); + else { + int needed = L->top - L->stack + n + EXTRA_STACK; + int newsize = 2 * size; + if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK; + if (newsize < needed) newsize = needed; + if (newsize > LUAI_MAXSTACK) { /* stack overflow? */ + luaD_reallocstack(L, ERRORSTACKSIZE); + luaG_runerror(L, "stack overflow"); + } + else + luaD_reallocstack(L, newsize); + } } -void luaD_growstack (lua_State *L, int n) { - if (n <= L->stacksize) /* double size is enough? */ - luaD_reallocstack(L, 2*L->stacksize); - else - luaD_reallocstack(L, L->stacksize + n); +static int stackinuse (lua_State *L) { + CallInfo *ci; + StkId lim = L->top; + for (ci = L->ci; ci != NULL; ci = ci->previous) { + lua_assert(ci->top <= L->stack_last); + if (lim < ci->top) lim = ci->top; + } + return cast_int(lim - L->stack) + 1; /* part of stack in use */ } -static CallInfo *growCI (lua_State *L) { - if (L->size_ci > LUAI_MAXCALLS) /* overflow while handling overflow? */ - luaD_throw(L, LUA_ERRERR); - else { - luaD_reallocCI(L, 2*L->size_ci); - if (L->size_ci > LUAI_MAXCALLS) - luaG_runerror(L, "stack overflow"); - } - return ++L->ci; +void luaD_shrinkstack (lua_State *L) { + int inuse = stackinuse(L); + int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK; + if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK; + if (inuse > LUAI_MAXSTACK || /* handling stack overflow? */ + goodsize >= L->stacksize) /* would grow instead of shrink? */ + condmovestack(L); /* don't change stack (change only for debugging) */ + else + luaD_reallocstack(L, goodsize); /* shrink it */ } -void luaD_callhook (lua_State *L, int event, int line) { +void luaD_hook (lua_State *L, int event, int line) { lua_Hook hook = L->hook; if (hook && L->allowhook) { + CallInfo *ci = L->ci; ptrdiff_t top = savestack(L, L->top); - ptrdiff_t ci_top = savestack(L, L->ci->top); + ptrdiff_t ci_top = savestack(L, ci->top); lua_Debug ar; ar.event = event; ar.currentline = line; - if (event == LUA_HOOKTAILRET) - ar.i_ci = 0; /* tail call; no debug information about it */ - else - ar.i_ci = cast_int(L->ci - L->base_ci); + ar.i_ci = ci; luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - L->ci->top = L->top + LUA_MINSTACK; - lua_assert(L->ci->top <= L->stack_last); + ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); L->allowhook = 0; /* cannot call hooks inside a hook */ + ci->callstatus |= CIST_HOOKED; lua_unlock(L); (*hook)(L, &ar); lua_lock(L); lua_assert(!L->allowhook); L->allowhook = 1; - L->ci->top = restorestack(L, ci_top); + ci->top = restorestack(L, ci_top); L->top = restorestack(L, top); + ci->callstatus &= ~CIST_HOOKED; } } +static void callhook (lua_State *L, CallInfo *ci) { + int hook = LUA_HOOKCALL; + ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ + if (isLua(ci->previous) && + GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) { + ci->callstatus |= CIST_TAIL; + hook = LUA_HOOKTAILCALL; + } + luaD_hook(L, hook, -1); + ci->u.l.savedpc--; /* correct 'pc' */ +} + + static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { int i; int nfixargs = p->numparams; - Table *htab = NULL; StkId base, fixed; - for (; actual < nfixargs; ++actual) - setnilvalue(L->top++); -#if defined(LUA_COMPAT_VARARG) - if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */ - int nvar = actual - nfixargs; /* number of extra arguments */ - lua_assert(p->is_vararg & VARARG_HASARG); - luaC_checkGC(L); - htab = luaH_new(L, nvar, 1); /* create `arg' table */ - for (i=0; i<nvar; i++) /* put extra arguments into `arg' table */ - setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i); - /* store counter in field `n' */ - setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar)); - } -#endif + lua_assert(actual >= nfixargs); /* move fixed parameters to final position */ fixed = L->top - actual; /* first fixed argument */ base = L->top; /* final position of first argument */ for (i=0; i<nfixargs; i++) { - setobjs2s(L, L->top++, fixed+i); - setnilvalue(fixed+i); - } - /* add `arg' parameter */ - if (htab) { - sethvalue(L, L->top++, htab); - lua_assert(iswhite(obj2gco(htab))); + setobjs2s(L, L->top++, fixed + i); + setnilvalue(fixed + i); } return base; } @@ -256,11 +286,12 @@ static StkId tryfuncTM (lua_State *L, StkId func) { -#define inc_ci(L) \ - ((L->ci == L->end_ci) ? growCI(L) : \ - (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci)) +#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L))) +/* +** returns true if function has been executed (C function) +*/ int luaD_precall (lua_State *L, StkId func, int nresults) { LClosure *cl; ptrdiff_t funcr; @@ -268,88 +299,70 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { func = tryfuncTM(L, func); /* check the `function' tag method */ funcr = savestack(L, func); cl = &clvalue(func)->l; - L->ci->savedpc = L->savedpc; + L->ci->nresults = nresults; if (!cl->isC) { /* Lua function? prepare its call */ CallInfo *ci; - StkId st, base; + int nparams, nargs; + StkId base; Proto *p = cl->p; luaD_checkstack(L, p->maxstacksize); func = restorestack(L, funcr); - if (!p->is_vararg) { /* no varargs? */ + nargs = cast_int(L->top - func) - 1; /* number of real arguments */ + nparams = p->numparams; /* number of expected parameters */ + for (; nargs < nparams; nargs++) + setnilvalue(L->top++); /* complete missing arguments */ + if (!p->is_vararg) /* no varargs? */ base = func + 1; - if (L->top > base + p->numparams) - L->top = base + p->numparams; - } - else { /* vararg function */ - int nargs = cast_int(L->top - func) - 1; + else /* vararg function */ base = adjust_varargs(L, p, nargs); - func = restorestack(L, funcr); /* previous call may change the stack */ - } - ci = inc_ci(L); /* now `enter' new function */ + ci = next_ci(L); /* now 'enter' new function */ ci->func = func; - L->base = ci->base = base; - ci->top = L->base + p->maxstacksize; + ci->u.l.base = base; + ci->top = base + p->maxstacksize; lua_assert(ci->top <= L->stack_last); - L->savedpc = p->code; /* starting point */ - ci->tailcalls = 0; - ci->nresults = nresults; - for (st = L->top; st < ci->top; st++) - setnilvalue(st); + ci->u.l.savedpc = p->code; /* starting point */ + ci->callstatus = CIST_LUA; L->top = ci->top; - if (L->hookmask & LUA_MASKCALL) { - L->savedpc++; /* hooks assume 'pc' is already incremented */ - luaD_callhook(L, LUA_HOOKCALL, -1); - L->savedpc--; /* correct 'pc' */ - } - return PCRLUA; + if (L->hookmask & LUA_MASKCALL) + callhook(L, ci); + return 0; } else { /* if is a C function, call it */ CallInfo *ci; int n; luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - ci = inc_ci(L); /* now `enter' new function */ + ci = next_ci(L); /* now 'enter' new function */ ci->func = restorestack(L, funcr); - L->base = ci->base = ci->func + 1; ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); - ci->nresults = nresults; + ci->callstatus = 0; if (L->hookmask & LUA_MASKCALL) - luaD_callhook(L, LUA_HOOKCALL, -1); + luaD_hook(L, LUA_HOOKCALL, -1); lua_unlock(L); n = (*curr_func(L)->c.f)(L); /* do the actual call */ lua_lock(L); - if (n < 0) /* yielding? */ - return PCRYIELD; - else { - luaD_poscall(L, L->top - n); - return PCRC; - } + api_checknelems(L, n); + luaD_poscall(L, L->top - n); + return 1; } } -static StkId callrethooks (lua_State *L, StkId firstResult) { - ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ - luaD_callhook(L, LUA_HOOKRET, -1); - if (f_isLua(L->ci)) { /* Lua function? */ - while ((L->hookmask & LUA_MASKRET) && L->ci->tailcalls--) /* tail calls */ - luaD_callhook(L, LUA_HOOKTAILRET, -1); - } - return restorestack(L, fr); -} - - int luaD_poscall (lua_State *L, StkId firstResult) { StkId res; int wanted, i; - CallInfo *ci; - if (L->hookmask & LUA_MASKRET) - firstResult = callrethooks(L, firstResult); - ci = L->ci--; + CallInfo *ci = L->ci; + if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) { + if (L->hookmask & LUA_MASKRET) { + ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ + luaD_hook(L, LUA_HOOKRET, -1); + firstResult = restorestack(L, fr); + } + L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */ + } res = ci->func; /* res == final position of 1st result */ + L->ci = ci = ci->previous; /* back to caller */ wanted = ci->nresults; - L->base = (ci - 1)->base; /* restore base */ - L->savedpc = (ci - 1)->savedpc; /* restore savedpc */ /* move results to correct place */ for (i = wanted; i != 0 && firstResult < L->top; i--) setobjs2s(L, res++, firstResult++); @@ -365,112 +378,219 @@ int luaD_poscall (lua_State *L, StkId firstResult) { ** The arguments are on the stack, right after the function. ** When returns, all the results are on the stack, starting at the original ** function position. -*/ -void luaD_call (lua_State *L, StkId func, int nResults) { - if (++L->nCcalls >= LUAI_MAXCCALLS) { - if (L->nCcalls == LUAI_MAXCCALLS) +*/ +void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) { + global_State *g = G(L); + if (++g->nCcalls >= LUAI_MAXCCALLS) { + if (g->nCcalls == LUAI_MAXCCALLS) luaG_runerror(L, "C stack overflow"); - else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) + else if (g->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } - if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */ - luaV_execute(L, 1); /* call it */ - L->nCcalls--; + if (!allowyield) L->nny++; + if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ + luaV_execute(L); /* call it */ + if (!allowyield) L->nny--; + g->nCcalls--; luaC_checkGC(L); } -static void resume (lua_State *L, void *ud) { - StkId firstArg = cast(StkId, ud); +static void finishCcall (lua_State *L) { CallInfo *ci = L->ci; - if (L->status == 0) { /* start coroutine? */ - lua_assert(ci == L->base_ci && firstArg > L->base); - if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) - return; - } - else { /* resuming from previous yield */ - lua_assert(L->status == LUA_YIELD); - L->status = 0; - if (!f_isLua(ci)) { /* `common' yield? */ - /* finish interrupted execution of `OP_CALL' */ - lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || - GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL); - if (luaD_poscall(L, firstArg)) /* complete it... */ - L->top = L->ci->top; /* and correct top if not multiple results */ + int n; + lua_assert(ci->u.c.k != NULL); /* must have a continuation */ + lua_assert(L->nny == 0); + /* finish 'luaD_call' */ + G(L)->nCcalls--; + /* finish 'lua_callk' */ + adjustresults(L, ci->nresults); + /* call continuation function */ + if (!(ci->callstatus & CIST_STAT)) /* no call status? */ + ci->u.c.status = LUA_YIELD; /* 'default' status */ + lua_assert(ci->u.c.status != LUA_OK); + ci->callstatus = (ci->callstatus & ~(CIST_YPCALL | CIST_STAT)) | CIST_YIELDED; + lua_unlock(L); + n = (*ci->u.c.k)(L); + lua_lock(L); + api_checknelems(L, n); + /* finish 'luaD_precall' */ + luaD_poscall(L, L->top - n); +} + + +static void unroll (lua_State *L, void *ud) { + UNUSED(ud); + for (;;) { + if (L->ci == &L->base_ci) /* stack is empty? */ + return; /* coroutine finished normally */ + if (!isLua(L->ci)) /* C function? */ + finishCcall(L); + else { /* Lua function */ + luaV_finishOp(L); /* finish interrupted instruction */ + luaV_execute(L); /* execute down to higher C 'boundary' */ } - else /* yielded inside a hook: just continue its execution */ - L->base = L->ci->base; } - luaV_execute(L, cast_int(L->ci - L->base_ci)); } -static int resume_error (lua_State *L, const char *msg) { - L->top = L->ci->base; - setsvalue2s(L, L->top, luaS_new(L, msg)); +/* +** check whether thread has a suspended protected call +*/ +static CallInfo *findpcall (lua_State *L) { + CallInfo *ci; + for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */ + if (ci->callstatus & CIST_YPCALL) + return ci; + } + return NULL; /* no pending pcall */ +} + + +static int recover (lua_State *L, int status) { + StkId oldtop; + CallInfo *ci = findpcall(L); + if (ci == NULL) return 0; /* no recovery point */ + /* "finish" luaD_pcall */ + oldtop = restorestack(L, ci->u.c.oldtop); + luaF_close(L, oldtop); + seterrorobj(L, status, oldtop); + L->ci = ci; + L->allowhook = ci->u.c.old_allowhook; + L->nny = 0; /* should be zero to be yieldable */ + luaD_shrinkstack(L); + L->errfunc = ci->u.c.old_errfunc; + ci->callstatus |= CIST_STAT; /* call has error status */ + ci->u.c.status = status; /* (here it is) */ + return 1; /* continue running the coroutine */ +} + + +/* +** signal an error in the call to 'resume', not in the execution of the +** coroutine itself. (Such errors should not be handled by any coroutine +** error hanlder and should not kill the coroutine.) +*/ +static void resume_error (lua_State *L, const char *msg, StkId firstArg) { + L->top = firstArg; /* remove args from the stack */ + setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ incr_top(L); - lua_unlock(L); - return LUA_ERRRUN; + luaD_throw(L, -1); /* jump back to 'lua_resume' */ +} + + +/* +** do the work for 'lua_resume' in protected mode +*/ +static void resume (lua_State *L, void *ud) { + StkId firstArg = cast(StkId, ud); + CallInfo *ci = L->ci; + if (G(L)->nCcalls >= LUAI_MAXCCALLS) + resume_error(L, "C stack overflow", firstArg); + if (L->status == LUA_OK) { /* may be starting a coroutine */ + if (ci != &L->base_ci) /* not in base level? */ + resume_error(L, "cannot resume non-suspended coroutine", firstArg); + /* coroutine is in base level; start running it */ + if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ + luaV_execute(L); /* call it */ + } + else if (L->status != LUA_YIELD) + resume_error(L, "cannot resume dead coroutine", firstArg); + else { /* resuming from previous yield */ + L->status = LUA_OK; + if (isLua(ci)) /* yielded inside a hook? */ + luaV_execute(L); /* just continue running Lua code */ + else { /* 'common' yield */ + if (ci->u.c.k != NULL) { /* does it have a continuation? */ + int n; + ci->u.c.status = LUA_YIELD; /* 'default' status */ + ci->callstatus |= CIST_YIELDED; + ci->func = restorestack(L, ci->u.c.oldtop); + lua_unlock(L); + n = (*ci->u.c.k)(L); /* call continuation */ + lua_lock(L); + api_checknelems(L, n); + firstArg = L->top - n; /* yield results come from continuation */ + } + G(L)->nCcalls--; /* finish 'luaD_call' */ + luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ + } + unroll(L, NULL); + } } LUA_API int lua_resume (lua_State *L, int nargs) { int status; lua_lock(L); - if (L->status != LUA_YIELD && (L->status != 0 || L->ci != L->base_ci)) - return resume_error(L, "cannot resume non-suspended coroutine"); - if (L->nCcalls >= LUAI_MAXCCALLS) - return resume_error(L, "C stack overflow"); luai_userstateresume(L, nargs); - lua_assert(L->errfunc == 0); - L->baseCcalls = ++L->nCcalls; + ++G(L)->nCcalls; /* count resume */ + L->nny = 0; /* allow yields */ status = luaD_rawrunprotected(L, resume, L->top - nargs); - if (status != 0) { /* error? */ - L->status = cast_byte(status); /* mark thread as `dead' */ - luaD_seterrorobj(L, status, L->top); - L->ci->top = L->top; - } - else { - lua_assert(L->nCcalls == L->baseCcalls); - status = L->status; + if (status == -1) /* error calling 'lua_resume'? */ + status = LUA_ERRRUN; + else { /* yield or regular error */ + while (status != LUA_OK && status != LUA_YIELD) { /* error? */ + if (recover(L, status)) /* recover point? */ + status = luaD_rawrunprotected(L, unroll, NULL); /* run continuation */ + else { /* unrecoverable error */ + L->status = cast_byte(status); /* mark thread as `dead' */ + seterrorobj(L, status, L->top); + L->ci->top = L->top; + break; + } + } + lua_assert(status == L->status); } - --L->nCcalls; + L->nny = 1; /* do not allow yields */ + --G(L)->nCcalls; lua_unlock(L); return status; } -LUA_API int lua_yield (lua_State *L, int nresults) { +LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) { + CallInfo *ci = L->ci; luai_userstateyield(L, nresults); lua_lock(L); - if (L->nCcalls > L->baseCcalls) + api_checknelems(L, nresults); + if (L->nny > 0) luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); - L->base = L->top - nresults; /* protect stack slots below */ L->status = LUA_YIELD; + if (isLua(ci)) { /* inside a hook? */ + api_check(L, k == NULL, "hooks cannot continue after yielding"); + } + else { + if ((ci->u.c.k = k) != NULL) { /* is there a continuation? */ + ci->u.c.ctx = ctx; /* save context */ + ci->u.c.oldtop = savestack(L, ci->func); /* save current 'func' */ + } + ci->func = L->top - nresults - 1; /* protect stack slots below */ + luaD_throw(L, LUA_YIELD); + } + lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ lua_unlock(L); - return -1; + return 0; /* return to 'luaD_hook' */ } int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t old_top, ptrdiff_t ef) { int status; - unsigned short oldnCcalls = L->nCcalls; - ptrdiff_t old_ci = saveci(L, L->ci); + CallInfo *old_ci = L->ci; lu_byte old_allowhooks = L->allowhook; + unsigned short old_nny = L->nny; ptrdiff_t old_errfunc = L->errfunc; L->errfunc = ef; status = luaD_rawrunprotected(L, func, u); - if (status != 0) { /* an error occurred? */ + if (status != LUA_OK) { /* an error occurred? */ StkId oldtop = restorestack(L, old_top); - luaF_close(L, oldtop); /* close eventual pending closures */ - luaD_seterrorobj(L, status, oldtop); - L->nCcalls = oldnCcalls; - L->ci = restoreci(L, old_ci); - L->base = L->ci->base; - L->savedpc = L->ci->savedpc; + luaF_close(L, oldtop); /* close possible pending closures */ + seterrorobj(L, status, oldtop); + L->ci = old_ci; L->allowhook = old_allowhooks; - restore_stack_limit(L); + L->nny = old_nny; + luaD_shrinkstack(L); } L->errfunc = old_errfunc; return status; @@ -484,6 +604,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, struct SParser { /* data to `f_parser' */ ZIO *z; Mbuffer buff; /* buffer to be used by the scanner */ + Varlist varl; /* list of local variables (to be used by the parser) */ const char *name; }; @@ -493,25 +614,30 @@ static void f_parser (lua_State *L, void *ud) { Closure *cl; struct SParser *p = cast(struct SParser *, ud); int c = luaZ_lookahead(p->z); - luaC_checkGC(L); - tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, - &p->buff, p->name); - cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L))); + tf = (c == LUA_SIGNATURE[0]) + ? luaU_undump(L, p->z, &p->buff, p->name) + : luaY_parser(L, p->z, &p->buff, &p->varl, p->name); + setptvalue2s(L, L->top, tf); + incr_top(L); + cl = luaF_newLclosure(L, tf->sizeupvalues, G(L)->l_gt); cl->l.p = tf; - for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */ + setclvalue(L, L->top - 1, cl); + for (i = 0; i < tf->sizeupvalues; i++) /* initialize upvalues */ cl->l.upvals[i] = luaF_newupval(L); - setclvalue(L, L->top, cl); - incr_top(L); } int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { struct SParser p; int status; + L->nny++; /* cannot yield during parsing */ p.z = z; p.name = name; + p.varl.actvar = NULL; p.varl.nactvar = p.varl.actvarsize = 0; luaZ_initbuffer(L, &p.buff); status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); luaZ_freebuffer(L, &p.buff); + luaM_freearray(L, p.varl.actvar, p.varl.actvarsize); + L->nny--; return status; } @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 2.7.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: ldo.h,v 2.18 2009/12/17 12:28:57 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -13,45 +13,33 @@ #include "lzio.h" -#define luaD_checkstack(L,n) \ - if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \ - luaD_growstack(L, n); \ - else condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); +#define luaD_checkstack(L,n) if (L->stack_last - L->top <= (n)) \ + luaD_growstack(L, n); else condmovestack(L); -#define incr_top(L) {luaD_checkstack(L,1); L->top++;} +#define incr_top(L) {L->top++; luaD_checkstack(L,0);} #define savestack(L,p) ((char *)(p) - (char *)L->stack) #define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) -#define saveci(L,p) ((char *)(p) - (char *)L->base_ci) -#define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n))) - - -/* results from luaD_precall */ -#define PCRLUA 0 /* initiated a call to a Lua function */ -#define PCRC 1 /* did a call to a C function */ -#define PCRYIELD 2 /* C funtion yielded */ - /* type of protected functions, to be ran by `runprotected' */ typedef void (*Pfunc) (lua_State *L, void *ud); LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); -LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line); +LUAI_FUNC void luaD_hook (lua_State *L, int event, int line); LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); -LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); +LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults, + int allowyield); LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult); -LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize); LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); LUAI_FUNC void luaD_growstack (lua_State *L, int n); +LUAI_FUNC void luaD_shrinkstack (lua_State *L); LUAI_FUNC void luaD_throw (lua_State *L, int errcode); LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); -LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); - #endif diff --git a/src/ldump.c b/src/ldump.c index c9d3d487..f95381ab 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: ldump.c,v 2.12 2009/09/30 15:38:37 roberto Exp $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -24,7 +24,7 @@ typedef struct { } DumpState; #define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D) -#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D) +#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D) static void DumpBlock(const void* b, size_t size, DumpState* D) { @@ -60,7 +60,7 @@ static void DumpVector(const void* b, int n, size_t size, DumpState* D) static void DumpString(const TString* s, DumpState* D) { - if (s==NULL || getstr(s)==NULL) + if (s==NULL) { size_t size=0; DumpVar(size,D); @@ -108,6 +108,17 @@ static void DumpConstants(const Proto* f, DumpState* D) for (i=0; i<n; i++) DumpFunction(f->p[i],f->source,D); } +static void DumpUpvalues(const Proto* f, DumpState* D) +{ + int i,n=f->sizeupvalues; + DumpInt(n,D); + for (i=0; i<n; i++) + { + DumpChar(f->upvalues[i].instack, D); + DumpChar(f->upvalues[i].idx, D); + } +} + static void DumpDebug(const Proto* f, DumpState* D) { int i,n; @@ -123,7 +134,7 @@ static void DumpDebug(const Proto* f, DumpState* D) } n= (D->strip) ? 0 : f->sizeupvalues; DumpInt(n,D); - for (i=0; i<n; i++) DumpString(f->upvalues[i],D); + for (i=0; i<n; i++) DumpString(f->upvalues[i].name,D); } static void DumpFunction(const Proto* f, const TString* p, DumpState* D) @@ -131,12 +142,13 @@ static void DumpFunction(const Proto* f, const TString* p, DumpState* D) DumpString((f->source==p || D->strip) ? NULL : f->source,D); DumpInt(f->linedefined,D); DumpInt(f->lastlinedefined,D); - DumpChar(f->nups,D); DumpChar(f->numparams,D); DumpChar(f->is_vararg,D); DumpChar(f->maxstacksize,D); + DumpChar(f->envreg,D); DumpCode(f,D); DumpConstants(f,D); + DumpUpvalues(f,D); DumpDebug(f,D); } diff --git a/src/lfunc.c b/src/lfunc.c index 813e88f5..afc097c6 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.12.1.2 2007/12/28 14:58:43 roberto Exp $ +** $Id: lfunc.c,v 2.19 2009/12/16 16:42:58 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -16,34 +16,32 @@ #include "lgc.h" #include "lmem.h" #include "lobject.h" +#include "lopcodes.h" #include "lstate.h" -Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) { - Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems))); - luaC_link(L, obj2gco(c), LUA_TFUNCTION); +Closure *luaF_newCclosure (lua_State *L, int n, Table *e) { + Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeCclosure(n), NULL, 0)->cl; c->c.isC = 1; c->c.env = e; - c->c.nupvalues = cast_byte(nelems); + c->c.nupvalues = cast_byte(n); return c; } -Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) { - Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); - luaC_link(L, obj2gco(c), LUA_TFUNCTION); +Closure *luaF_newLclosure (lua_State *L, int n, Table *e) { + Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeLclosure(n), NULL, 0)->cl; c->l.isC = 0; c->l.env = e; - c->l.nupvalues = cast_byte(nelems); - while (nelems--) c->l.upvals[nelems] = NULL; + c->l.nupvalues = cast_byte(n); + while (n--) c->l.upvals[n] = NULL; return c; } UpVal *luaF_newupval (lua_State *L) { - UpVal *uv = luaM_new(L, UpVal); - luaC_link(L, obj2gco(uv), LUA_TUPVAL); + UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), NULL, 0)->uv; uv->v = &uv->u.value; setnilvalue(uv->v); return uv; @@ -55,21 +53,18 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { GCObject **pp = &L->openupval; UpVal *p; UpVal *uv; - while (*pp != NULL && (p = ngcotouv(*pp))->v >= level) { + while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { lua_assert(p->v != &p->u.value); if (p->v == level) { /* found a corresponding upvalue? */ if (isdead(g, obj2gco(p))) /* is it dead? */ - changewhite(obj2gco(p)); /* ressurect it */ + changewhite(obj2gco(p)); /* ressurrect it */ return p; } pp = &p->next; } - uv = luaM_new(L, UpVal); /* not found: create a new one */ - uv->tt = LUA_TUPVAL; - uv->marked = luaC_white(g); + /* not found: create a new one */ + uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv; uv->v = level; /* current value lives in the stack */ - uv->next = *pp; /* chain it in the proper position */ - *pp = obj2gco(uv); uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */ uv->u.l.next = g->uvhead.u.l.next; uv->u.l.next->u.l.prev = uv; @@ -96,7 +91,7 @@ void luaF_freeupval (lua_State *L, UpVal *uv) { void luaF_close (lua_State *L, StkId level) { UpVal *uv; global_State *g = G(L); - while (L->openupval != NULL && (uv = ngcotouv(L->openupval))->v >= level) { + while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) { GCObject *o = obj2gco(uv); lua_assert(!isblack(o) && uv->v != &uv->u.value); L->openupval = uv->next; /* remove from `open' list */ @@ -113,38 +108,37 @@ void luaF_close (lua_State *L, StkId level) { Proto *luaF_newproto (lua_State *L) { - Proto *f = luaM_new(L, Proto); - luaC_link(L, obj2gco(f), LUA_TPROTO); + Proto *f = &luaC_newobj(L, LUA_TPROTO, sizeof(Proto), NULL, 0)->p; f->k = NULL; f->sizek = 0; f->p = NULL; f->sizep = 0; f->code = NULL; f->sizecode = 0; + f->lineinfo = NULL; f->sizelineinfo = 0; - f->sizeupvalues = 0; - f->nups = 0; f->upvalues = NULL; + f->sizeupvalues = 0; f->numparams = 0; f->is_vararg = 0; f->maxstacksize = 0; - f->lineinfo = NULL; - f->sizelocvars = 0; f->locvars = NULL; + f->sizelocvars = 0; f->linedefined = 0; f->lastlinedefined = 0; f->source = NULL; + f->envreg = NO_REG; return f; } void luaF_freeproto (lua_State *L, Proto *f) { - luaM_freearray(L, f->code, f->sizecode, Instruction); - luaM_freearray(L, f->p, f->sizep, Proto *); - luaM_freearray(L, f->k, f->sizek, TValue); - luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); - luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); - luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); + luaM_freearray(L, f->code, f->sizecode); + luaM_freearray(L, f->p, f->sizep); + luaM_freearray(L, f->k, f->sizek); + luaM_freearray(L, f->lineinfo, f->sizelineinfo); + luaM_freearray(L, f->locvars, f->sizelocvars); + luaM_freearray(L, f->upvalues, f->sizeupvalues); luaM_free(L, f); } diff --git a/src/lfunc.h b/src/lfunc.h index a68cf515..2e02419b 100644 --- a/src/lfunc.h +++ b/src/lfunc.h @@ -1,5 +1,5 @@ /* -** $Id: lfunc.h,v 2.4.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lfunc.h,v 2.4 2005/04/25 19:24:10 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.38.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lgc.c,v 2.67 2009/12/22 15:32:50 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -29,54 +29,148 @@ #define GCFINALIZECOST 100 -#define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) +#define maskcolors cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) #define makewhite(g,x) \ - ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g))) + (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g))) -#define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) -#define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) +#define white2gray(x) resetbits(gch(x)->marked, WHITEBITS) +#define black2gray(x) resetbit(gch(x)->marked, BLACKBIT) -#define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) +#define stringmark(s) resetbits((s)->tsv.marked, WHITEBITS) #define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) -#define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT) - - -#define KEYWEAK bitmask(KEYWEAKBIT) -#define VALUEWEAK bitmask(VALUEWEAKBIT) +#define checkdeadkey(n) lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n))) #define markvalue(g,o) { checkconsistency(o); \ - if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } + if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } -#define markobject(g,t) { if (iswhite(obj2gco(t))) \ +#define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \ reallymarkobject(g, obj2gco(t)); } -#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) +static void reallymarkobject (global_State *g, GCObject *o); + + +/* +** {====================================================== +** Generic functions +** ======================================================= +*/ + +static void linktable (Table *h, GCObject **p) { + h->gclist = *p; + *p = obj2gco(h); +} static void removeentry (Node *n) { lua_assert(ttisnil(gval(n))); if (iscollectable(gkey(n))) - setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ + setdeadvalue(gkey(n)); /* dead key; remove it */ +} + + +/* +** The next function tells whether a key or value can be cleared from +** a weak table. Non-collectable objects are never removed from weak +** tables. Strings behave as `values', so are never removed too. for +** other objects: if really collected, cannot keep them; for objects +** being finalized, keep them in keys, but not in values +*/ +static int iscleared (const TValue *o, int iskey) { + if (!iscollectable(o)) return 0; + if (ttisstring(o)) { + stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ + return 0; + } + return iswhite(gcvalue(o)) || + (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); +} + + +void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { + global_State *g = G(L); + lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + lua_assert(gch(o)->tt != LUA_TTABLE); + /* must keep invariant? */ + if (g->gcstate == GCSpropagate) + reallymarkobject(g, v); /* restore invariant */ + else /* don't mind */ + makewhite(g, o); /* mark as white just to avoid other barriers */ +} + + +void luaC_barrierback (lua_State *L, Table *t) { + global_State *g = G(L); + GCObject *o = obj2gco(t); + lua_assert(isblack(o) && !isdead(g, o)); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + black2gray(o); /* make table gray (again) */ + t->gclist = g->grayagain; + g->grayagain = o; +} + + +/* +** create a new collectable object and link it to '*list' +*/ +GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, + int offset) { + global_State *g = G(L); + GCObject *o = obj2gco(cast(char *, luaM_newobject(L, tt, sz)) + offset); + if (list == NULL) + list = &g->rootgc; /* standard list for collectable objects */ + gch(o)->marked = luaC_white(g); + gch(o)->tt = tt; + gch(o)->next = *list; + *list = o; + return o; +} + + +void luaC_linkupval (lua_State *L, UpVal *uv) { + global_State *g = G(L); + GCObject *o = obj2gco(uv); + gch(o)->next = g->rootgc; /* link upvalue into `rootgc' list */ + g->rootgc = o; + if (isgray(o)) { + if (g->gcstate == GCSpropagate) { + gray2black(o); /* closed upvalues need barrier */ + luaC_barrier(L, uv, uv->v); + } + else { /* sweep phase: sweep it (turning it into white) */ + makewhite(g, o); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + } + } } +/* }====================================================== */ + + + +/* +** {====================================================== +** Mark functions +** ======================================================= +*/ static void reallymarkobject (global_State *g, GCObject *o) { lua_assert(iswhite(o) && !isdead(g, o)); white2gray(o); - switch (o->gch.tt) { + switch (gch(o)->tt) { case LUA_TSTRING: { return; } case LUA_TUSERDATA: { Table *mt = gco2u(o)->metatable; gray2black(o); /* udata are never gray */ - if (mt) markobject(g, mt); + markobject(g, mt); markobject(g, gco2u(o)->env); return; } @@ -93,8 +187,7 @@ static void reallymarkobject (global_State *g, GCObject *o) { break; } case LUA_TTABLE: { - gco2h(o)->gclist = g->gray; - g->gray = o; + linktable(gco2t(o), &g->gray); break; } case LUA_TTHREAD: { @@ -112,87 +205,145 @@ static void reallymarkobject (global_State *g, GCObject *o) { } -static void marktmu (global_State *g) { - GCObject *u = g->tmudata; - if (u) { - do { - u = u->gch.next; - makewhite(g, u); /* may be marked, if left from previous GC */ - reallymarkobject(g, u); - } while (u != g->tmudata); +static void markmt (global_State *g) { + int i; + for (i=0; i<NUM_TAGS; i++) + markobject(g, g->mt[i]); +} + + +static void markbeingfnz (global_State *g) { + GCObject *o; + for (o = g->tobefnz; o != NULL; o = gch(o)->next) { + lua_assert(testbit(gch(o)->marked, SEPARATED)); + makewhite(g, o); + reallymarkobject(g, o); } } -/* move `dead' udata that need finalization to list `tmudata' */ -size_t luaC_separateudata (lua_State *L, int all) { +/* mark root set */ +static void markroot (lua_State *L) { global_State *g = G(L); - size_t deadmem = 0; - GCObject **p = &g->mainthread->next; - GCObject *curr; - while ((curr = *p) != NULL) { - if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) - p = &curr->gch.next; /* don't bother with them */ - else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { - markfinalized(gco2u(curr)); /* don't need finalization */ - p = &curr->gch.next; - } - else { /* must call its gc method */ - deadmem += sizeudata(gco2u(curr)); - markfinalized(gco2u(curr)); - *p = curr->gch.next; - /* link `curr' at the end of `tmudata' list */ - if (g->tmudata == NULL) /* list is empty? */ - g->tmudata = curr->gch.next = curr; /* creates a circular list */ - else { - curr->gch.next = g->tmudata->gch.next; - g->tmudata->gch.next = curr; - g->tmudata = curr; - } + g->gray = NULL; + g->grayagain = NULL; + g->weak = g->ephemeron = g->allweak = NULL; + markobject(g, g->mainthread); + /* make global table and registry to be traversed before main stack */ + markobject(g, g->l_gt); + markvalue(g, &g->l_registry); + markmt(g); + markbeingfnz(g); /* mark any finalizing object left from previous cycle */ + g->gcstate = GCSpropagate; +} + + +static void remarkupvals (global_State *g) { + UpVal *uv; + for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { + lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); + if (isgray(obj2gco(uv))) + markvalue(g, uv->v); + } +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Traverse functions +** ======================================================= +*/ + +static void traverseweakvalue (global_State *g, Table *h) { + int i = sizenode(h); + while (i--) { + Node *n = gnode(h, i); + checkdeadkey(n); + if (ttisnil(gval(n))) + removeentry(n); /* remove empty entries */ + else { + lua_assert(!ttisnil(gkey(n))); + markvalue(g, gkey(n)); } } - return deadmem; + linktable(h, &g->weak); } -static int traversetable (global_State *g, Table *h) { - int i; - int weakkey = 0; - int weakvalue = 0; - const TValue *mode; - if (h->metatable) - markobject(g, h->metatable); - mode = gfasttm(g, h->metatable, TM_MODE); - if (mode && ttisstring(mode)) { /* is there a weak mode? */ - weakkey = (strchr(svalue(mode), 'k') != NULL); - weakvalue = (strchr(svalue(mode), 'v') != NULL); - if (weakkey || weakvalue) { /* is really weak? */ - h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ - h->marked |= cast_byte((weakkey << KEYWEAKBIT) | - (weakvalue << VALUEWEAKBIT)); - h->gclist = g->weak; /* must be cleared after GC, ... */ - g->weak = obj2gco(h); /* ... so put in the appropriate list */ +static int traverseephemeron (global_State *g, Table *h) { + int marked = 0; + int hasclears = 0; + int i = h->sizearray; + while (i--) { /* mark array part (numeric keys are 'strong') */ + if (valiswhite(&h->array[i])) { + marked = 1; + reallymarkobject(g, gcvalue(&h->array[i])); } } - if (weakkey && weakvalue) return 1; - if (!weakvalue) { - i = h->sizearray; - while (i--) - markvalue(g, &h->array[i]); + i = sizenode(h); + while (i--) { + Node *n = gnode(h, i); + checkdeadkey(n); + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ + else if (valiswhite(gval(n))) { + /* value is not marked yet */ + if (iscleared(key2tval(n), 1)) /* key is not marked (yet)? */ + hasclears = 1; /* may have to propagate mark from key to value */ + else { /* mark value only if key is marked */ + marked = 1; /* some mark changed status */ + reallymarkobject(g, gcvalue(gval(n))); + } + } } + if (hasclears) + linktable(h, &g->ephemeron); + else /* nothing to propagate */ + linktable(h, &g->weak); /* avoid convergence phase */ + return marked; +} + + +static void traversestrongtable (global_State *g, Table *h) { + int i; + i = h->sizearray; + while (i--) + markvalue(g, &h->array[i]); i = sizenode(h); while (i--) { Node *n = gnode(h, i); - lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); + checkdeadkey(n); if (ttisnil(gval(n))) removeentry(n); /* remove empty entries */ else { lua_assert(!ttisnil(gkey(n))); - if (!weakkey) markvalue(g, gkey(n)); - if (!weakvalue) markvalue(g, gval(n)); + markvalue(g, gkey(n)); + markvalue(g, gval(n)); } } - return weakkey || weakvalue; +} + + +static void traversetable (global_State *g, Table *h) { + const TValue *mode = gfasttm(g, h->metatable, TM_MODE); + markobject(g, h->metatable); + if (mode && ttisstring(mode)) { /* is there a weak mode? */ + int weakkey = (strchr(svalue(mode), 'k') != NULL); + int weakvalue = (strchr(svalue(mode), 'v') != NULL); + if (weakkey || weakvalue) { /* is really weak? */ + black2gray(obj2gco(h)); /* keep table gray */ + if (!weakkey) /* strong keys? */ + traverseweakvalue(g, h); + else if (!weakvalue) /* strong values? */ + traverseephemeron(g, h); + else + linktable(h, &g->allweak); /* nothing to traverse now */ + return; + } /* else go through */ + } + traversestrongtable(g, h); } @@ -206,13 +357,11 @@ static void traverseproto (global_State *g, Proto *f) { for (i=0; i<f->sizek; i++) /* mark literals */ markvalue(g, &f->k[i]); for (i=0; i<f->sizeupvalues; i++) { /* mark upvalue names */ - if (f->upvalues[i]) - stringmark(f->upvalues[i]); - } - for (i=0; i<f->sizep; i++) { /* mark nested protos */ - if (f->p[i]) - markobject(g, f->p[i]); + if (f->upvalues[i].name) + stringmark(f->upvalues[i].name); } + for (i=0; i<f->sizep; i++) /* mark nested protos */ + markobject(g, f->p[i]); for (i=0; i<f->sizelocvars; i++) { /* mark local-variable names */ if (f->locvars[i].varname) stringmark(f->locvars[i].varname); @@ -220,7 +369,6 @@ static void traverseproto (global_State *g, Proto *f) { } - static void traverseclosure (global_State *g, Closure *cl) { markobject(g, cl->c.env); if (cl->c.isC) { @@ -230,7 +378,7 @@ static void traverseclosure (global_State *g, Closure *cl) { } else { int i; - lua_assert(cl->l.nupvalues == cl->l.p->nups); + lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues); markobject(g, cl->l.p); for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */ markobject(g, cl->l.upvals[i]); @@ -238,35 +386,17 @@ static void traverseclosure (global_State *g, Closure *cl) { } -static void checkstacksizes (lua_State *L, StkId max) { - int ci_used = cast_int(L->ci - L->base_ci); /* number of `ci' in use */ - int s_used = cast_int(max - L->stack); /* part of stack in use */ - if (L->size_ci > LUAI_MAXCALLS) /* handling overflow? */ - return; /* do not touch the stacks */ - if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) - luaD_reallocCI(L, L->size_ci/2); /* still big enough... */ - condhardstacktests(luaD_reallocCI(L, ci_used + 1)); - if (4*s_used < L->stacksize && - 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) - luaD_reallocstack(L, L->stacksize/2); /* still big enough... */ - condhardstacktests(luaD_reallocstack(L, s_used)); -} - - -static void traversestack (global_State *g, lua_State *l) { - StkId o, lim; - CallInfo *ci; - markvalue(g, gt(l)); - lim = l->top; - for (ci = l->base_ci; ci <= l->ci; ci++) { - lua_assert(ci->top <= l->stack_last); - if (lim < ci->top) lim = ci->top; - } - for (o = l->stack; o < l->top; o++) +static void traversestack (global_State *g, lua_State *L) { + StkId o; + if (L->stack == NULL) + return; /* stack not completely built yet */ + for (o = L->stack; o < L->top; o++) markvalue(g, o); - for (; o <= lim; o++) - setnilvalue(o); - checkstacksizes(l, lim); + if (g->gcstate == GCSatomic) { /* final traversal? */ + StkId lim = L->stack + L->stacksize; /* real end of stack */ + for (; o < lim; o++) /* clear not-marked stack slice */ + setnilvalue(o); + } } @@ -278,12 +408,11 @@ static l_mem propagatemark (global_State *g) { GCObject *o = g->gray; lua_assert(isgray(o)); gray2black(o); - switch (o->gch.tt) { + switch (gch(o)->tt) { case LUA_TTABLE: { - Table *h = gco2h(o); + Table *h = gco2t(o); g->gray = h->gclist; - if (traversetable(g, h)) /* table is weak? */ - black2gray(o); /* keep it gray */ + traversetable(g, h); return sizeof(Table) + sizeof(TValue) * h->sizearray + sizeof(Node) * sizenode(h); } @@ -301,8 +430,7 @@ static l_mem propagatemark (global_State *g) { g->grayagain = o; black2gray(o); traversestack(g, th); - return sizeof(lua_State) + sizeof(TValue) * th->stacksize + - sizeof(CallInfo) * th->size_ci; + return sizeof(lua_State) + sizeof(TValue) * th->stacksize; } case LUA_TPROTO: { Proto *p = gco2p(o); @@ -310,7 +438,7 @@ static l_mem propagatemark (global_State *g) { traverseproto(g, p); return sizeof(Proto) + sizeof(Instruction) * p->sizecode + sizeof(Proto *) * p->sizep + - sizeof(TValue) * p->sizek + + sizeof(TValue) * p->sizek + sizeof(int) * p->sizelineinfo + sizeof(LocVar) * p->sizelocvars + sizeof(TString *) * p->sizeupvalues; @@ -320,46 +448,54 @@ static l_mem propagatemark (global_State *g) { } -static size_t propagateall (global_State *g) { - size_t m = 0; - while (g->gray) m += propagatemark(g); - return m; +static void propagateall (global_State *g) { + while (g->gray) propagatemark(g); } -/* -** The next function tells whether a key or value can be cleared from -** a weak table. Non-collectable objects are never removed from weak -** tables. Strings behave as `values', so are never removed too. for -** other objects: if really collected, cannot keep them; for userdata -** being finalized, keep them in keys, but not in values -*/ -static int iscleared (const TValue *o, int iskey) { - if (!iscollectable(o)) return 0; - if (ttisstring(o)) { - stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ - return 0; - } - return iswhite(gcvalue(o)) || - (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); +static void traverselistofgrays (global_State *g, GCObject **l) { + lua_assert(g->gray == NULL); /* no grays left */ + g->gray = *l; /* now 'l' is new gray list */ + *l = NULL; + propagateall(g); } +static void convergeephemerons (global_State *g) { + int changed; + do { + GCObject *w; + GCObject *next = g->ephemeron; + g->ephemeron = NULL; + changed = 0; + while ((w = next) != NULL) { + next = gco2t(w)->gclist; + if (traverseephemeron(g, gco2t(w))) { + changed = 1; + propagateall(g); + } + } + } while (changed); +} + +/* }====================================================== */ + + /* -** clear collected entries from weaktables +** {====================================================== +** Sweep Functions +** ======================================================= */ + +/* clear collected entries from weaktables */ static void cleartable (GCObject *l) { while (l) { - Table *h = gco2h(l); + Table *h = gco2t(l); int i = h->sizearray; - lua_assert(testbit(h->marked, VALUEWEAKBIT) || - testbit(h->marked, KEYWEAKBIT)); - if (testbit(h->marked, VALUEWEAKBIT)) { - while (i--) { - TValue *o = &h->array[i]; - if (iscleared(o, 0)) /* value was collected? */ - setnilvalue(o); /* remove value */ - } + while (i--) { + TValue *o = &h->array[i]; + if (iscleared(o, 0)) /* value was collected? */ + setnilvalue(o); /* remove value */ } i = sizenode(h); while (i--) { @@ -376,32 +512,35 @@ static void cleartable (GCObject *l) { static void freeobj (lua_State *L, GCObject *o) { - switch (o->gch.tt) { + switch (gch(o)->tt) { case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; - case LUA_TTABLE: luaH_free(L, gco2h(o)); break; - case LUA_TTHREAD: { - lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); - luaE_freethread(L, gco2th(o)); - break; - } + case LUA_TTABLE: luaH_free(L, gco2t(o)); break; + case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; + case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; case LUA_TSTRING: { G(L)->strt.nuse--; luaM_freemem(L, o, sizestring(gco2ts(o))); break; } - case LUA_TUSERDATA: { - luaM_freemem(L, o, sizeudata(gco2u(o))); - break; - } default: lua_assert(0); } } - #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) +static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); + + +static void sweepthread (lua_State *L, lua_State *L1, int alive) { + if (L1->stack == NULL) return; /* stack not completely built yet */ + sweepwholelist(L, &L1->openupval); /* sweep open upvalues */ + luaE_freeCI(L1); /* free extra CallInfo slots */ + /* should not change the stack during an emergency gc cycle */ + if (alive && G(L)->gckind != KGC_EMERGENCY) + luaD_shrinkstack(L1); +} static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { @@ -409,54 +548,68 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { global_State *g = G(L); int deadmask = otherwhite(g); while ((curr = *p) != NULL && count-- > 0) { - if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ - sweepwholelist(L, &gco2th(curr)->openupval); - if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */ - lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); + int alive = (gch(curr)->marked ^ WHITEBITS) & deadmask; + if (gch(curr)->tt == LUA_TTHREAD) + sweepthread(L, gco2th(curr), alive); + if (alive) { + lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT)); makewhite(g, curr); /* make it white (for next cycle) */ - p = &curr->gch.next; + p = &gch(curr)->next; } else { /* must erase `curr' */ lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); - *p = curr->gch.next; - if (curr == g->rootgc) /* is the first element of the list? */ - g->rootgc = curr->gch.next; /* adjust first */ + *p = gch(curr)->next; /* remove 'curr' from list */ freeobj(L, curr); } } return p; } +/* }====================================================== */ + + +/* +** {====================================================== +** Finalization +** ======================================================= +*/ static void checkSizes (lua_State *L) { global_State *g = G(L); - /* check size of string hash */ - if (g->strt.nuse < cast(lu_int32, g->strt.size/4) && - g->strt.size > MINSTRTABSIZE*2) - luaS_resize(L, g->strt.size/2); /* table is too big */ - /* check size of buffer */ - if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ - size_t newsize = luaZ_sizebuffer(&g->buff) / 2; - luaZ_resizebuffer(L, &g->buff, newsize); + if (g->strt.nuse < cast(lu_int32, g->strt.size)) { + /* string-table size could be the smaller power of 2 larger than 'nuse' */ + int size = 1 << luaO_ceillog2(g->strt.nuse); + if (size < g->strt.size) /* current table too large? */ + luaS_resize(L, size); /* shrink it */ } + luaZ_freebuffer(L, &g->buff); } -static void GCTM (lua_State *L) { - global_State *g = G(L); - GCObject *o = g->tmudata->gch.next; /* get first element */ - Udata *udata = rawgco2u(o); - const TValue *tm; - /* remove udata from `tmudata' */ - if (o == g->tmudata) /* last element? */ - g->tmudata = NULL; - else - g->tmudata->gch.next = udata->uv.next; - udata->uv.next = g->mainthread->next; /* return it to `root' list */ - g->mainthread->next = o; +static Udata *udata2finalize (global_State *g) { + GCObject *o = g->tobefnz; /* get first element */ + g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */ + gch(o)->next = g->rootgc; /* return it to `root' list */ + g->rootgc = o; + lua_assert(isfinalized(gch(o))); + resetbit(gch(o)->marked, SEPARATED); /* mark it as such */ makewhite(g, o); - tm = fasttm(L, udata->uv.metatable, TM_GC); - if (tm != NULL) { + return rawgco2u(o); +} + + +static void dothecall (lua_State *L, void *ud) { + UNUSED(ud); + luaD_call(L, L->top - 2, 0, 0); +} + + +static void GCTM (lua_State *L, int propagateerrors) { + global_State *g = G(L); + Udata *udata = udata2finalize(g); + const TValue *tm = gfasttm(g, udata->uv.metatable, TM_GC); + if (tm != NULL && ttisfunction(tm)) { + int status; lu_byte oldah = L->allowhook; lu_mem oldt = g->GCthreshold; L->allowhook = 0; /* stop debug hooks during GC tag method */ @@ -464,92 +617,116 @@ static void GCTM (lua_State *L) { setobj2s(L, L->top, tm); setuvalue(L, L->top+1, udata); L->top += 2; - luaD_call(L, L->top - 2, 0); + status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); L->allowhook = oldah; /* restore hooks */ g->GCthreshold = oldt; /* restore threshold */ + if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ + if (status == LUA_ERRRUN) { /* is there an error msg.? */ + luaO_pushfstring(L, "error in __gc tag method (%s)", + lua_tostring(L, -1)); + status = LUA_ERRGCMM; /* error in __gc metamethod */ + } + luaD_throw(L, status); /* re-send error */ + } } } -/* -** Call all GC tag methods -*/ -void luaC_callGCTM (lua_State *L) { - while (G(L)->tmudata) - GCTM(L); +/* move 'dead' udata that need finalization to list 'tobefnz' */ +void luaC_separateudata (lua_State *L, int all) { + global_State *g = G(L); + GCObject **p = &g->mainthread->next; + GCObject *curr; + GCObject **lastnext = &g->tobefnz; + /* find last 'next' field in 'tobefnz' list (to insert elements in its end) */ + while (*lastnext != NULL) lastnext = &gch(*lastnext)->next; + while ((curr = *p) != NULL) { /* traverse all finalizable objects */ + lua_assert(gch(curr)->tt == LUA_TUSERDATA && !isfinalized(gco2u(curr))); + lua_assert(testbit(gch(curr)->marked, SEPARATED)); + if (!(all || iswhite(curr))) /* not being collected? */ + p = &gch(curr)->next; /* don't bother with it */ + else { + l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ + *p = gch(curr)->next; /* remove 'curr' from 'rootgc' list */ + /* link 'curr' at the end of 'tobefnz' list */ + gch(curr)->next = *lastnext; + *lastnext = curr; + lastnext = &gch(curr)->next; + } + } } -void luaC_freeall (lua_State *L) { +void luaC_checkfinalizer (lua_State *L, Udata *u) { global_State *g = G(L); - int i; - g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); /* mask to collect all elements */ - sweepwholelist(L, &g->rootgc); - for (i = 0; i < g->strt.size; i++) /* free all string lists */ - sweepwholelist(L, &g->strt.hash[i]); + if (testbit(u->uv.marked, SEPARATED) || /* userdata is already separated... */ + isfinalized(&u->uv) || /* ... or is finalized... */ + gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */ + return; /* nothing to be done */ + else { /* move 'u' to 2nd part of root list */ + GCObject **p; + for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next) + lua_assert(*p != obj2gco(g->mainthread)); /* 'u' must be in this list */ + *p = u->uv.next; /* remove 'u' from root list */ + u->uv.next = g->mainthread->next; /* re-link it in list */ + g->mainthread->next = obj2gco(u); + l_setbit(u->uv.marked, SEPARATED); /* mark it as such */ + } } +/* }====================================================== */ -static void markmt (global_State *g) { - int i; - for (i=0; i<NUM_TAGS; i++) - if (g->mt[i]) markobject(g, g->mt[i]); -} +/* +** {====================================================== +** GC control +** ======================================================= +*/ -/* mark root set */ -static void markroot (lua_State *L) { +void luaC_freeallobjects (lua_State *L) { global_State *g = G(L); - g->gray = NULL; - g->grayagain = NULL; - g->weak = NULL; - markobject(g, g->mainthread); - /* make global table be traversed before main stack */ - markvalue(g, gt(g->mainthread)); - markvalue(g, registry(L)); - markmt(g); - g->gcstate = GCSpropagate; -} - - -static void remarkupvals (global_State *g) { - UpVal *uv; - for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { - lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); - if (isgray(obj2gco(uv))) - markvalue(g, uv->v); - } + int i; + while (g->tobefnz) GCTM(L, 0); /* Call all pending finalizers */ + /* following "white" makes all objects look dead */ + g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); + sweepwholelist(L, &g->rootgc); + lua_assert(g->rootgc == obj2gco(g->mainthread) && + g->mainthread->next == NULL); + for (i = 0; i < g->strt.size; i++) /* free all string lists */ + sweepwholelist(L, &g->strt.hash[i]); + lua_assert(g->strt.nuse == 0); } static void atomic (lua_State *L) { global_State *g = G(L); - size_t udsize; /* total size of userdata to be finalized */ - /* remark occasional upvalues of (maybe) dead threads */ - remarkupvals(g); - /* traverse objects cautch by write barrier and by 'remarkupvals' */ - propagateall(g); - /* remark weak tables */ - g->gray = g->weak; - g->weak = NULL; + g->gcstate = GCSatomic; lua_assert(!iswhite(obj2gco(g->mainthread))); markobject(g, L); /* mark running thread */ - markmt(g); /* mark basic metatables (again) */ - propagateall(g); - /* remark gray again */ - g->gray = g->grayagain; - g->grayagain = NULL; + /* registry and global metatables may be changed by API */ + markvalue(g, &g->l_registry); + markmt(g); /* mark basic metatables */ + /* remark occasional upvalues of (maybe) dead threads */ + remarkupvals(g); + /* traverse objects caught by write barrier and by 'remarkupvals' */ propagateall(g); - udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ - marktmu(g); /* mark `preserved' userdata */ - udsize += propagateall(g); /* remark, to propagate `preserveness' */ - cleartable(g->weak); /* remove collected objects from weak tables */ - /* flip current white */ - g->currentwhite = cast_byte(otherwhite(g)); - g->sweepstrgc = 0; - g->sweepgc = &g->rootgc; + /* at this point, all strongly accessible objects are marked. + Start marking weakly accessible objects. */ + traverselistofgrays(g, &g->weak); /* remark weak tables */ + traverselistofgrays(g, &g->ephemeron); /* remark ephemeron tables */ + traverselistofgrays(g, &g->grayagain); /* remark gray again */ + convergeephemerons(g); + luaC_separateudata(L, 0); /* separate userdata to be finalized */ + markbeingfnz(g); /* mark userdata that will be finalized */ + propagateall(g); /* remark, to propagate `preserveness' */ + convergeephemerons(g); + /* remove collected objects from weak tables */ + cleartable(g->weak); + cleartable(g->ephemeron); + cleartable(g->allweak); + g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ + g->sweepstrgc = 0; /* go to sweep phase */ g->gcstate = GCSsweepstring; - g->estimate = g->totalbytes - udsize; /* first estimate */ } @@ -570,35 +747,27 @@ static l_mem singlestep (lua_State *L) { } } case GCSsweepstring: { - lu_mem old = g->totalbytes; sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); - if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ - g->gcstate = GCSsweep; /* end sweep-string phase */ - lua_assert(old >= g->totalbytes); - g->estimate -= old - g->totalbytes; + if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ + g->sweepgc = &g->rootgc; + g->gcstate = GCSsweep; /* sweep all other objects */ + } return GCSWEEPCOST; } case GCSsweep: { - lu_mem old = g->totalbytes; g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); - if (*g->sweepgc == NULL) { /* nothing more to sweep? */ - checkSizes(L); + if (*g->sweepgc == NULL) /* nothing more to sweep? */ g->gcstate = GCSfinalize; /* end sweep phase */ - } - lua_assert(old >= g->totalbytes); - g->estimate -= old - g->totalbytes; return GCSWEEPMAX*GCSWEEPCOST; } case GCSfinalize: { - if (g->tmudata) { - GCTM(L); - if (g->estimate > GCFINALIZECOST) - g->estimate -= GCFINALIZECOST; + if (g->tobefnz) { + GCTM(L, 1); return GCFINALIZECOST; } else { + checkSizes(L); g->gcstate = GCSpause; /* end collection */ - g->gcdept = 0; return 0; } } @@ -609,103 +778,56 @@ static l_mem singlestep (lua_State *L) { void luaC_step (lua_State *L) { global_State *g = G(L); - l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; - if (lim == 0) - lim = (MAX_LUMEM-1)/2; /* no limit */ - g->gcdept += g->totalbytes - g->GCthreshold; - do { + l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; /* how much to work */ + lu_mem debt = g->totalbytes - g->GCthreshold; + lua_assert(g->gckind == KGC_NORMAL); + do { /* always perform at least one single step */ lim -= singlestep(L); - if (g->gcstate == GCSpause) - break; - } while (lim > 0); - if (g->gcstate != GCSpause) { - if (g->gcdept < GCSTEPSIZE) - g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/g->gcstepmul;*/ - else { - g->gcdept -= GCSTEPSIZE; - g->GCthreshold = g->totalbytes; - } - } - else { - lua_assert(g->totalbytes >= g->estimate); - setthreshold(g); - } + } while (lim > 0 && g->gcstate != GCSpause); + g->GCthreshold = (g->gcstate != GCSpause) + ? g->totalbytes + GCSTEPSIZE + : (g->totalbytes/100) * g->gcpause; + /* compensate if GC is "behind schedule" (has some debt to pay) */ + if (g->GCthreshold > debt) g->GCthreshold -= debt; } -void luaC_fullgc (lua_State *L) { +/* +** advances the garbage collector until it reaches a state allowed +** by 'statemask' +*/ +void luaC_runtilstate (lua_State *L, int statesmask) { global_State *g = G(L); - if (g->gcstate <= GCSpropagate) { - /* reset sweep marks to sweep all elements (returning them to white) */ - g->sweepstrgc = 0; - g->sweepgc = &g->rootgc; - /* reset other collector lists */ - g->gray = NULL; - g->grayagain = NULL; - g->weak = NULL; - g->gcstate = GCSsweepstring; - } - lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); - /* finish any pending sweep phase */ - while (g->gcstate != GCSfinalize) { - lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); + while (!testbit(statesmask, g->gcstate)) singlestep(L); - } - markroot(L); - while (g->gcstate != GCSpause) { - singlestep(L); - } - setthreshold(g); -} - - -void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { - global_State *g = G(L); - lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); - lua_assert(ttype(&o->gch) != LUA_TTABLE); - /* must keep invariant? */ - if (g->gcstate == GCSpropagate) - reallymarkobject(g, v); /* restore invariant */ - else /* don't mind */ - makewhite(g, o); /* mark as white just to avoid other barriers */ } -void luaC_barrierback (lua_State *L, Table *t) { - global_State *g = G(L); - GCObject *o = obj2gco(t); - lua_assert(isblack(o) && !isdead(g, o)); - lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); - black2gray(o); /* make table gray (again) */ - t->gclist = g->grayagain; - g->grayagain = o; -} - - -void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { +/* +** performs a full GC cycle; if "isememrgency", does not call +** finalizers (which could change stack positions) +*/ +void luaC_fullgc (lua_State *L, int isemergency) { global_State *g = G(L); - o->gch.next = g->rootgc; - g->rootgc = o; - o->gch.marked = luaC_white(g); - o->gch.tt = tt; + lua_assert(g->gckind == KGC_NORMAL); + g->gckind = isemergency ? KGC_EMERGENCY : KGC_FORCED; + if (g->gcstate == GCSpropagate) { /* marking phase? */ + /* must sweep all objects to turn them back to white + (as white does not change, nothing will be collected) */ + g->sweepstrgc = 0; + g->gcstate = GCSsweepstring; + } + /* finish any pending sweep phase */ + luaC_runtilstate(L, ~bit2mask(GCSsweepstring, GCSsweep)); + markroot(L); /* start a new collection */ + /* run collector up to finalizers */ + luaC_runtilstate(L, bitmask(GCSfinalize)); + g->gckind = KGC_NORMAL; + if (!isemergency) /* do not run finalizers during emergency GC */ + luaC_runtilstate(L, ~bitmask(GCSfinalize)); + g->GCthreshold = (g->totalbytes/100) * g->gcpause; } +/* }====================================================== */ -void luaC_linkupval (lua_State *L, UpVal *uv) { - global_State *g = G(L); - GCObject *o = obj2gco(uv); - o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ - g->rootgc = o; - if (isgray(o)) { - if (g->gcstate == GCSpropagate) { - gray2black(o); /* closed upvalues need barrier */ - luaC_barrier(L, uv, uv->v); - } - else { /* sweep phase: sweep it (turning it into white) */ - makewhite(g, o); - lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); - } - } -} @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.15.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lgc.h,v 2.27 2009/12/16 16:42:58 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -16,25 +16,26 @@ */ #define GCSpause 0 #define GCSpropagate 1 -#define GCSsweepstring 2 -#define GCSsweep 3 -#define GCSfinalize 4 +#define GCSatomic 2 +#define GCSsweepstring 3 +#define GCSsweep 4 +#define GCSfinalize 5 + /* -** some userful bit tricks +** some useful bit tricks */ -#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) -#define setbits(x,m) ((x) |= (m)) -#define testbits(x,m) ((x) & (m)) -#define bitmask(b) (1<<(b)) -#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) -#define l_setbit(x,b) setbits(x, bitmask(b)) -#define resetbit(x,b) resetbits(x, bitmask(b)) -#define testbit(x,b) testbits(x, bitmask(b)) +#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) +#define setbits(x,m) ((x) |= (m)) +#define testbits(x,m) ((x) & (m)) +#define bitmask(b) (1<<(b)) +#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) +#define l_setbit(x,b) setbits(x, bitmask(b)) +#define resetbit(x,b) resetbits(x, bitmask(b)) +#define testbit(x,b) testbits(x, bitmask(b)) #define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2))) #define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2))) -#define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2))) @@ -44,8 +45,7 @@ ** bit 1 - object is white (type 1) ** bit 2 - object is black ** bit 3 - for userdata: has been finalized -** bit 3 - for tables: has weak keys -** bit 4 - for tables: has weak values +** bit 4 - for userdata: it's in 2nd part of rootgc list or in tobefnz ** bit 5 - object is fixed (should not be collected) ** bit 6 - object is "super" fixed (only the main thread) */ @@ -55,14 +55,13 @@ #define WHITE1BIT 1 #define BLACKBIT 2 #define FINALIZEDBIT 3 -#define KEYWEAKBIT 3 -#define VALUEWEAKBIT 4 +#define SEPARATED 4 #define FIXEDBIT 5 #define SFIXEDBIT 6 #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) -#define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) +#define iswhite(x) testbits((x)->gch.marked, WHITEBITS) #define isblack(x) testbit((x)->gch.marked, BLACKBIT) #define isgray(x) (!isblack(x) && !iswhite(x)) @@ -77,10 +76,8 @@ #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) -#define luaC_checkGC(L) { \ - condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \ - if (G(L)->totalbytes >= G(L)->GCthreshold) \ - luaC_step(L); } +#define luaC_checkGC(L) \ + {condchangemem(L); if (G(L)->totalbytes >= G(L)->GCthreshold) luaC_step(L);} #define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ @@ -96,15 +93,17 @@ #define luaC_objbarriert(L,t,o) \ { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } -LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all); -LUAI_FUNC void luaC_callGCTM (lua_State *L); -LUAI_FUNC void luaC_freeall (lua_State *L); +LUAI_FUNC void luaC_separateudata (lua_State *L, int all); +LUAI_FUNC void luaC_freeallobjects (lua_State *L); LUAI_FUNC void luaC_step (lua_State *L); -LUAI_FUNC void luaC_fullgc (lua_State *L); -LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt); +LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); +LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); +LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, + GCObject **list, int offset); LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); +LUAI_FUNC void luaC_checkfinalizer (lua_State *L, Udata *u); #endif diff --git a/src/linit.c b/src/linit.c index c1f90dfa..a9430605 100644 --- a/src/linit.c +++ b/src/linit.c @@ -1,10 +1,18 @@ /* -** $Id: linit.c,v 1.14.1.1 2007/12/27 13:02:25 roberto Exp $ -** Initialization of libraries for lua.c +** $Id: linit.c,v 1.23 2009/12/22 15:32:50 roberto Exp $ +** Initialization of libraries for lua.c and other clients ** See Copyright Notice in lua.h */ +/* +** If you embed Lua in your program and need to open the standard +** libraries, call luaL_openlibs in your program. If you need a +** different set of libraries, copy this file to your project and edit +** it to suit your needs. +*/ + + #define linit_c #define LUA_LIB @@ -14,25 +22,54 @@ #include "lauxlib.h" -static const luaL_Reg lualibs[] = { - {"", luaopen_base}, +/* +** these libs are loaded by lua.c and are readily available to any Lua +** program +*/ +static const luaL_Reg loadedlibs[] = { + {"_G", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, + {LUA_BITLIBNAME, luaopen_bit}, {LUA_MATHLIBNAME, luaopen_math}, + {NULL, NULL} +}; + + +/* +** these libs are preloaded and must be required before used +*/ +static const luaL_Reg preloadedlibs[] = { {LUA_DBLIBNAME, luaopen_debug}, {NULL, NULL} }; LUALIB_API void luaL_openlibs (lua_State *L) { - const luaL_Reg *lib = lualibs; - for (; lib->func; lib++) { + const luaL_Reg *lib; + /* call open functions from 'loadedlibs' */ + for (lib = loadedlibs; lib->func; lib++) { lua_pushcfunction(L, lib->func); lua_pushstring(L, lib->name); lua_call(L, 1, 0); } + /* add open functions from 'preloadedlibs' into 'package.preload' table */ + lua_pushglobaltable(L); + luaL_findtable(L, 0, "package.preload", 0); + for (lib = preloadedlibs; lib->func; lib++) { + lua_pushcfunction(L, lib->func); + lua_setfield(L, -2, lib->name); + } + lua_pop(L, 1); /* remove package.preload table */ +#if defined(LUA_COMPAT_DEBUGLIB) + lua_pushglobaltable(L); + lua_getfield(L, -1, "require"); + lua_pushliteral(L, LUA_DBLIBNAME); + lua_call(L, 1, 0); /* call 'require"debug"' */ + lua_pop(L, 1); /* remove global table */ +#endif } diff --git a/src/liolib.c b/src/liolib.c index e79ed1cb..64fa43b4 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.73.1.3 2008/01/18 17:47:43 roberto Exp $ +** $Id: liolib.c,v 2.85 2009/12/17 16:20:01 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -19,6 +19,33 @@ #include "lualib.h" +/* +** lua_popen spawns a new process connected to the current one through +** the file streams. +*/ +#if !defined(lua_popen) + +#if defined(LUA_USE_POPEN) + +#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m)) +#define lua_pclose(L,file) ((void)L, pclose(file)) + +#elif defined(LUA_WIN) + +#define lua_popen(L,c,m) ((void)L, _popen(c,m)) +#define lua_pclose(L,file) ((void)L, _pclose(file)) + +#else + +#define lua_popen(L,c,m) ((void)((void)c, m), \ + luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) +#define lua_pclose(L,file) ((void)((void)L, file), -1) + +#endif + +#endif + + #define IO_INPUT 1 #define IO_OUTPUT 2 @@ -57,9 +84,8 @@ static void fileerror (lua_State *L, int arg, const char *filename) { static int io_type (lua_State *L) { void *ud; luaL_checkany(L, 1); - ud = lua_touserdata(L, 1); - lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); - if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) + ud = luaL_testudata(L, 1, LUA_FILEHANDLE); + if (ud == NULL) lua_pushnil(L); /* not a file */ else if (*((FILE **)ud) == NULL) lua_pushliteral(L, "closed file"); @@ -107,9 +133,14 @@ static int io_noclose (lua_State *L) { */ static int io_pclose (lua_State *L) { FILE **p = tofilep(L); - int ok = lua_pclose(L, *p); + int stat = lua_pclose(L, *p); *p = NULL; - return pushresult(L, ok, NULL); + if (stat == -1) /* error? */ + return pushresult(L, 0, NULL); + else { + lua_pushinteger(L, stat); + return 1; /* return status */ + } } @@ -161,7 +192,16 @@ static int io_tostring (lua_State *L) { static int io_open (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); - FILE **pf = newfile(L); + FILE **pf; + int i = 0; + /* check whether 'mode' matches '[rwa]%+?b?' */ + if (!(mode[i] != '\0' && strchr("rwa", mode[i++]) != NULL && + (mode[i] != '+' || ++i) && /* skip if char is '+' */ + (mode[i] != 'b' || ++i) && /* skip if char is 'b' */ + (mode[i] == '\0'))) + luaL_error(L, "invalid mode " LUA_QL("%s") + " (should match " LUA_QL("[rwa]%%+?b?") ")", mode); + pf = newfile(L); *pf = fopen(filename, mode); return (*pf == NULL) ? pushresult(L, 0, filename) : 1; } @@ -296,7 +336,7 @@ static int read_line (lua_State *L, FILE *f) { char *p = luaL_prepbuffer(&b); if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ luaL_pushresult(&b); /* close buffer */ - return (lua_objlen(L, -1) > 0); /* check whether read something */ + return (lua_rawlen(L, -1) > 0); /* check whether read something */ } l = strlen(p); if (l == 0 || p[l-1] != '\n') @@ -311,20 +351,21 @@ static int read_line (lua_State *L, FILE *f) { static int read_chars (lua_State *L, FILE *f, size_t n) { - size_t rlen; /* how much to read */ - size_t nr; /* number of chars actually read */ + size_t tbr = n; /* number of chars to be read */ + size_t rlen; /* how much to read in each cycle */ + size_t nr; /* number of chars actually read in each cycle */ luaL_Buffer b; luaL_buffinit(L, &b); rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ do { char *p = luaL_prepbuffer(&b); - if (rlen > n) rlen = n; /* cannot read more than asked */ + if (rlen > tbr) rlen = tbr; /* cannot read more than asked */ nr = fread(p, sizeof(char), rlen, f); luaL_addsize(&b, nr); - n -= nr; /* still have to read `n' chars */ - } while (n > 0 && nr == rlen); /* until end of count or eof */ + tbr -= nr; /* still have to read 'tbr' chars */ + } while (tbr > 0 && nr == rlen); /* until end of count or eof */ luaL_pushresult(&b); /* close buffer */ - return (n == 0 || lua_objlen(L, -1) > 0); + return (tbr < n); /* true iff read something */ } @@ -387,13 +428,13 @@ static int f_read (lua_State *L) { static int io_readline (lua_State *L) { FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); - int sucess; + int success; if (f == NULL) /* file is already closed? */ luaL_error(L, "file is already closed"); - sucess = read_line(L, f); + success = read_line(L, f); if (ferror(f)) return luaL_error(L, "%s", strerror(errno)); - if (sucess) return 1; + if (success) return 1; else { /* EOF */ if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ lua_settop(L, 0); @@ -408,7 +449,7 @@ static int io_readline (lua_State *L) { static int g_write (lua_State *L, FILE *f, int arg) { - int nargs = lua_gettop(L) - 1; + int nargs = lua_gettop(L) - arg; int status = 1; for (; nargs--; arg++) { if (lua_type(L, arg) == LUA_TNUMBER) { @@ -422,7 +463,8 @@ static int g_write (lua_State *L, FILE *f, int arg) { status = status && (fwrite(s, sizeof(char), l, f) == l); } } - return pushresult(L, status, NULL); + if (status) return 1; /* file handle already on stack top */ + else return pushresult(L, status, NULL); } @@ -432,7 +474,9 @@ static int io_write (lua_State *L) { static int f_write (lua_State *L) { - return g_write(L, tofile(L), 2); + FILE * f = tofile(L); + lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ + return g_write(L, f, 2); } @@ -531,7 +575,7 @@ static void newfenv (lua_State *L, lua_CFunction cls) { } -LUALIB_API int luaopen_io (lua_State *L) { +LUAMOD_API int luaopen_io (lua_State *L) { createmeta(L); /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ newfenv(L, io_fclose); @@ -1,11 +1,10 @@ /* -** $Id: llex.c,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: llex.c,v 2.34 2009/11/17 16:33:38 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ -#include <ctype.h> #include <locale.h> #include <string.h> @@ -14,6 +13,7 @@ #include "lua.h" +#include "lctype.h" #include "ldo.h" #include "llex.h" #include "lobject.h" @@ -29,35 +29,36 @@ - #define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') /* ORDER RESERVED */ -const char *const luaX_tokens [] = { +static const char *const luaX_tokens [] = { "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while", - "..", "...", "==", ">=", "<=", "~=", - "<number>", "<name>", "<string>", "<eof>", - NULL + "..", "...", "==", ">=", "<=", "~=", "<eof>", + "<number>", "<name>", "<string>" }; #define save_and_next(ls) (save(ls, ls->current), next(ls)) +static void lexerror (LexState *ls, const char *msg, int token); + + static void save (LexState *ls, int c) { Mbuffer *b = ls->buff; - if (b->n + 1 > b->buffsize) { + if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) { size_t newsize; - if (b->buffsize >= MAX_SIZET/2) - luaX_lexerror(ls, "lexical element too long", 0); - newsize = b->buffsize * 2; + if (luaZ_sizebuffer(b) >= MAX_SIZET/2) + lexerror(ls, "lexical element too long", 0); + newsize = luaZ_sizebuffer(b) * 2; luaZ_resizebuffer(ls->L, b, newsize); } - b->buffer[b->n++] = cast(char, c); + b->buffer[luaZ_bufflen(b)++] = cast(char, c); } @@ -72,17 +73,19 @@ void luaX_init (lua_State *L) { } -#define MAXSRC 80 - - const char *luaX_token2str (LexState *ls, int token) { if (token < FIRST_RESERVED) { lua_assert(token == cast(unsigned char, token)); - return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) : - luaO_pushfstring(ls->L, "%c", token); + return (lisprint(token)) ? luaO_pushfstring(ls->L, LUA_QL("%c"), token) : + luaO_pushfstring(ls->L, "char(%d)", token); + } + else { + const char *s = luaX_tokens[token - FIRST_RESERVED]; + if (token < TK_EOS) + return luaO_pushfstring(ls->L, LUA_QS, s); + else + return s; } - else - return luaX_tokens[token-FIRST_RESERVED]; } @@ -92,34 +95,39 @@ static const char *txtToken (LexState *ls, int token) { case TK_STRING: case TK_NUMBER: save(ls, '\0'); - return luaZ_buffer(ls->buff); + return luaO_pushfstring(ls->L, LUA_QS, luaZ_buffer(ls->buff)); default: return luaX_token2str(ls, token); } } -void luaX_lexerror (LexState *ls, const char *msg, int token) { - char buff[MAXSRC]; - luaO_chunkid(buff, getstr(ls->source), MAXSRC); +static void lexerror (LexState *ls, const char *msg, int token) { + char buff[LUA_IDSIZE]; + luaO_chunkid(buff, getstr(ls->source), LUA_IDSIZE); msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); if (token) - luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token)); + luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token)); luaD_throw(ls->L, LUA_ERRSYNTAX); } void luaX_syntaxerror (LexState *ls, const char *msg) { - luaX_lexerror(ls, msg, ls->t.token); + lexerror(ls, msg, ls->t.token); } TString *luaX_newstring (LexState *ls, const char *str, size_t l) { lua_State *L = ls->L; + TValue *o; /* entry for `str' */ TString *ts = luaS_newlstr(L, str, l); - TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */ - if (ttisnil(o)) + setsvalue2s(L, L->top++, ts); /* anchor string */ + o = luaH_setstr(L, ls->fs->h, ts); + if (ttisnil(o)) { setbvalue(o, 1); /* make sure `str' will not be collected */ + luaC_checkGC(L); + } + L->top--; return ts; } @@ -159,7 +167,7 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { static int check_next (LexState *ls, const char *set) { - if (!strchr(set, ls->current)) + if (ls->current == '\0' || !strchr(set, ls->current)) return 0; save_and_next(ls); return 1; @@ -174,29 +182,32 @@ static void buffreplace (LexState *ls, char from, char to) { } +#if !defined(getlocaledecpoint) +#define getlocaledecpoint() (localeconv()->decimal_point[0]) +#endif + static void trydecpoint (LexState *ls, SemInfo *seminfo) { /* format error: try to update decimal point separator */ - struct lconv *cv = localeconv(); char old = ls->decpoint; - ls->decpoint = (cv ? cv->decimal_point[0] : '.'); + ls->decpoint = getlocaledecpoint(); buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */ if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) { /* format error with correct decimal point: no more options */ buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ - luaX_lexerror(ls, "malformed number", TK_NUMBER); + lexerror(ls, "malformed number", TK_NUMBER); } } /* LUA_NUMBER */ static void read_numeral (LexState *ls, SemInfo *seminfo) { - lua_assert(isdigit(ls->current)); + lua_assert(lisdigit(ls->current)); do { save_and_next(ls); - } while (isdigit(ls->current) || ls->current == '.'); + } while (lisdigit(ls->current) || ls->current == '.'); if (check_next(ls, "Ee")) /* `E'? */ check_next(ls, "+-"); /* optional exponent sign */ - while (isalnum(ls->current) || ls->current == '_') + while (lislalnum(ls->current)) save_and_next(ls); save(ls, '\0'); buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ @@ -219,37 +230,18 @@ static int skip_sep (LexState *ls) { static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { - int cont = 0; - (void)(cont); /* avoid warnings when `cont' is not used */ save_and_next(ls); /* skip 2nd `[' */ if (currIsNewline(ls)) /* string starts with a newline? */ inclinenumber(ls); /* skip it */ for (;;) { switch (ls->current) { case EOZ: - luaX_lexerror(ls, (seminfo) ? "unfinished long string" : - "unfinished long comment", TK_EOS); + lexerror(ls, (seminfo) ? "unfinished long string" : + "unfinished long comment", TK_EOS); break; /* to avoid warnings */ -#if defined(LUA_COMPAT_LSTR) - case '[': { - if (skip_sep(ls) == sep) { - save_and_next(ls); /* skip 2nd `[' */ - cont++; -#if LUA_COMPAT_LSTR == 1 - if (sep == 0) - luaX_lexerror(ls, "nesting of [[...]] is deprecated", '['); -#endif - } - break; - } -#endif case ']': { if (skip_sep(ls) == sep) { save_and_next(ls); /* skip 2nd `]' */ -#if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2 - cont--; - if (sep == 0 && cont >= 0) break; -#endif goto endloop; } break; @@ -273,19 +265,61 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { } +static int hexavalue (int c) { + if (lisdigit(c)) return c - '0'; + else if (lisupper(c)) return c - 'A' + 10; + else return c - 'a' + 10; +} + + +static int readhexaesc (LexState *ls) { + int c1, c2 = EOZ; + if (!lisxdigit(c1 = next(ls)) || !lisxdigit(c2 = next(ls))) { + luaZ_resetbuffer(ls->buff); /* prepare error message */ + save(ls, '\\'); save(ls, 'x'); + if (c1 != EOZ) save(ls, c1); + if (c2 != EOZ) save(ls, c2); + lexerror(ls, "hexadecimal digit expected", TK_STRING); + } + return (hexavalue(c1) << 4) + hexavalue(c2); +} + + +static int readdecesc (LexState *ls) { + int c1 = ls->current, c2, c3; + int c = c1 - '0'; + if (lisdigit(c2 = next(ls))) { + c = 10*c + c2 - '0'; + if (lisdigit(c3 = next(ls))) { + c = 10*c + c3 - '0'; + if (c > UCHAR_MAX) { + luaZ_resetbuffer(ls->buff); /* prepare error message */ + save(ls, '\\'); + save(ls, c1); save(ls, c2); save(ls, c3); + lexerror(ls, "decimal escape too large", TK_STRING); + } + return c; + } + } + /* else, has read one character that was not a digit */ + zungetc(ls->z); /* return it to input stream */ + return c; +} + + static void read_string (LexState *ls, int del, SemInfo *seminfo) { save_and_next(ls); while (ls->current != del) { switch (ls->current) { case EOZ: - luaX_lexerror(ls, "unfinished string", TK_EOS); + lexerror(ls, "unfinished string", TK_EOS); continue; /* to avoid warnings */ case '\n': case '\r': - luaX_lexerror(ls, "unfinished string", TK_STRING); + lexerror(ls, "unfinished string", TK_STRING); continue; /* to avoid warnings */ - case '\\': { - int c; + case '\\': { /* escape sequences */ + int c; /* final character to be saved */ next(ls); /* do not save the `\' */ switch (ls->current) { case 'a': c = '\a'; break; @@ -295,28 +329,20 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) { case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'v': c = '\v'; break; - case '\n': /* go through */ + case 'x': c = readhexaesc(ls); break; + case '\n': case '\r': save(ls, '\n'); inclinenumber(ls); continue; case EOZ: continue; /* will raise an error next loop */ default: { - if (!isdigit(ls->current)) - save_and_next(ls); /* handles \\, \", \', and \? */ - else { /* \xxx */ - int i = 0; - c = 0; - do { - c = 10*c + (ls->current-'0'); - next(ls); - } while (++i<3 && isdigit(ls->current)); - if (c > UCHAR_MAX) - luaX_lexerror(ls, "escape sequence too large", TK_STRING); - save(ls, c); - } - continue; + if (!lisdigit(ls->current)) + c = ls->current; /* handles \\, \", \', and \? */ + else /* digital escape \ddd */ + c = readdecesc(ls); + break; } } - save(ls, c); next(ls); + save(ls, c); continue; } default: @@ -364,7 +390,7 @@ static int llex (LexState *ls, SemInfo *seminfo) { return TK_STRING; } else if (sep == -1) return '['; - else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING); + else lexerror(ls, "invalid long string delimiter", TK_STRING); } case '=': { next(ls); @@ -398,7 +424,7 @@ static int llex (LexState *ls, SemInfo *seminfo) { return TK_DOTS; /* ... */ else return TK_CONCAT; /* .. */ } - else if (!isdigit(ls->current)) return '.'; + else if (!lisdigit(ls->current)) return '.'; else { read_numeral(ls, seminfo); return TK_NUMBER; @@ -408,21 +434,21 @@ static int llex (LexState *ls, SemInfo *seminfo) { return TK_EOS; } default: { - if (isspace(ls->current)) { + if (lisspace(ls->current)) { lua_assert(!currIsNewline(ls)); next(ls); continue; } - else if (isdigit(ls->current)) { + else if (lisdigit(ls->current)) { read_numeral(ls, seminfo); return TK_NUMBER; } - else if (isalpha(ls->current) || ls->current == '_') { + else if (lislalpha(ls->current)) { /* identifier or reserved word */ TString *ts; do { save_and_next(ls); - } while (isalnum(ls->current) || ls->current == '_'); + } while (lislalnum(ls->current)); ts = luaX_newstring(ls, luaZ_buffer(ls->buff), luaZ_bufflen(ls->buff)); if (ts->tsv.reserved > 0) /* reserved word? */ @@ -454,8 +480,9 @@ void luaX_next (LexState *ls) { } -void luaX_lookahead (LexState *ls) { +int luaX_lookahead (LexState *ls) { lua_assert(ls->lookahead.token == TK_EOS); ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); + return ls->lookahead.token; } @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.58.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: llex.h,v 1.62 2009/10/11 20:02:19 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -28,18 +28,14 @@ enum RESERVED { TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, /* other terminal symbols */ - TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER, - TK_NAME, TK_STRING, TK_EOS + TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_EOS, + TK_NUMBER, TK_NAME, TK_STRING }; /* number of reserved words */ #define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) -/* array with token `names' */ -LUAI_DATA const char *const luaX_tokens []; - - typedef union { lua_Number r; TString *ts; @@ -62,6 +58,7 @@ typedef struct LexState { struct lua_State *L; ZIO *z; /* input stream */ Mbuffer *buff; /* buffer for tokens */ + struct Varlist *varl; /* list of all active local variables */ TString *source; /* current source name */ char decpoint; /* locale decimal point */ } LexState; @@ -72,8 +69,7 @@ LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source); LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); LUAI_FUNC void luaX_next (LexState *ls); -LUAI_FUNC void luaX_lookahead (LexState *ls); -LUAI_FUNC void luaX_lexerror (LexState *ls, const char *msg, int token); +LUAI_FUNC int luaX_lookahead (LexState *ls); LUAI_FUNC void luaX_syntaxerror (LexState *ls, const char *s); LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); diff --git a/src/llimits.h b/src/llimits.h index ca8dcb72..6bf49840 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.69.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: llimits.h,v 1.77 2009/12/17 12:50:20 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -15,7 +15,7 @@ #include "lua.h" -typedef LUAI_UINT32 lu_int32; +typedef unsigned LUA_INT32 lu_int32; typedef LUAI_UMEM lu_mem; @@ -44,6 +44,10 @@ typedef unsigned char lu_byte; /* type to ensure maximum alignment */ +#if !defined(LUAI_USER_ALIGNMENT_T) +#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; } +#endif + typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; @@ -52,34 +56,47 @@ typedef LUAI_UACNUMBER l_uacNumber; /* internal assertions for in-house debugging */ -#ifdef lua_assert - +#if defined(lua_assert) #define check_exp(c,e) (lua_assert(c), (e)) -#define api_check(l,e) lua_assert(e) - #else - #define lua_assert(c) ((void)0) #define check_exp(c,e) (e) -#define api_check luai_apicheck +#endif +/* +** assertion for checking API calls +*/ +#if defined(LUA_USE_APICHECK) +#include <assert.h> +#define luai_apicheck(L,e) { (void)L; assert(e); } +#elif !defined(luai_apicheck) +#define luai_apicheck(L,e) lua_assert(e) #endif +#define api_check(l,e,msg) luai_apicheck(l,(e) && msg) + -#ifndef UNUSED +#if !defined(UNUSED) #define UNUSED(x) ((void)(x)) /* to avoid warnings */ #endif -#ifndef cast #define cast(t, exp) ((t)(exp)) -#endif #define cast_byte(i) cast(lu_byte, (i)) #define cast_num(i) cast(lua_Number, (i)) #define cast_int(i) cast(int, (i)) +/* +** maximum depth for nested C calls and syntactical nested non-terminals +** in a program. (Value must fit in an unsigned short int.) +*/ +#if !defined(LUAI_MAXCCALLS) +#define LUAI_MAXCCALLS 200 +#endif + + /* ** type for virtual-machine instructions @@ -95,34 +112,73 @@ typedef lu_int32 Instruction; /* minimum size for the string table (must be power of 2) */ -#ifndef MINSTRTABSIZE +#if !defined(MINSTRTABSIZE) #define MINSTRTABSIZE 32 #endif /* minimum size for string buffer */ -#ifndef LUA_MINBUFFER +#if !defined(LUA_MINBUFFER) #define LUA_MINBUFFER 32 #endif -#ifndef lua_lock -#define lua_lock(L) ((void) 0) +#if !defined(lua_lock) +#define lua_lock(L) ((void) 0) #define lua_unlock(L) ((void) 0) #endif -#ifndef luai_threadyield +#if !defined(luai_threadyield) #define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} #endif /* +** these macros allow user-specific actions on threads when you defined +** LUAI_EXTRASPACE and need to do something extra when a thread is +** created/deleted/resumed/yielded. +*/ +#if !defined(luai_userstateopen) +#define luai_userstateopen(L) ((void)L) +#endif + +#if !defined(luai_userstateclose) +#define luai_userstateclose(L) ((void)L) +#endif + +#if !defined(luai_userstatethread) +#define luai_userstatethread(L,L1) ((void)L) +#endif + +#if !defined(luai_userstatefree) +#define luai_userstatefree(L) ((void)L) +#endif + +#if !defined(luai_userstateresume) +#define luai_userstateresume(L,n) ((void)L) +#endif + +#if !defined(luai_userstateyield) +#define luai_userstateyield(L,n) ((void)L) +#endif + + + + +/* ** macro to control inclusion of some hard tests on stack reallocation -*/ -#ifndef HARDSTACKTESTS -#define condhardstacktests(x) ((void)0) +*/ +#if !defined(HARDSTACKTESTS) +#define condmovestack(L) ((void)0) +#else +/* realloc stack keeping its size */ +#define condmovestack(L) luaD_reallocstack((L), (L)->stacksize) +#endif + +#if !defined(HARDMEMTESTS) +#define condchangemem(L) condmovestack(L) #else -#define condhardstacktests(x) x +#define condchangemem(L) luaC_fullgc(L, 0) #endif #endif diff --git a/src/lmathlib.c b/src/lmathlib.c index 441fbf73..27e6847e 100644 --- a/src/lmathlib.c +++ b/src/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.67.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lmathlib.c,v 1.74 2009/11/24 12:05:44 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -112,11 +112,24 @@ static int math_pow (lua_State *L) { } static int math_log (lua_State *L) { - lua_pushnumber(L, log(luaL_checknumber(L, 1))); + lua_Number x = luaL_checknumber(L, 1); + lua_Number res; + if (lua_isnoneornil(L, 2)) + res = log(x); + else { + lua_Number base = luaL_checknumber(L, 2); + if (base == 10.0) res = log10(x); + else res = log(x)/log(base); + } + lua_pushnumber(L, res); return 1; } static int math_log10 (lua_State *L) { +#if !defined(LUA_COMPAT_LOG10) + luaL_error(L, "function " LUA_QL("log10") + " is deprecated; use log(x, 10) instead"); +#endif lua_pushnumber(L, log10(luaL_checknumber(L, 1))); return 1; } @@ -188,16 +201,16 @@ static int math_random (lua_State *L) { break; } case 1: { /* only upper limit */ - int u = luaL_checkint(L, 1); - luaL_argcheck(L, 1<=u, 1, "interval is empty"); - lua_pushnumber(L, floor(r*u)+1); /* int between 1 and `u' */ + lua_Number u = luaL_checknumber(L, 1); + luaL_argcheck(L, 1.0 <= u, 1, "interval is empty"); + lua_pushnumber(L, floor(r*u) + 1.0); /* int between 1 and `u' */ break; } case 2: { /* lower and upper limits */ - int l = luaL_checkint(L, 1); - int u = luaL_checkint(L, 2); - luaL_argcheck(L, l<=u, 2, "interval is empty"); - lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */ + lua_Number l = luaL_checknumber(L, 1); + lua_Number u = luaL_checknumber(L, 2); + luaL_argcheck(L, l <= u, 2, "interval is empty"); + lua_pushnumber(L, floor(r*(u-l+1)) + l); /* int between `l' and `u' */ break; } default: return luaL_error(L, "wrong number of arguments"); @@ -208,6 +221,7 @@ static int math_random (lua_State *L) { static int math_randomseed (lua_State *L) { srand(luaL_checkint(L, 1)); + (void)rand(); /* discard first value to avoid undesirable correlations */ return 0; } @@ -248,16 +262,12 @@ static const luaL_Reg mathlib[] = { /* ** Open math library */ -LUALIB_API int luaopen_math (lua_State *L) { +LUAMOD_API int luaopen_math (lua_State *L) { luaL_register(L, LUA_MATHLIBNAME, mathlib); lua_pushnumber(L, PI); lua_setfield(L, -2, "pi"); lua_pushnumber(L, HUGE_VAL); lua_setfield(L, -2, "huge"); -#if defined(LUA_COMPAT_MOD) - lua_getfield(L, -1, "fmod"); - lua_setfield(L, -2, "mod"); -#endif return 1; } @@ -1,5 +1,5 @@ /* -** $Id: lmem.c,v 1.70.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lmem.c,v 1.74 2009/12/16 16:42:58 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -14,6 +14,7 @@ #include "ldebug.h" #include "ldo.h" +#include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" @@ -25,12 +26,11 @@ ** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); ** (`osize' is the old size, `nsize' is the new size) ** -** Lua ensures that (ptr == NULL) iff (osize == 0). -** -** * frealloc(ud, NULL, 0, x) creates a new block of size `x' +** * frealloc(ud, NULL, x, s) creates a new block of size `s' (no +** matter 'x'). ** ** * frealloc(ud, p, x, 0) frees the block `p' -** (in this specific case, frealloc must return NULL). +** (in this specific case, frealloc must return NULL); ** particularly, frealloc(ud, NULL, 0, 0) does nothing ** (which is equivalent to free(NULL) in ANSI C) ** @@ -44,12 +44,12 @@ void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, - int limit, const char *errormsg) { + int limit, const char *what) { void *newblock; int newsize; if (*size >= limit/2) { /* cannot double it? */ if (*size >= limit) /* cannot grow even a little? */ - luaG_runerror(L, errormsg); + luaG_runerror(L, "too many %s (limit is %d)", what, limit); newsize = limit; /* still have at least one free place */ } else { @@ -74,13 +74,26 @@ void *luaM_toobig (lua_State *L) { ** generic allocation routine. */ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { + void *newblock; global_State *g = G(L); - lua_assert((osize == 0) == (block == NULL)); - block = (*g->frealloc)(g->ud, block, osize, nsize); - if (block == NULL && nsize > 0) - luaD_throw(L, LUA_ERRMEM); - lua_assert((nsize == 0) == (block == NULL)); - g->totalbytes = (g->totalbytes - osize) + nsize; - return block; + size_t realosize = (block) ? osize : 0; + lua_assert((realosize == 0) == (block == NULL)); +#if defined(HARDMEMTESTS) + if (nsize > realosize && g->GCthreshold != MAX_LUMEM) + luaC_fullgc(L, 1); /* force a GC whenever possible */ +#endif + newblock = (*g->frealloc)(g->ud, block, osize, nsize); + if (newblock == NULL && nsize > 0) { + lua_assert(nsize > realosize); /* cannot fail when shrinking a block */ + if (g->GCthreshold != MAX_LUMEM) { + luaC_fullgc(L, 1); /* try to free some memory... */ + newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ + } + if (newblock == NULL) + luaD_throw(L, LUA_ERRMEM); + } + lua_assert((nsize == 0) == (newblock == NULL)); + g->totalbytes = (g->totalbytes - realosize) + nsize; + return newblock; } @@ -1,5 +1,5 @@ /* -** $Id: lmem.h,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lmem.h,v 1.35 2009/12/16 16:42:58 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -23,13 +23,15 @@ #define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) #define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) -#define luaM_freearray(L, b, n, t) luaM_reallocv(L, (b), n, 0, sizeof(t)) +#define luaM_freearray(L, b, n) luaM_reallocv(L, (b), n, 0, sizeof((b)[0])) -#define luaM_malloc(L,t) luaM_realloc_(L, NULL, 0, (t)) +#define luaM_malloc(L,s) luaM_realloc_(L, NULL, 0, (s)) #define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t))) #define luaM_newvector(L,n,t) \ cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t))) +#define luaM_newobject(L,tag,s) luaM_realloc_(L, NULL, tag, (s)) + #define luaM_growvector(L,v,nelems,size,t,limit,e) \ if ((nelems)+1 > (size)) \ ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) @@ -37,13 +39,14 @@ #define luaM_reallocvector(L, v,oldn,n,t) \ ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) +LUAI_FUNC void *luaM_toobig (lua_State *L); +/* not to be called directly */ LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, size_t size); -LUAI_FUNC void *luaM_toobig (lua_State *L); LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elem, int limit, - const char *errormsg); + const char *what); #endif diff --git a/src/loadlib.c b/src/loadlib.c index 0d401eba..8b2d6911 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.52.1.3 2008/08/06 13:29:28 roberto Exp $ +** $Id: loadlib.c,v 1.73 2010/01/06 14:35:17 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -22,6 +22,43 @@ #include "lualib.h" +/* +** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment +** variables that Lua check to set its paths. +*/ +#if !defined(LUA_PATH_VAR) +#define LUA_PATH_VAR "LUA_PATH" +#endif + +#if !defined(LUA_CPATH_VAR) +#define LUA_CPATH_VAR "LUA_CPATH" +#endif + + +/* +** LUA_PATH_SEP is the character that separates templates in a path. +** LUA_PATH_MARK is the string that marks the substitution points in a +** template. +** LUA_EXEC_DIR in a Windows path is replaced by the executable's +** directory. +** LUA_IGMARK is a mark to ignore all before it when building the +** luaopen_ function name. +*/ +#if !defined (LUA_PATH_SEP) +#define LUA_PATH_SEP ";" +#endif +#if !defined (LUA_PATH_MARK) +#define LUA_PATH_MARK "?" +#endif +#if !defined (LUA_EXEC_DIR) +#define LUA_EXEC_DIR "!" +#endif +#if !defined (LUA_IGMARK) +#define LUA_IGMARK "-" +#endif + + + /* prefix for open functions in C libraries */ #define LUA_POF "luaopen_" @@ -42,13 +79,16 @@ #define setprogdir(L) ((void)0) +/* +** system-dependent functions +*/ static void ll_unloadlib (void *lib); -static void *ll_load (lua_State *L, const char *path); +static void *ll_load (lua_State *L, const char *path, int seeglb); static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); -#if defined(LUA_DL_DLOPEN) +#if defined(LUA_USE_DLOPEN) /* ** {======================================================================== ** This is an implementation of loadlib based on the dlfcn interface. @@ -65,8 +105,8 @@ static void ll_unloadlib (void *lib) { } -static void *ll_load (lua_State *L, const char *path) { - void *lib = dlopen(path, RTLD_NOW); +static void *ll_load (lua_State *L, const char *path, int seeglb) { + void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : 0)); if (lib == NULL) lua_pushstring(L, dlerror()); return lib; } @@ -89,8 +129,6 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { ** ======================================================================= */ -#include <windows.h> - #undef setprogdir @@ -98,12 +136,12 @@ static void setprogdir (lua_State *L) { char buff[MAX_PATH + 1]; char *lb; DWORD nsize = sizeof(buff)/sizeof(char); - DWORD n = GetModuleFileNameA(NULL, buff, nsize); + DWORD n = GetModuleFileName(NULL, buff, nsize); if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) luaL_error(L, "unable to get ModuleFileName"); else { *lb = '\0'; - luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); + luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff); lua_remove(L, -2); /* remove original string */ } } @@ -112,7 +150,7 @@ static void setprogdir (lua_State *L) { static void pusherror (lua_State *L) { int error = GetLastError(); char buffer[128]; - if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, + if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, buffer, sizeof(buffer), NULL)) lua_pushstring(L, buffer); else @@ -124,8 +162,9 @@ static void ll_unloadlib (void *lib) { } -static void *ll_load (lua_State *L, const char *path) { - HINSTANCE lib = LoadLibraryA(path); +static void *ll_load (lua_State *L, const char *path, int seeglb) { + HINSTANCE lib = LoadLibrary(path); + (void)(seeglb); /* symbols are 'global' by default? */ if (lib == NULL) pusherror(L); return lib; } @@ -144,7 +183,7 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { #elif defined(LUA_DL_DYLD) /* ** {====================================================================== -** Native Mac OS X / Darwin Implementation +** Old native Mac OS X - only for old versions of Mac OS (< 10.3) ** ======================================================================= */ @@ -188,7 +227,7 @@ static void ll_unloadlib (void *lib) { } -static void *ll_load (lua_State *L, const char *path) { +static void *ll_load (lua_State *L, const char *path, int seeglb) { NSObjectFileImage img; NSObjectFileImageReturnCode ret; /* this would be a rare case, but prevents crashing if it happens */ @@ -198,8 +237,10 @@ static void *ll_load (lua_State *L, const char *path) { } ret = NSCreateObjectFileImageFromFile(path, &img); if (ret == NSObjectFileImageSuccess) { - NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | - NSLINKMODULE_OPTION_RETURN_ON_ERROR); + NSModule mod = NSLinkModule(img, + path, + NSLINKMODULE_OPTION_RETURN_ON_ERROR | + (seeglb ? 0 : NSLINKMODULE_OPTION_PRIVATE)); NSDestroyObjectFileImage(img); if (mod == NULL) pusherror(L); return mod; @@ -237,19 +278,19 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { static void ll_unloadlib (void *lib) { - (void)lib; /* to avoid warnings */ + (void)(lib); /* to avoid warnings */ } -static void *ll_load (lua_State *L, const char *path) { - (void)path; /* to avoid warnings */ +static void *ll_load (lua_State *L, const char *path, int seeglb) { + (void)(path); /* to avoid warnings */ lua_pushliteral(L, DLMSG); return NULL; } static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { - (void)lib; (void)sym; /* to avoid warnings */ + (void)(lib); (void)(sym); /* to avoid warnings */ lua_pushliteral(L, DLMSG); return NULL; } @@ -266,7 +307,7 @@ static void **ll_register (lua_State *L, const char *path) { if (!lua_isnil(L, -1)) /* is there an entry? */ plib = (void **)lua_touserdata(L, -1); else { /* no entry yet; create one */ - lua_pop(L, 1); + lua_pop(L, 1); /* remove result from gettable */ plib = (void **)lua_newuserdata(L, sizeof(const void *)); *plib = NULL; luaL_getmetatable(L, "_LOADLIB"); @@ -293,15 +334,18 @@ static int gctm (lua_State *L) { static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { void **reg = ll_register(L, path); - if (*reg == NULL) *reg = ll_load(L, path); - if (*reg == NULL) - return ERRLIB; /* unable to load library */ + if (*reg == NULL) *reg = ll_load(L, path, *sym == '*'); + if (*reg == NULL) return ERRLIB; /* unable to load library */ + if (*sym == '*') { /* loading only library (no function)? */ + lua_pushboolean(L, 1); /* return 'true' */ + return 0; /* no errors */ + } else { lua_CFunction f = ll_sym(L, *reg, sym); if (f == NULL) return ERRFUNC; /* unable to find function */ - lua_pushcfunction(L, f); - return 0; /* return function */ + lua_pushcfunction(L, f); /* else return function */ + return 0; /* no errors */ } } @@ -339,27 +383,21 @@ static int readable (const char *filename) { static const char *pushnexttemplate (lua_State *L, const char *path) { const char *l; - while (*path == *LUA_PATHSEP) path++; /* skip separators */ + while (*path == *LUA_PATH_SEP) path++; /* skip separators */ if (*path == '\0') return NULL; /* no more templates */ - l = strchr(path, *LUA_PATHSEP); /* find next separator */ + l = strchr(path, *LUA_PATH_SEP); /* find next separator */ if (l == NULL) l = path + strlen(path); lua_pushlstring(L, path, l - path); /* template */ return l; } -static const char *findfile (lua_State *L, const char *name, - const char *pname) { - const char *path; - name = luaL_gsub(L, name, ".", LUA_DIRSEP); - lua_getfield(L, LUA_ENVIRONINDEX, pname); - path = lua_tostring(L, -1); - if (path == NULL) - luaL_error(L, LUA_QL("package.%s") " must be a string", pname); +static const char *searchpath (lua_State *L, const char *name, + const char *path) { lua_pushliteral(L, ""); /* error accumulator */ while ((path = pushnexttemplate(L, path)) != NULL) { - const char *filename; - filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); + const char *filename = luaL_gsub(L, lua_tostring(L, -1), + LUA_PATH_MARK, name); lua_remove(L, -2); /* remove path template */ if (readable(filename)) /* does file exist and is readable? */ return filename; /* return that file name */ @@ -371,6 +409,29 @@ static const char *findfile (lua_State *L, const char *name, } +static int ll_searchpath (lua_State *L) { + const char *f = searchpath(L, luaL_checkstring(L, 1), luaL_checkstring(L, 2)); + if (f != NULL) return 1; + else { /* error message is on top of the stack */ + lua_pushnil(L); + lua_insert(L, -2); + return 2; /* return nil + error message */ + } +} + + +static const char *findfile (lua_State *L, const char *name, + const char *pname) { + const char *path; + name = luaL_gsub(L, name, ".", LUA_DIRSEP); + lua_getfield(L, LUA_ENVIRONINDEX, pname); + path = lua_tostring(L, -1); + if (path == NULL) + luaL_error(L, LUA_QL("package.%s") " must be a string", pname); + return searchpath(L, name, path); +} + + static void loaderror (lua_State *L, const char *filename) { luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s", lua_tostring(L, 1), filename, lua_tostring(L, -1)); @@ -382,37 +443,34 @@ static int loader_Lua (lua_State *L) { const char *name = luaL_checkstring(L, 1); filename = findfile(L, name, "path"); if (filename == NULL) return 1; /* library not found in this path */ - if (luaL_loadfile(L, filename) != 0) + if (luaL_loadfile(L, filename) != LUA_OK) loaderror(L, filename); return 1; /* library loaded successfully */ } -static const char *mkfuncname (lua_State *L, const char *modname) { +static int loadfunc(lua_State *L, const char *filename, const char *modname) { const char *funcname; const char *mark = strchr(modname, *LUA_IGMARK); if (mark) modname = mark + 1; funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); funcname = lua_pushfstring(L, POF"%s", funcname); lua_remove(L, -2); /* remove 'gsub' result */ - return funcname; + return ll_loadfunc(L, filename, funcname); } static int loader_C (lua_State *L) { - const char *funcname; const char *name = luaL_checkstring(L, 1); const char *filename = findfile(L, name, "cpath"); if (filename == NULL) return 1; /* library not found in this path */ - funcname = mkfuncname(L, name); - if (ll_loadfunc(L, filename, funcname) != 0) + if (loadfunc(L, filename, name) != 0) loaderror(L, filename); return 1; /* library loaded successfully */ } static int loader_Croot (lua_State *L) { - const char *funcname; const char *filename; const char *name = luaL_checkstring(L, 1); const char *p = strchr(name, '.'); @@ -421,8 +479,7 @@ static int loader_Croot (lua_State *L) { lua_pushlstring(L, name, p - name); filename = findfile(L, lua_tostring(L, -1), "cpath"); if (filename == NULL) return 1; /* root not found */ - funcname = mkfuncname(L, name); - if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { + if ((stat = loadfunc(L, filename, name)) != 0) { if (stat != ERRFUNC) loaderror(L, filename); /* real error */ lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, name, filename); @@ -502,7 +559,7 @@ static int ll_require (lua_State *L) { ** 'module' function ** ======================================================= */ - + static void setfenv (lua_State *L) { lua_Debug ar; @@ -510,9 +567,9 @@ static void setfenv (lua_State *L) { lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ lua_iscfunction(L, -1)) luaL_error(L, LUA_QL("module") " not called from a Lua function"); - lua_pushvalue(L, -2); + lua_pushvalue(L, -2); /* copy new environment table to top */ lua_setfenv(L, -2); - lua_pop(L, 1); + lua_pop(L, 1); /* remove function */ } @@ -549,7 +606,8 @@ static int ll_module (lua_State *L) { if (!lua_istable(L, -1)) { /* not found? */ lua_pop(L, 1); /* remove previous result */ /* try global variable (and create one if it does not exist) */ - if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL) + lua_pushglobaltable(L); + if (luaL_findtable(L, 0, modname, 1) != NULL) return luaL_error(L, "name conflict for module " LUA_QS, modname); lua_pushvalue(L, -1); lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ @@ -565,7 +623,7 @@ static int ll_module (lua_State *L) { lua_pushvalue(L, -1); setfenv(L); dooptions(L, loaded - 1); - return 0; + return 1; } @@ -576,7 +634,7 @@ static int ll_seeall (lua_State *L) { lua_pushvalue(L, -1); lua_setmetatable(L, 1); } - lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_pushglobaltable(L); lua_setfield(L, -2, "__index"); /* mt.__index = _G */ return 0; } @@ -596,8 +654,8 @@ static void setpath (lua_State *L, const char *fieldname, const char *envname, lua_pushstring(L, def); /* use default */ else { /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ - path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP, - LUA_PATHSEP AUXMARK LUA_PATHSEP); + path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP, + LUA_PATH_SEP AUXMARK LUA_PATH_SEP); luaL_gsub(L, path, AUXMARK, def); lua_remove(L, -2); } @@ -608,6 +666,7 @@ static void setpath (lua_State *L, const char *fieldname, const char *envname, static const luaL_Reg pk_funcs[] = { {"loadlib", ll_loadlib}, + {"searchpath", ll_searchpath}, {"seeall", ll_seeall}, {NULL, NULL} }; @@ -624,7 +683,7 @@ static const lua_CFunction loaders[] = {loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; -LUALIB_API int luaopen_package (lua_State *L) { +LUAMOD_API int luaopen_package (lua_State *L) { int i; /* create new type _LOADLIB */ luaL_newmetatable(L, "_LOADLIB"); @@ -632,25 +691,20 @@ LUALIB_API int luaopen_package (lua_State *L) { lua_setfield(L, -2, "__gc"); /* create `package' table */ luaL_register(L, LUA_LOADLIBNAME, pk_funcs); -#if defined(LUA_COMPAT_LOADLIB) - lua_getfield(L, -1, "loadlib"); - lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); -#endif - lua_pushvalue(L, -1); - lua_replace(L, LUA_ENVIRONINDEX); + lua_copy(L, -1, LUA_ENVIRONINDEX); /* create `loaders' table */ - lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1); + lua_createtable(L, sizeof(loaders)/sizeof(loaders[0]) - 1, 0); /* fill it with pre-defined loaders */ for (i=0; loaders[i] != NULL; i++) { lua_pushcfunction(L, loaders[i]); lua_rawseti(L, -2, i+1); } lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ - setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */ - setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */ + setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT); /* set field `path' */ + setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT); /* set field `cpath' */ /* store config information */ - lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" - LUA_EXECDIR "\n" LUA_IGMARK); + lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" + LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); lua_setfield(L, -2, "config"); /* set field `loaded' */ luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); @@ -658,7 +712,7 @@ LUALIB_API int luaopen_package (lua_State *L) { /* set field `preload' */ lua_newtable(L); lua_setfield(L, -2, "preload"); - lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_pushglobaltable(L); luaL_register(L, NULL, ll_funcs); /* open lib into global table */ lua_pop(L, 1); return 1; /* return 'package' table */ diff --git a/src/lobject.c b/src/lobject.c index 4ff50732..8f5c5691 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,10 +1,9 @@ /* -** $Id: lobject.c,v 2.22.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lobject.c,v 2.34 2009/11/26 11:39:20 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ -#include <ctype.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> @@ -15,6 +14,8 @@ #include "lua.h" +#include "lctype.h" +#include "ldebug.h" #include "ldo.h" #include "lmem.h" #include "lobject.h" @@ -24,7 +25,7 @@ -const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL}; +LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT}; /* @@ -32,26 +33,26 @@ const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL}; ** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if ** eeeee != 0 and (xxx) otherwise. */ -int luaO_int2fb (unsigned int x) { - int e = 0; /* expoent */ - while (x >= 16) { +int luaO_int2fb (lu_int32 x) { + int e = 0; /* exponent */ + if (x < 8) return x; + while (x >= 0x10) { x = (x+1) >> 1; e++; } - if (x < 8) return x; - else return ((e+1) << 3) | (cast_int(x) - 8); + return ((e+1) << 3) | (cast_int(x) - 8); } /* converts back */ int luaO_fb2int (int x) { - int e = (x >> 3) & 31; + int e = (x >> 3) & 0x1f; if (e == 0) return x; - else return ((x & 7)+8) << (e - 1); + else return ((x & 7) + 8) << (e - 1); } -int luaO_log2 (unsigned int x) { +int luaO_ceillog2 (unsigned int x) { static const lu_byte log_2[256] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, @@ -62,10 +63,10 @@ int luaO_log2 (unsigned int x) { 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 }; - int l = -1; + int l = 0; + x--; while (x >= 256) { l += 8; x >>= 8; } return l + log_2[x]; - } @@ -87,6 +88,20 @@ int luaO_rawequalObj (const TValue *t1, const TValue *t2) { } +lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) { + switch (op) { + case LUA_OPADD: return luai_numadd(NULL, v1, v2); + case LUA_OPSUB: return luai_numsub(NULL, v1, v2); + case LUA_OPMUL: return luai_nummul(NULL, v1, v2); + case LUA_OPDIV: return luai_numdiv(NULL, v1, v2); + case LUA_OPMOD: return luai_nummod(NULL, v1, v2); + case LUA_OPPOW: return luai_numpow(NULL, v1, v2); + case LUA_OPUNM: return luai_numunm(N, v1); + default: lua_assert(0); return 0; + } +} + + int luaO_str2d (const char *s, lua_Number *result) { char *endptr; *result = lua_str2number(s, &endptr); @@ -94,7 +109,7 @@ int luaO_str2d (const char *s, lua_Number *result) { if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */ *result = cast_num(strtoul(s, &endptr, 16)); if (*endptr == '\0') return 1; /* most common case */ - while (isspace(cast(unsigned char, *endptr))) endptr++; + while (lisspace(cast(unsigned char, *endptr))) endptr++; if (*endptr != '\0') return 0; /* invalid trailing characters? */ return 1; } @@ -151,11 +166,9 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { break; } default: { - char buff[3]; - buff[0] = '%'; - buff[1] = *(e+1); - buff[2] = '\0'; - pushstr(L, buff); + luaG_runerror(L, + "invalid option " LUA_QL("%%%c") " to " LUA_QL("lua_pushfstring"), + *(e + 1)); break; } } @@ -163,8 +176,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { fmt = e+2; } pushstr(L, fmt); - luaV_concat(L, n+1, cast_int(L->top - L->base) - 1); - L->top -= n; + luaV_concat(L, n+1); return svalue(L->top - 1); } @@ -179,36 +191,46 @@ const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { } + +#define LL(x) (sizeof(x) - 1) +#define RETS "..." +#define PRE "[string \"" +#define POS "\"]" + +#define addstr(a,b,l) ( memcpy(a,b,l), a += (l) ) + void luaO_chunkid (char *out, const char *source, size_t bufflen) { - if (*source == '=') { - strncpy(out, source+1, bufflen); /* remove first char */ - out[bufflen-1] = '\0'; /* ensures null termination */ + size_t l = strlen(source); + if (*source == '=') { /* 'literal' source */ + if (l <= bufflen) /* small enough? */ + memcpy(out, source + 1, l); + else { /* truncate it */ + addstr(out, source + 1, bufflen - 1); + *out = '\0'; + } } - else { /* out = "source", or "...source" */ - if (*source == '@') { - size_t l; - source++; /* skip the `@' */ - bufflen -= sizeof(" '...' "); - l = strlen(source); - strcpy(out, ""); - if (l > bufflen) { - source += (l-bufflen); /* get last part of file name */ - strcat(out, "..."); - } - strcat(out, source); + else if (*source == '@') { /* file name */ + if (l <= bufflen) /* small enough? */ + memcpy(out, source + 1, l); + else { /* add '...' before rest of name */ + addstr(out, RETS, LL(RETS)); + bufflen -= LL(RETS); + memcpy(out, source + 1 + l - bufflen, bufflen); } - else { /* out = [string "string"] */ - size_t len = strcspn(source, "\n\r"); /* stop at first newline */ - bufflen -= sizeof(" [string \"...\"] "); - if (len > bufflen) len = bufflen; - strcpy(out, "[string \""); - if (source[len] != '\0') { /* must truncate? */ - strncat(out, source, len); - strcat(out, "..."); - } - else - strcat(out, source); - strcat(out, "\"]"); + } + else { /* string; format as [string "source"] */ + const char *nl = strchr(source, '\n'); /* find first new line (if any) */ + addstr(out, PRE, LL(PRE)); /* add prefix */ + bufflen -= LL(PRE RETS POS); /* save space for prefix+suffix */ + if (l < bufflen && nl == NULL) { /* small one-line source? */ + addstr(out, source, l); /* keep it */ + } + else { + if (nl != NULL) l = nl - source; /* stop at first newline */ + if (l > bufflen) l = bufflen; + addstr(out, source, l); + addstr(out, RETS, LL(RETS)); } + memcpy(out, POS, LL(POS) + 1); } } diff --git a/src/lobject.h b/src/lobject.h index f1e447ef..2969fe7d 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.20.1.2 2008/08/06 13:29:48 roberto Exp $ +** $Id: lobject.h,v 2.34 2010/01/08 20:00:20 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -52,7 +52,6 @@ typedef struct GCheader { - /* ** Union of all Lua values */ @@ -64,17 +63,22 @@ typedef union { } Value; + /* ** Tagged Values */ -#define TValuefields Value value; int tt +#define TValuefields Value value_; int tt_ typedef struct lua_TValue { TValuefields; } TValue; +/* macro defining a nil value to be used in definitions */ +#define NILCONSTANT {NULL}, LUA_TNIL + + /* Macros to test type */ #define ttisnil(o) (ttype(o) == LUA_TNIL) #define ttisnumber(o) (ttype(o) == LUA_TNUMBER) @@ -85,83 +89,90 @@ typedef struct lua_TValue { #define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA) #define ttisthread(o) (ttype(o) == LUA_TTHREAD) #define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA) +#define ttisdeadkey(o) (ttype(o) == LUA_TDEADKEY) /* Macros to access values */ -#define ttype(o) ((o)->tt) -#define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc) -#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p) -#define nvalue(o) check_exp(ttisnumber(o), (o)->value.n) -#define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts) +#define ttype(o) ((o)->tt_) +#define gcvalue(o) check_exp(iscollectable(o), (o)->value_.gc) +#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value_.p) +#define nvalue(o) check_exp(ttisnumber(o), (o)->value_.n) +#define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value_.gc->ts) #define tsvalue(o) (&rawtsvalue(o)->tsv) -#define rawuvalue(o) check_exp(ttisuserdata(o), &(o)->value.gc->u) +#define rawuvalue(o) check_exp(ttisuserdata(o), &(o)->value_.gc->u) #define uvalue(o) (&rawuvalue(o)->uv) -#define clvalue(o) check_exp(ttisfunction(o), &(o)->value.gc->cl) -#define hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h) -#define bvalue(o) check_exp(ttisboolean(o), (o)->value.b) -#define thvalue(o) check_exp(ttisthread(o), &(o)->value.gc->th) +#define clvalue(o) check_exp(ttisfunction(o), &(o)->value_.gc->cl) +#define hvalue(o) check_exp(ttistable(o), &(o)->value_.gc->h) +#define bvalue(o) check_exp(ttisboolean(o), (o)->value_.b) +#define thvalue(o) check_exp(ttisthread(o), &(o)->value_.gc->th) #define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) /* ** for internal debug only */ -#define checkconsistency(obj) \ - lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) +#define iscollectable(o) (ttype(o) >= LUA_TSTRING) + +#define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt) + +#define checkconsistency(obj) lua_assert(!iscollectable(obj) || righttt(obj)) #define checkliveness(g,obj) \ - lua_assert(!iscollectable(obj) || \ - ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc))) + lua_assert(!iscollectable(obj) || (righttt(obj) && !isdead(g,gcvalue(obj)))) /* Macros to set values */ -#define setnilvalue(obj) ((obj)->tt=LUA_TNIL) +#define setnilvalue(obj) ((obj)->tt_=LUA_TNIL) #define setnvalue(obj,x) \ - { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; } + { TValue *i_o=(obj); i_o->value_.n=(x); i_o->tt_=LUA_TNUMBER; } + +#define changenvalue(obj,x) \ + ( lua_assert((obj)->tt_==LUA_TNUMBER), (obj)->value_.n=(x) ) #define setpvalue(obj,x) \ - { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; } + { TValue *i_o=(obj); i_o->value_.p=(x); i_o->tt_=LUA_TLIGHTUSERDATA; } #define setbvalue(obj,x) \ - { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; } + { TValue *i_o=(obj); i_o->value_.b=(x); i_o->tt_=LUA_TBOOLEAN; } #define setsvalue(L,obj,x) \ { TValue *i_o=(obj); \ - i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \ + i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TSTRING; \ checkliveness(G(L),i_o); } #define setuvalue(L,obj,x) \ { TValue *i_o=(obj); \ - i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \ + i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TUSERDATA; \ checkliveness(G(L),i_o); } #define setthvalue(L,obj,x) \ { TValue *i_o=(obj); \ - i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \ + i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TTHREAD; \ checkliveness(G(L),i_o); } #define setclvalue(L,obj,x) \ { TValue *i_o=(obj); \ - i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \ + i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TFUNCTION; \ checkliveness(G(L),i_o); } #define sethvalue(L,obj,x) \ { TValue *i_o=(obj); \ - i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \ + i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TTABLE; \ checkliveness(G(L),i_o); } #define setptvalue(L,obj,x) \ { TValue *i_o=(obj); \ - i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \ + i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TPROTO; \ checkliveness(G(L),i_o); } +#define setdeadvalue(obj) ((obj)->tt_=LUA_TDEADKEY) #define setobj(L,obj1,obj2) \ - { const TValue *o2=(obj2); TValue *o1=(obj1); \ - o1->value = o2->value; o1->tt=o2->tt; \ - checkliveness(G(L),o1); } + { const TValue *o2=(obj2); TValue *o1=(obj1); \ + o1->value_ = o2->value_; o1->tt_=o2->tt_; \ + checkliveness(G(L),o1); } /* @@ -183,11 +194,6 @@ typedef struct lua_TValue { #define setobj2n setobj #define setsvalue2n setsvalue -#define setttype(obj, tt) (ttype(obj) = (tt)) - - -#define iscollectable(o) (ttype(o) >= LUA_TSTRING) - typedef TValue *StkId; /* index to stack elements */ @@ -224,6 +230,15 @@ typedef union Udata { +/* +** Upvalues from a function prototype +*/ +typedef struct Upvaldesc { + TString *name; /* upvalue name (for debug information) */ + lu_byte instack; + lu_byte idx; /* index of upvalue (in stack or in outer function's list) */ +} Upvaldesc; + /* ** Function Prototypes @@ -235,9 +250,9 @@ typedef struct Proto { struct Proto **p; /* functions defined inside the function */ int *lineinfo; /* map from opcodes to source lines */ struct LocVar *locvars; /* information about local variables */ - TString **upvalues; /* upvalue names */ + Upvaldesc *upvalues; /* upvalue information */ TString *source; - int sizeupvalues; + int sizeupvalues; /* size of 'upvalues' */ int sizek; /* size of `k' */ int sizecode; int sizelineinfo; @@ -246,19 +261,13 @@ typedef struct Proto { int linedefined; int lastlinedefined; GCObject *gclist; - lu_byte nups; /* number of upvalues */ lu_byte numparams; lu_byte is_vararg; lu_byte maxstacksize; + lu_byte envreg; /* register in outer function with initial environment */ } Proto; -/* masks for new-style vararg */ -#define VARARG_HASARG 1 -#define VARARG_ISVARARG 2 -#define VARARG_NEEDSARG 4 - - typedef struct LocVar { TString *varname; int startpc; /* first point where variable is active */ @@ -312,9 +321,10 @@ typedef union Closure { } Closure; -#define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->c.isC) -#define isLfunction(o) (ttype(o) == LUA_TFUNCTION && !clvalue(o)->c.isC) +#define iscfunction(o) (ttisfunction(o) && clvalue(o)->c.isC) +#define isLfunction(o) (ttisfunction(o) && !clvalue(o)->c.isC) +#define getproto(o) (clvalue(o)->l.p) /* ** Tables @@ -337,7 +347,7 @@ typedef struct Node { typedef struct Table { CommonHeader; - lu_byte flags; /* 1<<p means tagmethod(p) is not present */ + lu_byte flags; /* 1<<p means tagmethod(p) is not present */ lu_byte lsizenode; /* log2 of size of `node' array */ struct Table *metatable; TValue *array; /* array part */ @@ -362,13 +372,12 @@ typedef struct Table { #define luaO_nilobject (&luaO_nilobject_) -LUAI_DATA const TValue luaO_nilobject_; - -#define ceillog2(x) (luaO_log2((x)-1) + 1) +LUAI_DDEC const TValue luaO_nilobject_; -LUAI_FUNC int luaO_log2 (unsigned int x); LUAI_FUNC int luaO_int2fb (unsigned int x); LUAI_FUNC int luaO_fb2int (int x); +LUAI_FUNC int luaO_ceillog2 (lu_int32 x); +LUAI_FUNC lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2); LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2); LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result); LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, diff --git a/src/lopcodes.c b/src/lopcodes.c index 4cc74523..188c7a55 100644 --- a/src/lopcodes.c +++ b/src/lopcodes.c @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.c,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lopcodes.c,v 1.41 2009/11/19 19:06:52 roberto Exp $ ** See Copyright Notice in lua.h */ @@ -13,7 +13,7 @@ /* ORDER OP */ -const char *const luaP_opnames[NUM_OPCODES+1] = { +LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "MOVE", "LOADK", "LOADBOOL", @@ -47,20 +47,22 @@ const char *const luaP_opnames[NUM_OPCODES+1] = { "RETURN", "FORLOOP", "FORPREP", - "TFORLOOP", + "TFORCALL", "SETLIST", "CLOSE", "CLOSURE", "VARARG", + "TFORLOOP", + "EXTRAARG", NULL }; #define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) -const lu_byte luaP_opmodes[NUM_OPCODES] = { +LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { /* T A B C mode opcode */ - opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ + opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LOADNIL */ @@ -93,10 +95,12 @@ const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ - ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TFORLOOP */ + ,opmode(0, 0, OpArgN, OpArgU, iABC) /* OP_TFORCALL */ ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ ,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */ ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_TFORLOOP */ + ,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */ }; diff --git a/src/lopcodes.h b/src/lopcodes.h index 41224d6e..19ddfea3 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.125.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lopcodes.h,v 1.133 2009/11/19 19:06:52 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -28,7 +28,7 @@ ===========================================================================*/ -enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ +enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */ /* @@ -38,6 +38,7 @@ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ #define SIZE_B 9 #define SIZE_Bx (SIZE_C + SIZE_B) #define SIZE_A 8 +#define SIZE_Ax (SIZE_C + SIZE_B + SIZE_A) #define SIZE_OP 6 @@ -46,6 +47,7 @@ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ #define POS_C (POS_A + SIZE_A) #define POS_B (POS_C + SIZE_C) #define POS_Bx POS_C +#define POS_Ax POS_A /* @@ -61,6 +63,12 @@ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ #define MAXARG_sBx MAX_INT #endif +#if SIZE_Ax < LUAI_BITSINT-1 +#define MAXARG_Ax ((1<<SIZE_Ax)-1) +#else +#define MAXARG_Ax MAX_INT +#endif + #define MAXARG_A ((1<<SIZE_A)-1) #define MAXARG_B ((1<<SIZE_B)-1) @@ -68,7 +76,7 @@ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ /* creates a mask with `n' 1 bits at position `p' */ -#define MASK1(n,p) ((~((~(Instruction)0)<<n))<<p) +#define MASK1(n,p) ((~((~(Instruction)0)<<(n)))<<(p)) /* creates a mask with `n' 0 bits at position `p' */ #define MASK0(n,p) (~MASK1(n,p)) @@ -81,21 +89,24 @@ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ #define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ ((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP)))) -#define GETARG_A(i) (cast(int, ((i)>>POS_A) & MASK1(SIZE_A,0))) -#define SETARG_A(i,u) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \ - ((cast(Instruction, u)<<POS_A)&MASK1(SIZE_A,POS_A)))) +#define getarg(i,pos,size) (cast(int, ((i)>>pos) & MASK1(size,0))) +#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \ + ((cast(Instruction, v)<<pos)&MASK1(size,pos)))) -#define GETARG_B(i) (cast(int, ((i)>>POS_B) & MASK1(SIZE_B,0))) -#define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \ - ((cast(Instruction, b)<<POS_B)&MASK1(SIZE_B,POS_B)))) +#define GETARG_A(i) getarg(i, POS_A, SIZE_A) +#define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A) -#define GETARG_C(i) (cast(int, ((i)>>POS_C) & MASK1(SIZE_C,0))) -#define SETARG_C(i,b) ((i) = (((i)&MASK0(SIZE_C,POS_C)) | \ - ((cast(Instruction, b)<<POS_C)&MASK1(SIZE_C,POS_C)))) +#define GETARG_B(i) getarg(i, POS_B, SIZE_B) +#define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B) -#define GETARG_Bx(i) (cast(int, ((i)>>POS_Bx) & MASK1(SIZE_Bx,0))) -#define SETARG_Bx(i,b) ((i) = (((i)&MASK0(SIZE_Bx,POS_Bx)) | \ - ((cast(Instruction, b)<<POS_Bx)&MASK1(SIZE_Bx,POS_Bx)))) +#define GETARG_C(i) getarg(i, POS_C, SIZE_C) +#define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C) + +#define GETARG_Bx(i) getarg(i, POS_Bx, SIZE_Bx) +#define SETARG_Bx(i,v) setarg(i, v, POS_Bx, SIZE_Bx) + +#define GETARG_Ax(i) getarg(i, POS_Ax, SIZE_Ax) +#define SETARG_Ax(i,v) setarg(i, v, POS_Ax, SIZE_Ax) #define GETARG_sBx(i) (GETARG_Bx(i)-MAXARG_sBx) #define SETARG_sBx(i,b) SETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx)) @@ -110,6 +121,9 @@ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ | (cast(Instruction, a)<<POS_A) \ | (cast(Instruction, bc)<<POS_Bx)) +#define CREATE_Ax(o,a) ((cast(Instruction, o)<<POS_OP) \ + | (cast(Instruction, a)<<POS_A)) + /* ** Macros to operate RK indices @@ -152,15 +166,15 @@ typedef enum { name args description ------------------------------------------------------------------------*/ OP_MOVE,/* A B R(A) := R(B) */ -OP_LOADK,/* A Bx R(A) := Kst(Bx) */ +OP_LOADK,/* A Bx R(A) := Kst(Bx - 1) */ OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */ OP_LOADNIL,/* A B R(A) := ... := R(B) := nil */ OP_GETUPVAL,/* A B R(A) := UpValue[B] */ -OP_GETGLOBAL,/* A Bx R(A) := Gbl[Kst(Bx)] */ +OP_GETGLOBAL,/* A Bx R(A) := Gbl[Kst(Bx - 1)] */ OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */ -OP_SETGLOBAL,/* A Bx Gbl[Kst(Bx)] := R(A) */ +OP_SETGLOBAL,/* A Bx Gbl[Kst(Bx - 1)] := R(A) */ OP_SETUPVAL,/* A B UpValue[B] := R(A) */ OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */ @@ -183,11 +197,11 @@ OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ OP_JMP,/* sBx pc+=sBx */ OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ -OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ -OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ +OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ +OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ -OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ -OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ +OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ +OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ @@ -197,39 +211,46 @@ OP_FORLOOP,/* A sBx R(A)+=R(A+2); if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/ OP_FORPREP,/* A sBx R(A)-=R(A+2); pc+=sBx */ -OP_TFORLOOP,/* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); - if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++ */ +OP_TFORCALL,/* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */ OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */ -OP_CLOSE,/* A close all variables in the stack up to (>=) R(A)*/ -OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ +OP_CLOSE,/* A close all variables in the stack up to (>=) R(A)*/ +OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx]) */ -OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ +OP_VARARG,/* A B R(A), R(A+1), ..., R(A+B-2) = vararg */ + +OP_TFORLOOP,/* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/ + +OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ } OpCode; -#define NUM_OPCODES (cast(int, OP_VARARG) + 1) +#define NUM_OPCODES (cast(int, OP_EXTRAARG) + 1) /*=========================================================================== Notes: - (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1, - and can be 0: OP_CALL then sets `top' to last_result+1, so - next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'. + (*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then `top' is + set to last_result+1, so next open instruction (OP_CALL, OP_RETURN, + OP_SETLIST) may use `top'. (*) In OP_VARARG, if (B == 0) then use actual number of varargs and - set top (like in OP_CALL with C == 0). + set top (like in OP_CALL with C == 0). + + (*) In OP_RETURN, if (B == 0) then return up to `top'. - (*) In OP_RETURN, if (B == 0) then return up to `top' + (*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next + 'instruction' is EXTRAARG(real C). - (*) In OP_SETLIST, if (B == 0) then B = `top'; - if (C == 0) then next `instruction' is real C + (*) In OP_LOADK, OP_GETGLOBAL, and OP_SETGLOBAL, if (Bx == 0) then next + 'instruction' is EXTRAARG(real Bx). (*) For comparisons, A specifies what condition the test should accept - (true or false). + (true or false). + + (*) All `skips' (pc++) assume that next instruction is a jump. - (*) All `skips' (pc++) assume that next instruction is a jump ===========================================================================*/ @@ -239,8 +260,8 @@ OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ ** bits 2-3: C arg mode ** bits 4-5: B arg mode ** bit 6: instruction set register A -** bit 7: operator is a test -*/ +** bit 7: operator is a test (next instruction must be a jump) +*/ enum OpArgMask { OpArgN, /* argument is not used */ @@ -249,7 +270,7 @@ enum OpArgMask { OpArgK /* argument is a constant or register/constant */ }; -LUAI_DATA const lu_byte luaP_opmodes[NUM_OPCODES]; +LUAI_DDEC const lu_byte luaP_opmodes[NUM_OPCODES]; #define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3)) #define getBMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3)) @@ -258,7 +279,7 @@ LUAI_DATA const lu_byte luaP_opmodes[NUM_OPCODES]; #define testTMode(m) (luaP_opmodes[m] & (1 << 7)) -LUAI_DATA const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ +LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ /* number of list items to accumulate before a SETLIST instruction */ diff --git a/src/loslib.c b/src/loslib.c index da06a572..41592088 100644 --- a/src/loslib.c +++ b/src/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.19.1.3 2008/01/18 16:38:18 roberto Exp $ +** $Id: loslib.c,v 1.29 2009/12/17 13:08:51 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -20,6 +20,45 @@ #include "lualib.h" +/* +** list of valid conversion specifiers @* for the 'strftime' function +*/ +#if !defined(LUA_STRFTIMEOPTIONS) + +#if !defined(LUA_USE_POSIX) +#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" } +#else +#define LUA_STRFTIMEOPTIONS { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \ + "E", "cCxXyY", \ + "O", "deHImMSuUVwWy" } +#endif + +#endif + + + +/* +** By default, Lua uses tmpnam except when POSIX is available, where it +** uses mkstemp. +*/ +#if defined(LUA_USE_MKSTEMP) +#include <unistd.h> +#define LUA_TMPNAMBUFSIZE 32 +#define lua_tmpnam(b,e) { \ + strcpy(b, "/tmp/lua_XXXXXX"); \ + e = mkstemp(b); \ + if (e != -1) close(e); \ + e = (e == -1); } + +#elif !defined(lua_tmpnam) + +#define LUA_TMPNAMBUFSIZE L_tmpnam +#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } + +#endif + + + static int os_pushresult (lua_State *L, int i, const char *filename) { int en = errno; /* calls to Lua API may change this value */ if (i) { @@ -121,6 +160,30 @@ static int getfield (lua_State *L, const char *key, int d) { } +static const char *checkoption (lua_State *L, const char *conv, char *buff) { + static const char *const options[] = LUA_STRFTIMEOPTIONS; + unsigned int i; + for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2) { + if (*conv != '\0' && strchr(options[i], *conv) != NULL) { + buff[1] = *conv; + if (*options[i + 1] == '\0') { /* one-char conversion specifier? */ + buff[2] = '\0'; /* end buffer */ + return conv + 1; + } + else if (*(conv + 1) != '\0' && + strchr(options[i + 1], *(conv + 1)) != NULL) { + buff[2] = *(conv + 1); /* valid two-char conversion specifier */ + buff[3] = '\0'; /* end buffer */ + return conv + 2; + } + } + } + luaL_argerror(L, 1, + lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv)); + return conv; /* to avoid warnings */ +} + + static int os_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); @@ -146,17 +209,17 @@ static int os_date (lua_State *L) { setboolfield(L, "isdst", stm->tm_isdst); } else { - char cc[3]; + char cc[4]; luaL_Buffer b; - cc[0] = '%'; cc[2] = '\0'; + cc[0] = '%'; luaL_buffinit(L, &b); - for (; *s; s++) { - if (*s != '%' || *(s + 1) == '\0') /* no conversion specifier? */ - luaL_addchar(&b, *s); + while (*s) { + if (*s != '%') /* no conversion specifier? */ + luaL_addchar(&b, *s++); else { size_t reslen; char buff[200]; /* should be big enough for any conversion result */ - cc[1] = *(++s); + s = checkoption(L, s + 1, cc); reslen = strftime(buff, sizeof(buff), cc, stm); luaL_addlstring(&b, buff, reslen); } @@ -214,9 +277,13 @@ static int os_setlocale (lua_State *L) { static int os_exit (lua_State *L) { - exit(luaL_optint(L, 1, EXIT_SUCCESS)); + int status = luaL_optint(L, 1, EXIT_SUCCESS); + if (lua_toboolean(L, 2)) + lua_close(L); + exit(status); } + static const luaL_Reg syslib[] = { {"clock", os_clock}, {"date", os_date}, @@ -236,7 +303,7 @@ static const luaL_Reg syslib[] = { -LUALIB_API int luaopen_os (lua_State *L) { +LUAMOD_API int luaopen_os (lua_State *L) { luaL_register(L, LUA_OSLIBNAME, syslib); return 1; } diff --git a/src/lparser.c b/src/lparser.c index 1e2a9a88..cc21f67f 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.42.1.3 2007/12/28 15:32:23 roberto Exp $ +** $Id: lparser.c,v 2.75 2010/01/06 11:48:02 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -27,11 +27,13 @@ -#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) +/* maximum number of local variables per function (must be smaller + than 250, due to the bytecode format) */ +#define MAXVARS 200 + -#define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]]) +#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) -#define luaY_checklimit(fs,v,l,m) if ((v)>(l)) errorlimit(fs,l,m) /* @@ -55,6 +57,8 @@ static void expr (LexState *ls, expdesc *v); static void anchor_token (LexState *ls) { + /* last token from outer function must be EOS */ + lua_assert(ls->fs != NULL || ls->t.token == TK_EOS); if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { TString *ts = ls->t.seminfo.ts; luaX_newstring(ls, getstr(ts), ts->tsv.len); @@ -64,16 +68,23 @@ static void anchor_token (LexState *ls) { static void error_expected (LexState *ls, int token) { luaX_syntaxerror(ls, - luaO_pushfstring(ls->L, LUA_QS " expected", luaX_token2str(ls, token))); + luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token))); } static void errorlimit (FuncState *fs, int limit, const char *what) { - const char *msg = (fs->f->linedefined == 0) ? - luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) : - luaO_pushfstring(fs->L, "function at line %d has more than %d %s", - fs->f->linedefined, limit, what); - luaX_lexerror(fs->ls, msg, 0); + const char *msg; + const char *where = (fs->f->linedefined == 0) ? + "main function" : + luaO_pushfstring(fs->L, "function at line %d", fs->f->linedefined); + msg = luaO_pushfstring(fs->L, "too many %s (limit is %d) in %s", + what, limit, where); + luaX_syntaxerror(fs->ls, msg); +} + + +static void checklimit (FuncState *fs, int v, int l, const char *what) { + if (v > l) errorlimit(fs, l, what); } @@ -107,7 +118,7 @@ static void check_match (LexState *ls, int what, int who, int where) { error_expected(ls, what); else { luaX_syntaxerror(ls, luaO_pushfstring(ls->L, - LUA_QS " expected (to close " LUA_QS " at line %d)", + "%s expected (to close %s at line %d)", luaX_token2str(ls, what), luaX_token2str(ls, who), where)); } } @@ -135,7 +146,7 @@ static void codestring (LexState *ls, expdesc *e, TString *s) { } -static void checkname(LexState *ls, expdesc *e) { +static void checkname (LexState *ls, expdesc *e) { codestring(ls, e, str_checkname(ls)); } @@ -145,7 +156,7 @@ static int registerlocalvar (LexState *ls, TString *varname) { Proto *f = fs->f; int oldsize = f->sizelocvars; luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, - LocVar, SHRT_MAX, "too many local variables"); + LocVar, SHRT_MAX, "local variables"); while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; f->locvars[fs->nlocvars].varname = varname; luaC_objbarrier(ls->L, f, varname); @@ -153,14 +164,30 @@ static int registerlocalvar (LexState *ls, TString *varname) { } -#define new_localvarliteral(ls,v,n) \ - new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n) +static void new_localvar (LexState *ls, TString *name) { + FuncState *fs = ls->fs; + Varlist *vl = ls->varl; + int reg = registerlocalvar(ls, name); + checklimit(fs, vl->nactvar + 1 - fs->firstlocal, + MAXVARS, "local variables"); + luaM_growvector(ls->L, vl->actvar, vl->nactvar + 1, + vl->actvarsize, vardesc, MAX_INT, "local variables"); + vl->actvar[vl->nactvar++].idx = cast(unsigned short, reg); +} + + +static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) { + new_localvar(ls, luaX_newstring(ls, name, sz)); +} +#define new_localvarliteral(ls,v) \ + new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1) -static void new_localvar (LexState *ls, TString *name, int n) { - FuncState *fs = ls->fs; - luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables"); - fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name)); + +static LocVar *getlocvar (FuncState *fs, int i) { + int idx = fs->ls->varl->actvar[fs->firstlocal + i].idx; + lua_assert(idx < fs->nlocvars); + return &fs->f->locvars[idx]; } @@ -168,15 +195,15 @@ static void adjustlocalvars (LexState *ls, int nvars) { FuncState *fs = ls->fs; fs->nactvar = cast_byte(fs->nactvar + nvars); for (; nvars; nvars--) { - getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc; + getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc; } } -static void removevars (LexState *ls, int tolevel) { - FuncState *fs = ls->fs; +static void removevars (FuncState *fs, int tolevel) { + fs->ls->varl->nactvar -= (fs->nactvar - tolevel); while (fs->nactvar > tolevel) - getlocvar(fs, --fs->nactvar).endpc = fs->pc; + getlocvar(fs, --fs->nactvar)->endpc = fs->pc; } @@ -184,30 +211,31 @@ static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { int i; Proto *f = fs->f; int oldsize = f->sizeupvalues; - for (i=0; i<f->nups; i++) { - if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->u.s.info) { - lua_assert(f->upvalues[i] == name); + int instk = (v->k == VLOCAL); + lua_assert(instk || v->k == VUPVAL); + for (i=0; i<fs->nups; i++) { + if (f->upvalues[i].instack == instk && f->upvalues[i].idx == v->u.s.info) { + lua_assert(f->upvalues[i].name == name); return i; } } /* new one */ - luaY_checklimit(fs, f->nups + 1, LUAI_MAXUPVALUES, "upvalues"); - luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues, - TString *, MAX_INT, ""); - while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL; - f->upvalues[f->nups] = name; + checklimit(fs, fs->nups + 1, UCHAR_MAX, "upvalues"); + luaM_growvector(fs->L, f->upvalues, fs->nups, f->sizeupvalues, + Upvaldesc, UCHAR_MAX, "upvalues"); + while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL; + f->upvalues[fs->nups].name = name; luaC_objbarrier(fs->L, f, name); - lua_assert(v->k == VLOCAL || v->k == VUPVAL); - fs->upvalues[f->nups].k = cast_byte(v->k); - fs->upvalues[f->nups].info = cast_byte(v->u.s.info); - return f->nups++; + f->upvalues[fs->nups].instack = cast_byte(instk); + f->upvalues[fs->nups].idx = cast_byte(v->u.s.info); + return fs->nups++; } static int searchvar (FuncState *fs, TString *n) { int i; for (i=fs->nactvar-1; i >= 0; i--) { - if (n == getlocvar(fs, i).varname) + if (n == getlocvar(fs, i)->varname) return i; } return -1; /* not found */ @@ -222,10 +250,8 @@ static void markupval (FuncState *fs, int level) { static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { - if (fs == NULL) { /* no more levels? */ - init_exp(var, VGLOBAL, NO_REG); /* default is global variable */ - return VGLOBAL; - } + if (fs == NULL) /* no more levels? */ + return VGLOBAL; /* default is global variable */ else { int v = searchvar(fs, n); /* look up at current level */ if (v >= 0) { @@ -248,8 +274,16 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { static void singlevar (LexState *ls, expdesc *var) { TString *varname = str_checkname(ls); FuncState *fs = ls->fs; - if (singlevaraux(fs, varname, var, 1) == VGLOBAL) - var->u.s.info = luaK_stringK(fs, varname); /* info points to global name */ + if (singlevaraux(fs, varname, var, 1) == VGLOBAL) { + if (fs->envreg == NO_REG) /* regular global? */ + init_exp(var, VGLOBAL, luaK_stringK(fs, varname)); + else { /* "globals" are in current lexical environment */ + expdesc key; + init_exp(var, VLOCAL, fs->envreg); /* current environment */ + codestring(ls, &key, varname); /* key is variable name */ + luaK_indexed(fs, var, &key); /* env[varname] */ + } + } } @@ -274,12 +308,13 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { static void enterlevel (LexState *ls) { - if (++ls->L->nCcalls > LUAI_MAXCCALLS) - luaX_lexerror(ls, "chunk has too many syntax levels", 0); + global_State *g = G(ls->L); + ++g->nCcalls; + checklimit(ls->fs, g->nCcalls, LUAI_MAXCCALLS, "syntax levels"); } -#define leavelevel(ls) ((ls)->L->nCcalls--) +#define leavelevel(ls) (G((ls)->L)->nCcalls--) static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { @@ -296,7 +331,7 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { static void leaveblock (FuncState *fs) { BlockCnt *bl = fs->bl; fs->bl = bl->previous; - removevars(fs->ls, bl->nactvar); + removevars(fs, bl->nactvar); if (bl->upval) luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); /* a block either controls scope or breaks (never both) */ @@ -307,49 +342,51 @@ static void leaveblock (FuncState *fs) { } -static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { - FuncState *fs = ls->fs; - Proto *f = fs->f; +static void pushclosure (LexState *ls, Proto *clp, expdesc *v) { + FuncState *fs = ls->fs->prev; + Proto *f = fs->f; /* prototype of function creating new closure */ int oldsize = f->sizep; - int i; luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, - MAXARG_Bx, "constant table overflow"); + MAXARG_Bx, "functions"); while (oldsize < f->sizep) f->p[oldsize++] = NULL; - f->p[fs->np++] = func->f; - luaC_objbarrier(ls->L, f, func->f); + f->p[fs->np++] = clp; + /* initial environment for new function is current lexical environment */ + clp->envreg = fs->envreg; + luaC_objbarrier(ls->L, f, clp); init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); - for (i=0; i<func->f->nups; i++) { - OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; - luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0); - } } static void open_func (LexState *ls, FuncState *fs) { lua_State *L = ls->L; - Proto *f = luaF_newproto(L); - fs->f = f; + Proto *f; fs->prev = ls->fs; /* linked list of funcstates */ fs->ls = ls; fs->L = L; ls->fs = fs; fs->pc = 0; - fs->lasttarget = -1; + fs->lasttarget = 0; fs->jpc = NO_JUMP; fs->freereg = 0; fs->nk = 0; fs->np = 0; + fs->nups = 0; fs->nlocvars = 0; fs->nactvar = 0; + fs->firstlocal = ls->varl->nactvar; + fs->envreg = NO_REG; fs->bl = NULL; + f = luaF_newproto(L); + fs->f = f; f->source = ls->source; f->maxstacksize = 2; /* registers 0/1 are always valid */ - fs->h = luaH_new(L, 0, 0); - /* anchor table of constants and prototype (to avoid being collected) */ - sethvalue2s(L, L->top, fs->h); - incr_top(L); + /* anchor prototype (to avoid being collected) */ setptvalue2s(L, L->top, f); incr_top(L); + fs->h = luaH_new(L); + /* anchor table of constants (to avoid being collected) */ + sethvalue2s(L, L->top, fs->h); + incr_top(L); } @@ -357,7 +394,7 @@ static void close_func (LexState *ls) { lua_State *L = ls->L; FuncState *fs = ls->fs; Proto *f = fs->f; - removevars(ls, 0); + removevars(fs, 0); luaK_ret(fs, 0, 0); /* final return */ luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); f->sizecode = fs->pc; @@ -369,30 +406,37 @@ static void close_func (LexState *ls) { f->sizep = fs->np; luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); f->sizelocvars = fs->nlocvars; - luaM_reallocvector(L, f->upvalues, f->sizeupvalues, f->nups, TString *); - f->sizeupvalues = f->nups; - lua_assert(luaG_checkcode(f)); + luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); + f->sizeupvalues = fs->nups; lua_assert(fs->bl == NULL); ls->fs = fs->prev; - L->top -= 2; /* remove table and prototype from the stack */ - /* last token read was anchored in defunct function; must reanchor it */ - if (fs) anchor_token(ls); + /* last token read was anchored in defunct function; must re-anchor it */ + anchor_token(ls); + L->top--; /* pop table of constants */ + luaC_checkGC(L); + L->top--; /* pop prototype (after possible collection) */ } -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { +Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Varlist *varl, + const char *name) { struct LexState lexstate; struct FuncState funcstate; + TString *tname = luaS_new(L, name); + setsvalue2s(L, L->top, tname); /* push name to protect it */ + incr_top(L); lexstate.buff = buff; - luaX_setinput(L, &lexstate, z, luaS_new(L, name)); + lexstate.varl = varl; + luaX_setinput(L, &lexstate, z, tname); open_func(&lexstate, &funcstate); - funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ + funcstate.f->is_vararg = 1; /* main function is always vararg */ luaX_next(&lexstate); /* read first token */ chunk(&lexstate); check(&lexstate, TK_EOS); close_func(&lexstate); + L->top--; /* pop name */ lua_assert(funcstate.prev == NULL); - lua_assert(funcstate.f->nups == 0); + lua_assert(funcstate.nups == 0); lua_assert(lexstate.fs == NULL); return funcstate.f; } @@ -404,8 +448,8 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { /*============================================================*/ -static void field (LexState *ls, expdesc *v) { - /* field -> ['.' | ':'] NAME */ +static void fieldsel (LexState *ls, expdesc *v) { + /* fieldsel -> ['.' | ':'] NAME */ FuncState *fs = ls->fs; expdesc key; luaK_exp2anyreg(fs, v); @@ -447,7 +491,7 @@ static void recfield (LexState *ls, struct ConsControl *cc) { expdesc key, val; int rkkey; if (ls->t.token == TK_NAME) { - luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); + checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); checkname(ls, &key); } else /* ls->t.token == '[' */ @@ -488,15 +532,39 @@ static void lastlistfield (FuncState *fs, struct ConsControl *cc) { static void listfield (LexState *ls, struct ConsControl *cc) { + /* listfield -> exp */ expr(ls, &cc->v); - luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); + checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); cc->na++; cc->tostore++; } +static void field (LexState *ls, struct ConsControl *cc) { + /* field -> listfield | recfield */ + switch(ls->t.token) { + case TK_NAME: { /* may be 'listfield' or 'recfield' */ + if (luaX_lookahead(ls) != '=') /* expression? */ + listfield(ls, cc); + else + recfield(ls, cc); + break; + } + case '[': { + recfield(ls, cc); + break; + } + default: { + listfield(ls, cc); + break; + } + } +} + + static void constructor (LexState *ls, expdesc *t) { - /* constructor -> ?? */ + /* constructor -> '{' [ field { sep field } [sep] ] '}' + sep -> ',' | ';' */ FuncState *fs = ls->fs; int line = ls->linenumber; int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); @@ -511,24 +579,7 @@ static void constructor (LexState *ls, expdesc *t) { lua_assert(cc.v.k == VVOID || cc.tostore > 0); if (ls->t.token == '}') break; closelistfield(fs, &cc); - switch(ls->t.token) { - case TK_NAME: { /* may be listfields or recfields */ - luaX_lookahead(ls); - if (ls->lookahead.token != '=') /* expression? */ - listfield(ls, &cc); - else - recfield(ls, &cc); - break; - } - case '[': { /* constructor_item -> recfield */ - recfield(ls, &cc); - break; - } - default: { /* constructor_part -> listfield */ - listfield(ls, &cc); - break; - } - } + field(ls, &cc); } while (testnext(ls, ',') || testnext(ls, ';')); check_match(ls, '}', '{', line); lastlistfield(fs, &cc); @@ -550,17 +601,13 @@ static void parlist (LexState *ls) { do { switch (ls->t.token) { case TK_NAME: { /* param -> NAME */ - new_localvar(ls, str_checkname(ls), nparams++); + new_localvar(ls, str_checkname(ls)); + nparams++; break; } case TK_DOTS: { /* param -> `...' */ luaX_next(ls); -#if defined(LUA_COMPAT_VARARG) - /* use `arg' as default name */ - new_localvarliteral(ls, "arg", nparams++); - f->is_vararg = VARARG_HASARG | VARARG_NEEDSARG; -#endif - f->is_vararg |= VARARG_ISVARARG; + f->is_vararg = 1; break; } default: luaX_syntaxerror(ls, "<name> or " LUA_QL("...") " expected"); @@ -568,7 +615,7 @@ static void parlist (LexState *ls) { } while (!f->is_vararg && testnext(ls, ',')); } adjustlocalvars(ls, nparams); - f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG)); + f->numparams = cast_byte(fs->nactvar); luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ } @@ -580,7 +627,7 @@ static void body (LexState *ls, expdesc *e, int needself, int line) { new_fs.f->linedefined = line; checknext(ls, '('); if (needself) { - new_localvarliteral(ls, "self", 0); + new_localvarliteral(ls, "self"); adjustlocalvars(ls, 1); } parlist(ls); @@ -588,8 +635,8 @@ static void body (LexState *ls, expdesc *e, int needself, int line) { chunk(ls); new_fs.f->lastlinedefined = ls->linenumber; check_match(ls, TK_END, TK_FUNCTION, line); + pushclosure(ls, new_fs.f, e); close_func(ls); - pushclosure(ls, &new_fs, e); } @@ -694,8 +741,8 @@ static void primaryexp (LexState *ls, expdesc *v) { prefixexp(ls, v); for (;;) { switch (ls->t.token) { - case '.': { /* field */ - field(ls, v); + case '.': { /* fieldsel */ + fieldsel(ls, v); break; } case '[': { /* `[' exp1 `]' */ @@ -725,7 +772,7 @@ static void primaryexp (LexState *ls, expdesc *v) { static void simpleexp (LexState *ls, expdesc *v) { - /* simpleexp -> NUMBER | STRING | NIL | true | false | ... | + /* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... | constructor | FUNCTION body | primaryexp */ switch (ls->t.token) { case TK_NUMBER: { @@ -753,7 +800,6 @@ static void simpleexp (LexState *ls, expdesc *v) { FuncState *fs = ls->fs; check_condition(ls, fs->f->is_vararg, "cannot use " LUA_QL("...") " outside a vararg function"); - fs->f->is_vararg &= ~VARARG_NEEDSARG; /* don't need 'arg' */ init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); break; } @@ -811,11 +857,11 @@ static const struct { lu_byte left; /* left priority for each binary operator */ lu_byte right; /* right priority */ } priority[] = { /* ORDER OPR */ - {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `/' `%' */ - {10, 9}, {5, 4}, /* power and concat (right associative) */ - {3, 3}, {3, 3}, /* equality and inequality */ - {3, 3}, {3, 3}, {3, 3}, {3, 3}, /* order */ - {2, 2}, {1, 1} /* logical (and/or) */ + {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `*' `/' `%' */ + {10, 9}, {5, 4}, /* ^, .. (right associative) */ + {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ + {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ + {2, 2}, {1, 1} /* and, or */ }; #define UNARY_PRIORITY 8 /* priority for unary operators */ @@ -938,8 +984,8 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { primaryexp(ls, &nv.v); if (nv.v.k == VLOCAL) check_conflict(ls, lh, &nv.v); - luaY_checklimit(ls->fs, nvars, LUAI_MAXCCALLS - ls->L->nCcalls, - "variables in assignment"); + checklimit(ls->fs, nvars, LUAI_MAXCCALLS - G(ls->L)->nCcalls, + "variable names"); assignment(ls, &nv, nvars+1); } else { /* assignment -> `=' explist1 */ @@ -1000,7 +1046,7 @@ static void whilestat (LexState *ls, int line) { enterblock(fs, &bl, 1); checknext(ls, TK_DO); block(ls); - luaK_patchlist(fs, luaK_jump(fs), whileinit); + luaK_jumpto(fs, whileinit); check_match(ls, TK_END, TK_WHILE, line); leaveblock(fs); luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ @@ -1021,13 +1067,13 @@ static void repeatstat (LexState *ls, int line) { condexit = cond(ls); /* read condition (inside scope block) */ if (!bl2.upval) { /* no upvalues? */ leaveblock(fs); /* finish scope */ - luaK_patchlist(ls->fs, condexit, repeat_init); /* close the loop */ + luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ } else { /* complete semantics when there are upvalues */ breakstat(ls); /* if condition then break */ luaK_patchtohere(ls->fs, condexit); /* else... */ leaveblock(fs); /* finish scope... */ - luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init); /* and repeat */ + luaK_jumpto(fs, repeat_init); /* and repeat */ } leaveblock(fs); /* finish loop */ } @@ -1035,11 +1081,12 @@ static void repeatstat (LexState *ls, int line) { static int exp1 (LexState *ls) { expdesc e; - int k; + int reg; expr(ls, &e); - k = e.k; luaK_exp2nextreg(ls->fs, &e); - return k; + lua_assert(e.k == VNONRELOC); + reg = e.u.s.info; + return reg; } @@ -1057,10 +1104,15 @@ static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { block(ls); leaveblock(fs); /* end of scope for declared variables */ luaK_patchtohere(fs, prep); - endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) : - luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars); - luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ - luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1); + if (isnum) /* numeric for? */ + endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP); + else { /* generic for */ + luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); + luaK_fixline(fs, line); + endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP); + } + luaK_patchlist(fs, endfor, prep + 1); + luaK_fixline(fs, line); } @@ -1068,10 +1120,10 @@ static void fornum (LexState *ls, TString *varname, int line) { /* fornum -> NAME = exp1,exp1[,exp1] forbody */ FuncState *fs = ls->fs; int base = fs->freereg; - new_localvarliteral(ls, "(for index)", 0); - new_localvarliteral(ls, "(for limit)", 1); - new_localvarliteral(ls, "(for step)", 2); - new_localvar(ls, varname, 3); + new_localvarliteral(ls, "(for index)"); + new_localvarliteral(ls, "(for limit)"); + new_localvarliteral(ls, "(for step)"); + new_localvar(ls, varname); checknext(ls, '='); exp1(ls); /* initial value */ checknext(ls, ','); @@ -1079,7 +1131,7 @@ static void fornum (LexState *ls, TString *varname, int line) { if (testnext(ls, ',')) exp1(ls); /* optional step */ else { /* default step = 1 */ - luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1)); + luaK_codek(fs, fs->freereg, luaK_numberK(fs, 1)); luaK_reserveregs(fs, 1); } forbody(ls, base, line, 1, 1); @@ -1090,17 +1142,19 @@ static void forlist (LexState *ls, TString *indexname) { /* forlist -> NAME {,NAME} IN explist1 forbody */ FuncState *fs = ls->fs; expdesc e; - int nvars = 0; + int nvars = 4; /* gen, state, control, plus at least one declared var */ int line; int base = fs->freereg; /* create control variables */ - new_localvarliteral(ls, "(for generator)", nvars++); - new_localvarliteral(ls, "(for state)", nvars++); - new_localvarliteral(ls, "(for control)", nvars++); + new_localvarliteral(ls, "(for generator)"); + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for control)"); /* create declared variables */ - new_localvar(ls, indexname, nvars++); - while (testnext(ls, ',')) - new_localvar(ls, str_checkname(ls), nvars++); + new_localvar(ls, indexname); + while (testnext(ls, ',')) { + new_localvar(ls, str_checkname(ls)); + nvars++; + } checknext(ls, TK_IN); line = ls->linenumber; adjust_assign(ls, 3, explist1(ls, &e), &e); @@ -1165,14 +1219,12 @@ static void ifstat (LexState *ls, int line) { static void localfunc (LexState *ls) { expdesc v, b; FuncState *fs = ls->fs; - new_localvar(ls, str_checkname(ls), 0); + new_localvar(ls, str_checkname(ls)); init_exp(&v, VLOCAL, fs->freereg); luaK_reserveregs(fs, 1); adjustlocalvars(ls, 1); body(ls, &b, 0, ls->linenumber); luaK_storevar(fs, &v, &b); - /* debug information will only see the variable after this point! */ - getlocvar(fs, fs->nactvar - 1).startpc = fs->pc; } @@ -1182,7 +1234,8 @@ static void localstat (LexState *ls) { int nexps; expdesc e; do { - new_localvar(ls, str_checkname(ls), nvars++); + new_localvar(ls, str_checkname(ls)); + nvars++; } while (testnext(ls, ',')); if (testnext(ls, '=')) nexps = explist1(ls, &e); @@ -1196,14 +1249,14 @@ static void localstat (LexState *ls) { static int funcname (LexState *ls, expdesc *v) { - /* funcname -> NAME {field} [`:' NAME] */ + /* funcname -> NAME {fieldsel} [`:' NAME] */ int needself = 0; singlevar(ls, v); while (ls->t.token == '.') - field(ls, v); + fieldsel(ls, v); if (ls->t.token == ':') { needself = 1; - field(ls, v); + fieldsel(ls, v); } return needself; } @@ -1221,6 +1274,24 @@ static void funcstat (LexState *ls, int line) { } +static void instat (LexState *ls, int line) { + /* instat -> IN exp DO block END */ + FuncState *fs = ls->fs; + int oldenv = fs->envreg; /* save current environment */ + BlockCnt bl; + luaX_next(ls); /* skip IN */ + enterblock(fs, &bl, 0); /* scope for environment variable */ + new_localvarliteral(ls, "(environment)"); + fs->envreg = exp1(ls); /* new environment */ + adjustlocalvars(ls, 1); + checknext(ls, TK_DO); + block(ls); + leaveblock(fs); + check_match(ls, TK_END, TK_IN, line); + fs->envreg = oldenv; /* restore outer environment */ +} + + static void exprstat (LexState *ls) { /* stat -> func | assignment */ FuncState *fs = ls->fs; @@ -1285,6 +1356,10 @@ static int statement (LexState *ls) { check_match(ls, TK_END, TK_DO, line); return 0; } + case TK_IN: { + instat(ls, line); + return 0; + } case TK_FOR: { /* stat -> forstat */ forstat(ls, line); return 0; diff --git a/src/lparser.h b/src/lparser.h index 18836afd..2ad0a509 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.57.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lparser.h,v 1.61 2009/10/11 20:02:19 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -23,8 +23,8 @@ typedef enum { VFALSE, VK, /* info = index of constant in `k' */ VKNUM, /* nval = numerical value */ - VLOCAL, /* info = local register */ - VUPVAL, /* info = index of upvalue in `upvalues' */ + VLOCAL, /* info = local register; aux = read only */ + VUPVAL, /* info = index of upvalue in 'upvalues'; aux = read only */ VGLOBAL, /* info = index of table; aux = index of global name in `k' */ VINDEXED, /* info = table register; aux = index register (or `k') */ VJMP, /* info = instruction pc */ @@ -34,6 +34,7 @@ typedef enum { VVARARG /* info = instruction pc */ } expkind; + typedef struct expdesc { expkind k; union { @@ -45,10 +46,17 @@ typedef struct expdesc { } expdesc; -typedef struct upvaldesc { - lu_byte k; - lu_byte info; -} upvaldesc; +typedef struct vardesc { + unsigned short idx; +} vardesc; + + +/* list of all active local variables */ +typedef struct Varlist { + vardesc *actvar; + int nactvar; + int actvarsize; +} Varlist; struct BlockCnt; /* defined in lparser.c */ @@ -68,15 +76,16 @@ typedef struct FuncState { int freereg; /* first free register */ int nk; /* number of elements in `k' */ int np; /* number of elements in `p' */ + int firstlocal; /* index of first local var of this function */ short nlocvars; /* number of elements in `locvars' */ lu_byte nactvar; /* number of active local variables */ - upvaldesc upvalues[LUAI_MAXUPVALUES]; /* upvalues */ - unsigned short actvar[LUAI_MAXVARS]; /* declared-variable stack */ + lu_byte nups; /* number of upvalues */ + lu_byte envreg; /* register holding current lexical environment */ } FuncState; LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - const char *name); + Varlist *varl, const char *name); #endif diff --git a/src/lstate.c b/src/lstate.c index 4313b83a..426fdec6 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.36.1.2 2008/01/03 15:20:39 roberto Exp $ +** $Id: lstate.c,v 2.68 2009/12/22 15:32:50 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -12,6 +12,7 @@ #include "lua.h" +#include "lapi.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" @@ -24,55 +25,139 @@ #include "ltm.h" -#define state_size(x) (sizeof(x) + LUAI_EXTRASPACE) -#define fromstate(l) (cast(lu_byte *, (l)) - LUAI_EXTRASPACE) -#define tostate(l) (cast(lua_State *, cast(lu_byte *, l) + LUAI_EXTRASPACE)) +#if !defined(LUAI_GCPAUSE) +#define LUAI_GCPAUSE 162 /* 162% (wait memory to double before next GC) */ +#endif + +#if !defined(LUAI_GCMUL) +#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ +#endif + + +/* +** thread state + extra space +*/ +typedef struct LX { +#if defined(LUAI_EXTRASPACE) + char buff[LUAI_EXTRASPACE]; +#endif + lua_State l; +} LX; /* ** Main thread combines a thread state and the global state */ typedef struct LG { - lua_State l; + LX l; global_State g; } LG; - + + + +#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l))) + + + +/* +** maximum number of nested calls made by error-handling function +*/ +#define LUAI_EXTRACALLS 10 + + +CallInfo *luaE_extendCI (lua_State *L) { + CallInfo *ci = luaM_new(L, CallInfo); + lua_assert(L->ci->next == NULL); + L->ci->next = ci; + ci->previous = L->ci; + ci->next = NULL; + return ci; +} + + +void luaE_freeCI (lua_State *L) { + CallInfo *ci = L->ci; + CallInfo *next = ci->next; + ci->next = NULL; + while ((ci = next) != NULL) { + next = ci->next; + luaM_free(L, ci); + } +} static void stack_init (lua_State *L1, lua_State *L) { - /* initialize CallInfo array */ - L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); - L1->ci = L1->base_ci; - L1->size_ci = BASIC_CI_SIZE; - L1->end_ci = L1->base_ci + L1->size_ci - 1; + int i; /* initialize stack array */ - L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue); - L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; + L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue); + L1->stacksize = BASIC_STACK_SIZE; + for (i = 0; i < BASIC_STACK_SIZE; i++) + setnilvalue(L1->stack + i); /* erase new stack */ L1->top = L1->stack; - L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; + L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK; /* initialize first ci */ L1->ci->func = L1->top; - setnilvalue(L1->top++); /* `function' entry for this `ci' */ - L1->base = L1->ci->base = L1->top; + setnilvalue(L1->top++); /* 'function' entry for this 'ci' */ L1->ci->top = L1->top + LUA_MINSTACK; + L1->ci->callstatus = 0; +} + + +static void freestack (lua_State *L) { + L->ci = &L->base_ci; /* reset 'ci' list */ + luaE_freeCI(L); + luaM_freearray(L, L->stack, L->stacksize); +} + + +/* +** Calls the function in variable pointed to by userdata in first argument +** (Userdata cannot point directly to the function because pointer to +** function is not compatible with void*.) +*/ +static int cpcall (lua_State *L) { + lua_CFunction f = *(lua_CFunction *)lua_touserdata(L, 1); + lua_remove(L, 1); /* remove f from stack */ + /* restore original environment for 'cpcall' */ + lua_pushglobaltable(L); + lua_replace(L, LUA_ENVIRONINDEX); + return f(L); } -static void freestack (lua_State *L, lua_State *L1) { - luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo); - luaM_freearray(L, L1->stack, L1->stacksize, TValue); +/* +** Create registry table and its predefined values +*/ +static void init_registry (lua_State *L, global_State *g) { + Closure *cp; + TValue mt; + /* create registry */ + Table *registry = luaH_new(L); + sethvalue(L, &g->l_registry, registry); + luaH_resize(L, registry, LUA_RIDX_LAST, 0); + /* registry[LUA_RIDX_MAINTHREAD] = L */ + setthvalue(L, &mt, L); + setobj2t(L, luaH_setint(L, registry, LUA_RIDX_MAINTHREAD), &mt); + /* registry[LUA_RIDX_CPCALL] = cpcall */ + cp = luaF_newCclosure(L, 0, g->l_gt); + cp->c.f = cpcall; + setclvalue(L, &mt, cp); + setobj2t(L, luaH_setint(L, registry, LUA_RIDX_CPCALL), &mt); + /* registry[LUA_RIDX_GLOBALS] = l_gt */ + sethvalue(L, &mt, g->l_gt); + setobj2t(L, luaH_setint(L, registry, LUA_RIDX_GLOBALS), &mt); } /* -** open parts that may cause memory-allocation errors +** open parts of the state that may cause memory-allocation errors */ static void f_luaopen (lua_State *L, void *ud) { global_State *g = G(L); UNUSED(ud); stack_init(L, L); /* init stack */ - sethvalue(L, gt(L), luaH_new(L, 0, 2)); /* table of globals */ - sethvalue(L, registry(L), luaH_new(L, 0, 2)); /* registry */ + g->l_gt = luaH_new(L); /* table of globals */ + init_registry(L, g); luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ luaT_init(L); luaX_init(L); @@ -81,6 +166,10 @@ static void f_luaopen (lua_State *L, void *ud) { } +/* +** preinitialize a state with consistent values without allocating +** any memory (to avoid errors) +*/ static void preinit_state (lua_State *L, global_State *g) { G(L) = g; L->stack = NULL; @@ -92,51 +181,53 @@ static void preinit_state (lua_State *L, global_State *g) { L->allowhook = 1; resethookcount(L); L->openupval = NULL; - L->size_ci = 0; - L->nCcalls = L->baseCcalls = 0; - L->status = 0; - L->base_ci = L->ci = NULL; - L->savedpc = NULL; + L->nny = 1; + L->status = LUA_OK; + L->base_ci.next = L->base_ci.previous = NULL; + L->ci = &L->base_ci; L->errfunc = 0; - setnilvalue(gt(L)); } static void close_state (lua_State *L) { global_State *g = G(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ - luaC_freeall(L); /* collect all objects */ - lua_assert(g->rootgc == obj2gco(L)); - lua_assert(g->strt.nuse == 0); - luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); + luaC_freeallobjects(L); /* collect all objects */ + luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); luaZ_freebuffer(L, &g->buff); - freestack(L, L); + freestack(L); lua_assert(g->totalbytes == sizeof(LG)); - (*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0); + (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); } -lua_State *luaE_newthread (lua_State *L) { - lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); - luaC_link(L, obj2gco(L1), LUA_TTHREAD); +LUA_API lua_State *lua_newthread (lua_State *L) { + lua_State *L1; + lua_lock(L); + luaC_checkGC(L); + L1 = &luaC_newobj(L, LUA_TTHREAD, sizeof(LX), NULL, offsetof(LX, l))->th; + setthvalue(L, L->top, L1); + api_incr_top(L); preinit_state(L1, G(L)); stack_init(L1, L); /* init stack */ - setobj2n(L, gt(L1), gt(L)); /* share table of globals */ L1->hookmask = L->hookmask; L1->basehookcount = L->basehookcount; L1->hook = L->hook; resethookcount(L1); lua_assert(iswhite(obj2gco(L1))); + lua_unlock(L); + luai_userstatethread(L, L1); return L1; } void luaE_freethread (lua_State *L, lua_State *L1) { + LX *l = fromstate(L1); luaF_close(L1, L1->stack); /* close all upvalues for this thread */ lua_assert(L1->openupval == NULL); luai_userstatefree(L1); - freestack(L, L1); - luaM_freemem(L, fromstate(L1), state_size(lua_State)); + freestack(L1); + luaM_free(L, l); } @@ -144,14 +235,16 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { int i; lua_State *L; global_State *g; - void *l = (*f)(ud, NULL, 0, state_size(LG)); + LG *l = cast(LG *, (*f)(ud, NULL, 0, sizeof(LG))); if (l == NULL) return NULL; - L = tostate(l); - g = &((LG *)L)->g; + L = &l->l.l; + g = &l->g; L->next = NULL; L->tt = LUA_TTHREAD; g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT); L->marked = luaC_white(g); + g->gckind = KGC_NORMAL; + g->nCcalls = 0; set2bits(L->marked, FIXEDBIT, SFIXEDBIT); preinit_state(L, g); g->frealloc = f; @@ -159,27 +252,23 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->mainthread = L; g->uvhead.u.l.prev = &g->uvhead; g->uvhead.u.l.next = &g->uvhead; - g->GCthreshold = 0; /* mark it as unfinished state */ + g->GCthreshold = MAX_LUMEM; /* no GC while building state */ g->strt.size = 0; g->strt.nuse = 0; g->strt.hash = NULL; - setnilvalue(registry(L)); + setnilvalue(&g->l_registry); + g->l_gt = NULL; luaZ_initbuffer(L, &g->buff); g->panic = NULL; + g->version = lua_version(NULL); g->gcstate = GCSpause; g->rootgc = obj2gco(L); - g->sweepstrgc = 0; - g->sweepgc = &g->rootgc; - g->gray = NULL; - g->grayagain = NULL; - g->weak = NULL; - g->tmudata = NULL; + g->tobefnz = NULL; g->totalbytes = sizeof(LG); g->gcpause = LUAI_GCPAUSE; g->gcstepmul = LUAI_GCMUL; - g->gcdept = 0; for (i=0; i<NUM_TAGS; i++) g->mt[i] = NULL; - if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { + if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { /* memory allocation error: free partial state */ close_state(L); L = NULL; @@ -190,25 +279,14 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { } -static void callallgcTM (lua_State *L, void *ud) { - UNUSED(ud); - luaC_callGCTM(L); /* call GC metamethods for all udata */ -} - - LUA_API void lua_close (lua_State *L) { L = G(L)->mainthread; /* only the main thread can be closed */ lua_lock(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ - luaC_separateudata(L, 1); /* separate udata that have GC metamethods */ - L->errfunc = 0; /* no error function during GC metamethods */ - do { /* repeat until no more errors */ - L->ci = L->base_ci; - L->base = L->top = L->ci->base; - L->nCcalls = L->baseCcalls = 0; - } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); - lua_assert(G(L)->tmudata == NULL); + luaC_separateudata(L, 1); /* separate all udata with GC metamethods */ + lua_assert(L->next == NULL); luai_userstateclose(L); close_state(L); } + diff --git a/src/lstate.h b/src/lstate.h index 3bc575b6..4ca3e02f 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.24.1.2 2008/01/03 15:20:39 roberto Exp $ +** $Id: lstate.h,v 2.52 2009/12/22 15:32:50 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -14,15 +14,35 @@ #include "lzio.h" +/* -struct lua_longjmp; /* defined in ldo.c */ +** Some notes about garbage-collected objects: All objects in Lua must +** be kept somehow accessible until being freed. +** +** Lua keeps most objects linked in list g->rootgc. The link uses field +** 'next' of the CommonHeader. +** +** Strings are kept in several lists headed by the array g->strt.hash. +** +** Open upvalues are not subject to independent garbage collection. They +** are collected together with their respective threads. Lua keeps a +** double-linked list with all open upvalues (g->uvhead) so that it can +** mark objects referred by them. (They are always gray, so they must +** be remarked in the atomic step. Usually their contents would be marked +** when traversing the respective threads, but the thread may already be +** dead, while the upvalue is still accessible through closures.) +** +** Userdata with finalizers are kept in the list g->rootgc, but after +** the mainthread, which should be otherwise the last element in the +** list, as it was the first one inserted there. +** +** The list g->tobefnz links all userdata being finalized. +*/ -/* table of globals */ -#define gt(L) (&L->l_gt) -/* registry */ -#define registry(L) (&G(L)->l_registry) +struct lua_longjmp; /* defined in ldo.c */ + /* extra stack space to handle TM calls and some other extras */ @@ -34,6 +54,11 @@ struct lua_longjmp; /* defined in ldo.c */ #define BASIC_STACK_SIZE (2*LUA_MINSTACK) +/* kinds of Garbage Collection */ +#define KGC_NORMAL 0 +#define KGC_FORCED 1 /* gc was forced by the program */ +#define KGC_EMERGENCY 2 /* gc was forced by an allocation failure */ + typedef struct stringtable { GCObject **hash; @@ -46,20 +71,44 @@ typedef struct stringtable { ** informations about a call */ typedef struct CallInfo { - StkId base; /* base for this function */ StkId func; /* function index in the stack */ StkId top; /* top for this function */ - const Instruction *savedpc; - int nresults; /* expected number of results from this function */ - int tailcalls; /* number of tail calls lost under this entry */ + struct CallInfo *previous, *next; /* dynamic call link */ + short nresults; /* expected number of results from a call */ + lu_byte callstatus; + union { + struct { /* only for Lua functions */ + StkId base; /* base for this function */ + const Instruction *savedpc; + } l; + struct { /* only for C functions */ + int ctx; /* context info. in case of yields */ + lua_CFunction k; /* continuation in case of yields */ + ptrdiff_t old_errfunc; + ptrdiff_t oldtop; + lu_byte old_allowhook; + lu_byte status; + } c; + } u; } CallInfo; +/* +** Bits in CallInfo status +*/ +#define CIST_LUA (1<<0) /* call is running a Lua function */ +#define CIST_HOOKED (1<<1) /* call is running a debug hook */ +#define CIST_REENTRY (1<<2) /* call is running on same invocation of + luaV_execute of previous call */ +#define CIST_YIELDED (1<<3) /* call reentered after suspension */ +#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ +#define CIST_STAT (1<<5) /* call has an error status (pcall) */ +#define CIST_TAIL (1<<6) /* call was tail called */ + #define curr_func(L) (clvalue(L->ci->func)) #define ci_func(ci) (clvalue((ci)->func)) -#define f_isLua(ci) (!ci_func(ci)->c.isC) -#define isLua(ci) (ttisfunction((ci)->func) && f_isLua(ci)) +#define isLua(ci) ((ci)->callstatus & CIST_LUA) /* @@ -69,26 +118,30 @@ typedef struct global_State { stringtable strt; /* hash table for strings */ lua_Alloc frealloc; /* function to reallocate memory */ void *ud; /* auxiliary data to `frealloc' */ + unsigned short nCcalls; /* number of nested C calls */ lu_byte currentwhite; lu_byte gcstate; /* state of garbage collector */ + lu_byte gckind; /* kind of GC running */ int sweepstrgc; /* position of sweep in `strt' */ GCObject *rootgc; /* list of all collectable objects */ - GCObject **sweepgc; /* position of sweep in `rootgc' */ + GCObject **sweepgc; /* current position of sweep */ GCObject *gray; /* list of gray objects */ GCObject *grayagain; /* list of objects to be traversed atomically */ - GCObject *weak; /* list of weak tables (to be cleared) */ - GCObject *tmudata; /* last element of list of userdata to be GC */ - Mbuffer buff; /* temporary buffer for string concatentation */ - lu_mem GCthreshold; + GCObject *weak; /* list of tables with weak values */ + GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ + GCObject *allweak; /* list of all-weak tables */ + GCObject *tobefnz; /* list of userdata to be GC */ + Mbuffer buff; /* temporary buffer for string concatenation */ + lu_mem GCthreshold; /* when totalbytes > GCthreshold, run GC step */ lu_mem totalbytes; /* number of bytes currently allocated */ - lu_mem estimate; /* an estimate of number of bytes actually in use */ - lu_mem gcdept; /* how much GC is `behind schedule' */ int gcpause; /* size of pause between successive GCs */ int gcstepmul; /* GC `granularity' */ lua_CFunction panic; /* to be called in unprotected errors */ TValue l_registry; + struct Table *l_gt; /* table of globals */ struct lua_State *mainthread; UpVal uvhead; /* head of double-linked list of all open upvalues */ + const lua_Number *version; /* pointer to version number */ struct Table *mt[NUM_TAGS]; /* metatables for basic types */ TString *tmname[TM_N]; /* array with tag-method names */ } global_State; @@ -101,29 +154,24 @@ struct lua_State { CommonHeader; lu_byte status; StkId top; /* first free slot in the stack */ - StkId base; /* base of current function */ global_State *l_G; CallInfo *ci; /* call info for current function */ - const Instruction *savedpc; /* `savedpc' of current function */ + const Instruction *oldpc; /* last pc traced */ StkId stack_last; /* last free slot in the stack */ StkId stack; /* stack base */ - CallInfo *end_ci; /* points after end of ci array*/ - CallInfo *base_ci; /* array of CallInfo's */ int stacksize; - int size_ci; /* size of array `base_ci' */ - unsigned short nCcalls; /* number of nested C calls */ - unsigned short baseCcalls; /* nested C calls when resuming coroutine */ + unsigned short nny; /* number of non-yieldable calls in stack */ lu_byte hookmask; lu_byte allowhook; int basehookcount; int hookcount; lua_Hook hook; - TValue l_gt; /* table of globals */ TValue env; /* temporary place for environments */ GCObject *openupval; /* list of open upvalues in this stack */ GCObject *gclist; struct lua_longjmp *errorJmp; /* current error recover point */ ptrdiff_t errfunc; /* current error handling function (stack index) */ + CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ }; @@ -134,7 +182,7 @@ struct lua_State { ** Union of all collectable objects */ union GCObject { - GCheader gch; + GCheader gch; /* common header */ union TString ts; union Udata u; union Closure cl; @@ -145,25 +193,27 @@ union GCObject { }; +#define gch(o) (&(o)->gch) + /* macros to convert a GCObject into a specific value */ #define rawgco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) #define gco2ts(o) (&rawgco2ts(o)->tsv) #define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) #define gco2u(o) (&rawgco2u(o)->uv) #define gco2cl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl)) -#define gco2h(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) +#define gco2t(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) #define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) #define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) -#define ngcotouv(o) \ - check_exp((o) == NULL || (o)->gch.tt == LUA_TUPVAL, &((o)->uv)) #define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) /* macro to convert any Lua object into a GCObject */ #define obj2gco(v) (cast(GCObject *, (v))) -LUAI_FUNC lua_State *luaE_newthread (lua_State *L); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); +LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); +LUAI_FUNC void luaE_freeCI (lua_State *L); + #endif diff --git a/src/lstring.c b/src/lstring.c index 49113151..69b96d02 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lstring.c,v 2.16 2009/12/16 16:42:58 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -20,54 +20,54 @@ void luaS_resize (lua_State *L, int newsize) { - GCObject **newhash; - stringtable *tb; int i; - if (G(L)->gcstate == GCSsweepstring) - return; /* cannot resize during GC traverse */ - newhash = luaM_newvector(L, newsize, GCObject *); - tb = &G(L)->strt; - for (i=0; i<newsize; i++) newhash[i] = NULL; + stringtable *tb = &G(L)->strt; + /* cannot resize while GC is traversing strings */ + luaC_runtilstate(L, ~bitmask(GCSsweepstring)); + if (newsize > tb->size) { + luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *); + for (i = tb->size; i < newsize; i++) tb->hash[i] = NULL; + } /* rehash */ for (i=0; i<tb->size; i++) { GCObject *p = tb->hash[i]; + tb->hash[i] = NULL; while (p) { /* for each node in the list */ - GCObject *next = p->gch.next; /* save next */ - unsigned int h = gco2ts(p)->hash; - int h1 = lmod(h, newsize); /* new position */ - lua_assert(cast_int(h%newsize) == lmod(h, newsize)); - p->gch.next = newhash[h1]; /* chain it */ - newhash[h1] = p; + GCObject *next = gch(p)->next; /* save next */ + unsigned int h = lmod(gco2ts(p)->hash, newsize); /* new position */ + gch(p)->next = tb->hash[h]; /* chain it */ + tb->hash[h] = p; p = next; } } - luaM_freearray(L, tb->hash, tb->size, TString *); + if (newsize < tb->size) { + /* shrinking slice must be empty */ + lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL); + luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *); + } tb->size = newsize; - tb->hash = newhash; } static TString *newlstr (lua_State *L, const char *str, size_t l, unsigned int h) { + size_t totalsize; /* total size of TString object */ + GCObject **list; /* (pointer to) list where it will be inserted */ TString *ts; - stringtable *tb; + stringtable *tb = &G(L)->strt; if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) luaM_toobig(L); - ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString))); + if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) + luaS_resize(L, tb->size*2); /* too crowded */ + totalsize = sizeof(TString) + ((l + 1) * sizeof(char)); + list = &tb->hash[lmod(h, tb->size)]; + ts = &luaC_newobj(L, LUA_TSTRING, totalsize, list, 0)->ts; ts->tsv.len = l; ts->tsv.hash = h; - ts->tsv.marked = luaC_white(G(L)); - ts->tsv.tt = LUA_TSTRING; ts->tsv.reserved = 0; memcpy(ts+1, str, l*sizeof(char)); ((char *)(ts+1))[l] = '\0'; /* ending 0 */ - tb = &G(L)->strt; - h = lmod(h, tb->size); - ts->tsv.next = tb->hash[h]; /* chain new entry */ - tb->hash[h] = obj2gco(ts); tb->nuse++; - if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) - luaS_resize(L, tb->size*2); /* too crowded */ return ts; } @@ -81,15 +81,16 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; o != NULL; - o = o->gch.next) { + o = gch(o)->next) { TString *ts = rawgco2ts(o); - if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) { - /* string may be dead */ - if (isdead(G(L), o)) changewhite(o); + if (h == ts->tsv.hash && ts->tsv.len == l && + (memcmp(str, getstr(ts), l) == 0)) { + if (isdead(G(L), o)) /* string is dead (but was not collected yet)? */ + changewhite(o); /* resurrect it */ return ts; } } - return newlstr(L, str, l, h); /* not found */ + return newlstr(L, str, l, h); /* not found; create a new string */ } @@ -97,15 +98,10 @@ Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { Udata *u; if (s > MAX_SIZET - sizeof(Udata)) luaM_toobig(L); - u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata))); - u->uv.marked = luaC_white(G(L)); /* is not finalized */ - u->uv.tt = LUA_TUSERDATA; + u = &luaC_newobj(L, LUA_TUSERDATA, sizeof(Udata) + s, NULL, 0)->u; u->uv.len = s; u->uv.metatable = NULL; u->uv.env = e; - /* chain it on udata list (after main thread) */ - u->uv.next = G(L)->mainthread->next; - G(L)->mainthread->next = obj2gco(u); return u; } diff --git a/src/lstring.h b/src/lstring.h index 73a2ff8b..1d2e91ea 100644 --- a/src/lstring.h +++ b/src/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.43.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lstring.h,v 1.43 2005/04/25 19:24:10 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ diff --git a/src/lstrlib.c b/src/lstrlib.c index 1b4763d4..0c03b493 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp $ +** $Id: lstrlib.c,v 1.148 2010/01/04 16:37:19 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -20,6 +20,15 @@ #include "lualib.h" +/* +** maximum number of captures that a pattern can do during +** pattern-matching. This limit is arbitrary. +*/ +#if !defined(LUA_MAXCAPTURES) +#define LUA_MAXCAPTURES 32 +#endif + + /* macro to `unsign' a character */ #define uchar(c) ((unsigned char)(c)) @@ -28,27 +37,28 @@ static int str_len (lua_State *L) { size_t l; luaL_checklstring(L, 1, &l); - lua_pushinteger(L, l); + lua_pushinteger(L, (lua_Integer)l); return 1; } -static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { - /* relative string position: negative means back from end */ - if (pos < 0) pos += (ptrdiff_t)len + 1; - return (pos >= 0) ? pos : 0; +/* translate a relative string position: negative means back from end */ +static size_t posrelat (ptrdiff_t pos, size_t len) { + if (pos >= 0) return (size_t)pos; + else if (pos == -pos || (size_t)-pos > len) return 0; + else return len - ((size_t)-pos) + 1; } static int str_sub (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); - ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); + size_t start = posrelat(luaL_checkinteger(L, 2), l); + size_t end = posrelat(luaL_optinteger(L, 3, -1), l); if (start < 1) start = 1; - if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; + if (end > l) end = l; if (start <= end) - lua_pushlstring(L, s+start-1, end-start+1); + lua_pushlstring(L, s + start - 1, end - start + 1); else lua_pushliteral(L, ""); return 1; } @@ -106,11 +116,11 @@ static int str_rep (lua_State *L) { static int str_byte (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); - ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); + size_t posi = posrelat(luaL_optinteger(L, 2, 1), l); + size_t pose = posrelat(luaL_optinteger(L, 3, posi), l); int n, i; - if (posi <= 0) posi = 1; - if ((size_t)pose > l) pose = l; + if (posi < 1) posi = 1; + if (pose > l) pose = l; if (posi > pose) return 0; /* empty interval; return no values */ n = (int)(pose - posi + 1); if (posi + n <= pose) /* overflow? */ @@ -186,7 +196,7 @@ typedef struct MatchState { static int check_capture (MatchState *ms, int l) { l -= '1'; if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) - return luaL_error(ms->L, "invalid capture index"); + return luaL_error(ms->L, "invalid capture index %%%d", l + 1); return l; } @@ -374,7 +384,15 @@ static const char *match (MatchState *ms, const char *s, const char *p) { case ')': { /* end capture */ return end_capture(ms, s, p+1); } - case L_ESC: { + case '\0': { /* end of pattern */ + return s; /* match succeeded */ + } + case '$': { + if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ + return (s == ms->src_end) ? s : NULL; /* check end of string */ + else goto dflt; + } + case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ switch (*(p+1)) { case 'b': { /* balanced string? */ s = matchbalance(ms, s, p+2); @@ -393,25 +411,17 @@ static const char *match (MatchState *ms, const char *s, const char *p) { !matchbracketclass(uchar(*s), p, ep-1)) return NULL; p=ep; goto init; /* else return match(ms, s, ep); */ } - default: { - if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ - s = match_capture(ms, s, uchar(*(p+1))); - if (s == NULL) return NULL; - p+=2; goto init; /* else return match(ms, s, p+2) */ - } - goto dflt; /* case default */ + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': { /* capture results (%0-%9)? */ + s = match_capture(ms, s, uchar(*(p+1))); + if (s == NULL) return NULL; + p+=2; goto init; /* else return match(ms, s, p+2) */ } + default: break; /* go through to 'dflt' */ } } - case '\0': { /* end of pattern */ - return s; /* match succeeded */ - } - case '$': { - if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ - return (s == ms->src_end) ? s : NULL; /* check end of string */ - else goto dflt; - } - default: dflt: { /* it is a pattern item */ + default: dflt: { /* pattern class plus optional sufix */ const char *ep = classend(ms, p); /* points to what is next */ int m = s<ms->src_end && singlematch(uchar(*s), p, ep); switch (*ep) { @@ -496,33 +506,36 @@ static int str_find_aux (lua_State *L, int find) { size_t l1, l2; const char *s = luaL_checklstring(L, 1, &l1); const char *p = luaL_checklstring(L, 2, &l2); - ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; - if (init < 0) init = 0; - else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; + size_t init = posrelat(luaL_optinteger(L, 3, 1), l1); + if (init < 1) init = 1; + else if (init > l1 + 1) { /* start after string's end? */ + lua_pushnil(L); /* cannot find anything */ + return 1; + } if (find && (lua_toboolean(L, 4) || /* explicit request? */ strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ /* do a plain search */ - const char *s2 = lmemfind(s+init, l1-init, p, l2); + const char *s2 = lmemfind(s + init - 1, l1 - init + 1, p, l2); if (s2) { - lua_pushinteger(L, s2-s+1); - lua_pushinteger(L, s2-s+l2); + lua_pushinteger(L, s2 - s + 1); + lua_pushinteger(L, s2 - s + l2); return 2; } } else { MatchState ms; int anchor = (*p == '^') ? (p++, 1) : 0; - const char *s1=s+init; + const char *s1 = s + init - 1; ms.L = L; ms.src_init = s; - ms.src_end = s+l1; + ms.src_end = s + l1; do { const char *res; ms.level = 0; if ((res=match(&ms, s1, p)) != NULL) { if (find) { - lua_pushinteger(L, s1-s+1); /* start */ - lua_pushinteger(L, res-s); /* end */ + lua_pushinteger(L, s1 - s + 1); /* start */ + lua_pushinteger(L, res - s); /* end */ return push_captures(&ms, NULL, 0) + 2; } else @@ -596,8 +609,12 @@ static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, luaL_addchar(b, news[i]); else { i++; /* skip ESC */ - if (!isdigit(uchar(news[i]))) + if (!isdigit(uchar(news[i]))) { + if (news[i] != L_ESC) + luaL_error(ms->L, "invalid use of " LUA_QL("%c") + " in replacement string", L_ESC); luaL_addchar(b, news[i]); + } else if (news[i] == '0') luaL_addlstring(b, s, e - s); else { @@ -610,14 +627,9 @@ static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, - const char *e) { + const char *e, int tr) { lua_State *L = ms->L; - switch (lua_type(L, 3)) { - case LUA_TNUMBER: - case LUA_TSTRING: { - add_s(ms, b, s, e); - return; - } + switch (tr) { case LUA_TFUNCTION: { int n; lua_pushvalue(L, 3); @@ -630,13 +642,17 @@ static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, lua_gettable(L, 3); break; } + default: { /* LUA_TNUMBER or LUA_TSTRING */ + add_s(ms, b, s, e); + return; + } } if (!lua_toboolean(L, -1)) { /* nil or false? */ lua_pop(L, 1); lua_pushlstring(L, s, e - s); /* keep original text */ } else if (!lua_isstring(L, -1)) - luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); + luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); luaL_addvalue(b); /* add result to accumulator */ } @@ -645,10 +661,10 @@ static int str_gsub (lua_State *L) { size_t srcl; const char *src = luaL_checklstring(L, 1, &srcl); const char *p = luaL_checkstring(L, 2); - int tr = lua_type(L, 3); - int max_s = luaL_optint(L, 4, srcl+1); + int tr = lua_type(L, 3); + size_t max_s = luaL_optinteger(L, 4, srcl+1); int anchor = (*p == '^') ? (p++, 1) : 0; - int n = 0; + size_t n = 0; MatchState ms; luaL_Buffer b; luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || @@ -664,7 +680,7 @@ static int str_gsub (lua_State *L) { e = match(&ms, src, p); if (e) { n++; - add_value(&ms, &b, src, e); + add_value(&ms, &b, src, e, tr); } if (e && e>src) /* non empty match? */ src = e; /* skip it */ @@ -682,6 +698,24 @@ static int str_gsub (lua_State *L) { /* }====================================================== */ +/* +** length modifier for integer conversions ** in 'string.format' and +** integer type corresponding to the previous length +*/ + +#if defined(LUA_USELONGLONG) + +#define LUA_INTFRMLEN "ll" +#define LUA_INTFRM_T long long + +#else + +#define LUA_INTFRMLEN "l" +#define LUA_INTFRM_T long + +#endif + + /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ #define MAX_ITEM 512 /* valid flags in a format specification */ @@ -698,25 +732,20 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { const char *s = luaL_checklstring(L, arg, &l); luaL_addchar(b, '"'); while (l--) { - switch (*s) { - case '"': case '\\': case '\n': { - luaL_addchar(b, '\\'); - luaL_addchar(b, *s); - break; - } - case '\r': { - luaL_addlstring(b, "\\r", 2); - break; - } - case '\0': { - luaL_addlstring(b, "\\000", 4); - break; - } - default: { - luaL_addchar(b, *s); - break; - } + if (*s == '"' || *s == '\\' || *s == '\n') { + luaL_addchar(b, '\\'); + luaL_addchar(b, *s); } + else if (*s == '\0' || iscntrl(uchar(*s))) { + char buff[10]; + if (*s != '\0' && !isdigit(uchar(*(s+1)))) + sprintf(buff, "\\%d", uchar(*s)); + else + sprintf(buff, "\\%03d", uchar(*s)); + luaL_addstring(b, buff); + } + else + luaL_addchar(b, *s); s++; } luaL_addchar(b, '"'); @@ -737,7 +766,7 @@ static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { if (isdigit(uchar(*p))) luaL_error(L, "invalid format (width or precision too long)"); *(form++) = '%'; - strncpy(form, strfrmt, p - strfrmt + 1); + memcpy(form, strfrmt, p - strfrmt + 1); form += p - strfrmt + 1; *form = '\0'; return p; @@ -772,17 +801,16 @@ static int str_format (lua_State *L) { strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { - sprintf(buff, form, (int)luaL_checknumber(L, arg)); - break; - } - case 'd': case 'i': { - addintlen(form); - sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); + sprintf(buff, form, luaL_checkint(L, arg)); break; } + case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { + lua_Number n = luaL_checknumber(L, arg); + LUA_INTFRM_T r = (n < 0) ? (LUA_INTFRM_T)n : + (LUA_INTFRM_T)(unsigned LUA_INTFRM_T)n; addintlen(form); - sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); + sprintf(buff, form, r); break; } case 'e': case 'E': case 'f': @@ -857,12 +885,8 @@ static void createmetatable (lua_State *L) { /* ** Open string library */ -LUALIB_API int luaopen_string (lua_State *L) { +LUAMOD_API int luaopen_string (lua_State *L) { luaL_register(L, LUA_STRLIBNAME, strlib); -#if defined(LUA_COMPAT_GFIND) - lua_getfield(L, -1, "gmatch"); - lua_setfield(L, -2, "gfind"); -#endif createmetatable(L); return 1; } diff --git a/src/ltable.c b/src/ltable.c index ec84f4fa..78ff1d74 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.32.1.2 2007/12/28 15:32:23 roberto Exp $ +** $Id: ltable.c,v 2.47 2009/12/17 15:46:44 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -18,7 +18,6 @@ ** Hence even when the load factor reaches 100%, performance remains good. */ -#include <math.h> #include <string.h> #define ltable_c @@ -48,7 +47,7 @@ #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) - + #define hashstr(t,str) hashpow2(t, (str)->tsv.hash) #define hashboolean(t,p) hashpow2(t, p) @@ -72,9 +71,11 @@ #define dummynode (&dummynode_) +#define isdummy(n) ((n) == dummynode) + static const Node dummynode_ = { - {{NULL}, LUA_TNIL}, /* value */ - {{{NULL}, LUA_TNIL, NULL}} /* key */ + {NILCONSTANT}, /* value */ + {{NILCONSTANT, NULL}} /* key */ }; @@ -82,13 +83,13 @@ static const Node dummynode_ = { ** hash for lua_Numbers */ static Node *hashnum (const Table *t, lua_Number n) { - unsigned int a[numints]; int i; - if (luai_numeq(n, 0)) /* avoid problems with -0 */ - return gnode(t, 0); - memcpy(a, &n, sizeof(a)); - for (i = 1; i < numints; i++) a[0] += a[i]; - return hashmod(t, a[0]); + luai_hashnum(i, n); + if (i < 0) { + i = -i; /* must be a positive value */ + if (i < 0) i = 0; /* handle INT_MIN */ + } + return hashmod(t, i); } @@ -132,7 +133,7 @@ static int arrayindex (const TValue *key) { /* ** returns the index of a `key' for table traversals. First goes all ** elements in the array part, then elements in the hash part. The -** beginning of a traversal is signalled by -1. +** beginning of a traversal is signaled by -1. */ static int findindex (lua_State *L, Table *t, StkId key) { int i; @@ -211,7 +212,7 @@ static int computesizes (int nums[], int *narray) { static int countint (const TValue *key, int *nums) { int k = arrayindex(key); if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ - nums[ceillog2(k)]++; /* count as such */ + nums[luaO_ceillog2(k)]++; /* count as such */ return 1; } else @@ -277,7 +278,7 @@ static void setnodevector (lua_State *L, Table *t, int size) { } else { int i; - lsize = ceillog2(size); + lsize = luaO_ceillog2(size); if (lsize > MAXBITS) luaG_runerror(L, "table overflow"); size = twoto(lsize); @@ -294,7 +295,7 @@ static void setnodevector (lua_State *L, Table *t, int size) { } -static void resize (lua_State *L, Table *t, int nasize, int nhsize) { +void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { int i; int oldasize = t->sizearray; int oldhsize = t->lsizenode; @@ -302,13 +303,13 @@ static void resize (lua_State *L, Table *t, int nasize, int nhsize) { if (nasize > oldasize) /* array part must grow? */ setarrayvector(L, t, nasize); /* create new hash part with appropriate size */ - setnodevector(L, t, nhsize); + setnodevector(L, t, nhsize); if (nasize < oldasize) { /* array part must shrink? */ t->sizearray = nasize; /* re-insert elements from vanishing slice */ for (i=nasize; i<oldasize; i++) { if (!ttisnil(&t->array[i])) - setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]); + setobjt2t(L, luaH_setint(L, t, i+1), &t->array[i]); } /* shrink array */ luaM_reallocvector(L, t->array, oldasize, nasize, TValue); @@ -319,14 +320,14 @@ static void resize (lua_State *L, Table *t, int nasize, int nhsize) { if (!ttisnil(gval(old))) setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); } - if (nold != dummynode) - luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ + if (!isdummy(nold)) + luaM_freearray(L, nold, twoto(oldhsize)); /* free old array */ } void luaH_resizearray (lua_State *L, Table *t, int nasize) { - int nsize = (t->node == dummynode) ? 0 : sizenode(t); - resize(L, t, nasize, nsize); + int nsize = isdummy(t->node) ? 0 : sizenode(t); + luaH_resize(L, t, nasize, nsize); } @@ -345,7 +346,7 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) { /* compute new size for array part */ na = computesizes(nums, &nasize); /* resize the table to new computed sizes */ - resize(L, t, nasize, totaluse - na); + luaH_resize(L, t, nasize, totaluse - na); } @@ -355,32 +356,28 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) { */ -Table *luaH_new (lua_State *L, int narray, int nhash) { - Table *t = luaM_new(L, Table); - luaC_link(L, obj2gco(t), LUA_TTABLE); +Table *luaH_new (lua_State *L) { + Table *t = &luaC_newobj(L, LUA_TTABLE, sizeof(Table), NULL, 0)->h; t->metatable = NULL; t->flags = cast_byte(~0); - /* temporary values (kept only if some malloc fails) */ t->array = NULL; t->sizearray = 0; - t->lsizenode = 0; - t->node = cast(Node *, dummynode); - setarrayvector(L, t, narray); - setnodevector(L, t, nhash); + setnodevector(L, t, 0); return t; } void luaH_free (lua_State *L, Table *t) { - if (t->node != dummynode) - luaM_freearray(L, t->node, sizenode(t), Node); - luaM_freearray(L, t->array, t->sizearray, TValue); + if (!isdummy(t->node)) + luaM_freearray(L, t->node, sizenode(t)); + luaM_freearray(L, t->array, t->sizearray); luaM_free(L, t); } static Node *getfreepos (Table *t) { - while (t->lastfree-- > t->node) { + while (t->lastfree > t->node) { + t->lastfree--; if (ttisnil(gkey(t->lastfree))) return t->lastfree; } @@ -390,22 +387,22 @@ static Node *getfreepos (Table *t) { /* -** inserts a new key into a hash table; first, check whether key's main -** position is free. If not, check whether colliding node is in its main -** position or not: if it is not, move colliding node to an empty place and -** put new key in its main position; otherwise (colliding node is in its main -** position), new key goes to an empty position. +** inserts a new key into a hash table; first, check whether key's main +** position is free. If not, check whether colliding node is in its main +** position or not: if it is not, move colliding node to an empty place and +** put new key in its main position; otherwise (colliding node is in its main +** position), new key goes to an empty position. */ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { Node *mp = mainposition(t, key); - if (!ttisnil(gval(mp)) || mp == dummynode) { + if (!ttisnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */ Node *othern; Node *n = getfreepos(t); /* get a free place */ if (n == NULL) { /* cannot find a free place? */ rehash(L, t, key); /* grow table */ return luaH_set(L, t, key); /* re-insert key into grown table */ } - lua_assert(n != dummynode); + lua_assert(!isdummy(n)); othern = mainposition(t, key2tval(mp)); if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ @@ -422,7 +419,7 @@ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { mp = n; } } - gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; + setobj2t(L, gkey(mp), key); luaC_barriert(L, t, key); lua_assert(ttisnil(gval(mp))); return gval(mp); @@ -432,7 +429,7 @@ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { /* ** search function for integers */ -const TValue *luaH_getnum (Table *t, int key) { +const TValue *luaH_getint (Table *t, int key) { /* (1 <= key && key <= t->sizearray) */ if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) return &t->array[key-1]; @@ -475,7 +472,7 @@ const TValue *luaH_get (Table *t, const TValue *key) { lua_Number n = nvalue(key); lua_number2int(k, n); if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ - return luaH_getnum(t, k); /* use specialized version */ + return luaH_getint(t, k); /* use specialized version */ /* else go through */ } default: { @@ -498,15 +495,15 @@ TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { return cast(TValue *, p); else { if (ttisnil(key)) luaG_runerror(L, "table index is nil"); - else if (ttisnumber(key) && luai_numisnan(nvalue(key))) + else if (ttisnumber(key) && luai_numisnan(L, nvalue(key))) luaG_runerror(L, "table index is NaN"); return newkey(L, t, key); } } -TValue *luaH_setnum (lua_State *L, Table *t, int key) { - const TValue *p = luaH_getnum(t, key); +TValue *luaH_setint (lua_State *L, Table *t, int key) { + const TValue *p = luaH_getint(t, key); if (p != luaO_nilobject) return cast(TValue *, p); else { @@ -533,20 +530,20 @@ static int unbound_search (Table *t, unsigned int j) { unsigned int i = j; /* i is zero or a present index */ j++; /* find `i' and `j' such that i is present and j is not */ - while (!ttisnil(luaH_getnum(t, j))) { + while (!ttisnil(luaH_getint(t, j))) { i = j; j *= 2; if (j > cast(unsigned int, MAX_INT)) { /* overflow? */ /* table was built with bad purposes: resort to linear search */ i = 1; - while (!ttisnil(luaH_getnum(t, i))) i++; + while (!ttisnil(luaH_getint(t, i))) i++; return i - 1; } } /* now do a binary search between them */ while (j - i > 1) { unsigned int m = (i+j)/2; - if (ttisnil(luaH_getnum(t, m))) j = m; + if (ttisnil(luaH_getint(t, m))) j = m; else i = m; } return i; @@ -570,7 +567,7 @@ int luaH_getn (Table *t) { return i; } /* else must find a boundary in hash part */ - else if (t->node == dummynode) /* hash part is empty? */ + else if (isdummy(t->node)) /* hash part is empty? */ return j; /* that is easy... */ else return unbound_search(t, j); } @@ -583,6 +580,6 @@ Node *luaH_mainposition (const Table *t, const TValue *key) { return mainposition(t, key); } -int luaH_isdummy (Node *n) { return n == dummynode; } +int luaH_isdummy (Node *n) { return isdummy(n); } #endif diff --git a/src/ltable.h b/src/ltable.h index f5b9d5ea..784377ac 100644 --- a/src/ltable.h +++ b/src/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 2.10.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: ltable.h,v 2.13 2009/11/06 17:07:48 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -11,20 +11,21 @@ #define gnode(t,i) (&(t)->node[i]) -#define gkey(n) (&(n)->i_key.nk) +#define gkey(n) (&(n)->i_key.tvk) #define gval(n) (&(n)->i_val) #define gnext(n) ((n)->i_key.nk.next) #define key2tval(n) (&(n)->i_key.tvk) -LUAI_FUNC const TValue *luaH_getnum (Table *t, int key); -LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key); +LUAI_FUNC const TValue *luaH_getint (Table *t, int key); +LUAI_FUNC TValue *luaH_setint (lua_State *L, Table *t, int key); LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); LUAI_FUNC TValue *luaH_setstr (lua_State *L, Table *t, TString *key); LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); -LUAI_FUNC Table *luaH_new (lua_State *L, int narray, int lnhash); +LUAI_FUNC Table *luaH_new (lua_State *L); +LUAI_FUNC void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize); LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize); LUAI_FUNC void luaH_free (lua_State *L, Table *t); LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); diff --git a/src/ltablib.c b/src/ltablib.c index b6d9cb4a..b2360807 100644 --- a/src/ltablib.c +++ b/src/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.38.1.3 2008/02/14 16:46:58 roberto Exp $ +** $Id: ltablib.c,v 1.53 2009/12/28 16:30:31 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -16,18 +16,20 @@ #include "lualib.h" -#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n)) +#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), lua_rawlen(L, n)) static int foreachi (lua_State *L) { - int i; int n = aux_getn(L, 1); + int i; + if (lua_getctx(L, &i) == LUA_YIELD) goto poscall; luaL_checktype(L, 2, LUA_TFUNCTION); - for (i=1; i <= n; i++) { + for (i = 1; i <= n; i++) { lua_pushvalue(L, 2); /* function */ lua_pushinteger(L, i); /* 1st argument */ lua_rawgeti(L, 1, i); /* 2nd argument */ - lua_call(L, 2, 1); + lua_callk(L, 2, 1, i, foreachi); + poscall: if (!lua_isnil(L, -1)) return 1; lua_pop(L, 1); /* remove nil result */ @@ -36,23 +38,32 @@ static int foreachi (lua_State *L) { } -static int foreach (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - luaL_checktype(L, 2, LUA_TFUNCTION); - lua_pushnil(L); /* first key */ - while (lua_next(L, 1)) { - lua_pushvalue(L, 2); /* function */ - lua_pushvalue(L, -3); /* key */ - lua_pushvalue(L, -3); /* value */ - lua_call(L, 2, 1); +static int foreachcont (lua_State *L) { + for (;;) { if (!lua_isnil(L, -1)) return 1; lua_pop(L, 2); /* remove value and result */ + if (lua_next(L, 1) == 0) /* no more elements? */ + return 0; + lua_pushvalue(L, 2); /* function */ + lua_pushvalue(L, -3); /* key */ + lua_pushvalue(L, -3); /* value */ + lua_callk(L, 2, 1, 0, foreachcont); } - return 0; } +static int foreach (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checktype(L, 2, LUA_TFUNCTION); + lua_pushnil(L); /* first key */ + lua_pushnil(L); /* first value */ + lua_pushnil(L); /* first "return" */ + return foreachcont(L); +} + + +#if defined(LUA_COMPAT_MAXN) static int maxn (lua_State *L) { lua_Number max = 0; luaL_checktype(L, 1, LUA_TTABLE); @@ -67,7 +78,11 @@ static int maxn (lua_State *L) { lua_pushnumber(L, max); return 1; } - +#else +static int maxn (lua_State *L) { + return luaL_error(L, "function 'maxn' is deprecated"); +} +#endif static int getn (lua_State *L) { lua_pushinteger(L, aux_getn(L, 1)); @@ -75,18 +90,6 @@ static int getn (lua_State *L) { } -static int setn (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); -#ifndef luaL_setn - luaL_setn(L, 1, luaL_checkint(L, 2)); -#else - luaL_error(L, LUA_QL("setn") " is obsolete"); -#endif - lua_pushvalue(L, 1); - return 1; -} - - static int tinsert (lua_State *L) { int e = aux_getn(L, 1) + 1; /* first empty element */ int pos; /* where to insert new element */ @@ -109,7 +112,6 @@ static int tinsert (lua_State *L) { return luaL_error(L, "wrong number of arguments to " LUA_QL("insert")); } } - luaL_setn(L, 1, e); /* new size */ lua_rawseti(L, 1, pos); /* t[pos] = v */ return 0; } @@ -119,8 +121,7 @@ static int tremove (lua_State *L) { int e = aux_getn(L, 1); int pos = luaL_optint(L, 2, e); if (!(1 <= pos && pos <= e)) /* position is outside bounds? */ - return 0; /* nothing to remove */ - luaL_setn(L, 1, e - 1); /* t.n = n-1 */ + return 0; /* nothing to remove */ lua_rawgeti(L, 1, pos); /* result = t[pos] */ for ( ;pos<e; pos++) { lua_rawgeti(L, 1, pos+1); @@ -148,7 +149,7 @@ static int tconcat (lua_State *L) { const char *sep = luaL_optlstring(L, 2, "", &lsep); luaL_checktype(L, 1, LUA_TTABLE); i = luaL_optint(L, 3, 1); - last = luaL_opt(L, luaL_checkint, 4, luaL_getn(L, 1)); + last = luaL_opt(L, luaL_checkint, 4, (int)lua_rawlen(L, 1)); luaL_buffinit(L, &b); for (; i < last; i++) { addfield(L, &b, i); @@ -161,12 +162,51 @@ static int tconcat (lua_State *L) { } +/* +** {====================================================== +** Pack/unpack +** ======================================================= +*/ + +static int pack (lua_State *L) { + int top = lua_gettop(L); + lua_createtable(L, top, 1); /* create result table */ + /* use function environment as a temporary place to keep new table */ + lua_replace(L, LUA_ENVIRONINDEX); + lua_pushinteger(L, top); /* number of elements */ + lua_setfield(L, LUA_ENVIRONINDEX, "n"); /* t.n = number of elements */ + for (; top >= 1; top--) /* assign elements */ + lua_rawseti(L, LUA_ENVIRONINDEX, top); + lua_pushvalue(L, LUA_ENVIRONINDEX); /* return new table */ + return 1; +} + + +static int unpack (lua_State *L) { + int i, e, n; + luaL_checktype(L, 1, LUA_TTABLE); + i = luaL_optint(L, 2, 1); + e = luaL_opt(L, luaL_checkint, 3, (int)lua_rawlen(L, 1)); + if (i > e) return 0; /* empty range */ + n = e - i + 1; /* number of elements */ + if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */ + return luaL_error(L, "too many results to unpack"); + lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */ + while (i++ < e) /* push arg[i + 1...e] */ + lua_rawgeti(L, 1, i); + return n; +} + +/* }====================================================== */ + + /* ** {====================================================== ** Quicksort ** (based on `Algorithms in MODULA-3', Robert Sedgewick; ** Addison-Wesley, 1993.) +** ======================================================= */ @@ -187,7 +227,7 @@ static int sort_comp (lua_State *L, int a, int b) { return res; } else /* a < b? */ - return lua_lessthan(L, a, b); + return lua_compare(L, a, b, LUA_OPLT); } static void auxsort (lua_State *L, int l, int u) { @@ -224,12 +264,12 @@ static void auxsort (lua_State *L, int l, int u) { for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */ /* repeat ++i until a[i] >= P */ while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { - if (i>u) luaL_error(L, "invalid order function for sorting"); + if (i>=u) luaL_error(L, "invalid order function for sorting"); lua_pop(L, 1); /* remove a[i] */ } /* repeat --j until a[j] <= P */ while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { - if (j<l) luaL_error(L, "invalid order function for sorting"); + if (j<=l) luaL_error(L, "invalid order function for sorting"); lua_pop(L, 1); /* remove a[j] */ } if (j<i) { @@ -273,15 +313,21 @@ static const luaL_Reg tab_funcs[] = { {"getn", getn}, {"maxn", maxn}, {"insert", tinsert}, + {"pack", pack}, + {"unpack", unpack}, {"remove", tremove}, - {"setn", setn}, {"sort", sort}, {NULL, NULL} }; -LUALIB_API int luaopen_table (lua_State *L) { +LUAMOD_API int luaopen_table (lua_State *L) { luaL_register(L, LUA_TABLIBNAME, tab_funcs); +#if defined(LUA_COMPAT_UNPACK) + /* _G.unpack = table.unpack */ + lua_getfield(L, -1, "unpack"); + lua_setfield(L, LUA_ENVIRONINDEX, "unpack"); +#endif return 1; } @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: ltm.c,v 2.10 2009/11/19 19:06:52 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -20,7 +20,7 @@ -const char *const luaT_typenames[] = { +LUAI_DDEF const char *const luaT_typenames[] = { "nil", "boolean", "userdata", "number", "string", "table", "function", "userdata", "thread", "proto", "upval" @@ -30,9 +30,9 @@ const char *const luaT_typenames[] = { void luaT_init (lua_State *L) { static const char *const luaT_eventname[] = { /* ORDER TM */ "__index", "__newindex", - "__gc", "__mode", "__eq", + "__gc", "__mode", "__len", "__eq", "__add", "__sub", "__mul", "__div", "__mod", - "__pow", "__unm", "__len", "__lt", "__le", + "__pow", "__unm", "__lt", "__le", "__concat", "__call" }; int i; @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 2.6.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: ltm.h,v 2.8 2009/11/19 19:06:52 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -20,6 +20,7 @@ typedef enum { TM_NEWINDEX, TM_GC, TM_MODE, + TM_LEN, TM_EQ, /* last tag method with `fast' access */ TM_ADD, TM_SUB, @@ -28,7 +29,6 @@ typedef enum { TM_MOD, TM_POW, TM_UNM, - TM_LEN, TM_LT, TM_LE, TM_CONCAT, @@ -43,7 +43,7 @@ typedef enum { #define fasttm(l,et,e) gfasttm(G(l), et, e) -LUAI_DATA const char *const luaT_typenames[]; +LUAI_DDEC const char *const luaT_typenames[]; LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 roberto Exp $ +** $Id: lua.c,v 1.182 2009/12/22 16:47:12 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -18,6 +18,69 @@ #include "lualib.h" +#if !defined(LUA_PROMPT) +#define LUA_PROMPT "> " +#define LUA_PROMPT2 ">> " +#endif + +#if !defined(LUA_PROGNAME) +#define LUA_PROGNAME "lua" +#endif + +#if !defined(LUA_MAXINPUT) +#define LUA_MAXINPUT 512 +#endif + +#if !defined(LUA_INIT_VAR) +#define LUA_INIT_VAR "LUA_INIT" +#endif + + +/* +** lua_stdin_is_tty detects whether the standard input is a 'tty' (that +** is, whether we're running lua interactively). +*/ +#if defined(LUA_USE_ISATTY) +#include <unistd.h> +#define lua_stdin_is_tty() isatty(0) +#elif defined(LUA_WIN) +#include <io.h> +#include <stdio.h> +#define lua_stdin_is_tty() _isatty(_fileno(stdin)) +#else +#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ +#endif + + +/* +** lua_readline defines how to show a prompt and then read a line from +** the standard input. +** lua_saveline defines how to "save" a read line in a "history". +** lua_freeline defines how to free a line read by lua_readline. +*/ +#if defined(LUA_USE_READLINE) + +#include <stdio.h> +#include <readline/readline.h> +#include <readline/history.h> +#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) +#define lua_saveline(L,idx) \ + if (lua_rawlen(L,idx) > 0) /* non-empty line? */ \ + add_history(lua_tostring(L, idx)); /* add it to history */ +#define lua_freeline(L,b) ((void)L, free(b)) + +#elif !defined(lua_readline) + +#define lua_readline(L,b,p) \ + ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ + fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ +#define lua_saveline(L,idx) { (void)L; (void)idx; } +#define lua_freeline(L,b) { (void)L; (void)b; } + +#endif + + + static lua_State *globalL = NULL; @@ -41,7 +104,7 @@ static void laction (int i) { static void print_usage (void) { fprintf(stderr, - "usage: %s [options] [script [args]].\n" + "usage: %s [options] [script [args]]\n" "Available options are:\n" " -e stat execute string " LUA_QL("stat") "\n" " -l name require library " LUA_QL("name") "\n" @@ -63,32 +126,38 @@ static void l_message (const char *pname, const char *msg) { static int report (lua_State *L, int status) { - if (status && !lua_isnil(L, -1)) { + if (status != LUA_OK && !lua_isnil(L, -1)) { const char *msg = lua_tostring(L, -1); if (msg == NULL) msg = "(error object is not a string)"; l_message(progname, msg); lua_pop(L, 1); + /* force a complete garbage collection in case of errors */ + lua_gc(L, LUA_GCCOLLECT, 0); } return status; } -static int traceback (lua_State *L) { - if (!lua_isstring(L, 1)) /* 'message' not a string? */ - return 1; /* keep it intact */ - lua_getfield(L, LUA_GLOBALSINDEX, "debug"); - if (!lua_istable(L, -1)) { +/* the next function is called unprotected, so it must avoid errors */ +static void finalreport (lua_State *L, int status) { + if (status != LUA_OK) { + const char *msg = (lua_type(L, -1) == LUA_TSTRING) ? lua_tostring(L, -1) + : NULL; + if (msg == NULL) msg = "(error object is not a string)"; + l_message(progname, msg); lua_pop(L, 1); - return 1; } - lua_getfield(L, -1, "traceback"); - if (!lua_isfunction(L, -1)) { - lua_pop(L, 2); - return 1; +} + + +static int traceback (lua_State *L) { + const char *msg = lua_tostring(L, 1); + if (msg) + luaL_traceback(L, L, msg, 1); + else if (!lua_isnoneornil(L, 1)) { /* is there an error object? */ + if (!luaL_callmeta(L, 1, "__tostring")) /* try its 'tostring' metamethod */ + lua_pushliteral(L, "(no error message)"); } - lua_pushvalue(L, 1); /* pass error message */ - lua_pushinteger(L, 2); /* skip this function and traceback */ - lua_call(L, 2, 1); /* call debug.traceback */ return 1; } @@ -98,18 +167,17 @@ static int docall (lua_State *L, int narg, int clear) { int base = lua_gettop(L) - narg; /* function index */ lua_pushcfunction(L, traceback); /* push traceback function */ lua_insert(L, base); /* put it under chunk and args */ + globalL = L; /* to be available to 'laction' */ signal(SIGINT, laction); status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); signal(SIGINT, SIG_DFL); lua_remove(L, base); /* remove traceback function */ - /* force a complete garbage collection in case of errors */ - if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); return status; } static void print_version (void) { - l_message(NULL, LUA_RELEASE " " LUA_COPYRIGHT); + printf("%s\n", LUA_COPYRIGHT); } @@ -132,19 +200,21 @@ static int getargs (lua_State *L, char **argv, int n) { static int dofile (lua_State *L, const char *name) { - int status = luaL_loadfile(L, name) || docall(L, 0, 1); + int status = luaL_loadfile(L, name); + if (status == LUA_OK) status = docall(L, 0, 1); return report(L, status); } static int dostring (lua_State *L, const char *s, const char *name) { - int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1); + int status = luaL_loadbuffer(L, s, strlen(s), name); + if (status == LUA_OK) status = docall(L, 0, 1); return report(L, status); } static int dolibrary (lua_State *L, const char *name) { - lua_getglobal(L, "require"); + lua_getfield(L, LUA_ENVIRONINDEX, "require"); lua_pushstring(L, name); return report(L, docall(L, 1, 1)); } @@ -152,20 +222,22 @@ static int dolibrary (lua_State *L, const char *name) { static const char *get_prompt (lua_State *L, int firstline) { const char *p; - lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2"); + lua_getfield(L, LUA_ENVIRONINDEX, firstline ? "_PROMPT" : "_PROMPT2"); p = lua_tostring(L, -1); if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); lua_pop(L, 1); /* remove global */ return p; } +/* mark in error messages for incomplete statements */ +#define mark "<eof>" +#define marklen (sizeof(mark) - 1) static int incomplete (lua_State *L, int status) { if (status == LUA_ERRSYNTAX) { size_t lmsg; const char *msg = lua_tolstring(L, -1, &lmsg); - const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1); - if (strstr(msg, LUA_QL("<eof>")) == tp) { + if (lmsg >= marklen && strcmp(msg + lmsg - marklen, mark) == 0) { lua_pop(L, 1); return 1; } @@ -199,7 +271,9 @@ static int loadline (lua_State *L) { if (!pushline(L, 1)) return -1; /* no input */ for (;;) { /* repeat until gets a complete line */ - status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); + size_t l; + const char *line = lua_tolstring(L, 1, &l); + status = luaL_loadbuffer(L, line, l, "=stdin"); if (!incomplete(L, status)) break; /* cannot try to add lines? */ if (!pushline(L, 0)) /* no more input? */ return -1; @@ -218,19 +292,20 @@ static void dotty (lua_State *L) { const char *oldprogname = progname; progname = NULL; while ((status = loadline(L)) != -1) { - if (status == 0) status = docall(L, 0, 0); + if (status == LUA_OK) status = docall(L, 0, 0); report(L, status); - if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ - lua_getglobal(L, "print"); + if (status == LUA_OK && lua_gettop(L) > 0) { /* any result to print? */ + luaL_checkstack(L, LUA_MINSTACK, "too many results to print"); + lua_getfield(L, LUA_ENVIRONINDEX, "print"); lua_insert(L, 1); - if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != LUA_OK) l_message(progname, lua_pushfstring(L, "error calling " LUA_QL("print") " (%s)", lua_tostring(L, -1))); } } lua_settop(L, 0); /* clear stack */ - fputs("\n", stdout); + luai_writestring("\n", 1); fflush(stdout); progname = oldprogname; } @@ -240,22 +315,22 @@ static int handle_script (lua_State *L, char **argv, int n) { int status; const char *fname; int narg = getargs(L, argv, n); /* collect arguments */ - lua_setglobal(L, "arg"); + lua_setfield(L, LUA_ENVIRONINDEX, "arg"); fname = argv[n]; - if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) + if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) fname = NULL; /* stdin */ status = luaL_loadfile(L, fname); lua_insert(L, -(narg+1)); - if (status == 0) + if (status == LUA_OK) status = docall(L, narg, 0); else - lua_pop(L, narg); + lua_pop(L, narg); return report(L, status); } /* check that argument has no extra characters at the end */ -#define notail(x) {if ((x)[2] != '\0') return -1;} +#define noextrachars(x) {if ((x)[2] != '\0') return -1;} static int collectargs (char **argv, int *pi, int *pv, int *pe) { @@ -265,15 +340,15 @@ static int collectargs (char **argv, int *pi, int *pv, int *pe) { return i; switch (argv[i][1]) { /* option */ case '-': - notail(argv[i]); + noextrachars(argv[i]); return (argv[i+1] != NULL ? i+1 : 0); case '\0': return i; case 'i': - notail(argv[i]); + noextrachars(argv[i]); *pi = 1; /* go through */ case 'v': - notail(argv[i]); + noextrachars(argv[i]); *pv = 1; break; case 'e': @@ -301,92 +376,89 @@ static int runargs (lua_State *L, char **argv, int n) { const char *chunk = argv[i] + 2; if (*chunk == '\0') chunk = argv[++i]; lua_assert(chunk != NULL); - if (dostring(L, chunk, "=(command line)") != 0) - return 1; + if (dostring(L, chunk, "=(command line)") != LUA_OK) + return 0; break; } case 'l': { const char *filename = argv[i] + 2; if (*filename == '\0') filename = argv[++i]; lua_assert(filename != NULL); - if (dolibrary(L, filename)) - return 1; /* stop if file fails */ + if (dolibrary(L, filename) != LUA_OK) + return 0; /* stop if file fails */ break; } default: break; } } - return 0; + return 1; } static int handle_luainit (lua_State *L) { - const char *init = getenv(LUA_INIT); - if (init == NULL) return 0; /* status OK */ + const char *init = getenv(LUA_INIT_VAR); + if (init == NULL) return LUA_OK; else if (init[0] == '@') return dofile(L, init+1); else - return dostring(L, init, "=" LUA_INIT); + return dostring(L, init, "=" LUA_INIT_VAR); } -struct Smain { - int argc; - char **argv; - int status; -}; - - static int pmain (lua_State *L) { - struct Smain *s = (struct Smain *)lua_touserdata(L, 1); - char **argv = s->argv; + int argc = lua_tointeger(L, 1); + char **argv = (char **)lua_touserdata(L, 2); int script; int has_i = 0, has_v = 0, has_e = 0; - globalL = L; if (argv[0] && argv[0][0]) progname = argv[0]; - lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ - luaL_openlibs(L); /* open libraries */ - lua_gc(L, LUA_GCRESTART, 0); - s->status = handle_luainit(L); - if (s->status != 0) return 0; script = collectargs(argv, &has_i, &has_v, &has_e); if (script < 0) { /* invalid args? */ print_usage(); - s->status = 1; return 0; } if (has_v) print_version(); - s->status = runargs(L, argv, (script > 0) ? script : s->argc); - if (s->status != 0) return 0; - if (script) - s->status = handle_script(L, argv, script); - if (s->status != 0) return 0; - if (has_i) + /* open standard libraries */ + luaL_checkversion(L); + lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ + luaL_openlibs(L); /* open libraries */ + lua_gc(L, LUA_GCRESTART, 0); + /* run LUA_INIT */ + if (handle_luainit(L) != LUA_OK) return 0; + /* execute arguments -e and -l */ + if (!runargs(L, argv, (script > 0) ? script : argc)) return 0; + /* execute main script (if there is one) */ + if (script && handle_script(L, argv, script) != LUA_OK) return 0; + if (has_i) /* -i option? */ dotty(L); - else if (script == 0 && !has_e && !has_v) { + else if (script == 0 && !has_e && !has_v) { /* no arguments? */ if (lua_stdin_is_tty()) { print_version(); dotty(L); } else dofile(L, NULL); /* executes stdin as a file */ } - return 0; + lua_pushboolean(L, 1); /* signal no errors */ + return 1; } int main (int argc, char **argv) { - int status; - struct Smain s; - lua_State *L = lua_open(); /* create state */ + static lua_CFunction ppmain = &pmain; + int status, result; + lua_State *L = luaL_newstate(); /* create state */ if (L == NULL) { l_message(argv[0], "cannot create state: not enough memory"); return EXIT_FAILURE; } - s.argc = argc; - s.argv = argv; - status = lua_cpcall(L, &pmain, &s); - report(L, status); + /* call 'pmain' in protected mode */ + lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_CPCALL); /* calling function */ + lua_pushlightuserdata(L, &ppmain); + lua_pushinteger(L, argc); + lua_pushlightuserdata(L, argv); + status = lua_pcall(L, 3, 1, 0); + result = lua_toboolean(L, -1); /* get result */ + finalreport(L, status); lua_close(L); - return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; + return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE; } @@ -1,6 +1,6 @@ /* -** $Id: lua.h,v 1.218.1.5 2008/08/06 13:30:12 roberto Exp $ -** Lua - An Extensible Extension Language +** $Id: lua.h,v 1.260 2010/01/06 15:08:00 roberto Exp $ +** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file */ @@ -16,35 +16,36 @@ #include "luaconf.h" -#define LUA_VERSION "Lua 5.1" -#define LUA_RELEASE "Lua 5.1.4" -#define LUA_VERSION_NUM 501 -#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio" -#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" +#define LUA_VERSION "Lua 5.2" +#define LUA_RELEASE "Lua 5.2.0 (work1)" +#define LUA_VERSION_NUM 502 +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2008 Lua.org, PUC-Rio" +#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" -/* mark for precompiled code (`<esc>Lua') */ -#define LUA_SIGNATURE "\033Lua" +/* mark for precompiled code ('<esc>Lua') */ +#define LUA_SIGNATURE "\033Lua" -/* option for multiple returns in `lua_pcall' and `lua_call' */ +/* option for multiple returns in 'lua_pcall' and 'lua_call' */ #define LUA_MULTRET (-1) /* ** pseudo-indices */ -#define LUA_REGISTRYINDEX (-10000) -#define LUA_ENVIRONINDEX (-10001) -#define LUA_GLOBALSINDEX (-10002) -#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) +#define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX +#define LUA_ENVIRONINDEX (LUA_REGISTRYINDEX - 1) +#define lua_upvalueindex(i) (LUA_ENVIRONINDEX - (i)) -/* thread status; 0 is OK */ +/* thread status */ +#define LUA_OK 0 #define LUA_YIELD 1 #define LUA_ERRRUN 2 #define LUA_ERRSYNTAX 3 #define LUA_ERRMEM 4 -#define LUA_ERRERR 5 +#define LUA_ERRGCMM 5 +#define LUA_ERRERR 6 typedef struct lua_State lua_State; @@ -87,12 +88,11 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); #define LUA_MINSTACK 20 -/* -** generic extra include file -*/ -#if defined(LUA_USER_H) -#include LUA_USER_H -#endif +/* predefined values in the registry */ +#define LUA_RIDX_MAINTHREAD 1 +#define LUA_RIDX_CPCALL 2 +#define LUA_RIDX_GLOBALS 3 +#define LUA_RIDX_LAST LUA_RIDX_GLOBALS /* type of numbers in Lua */ @@ -105,6 +105,15 @@ typedef LUA_INTEGER lua_Integer; /* +** generic extra include file +*/ +#if defined(LUA_USER_H) +#include LUA_USER_H +#endif + + + +/* ** state manipulation */ LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); @@ -114,6 +123,9 @@ LUA_API lua_State *(lua_newthread) (lua_State *L); LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); +LUA_API const lua_Number *(lua_version) (lua_State *L); + + /* ** basic stack manipulation */ @@ -123,6 +135,7 @@ LUA_API void (lua_pushvalue) (lua_State *L, int idx); LUA_API void (lua_remove) (lua_State *L, int idx); LUA_API void (lua_insert) (lua_State *L, int idx); LUA_API void (lua_replace) (lua_State *L, int idx); +LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx); LUA_API int (lua_checkstack) (lua_State *L, int sz); LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); @@ -139,15 +152,11 @@ LUA_API int (lua_isuserdata) (lua_State *L, int idx); LUA_API int (lua_type) (lua_State *L, int idx); LUA_API const char *(lua_typename) (lua_State *L, int tp); -LUA_API int (lua_equal) (lua_State *L, int idx1, int idx2); -LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); -LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2); - LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx); LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx); LUA_API int (lua_toboolean) (lua_State *L, int idx); LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); -LUA_API size_t (lua_objlen) (lua_State *L, int idx); +LUA_API size_t (lua_rawlen) (lua_State *L, int idx); LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); LUA_API void *(lua_touserdata) (lua_State *L, int idx); LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); @@ -155,13 +164,35 @@ LUA_API const void *(lua_topointer) (lua_State *L, int idx); /* +** Comparison and arithmetic functions +*/ + +#define LUA_OPADD 0 /* ORDER TM */ +#define LUA_OPSUB 1 +#define LUA_OPMUL 2 +#define LUA_OPDIV 3 +#define LUA_OPMOD 4 +#define LUA_OPPOW 5 +#define LUA_OPUNM 6 + +LUA_API void (lua_arith) (lua_State *L, int op); + +#define LUA_OPEQ 0 +#define LUA_OPLT 1 +#define LUA_OPLE 2 + +LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op); + + +/* ** push functions (C -> stack) */ -LUA_API void (lua_pushnil) (lua_State *L); -LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); -LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); -LUA_API void (lua_pushlstring) (lua_State *L, const char *s, size_t l); -LUA_API void (lua_pushstring) (lua_State *L, const char *s); +LUA_API void (lua_pushnil) (lua_State *L); +LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); +LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); +LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t l); +LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, va_list argp); LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); @@ -196,11 +227,18 @@ LUA_API int (lua_setfenv) (lua_State *L, int idx); /* -** `load' and `call' functions (load and run Lua code) +** 'load' and 'call' functions (load and run Lua code) */ -LUA_API void (lua_call) (lua_State *L, int nargs, int nresults); -LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); -LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); +LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, int ctx, + lua_CFunction k); +#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) + +LUA_API int (lua_getctx) (lua_State *L, int *ctx); + +LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, + int ctx, lua_CFunction k); +#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) + LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, const char *chunkname); @@ -210,7 +248,9 @@ LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); /* ** coroutine functions */ -LUA_API int (lua_yield) (lua_State *L, int nresults); +LUA_API int (lua_yieldk) (lua_State *L, int nresults, int ctx, + lua_CFunction k); +#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) LUA_API int (lua_resume) (lua_State *L, int narg); LUA_API int (lua_status) (lua_State *L); @@ -226,6 +266,7 @@ LUA_API int (lua_status) (lua_State *L); #define LUA_GCSTEP 5 #define LUA_GCSETPAUSE 6 #define LUA_GCSETSTEPMUL 7 +#define LUA_GCISRUNNING 8 LUA_API int (lua_gc) (lua_State *L, int what, int data); @@ -239,13 +280,14 @@ LUA_API int (lua_error) (lua_State *L); LUA_API int (lua_next) (lua_State *L, int idx); LUA_API void (lua_concat) (lua_State *L, int n); +LUA_API void (lua_len) (lua_State *L, int idx); LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); -LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); +LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); -/* +/* ** =============================================================== ** some useful macros ** =============================================================== @@ -255,11 +297,13 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); #define lua_newtable(L) lua_createtable(L, 0, 0) -#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) +#define lua_setglobal(L,s) lua_setfield(L, LUA_ENVIRONINDEX, (s)) +#define lua_getglobal(L,s) lua_getfield(L, LUA_ENVIRONINDEX, (s)) -#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) +#define lua_register(L,n,f) \ + (lua_pushcfunction(L, (f)), lua_setfield(L, LUA_ENVIRONINDEX, (n))) -#define lua_strlen(L,i) lua_objlen(L, (i)) +#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) #define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) #define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) @@ -273,32 +317,14 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); #define lua_pushliteral(L, s) \ lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) -#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s)) -#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s)) +#define lua_pushglobaltable(L) \ + lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS) #define lua_tostring(L,i) lua_tolstring(L, (i), NULL) /* -** compatibility macros and functions -*/ - -#define lua_open() luaL_newstate() - -#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX) - -#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0) - -#define lua_Chunkreader lua_Reader -#define lua_Chunkwriter lua_Writer - - -/* hack */ -LUA_API void lua_setlevel (lua_State *from, lua_State *to); - - -/* ** {====================================================================== ** Debug API ** ======================================================================= @@ -312,7 +338,7 @@ LUA_API void lua_setlevel (lua_State *from, lua_State *to); #define LUA_HOOKRET 1 #define LUA_HOOKLINE 2 #define LUA_HOOKCOUNT 3 -#define LUA_HOOKTAILRET 4 +#define LUA_HOOKTAILCALL 4 /* @@ -326,36 +352,43 @@ LUA_API void lua_setlevel (lua_State *from, lua_State *to); typedef struct lua_Debug lua_Debug; /* activation record */ -/* Functions to be called by the debuger in specific events */ +/* Functions to be called by the debugger in specific events */ typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); -LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar); -LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); -LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n); -LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n); -LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n); -LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n); +LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); +LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); +LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n); +LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n); + +LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n); +LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1, + int fidx2, int n2); -LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count); -LUA_API lua_Hook lua_gethook (lua_State *L); -LUA_API int lua_gethookmask (lua_State *L); -LUA_API int lua_gethookcount (lua_State *L); +LUA_API int (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); +LUA_API lua_Hook (lua_gethook) (lua_State *L); +LUA_API int (lua_gethookmask) (lua_State *L); +LUA_API int (lua_gethookcount) (lua_State *L); struct lua_Debug { int event; const char *name; /* (n) */ - const char *namewhat; /* (n) `global', `local', `field', `method' */ - const char *what; /* (S) `Lua', `C', `main', `tail' */ + const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */ + const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */ const char *source; /* (S) */ int currentline; /* (l) */ - int nups; /* (u) number of upvalues */ int linedefined; /* (S) */ int lastlinedefined; /* (S) */ + unsigned char nups; /* (u) number of upvalues */ + unsigned char nparams;/* (u) number of parameters */ + char isvararg; /* (u) */ + char istailcall; /* (t) */ char short_src[LUA_IDSIZE]; /* (S) */ /* private part */ - int i_ci; /* active function */ + struct CallInfo *i_ci; /* active function */ }; /* }====================================================================== */ diff --git a/etc/lua.hpp b/src/lua.hpp index ec417f59..ec417f59 100644 --- a/etc/lua.hpp +++ b/src/lua.hpp @@ -1,5 +1,5 @@ /* -** $Id: luac.c,v 1.54 2006/06/02 17:37:11 lhf Exp $ +** $Id: luac.c,v 1.57 2008/03/26 13:40:18 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ @@ -24,7 +24,7 @@ #include "lundump.h" #define PROGNAME "luac" /* default program name */ -#define OUTPUT PROGNAME ".out" /* default output file */ +#define OUTPUT PROGNAME ".out" /* default output file */ static int listing=0; /* list bytecodes? */ static int dumping=1; /* dump bytecodes? */ @@ -52,20 +52,20 @@ static void usage(const char* message) else fprintf(stderr,"%s: %s\n",progname,message); fprintf(stderr, - "usage: %s [options] [filenames].\n" + "usage: %s [options] [filenames]\n" "Available options are:\n" - " - process stdin\n" " -l list\n" " -o name output to file " LUA_QL("name") " (default is \"%s\")\n" " -p parse only\n" " -s strip debug information\n" " -v show version information\n" - " -- stop handling options\n", - progname,Output); + " -- stop handling options\n" + " - process stdin and stop handling options\n" + ,progname,Output); exit(EXIT_FAILURE); } -#define IS(s) (strcmp(argv[i],s)==0) +#define IS(s) (strcmp(argv[i],s)==0) static int doargs(int argc, char* argv[]) { @@ -108,7 +108,7 @@ static int doargs(int argc, char* argv[]) } if (version) { - printf("%s %s\n",LUA_RELEASE,LUA_COPYRIGHT); + printf("%s\n",LUA_COPYRIGHT); if (version==argc-1) exit(EXIT_SUCCESS); } return i; @@ -183,6 +183,13 @@ static int pmain(lua_State* L) return 0; } +LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { + lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_CPCALL); + lua_pushlightuserdata(L, &func); + lua_pushlightuserdata(L, ud); + return lua_pcall(L, 2, 0, 0); +} + int main(int argc, char* argv[]) { lua_State* L; @@ -190,7 +197,7 @@ int main(int argc, char* argv[]) int i=doargs(argc,argv); argc-=i; argv+=i; if (argc<=0) usage("no input files given"); - L=lua_open(); + L=luaL_newstate(); if (L==NULL) fatal("not enough memory for state"); s.argc=argc; s.argv=argv; diff --git a/src/luaconf.h b/src/luaconf.h index e2cb2616..9cd0beb2 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.82.1.7 2008/02/11 16:25:08 roberto Exp $ +** $Id: luaconf.h,v 1.127 2010/01/06 15:15:04 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -24,7 +24,7 @@ ** CHANGE it (define it) if you want Lua to avoid the use of any ** non-ansi feature or library. */ -#if defined(__STRICT_ANSI__) +#if !defined(LUA_ANSI) && defined(__STRICT_ANSI__) #define LUA_ANSI #endif @@ -33,6 +33,13 @@ #define LUA_WIN #endif +#if defined(LUA_WIN) +#include <windows.h> +#define LUA_DL_DLL +#endif + + + #if defined(LUA_USE_LINUX) #define LUA_USE_POSIX #define LUA_USE_DLOPEN /* needs an extra library: -ldl */ @@ -41,13 +48,14 @@ #if defined(LUA_USE_MACOSX) #define LUA_USE_POSIX -#define LUA_DL_DYLD /* does not need extra library */ +#define LUA_USE_DLOPEN +#define LUA_USE_READLINE /* needs some extra libraries */ #endif /* -@@ LUA_USE_POSIX includes all functionallity listed as X/Open System +@@ LUA_USE_POSIX includes all functionality listed as X/Open System @* Interfaces Extension (XSI). ** CHANGE it (define it) if your system is XSI compatible. */ @@ -59,17 +67,6 @@ #endif -/* -@@ LUA_PATH and LUA_CPATH are the names of the environment variables that -@* Lua check to set its paths. -@@ LUA_INIT is the name of the environment variable that Lua -@* checks for initialization code. -** CHANGE them if you want different names. -*/ -#define LUA_PATH "LUA_PATH" -#define LUA_CPATH "LUA_CPATH" -#define LUA_INIT "LUA_INIT" - /* @@ LUA_PATH_DEFAULT is the default path that Lua uses to look for @@ -88,20 +85,20 @@ #define LUA_LDIR "!\\lua\\" #define LUA_CDIR "!\\" #define LUA_PATH_DEFAULT \ - ".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ - LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua" + LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" ".\\?.lua" #define LUA_CPATH_DEFAULT \ - ".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll" + LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll;" ".\\?.dll" #else #define LUA_ROOT "/usr/local/" #define LUA_LDIR LUA_ROOT "share/lua/5.1/" #define LUA_CDIR LUA_ROOT "lib/lua/5.1/" #define LUA_PATH_DEFAULT \ - "./?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ - LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua" + LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" "./?.lua" #define LUA_CPATH_DEFAULT \ - "./?.so;" LUA_CDIR"?.so;" LUA_CDIR"loadall.so" + LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" #endif @@ -118,34 +115,9 @@ /* -@@ LUA_PATHSEP is the character that separates templates in a path. -@@ LUA_PATH_MARK is the string that marks the substitution points in a -@* template. -@@ LUA_EXECDIR in a Windows path is replaced by the executable's -@* directory. -@@ LUA_IGMARK is a mark to ignore all before it when bulding the -@* luaopen_ function name. -** CHANGE them if for some reason your system cannot use those -** characters. (E.g., if one of those characters is a common character -** in file/directory names.) Probably you do not need to change them. -*/ -#define LUA_PATHSEP ";" -#define LUA_PATH_MARK "?" -#define LUA_EXECDIR "!" -#define LUA_IGMARK "-" - - -/* -@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger. -** CHANGE that if ptrdiff_t is not adequate on your machine. (On most -** machines, ptrdiff_t gives a good choice between int or long.) -*/ -#define LUA_INTEGER ptrdiff_t - - -/* @@ LUA_API is a mark for all core API functions. -@@ LUALIB_API is a mark for all standard library functions. +@@ LUALIB_API is a mark for all auxiliary library functions. +@@ LUAMOD_API is a mark for all standard library opening functions. ** CHANGE them if you need to define those functions in some special way. ** For instance, if you want to create one Windows DLL with the core and ** the libraries, you may want to use the following definition (define @@ -167,29 +139,38 @@ /* more often than not the libs go together with the core */ #define LUALIB_API LUA_API +#define LUAMOD_API LUALIB_API /* @@ LUAI_FUNC is a mark for all extern functions that are not to be @* exported to outside modules. -@@ LUAI_DATA is a mark for all extern (const) variables that are not to -@* be exported to outside modules. +@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables +@* that are not to be exported to outside modules (LUAI_DDEF for +@* definitions and LUAI_DDEC for declarations). ** CHANGE them if you need to mark them in some special way. Elf/gcc ** (versions 3.2 and later) mark them as "hidden" to optimize access -** when Lua is compiled as a shared library. +** when Lua is compiled as a shared library. Not all elf targets support +** this attribute. Unfortunately, gcc does not offer a way to check +** whether the target offers that support, and those without support +** give a warning about it. To avoid these warnings, change to the +** default definition. */ #if defined(luaall_c) #define LUAI_FUNC static -#define LUAI_DATA /* empty */ +#define LUAI_DDEC static +#define LUAI_DDEF static #elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ defined(__ELF__) #define LUAI_FUNC __attribute__((visibility("hidden"))) extern -#define LUAI_DATA LUAI_FUNC +#define LUAI_DDEC LUAI_FUNC +#define LUAI_DDEF /* empty */ #else #define LUAI_FUNC extern -#define LUAI_DATA extern +#define LUAI_DDEC extern +#define LUAI_DDEF /* empty */ #endif @@ -211,175 +192,86 @@ /* -** {================================================================== -** Stand-alone configuration -** =================================================================== +@@ luai_writestring defines how 'print' prints its results. +** CHANGE it if your system does not have a useful stdout. */ +#define luai_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) -#if defined(lua_c) || defined(luaall_c) -/* -@@ lua_stdin_is_tty detects whether the standard input is a 'tty' (that -@* is, whether we're running lua interactively). -** CHANGE it if you have a better definition for non-POSIX/non-Windows -** systems. -*/ -#if defined(LUA_USE_ISATTY) -#include <unistd.h> -#define lua_stdin_is_tty() isatty(0) -#elif defined(LUA_WIN) -#include <io.h> -#include <stdio.h> -#define lua_stdin_is_tty() _isatty(_fileno(stdin)) -#else -#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ -#endif -/* -@@ LUA_PROMPT is the default prompt used by stand-alone Lua. -@@ LUA_PROMPT2 is the default continuation prompt used by stand-alone Lua. -** CHANGE them if you want different prompts. (You can also change the -** prompts dynamically, assigning to globals _PROMPT/_PROMPT2.) -*/ -#define LUA_PROMPT "> " -#define LUA_PROMPT2 ">> " - /* -@@ LUA_PROGNAME is the default name for the stand-alone Lua program. -** CHANGE it if your stand-alone interpreter has a different name and -** your system is not able to detect that name automatically. +** {================================================================== +** Compatibility with previous versions +** =================================================================== */ -#define LUA_PROGNAME "lua" - /* -@@ LUA_MAXINPUT is the maximum length for an input line in the -@* stand-alone interpreter. -** CHANGE it if you need longer lines. +@@ LUA_COMPAT_ALL controls all compatibility options. +** You can define it to get all options, or change specific options +** to fit your specific needs. */ -#define LUA_MAXINPUT 512 - +#if defined(LUA_COMPAT_ALL) /* -@@ lua_readline defines how to show a prompt and then read a line from -@* the standard input. -@@ lua_saveline defines how to "save" a read line in a "history". -@@ lua_freeline defines how to free a line read by lua_readline. -** CHANGE them if you want to improve this functionality (e.g., by using -** GNU readline and history facilities). +@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'. +** You can replace it with 'table.unpack'. */ -#if defined(LUA_USE_READLINE) -#include <stdio.h> -#include <readline/readline.h> -#include <readline/history.h> -#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) -#define lua_saveline(L,idx) \ - if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ - add_history(lua_tostring(L, idx)); /* add it to history */ -#define lua_freeline(L,b) ((void)L, free(b)) -#else -#define lua_readline(L,b,p) \ - ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ - fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ -#define lua_saveline(L,idx) { (void)L; (void)idx; } -#define lua_freeline(L,b) { (void)L; (void)b; } -#endif - -#endif - -/* }================================================================== */ - +#define LUA_COMPAT_UNPACK /* -@@ LUAI_GCPAUSE defines the default pause between garbage-collector cycles -@* as a percentage. -** CHANGE it if you want the GC to run faster or slower (higher values -** mean larger pauses which mean slower collection.) You can also change -** this value dynamically. +@@ LUA_COMPAT_CPCALL controls the presence of function 'lua_cpcall'. +** You can replace it with the preregistered function 'cpcall'. */ -#define LUAI_GCPAUSE 200 /* 200% (wait memory to double before next GC) */ - +#define LUA_COMPAT_CPCALL +LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); /* -@@ LUAI_GCMUL defines the default speed of garbage collection relative to -@* memory allocation as a percentage. -** CHANGE it if you want to change the granularity of the garbage -** collection. (Higher values mean coarser collections. 0 represents -** infinity, where each step performs a full collection.) You can also -** change this value dynamically. +@@ LUA_COMPAT_FENV controls the presence of functions 'setfenv/getfenv'. +** You can replace them with lexical environments, 'loadin', or the +** debug library. */ -#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ - - +#define LUA_COMPAT_FENV /* -@@ LUA_COMPAT_GETN controls compatibility with old getn behavior. -** CHANGE it (define it) if you want exact compatibility with the -** behavior of setn/getn in Lua 5.0. +@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library. +** You can rewrite 'log10(x)' as 'log(x, 10)'. */ -#undef LUA_COMPAT_GETN +#define LUA_COMPAT_LOG10 /* -@@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib. -** CHANGE it to undefined as soon as you do not need a global 'loadlib' -** function (the function is still available as 'package.loadlib'). +@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library. */ -#undef LUA_COMPAT_LOADLIB +#define LUA_COMPAT_MAXN /* -@@ LUA_COMPAT_VARARG controls compatibility with old vararg feature. -** CHANGE it to undefined as soon as your programs use only '...' to -** access vararg parameters (instead of the old 'arg' table). +@@ LUA_COMPAT_DEBUGLIB controls compatibility with preloading +** the debug library. +** You should add 'require"debug"' everywhere you need the debug +** library. */ -#define LUA_COMPAT_VARARG +#define LUA_COMPAT_DEBUGLIB /* -@@ LUA_COMPAT_MOD controls compatibility with old math.mod function. -** CHANGE it to undefined as soon as your programs use 'math.fmod' or -** the new '%' operator instead of 'math.mod'. +@@ The following macros supply trivial compatibility for some +** changes in the API. The macros themselves document how to +** change your code to avoid using them. */ -#define LUA_COMPAT_MOD +#define lua_strlen(L,i) lua_rawlen(L, (i)) -/* -@@ LUA_COMPAT_LSTR controls compatibility with old long string nesting -@* facility. -** CHANGE it to 2 if you want the old behaviour, or undefine it to turn -** off the advisory error when nesting [[...]]. -*/ -#define LUA_COMPAT_LSTR 1 +#define lua_objlen(L,i) lua_rawlen(L, (i)) -/* -@@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name. -** CHANGE it to undefined as soon as you rename 'string.gfind' to -** 'string.gmatch'. -*/ -#define LUA_COMPAT_GFIND +#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) +#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT) -/* -@@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib' -@* behavior. -** CHANGE it to undefined as soon as you replace to 'luaL_register' -** your uses of 'luaL_openlib' -*/ -#define LUA_COMPAT_OPENLIB +/* compatibility with previous wrong spelling */ +#define luaL_typerror luaL_typeerror +#endif +/* }================================================================== */ -/* -@@ luai_apicheck is the assert macro used by the Lua-C API. -** CHANGE luai_apicheck if you want Lua to perform some checks in the -** parameters it gets from API calls. This may slow down the interpreter -** a bit, but may be quite useful when debugging C code that interfaces -** with Lua. A useful redefinition is to use assert.h. -*/ -#if defined(LUA_USE_APICHECK) -#include <assert.h> -#define luai_apicheck(L,o) { (void)L; assert(o); } -#else -#define luai_apicheck(L,o) { (void)L; } -#endif /* @@ -399,51 +291,41 @@ /* -@@ LUAI_UINT32 is an unsigned integer with at least 32 bits. -@@ LUAI_INT32 is an signed integer with at least 32 bits. +@@ LUA_INT32 is an signed integer with exactly 32 bits. @@ LUAI_UMEM is an unsigned integer big enough to count the total @* memory used by Lua. @@ LUAI_MEM is a signed integer big enough to count the total memory @* used by Lua. ** CHANGE here if for some weird reason the default definitions are not -** good enough for your machine. (The definitions in the 'else' -** part always works, but may waste space on machines with 64-bit -** longs.) Probably you do not need to change this. +** good enough for your machine. Probably you do not need to change +** this. */ #if LUAI_BITSINT >= 32 -#define LUAI_UINT32 unsigned int -#define LUAI_INT32 int -#define LUAI_MAXINT32 INT_MAX +#define LUA_INT32 int #define LUAI_UMEM size_t #define LUAI_MEM ptrdiff_t #else /* 16-bit ints */ -#define LUAI_UINT32 unsigned long -#define LUAI_INT32 long -#define LUAI_MAXINT32 LONG_MAX +#define LUA_INT32 long #define LUAI_UMEM unsigned long #define LUAI_MEM long #endif /* -@@ LUAI_MAXCALLS limits the number of nested calls. -** CHANGE it if you need really deep recursive calls. This limit is -** arbitrary; its only purpose is to stop infinite recursion before -** exhausting memory. +@@ LUAI_MAXSTACK limits the size of the Lua stack. +** CHANGE it if you need a different limit. This limit is arbitrary; +** its only purpose is to stop Lua to consume unlimited stack +** space (and to reserve some numbers for pseudo-indices). */ -#define LUAI_MAXCALLS 20000 +#if LUAI_BITSINT >= 32 +#define LUAI_MAXSTACK 1000000 +#else +#define LUAI_MAXSTACK 15000 +#endif - -/* -@@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function -@* can use. -** CHANGE it if you need lots of (Lua) stack space for your C -** functions. This limit is arbitrary; its only purpose is to stop C -** functions to consume unlimited stack space. (must be smaller than -** -LUA_REGISTRYINDEX) -*/ -#define LUAI_MAXCSTACK 8000 +/* reserve some space for error handling */ +#define LUAI_FIRSTPSEUDOIDX (-LUAI_MAXSTACK - 1000) @@ -462,27 +344,6 @@ /* -@@ LUAI_MAXCCALLS is the maximum depth for nested C calls (short) and -@* syntactical nested non-terminals in a program. -*/ -#define LUAI_MAXCCALLS 200 - - -/* -@@ LUAI_MAXVARS is the maximum number of local variables per function -@* (must be smaller than 250). -*/ -#define LUAI_MAXVARS 200 - - -/* -@@ LUAI_MAXUPVALUES is the maximum number of upvalues per function -@* (must be smaller than 250). -*/ -#define LUAI_MAXUPVALUES 60 - - -/* @@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. */ #define LUAL_BUFFERSIZE BUFSIZ @@ -528,25 +389,44 @@ /* @@ The luai_num* macros define the primitive operations over numbers. */ -#if defined(LUA_CORE) + +/* the following operations need the math library */ +#if defined(lobject_c) || defined(lvm_c) || defined(luaall_c) #include <math.h> -#define luai_numadd(a,b) ((a)+(b)) -#define luai_numsub(a,b) ((a)-(b)) -#define luai_nummul(a,b) ((a)*(b)) -#define luai_numdiv(a,b) ((a)/(b)) -#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) -#define luai_numpow(a,b) (pow(a,b)) -#define luai_numunm(a) (-(a)) +#define luai_nummod(L,a,b) ((a) - floor((a)/(b))*(b)) +#define luai_numpow(L,a,b) (pow(a,b)) +#endif + +/* these are quite standard operations */ +#if defined(LUA_CORE) +#define luai_numadd(L,a,b) ((a)+(b)) +#define luai_numsub(L,a,b) ((a)-(b)) +#define luai_nummul(L,a,b) ((a)*(b)) +#define luai_numdiv(L,a,b) ((a)/(b)) +#define luai_numunm(L,a) (-(a)) #define luai_numeq(a,b) ((a)==(b)) -#define luai_numlt(a,b) ((a)<(b)) -#define luai_numle(a,b) ((a)<=(b)) -#define luai_numisnan(a) (!luai_numeq((a), (a))) +#define luai_numlt(L,a,b) ((a)<(b)) +#define luai_numle(L,a,b) ((a)<=(b)) +#define luai_numisnan(L,a) (!luai_numeq((a), (a))) #endif + +/* +@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger. +** CHANGE that if ptrdiff_t is not adequate on your machine. (On most +** machines, ptrdiff_t gives a good choice between int or long.) +*/ +#define LUA_INTEGER ptrdiff_t + + /* @@ lua_number2int is a macro to convert lua_Number to int. -@@ lua_number2integer is a macro to convert lua_Number to lua_Integer. +@@ lua_number2integer is a macro to convert lua_Number to lUA_INTEGER. +@@ lua_number2uint is a macro to convert a lua_Number to an unsigned +@* LUA_INT32. +@@ lua_uint2number is a macro to convert an unsigned LUA_INT32 +@* to a lua_Number. ** CHANGE them if you know a faster way to convert a lua_Number to ** int (with any rounding method and without throwing errors) in your ** system. In Pentium machines, a naive typecast from double to int @@ -555,7 +435,7 @@ /* On a Pentium, resort to a trick */ #if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \ - (defined(__i386) || defined (_M_IX86) || defined(__i386__)) + (defined(__i386) || defined (_M_IX86) || defined(__i386__)) /* On a Microsoft compiler, use assembler */ #if defined(_MSC_VER) @@ -563,190 +443,54 @@ #define lua_number2int(i,d) __asm fld d __asm fistp i #define lua_number2integer(i,n) lua_number2int(i, n) +#else /* the next trick should work on any Pentium, but sometimes clashes with a DirectX idiosyncrasy */ -#else union luai_Cast { double l_d; long l_l; }; #define lua_number2int(i,d) \ { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; } #define lua_number2integer(i,n) lua_number2int(i, n) +#define lua_number2uint(i,n) lua_number2int(i, n) #endif -/* this option always works, but may be slow */ #else +/* this option always works, but may be slow */ #define lua_number2int(i,d) ((i)=(int)(d)) -#define lua_number2integer(i,d) ((i)=(lua_Integer)(d)) +#define lua_number2integer(i,d) ((i)=(LUA_INTEGER)(d)) +#define lua_number2uint(i,d) ((i)=(unsigned LUA_INT32)(d)) #endif -/* }================================================================== */ - - -/* -@@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment. -** CHANGE it if your system requires alignments larger than double. (For -** instance, if your system supports long doubles and they must be -** aligned in 16-byte boundaries, then you should add long double in the -** union.) Probably you do not need to change this. -*/ -#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; } - - -/* -@@ LUAI_THROW/LUAI_TRY define how Lua does exception handling. -** CHANGE them if you prefer to use longjmp/setjmp even with C++ -** or if want/don't to use _longjmp/_setjmp instead of regular -** longjmp/setjmp. By default, Lua handles errors with exceptions when -** compiling as C++ code, with _longjmp/_setjmp when asked to use them, -** and with longjmp/setjmp otherwise. -*/ -#if defined(__cplusplus) -/* C++ exceptions */ -#define LUAI_THROW(L,c) throw(c) -#define LUAI_TRY(L,c,a) try { a } catch(...) \ - { if ((c)->status == 0) (c)->status = -1; } -#define luai_jmpbuf int /* dummy variable */ - -#elif defined(LUA_USE_ULONGJMP) -/* in Unix, try _longjmp/_setjmp (more efficient) */ -#define LUAI_THROW(L,c) _longjmp((c)->b, 1) -#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } -#define luai_jmpbuf jmp_buf - -#else -/* default handling with long jumps */ -#define LUAI_THROW(L,c) longjmp((c)->b, 1) -#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } -#define luai_jmpbuf jmp_buf - -#endif - - -/* -@@ LUA_MAXCAPTURES is the maximum number of captures that a pattern -@* can do during pattern-matching. -** CHANGE it if you need more captures. This limit is arbitrary. -*/ -#define LUA_MAXCAPTURES 32 - -/* -@@ lua_tmpnam is the function that the OS library uses to create a -@* temporary name. -@@ LUA_TMPNAMBUFSIZE is the maximum size of a name created by lua_tmpnam. -** CHANGE them if you have an alternative to tmpnam (which is considered -** insecure) or if you want the original tmpnam anyway. By default, Lua -** uses tmpnam except when POSIX is available, where it uses mkstemp. -*/ -#if defined(loslib_c) || defined(luaall_c) - -#if defined(LUA_USE_MKSTEMP) -#include <unistd.h> -#define LUA_TMPNAMBUFSIZE 32 -#define lua_tmpnam(b,e) { \ - strcpy(b, "/tmp/lua_XXXXXX"); \ - e = mkstemp(b); \ - if (e != -1) close(e); \ - e = (e == -1); } - -#else -#define LUA_TMPNAMBUFSIZE L_tmpnam -#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } -#endif - -#endif +/* on several machines, coercion from unsigned to double is too slow, + so avoid that if possible */ +#define lua_uint2number(u) \ + ((LUA_INT32)(u) < 0 ? (lua_Number)(u) : (lua_Number)(LUA_INT32)(u)) /* -@@ lua_popen spawns a new process connected to the current one through -@* the file streams. -** CHANGE it if you have a way to implement it in your system. +@@ luai_hashnum is a macro do hash a lua_Number value into an integer. +@* The hash must be deterministic and give reasonable values for +@* both small and large values (outside the range of integers). +@* It is used only in ltable.c. */ -#if defined(LUA_USE_POPEN) - -#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m)) -#define lua_pclose(L,file) ((void)L, (pclose(file) != -1)) - -#elif defined(LUA_WIN) -#define lua_popen(L,c,m) ((void)L, _popen(c,m)) -#define lua_pclose(L,file) ((void)L, (_pclose(file) != -1)) +#if defined(ltable_c) || defined(luaall_c) -#else +#include <float.h> +#include <math.h> -#define lua_popen(L,c,m) ((void)((void)c, m), \ - luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) -#define lua_pclose(L,file) ((void)((void)L, file), 0) +#define luai_hashnum(i,d) { int e; \ + d = frexp(d, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ + lua_number2int(i, d); i += e; } #endif -/* -@@ LUA_DL_* define which dynamic-library system Lua should use. -** CHANGE here if Lua has problems choosing the appropriate -** dynamic-library system for your platform (either Windows' DLL, Mac's -** dyld, or Unix's dlopen). If your system is some kind of Unix, there -** is a good chance that it has dlopen, so LUA_DL_DLOPEN will work for -** it. To use dlopen you also need to adapt the src/Makefile (probably -** adding -ldl to the linker options), so Lua does not select it -** automatically. (When you change the makefile to add -ldl, you must -** also add -DLUA_USE_DLOPEN.) -** If you do not want any kind of dynamic library, undefine all these -** options. -** By default, _WIN32 gets LUA_DL_DLL and MAC OS X gets LUA_DL_DYLD. -*/ -#if defined(LUA_USE_DLOPEN) -#define LUA_DL_DLOPEN -#endif - -#if defined(LUA_WIN) -#define LUA_DL_DLL -#endif - - -/* -@@ LUAI_EXTRASPACE allows you to add user-specific data in a lua_State -@* (the data goes just *before* the lua_State pointer). -** CHANGE (define) this if you really need that. This value must be -** a multiple of the maximum alignment required for your machine. -*/ -#define LUAI_EXTRASPACE 0 - - -/* -@@ luai_userstate* allow user-specific actions on threads. -** CHANGE them if you defined LUAI_EXTRASPACE and need to do something -** extra when a thread is created/deleted/resumed/yielded. -*/ -#define luai_userstateopen(L) ((void)L) -#define luai_userstateclose(L) ((void)L) -#define luai_userstatethread(L,L1) ((void)L) -#define luai_userstatefree(L) ((void)L) -#define luai_userstateresume(L,n) ((void)L) -#define luai_userstateyield(L,n) ((void)L) - - -/* -@@ LUA_INTFRMLEN is the length modifier for integer conversions -@* in 'string.format'. -@@ LUA_INTFRM_T is the integer type correspoding to the previous length -@* modifier. -** CHANGE them if your system supports long long or does not support long. -*/ - -#if defined(LUA_USELONGLONG) - -#define LUA_INTFRMLEN "ll" -#define LUA_INTFRM_T long long - -#else - -#define LUA_INTFRMLEN "l" -#define LUA_INTFRM_T long +/* }================================================================== */ -#endif diff --git a/src/lualib.h b/src/lualib.h index 469417f6..d5e4ba9d 100644 --- a/src/lualib.h +++ b/src/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.36.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lualib.h,v 1.39 2009/11/24 12:05:44 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -16,32 +16,35 @@ #define LUA_COLIBNAME "coroutine" -LUALIB_API int (luaopen_base) (lua_State *L); +LUAMOD_API int (luaopen_base) (lua_State *L); #define LUA_TABLIBNAME "table" -LUALIB_API int (luaopen_table) (lua_State *L); +LUAMOD_API int (luaopen_table) (lua_State *L); #define LUA_IOLIBNAME "io" -LUALIB_API int (luaopen_io) (lua_State *L); +LUAMOD_API int (luaopen_io) (lua_State *L); #define LUA_OSLIBNAME "os" -LUALIB_API int (luaopen_os) (lua_State *L); +LUAMOD_API int (luaopen_os) (lua_State *L); #define LUA_STRLIBNAME "string" -LUALIB_API int (luaopen_string) (lua_State *L); +LUAMOD_API int (luaopen_string) (lua_State *L); + +#define LUA_BITLIBNAME "bit" +LUAMOD_API int (luaopen_bit) (lua_State *L); #define LUA_MATHLIBNAME "math" -LUALIB_API int (luaopen_math) (lua_State *L); +LUAMOD_API int (luaopen_math) (lua_State *L); #define LUA_DBLIBNAME "debug" -LUALIB_API int (luaopen_debug) (lua_State *L); +LUAMOD_API int (luaopen_debug) (lua_State *L); #define LUA_LOADLIBNAME "package" -LUALIB_API int (luaopen_package) (lua_State *L); +LUAMOD_API int (luaopen_package) (lua_State *L); /* open all previous libraries */ -LUALIB_API void (luaL_openlibs) (lua_State *L); +LUALIB_API void (luaL_openlibs) (lua_State *L); diff --git a/src/lundump.c b/src/lundump.c index 8010a457..244d6e52 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 2.7.1.4 2008/04/04 19:51:41 roberto Exp $ +** $Id: lundump.c,v 2.12 2009/09/30 15:38:37 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -29,7 +29,6 @@ typedef struct { #ifdef LUAC_TRUST_BINARIES #define IF(c,s) -#define error(S,s) #else #define IF(c,s) if (c) error(S,s) @@ -111,10 +110,10 @@ static void LoadConstants(LoadState* S, Proto* f) switch (t) { case LUA_TNIL: - setnilvalue(o); + setnilvalue(o); break; case LUA_TBOOLEAN: - setbvalue(o,LoadChar(S)!=0); + setbvalue(o,LoadChar(S)!=0); break; case LUA_TNUMBER: setnvalue(o,LoadNumber(S)); @@ -123,7 +122,7 @@ static void LoadConstants(LoadState* S, Proto* f) setsvalue2n(S->L,o,LoadString(S)); break; default: - error(S,"bad constant"); + IF (1, "bad constant"); break; } } @@ -134,6 +133,20 @@ static void LoadConstants(LoadState* S, Proto* f) for (i=0; i<n; i++) f->p[i]=LoadFunction(S,f->source); } +static void LoadUpvalues(LoadState* S, Proto* f) +{ + int i,n; + n=LoadInt(S); + f->upvalues=luaM_newvector(S->L,n,Upvaldesc); + f->sizeupvalues=n; + for (i=0; i<n; i++) f->upvalues[i].name=NULL; + for (i=0; i<n; i++) + { + f->upvalues[i].instack=LoadChar(S); + f->upvalues[i].idx=LoadChar(S); + } +} + static void LoadDebug(LoadState* S, Proto* f) { int i,n; @@ -152,31 +165,28 @@ static void LoadDebug(LoadState* S, Proto* f) f->locvars[i].endpc=LoadInt(S); } n=LoadInt(S); - f->upvalues=luaM_newvector(S->L,n,TString*); - f->sizeupvalues=n; - for (i=0; i<n; i++) f->upvalues[i]=NULL; - for (i=0; i<n; i++) f->upvalues[i]=LoadString(S); + for (i=0; i<n; i++) f->upvalues[i].name=LoadString(S); } static Proto* LoadFunction(LoadState* S, TString* p) { Proto* f; - if (++S->L->nCcalls > LUAI_MAXCCALLS) error(S,"code too deep"); + if (++G(S->L)->nCcalls > LUAI_MAXCCALLS) error(S, "function nest too deep"); f=luaF_newproto(S->L); setptvalue2s(S->L,S->L->top,f); incr_top(S->L); f->source=LoadString(S); if (f->source==NULL) f->source=p; f->linedefined=LoadInt(S); f->lastlinedefined=LoadInt(S); - f->nups=LoadByte(S); f->numparams=LoadByte(S); f->is_vararg=LoadByte(S); f->maxstacksize=LoadByte(S); + f->envreg=LoadByte(S); LoadCode(S,f); LoadConstants(S,f); + LoadUpvalues(S,f); LoadDebug(S,f); - IF (!luaG_checkcode(f), "bad code"); S->L->top--; - S->L->nCcalls--; + G(S->L)->nCcalls--; return f; } diff --git a/src/lundump.h b/src/lundump.h index c80189db..5b19104f 100644 --- a/src/lundump.h +++ b/src/lundump.h @@ -1,5 +1,5 @@ /* -** $Id: lundump.h,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lundump.h,v 1.37 2005/11/16 11:55:07 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.63.1.3 2007/12/28 15:32:23 roberto Exp $ +** $Id: lvm.c,v 2.102 2009/12/17 16:20:01 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -57,51 +57,41 @@ int luaV_tostring (lua_State *L, StkId obj) { } -static void traceexec (lua_State *L, const Instruction *pc) { +static void traceexec (lua_State *L) { + CallInfo *ci = L->ci; lu_byte mask = L->hookmask; - const Instruction *oldpc = L->savedpc; - L->savedpc = pc; if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) { resethookcount(L); - luaD_callhook(L, LUA_HOOKCOUNT, -1); + luaD_hook(L, LUA_HOOKCOUNT, -1); } if (mask & LUA_MASKLINE) { - Proto *p = ci_func(L->ci)->l.p; - int npc = pcRel(pc, p); - int newline = getline(p, npc); - /* call linehook when enter a new function, when jump back (loop), - or when enter a new line */ - if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) - luaD_callhook(L, LUA_HOOKLINE, newline); + Proto *p = ci_func(ci)->l.p; + int npc = pcRel(ci->u.l.savedpc, p); + int newline = getfuncline(p, npc); + if (npc == 0 || /* call linehook when enter a new function, */ + ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ + newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ + luaD_hook(L, LUA_HOOKLINE, newline); } + L->oldpc = ci->u.l.savedpc; } -static void callTMres (lua_State *L, StkId res, const TValue *f, - const TValue *p1, const TValue *p2) { - ptrdiff_t result = savestack(L, res); - setobj2s(L, L->top, f); /* push function */ - setobj2s(L, L->top+1, p1); /* 1st argument */ - setobj2s(L, L->top+2, p2); /* 2nd argument */ - luaD_checkstack(L, 3); - L->top += 3; - luaD_call(L, L->top - 3, 1); - res = restorestack(L, result); - L->top--; - setobjs2s(L, res, L->top); -} - - - static void callTM (lua_State *L, const TValue *f, const TValue *p1, - const TValue *p2, const TValue *p3) { - setobj2s(L, L->top, f); /* push function */ - setobj2s(L, L->top+1, p1); /* 1st argument */ - setobj2s(L, L->top+2, p2); /* 2nd argument */ - setobj2s(L, L->top+3, p3); /* 3th argument */ - luaD_checkstack(L, 4); - L->top += 4; - luaD_call(L, L->top - 4, 0); + const TValue *p2, TValue *p3, int hasres) { + ptrdiff_t result = savestack(L, p3); + setobj2s(L, L->top++, f); /* push function */ + setobj2s(L, L->top++, p1); /* 1st argument */ + setobj2s(L, L->top++, p2); /* 2nd argument */ + if (!hasres) /* no result? 'p3' is third argument */ + setobj2s(L, L->top++, p3); /* 3th argument */ + luaD_checkstack(L, 0); + /* metamethod may yield only when called from Lua code */ + luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci)); + if (hasres) { /* if has result, move it to its place */ + p3 = restorestack(L, result); + setobjs2s(L, p3, --L->top); + } } @@ -122,10 +112,10 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { - callTMres(L, val, tm, t, key); + callTM(L, tm, t, key, val, 1); return; } - t = tm; /* else repeat with `tm' */ + t = tm; /* else repeat with 'tm' */ } luaG_runerror(L, "loop in gettable"); } @@ -133,6 +123,7 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; + TValue temp; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ @@ -149,10 +140,12 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { - callTM(L, tm, t, key, val); + callTM(L, tm, t, key, val, 0); return; } - t = tm; /* else repeat with `tm' */ + /* else repeat with 'tm' */ + setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */ + t = &temp; } luaG_runerror(L, "loop in settable"); } @@ -164,7 +157,7 @@ static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ if (ttisnil(tm)) return 0; - callTMres(L, res, tm, p1, p2); + callTM(L, tm, p1, p2, res, 1); return 1; } @@ -191,7 +184,7 @@ static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, tm2 = luaT_gettmbyobj(L, p2, event); if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ return -1; - callTMres(L, L->top, tm1, p1, p2); + callTM(L, tm1, p1, p2, L->top, 1); return !l_isfalse(L->top); } @@ -223,7 +216,7 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) - return luai_numlt(nvalue(l), nvalue(r)); + return luai_numlt(L, nvalue(l), nvalue(r)); else if (ttisstring(l)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) @@ -232,12 +225,12 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { } -static int lessequal (lua_State *L, const TValue *l, const TValue *r) { +int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { int res; if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) - return luai_numle(nvalue(l), nvalue(r)); + return luai_numle(L, nvalue(l), nvalue(r)); else if (ttisstring(l)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ @@ -248,7 +241,7 @@ static int lessequal (lua_State *L, const TValue *l, const TValue *r) { } -int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { +int luaV_equalval_ (lua_State *L, const TValue *t1, const TValue *t2) { const TValue *tm; lua_assert(ttype(t1) == ttype(t2)); switch (ttype(t1)) { @@ -258,8 +251,7 @@ int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; - tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, - TM_EQ); + tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } case LUA_TTABLE: { @@ -270,22 +262,27 @@ int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { default: return gcvalue(t1) == gcvalue(t2); } if (tm == NULL) return 0; /* no TM? */ - callTMres(L, L->top, tm, t1, t2); /* call TM */ + callTM(L, tm, t1, t2, L->top, 1); /* call TM */ return !l_isfalse(L->top); } -void luaV_concat (lua_State *L, int total, int last) { +void luaV_concat (lua_State *L, int total) { + lua_assert(total >= 2); do { - StkId top = L->base + last + 1; + StkId top = L->top; int n = 2; /* number of elements handled in this pass (at least 2) */ if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) luaG_concaterror(L, top-2, top-1); - } else if (tsvalue(top-1)->len == 0) /* second op is empty? */ - (void)tostring(L, top - 2); /* result is first op (as string) */ + } + else if (tsvalue(top-1)->len == 0) /* second operand is empty? */ + (void)tostring(L, top - 2); /* result is first operand */ + else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) { + setsvalue2s(L, top-2, rawtsvalue(top-1)); /* result is second op. */ + } else { - /* at least two string values; get as many as possible */ + /* at least two non-empty string values; get as many as possible */ size_t tl = tsvalue(top-1)->len; char *buffer; int i; @@ -304,42 +301,119 @@ void luaV_concat (lua_State *L, int total, int last) { } setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); } - total -= n-1; /* got `n' strings to create 1 new */ - last -= n-1; + total -= n-1; /* got 'n' strings to create 1 new */ + L->top -= n-1; /* poped 'n' strings and pushed one */ } while (total > 1); /* repeat until only 1 result left */ } -static void Arith (lua_State *L, StkId ra, const TValue *rb, - const TValue *rc, TMS op) { +void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { + const TValue *tm; + switch (ttype(rb)) { + case LUA_TTABLE: { + Table *h = hvalue(rb); + tm = fasttm(L, h->metatable, TM_LEN); + if (tm) break; /* metamethod? break switch to call it */ + setnvalue(ra, cast_num(luaH_getn(h))); /* else primitive len */ + return; + } + case LUA_TSTRING: { + setnvalue(ra, cast_num(tsvalue(rb)->len)); + return; + } + default: { /* try metamethod */ + tm = luaT_gettmbyobj(L, rb, TM_LEN); + if (ttisnil(tm)) /* no metamethod? */ + luaG_typeerror(L, rb, "get length of"); + break; + } + } + callTM(L, tm, rb, luaO_nilobject, ra, 1); +} + + +void luaV_arith (lua_State *L, StkId ra, const TValue *rb, + const TValue *rc, TMS op) { TValue tempb, tempc; const TValue *b, *c; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { - lua_Number nb = nvalue(b), nc = nvalue(c); - switch (op) { - case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; - case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; - case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; - case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; - case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; - case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; - case TM_UNM: setnvalue(ra, luai_numunm(nb)); break; - default: lua_assert(0); break; - } + lua_Number res = luaO_arith(op - TM_ADD + LUA_OPADD, nvalue(b), nvalue(c)); + setnvalue(ra, res); } else if (!call_binTM(L, rb, rc, ra, op)) luaG_aritherror(L, rb, rc); } +/* +** finish execution of an opcode interrupted by an yield +*/ +void luaV_finishOp (lua_State *L) { + CallInfo *ci = L->ci; + StkId base = ci->u.l.base; + Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ + OpCode op = GET_OPCODE(inst); + if (op == OP_EXTRAARG) { /* extra argument? */ + inst = *(ci->u.l.savedpc - 2); /* get its 'main' instruction */ + op = GET_OPCODE(inst); + } + switch (op) { /* finish its execution */ + case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: + case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN: + case OP_GETGLOBAL: case OP_GETTABLE: case OP_SELF: { + setobjs2s(L, base + GETARG_A(inst), --L->top); + break; + } + case OP_LE: case OP_LT: case OP_EQ: { + int res = !l_isfalse(L->top - 1); + L->top--; + /* metamethod should not be called when operand is K */ + lua_assert(!ISK(GETARG_B(inst))); + if (op == OP_LE && /* "<=" using "<" instead? */ + ttisnil(luaT_gettmbyobj(L, base + GETARG_B(inst), TM_LE))) + res = !res; /* invert result */ + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); + if (res != GETARG_A(inst)) /* condition failed? */ + ci->u.l.savedpc++; /* skip jump instruction */ + break; + } + case OP_CONCAT: { + StkId top = L->top - 1; /* top when 'call_binTM' was called */ + int b = GETARG_B(inst); /* first element to concatenate */ + int total = top - 1 - (base + b); /* elements yet to concatenate */ + setobj2s(L, top - 2, top); /* put TM result in proper position */ + if (total > 1) { /* are there elements to concat? */ + L->top = top - 1; /* top is one after last element (at top-2) */ + luaV_concat(L, total); /* concat them (may yield again) */ + } + /* move final result to final position */ + setobj2s(L, ci->u.l.base + GETARG_A(inst), L->top - 1); + L->top = ci->top; /* restore top */ + break; + } + case OP_TFORCALL: { + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_TFORLOOP); + L->top = ci->top; /* correct top */ + break; + } + case OP_CALL: { + if (GETARG_C(inst) - 1 >= 0) /* nresults >= 0? */ + L->top = ci->top; /* adjust results */ + break; + } + case OP_TAILCALL: case OP_SETGLOBAL: case OP_SETTABLE: + break; + default: lua_assert(0); + } +} + + /* ** some macros for common tasks in `luaV_execute' */ -#define runtime_check(L, c) { if (!(c)) break; } - #define RA(i) (base+GETARG_A(i)) /* to be used after possible stack reallocation */ #define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) @@ -348,13 +422,14 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb, ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) #define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) -#define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) +#define KBx(i) \ + (k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++))) -#define dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);} +#define dojump(i) { ci->u.l.savedpc += (i); luai_threadyield(L);} -#define Protect(x) { L->savedpc = pc; {x;}; base = L->base; } +#define Protect(x) { {x;}; base = ci->u.l.base; } #define arith_op(op,tm) { \ @@ -362,55 +437,50 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb, TValue *rc = RKC(i); \ if (ttisnumber(rb) && ttisnumber(rc)) { \ lua_Number nb = nvalue(rb), nc = nvalue(rc); \ - setnvalue(ra, op(nb, nc)); \ + setnvalue(ra, op(L, nb, nc)); \ } \ else \ - Protect(Arith(L, ra, rb, rc, tm)); \ + Protect(luaV_arith(L, ra, rb, rc, tm)); \ } -void luaV_execute (lua_State *L, int nexeccalls) { - LClosure *cl; - StkId base; - TValue *k; - const Instruction *pc; - reentry: /* entry point */ - lua_assert(isLua(L->ci)); - pc = L->savedpc; - cl = &clvalue(L->ci->func)->l; - base = L->base; - k = cl->p->k; +void luaV_execute (lua_State *L) { + CallInfo *ci = L->ci; + LClosure *cl = &clvalue(ci->func)->l; + TValue *k = cl->p->k; + StkId base = ci->u.l.base; + lua_assert(isLua(ci)); /* main loop of interpreter */ for (;;) { - const Instruction i = *pc++; + Instruction i = *(ci->u.l.savedpc++); StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { - traceexec(L, pc); + traceexec(L); if (L->status == LUA_YIELD) { /* did hook yield? */ - L->savedpc = pc - 1; - return; + ci->u.l.savedpc--; /* undo increment */ + luaD_throw(L, LUA_YIELD); } - base = L->base; + base = ci->u.l.base; } /* warning!! several calls may realloc the stack and invalidate `ra' */ ra = RA(i); - lua_assert(base == L->base && L->base == L->ci->base); - lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); - lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); + lua_assert(base == ci->u.l.base); + lua_assert(base <= L->top && L->top < L->stack + L->stacksize); switch (GET_OPCODE(i)) { case OP_MOVE: { setobjs2s(L, ra, RB(i)); continue; } case OP_LOADK: { - setobj2s(L, ra, KBx(i)); + TValue *rb = KBx(i); + setobj2s(L, ra, rb); continue; } case OP_LOADBOOL: { setbvalue(ra, GETARG_B(i)); - if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ + if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ continue; } case OP_LOADNIL: { @@ -439,9 +509,10 @@ void luaV_execute (lua_State *L, int nexeccalls) { } case OP_SETGLOBAL: { TValue g; + TValue *rb = KBx(i); sethvalue(L, &g, cl->env); - lua_assert(ttisstring(KBx(i))); - Protect(luaV_settable(L, &g, KBx(i), ra)); + lua_assert(ttisstring(rb)); + Protect(luaV_settable(L, &g, rb, ra)); continue; } case OP_SETUPVAL: { @@ -457,7 +528,10 @@ void luaV_execute (lua_State *L, int nexeccalls) { case OP_NEWTABLE: { int b = GETARG_B(i); int c = GETARG_C(i); - sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); + Table *t = luaH_new(L); + sethvalue(L, ra, t); + if (b != 0 || c != 0) + luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); Protect(luaC_checkGC(L)); continue; } @@ -495,10 +569,10 @@ void luaV_execute (lua_State *L, int nexeccalls) { TValue *rb = RB(i); if (ttisnumber(rb)) { lua_Number nb = nvalue(rb); - setnvalue(ra, luai_numunm(nb)); + setnvalue(ra, luai_numunm(L, nb)); } else { - Protect(Arith(L, ra, rb, rb, TM_UNM)); + Protect(luaV_arith(L, ra, rb, rb, TM_UNM)); } continue; } @@ -508,34 +582,20 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_LEN: { - const TValue *rb = RB(i); - switch (ttype(rb)) { - case LUA_TTABLE: { - setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); - break; - } - case LUA_TSTRING: { - setnvalue(ra, cast_num(tsvalue(rb)->len)); - break; - } - default: { /* try metamethod */ - Protect( - if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) - luaG_typeerror(L, rb, "get length of"); - ) - } - } + Protect(luaV_objlen(L, ra, RB(i))); continue; } case OP_CONCAT: { int b = GETARG_B(i); int c = GETARG_C(i); - Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); + L->top = base + c + 1; /* mark the end of concat operands */ + Protect(luaV_concat(L, c-b+1); luaC_checkGC(L)); + L->top = ci->top; /* restore top */ setobjs2s(L, RA(i), base+b); continue; } case OP_JMP: { - dojump(L, pc, GETARG_sBx(i)); + dojump(GETARG_sBx(i)); continue; } case OP_EQ: { @@ -543,117 +603,110 @@ void luaV_execute (lua_State *L, int nexeccalls) { TValue *rc = RKC(i); Protect( if (equalobj(L, rb, rc) == GETARG_A(i)) - dojump(L, pc, GETARG_sBx(*pc)); + dojump(GETARG_sBx(*ci->u.l.savedpc)); ) - pc++; + ci->u.l.savedpc++; continue; } case OP_LT: { Protect( if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) - dojump(L, pc, GETARG_sBx(*pc)); + dojump(GETARG_sBx(*ci->u.l.savedpc)); ) - pc++; + ci->u.l.savedpc++; continue; } case OP_LE: { Protect( - if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) - dojump(L, pc, GETARG_sBx(*pc)); + if (luaV_lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) + dojump(GETARG_sBx(*ci->u.l.savedpc)); ) - pc++; + ci->u.l.savedpc++; continue; } case OP_TEST: { - if (l_isfalse(ra) != GETARG_C(i)) - dojump(L, pc, GETARG_sBx(*pc)); - pc++; + if (GETARG_C(i) ? !l_isfalse(ra) : l_isfalse(ra)) + dojump(GETARG_sBx(*ci->u.l.savedpc)); + ci->u.l.savedpc++; continue; } case OP_TESTSET: { TValue *rb = RB(i); - if (l_isfalse(rb) != GETARG_C(i)) { + if (GETARG_C(i) ? !l_isfalse(rb) : l_isfalse(rb)) { setobjs2s(L, ra, rb); - dojump(L, pc, GETARG_sBx(*pc)); + dojump(GETARG_sBx(*ci->u.l.savedpc)); } - pc++; + ci->u.l.savedpc++; continue; } case OP_CALL: { int b = GETARG_B(i); int nresults = GETARG_C(i) - 1; if (b != 0) L->top = ra+b; /* else previous instruction set top */ - L->savedpc = pc; - switch (luaD_precall(L, ra, nresults)) { - case PCRLUA: { - nexeccalls++; - goto reentry; /* restart luaV_execute over new Lua function */ - } - case PCRC: { - /* it was a C function (`precall' called it); adjust results */ - if (nresults >= 0) L->top = L->ci->top; - base = L->base; - continue; - } - default: { - return; /* yield */ - } + if (luaD_precall(L, ra, nresults)) { /* C function? */ + if (nresults >= 0) L->top = ci->top; /* adjust results */ + base = ci->u.l.base; + continue; + } + else { /* Lua function */ + ci = L->ci; + ci->callstatus |= CIST_REENTRY; + break; /* restart luaV_execute over new Lua function */ } } case OP_TAILCALL: { int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ - L->savedpc = pc; lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); - switch (luaD_precall(L, ra, LUA_MULTRET)) { - case PCRLUA: { - /* tail call: put new frame in place of previous one */ - CallInfo *ci = L->ci - 1; /* previous frame */ - int aux; - StkId func = ci->func; - StkId pfunc = (ci+1)->func; /* previous function index */ - if (L->openupval) luaF_close(L, ci->base); - L->base = ci->base = ci->func + ((ci+1)->base - pfunc); - for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ - setobjs2s(L, func+aux, pfunc+aux); - ci->top = L->top = func+aux; /* correct top */ - lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); - ci->savedpc = L->savedpc; - ci->tailcalls++; /* one more call lost */ - L->ci--; /* remove new frame */ - goto reentry; - } - case PCRC: { /* it was a C function (`precall' called it) */ - base = L->base; - continue; - } - default: { - return; /* yield */ - } + if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */ + base = ci->u.l.base; + continue; + } + else { + /* tail call: put called frame (n) in place of caller one (o) */ + CallInfo *nci = L->ci; /* called frame */ + CallInfo *oci = nci->previous; /* caller frame */ + StkId nfunc = nci->func; /* called function */ + StkId ofunc = oci->func; /* caller function */ + /* last stack slot filled by 'precall' */ + StkId lim = nci->u.l.base + getproto(nfunc)->numparams; + int aux; + /* close all upvalues from previous call */ + if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base); + /* move new frame into old one */ + for (aux = 0; nfunc + aux < lim; aux++) + setobjs2s(L, ofunc + aux, nfunc + aux); + oci->u.l.base = ofunc + (nci->u.l.base - nfunc); /* correct base */ + oci->top = L->top = ofunc + (L->top - nfunc); /* correct top */ + oci->u.l.savedpc = nci->u.l.savedpc; + oci->callstatus |= CIST_TAIL; /* function was tail called */ + ci = L->ci = oci; /* remove new frame */ + lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize); + break; /* restart luaV_execute over new Lua function */ } } case OP_RETURN: { int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; - if (L->openupval) luaF_close(L, base); - L->savedpc = pc; + if (cl->p->sizep > 0) luaF_close(L, base); b = luaD_poscall(L, ra); - if (--nexeccalls == 0) /* was previous function running `here'? */ - return; /* no: return */ - else { /* yes: continue its execution */ - if (b) L->top = L->ci->top; - lua_assert(isLua(L->ci)); - lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL); - goto reentry; + if (!(ci->callstatus & CIST_REENTRY)) /* 'ci' still the called one */ + return; /* external invocation: return */ + else { /* invocation via reentry: continue execution */ + ci = L->ci; + if (b) L->top = ci->top; + lua_assert(isLua(ci)); + lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL); + break; /* restart luaV_execute over new Lua function */ } } case OP_FORLOOP: { lua_Number step = nvalue(ra+2); - lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ + lua_Number idx = luai_numadd(L, nvalue(ra), step); /* increment index */ lua_Number limit = nvalue(ra+1); - if (luai_numlt(0, step) ? luai_numle(idx, limit) - : luai_numle(limit, idx)) { - dojump(L, pc, GETARG_sBx(i)); /* jump back */ + if (luai_numlt(L, 0, step) ? luai_numle(L, idx, limit) + : luai_numle(L, limit, idx)) { + dojump(GETARG_sBx(i)); /* jump back */ setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ } @@ -663,31 +716,34 @@ void luaV_execute (lua_State *L, int nexeccalls) { const TValue *init = ra; const TValue *plimit = ra+1; const TValue *pstep = ra+2; - L->savedpc = pc; /* next steps may throw errors */ if (!tonumber(init, ra)) luaG_runerror(L, LUA_QL("for") " initial value must be a number"); else if (!tonumber(plimit, ra+1)) luaG_runerror(L, LUA_QL("for") " limit must be a number"); else if (!tonumber(pstep, ra+2)) luaG_runerror(L, LUA_QL("for") " step must be a number"); - setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); - dojump(L, pc, GETARG_sBx(i)); + setnvalue(ra, luai_numsub(L, nvalue(ra), nvalue(pstep))); + dojump(GETARG_sBx(i)); continue; } - case OP_TFORLOOP: { + case OP_TFORCALL: { StkId cb = ra + 3; /* call base */ setobjs2s(L, cb+2, ra+2); setobjs2s(L, cb+1, ra+1); setobjs2s(L, cb, ra); - L->top = cb+3; /* func. + 2 args (state and index) */ - Protect(luaD_call(L, cb, GETARG_C(i))); - L->top = L->ci->top; - cb = RA(i) + 3; /* previous call may change the stack */ - if (!ttisnil(cb)) { /* continue loop? */ - setobjs2s(L, cb-1, cb); /* save control variable */ - dojump(L, pc, GETARG_sBx(*pc)); /* jump back */ + L->top = cb + 3; /* func. + 2 args (state and index) */ + Protect(luaD_call(L, cb, GETARG_C(i), 1)); + L->top = ci->top; + i = *(ci->u.l.savedpc++); /* go to next instruction */ + ra = RA(i); + lua_assert(GET_OPCODE(i) == OP_TFORLOOP); + /* go through */ + } + case OP_TFORLOOP: { + if (!ttisnil(ra + 1)) { /* continue loop? */ + setobjs2s(L, ra, ra + 1); /* save control variable */ + dojump(GETARG_sBx(i)); /* jump back */ } - pc++; continue; } case OP_SETLIST: { @@ -695,21 +751,21 @@ void luaV_execute (lua_State *L, int nexeccalls) { int c = GETARG_C(i); int last; Table *h; - if (n == 0) { - n = cast_int(L->top - ra) - 1; - L->top = L->ci->top; + if (n == 0) n = cast_int(L->top - ra) - 1; + if (c == 0) { + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); + c = GETARG_Ax(*ci->u.l.savedpc++); } - if (c == 0) c = cast_int(*pc++); - runtime_check(L, ttistable(ra)); h = hvalue(ra); last = ((c-1)*LFIELDS_PER_FLUSH) + n; if (last > h->sizearray) /* needs more space? */ luaH_resizearray(L, h, last); /* pre-alloc it at once */ for (; n > 0; n--) { TValue *val = ra+n; - setobj2t(L, luaH_setnum(L, h, last--), val); + setobj2t(L, luaH_setint(L, h, last--), val); luaC_barriert(L, h, val); } + L->top = ci->top; /* correct top (in case of previous open call) */ continue; } case OP_CLOSE: { @@ -717,39 +773,43 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_CLOSURE: { - Proto *p; - Closure *ncl; - int nup, j; - p = cl->p->p[GETARG_Bx(i)]; - nup = p->nups; - ncl = luaF_newLclosure(L, nup, cl->env); + Proto *p = cl->p->p[GETARG_Bx(i)]; /* prototype for new closure */ + int nup = p->sizeupvalues; + Closure *ncl = luaF_newLclosure(L, nup, cl->env); + Upvaldesc *uv = p->upvalues; + int j; ncl->l.p = p; - for (j=0; j<nup; j++, pc++) { - if (GET_OPCODE(*pc) == OP_GETUPVAL) - ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)]; - else { - lua_assert(GET_OPCODE(*pc) == OP_MOVE); - ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); - } + setclvalue(L, ra, ncl); /* anchor new closure in stack */ + if (p->envreg != NO_REG) { /* lexical environment? */ + StkId env = base + p->envreg; + if (!ttistable(env)) + luaG_runerror(L, "environment is not a table: " + "cannot create closure"); + else + ncl->l.env = hvalue(env); + } + for (j = 0; j < nup; j++) { /* fill in upvalues */ + if (uv[j].instack) /* upvalue refers to local variable? */ + ncl->l.upvals[j] = luaF_findupval(L, base + uv[j].idx); + else /* get upvalue from enclosing function */ + ncl->l.upvals[j] = cl->upvals[uv[j].idx]; } - setclvalue(L, ra, ncl); Protect(luaC_checkGC(L)); continue; } case OP_VARARG: { int b = GETARG_B(i) - 1; int j; - CallInfo *ci = L->ci; - int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1; - if (b == LUA_MULTRET) { + int n = cast_int(base - ci->func) - cl->p->numparams - 1; + if (b < 0) { /* B == 0? */ + b = n; /* get all var. arguments */ Protect(luaD_checkstack(L, n)); ra = RA(i); /* previous call may change the stack */ - b = n; L->top = ra + n; } for (j = 0; j < b; j++) { if (j < n) { - setobjs2s(L, ra + j, ci->base - n + j); + setobjs2s(L, ra + j, base - n + j); } else { setnilvalue(ra + j); @@ -757,7 +817,16 @@ void luaV_execute (lua_State *L, int nexeccalls) { } continue; } + case OP_EXTRAARG: { + luaG_runerror(L, "bad opcode"); + return; + } } + /* function changed (call/return): update pointers */ + lua_assert(ci == L->ci); + cl = &clvalue(ci->func)->l; + k = cl->p->k; + base = ci->u.l.base; } } @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 2.5.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lvm.h,v 2.14 2009/12/17 16:20:01 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -13,24 +13,30 @@ #include "ltm.h" -#define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o))) +#define tostring(L,o) (ttisstring(o) || (luaV_tostring(L, o))) -#define tonumber(o,n) (ttype(o) == LUA_TNUMBER || \ - (((o) = luaV_tonumber(o,n)) != NULL)) +#define tonumber(o,n) (ttisnumber(o) || (((o) = luaV_tonumber(o,n)) != NULL)) #define equalobj(L,o1,o2) \ - (ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2)) + (ttype(o1) == ttype(o2) && luaV_equalval_(L, o1, o2)) +/* not to called directly */ +LUAI_FUNC int luaV_equalval_ (lua_State *L, const TValue *t1, const TValue *t2); + LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); -LUAI_FUNC int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2); +LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r); LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n); LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj); LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val); LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val); -LUAI_FUNC void luaV_execute (lua_State *L, int nexeccalls); -LUAI_FUNC void luaV_concat (lua_State *L, int total, int last); +LUAI_FUNC void luaV_finishOp (lua_State *L); +LUAI_FUNC void luaV_execute (lua_State *L); +LUAI_FUNC void luaV_concat (lua_State *L, int total); +LUAI_FUNC void luaV_arith (lua_State *L, StkId ra, const TValue *rb, + const TValue *rc, TMS op); +LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb); #endif @@ -1,5 +1,5 @@ /* -** $Id: lzio.c,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lzio.c,v 1.31 2005/06/03 20:15:29 roberto Exp $ ** a generic input stream interface ** See Copyright Notice in lua.h */ @@ -1,5 +1,5 @@ /* -** $Id: lzio.h,v 1.21.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lzio.h,v 1.22 2009/05/18 17:26:25 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ @@ -21,6 +21,9 @@ typedef struct Zio ZIO; #define zgetc(z) (((z)->n--)>0 ? char2int(*(z)->p++) : luaZ_fill(z)) +#define zungetc(z) ((z)->n++, (z)->p--) + + typedef struct Mbuffer { char *buffer; size_t n; diff --git a/src/print.c b/src/print.c index e240cfc3..fb491e7e 100644 --- a/src/print.c +++ b/src/print.c @@ -1,5 +1,5 @@ /* -** $Id: print.c,v 1.55a 2006/05/31 13:30:05 lhf Exp $ +** $Id: print.c,v 1.58 2008/09/11 12:05:06 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -30,7 +30,7 @@ static void PrintString(const TString* ts) int c=s[i]; switch (c) { - case '"': printf("\\\""); break; + case '"': printf("\\\""); break; case '\\': printf("\\\\"); break; case '\a': printf("\\a"); break; case '\b': printf("\\b"); break; @@ -84,7 +84,10 @@ static void PrintCode(const Proto* f) int c=GETARG_C(i); int bx=GETARG_Bx(i); int sbx=GETARG_sBx(i); - int line=getline(f,pc); + int line=getfuncline(f,pc); +#ifdef LUAC_DUMP_INSTRUCTIONS + printf("%0*X",2*sizeof(i),i); +#endif printf("\t%d\t",pc+1); if (line>0) printf("[%d]\t",line); else printf("[-]\t"); printf("%-9s\t",luaP_opnames[o]); @@ -109,7 +112,7 @@ static void PrintCode(const Proto* f) break; case OP_GETUPVAL: case OP_SETUPVAL: - printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b]) : "-"); + printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b].name) : "-"); break; case OP_GETGLOBAL: case OP_SETGLOBAL: @@ -155,7 +158,7 @@ static void PrintCode(const Proto* f) } } -#define SS(x) (x==1)?"":"s" +#define SS(x) ((x==1)?"":"s") #define S(x) x,SS(x) static void PrintHeader(const Proto* f) @@ -173,14 +176,15 @@ static void PrintHeader(const Proto* f) S(f->sizecode),f->sizecode*Sizeof(Instruction),VOID(f)); printf("%d%s param%s, %d slot%s, %d upvalue%s, ", f->numparams,f->is_vararg?"+":"",SS(f->numparams), - S(f->maxstacksize),S(f->nups)); + S(f->maxstacksize),S(f->sizeupvalues)); printf("%d local%s, %d constant%s, %d function%s\n", S(f->sizelocvars),S(f->sizek),S(f->sizep)); } -static void PrintConstants(const Proto* f) +static void PrintDebug(const Proto* f) { - int i,n=f->sizek; + int i,n; + n=f->sizek; printf("constants (%d) for %p:\n",n,VOID(f)); for (i=0; i<n; i++) { @@ -188,27 +192,19 @@ static void PrintConstants(const Proto* f) PrintConstant(f,i); printf("\n"); } -} - -static void PrintLocals(const Proto* f) -{ - int i,n=f->sizelocvars; + n=f->sizelocvars; printf("locals (%d) for %p:\n",n,VOID(f)); for (i=0; i<n; i++) { printf("\t%d\t%s\t%d\t%d\n", i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1); } -} - -static void PrintUpvalues(const Proto* f) -{ - int i,n=f->sizeupvalues; + n=f->sizeupvalues; printf("upvalues (%d) for %p:\n",n,VOID(f)); if (f->upvalues==NULL) return; for (i=0; i<n; i++) { - printf("\t%d\t%s\n",i,getstr(f->upvalues[i])); + printf("\t%d\t%s\n",i,getstr(f->upvalues[i].name)); } } @@ -217,11 +213,6 @@ void PrintFunction(const Proto* f, int full) int i,n=f->sizep; PrintHeader(f); PrintCode(f); - if (full) - { - PrintConstants(f); - PrintLocals(f); - PrintUpvalues(f); - } + if (full) PrintDebug(f); for (i=0; i<n; i++) PrintFunction(f->p[i],full); } diff --git a/test/ALL.lua b/test/ALL.lua new file mode 100644 index 00000000..0045fc36 --- /dev/null +++ b/test/ALL.lua @@ -0,0 +1,26 @@ +function run(x) + print("\n-------------------------------------------------------------") + print(x) + os.execute("../src/lua "..x) + print("DONE",x) +end + +run"bisect.lua" +run"cf.lua" +run"echo.lua jan feb mar apr may jun jul aug sep oct nov dec" +run"env.lua" +run"factorial.lua" +run"fib.lua" +run"fibfor.lua" +--run"globals.lua" +run"hello.lua" +run"luac.lua" +run"printf.lua" +run"readonly.lua" +run"sieve.lua" +run"sort.lua" +run"table.lua" +run"trace-calls.lua" +run"trace-globals.lua" +run"xd.lua < hello.lua" +run"life.lua" diff --git a/test/sieve.lua b/test/sieve.lua index 0871bb21..e27c1a20 100644 --- a/test/sieve.lua +++ b/test/sieve.lua @@ -14,7 +14,7 @@ function filter (p, g) while 1 do local n = g() if n == nil then return end - if math.mod(n, p) ~= 0 then coroutine.yield(n) end + if n % p ~= 0 then coroutine.yield(n) end end end) end diff --git a/test/xd.lua b/test/xd.lua index ebc3effc..8b420394 100644 --- a/test/xd.lua +++ b/test/xd.lua @@ -1,14 +1,15 @@ -- hex dump -- usage: lua xd.lua < file +local N=16 local offset=0 while true do - local s=io.read(16) + local s=io.read(N) if s==nil then return end io.write(string.format("%08X ",offset)) string.gsub(s,"(.)", function (c) io.write(string.format("%02X ",string.byte(c))) end) - io.write(string.rep(" ",3*(16-string.len(s)))) + io.write(string.rep(" ",3*(N-string.len(s)))) io.write(" ",string.gsub(s,"%c","."),"\n") - offset=offset+16 + offset=offset+N end |