summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYRIGHT29
-rw-r--r--HISTORY32
-rw-r--r--INSTALL57
-rw-r--r--MANIFEST41
-rw-r--r--Makefile36
-rw-r--r--README60
-rw-r--r--config70
-rw-r--r--doc/idx.html577
-rw-r--r--doc/index.html74
-rw-r--r--doc/logo.gifbin0 -> 2750 bytes
-rw-r--r--doc/lua.1143
-rw-r--r--doc/lua.html151
-rw-r--r--doc/luac.1139
-rw-r--r--doc/luac.html149
-rw-r--r--doc/luac.man188
-rw-r--r--doc/manual.html4213
-rw-r--r--doc/readme.html23
-rw-r--r--etc/Makefile32
-rw-r--r--etc/README41
-rw-r--r--etc/bin2c.c6
-rw-r--r--etc/def.lua9
-rw-r--r--etc/lua.icobin0 -> 1078 bytes
-rw-r--r--etc/lua.magic10
-rw-r--r--etc/lua.xpm44
-rw-r--r--etc/min.c25
-rw-r--r--etc/stdcall.lua10
-rw-r--r--etc/trace.c35
-rw-r--r--include/Makefile2
-rw-r--r--include/lauxlib.h115
-rw-r--r--include/lua.h247
-rw-r--r--include/luadebug.h40
-rw-r--r--include/lualib.h26
-rw-r--r--src/Makefile18
-rw-r--r--src/lapi.c796
-rw-r--r--src/lapi.h11
-rw-r--r--src/lauxlib.c133
-rw-r--r--src/lbuffer.c75
-rw-r--r--src/lbuiltin.c736
-rw-r--r--src/lbuiltin.h14
-rw-r--r--src/lcode.c701
-rw-r--r--src/lcode.h70
-rw-r--r--src/ldebug.c466
-rw-r--r--src/ldebug.h21
-rw-r--r--src/ldo.c544
-rw-r--r--src/ldo.h33
-rw-r--r--src/lfunc.c121
-rw-r--r--src/lfunc.h15
-rw-r--r--src/lgc.c442
-rw-r--r--src/lgc.h9
-rw-r--r--src/lib/Makefile6
-rw-r--r--src/lib/README6
-rw-r--r--src/lib/lauxlib.c216
-rw-r--r--src/lib/lbaselib.c651
-rw-r--r--src/lib/ldblib.c277
-rw-r--r--src/lib/linit.c17
-rw-r--r--src/lib/liolib.c729
-rw-r--r--src/lib/lmathlib.c193
-rw-r--r--src/lib/lstrlib.c503
-rw-r--r--src/llex.c495
-rw-r--r--src/llex.h70
-rw-r--r--src/llimits.h204
-rw-r--r--src/lmem.c178
-rw-r--r--src/lmem.h45
-rw-r--r--src/lobject.c170
-rw-r--r--src/lobject.h250
-rw-r--r--src/lopcodes.h210
-rw-r--r--src/lparser.c1910
-rw-r--r--src/lparser.h50
-rw-r--r--src/lstate.c153
-rw-r--r--src/lstate.h87
-rw-r--r--src/lstring.c335
-rw-r--r--src/lstring.h35
-rw-r--r--src/ltable.c336
-rw-r--r--src/ltable.h34
-rw-r--r--src/ltests.c543
-rw-r--r--src/ltm.c271
-rw-r--r--src/ltm.h71
-rw-r--r--src/lua/Makefile4
-rw-r--r--src/lua/README50
-rw-r--r--src/lua/lua.c314
-rw-r--r--src/luac/Makefile6
-rw-r--r--src/luac/README34
-rw-r--r--src/luac/dump.c173
-rw-r--r--src/luac/luac.c252
-rw-r--r--src/luac/luac.h37
-rw-r--r--src/luac/opcode.c102
-rw-r--r--src/luac/opcode.h70
-rw-r--r--src/luac/opt.c326
-rw-r--r--src/luac/print.c252
-rw-r--r--src/luac/print.h55
-rw-r--r--src/luac/stubs.c176
-rw-r--r--src/luac/test.c253
-rw-r--r--src/lundump.c303
-rw-r--r--src/lundump.h28
-rw-r--r--src/lvm.c1023
-rw-r--r--src/lvm.h28
-rw-r--r--src/lzio.c68
-rw-r--r--src/lzio.h27
-rw-r--r--test/array.lua13
-rw-r--r--test/bisect.lua3
-rw-r--r--test/cf-for.lua19
-rw-r--r--test/examples/ps/hilbert.lua2
-rw-r--r--test/examples/www/staff.lua8
-rw-r--r--test/fib.lua30
-rw-r--r--test/globals.lua13
-rw-r--r--test/life.lua121
-rw-r--r--test/lisp.lua22
-rw-r--r--test/old.lua42
-rw-r--r--test/qp.lua6
-rw-r--r--test/save.lua13
-rw-r--r--test/sort.lua5
-rw-r--r--test/table.lua7
-rw-r--r--test/trace-calls.lua23
-rw-r--r--test/trace-globals.lua75
-rw-r--r--test/trace.lua33
-rw-r--r--test/undefined.lua20
-rw-r--r--test/webform.lua8
117 files changed, 12826 insertions, 10092 deletions
diff --git a/COPYRIGHT b/COPYRIGHT
index 65c64ac3..eef88b05 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -1,4 +1,4 @@
-Lua COPYRIGHT NOTICE
+Lua Copyright Notice
--------------------
Lua is free and non-proprietary.
@@ -8,44 +8,47 @@ Lua (probably) qualifies as Open Source software.
Nevertheless, Lua is not in the public domain and TeCGraf keeps its copyright.
If you use Lua, please give us credit (a nice way to do this is to include a
-logo in a web page for your product), but we would appreciate *not* receiving
-lengthy legal documents to sign.
+Lua logo in a web page for your product), but we would appreciate *not*
+receiving lengthy legal documents to sign.
The legal details are below.
===============================================================================
-Copyright (c) 1994-1999 TeCGraf, PUC-Rio. All rights reserved.
+Copyright (C) 1994-2000 TeCGraf, PUC-Rio. All rights reserved.
Permission is hereby granted, without written agreement and without license
-or royalty fees, to use, copy, modify, and distribute this software and its
-documentation for any purpose, including commercial applications, subject to
+or royalty fees, to use, copy, modify, translate, and distribute
+this software and its documentation (hereby called the "package")
+for any purpose, including commercial applications, subject to
the following conditions:
* The above copyright notice and this permission notice shall appear in all
- copies or substantial portions of this software.
+ copies or substantial portions of this package.
- * The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software in a
+ * The origin of this package must not be misrepresented; you must not
+ claim that you wrote the original package. If you use this package in a
product, an acknowledgment in the product documentation would be greatly
appreciated (but it is not required).
* Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
+ misrepresented as being the original package.
The authors specifically disclaim any warranties, including, but not limited
to, the implied warranties of merchantability and fitness for a particular
-purpose. The software provided hereunder is on an "as is" basis, and the
+purpose. The package provided hereunder is on an "as is" basis, and the
authors have no obligation to provide maintenance, support, updates,
enhancements, or modifications. In no event shall TeCGraf, PUC-Rio, or the
authors be held liable to any party for direct, indirect, special,
-incidental, or consequential damages arising out of the use of this software
+incidental, or consequential damages arising out of the use of this package
and its documentation.
The Lua language and this implementation have been entirely designed and written
by Waldemar Celes, Roberto Ierusalimschy, and Luiz Henrique de Figueiredo
-at TeCGraf, PUC-Rio.
+at TeCGraf, PUC-Rio in Brazil.
This implementation contains no third-party code.
===============================================================================
+
+(end of COPYRIGHT)
diff --git a/HISTORY b/HISTORY
index b01a4c41..10b033ae 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1,4 +1,32 @@
-This is Lua 3.2
+This is Lua 4.0.
+
+* 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:
+ + cleaner virtual machine -- at least 20% faster.
+ + 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
-------------------------------
@@ -79,3 +107,5 @@ This is Lua 3.2
+ fallbacks
+ simplified syntax for tables
+ many internal improvements
+
+(end of HISTORY)
diff --git a/INSTALL b/INSTALL
index 1c5b9242..e31eefad 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,11 +1,14 @@
-This is Lua 3.2
+This is Lua 4.0.
* Installation
------------
Building Lua on a Unix system should be very easy:
1. Edit "config" to suit your platform, if at all necessary.
- 2. Then, type "make".
+ 2. Do "make".
+ 3. If you want to install Lua in an "official" place in your system,
+ then do "make install". The official place and the way to install
+ files are defined in "config". You may have to be root to do this.
See below for instructions for Windows and Macintosh.
@@ -17,55 +20,53 @@ This is Lua 3.2
* include files in ./include.
These are the only directories you need for development.
- There is 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.
+ There 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.
See also the README files in the various subdirectories.
- A convenient staring point is ./doc/readme.html.
+ A convenient starting point is ./doc/readme.html.
* If you have problems (and solutions!)
-------------------------------------
If "make" fails, please let us know (lua@tecgraf.puc-rio.br).
- If you make changes to "config", please send them to us.
+ If you make changes to "config" or to the Makefiles, please send them to us.
* Shared libraries
----------------
- If you are running SunOs 4.x, type the following after "make" succeeds:
- ld -o lib/liblua.so.3.2 src/*.o
- ld -o lib/liblualib.so.3.2 src/lib/*.o
+ If you are running Linux, do "make so" after "make" succeeds.
+ This will create shared libraries in ./lib. It's probably better to
+ build shared libraries before "make install".
- If you are running Linux, type the following after "make" succeeds:
- ld -o lib/liblua.so.3.2 -shared src/*.o
- ld -o lib/liblualib.so.3.2 -shared src/lib/*.o
- cd lib
- ln -s liblua.so.3.2 liblua.so
- ln -s liblualib.so.3.2 liblualib.so.3.2
+ If you want the interpreter and the compiler to use shared libraries,
+ then do "make sobin" too.
- If you want the interpreter to use shared libraries, then do this too:
- rm bin/lua
- cd src/lua; make
- You may need to include lib/ in the LD_LIBRAY_PATH environment variable.
+ You may need to include lib/ in the LD_LIBRAY_PATH environment variable
+ to link programs that use the shared libraries if you don't put them in
+ the "official" places with "make install".
- Building shared libraries in other systems is similar but details differ.
+ Building shared libraries in other systems is similar but details differ;
+ you may need to fix a few details in the top-level Makefile.
* Installation on Windows or Macintosh
------------------------------------
The instructions for building Lua on a Mac or Windows machine depend on
the particular compiler you are using.
The simplest way is to create a folder with all .c and .h files.
- Then create projects for the basic library, the standard library,
- the interpreter and the compiler, as follows:
+ Then create projects for the core library, the standard library,
+ the interpreter, and the compiler, as follows:
- basic lib: lapi.c lauxlib.c lbuffer.c lbuiltin.c ldo.c lfunc.c lgc.c
- llex.c lmem.c lobject.c lparser.c lstate.c lstring.c ltable.c
+ core lib: lapi.c lcode.c ldebug.c ldo.c lfunc.c lgc.c llex.c lmem.c
+ lobject.c lparser.c lstate.c lstring.c ltable.c ltests.c
ltm.c lundump.c lvm.c lzio.c
- standard lib: linit.c ldblib.c liolib.c lmathlib.c lstrlib.c
+ standard lib: lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c lstrlib.c
- interpreter: basic lib, standard lib, lua.c
+ interpreter: core lib, standard lib, lua.c
- compiler: basic lib, dump.c luac.c opcode.c opt.c print.c stubs.c test.c
+ compiler: core lib, dump.c luac.c opt.c print.c stubs.c
Of course, to use Lua as a library, you'll have to know how to create
and use libraries with your compiler.
+
+(end of INSTALL)
diff --git a/MANIFEST b/MANIFEST
index 3b2aec56..d7dfbc54 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -1,4 +1,4 @@
-MANIFEST contents of Lua 3.2 distribution on Thu Jul 8 10:34:45 EST 1999
+MANIFEST contents of Lua 4.0 distribution on Mon Nov 6 19:15:16 EDT 2000
lua
lua/COPYRIGHT
lua/HISTORY
@@ -11,16 +11,24 @@ lua/config
lua/doc
lua/doc/idx.html
lua/doc/index.html
+lua/doc/logo.gif
+lua/doc/lua.1
+lua/doc/lua.html
+lua/doc/luac.1
lua/doc/luac.html
-lua/doc/luac.man
lua/doc/manual.html
lua/doc/readme.html
lua/etc
lua/etc/Makefile
lua/etc/README
lua/etc/bin2c.c
+lua/etc/def.lua
+lua/etc/lua.ico
+lua/etc/lua.magic
+lua/etc/lua.xpm
lua/etc/min.c
lua/etc/setfallback.lua
+lua/etc/stdcall.lua
lua/etc/trace.c
lua/include
lua/include/Makefile
@@ -33,10 +41,10 @@ lua/src
lua/src/Makefile
lua/src/lapi.c
lua/src/lapi.h
-lua/src/lauxlib.c
-lua/src/lbuffer.c
-lua/src/lbuiltin.c
-lua/src/lbuiltin.h
+lua/src/lcode.c
+lua/src/lcode.h
+lua/src/ldebug.c
+lua/src/ldebug.h
lua/src/ldo.c
lua/src/ldo.h
lua/src/lfunc.c
@@ -46,13 +54,15 @@ lua/src/lgc.h
lua/src/lib
lua/src/lib/Makefile
lua/src/lib/README
+lua/src/lib/lauxlib.c
+lua/src/lib/lbaselib.c
lua/src/lib/ldblib.c
-lua/src/lib/linit.c
lua/src/lib/liolib.c
lua/src/lib/lmathlib.c
lua/src/lib/lstrlib.c
lua/src/llex.c
lua/src/llex.h
+lua/src/llimits.h
lua/src/lmem.c
lua/src/lmem.h
lua/src/lobject.c
@@ -66,6 +76,7 @@ lua/src/lstring.c
lua/src/lstring.h
lua/src/ltable.c
lua/src/ltable.h
+lua/src/ltests.c
lua/src/ltm.c
lua/src/ltm.h
lua/src/lua
@@ -78,12 +89,10 @@ lua/src/luac/README
lua/src/luac/dump.c
lua/src/luac/luac.c
lua/src/luac/luac.h
-lua/src/luac/opcode.c
-lua/src/luac/opcode.h
lua/src/luac/opt.c
lua/src/luac/print.c
+lua/src/luac/print.h
lua/src/luac/stubs.c
-lua/src/luac/test.c
lua/src/lundump.c
lua/src/lundump.h
lua/src/lvm.c
@@ -92,8 +101,8 @@ lua/src/lzio.c
lua/src/lzio.h
lua/test
lua/test/README
-lua/test/array.lua
lua/test/bisect.lua
+lua/test/cf-for.lua
lua/test/cf.lua
lua/test/examples
lua/test/examples/ps
@@ -108,9 +117,17 @@ lua/test/factorial.lua
lua/test/fib.lua
lua/test/globals.lua
lua/test/hello.lua
+lua/test/life.lua
+lua/test/lisp.lua
lua/test/lua
lua/test/luac
+lua/test/old.lua
+lua/test/qp.lua
lua/test/save.lua
lua/test/sort.lua
-lua/test/trace.lua
+lua/test/table.lua
+lua/test/trace-calls.lua
+lua/test/trace-globals.lua
+lua/test/undefined.lua
+lua/test/webform.lua
END OF MANIFEST
diff --git a/Makefile b/Makefile
index bd67221b..adf018f2 100644
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,41 @@
-# makefile for lua hierarchy
+# makefile for Lua hierarchy
+# see INSTALL for installation instructions
+# see file "config" for customization instructions
-all co clean klean:
+LUA= .
+
+include $(LUA)/config
+
+# primary targets (only "all" and "clean" are useful after distribution)
+all clean co klean:
cd include; $(MAKE) $@
cd src; $(MAKE) $@
cd src/luac; $(MAKE) $@
cd src/lib; $(MAKE) $@
cd src/lua; $(MAKE) $@
+# remove debug information from binaries
strip:
- strip bin/lua*
+ strip bin/lua bin/luac
+
+# official installation
+install: all strip
+ mkdir -p $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN)
+ $(INSTALL_EXEC) bin/* $(INSTALL_BIN)
+ $(INSTALL_DATA) include/*.h $(INSTALL_INC)
+ $(INSTALL_DATA) lib/lib* $(INSTALL_LIB)
+ $(INSTALL_DATA) doc/*.1 $(INSTALL_MAN)
+
+# shared libraries (for Linux)
+so:
+ ld -o lib/liblua.so.$V -shared src/*.o
+ ld -o lib/liblualib.so.$V -shared src/lib/*.o
+ cd lib; ln -s liblua.so.$V liblua.so; ln -s liblualib.so.$V liblualib.so
+
+# binaries using shared libraries
+sobin:
+ rm -f bin/lua bin/luac
+ cd src/lua; $(MAKE)
+ cd src/luac; $(MAKE)
+
+# (end of Makefile)
diff --git a/README b/README
index 07896c24..81f767ae 100644
--- a/README
+++ b/README
@@ -1,37 +1,53 @@
-This is Lua 3.2
+This is Lua 4.0.
+See HISTORY for a summary of changes since the last version.
* What is Lua?
------------
- Lua is a programming language originally designed for extending applications,
- but also frequently used as a general-purpose, stand-alone language.
+ 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 combines simple procedural syntax (similar to Pascal) with powerful
data description constructs based on associative arrays and extensible
semantics. Lua is dynamically typed, interpreted from bytecodes, and has
automatic memory management, making it ideal for configuration, scripting,
and rapid prototyping.
+ Lua is a language engine that you can embed into your application.
+ This means that, besides syntax and semantics, Lua has an API that
+ allows the application to exchange data with Lua programs and also to
+ extend Lua with C functions. In this sense, Lua can be regarded as a
+ language framework for building domain-specific languages.
+
Lua is implemented as a small library of C functions, written in ANSI C,
and compiles unmodified in all known platforms. The implementation goals
are simplicity, efficiency, portability, and low embedding cost.
+ The result is a fast language engine with small footprint, making it
+ ideal in embedded systems too.
- Lua was awarded the first prize (technological category) in the Second Compaq
- Award for Research and Development in Computer Science in 1997. This award
- is a joint venture of Compaq Computer in Brazil, the Brazilian Ministry of
- Science and Technology, and the Brazilian Academy of Sciences.
+ Lua was awarded the first prize (technological category) in the
+ Second Compaq Award for Research and Development in Computer Science in 1997.
+ This award was a joint venture of Compaq Computer in Brazil, the Brazilian
+ Ministry of Science and Technology, and the Brazilian Academy of Sciences.
+
+ Lua has been used in many different projects around the world.
+ For a short list, see http://www.tecgraf.puc-rio.br/lua/uses.html .
* Availability
------------
Lua is freely available for both academic and commercial purposes and
can be downloaded from the sites below. See COPYRIGHT for details.
- Home page: http://www.tecgraf.puc-rio.br/lua/
- http://csg.uwaterloo.ca/~lhf/lua/
- In Brazil: ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz
- In Canada: ftp://csg.uwaterloo.ca/pub/lhf/lua/lua.tar.gz
- In the US: ftp://ftp.cdrom.com/pub/languages/lua/lua.tar.gz
- In Germany: ftp://ftp.uni-trier.de/pub/languages/lua/lua.tar.gz
- In Germany: ftp://ftp.gwdg.de/pub/languages/lua/lua.tar.gz
- In Greece: ftp://ftp.ntua.gr/pub/lang/lua/lua.tar.gz
+ Home page: http://www.tecgraf.puc-rio.br/lua/
+ http://csg.uwaterloo.ca/~lhf/lua/
+ In Brazil: ftp://ftp.tecgraf.puc-rio.br/pub/lua/
+ In Canada: ftp://csg.uwaterloo.ca/pub/lhf/lua/
+ In the US: ftp://ftp.freesoftware.com/pub/languages/lua/
+ In Germany: ftp://ftp.uni-trier.de/pub/languages/lua/
+ In Germany: ftp://ftp.gwdg.de/pub/languages/lua/
+ In Greece: ftp://ftp.ntua.gr/pub/lang/lua/
+ In Japan: ftp://ftp.u-aizu.ac.jp/pub/lang/lua/
+ In Denmark: ftp://ftp.ucore.com/lua/dist
* Installation
------------
@@ -39,16 +55,18 @@ This is Lua 3.2
* Contacting the authors
----------------------
- Lua has been designed and implemented by Waldemar Celes,
- Roberto Ierusalimschy and Luiz Henrique de Figueiredo.
+ Lua was designed and implemented by Waldemar Celes, Roberto Ierusalimschy
+ and Luiz Henrique de Figueiredo.
They can be contacted by email at lua@tecgraf.puc-rio.br.
- Send your comments, bug reports and anything else to lua@tecgraf.puc-rio.br.
+ Send your comments, questions, and bug reports to lua@tecgraf.puc-rio.br.
For reporting bugs, try also the mailing list: lua-l@tecgraf.puc-rio.br.
- To subscribe to this list, send "subscribe lua-l YOUR-NAME" to
- listproc@tecgraf.puc-rio.br in the body of the message (not in the subject).
+ For more information about this list, including instructions on how to
+ subscribe, see http://www.tecgraf.puc-rio.br/lua/lua-l.html .
- Lua has been developed at TeCGraf, the Computer Graphics Technology Group
+ Lua is developed at TeCGraf, the Computer Graphics Technology Group
of PUC-Rio (the Pontifical Catholic University of Rio de Janeiro in Brazil).
TeCGraf is a laboratory of the Department of Computer Science.
Dozens of industrial products developed by TeCGraf use Lua.
+
+(end of README)
diff --git a/config b/config
index fe62a51e..6a271eaf 100644
--- a/config
+++ b/config
@@ -1,68 +1,100 @@
# configuration file for making Lua
+# see INSTALL for installation instructions
# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
# ------------------------------------------------------------------ Lua
-# if you need compatibility with version 2.5 or older, uncomment the line below.
-#COMPAT= -DLUA_COMPAT2_5
-
# Lua uses double for numbers. To change this, uncomment one of the lines below.
#NUMBER= -DLUA_NUM_TYPE=double
#NUMBER= -DLUA_NUM_TYPE=float
#NUMBER= -DLUA_NUM_TYPE=long
+# Optionally, you may also want change how numbers are converted to strings,
+# and vice-versa. Look for LUA_NUMBER in llimits.h and in the rest of the code.
-# if you want support for pipes, uncomment the following line.
+# If you want support for pipes, uncomment the following line.
+# You need popen in your C library.
#POPEN= -DPOPEN
+# If you need compatibility with previous versions, edit and uncomment the
+# definition of COMPAT below.
+# Use -DLUA_COMPAT_READPATTERN if you need complex read patterns.
+# Use -DLUA_COMPAT_ARGRET if you need the old semantics that used only the
+# first value returned by a function when it is called as the last parameter.
+# Use -DLUA_DEPRECATEDFUNCS if you need the obsolete functions in the standard
+# Lua library (not recommended).
+#COMPAT= -DLUA_COMPAT_READPATTERN -DLUA_COMPAT_ARGRET -DLUA_DEPRECATEDFUNCS
+
# ------------------------------------------------------------------ C compiler
-# you need an ANSI C compiler. gcc is a popular one.
+# You need an ANSI C compiler. gcc is a popular one.
CC= gcc
-WARN= -ansi -Wall
+WARN= -ansi -pedantic -Wall
-# on IRIX, cc is a good ANSI compiler.
+# On IRIX, cc is a good ANSI compiler.
#CC= cc
#WARN= -ansi -fullwarn
-# on Solaris, cc is optional. you may have to add -Dsparc if you use -Xc.
+# On Solaris, cc is optional. You may have to add -Dsparc if you use -Xc.
#CC= cc
#WARN= -Xc # -Dsparc
# ------------------------------------------------------------------ C library
-# if your C library is not POSIX compliant, comment the following line.
+# If your C library is not POSIX compliant, comment the following line.
POSIX= -D_POSIX_SOURCE
-# if your C library does not have the newer ANSI functions memmove, strerror,
+# If your C library does not have the newer ANSI functions strerror, strcoll,
# and locale support, uncomment the following line. SunOs 4.1.x is one example.
#OLD_ANSI= -DOLD_ANSI
-# in SunOs 4.1.x, standard headers in /usr/include are not ANSI,
+# In SunOs 4.1.x, standard headers in /usr/include are not ANSI,
# so uncomment the following line to avoid prototypes warnings.
-#EXTRA_INCS= -I/usr/5include
+#EXTRA_INCS= -I/usr/5include
+
+# The stand-alone Lua interpreter needs the math functions, which are usually
+# in libm.a (-lm). If your C library already includes the math functions,
+# or if you are using a modified interpreter that does not need them,
+# then comment the following line.
+EXTRA_LIBS= -lm
# ------------------------------------------------------------------ librarian
-# this should work in all unix systems.
+# This should work in all Unix systems.
AR= ar rcu
-# if your system doesn't have (or need) ranlib, use RANLIB=true.
-# on some systems, "ar s" does what ranlib would do.
+# If your system doesn't have (or need) ranlib, use RANLIB=true.
+# On some systems, "ar s" does what ranlib would do.
RANLIB= ranlib
#RANLIB= ar s
#RANLIB= true
-# == END OF USER SETTINGS. DO NOT CHANGE ANYTHING BELOW THIS LINE =============
+# ------------------------------------------------------------------ install
+
+# Locations for "make install". You may need to be root do "make install".
+INSTALL_ROOT= /usr/local
+INSTALL_BIN= $(INSTALL_ROOT)/bin
+INSTALL_INC= $(INSTALL_ROOT)/include
+INSTALL_LIB= $(INSTALL_ROOT)/lib
+INSTALL_MAN= $(INSTALL_ROOT)/man/man1
-VERSION= 3.2
+# You might prefer to use "install" if you have it.
+INSTALL_EXEC= cp
+INSTALL_DATA= cp
+#INSTALL_EXEC= install -m 0755
+#INSTALL_DATA= install -m 0644
+# == END OF USER SETTINGS. DO NOT CHANGE ANYTHING BELOW THIS LINE =============
+
+BIN= $(LUA)/bin
INC= $(LUA)/include
LIB= $(LUA)/lib
-BIN= $(LUA)/bin
INCS= -I$(INC) $(EXTRA_INCS)
-DEFS= $(COMPAT) $(NUMBER) $(OLD_ANSI) $(EXTRALIB) $(EXTRA_DEFS)
+DEFS= $(COMPAT) $(NUMBER) $(OLD_ANSI) $(EXTRA_DEFS)
CFLAGS= -O2 $(WARN) $(INCS) $(DEFS)
+V=4.0
+
+# (end of config)
diff --git a/doc/idx.html b/doc/idx.html
index 65b0e78a..74693a56 100644
--- a/doc/idx.html
+++ b/doc/idx.html
@@ -1,282 +1,409 @@
<HTML>
<HEAD>
-<TITLE>Lua 3.2 Reference Manual - Word Index</TITLE>
+<TITLE>Lua 4.0 Reference Manual - Word Index</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
-<H1>Index</H1>
+<HR>
+<H1>
+<IMG SRC="logo.gif" ALT="Lua" ALIGN="bottom">
+<A HREF="index.html">Reference manual</A>
+- word index
+</H1>
-<A HREF="manual.html#..">..</A><BR>
-<A HREF="manual.html#Adjustment">Adjustment</A><BR>
-<A HREF="manual.html#Assignment">Assignment</A><BR>
-<A HREF="manual.html#Basic Expressions">Basic Expressions</A><BR>
-<A HREF="manual.html#C pointers">C pointers</A><BR>
-<A HREF="manual.html#C2lua">C2lua</A><BR>
-<A HREF="manual.html#Coercion">Coercion</A><BR>
-<A HREF="manual.html#Comments">Comments</A><BR>
-<A HREF="manual.html#Expressions">Expressions</A><BR>
-<A HREF="manual.html#Function Definitions">Function Definitions</A><BR>
-<A HREF="manual.html#Global variables">Global variables</A><BR>
-<A HREF="manual.html#Identifiers">Identifiers</A><BR>
-<A HREF="manual.html#LUA_ANYTAG">LUA_ANYTAG</A><BR>
-<A HREF="manual.html#LUA_NOOBJECT">LUA_NOOBJECT</A><BR>
-<A HREF="manual.html#Literal strings">Literal strings</A><BR>
-<A HREF="manual.html#Local variables">Local variables</A><BR>
-<A HREF="manual.html#Lua Stand-alone">Lua Stand-alone</A><BR>
-<A HREF="manual.html#Numerical constants">Numerical constants</A><BR>
-<A HREF="manual.html#Operator precedence">Operator precedence</A><BR>
-<A HREF="manual.html#PI">PI</A><BR>
-<A HREF="manual.html#Pre-processor">Pre-processor</A><BR>
-<A HREF="manual.html#Types and Tags">Types and Tags</A><BR>
-<A HREF="manual.html#Upvalues">Upvalues</A><BR>
-<A HREF="manual.html#Visibility">Visibility</A><BR>
-<A HREF="manual.html#_ERRORMESSAGE">_ERRORMESSAGE</A><BR>
-<A HREF="manual.html#_INPUT">_INPUT</A><BR>
-<A HREF="manual.html#_OUTPUT">_OUTPUT</A><BR>
-<A HREF="manual.html#_STDERR">_STDERR</A><BR>
-<A HREF="manual.html#_STDIN">_STDIN</A><BR>
-<A HREF="manual.html#_STDOUT">_STDOUT</A><BR>
-<A HREF="manual.html#abs">abs</A><BR>
-<A HREF="manual.html#acos">acos</A><BR>
-<A HREF="manual.html#add event">add event</A><BR>
-<A HREF="manual.html#alert">alert</A><BR>
+<A HREF="manual.html#.."><TT>..</TT></A><BR>
+<A HREF="manual.html#_ALERT"><TT>_ALERT</TT></A><BR>
+<A HREF="manual.html#_ERRORMESSAGE"><TT>_ERRORMESSAGE</TT></A><BR>
+<A HREF="manual.html#_INPUT"><TT>_INPUT</TT></A><BR>
+<A HREF="manual.html#_OUTPUT"><TT>_OUTPUT</TT></A><BR>
+<A HREF="manual.html#_PROMPT"><TT>_PROMPT</TT></A><BR>
+<A HREF="manual.html#_STDERR"><TT>_STDERR</TT></A><BR>
+<A HREF="manual.html#_STDIN"><TT>_STDIN</TT></A><BR>
+<A HREF="manual.html#_STDOUT"><TT>_STDOUT</TT></A><BR>
+
+ <P>
+
+<A HREF="manual.html#abs"><TT>abs</TT></A><BR>
+<A HREF="manual.html#acceptable index">acceptable index</A><BR>
+<A HREF="manual.html#acos"><TT>acos</TT></A><BR>
+<A HREF="manual.html#add event">``add'' event</A><BR>
+<A HREF="manual.html#Adjustment">adjustment</A><BR>
+<A HREF="manual.html#alert"><TT>alert</TT></A><BR>
<A HREF="manual.html#and">and</A><BR>
-<A HREF="manual.html#appendto">appendto</A><BR>
+<A HREF="manual.html#appendto"><TT>appendto</TT></A><BR>
+<A HREF="manual.html#arg"><TT>arg</TT></A><BR>
<A HREF="manual.html#arguments">arguments</A><BR>
-<A HREF="manual.html#arg">arg</A><BR>
<A HREF="manual.html#arithmetic operators">arithmetic operators</A><BR>
<A HREF="manual.html#arrays">arrays</A><BR>
-<A HREF="manual.html#asin">asin</A><BR>
-<A HREF="manual.html#assert">assert</A><BR>
+<A HREF="manual.html#asin"><TT>asin</TT></A><BR>
+<A HREF="manual.html#assert"><TT>assert</TT></A><BR>
+<A HREF="manual.html#Assignment">assignment</A><BR>
<A HREF="manual.html#associative arrays">associative arrays</A><BR>
-<A HREF="manual.html#atan2">atan2</A><BR>
-<A HREF="manual.html#atan">atan</A><BR>
+<A HREF="manual.html#atan"><TT>atan</TT></A><BR>
+<A HREF="manual.html#atan2"><TT>atan2</TT></A><BR>
+
+ <P>
+
+<A HREF="manual.html#Basic Expressions">basic expressions</A><BR>
<A HREF="manual.html#basic types">basic types</A><BR>
<A HREF="manual.html#block">block</A><BR>
-<A HREF="manual.html#call">call</A><BR>
+<A HREF="manual.html#break statement">break statement</A><BR>
+
+ <P>
+
+<A HREF="manual.html#C API">C API</A><BR>
+....... <A HREF="manual.html#LUA_ANYTAG"><TT>LUA_ANYTAG</TT></A><BR>
+....... <A HREF="manual.html#lua_baselibopen"><TT>lua_baselibopen</TT></A><BR>
+....... <A HREF="manual.html#lua_call"><TT>lua_call</TT></A><BR>
+....... <A HREF="manual.html#lua_CFunction"><TT>lua_CFunction</TT></A><BR>
+....... <A HREF="manual.html#lua_close"><TT>lua_close</TT></A><BR>
+....... <A HREF="manual.html#lua_concat"><TT>lua_concat</TT></A><BR>
+....... <A HREF="manual.html#lua_copytagmethods"><TT>lua_copytagmethods</TT></A><BR>
+....... <A HREF="manual.html#lua_dblibopen"><TT>lua_dblibopen</TT></A><BR>
+....... <A HREF="manual.html#lua_Debug"><TT>lua_Debug</TT></A><BR>
+....... <A HREF="manual.html#lua_dobuffer"><TT>lua_dobuffer</TT></A><BR>
+....... <A HREF="manual.html#lua_dofile"><TT>lua_dofile</TT></A><BR>
+....... <A HREF="manual.html#lua_dostring"><TT>lua_dostring</TT></A><BR>
+....... <A HREF="manual.html#lua_equal"><TT>lua_equal</TT></A><BR>
+....... <A HREF="manual.html#LUA_ERRERR"><TT>LUA_ERRERR</TT></A><BR>
+....... <A HREF="manual.html#LUA_ERRFILE"><TT>LUA_ERRFILE</TT></A><BR>
+....... <A HREF="manual.html#LUA_ERRMEM"><TT>LUA_ERRMEM</TT></A><BR>
+....... <A HREF="manual.html#lua_error"><TT>lua_error</TT></A><BR>
+....... <A HREF="manual.html#LUA_ERRRUN"><TT>LUA_ERRRUN</TT></A><BR>
+....... <A HREF="manual.html#LUA_ERRSYNTAX"><TT>LUA_ERRSYNTAX</TT></A><BR>
+....... <A HREF="manual.html#lua_getgccount"><TT>lua_getgccount</TT></A><BR>
+....... <A HREF="manual.html#lua_getgcthreshold"><TT>lua_getgcthreshold</TT></A><BR>
+....... <A HREF="manual.html#lua_getglobal"><TT>lua_getglobal</TT></A><BR>
+....... <A HREF="manual.html#lua_getglobals"><TT>lua_getglobals</TT></A><BR>
+....... <A HREF="manual.html#lua_getinfo"><TT>lua_getinfo</TT></A><BR>
+....... <A HREF="manual.html#lua_getlocal"><TT>lua_getlocal</TT></A><BR>
+....... <A HREF="manual.html#lua_getn"><TT>lua_getn</TT></A><BR>
+....... <A HREF="manual.html#lua_getref"><TT>lua_getref</TT></A><BR>
+....... <A HREF="manual.html#lua_getregistry"><TT>lua_getregistry</TT></A><BR>
+....... <A HREF="manual.html#lua_getstack"><TT>lua_getstack</TT></A><BR>
+....... <A HREF="manual.html#lua_gettable"><TT>lua_gettable</TT></A><BR>
+....... <A HREF="manual.html#lua_gettagmethod"><TT>lua_gettagmethod</TT></A><BR>
+....... <A HREF="manual.html#lua_gettop"><TT>lua_gettop</TT></A><BR>
+....... <A HREF="manual.html#lua_Hook"><TT>lua_Hook</TT></A><BR>
+....... <A HREF="manual.html#lua_insert"><TT>lua_insert</TT></A><BR>
+....... <A HREF="manual.html#lua_iolibopen"><TT>lua_iolibopen</TT></A><BR>
+....... <A HREF="manual.html#lua_iscfunction"><TT>lua_iscfunction</TT></A><BR>
+....... <A HREF="manual.html#lua_isfunction"><TT>lua_isfunction</TT></A><BR>
+....... <A HREF="manual.html#lua_isnil"><TT>lua_isnil</TT></A><BR>
+....... <A HREF="manual.html#lua_isnumber"><TT>lua_isnumber</TT></A><BR>
+....... <A HREF="manual.html#lua_isstring"><TT>lua_isstring</TT></A><BR>
+....... <A HREF="manual.html#lua_istable"><TT>lua_istable</TT></A><BR>
+....... <A HREF="manual.html#lua_isuserdata"><TT>lua_isuserdata</TT></A><BR>
+....... <A HREF="manual.html#lua_lessthan"><TT>lua_lessthan</TT></A><BR>
+....... <A HREF="manual.html#lua_mathlibopen"><TT>lua_mathlibopen</TT></A><BR>
+....... <A HREF="manual.html#LUA_MINSTACK"><TT>LUA_MINSTACK</TT></A><BR>
+....... <A HREF="manual.html#LUA_MULTRET"><TT>LUA_MULTRET</TT></A><BR>
+....... <A HREF="manual.html#lua_newtable"><TT>lua_newtable</TT></A><BR>
+....... <A HREF="manual.html#lua_newtag"><TT>lua_newtag</TT></A><BR>
+....... <A HREF="manual.html#lua_next"><TT>lua_next</TT></A><BR>
+....... <A HREF="manual.html#LUA_NOREF"><TT>LUA_NOREF</TT></A><BR>
+....... <A HREF="manual.html#lua_open"><TT>lua_open</TT></A><BR>
+....... <A HREF="manual.html#lua_pushcclosure"><TT>lua_pushcclosure</TT></A><BR>
+....... <A HREF="manual.html#lua_pushcfunction"><TT>lua_pushcfunction</TT></A><BR>
+....... <A HREF="manual.html#lua_pushlstring"><TT>lua_pushlstring</TT></A><BR>
+....... <A HREF="manual.html#lua_pushnil"><TT>lua_pushnil</TT></A><BR>
+....... <A HREF="manual.html#lua_pushnumber"><TT>lua_pushnumber</TT></A><BR>
+....... <A HREF="manual.html#lua_pushstring"><TT>lua_pushstring</TT></A><BR>
+....... <A HREF="manual.html#lua_pushuserdata"><TT>lua_pushuserdata</TT></A><BR>
+....... <A HREF="manual.html#lua_pushusertag"><TT>lua_pushusertag</TT></A><BR>
+....... <A HREF="manual.html#lua_pushvalue"><TT>lua_pushvalue</TT></A><BR>
+....... <A HREF="manual.html#lua_rawcall"><TT>lua_rawcall</TT></A><BR>
+....... <A HREF="manual.html#lua_rawget"><TT>lua_rawget</TT></A><BR>
+....... <A HREF="manual.html#lua_rawgeti"><TT>lua_rawgeti</TT></A><BR>
+....... <A HREF="manual.html#lua_rawset"><TT>lua_rawset</TT></A><BR>
+....... <A HREF="manual.html#lua_rawseti"><TT>lua_rawseti</TT></A><BR>
+....... <A HREF="manual.html#lua_ref"><TT>lua_ref</TT></A><BR>
+....... <A HREF="manual.html#LUA_REFNIL"><TT>LUA_REFNIL</TT></A><BR>
+....... <A HREF="manual.html#LUA_REFREGISTRY"><TT>LUA_REFREGISTRY</TT></A><BR>
+....... <A HREF="manual.html#lua_register"><TT>lua_register</TT></A><BR>
+....... <A HREF="manual.html#lua_remove"><TT>lua_remove</TT></A><BR>
+....... <A HREF="manual.html#lua_setcallhook"><TT>lua_setcallhook</TT></A><BR>
+....... <A HREF="manual.html#lua_setgcthreshold"><TT>lua_setgcthreshold</TT></A><BR>
+....... <A HREF="manual.html#lua_setglobal"><TT>lua_setglobal</TT></A><BR>
+....... <A HREF="manual.html#lua_setglobals"><TT>lua_setglobals</TT></A><BR>
+....... <A HREF="manual.html#lua_setlinehook"><TT>lua_setlinehook</TT></A><BR>
+....... <A HREF="manual.html#lua_setlocal"><TT>lua_setlocal</TT></A><BR>
+....... <A HREF="manual.html#lua_settable"><TT>lua_settable</TT></A><BR>
+....... <A HREF="manual.html#lua_settag"><TT>lua_settag</TT></A><BR>
+....... <A HREF="manual.html#lua_settagmethod"><TT>lua_settagmethod</TT></A><BR>
+....... <A HREF="manual.html#lua_settop"><TT>lua_settop</TT></A><BR>
+....... <A HREF="manual.html#lua_stackspace"><TT>lua_stackspace</TT></A><BR>
+....... <A HREF="manual.html#lua_State"><TT>lua_State</TT></A><BR>
+....... <A HREF="manual.html#lua_strlen"><TT>lua_strlen</TT></A><BR>
+....... <A HREF="manual.html#lua_strlibopen"><TT>lua_strlibopen</TT></A><BR>
+....... <A HREF="manual.html#lua_tag"><TT>lua_tag</TT></A><BR>
+....... <A HREF="manual.html#lua_tocfunction"><TT>lua_tocfunction</TT></A><BR>
+....... <A HREF="manual.html#lua_tonumber"><TT>lua_tonumber</TT></A><BR>
+....... <A HREF="manual.html#lua_tostring"><TT>lua_tostring</TT></A><BR>
+....... <A HREF="manual.html#lua_touserdata"><TT>lua_touserdata</TT></A><BR>
+....... <A HREF="manual.html#lua_type"><TT>lua_type</TT></A><BR>
+....... <A HREF="manual.html#lua_typename"><TT>lua_typename</TT></A><BR>
+....... <A HREF="manual.html#lua_unref"><TT>lua_unref</TT></A><BR>
+<A HREF="manual.html#C closure">C closure</A><BR>
+<A HREF="manual.html#C pointers">C pointers</A><BR>
+<A HREF="manual.html#call"><TT>call</TT></A><BR>
<A HREF="manual.html#captures">captures</A><BR>
-<A HREF="manual.html#ceil">ceil</A><BR>
+<A HREF="manual.html#ceil"><TT>ceil</TT></A><BR>
<A HREF="manual.html#character class">character class</A><BR>
<A HREF="manual.html#chunk">chunk</A><BR>
-<A HREF="manual.html#clock">clock</A><BR>
-<A HREF="manual.html#closefile">closefile</A><BR>
+<A HREF="manual.html#clock"><TT>clock</TT></A><BR>
+<A HREF="manual.html#closefile"><TT>closefile</TT></A><BR>
<A HREF="manual.html#closing a file">closing a file</A><BR>
-<A HREF="manual.html#collectgarbage">collectgarbage</A><BR>
-<A HREF="manual.html#concatenation event">concatenation event</A><BR>
+<A HREF="manual.html#Coercion">coercion</A><BR>
+<A HREF="manual.html#collectgarbage"><TT>collectgarbage</TT></A><BR>
+<A HREF="manual.html#Comments">comments</A><BR>
<A HREF="manual.html#concatenation">concatenation</A><BR>
+<A HREF="manual.html#concatenation event">``concatenation'' event</A><BR>
<A HREF="manual.html#condition expression">condition expression</A><BR>
<A HREF="manual.html#constructors">constructors</A><BR>
-<A HREF="manual.html#copytagmethods">copytagmethods</A><BR>
-<A HREF="manual.html#cos">cos</A><BR>
-<A HREF="manual.html#date">date</A><BR>
-<A HREF="manual.html#debug pragma">debug pragma</A><BR>
-<A HREF="manual.html#deg">deg</A><BR>
-<A HREF="manual.html#div event">div event</A><BR>
-<A HREF="manual.html#dofile">dofile</A><BR>
-<A HREF="manual.html#dostring">dostring</A><BR>
+<A HREF="manual.html#copytagmethods"><TT>copytagmethods</TT></A><BR>
+<A HREF="manual.html#cos"><TT>cos</TT></A><BR>
+
+ <P>
+
+<A HREF="manual.html#date"><TT>date</TT></A><BR>
+<A HREF="manual.html#def"><TT>def</TT></A><BR>
+<A HREF="manual.html#div event">``div'' event</A><BR>
+<A HREF="manual.html#dofile"><TT>dofile</TT></A><BR>
+<A HREF="manual.html#dostring"><TT>dostring</TT></A><BR>
+
+ <P>
+
<A HREF="manual.html#eight-bit clean">eight-bit clean</A><BR>
-<A HREF="manual.html#error">error</A><BR>
+<A HREF="manual.html#error"><TT>error</TT></A><BR>
<A HREF="manual.html#event">event</A><BR>
-<A HREF="manual.html#execute">execute</A><BR>
-<A HREF="manual.html#exit">exit</A><BR>
+<A HREF="manual.html#execute"><TT>execute</TT></A><BR>
+<A HREF="manual.html#exit"><TT>exit</TT></A><BR>
+<A HREF="manual.html#exp"><TT>exp</TT></A><BR>
<A HREF="manual.html#exponentiation">exponentiation</A><BR>
+<A HREF="manual.html#Expressions">expressions</A><BR>
+
+ <P>
+
<A HREF="manual.html#file handles">file handles</A><BR>
-<A HREF="manual.html#floor">floor</A><BR>
-<A HREF="manual.html#flush">flush</A><BR>
-<A HREF="manual.html#foreachi">foreachi</A><BR>
-<A HREF="manual.html#foreachvar">foreachvar</A><BR>
-<A HREF="manual.html#foreach">foreach</A><BR>
-<A HREF="manual.html#format">format</A><BR>
-<A HREF="manual.html#frexp">frexp</A><BR>
-<A HREF="manual.html#funcinfo">funcinfo</A><BR>
-<A HREF="manual.html#function call">function call</A><BR>
-<A HREF="manual.html#function event">function event</A><BR>
+<A HREF="manual.html#floor"><TT>floor</TT></A><BR>
+<A HREF="manual.html#flush"><TT>flush</TT></A><BR>
+<A HREF="manual.html#for statement">for statement</A><BR>
+<A HREF="manual.html#foreach"><TT>foreach</TT></A><BR>
+<A HREF="manual.html#foreachi"><TT>foreachi</TT></A><BR>
+<A HREF="manual.html#format"><TT>format</TT></A><BR>
+<A HREF="manual.html#frexp"><TT>frexp</TT></A><BR>
<A HREF="manual.html#function">function</A><BR>
-<A HREF="manual.html#gc event">gc event</A><BR>
-<A HREF="manual.html#ge event">ge event</A><BR>
-<A HREF="manual.html#getenv">getenv</A><BR>
-<A HREF="manual.html#getglobal event">getglobal event</A><BR>
-<A HREF="manual.html#getglobal">getglobal</A><BR>
-<A HREF="manual.html#getlocal">getlocal</A><BR>
-<A HREF="manual.html#getn">getn</A><BR>
-<A HREF="manual.html#getstack">getstack</A><BR>
-<A HREF="manual.html#gettable event">gettable event</A><BR>
-<A HREF="manual.html#gettagmethod">gettagmethod</A><BR>
-<A HREF="manual.html#gettagmethod">gettagmethod</A><BR>
+<A HREF="manual.html#function call">function call</A><BR>
+<A HREF="manual.html#Function Definitions">function definitions</A><BR>
+<A HREF="manual.html#function event">``function'' event</A><BR>
+
+ <P>
+
+<A HREF="manual.html#gc event">``gc'' event</A><BR>
+<A HREF="manual.html#getargs"><TT>getargs</TT></A><BR>
+<A HREF="manual.html#getenv"><TT>getenv</TT></A><BR>
+<A HREF="manual.html#getglobal"><TT>getglobal</TT></A><BR>
+<A HREF="manual.html#getglobal event">``getglobal'' event</A><BR>
+<A HREF="manual.html#getinfo"><TT>getinfo</TT></A><BR>
+<A HREF="manual.html#getlocal"><TT>getlocal</TT></A><BR>
+<A HREF="manual.html#getn"><TT>getn</TT></A><BR>
+<A HREF="manual.html#gettable event">``gettable'' event</A><BR>
+<A HREF="manual.html#gettagmethod"><TT>gettagmethod</TT></A><BR>
<A HREF="manual.html#global environment">global environment</A><BR>
-<A HREF="manual.html#gsub">gsub</A><BR>
-<A HREF="manual.html#gt event">gt event</A><BR>
-<A HREF="manual.html#if-then-else">if-then-else</A><BR>
-<A HREF="manual.html#index event">index event</A><BR>
-<A HREF="manual.html#ldexp">ldexp</A><BR>
-<A HREF="manual.html#le event">le event</A><BR>
-<A HREF="manual.html#log10">log10</A><BR>
+<A HREF="manual.html#Global variables">global variables</A><BR>
+<A HREF="manual.html#globals"><TT>globals</TT></A><BR>
+<A HREF="manual.html#grammar">grammar</A><BR>
+....... <A HREF="manual.html#args">args</A><BR>
+....... <A HREF="manual.html#binop">binop</A><BR>
+....... <A HREF="manual.html#block">block</A><BR>
+....... <A HREF="manual.html#chunk">chunk</A><BR>
+....... <A HREF="manual.html#declist">declist</A><BR>
+....... <A HREF="manual.html#exp">exp</A><BR>
+....... <A HREF="manual.html#exp1">exp1</A><BR>
+....... <A HREF="manual.html#explist1">explist1</A><BR>
+....... <A HREF="manual.html#ffield">ffield</A><BR>
+....... <A HREF="manual.html#ffieldlist">ffieldlist</A><BR>
+....... <A HREF="manual.html#ffieldlist1">ffieldlist1</A><BR>
+....... <A HREF="manual.html#fieldlist">fieldlist</A><BR>
+....... <A HREF="manual.html#funcname">funcname</A><BR>
+....... <A HREF="manual.html#function">function</A><BR>
+....... <A HREF="manual.html#functioncall">functioncall</A><BR>
+....... <A HREF="manual.html#init">init</A><BR>
+....... <A HREF="manual.html#lfieldlist">lfieldlist</A><BR>
+....... <A HREF="manual.html#lfieldlist1">lfieldlist1</A><BR>
+....... <A HREF="manual.html#parlist1">parlist1</A><BR>
+....... <A HREF="manual.html#stat">stat</A><BR>
+....... <A HREF="manual.html#tableconstructor">tableconstructor</A><BR>
+....... <A HREF="manual.html#unop">unop</A><BR>
+....... <A HREF="manual.html#upvalue">upvalue</A><BR>
+....... <A HREF="manual.html#var">var</A><BR>
+....... <A HREF="manual.html#varlist1">varlist1</A><BR>
+....... <A HREF="manual.html#varorfunc">varorfunc</A><BR>
+<A HREF="manual.html#gsub"><TT>gsub</TT></A><BR>
+
+ <P>
+
+<A HREF="manual.html#Identifiers">identifiers</A><BR>
+<A HREF="manual.html#if-then-else statement">if-then-else statement</A><BR>
+<A HREF="manual.html#index event">``index'' event</A><BR>
+
+ <P>
+
+<A HREF="manual.html#ldexp"><TT>ldexp</TT></A><BR>
+<A HREF="manual.html#Literal strings">literal strings</A><BR>
+<A HREF="manual.html#Local variables">local variables</A><BR>
+<A HREF="manual.html#log"><TT>log</TT></A><BR>
+<A HREF="manual.html#log10"><TT>log10</TT></A><BR>
<A HREF="manual.html#logical operators">logical operators</A><BR>
-<A HREF="manual.html#log">log</A><BR>
-<A HREF="manual.html#lt event">lt event</A><BR>
-<A HREF="manual.html#lua2C">lua2C</A><BR>
-<A HREF="manual.html#lua_CFunction">lua_CFunction</A><BR>
-<A HREF="manual.html#lua_Object">lua_Object</A><BR>
-<A HREF="manual.html#lua_callfunction">lua_callfunction</A><BR>
-<A HREF="manual.html#lua_close">lua_close</A><BR>
-<A HREF="manual.html#lua_collectgarbage">lua_collectgarbage</A><BR>
-<A HREF="manual.html#lua_copytagmethods">lua_copytagmethods</A><BR>
-<A HREF="manual.html#lua_createtable">lua_createtable</A><BR>
-<A HREF="manual.html#lua_dobuffer">lua_dobuffer</A><BR>
-<A HREF="manual.html#lua_dofile">lua_dofile</A><BR>
-<A HREF="manual.html#lua_dostring">lua_dostring</A><BR>
-<A HREF="manual.html#lua_error">lua_error</A><BR>
-<A HREF="manual.html#lua_getcfunction">lua_getcfunction</A><BR>
-<A HREF="manual.html#lua_getglobal">lua_getglobal</A><BR>
-<A HREF="manual.html#lua_getnumber">lua_getnumber</A><BR>
-<A HREF="manual.html#lua_getparam">lua_getparam</A><BR>
-<A HREF="manual.html#lua_getref">lua_getref</A><BR>
-<A HREF="manual.html#lua_getresult">lua_getresult</A><BR>
-<A HREF="manual.html#lua_getstring">lua_getstring</A><BR>
-<A HREF="manual.html#lua_gettable">lua_gettable</A><BR>
-<A HREF="manual.html#lua_gettagmethod">lua_gettagmethod</A><BR>
-<A HREF="manual.html#lua_getuserdata">lua_getuserdata</A><BR>
-<A HREF="manual.html#lua_iolibopen">lua_iolibopen</A><BR>
-<A HREF="manual.html#lua_iscfunction">lua_iscfunction</A><BR>
-<A HREF="manual.html#lua_isfunction">lua_isfunction</A><BR>
-<A HREF="manual.html#lua_isnil">lua_isnil</A><BR>
-<A HREF="manual.html#lua_isnumber">lua_isnumber</A><BR>
-<A HREF="manual.html#lua_isstring">lua_isstring</A><BR>
-<A HREF="manual.html#lua_istable">lua_istable</A><BR>
-<A HREF="manual.html#lua_isuserdata">lua_isuserdata</A><BR>
-<A HREF="manual.html#lua_lua2C">lua_lua2C</A><BR>
-<A HREF="manual.html#lua_mathlibopen">lua_mathlibopen</A><BR>
-<A HREF="manual.html#lua_newtag">lua_newtag</A><BR>
-<A HREF="manual.html#lua_open">lua_open</A><BR>
-<A HREF="manual.html#lua_pop">lua_pop</A><BR>
-<A HREF="manual.html#lua_pushcclosure">lua_pushcclosure</A><BR>
-<A HREF="manual.html#lua_pushcfunction">lua_pushcfunction</A><BR>
-<A HREF="manual.html#lua_pushlstring">lua_pushlstring</A><BR>
-<A HREF="manual.html#lua_pushnil">lua_pushnil</A><BR>
-<A HREF="manual.html#lua_pushnumber">lua_pushnumber</A><BR>
-<A HREF="manual.html#lua_pushobject">lua_pushobject</A><BR>
-<A HREF="manual.html#lua_pushstring">lua_pushstring</A><BR>
-<A HREF="manual.html#lua_pushuserdata">lua_pushuserdata</A><BR>
-<A HREF="manual.html#lua_pushusertag">lua_pushusertag</A><BR>
-<A HREF="manual.html#lua_rawgetglobal">lua_rawgetglobal</A><BR>
-<A HREF="manual.html#lua_rawgetglobal">lua_rawgetglobal</A><BR>
-<A HREF="manual.html#lua_rawgetglobal">lua_rawgetglobal</A><BR>
-<A HREF="manual.html#lua_rawsettable">lua_rawsettable</A><BR>
-<A HREF="manual.html#lua_ref">lua_ref</A><BR>
-<A HREF="manual.html#lua_register">lua_register</A><BR>
-<A HREF="manual.html#lua_setglobal">lua_setglobal</A><BR>
-<A HREF="manual.html#lua_setstate">lua_setstate</A><BR>
-<A HREF="manual.html#lua_settable">lua_settable</A><BR>
-<A HREF="manual.html#lua_settagmethod">lua_settagmethod</A><BR>
-<A HREF="manual.html#lua_settag">lua_settag</A><BR>
-<A HREF="manual.html#lua_state">lua_state</A><BR>
-<A HREF="manual.html#lua_strlen">lua_strlen</A><BR>
-<A HREF="manual.html#lua_strlibopen">lua_strlibopen</A><BR>
-<A HREF="manual.html#lua_tag">lua_tag</A><BR>
-<A HREF="manual.html#lua_unref">lua_unref</A><BR>
-<A HREF="manual.html#luac">luac</A><BR>
-<A HREF="manual.html#luac">luac</A><BR>
-<A HREF="manual.html#max">max</A><BR>
+<A HREF="manual.html#lt event">``lt'' event</A><BR>
+<A HREF="manual.html#Lua Stand-alone">Lua stand-alone</A><BR>
+<A HREF="manual.html#luac"><TT>luac</TT></A><BR>
+
+ <P>
+
+<A HREF="manual.html#max"><TT>max</TT></A><BR>
<A HREF="manual.html#methods">methods</A><BR>
-<A HREF="manual.html#min">min</A><BR>
-<A HREF="manual.html#mod">mod</A><BR>
-<A HREF="manual.html#mul event">mul event</A><BR>
+<A HREF="manual.html#min"><TT>min</TT></A><BR>
+<A HREF="manual.html#mod"><TT>mod</TT></A><BR>
+<A HREF="manual.html#mul event">``mul'' event</A><BR>
<A HREF="manual.html#multiple assignment">multiple assignment</A><BR>
-<A HREF="manual.html#newtag">newtag</A><BR>
-<A HREF="manual.html#nextvar">nextvar</A><BR>
-<A HREF="manual.html#next">next</A><BR>
+
+ <P>
+
+<A HREF="manual.html#newtag"><TT>newtag</TT></A><BR>
+<A HREF="manual.html#next"><TT>next</TT></A><BR>
<A HREF="manual.html#nil">nil</A><BR>
<A HREF="manual.html#not">not</A><BR>
<A HREF="manual.html#number">number</A><BR>
-<A HREF="manual.html#openfile">openfile</A><BR>
+<A HREF="manual.html#Numerical constants">numerical constants</A><BR>
+
+ <P>
+
+<A HREF="manual.html#openfile"><TT>openfile</TT></A><BR>
+<A HREF="manual.html#Operator precedence">operator precedence</A><BR>
<A HREF="manual.html#or">or</A><BR>
-<A HREF="manual.html#packed results">packed results</A><BR>
-<A HREF="manual.html#pattern item">pattern item</A><BR>
+
+ <P>
+
<A HREF="manual.html#pattern">pattern</A><BR>
+<A HREF="manual.html#pattern item">pattern item</A><BR>
+<A HREF="manual.html#PI"><TT>PI</TT></A><BR>
<A HREF="manual.html#piped input">piped input</A><BR>
-<A HREF="manual.html#piped output">piped output</A><BR>
-<A HREF="manual.html#popen">popen</A><BR>
-<A HREF="manual.html#popen">popen</A><BR>
-<A HREF="manual.html#pow event">pow event</A><BR>
+<A HREF="manual.html#popen"><TT>popen</TT></A><BR>
+<A HREF="manual.html#pow event">``pow'' event</A><BR>
<A HREF="manual.html#pre-compilation">pre-compilation</A><BR>
-<A HREF="manual.html#predefined functions">predefined functions</A><BR>
-<A HREF="manual.html#print">print</A><BR>
+<A HREF="manual.html#print"><TT>print</TT></A><BR>
<A HREF="manual.html#protected calls">protected calls</A><BR>
-<A HREF="manual.html#rad">rad</A><BR>
-<A HREF="manual.html#randomseed">randomseed</A><BR>
-<A HREF="manual.html#random">random</A><BR>
-<A HREF="manual.html#rawgetglobal">rawgetglobal</A><BR>
-<A HREF="manual.html#rawgettable">rawgettable</A><BR>
-<A HREF="manual.html#rawsetglobal">rawsetglobal</A><BR>
-<A HREF="manual.html#rawsettable">rawsettable</A><BR>
-<A HREF="manual.html#read pattern">read pattern</A><BR>
-<A HREF="manual.html#readfrom">readfrom</A><BR>
-<A HREF="manual.html#read">read</A><BR>
+
+ <P>
+
+<A HREF="manual.html#rad"><TT>rad</TT></A><BR>
+<A HREF="manual.html#random"><TT>random</TT></A><BR>
+<A HREF="manual.html#randomseed"><TT>randomseed</TT></A><BR>
+<A HREF="manual.html#rawget"><TT>rawget</TT></A><BR>
+<A HREF="manual.html#rawset"><TT>rawset</TT></A><BR>
+<A HREF="manual.html#read"><TT>read</TT></A><BR>
+<A HREF="manual.html#readfrom"><TT>readfrom</TT></A><BR>
<A HREF="manual.html#records">records</A><BR>
<A HREF="manual.html#reference">reference</A><BR>
-<A HREF="manual.html#reflexivity">reflexivity</A><BR>
<A HREF="manual.html#relational operators">relational operators</A><BR>
-<A HREF="manual.html#remove">remove</A><BR>
-<A HREF="manual.html#rename">rename</A><BR>
-<A HREF="manual.html#repeat-until">repeat-until</A><BR>
+<A HREF="manual.html#remove"><TT>remove</TT></A><BR>
+<A HREF="manual.html#rename"><TT>rename</TT></A><BR>
+<A HREF="manual.html#repeat-until statement">repeat-until statement</A><BR>
<A HREF="manual.html#reserved words">reserved words</A><BR>
<A HREF="manual.html#return statement">return statement</A><BR>
-<A HREF="manual.html#return">return</A><BR>
-<A HREF="manual.html#seek">seek</A><BR>
-<A HREF="manual.html#self">self</A><BR>
-<A HREF="manual.html#setcallhook">setcallhook</A><BR>
-<A HREF="manual.html#setglobal event">setglobal event</A><BR>
-<A HREF="manual.html#setglobal">setglobal</A><BR>
-<A HREF="manual.html#setlinehook">setlinehook</A><BR>
-<A HREF="manual.html#setlocale">setlocale</A><BR>
-<A HREF="manual.html#setlocal">setlocal</A><BR>
-<A HREF="manual.html#settable event">settable event</A><BR>
-<A HREF="manual.html#settagmethod">settagmethod</A><BR>
-<A HREF="manual.html#settagmethod">settagmethod</A><BR>
-<A HREF="manual.html#settag">settag</A><BR>
+
+ <P>
+
+<A HREF="manual.html#seek"><TT>seek</TT></A><BR>
+<A HREF="manual.html#self"><TT>self</TT></A><BR>
+<A HREF="manual.html#setcallhook"><TT>setcallhook</TT></A><BR>
+<A HREF="manual.html#setglobal"><TT>setglobal</TT></A><BR>
+<A HREF="manual.html#setglobal event">``setglobal'' event</A><BR>
+<A HREF="manual.html#setlinehook"><TT>setlinehook</TT></A><BR>
+<A HREF="manual.html#setlocal"><TT>setlocal</TT></A><BR>
+<A HREF="manual.html#setlocale"><TT>setlocale</TT></A><BR>
+<A HREF="manual.html#settable event">``settable'' event</A><BR>
+<A HREF="manual.html#settag"><TT>settag</TT></A><BR>
+<A HREF="manual.html#settagmethod"><TT>settagmethod</TT></A><BR>
<A HREF="manual.html#short-cut evaluation">short-cut evaluation</A><BR>
-<A HREF="manual.html#sin">sin</A><BR>
-<A HREF="manual.html#skips">skips</A><BR>
-<A HREF="manual.html#sort">sort</A><BR>
-<A HREF="manual.html#sqrt">sqrt</A><BR>
+<A HREF="manual.html#sin"><TT>sin</TT></A><BR>
+<A HREF="manual.html#sort"><TT>sort</TT></A><BR>
+<A HREF="manual.html#sqrt"><TT>sqrt</TT></A><BR>
+<A HREF="manual.html#stack index">stack index</A><BR>
+<A HREF="manual.html#state">state</A><BR>
<A HREF="manual.html#statements">statements</A><BR>
-<A HREF="manual.html#stderr">stderr</A><BR>
-<A HREF="manual.html#strbyte">strbyte</A><BR>
-<A HREF="manual.html#strchar">strchar</A><BR>
-<A HREF="manual.html#strfind">strfind</A><BR>
+<A HREF="manual.html#stderr"><TT>stderr</TT></A><BR>
+<A HREF="manual.html#strbyte"><TT>strbyte</TT></A><BR>
+<A HREF="manual.html#strchar"><TT>strchar</TT></A><BR>
+<A HREF="manual.html#strfind"><TT>strfind</TT></A><BR>
<A HREF="manual.html#string">string</A><BR>
-<A HREF="manual.html#strlen">strlen</A><BR>
-<A HREF="manual.html#strlower">strlower</A><BR>
-<A HREF="manual.html#strrep">strrep</A><BR>
-<A HREF="manual.html#strsub">strsub</A><BR>
-<A HREF="manual.html#strupper">strupper</A><BR>
-<A HREF="manual.html#sub event">sub event</A><BR>
+<A HREF="manual.html#strlen"><TT>strlen</TT></A><BR>
+<A HREF="manual.html#strlower"><TT>strlower</TT></A><BR>
+<A HREF="manual.html#strrep"><TT>strrep</TT></A><BR>
+<A HREF="manual.html#strsub"><TT>strsub</TT></A><BR>
+<A HREF="manual.html#strupper"><TT>strupper</TT></A><BR>
+<A HREF="manual.html#sub event">``sub'' event</A><BR>
+
+ <P>
+
<A HREF="manual.html#table">table</A><BR>
-<A HREF="manual.html#tag methods">tag methods</A><BR>
<A HREF="manual.html#tag">tag</A><BR>
-<A HREF="manual.html#tag">tag</A><BR>
-<A HREF="manual.html#tan">tan</A><BR>
-<A HREF="manual.html#tinsert">tinsert</A><BR>
-<A HREF="manual.html#tmpname">tmpname</A><BR>
+<A HREF="manual.html#tag"><TT>tag</TT></A><BR>
+<A HREF="manual.html#tag method">tag method</A><BR>
+....... <A HREF="manual.html#add">add</A><BR>
+....... <A HREF="manual.html#concatenation">concatenation</A><BR>
+....... <A HREF="manual.html#div">div</A><BR>
+....... <A HREF="manual.html#function">function</A><BR>
+....... <A HREF="manual.html#gc">gc</A><BR>
+....... <A HREF="manual.html#getglobal">getglobal</A><BR>
+....... <A HREF="manual.html#gettable">gettable</A><BR>
+....... <A HREF="manual.html#index">index</A><BR>
+....... <A HREF="manual.html#lt">lt</A><BR>
+....... <A HREF="manual.html#mul">mul</A><BR>
+....... <A HREF="manual.html#pow">pow</A><BR>
+....... <A HREF="manual.html#setglobal">setglobal</A><BR>
+....... <A HREF="manual.html#settable">settable</A><BR>
+....... <A HREF="manual.html#sub">sub</A><BR>
+....... <A HREF="manual.html#unm">unm</A><BR>
+<A HREF="manual.html#tan"><TT>tan</TT></A><BR>
+<A HREF="manual.html#tinsert"><TT>tinsert</TT></A><BR>
+<A HREF="manual.html#tmpname"><TT>tmpname</TT></A><BR>
<A HREF="manual.html#tokens">tokens</A><BR>
-<A HREF="manual.html#tonumber">tonumber</A><BR>
-<A HREF="manual.html#tostring">tostring</A><BR>
-<A HREF="manual.html#tremove">tremove</A><BR>
-<A HREF="manual.html#type">type</A><BR>
-<A HREF="manual.html#unm event">unm event</A><BR>
+<A HREF="manual.html#tonumber"><TT>tonumber</TT></A><BR>
+<A HREF="manual.html#tostring"><TT>tostring</TT></A><BR>
+<A HREF="manual.html#tremove"><TT>tremove</TT></A><BR>
+<A HREF="manual.html#type"><TT>type</TT></A><BR>
+<A HREF="manual.html#Types and Tags">types and tags</A><BR>
+
+ <P>
+
+<A HREF="manual.html#unm event">``unm'' event</A><BR>
+<A HREF="manual.html#upvalues">upvalues</A><BR>
<A HREF="manual.html#userdata">userdata</A><BR>
-<A HREF="manual.html#vararg">vararg</A><BR>
-<A HREF="manual.html#version 3.0">version 3.0</A><BR>
-<A HREF="manual.html#version 3.1">version 3.1</A><BR>
-<A HREF="manual.html#while-do">while-do</A><BR>
-<A HREF="manual.html#writeto">writeto</A><BR>
-<A HREF="manual.html#write">write</A><BR>
+
+ <P>
+
+<A HREF="manual.html#valid index">valid index</A><BR>
+<A HREF="manual.html#vararg function">vararg function</A><BR>
+<A HREF="manual.html#version 3.2">version 3.2</A><BR>
+<A HREF="manual.html#visibility">visibility</A><BR>
+
+ <P>
+
+<A HREF="manual.html#while-do statement">while-do statement</A><BR>
+<A HREF="manual.html#write"><TT>write</TT></A><BR>
+<A HREF="manual.html#writeto"><TT>writeto</TT></A><BR>
+
+ <P>
+
<HR>
<SMALL>
Last update:
-Wed Jul 7 13:36:24 EST 1999
+Mon Nov 6 17:35:51 EDT 2000
by <A HREF="http://www.tecgraf.puc-rio.br/~lhf/">lhf</A>.
</SMALL>
diff --git a/doc/index.html b/doc/index.html
index e6ff5faf..b7603a30 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -1,30 +1,23 @@
<HTML>
<HEAD>
-<TITLE>Lua 3.2 Reference Manual - Contents</TITLE>
+<TITLE>Lua: reference manual - contents</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<HR>
-<H1>Reference Manual of the Programming Language
-<A HREF="http://www.tecgraf.puc-rio.br/lua/">Lua</A>
-3.2</H1>
-<P>
-<A HREF="http://www.inf.puc-rio.br/~roberto/">Roberto Ierusalimschy</A>,
-<A HREF="http://www.tecgraf.puc-rio.br/~lhf/">Luiz Henrique de Figueiredo</A>,
-<A HREF="http://www.tecgraf.puc-rio.br/~celes/">Waldemar Celes</A>
-<BR>
-<A HREF="mailto:lua@tecgraf.puc-rio.br">lua@tecgraf.puc-rio.br</A><BR>
-<A HREF="http://www.tecgraf.puc-rio.br">TeCGraf</A>,
-<A HREF="http://www.inf.puc-rio.br">Computer Science Department</A>,
-<A HREF="http://www.puc-rio.br">PUC-Rio</A>
-<P>
+<H1>
+<IMG SRC="logo.gif" ALT="Lua" ALIGN="bottom">
+Reference manual
+</H1>
+<A HREF="manual.html">
+Reference Manual of the Programming Language
+<A HREF="http://www.tecgraf.puc-rio.br/lua/">Lua</A>
+4.0</A>
[
<A HREF="manual.html">top</A>
|
-<A HREF="#contents">contents</A>
-|
<A HREF="idx.html">index</A>
|
<A HREF="ftp://ftp.tecgraf.puc-rio.br/pub/lua/refman.ps.gz">ps</A>
@@ -33,7 +26,7 @@
|
<A HREF="old/">old versions</A>
]
-<HR>
+<P>
<A NAME="contents"></A>
<UL>
<LI><A HREF="manual.html#1.">1 - Introduction</A>
@@ -42,50 +35,57 @@
<LI><A HREF="manual.html#4.">4 - The Language</A>
<UL>
<LI><A HREF="manual.html#4.1">4.1 - Lexical Conventions</A>
- <LI><A HREF="manual.html#4.2">4.2 - The Pre-processor</A>
- <LI><A HREF="manual.html#4.3">4.3 - Coercion</A>
- <LI><A HREF="manual.html#4.4">4.4 - Adjustment</A>
- <LI><A HREF="manual.html#4.5">4.5 - Statements</A>
- <LI><A HREF="manual.html#4.6">4.6 - Expressions</A>
- <LI><A HREF="manual.html#4.7">4.7 - Visibility and Upvalues</A>
+ <LI><A HREF="manual.html#4.2">4.2 - Coercion</A>
+ <LI><A HREF="manual.html#4.3">4.3 - Adjustment</A>
+ <LI><A HREF="manual.html#4.4">4.4 - Statements</A>
+ <LI><A HREF="manual.html#4.5">4.5 - Expressions</A>
+ <LI><A HREF="manual.html#4.6">4.6 - Visibility and Upvalues</A>
+ <LI><A HREF="manual.html#4.7">4.7 - Error Handling</A>
<LI><A HREF="manual.html#4.8">4.8 - Tag Methods</A>
- <LI><A HREF="manual.html#4.9">4.9 - Error Handling</A>
</UL>
<LI><A HREF="manual.html#5.">5 - The Application Program Interface</A>
<UL>
- <LI><A HREF="manual.html#5.1">5.1 - Managing States</A>
- <LI><A HREF="manual.html#5.2">5.2 - Exchanging Values between C and Lua</A>
- <LI><A HREF="manual.html#5.3">5.3 - Garbage Collection</A>
- <LI><A HREF="manual.html#5.4">5.4 - Executing Lua Code</A>
- <LI><A HREF="manual.html#5.5">5.5 - Manipulating Lua Objects</A>
- <LI><A HREF="manual.html#5.6">5.6 - Calling Lua Functions</A>
- <LI><A HREF="manual.html#5.7">5.7 - C Functions</A>
- <LI><A HREF="manual.html#5.8">5.8 - References to Lua Objects</A>
+ <LI><A HREF="manual.html#5.1">5.1 - States</A>
+ <LI><A HREF="manual.html#5.2">5.2 - The Stack and Indices</A>
+ <LI><A HREF="manual.html#5.3">5.3 - Stack Manipulation</A>
+ <LI><A HREF="manual.html#5.4">5.4 - Querying the Stack</A>
+ <LI><A HREF="manual.html#5.5">5.5 - Pushing values onto the Stack</A>
+ <LI><A HREF="manual.html#5.6">5.6 - Garbage Collection</A>
+ <LI><A HREF="manual.html#5.7">5.7 - Userdata and Tags</A>
+ <LI><A HREF="manual.html#5.8">5.8 - Executing Lua Code</A>
+ <LI><A HREF="manual.html#5.9">5.9 - Manipulating Global Variables in Lua</A>
+ <LI><A HREF="manual.html#5.10">5.10 - Manipulating Tables in Lua</A>
+ <LI><A HREF="manual.html#5.11">5.11 - Using Tables as Arrays</A>
+ <LI><A HREF="manual.html#5.12">5.12 - Calling Lua Functions</A>
+ <LI><A HREF="manual.html#5.13">5.13 - Defining C Functions</A>
+ <LI><A HREF="manual.html#5.14">5.14 - References to Lua Objects</A>
</UL>
-<LI><A HREF="manual.html#6.">6 - Predefined Functions and Libraries</A>
+<LI><A HREF="manual.html#6.">6 - Standard Libraries</A>
<UL>
- <LI><A HREF="manual.html#6.1">6.1 - Predefined Functions</A>
+ <LI><A HREF="manual.html#6.1">6.1 - Basic Functions</A>
<LI><A HREF="manual.html#6.2">6.2 - String Manipulation</A>
<LI><A HREF="manual.html#6.3">6.3 - Mathematical Functions</A>
<LI><A HREF="manual.html#6.4">6.4 - I/O Facilities</A>
+ <LI><A HREF="manual.html#6.5">6.5 - System Facilities</A>
</UL>
-<LI><A HREF="manual.html#7.">7 - The Debugger Interface</A>
+<LI><A HREF="manual.html#7.">7 - The Debug Interface</A>
<UL>
<LI><A HREF="manual.html#7.1">7.1 - Stack and Function Information</A>
<LI><A HREF="manual.html#7.2">7.2 - Manipulating Local Variables</A>
<LI><A HREF="manual.html#7.3">7.3 - Hooks</A>
- <LI><A HREF="manual.html#7.4">7.4 - The Reflexive Debugger Interface</A>
+ <LI><A HREF="manual.html#7.4">7.4 - The Reflexive Debug Interface</A>
</UL>
<LI><A HREF="manual.html#8.">8 - Lua Stand-alone</A>
<LI><A HREF="manual.html#Acknowledgments">Acknowledgments</A>
<LI><A HREF="manual.html#Incompatibilities">Incompatibilities with Previous Versions</A>
+<LI><A HREF="manual.html#BNF">The Complete Syntax of Lua</A>
<LI><A HREF="idx.html">Index</A>
</UL>
<HR>
<SMALL>
Last update:
-Wed Jul 7 13:36:24 EST 1999
+Mon Nov 6 17:36:08 EDT 2000
by <A HREF="http://www.tecgraf.puc-rio.br/~lhf/">lhf</A>.
</SMALL>
diff --git a/doc/logo.gif b/doc/logo.gif
new file mode 100644
index 00000000..f3e68936
--- /dev/null
+++ b/doc/logo.gif
Binary files differ
diff --git a/doc/lua.1 b/doc/lua.1
new file mode 100644
index 00000000..b1561818
--- /dev/null
+++ b/doc/lua.1
@@ -0,0 +1,143 @@
+.\" lua.man,v 1.3 2000/09/04 21:41:28 lhf Exp
+.TH LUA 1 "2000/09/04 21:41:28"
+.SH NAME
+lua \- Lua interpreter
+.SH SYNOPSIS
+.B lua
+[
+.I arguments
+]
+.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,
+as output by
+.BR luac ,
+the Lua compiler.
+.B lua
+can be used as a batch interpreter and also interactively.
+.LP
+The
+.I arguments
+can be options, assignments, or filenames,
+and are processed in order,
+from left to right.
+.LP
+Options start with
+.B \-
+and are described below.
+.LP
+An assignment is an argument of the form
+.BR a=b ,
+which assigns the string
+.RB ` b '
+to the global variable
+.BR a .
+Note that no quotes are needed around the string if it does not contain spaces
+or other characters special to the shell.
+This is for convenience only.
+(In general,
+you should be careful when using quotes and spaces on the command line
+because they are usually handled by the shell.)
+.LP
+If the argument is neither an option nor an assignment,
+then it is assumed to be a filename,
+which is then loaded and executed.
+.LP
+If no arguments are given,
+then
+.B "\-v \-i"
+is assumed when the standard input is a terminal;
+otherwise,
+.B \-
+is assumed.
+.SH OPTIONS
+.TP
+.B \-
+load the standard input as a file,
+that is,
+not interactively,
+even when the standard input is a terminal.
+.TP
+.B \-c
+close Lua before exiting.
+.TP
+.BI \-e " stat"
+execute statement
+.IR stat .
+You will need to quote
+.I stat
+if it contains spaces or quotes.
+.TP
+.BI \-f " file"
+collect all remaining arguments as strings into a global table named
+.B arg
+and then execute
+.IR file .
+The arguments in
+.B arg
+start at 0,
+which contains the string
+.RI ` file '.
+The index of the last argument is stored in
+.BR "arg.n" .
+.TP
+.B \-i
+enter interactive mode,
+displaying a prompt.
+In this mode,
+.B lua
+reads lines from the standard input and executes them as they are read.
+Each line must contain a complete statement.
+To span a statement across several lines, end each line with a backslash
+.BR `\e' .
+The prompt shown is the value of the global variable
+.BR _PROMPT ,
+if this value is a string.
+So,
+to change the prompt,
+set
+.B _PROMPT
+to a string of your choice.
+You can do that after calling the interpreter
+or on the command line with
+.BR "_PROMPT=\'lua: \'" ,
+for example.
+(Note the need for quotes, because the string contains a space.)
+The default prompt is ``> ''.
+.TP
+.B \-q
+enter interactive mode,
+but without displaying a prompt.
+.TP
+.BI \-s n
+set the stack size to
+.IB n .
+If present,
+this must be the first option.
+Note that
+.I n
+is in the same argument as
+.BR -s .
+For example,
+to specify a stack size of 2000,
+use
+.BR -s2000 .
+.TP
+.B \-v
+print version information.
+.SH "SEE ALSO"
+.BR luac (1)
+.br
+http://www.tecgraf.puc-rio.br/lua/
+.SH DIAGNOSTICS
+Error messages should be self explanatory.
+.SH AUTHORS
+R. Ierusalimschy,
+L. H. de Figueiredo,
+and
+W. Celes
+(lua@tecgraf.puc-rio.br)
+.\" EOF
diff --git a/doc/lua.html b/doc/lua.html
new file mode 100644
index 00000000..ef861bb5
--- /dev/null
+++ b/doc/lua.html
@@ -0,0 +1,151 @@
+<!-- lua.man,v 1.3 2000/09/04 21:41:28 lhf Exp -->
+<HTML>
+<HEAD>
+<TITLE>LUA man page</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#FFFFFF">
+
+<H1>NAME</H1>
+lua - Lua interpreter
+<H1>SYNOPSIS</H1>
+<B>lua</B>
+[
+<I>arguments</I>
+]
+<H1>DESCRIPTION</H1>
+<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,
+as output by
+<B>luac</B>,
+the Lua compiler.
+<B>lua</B>
+can be used as a batch interpreter and also interactively.
+<P>
+The
+<I>arguments</I>
+can be options, assignments, or filenames,
+and are processed in order,
+from left to right.
+<P>
+Options start with
+<B>-</B>
+and are described below.
+<P>
+An assignment is an argument of the form
+<B>a=b</B>,
+which assigns the string
+.RB ` b '
+to the global variable
+<B>a</B>.
+Note that no quotes are needed around the string if it does not contain spaces
+or other characters special to the shell.
+This is for convenience only.
+(In general,
+you should be careful when using quotes and spaces on the command line
+because they are usually handled by the shell.)
+<P>
+If the argument is neither an option nor an assignment,
+then it is assumed to be a filename,
+which is then loaded and executed.
+<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.
+<H1>OPTIONS</H1>
+<P>
+<B>-</B>
+load the standard input as a file,
+that is,
+not interactively,
+even when the standard input is a terminal.
+<P>
+<B>-c</B>
+close Lua before exiting.
+<P>
+<B>-e "</B><I>stat"</I>
+execute statement
+<I>stat</I>.
+You will need to quote
+<I>stat </I>
+if it contains spaces or quotes.
+<P>
+<B>-f "</B><I>file"</I>
+collect all remaining arguments as strings into a global table named
+<B>arg</B>
+and then execute
+<I>file</I>.
+The arguments in
+<B>arg</B>
+start at 0,
+which contains the string
+.RI ` file '.
+The index of the last argument is stored in
+<B>"arg.n"</B>.
+<P>
+<B>-i</B>
+enter interactive mode,
+displaying a prompt.
+In this mode,
+<B>lua</B>
+reads lines from the standard input and executes them as they are read.
+Each line must contain a complete statement.
+To span a statement across several lines, end each line with a backslash
+<B>`\e'</B>.
+The prompt shown is the value of the global variable
+<B>_PROMPT</B>,
+if this value is a string.
+So,
+to change the prompt,
+set
+<B>_PROMPT</B>
+to a string of your choice.
+You can do that after calling the interpreter
+or on the command line with
+<B>"_PROMPT=\'lua: \'"</B>,
+for example.
+(Note the need for quotes, because the string contains a space.)
+The default prompt is ``&gt; ''.
+<P>
+<B>-q</B>
+enter interactive mode,
+but without displaying a prompt.
+<P>
+<B>-s</B><I>n</I>
+set the stack size to
+.IB n .
+If present,
+this must be the first option.
+Note that
+<I>n</I>
+is in the same argument as
+<B>-s</B>.
+For example,
+to specify a stack size of 2000,
+use
+<B>-s2000</B>.
+<P>
+<B>-v</B>
+print version information.
+<H1>SEE ALSO</H1>
+<B>luac</B>(1)
+<BR>
+<A HREF="http://www.tecgraf.puc-rio.br/lua/">http://www.tecgraf.puc-rio.br/lua/</A>
+<H1>DIAGNOSTICS</H1>
+Error messages should be self explanatory.
+<H1>AUTHORS</H1>
+R. Ierusalimschy,
+L. H. de Figueiredo,
+and
+W. Celes
+(<A HREF="mailto:lua@tecgraf.puc-rio.br">lua@tecgraf.puc-rio.br</A>)
+<!-- EOF -->
+</BODY>
+</HTML>
diff --git a/doc/luac.1 b/doc/luac.1
new file mode 100644
index 00000000..212f9b61
--- /dev/null
+++ b/doc/luac.1
@@ -0,0 +1,139 @@
+.\" luac.man,v 1.20 2000/10/06 15:11:21 lhf Exp
+.TH LUAC 1 "2000/10/06 15:11:21"
+.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 loaded and executed with
+.B lua_dofile
+in C or with
+.B dofile
+in Lua.
+.LP
+The main advantages of precompiling chunks are:
+faster loading,
+protecting source code from user changes,
+and
+off-line syntax error detection.
+.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
+.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
+The binary files created by
+.B luac
+are portable to all architectures with the same word size.
+This means that
+binary files created on a 32-bit platform (such as Intel)
+can be read without change in another 32-bit platform (such as Sparc),
+even if the byte order (``endianess'') is different.
+On the other hand,
+binary files created on a 16-bit platform cannot be read in a 32-bit platform.
+.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
+.I stdin
+as a source file.
+.LP
+The internal format of the binary files produced by
+.B luac
+may change when a new version of Lua is released.
+We try to maintain compatibility even for binary files,
+but it is not always possible.
+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 .
+The output file can be a source file because
+all files are loaded before the output file is written.
+.TP
+.B \-p
+load files but do not generate any output file.
+Used mainly for syntax checking or testing precompiled chunks:
+corrupted files will probably generate errors when loaded.
+For a thourough integrity test,
+use
+.BR \-t .
+.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 these chunks,
+then the error messages might not contain the full information they usually do.
+.TP
+.B \-t
+perform a thourough integrity test of precompiled chunks.
+Code 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.
+.TP
+.B \-v
+print version information.
+.SH FILES
+.TP 15
+.B luac.out
+default output file
+.SH "SEE ALSO"
+.BR lua (1)
+.br
+http://www.tecgraf.puc-rio.br/lua/
+.SH DIAGNOSTICS
+Error messages should be self explanatory.
+.SH AUTHORS
+L. H. de Figueiredo,
+R. Ierusalimschy and
+W. Celes
+(lua@tecgraf.puc-rio.br)
+.\" EOF
diff --git a/doc/luac.html b/doc/luac.html
index 92d9ddf1..e083c2b3 100644
--- a/doc/luac.html
+++ b/doc/luac.html
@@ -1,4 +1,4 @@
-<!-- luac.man,v 1.17 1999/07/07 16:02:07 lhf Exp -->
+<!-- luac.man,v 1.20 2000/10/06 15:11:21 lhf Exp -->
<HTML>
<HEAD>
<TITLE>LUAC man page</TITLE>
@@ -25,14 +25,11 @@ in C or with
<B>dofile</B>
in Lua.
<P>
-The main advantages of pre-compiling chunks are:
+The main advantages of precompiling chunks are:
faster loading,
protecting source code from user changes,
and
off-line syntax error detection.
-The binary files created by
-<B>luac</B>
-are portable to all architectures.
<P>
Pre-compiling does not imply faster execution
because in Lua chunks are always compiled into bytecodes before being executed.
@@ -49,126 +46,87 @@ but you can change this with the
<B>-o</B>
option.
<P>
+The binary files created by
+<B>luac</B>
+are portable to all architectures with the same word size.
+This means that
+binary files created on a 32-bit platform (such as Intel)
+can be read without change in another 32-bit platform (such as Sparc),
+even if the byte order (``endianess'') is different.
+On the other hand,
+binary files created on a 16-bit platform cannot be read in a 32-bit platform.
+<P>
+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.
+<P>
You can use
<B>"-"</B>
to indicate
<I>stdin</I>
as a source file.
<P>
-<B>luac</B>
-can also load and list binary files with the
-<B>-u</B>
-option.
-<P>
-Binary files produced by differents runs of
-<B>luac</B>
-(even in different machines)
-can be combined into one large file,
-using
-<B>cat</B>(1).
-The result is still a valid binary file
-and can be loaded with a single call to
-<B>lua_dofile</B>
-or
-<B>dofile</B>.
-<P>
The internal format of the binary files produced by
<B>luac</B>
may change when a new version of Lua is released.
We try to maintain compatibility even for binary files,
-but sometimes it cannot be done.
+but it is not always possible.
So,
save the source files of all Lua programs that you precompile.
<P>
<H1>OPTIONS</H1>
Options must be separate.
<P>
-<B>-c</B>
-compile (this is the default).
-<P>
-<B>-u</B>
-undump, i.e., load and list the given binary files.
-If no files are given, then luac undumps
-<B>luac.out</B>.
-Listing a binary file is useful to learn Lua's virtual machine.
-Listing is also useful to test the integrity of binary files:
-corrupted files will probably generate errors when undumped.
-To test without listing, use
-<B>-q</B>.
-For a thourough integrity test,
-use
-<B>-t</B>.
-<P>
-<B>-d</B>
-turn debugging on.
-Individual chunks may
-still control the generation of debug information with
-$debug and $nodebug.
-If debugging is on, then listings show the names of the local variables.
-<P>
-<B>-D "</B><I>name"</I>
-predefine symbol
-<I>name</I>
-for conditional compilation.
-By default,
-<B>luac</B>
-does
-<I>not</I>
-predefine any symbols,
-not even the built-in functions.
-<P>
<B>-l</B>
produce a listing of the compiled bytecode for Lua's virtual machine.
-This is the default when undumping.
-<P>
-<B>-n</B>
-Save numbers in native format.
-By default,
-numbers are saved in text form,
-for maximum portability.
-Binary files with numbers in native format are slightly faster to load,
-but are not completely portable.
+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>filename"</I>
+<B>-o "</B><I>file"</I>
output to
-<I>filename</I>,
+<I>file</I>,
instead of the default
<B>luac.out</B>.
-The output file cannot be a source file.
-<P>
-<B>-O</B>
-optimize.
-Debug information is removed
-and
-duplicate constants are coalesced.
+The output file can be a source file because
+all files are loaded before the output file is written.
<P>
<B>-p</B>
-parse sources files but do not generate any output file.
-Used mainly for syntax checking.
+load files but do not generate any output file.
+Used mainly for syntax checking or testing precompiled chunks:
+corrupted files will probably generate errors when loaded.
+For a thourough integrity test,
+use
+<B>-t</B>.
<P>
-<B>-q</B>
-quiet; produces no listing.
-This is the default when compiling.
+<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 these chunks,
+then the error messages might not contain the full information they usually do.
<P>
<B>-t</B>
-perform a thourough integrity test when undumping.
+perform a thourough integrity test of precompiled chunks.
Code 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.)
-<P>
-<B>-U "</B><I>name"</I>
-undefine symbol
-<I>name</I>
-for conditional compilation.
+If no files are given, then
+<B>luac</B>
+loads
+<B>luac.out</B>
+and tests its contents.
<P>
<B>-v</B>
print version information.
-<P>
-<B>-V</B>
-verbose;
-print the names of the source files as they are processed.
<H1>FILES</H1>
<P>
<B>luac.out</B>
@@ -176,19 +134,14 @@ default output file
<H1>SEE ALSO</H1>
<B>lua</B>(1)
<BR>
-<I>"Reference Manual of the Programming Language Lua"</I>
-<BR>
<A HREF="http://www.tecgraf.puc-rio.br/lua/">http://www.tecgraf.puc-rio.br/lua/</A>
-<BR>
-"Lua: an extensible extension language",
-<I>Software: Practice &amp; Experience</I>
-<B>26</B>
-#6 (1996) 635-652.
<H1>DIAGNOSTICS</H1>
Error messages should be self explanatory.
<H1>AUTHORS</H1>
L. H. de Figueiredo,
R. Ierusalimschy and
W. Celes
-<I>(<A HREF="mailto:lua@tecgraf.puc-rio.br">lua@tecgraf.puc-rio.br</A>)</I>
+(<A HREF="mailto:lua@tecgraf.puc-rio.br">lua@tecgraf.puc-rio.br</A>)
<!-- EOF -->
+</BODY>
+</HTML>
diff --git a/doc/luac.man b/doc/luac.man
deleted file mode 100644
index 818448b8..00000000
--- a/doc/luac.man
+++ /dev/null
@@ -1,188 +0,0 @@
-.\" luac.man,v 1.17 1999/07/07 16:02:07 lhf Exp
-.TH LUAC 1 "1999/07/07 16:02:07"
-.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 loaded and executed with
-.B lua_dofile
-in C or with
-.B dofile
-in Lua.
-.LP
-The main advantages of pre-compiling chunks are:
-faster loading,
-protecting source code from user changes,
-and
-off-line syntax error detection.
-The binary files created by
-.B luac
-are portable to all architectures.
-.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
-.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
-You can use
-.B "\-"
-to indicate
-.I stdin
-as a source file.
-.LP
-.B luac
-can also load and list binary files with the
-.B \-u
-option.
-.LP
-Binary files produced by differents runs of
-.B luac
-(even in different machines)
-can be combined into one large file,
-using
-.BR cat (1).
-The result is still a valid binary file
-and can be loaded with a single call to
-.B lua_dofile
-or
-.BR dofile .
-.LP
-The internal format of the binary files produced by
-.B luac
-may change when a new version of Lua is released.
-We try to maintain compatibility even for binary files,
-but sometimes it cannot be done.
-So,
-save the source files of all Lua programs that you precompile.
-.LP
-.SH OPTIONS
-Options must be separate.
-.TP
-.B \-c
-compile (this is the default).
-.TP
-.B \-u
-undump, i.e., load and list the given binary files.
-If no files are given, then luac undumps
-.BR luac.out .
-Listing a binary file is useful to learn Lua's virtual machine.
-Listing is also useful to test the integrity of binary files:
-corrupted files will probably generate errors when undumped.
-To test without listing, use
-.BR \-q .
-For a thourough integrity test,
-use
-.BR \-t .
-.TP
-.B \-d
-turn debugging on.
-Individual chunks may
-still control the generation of debug information with
-$debug and $nodebug.
-If debugging is on, then listings show the names of the local variables.
-.TP
-.BI \-D " name"
-predefine symbol
-.I name
-for conditional compilation.
-By default,
-.B luac
-does
-.I not
-predefine any symbols,
-not even the built-in functions.
-.TP
-.B \-l
-produce a listing of the compiled bytecode for Lua's virtual machine.
-This is the default when undumping.
-.TP
-.B \-n
-Save numbers in native format.
-By default,
-numbers are saved in text form,
-for maximum portability.
-Binary files with numbers in native format are slightly faster to load,
-but are not completely portable.
-.TP
-.BI \-o " filename"
-output to
-.IR filename ,
-instead of the default
-.BR luac.out .
-The output file cannot be a source file.
-.TP
-.B \-O
-optimize.
-Debug information is removed
-and
-duplicate constants are coalesced.
-.TP
-.B \-p
-parse sources files but do not generate any output file.
-Used mainly for syntax checking.
-.TP
-.B \-q
-quiet; produces no listing.
-This is the default when compiling.
-.TP
-.B \-t
-perform a thourough integrity test when undumping.
-Code 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.)
-.TP
-.BI \-U " name"
-undefine symbol
-.I name
-for conditional compilation.
-.TP
-.B \-v
-print version information.
-.TP
-.B \-V
-verbose;
-print the names of the source files as they are processed.
-.SH FILES
-.TP 15
-.B luac.out
-default output file
-.SH "SEE ALSO"
-.BR lua (1)
-.br
-.I "Reference Manual of the Programming Language Lua"
-.br
-http://www.tecgraf.puc-rio.br/lua/
-.br
-"Lua: an extensible extension language",
-.I Software: Practice & Experience
-.B 26
-#6 (1996) 635-652.
-.SH DIAGNOSTICS
-Error messages should be self explanatory.
-.SH AUTHORS
-L. H. de Figueiredo,
-R. Ierusalimschy and
-W. Celes
-.I (lua@tecgraf.puc-rio.br)
-.\" EOF
diff --git a/doc/manual.html b/doc/manual.html
index 8c157c2b..703bd165 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -1,10 +1,19 @@
+<HTML>
<HEAD>
-<TITLE>Lua 3.2 Reference Manual</TITLE>
+<TITLE>Lua: reference manual 4.0</TITLE>
</HEAD>
+
<BODY BGCOLOR="#FFFFFF">
-<h1>Lua 3.2 Reference Manual</h1>
-<!-- $Id: manual.tex,v 1.33 1999/05/27 20:21:03 roberto Exp $ -->
+<HR>
+<H1>
+<IMG SRC="logo.gif" ALT="Lua" ALIGN="bottom">
+Reference Manual of the Programming Language
+<A HREF="http://www.tecgraf.puc-rio.br/lua/">Lua</A>
+4.0
+</H1>
+
+<!-- $Id: manual.tex,v 1.45 2000/10/31 18:20:01 roberto Exp roberto $ -->
<P>
<P>
<!-- ====================================================================== -->
@@ -15,7 +24,7 @@
Lua is an extension programming language designed to support
general procedural programming with data description
facilities.
-Lua is intended to be used as a light-weight, but powerful,
+Lua is intended to be used as a powerful, light-weight
configuration language for any program that needs one.
<P>
Lua is implemented as a library, written in C.
@@ -24,21 +33,40 @@ it only works <EM>embedded</EM> in a host client,
called the <EM>embedding</EM> program.
This host program can invoke functions to execute a piece of
code in Lua, can write and read Lua variables,
-and can register C functions to be called by Lua code.
-Through the use of C functions, Lua can be augmented to cope with
+and can register C&nbsp;functions to be called by Lua code.
+Through the use of C&nbsp;functions, Lua can be augmented to cope with
a wide range of different domains,
thus creating customized programming languages sharing a syntactical framework.
<P>
Lua is free-distribution software,
-and provided as usual with no guarantees,
-as stated in the copyright notice.
+and is provided as usual with no guarantees,
+as stated in its copyright notice.
The implementation described in this manual is available
at the following URL's:
<PRE>
- <A HREF="http://www.tecgraf.puc-rio.br/lua/">http://www.tecgraf.puc-rio.br/lua/</A>
- <A HREF="ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz">ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz</A>
+ <A HREF="http://www.tecgraf.puc-rio.br/lua/">http://www.tecgraf.puc-rio.br/lua/</A>
+ <A HREF="ftp://ftp.tecgraf.puc-rio.br/pub/lua/">ftp://ftp.tecgraf.puc-rio.br/pub/lua/</A>
</PRE>
<P>
+Like any other reference manual,
+this document is dry in places.
+For a discussion of the decisions behind the design of Lua,
+see the papers below,
+which are available at the web site above.
+<UL>
+<LI>
+R.&nbsp;Ierusalimschy, L.&nbsp;H.&nbsp;de Figueiredo, and W.&nbsp;Celes.
+Lua-an extensible extension language.
+<EM>Software: Practice &amp; Experience</EM> <B>26</B> #6 (1996) 635--652.
+<LI>
+L.&nbsp;H.&nbsp;de Figueiredo, R.&nbsp;Ierusalimschy, and W.&nbsp;Celes.
+The design and implementation of a language for extending applications.
+<EM>Proceedings of XXI Brazilian Seminar on Software and Hardware</EM> (1994) 273--283.
+<LI>
+L.&nbsp;H.&nbsp;de Figueiredo, R.&nbsp;Ierusalimschy, and W.&nbsp;Celes.
+Lua: an extensible embedded language.
+<EM>Dr. Dobb's Journal</EM> <B>21</B> #12 (Dec 1996) 26--33.
+</UL>
<P>
<!-- ====================================================================== -->
<HR>
@@ -46,43 +74,50 @@ at the following URL's:
<H1>2 - Environment and Chunks</H1>
<P>
All statements in Lua are executed in a <A NAME="global environment"><EM>global environment</EM></A>.
-This environment, which keeps all global variables,
-is initialized with a call from the embedding program to
+This environment is initialized with a call from the embedding program to
<CODE>lua_open</CODE> and
persists until a call to <CODE>lua_close</CODE>,
or the end of the embedding program.
-Optionally, a user can create multiple independent global
-environments (see Section&nbsp;<A HREF="#mangstate">5.1</A>).
+If necessary,
+the host programmer can create multiple independent global
+environments, and freely switch between them (see Section&nbsp;<A HREF="#mangstate">5.1</A>).
<P>
The global environment can be manipulated by Lua code or
by the embedding program,
which can read and write global variables
using API functions from the library that implements Lua.
<P>
-<A NAME="Global variables">Global variables</A> do not need declaration.
+<A NAME="Global variables">Global variables</A> in Lua do not need to be declared.
Any variable is assumed to be global unless explicitly declared local
-(see Section&nbsp;<A HREF="#localvar">4.5.5</A>).
-Before the first assignment, the value of a global variable is <B>nil</B>;
-this default can be changed (see Section&nbsp;<A HREF="#tag-method">4.8</A>).
+(see Section&nbsp;<A HREF="#localvar">4.4.6</A>).
+Before the first assignment, the value of a global variable is <B>nil</B>
+(this default can be changed; see Section&nbsp;<A HREF="#tag-method">4.8</A>).
+A table is used to keep all global names and values
+(tables are explained in Section&nbsp;<A HREF="#TypesSec">3</A>).
<P>
The unit of execution of Lua is called a <A NAME="chunk"><EM>chunk</EM></A>.
-A chunk is simply a sequence of statements:
-<PRE>
-chunk ::= {stat} [ret]
-</PRE>
-Statements are described in Section&nbsp;<A HREF="#stats">4.5</A>.
-(As usual, {<EM>a</EM>} means 0 or more <EM>a</EM>'s,
-[<EM>a</EM>] means an optional <EM>a</EM> and ('<EM>a</EM>)+ means
-one or more <EM>a</EM>'s.)
-<P>
-A chunk may be in a file or in a string inside the host program.
-A chunk may optionally end with a <CODE>return</CODE> statement (see Section&nbsp;<A HREF="#return">4.5.3</A>).
-When a chunk is executed, first all its code is pre-compiled,
-then the statements are executed in sequential order.
+A chunk is simply a sequence of statements,
+which are executed sequentially.
+Each statement can be optionally followed by a semicolon:
+<PRE>
+ chunk ::= {stat [`<B>;</B>']}
+</PRE>
+Statements are described in Section&nbsp;<A HREF="#stats">4.4</A>.
+(The notation above is the usual extended BNF,
+in which
+{<EM>a</EM>} means 0 or more <EM>a</EM>'s,
+[<EM>a</EM>] means an optional <EM>a</EM>, and
+(<EM>a</EM>)+ means one or more <EM>a</EM>'s.
+The complete syntax of Lua is given in <A HREF="BNF">BNF</A>).
+<P>
+A chunk may be stored in a file or in a string inside the host program.
+When a chunk is executed, first it is pre-compiled into bytecodes for
+a virtual machine, and then the statements are executed in sequential order,
+by simulating the virtual machine.
All modifications a chunk effects on the global environment persist
-after the chunk end.
+after the chunk ends.
<P>
-Chunks may also be pre-compiled into binary form;
+Chunks may also be pre-compiled into binary form and stored in files;
see program <A NAME="luac"><TT><A HREF="luac.html">luac</A></TT></A> for details.
Text files with chunks and their binary pre-compiled forms
are interchangeable.
@@ -95,11 +130,12 @@ Lua automatically detects the file type and acts accordingly.
<A NAME="3."></A>
<H1>3 - Types and Tags</H1>
<P>
-Lua is a dynamically typed language.
-Variables do not have types; only values do.
+Lua is a <EM>dynamically typed language</EM>.
+This means that
+variables do not have types; only values do.
Therefore, there are no type definitions in the language.
All values carry their own type.
-Besides a type, all values also have a <A NAME="tag">tag</A>.
+Besides a type, all values also have a <A NAME="tag"><EM>tag</EM></A>.
<P>
There are six <A NAME="basic types">basic types</A> in Lua: <A NAME="nil"><EM>nil</EM></A>, <A NAME="number"><EM>number</EM></A>,
<A NAME="string"><EM>string</EM></A>, <A NAME="function"><EM>function</EM></A>, <A NAME="userdata"><EM>userdata</EM></A>, and <A NAME="table"><EM>table</EM></A>.
@@ -107,26 +143,30 @@ There are six <A NAME="basic types">basic types</A> in Lua: <A NAME="nil"><EM>ni
whose main property is to be different from any other value.
<EM>Number</EM> represents real (double-precision floating-point) numbers,
while <EM>string</EM> has the usual meaning.
-Lua is <A NAME="eight-bit clean">eight-bit clean</A>,
+<A NAME="eight-bit clean"></A>
+Lua is 8-bit clean,
and so strings may contain any 8-bit character,
-<EM>including</EM> embedded zeros (<CODE>'\0'</CODE>).
-The function <CODE>type</CODE> returns a string describing the type
+including embedded zeros (<CODE>'\0'</CODE>) (see Section&nbsp;<A HREF="#lexical">4.1</A>).
+The <CODE>type</CODE> function returns a string describing the type
of a given value (see Section&nbsp;<A HREF="#pdf-type">6.1</A>).
<P>
-Functions are considered first-class values in Lua.
+Functions are considered <EM>first-class values</EM> in Lua.
This means that functions can be stored in variables,
passed as arguments to other functions, and returned as results.
Lua can call (and manipulate) functions written in Lua and
functions written in C.
-They can be distinguished by their tags:
+The two kinds of functions can be distinguished by their tags:
all Lua functions have the same tag,
-and all C functions have the same tag,
+and all C&nbsp;functions have the same tag,
which is different from the tag of Lua functions.
+The <CODE>tag</CODE> function returns the tag
+of a given value (see Section&nbsp;<A HREF="#pdf-tag">6.1</A>).
<P>
The type <EM>userdata</EM> is provided to allow
-arbitrary <A NAME="C pointers">C pointers</A> to be stored in Lua variables.
-It corresponds to a <CODE>void*</CODE> and has no pre-defined operations in Lua,
-besides assignment and equality test.
+arbitrary <A NAME="C pointers">C&nbsp;pointers</A> to be stored in Lua variables.
+This type corresponds to a <CODE>void*</CODE>
+and has no pre-defined operations in Lua,
+except assignment and equality test.
However, by using <EM>tag methods</EM>,
the programmer can define operations for <EM>userdata</EM> values
(see Section&nbsp;<A HREF="#tag-method">4.8</A>).
@@ -135,100 +175,109 @@ The type <EM>table</EM> implements <A NAME="associative arrays">associative arra
that is, <A NAME="arrays">arrays</A> that can be indexed not only with numbers,
but with any value (except <B>nil</B>).
Therefore, this type may be used not only to represent ordinary arrays,
-but also symbol tables, sets, records, etc.
+but also symbol tables, sets, records, graphs, trees, etc.
Tables are the main data structuring mechanism in Lua.
To represent <A NAME="records">records</A>, Lua uses the field name as an index.
The language supports this representation by
providing <CODE>a.name</CODE> as syntactic sugar for <CODE>a["name"]</CODE>.
-Tables may also carry methods.
+Tables may also carry <EM>methods</EM>:
Because functions are first class values,
table fields may contain functions.
The form <CODE>t:f(x)</CODE> is syntactic sugar for <CODE>t.f(t,x)</CODE>,
which calls the method <CODE>f</CODE> from the table <CODE>t</CODE> passing
-itself as the first parameter (see Section&nbsp;<A HREF="#func-def">4.6.9</A>).
+the table itself as the first parameter (see Section&nbsp;<A HREF="#func-def">4.5.9</A>).
<P>
Note that tables are <EM>objects</EM>, and not values.
-Variables cannot contain tables, only <EM>references</EM> to them.
+Variables do not contain tables, only <EM>references</EM> to them.
Assignment, parameter passing, and returns always manipulate references
to tables, and do not imply any kind of copy.
Moreover, tables must be explicitly created before used
-(see Section&nbsp;<A HREF="#tableconstructor">4.6.7</A>).
+(see Section&nbsp;<A HREF="#tableconstructor">4.5.7</A>).
<P>
-Tags are mainly used to select tag methods when
+Each of the types <EM>nil</EM>, <EM>number</EM>, and <EM>string</EM> has a different tag.
+All values of each of these types have the same pre-defined tag.
+As explained above,
+values of type <EM>function</EM> can have two different tags,
+depending on whether they are Lua functions or C&nbsp;functions.
+Finally,
+values of type <EM>userdata</EM> and <EM>table</EM> can have variable tags,
+assigned by the programmer (see Section&nbsp;<A HREF="#tag-method">4.8</A>).
+The <CODE>tag</CODE> function returns the tag of a given value.
+User tags are created with the function <CODE>newtag</CODE>.
+The <CODE>settag</CODE> function
+is used to change the tag of a table (see Section&nbsp;<A HREF="#pdf-newtag">6.1</A>).
+The tag of userdata values can only be set from&nbsp;C (see Section&nbsp;<A HREF="#C-tags">5.7</A>).
+Tags are mainly used to select <EM>tag methods</EM> when
some events occur.
Tag methods are the main mechanism for extending the
semantics of Lua (see Section&nbsp;<A HREF="#tag-method">4.8</A>).
-Each of the types <EM>nil</EM>, <EM>number</EM> and <EM>string</EM> has a different tag.
-All values of each of these types have this same pre-defined tag.
-Values of type <EM>function</EM> can have two different tags,
-depending on whether they are Lua functions or C functions.
-Finally,
-values of type <EM>userdata</EM> and <EM>table</EM> can have
-as many different tags as needed (see Section&nbsp;<A HREF="#tag-method">4.8</A>).
-Tags are created with the function <CODE>newtag</CODE>,
-and the function <CODE>tag</CODE> returns the tag of a given value.
-To change the tag of a given table,
-there is the function <CODE>settag</CODE> (see Section&nbsp;<A HREF="#pdf-newtag">6.1</A>).
-<P>
<P>
<!-- ====================================================================== -->
<HR>
<A NAME="4."></A>
<H1>4 - The Language</H1>
<P>
-This section describes the lexis, the syntax and the semantics of Lua.
+This section describes the lexis, the syntax, and the semantics of Lua.
<P>
<P>
<A NAME="lexical"></A>
<A NAME="4.1"></A>
<H2>4.1 - Lexical Conventions</H2>
<P>
-<A NAME="Identifiers">Identifiers</A> in Lua can be any string of letters,
+<A NAME="Identifiers"><EM>Identifiers</EM></A> in Lua can be any string of letters,
digits, and underscores,
not beginning with a digit.
-The definition of letter depends on the current locale:
+This coincides with the definition of identifiers in most languages,
+except that
+the definition of letter depends on the current locale:
Any character considered alphabetic by the current locale
can be used in an identifier.
-The following words are reserved, and cannot be used as identifiers:
+The following words are <EM>reserved</EM>, and cannot be used as identifiers:
<A NAME="reserved words"></A>
<PRE>
- and do else elseif
- end function if local
- nil not or repeat
- return then until while
+ and break do else elseif
+ end for function if in
+ local nil not or repeat
+ return then until while
</PRE>
+<P>
Lua is a case-sensitive language:
-<TT>and</TT> is a reserved word, but <TT>And</TT> and <TT>\'and</TT>
-(if the locale permits) are two other different identifiers.
+<TT>and</TT> is a reserved word, but <TT>And</TT> and <TT>ánd</TT>
+(if the locale permits) are two different, valid identifiers.
As a convention, identifiers starting with underscore followed by
-uppercase letters are reserved for internal variables.
+uppercase letters (such as <CODE>_INPUT</CODE>)
+are reserved for internal variables.
<P>
The following strings denote other <A NAME="tokens">tokens</A>:
<PRE>
- ~= &lt;= &gt;= &lt; &gt; == = + - * /
- ( ) { } [ ] ; , . .. ...
+ ~= &lt;= &gt;= &lt; &gt; == = + - * /
+ ( ) { } [ ] ; , . .. ...
</PRE>
<P>
-<A NAME="Literal strings">Literal strings</A> can be delimited by matching single or double quotes,
+<A NAME="Literal strings"><EM>Literal strings</EM></A>
+can be delimited by matching single or double quotes,
and can contain the C-like escape sequences
-<CODE>'\a'</CODE> (bell),
-<CODE>'\b'</CODE> (backspace),
-<CODE>'\f'</CODE> (form feed),
-<CODE>'\n'</CODE> (new line),
-<CODE>'\r'</CODE> (carriage return),
-<CODE>'\t'</CODE> (horizontal tab),
-<CODE>'\v'</CODE> (vertical tab),
-<CODE>'\\'</CODE>, (backslash),
-<CODE>'\"'</CODE>, (double quote),
-and <CODE>'\''</CODE> (single quote).
+`<CODE>\a</CODE>' (bell),
+`<CODE>\b</CODE>' (backspace),
+`<CODE>\f</CODE>' (form feed),
+`<CODE>\n</CODE>' (newline),
+`<CODE>\r</CODE>' (carriage return),
+`<CODE>\t</CODE>' (horizontal tab),
+`<CODE>\v</CODE>' (vertical tab),
+`<CODE>\\</CODE>' (backslash),
+`<CODE>\"</CODE>' (double quote),
+`<CODE>\'</CODE>' (single quote),
+and `<CODE>\</CODE><EM>newline</EM>' (that is, a backslash followed by a real newline,
+which results in a newline in the string).
A character in a string may also be specified by its numerical value,
-through the escape sequence <CODE>'\ddd'</CODE>,
-where <CODE>ddd</CODE> is a sequence of up to three <EM>decimal</EM> digits.
-Strings in Lua may contain any 8-bit value, including embedded 0.
+through the escape sequence `<CODE>\</CODE><EM>ddd</EM>',
+where <EM>ddd</EM> is a sequence of up to three <EM>decimal</EM> digits.
+Strings in Lua may contain any 8-bit value, including embedded zeros,
+which can be specified as `<CODE>\000</CODE>'.
<P>
-Literal strings can also be delimited by matching <CODE>[[ ... ]]</CODE>.
+Literal strings can also be delimited by matching <CODE>[[</CODE> ... <CODE>]]</CODE>.
Literals in this bracketed form may run for several lines,
-may contain nested <CODE>[[ ... ]]</CODE> pairs,
+may contain nested <CODE>[[</CODE> ... <CODE>]]</CODE> pairs,
and do not interpret escape sequences.
This form is specially convenient for
writing strings that contain program pieces or
@@ -236,268 +285,363 @@ other quoted strings.
As an example, in a system using ASCII,
the following three literals are equivalent:
<PRE>
-1) "alo\n123\""
-2) '\97lo\10\04923"'
-3) [[alo
- 123"]]
+ 1) "alo\n123\""
+ 2) '\97lo\10\04923"'
+ 3) [[alo
+ 123"]]
</PRE>
<P>
-<P>
-<A NAME="Comments">Comments</A> start anywhere outside a string with a
+<A NAME="Comments"><EM>Comments</EM></A> start anywhere outside a string with a
double hyphen (<CODE>--</CODE>) and run until the end of the line.
Moreover,
the first line of a chunk is skipped if it starts with <CODE>#</CODE>.
This facility allows the use of Lua as a script interpreter
in Unix systems (see Section&nbsp;<A HREF="#lua-sa">8</A>).
<P>
-<A NAME="Numerical constants">Numerical constants</A> may be written with an optional decimal part,
+<A NAME="Numerical constants"><EM>Numerical constants</EM></A> may be written with an optional decimal part
and an optional decimal exponent.
Examples of valid numerical constants are
<PRE>
3 3.0 3.1416 314.16e-2 0.31416E1
</PRE>
<P>
-<A NAME="pre-processor"></A>
-<A NAME="4.2"></A>
-<H2>4.2 - The Pre-processor</H2>
-<P>
-All lines that start with a <CODE>$</CODE> sign are handled by a pre-processor.
-The <CODE>$</CODE> sign must be immediately
-followed by one of the following directives:
-<DL>
-<DT><B><TT>debug</TT></B><DD> - turn on debugging facilities (see Section&nbsp;<A HREF="#pragma">4.9</A>).
-<DT><B><TT>nodebug</TT></B><DD> - turn off debugging facilities (see Section&nbsp;<A HREF="#pragma">4.9</A>).
-<DT><B><TT>if <EM>cond</TT></EM></B><DD> - starts a conditional part.
-If <EM>cond</EM> is false, then this part is skipped by the lexical analyzer.
-<DT><B><TT>ifnot <EM>cond</TT></EM></B><DD> - starts a conditional part.
-If <EM>cond</EM> is true, then this part is skipped by the lexical analyzer.
-<DT><B><TT>end</TT></B><DD> - ends a conditional part.
-<DT><B><TT>else</TT></B><DD> - starts an ``else'' conditional part,
-flipping the ``skip'' status.
-<DT><B><TT>endinput</TT></B><DD> - ends the lexical parse of the file.
-</DL>
-<P>
-Directives may be freely nested.
-Particularly, a <CODE>$endinput</CODE> may occur inside a <CODE>$if</CODE>;
-in that case, even the matching <CODE>$end</CODE> is not parsed.
-<P>
-A <EM>cond</EM> part may be
-<DL>
-<DT><B><TT>nil</TT></B><DD> - always false.
-<DT><B><TT>1</TT></B><DD> - always true.
-<DT><B><EM>name</EM></B><DD> - true if the value of the
-global variable <EM>name</EM> is different from <B>nil</B>.
-Note that <EM>name</EM> is evaluated <EM>before</EM> the chunk starts its execution.
-Therefore, actions in a chunk do not affect its own conditional directives.
-</DL>
-<P>
<A NAME="coercion"></A>
-<A NAME="4.3"></A>
-<H2>4.3 - Coercion</H2>
+<A NAME="4.2"></A>
+<H2>4.2 - Coercion</H2>
<P>
Lua provides some automatic conversions between values at run time.
Any arithmetic operation applied to a string tries to convert
that string to a number, following the usual rules.
Conversely, whenever a number is used when a string is expected,
that number is converted to a string, in a reasonable format.
-For complete control on how numbers are converted to strings,
+The format is chosen so that
+a conversion from number to string then back to number
+reproduces the original number <EM>exactly</EM>.
+Thus,
+the conversion does not necessarily produces nice-looking text for some numbers.
+For complete control of how numbers are converted to strings,
use the <CODE>format</CODE> function (see Section&nbsp;<A HREF="#format">6.2</A>).
<P>
<P>
<A NAME="adjust"></A>
-<A NAME="4.4"></A>
-<H2>4.4 - Adjustment</H2>
+<A NAME="4.3"></A>
+<H2>4.3 - Adjustment</H2>
<P>
Functions in Lua can return many values.
Because there are no type declarations,
when a function is called
-the system does not know how many values a function will return,
+the system does not know how many values the function will return,
or how many parameters it needs.
Therefore, sometimes, a list of values must be <EM>adjusted</EM>, at run time,
to a given length.
If there are more values than are needed,
then the excess values are thrown away.
-If there are more needs than values,
+If there are less values than are needed,
then the list is extended with as many <B>nil</B>'s as needed.
-Adjustment occurs in multiple assignment (see Section&nbsp;<A HREF="#assignment">4.5.2</A>)
-and function calls (see Section&nbsp;<A HREF="#functioncall">4.6.8</A>).
+This adjustment occurs in multiple assignments (see Section&nbsp;<A HREF="#assignment">4.4.2</A>)
+and in function calls (see Section&nbsp;<A HREF="#functioncall">4.5.8</A>).
<P>
<P>
<A NAME="stats"></A>
-<A NAME="4.5"></A>
-<H2>4.5 - Statements</H2>
+<A NAME="4.4"></A>
+<H2>4.4 - Statements</H2>
<P>
Lua supports an almost conventional set of <A NAME="statements">statements</A>,
similar to those in Pascal or C.
The conventional commands include
-assignment, control structures and procedure calls.
+assignment, control structures, and procedure calls.
Non-conventional commands include table constructors
-(see Section&nbsp;<A HREF="#tableconstructor">4.6.7</A>),
-and local variable declarations (see Section&nbsp;<A HREF="#localvar">4.5.5</A>).
+(see Section&nbsp;<A HREF="#tableconstructor">4.5.7</A>)
+and local variable declarations (see Section&nbsp;<A HREF="#localvar">4.4.6</A>).
<P>
-<H3>4.5.1 - Blocks</H3>
-A <A NAME="block">block</A> is a list of statements, which are executed sequentially.
-A statement may be optionally followed by a semicolon:
+<H3>4.4.1 - Blocks</H3>
+A <A NAME="block">block</A> is a list of statements;
+syntactically, a block is equal to a chunk:
<PRE>
-block ::= {stat sc} [ret]
-sc ::= ['<B>;</B>']
+ block ::= chunk
</PRE>
-For syntactic reasons, a <A NAME="return"><TT>return</TT></A> statement can only be written
-as the last statement of a block.
-This restriction also avoids some ``statement not reached'' conditions.
<P>
A block may be explicitly delimited:
<PRE>
-stat ::= <B>do</B> block <B>end</B>
+ stat ::= <B>do</B> block <B>end</B>
</PRE>
-This is useful to control the scope of local variables (see Section&nbsp;<A HREF="#localvar">4.5.5</A>).
+Explicit blocks are useful
+to control the scope of local variables (see Section&nbsp;<A HREF="#localvar">4.4.6</A>).
+Explicit blocks are also sometimes used to
+add a <B>return</B> or <B>break</B> statement in the middle
+of another block (see Section&nbsp;<A HREF="#control">4.4.3</A>).
<P>
<A NAME="assignment"></A>
-<H3>4.5.2 - <A NAME="Assignment</H3>">Assignment</H3></A>
-The language allows <A NAME="multiple assignment">multiple assignment</A>.
+<H3>4.4.2 - <A NAME="Assignment</H3>">Assignment</H3></A>
+Lua allows <A NAME="multiple assignment">multiple assignment</A>.
Therefore, the syntax for assignment
-defines a list of variables on the left side,
+defines a list of variables on the left side
and a list of expressions on the right side.
-Both lists have their elements separated by commas:
+The elements in both lists are separated by commas:
<PRE>
-stat ::= varlist1 '<B>=</B>' explist1
-varlist1 ::= var {'<B>,</B>' var}
+ stat ::= varlist1 `<B>=</B>' explist1
+ varlist1 ::= var {`<B>,</B>' var}
</PRE>
This statement first evaluates all values on the right side
and eventual indices on the left side,
and then makes the assignments.
-Therefore, it can be used to exchange two values, as in
+So, the code
+<PRE>
+ i = 3
+ i, a[i] = 4, 20
+</PRE>
+sets <CODE>a[3]</CODE> to 20, but does not affect <CODE>a[4]</CODE>
+because the <CODE>i</CODE> in <CODE>a[i]</CODE> is evaluated
+before it is assigned <CODE>4</CODE>.
+<P>
+Multiple assignment can be used to exchange two values, as in
<PRE>
- x, y = y, x
+ x, y = y, x
</PRE>
-The two lists may have different lengths.
-Before the assignment, the list of values is <EM>adjusted</EM> to
-the length of the list of variables (see Section&nbsp;<A HREF="#adjust">4.4</A>).
+<P>
+The two lists in a multiple assignment may have different lengths.
+Before the assignment, the list of values is adjusted to
+the length of the list of variables (see Section&nbsp;<A HREF="#adjust">4.3</A>).
<P>
A single name can denote a global variable, a local variable,
or a formal parameter:
<PRE>
-var ::= name
+ var ::= name
</PRE>
+<P>
Square brackets are used to index a table:
<PRE>
-var ::= simpleexp '<B>[</B>' exp1 '<B>]</B>'
+ var ::= varorfunc `<B>[</B>' exp1 `<B>]</B>'
+ varorfunc ::= var | functioncall
</PRE>
-The <EM>simpleexp</EM> should result in a table value,
-from where the field indexed by the expression
+The <EM>varorfunc</EM> should result in a table value,
+from where the field indexed by the expression <EM>exp1</EM>
value gets the assigned value.
<P>
The syntax <CODE>var.NAME</CODE> is just syntactic sugar for
<CODE>var["NAME"]</CODE>:
<PRE>
-var ::= simpleexp '<B>.</B>' name
+ var ::= varorfunc `<B>.</B>' name
</PRE>
<P>
The meaning of assignments and evaluations of global variables and
indexed variables can be changed by tag methods (see Section&nbsp;<A HREF="#tag-method">4.8</A>).
Actually,
an assignment <CODE>x = val</CODE>, where <CODE>x</CODE> is a global variable,
-is equivalent to a call <CODE>setglobal('x', val)</CODE>;
+is equivalent to a call <CODE>setglobal("x", val)</CODE> and
an assignment <CODE>t[i] = val</CODE> is equivalent to
-<CODE>settable_event(t, i, val)</CODE>.
-See Section&nbsp;<A HREF="#tag-method">4.8</A> for a complete description of these functions.
-(Function <CODE>setglobal</CODE> is pre-defined in Lua.
-Function <TT>settable_event</TT> is used only for explanatory purposes.)
-<P>
-<H3>4.5.3 - Control Structures</H3>
-The <A NAME="condition expression">condition expression</A> of a control structure may return any value.
+<CODE>settable_event(t,i,val)</CODE>.
+See Section&nbsp;<A HREF="#tag-method">4.8</A> for a complete description of these functions
+(<CODE>setglobal</CODE> is in the basic library;
+<TT>settable_event</TT> is used for explanatory purposes only).
+<P>
+<A NAME="control"></A>
+<H3>4.4.3 - Control Structures</H3>
+The control structures
+<B>if</B>, <B>while</B>, and <B>repeat</B> have the usual meaning and
+familiar syntax
+<A NAME="while-do statement"></A>
+<A NAME="repeat-until statement"></A>
+<A NAME="if-then-else statement"></A>
+<PRE>
+ stat ::= <B>while</B> exp1 <B>do</B> block <B>end</B>
+ stat ::= <B>repeat</B> block <B>until</B> exp1
+ stat ::= <B>if</B> exp1 <B>then</B> block {<B>elseif</B> exp1 <B>then</B> block} [<B>else</B> block] <B>end</B>
+</PRE>
+The <A NAME="condition expression">condition expression</A> <EM>exp1</EM> of a control structure may return any value.
All values different from <B>nil</B> are considered true;
only <B>nil</B> is considered false.
-<TT>if</TT>'s, <TT>while</TT>'s and <TT>repeat</TT>'s have the usual meaning.
-<P>
-<A NAME="while-do"></A><A NAME="repeat-until"></A><A NAME="if-then-else"></A>
-<PRE>
-stat ::= <B>while</B> exp1 <B>do</B> block <B>end</B> <BR> | <B>repeat</B> block <B>until</B> exp1 <BR> | <B>if</B> exp1 <B>then</B> block {<B>elseif</B> exp1 <B>then</B> block} [<B>else</B> block] <B>end</B>
-</PRE>
<P>
-A <TT>return</TT> is used to return values from a function or from a chunk.
+The <B>return</B> statement is used to return values
+from a function or from a chunk.
<A NAME="return"></A>
-Because they may return more than one value,
-the syntax for a <A NAME="return statement">return statement</A> is
-<PRE>
-ret ::= <B>return</B> [explist1] [sc]
-</PRE>
+<A NAME="return statement"></A>
+Because functions or chunks may return more than one value,
+the syntax for the <B>return</B> statement is
+<PRE>
+ stat ::= <B>return</B> [explist1]
+</PRE>
+<P>
+The <B>break</B> statement can be used to terminate the execution of a loop,
+skipping to the next statement after the loop:
+<A NAME="break statement"></A>
+<PRE>
+ stat ::= <B>break</B>
+</PRE>
+A <B>break</B> ends the innermost enclosing loop
+(<B>while</B>, <B>repeat</B>, or <B>for</B>).
+<P>
+For syntactic reasons, <B>return</B> and <B>break</B>
+statements can only be written as the <EM>last</EM> statements of a block.
+If it is really necessary to <B>return</B> or <B>break</B> in the
+middle of a block,
+an explicit inner block can used,
+as in the idiom `<CODE>do return end</CODE>',
+because now <B>return</B> is last statement in the inner block.
+<P>
+<A NAME="for"></A>
+<H3>4.4.4 - For Statement</H3> <A NAME="for statement"></A>
+<P>
+The <B>for</B> statement has two forms,
+one for numbers and one for tables.
+The numerical <B>for</B> loop has the following syntax:
+<PRE>
+ stat ::= <B>for</B> name `<B>=</B>' exp1 `<B>,</B>' exp1 [`<B>,</B>' exp1] <B>do</B> block <B>end</B>
+</PRE>
+A <B>for</B> statement like
+<PRE>
+ for var = e1 ,e2, e3 do block end
+</PRE>
+is equivalent to the code:
+<PRE>
+ do
+ local var, _limit, _step = tonumber(e1), tonumber(e2), tonumber(e3)
+ if not (var and _limit and _step) then error() end
+ while (_step&gt;0 and var&lt;=_limit) or (_step&lt;=0 and var&gt;=_limit) do
+ block
+ var = var+_step
+ end
+ end
+</PRE>
+Note the following:
+<UL><LI>sep=0pt
+<LI><CODE>_limit</CODE> and <CODE>_step</CODE> are invisible variables.
+The names are here for explanatory purposes only.
+<LI>The behavior is <EM>undefined</EM> if you assign to <CODE>var</CODE> inside
+the block.
+<LI>If the third expression (the step) is absent, then a step of&nbsp;1 is used.
+<LI>Both the limit and the step are evaluated only once,
+before the loop starts.
+<LI>The variable <CODE>var</CODE> is local to the statement;
+you cannot use its value after the <B>for</B> ends.
+<LI>You can use <B>break</B> to exit a <B>for</B>.
+If you need the value of the index,
+assign it to another variable before breaking.
+</UL>
+<P>
+The table <B>for</B> statement traverses all pairs
+(index,value) of a given table.
+It has the following syntax:
+<PRE>
+ stat ::= <B>for</B> name `<B>,</B>' name <B>in</B> exp1 <B>do</B> block <B>end</B>
+</PRE>
+A <B>for</B> statement like
+<PRE>
+ for index, value in exp do block end
+</PRE>
+is equivalent to the code:
+<PRE>
+ do
+ local _t = exp
+ local index, value = next(t, nil)
+ while index do
+ block
+ index, value = next(t, index)
+ end
+ end
+</PRE>
+Note the following:
+<UL><LI>sep=0pt
+<LI><CODE>_t</CODE> is an invisible variable.
+The name is here for explanatory purposes only.
+<LI>The behavior is <EM>undefined</EM> if you assign to <CODE>index</CODE> inside
+the block.
+<LI>The behavior is <EM>undefined</EM> if you change
+the table <CODE>_t</CODE> during the traversal.
+<LI>The variables <CODE>index</CODE> and <CODE>value</CODE> are local to the statement;
+you cannot use their values after the <B>for</B> ends.
+<LI>You can use <B>break</B> to exit a <B>for</B>.
+If you need the value of <CODE>index</CODE> or <CODE>value</CODE>,
+assign them to other variables before breaking.
+<LI>The order that table elements are traversed is undefined,
+<EM>even for numerical indices</EM>.
+If you want to traverse indices in numerical order,
+use a numerical <B>for</B>.
+</UL>
+<P>
<P>
<A NAME="funcstat"></A>
-<H3>4.5.4 - Function Calls as Statements</H3>
+<H3>4.4.5 - Function Calls as Statements</H3>
Because of possible side-effects,
function calls can be executed as statements:
<PRE>
-stat ::= functioncall
+ stat ::= functioncall
</PRE>
In this case, all returned values are thrown away.
-Function calls are explained in Section&nbsp;<A HREF="#functioncall">4.6.8</A>.
+Function calls are explained in Section&nbsp;<A HREF="#functioncall">4.5.8</A>.
<P>
<A NAME="localvar"></A>
-<H3>4.5.5 - Local Declarations</H3>
+<H3>4.4.6 - Local Declarations</H3>
<A NAME="Local variables">Local variables</A> may be declared anywhere inside a block.
-Their scope begins after the declaration and lasts until the
-end of the block.
The declaration may include an initial assignment:
<PRE>
-stat ::= <B>local</B> declist [init]
-declist ::= name {'<B>,</B>' name}
-init ::= '<B>=</B>' explist1
+ stat ::= <B>local</B> declist [init]
+ declist ::= name {`<B>,</B>' name}
+ init ::= `<B>=</B>' explist1
</PRE>
If present, an initial assignment has the same semantics
of a multiple assignment.
Otherwise, all variables are initialized with <B>nil</B>.
<P>
+A chunk is also a block,
+and so local variables can be declared outside any explicit block.
<P>
-<A NAME="4.6"></A>
-<H2>4.6 - Expressions</H2>
+The scope of local variables begins <EM>after</EM>
+the declaration and lasts until the end of the block.
+Thus, the code
+<CODE>local print=print</CODE>
+creates a local variable called <CODE>print</CODE> whose
+initial value is that of the <EM>global</EM> variable of the same name.
<P>
-<H3>4.6.1 - <A NAME="Basic Expressions</H3>">Basic Expressions</H3></A>
-Basic expressions are
-<PRE>
-exp ::= '<B>(</B>' exp '<B>)</B>'
-exp ::= <B>nil</B>
-exp ::= '<B>number</B>'
-exp ::= '<B>literal</B>'
-exp ::= function
-exp ::= simpleexp
-</PRE>
+<P>
+<A NAME="4.5"></A>
+<H2>4.5 - Expressions</H2>
+<P>
+<H3>4.5.1 - <A NAME="Basic Expressions</H3>">Basic Expressions</H3></A>
+The basic expressions in Lua are
<PRE>
-simpleexp ::= var
-simpleexp ::= upvalue
-simpleexp ::= functioncall
+ exp ::= `<B>(</B>' exp `<B>)</B>'
+ exp ::= <B>nil</B>
+ exp ::= number
+ exp ::= literal
+ exp ::= var
+ exp ::= upvalue
+ exp ::= function
+ exp ::= functioncall
+ exp ::= tableconstructor
</PRE>
<P>
Numbers (numerical constants) and
-string literals are explained in Section&nbsp;<A HREF="#lexical">4.1</A>;
-variables are explained in Section&nbsp;<A HREF="#assignment">4.5.2</A>;
-upvalues are explained in Section&nbsp;<A HREF="#upvalue">4.7</A>;
-function definitions (<EM>function</EM>) are explained in Section&nbsp;<A HREF="#func-def">4.6.9</A>;
-function calls are explained in Section&nbsp;<A HREF="#functioncall">4.6.8</A>.
+literal strings are explained in Section&nbsp;<A HREF="#lexical">4.1</A>;
+variables are explained in Section&nbsp;<A HREF="#assignment">4.4.2</A>;
+upvalues are explained in Section&nbsp;<A HREF="#upvalue">4.6</A>;
+function definitions are explained in Section&nbsp;<A HREF="#func-def">4.5.9</A>;
+function calls are explained in Section&nbsp;<A HREF="#functioncall">4.5.8</A>.
+Table constructors are explained in Section&nbsp;<A HREF="#tableconstructor">4.5.7</A>.
<P>
An access to a global variable <CODE>x</CODE> is equivalent to a
-call <CODE>getglobal('x')</CODE>;
+call <CODE>getglobal("x")</CODE> and
an access to an indexed variable <CODE>t[i]</CODE> is equivalent to
-a call <CODE>gettable_event(t, i)</CODE>.
-See Section&nbsp;<A HREF="#tag-method">4.8</A> for a description of these functions.
-(Function <CODE>getglobal</CODE> is pre-defined in Lua.
-Function <TT>gettable_event</TT> is used only for explanatory purposes.)
+a call <CODE>gettable_event(t,i)</CODE>.
+See Section&nbsp;<A HREF="#tag-method">4.8</A> for a description of these functions
+(<CODE>getglobal</CODE> is in the basic library;
+<TT>gettable_event</TT> is used for explanatory purposes only).
<P>
The non-terminal <EM>exp1</EM> is used to indicate that the values
returned by an expression must be adjusted to one single value:
<PRE>
-exp1 ::= exp
+ exp1 ::= exp
</PRE>
<P>
-<H3>4.6.2 - Arithmetic Operators</H3>
+<H3>4.5.2 - Arithmetic Operators</H3>
Lua supports the usual <A NAME="arithmetic operators">arithmetic operators</A>:
the binary <CODE>+</CODE> (addition),
<CODE>-</CODE> (subtraction), <CODE>*</CODE> (multiplication),
-<CODE>/</CODE> (division) and <CODE>^</CODE> (exponentiation),
+<CODE>/</CODE> (division), and <CODE>^</CODE> (exponentiation);
and unary <CODE>-</CODE> (negation).
If the operands are numbers, or strings that can be converted to
-numbers (according to the rules given in Section&nbsp;<A HREF="#coercion">4.3</A>),
+numbers (according to the rules given in Section&nbsp;<A HREF="#coercion">4.2</A>),
then all operations except exponentiation have the usual meaning.
Otherwise, an appropriate tag method is called (see Section&nbsp;<A HREF="#tag-method">4.8</A>).
An exponentiation always calls a tag method.
@@ -505,196 +649,216 @@ The standard mathematical library redefines this method for numbers,
giving the expected meaning to <A NAME="exponentiation">exponentiation</A>
(see Section&nbsp;<A HREF="#mathlib">6.3</A>).
<P>
-<H3>4.6.3 - Relational Operators</H3>
-Lua provides the following <A NAME="relational operators">relational operators</A>:
+<H3>4.5.3 - Relational Operators</H3>
+The <A NAME="relational operators">relational operators</A> in Lua are
<PRE>
- &lt; &gt; &lt;= &gt;= ~= ==
+ == ~= &lt; &gt; &lt;= &gt;=
</PRE>
-All these return <B>nil</B> as false and a value different from <B>nil</B> as true.
+These operators return <B>nil</B> as false and a value different from <B>nil</B> as true.
<P>
-Equality first compares the tags of its operands.
+Equality (<CODE>==</CODE>) first compares the tags of its operands.
If they are different, then the result is <B>nil</B>.
Otherwise, their values are compared.
Numbers and strings are compared in the usual way.
-Tables, userdata and functions are compared by reference,
-that is, two tables are considered equal only if they are the same table.
+Tables, userdata, and functions are compared by reference,
+that is, two tables are considered equal only if they are the <EM>same</EM> table.
The operator <CODE>~=</CODE> is exactly the negation of equality (<CODE>==</CODE>).
-Note that the conversion rules of Section&nbsp;<A HREF="#coercion">4.3</A>
+<P>
+The conversion rules of Section&nbsp;<A HREF="#coercion">4.2</A>
<EM>do not</EM> apply to equality comparisons.
-Thus, <CODE>"0"==0</CODE> evaluates to false,
+Thus, <CODE>"0"==0</CODE> evaluates to <EM>false</EM>,
and <CODE>t[0]</CODE> and <CODE>t["0"]</CODE> denote different
entries in a table.
<P>
-The other operators work as follows.
+The order operators work as follows.
If both arguments are numbers, then they are compared as such.
Otherwise, if both arguments are strings,
then their values are compared using lexicographical order.
-Otherwise, the ``order'' tag method is called (see Section&nbsp;<A HREF="#tag-method">4.8</A>).
+Otherwise, the ``lt'' tag method is called (see Section&nbsp;<A HREF="#tag-method">4.8</A>).
<P>
-<H3>4.6.4 - Logical Operators</H3>
-The <A NAME="logical operators">logical operators</A> are
+<H3>4.5.4 - Logical Operators</H3>
+The <A NAME="logical operators">logical operators</A> in Lua are
<A NAME="and"></A><A NAME="or"></A><A NAME="not"></A>
<PRE>
- and or not
+ and or not
</PRE>
-Like control structures, all logical operators
+Like the control structures, all logical operators
consider <B>nil</B> as false and anything else as true.
-The operator <CODE>and</CODE> returns <B>nil</B> if its first argument is <B>nil</B>;
+<P>
+The conjunction operator <CODE>and</CODE> returns <B>nil</B> if its first argument is <B>nil</B>;
otherwise, it returns its second argument.
-The operator <CODE>or</CODE> returns its first argument
+The disjunction operator <CODE>or</CODE> returns its first argument
if it is different from <B>nil</B>;
otherwise, it returns its second argument.
Both <CODE>and</CODE> and <CODE>or</CODE> use <A NAME="short-cut evaluation">short-cut evaluation</A>,
that is,
-the second operand is evaluated only when necessary.
+the second operand is evaluated only if necessary.
<P>
-A useful Lua idiom is <CODE>x = x or v</CODE>,
+There are two useful Lua idioms that use logical operators.
+The first idiom is
+<PRE>
+ x = x or v
+</PRE>
which is equivalent to
<PRE>
- if x == nil then x = v end
+ if x == nil then x = v end
+</PRE>
+This idiom sets <CODE>x</CODE> to a default value <CODE>v</CODE> when <CODE>x</CODE> is not set.
+<P>
+The second idiom is
+<PRE>
+ x = a and b or c
</PRE>
-i.e., it sets <CODE>x</CODE> to a default value <CODE>v</CODE> when
-<CODE>x</CODE> is not set.
+which should be read as <CODE>x = (a and b) or c</CODE>.
+This idiom is equivalent to
+<PRE>
+ if a then x = b else x = c end
+</PRE>
+provided that <CODE>b</CODE> is not <B>nil</B>.
<P>
-<H3>4.6.5 - Concatenation</H3>
+<A NAME="concat"></A>
+<H3>4.5.5 - Concatenation</H3>
The string <A NAME="concatenation">concatenation</A> operator in Lua is
-denoted by ``<A NAME=".."><TT>..</TT></A>''.
-If both operands are strings or numbers, they are converted to
-strings according to the rules in Section&nbsp;<A HREF="#coercion">4.3</A>.
+denoted by two dots (`<A NAME=".."><TT>..</TT></A>').
+If both operands are strings or numbers, then they are converted to
+strings according to the rules in Section&nbsp;<A HREF="#coercion">4.2</A>.
Otherwise, the ``concat'' tag method is called (see Section&nbsp;<A HREF="#tag-method">4.8</A>).
<P>
-<H3>4.6.6 - Precedence</H3>
-<A NAME="Operator precedence">Operator precedence</A> follows the table below,
+<H3>4.5.6 - Precedence</H3>
+<A NAME="Operator precedence">Operator precedence</A> in Lua follows the table below,
from the lower to the higher priority:
<PRE>
- and or
- &lt; &gt; &lt;= &gt;= ~= ==
- ..
- + -
- * /
- not - (unary)
- ^
+ and or
+ &lt; &gt; &lt;= &gt;= ~= ==
+ ..
+ + -
+ * /
+ not - (unary)
+ ^
</PRE>
All binary operators are left associative,
except for <CODE>^</CODE> (exponentiation),
which is right associative.
+The pre-compiler may rearrange the order of evaluation of
+associative operators (such as&nbsp;<CODE>..</CODE> or&nbsp;<CODE>+</CODE>),
+as long as these optimizations do not change normal results.
+However, these optimizations may change some results
+if you define non-associative
+tag methods for these operators.
<P>
<A NAME="tableconstructor"></A>
-<H3>4.6.7 - Table Constructors</H3>
+<H3>4.5.7 - Table Constructors</H3>
Table <A NAME="constructors">constructors</A> are expressions that create tables;
every time a constructor is evaluated, a new table is created.
Constructors can be used to create empty tables,
-or to create a table and initialize some fields.
-<P>
+or to create a table and initialize some of its fields.
The general syntax for constructors is
<PRE>
-tableconstructor ::= '<B>{</B>' fieldlist '<B>}</B>'
-fieldlist ::= lfieldlist | ffieldlist | lfieldlist '<B>;</B>' ffieldlist | ffieldlist '<B>;</B>' lfieldlist
-lfieldlist ::= [lfieldlist1]
-ffieldlist ::= [ffieldlist1]
+ tableconstructor ::= `<B>{</B>' fieldlist `<B>}</B>'
+ fieldlist ::= lfieldlist | ffieldlist | lfieldlist `<B>;</B>' ffieldlist | ffieldlist `<B>;</B>' lfieldlist
+ lfieldlist ::= [lfieldlist1]
+ ffieldlist ::= [ffieldlist1]
</PRE>
<P>
The form <EM>lfieldlist1</EM> is used to initialize lists:
<PRE>
-lfieldlist1 ::= exp {'<B>,</B>' exp} ['<B>,</B>']
+ lfieldlist1 ::= exp {`<B>,</B>' exp} [`<B>,</B>']
</PRE>
The expressions in the list are assigned to consecutive numerical indices,
-starting with 1.
+starting with&nbsp;1.
For example,
<PRE>
- a = {"v1", "v2", 34}
+ a = {"v1", "v2", 34}
</PRE>
is equivalent to
<PRE>
- do
- local temp = {}
- temp[1] = "v1"
- temp[2] = "v2"
- temp[3] = 34
- a = temp
- end
+ do
+ local temp = {}
+ temp[1] = "v1"
+ temp[2] = "v2"
+ temp[3] = 34
+ a = temp
+ end
</PRE>
<P>
The form <EM>ffieldlist1</EM> initializes other fields in a table:
<PRE>
-ffieldlist1 ::= ffield {'<B>,</B>' ffield} ['<B>,</B>']
-ffield ::= '<B>[</B>' exp '<B>]</B>' '<B>=</B>' exp | name '<B>=</B>' exp
+ ffieldlist1 ::= ffield {`<B>,</B>' ffield} [`<B>,</B>']
+ ffield ::= `<B>[</B>' exp `<B>]</B>' `<B>=</B>' exp | name `<B>=</B>' exp
</PRE>
For example,
<PRE>
- a = {[f(k)] = g(y), x = 1, y = 3, [0] = b+c}
+ a = {[f(k)] = g(y), x = 1, y = 3, [0] = b+c}
</PRE>
is equivalent to
<PRE>
- do
- local temp = {}
- temp[f(k)] = g(y)
- temp.x = 1 -- or temp["x"] = 1
- temp.y = 3 -- or temp["y"] = 3
- temp[0] = b+c
- a = temp
- end
+ do
+ local temp = {}
+ temp[f(k)] = g(y)
+ temp.x = 1 -- or temp["x"] = 1
+ temp.y = 3 -- or temp["y"] = 3
+ temp[0] = b+c
+ a = temp
+ end
</PRE>
An expression like <CODE>{x = 1, y = 4}</CODE> is
in fact syntactic sugar for <CODE>{["x"] = 1, ["y"] = 4}</CODE>.
<P>
Both forms may have an optional trailing comma,
and can be used in the same constructor separated by
-a semi-collon.
-For example, all forms below are correct:
+a semi-colon.
+For example, all forms below are correct.
<PRE>
- x = {;}
- x = {'a', 'b',}
- x = {type='list'; 'a', 'b'}
- x = {f(0), f(1), f(2),; n=3,}
+ x = {;}
+ x = {"a", "b",}
+ x = {type="list"; "a", "b"}
+ x = {f(0), f(1), f(2),; n=3,}
</PRE>
<P>
<A NAME="functioncall"></A>
-<H3>4.6.8 - Function Calls</H3>
-A <A NAME="function call">function call</A> has the following syntax:
+<H3>4.5.8 - Function Calls</H3>
+A <A NAME="function call">function call</A> in Lua has the following syntax:
<PRE>
-functioncall ::= simpleexp args
+ functioncall ::= varorfunc args
</PRE>
-First, <EM>simpleexp</EM> is evaluated.
+First, <EM>varorfunc</EM> is evaluated.
If its value has type <EM>function</EM>,
then this function is called,
with the given arguments.
Otherwise, the ``function'' tag method is called,
-having as first parameter the value of <EM>simpleexp</EM>,
-and then the original call parameters.
+having as first parameter the value of <EM>varorfunc</EM>,
+and then the original call arguments
+(see Section&nbsp;<A HREF="#tag-method">4.8</A>).
<P>
-The form:
+The form
<PRE>
-functioncall ::= simpleexp '<B>:</B>' name args
+ functioncall ::= varorfunc `<B>:</B>' name args
</PRE>
can be used to call ``methods''.
-A call <CODE>simpleexp:name(...)</CODE>
-is syntactic sugar for
-<PRE>
- simpleexp.name(simpleexp, ...)
-</PRE>
-except that <CODE>simpleexp</CODE> is evaluated only once.
+A call <CODE>v:name(...)</CODE>
+is syntactic sugar for <CODE>v.name(v, ...)</CODE>,
+except that <CODE>v</CODE> is evaluated only once.
<P>
Arguments have the following syntax:
<PRE>
-args ::= '<B>(</B>' [explist1] '<B>)</B>'
-args ::= tableconstructor
-args ::= '<B>literal</B>'
-explist1 ::= exp1 {'<B>,</B>' exp1}
+ args ::= `<B>(</B>' [explist1] `<B>)</B>'
+ args ::= tableconstructor
+ args ::= literal
+ explist1 ::= {exp1 `<B>,</B>'} exp
</PRE>
All argument expressions are evaluated before the call.
A call of the form <CODE>f{...}</CODE> is syntactic sugar for
<CODE>f({...})</CODE>, that is,
-the parameter list is a single new table.
+the argument list is a single new table.
A call of the form <CODE>f'...'</CODE>
(or <CODE>f"..."</CODE> or <CODE>f[[...]]</CODE>) is syntactic sugar for
<CODE>f('...')</CODE>, that is,
-the parameter list is a single literal string.
+the argument list is a single literal string.
<P>
Because a function can return any number of results
-(see Section&nbsp;<A HREF="#return">4.5.3</A>),
-the number of results must be adjusted before used.
-If the function is called as a statement (see Section&nbsp;<A HREF="#funcstat">4.5.4</A>),
+(see Section&nbsp;<A HREF="#return">4.4.3</A>),
+the number of results must be adjusted before they are used (see Section&nbsp;<A HREF="#adjust">4.3</A>).
+If the function is called as a statement (see Section&nbsp;<A HREF="#funcstat">4.4.5</A>),
then its return list is adjusted to&nbsp;0,
thus discarding all returned values.
If the function is called in a place that needs a single value
@@ -704,166 +868,230 @@ thus discarding all returned values but the first one.
If the function is called in a place that can hold many values
(syntactically denoted by the non-terminal <EM>exp</EM>),
then no adjustment is made.
-Note that the only place that can hold many values
-is the last (or the only) expression in an assignment
-or in a return statement; see examples below.
+The only places that can hold many values
+is the last (or the only) expression in an assignment,
+in an argument list, or in the <B>return</B> statement.
+Here are some examples:
<PRE>
- f(); -- adjusted to 0
- g(x, f()); -- f() is adjusted to 1
- a,b,c = f(), x; -- f() is adjusted to 1 result (and c gets nil)
- a,b,c = x, f(); -- f() is adjusted to 2
- a,b,c = f(); -- f() is adjusted to 3
- return f(); -- returns all values returned by f()
+ f() -- adjusted to 0 results
+ g(f(), x) -- f() is adjusted to 1 result
+ g(x, f()) -- g gets x plus all values returned by f()
+ a,b,c = f(), x -- f() is adjusted to 1 result (and c gets nil)
+ a,b,c = x, f() -- f() is adjusted to 2
+ a,b,c = f() -- f() is adjusted to 3
+ return f() -- returns all values returned by f()
+ return x,y,f() -- returns a, b, and all values returned by f()
</PRE>
<P>
<A NAME="func-def"></A>
-<H3>4.6.9 - <A NAME="Function Definitions</H3>">Function Definitions</H3></A>
+<H3>4.5.9 - <A NAME="Function Definitions</H3>">Function Definitions</H3></A>
<P>
The syntax for function definition is
<PRE>
-function ::= <B>function</B> '<B>(</B>' [parlist1] '<B>)</B>' block <B>end</B>
-stat ::= <B>function</B> funcname '<B>(</B>' [parlist1] '<B>)</B>' block <B>end</B>
-funcname ::= name | name '<B>.</B>' name
+ function ::= <B>function</B> `<B>(</B>' [parlist1] `<B>)</B>' block <B>end</B>
+ stat ::= <B>function</B> funcname `<B>(</B>' [parlist1] `<B>)</B>' block <B>end</B>
+ funcname ::= name | name `<B>.</B>' name | name `<B>:</B>' name
</PRE>
The statement
<PRE>
- function f (...)
- ...
- end
+ function f () ... end
</PRE>
is just syntactic sugar for
<PRE>
- f = function (...)
- ...
- end
+ f = function () ... end
+</PRE>
+and the statement
+<PRE>
+ function v.f () ... end
+</PRE>
+is syntactic sugar for
+<PRE>
+ v.f = function () ... end
</PRE>
<P>
A function definition is an executable expression,
whose value has type <EM>function</EM>.
When Lua pre-compiles a chunk,
-all its function bodies are pre-compiled, too.
+all its function bodies are pre-compiled too.
Then, whenever Lua executes the function definition,
-its upvalues are fixed (see Section&nbsp;<A HREF="#upvalue">4.7</A>),
-and the function is <EM>instantiated</EM> (or ``closed'').
-This function instance (or ``closure'')
+its upvalues are fixed (see Section&nbsp;<A HREF="#upvalue">4.6</A>),
+and the function is <EM>instantiated</EM> (or <EM>closed</EM>).
+This function instance (or <EM>closure</EM>)
is the final value of the expression.
-Different instances of a same function
+Different instances of the same function
may have different upvalues.
<P>
Parameters act as local variables,
initialized with the argument values:
<PRE>
-parlist1 ::= '<B>...</B>'
-parlist1 ::= name {'<B>,</B>' name} ['<B>,</B>' '<B>...</B>']
+ parlist1 ::= `<B>...</B>'
+ parlist1 ::= name {`<B>,</B>' name} [`<B>,</B>' `<B>...</B>']
</PRE>
<A NAME="vararg"></A>
When a function is called,
the list of <A NAME="arguments">arguments</A> is adjusted to
-the length of the list of parameters (see Section&nbsp;<A HREF="#adjust">4.4</A>),
-unless the function is a <A NAME="vararg"><EM>vararg</EM></A> function,
-indicated by the dots (...) at the end of its parameter list.
+the length of the list of parameters (see Section&nbsp;<A HREF="#adjust">4.3</A>),
+unless the function is a <A NAME="vararg function"><EM>vararg function</EM></A>,
+which is
+indicated by three dots (`<CODE>...</CODE>') at the end of its parameter list.
A vararg function does not adjust its argument list;
-instead, it collects any extra arguments into an implicit parameter,
+instead, it collects all extra arguments into an implicit parameter,
called <A NAME="arg"><TT>arg</TT></A>.
-This parameter is always initialized as a table,
-with a field <CODE>n</CODE> whose value is the number of extra arguments,
-and the extra arguments at positions 1,&nbsp;2,&nbsp;...
+The value of <CODE>arg</CODE> is a table,
+with a field&nbsp;<CODE>n</CODE> whose value is the number of extra arguments,
+and the extra arguments at positions 1,&nbsp;2,&nbsp;...,&nbsp;<CODE>n</CODE>.
<P>
-As an example, suppose definitions like:
+As an example, consider the following definitions:
<PRE>
- function f(a, b) end
- function g(a, b, ...) end
+ function f(a, b) end
+ function g(a, b, ...) end
+ function r() return 1,2,3 end
</PRE>
Then, we have the following mapping from arguments to parameters:
<PRE>
- CALL PARAMETERS
+ CALL PARAMETERS
<P>
- f(3) a=3, b=nil
- f(3, 4) a=3, b=4
- f(3, 4, 5) a=3, b=4
+ f(3) a=3, b=nil
+ f(3, 4) a=3, b=4
+ f(3, 4, 5) a=3, b=4
+ f(r(), 10) a=1, b=10
+ f(r()) a=1, b=2
<P>
- g(3) a=3, b=nil, arg={n=0}
- g(3, 4) a=3, b=4, arg={n=0}
- g(3, 4, 5, 8) a=3, b=4, arg={5, 8; n=2}
+ g(3) a=3, b=nil, arg={n=0}
+ g(3, 4) a=3, b=4, arg={n=0}
+ g(3, 4, 5, 8) a=3, b=4, arg={5, 8; n=2}
+ g(5, r()) a=5, b=1, arg={2, 3; n=2}
</PRE>
<P>
-Results are returned using the <CODE>return</CODE> statement (see Section&nbsp;<A HREF="#return">4.5.3</A>).
-If control reaches the end of a function without a return instruction,
+Results are returned using the <B>return</B> statement (see Section&nbsp;<A HREF="#return">4.4.3</A>).
+If control reaches the end of a function
+without encountering a <B>return</B> statement,
then the function returns with no results.
<P>
-There is a special syntax for defining <A NAME="methods">methods</A>,
-that is, functions that have an implicit extra parameter <A NAME="self"><TT>self</TT></A>:
+The syntax
<PRE>
-function ::= <B>function</B> name '<B>:</B>' name '<B>(</B>' [parlist1] '<B>)</B>' block <B>end</B>
+ funcname ::= name `<B>:</B>' name
</PRE>
-Thus, a declaration like
+is used for defining <A NAME="methods"><EM>methods</EM></A>,
+that is, functions that have an implicit extra parameter <A NAME="self"><TT>self</TT></A>.
+<P>
+The statement
<PRE>
- function v:f (...)
- ...
- end
+ function v:f (...) ... end
</PRE>
-is equivalent to
+is just syntactic sugar for
<PRE>
- v.f = function (self, ...)
- ...
- end
+ v.f = function (self, ...) ... end
</PRE>
-that is, the function gets an extra formal parameter called <CODE>self</CODE>.
-Note that the variable <CODE>v</CODE> must have been
-previously initialized with a table value.
+Note that the function gets an extra formal parameter called <CODE>self</CODE>.
<P>
<P>
<A NAME="upvalue"></A>
-<A NAME="4.7"></A>
-<H2>4.7 - Visibility and Upvalues</H2>
-<A NAME="Visibility"></A> <A NAME="Upvalues"></A>
+<A NAME="4.6"></A>
+<H2>4.6 - Visibility and Upvalues</H2>
+<A NAME="visibility"></A><A NAME="upvalues"></A>
<P>
A function body may refer to its own local variables
-(which includes its parameters) and to global variables,
-as long as they are not shadowed by local
-variables from enclosing functions.
+(which include its parameters) and to global variables,
+as long as they are not <EM>shadowed</EM> by local
+variables with the same name from enclosing functions.
A function <EM>cannot</EM> access a local
variable from an enclosing function,
since such variables may no longer exist when the function is called.
However, a function may access the <EM>value</EM> of a local variable
-from an enclosing function, using <EM>upvalues</EM>.
-<P>
+from an enclosing function, using <EM>upvalues</EM>,
+whose syntax is
<PRE>
-upvalue ::= '<B>%</B>' name
+ upvalue ::= `<B>%</B>' name
</PRE>
+<P>
An upvalue is somewhat similar to a variable expression,
-but whose value is frozen when the function wherein it
+but whose value is <EM>frozen</EM> when the function wherein it
appears is instantiated.
The name used in an upvalue may be the name of any variable visible
-at the point where the function is defined.
+at the point where the function is defined,
+that is,
+global variables and local variables
+from the <EM>immediately enclosing</EM> function.
+Note that when the upvalue is a table,
+only the <EM>reference</EM> to that table
+(which is the value of the upvalue) is frozen;
+the table contents can be changed at will.
+Using table values as upvalues is a technique for having
+writable but private state attached to functions.
<P>
Here are some examples:
<PRE>
- a,b,c = 1,2,3 -- global variables
- function f (x)
- local b -- x and b are local to f
- local g = function (a)
- local y -- a and y are local to g
- p = a -- OK, access local 'a'
- p = c -- OK, access global 'c'
- p = b -- ERROR: cannot access a variable in outer scope
- p = %b -- OK, access frozen value of 'b' (local to 'f')
- p = %c -- OK, access frozen value of global 'c'
- p = %y -- ERROR: 'y' is not visible where 'g' is defined
- end -- g
- end -- f
+ a,b,c = 1,2,3 -- global variables
+ local d
+ function f (x)
+ local b = {} -- x and b are local to f; b shadows the global b
+ local g = function (a)
+ local y -- a and y are local to g
+ p = a -- OK, access local `a'
+ p = c -- OK, access global `c'
+ p = b -- ERROR: cannot access a variable in outer scope
+ p = %b -- OK, access frozen value of `b' (local to `f')
+ %b = 3 -- ERROR: cannot change an upvalue
+ %b.x = 3 -- OK, change the table contents
+ p = %c -- OK, access frozen value of global `c'
+ p = %y -- ERROR: `y' is not visible where `g' is defined
+ p = %d -- ERROR: `d' is not visible where `g' is defined
+ end -- g
+ end -- f
</PRE>
<P>
<P>
+<A NAME="error"></A>
+<A NAME="4.7"></A>
+<H2>4.7 - Error Handling</H2>
+<P>
+Because Lua is an extension language,
+all Lua actions start from C&nbsp;code in the host program
+calling a function from the Lua library.
+Whenever an error occurs during Lua compilation or execution,
+the function <CODE>_ERRORMESSAGE</CODE> is called <A NAME="_ERRORMESSAGE"></A>
+(provided it is different from <B>nil</B>),
+and then the corresponding function from the library
+(<CODE>lua_dofile</CODE>, <CODE>lua_dostring</CODE>,
+<CODE>lua_dobuffer</CODE>, or <CODE>lua_call</CODE>)
+is terminated, returning an error condition.
+<P>
+Memory allocation errors are an exception to the previous rule.
+When memory allocation fails, Lua may not be able to execute the
+<CODE>_ERRORMESSAGE</CODE> function.
+So, for this kind of error, Lua does not call
+the <CODE>_ERRORMESSAGE</CODE> function;
+instead, the corresponding function from the library
+returns immediately with a special error code (<CODE>LUA_ERRMEM</CODE>).
+This and other error codes are defined in <CODE>lua.h</CODE>;
+Section&nbsp;<A HREF="#luado">5.8</A>.
+<P>
+The only argument to <CODE>_ERRORMESSAGE</CODE> is a string
+describing the error.
+The default definition for
+this function calls <CODE>_ALERT</CODE>, <A NAME="_ALERT"></A>
+which prints the message to <CODE>stderr</CODE> (see Section&nbsp;<A HREF="#alert">6.1</A>).
+The standard I/O library redefines <CODE>_ERRORMESSAGE</CODE>
+and uses the debug facilities (see Section&nbsp;<A HREF="#debugI">7</A>)
+to print some extra information,
+such as a call stack traceback.
+<P>
+Lua code can explicitly generate an error by calling the
+function <CODE>error</CODE> (see Section&nbsp;<A HREF="#pdf-error">6.1</A>).
+Lua code can ``catch'' an error using the function
+<CODE>call</CODE> (see Section&nbsp;<A HREF="#pdf-call">6.1</A>).
+<P>
+<P>
<A NAME="tag-method"></A>
<A NAME="4.8"></A>
<H2>4.8 - Tag Methods</H2>
<P>
Lua provides a powerful mechanism to extend its semantics,
-called <A NAME="tag methods"><EM>tag methods</EM></A>.
+called <EM>tag methods</EM>.
A tag method is a programmer-defined function
-that is called at specific key points during the evaluation of a program,
+that is called at specific key points during the execution of a Lua program,
allowing the programmer to change the standard Lua behavior at these points.
Each of these points is called an <A NAME="event"><EM>event</EM></A>.
<P>
@@ -876,8 +1104,8 @@ Its first parameter is the tag, the second parameter is the event name
(a string; see below),
and the third parameter is the new method (a function),
or <B>nil</B> to restore the default behavior for the pair.
-The function returns the previous tag method for that pair.
-Another function, <A NAME="gettagmethod"><TT>gettagmethod</TT></A>,
+The <CODE>settagmethod</CODE> function returns the previous tag method for that pair.
+A companion function <A NAME="gettagmethod"><TT>gettagmethod</TT></A>
receives a tag and an event name and returns the
current method associated with the pair.
<P>
@@ -885,573 +1113,640 @@ Tag methods are called in the following events,
identified by the given names.
The semantics of tag methods is better explained by a Lua function
describing the behavior of the interpreter at each event.
-The function not only shows when a tag method is called,
-but also its arguments, its results and the default behavior.
-Please notice that the code shown here is only illustrative;
+This function not only shows when a tag method is called,
+but also its arguments, its results, and the default behavior.
+The code shown here is only <EM>illustrative</EM>;
the real behavior is hard coded in the interpreter,
and it is much more efficient than this simulation.
All functions used in these descriptions
-(<CODE>rawgetglobal</CODE>, <CODE>tonumber</CODE>, <CODE>call</CODE>, etc.)
+(<CODE>rawget</CODE>, <CODE>tonumber</CODE>, <CODE>call</CODE>, etc.)
are described in Section&nbsp;<A HREF="#predefined">6.1</A>.
<P>
<DL>
<P>
<DT><B>``add'':</B><DD><A NAME="add event"></A>
-called when a <CODE>+</CODE> operation is applied to non numerical operands.
+called when a <CODE>+</CODE> operation is applied to non-numerical operands.
<P>
-The function <CODE>getbinmethod</CODE> defines how Lua chooses a tag method
+The function <CODE>getbinmethod</CODE> below defines how Lua chooses a tag method
for a binary operation.
First, Lua tries the first operand.
If its tag does not define a tag method for the operation,
then Lua tries the second operand.
-If it also fails, then it gets a tag method from tag&nbsp;0:
-<PRE>
- function getbinmethod (op1, op2, event)
- return gettagmethod(tag(op1), event) or
- gettagmethod(tag(op2), event) or
- gettagmethod(0, event)
- end
-</PRE>
-<PRE>
- function add_event (op1, op2)
- local o1, o2 = tonumber(op1), tonumber(op2)
- if o1 and o2 then -- both operands are numeric
- return o1+o2 -- '+' here is the primitive 'add'
- else -- at least one of the operands is not numeric
- local tm = getbinmethod(op1, op2, "add")
- if tm then
- -- call the method with both operands and an extra
- -- argument with the event name
- return tm(op1, op2, "add")
- else -- no tag method available: default behavior
- error("unexpected type at arithmetic operation")
- end
- end
- end
+If it also fails, then it gets a tag method from tag&nbsp;0.
+<PRE>
+ function getbinmethod (op1, op2, event)
+ return gettagmethod(tag(op1), event) or
+ gettagmethod(tag(op2), event) or
+ gettagmethod(0, event)
+ end
+</PRE>
+Using this function,
+the tag method for the ``add'' event is
+<PRE>
+ function add_event (op1, op2)
+ local o1, o2 = tonumber(op1), tonumber(op2)
+ if o1 and o2 then -- both operands are numeric
+ return o1+o2 -- '+' here is the primitive 'add'
+ else -- at least one of the operands is not numeric
+ local tm = getbinmethod(op1, op2, "add")
+ if tm then
+ -- call the method with both operands and an extra
+ -- argument with the event name
+ return tm(op1, op2, "add")
+ else -- no tag method available: default behavior
+ error("unexpected type at arithmetic operation")
+ end
+ end
+ end
</PRE>
<P>
<DT><B>``sub'':</B><DD><A NAME="sub event"></A>
-called when a <CODE>-</CODE> operation is applied to non numerical operands.
-Behavior similar to the <CODE>"add"</CODE> event.
+called when a <CODE>-</CODE> operation is applied to non-numerical operands.
+Behavior similar to the ``add'' event.
<P>
<DT><B>``mul'':</B><DD><A NAME="mul event"></A>
-called when a <CODE>*</CODE> operation is applied to non numerical operands.
-Behavior similar to the <CODE>"add"</CODE> event.
+called when a <CODE>*</CODE> operation is applied to non-numerical operands.
+Behavior similar to the ``add'' event.
<P>
<DT><B>``div'':</B><DD><A NAME="div event"></A>
-called when a <CODE>/</CODE> operation is applied to non numerical operands.
-Behavior similar to the <CODE>"add"</CODE> event.
+called when a <CODE>/</CODE> operation is applied to non-numerical operands.
+Behavior similar to the ``add'' event.
<P>
<DT><B>``pow'':</B><DD><A NAME="pow event"></A>
-called when a <CODE>^</CODE> operation is applied.
+called when a <CODE>^</CODE> operation (exponentiation) is applied,
+even for numerical operands.
<PRE>
- function pow_event (op1, op2)
- local tm = getbinmethod(op1, op2, "pow")
- if tm then
- -- call the method with both operands and an extra
- -- argument with the event name
- return tm(op1, op2, "pow")
- else -- no tag method available: default behavior
- error("unexpected type at arithmetic operation")
- end
- end
+ function pow_event (op1, op2)
+ local tm = getbinmethod(op1, op2, "pow")
+ if tm then
+ -- call the method with both operands and an extra
+ -- argument with the event name
+ return tm(op1, op2, "pow")
+ else -- no tag method available: default behavior
+ error("unexpected type at arithmetic operation")
+ end
+ end
</PRE>
<P>
<DT><B>``unm'':</B><DD><A NAME="unm event"></A>
-called when an unary <CODE>-</CODE> operation is applied to a non numerical operand.
-<PRE>
- function unm_event (op)
- local o = tonumber(op)
- if o then -- operand is numeric
- return -o -- '-' here is the primitive 'unm'
- else -- the operand is not numeric.
- -- Try to get a tag method from the operand;
- -- if it does not have one, try a "global" one (tag 0)
- local tm = gettagmethod(tag(op), "unm") or
- gettagmethod(0, "unm")
- if tm then
- -- call the method with the operand, nil, and an extra
- -- argument with the event name
- return tm(op, nil, "unm")
- else -- no tag method available: default behavior
- error("unexpected type at arithmetic operation")
- end
- end
- end
+called when a unary <CODE>-</CODE> operation is applied to a non-numerical operand.
+<PRE>
+ function unm_event (op)
+ local o = tonumber(op)
+ if o then -- operand is numeric
+ return -o -- '-' here is the primitive 'unm'
+ else -- the operand is not numeric.
+ -- Try to get a tag method from the operand;
+ -- if it does not have one, try a "global" one (tag 0)
+ local tm = gettagmethod(tag(op), "unm") or
+ gettagmethod(0, "unm")
+ if tm then
+ -- call the method with the operand, nil, and an extra
+ -- argument with the event name
+ return tm(op, nil, "unm")
+ else -- no tag method available: default behavior
+ error("unexpected type at arithmetic operation")
+ end
+ end
+ end
</PRE>
<P>
<DT><B>``lt'':</B><DD><A NAME="lt event"></A>
-called when a <CODE>&lt;</CODE> operation is applied to non numerical
-or non string operands.
-<PRE>
- function lt_event (op1, op2)
- if type(op1) == "number" and type(op2) == "number" then
- return op1 &lt; op2 -- numeric comparison
- elseif type(op1) == "string" and type(op2) == "string" then
- return op1 &lt; op2 -- lexicographic comparison
- else
- local tm = getbinmethod(op1, op2, "lt")
- if tm then
- return tm(op1, op2, "lt")
- else
- error("unexpected type at comparison");
- end
- end
- end
-</PRE>
-<P>
-<DT><B>``gt'':</B><DD><A NAME="gt event"></A>
-called when a <CODE>&gt;</CODE> operation is applied to non numerical
-or non string operands.
-Behavior similar to the <CODE>"lt"</CODE> event.
-<P>
-<DT><B>``le'':</B><DD><A NAME="le event"></A>
-called when a <CODE>&lt;=</CODE> operation is applied to non numerical
-or non string operands.
-Behavior similar to the <CODE>"lt"</CODE> event.
-<P>
-<DT><B>``ge'':</B><DD><A NAME="ge event"></A>
-called when a <CODE>&gt;=</CODE> operation is applied to non numerical
-or non string operands.
-Behavior similar to the <CODE>"lt"</CODE> event.
+called when an order operation is applied to non-numerical
+or non-string operands.
+It corresponds to the <CODE>&lt;</CODE> operator.
+<PRE>
+ function lt_event (op1, op2)
+ if type(op1) == "number" and type(op2) == "number" then
+ return op1 &lt; op2 -- numeric comparison
+ elseif type(op1) == "string" and type(op2) == "string" then
+ return op1 &lt; op2 -- lexicographic comparison
+ else
+ local tm = getbinmethod(op1, op2, "lt")
+ if tm then
+ return tm(op1, op2, "lt")
+ else
+ error("unexpected type at comparison");
+ end
+ end
+ end
+</PRE>
+The other order operators use this tag method according to the
+usual equivalences:
+<PRE>
+ a&gt;b &lt;=&gt; b&lt;a
+ a&lt;=b &lt;=&gt; not (b&lt;a)
+ a&gt;=b &lt;=&gt; not (a&lt;b)
+</PRE>
<P>
<DT><B>``concat'':</B><DD><A NAME="concatenation event"></A>
-called when a concatenation is applied to non string operands.
-<PRE>
- function concat_event (op1, op2)
- if (type(op1) == "string" or type(op1) == "number") and
- (type(op2) == "string" or type(op2) == "number") then
- return op1..op2 -- primitive string concatenation
- else
- local tm = getbinmethod(op1, op2, "concat")
- if tm then
- return tm(op1, op2, "concat")
- else
- error("unexpected type for concatenation")
- end
- end
- end
+called when a concatenation is applied to non-string operands.
+<PRE>
+ function concat_event (op1, op2)
+ if (type(op1) == "string" or type(op1) == "number") and
+ (type(op2) == "string" or type(op2) == "number") then
+ return op1..op2 -- primitive string concatenation
+ else
+ local tm = getbinmethod(op1, op2, "concat")
+ if tm then
+ return tm(op1, op2, "concat")
+ else
+ error("unexpected type for concatenation")
+ end
+ end
+ end
</PRE>
<P>
<DT><B>``index'':</B><DD><A NAME="index event"></A>
called when Lua tries to retrieve the value of an index
not present in a table.
-See event <CODE>"gettable"</CODE> for its semantics.
+See the ``gettable'' event for its semantics.
<P>
<DT><B>``getglobal'':</B><DD><A NAME="getglobal event"></A>
called whenever Lua needs the value of a global variable.
This method can only be set for <B>nil</B> and for tags
created by <CODE>newtag</CODE>.
-<PRE>
- function getglobal (varname)
- local value = rawgetglobal(varname)
- local tm = gettagmethod(tag(value), "getglobal")
- if not tm then
- return value
- else
- return tm(varname, value)
- end
- end
-</PRE>
-The function <CODE>getglobal</CODE> is pre-defined in Lua (see Section&nbsp;<A HREF="#predefined">6.1</A>).
+Note that
+the tag is that of the <EM>current value</EM> of the global variable.
+<PRE>
+ function getglobal (varname)
+ -- access the table of globals
+ local value = rawget(globals(), varname)
+ local tm = gettagmethod(tag(value), "getglobal")
+ if not tm then
+ return value
+ else
+ return tm(varname, value)
+ end
+ end
+</PRE>
+The function <CODE>getglobal</CODE> is defined in the basic library&nbsp;(see Section&nbsp;<A HREF="#predefined">6.1</A>).
<P>
<DT><B>``setglobal'':</B><DD><A NAME="setglobal event"></A>
called whenever Lua assigns to a global variable.
This method cannot be set for numbers, strings, and tables and
-userdata with default tags.
+userdata with the default tag.
<PRE>
- function setglobal (varname, newvalue)
- local oldvalue = rawgetglobal(varname)
- local tm = gettagmethod(tag(oldvalue), "setglobal")
- if not tm then
- return rawsetglobal(varname, newvalue)
- else
- return tm(varname, oldvalue, newvalue)
- end
- end
+ function setglobal (varname, newvalue)
+ local oldvalue = rawget(globals(), varname)
+ local tm = gettagmethod(tag(oldvalue), "setglobal")
+ if not tm then
+ rawset(globals(), varname, newvalue)
+ else
+ tm(varname, oldvalue, newvalue)
+ end
+ end
</PRE>
-Notice: the function <CODE>setglobal</CODE> is pre-defined in Lua (see Section&nbsp;<A HREF="#predefined">6.1</A>).
+The function <CODE>setglobal</CODE> is defined in the basic library&nbsp;(see Section&nbsp;<A HREF="#predefined">6.1</A>).
<P>
<DT><B>``gettable'':</B><DD><A NAME="gettable event"></A>
called whenever Lua accesses an indexed variable.
-This method cannot be set for tables with default tag.
-<PRE>
- function gettable_event (table, index)
- local tm = gettagmethod(tag(table), "gettable")
- if tm then
- return tm(table, index)
- elseif type(table) ~= "table" then
- error("indexed expression not a table");
- else
- local v = rawgettable(table, index)
- tm = gettagmethod(tag(table), "index")
- if v == nil and tm then
- return tm(table, index)
- else
- return v
- end
- end
- end
+This method cannot be set for tables with the default tag.
+<PRE>
+ function gettable_event (table, index)
+ local tm = gettagmethod(tag(table), "gettable")
+ if tm then
+ return tm(table, index)
+ elseif type(table) ~= "table" then
+ error("indexed expression not a table");
+ else
+ local v = rawget(table, index)
+ tm = gettagmethod(tag(table), "index")
+ if v == nil and tm then
+ return tm(table, index)
+ else
+ return v
+ end
+ end
+ end
</PRE>
<P>
<DT><B>``settable'':</B><DD><A NAME="settable event"></A>
called when Lua assigns to an indexed variable.
-This method cannot be set for tables with default tag.
+This method cannot be set for tables with the default tag.
<PRE>
- function settable_event (table, index, value)
- local tm = gettagmethod(tag(table), "settable")
- if tm then
- tm(table, index, value)
- elseif type(table) ~= "table" then
- error("indexed expression not a table")
- else
- rawsettable(table, index, value)
- end
- end
+ function settable_event (table, index, value)
+ local tm = gettagmethod(tag(table), "settable")
+ if tm then
+ tm(table, index, value)
+ elseif type(table) ~= "table" then
+ error("indexed expression not a table")
+ else
+ rawset(table, index, value)
+ end
+ end
</PRE>
<P>
<DT><B>``function'':</B><DD><A NAME="function event"></A>
-called when Lua tries to call a non function value.
-<PRE>
- function function_event (func, ...)
- if type(func) == "function" then
- return call(func, arg)
- else
- local tm = gettagmethod(tag(func), "function")
- if tm then
- local i = arg.n
- while i &gt; 0 do
- arg[i+1] = arg[i]
- i = i-1
- end
- arg.n = arg.n+1
- arg[1] = func
- return call(tm, arg)
- else
- error("call expression not a function")
- end
- end
- end
+called when Lua tries to call a non-function value.
+<PRE>
+ function function_event (func, ...)
+ if type(func) == "function" then
+ return call(func, arg)
+ else
+ local tm = gettagmethod(tag(func), "function")
+ if tm then
+ for i=arg.n,1,-1 do
+ arg[i+1] = arg[i]
+ end
+ arg.n = arg.n+1
+ arg[1] = func
+ return call(tm, arg)
+ else
+ error("call expression not a function")
+ end
+ end
+ end
</PRE>
<P>
<DT><B>``gc'':</B><DD><A NAME="gc event"></A>
-called when Lua is ``garbage collecting'' an object.
-This method cannot be set for strings, numbers, functions,
-and userdata with default tag.
-For each object to be collected,
+called when Lua is ``garbage collecting'' a userdata.
+This tag method can be set only from&nbsp;C,
+and cannot be set for a userdata with the default tag.
+For each userdata to be collected,
Lua does the equivalent of the following function:
<PRE>
- function gc_event (obj)
- local tm = gettagmethod(tag(obj), "gc")
- if tm then
- tm(obj)
- end
- end
-</PRE>
-Moreover, at the end of a garbage collection cycle,
+ function gc_event (obj)
+ local tm = gettagmethod(tag(obj), "gc")
+ if tm then
+ tm(obj)
+ end
+ end
+</PRE>
+In a garbage-collection cycle,
+the tag methods for userdata are called in <EM>reverse</EM> order of tag creation,
+that is, the first tag methods to be called are those associated
+with the last tag created in the program.
+Moreover, at the end of the cycle,
Lua does the equivalent of the call <CODE>gc_event(nil)</CODE>.
<P>
</DL>
<P>
<P>
<P>
-<A NAME="error"></A>
-<A NAME="4.9"></A>
-<H2>4.9 - Error Handling</H2>
-<P>
-Because Lua is an extension language,
-all Lua actions start from C code in the host program
-calling a function from the Lua library.
-Whenever an error occurs during Lua compilation or execution,
-function <CODE>_ERRORMESSAGE</CODE> is called <A NAME="_ERRORMESSAGE"></A>
-(provided it is different from <B>nil</B>),
-and then the corresponding function from the library
-(<CODE>lua_dofile</CODE>, <CODE>lua_dostring</CODE>,
-<CODE>lua_dobuffer</CODE>, or <CODE>lua_callfunction</CODE>)
-is terminated, returning an error condition.
-<P>
-The only argument to <CODE>_ERRORMESSAGE</CODE> is a string
-describing the error.
-The default definition for this function calls <CODE>_ALERT</CODE>,
-which prints the message to <CODE>stderr</CODE> (see Section&nbsp;<A HREF="#alert">6.1</A>).
-The standard I/O library redefines <CODE>_ERRORMESSAGE</CODE>,
-and uses the debug facilities (see Section&nbsp;<A HREF="#debugI">7</A>)
-to print some extra information,
-such as the call stack.
-<P>
-To provide more information about errors,
-Lua programs should include the compilation pragma <CODE>$debug</CODE>.
-<A NAME="pragma"></A>
-<A NAME="debug pragma"></A>
-When an error occurs in a chunk compiled with this option,
-the I/O error routine is able to print the number of the
-lines where the calls (and the error) were made.
-<P>
-Lua code can explicitly generate an error by calling the built-in
-function <CODE>error</CODE> (see Section&nbsp;<A HREF="#pdf-error">6.1</A>).
-Lua code can ``catch'' an error using the built-in function
-<CODE>call</CODE> (see Section&nbsp;<A HREF="#pdf-call">6.1</A>).
-<P>
-<P>
<P>
<!-- ====================================================================== -->
<HR>
<A NAME="5."></A>
<H1>5 - The Application Program Interface</H1>
-<P>
+<A NAME="C API"></A>
This section describes the API for Lua, that is,
-the set of C functions available to the host program to communicate
-with the Lua library.
-The API functions can be classified in the following categories:
-<OL>
-<LI>managing states;
-<LI>exchanging values between C and Lua;
-<LI>executing Lua code;
-<LI>manipulating (reading and writing) Lua objects;
-<LI>calling Lua functions;
-<LI>C functions to be called by Lua;
-<LI>manipulating references to Lua Objects.
-</OL>
+the set of C&nbsp;functions available to the host program to communicate
+with Lua.
All API functions and related types and constants
are declared in the header file <CODE>lua.h</CODE>.
<P>
+Even when we use the term ``function'',
+any facility in the API may be provided as a <EM>macro</EM> instead.
+All such macros use each of its arguments exactly once,
+and so do not generate hidden side-effects.
+<P>
+<P>
<A NAME="mangstate"></A>
<A NAME="5.1"></A>
-<H2>5.1 - Managing States</H2>
+<H2>5.1 - States</H2>
+<P>
+The Lua library is fully reentrant:
+it does not have any global variables.
+<A NAME="state"></A>
The whole state of the Lua interpreter
-(global variables, stack, tag methods, etc)
-is stored in a dynamic structure pointed by<A NAME="lua_state"></A>
-<PRE>
-typedef struct lua_State lua_State;
-extern lua_State *lua_state;
-</PRE>
-The variable <CODE>lua_state</CODE> is the only C global variable in
-the Lua library.
+(global variables, stack, tag methods, etc.)
+is stored in a dynamically allocated structure of type <CODE>lua_State</CODE>; <A NAME="lua_State"></A>
+this state must be passed as the first argument to
+every function in the library (except <CODE>lua_open</CODE> below).
<P>
Before calling any API function,
-this state must be initialized.
-This is done by calling<A NAME="lua_open"></A>
+you must create a state by calling
+<A NAME="lua_open"></A>
<PRE>
-void lua_open (void);
+ lua_State *lua_open (int stacksize);
</PRE>
-This function allocates and initializes some internal structures,
-and defines all pre-defined functions of Lua.
-If <CODE>lua_state</CODE> is already different from <CODE>NULL</CODE>,
-<CODE>lua_open</CODE> has no effect;
-therefore, it is safe to call this function multiple times.
-All standard libraries call <CODE>lua_open</CODE> when they are opened.
+The sole argument to this function is the stack size for the interpreter.
+(Each function call needs one stack position for each argument, local variable,
+and temporary value, plus one position for book-keeping.
+The stack must also have some 20 extra positions available.
+For very small implementations, without recursive functions,
+a stack size of&nbsp;100 should be enough.)
+If <CODE>stacksize</CODE> is zero,
+then a default size of&nbsp;1024 is used.
<P>
-Function <CODE>lua_setstate</CODE> is used to change the current state
-of Lua:<A NAME="lua_setstate"></A>
+To release a state created with <CODE>lua_open</CODE>, call
+<A NAME="lua_close"></A>
<PRE>
-lua_State *lua_setstate (lua_State *st);
+ void lua_close (lua_State *L);
</PRE>
-It sets <CODE>lua_state</CODE> to <CODE>st</CODE> and returns the old state.
+This function destroys all objects in the given Lua environment
+(calling the corresponding garbage-collection tag methods, if any)
+and frees all dynamic memory used by that state.
+Usually, you do not need to call this function,
+because all resources are naturally released when your program ends.
+On the other hand,
+long-running programs -
+like a daemon or a web server -
+might need to release states as soon as they are not needed,
+to avoid growing too big.
+<P>
+With the exception of <CODE>lua_open</CODE>,
+all functions in the Lua API need a state as their first argument.
<P>
-Multiple, independent states may be created.
-For that, you must set <CODE>lua_state</CODE> back to <CODE>NULL</CODE> before
-calling <CODE>lua_open</CODE>.
-An easy way to do that is defining an auxiliary function:
-<PRE>
- lua_State *lua_newstate (void) {
- lua_State *old = lua_setstate(NULL);
- lua_open();
- return lua_setstate(old);
- }
-</PRE>
-This function creates a new state without changing the current state
-of the interpreter.
-Note that any new state is created with all predefined functions,
-but any additional library (such as the standard libraries) must be
-explicitly open in the new state, if needed.
-<P>
-If necessary, a state may be released by calling<A NAME="lua_close"></A>
-<PRE>
-void lua_close (void);
-</PRE>
-This function destroys all objects in the current Lua environment
-(calling the correspondent garbage collector tag methods),
-frees all dynamic memory used by the state,
-and then sets <CODE>lua_state</CODE> to <CODE>NULL</CODE>.
-Usually, there is no need to call this function,
-since these resources are naturally released when the program ends.
-If <CODE>lua_state</CODE> is already <CODE>NULL</CODE>,
-<CODE>lua_close</CODE> has no effect.
-<P>
-If you are using multiple states,
-you may find useful to define the following function,
-which releases a given state:
-<PRE>
- void lua_freestate (lua_State *st) {
- lua_State *old = lua_setstate(st);
- lua_close();
- if (old != st) lua_setstate(old);
- }
-</PRE>
<P>
-<A NAME="valuesCLua"></A>
<A NAME="5.2"></A>
-<H2>5.2 - Exchanging Values between C and Lua</H2>
-Because Lua has no static type system,
-all values passed between Lua and C have type
-<CODE>lua_Object</CODE><A NAME="lua_Object"></A>,
-which works like an abstract type in C that can hold any Lua value.
-Values of type <CODE>lua_Object</CODE> have no meaning outside Lua;
-for instance,
-the comparison of two <CODE>lua_Object's</CODE> is undefined.
-<P>
-To check the type of a <CODE>lua_Object</CODE>,
+<H2>5.2 - The Stack and Indices</H2>
+<P>
+Lua uses a <EM>stack</EM> to pass values to and from C.
+Each element in this stack represents a Lua value
+(nil, number, string, etc.).
+<P>
+For convenience,
+most query operations in the API do not follow a strict stack discipline.
+Instead, they can refer to any element in the stack by using an <EM>index</EM>:
+A positive index represents an <EM>absolute</EM> stack position
+(starting at&nbsp;1, not 0 as in C);
+a negative index represents an <EM>offset</EM> from the top of the stack.
+More specifically, if the stack has <EM>n</EM> elements,
+index&nbsp;1 represents the first element
+(that is, the first element pushed onto the stack),
+and
+index&nbsp;<EM>n</EM> represents the last element;
+index&nbsp;<I>-1</I> also represents the last element
+(that is, the element at the top),
+and index <I>-n</I> represents the first element.
+We say that an index is <EM>valid</EM>
+if it lays between&nbsp;1 and the stack top
+(that is, if <CODE>1 &lt;= abs(index) &lt;= top</CODE>).
+<A NAME="stack index"></A> <A NAME="valid index"></A>
+<P>
+At any time, you can get the index of the top element by calling
+<A NAME="lua_gettop"></A>
+<PRE>
+ int lua_gettop (lua_State *L);
+</PRE>
+Because indices start at&nbsp;1,
+the result of <CODE>lua_gettop</CODE> is equal to the number of elements in the stack
+(and so 0&nbsp;means an empty stack).
+<P>
+When you interact with Lua API,
+<EM>you are responsible for controlling stack overflow</EM>.
+The function <A NAME="lua_stackspace"></A>
+<PRE>
+ int lua_stackspace (lua_State *L);
+</PRE>
+returns the number of stack positions still available.
+Whenever Lua calls C, <A NAME="LUA_MINSTACK"></A>
+it ensures that
+at least <CODE>LUA_MINSTACK</CODE> positions are still available.
+<CODE>LUA_MINSTACK</CODE> is defined in <CODE>lua.h</CODE> and is at least&nbsp;16,
+and so you have to worry about stack space only
+when your code has loops pushing elements onto the stack.
+<P>
+Most query functions accept as indices any value inside the
+available stack space.
+Such indices are called <EM>acceptable indices</EM>.
+More formally, we can define an <A NAME="acceptable index"><EM>acceptable index</EM></A>
+as
+<PRE>
+ (index &lt; 0 &amp;&amp; abs(index) &lt;= top) || (index &gt; 0 &amp;&amp; index &lt;= top + stackspace)
+</PRE>
+Note that 0 is not an acceptable index.
+<P>
+<A NAME="5.3"></A>
+<H2>5.3 - Stack Manipulation</H2>
+The API offers the following functions for basic stack manipulation:
+<A NAME="lua_settop"></A><A NAME="lua_pushvalue"></A>
+<A NAME="lua_remove"></A><A NAME="lua_insert"></A>
+<PRE>
+ void lua_settop (lua_State *L, int index);
+ void lua_pushvalue (lua_State *L, int index);
+ void lua_remove (lua_State *L, int index);
+ void lua_insert (lua_State *L, int index);
+</PRE>
+<P>
+<CODE>lua_settop</CODE> accepts any acceptable index,
+or 0,
+and sets the stack top to that index.
+If the new top is larger than the old one,
+then the new elements are filled with <B>nil</B>.
+If <CODE>index</CODE> is 0, then all stack elements are removed.
+A useful macro defined in the API is
+<PRE>
+ #define lua_pop(L,n) lua_settop(L, -(n)-1)
+</PRE>
+which pops <CODE>n</CODE> elements from the stack.
+<P>
+<CODE>lua_pushvalue</CODE> pushes onto the stack a <EM>copy</EM> of the element
+at the given index.
+<CODE>lua_remove</CODE> removes the element at the given position,
+shifting down the elements on top of that position to fill in the gap.
+<CODE>lua_insert</CODE> moves the top element into the given position,
+shifting up the elements on top of that position to open space.
+These functions accept only valid indices.
+As an example, if the stack starts as <CODE>10 20 30 40 50</CODE>
+(from bottom to top),
+then
+<PRE>
+ lua_pushvalue(L, 3) --&gt; 10 20 30 40 50 30
+ lua_pushvalue(L, -1) --&gt; 10 20 30 40 50 30 30
+ lua_remove(L, -3) --&gt; 10 20 30 40 30 30
+ lua_remove(L, 6) --&gt; 10 20 30 40 30
+ lua_insert(L, 1) --&gt; 30 10 20 30 40
+ lua_insert(L, -1) --&gt; 30 10 20 30 40 (no effect)
+ lua_settop(L, -3) --&gt; 30 10 20
+ lua_settop(L, 6) --&gt; 30 10 20 nil nil nil
+</PRE>
+<P>
+<P>
+<A NAME="5.4"></A>
+<H2>5.4 - Querying the Stack</H2>
+<P>
+To check the type of a stack element,
the following functions are available:
+<A NAME="lua_type"></A><A NAME="lua_tag"></A>
<A NAME="lua_isnil"></A><A NAME="lua_isnumber"></A><A NAME="lua_isstring"></A>
-<A NAME="lua_istable"></A><A NAME="lua_iscfunction"></A><A NAME="lua_isuserdata"></A>
-<A NAME="lua_isfunction"></A>
-<PRE>
-int lua_isnil (lua_Object object);
-int lua_isnumber (lua_Object object);
-int lua_isstring (lua_Object object);
-int lua_istable (lua_Object object);
-int lua_isfunction (lua_Object object);
-int lua_iscfunction (lua_Object object);
-int lua_isuserdata (lua_Object object);
-</PRE>
-These functions return 1 if the object is compatible with the given type,
-and 0 otherwise.
-The function <CODE>lua_isnumber</CODE> accepts numbers and numerical strings,
-whereas
-<CODE>lua_isstring</CODE> accepts strings and numbers (see Section&nbsp;<A HREF="#coercion">4.3</A>),
-and <CODE>lua_isfunction</CODE> accepts Lua functions and C functions.
-<P>
-To get the tag of a <CODE>lua_Object</CODE>,
-the following function is available:
-<A NAME="lua_tag"></A>
-<PRE>
-int lua_tag (lua_Object object);
-</PRE>
-<P>
-To translate a value from type <CODE>lua_Object</CODE> to a specific C type,
-the programmer can use:
-<A NAME="lua_getnumber"></A><A NAME="lua_getstring"></A><A NAME="lua_strlen"></A>
-<A NAME="lua_getcfunction"></A><A NAME="lua_getuserdata"></A>
-<PRE>
-double lua_getnumber (lua_Object object);
-char *lua_getstring (lua_Object object);
-long lua_strlen (lua_Object object);
-lua_CFunction lua_getcfunction (lua_Object object);
-void *lua_getuserdata (lua_Object object);
-</PRE>
-<P>
-<CODE>lua_getnumber</CODE> converts a <CODE>lua_Object</CODE> to a floating-point number.
-This <CODE>lua_Object</CODE> must be a number or a string convertible to number
-(see Section&nbsp;<A HREF="#coercion">4.3</A>); otherwise, <CODE>lua_getnumber</CODE> returns&nbsp;0.
-<P>
-<CODE>lua_getstring</CODE> converts a <CODE>lua_Object</CODE> to a string (<CODE>char*</CODE>).
-This <CODE>lua_Object</CODE> must be a string or a number;
-otherwise, the function returns&nbsp;0 (the <CODE>NULL</CODE> pointer).
-This function does not create a new string,
-but returns a pointer to a string inside the Lua environment.
-Those strings always have a 0 after their last character (like in C),
+<A NAME="lua_istable"></A>
+<A NAME="lua_isfunction"></A><A NAME="lua_iscfunction"></A><A NAME="lua_isuserdata"></A>
+<PRE>
+ int lua_type (lua_State *L, int index);
+ int lua_tag (lua_State *L, int index);
+ int lua_isnil (lua_State *L, int index);
+ int lua_isnumber (lua_State *L, int index);
+ int lua_isstring (lua_State *L, int index);
+ int lua_istable (lua_State *L, int index);
+ int lua_isfunction (lua_State *L, int index);
+ int lua_iscfunction (lua_State *L, int index);
+ int lua_isuserdata (lua_State *L, int index);
+</PRE>
+These functions can be called with any acceptable index.
+<P>
+<CODE>lua_type</CODE> returns one of the following constants,
+according to the type of the given object:
+<CODE>LUA_TNIL</CODE>,
+<CODE>LUA_TNUMBER</CODE>,
+<CODE>LUA_TSTRING</CODE>,
+<CODE>LUA_TTABLE</CODE>,
+<CODE>LUA_TFUNCTION</CODE>,
+<CODE>LUA_TUSERDATA</CODE>.
+If the index is non-valid
+(that is, if that stack position is ``empty''),
+then <CODE>lua_type</CODE> returns <CODE>LUA_TNONE</CODE>.
+These constants can be converted to strings with
+<A NAME="lua_typename"></A>
+<PRE>
+ const char *lua_typename (lua_State *L, int t);
+</PRE>
+where <CODE>t</CODE> is a type returned by <CODE>lua_type</CODE>.
+The strings returned by <CODE>lua_typename</CODE> are
+<CODE>"nil"</CODE>, <CODE>"number"</CODE>, <CODE>"string"</CODE>, <CODE>"table"</CODE>,
+<CODE>"function"</CODE>, <CODE>"userdata"</CODE>, and <CODE>"no value"</CODE>,
+<P>
+<CODE>lua_tag</CODE> returns the tag of a value,
+or <CODE>LUA_NOTAG</CODE> for a non-valid index.
+<P>
+The <CODE>lua_is*</CODE> functions return&nbsp;1 if the object is compatible
+with the given type, and 0 otherwise.
+They always return 0 for a non-valid index.
+<CODE>lua_isnumber</CODE> accepts numbers and numerical strings,
+<CODE>lua_isstring</CODE> accepts strings and numbers (see Section&nbsp;<A HREF="#coercion">4.2</A>),
+and <CODE>lua_isfunction</CODE> accepts both Lua functions and C&nbsp;functions.
+To distinguish between Lua functions and C&nbsp;functions,
+you should use <CODE>lua_iscfunction</CODE>.
+To distinguish between numbers and numerical strings,
+you can use <CODE>lua_type</CODE>.
+<P>
+The API also has functions to compare two values in the stack:
+<A NAME="lua_equal"></A>
+<A NAME="lua_lessthan"></A>
+<PRE>
+ int lua_equal (lua_State *L, int index1, int index2);
+ int lua_lessthan (lua_State *L, int index1, int index2);
+</PRE>
+These functions are equivalent to their counterparts in Lua.
+Specifically, <CODE>lua_lessthan</CODE> is equivalent to the <CODE>lt_event</CODE>
+described in Section&nbsp;<A HREF="#tag-method">4.8</A>.
+Both functions return 0 if any of the indices are non-valid.
+<P>
+To translate a value in the stack to a specific C&nbsp;type,
+you can use the following conversion functions:
+<A NAME="lua_tonumber"></A><A NAME="lua_tostring"></A><A NAME="lua_strlen"></A>
+<A NAME="lua_tocfunction"></A><A NAME="lua_touserdata"></A>
+<PRE>
+ double lua_tonumber (lua_State *L, int index);
+ const char *lua_tostring (lua_State *L, int index);
+ size_t lua_strlen (lua_State *L, int index);
+ lua_CFunction lua_tocfunction (lua_State *L, int index);
+ void *lua_touserdata (lua_State *L, int index);
+</PRE>
+These functions can be called with any acceptable index.
+When called with a non-valid index,
+they act as if the given value had an incorrect type.
+<P>
+<CODE>lua_tonumber</CODE> converts the value at the given index
+to a floating-point number.
+This value must be a number or a string convertible to number
+(see Section&nbsp;<A HREF="#coercion">4.2</A>); otherwise, <CODE>lua_tonumber</CODE> returns&nbsp;0.
+<P>
+<CODE>lua_tostring</CODE> converts a Lua value to a string
+(<CODE>const char*</CODE>).
+This value must be a string or a number;
+otherwise, the function returns <CODE>NULL</CODE>.
+This function returns a pointer to a string inside the Lua environment.
+Those strings always have a zero (<CODE>'\0'</CODE>) after their last character (as in C),
but may contain other zeros in their body.
If you do not know whether a string may contain zeros,
-you can use <CODE>lua_strlen</CODE> to get the actual length.
+you should use <CODE>lua_strlen</CODE> to get its actual length.
Because Lua has garbage collection,
-there is no guarantee that the pointer returned by <CODE>lua_getstring</CODE>
-will be valid after the block ends
-(see Section&nbsp;<A HREF="#GC">5.3</A>).
+there is no guarantee that the pointer returned by <CODE>lua_tostring</CODE>
+will be valid after the respective value is removed from the stack.
<P>
-<CODE>lua_getcfunction</CODE> converts a <CODE>lua_Object</CODE> to a C function.
-This <CODE>lua_Object</CODE> must have type <EM>CFunction</EM>;
-otherwise, <CODE>lua_getcfunction</CODE> returns 0 (the <CODE>NULL</CODE> pointer).
-The type <CODE>lua_CFunction</CODE> is explained in Section&nbsp;<A HREF="#LuacallC">5.7</A>.
+<CODE>lua_tocfunction</CODE> converts a value in the stack to a C&nbsp;function.
+This value must be a C&nbsp;function;
+otherwise, <CODE>lua_tocfunction</CODE> returns <CODE>NULL</CODE>.
+The type <CODE>lua_CFunction</CODE> is explained in Section&nbsp;<A HREF="#LuacallC">5.13</A>.
<P>
-<CODE>lua_getuserdata</CODE> converts a <CODE>lua_Object</CODE> to <CODE>void*</CODE>.
-This <CODE>lua_Object</CODE> must have type <EM>userdata</EM>;
-otherwise, <CODE>lua_getuserdata</CODE> returns 0 (the <CODE>NULL</CODE> pointer).
+<CODE>lua_touserdata</CODE> converts a value to <CODE>void*</CODE>.
+This value must have type <EM>userdata</EM>;
+otherwise, <CODE>lua_touserdata</CODE> returns <CODE>NULL</CODE>.
<P>
-<A NAME="GC"></A>
-<A NAME="5.3"></A>
-<H2>5.3 - Garbage Collection</H2>
-Because Lua has automatic memory management and garbage collection,
-a <CODE>lua_Object</CODE> has a limited scope,
-and is only valid inside the <EM>block</EM> where it has been created.
-A C function called from Lua is a block,
-and its parameters are valid only until its end.
-It is good programming practice to convert Lua objects to C values
-as soon as they are available,
-and never to store <CODE>lua_Object</CODE>s in C global variables.
-<P>
-A garbage collection cycle can be forced by:
-<A NAME="lua_collectgarbage"></A>
-<PRE>
-long lua_collectgarbage (long limit);
-</PRE>
-This function returns the number of objects collected.
-The argument <CODE>limit</CODE> makes the next cycle occur only
-after that number of new objects have been created.
-If <CODE>limit</CODE>=0, then Lua uses an adaptive heuristics to set this limit.
-<P>
-<P>
-All communication between Lua and C is done through two
-abstract data types, called <A NAME="lua2C"><EM>lua2C</EM></A> and <A NAME="C2lua"><EM>C2lua</EM></A>.
-The first one, as the name implies, is used to pass values
-from Lua to C:
-parameters when Lua calls C and results when C calls Lua.
-The structure C2lua is used in the reverse direction:
-parameters when C calls Lua and results when Lua calls C.
-<P>
-The structure lua2C is an abstract array,
-which can be indexed with the function:
-<A NAME="lua_lua2C"></A>
-<PRE>
-lua_Object lua_lua2C (int number);
-</PRE>
-where <CODE>number</CODE> starts with 1.
-When called with a number larger than the array size,
-this function returns <CODE>LUA_NOOBJECT</CODE><A NAME="LUA_NOOBJECT"></A>.
-In this way, it is possible to write C functions that receive
-a variable number of parameters,
-and to call Lua functions that return a variable number of results.
-Note that the structure lua2C cannot be directly modified by C code.
-<P>
-The second structure, C2lua, is an abstract stack.
-Pushing elements into this stack
-is done with the following functions:
+<P>
+<P>
+<A NAME="5.5"></A>
+<H2>5.5 - Pushing values onto the Stack</H2>
+<P>
+The API has the following functions to
+push C&nbsp;values onto the stack:
<A NAME="lua_pushnumber"></A><A NAME="lua_pushlstring"></A><A NAME="lua_pushstring"></A>
<A NAME="lua_pushcfunction"></A><A NAME="lua_pushusertag"></A>
-<A NAME="lua_pushnil"></A><A NAME="lua_pushobject"></A>
<A NAME="pushing"></A>
-<A NAME="lua_pushuserdata"></A>
-<PRE>
-void lua_pushnumber (double n);
-void lua_pushlstring (char *s, long len);
-void lua_pushstring (char *s);
-void lua_pushusertag (void *u, int tag);
-void lua_pushnil (void);
-void lua_pushobject (lua_Object object);
-void lua_pushcfunction (lua_CFunction f); /* macro */
-</PRE>
-All of them receive a C value,
-convert it to a corresponding <CODE>lua_Object</CODE>,
-and leave the result on the top of C2lua.
-In particular, functions <CODE>lua_pushlstring</CODE> and <CODE>lua_pushstring</CODE>
-make an internal copy of the given string.
-Function <CODE>lua_pushstring</CODE> can only be used to push proper C strings
-(that is, strings that do not contain zeros and end with a zero);
-otherwise you should use the more generic <CODE>lua_pushlstring</CODE>.
-The function
-<A NAME="lua_pop"></A>
-<PRE>
-lua_Object lua_pop (void);
-</PRE>
-returns a reference to the object at the top of the C2lua stack,
-and pops it.
-<P>
-As a general rule, all API functions pop from the stack
-all elements they use.
+<A NAME="lua_pushnil"></A><A NAME="lua_pushuserdata"></A>
+<PRE>
+ void lua_pushnumber (lua_State *L, double n);
+ void lua_pushlstring (lua_State *L, const char *s, size_t len);
+ void lua_pushstring (lua_State *L, const char *s);
+ void lua_pushusertag (lua_State *L, void *u, int tag);
+ void lua_pushnil (lua_State *L);
+ void lua_pushcfunction (lua_State *L, lua_CFunction f);
+</PRE>
+These functions receive a C&nbsp;value,
+convert it to a corresponding Lua value,
+and push the result onto the stack.
+In particular, <CODE>lua_pushlstring</CODE> and <CODE>lua_pushstring</CODE>
+make an <EM>internal copy</EM> of the given string.
+<CODE>lua_pushstring</CODE> can only be used to push proper C&nbsp;strings
+(that is, strings that end with a zero and do not contain embedded zeros);
+otherwise you should use the more general <CODE>lua_pushlstring</CODE>,
+which accepts an explicit size.
+<P>
+<P>
+<A NAME="GC"></A>
+<A NAME="5.6"></A>
+<H2>5.6 - Garbage Collection</H2>
+<P>
+Lua uses two numbers to control its garbage collection.
+One number counts how many bytes of dynamic memory Lua is using,
+and the other is a threshold.
+(This internal byte counter kept by Lua is not completely acurate;
+it is just a lower bound, usually within&nbsp;10% of the correct value.)
+When the number of bytes crosses the threshold,
+Lua runs a garbage-collection cycle,
+which reclaims the memory of all ``dead'' objects
+(that is, objects no longer accessible from Lua).
+The byte counter is corrected,
+and then the threshold is reset to twice the value of the byte counter.
+<P>
+You can access the current values of these two numbers through the
+following functions:
+<A NAME="lua_getgcthreshold"></A> <A NAME="lua_getgccount"></A>
+<PRE>
+ int lua_getgccount (lua_State *L);
+ int lua_getgcthreshold (lua_State *L);
+</PRE>
+Both return their respective values in Kbytes.
+You can change the threshold value with
+<A NAME="lua_setgcthreshold"></A>
+<PRE>
+ void lua_setgcthreshold (lua_State *L, int newthreshold);
+</PRE>
+Again, the <CODE>newthreshold</CODE> value is given in Kbytes.
+When you call this function,
+Lua sets the new threshold and checks it against the byte counter.
+If the new threshold is smaller than the byte counter,
+then Lua immediately runs the garbage collector;
+after the collection,
+a new threshold is set according to the previous rule.
+<P>
+If you want to change the adaptative behavior of the garbage collector,
+you can use the garbage-collection tag method for <B>nil</B>
+to set your own threshold
+(the tag method is called after Lua resets the threshold).
+<P>
+<P>
+<A NAME="C-tags"></A>
+<A NAME="5.7"></A>
+<H2>5.7 - Userdata and Tags</H2>
<P>
Because userdata are objects,
the function <CODE>lua_pushusertag</CODE> may create a new userdata.
If Lua has a userdata with the given value (<CODE>void*</CODE>) and tag,
-that userdata is pushed.
+then that userdata is pushed.
Otherwise, a new userdata is created, with the given value and tag.
If this function is called with
<CODE>tag</CODE> equal to <CODE>LUA_ANYTAG</CODE><A NAME="LUA_ANYTAG"></A>,
@@ -1462,230 +1757,361 @@ with tag equal to 0.
<P>
Userdata can have different tags,
whose semantics are only known to the host program.
-Tags are created with the function:
+Tags are created with the function
<A NAME="lua_newtag"></A>
<PRE>
-int lua_newtag (void);
+ int lua_newtag (lua_State *L);
</PRE>
The function <CODE>lua_settag</CODE> changes the tag of
-the object on the top of C2lua (and pops it);
-the object must be a userdata or a table.
+the object on top of the stack (without popping it):
<A NAME="lua_settag"></A>
<PRE>
-void lua_settag (int tag);
+ void lua_settag (lua_State *L, int tag);
</PRE>
-<CODE>tag</CODE> must be a value created with <CODE>lua_newtag</CODE>.
+The object must be a userdata or a table;
+the given <CODE>tag</CODE> must be a value created with <CODE>lua_newtag</CODE>.
<P>
-When C code calls Lua repeatedly, as in a loop,
-objects returned by these calls can accumulate,
-and may cause a stack overflow.
-To avoid this,
-nested blocks can be defined with the functions:
-<PRE>
-void lua_beginblock (void);
-void lua_endblock (void);
-</PRE>
-After the end of the block,
-all <CODE>lua_Object</CODE>'s created inside it are released.
-The use of explicit nested blocks is good programming practice
-and is strongly encouraged.
-<P>
-<A NAME="5.4"></A>
-<H2>5.4 - Executing Lua Code</H2>
+<A NAME="luado"></A>
+<A NAME="5.8"></A>
+<H2>5.8 - Executing Lua Code</H2>
A host program can execute Lua chunks written in a file or in a string
-using the following functions:
+by using the following functions:
<A NAME="lua_dofile"></A><A NAME="lua_dostring"></A><A NAME="lua_dobuffer"></A>
<PRE>
-int lua_dofile (char *filename);
-int lua_dostring (char *string);
-int lua_dobuffer (char *buff, int size, char *name);
+ int lua_dofile (lua_State *L, const char *filename);
+ int lua_dostring (lua_State *L, const char *string);
+ int lua_dobuffer (lua_State *L, const char *buff,
+ size_t size, const char *name);
</PRE>
-All these functions return an error code:
-0, in case of success; non zero, in case of errors.
-More specifically, <CODE>lua_dofile</CODE> returns 2 if for any reason
-it could not open the file.
+These functions return
+0 in case of success, or one of the following error codes if they fail:
+<UL>
+<LI><A NAME="LUA_ERRRUN"><TT>LUA_ERRRUN</TT></A> -
+error while running the chunk.
+<LI><A NAME="LUA_ERRSYNTAX"><TT>LUA_ERRSYNTAX</TT></A> -
+syntax error during pre-compilation.
+<LI><A NAME="LUA_ERRMEM"><TT>LUA_ERRMEM</TT></A> -
+memory allocation error.
+For such errors, Lua does not call <CODE>_ERRORMESSAGE</CODE> (see Section&nbsp;<A HREF="#error">4.7</A>).
+<LI><A NAME="LUA_ERRERR"><TT>LUA_ERRERR</TT></A> -
+error while running <CODE>_ERRORMESSAGE</CODE>.
+For such errors, Lua does not call <CODE>_ERRORMESSAGE</CODE> again, to avoid loops.
+<LI><A NAME="LUA_ERRFILE"><TT>LUA_ERRFILE</TT></A> -
+error opening the file (only for <CODE>lua_dofile</CODE>).
+In this case,
+you may want to
+check <CODE>errno</CODE>,
+call <CODE>strerror</CODE>,
+or call <CODE>perror</CODE> to tell the user what went wrong.
+</UL>
+These constants are defined in <CODE>lua.h</CODE>.
+<P>
When called with argument <CODE>NULL</CODE>,
<CODE>lua_dofile</CODE> executes the <CODE>stdin</CODE> stream.
-Functions <CODE>lua_dofile</CODE> and <CODE>lua_dobuffer</CODE>
+<CODE>lua_dofile</CODE> and <CODE>lua_dobuffer</CODE>
are both able to execute pre-compiled chunks.
They automatically detect whether the chunk is text or binary,
and load it accordingly (see program <A NAME="luac"><TT><A HREF="luac.html">luac</A></TT></A>).
-Function <CODE>lua_dostring</CODE> executes only source code.
+<CODE>lua_dostring</CODE> executes only source code,
+given in textual form.
<P>
-The third parameter to <CODE>lua_dobuffer</CODE> (<CODE>name</CODE>)
+The third parameter to <CODE>lua_dobuffer</CODE>
is the ``name of the chunk'',
-used in error messages and debug information.
+which is used in error messages and debug information.
If <CODE>name</CODE> is <CODE>NULL</CODE>,
-Lua gives a default name to the chunk.
+then Lua gives a default name to the chunk.
+<P>
+These functions push onto the stack
+any values eventually returned by the chunk.
+A chunk may return any number of values;
+Lua takes care that these values fit into the stack space,
+but after the call the responsibility is back to you.
+If you need to push other elements after calling any of these functions,
+and you want to ``play safe'',
+you must either check the stack space
+with <CODE>lua_stackspace</CODE>
+or remove the returned elements
+from the stack (if you do not need them).
+For instance, the following code
+loads a chunk in a file and discards all results returned by this chunk,
+leaving the stack as it was before the call:
+<PRE>
+ {
+ int oldtop = lua_gettop(L);
+ lua_dofile(L, filename);
+ lua_settop(L, oldtop);
+ }
+</PRE>
<P>
-These functions return, in structure lua2C,
-any values eventually returned by the chunks.
-They also empty the stack C2lua.
<P>
+<A NAME="5.9"></A>
+<H2>5.9 - Manipulating Global Variables in Lua</H2>
<P>
-<A NAME="5.5"></A>
-<H2>5.5 - Manipulating Lua Objects</H2>
-To read the value of any global Lua variable,
-one uses the function:
+To read the value of a global Lua variable,
+you call
<A NAME="lua_getglobal"></A>
<PRE>
-lua_Object lua_getglobal (char *varname);
+ void lua_getglobal (lua_State *L, const char *varname);
</PRE>
-As in Lua, this function may trigger a tag method.
-To read the real value of any global variable,
+which pushes onto the stack the value of the given variable.
+As in Lua, this function may trigger a tag method
+for the ``getglobal'' event (see Section&nbsp;<A HREF="#tag-method">4.8</A>).
+To read the real value of a global variable,
without invoking any tag method,
-use the <EM>raw</EM> version:
-<A NAME="lua_rawgetglobal"></A>
-<PRE>
-lua_Object lua_rawgetglobal (char *varname);
-</PRE>
+use <CODE>lua_rawget</CODE> over the table of globals
+(see below).
<P>
-To store a value previously pushed onto C2lua in a global variable,
-there is the function:
+To store a value in a global variable,
+you call
<A NAME="lua_setglobal"></A>
<PRE>
-void lua_setglobal (char *varname);
+ void lua_setglobal (lua_State *L, const char *varname);
</PRE>
-As in Lua, this function may trigger a tag method.
-To set the real value of any global variable,
+which pops from the stack the value to be stored in the given variable.
+As in Lua, this function may trigger a tag method
+for the ``setglobal'' event (see Section&nbsp;<A HREF="#tag-method">4.8</A>).
+To set the real value of a global variable,
without invoking any tag method,
-use the <EM>raw</EM> version:
-<A NAME="lua_rawgetglobal"></A>
+use <CODE>lua_rawset</CODE> over the table of globals
+(see below).
+<P>
+All global variables are kept in an ordinary Lua table.
+You can get this table calling
+<A NAME="lua_getglobals"></A>
<PRE>
-void lua_rawsetglobal (char *varname);
+ void lua_getglobals (lua_State *L);
</PRE>
+which pushes the current table of globals onto the stack.
+To set another table as the table of globals,
+you call
+<A NAME="lua_setglobals"></A>
+<PRE>
+ void lua_setglobals (lua_State *L);
+</PRE>
+The table to be used is popped from the stack.
+<P>
+<A NAME="5.10"></A>
+<H2>5.10 - Manipulating Tables in Lua</H2>
+Lua tables can also be manipulated through the API.
<P>
-Tables can also be manipulated via the API.
-The function
+To read the value of in a table,
+the table must reside somewhere in the stack.
+With this set,
+you call
<A NAME="lua_gettable"></A>
<PRE>
-lua_Object lua_gettable (void);
+ void lua_gettable (lua_State *L, int index);
</PRE>
-pops a table and an index from the stack C2lua,
-and returns the contents of the table at that index.
-As in Lua, this operation may trigger a tag method.
-To get the real value of any table index,
+where <CODE>index</CODE> refers to the table.
+<CODE>lua_gettable</CODE> pops a key from the stack,
+and returns (on the stack) the contents of the table at that key.
+As in Lua, this operation may trigger a tag method
+for the ``gettable'' event.
+To get the real value of any table key,
without invoking any tag method,
use the <EM>raw</EM> version:
-<A NAME="lua_rawgetglobal"></A>
+<A NAME="lua_rawget"></A>
<PRE>
-lua_Object lua_rawgettable (void);
+ void lua_rawget (lua_State *L, int index);
</PRE>
<P>
-To store a value in an index,
-the program must push the table, the index,
-and the value onto C2lua,
-and then call the function
+To store a value into a table that resides somewhere in the stack,
+you push the key and the value onto the stack
+(in this order),
+and then call
<A NAME="lua_settable"></A>
<PRE>
-void lua_settable (void);
+ void lua_settable (lua_State *L, int index);
</PRE>
-Again, the tag method for ``settable'' may be called.
+where <CODE>index</CODE> refers to the table.
+<CODE>lua_settable</CODE> pops from the stack both the key and the value.
+As in Lua, this operation may trigger a tag method
+for the ``settable'' event.
To set the real value of any table index,
without invoking any tag method,
use the <EM>raw</EM> version:
-<A NAME="lua_rawsettable"></A>
+<A NAME="lua_rawset"></A>
<PRE>
-void lua_rawsettable (void);
+ void lua_rawset (lua_State *L, int index);
</PRE>
<P>
Finally, the function
-<A NAME="lua_createtable"></A>
+<A NAME="lua_newtable"></A>
<PRE>
-lua_Object lua_createtable (void);
+ void lua_newtable (lua_State *L);
</PRE>
-creates and returns a new, empty table.
+creates a new, empty table and pushes it onto the stack.
<P>
+<A NAME="5.11"></A>
+<H2>5.11 - Using Tables as Arrays</H2>
+The API has functions that help to use Lua tables as arrays,
+that is,
+tables indexed by numbers only:
+<A NAME="lua_rawgeti"></A>
+<A NAME="lua_rawseti"></A>
+<A NAME="lua_getn"></A>
+<PRE>
+ void lua_rawgeti (lua_State *L, int index, int n);
+ void lua_rawseti (lua_State *L, int index, int n);
+ int lua_getn (lua_State *L, int index);
+</PRE>
<P>
-<A NAME="5.6"></A>
-<H2>5.6 - Calling Lua Functions</H2>
-Functions defined in Lua by a chunk
+<CODE>lua_rawgeti</CODE> gets the value of the <EM>n</EM>-th element of the table
+at stack position <CODE>index</CODE>.
+<P>
+<CODE>lua_rawseti</CODE> sets the value of the <EM>n</EM>-th element of the table
+at stack position <CODE>index</CODE> to the value at the top of the stack.
+<P>
+<CODE>lua_getn</CODE> returns the number of elements in the table
+at stack position <CODE>index</CODE>.
+This number is the value of the table field <CODE>n</CODE>,
+if it has a numeric value,
+or
+the largest numerical index with a non-nil value in the table.
+<P>
+<A NAME="5.12"></A>
+<H2>5.12 - Calling Lua Functions</H2>
+<P>
+Functions defined in Lua
+(and C&nbsp;functions registered in Lua)
can be called from the host program.
This is done using the following protocol:
-first, the arguments to the function are pushed onto C2lua
-(see Section&nbsp;<A HREF="#pushing">5.3</A>), in direct order, i.e., the first argument is pushed first.
-Then, the function is called using
-<A NAME="lua_callfunction"></A>
-<PRE>
-int lua_callfunction (lua_Object function);
-</PRE>
-This function returns an error code:
-0, in case of success; non zero, in case of errors.
-Finally, the results (a Lua function may return many values)
-are returned in structure lua2C,
-and can be retrieved with the macro <CODE>lua_getresult</CODE>,
-<A NAME="lua_getresult"></A>
-which is just another name to function <CODE>lua_lua2C</CODE>.
-Note that function <CODE>lua_callfunction</CODE>
-pops all elements from the C2lua stack.
-<P>
-The following example shows how a C program may do the
+First, the function to be called is pushed onto the stack;
+then, the arguments to the function are pushed
+(see Section&nbsp;<A HREF="#pushing">5.5</A>) in <EM>direct order</EM>, that is, the first argument is pushed first.
+Finally, the function is called using
+<A NAME="lua_call"></A>
+<PRE>
+ int lua_call (lua_State *L, int nargs, int nresults);
+</PRE>
+This function returns the same error codes as <CODE>lua_dostring</CODE> and
+friends (see Section&nbsp;<A HREF="#luado">5.8</A>).
+If you want to propagate the error,
+instead of returning an error code,
+use
+<A NAME="lua_rawcall"></A>
+<PRE>
+ void lua_rawcall (lua_State *L, int nargs, int nresults);
+</PRE>
+<P>
+In both functions,
+<CODE>nargs</CODE> is the number of arguments that you pushed onto the stack.
+All arguments and the function value are popped from the stack,
+and the function results are pushed.
+The number of results are adjusted (see Section&nbsp;<A HREF="#adjust">4.3</A>) to <CODE>nresults</CODE>,
+unless <CODE>nresults</CODE> is <A NAME="LUA_MULTRET"><TT>LUA_MULTRET</TT></A>.
+In that case, <EM>all</EM> results from the function are pushed.
+The function results are pushed in direct order
+(the first result is pushed first),
+so that after the call the last result is on the top.
+<P>
+The following example shows how the host program may do the
equivalent to the Lua code:
<PRE>
- a,b = f("how", t.x, 4)
+ a,b = f("how", t.x, 4)
</PRE>
+Here it is in&nbsp;C:
<PRE>
- lua_pushstring("how"); /* 1st argument */
- lua_pushobject(lua_getglobal("t")); /* push value of global 't' */
- lua_pushstring("x"); /* push the string 'x' */
- lua_pushobject(lua_gettable()); /* push result of t.x (2nd arg) */
- lua_pushnumber(4); /* 3rd argument */
- lua_callfunction(lua_getglobal("f")); /* call Lua function */
- lua_pushobject(lua_getresult(1)); /* push first result of the call */
- lua_setglobal("a"); /* set global variable 'a' */
- lua_pushobject(lua_getresult(2)); /* push second result of the call */
- lua_setglobal("b"); /* set global variable 'b' */
+ lua_getglobal(L, "t"); /* global `t' (for later use) */
+ lua_getglobal(L, "f"); /* function to be called */
+ lua_pushstring(L, "how"); /* 1st argument */
+ lua_pushstring(L, "x"); /* push the string `x' */
+ lua_gettable(L, -4); /* push result of t.x (2nd arg) */
+ lua_pushnumber(L, 4); /* 3rd argument */
+ lua_call(L, 3, 2); /* call function with 3 arguments and 2 results */
+ lua_setglobal(L, "b"); /* set global variable `b' */
+ lua_setglobal(L, "a"); /* set global variable `a' */
+ lua_pop(L, 1); /* remove `t' from the stack */
</PRE>
+Notice that the code above is ``balanced'':
+at its end ,the stack is back to its original configuration.
+This is considered good programming practice.
+<P>
+<P>
<P>
-Some special Lua functions have exclusive interfaces.
-A C function can generate a Lua error calling the function
+Some special Lua functions have their own C&nbsp;interfaces.
+The host program can generate a Lua error calling the function
<A NAME="lua_error"></A>
<PRE>
-void lua_error (char *message);
+ void lua_error (lua_State *L, const char *message);
</PRE>
This function never returns.
-If the C function has been called from Lua,
+If <CODE>lua_error</CODE> is called from a C&nbsp;function that has been called from Lua,
then the corresponding Lua execution terminates,
as if an error had occurred inside Lua code.
-Otherwise, the whole host program terminates with a call to <CODE>exit(1)</CODE>.
-The <CODE>message</CODE> is passed to the error handler function,
-<CODE>_ERRORMESSAGE</CODE>.
+Otherwise, the whole host program terminates with a call to
+<CODE>exit(EXIT_FAILURE)</CODE>.
+Before terminating execution,
+the <CODE>message</CODE> is passed to the error handler function,
+<CODE>_ERRORMESSAGE</CODE> (see Section&nbsp;<A HREF="#error">4.7</A>).
If <CODE>message</CODE> is <CODE>NULL</CODE>,
then <CODE>_ERRORMESSAGE</CODE> is not called.
<P>
-Tag methods can be changed with: <A NAME="lua_settagmethod"></A>
+<P>
+Tag methods can be changed with <A NAME="lua_settagmethod"></A>
<PRE>
-lua_Object lua_settagmethod (int tag, char *event);
+ void lua_settagmethod (lua_State *L, int tag, const char *event);
</PRE>
-The first parameter is the tag,
-and the second is the event name (see Section&nbsp;<A HREF="#tag-method">4.8</A>);
-the new method is pushed from C2lua.
-This function returns a <CODE>lua_Object</CODE>,
-which is the old tag method value.
-To get just the current value of a tag method,
+The second parameter is the tag,
+and the third is the event name (see Section&nbsp;<A HREF="#tag-method">4.8</A>);
+the new method is popped from the stack.
+To get the current value of a tag method,
use the function <A NAME="lua_gettagmethod"></A>
<PRE>
-lua_Object lua_gettagmethod (int tag, char *event);
+ void lua_gettagmethod (lua_State *L, int tag, const char *event);
</PRE>
<P>
It is also possible to copy all tag methods from one tag
to another: <A NAME="lua_copytagmethods"></A>
<PRE>
-int lua_copytagmethods (int tagto, int tagfrom);
+ int lua_copytagmethods (lua_State *L, int tagto, int tagfrom);
</PRE>
This function returns <CODE>tagto</CODE>.
<P>
<P>
+You can traverse a table with the function <A NAME="lua_next"></A>
+<PRE>
+ int lua_next (lua_State *L, int index);
+</PRE>
+where <CODE>index</CODE> refers to the table to be traversed.
+The function pops a key from the stack,
+and pushes a key-value pair from the table
+(the ``next'' pair after the given key).
+If there are no more elements, then the function returns 0
+(and pushes nothing).
+A typical traversal looks like this:
+<PRE>
+ /* table is in the stack at index `t' */
+ lua_pushnil(L); /* first key */
+ while (lua_next(L, t) != 0) {
+ /* `key' is at index -2 and `value' at index -1 */
+ printf("%s - %s\n",
+ lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1)));
+ lua_pop(L, 1); /* removes `value'; keeps `index' for next iteration */
+ }
+</PRE>
+<P>
+The function <A NAME="lua_concat"></A>
+<PRE>
+ void lua_concat (lua_State *L, int n);
+</PRE>
+concatenates the <CODE>n</CODE> values at the top of the stack,
+pops them, and leaves the result at the top;
+<CODE>n</CODE>&nbsp;must be at least 2.
+Concatenation is done following the usual semantics of Lua
+(see Section&nbsp;<A HREF="#concat">4.5.5</A>).
+<P>
+<P>
<A NAME="LuacallC"></A>
-<A NAME="5.7"></A>
-<H2>5.7 - C Functions</H2>
-To register a C function to Lua,
-there is the following macro:
+<A NAME="5.13"></A>
+<H2>5.13 - Defining C Functions</H2>
+To register a C&nbsp;function to Lua,
+there is the following convenience macro:
<A NAME="lua_register"></A>
<PRE>
-#define lua_register(n,f) (lua_pushcfunction(f), lua_setglobal(n))
-/* char *n; */
-/* lua_CFunction f; */
+ #define lua_register(L, n, f) (lua_pushcfunction(L, f), lua_setglobal(L, n))
+ /* const char *n; */
+ /* lua_CFunction f; */
</PRE>
which receives the name the function will have in Lua,
and a pointer to the function.
@@ -1693,110 +2119,185 @@ This pointer must have type <CODE>lua_CFunction</CODE>,
which is defined as
<A NAME="lua_CFunction"></A>
<PRE>
-typedef void (*lua_CFunction) (void);
+ typedef int (*lua_CFunction) (lua_State *L);
</PRE>
-that is, a pointer to a function with no parameters and no results.
+that is, a pointer to a function with integer result and a single argument,
+a Lua environment.
<P>
In order to communicate properly with Lua,
-a C function must follow a protocol,
-which defines the way parameters and results are passed.
-<P>
-A C function receives its arguments in structure lua2C;
-to access them, it uses the macro <CODE>lua_getparam</CODE>, <A NAME="lua_getparam"></A>
-again just another name for <CODE>lua_lua2C</CODE>.
-To return values, a C function just pushes them onto the stack C2lua,
-in direct order (see Section&nbsp;<A HREF="#valuesCLua">5.2</A>).
-Like a Lua function, a C function called by Lua can also return
+a C&nbsp;function must follow the following protocol,
+which defines the way parameters and results are passed:
+A C&nbsp;function receives its arguments from Lua in the stack,
+in direct order (the first argument is pushed first).
+To return values to Lua, a C&nbsp;function just pushes them onto the stack,
+in direct order (the first result is pushed first),
+and returns the number of results.
+Like a Lua function, a C&nbsp;function called by Lua can also return
many results.
<P>
-When a C function is created,
-it is possible to associate some <EM>upvalues</EM> to it,
-thus creating a C closure;
-then these values are passed to the function whenever it is called,
-as common arguments.
-To associate upvalues to a function,
-first these values must be pushed on C2lua.
-Then the function
-<A NAME="lua_pushcclosure"></A>
-<PRE>
-void lua_pushcclosure (lua_CFunction fn, int n);
-</PRE>
-is used to put the C function on C2lua,
-with the argument <CODE>n</CODE> telling how many upvalues must be
-associated with the function;
+As an example, the following function receives a variable number
+of numerical arguments and returns their average and sum:
+<PRE>
+ static int foo (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ double sum = 0;
+ int i;
+ for (i = 1; i &lt;= n; i++) {
+ if (!lua_isnumber(L, i))
+ lua_error(L, "incorrect argument to function `average'");
+ sum += lua_tonumber(L, i);
+ }
+ lua_pushnumber(L, sum/n); /* first result */
+ lua_pushnumber(L, sum); /* second result */
+ return 2; /* number of results */
+ }
+</PRE>
+This function may be registered in Lua as `<CODE>average</CODE>' by calling
+<PRE>
+ lua_register(L, "average", foo);
+</PRE>
+<P>
+<P>
+When a C&nbsp;function is created,
+it is possible to associate some <EM>upvalues</EM> to it
+(see Section&nbsp;<A HREF="#upvalue">4.6</A>),
+thus creating a <A NAME="C closure"><EM>C&nbsp;closure</EM></A>;
+these values are passed to the function whenever it is called,
+as ordinary arguments.
+To associate upvalues to a C&nbsp;function,
+first these values should be pushed onto the stack.
+Then the function <A NAME="lua_pushcclosure"></A>
+<PRE>
+ void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
+</PRE>
+is used to push the C&nbsp;function onto the stack,
+with the argument <CODE>n</CODE> telling how many upvalues should be
+associated with the function
+(these upvalues are popped from the stack);
in fact, the macro <CODE>lua_pushcfunction</CODE> is defined as
<CODE>lua_pushcclosure</CODE> with <CODE>n</CODE> set to 0.
-Then, any time the function is called,
-these upvalues are inserted as the first arguments to the function,
-before the actual arguments provided in the call.
-<P>
-For some examples of C functions, see files <CODE>lstrlib.c</CODE>,
-<CODE>liolib.c</CODE> and <CODE>lmathlib.c</CODE> in the official Lua distribution.
-<P>
-<A NAME="5.8"></A>
-<H2>5.8 - References to Lua Objects</H2>
-<P>
-As noted in Section&nbsp;<A HREF="#GC">5.3</A>, <CODE>lua_Object</CODE>s are volatile.
-If the C code needs to keep a <CODE>lua_Object</CODE>
-outside block boundaries,
-then it must create a <A NAME="reference"><EM>reference</EM></A> to the object.
-The routines to manipulate references are the following:
+Then, whenever the C&nbsp;function is called,
+these upvalues are inserted as the <EM>last</EM> arguments to the function,
+after the actual arguments provided in the call.
+This makes it easy to get the upvalues without knowing how many arguments
+the function received (recall that functions in Lua can receive any number of
+arguments): The <EM>i</EM>-th upvalue is in the stack at index <I>i-(n+1)</I>,
+where <EM>n</EM> is the number of upvalues.
+<P>
+For more examples of C&nbsp;functions and closures, see files
+<CODE>lbaselib.c</CODE>, <CODE>liolib.c</CODE>, <CODE>lmathlib.c</CODE>, and <CODE>lstrlib.c</CODE>
+in the official Lua distribution.
+<P>
+<A NAME="5.14"></A>
+<H2>5.14 - References to Lua Objects</H2>
+<P>
+If the C&nbsp;code needs to keep a Lua value
+outside the life span of a C&nbsp;function,
+then it must create a <A NAME="reference"><EM>reference</EM></A> to the value.
+The functions to manipulate references are the following:
<A NAME="lua_ref"></A><A NAME="lua_getref"></A>
<A NAME="lua_unref"></A>
<PRE>
-int lua_ref (int lock);
-lua_Object lua_getref (int ref);
-void lua_unref (int ref);
+ int lua_ref (lua_State *L, int lock);
+ int lua_getref (lua_State *L, int ref);
+ void lua_unref (lua_State *L, int ref);
</PRE>
-The function <CODE>lua_ref</CODE> creates a reference
-to the object that is on the top of the stack,
+<P>
+<CODE>lua_ref</CODE> pops a value from
+the stack, creates a reference to it,
and returns this reference.
-If <CODE>lock</CODE> is true, the object is <EM>locked</EM>:
+For a <B>nil</B> value,
+the reference is always <CODE>LUA_REFNIL</CODE>.<A NAME="LUA_REFNIL"></A>
+(<CODE>lua.h</CODE> also defines a constant <CODE>LUA_NOREF</CODE> <A NAME="LUA_NOREF"></A>
+that
+is different from any valid reference.)
+If <CODE>lock</CODE> is not zero, then the object is <EM>locked</EM>:
this means the object will not be garbage collected.
-Note that an unlocked reference may be garbage collected.
-Whenever the referenced object is needed,
+<EM>Unlocked references may be garbage collected</EM>.
+<P>
+Whenever the referenced object is needed in&nbsp;C,
a call to <CODE>lua_getref</CODE>
-returns a handle to it;
+pushes that object onto the stack;
if the object has been collected,
-<CODE>lua_getref</CODE> returns <CODE>LUA_NOOBJECT</CODE>.
+<CODE>lua_getref</CODE> returns 0 (and does not push anything).
<P>
When a reference is no longer needed,
-it can be released with a call to <CODE>lua_unref</CODE>.
+it should be released with a call to <CODE>lua_unref</CODE>.
+<P>
+<P>
+<h3>Registry</h3>
<P>
+When Lua starts, it registers a table at position
+<A NAME="LUA_REFREGISTRY"><TT>LUA_REFREGISTRY</TT></A>.
+It can be accessed through the macro<A NAME="lua_getregistry"></A>
+<PRE>
+ #define lua_getregistry(L) lua_getref(L, LUA_REFREGISTRY)
+</PRE>
+This table can be used by C&nbsp;libraries as a general registry mechanism.
+Any C&nbsp;library can store data into this table,
+as long as it chooses a key different from other libraries.
<P>
<P>
<!-- ====================================================================== -->
<HR>
<A NAME="6."></A>
-<H1>6 - Predefined Functions and Libraries</H1>
+<H1>6 - Standard Libraries</H1>
<P>
-The set of <A NAME="predefined functions">predefined functions</A> in Lua is small but powerful.
-Most of them provide features that allow some degree of
-<A NAME="reflexivity">reflexivity</A> in the language.
-Some of these features cannot be simulated with the rest of the
-language nor with the standard Lua API.
-Others are just convenient interfaces to common API functions.
-<P>
-The libraries, on the other hand, provide useful routines
+The standard libraries provide useful functions
that are implemented directly through the standard API.
Therefore, they are not necessary to the language,
-and are provided as separate C modules.
-Currently, there are three standard libraries:
+and are provided as separate C&nbsp;modules.
+Currently, Lua has the following standard libraries:
<UL>
+<LI>basic library;
<LI>string manipulation;
<LI>mathematical functions (sin, log, etc);
<LI>input and output (plus some system facilities).
</UL>
To have access to these libraries,
-the C host program must call the functions
+the C&nbsp;host program must call the functions
+<CODE>lua_baselibopen</CODE>,
<CODE>lua_strlibopen</CODE>, <CODE>lua_mathlibopen</CODE>,
-and <CODE>lua_iolibopen</CODE>, declared in <CODE>lualib.h</CODE>.
-<A NAME="lua_strlibopen"></A><A NAME="lua_mathlibopen"></A><A NAME="lua_iolibopen"></A>
-<P>
+and <CODE>lua_iolibopen</CODE>, which are declared in <CODE>lualib.h</CODE>.
+<A NAME="lua_baselibopen"></A>
+<A NAME="lua_strlibopen"></A>
+<A NAME="lua_mathlibopen"></A>
+<A NAME="lua_iolibopen"></A>
<P>
<A NAME="predefined"></A>
<A NAME="6.1"></A>
-<H2>6.1 - Predefined Functions</H2>
+<H2>6.1 - Basic Functions</H2>
+<P>
+The basic library provides some core functions to Lua.
+Therefore, if you do not include this library in your application,
+you should check carefully whether you need to provide some alternative
+implementation for some facilities.
+(For instance,
+without function <CODE>_ERRORMESSAGE</CODE>,
+Lua is unable to show error messages.)
+<P>
+<A NAME="alert"></A>
+<h3> <TT>_ALERT (message)</TT></h3><A NAME="alert"></A>
+Prints its only string argument to <A NAME="stderr"><TT>stderr</TT></A>.
+All error messages in Lua are printed through the function stored
+in the <CODE>_ALERT</CODE> global variable
+(see Section&nbsp;<A HREF="#error">4.7</A>).
+Therefore, a program may assign another function to this variable
+to change the way such messages are shown
+(for instance, for systems without <CODE>stderr</CODE>).
+<P>
+<h3> <TT>assert (v [, message])</TT></h3><A NAME="assert"></A>
+Issues an <EM>``assertion failed!''</EM> error
+when its argument <CODE>v</CODE> is <B>nil</B>.
+This function is equivalent to the following Lua function:
+<PRE>
+ function assert (v, m)
+ if not v then
+ m = m or ""
+ error("assertion failed! " .. m)
+ end
+ end
+</PRE>
<P>
<h3> <TT>call (func, arg [, mode [, errhandler]])</TT></h3><A NAME="call"></A>
<A NAME="pdf-call"></A>
@@ -1805,29 +2306,13 @@ Calls function <CODE>func</CODE> with
the arguments given by the table <CODE>arg</CODE>.
The call is equivalent to
<PRE>
- func(arg[1], arg[2], ..., arg[n])
+ func(arg[1], arg[2], ..., arg[n])
</PRE>
where <CODE>n</CODE> is the result of <CODE>getn(arg)</CODE> (see Section&nbsp;<A HREF="#getn">6.1</A>).
+All results from <CODE>func</CODE> are simply returned by <CODE>call</CODE>.
<P>
By default,
-all results from <CODE>func</CODE> are just returned by the call.
-If the string <CODE>mode</CODE> contains <CODE>"p"</CODE>,
-the results are <EM>packed</EM> in a single table.<A NAME="packed results"></A>
-That is, <CODE>call</CODE> returns just one table;
-at index <CODE>n</CODE>, the table has the total number of results
-from the call;
-the first result is at index 1, etc.
-For instance, the following calls produce the following results:
-<PRE>
-a = call(sin, {5}) --&gt; a = 0.0871557 = sin(5)
-a = call(max, {1,4,5; n=2}) --&gt; a = 4 (only 1 and 4 are arguments)
-a = call(max, {1,4,5; n=2}, "p") --&gt; a = {4; n=1}
-t = {x=1}
-a = call(next, {t,nil;n=2}, "p") --&gt; a={"x", 1; n=2}
-</PRE>
-<P>
-By default,
-if an error occurs during the function call,
+if an error occurs during the call to <CODE>func</CODE>,
the error is propagated.
If the string <CODE>mode</CODE> contains <CODE>"x"</CODE>,
then the call is <EM>protected</EM>.<A NAME="protected calls"></A>
@@ -1836,96 +2321,168 @@ regardless of what happens during the call.
Instead, it returns <B>nil</B> to signal the error
(besides calling the appropriated error handler).
<P>
-If provided,
-<CODE>errhandler</CODE> is temporarily set as the error function
-<CODE>_ERRORMESSAGE</CODE>, while <CODE>func</CODE> runs.
+If <CODE>errhandler</CODE> is provided,
+the error function <CODE>_ERRORMESSAGE</CODE> is temporarily set to <CODE>errhandler</CODE>,
+while <CODE>func</CODE> runs.
In particular, if <CODE>errhandler</CODE> is <B>nil</B>,
no error messages will be issued during the execution of the called function.
<P>
<h3> <TT>collectgarbage ([limit])</TT></h3><A NAME="collectgarbage"></A>
-Forces a garbage collection cycle.
-Returns the number of objects collected.
-An optional argument, <CODE>limit</CODE>, is a number that
-makes the next cycle occur only after that number of new
-objects have been created.
-If <CODE>limit</CODE> is absent or equal to 0,
-Lua uses an adaptive algorithm to set this limit.
-<CODE>collectgarbage</CODE> is equivalent to
-the API function <CODE>lua_collectgarbage</CODE>.
+<P>
+Sets the garbage-collection threshold for the given limit
+(in Kbytes), and checks it against the byte counter.
+If the new threshold is smaller than the byte counter,
+then Lua immediately runs the garbage collector (see Section&nbsp;<A HREF="#GC">5.6</A>).
+If <CODE>limit</CODE> is absent, it defaults to zero
+(thus forcing a garbage-collection cycle).
+<P>
+<h3> <TT>copytagmethods (tagto, tagfrom)</TT></h3>
+<A NAME="copytagmethods"></A>
+Copies all tag methods from one tag to another;
+returns <CODE>tagto</CODE>.
<P>
<h3> <TT>dofile (filename)</TT></h3><A NAME="dofile"></A>
Receives a file name,
-opens the file, and executes the file contents as a Lua chunk,
+opens the named file, and executes its contents as a Lua chunk,
or as pre-compiled chunks.
When called without arguments,
<CODE>dofile</CODE> executes the contents of the standard input (<CODE>stdin</CODE>).
If there is any error executing the file,
then <CODE>dofile</CODE> returns <B>nil</B>.
Otherwise, it returns the values returned by the chunk,
-or a non <B>nil</B> value if the chunk returns no values.
-It issues an error when called with a non string argument.
-<CODE>dofile</CODE> is equivalent to the API function <CODE>lua_dofile</CODE>.
+or a non-<B>nil</B> value if the chunk returns no values.
+It issues an error when called with a non-string argument.
<P>
<h3> <TT>dostring (string [, chunkname])</TT></h3><A NAME="dostring"></A>
Executes a given string as a Lua chunk.
If there is any error executing the string,
-<CODE>dostring</CODE> returns <B>nil</B>.
+then <CODE>dostring</CODE> returns <B>nil</B>.
Otherwise, it returns the values returned by the chunk,
-or a non <B>nil</B> value if the chunk returns no values.
-An optional second parameter (<CODE>chunkname</CODE>)
+or a non-<B>nil</B> value if the chunk returns no values.
+The optional parameter <CODE>chunkname</CODE>
is the ``name of the chunk'',
used in error messages and debug information.
-<CODE>dostring</CODE> is equivalent to the API function <CODE>lua_dostring</CODE>.
+<P>
+<A NAME="pdf-error"></A>
+<h3> <TT>error (message)</TT></h3><A NAME="error"></A>
+Calls the error handler (see Section&nbsp;<A HREF="#error">4.7</A>) and then terminates
+the last protected function called
+(in&nbsp;C: <CODE>lua_dofile</CODE>, <CODE>lua_dostring</CODE>,
+<CODE>lua_dobuffer</CODE>, or <CODE>lua_callfunction</CODE>;
+in Lua: <CODE>dofile</CODE>, <CODE>dostring</CODE>, or <CODE>call</CODE> in protected mode).
+If <CODE>message</CODE> is <B>nil</B>, then the error handler is not called.
+Function <CODE>error</CODE> never returns.
+<P>
+<h3> <TT>foreach (table, func)</TT></h3><A NAME="foreach"></A>
+Executes the given <CODE>func</CODE> over all elements of <CODE>table</CODE>.
+For each element, the function is called with the index and
+respective value as arguments.
+If the function returns any non-<B>nil</B> value,
+then the loop is broken, and this value is returned
+as the final value of <CODE>foreach</CODE>.
+This function could be defined in Lua:
+<PRE>
+ function foreach (t, f)
+ for i, v in t do
+ local res = f(i, v)
+ if res then return res end
+ end
+ end
+</PRE>
+<P>
+The behavior of <CODE>foreach</CODE> is <EM>undefined</EM> if you change
+the table <CODE>t</CODE> during the traversal.
+<P>
+<P>
+<h3> <TT>foreachi (table, func)</TT></h3><A NAME="foreachi"></A>
+Executes the given <CODE>func</CODE> over the
+numerical indices of <CODE>table</CODE>.
+For each index, the function is called with the index and
+respective value as arguments.
+Indices are visited in sequential order,
+from&nbsp;1 to <CODE>n</CODE>,
+where <CODE>n</CODE> is the result of <CODE>getn(table)</CODE> (see Section&nbsp;<A HREF="#getn">6.1</A>).
+If the function returns any non-<B>nil</B> value,
+then the loop is broken, and this value is returned
+as the final value of <CODE>foreachi</CODE>.
+This function could be defined in Lua:
+<PRE>
+ function foreachi (t, f)
+ for i=1,getn(t) do
+ local res = f(i, t[i])
+ if res then return res end
+ end
+ end
+</PRE>
+<P>
+<P>
+<h3> <TT>getglobal (name)</TT></h3><A NAME="getglobal"></A>
+Gets the value of a global variable,
+or calls a tag method for ``getglobal''.
+Its full semantics is explained in Section&nbsp;<A HREF="#tag-method">4.8</A>.
+The string <CODE>name</CODE> does not need to be a
+syntactically valid variable name.
+<P>
+<A NAME="getn"></A>
+<h3> <TT>getn (table)</TT></h3><A NAME="getn"></A>
+Returns the ``size'' of a table, when seen as a list.
+If the table has an <CODE>n</CODE> field with a numeric value,
+this value is the ``size'' of the table.
+Otherwise, the ``size'' is the largest numerical index with a non-nil
+value in the table.
+This function could be defined in Lua:
+<PRE>
+ function getn (t)
+ if type(t.n) == "number" then return t.n end
+ local max = 0
+ for i, _ in t do
+ if type(i) == "number" and i&gt;max then max=i end
+ end
+ return max
+ end
+</PRE>
+<P>
+<h3> <TT>gettagmethod (tag, event)</TT></h3>
+<A NAME="gettagmethod"></A>
+Returns the current tag method
+for a given pair <EM>(tag, event)</EM>.
+This function cannot be used to get a tag method for the ``gc'' event.
+(Such tag methods can only be manipulated by C&nbsp;code.)
+<P>
+<h3> <TT>globals ([table])</TT></h3><A NAME="globals"></A>
+Returns the current table of globals.
+If the argument <CODE>table</CODE> is given,
+then it also sets this table as the table of globals.
<P>
<A NAME="pdf-newtag"></A>
<h3> <TT>newtag ()</TT></h3><A NAME="newtag"></A>
Returns a new tag.
-<CODE>newtag</CODE> is equivalent to the API function <CODE>lua_newtag</CODE>.
<P>
-<h3> <TT>next (table, index)</TT></h3><A NAME="next"></A>
+<h3> <TT>next (table, [index])</TT></h3><A NAME="next"></A>
Allows a program to traverse all fields of a table.
Its first argument is a table and its second argument
is an index in this table.
-It returns the next index of the table and the
+<CODE>next</CODE> returns the next index of the table and the
value associated with the index.
When called with <B>nil</B> as its second argument,
-the function returns the first index
-of the table (and its associated value).
+<CODE>next</CODE> returns the first index
+of the table and its associated value.
When called with the last index,
or with <B>nil</B> in an empty table,
-it returns <B>nil</B>.
+<CODE>next</CODE> returns <B>nil</B>.
+If the second argument is absent, then it is interpreted as <B>nil</B>.
<P>
Lua has no declaration of fields;
semantically, there is no difference between a
field not present in a table or a field with value <B>nil</B>.
-Therefore, the function only considers fields with non <B>nil</B> values.
+Therefore, <CODE>next</CODE> only considers fields with non-<B>nil</B> values.
The order in which the indices are enumerated is not specified,
<EM>even for numeric indices</EM>
(to traverse a table in numeric order,
-use a counter or the function <CODE>foreachi</CODE>).
-If the table indices are modified in any way during a traversal,
-the semantics of <CODE>next</CODE> is undefined.
-<P>
-This function cannot be written with the standard API.
-<P>
-<h3> <TT>nextvar (name)</TT></h3><A NAME="nextvar"></A>
-This function is similar to the function <CODE>next</CODE>,
-but iterates instead over the global variables.
-Its single argument is the name of a global variable,
-or <B>nil</B> to get a first name.
-Similarly to <CODE>next</CODE>, it returns the name of another variable
-and its value,
-or <B>nil</B> if there are no more variables.
-There can be no creation of new global variables during the traversal;
-otherwise the semantics of <CODE>nextvar</CODE> is undefined.
-<P>
-This function cannot be written with the standard API.
+use a numerical <B>for</B> or the function <CODE>foreachi</CODE>).
<P>
-<h3> <TT>tostring (e)</TT></h3><A NAME="tostring"></A>
-Receives an argument of any type and
-converts it to a string in a reasonable format.
-For complete control on how numbers are converted,
-use function <CODE>format</CODE>.
+The behavior of <CODE>next</CODE> is <EM>undefined</EM> if you change
+the table during the traversal.
<P>
<h3> <TT>print (e1, e2, ...)</TT></h3><A NAME="print"></A>
Receives any number of arguments,
@@ -1935,342 +2492,225 @@ but only as a quick way to show a value,
for instance for debugging.
See Section&nbsp;<A HREF="#libio">6.4</A> for functions for formatted output.
<P>
-<A NAME="alert"></A>
-<h3> <TT>_ALERT (message)</TT></h3><A NAME="alert"></A>
-Prints its only string argument to <A NAME="stderr"><TT>stderr</TT></A>.
-All error messages in Lua are printed through this function.
-Therefore, a program may redefine it
-to change the way such messages are shown
-(for instance, for systems without <CODE>stderr</CODE>).
-<P>
-<h3> <TT>tonumber (e [, base])</TT></h3><A NAME="tonumber"></A>
-Receives one argument,
-and tries to convert it to a number.
-If the argument is already a number or a string convertible
-to a number, then <CODE>tonumber</CODE> returns that number;
-otherwise, it returns <B>nil</B>.
-<P>
-An optional argument specifies the base to interpret the numeral.
-The base may be any integer between 2 and 36 inclusive.
-In bases above 10, the letter `A' (either upper or lower case)
-represents 10, `B' represents 11, and so forth, with `Z' representing 35.
-<P>
-In base 10 (the default), the number may have a decimal part,
-as well as an optional exponent part (see Section&nbsp;<A HREF="#coercion">4.3</A>).
-In other bases, only integers are accepted.
-<P>
-<A NAME="pdf-type"></A>
-<h3> <TT>type (v)</TT></h3><A NAME="type"></A>
-Allows Lua to test the type of a value.
-It receives one argument, and returns its type, coded as a string.
-The possible results of this function are
-<CODE>"nil"</CODE> (a string, not the value <B>nil</B>),
-<CODE>"number"</CODE>,
-<CODE>"string"</CODE>,
-<CODE>"table"</CODE>,
-<CODE>"function"</CODE>,
-and <CODE>"userdata"</CODE>.
-<P>
-<h3> <TT>tag (v)</TT></h3><A NAME="tag"></A>
-Allows Lua to test the tag of a value (see Section&nbsp;<A HREF="#TypesSec">3</A>).
-It receives one argument, and returns its tag (a number).
-<CODE>tag</CODE> is equivalent to the API function <CODE>lua_tag</CODE>.
-<P>
-<h3> <TT>settag (t, tag)</TT></h3><A NAME="settag"></A>
-Sets the tag of a given table (see Section&nbsp;<A HREF="#TypesSec">3</A>).
-<CODE>tag</CODE> must be a value created with <CODE>newtag</CODE>
-(see Section&nbsp;<A HREF="#pdf-newtag">6.1</A>).
-It returns the value of its first argument (the table).
-For security reasons,
-it is impossible to change the tag of a userdata from Lua.
-<P>
-<P>
-<h3> <TT>assert (v [, message])</TT></h3><A NAME="assert"></A>
-Issues an <EM>``assertion failed!''</EM> error
-when its argument is <B>nil</B>.
-This function is equivalent to the following Lua function:
-<PRE>
- function assert (v, m)
- if not v then
- m = m or ""
- error("assertion failed! " .. m)
- end
- end
-</PRE>
-<P>
-<A NAME="pdf-error"></A>
-<h3> <TT>error (message)</TT></h3><A NAME="error"></A>
-Calls the error handler and then terminates
-the last protected function called
-(in&nbsp;C: <CODE>lua_dofile</CODE>, <CODE>lua_dostring</CODE>,
-<CODE>lua_dobuffer</CODE>, or <CODE>lua_callfunction</CODE>;
-in Lua: <CODE>dofile</CODE>, <CODE>dostring</CODE>, or <CODE>call</CODE> in protected mode).
-If <CODE>message</CODE> is <B>nil</B>, the error handler is not called.
-Function <CODE>error</CODE> never returns.
-<CODE>error</CODE> is equivalent to the API function <CODE>lua_error</CODE>.
-<P>
-<h3> <TT>rawgettable (table, index)</TT></h3><A NAME="rawgettable"></A>
+<h3> <TT>rawget (table, index)</TT></h3><A NAME="rawget"></A>
Gets the real value of <CODE>table[index]</CODE>,
without invoking any tag method.
<CODE>table</CODE> must be a table,
and <CODE>index</CODE> is any value different from <B>nil</B>.
<P>
-<h3> <TT>rawsettable (table, index, value)</TT></h3><A NAME="rawsettable"></A>
+<h3> <TT>rawset (table, index, value)</TT></h3><A NAME="rawset"></A>
Sets the real value of <CODE>table[index]</CODE> to <CODE>value</CODE>,
without invoking any tag method.
<CODE>table</CODE> must be a table,
<CODE>index</CODE> is any value different from <B>nil</B>,
and <CODE>value</CODE> is any Lua value.
<P>
-<h3> <TT>rawsetglobal (name, value)</TT></h3><A NAME="rawsetglobal"></A>
-Assigns the given value to a global variable.
-The string <CODE>name</CODE> does not need to be a
-syntactically valid variable name.
-Therefore,
-this function can set global variables with strange names like
-<CODE>"m v 1"</CODE> or <CODE>34</CODE>.
-Function <CODE>rawsetglobal</CODE> returns the value of its second argument.
-<P>
<h3> <TT>setglobal (name, value)</TT></h3><A NAME="setglobal"></A>
-Assigns the given value to a global variable,
-or calls a tag method.
+Sets the named global variable to the given value,
+or calls a tag method for ``setglobal''.
Its full semantics is explained in Section&nbsp;<A HREF="#tag-method">4.8</A>.
The string <CODE>name</CODE> does not need to be a
syntactically valid variable name.
-Function <CODE>setglobal</CODE> returns the value of its second argument.
<P>
-<h3> <TT>rawgetglobal (name)</TT></h3><A NAME="rawgetglobal"></A>
-Retrieves the value of a global variable.
-The string <CODE>name</CODE> does not need to be a
-syntactically valid variable name.
-<P>
-<h3> <TT>getglobal (name)</TT></h3><A NAME="getglobal"></A>
-Retrieves the value of a global variable,
-or calls a tag method.
-Its full semantics is explained in Section&nbsp;<A HREF="#tag-method">4.8</A>.
-The string <CODE>name</CODE> does not need to be a
-syntactically valid variable name.
+<h3> <TT>settag (t, tag)</TT></h3><A NAME="settag"></A>
+Sets the tag of a given table (see Section&nbsp;<A HREF="#TypesSec">3</A>).
+<CODE>tag</CODE> must be a value created with <CODE>newtag</CODE>
+(see Section&nbsp;<A HREF="#pdf-newtag">6.1</A>).
+<CODE>settag</CODE> returns the value of its first argument (the table).
+For the safety of host programs,
+it is impossible to change the tag of a userdata from Lua.
<P>
<h3> <TT>settagmethod (tag, event, newmethod)</TT></h3>
<A NAME="settagmethod"></A>
-Sets a new tag method to the given pair <EM>(tag, event)</EM>.
-It returns the old method.
+Sets a new tag method to the given pair <EM>(tag, event)</EM> and
+returns the old method.
If <CODE>newmethod</CODE> is <B>nil</B>,
-<CODE>settagmethod</CODE> restores the default behavior for the given event.
-<P>
-<h3> <TT>gettagmethod (tag, event)</TT></h3>
-<A NAME="gettagmethod"></A>
-Returns the current tag method
-for a given pair <EM>(tag, event)</EM>.
-<P>
-<h3> <TT>copytagmethods (tagto, tagfrom)</TT></h3>
-<A NAME="copytagmethods"></A>
-Copies all tag methods from one tag to another;
-it returns <CODE>tagto</CODE>.
-<P>
-<A NAME="getn"></A>
-<h3> <TT>getn (table)</TT></h3><A NAME="getn"></A>
-Returns the ``size'' of a table, when seen as a list.
-If the table has an <CODE>n</CODE> field with a numeric value,
-this is its ``size''.
-Otherwise, the size is the largest numerical index with a non-nil
-value in the table.
-This function could be defined in Lua:
-<PRE>
- function getn (t)
- if type(t.n) == 'number' then return t.n end
- local max = 0
- local i = next(t, nil)
- while i do
- if type(i) == 'number' and i&gt;max then max=i end
- i = next(t, i)
- end
- return max
- end
-</PRE>
+then <CODE>settagmethod</CODE> restores the default behavior for the given event.
+This function cannot be used to set a tag method for the ``gc'' event.
+(Such tag methods can only be manipulated by C&nbsp;code.)
<P>
+<h3> <TT>sort (table [, comp])</TT></h3><A NAME="sort"></A>
+Sorts table elements in a given order, <EM>in-place</EM>,
+from <CODE>table[1]</CODE> to <CODE>table[n]</CODE>,
+where <CODE>n</CODE> is the result of <CODE>getn(table)</CODE> (see Section&nbsp;<A HREF="#getn">6.1</A>).
+If <CODE>comp</CODE> is given,
+then it must be a function that receives two table elements,
+and returns true (that is, a value different from <B>nil</B>)
+when the first is less than the second
+(so that <CODE>not comp(a[i+1], a[i])</CODE> will be true after the sort).
+If <CODE>comp</CODE> is not given,
+then the standard Lua operator <CODE>&lt;</CODE> is used instead.
<P>
-<h3> <TT>foreach (table, function)</TT></h3><A NAME="foreach"></A>
-Executes the given <CODE>function</CODE> over all elements of <CODE>table</CODE>.
-For each element, the function is called with the index and
-respective value as arguments.
-If the function returns any non-<B>nil</B> value,
-the loop is broken, and the value is returned
-as the final value of <CODE>foreach</CODE>.
+The sort algorithm is <EM>not</EM> stable
+(that is, elements considered equal by the given order
+may have their relative positions changed by the sort).
<P>
-This function could be defined in Lua:
-<PRE>
- function foreach (t, f)
- local i, v = next(t, nil)
- while i do
- local res = f(i, v)
- if res then return res end
- i, v = next(t, i)
- end
- end
-</PRE>
+<A NAME="pdf-tag"></A>
+<h3> <TT>tag (v)</TT></h3><A NAME="tag"></A>
+Allows Lua programs to test the tag of a value (see Section&nbsp;<A HREF="#TypesSec">3</A>).
+It receives one argument, and returns its tag (a number).
<P>
+<h3> <TT>tonumber (e [, base])</TT></h3><A NAME="tonumber"></A>
+Tries to convert its argument to a number.
+If the argument is already a number or a string convertible
+to a number, then <CODE>tonumber</CODE> returns that number;
+otherwise, it returns <B>nil</B>.
<P>
-<h3> <TT>foreachi (table, function)</TT></h3><A NAME="foreachi"></A>
-Executes the given <CODE>function</CODE> over the
-numerical indices of <CODE>table</CODE>.
-For each index, the function is called with the index and
-respective value as arguments.
-Indices are visited in sequential order,
-from 1 to <CODE>n</CODE>,
-where <CODE>n</CODE> is the result of <CODE>getn(table)</CODE> (see Section&nbsp;<A HREF="#getn">6.1</A>).
-If the function returns any non-<B>nil</B> value,
-the loop is broken, and the value is returned
-as the final value of <CODE>foreachi</CODE>.
+An optional argument specifies the base to interpret the numeral.
+The base may be any integer between 2 and 36, inclusive.
+In bases above&nbsp;10, the letter `A' (either upper or lower case)
+represents&nbsp;10, `B' represents&nbsp;11, and so forth, with `Z' representing 35.
+In base 10 (the default), the number may have a decimal part,
+as well as an optional exponent part (see Section&nbsp;<A HREF="#coercion">4.2</A>).
+In other bases, only unsigned integers are accepted.
<P>
-This function could be defined in Lua:
-<PRE>
- function foreachi (t, f)
- local i, n = 1, getn(t)
- while i &lt;= n do
- local res = f(i, t[i])
- if res then return res end
- i = i+1
- end
- end
-</PRE>
+<h3> <TT>tostring (e)</TT></h3><A NAME="tostring"></A>
+Receives an argument of any type and
+converts it to a string in a reasonable format.
+For complete control of how numbers are converted,
+use function <CODE>format</CODE>.
<P>
-<h3> <TT>foreachvar (function)</TT></h3><A NAME="foreachvar"></A>
-Executes <CODE>function</CODE> over all global variables.
-For each variable,
-the function is called with its name and its value as arguments.
-If the function returns any non-nil value,
-the loop is broken, and the value is returned
-as the final value of <CODE>foreachvar</CODE>.
<P>
-This function could be defined in Lua:
-<PRE>
- function foreachvar (f)
- local n, v = nextvar(nil)
- while n do
- local res = f(n, v)
- if res then return res end
- n, v = nextvar(n)
- end
- end
-</PRE>
<P>
<h3> <TT>tinsert (table [, pos] , value)</TT></h3><A NAME="tinsert"></A>
<P>
Inserts element <CODE>value</CODE> at table position <CODE>pos</CODE>,
-shifting other elements to open space.
-The default value for <CODE>pos</CODE> is <CODE>n+1</CODE>
-(where <CODE>n</CODE> is the result of <CODE>getn(table)</CODE> (see Section&nbsp;<A HREF="#getn">6.1</A>))
+shifting other elements to open space, if necessary.
+The default value for <CODE>pos</CODE> is <CODE>n+1</CODE>,
+where <CODE>n</CODE> is the result of <CODE>getn(table)</CODE> (see Section&nbsp;<A HREF="#getn">6.1</A>),
so that a call <CODE>tinsert(t,x)</CODE> inserts <CODE>x</CODE> at the end
of table <CODE>t</CODE>.
-<P>
-This function also sets or increments the field <CODE>n</CODE> of the table,
+This function also sets or increments the field <CODE>n</CODE> of the table
to <CODE>n+1</CODE>.
-<P>
This function is equivalent to the following Lua function,
-except that the table accesses are all raw (that is, without tag methods):
-<PRE>
- function tinsert (t, ...)
- local pos, value
- local n = getn(t)
- if arg.n == 1 then
- pos = n+1; value = arg[1]
- else
- pos = arg[1]; value = arg[2]
- end
- t.n = n+1;
- while n &gt;= pos do
- t[n+1] = t[n]
- n = n-1
- end
- t[pos] = value
- end
+except that the table accesses are all <EM>raw</EM>
+(that is, without tag methods):
+<PRE>
+ function tinsert (t, ...)
+ local pos, value
+ local n = getn(t)
+ if arg.n == 1 then
+ pos, value = n+1, arg[1]
+ else
+ pos, value = arg[1], arg[2]
+ end
+ t.n = n+1;
+ for i=n,pos,-1 do
+ t[i+1] = t[i]
+ end
+ t[pos] = value
+ end
</PRE>
<P>
<h3> <TT>tremove (table [, pos])</TT></h3><A NAME="tremove"></A>
<P>
Removes from <CODE>table</CODE> the element at position <CODE>pos</CODE>,
-shifting other elements to close the space.
+shifting other elements to close the space, if necessary.
Returns the value of the removed element.
-The default value for <CODE>pos</CODE> is <CODE>n</CODE>
-(where <CODE>n</CODE> is the result of <CODE>getn(table)</CODE> (see Section&nbsp;<A HREF="#getn">6.1</A>)),
+The default value for <CODE>pos</CODE> is <CODE>n</CODE>,
+where <CODE>n</CODE> is the result of <CODE>getn(table)</CODE> (see Section&nbsp;<A HREF="#getn">6.1</A>),
so that a call <CODE>tremove(t)</CODE> removes the last element
of table <CODE>t</CODE>.
-<P>
-This function also sets or decrements the field <CODE>n</CODE> of the table,
+This function also sets or decrements the field <CODE>n</CODE> of the table
to <CODE>n-1</CODE>.
<P>
This function is equivalent to the following Lua function,
-except that the table accesses are all raw (that is, without tag methods):
-<PRE>
- function tremove (t, pos)
- local n = getn(t)
- pos = pos or n
- local value = t[pos]
- if n&lt;=0 then return end
- while pos &lt; n do
- t[pos] = t[pos+1]
- pos = pos+1
- end
- t[n] = nil
- t.n = n-1
- return value
- end
+except that the table accesses are all <EM>raw</EM>
+(that is, without tag methods):
+<PRE>
+ function tremove (t, pos)
+ local n = getn(t)
+ if n&lt;=0 then return end
+ pos = pos or n
+ local value = t[pos]
+ for i=pos,n-1 do
+ t[i] = t[i+1]
+ end
+ t[n] = nil
+ t.n = n-1
+ return value
+ end
</PRE>
<P>
-<h3> <TT>sort (table [, comp])</TT></h3><A NAME="sort"></A>
-Sorts table elements in a given order, <EM>in-place</EM>,
-from <CODE>table[1]</CODE> to <CODE>table[n]</CODE>,
-where <CODE>n</CODE> is the result of <CODE>getn(table)</CODE> (see Section&nbsp;<A HREF="#getn">6.1</A>).
-If <CODE>comp</CODE> is given,
-it must be a function that receives two table elements,
-and returns true when the first is less than the second
-(so that <CODE>not comp(a[i+1], a[i])</CODE> will be true after the sort).
-If <CODE>comp</CODE> is not given,
-the standard <CODE>&lt;</CODE> Lua operator is used instead.
-<P>
-Function <CODE>sort</CODE> returns the (sorted) table.
+<A NAME="pdf-type"></A>
+<h3> <TT>type (v)</TT></h3><A NAME="type"></A>
+Allows Lua programs to test the type of a value.
+It receives one argument, and returns its type, coded as a string.
+The possible results of this function are
+<CODE>"nil"</CODE> (a string, not the value <B>nil</B>),
+<CODE>"number"</CODE>,
+<CODE>"string"</CODE>,
+<CODE>"table"</CODE>,
+<CODE>"function"</CODE>,
+and <CODE>"userdata"</CODE>.
<P>
<P>
<A NAME="6.2"></A>
<H2>6.2 - String Manipulation</H2>
This library provides generic functions for string manipulation,
such as finding and extracting substrings and pattern matching.
-When indexing a string, the first character is at position&nbsp;1
+When indexing a string in Lua, the first character is at position&nbsp;1
(not at&nbsp;0, as in C).
+Also,
+indices are allowed to be negative and are intepreted as indexing backwards,
+from the end of the string. Thus, the last character is at position <I>-1</I>,
+and so on.
<P>
-<h3> <TT>strfind (str, pattern [, init [, plain]])</TT></h3>
+<h3> <TT>strbyte (s [, i])</TT></h3><A NAME="strbyte"></A>
+Returns the internal numerical code of the <EM>i</EM>-th character of <CODE>s</CODE>.
+If <CODE>i</CODE> is absent, then it is assumed to be&nbsp;1.
+<CODE>i</CODE> may be negative.
+<P>
+Numerical codes are not necessarily portable across platforms.
+<P>
+<h3> <TT>strchar (i1, i2, ...)</TT></h3><A NAME="strchar"></A>
+Receives 0 or more integers.
+Returns a string with length equal to the number of arguments,
+wherein each character has the internal numerical code equal
+to its correspondent argument.
+<P>
+Numerical codes are not necessarily portable across platforms.
+<P>
+<h3> <TT>strfind (s, pattern [, init [, plain]])</TT></h3>
<A NAME="strfind"></A>
Looks for the first <EM>match</EM> of
-<CODE>pattern</CODE> in <CODE>str</CODE>.
-If it finds one, then it returns the indices on <CODE>str</CODE>
+<CODE>pattern</CODE> in <CODE>s</CODE>.
+If it finds one, then <CODE>strfind</CODE> returns the indices of <CODE>s</CODE>
where this occurrence starts and ends;
otherwise, it returns <B>nil</B>.
-If the pattern specifies captures,
+If the pattern specifies captures (see <CODE>gsub</CODE> below),
the captured strings are returned as extra results.
-A third optional numerical argument specifies where to start the search;
-its default value is 1.
-If <CODE>init</CODE> is negative,
-it is replaced by the length of the string minus its
-absolute value plus 1.
-Therefore, <I>-1</I> points to the last character of <CODE>str</CODE>.
-A value of 1 as a fourth optional argument
+A third, optional numerical argument <CODE>init</CODE> specifies
+where to start the search;
+its default value is&nbsp;1, and may be negative.
+A value of&nbsp;1 as a fourth, optional argument <CODE>plain</CODE>
turns off the pattern matching facilities,
so the function does a plain ``find substring'' operation,
with no characters in <CODE>pattern</CODE> being considered ``magic''.
+Note that if <CODE>plain</CODE> is given, then <CODE>init</CODE> must be given too.
<P>
<h3> <TT>strlen (s)</TT></h3><A NAME="strlen"></A>
Receives a string and returns its length.
+The empty string <CODE>""</CODE> has length 0.
+Embedded zeros are counted,
+and so <CODE>"a\000b\000c"</CODE> has length 5.
+<P>
+<h3> <TT>strlower (s)</TT></h3><A NAME="strlower"></A>
+Receives a string and returns a copy of that string with all
+upper case letters changed to lower case.
+All other characters are left unchanged.
+The definition of what is an upper-case
+letter depends on the current locale.
+<P>
+<h3> <TT>strrep (s, n)</TT></h3><A NAME="strrep"></A>
+Returns a string that is the concatenation of <CODE>n</CODE> copies of
+the string <CODE>s</CODE>.
<P>
<h3> <TT>strsub (s, i [, j])</TT></h3><A NAME="strsub"></A>
Returns another string, which is a substring of <CODE>s</CODE>,
-starting at <CODE>i</CODE> and running until <CODE>j</CODE>.
-If <CODE>i</CODE> or <CODE>j</CODE> are negative,
-they are replaced by the length of the string minus their
-absolute value plus 1.
-Therefore, <I>-1</I> points to the last character of <CODE>s</CODE>
-and <I>-2</I> to the previous one.
-If <CODE>j</CODE> is absent, it is assumed to be equal to <I>-1</I>
+starting at <CODE>i</CODE> and running until <CODE>j</CODE>;
+<CODE>i</CODE> and <CODE>j</CODE> may be negative,
+If <CODE>j</CODE> is absent, then it is assumed to be equal to <I>-1</I>
(which is the same as the string length).
In particular,
the call <CODE>strsub(s,1,j)</CODE> returns a prefix of <CODE>s</CODE>
@@ -2278,13 +2718,6 @@ with length <CODE>j</CODE>,
and the call <CODE>strsub(s, -i)</CODE> returns a suffix of <CODE>s</CODE>
with length <CODE>i</CODE>.
<P>
-<h3> <TT>strlower (s)</TT></h3><A NAME="strlower"></A>
-Receives a string and returns a copy of that string with all
-upper case letters changed to lower case.
-All other characters are left unchanged.
-The definition of what is an upper case
-letter depends on the current locale.
-<P>
<h3> <TT>strupper (s)</TT></h3><A NAME="strupper"></A>
Receives a string and returns a copy of that string with all
lower case letters changed to upper case.
@@ -2292,47 +2725,25 @@ All other characters are left unchanged.
The definition of what is a lower case
letter depends on the current locale.
<P>
-<h3> <TT>strrep (s, n)</TT></h3><A NAME="strrep"></A>
-Returns a string that is the concatenation of <CODE>n</CODE> copies of
-the string <CODE>s</CODE>.
-<P>
-<h3> <TT>strbyte (s [, i])</TT></h3><A NAME="strbyte"></A>
-Returns the internal numerical code of the character <CODE>s[i]</CODE>.
-If <CODE>i</CODE> is absent, then it is assumed to be 1.
-If <CODE>i</CODE> is negative,
-it is replaced by the length of the string minus its
-absolute value plus 1.
-Therefore, <I>-1</I> points to the last character of <CODE>s</CODE>.
-<P>
-Note that numerical codes are not necessarily portable across platforms.
-<P>
-<h3> <TT>strchar (i1, i2, ...)</TT></h3><A NAME="strchar"></A>
-Receives 0 or more integers.
-Returns a string with length equal to the number of arguments,
-wherein each character has the internal numerical code equal
-to its correspondent argument.
-<P>
-Note that numerical codes are not necessarily portable across platforms.
-<P>
<h3> <TT>format (formatstring, e1, e2, ...)</TT></h3><A NAME="format"></A>
<A NAME="format"></A>
Returns a formatted version of its variable number of arguments
following the description given in its first argument (which must be a string).
The format string follows the same rules as the <CODE>printf</CODE> family of
-standard C functions.
+standard C&nbsp;functions.
The only differences are that the options/modifiers
<CODE>*</CODE>, <CODE>l</CODE>, <CODE>L</CODE>, <CODE>n</CODE>, <CODE>p</CODE>,
and <CODE>h</CODE> are not supported,
and there is an extra option, <CODE>q</CODE>.
-This option formats a string in a form suitable to be safely read
+The <CODE>q</CODE> option formats a string in a form suitable to be safely read
back by the Lua interpreter:
The string is written between double quotes,
-and all double quotes, returns and backslashes in the string
+and all double quotes, returns, and backslashes in the string
are correctly escaped when written.
For instance, the call
<PRE>
-format('%q', 'a string with "quotes" and \n new line')
+ format('%q', 'a string with "quotes" and \n new line')
</PRE>
will produce the string:
<PRE>
@@ -2340,7 +2751,7 @@ will produce the string:
new line"
</PRE>
<P>
-Conversions can be applied to the n-th argument in the argument list,
+Conversions can be applied to the <EM>n</EM>-th argument in the argument list,
rather than the next unused argument.
In this case, the conversion character <CODE>%</CODE> is replaced
by the sequence <CODE>%d$</CODE>, where <CODE>d</CODE> is a
@@ -2359,20 +2770,22 @@ the appropriate format string.
For example, <CODE>"%*g"</CODE> can be simulated with
<CODE>"%"..width.."g"</CODE>.
<P>
-<EM>Note: function <TT>format</TT> can only be used with strings that do not contain zeros.</EM>
+Neither the format string nor the string values to be formatted with
+<CODE>%s</CODE> can contain embedded zeros.
+<CODE>%q</CODE> handles string values with embedded zeros.
<P>
<h3> <TT>gsub (s, pat, repl [, n])</TT></h3>
<A NAME="gsub"></A>
-Returns a copy of <CODE>s</CODE>,
-where all occurrences of the pattern <CODE>pat</CODE> have been
+Returns a copy of <CODE>s</CODE>
+in which all occurrences of the pattern <CODE>pat</CODE> have been
replaced by a replacement string specified by <CODE>repl</CODE>.
-This function also returns, as a second value,
+<CODE>gsub</CODE> also returns, as a second value,
the total number of substitutions made.
<P>
If <CODE>repl</CODE> is a string, then its value is used for replacement.
Any sequence in <CODE>repl</CODE> of the form <CODE>%n</CODE>
with <CODE>n</CODE> between 1 and 9
-stands for the value of the n-th captured substring.
+stands for the value of the <EM>n</EM>-th captured substring.
<P>
If <CODE>repl</CODE> is a function, then this function is called every time a
match occurs, with all captured substrings passed as arguments,
@@ -2381,35 +2794,35 @@ If the value returned by this function is a string,
then it is used as the replacement string;
otherwise, the replacement string is the empty string.
<P>
-A last optional parameter <CODE>n</CODE> limits
+The last, optional parameter <CODE>n</CODE> limits
the maximum number of substitutions to occur.
For instance, when <CODE>n</CODE> is 1 only the first occurrence of
<CODE>pat</CODE> is replaced.
<P>
Here are some examples:
<PRE>
- x = gsub("hello world", "(%w+)", "%1 %1")
- --&gt; x="hello hello world world"
+ x = gsub("hello world", "(%w+)", "%1 %1")
+ --&gt; x="hello hello world world"
<P>
- x = gsub("hello world", "(%w+)", "%1 %1", 1)
- --&gt; x="hello hello world"
+ x = gsub("hello world", "(%w+)", "%1 %1", 1)
+ --&gt; x="hello hello world"
<P>
- x = gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
- --&gt; x="world hello Lua from"
+ x = gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
+ --&gt; x="world hello Lua from"
<P>
- x = gsub("home = $HOME, user = $USER", "%$(%w+)", getenv)
- --&gt; x="home = /home/roberto, user = roberto" (for instance)
+ x = gsub("home = $HOME, user = $USER", "%$(%w+)", getenv)
+ --&gt; x="home = /home/roberto, user = roberto" (for instance)
<P>
- x = gsub("4+5 = $return 4+5$", "%$(.-)%$", dostring)
- --&gt; x="4+5 = 9"
+ x = gsub("4+5 = $return 4+5$", "%$(.-)%$", dostring)
+ --&gt; x="4+5 = 9"
<P>
- local t = {name="lua", version="3.2"}
- x = gsub("$name - $version", "%$(%w+)", function (v) return %t[v] end)
- --&gt; x="lua - 3.2"
+ local t = {name="lua", version="4.0"}
+ x = gsub("$name - $version", "%$(%w+)", function (v) return %t[v] end)
+ --&gt; x="lua - 4.0"
<P>
- t = {n=0}
- gsub("first second word", "(%w+)", function (w) tinsert(%t, w) end)
- --&gt; t={"first", "second", "word"; n=3}
+ t = {n=0}
+ gsub("first second word", "(%w+)", function (w) tinsert(%t, w) end)
+ --&gt; t={"first", "second", "word"; n=3}
</PRE>
<P>
<P>
@@ -2420,7 +2833,7 @@ Here are some examples:
a <A NAME="character class"><EM>character class</EM></A> is used to represent a set of characters.
The following combinations are allowed in describing a character class:
<DL>
-<DT><B><EM>x</EM></B><DD> (where <EM>x</EM> is any character not in the list
+<DT><B><EM>x</EM></B><DD> (where <EM>x</EM> is any magic characters
<CODE>^$()%.[]*+-?</CODE>)
- represents the character <EM>x</EM> itself.
<DT><B><TT>.</TT></B><DD> - (a dot) represents all characters.
@@ -2432,37 +2845,44 @@ The following combinations are allowed in describing a character class:
<DT><B><TT>%s</TT></B><DD> - represents all space characters.
<DT><B><TT>%u</TT></B><DD> - represents all upper case letters.
<DT><B><TT>%w</TT></B><DD> - represents all alphanumeric characters.
-<DT><B><TT>%x</TT></B><DD> - represents all hexa-decimal digits.
+<DT><B><TT>%x</TT></B><DD> - represents all hexadecimal digits.
<DT><B><TT>%z</TT></B><DD> - represents the character with representation 0.
-<DT><B><TT>%<EM>x</TT></EM></B><DD> (where <EM>x</EM> is any non alphanumeric character) -
+<DT><B><TT>%<EM>x</TT></EM></B><DD> (where <EM>x</EM> is any non-alphanumeric character) -
represents the character <EM>x</EM>.
-This is the standard way to escape the magic characters <CODE>()%.[]*-?</CODE>.
-It is strongly recommended that any control character (even the non magic),
-when used to represent itself in a pattern, should be preceded by a <CODE>%</CODE>.
+This is the standard way to escape the magic characters.
+We recommend that any punctuation character (even the non magic)
+should be preceded by a <CODE>%</CODE>
+when used to represent itself in a pattern.
+<P>
<DT><B><TT>[char-set</TT></B>]<DD> -
-Represents the class which is the union of all
-characters in char-set.
-To include a <CODE>]</CODE> in char-set, it must be the first character.
+represents the class which is the union of all
+characters in <CODE>char-set</CODE>.
A range of characters may be specified by
separating the end characters of the range with a <CODE>-</CODE>.
-If <CODE>-</CODE> appears as the first or last character of char-set,
-then it represents itself.
-All classes <CODE>%</CODE><EM>x</EM> described above can also be used as
+All classes <CODE>%</CODE><EM>x</EM> described above may also be used as
components in a char-set.
All other characters in char-set represent themselves.
-E.g., assuming an <EM>ascii</EM> character set,
-<CODE>[%dA-Fa-f]</CODE> specifies the hexa-decimal digits.
+For example, <CODE>[%w_]</CODE> (or <CODE>[_%w]</CODE>)
+represents all alphanumeric characters plus the underscore,
+<CODE>[0-7]</CODE> represents the octal digits,
+and <CODE>[0-7%l%-]</CODE> represents the octal digits plus
+the lower case letters plus the <CODE>-</CODE> character.
+<P>
+The interaction between ranges and classes is not defined.
+Therefore, patterns like <CODE>[%a-z]</CODE> or <CODE>[a-%%]</CODE>
+have no meaning.
+<P>
<DT><B><TT>[^char-set</TT></B>]<DD> -
-represents the complement of char-set,
-where char-set is interpreted as above.
+represents the complement of <CODE>char-set</CODE>,
+where <CODE>char-set</CODE> is interpreted as above.
</DL>
For all classes represented by single letters (<CODE>%a</CODE>, <CODE>%c</CODE>, ...),
-the correspondent upper-case letter represents the complement of the class.
+the corresponding upper-case letter represents the complement of the class.
For instance, <CODE>%S</CODE> represents all non-space characters.
<P>
The definitions of letter, space, etc. depend on the current locale.
In particular, the class <CODE>[a-z]</CODE> may not be equivalent to <CODE>%l</CODE>.
-The second form should be preferred for more portable programs.
+The second form should be preferred for portability.
<P>
<H4>Pattern Item:</H4>
a <A NAME="pattern item"><EM>pattern item</EM></A> may be
@@ -2488,15 +2908,15 @@ a single character class followed by <CODE>?</CODE>,
which matches 0 or 1 occurrence of a character in the class;
<LI>
<TT>%<EM>n</TT></EM>, for <EM>n</EM> between 1 and 9;
-such item matches a sub-string equal to the n-th captured string
+such item matches a sub-string equal to the <EM>n</EM>-th captured string
(see below);
<LI>
<TT>%b<EM>xy</TT></EM>, where <EM>x</EM> and <EM>y</EM> are two distinct characters;
-such item matches strings that start with <EM>x</EM>, end with <EM>y</EM>,
+such item matches strings that start with&nbsp;<EM>x</EM>, end with&nbsp;<EM>y</EM>,
and where the <EM>x</EM> and <EM>y</EM> are <EM>balanced</EM>.
-That means that, if one reads the string from left to write,
-counting plus 1 for an <EM>x</EM> and minus 1 for a <EM>y</EM>,
-the ending <EM>y</EM> is the first where the count reaches 0.
+This means that, if one reads the string from left to right,
+counting <I>+1</I> for an <EM>x</EM> and <I>-1</I> for a <EM>y</EM>,
+the ending <EM>y</EM> is the first <EM>y</EM> where the count reaches 0.
For instance, the item <CODE>%b()</CODE> matches expressions with
balanced parentheses.
</UL>
@@ -2507,10 +2927,12 @@ A <CODE>^</CODE> at the beginning of a pattern anchors the match at the
beginning of the subject string.
A <CODE>$</CODE> at the end of a pattern anchors the match at the
end of the subject string.
+At other positions,
+<CODE>^</CODE> and <CODE>$</CODE> have no special meaning and represent themselves.
<P>
<H4>Captures:</H4>
-a pattern may contain sub-patterns enclosed in parentheses,
-that describe <A NAME="captures"><EM>captures</EM></A>.
+A pattern may contain sub-patterns enclosed in parentheses,
+they describe <A NAME="captures"><EM>captures</EM></A>.
When a match succeeds, the sub-strings of the subject string
that match captures are stored (<EM>captured</EM>) for future use.
Captures are numbered according to their left parentheses.
@@ -2520,43 +2942,44 @@ stored as the first capture (and therefore has number&nbsp;1);
the character matching <CODE>.</CODE> is captured with number&nbsp;2,
and the part matching <CODE>%s*</CODE> has number&nbsp;3.
<P>
+A pattern cannot contain embedded zeros. Use <CODE>%z</CODE> instead.
+<P>
<P>
<A NAME="mathlib"></A>
<A NAME="6.3"></A>
<H2>6.3 - Mathematical Functions</H2>
<P>
-This library is an interface to some functions of the standard C math library.
+This library is an interface to some functions of the standard C&nbsp;math library.
In addition, it registers a tag method for the binary operator <CODE>^</CODE> that
returns <I>x^y</I> when applied to numbers <CODE>x^y</CODE>.
<P>
The library provides the following functions:
<A NAME="abs"></A><A NAME="acos"></A><A NAME="asin"></A><A NAME="atan"></A>
-<A NAME="atan2"></A><A NAME="ceil"></A><A NAME="cos"></A><A NAME="floor"></A>
-<A NAME="log"></A><A NAME="log10"></A><A NAME="max"></A><A NAME="min"></A>
-<A NAME="mod"></A><A NAME="sin"></A><A NAME="sqrt"></A><A NAME="tan"></A>
-<A NAME="frexp"></A><A NAME="ldexp"></A>
-<A NAME="random"></A><A NAME="randomseed"></A>
+<A NAME="atan2"></A><A NAME="ceil"></A><A NAME="cos"></A><A NAME="def"></A><A NAME="exp"></A>
+<A NAME="floor"></A><A NAME="log"></A><A NAME="log10"></A><A NAME="max"></A><A NAME="min"></A>
+<A NAME="mod"></A><A NAME="rad"></A><A NAME="sin"></A><A NAME="sqrt"></A><A NAME="tan"></A>
+<A NAME="frexp"></A><A NAME="ldexp"></A><A NAME="random"></A><A NAME="randomseed"></A>
<PRE>
-abs acos asin atan atan2 ceil cos deg floor log log10
-max min mod rad sin sqrt tan frexp ldexp
-random randomseed
+ abs acos asin atan atan2 ceil cos deg exp floor log log10
+ max min mod rad sin sqrt tan frexp ldexp random randomseed
</PRE>
plus a global variable <A NAME="PI"><TT>PI</TT></A>.
Most of them
-are only interfaces to the homonymous functions in the C library,
+are only interfaces to the homonymous functions in the C&nbsp;library,
except that, for the trigonometric functions,
all angles are expressed in <EM>degrees</EM>, not radians.
-Functions <A NAME="deg"><TT>deg</TT></A> and <A NAME="rad"><TT>rad</TT></A> can be used to convert
+The functions <CODE>deg</CODE> and <CODE>rad</CODE> can be used to convert
between radians and degrees.
<P>
The function <CODE>max</CODE> returns the maximum
value of its numeric arguments.
Similarly, <CODE>min</CODE> computes the minimum.
-Both can be used with 1, 2 or more arguments.
+Both can be used with 1, 2, or more arguments.
<P>
The functions <CODE>random</CODE> and <CODE>randomseed</CODE> are interfaces to
the simple random generator functions <CODE>rand</CODE> and <CODE>srand</CODE>,
provided by ANSI C.
+(No guarantees can be given for their statistical properties.)
The function <CODE>random</CODE>, when called without arguments,
returns a pseudo-random real number in the range <I>[0,1)</I>.
When called with a number <I>n</I>,
@@ -2574,17 +2997,15 @@ over two <A NAME="file handles"><EM>file handles</EM></A>, one for reading and o
These handles are stored in two Lua global variables,
called <CODE>_INPUT</CODE> and <CODE>_OUTPUT</CODE>.
The global variables
-<CODE>_STDIN</CODE>, <CODE>_STDOUT</CODE> and <CODE>_STDERR</CODE>
+<CODE>_STDIN</CODE>, <CODE>_STDOUT</CODE>, and <CODE>_STDERR</CODE>
are initialized with file descriptors for
-<CODE>stdin</CODE>, <CODE>stdout</CODE> and <CODE>stderr</CODE>.
+<CODE>stdin</CODE>, <CODE>stdout</CODE>, and <CODE>stderr</CODE>.
Initially, <CODE>_INPUT=_STDIN</CODE> and <CODE>_OUTPUT=_STDOUT</CODE>.
<A NAME="_INPUT"></A><A NAME="_OUTPUT"></A>
<A NAME="_STDIN"></A><A NAME="_STDOUT"></A><A NAME="_STDERR"></A>
<P>
-A file handle is a userdata containing the file stream <CODE>FILE*</CODE>,
+A file handle is a userdata containing the file stream (<CODE>FILE*</CODE>),
and with a distinctive tag created by the I/O library.
-Whenever a file handle is collected by the garbage collector,
-its correspondent stream is automatically closed.
<P>
Unless otherwise stated,
all I/O functions return <B>nil</B> on failure and
@@ -2598,18 +3019,19 @@ It returns a new file handle,
or, in case of errors, <B>nil</B> plus a string describing the error.
This function does not modify either <CODE>_INPUT</CODE> or <CODE>_OUTPUT</CODE>.
<P>
-The string mode can be any of the following:
+The <CODE>mode</CODE> string can be any of the following:
<DL>
-<DT><B>"r"</B><DD> read mode;
-<DT><B>"w"</B><DD> write mode;
-<DT><B>"a"</B><DD> append mode;
-<DT><B>"r+"</B><DD> update mode, all previous data is preserved;
-<DT><B>"w+"</B><DD> update mode, all previous data is erased;
-<DT><B>"a+"</B><DD> append update mode, previous data is preserved,
+<DT><B>``r''</B><DD> read mode;
+<DT><B>``w''</B><DD> write mode;
+<DT><B>``a''</B><DD> append mode;
+<DT><B>``r+''</B><DD> update mode, all previous data is preserved;
+<DT><B>``w+''</B><DD> update mode, all previous data is erased;
+<DT><B>``a+''</B><DD> append update mode, previous data is preserved,
writing is only allowed at the end of file.
</DL>
-The string mode may also have a <CODE>b</CODE> at the end,
+The <CODE>mode</CODE> string may 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 exactlty what is used in the standard&nbsp;C function <CODE>fopen</CODE>.
<P>
<h3> <TT>closefile (handle)</TT></h3><A NAME="closefile"></A>
<P>
@@ -2626,18 +3048,15 @@ It does not close the current input file.
When called without parameters,
it closes the <CODE>_INPUT</CODE> file,
and restores <CODE>stdin</CODE> as the value of <CODE>_INPUT</CODE>.
-<P>
If this function fails, it returns <B>nil</B>,
plus a string describing the error.
<P>
-<CITE>
-<EM>System dependent</EM>: if <CODE>filename</CODE> starts with a <CODE>|</CODE>,
+If <CODE>filename</CODE> starts with a <CODE>|</CODE>,
then a <A NAME="piped input">piped input</A> is opened, via function <A NAME="popen"><TT>popen</TT></A>.
Not all systems implement pipes.
Moreover,
the number of files that can be open at the same time is
usually limited and depends on the system.
-</CITE>
<P>
<h3> <TT>writeto (filename)</TT></h3><A NAME="writeto"></A>
<P>
@@ -2653,25 +3072,23 @@ When called without parameters,
this function closes the <CODE>_OUTPUT</CODE> file,
and restores <CODE>stdout</CODE> as the value of <CODE>_OUTPUT</CODE>.
<A NAME="closing a file"></A>
-<P>
If this function fails, it returns <B>nil</B>,
plus a string describing the error.
<P>
-<CITE>
-<EM>System dependent</EM>: if <CODE>filename</CODE> starts with a <CODE>|</CODE>,
-then a <A NAME="piped output">piped output</A> is opened, via function <A NAME="popen"><TT>popen</TT></A>.
+If <CODE>filename</CODE> starts with a <CODE>|</CODE>,
+then a <A NAME="piped input">piped input</A> is opened, via function <A NAME="popen"><TT>popen</TT></A>.
Not all systems implement pipes.
Moreover,
the number of files that can be open at the same time is
usually limited and depends on the system.
-</CITE>
<P>
<h3> <TT>appendto (filename)</TT></h3><A NAME="appendto"></A>
<P>
Opens a file named <CODE>filename</CODE> and sets it as the
value of <CODE>_OUTPUT</CODE>.
Unlike the <CODE>writeto</CODE> operation,
-this function does not erase any previous content of the file.
+this function does not erase any previous contents of the file;
+instead, anything written to the file is appended to its end.
If this function fails, it returns <B>nil</B>,
plus a string describing the error.
<P>
@@ -2691,7 +3108,7 @@ plus a string describing the error.
<P>
Saves any written data to the given file.
If <CODE>filehandle</CODE> is not specified,
-flushes all open files.
+then <CODE>flush</CODE> flushes all open files.
If this function fails, it returns <B>nil</B>,
plus a string describing the error.
<P>
@@ -2702,9 +3119,9 @@ measured in bytes from the beginning of the file,
to the position given by <CODE>offset</CODE> plus a base
specified by the string <CODE>whence</CODE>, as follows:
<DL>
-<DT><B>"set"</B><DD> base is position 0 (beginning of the file);
-<DT><B>"cur"</B><DD> base is current position;
-<DT><B>"end"</B><DD> base is end of file;
+<DT><B>``set''</B><DD> base is position 0 (beginning of the file);
+<DT><B>``cur''</B><DD> base is current position;
+<DT><B>``end''</B><DD> base is end of file;
</DL>
In case of success, function <CODE>seek</CODE> returns the final file position,
measured in bytes from the beginning of the file.
@@ -2724,62 +3141,35 @@ end of the file, and returns its size.
<P>
Returns a string with a file name that can safely
be used for a temporary file.
-The file must be explicitly removed when no longer needed.
+The file must be explicitly opened before its use
+and removed when no longer needed.
<P>
-<h3> <TT>read ([filehandle,] readpattern1, ...)</TT></h3><A NAME="read"></A>
+<h3> <TT>read ([filehandle,] format1, ...)</TT></h3><A NAME="read"></A>
<P>
Reads file <CODE>_INPUT</CODE>,
or <CODE>filehandle</CODE> if this argument is given,
-according to read patterns, which specify how much to read.
-For each pattern,
-the function returns a string with the characters read,
-even if the pattern succeeds only partially,
-or <B>nil</B> if the read pattern fails <EM>and</EM>
-the result string would be empty.
-When called without patterns,
-it uses a default pattern that reads the next line
+according to the given formats, which specify what to read.
+For each format,
+the function returns a string (or a number) with the characters read,
+or <B>nil</B> if it cannot read data with the specified format.
+When called without formats,
+it uses a default format that reads the next line
(see below).
<P>
-A <A NAME="read pattern"><EM>read pattern</EM></A> is a sequence of read pattern items.
-An item may be a single character class
-or a character class followed by <CODE>?</CODE>, by <CODE>*</CODE>, or by <CODE>+</CODE>.
-A single character class reads the next character from the input
-if it belongs to the class, otherwise it fails.
-A character class followed by <CODE>?</CODE> reads the next character
-from the input if it belongs to the class;
-it never fails.
-A character class followed by <CODE>*</CODE> reads until a character that
-does not belong to the class, or end of file;
-since it can match a sequence of zero characters, it never fails.
-A character class followed by <CODE>+</CODE> reads until a character that
-does not belong to the class, or end of file;
-it fails if it cannot read at least one character.
-Note that the behavior of read patterns is slightly different from
-the regular pattern matching behavior,
-where a <CODE>*</CODE> expands to the maximum length <EM>such that</EM>
-the rest of the pattern does not fail.
-With the read pattern behavior
-there is no need for backtracking the reading.
-<P>
-A pattern item may contain sub-patterns enclosed in curly brackets,
-that describe <A NAME="skips"><EM>skips</EM></A>.
-Characters matching a skip are read,
-but are not included in the resulting string.
-<P>
-There are some predefined patterns, as follows:
+The available formats are
<DL>
<DT><B>``*n''</B><DD> reads a number;
-this is the only pattern that returns a number instead of a string.
-<DT><B>``*l''</B><DD> returns the next line
+this is the only format that returns a number instead of a string.
+<DT><B>``*l''</B><DD> reads the next line
(skipping the end of line), or <B>nil</B> on end of file.
-This is the default pattern.
-It is equivalent to the pattern <CODE>"[^\n]*{\n}"</CODE>.
-<DT><B>``*a''</B><DD> reads the whole file.
-It is equivalent to the pattern <CODE>".*"</CODE>.
-<DT><B>``*w''</B><DD> returns the next word
-(maximal sequence of non white-space characters),
+This is the default format.
+<DT><B>``*a''</B><DD> reads the whole file, starting at the current position.
+On end of file, it returns the empty string.
+<DT><B>``*w''</B><DD> reads the next word
+(maximal sequence of non--white-space characters),
skipping spaces if necessary, or <B>nil</B> on end of file.
-It is equivalent to the pattern <CODE>"{%s*}%S+"</CODE>.
+<DT><B><EM>number</EM></B><DD> reads a string with up to that number of characters,
+or <B>nil</B> on end of file.
</DL>
<P>
<h3> <TT>write ([filehandle, ] value1, ...)</TT></h3><A NAME="write"></A>
@@ -2793,41 +3183,45 @@ use <CODE>tostring</CODE> or <CODE>format</CODE> before <CODE>write</CODE>.
If this function fails, it returns <B>nil</B>,
plus a string describing the error.
<P>
+<A NAME="libiosys"></A>
+<A NAME="6.5"></A>
+<H2>6.5 - System Facilities</H2>
+<P>
+<h3> <TT>clock ()</TT></h3><A NAME="clock"></A>
+<P>
+Returns an approximation of the amount of CPU time
+used by the program, in seconds.
+<P>
<h3> <TT>date ([format])</TT></h3><A NAME="date"></A>
<P>
Returns a string containing date and time
formatted according to the given string <CODE>format</CODE>,
-following the same rules of the ANSI C function <CODE>strftime</CODE>.
+following the same rules of the ANSI&nbsp;C function <CODE>strftime</CODE>.
When called without arguments,
it returns a reasonable date and time representation that depends on
-the host system and on the locale.
+the host system and on the current locale.
<P>
-<h3> <TT>clock ()</TT></h3><A NAME="clock"></A>
+<h3> <TT>execute (command)</TT></h3><A NAME="execute"></A>
<P>
-Returns an approximation of the amount of CPU time
-used by the program, in seconds.
+This function is equivalent to the C&nbsp;function <CODE>system</CODE>.
+It passes <CODE>command</CODE> to be executed by an operating system shell.
+It returns a status code, which is system-dependent.
<P>
<h3> <TT>exit ([code])</TT></h3><A NAME="exit"></A>
<P>
-Calls the C function <CODE>exit</CODE>,
+Calls the C&nbsp;function <CODE>exit</CODE>,
with an optional <CODE>code</CODE>,
to terminate the program.
-The default value for <CODE>code</CODE> is 1.
+The default value for <CODE>code</CODE> is the success code.
<P>
<h3> <TT>getenv (varname)</TT></h3><A NAME="getenv"></A>
<P>
Returns the value of the process environment variable <CODE>varname</CODE>,
or <B>nil</B> if the variable is not defined.
<P>
-<h3> <TT>execute (command)</TT></h3><A NAME="execute"></A>
-<P>
-This function is equivalent to the C function <CODE>system</CODE>.
-It passes <CODE>command</CODE> to be executed by an operating system shell.
-It returns an error code, which is system-dependent.
-<P>
<h3> <TT>setlocale (locale [, category])</TT></h3><A NAME="setlocale"></A>
<P>
-This function is an interface to the ANSI C function <CODE>setlocale</CODE>.
+This function is an interface to the ANSI&nbsp;C function <CODE>setlocale</CODE>.
<CODE>locale</CODE> is a string specifying a locale;
<CODE>category</CODE> is an optional string describing which category to change:
<CODE>"all"</CODE>, <CODE>"collate"</CODE>, <CODE>"ctype"</CODE>,
@@ -2841,7 +3235,7 @@ or <B>nil</B> if the request cannot be honored.
<!-- ====================================================================== -->
<HR>
<A NAME="7."></A>
-<H1>7 - The Debugger Interface</H1>
+<H1>7 - The Debug Interface</H1>
<P>
Lua has no built-in debugging facilities.
Instead, it offers a special interface,
@@ -2849,264 +3243,302 @@ by means of functions and <EM>hooks</EM>,
which allows the construction of different
kinds of debuggers, profilers, and other tools
that need ``inside information'' from the interpreter.
-This interface is declared in the header file <CODE>luadebug.h</CODE>.
+This interface is declared in <CODE>luadebug.h</CODE>.
<P>
<A NAME="7.1"></A>
<H2>7.1 - Stack and Function Information</H2>
<P>
-The main function to get information about the interpreter stack
-is
+<A NAME="lua_getstack"></A>
+The main function to get information about the interpreter stack is
<PRE>
-lua_Function lua_stackedfunction (int level);
+ int lua_getstack (lua_State *L, int level, lua_Debug *ar);
</PRE>
-It returns a handle (<CODE>lua_Function</CODE>) to the <EM>activation record</EM>
+It fills parts of a <CODE>lua_Debug</CODE> structure with
+an identification of the <EM>activation record</EM>
of the function executing at a given level.
Level&nbsp;0 is the current running function,
-while level <I>n+1</I> is the function that has called level <I>n</I>.
-When called with a level greater than the stack depth,
-<CODE>lua_stackedfunction</CODE> returns <CODE>LUA_NOOBJECT</CODE>.
-<P>
-The type <CODE>lua_Function</CODE> is just another name
-to <CODE>lua_Object</CODE>.
-Although, in this library,
-a <CODE>lua_Function</CODE> can be used wherever a <CODE>lua_Object</CODE> is required,
-when a parameter has type <CODE>lua_Function</CODE>
-it accepts only a handle returned by
-<CODE>lua_stackedfunction</CODE>.
-<P>
-Three other functions produce extra information about a function:
-<PRE>
-void lua_funcinfo (lua_Object func, char **source, int *linedefined);
-int lua_currentline (lua_Function func);
-char *lua_getobjname (lua_Object o, char **name);
-</PRE>
-<CODE>lua_funcinfo</CODE> gives the source and the line where the
-given function has been defined:
+whereas level <I>n+1</I> is the function that has called level <I>n</I>.
+Usually, <CODE>lua_getstack</CODE> returns 1;
+when called with a level greater than the stack depth,
+it returns 0.
+<P>
+<A NAME="lua_Debug"></A>
+The structure <CODE>lua_Debug</CODE> is used to carry different pieces of
+information about an active function:
+<PRE>
+ typedef struct lua_Debug {
+ const char *event; /* "call", "return" */
+ int currentline; /* (l) */
+ const char *name; /* (n) */
+ const char *namewhat; /* (n) global, tag method, local, field */
+ int nups; /* (u) number of upvalues */
+ int linedefined; /* (S) */
+ const char *what; /* (S) "Lua" function, "C" function, Lua "main" */
+ const char *source; /* (S) */
+ char short_src[LUA_IDSIZE]; /* (S) */
+<P>
+ /* private part */
+ ...
+ } lua_Debug;
+</PRE>
+<CODE>lua_getstack</CODE> fills only the private part
+of this structure, for future use.
+To fill in the other fields of <CODE>lua_Debug</CODE> with useful information,
+call <A NAME="lua_getinfo"></A>
+<PRE>
+ int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
+</PRE>
+This function returns 0 on error
+(e.g., an invalid option in <CODE>what</CODE>).
+Each character in the string <CODE>what</CODE>
+selects some fields of <CODE>ar</CODE> to be filled,
+as indicated by the letter in parentheses in the definition of <CODE>lua_Debug</CODE>:
+`<CODE>S</CODE>' fills in the fields <CODE>source</CODE>, <CODE>linedefined</CODE>,
+and <CODE>what</CODE>;
+`<CODE>l</CODE>' fills in the field <CODE>currentline</CODE>, etc.
+Moreover, `<CODE>f</CODE>' pushes onto the stack the function that is
+running at the given level.
+<P>
+To get information about a function that is not active (that is,
+it is not in the stack),
+you push the function onto the stack,
+and start the <CODE>what</CODE> string with the character <CODE>&gt;</CODE>.
+For instance, to know in which line a function <CODE>f</CODE> was defined,
+you can write
+<PRE>
+ lua_Debug ar;
+ lua_getglobal(L, "f");
+ lua_getinfo(L, "&gt;S", &amp;ar);
+ printf("%d\n", ar.linedefined);
+</PRE>
+The fields of <CODE>lua_Debug</CODE> have the following meaning:
+<DL>
+<P>
+<DT><B>source</B><DD>
If the function was defined in a string,
<CODE>source</CODE> is that string;
-If the function was defined in a file,
+if the function was defined in a file,
<CODE>source</CODE> starts with a <CODE>@</CODE> followed by the file name.
-If the ``function'' is in fact the main code of a chunk,
-then <CODE>linedefined</CODE> is 0.
-If the function is a C function,
-then <CODE>linedefined</CODE> is <I>-1</I>, and <CODE>filename</CODE> is <CODE>"(C)"</CODE>.
-<P>
-The function <CODE>lua_currentline</CODE> gives the current line where
-a given function is executing.
-It only works if the function has been compiled with debug
-information.
-When no line information is available,
-<CODE>lua_currentline</CODE> returns <I>-1</I>.
<P>
-The generation of debug information is controled by an internal flag,
-which can be switched with
-<PRE>
-int lua_setdebug (int debug);
-</PRE>
-This function sets the flag and returns its previous value.
-This flag can also be set from Lua&nbsp;(see Section&nbsp;<A HREF="#pragma">4.9</A>).
+<DT><B>short_src</B><DD>
+A ``printable'' version of <CODE>source</CODE>, to be used in error messages.
+<P>
+<DT><B>linedefined</B><DD>
+the line number where the definition of the function starts.
+<P>
+<DT><B>what</B><DD> the string <CODE>"Lua"</CODE> if this is a Lua function,
+<CODE>"C"</CODE> if this is a C&nbsp;function,
+or <CODE>"main"</CODE> if this is the main part of a chunk.
+<P>
+<DT><B>currentline</B><DD>
+the current line where the given function is executing.
+When no line information is available,
+<CODE>currentline</CODE> is set to <I>-1</I>.
<P>
-Function <CODE>lua_getobjname</CODE> tries to find a reasonable name for
-a given function.
+<DT><B>name</B><DD>
+a reasonable name for the given function.
Because functions in Lua are first class values,
they do not have a fixed name:
Some functions may be the value of many global variables,
while others may be stored only in a table field.
-Function <CODE>lua_getobjname</CODE> checks whether the given
+The <CODE>lua_getinfo</CODE> function checks whether the given
function is a tag method or the value of a global variable.
-If the given function is a tag method, then <CODE>lua_getobjname</CODE>
-returns the string <CODE>"tag-method"</CODE>,
-and <CODE>name</CODE> is set to point to the event name.
+If the given function is a tag method,
+then <CODE>name</CODE> points to the event name.
If the given function is the value of a global variable,
-then <CODE>lua_getobjname</CODE> returns the string <CODE>"global"</CODE>,
-and <CODE>name</CODE> points to the variable name.
+then <CODE>name</CODE> points to the variable name.
If the given function is neither a tag method nor a global variable,
-then <CODE>lua_getobjname</CODE> returns the empty string,
-and <CODE>name</CODE> is set to <CODE>NULL</CODE>.
+then <CODE>name</CODE> is set to <CODE>NULL</CODE>.
+<P>
+<DT><B>namewhat</B><DD>
+Explains the previous field.
+If the function is a global variable,
+<CODE>namewhat</CODE> is <CODE>"global"</CODE>;
+if the function is a tag method,
+<CODE>namewhat</CODE> is <CODE>"tag-method"</CODE>;
+otherwise <CODE>namewhat</CODE> is <CODE>""</CODE> (the empty string).
+<P>
+<DT><B>nups</B><DD>
+Number of upvalues of a function.
+<P>
+</DL>
+<P>
<P>
<A NAME="7.2"></A>
<H2>7.2 - Manipulating Local Variables</H2>
<P>
+For the manipulation of local variables,
+<CODE>luadebug.h</CODE> uses indices:
+The first parameter or local variable has index&nbsp;1, and so on,
+until the last active local variable.
+<P>
+<A NAME="lua_getlocal"></A><A NAME="lua_setlocal"></A>
The following functions allow the manipulation of the
local variables of a given activation record.
-They only work if the function has been compiled with debug
-information (see Section&nbsp;<A HREF="#pragma">4.9</A>).
-Moreover, for these functions, a local variable becomes
-visible in the line after its definition.
-<PRE>
-lua_Object lua_getlocal (lua_Function func, int local_number, char **name);
-int lua_setlocal (lua_Function func, int local_number);
-</PRE>
-<CODE>lua_getlocal</CODE> returns the value of a local variable,
-and sets <CODE>name</CODE> to point to the variable name.
-<CODE>local_number</CODE> is an index for local variables.
-The first parameter has index 1, and so on, until the
-last active local variable.
-When called with a <CODE>local_number</CODE> greater than the
-number of active local variables,
-or if the activation record has no debug information,
-<CODE>lua_getlocal</CODE> returns <CODE>LUA_NOOBJECT</CODE>.
-Formal parameters are the first local variables.
-<P>
-The function <CODE>lua_setlocal</CODE> sets the local variable
-<CODE>local_number</CODE> to the value previously pushed on the stack
-(see Section&nbsp;<A HREF="#valuesCLua">5.2</A>).
-If the function succeeds, then it returns 1.
-If <CODE>local_number</CODE> is greater than the number
-of active local variables,
-or if the activation record has no debug information,
-then this function fails and returns 0.
-<P>
+<PRE>
+ const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
+ const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
+</PRE>
+The parameter <CODE>ar</CODE> must be a valid activation record,
+filled by a previous call to <CODE>lua_getstack</CODE> or
+given as argument to a hook (see Section&nbsp;<A HREF="#sub-hooks">7.3</A>).
+Function <CODE>lua_getlocal</CODE> gets the index of a local variable
+(<CODE>n</CODE>), pushes its value onto the stack,
+and returns its name.
+For <CODE>lua_setlocal</CODE>,
+you push the new value onto the stack,
+and the function assigns that value to the variable and returns its name.
+Both functions return <CODE>NULL</CODE> on failure;
+that happens if the index is greater than
+the number of active local variables.
+<P>
+As an example, the following function lists the names of all
+local variables for a function at a given level of the stack:
+<PRE>
+ int listvars (lua_State *L, int level) {
+ lua_Debug ar;
+ int i = 1;
+ const char *name;
+ if (lua_getstack(L, level, &amp;ar) == 0)
+ return 0; /* failure: no such level in the stack */
+ while ((name = lua_getlocal(L, &amp;ar, i++)) != NULL) {
+ printf("%s\n", name);
+ lua_pop(L, 1); /* remove variable value */
+ }
+ return 1;
+ }
+</PRE>
+<P>
+<P>
+<A NAME="sub-hooks"></A>
<A NAME="7.3"></A>
<H2>7.3 - Hooks</H2>
<P>
The Lua interpreter offers two hooks for debugging purposes:
+a <EM>call</EM> hook and a <EM>line</EM> hook.
+Both have the same type,
+<A NAME="lua_Hook"></A>
<PRE>
-typedef void (*lua_CHFunction) (lua_Function func, char *file, int line);
-lua_CHFunction lua_setcallhook (lua_CHFunction func);
-<P>
-typedef void (*lua_LHFunction) (int line);
-lua_LHFunction lua_setlinehook (lua_LHFunction func);
+ typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
+</PRE>
+and you can set them with the following functions:
+<A NAME="lua_setcallhook"></A><A NAME="lua_setlinehook"></A>
+<PRE>
+ lua_Hook lua_setcallhook (lua_State *L, lua_Hook func);
+ lua_Hook lua_setlinehook (lua_State *L, lua_Hook func);
</PRE>
-The first hook is called whenever the interpreter enters or leaves a
-function.
-When entering a function,
-its parameters are a handle to the function activation record,
-plus the file and the line where the function is defined
-(the same information which is provided by <CODE>lua_funcinfo</CODE>);
-when leaving a function, <CODE>func</CODE> is <CODE>LUA_NOOBJECT</CODE>,
-<CODE>file</CODE> is <CODE>"(return)"</CODE>, and <CODE>line</CODE> is 0.
-<P>
-The other hook is called every time the interpreter changes
-the line of code it is executing.
-Its only parameter is the line number
-(the same information which is provided by the call
-<CODE>lua_currentline(lua_stackedfunction(0))</CODE>).
-This second hook is called only if the active function
-has been compiled with debug information (see Section&nbsp;<A HREF="#pragma">4.9</A>).
-<P>
A hook is disabled when its value is <CODE>NULL</CODE>,
which is the initial value of both hooks.
-Both <CODE>lua_setcallhook</CODE> and <CODE>lua_setlinehook</CODE>
+The functions <CODE>lua_setcallhook</CODE> and <CODE>lua_setlinehook</CODE>
set their corresponding hooks and return their previous values.
<P>
+The call hook is called whenever the
+interpreter enters or leaves a function.
+The <CODE>event</CODE> field of <CODE>ar</CODE> has the strings <CODE>"call"</CODE>
+or <CODE>"return"</CODE>.
+This <CODE>ar</CODE> can then be used in calls to <CODE>lua_getinfo</CODE>,
+<CODE>lua_getlocal</CODE>, and <CODE>lua_setlocal</CODE>
+to get more information about the function and to manipulate its
+local variables.
+<P>
+The line hook is called every time the interpreter changes
+the line of code it is executing.
+The <CODE>event</CODE> field of <CODE>ar</CODE> has the string <CODE>"line"</CODE>,
+and the <CODE>currentline</CODE> field has the line number.
+Again, you can use this <CODE>ar</CODE> in other calls to the debug API.
+<P>
+While Lua is running a hook, it disables other calls to hooks.
+Therefore, if a hook calls Lua to execute a function or a chunk,
+this execution ocurrs without any calls to hooks.
<P>
<P>
<A NAME="7.4"></A>
-<H2>7.4 - The Reflexive Debugger Interface</H2>
+<H2>7.4 - The Reflexive Debug Interface</H2>
<P>
The library <CODE>ldblib</CODE> provides
-the functionallity of the debugger interface to Lua programs.
+the functionality of the debug interface to Lua programs.
If you want to use this library,
your host application must open it,
-calling <CODE>lua_dblibopen</CODE>.
+by calling <CODE>lua_dblibopen</CODE>.
+<A NAME="lua_dblibopen"></A>
<P>
You should exert great care when using this library.
The functions provided here should be used exclusively for debugging
-and similar tasks (e.g. profiling).
+and similar tasks (e.g., profiling).
Please resist the temptation to use them as a
usual programming tool.
They are slow and violate some (otherwise) secure aspects of the
-language (e.g. privacy of local variables).
+language (e.g., privacy of local variables).
As a general rule, if your program does not need this library,
do not open it.
<P>
<P>
-<h3> <TT>funcinfo (function)</TT></h3><A NAME="funcinfo"></A>
+<h3> <TT>getinfo (function, [what])</TT></h3><A NAME="getinfo"></A>
<P>
-This function returns a table with information about the given function.
-The table contains the following fields:
-<DL>
-<DT><B>kind</B><DD>: may be <CODE>"C"</CODE>, if this is a C function,
-<CODE>"chunk"</CODE>, if this is the main part of a chunk,
-or <CODE>"Lua"</CODE> if this is a Lua function.
+This function returns a table with information about a function.
+You can give the function directly,
+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 stack:
+Level 0 is the current function (<CODE>getinfo</CODE> itself);
+level 1 is the function that called <CODE>getinfo</CODE>;
+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>.
<P>
-<DT><B>source</B><DD> the source where the function was defined.
-If the function was defined in a string,
-<CODE>source</CODE> is that string;
-If the function was defined in a file,
-<CODE>source</CODE> starts with a <CODE>@</CODE> followed by the file name.
+The returned table contains all the fields returned by <CODE>lua_getinfo</CODE>,
+with the string <CODE>what</CODE> describing what to get.
+The default for <CODE>what</CODE> is to get all information available.
<P>
-<DT><B>def_line</B><DD> the line where the function was defined in the source
-(only valid if this is a Lua function).
+For instance, the expression <CODE>getinfo(1,"n").name</CODE> returns
+the name of the current function, if a reasonable name can be found,
+and <CODE>getinfo(print)</CODE> returns a table with all available information
+about the <CODE>print</CODE> function.
<P>
-<DT><B>where</B><DD> can be <CODE>"global"</CODE> if this function has a global name,
-or <CODE>"tag-method"</CODE> if this function is a tag method handler.
-<P>
-<DT><B>name</B><DD> if <CODE>where</CODE> = <CODE>global</CODE>,
-<CODE>name</CODE> is the global name of the function;
-if <CODE>where</CODE> = <CODE>tag-method</CODE>,
-<CODE>name</CODE> is the event name of the tag method.
-</DL>
<P>
-<h3> <TT>getstack (index)</TT></h3><A NAME="getstack"></A>
+<h3> <TT>getlocal (level, local)</TT></h3><A NAME="getlocal"></A>
<P>
-This function returns a table with informations about the function
-running at level <CODE>index</CODE> of the stack.
-Index 0 is the current function (<CODE>getstack</CODE> itself).
-If <CODE>index</CODE> is bigger than the number of active functions,
-the function returns <B>nil</B>.
-The table contains all the fields returned by <CODE>funcinfo</CODE>,
-plus the following:
-<DL>
-<DT><B>func</B><DD> the function at that level.
-<DT><B>current</B><DD> the current line on the function execution;
-this will be available only when the function is
-precompiled with debug information.
-</DL>
-<P>
-<h3> <TT>getlocal (index [, local])</TT></h3><A NAME="getlocal"></A>
-<P>
-This function returns information about the local variables of the
-function at level <CODE>index</CODE> of the stack.
-It can be called in three ways.
-When called without a <CODE>local</CODE> argument,
-it returns a table, which associates variable names to their values.
-When called with a name (a string) as <CODE>local</CODE>,
-it returns the value of the local variable with that name.
-Finally, when called with an index (a number),
-it returns the value and the name of the local variable
-with that index.
-(The first parameter has index 1, and so on,
+This function returns the name and the value of the local variable
+with index <CODE>local</CODE> of the function at level <CODE>level</CODE> of the stack.
+(The first parameter or local variable has index&nbsp;1, and so on,
until the last active local variable.)
-In that case, the function returns <B>nil</B> if there is no local
-variable with the given index.
-The specification by index is the only way to distinguish
-homonym variables in a function.
+The function returns <B>nil</B> if there is no local
+variable with the given index,
+and raises an error when called with a <CODE>level</CODE> out of range.
+(You can call <CODE>getinfo</CODE> to check whether the level is valid.)
<P>
-<h3> <TT>setlocal (index, local, newvalue)</TT></h3><A NAME="setlocal"></A>
+<h3> <TT>setlocal (level, local, value)</TT></h3><A NAME="setlocal"></A>
<P>
-This function changes the values of the local variables of the
-function at level <CODE>index</CODE> of the stack.
-The local variable can be specified by name or by index;
-see function <CODE>getlocal</CODE>.
+This function assigns the value <CODE>value</CODE> to the local variable
+with index <CODE>local</CODE> of the function at level <CODE>level</CODE> of the stack.
+The function returns <B>nil</B> if there is no local
+variable with the given index,
+and raises an error when called with a <CODE>level</CODE> out of range.
<P>
<h3> <TT>setcallhook (hook)</TT></h3><A NAME="setcallhook"></A>
<P>
Sets the function <CODE>hook</CODE> as the call hook;
this hook will be called every time the interpreter starts and
exits the execution of a function.
-When Lua enters a function,
-the hook is called with the function been called,
-plus the source and the line where the function is defined.
-When Lua exits a function,
-the hook is called with no arguments.
-<P>
+The only argument to the call hook is the event name (<CODE>"call"</CODE> or
+<CODE>"return"</CODE>).
+You can call <CODE>getinfo</CODE> with level 2 to get more information about
+the function being called or returning
+(level&nbsp;0 is the <CODE>getinfo</CODE> function,
+and level&nbsp;1 is the hook function).
When called without arguments,
this function turns off call hooks.
+<CODE>setcallhook</CODE> returns the old hook.
<P>
<h3> <TT>setlinehook (hook)</TT></h3><A NAME="setlinehook"></A>
<P>
Sets the function <CODE>hook</CODE> as the line hook;
this hook will be called every time the interpreter changes
the line of code it is executing.
-The only argument to the hook is the line number the interpreter
-is about to execut.
-This hook is called only if the active function
-has been compiled with debug information (see Section&nbsp;<A HREF="#pragma">4.9</A>).
-<P>
+The only argument to the line hook is the line number the interpreter
+is about to execute.
When called without arguments,
this function turns off line hooks.
+<CODE>setlinehook</CODE> returns the old hook.
<P>
<P>
<A NAME="lua-sa"></A>
@@ -3116,60 +3548,96 @@ this function turns off line hooks.
<H1>8 - Lua Stand-alone</H1>
<P>
Although Lua has been designed as an extension language,
-the language can also be used as a stand-alone interpreter.
-An implementation of such an interpreter,
+to be embedded in a host C&nbsp;program,
+it is frequently used as a stand-alone language.
+An interpreter for Lua as a stand-alone language,
called simply <CODE>lua</CODE>,
is provided with the standard distribution.
This program can be called with any sequence of the following arguments:
<DL>
-<DT><B><TT>-v</TT></B><DD> prints version information.
-<DT><B><TT>-d</TT></B><DD> turns on debug information.
-<DT><B><TT>-e stat</TT></B><DD> executes <CODE>stat</CODE> as a Lua chunk.
-<DT><B><TT>-i</TT></B><DD> runs interactively,
-accepting commands from standard input until an <CODE>EOF</CODE>.
-Each line entered is immediately executed.
-<DT><B><TT>-q</TT></B><DD> same as <TT>-i</TT>, but without a prompt (quiet mode).
-<DT><B><TT>-</TT></B><DD> executes <CODE>stdin</CODE> as a file.
-<DT><B><TT>var=value</TT></B><DD> sets global <CODE>var</CODE> with string <CODE>"value"</CODE>.
-<DT><B><TT>filename</TT></B><DD> executes file <CODE>filename</CODE> as a Lua chunk.
+<DT><B><TT>-sNUM</TT></B><DD> sets the stack size to <TT>NUM</TT>
+(if present, this must be the first option);
+<DT><B><TT>-</TT> </B><DD> executes <CODE>stdin</CODE> as a file;
+<DT><B><TT>-c</TT></B><DD> calls <CODE>lua_close</CODE> after running all arguments;
+<DT><B><TT>-e</TT> \rm<EM>stat</EM></B><DD> executes string <CODE>stat</CODE>;
+<DT><B><TT>-f filename</TT></B><DD> executes file <CODE>filename</CODE> with the
+remaining arguments in table <CODE>arg</CODE>;
+<DT><B><TT>-i</TT></B><DD> enters interactive mode with prompt;
+<DT><B><TT>-q</TT></B><DD> enters interactive mode without prompt;
+<DT><B><TT>-v</TT></B><DD> prints version information;
+<DT><B><TT>var=value</TT></B><DD> sets global <CODE>var</CODE> to string <CODE>"value"</CODE>;
+<DT><B><TT>filename</TT></B><DD> executes file <CODE>filename</CODE>.
</DL>
When called without arguments,
-Lua behaves as <CODE>lua -v -i</CODE> when <CODE>stdin</CODE> is a terminal,
+<CODE>lua</CODE> behaves as <CODE>lua -v -i</CODE> when <CODE>stdin</CODE> is a terminal,
and as <CODE>lua -</CODE> otherwise.
<P>
-All arguments are handled in order.
+All arguments are handled in order, except <CODE>-c</CODE>.
For instance, an invocation like
<PRE>
-$ lua -i a=test prog.lua
+ $ lua -i a=test prog.lua
</PRE>
-will first interact with the user until an <CODE>EOF</CODE>,
+will first interact with the user until an <CODE>EOF</CODE> in <CODE>stdin</CODE>,
then will set <CODE>a</CODE> to <CODE>"test"</CODE>,
and finally will run the file <CODE>prog.lua</CODE>.
+(Here,
+<CODE>$</CODE> is the shell prompt. Your prompt may be different.)
<P>
-When in interactive mode,
+When the option <TT>-f filename</TT> is used,
+all remaining arguments in the command line
+are passed to the Lua program <CODE>filename</CODE> in a table called <CODE>arg</CODE>.
+In this table,
+the field <CODE>n</CODE> gets the index of the last argument,
+and the field 0 gets <CODE>"filename"</CODE>.
+For instance, in the call
+<PRE>
+ $ lua a.lua -f b.lua t1 t3
+</PRE>
+the interpreter first runs the file <TT>a.lua</TT>,
+then creates a table
+<PRE>
+ arg = {"t1", "t3"; n = 2, [0] = "b.lua"}
+</PRE>
+and finally runs the file <TT>b.lua</TT>.
+<A NAME="getargs"></A>
+The stand-alone interpreter also provides a <CODE>getargs</CODE> function that
+can be used to access <EM>all</EM> command line arguments.
+For instance, if you call Lua with the line
+<PRE>
+ $ lua -c a b
+</PRE>
+then a call to <CODE>getargs</CODE> in <CODE>a</CODE> or <CODE>b</CODE> will return the table
+<PRE>
+ {[0] = "lua", [1] = "-c", [2] = "a", [3] = "b", n = 3}
+</PRE>
+<P>
+In interactive mode,
a multi-line statement can be written finishing intermediate
-lines with a backslash (<CODE>\</CODE>).
-The prompt presented is the value of the global variable <CODE>_PROMPT</CODE>.
-Therefore, the prompt can be changed like below:
+lines with a backslash (`<CODE>\</CODE>').
+If the global variable <A NAME="_PROMPT"><TT>_PROMPT</TT></A> is defined as a string,
+then its value is used as the prompt.
+Therefore, the prompt can be changed directly on the command line:
<PRE>
-$ lua _PROMPT='myprompt&gt; ' -i
+ $ lua _PROMPT='myprompt&gt; ' -i
</PRE>
+or in any Lua programs by assigning to <CODE>_PROMPT</CODE>.
<P>
In Unix systems, Lua scripts can be made into executable programs
-by using the <CODE>#!</CODE> form,
-as in <CODE>#!/usr/local/bin/lua</CODE>.
+by using <CODE>chmod +x</CODE> and the&nbsp;<CODE>#!</CODE> form,
+as in <CODE>#!/usr/local/bin/lua</CODE>,
+or <CODE>#!/usr/local/bin/lua -f</CODE> to get other arguments.
+<P>
<P>
<HR>
<A NAME="Acknowledgments"></A>
<h1>Acknowledgments</h1>
<P>
The authors would like to thank CENPES/PETROBRAS which,
-jointly with TeCGraf, used extensively early versions of
-this system and gave valuable comments.
+jointly with TeCGraf, used early versions of
+this system extensively and gave valuable comments.
The authors would also like to thank Carlos Henrique Levy,
who found the name of the game.
-Lua means <EM>moon</EM> in Portuguese.
-<P>
+Lua means ``moon'' in Portuguese.
<P>
<P>
<P>
@@ -3177,60 +3645,153 @@ Lua means <EM>moon</EM> in Portuguese.
<A NAME="Incompatibilities"></A>
<h1>Incompatibilities with Previous Versions</h1>
<P>
-Although great care has been taken to avoid incompatibilities with
+Lua 4.0 is a major revision of the language.
+We took a great care to avoid incompatibilities with
the previous public versions of Lua,
-some differences had to be introduced.
+but some differences had to be introduced.
Here is a list of all these incompatibilities.
<P>
-<h2>Incompatibilities with <A NAME="version 3.1</h2>">version 3.1</h2></A>
+<P>
+<h2>Incompatibilities with <A NAME="version 3.2</h2>">version 3.2</h2></A>
+<P>
+<h3>Changes in the Language</h3>
<UL>
+<P>
<LI>
-In the debug API, the old variables <CODE>lua_debug</CODE>,
-<CODE>lua_callhook</CODE> and <CODE>lua_linehook</CODE> now live inside <CODE>lua_state</CODE>.
-Therefore, they are no longer directly accessible, and must be
-manipulated only through the new functions <CODE>lua_setdebug</CODE>,
-<CODE>lua_setcallhook</CODE> and <CODE>lua_setlinehook</CODE>.
+All pragmas (<CODE>$debug</CODE>, <CODE>$if</CODE>, ...) have been removed.
+<P>
+<LI>
+<B>for</B>, <B>break</B>, and <B>in</B> are now reserved words.
+<P>
+<LI>
+Garbage-collection tag methods for tables is now obsolete.
+<P>
+<LI>
+There is now only one tag method for order operators.
+<P>
+<LI>
+In nested function calls like <CODE>f(g(x))</CODE>,
+<EM>all</EM> return values from <CODE>g</CODE> are passed as arguments to <CODE>f</CODE>.
+This only happens when <CODE>g</CODE> is the last
+or the only argument to <CODE>f</CODE>.
+<P>
+<LI>
+The pre-compiler may assume that some operators are associative,
+for optimizations.
+This may cause problems if these operators
+have non-associative tag methods.
<P>
<LI>Old pre-compiled code is obsolete, and must be re-compiled.
+<P>
</UL>
<P>
-<h2>Incompatibilities with <A NAME="version 3.0</h2>">version 3.0</h2></A>
+<P>
+<h3>Changes in the Libraries</h3>
<UL>
<P>
-<LI>To support multiple contexts,
-Lua 3.1 must be explicitly opened before used,
-with function <CODE>lua_open</CODE>.
-However, all standard libraries check whether Lua is already opened,
-so any existing program that opens at least one standard
-library before calling Lua does not need to be modified.
+<LI>
+When traversing a table with <CODE>next</CODE> or <CODE>foreach</CODE>,
+the table cannot be modified in any way.
<P>
-<LI>Function <CODE>dostring</CODE> no longer accepts an optional second argument,
-with a temporary error handler.
-This facility is now provided by function <CODE>call</CODE>.
+<LI>
+General read patterns are now obsolete.
<P>
-<LI>Function <CODE>gsub</CODE> no longer accepts an optional fourth argument
-(a callback data, a table).
-Closures replace this feature with advantage.
+<LI>
+The functions <CODE>rawgettable</CODE> and <CODE>rawsettable</CODE>
+have been renamed to <CODE>rawget</CODE> and <CODE>rawset</CODE>.
<P>
-<LI>The syntax for function declaration is now more restricted;
-for instance, the old syntax <CODE>function f[exp] (x) ... end</CODE> is not
-accepted in Lua 3.1.
-In these cases,
-programs should use an explicit assignment instead, such as
-<CODE>f[exp] = function (x) ... end</CODE>.
+<LI>
+The functions <CODE>foreachvar</CODE>, <CODE>nextvar</CODE>,
+<CODE>rawsetglobal</CODE>, and <CODE>rawgetglobal</CODE> are obsolete.
+You can get their functionality using table operations
+over the table of globals,
+which is returned by <CODE>globals</CODE>.
<P>
-<LI>Old pre-compiled code is obsolete, and must be re-compiled.
+<LI>
+<CODE>setglobal</CODE> and <CODE>sort</CODE> no longer return a value;
+<CODE>type</CODE> no longer returns a second value.
<P>
-<LI>The option <CODE>a=b</CODE> in Lua stand-alone now sets <CODE>a</CODE> to the
-<EM>string</EM> <CODE>b</CODE>, and not to the value of <CODE>b</CODE>.
+<LI>
+The <CODE>p</CODE> option in function <CODE>call</CODE> is now obsolete.
<P>
</UL>
<P>
+<P>
+<h3>Changes in the API</h3>
+<UL>
+<P>
+<LI>
+The API has been completely rewritten:
+It is now fully reentrant and much clearer.
+<P>
+<LI>
+The debug API has been completely rewritten.
+<P>
+</UL>
+<P>
+<A NAME="BNF"></A>
+<A NAME="grammar"></A>
+<HR>
+<h1>The Complete Syntax of Lua</h1>
+<P>
+<A NAME="grammar"></A>
+<P>
+<PRE>
+<P>
+ chunk ::= {stat [`<B>;</B>']}
+<P>
+ block ::= chunk
+<P>
+ stat ::= varlist1 `<B>=</B>' explist1 <BR> | functioncall <BR> | <B>do</B> block <B>end</B> <BR> | <B>while</B> exp1 <B>do</B> block <B>end</B> <BR> | <B>repeat</B> block <B>until</B> exp1 <BR> | <B>if</B> exp1 <B>then</B> block {<B>elseif</B> exp1 <B>then</B> block} [<B>else</B> block] <B>end</B> <BR> | <B>return</B> [explist1] <BR> | <B>break</B> <BR> | <B>for</B> `<B>name</B>' `<B>=</B>' exp1 `<B>,</B>' exp1 [`<B>,</B>' exp1] <B>do</B> block <B>end</B> <BR> | <B>for</B> `<B>name</B>' `<B>,</B>' `<B>name</B>' <B>in</B> exp1 <B>do</B> block <B>end</B> <BR> | <B>function</B> funcname `<B>(</B>' [parlist1] `<B>)</B>' block <B>end</B> <BR> | <B>local</B> declist [init]
+<P>
+ funcname ::= `<B>name</B>' | `<B>name</B>' `<B>.</B>' `<B>name</B>' | `<B>name</B>' `<B>:</B>' `<B>name</B>'
+<P>
+ varlist1 ::= var {`<B>,</B>' var}
+<P>
+ var ::= `<B>name</B>' | varorfunc `<B>[</B>' exp1 `<B>]</B>' | varorfunc `<B>.</B>' `<B>name</B>'
+<P>
+ varorfunc ::= var | functioncall
+<P>
+ declist ::= `<B>name</B>' {`<B>,</B>' `<B>name</B>'}
+<P>
+ init ::= `<B>=</B>' explist1
+<P>
+ explist1 ::= {exp1 `<B>,</B>'} exp
+<P>
+ exp1 ::= exp
+<P>
+ exp ::= <B>nil</B> | `<B>number</B>' | `<B>literal</B>' | var | function | upvalue <BR> | functioncall | tableconstructor | `<B>(</B>' exp `<B>)</B>' | exp binop exp | unop exp
+<P>
+<P>
+ functioncall ::= varorfunc args | varorfunc `<B>:</B>' `<B>name</B>' args
+<P>
+ args ::= `<B>(</B>' [explist1] `<B>)</B>' | tableconstructor | `<B>literal</B>'
+<P>
+ function ::= <B>function</B> `<B>(</B>' [parlist1] `<B>)</B>' block <B>end</B>
+<P>
+ parlist1 ::= `<B>...</B>' | `<B>name</B>' {`<B>,</B>' `<B>name</B>'} [`<B>,</B>' `<B>...</B>']
+<P>
+ upvalue ::= `<B>%</B>' `<B>name</B>'
+<P>
+ tableconstructor ::= `<B>{</B>' fieldlist `<B>}</B>'
+ fieldlist ::= lfieldlist | ffieldlist | lfieldlist `<B>;</B>' ffieldlist | ffieldlist `<B>;</B>' lfieldlist
+ lfieldlist ::= [lfieldlist1]
+ ffieldlist ::= [ffieldlist1]
+ lfieldlist1 ::= exp {`<B>,</B>' exp} [`<B>,</B>']
+ ffieldlist1 ::= ffield {`<B>,</B>' ffield} [`<B>,</B>']
+ ffield ::= `<B>[</B>' exp `<B>]</B>' `<B>=</B>' exp | `<B>name</B>' `<B>=</B>' exp
+<P>
+ binop ::= `<B>+</B>' | `<B>-</B>' | `<B>*</B>' | `<B>/</B>' | `<B>\^{ </B>' | `<B>..</B>' <BR> | `<B>&lt;</B>' | `<B>&lt;=</B>' | `<B>&gt;</B>' | `<B>&gt;=</B>' | `<B>==</B>' | `<B>\&nbsp;{ </B>'=} <BR> | <B>and</B> | <B>or</B>}
+<P>
+ unop ::= `<B>-</B>' | <B>not</B>
+<P>
+</PRE>
+<P>
<HR>
<SMALL>
Last update:
-Wed Jul 7 13:36:24 EST 1999
+Mon Nov 6 17:37:03 EDT 2000
by <A HREF="http://www.tecgraf.puc-rio.br/~lhf/">lhf</A>.
</SMALL>
diff --git a/doc/readme.html b/doc/readme.html
index dd75b1d1..a574eccd 100644
--- a/doc/readme.html
+++ b/doc/readme.html
@@ -6,24 +6,29 @@
<BODY BGCOLOR="#FFFFFF">
<HR>
-<H1><A HREF="http://www.tecgraf.puc-rio.br/lua/">Lua</A> documentation</H1>
+<H1>
+<IMG SRC="logo.gif" ALT="Lua" ALIGN="bottom">
+Documentation
+</H1>
<UL>
+<LI><A HREF="http://www.tecgraf.puc-rio.br/lua/">Official web site</A>
<LI><A HREF="index.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">README</A>
-<LI><A HREF="../src/lib/README">src/lib/README</A>
-<LI><A HREF="../src/lua/README">src/lua/README</A>
-<LI><A HREF="../src/luac/README">src/luac/README</A>
-<LI><A HREF="../etc/README">etc/README</A>
-<LI><A HREF="../test/README">test/README</A>
-<LI><A HREF="../test/examples/www/README">test/examples/www/README</A>
+<LI><A HREF="../README">lua/README</A>
+<LI><A HREF="../src/lib/README">lua/src/lib/README</A>
+<LI><A HREF="../src/lua/README">lua/src/lua/README</A>
+<LI><A HREF="../src/luac/README">lua/src/luac/README</A>
+<LI><A HREF="../etc/README">lua/etc/README</A>
+<LI><A HREF="../test/README">lua/test/README</A>
+<LI><A HREF="../test/examples/www/README">lua/test/examples/www/README</A>
</UL>
<HR>
<SMALL>
Last update:
-Wed Jul 7 13:24:17 EST 1999
+Mon Nov 6 19:13:31 EDT 2000
by <A HREF="http://www.tecgraf.puc-rio.br/~lhf/">lhf</A>.
</SMALL>
diff --git a/etc/Makefile b/etc/Makefile
index 216d3ef6..a7768697 100644
--- a/etc/Makefile
+++ b/etc/Makefile
@@ -4,21 +4,35 @@ LUA= ..
include $(LUA)/config
-ALL= bin2c min trace
+LIBLUA=$(LIB)/liblua.a
+ALL= bin2c min trace lua.def
+
+x:
+ @echo 'choose a target:' all $(ALL)
all: $(ALL)
-bin2c: bin2c.c
- $(CC) -o $@ $<
+bin2c: bin2c.c
+ $(CC) $(CFLAGS) -o $@ $@.c
+
+min: min.c $(LIBLUA)
+ $(CC) $(CFLAGS) -o $@ $@.c -L$(LIB) -llua
+
+trace: trace.c $(LIBLUA)
+ $(CC) $(CFLAGS) -o $@ $@.c -L$(LIB) -llua -llualib -lm
+
+def: lua.def
-min: min.c $(LIB)/liblua.a
- $(CC) $(CFLAGS) -o $@ $< -L$(LIB) -llua
+lua.def: $(INC)/lua.h
+ $(BIN)/lua def.lua < $(INC)/lua.h > $@
+ # cat $(INC)/l*.h | $(BIN)/lua def.lua > $@
-trace: trace.c $(LIB)/liblua.a
- $(CC) $(CFLAGS) -o $@ $< -L$(LIB) -llua
+stdcall:
+ mkdir -p Stdcall
+ grep -l _API $(LUA)/src/*.[ch] $(LUA)/src/*/*.[ch] | xargs -n1 -i echo $(BIN)/lua stdcall.lua '<{}' '>Stdcall/{}'
-$(LIB)/liblua.a:
- cd ../src; make
+$(LIBLUA):
+ cd ../src; $(MAKE)
clean:
rm -f $(ALL)
diff --git a/etc/README b/etc/README
index 002190ae..eaae1c3d 100644
--- a/etc/README
+++ b/etc/README
@@ -2,25 +2,42 @@ This directory contains some code that might be useful.
bin2c.c
This program converts files to byte arrays that are automatically
- run with lua_dobuffer.
- This allows C programs to include all necessary Lua code, even in
- precompiled form.
- Even if the code is included in source form, bin2c is useful because it
- avoids the hassle of having to quote special characters in C strings.
+ run with lua_dobuffer. This allows C programs to include all necessary
+ Lua code, even in precompiled form. Even if the code is included in
+ source form, bin2c is useful because it avoids the hassle of having to
+ quote special characters in C strings.
Example of usage: Run bin2c file1 file2 ... > init.h. Then, in your C
program, just do #include "init.h" anywhere in the *body* of a
function. This will be equivalent to calling
- lua_dofile("file1"); lua_dofile("file2"); ...
+ lua_dofile(L,"file1"); lua_dofile(L,"file2"); ...
+ Note that the Lua state is called "L". If you use a different name,
+ say "mystate", just #define L mystate before #include "init.h".
+
+def.lua
+ A Lua script for creating .DEF for Windows DLLs.
+ Just do "make def" to create lua.def.
min.c
- The smallest Lua interpreter possible.
+ A minimal Lua interpreter.
+
+lua.ico
+ A Lua icon for Windows.
+ It was drawn by hand by Markus Gritsch <gritsch@iue.tuwien.ac.at>.
+
+lua.xpm
+ The same icon as lua.ico, but in XPM format.
+ It was converted with ImageMagick by Andy Tai <andy@exp.com>.
+
+lua.magic
+ Data for teaching file(1) about Lua precompiled chunks.
+
+stdcall.lua
+ A Lua script for changing the calling convention to __stdcall.
+ Do "make stdcall" and new modules will be created in stdcall/.
setfallback.lua
- An implementation of fallbacks on top of tag methods.
- Useful if you have Lua code written for version 2.5 or earlier,
- which uses setfallback.
- If you have C code that uses lua_setfallback, then define LUA_COMPAT2_5
- before building Lua (see config).
+ A Lua implementation of fallbacks on top of tag methods.
+ You only need this module if you have Lua code that uses setfallback.
trace.c
A simple execution tracer. An example of how to use the debugging hooks.
diff --git a/etc/bin2c.c b/etc/bin2c.c
index fca82a55..ac95a6e8 100644
--- a/etc/bin2c.c
+++ b/etc/bin2c.c
@@ -2,7 +2,7 @@
* bin2c.c
* convert binary files to byte arrays
* Luiz Henrique de Figueiredo (lhf@tecgraf.puc-rio.br)
-* 24 Nov 98 12:15:27
+* 11 Sep 2000 22:37:14
*/
#include <ctype.h>
@@ -45,7 +45,7 @@ void fdump(char* fn, int n)
void emit(char* fn, int n)
{
- printf(" lua_dobuffer(B%d,sizeof(B%d),\"%s\");\n",n,n,fn);
+ printf(" lua_dobuffer(L,B%d,sizeof(B%d),\"%s\");\n",n,n,fn);
}
int main(int argc, char* argv[])
@@ -61,7 +61,7 @@ int main(int argc, char* argv[])
{
int i;
printf("/* #include'ing this file in a C program is equivalent to calling\n");
- for (i=1; i<argc; i++) printf(" lua_dofile(\"%s\");\n",argv[i]);
+ for (i=1; i<argc; i++) printf(" lua_dofile(L,\"%s\");\n",argv[i]);
printf("*/\n");
for (i=1; i<argc; i++) fdump(argv[i],i);
for (i=1; i<argc; i++) emit(argv[i],i);
diff --git a/etc/def.lua b/etc/def.lua
new file mode 100644
index 00000000..736e32cd
--- /dev/null
+++ b/etc/def.lua
@@ -0,0 +1,9 @@
+-- def.lua
+-- make .DEF file from lua.h
+-- usage: lua def.lua <lua.h >lua.def
+
+T=read"*a"
+write("LIBRARY LUA\nVERSION ")
+gsub(T,"LUA_VERSION.-(%d+%.%d+)",write)
+write("\nEXPORTS\n")
+gsub(T,"(lua_%w+)%s+%(",function (f) write(" ",f,"\n") end)
diff --git a/etc/lua.ico b/etc/lua.ico
new file mode 100644
index 00000000..ccbabc4e
--- /dev/null
+++ b/etc/lua.ico
Binary files differ
diff --git a/etc/lua.magic b/etc/lua.magic
new file mode 100644
index 00000000..eb78f8d0
--- /dev/null
+++ b/etc/lua.magic
@@ -0,0 +1,10 @@
+
+# Lua precompiled files
+0 string \33Lua precompiled chunk for Lua
+>4 byte 0x23 2.3
+>4 byte 0x24 2.4
+>4 byte 0x25 2.5
+>4 byte 0x30 3.0
+>4 byte 0x31 3.1
+>4 byte 0x32 3.2
+>4 byte 0x40 4.0
diff --git a/etc/lua.xpm b/etc/lua.xpm
new file mode 100644
index 00000000..d3dcd379
--- /dev/null
+++ b/etc/lua.xpm
@@ -0,0 +1,44 @@
+/* XPM */
+static char *magick[] = {
+/* columns rows colors chars-per-pixel */
+"32 32 6 1",
+" c Gray0",
+". c #000000008080",
+"X c #808080808080",
+"o c #c0c0c0c0c0c0",
+"O c Gray100",
+"+ c None",
+/* pixels */
+"++++++++++++++++++++++++++ooo+++",
+"++++++++++++++++++++++++oX...Xo+",
+"++++++++++++++++++++++++X.....X+",
+"+++++++++++++++++++++++o.......o",
+"+++++++++XX......XX++++o.......o",
+"+++++++X............X++o.......o",
+"+++++o................o+X.....X+",
+"++++X..................XoX...Xo+",
+"+++X..............XXX...X+ooo+++",
+"++o.............XoOOOoX..o++++++",
+"++..............oOOOOOo...++++++",
+"+X.............XOOOOOOOX..X+++++",
+"+..............XOOOOOOOX...+++++",
+"X..............XOOOOOOOX...X++++",
+"X...............oOOOOOo....X++++",
+"................XoOOOoX.....++++",
+"....XO............XXX.......++++",
+"....XO......................++++",
+"....XO.....OX..OX.XOOOo.....++++",
+"....XO.....OX..OX.OoXXOX....++++",
+"....XO.....OX..OX....XOX....++++",
+"X...XO.....OX..OX..OOoOX...X++++",
+"X...XO.....OX..OX.OX..OX...X++++",
+"+...XOXXXX.OoXoOX.OXXXOX...+++++",
+"+X..XOOOOO.XOOXOX.XOOOXo..X+++++",
+"++........................++++++",
+"++o......................o++++++",
+"+++X....................X+++++++",
+"++++X..................X++++++++",
+"+++++o................o+++++++++",
+"+++++++X............X+++++++++++",
+"+++++++++XX......XX+++++++++++++"
+};
diff --git a/etc/min.c b/etc/min.c
index 7d45f5b6..0579ed3f 100644
--- a/etc/min.c
+++ b/etc/min.c
@@ -1,13 +1,32 @@
/*
* min.c
* a minimal Lua interpreter. loads stdin only.
-* no standard library, only builtin functions.
+* no standard library, only a "print" function.
*/
+#include <stdio.h>
#include "lua.h"
+/* a simple "print". based on the code in lbaselib.c */
+static int print(lua_State *L)
+{
+ int n=lua_gettop(L);
+ int i;
+ for (i=1; i<=n; i++)
+ {
+ if (i>1) printf("\t");
+ if (lua_isstring(L,i))
+ printf("%s",lua_tostring(L,i));
+ else
+ printf("%s:%p",lua_typename(L,lua_type(L,i)),lua_topointer(L,i));
+ }
+ printf("\n");
+ return 0;
+}
+
int main(void)
{
- lua_open();
- return lua_dofile(0);
+ lua_State *L=lua_open(0);
+ lua_register(L,"print",print);
+ return lua_dofile(L,NULL);
}
diff --git a/etc/stdcall.lua b/etc/stdcall.lua
new file mode 100644
index 00000000..7eac5c2e
--- /dev/null
+++ b/etc/stdcall.lua
@@ -0,0 +1,10 @@
+-- stdcall.lua
+-- add __stdcall where appropriate
+-- usage: lua stdcall.lua <lua.h >s_lua.h
+-- usage: lua stdcall.lua <lapi.c >s_lapi.c
+
+T=read"*a"
+T=gsub(T,"(lua_%w+%s+%()","__stdcall %1")
+T=gsub(T,"(%*lua_CFunction)","__stdcall %1")
+
+write(T)
diff --git a/etc/trace.c b/etc/trace.c
index 2c92850f..7c0b86ed 100644
--- a/etc/trace.c
+++ b/etc/trace.c
@@ -6,44 +6,51 @@
#include <stdio.h>
#include <string.h>
#include "lua.h"
+#include "lualib.h"
#include "luadebug.h"
+lua_State *lua_state = NULL;
+#define L lua_state /* lazy! */
+
static FILE* LOG; /* output file */
-static int L=0; /* indentation level */
+static int I=0; /* indentation level */
-static void linehook(int line)
+static void linehook(lua_State *L, lua_Debug *ar)
{
- fprintf(LOG,"%*sLINE(%d)\t-- %d\n",L,"",line,L);
+ fprintf(LOG,"%*sdo_line(%d)\t-- %d\n",I,"",ar->currentline,I);
}
-static void callhook(lua_Function func, char* file, int line)
+static void callhook(lua_State *L, lua_Debug *ar)
{
- fprintf(LOG,"%*sCALL('%s',%d)\t-- %d\n",L,"",file,line,L);
- if (line==0 && strcmp(file,"(return)")==0) --L; else ++L;
+ fprintf(LOG,"%*sdo_%s\t-- %p %d\n",I,"",ar->event,ar->_func,I);
+ if (*ar->event=='r') --I; else ++I;
}
void start_trace(FILE* logfile)
{
- lua_setlinehook(linehook);
- lua_setcallhook(callhook);
- lua_setdebug(1);
+ lua_setlinehook(L,linehook);
+ lua_setcallhook(L,callhook);
LOG=logfile;
}
void stop_trace(void)
{
- lua_setlinehook(NULL);
- lua_setcallhook(NULL);
- lua_setdebug(0);
+ lua_setlinehook(L,NULL);
+ lua_setcallhook(L,NULL);
fclose(LOG);
}
int main(void)
{
int rc;
- lua_open();
+ L=lua_open(0);
+ lua_baselibopen(L);
+ lua_iolibopen(L);
+ lua_strlibopen(L);
+ lua_mathlibopen(L);
+ lua_dblibopen(L);
start_trace(stderr);
- rc=lua_dofile(0);
+ rc=lua_dofile(L,0);
stop_trace();
return rc;
}
diff --git a/include/Makefile b/include/Makefile
index 48f12a79..0a2dfd95 100644
--- a/include/Makefile
+++ b/include/Makefile
@@ -1,4 +1,4 @@
-# makefile for lua distribution (includes)
+# makefile for Lua distribution (includes)
LUA= ..
diff --git a/include/lauxlib.h b/include/lauxlib.h
index 28a46647..9df0c8e8 100644
--- a/include/lauxlib.h
+++ b/include/lauxlib.h
@@ -1,53 +1,100 @@
/*
-** $Id: lauxlib.h,v 1.12 1999/03/10 14:19:41 roberto Exp $
+** $Id: lauxlib.h,v 1.30 2000/10/30 12:38:50 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
-#ifndef auxlib_h
-#define auxlib_h
+#ifndef lauxlib_h
+#define lauxlib_h
+#include <stddef.h>
+#include <stdio.h>
+
#include "lua.h"
+#ifndef LUALIB_API
+#define LUALIB_API extern
+#endif
+
+
struct luaL_reg {
- char *name;
+ const char *name;
lua_CFunction func;
};
-#define luaL_arg_check(cond,numarg,extramsg) if (!(cond)) \
- luaL_argerror(numarg,extramsg)
-
-void luaL_openlib (struct luaL_reg *l, int n);
-void luaL_argerror (int numarg, char *extramsg);
-#define luaL_check_string(n) (luaL_check_lstr((n), NULL))
-char *luaL_check_lstr (int numArg, long *len);
-#define luaL_opt_string(n, d) (luaL_opt_lstr((n), (d), NULL))
-char *luaL_opt_lstr (int numArg, char *def, long *len);
-double luaL_check_number (int numArg);
-#define luaL_check_int(n) ((int)luaL_check_number(n))
-#define luaL_check_long(n) ((long)luaL_check_number(n))
-double luaL_opt_number (int numArg, double def);
-#define luaL_opt_int(n,d) ((int)luaL_opt_number(n,d))
-#define luaL_opt_long(n,d) ((long)luaL_opt_number(n,d))
-lua_Object luaL_functionarg (int arg);
-lua_Object luaL_tablearg (int arg);
-lua_Object luaL_nonnullarg (int numArg);
-void luaL_verror (char *fmt, ...);
-char *luaL_openspace (int size);
-void luaL_resetbuffer (void);
-void luaL_addchar (int c);
-int luaL_getsize (void);
-void luaL_addsize (int n);
-int luaL_newbuffer (int size);
-void luaL_oldbuffer (int old);
-char *luaL_buffer (void);
-int luaL_findstring (char *name, char *list[]);
-void luaL_chunkid (char *out, char *source, int len);
-void luaL_filesource (char *out, char *filename, int len);
+LUALIB_API void luaL_openlib (lua_State *L, const struct luaL_reg *l, int n);
+LUALIB_API void luaL_argerror (lua_State *L, int numarg, const char *extramsg);
+LUALIB_API const char *luaL_check_lstr (lua_State *L, int numArg, size_t *len);
+LUALIB_API const char *luaL_opt_lstr (lua_State *L, int numArg, const char *def, size_t *len);
+LUALIB_API double luaL_check_number (lua_State *L, int numArg);
+LUALIB_API double luaL_opt_number (lua_State *L, int numArg, double def);
+
+LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg);
+LUALIB_API void luaL_checktype (lua_State *L, int narg, int t);
+LUALIB_API void luaL_checkany (lua_State *L, int narg);
+
+LUALIB_API void luaL_verror (lua_State *L, const char *fmt, ...);
+LUALIB_API int luaL_findstring (const char *name, const char *const list[]);
+
+
+
+/*
+** ===============================================================
+** some useful macros
+** ===============================================================
+*/
+
+#define luaL_arg_check(L, cond,numarg,extramsg) if (!(cond)) \
+ luaL_argerror(L, numarg,extramsg)
+#define luaL_check_string(L,n) (luaL_check_lstr(L, (n), NULL))
+#define luaL_opt_string(L,n,d) (luaL_opt_lstr(L, (n), (d), NULL))
+#define luaL_check_int(L,n) ((int)luaL_check_number(L, n))
+#define luaL_check_long(L,n) ((long)luaL_check_number(L, n))
+#define luaL_opt_int(L,n,d) ((int)luaL_opt_number(L, n,d))
+#define luaL_opt_long(L,n,d) ((long)luaL_opt_number(L, n,d))
+#define luaL_openl(L,a) luaL_openlib(L, a, (sizeof(a)/sizeof(a[0])))
+
+
+/*
+** {======================================================
+** Generic Buffer manipulation
+** =======================================================
+*/
+
+
+#ifndef LUAL_BUFFERSIZE
+#define LUAL_BUFFERSIZE BUFSIZ
+#endif
+
+
+typedef struct luaL_Buffer {
+ char *p; /* current position in buffer */
+ int level;
+ lua_State *L;
+ char buffer[LUAL_BUFFERSIZE];
+} luaL_Buffer;
+
+#define luaL_putchar(B,c) \
+ ((void)((B)->p < &(B)->buffer[LUAL_BUFFERSIZE] || luaL_prepbuffer(B)), \
+ (*(B)->p++ = (char)(c)))
+
+#define luaL_addsize(B,n) ((B)->p += (n))
+
+LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B);
+LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B);
+LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);
+LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s);
+LUALIB_API void luaL_addvalue (luaL_Buffer *B);
+LUALIB_API void luaL_pushresult (luaL_Buffer *B);
+
+
+/* }====================================================== */
#endif
+
+
diff --git a/include/lua.h b/include/lua.h
index 03ebe7d0..1b271534 100644
--- a/include/lua.h
+++ b/include/lua.h
@@ -1,5 +1,5 @@
/*
-** $Id: lua.h,v 1.32b 1999/05/11 20:29:19 roberto Exp $
+** $Id: lua.h,v 1.79 2000/10/31 12:44:07 roberto Exp $
** Lua - An Extensible Extension Language
** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil
** e-mail: lua@tecgraf.puc-rio.br
@@ -11,154 +11,208 @@
#ifndef lua_h
#define lua_h
-#define LUA_VERSION "Lua 3.2.2"
-#define LUA_COPYRIGHT "Copyright (C) 1994-1999 TeCGraf, PUC-Rio"
+
+/* definition of `size_t' */
+#include <stddef.h>
+
+
+/* mark for all API functions */
+#ifndef LUA_API
+#define LUA_API extern
+#endif
+
+
+#define LUA_VERSION "Lua 4.0"
+#define LUA_COPYRIGHT "Copyright (C) 1994-2000 TeCGraf, PUC-Rio"
#define LUA_AUTHORS "W. Celes, R. Ierusalimschy & L. H. de Figueiredo"
-#define LUA_NOOBJECT 0
+/* name of global variable with error handler */
+#define LUA_ERRORMESSAGE "_ERRORMESSAGE"
-#define LUA_ANYTAG (-1)
-typedef struct lua_State lua_State;
-extern lua_State *lua_state;
+/* pre-defined references */
+#define LUA_NOREF (-2)
+#define LUA_REFNIL (-1)
+#define LUA_REFREGISTRY 0
+
+/* pre-defined tags */
+#define LUA_ANYTAG (-1)
+#define LUA_NOTAG (-2)
-typedef void (*lua_CFunction) (void);
-typedef unsigned int lua_Object;
-void lua_open (void);
-void lua_close (void);
-lua_State *lua_setstate (lua_State *st);
+/* option for multiple returns in lua_call */
+#define LUA_MULTRET (-1)
-lua_Object lua_settagmethod (int tag, char *event); /* In: new method */
-lua_Object lua_gettagmethod (int tag, char *event);
-int lua_newtag (void);
-int lua_copytagmethods (int tagto, int tagfrom);
-void lua_settag (int tag); /* In: object */
+/* minimum stack available for a C function */
+#define LUA_MINSTACK 20
-void lua_error (char *s);
-int lua_dofile (char *filename); /* Out: returns */
-int lua_dostring (char *string); /* Out: returns */
-int lua_dobuffer (char *buff, int size, char *name);
- /* Out: returns */
-int lua_callfunction (lua_Object f);
- /* In: parameters; Out: returns */
-void lua_beginblock (void);
-void lua_endblock (void);
+/* error codes for lua_do* */
+#define LUA_ERRRUN 1
+#define LUA_ERRFILE 2
+#define LUA_ERRSYNTAX 3
+#define LUA_ERRMEM 4
+#define LUA_ERRERR 5
-lua_Object lua_lua2C (int number);
-#define lua_getparam(_) lua_lua2C(_)
-#define lua_getresult(_) lua_lua2C(_)
-int lua_isnil (lua_Object object);
-int lua_istable (lua_Object object);
-int lua_isuserdata (lua_Object object);
-int lua_iscfunction (lua_Object object);
-int lua_isnumber (lua_Object object);
-int lua_isstring (lua_Object object);
-int lua_isfunction (lua_Object object);
+typedef struct lua_State lua_State;
+
+typedef int (*lua_CFunction) (lua_State *L);
-double lua_getnumber (lua_Object object);
-char *lua_getstring (lua_Object object);
-long lua_strlen (lua_Object object);
-lua_CFunction lua_getcfunction (lua_Object object);
-void *lua_getuserdata (lua_Object object);
+/*
+** types returned by `lua_type'
+*/
+#define LUA_TNONE (-1)
+#define LUA_TUSERDATA 0
+#define LUA_TNIL 1
+#define LUA_TNUMBER 2
+#define LUA_TSTRING 3
+#define LUA_TTABLE 4
+#define LUA_TFUNCTION 5
-void lua_pushnil (void);
-void lua_pushnumber (double n);
-void lua_pushlstring (char *s, long len);
-void lua_pushstring (char *s);
-void lua_pushcclosure (lua_CFunction fn, int n);
-void lua_pushusertag (void *u, int tag);
-void lua_pushobject (lua_Object object);
-lua_Object lua_pop (void);
-lua_Object lua_getglobal (char *name);
-lua_Object lua_rawgetglobal (char *name);
-void lua_setglobal (char *name); /* In: value */
-void lua_rawsetglobal (char *name); /* In: value */
+/*
+** state manipulation
+*/
+LUA_API lua_State *lua_open (int stacksize);
+LUA_API void lua_close (lua_State *L);
-void lua_settable (void); /* In: table, index, value */
-void lua_rawsettable (void); /* In: table, index, value */
-lua_Object lua_gettable (void); /* In: table, index */
-lua_Object lua_rawgettable (void); /* In: table, index */
-int lua_tag (lua_Object object);
+/*
+** basic stack manipulation
+*/
+LUA_API int lua_gettop (lua_State *L);
+LUA_API void lua_settop (lua_State *L, int index);
+LUA_API void lua_pushvalue (lua_State *L, int index);
+LUA_API void lua_remove (lua_State *L, int index);
+LUA_API void lua_insert (lua_State *L, int index);
+LUA_API int lua_stackspace (lua_State *L);
-char *lua_nextvar (char *varname); /* Out: value */
-int lua_next (lua_Object o, int i);
- /* Out: ref, value */
-int lua_ref (int lock); /* In: value */
-lua_Object lua_getref (int ref);
-void lua_unref (int ref);
+/*
+** access functions (stack -> C)
+*/
-lua_Object lua_createtable (void);
+LUA_API int lua_type (lua_State *L, int index);
+LUA_API const char *lua_typename (lua_State *L, int t);
+LUA_API int lua_isnumber (lua_State *L, int index);
+LUA_API int lua_isstring (lua_State *L, int index);
+LUA_API int lua_iscfunction (lua_State *L, int index);
+LUA_API int lua_tag (lua_State *L, int index);
-long lua_collectgarbage (long limit);
+LUA_API int lua_equal (lua_State *L, int index1, int index2);
+LUA_API int lua_lessthan (lua_State *L, int index1, int index2);
+LUA_API double lua_tonumber (lua_State *L, int index);
+LUA_API const char *lua_tostring (lua_State *L, int index);
+LUA_API size_t lua_strlen (lua_State *L, int index);
+LUA_API lua_CFunction lua_tocfunction (lua_State *L, int index);
+LUA_API void *lua_touserdata (lua_State *L, int index);
+LUA_API const void *lua_topointer (lua_State *L, int index);
-/* =============================================================== */
-/* some useful macros/functions */
-#define lua_call(name) lua_callfunction(lua_getglobal(name))
+/*
+** push functions (C -> stack)
+*/
+LUA_API void lua_pushnil (lua_State *L);
+LUA_API void lua_pushnumber (lua_State *L, double n);
+LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len);
+LUA_API void lua_pushstring (lua_State *L, const char *s);
+LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
+LUA_API void lua_pushusertag (lua_State *L, void *u, int tag);
-#define lua_pushref(ref) lua_pushobject(lua_getref(ref))
-#define lua_refobject(o,l) (lua_pushobject(o), lua_ref(l))
+/*
+** get functions (Lua -> stack)
+*/
+LUA_API void lua_getglobal (lua_State *L, const char *name);
+LUA_API void lua_gettable (lua_State *L, int index);
+LUA_API void lua_rawget (lua_State *L, int index);
+LUA_API void lua_rawgeti (lua_State *L, int index, int n);
+LUA_API void lua_getglobals (lua_State *L);
+LUA_API void lua_gettagmethod (lua_State *L, int tag, const char *event);
+LUA_API int lua_getref (lua_State *L, int ref);
+LUA_API void lua_newtable (lua_State *L);
-#define lua_register(n,f) (lua_pushcfunction(f), lua_setglobal(n))
-#define lua_pushuserdata(u) lua_pushusertag(u, 0)
+/*
+** set functions (stack -> Lua)
+*/
+LUA_API void lua_setglobal (lua_State *L, const char *name);
+LUA_API void lua_settable (lua_State *L, int index);
+LUA_API void lua_rawset (lua_State *L, int index);
+LUA_API void lua_rawseti (lua_State *L, int index, int n);
+LUA_API void lua_setglobals (lua_State *L);
+LUA_API void lua_settagmethod (lua_State *L, int tag, const char *event);
+LUA_API int lua_ref (lua_State *L, int lock);
-#define lua_pushcfunction(f) lua_pushcclosure(f, 0)
-#define lua_clonetag(t) lua_copytagmethods(lua_newtag(), (t))
+/*
+** "do" functions (run Lua code)
+*/
+LUA_API int lua_call (lua_State *L, int nargs, int nresults);
+LUA_API void lua_rawcall (lua_State *L, int nargs, int nresults);
+LUA_API int lua_dofile (lua_State *L, const char *filename);
+LUA_API int lua_dostring (lua_State *L, const char *str);
+LUA_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, const char *name);
-lua_Object lua_seterrormethod (void); /* In: new method */
+/*
+** Garbage-collection functions
+*/
+LUA_API int lua_getgcthreshold (lua_State *L);
+LUA_API int lua_getgccount (lua_State *L);
+LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold);
-/* ==========================================================================
-** for compatibility with old versions. Avoid using these macros/functions
-** If your program does need any of these, define LUA_COMPAT2_5
+/*
+** miscellaneous functions
*/
+LUA_API int lua_newtag (lua_State *L);
+LUA_API int lua_copytagmethods (lua_State *L, int tagto, int tagfrom);
+LUA_API void lua_settag (lua_State *L, int tag);
+LUA_API void lua_error (lua_State *L, const char *s);
-#ifdef LUA_COMPAT2_5
+LUA_API void lua_unref (lua_State *L, int ref);
+LUA_API int lua_next (lua_State *L, int index);
+LUA_API int lua_getn (lua_State *L, int index);
-lua_Object lua_setfallback (char *event, lua_CFunction fallback);
+LUA_API void lua_concat (lua_State *L, int n);
-#define lua_storeglobal lua_setglobal
-#define lua_type lua_tag
+LUA_API void *lua_newuserdata (lua_State *L, size_t size);
-#define lua_lockobject(o) lua_refobject(o,1)
-#define lua_lock() lua_ref(1)
-#define lua_getlocked lua_getref
-#define lua_pushlocked lua_pushref
-#define lua_unlock lua_unref
-#define lua_pushliteral(o) lua_pushstring(o)
+/*
+** ===============================================================
+** some useful macros
+** ===============================================================
+*/
-#define lua_getindexed(o,n) (lua_pushobject(o), lua_pushnumber(n), lua_gettable())
-#define lua_getfield(o,f) (lua_pushobject(o), lua_pushstring(f), lua_gettable())
+#define lua_pop(L,n) lua_settop(L, -(n)-1)
-#define lua_copystring(o) (strdup(lua_getstring(o)))
+#define lua_register(L,n,f) (lua_pushcfunction(L, f), lua_setglobal(L, n))
+#define lua_pushuserdata(L,u) lua_pushusertag(L, u, 0)
+#define lua_pushcfunction(L,f) lua_pushcclosure(L, f, 0)
+#define lua_clonetag(L,t) lua_copytagmethods(L, lua_newtag(L), (t))
-#define lua_getsubscript lua_gettable
-#define lua_storesubscript lua_settable
+#define lua_isfunction(L,n) (lua_type(L,n) == LUA_TFUNCTION)
+#define lua_istable(L,n) (lua_type(L,n) == LUA_TTABLE)
+#define lua_isuserdata(L,n) (lua_type(L,n) == LUA_TUSERDATA)
+#define lua_isnil(L,n) (lua_type(L,n) == LUA_TNIL)
+#define lua_isnull(L,n) (lua_type(L,n) == LUA_TNONE)
-#endif
+#define lua_getregistry(L) lua_getref(L, LUA_REFREGISTRY)
#endif
/******************************************************************************
-* Copyright (c) 1994-1999 TeCGraf, PUC-Rio. All rights reserved.
+* Copyright (C) 1994-2000 TeCGraf, PUC-Rio. All rights reserved.
*
* Permission is hereby granted, without written agreement and without license
* or royalty fees, to use, copy, modify, and distribute this software and its
@@ -191,3 +245,4 @@ lua_Object lua_setfallback (char *event, lua_CFunction fallback);
*
* This implementation contains no third-party code.
******************************************************************************/
+
diff --git a/include/luadebug.h b/include/luadebug.h
index 1dc9f206..77753d37 100644
--- a/include/luadebug.h
+++ b/include/luadebug.h
@@ -1,5 +1,5 @@
/*
-** $Id: luadebug.h,v 1.6 1999/03/04 21:17:26 roberto Exp $
+** $Id: luadebug.h,v 1.17 2000/10/30 12:38:50 roberto Exp $
** Debugging API
** See Copyright Notice in lua.h
*/
@@ -11,24 +11,36 @@
#include "lua.h"
-typedef lua_Object lua_Function;
+typedef struct lua_Debug lua_Debug; /* activation record */
+typedef struct lua_Localvar lua_Localvar;
-typedef void (*lua_LHFunction) (int line);
-typedef void (*lua_CHFunction) (lua_Function func, char *file, int line);
+typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
-lua_Function lua_stackedfunction (int level);
-void lua_funcinfo (lua_Object func, char **source, int *linedefined);
-int lua_currentline (lua_Function func);
-char *lua_getobjname (lua_Object o, char **name);
-lua_Object lua_getlocal (lua_Function func, int local_number, char **name);
-int lua_setlocal (lua_Function func, int local_number);
+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);
-int lua_nups (lua_Function func);
+LUA_API lua_Hook lua_setcallhook (lua_State *L, lua_Hook func);
+LUA_API lua_Hook lua_setlinehook (lua_State *L, lua_Hook func);
-lua_LHFunction lua_setlinehook (lua_LHFunction func);
-lua_CHFunction lua_setcallhook (lua_CHFunction func);
-int lua_setdebug (int debug);
+
+#define LUA_IDSIZE 60
+
+struct lua_Debug {
+ const char *event; /* `call', `return' */
+ int currentline; /* (l) */
+ const char *name; /* (n) */
+ const char *namewhat; /* (n) `global', `tag method', `local', `field' */
+ int nups; /* (u) number of upvalues */
+ int linedefined; /* (S) */
+ const char *what; /* (S) `Lua' function, `C' function, Lua `main' */
+ const char *source; /* (S) */
+ char short_src[LUA_IDSIZE]; /* (S) */
+ /* private part */
+ struct lua_TObject *_func; /* active function */
+};
#endif
diff --git a/include/lualib.h b/include/lualib.h
index c7187868..fe48cb10 100644
--- a/include/lualib.h
+++ b/include/lualib.h
@@ -1,5 +1,5 @@
/*
-** $Id: lualib.h,v 1.6 1999/05/05 19:23:11 roberto Exp $
+** $Id: lualib.h,v 1.14 2000/10/27 16:15:53 roberto Exp $
** Lua standard libraries
** See Copyright Notice in lua.h
*/
@@ -10,27 +10,25 @@
#include "lua.h"
-void lua_iolibopen (void);
-void lua_strlibopen (void);
-void lua_mathlibopen (void);
-void lua_dblibopen (void);
-
-void lua_userinit (void);
+#ifndef LUALIB_API
+#define LUALIB_API extern
+#endif
-/* To keep compatibility with old versions */
+#define LUA_ALERT "_ALERT"
-#define iolib_open lua_iolibopen
-#define strlib_open lua_strlibopen
-#define mathlib_open lua_mathlibopen
+LUALIB_API void lua_baselibopen (lua_State *L);
+LUALIB_API void lua_iolibopen (lua_State *L);
+LUALIB_API void lua_strlibopen (lua_State *L);
+LUALIB_API void lua_mathlibopen (lua_State *L);
+LUALIB_API void lua_dblibopen (lua_State *L);
/* Auxiliary functions (private) */
-char *luaI_classend (char *p);
-int luaI_singlematch (int c, char *p, char *ep);
+const char *luaI_classend (lua_State *L, const char *p);
+int luaI_singlematch (int c, const char *p, const char *ep);
#endif
-
diff --git a/src/Makefile b/src/Makefile
index 7d01a924..66e0ea8d 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,4 +1,4 @@
-# makefile for lua basic library
+# makefile for Lua core library
LUA= ..
@@ -6,9 +6,8 @@ include $(LUA)/config
OBJS= \
lapi.o \
- lauxlib.o \
- lbuffer.o \
- lbuiltin.o \
+ lcode.o \
+ ldebug.o \
ldo.o \
lfunc.o \
lgc.o \
@@ -19,6 +18,7 @@ OBJS= \
lstate.o \
lstring.o \
ltable.o \
+ ltests.o \
ltm.o \
lundump.o \
lvm.o \
@@ -26,9 +26,8 @@ OBJS= \
SRCS= \
lapi.c \
- lauxlib.c \
- lbuffer.c \
- lbuiltin.c \
+ lcode.c \
+ ldebug.c \
ldo.c \
lfunc.c \
lgc.c \
@@ -39,16 +38,19 @@ SRCS= \
lstate.c \
lstring.c \
ltable.c \
+ ltests.c \
ltm.c \
lundump.c \
lvm.c \
lzio.c \
lapi.h \
- lbuiltin.h \
+ lcode.h \
+ ldebug.h \
ldo.h \
lfunc.h \
lgc.h \
llex.h \
+ llimits.h \
lmem.h \
lobject.h \
lopcodes.h \
diff --git a/src/lapi.c b/src/lapi.c
index 16bd9ff9..e8002342 100644
--- a/src/lapi.c
+++ b/src/lapi.c
@@ -1,15 +1,15 @@
/*
-** $Id: lapi.c,v 1.47b 1999/06/22 20:37:23 roberto Exp $
+** $Id: lapi.c,v 1.110 2000/10/30 12:50:09 roberto Exp $
** Lua API
** See Copyright Notice in lua.h
*/
-#include <stdlib.h>
#include <string.h>
+#include "lua.h"
+
#include "lapi.h"
-#include "lauxlib.h"
#include "ldo.h"
#include "lfunc.h"
#include "lgc.h"
@@ -19,676 +19,476 @@
#include "lstring.h"
#include "ltable.h"
#include "ltm.h"
-#include "lua.h"
-#include "luadebug.h"
#include "lvm.h"
-char lua_ident[] = "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n"
- "$Authors: " LUA_AUTHORS " $";
-
-
-
-TObject *luaA_Address (lua_Object o) {
- return (o != LUA_NOOBJECT) ? Address(o) : NULL;
-}
-
-
-static lua_Type normalized_type (TObject *o)
-{
- int t = ttype(o);
- switch (t) {
- case LUA_T_PMARK:
- return LUA_T_PROTO;
- case LUA_T_CMARK:
- return LUA_T_CPROTO;
- case LUA_T_CLMARK:
- return LUA_T_CLOSURE;
- default:
- return t;
- }
-}
+const char lua_ident[] = "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n"
+ "$Authors: " LUA_AUTHORS " $";
-static void set_normalized (TObject *d, TObject *s)
-{
- d->value = s->value;
- d->ttype = normalized_type(s);
-}
+#define Index(L,i) ((i) >= 0 ? (L->Cbase+((i)-1)) : (L->top+(i)))
-static TObject *luaA_protovalue (TObject *o)
-{
- return (normalized_type(o) == LUA_T_CLOSURE) ? protovalue(o) : o;
-}
+#define api_incr_top(L) incr_top
-void luaA_packresults (void)
-{
- luaV_pack(L->Cstack.lua2C, L->Cstack.num, L->stack.top);
- incr_top;
-}
-int luaA_passresults (void) {
- L->Cstack.base = L->Cstack.lua2C; /* position of first result */
- return L->Cstack.num;
+TObject *luaA_index (lua_State *L, int index) {
+ return Index(L, index);
}
-static void checkCparams (int nParams)
-{
- if (L->stack.top-L->stack.stack < L->Cstack.base+nParams)
- lua_error("API error - wrong number of arguments in C2lua stack");
-}
-
-
-static lua_Object put_luaObject (TObject *o) {
- luaD_openstack((L->stack.top-L->stack.stack)-L->Cstack.base);
- L->stack.stack[L->Cstack.base++] = *o;
- return L->Cstack.base; /* this is +1 real position (see Ref) */
+static TObject *luaA_indexAcceptable (lua_State *L, int index) {
+ if (index >= 0) {
+ TObject *o = L->Cbase+(index-1);
+ if (o >= L->top) return NULL;
+ else return o;
+ }
+ else return L->top+index;
}
-static lua_Object put_luaObjectonTop (void) {
- luaD_openstack((L->stack.top-L->stack.stack)-L->Cstack.base);
- L->stack.stack[L->Cstack.base++] = *(--L->stack.top);
- return L->Cstack.base; /* this is +1 real position (see Ref) */
+void luaA_pushobject (lua_State *L, const TObject *o) {
+ *L->top = *o;
+ incr_top;
}
-
-static void top2LC (int n) {
- /* Put the 'n' elements on the top as the Lua2C contents */
- L->Cstack.base = (L->stack.top-L->stack.stack); /* new base */
- L->Cstack.lua2C = L->Cstack.base-n; /* position of the new results */
- L->Cstack.num = n; /* number of results */
+LUA_API int lua_stackspace (lua_State *L) {
+ return (L->stack_last - L->top);
}
-lua_Object lua_pop (void) {
- checkCparams(1);
- return put_luaObjectonTop();
-}
-
/*
-** Get a parameter, returning the object handle or LUA_NOOBJECT on error.
-** 'number' must be 1 to get the first parameter.
+** basic stack manipulation
*/
-lua_Object lua_lua2C (int number)
-{
- if (number <= 0 || number > L->Cstack.num) return LUA_NOOBJECT;
- /* Ref(L->stack.stack+(L->Cstack.lua2C+number-1)) ==
- L->stack.stack+(L->Cstack.lua2C+number-1)-L->stack.stack+1 == */
- return L->Cstack.lua2C+number;
-}
-int lua_callfunction (lua_Object function)
-{
- if (function == LUA_NOOBJECT)
- return 1;
- else {
- luaD_openstack((L->stack.top-L->stack.stack)-L->Cstack.base);
- set_normalized(L->stack.stack+L->Cstack.base, Address(function));
- return luaD_protectedrun();
- }
+LUA_API int lua_gettop (lua_State *L) {
+ return (L->top - L->Cbase);
}
-lua_Object lua_gettagmethod (int tag, char *event)
-{
- return put_luaObject(luaT_gettagmethod(tag, event));
+LUA_API void lua_settop (lua_State *L, int index) {
+ if (index >= 0)
+ luaD_adjusttop(L, L->Cbase, index);
+ else
+ L->top = L->top+index+1; /* index is negative */
}
-lua_Object lua_settagmethod (int tag, char *event)
-{
- checkCparams(1);
- luaT_settagmethod(tag, event, L->stack.top-1);
- return put_luaObjectonTop();
+LUA_API void lua_remove (lua_State *L, int index) {
+ StkId p = luaA_index(L, index);
+ while (++p < L->top) *(p-1) = *p;
+ L->top--;
}
-lua_Object lua_seterrormethod (void) {
- lua_Object temp;
- checkCparams(1);
- temp = lua_getglobal("_ERRORMESSAGE");
- lua_setglobal("_ERRORMESSAGE");
- return temp;
+LUA_API void lua_insert (lua_State *L, int index) {
+ StkId p = luaA_index(L, index);
+ StkId q;
+ for (q = L->top; q>p; q--)
+ *q = *(q-1);
+ *p = *L->top;
}
-lua_Object lua_gettable (void)
-{
- checkCparams(2);
- luaV_gettable();
- return put_luaObjectonTop();
+LUA_API void lua_pushvalue (lua_State *L, int index) {
+ *L->top = *luaA_index(L, index);
+ api_incr_top(L);
}
-lua_Object lua_rawgettable (void) {
- checkCparams(2);
- if (ttype(L->stack.top-2) != LUA_T_ARRAY)
- lua_error("indexed expression not a table in rawgettable");
- *(L->stack.top-2) = *luaH_get(avalue(L->stack.top-2), L->stack.top-1);
- --L->stack.top;
- return put_luaObjectonTop();
-}
-
-void lua_settable (void) {
- checkCparams(3);
- luaD_checkstack(3); /* may need that to call T.M. */
- luaV_settable(L->stack.top-3);
- L->stack.top -= 2; /* pop table and index */
-}
+/*
+** access functions (stack -> C)
+*/
-void lua_rawsettable (void) {
- checkCparams(3);
- luaV_rawsettable(L->stack.top-3);
+LUA_API int lua_type (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ return (o == NULL) ? LUA_TNONE : ttype(o);
}
-
-lua_Object lua_createtable (void)
-{
- TObject o;
- luaC_checkGC();
- avalue(&o) = luaH_new(0);
- ttype(&o) = LUA_T_ARRAY;
- return put_luaObject(&o);
+LUA_API const char *lua_typename (lua_State *L, int t) {
+ UNUSED(L);
+ return (t == LUA_TNONE) ? "no value" : luaO_typenames[t];
}
-lua_Object lua_getglobal (char *name)
-{
- luaD_checkstack(2); /* may need that to call T.M. */
- luaV_getglobal(luaS_new(name));
- return put_luaObjectonTop();
+LUA_API int lua_iscfunction (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ return (o == NULL) ? 0 : iscfunction(o);
}
+LUA_API int lua_isnumber (lua_State *L, int index) {
+ TObject *o = luaA_indexAcceptable(L, index);
+ return (o == NULL) ? 0 : (tonumber(o) == 0);
+}
-lua_Object lua_rawgetglobal (char *name)
-{
- TaggedString *ts = luaS_new(name);
- return put_luaObject(&ts->u.s.globalval);
+LUA_API int lua_isstring (lua_State *L, int index) {
+ int t = lua_type(L, index);
+ return (t == LUA_TSTRING || t == LUA_TNUMBER);
}
-void lua_setglobal (char *name)
-{
- checkCparams(1);
- luaD_checkstack(2); /* may need that to call T.M. */
- luaV_setglobal(luaS_new(name));
+LUA_API int lua_tag (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ return (o == NULL) ? LUA_NOTAG : luaT_tag(o);
}
+LUA_API int lua_equal (lua_State *L, int index1, int index2) {
+ StkId o1 = luaA_indexAcceptable(L, index1);
+ StkId o2 = luaA_indexAcceptable(L, index2);
+ if (o1 == NULL || o2 == NULL) return 0; /* index out-of-range */
+ else return luaO_equalObj(o1, o2);
+}
-void lua_rawsetglobal (char *name)
-{
- TaggedString *ts = luaS_new(name);
- checkCparams(1);
- luaS_rawsetglobal(ts, --L->stack.top);
+LUA_API int lua_lessthan (lua_State *L, int index1, int index2) {
+ StkId o1 = luaA_indexAcceptable(L, index1);
+ StkId o2 = luaA_indexAcceptable(L, index2);
+ if (o1 == NULL || o2 == NULL) return 0; /* index out-of-range */
+ else return luaV_lessthan(L, o1, o2, L->top);
}
-int lua_isnil (lua_Object o)
-{
- return (o!= LUA_NOOBJECT) && (ttype(Address(o)) == LUA_T_NIL);
+LUA_API double lua_tonumber (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ return (o == NULL || tonumber(o)) ? 0 : nvalue(o);
}
-int lua_istable (lua_Object o)
-{
- return (o!= LUA_NOOBJECT) && (ttype(Address(o)) == LUA_T_ARRAY);
+LUA_API const char *lua_tostring (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ return (o == NULL || tostring(L, o)) ? NULL : svalue(o);
}
-int lua_isuserdata (lua_Object o)
-{
- return (o!= LUA_NOOBJECT) && (ttype(Address(o)) == LUA_T_USERDATA);
+LUA_API size_t lua_strlen (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ return (o == NULL || tostring(L, o)) ? 0 : tsvalue(o)->len;
}
-int lua_iscfunction (lua_Object o)
-{
- return (lua_tag(o) == LUA_T_CPROTO);
+LUA_API lua_CFunction lua_tocfunction (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ return (o == NULL || !iscfunction(o)) ? NULL : clvalue(o)->f.c;
}
-int lua_isnumber (lua_Object o)
-{
- return (o!= LUA_NOOBJECT) && (tonumber(Address(o)) == 0);
+LUA_API void *lua_touserdata (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ return (o == NULL || ttype(o) != LUA_TUSERDATA) ? NULL :
+ tsvalue(o)->u.d.value;
}
-int lua_isstring (lua_Object o)
-{
- int t = lua_tag(o);
- return (t == LUA_T_STRING) || (t == LUA_T_NUMBER);
+LUA_API const void *lua_topointer (lua_State *L, int index) {
+ StkId o = luaA_indexAcceptable(L, index);
+ if (o == NULL) return NULL;
+ switch (ttype(o)) {
+ case LUA_TTABLE:
+ return hvalue(o);
+ case LUA_TFUNCTION:
+ return clvalue(o);
+ default: return NULL;
+ }
}
-int lua_isfunction (lua_Object o)
-{
- int t = lua_tag(o);
- return (t == LUA_T_PROTO) || (t == LUA_T_CPROTO);
-}
-double lua_getnumber (lua_Object object)
-{
- if (object == LUA_NOOBJECT) return 0.0;
- if (tonumber(Address(object))) return 0.0;
- else return (nvalue(Address(object)));
-}
+/*
+** push functions (C -> stack)
+*/
-char *lua_getstring (lua_Object object)
-{
- luaC_checkGC(); /* "tostring" may create a new string */
- if (object == LUA_NOOBJECT || tostring(Address(object)))
- return NULL;
- else return (svalue(Address(object)));
-}
-long lua_strlen (lua_Object object)
-{
- luaC_checkGC(); /* "tostring" may create a new string */
- if (object == LUA_NOOBJECT || tostring(Address(object)))
- return 0L;
- else return (tsvalue(Address(object))->u.s.len);
+LUA_API void lua_pushnil (lua_State *L) {
+ ttype(L->top) = LUA_TNIL;
+ api_incr_top(L);
}
-void *lua_getuserdata (lua_Object object)
-{
- if (object == LUA_NOOBJECT || ttype(Address(object)) != LUA_T_USERDATA)
- return NULL;
- else return tsvalue(Address(object))->u.d.v;
-}
-lua_CFunction lua_getcfunction (lua_Object object)
-{
- if (!lua_iscfunction(object))
- return NULL;
- else return fvalue(luaA_protovalue(Address(object)));
+LUA_API void lua_pushnumber (lua_State *L, double n) {
+ nvalue(L->top) = n;
+ ttype(L->top) = LUA_TNUMBER;
+ api_incr_top(L);
}
-void lua_pushnil (void)
-{
- ttype(L->stack.top) = LUA_T_NIL;
- incr_top;
+LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) {
+ tsvalue(L->top) = luaS_newlstr(L, s, len);
+ ttype(L->top) = LUA_TSTRING;
+ api_incr_top(L);
}
-void lua_pushnumber (double n)
-{
- ttype(L->stack.top) = LUA_T_NUMBER;
- nvalue(L->stack.top) = n;
- incr_top;
-}
-void lua_pushlstring (char *s, long len)
-{
- tsvalue(L->stack.top) = luaS_newlstr(s, len);
- ttype(L->stack.top) = LUA_T_STRING;
- incr_top;
- luaC_checkGC();
-}
-
-void lua_pushstring (char *s)
-{
+LUA_API void lua_pushstring (lua_State *L, const char *s) {
if (s == NULL)
- lua_pushnil();
+ lua_pushnil(L);
else
- lua_pushlstring(s, strlen(s));
+ lua_pushlstring(L, s, strlen(s));
}
-void lua_pushcclosure (lua_CFunction fn, int n)
-{
- if (fn == NULL)
- lua_error("API error - attempt to push a NULL Cfunction");
- checkCparams(n);
- ttype(L->stack.top) = LUA_T_CPROTO;
- fvalue(L->stack.top) = fn;
- incr_top;
- luaV_closure(n);
- luaC_checkGC();
-}
-void lua_pushusertag (void *u, int tag)
-{
- if (tag < 0 && tag != LUA_ANYTAG)
- luaT_realtag(tag); /* error if tag is not valid */
- tsvalue(L->stack.top) = luaS_createudata(u, tag);
- ttype(L->stack.top) = LUA_T_USERDATA;
- incr_top;
- luaC_checkGC();
+LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
+ luaV_Cclosure(L, fn, n);
}
-void luaA_pushobject (TObject *o)
-{
- *L->stack.top = *o;
- incr_top;
-}
-void lua_pushobject (lua_Object o) {
- if (o == LUA_NOOBJECT)
- lua_error("API error - attempt to push a NOOBJECT");
- set_normalized(L->stack.top, Address(o));
- incr_top;
+LUA_API void lua_pushusertag (lua_State *L, void *u, int tag) {
+ /* ORDER LUA_T */
+ if (!(tag == LUA_ANYTAG || tag == LUA_TUSERDATA || validtag(tag)))
+ luaO_verror(L, "invalid tag for a userdata (%d)", tag);
+ tsvalue(L->top) = luaS_createudata(L, u, tag);
+ ttype(L->top) = LUA_TUSERDATA;
+ api_incr_top(L);
}
-int lua_tag (lua_Object lo)
-{
- if (lo == LUA_NOOBJECT)
- return LUA_T_NIL;
- else {
- TObject *o = Address(lo);
- int t;
- switch (t = ttype(o)) {
- case LUA_T_USERDATA:
- return o->value.ts->u.d.tag;
- case LUA_T_ARRAY:
- return o->value.a->htag;
- case LUA_T_PMARK:
- return LUA_T_PROTO;
- case LUA_T_CMARK:
- return LUA_T_CPROTO;
- case LUA_T_CLOSURE: case LUA_T_CLMARK:
- return o->value.cl->consts[0].ttype;
-#ifdef DEBUG
- case LUA_T_LINE:
- LUA_INTERNALERROR("invalid type");
-#endif
- default:
- return t;
- }
- }
-}
-
-void lua_settag (int tag)
-{
- checkCparams(1);
- luaT_realtag(tag);
- switch (ttype(L->stack.top-1)) {
- case LUA_T_ARRAY:
- (L->stack.top-1)->value.a->htag = tag;
- break;
- case LUA_T_USERDATA:
- (L->stack.top-1)->value.ts->u.d.tag = tag;
- break;
- default:
- luaL_verror("cannot change the tag of a %.20s",
- luaO_typename(L->stack.top-1));
- }
- L->stack.top--;
-}
+/*
+** get functions (Lua -> stack)
+*/
-TaggedString *luaA_nextvar (TaggedString *g) {
- if (g == NULL)
- g = (TaggedString *)L->rootglobal.next; /* first variable */
- else {
- /* check whether name is in global var list */
- luaL_arg_check((GCnode *)g != g->head.next, 1, "variable name expected");
- g = (TaggedString *)g->head.next; /* get next */
- }
- while (g && g->u.s.globalval.ttype == LUA_T_NIL) /* skip globals with nil */
- g = (TaggedString *)g->head.next;
- if (g) {
- ttype(L->stack.top) = LUA_T_STRING; tsvalue(L->stack.top) = g;
- incr_top;
- luaA_pushobject(&g->u.s.globalval);
- }
- return g;
+LUA_API void lua_getglobal (lua_State *L, const char *name) {
+ StkId top = L->top;
+ *top = *luaV_getglobal(L, luaS_new(L, name));
+ L->top = top;
+ api_incr_top(L);
}
-char *lua_nextvar (char *varname) {
- TaggedString *g = (varname == NULL) ? NULL : luaS_new(varname);
- g = luaA_nextvar(g);
- if (g) {
- top2LC(2);
- return g->str;
- }
- else {
- top2LC(0);
- return NULL;
- }
+LUA_API void lua_gettable (lua_State *L, int index) {
+ StkId t = Index(L, index);
+ StkId top = L->top;
+ *(top-1) = *luaV_gettable(L, t);
+ L->top = top; /* tag method may change top */
}
-int luaA_next (Hash *t, int i) {
- int tsize = nhash(t);
- for (; i<tsize; i++) {
- Node *n = node(t, i);
- if (ttype(val(n)) != LUA_T_NIL) {
- luaA_pushobject(ref(n));
- luaA_pushobject(val(n));
- return i+1; /* index to be used next time */
- }
- }
- return 0; /* no more elements */
+LUA_API void lua_rawget (lua_State *L, int index) {
+ StkId t = Index(L, index);
+ LUA_ASSERT(ttype(t) == LUA_TTABLE, "table expected");
+ *(L->top - 1) = *luaH_get(L, hvalue(t), L->top - 1);
}
-int lua_next (lua_Object o, int i) {
- TObject *t = Address(o);
- if (ttype(t) != LUA_T_ARRAY)
- lua_error("API error - object is not a table in `lua_next'");
- i = luaA_next(avalue(t), i);
- top2LC((i==0) ? 0 : 2);
- return i;
+LUA_API void lua_rawgeti (lua_State *L, int index, int n) {
+ StkId o = Index(L, index);
+ LUA_ASSERT(ttype(o) == LUA_TTABLE, "table expected");
+ *L->top = *luaH_getnum(hvalue(o), n);
+ api_incr_top(L);
}
-
-/*
-** {======================================================
-** To manipulate some state information
-** =======================================================
-*/
-
-lua_State *lua_setstate (lua_State *st) {
- lua_State *old = lua_state;
- lua_state = st;
- return old;
+LUA_API void lua_getglobals (lua_State *L) {
+ hvalue(L->top) = L->gt;
+ ttype(L->top) = LUA_TTABLE;
+ api_incr_top(L);
}
-lua_LHFunction lua_setlinehook (lua_LHFunction func) {
- lua_LHFunction old = L->linehook;
- L->linehook = func;
- return old;
-}
-lua_CHFunction lua_setcallhook (lua_CHFunction func) {
- lua_CHFunction old = L->callhook;
- L->callhook = func;
- return old;
+LUA_API int lua_getref (lua_State *L, int ref) {
+ if (ref == LUA_REFNIL)
+ ttype(L->top) = LUA_TNIL;
+ else if (0 <= ref && ref < L->refSize &&
+ (L->refArray[ref].st == LOCK || L->refArray[ref].st == HOLD))
+ *L->top = L->refArray[ref].o;
+ else
+ return 0;
+ api_incr_top(L);
+ return 1;
}
-int lua_setdebug (int debug) {
- int old = L->debug;
- L->debug = debug;
- return old;
+
+LUA_API void lua_newtable (lua_State *L) {
+ hvalue(L->top) = luaH_new(L, 0);
+ ttype(L->top) = LUA_TTABLE;
+ api_incr_top(L);
}
-/* }====================================================== */
/*
-** {======================================================
-** Debug interface
-** =======================================================
+** set functions (stack -> Lua)
*/
-lua_Function lua_stackedfunction (int level)
-{
- StkId i;
- for (i = (L->stack.top-1)-L->stack.stack; i>=0; i--) {
- int t = L->stack.stack[i].ttype;
- if (t == LUA_T_CLMARK || t == LUA_T_PMARK || t == LUA_T_CMARK)
- if (level-- == 0)
- return Ref(L->stack.stack+i);
- }
- return LUA_NOOBJECT;
+LUA_API void lua_setglobal (lua_State *L, const char *name) {
+ StkId top = L->top;
+ luaV_setglobal(L, luaS_new(L, name));
+ L->top = top-1; /* remove element from the top */
}
-int lua_nups (lua_Function func) {
- TObject *o = luaA_Address(func);
- return (!o || normalized_type(o) != LUA_T_CLOSURE) ? 0 : o->value.cl->nelems;
+LUA_API void lua_settable (lua_State *L, int index) {
+ StkId t = Index(L, index);
+ StkId top = L->top;
+ luaV_settable(L, t, top-2);
+ L->top = top-2; /* pop index and value */
}
-int lua_currentline (lua_Function func)
-{
- TObject *f = Address(func);
- return (f+1 < L->stack.top && (f+1)->ttype == LUA_T_LINE) ?
- (f+1)->value.i : -1;
+LUA_API void lua_rawset (lua_State *L, int index) {
+ StkId t = Index(L, index);
+ LUA_ASSERT(ttype(t) == LUA_TTABLE, "table expected");
+ *luaH_set(L, hvalue(t), L->top-2) = *(L->top-1);
+ L->top -= 2;
}
-lua_Object lua_getlocal (lua_Function func, int local_number, char **name) {
- /* check whether func is a Lua function */
- if (lua_tag(func) != LUA_T_PROTO)
- return LUA_NOOBJECT;
- else {
- TObject *f = Address(func);
- TProtoFunc *fp = luaA_protovalue(f)->value.tf;
- *name = luaF_getlocalname(fp, local_number, lua_currentline(func));
- if (*name) {
- /* if "*name", there must be a LUA_T_LINE */
- /* therefore, f+2 points to function base */
- return put_luaObject((f+2)+(local_number-1));
- }
- else
- return LUA_NOOBJECT;
- }
+LUA_API void lua_rawseti (lua_State *L, int index, int n) {
+ StkId o = Index(L, index);
+ LUA_ASSERT(ttype(o) == LUA_TTABLE, "table expected");
+ *luaH_setint(L, hvalue(o), n) = *(L->top-1);
+ L->top--;
}
-int lua_setlocal (lua_Function func, int local_number)
-{
- /* check whether func is a Lua function */
- if (lua_tag(func) != LUA_T_PROTO)
- return 0;
- else {
- TObject *f = Address(func);
- TProtoFunc *fp = luaA_protovalue(f)->value.tf;
- char *name = luaF_getlocalname(fp, local_number, lua_currentline(func));
- checkCparams(1);
- --L->stack.top;
- if (name) {
- /* if "name", there must be a LUA_T_LINE */
- /* therefore, f+2 points to function base */
- *((f+2)+(local_number-1)) = *L->stack.top;
- return 1;
- }
- else
- return 0;
- }
+LUA_API void lua_setglobals (lua_State *L) {
+ StkId newtable = --L->top;
+ LUA_ASSERT(ttype(newtable) == LUA_TTABLE, "table expected");
+ L->gt = hvalue(newtable);
}
-void lua_funcinfo (lua_Object func, char **source, int *linedefined) {
- if (!lua_isfunction(func))
- lua_error("API error - `funcinfo' called with a non-function value");
+LUA_API int lua_ref (lua_State *L, int lock) {
+ int ref;
+ if (ttype(L->top-1) == LUA_TNIL)
+ ref = LUA_REFNIL;
else {
- TObject *f = luaA_protovalue(Address(func));
- if (normalized_type(f) == LUA_T_PROTO) {
- *source = tfvalue(f)->source->str;
- *linedefined = tfvalue(f)->lineDefined;
+ if (L->refFree != NONEXT) { /* is there a free place? */
+ ref = L->refFree;
+ L->refFree = L->refArray[ref].st;
}
- else {
- *source = "(C)";
- *linedefined = -1;
+ else { /* no more free places */
+ luaM_growvector(L, L->refArray, L->refSize, 1, struct Ref,
+ "reference table overflow", MAX_INT);
+ L->nblocks += sizeof(struct Ref);
+ ref = L->refSize++;
}
+ L->refArray[ref].o = *(L->top-1);
+ L->refArray[ref].st = lock ? LOCK : HOLD;
}
+ L->top--;
+ return ref;
}
-static int checkfunc (TObject *o)
-{
- return luaO_equalObj(o, L->stack.top);
-}
-
+/*
+** "do" functions (run Lua code)
+** (most of them are in ldo.c)
+*/
-char *lua_getobjname (lua_Object o, char **name)
-{ /* try to find a name for given function */
- set_normalized(L->stack.top, Address(o)); /* to be accessed by "checkfunc" */
- if ((*name = luaS_travsymbol(checkfunc)) != NULL)
- return "global";
- else if ((*name = luaT_travtagmethods(checkfunc)) != NULL)
- return "tag-method";
- else return "";
+LUA_API void lua_rawcall (lua_State *L, int nargs, int nresults) {
+ luaD_call(L, L->top-(nargs+1), nresults);
}
-/* }====================================================== */
-
/*
-** {======================================================
-** BLOCK mechanism
-** =======================================================
+** Garbage-collection functions
*/
+/* GC values are expressed in Kbytes: #bytes/2^10 */
+#define GCscale(x) ((int)((x)>>10))
+#define GCunscale(x) ((unsigned long)(x)<<10)
-#ifndef MAX_C_BLOCKS
-#define MAX_C_BLOCKS 1000 /* arbitrary limit */
-#endif
-
+LUA_API int lua_getgcthreshold (lua_State *L) {
+ return GCscale(L->GCthreshold);
+}
-void lua_beginblock (void) {
- luaM_growvector(L->Cblocks, L->numCblocks, 1, struct C_Lua_Stack,
- "too many nested blocks", MAX_C_BLOCKS);
- L->Cblocks[L->numCblocks] = L->Cstack;
- L->numCblocks++;
+LUA_API int lua_getgccount (lua_State *L) {
+ return GCscale(L->nblocks);
}
-void lua_endblock (void) {
- --L->numCblocks;
- L->Cstack = L->Cblocks[L->numCblocks];
- luaD_adjusttop(L->Cstack.base);
+LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold) {
+ if (newthreshold > GCscale(ULONG_MAX))
+ L->GCthreshold = ULONG_MAX;
+ else
+ L->GCthreshold = GCunscale(newthreshold);
+ luaC_checkGC(L);
}
+/*
+** miscellaneous functions
+*/
-int lua_ref (int lock) {
- int ref;
- checkCparams(1);
- ref = luaC_ref(L->stack.top-1, lock);
- L->stack.top--;
- return ref;
+LUA_API void lua_settag (lua_State *L, int tag) {
+ luaT_realtag(L, tag);
+ switch (ttype(L->top-1)) {
+ case LUA_TTABLE:
+ hvalue(L->top-1)->htag = tag;
+ break;
+ case LUA_TUSERDATA:
+ tsvalue(L->top-1)->u.d.tag = tag;
+ break;
+ default:
+ luaO_verror(L, "cannot change the tag of a %.20s",
+ luaO_typename(L->top-1));
+ }
}
-
-lua_Object lua_getref (int ref) {
- TObject *o = luaC_getref(ref);
- return (o ? put_luaObject(o) : LUA_NOOBJECT);
+LUA_API void lua_unref (lua_State *L, int ref) {
+ if (ref >= 0) {
+ LUA_ASSERT(ref < L->refSize && L->refArray[ref].st < 0, "invalid ref");
+ L->refArray[ref].st = L->refFree;
+ L->refFree = ref;
+ }
}
-/* }====================================================== */
+LUA_API int lua_next (lua_State *L, int index) {
+ StkId t = luaA_index(L, index);
+ Node *n;
+ LUA_ASSERT(ttype(t) == LUA_TTABLE, "table expected");
+ n = luaH_next(L, hvalue(t), luaA_index(L, -1));
+ if (n) {
+ *(L->top-1) = *key(n);
+ *L->top = *val(n);
+ api_incr_top(L);
+ return 1;
+ }
+ else { /* no more elements */
+ L->top -= 1; /* remove key */
+ return 0;
+ }
+}
-#ifdef LUA_COMPAT2_5
-/*
-** API: set a function as a fallback
-*/
+LUA_API int lua_getn (lua_State *L, int index) {
+ Hash *h = hvalue(luaA_index(L, index));
+ const TObject *value = luaH_getstr(h, luaS_new(L, "n")); /* value = h.n */
+ if (ttype(value) == LUA_TNUMBER)
+ return (int)nvalue(value);
+ else {
+ Number max = 0;
+ int i = h->size;
+ Node *n = h->node;
+ while (i--) {
+ if (ttype(key(n)) == LUA_TNUMBER &&
+ ttype(val(n)) != LUA_TNIL &&
+ nvalue(key(n)) > max)
+ max = nvalue(key(n));
+ n++;
+ }
+ return (int)max;
+ }
+}
+
-static void do_unprotectedrun (lua_CFunction f, int nParams, int nResults) {
- luaD_openstack(nParams);
- (L->stack.top-nParams)->ttype = LUA_T_CPROTO;
- (L->stack.top-nParams)->value.f = f;
- luaD_calln(nParams, nResults);
+LUA_API void lua_concat (lua_State *L, int n) {
+ StkId top = L->top;
+ luaV_strconc(L, n, top);
+ L->top = top-(n-1);
+ luaC_checkGC(L);
}
-lua_Object lua_setfallback (char *name, lua_CFunction fallback) {
- lua_pushstring(name);
- lua_pushcfunction(fallback);
- do_unprotectedrun(luaT_setfallback, 2, 1);
- return put_luaObjectonTop();
+LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
+ TString *ts = luaS_newudata(L, size, NULL);
+ tsvalue(L->top) = ts;
+ ttype(L->top) = LUA_TUSERDATA;
+ api_incr_top(L);
+ return ts->u.d.value;
}
-#endif
diff --git a/src/lapi.h b/src/lapi.h
index 638a847f..5cefdc7a 100644
--- a/src/lapi.h
+++ b/src/lapi.h
@@ -1,5 +1,5 @@
/*
-** $Id: lapi.h,v 1.4 1999/02/23 14:57:28 roberto Exp $
+** $Id: lapi.h,v 1.20 2000/08/31 14:08:27 roberto Exp $
** Auxiliary functions from Lua API
** See Copyright Notice in lua.h
*/
@@ -8,15 +8,10 @@
#define lapi_h
-#include "lua.h"
#include "lobject.h"
-TObject *luaA_Address (lua_Object o);
-void luaA_pushobject (TObject *o);
-void luaA_packresults (void);
-int luaA_passresults (void);
-TaggedString *luaA_nextvar (TaggedString *g);
-int luaA_next (Hash *t, int i);
+TObject *luaA_index (lua_State *L, int index);
+void luaA_pushobject (lua_State *L, const TObject *o);
#endif
diff --git a/src/lauxlib.c b/src/lauxlib.c
deleted file mode 100644
index db929c4f..00000000
--- a/src/lauxlib.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
-** $Id: lauxlib.c,v 1.17 1999/03/11 18:59:19 roberto Exp $
-** Auxiliary functions for building Lua libraries
-** See Copyright Notice in lua.h
-*/
-
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-
-/* Please Notice: This file uses only the official API of Lua
-** Any function declared here could be written as an application function.
-** With care, these functions can be used by other libraries.
-*/
-
-#include "lauxlib.h"
-#include "lua.h"
-#include "luadebug.h"
-
-
-
-int luaL_findstring (char *name, char *list[]) {
- int i;
- for (i=0; list[i]; i++)
- if (strcmp(list[i], name) == 0)
- return i;
- return -1; /* name not found */
-}
-
-void luaL_argerror (int numarg, char *extramsg) {
- lua_Function f = lua_stackedfunction(0);
- char *funcname;
- lua_getobjname(f, &funcname);
- numarg -= lua_nups(f);
- if (funcname == NULL)
- funcname = "?";
- if (extramsg == NULL)
- luaL_verror("bad argument #%d to function `%.50s'", numarg, funcname);
- else
- luaL_verror("bad argument #%d to function `%.50s' (%.100s)",
- numarg, funcname, extramsg);
-}
-
-char *luaL_check_lstr (int numArg, long *len)
-{
- lua_Object o = lua_getparam(numArg);
- luaL_arg_check(lua_isstring(o), numArg, "string expected");
- if (len) *len = lua_strlen(o);
- return lua_getstring(o);
-}
-
-char *luaL_opt_lstr (int numArg, char *def, long *len)
-{
- return (lua_getparam(numArg) == LUA_NOOBJECT) ? def :
- luaL_check_lstr(numArg, len);
-}
-
-double luaL_check_number (int numArg)
-{
- lua_Object o = lua_getparam(numArg);
- luaL_arg_check(lua_isnumber(o), numArg, "number expected");
- return lua_getnumber(o);
-}
-
-
-double luaL_opt_number (int numArg, double def)
-{
- return (lua_getparam(numArg) == LUA_NOOBJECT) ? def :
- luaL_check_number(numArg);
-}
-
-
-lua_Object luaL_tablearg (int arg)
-{
- lua_Object o = lua_getparam(arg);
- luaL_arg_check(lua_istable(o), arg, "table expected");
- return o;
-}
-
-lua_Object luaL_functionarg (int arg)
-{
- lua_Object o = lua_getparam(arg);
- luaL_arg_check(lua_isfunction(o), arg, "function expected");
- return o;
-}
-
-lua_Object luaL_nonnullarg (int numArg)
-{
- lua_Object o = lua_getparam(numArg);
- luaL_arg_check(o != LUA_NOOBJECT, numArg, "value expected");
- return o;
-}
-
-void luaL_openlib (struct luaL_reg *l, int n)
-{
- int i;
- lua_open(); /* make sure lua is already open */
- for (i=0; i<n; i++)
- lua_register(l[i].name, l[i].func);
-}
-
-
-void luaL_verror (char *fmt, ...)
-{
- char buff[500];
- va_list argp;
- va_start(argp, fmt);
- vsprintf(buff, fmt, argp);
- va_end(argp);
- lua_error(buff);
-}
-
-
-void luaL_chunkid (char *out, char *source, int len) {
- len -= 13; /* 13 = strlen("string ''...\0") */
- if (*source == '@')
- sprintf(out, "file `%.*s'", len, source+1);
- else if (*source == '(')
- strcpy(out, "(C code)");
- else {
- char *b = strchr(source , '\n'); /* stop string at first new line */
- int lim = (b && (b-source)<len) ? b-source : len;
- sprintf(out, "string `%.*s'", lim, source);
- strcpy(out+lim+(13-5), "...'"); /* 5 = strlen("...'\0") */
- }
-}
-
-
-void luaL_filesource (char *out, char *filename, int len) {
- if (filename == NULL) filename = "(stdin)";
- sprintf(out, "@%.*s", len-2, filename); /* -2 for '@' and '\0' */
-}
diff --git a/src/lbuffer.c b/src/lbuffer.c
deleted file mode 100644
index 81ff16ca..00000000
--- a/src/lbuffer.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
-** $Id: lbuffer.c,v 1.9 1999/02/26 15:48:55 roberto Exp $
-** Auxiliary functions for building Lua libraries
-** See Copyright Notice in lua.h
-*/
-
-
-#include <stdio.h>
-
-#include "lauxlib.h"
-#include "lmem.h"
-#include "lstate.h"
-
-
-/*-------------------------------------------------------
-** Auxiliary buffer
--------------------------------------------------------*/
-
-
-#define EXTRABUFF 32
-
-
-#define openspace(size) if (L->Mbuffnext+(size) > L->Mbuffsize) Openspace(size)
-
-static void Openspace (int size) {
- lua_State *l = L; /* to optimize */
- size += EXTRABUFF;
- l->Mbuffsize = l->Mbuffnext+size;
- luaM_growvector(l->Mbuffer, l->Mbuffnext, size, char, arrEM, MAX_INT);
-}
-
-
-char *luaL_openspace (int size) {
- openspace(size);
- return L->Mbuffer+L->Mbuffnext;
-}
-
-
-void luaL_addchar (int c) {
- openspace(1);
- L->Mbuffer[L->Mbuffnext++] = (char)c;
-}
-
-
-void luaL_resetbuffer (void) {
- L->Mbuffnext = L->Mbuffbase;
-}
-
-
-void luaL_addsize (int n) {
- L->Mbuffnext += n;
-}
-
-int luaL_getsize (void) {
- return L->Mbuffnext-L->Mbuffbase;
-}
-
-int luaL_newbuffer (int size) {
- int old = L->Mbuffbase;
- openspace(size);
- L->Mbuffbase = L->Mbuffnext;
- return old;
-}
-
-
-void luaL_oldbuffer (int old) {
- L->Mbuffnext = L->Mbuffbase;
- L->Mbuffbase = old;
-}
-
-
-char *luaL_buffer (void) {
- return L->Mbuffer+L->Mbuffbase;
-}
-
diff --git a/src/lbuiltin.c b/src/lbuiltin.c
deleted file mode 100644
index c88ccd41..00000000
--- a/src/lbuiltin.c
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
-** $Id: lbuiltin.c,v 1.59 1999/06/17 17:04:03 roberto Exp $
-** Built-in functions
-** See Copyright Notice in lua.h
-*/
-
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "lapi.h"
-#include "lauxlib.h"
-#include "lbuiltin.h"
-#include "ldo.h"
-#include "lfunc.h"
-#include "lmem.h"
-#include "lobject.h"
-#include "lstate.h"
-#include "lstring.h"
-#include "ltable.h"
-#include "ltm.h"
-#include "lua.h"
-#include "lundump.h"
-#include "lvm.h"
-
-
-
-/*
-** {======================================================
-** Auxiliary functions
-** =======================================================
-*/
-
-
-static void pushtagstring (TaggedString *s) {
- TObject o;
- o.ttype = LUA_T_STRING;
- o.value.ts = s;
- luaA_pushobject(&o);
-}
-
-
-static real getsize (Hash *h) {
- real max = 0;
- int i;
- for (i = 0; i<nhash(h); i++) {
- Node *n = h->node+i;
- if (ttype(ref(n)) == LUA_T_NUMBER &&
- ttype(val(n)) != LUA_T_NIL &&
- nvalue(ref(n)) > max)
- max = nvalue(ref(n));
- }
- return max;
-}
-
-
-static real getnarg (Hash *a) {
- TObject index;
- TObject *value;
- /* value = table.n */
- ttype(&index) = LUA_T_STRING;
- tsvalue(&index) = luaS_new("n");
- value = luaH_get(a, &index);
- return (ttype(value) == LUA_T_NUMBER) ? nvalue(value) : getsize(a);
-}
-
-
-static Hash *gethash (int arg) {
- return avalue(luaA_Address(luaL_tablearg(arg)));
-}
-
-/* }====================================================== */
-
-
-/*
-** {======================================================
-** Functions that use only the official API
-** =======================================================
-*/
-
-
-/*
-** If your system does not support "stderr", redefine this function, or
-** redefine _ERRORMESSAGE so that it won't need _ALERT.
-*/
-static void luaB_alert (void) {
- fputs(luaL_check_string(1), stderr);
-}
-
-
-/*
-** Standard implementation of _ERRORMESSAGE.
-** The library "iolib" redefines _ERRORMESSAGE for better error information.
-*/
-static void error_message (void) {
- lua_Object al = lua_rawgetglobal("_ALERT");
- if (lua_isfunction(al)) { /* avoid error loop if _ALERT is not defined */
- char buff[600];
- sprintf(buff, "lua error: %.500s\n", luaL_check_string(1));
- lua_pushstring(buff);
- lua_callfunction(al);
- }
-}
-
-
-/*
-** If your system does not support "stdout", 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).
-*/
-#ifndef MAXPRINT
-#define MAXPRINT 40 /* arbitrary limit */
-#endif
-
-static void luaB_print (void) {
- lua_Object args[MAXPRINT];
- lua_Object obj;
- int n = 0;
- int i;
- while ((obj = lua_getparam(n+1)) != LUA_NOOBJECT) {
- luaL_arg_check(n < MAXPRINT, n+1, "too many arguments");
- args[n++] = obj;
- }
- for (i=0; i<n; i++) {
- lua_pushobject(args[i]);
- if (lua_call("tostring"))
- lua_error("error in `tostring' called by `print'");
- obj = lua_getresult(1);
- if (!lua_isstring(obj))
- lua_error("`tostring' must return a string to `print'");
- if (i>0) fputs("\t", stdout);
- fputs(lua_getstring(obj), stdout);
- }
- fputs("\n", stdout);
-}
-
-
-static void luaB_tonumber (void) {
- int base = luaL_opt_int(2, 10);
- if (base == 10) { /* standard conversion */
- lua_Object o = lua_getparam(1);
- if (lua_isnumber(o)) lua_pushnumber(lua_getnumber(o));
- else lua_pushnil(); /* not a number */
- }
- else {
- char *s = luaL_check_string(1);
- long n;
- luaL_arg_check(0 <= base && base <= 36, 2, "base out of range");
- n = strtol(s, &s, base);
- while (isspace((unsigned char)*s)) s++; /* skip trailing spaces */
- if (*s) lua_pushnil(); /* invalid format: return nil */
- else lua_pushnumber(n);
- }
-}
-
-
-static void luaB_error (void) {
- lua_error(lua_getstring(lua_getparam(1)));
-}
-
-static void luaB_setglobal (void) {
- char *n = luaL_check_string(1);
- lua_Object value = luaL_nonnullarg(2);
- lua_pushobject(value);
- lua_setglobal(n);
- lua_pushobject(value); /* return given value */
-}
-
-static void luaB_rawsetglobal (void) {
- char *n = luaL_check_string(1);
- lua_Object value = luaL_nonnullarg(2);
- lua_pushobject(value);
- lua_rawsetglobal(n);
- lua_pushobject(value); /* return given value */
-}
-
-static void luaB_getglobal (void) {
- lua_pushobject(lua_getglobal(luaL_check_string(1)));
-}
-
-static void luaB_rawgetglobal (void) {
- lua_pushobject(lua_rawgetglobal(luaL_check_string(1)));
-}
-
-static void luaB_luatag (void) {
- lua_pushnumber(lua_tag(lua_getparam(1)));
-}
-
-static void luaB_settag (void) {
- lua_Object o = luaL_tablearg(1);
- lua_pushobject(o);
- lua_settag(luaL_check_int(2));
- lua_pushobject(o); /* return first argument */
-}
-
-static void luaB_newtag (void) {
- lua_pushnumber(lua_newtag());
-}
-
-static void luaB_copytagmethods (void) {
- lua_pushnumber(lua_copytagmethods(luaL_check_int(1),
- luaL_check_int(2)));
-}
-
-static void luaB_rawgettable (void) {
- lua_pushobject(luaL_nonnullarg(1));
- lua_pushobject(luaL_nonnullarg(2));
- lua_pushobject(lua_rawgettable());
-}
-
-static void luaB_rawsettable (void) {
- lua_pushobject(luaL_nonnullarg(1));
- lua_pushobject(luaL_nonnullarg(2));
- lua_pushobject(luaL_nonnullarg(3));
- lua_rawsettable();
-}
-
-static void luaB_settagmethod (void) {
- lua_Object nf = luaL_nonnullarg(3);
- lua_pushobject(nf);
- lua_pushobject(lua_settagmethod(luaL_check_int(1), luaL_check_string(2)));
-}
-
-static void luaB_gettagmethod (void) {
- lua_pushobject(lua_gettagmethod(luaL_check_int(1), luaL_check_string(2)));
-}
-
-static void luaB_seterrormethod (void) {
- lua_Object nf = luaL_functionarg(1);
- lua_pushobject(nf);
- lua_pushobject(lua_seterrormethod());
-}
-
-static void luaB_collectgarbage (void) {
- lua_pushnumber(lua_collectgarbage(luaL_opt_int(1, 0)));
-}
-
-/* }====================================================== */
-
-
-/*
-** {======================================================
-** Functions that could use only the official API but
-** do not, for efficiency.
-** =======================================================
-*/
-
-static void luaB_dostring (void) {
- long l;
- char *s = luaL_check_lstr(1, &l);
- if (*s == ID_CHUNK)
- lua_error("`dostring' cannot run pre-compiled code");
- if (lua_dobuffer(s, l, luaL_opt_string(2, s)) == 0)
- if (luaA_passresults() == 0)
- lua_pushuserdata(NULL); /* at least one result to signal no errors */
-}
-
-
-static void luaB_dofile (void) {
- char *fname = luaL_opt_string(1, NULL);
- if (lua_dofile(fname) == 0)
- if (luaA_passresults() == 0)
- lua_pushuserdata(NULL); /* at least one result to signal no errors */
-}
-
-
-static void luaB_call (void) {
- lua_Object f = luaL_nonnullarg(1);
- Hash *arg = gethash(2);
- char *options = luaL_opt_string(3, "");
- lua_Object err = lua_getparam(4);
- int narg = (int)getnarg(arg);
- int i, status;
- if (err != LUA_NOOBJECT) { /* set new error method */
- lua_pushobject(err);
- err = lua_seterrormethod();
- }
- /* push arg[1...n] */
- luaD_checkstack(narg);
- for (i=0; i<narg; i++)
- *(L->stack.top++) = *luaH_getint(arg, i+1);
- status = lua_callfunction(f);
- if (err != LUA_NOOBJECT) { /* restore old error method */
- lua_pushobject(err);
- lua_seterrormethod();
- }
- if (status != 0) { /* error in call? */
- if (strchr(options, 'x')) {
- lua_pushnil();
- return; /* return nil to signal the error */
- }
- else
- lua_error(NULL);
- }
- else { /* no errors */
- if (strchr(options, 'p'))
- luaA_packresults();
- else
- luaA_passresults();
- }
-}
-
-
-static void luaB_nextvar (void) {
- TObject *o = luaA_Address(luaL_nonnullarg(1));
- TaggedString *g;
- if (ttype(o) == LUA_T_NIL)
- g = NULL;
- else {
- luaL_arg_check(ttype(o) == LUA_T_STRING, 1, "variable name expected");
- g = tsvalue(o);
- }
- if (!luaA_nextvar(g))
- lua_pushnil();
-}
-
-
-static void luaB_next (void) {
- Hash *a = gethash(1);
- TObject *k = luaA_Address(luaL_nonnullarg(2));
- int i = (ttype(k) == LUA_T_NIL) ? 0 : luaH_pos(a, k)+1;
- if (luaA_next(a, i) == 0)
- lua_pushnil();
-}
-
-
-static void luaB_tostring (void) {
- lua_Object obj = lua_getparam(1);
- TObject *o = luaA_Address(obj);
- char buff[64];
- switch (ttype(o)) {
- case LUA_T_NUMBER:
- lua_pushstring(lua_getstring(obj));
- return;
- case LUA_T_STRING:
- lua_pushobject(obj);
- return;
- case LUA_T_ARRAY:
- sprintf(buff, "table: %p", (void *)o->value.a);
- break;
- case LUA_T_CLOSURE:
- sprintf(buff, "function: %p", (void *)o->value.cl);
- break;
- case LUA_T_PROTO:
- sprintf(buff, "function: %p", (void *)o->value.tf);
- break;
- case LUA_T_CPROTO:
- sprintf(buff, "function: %p", (void *)o->value.f);
- break;
- case LUA_T_USERDATA:
- sprintf(buff, "userdata: %p", o->value.ts->u.d.v);
- break;
- case LUA_T_NIL:
- lua_pushstring("nil");
- return;
- default:
- LUA_INTERNALERROR("invalid type");
- }
- lua_pushstring(buff);
-}
-
-
-static void luaB_type (void) {
- lua_Object o = luaL_nonnullarg(1);
- lua_pushstring(luaO_typename(luaA_Address(o)));
- lua_pushnumber(lua_tag(o));
-}
-
-/* }====================================================== */
-
-
-
-/*
-** {======================================================
-** "Extra" functions
-** These functions can be written in Lua, so you can
-** delete them if you need a tiny Lua implementation.
-** If you delete them, remove their entries in array
-** "builtin_funcs".
-** =======================================================
-*/
-
-static void luaB_assert (void) {
- lua_Object p = lua_getparam(1);
- if (p == LUA_NOOBJECT || lua_isnil(p))
- luaL_verror("assertion failed! %.100s", luaL_opt_string(2, ""));
-}
-
-
-static void luaB_foreachi (void) {
- Hash *t = gethash(1);
- int i;
- int n = (int)getnarg(t);
- TObject f;
- /* 'f' cannot be a pointer to TObject, because it is on the stack, and the
- stack may be reallocated by the call. Moreover, some C compilers do not
- initialize structs, so we must do the assignment after the declaration */
- f = *luaA_Address(luaL_functionarg(2));
- luaD_checkstack(3); /* for f, ref, and val */
- for (i=1; i<=n; i++) {
- *(L->stack.top++) = f;
- ttype(L->stack.top) = LUA_T_NUMBER; nvalue(L->stack.top++) = i;
- *(L->stack.top++) = *luaH_getint(t, i);
- luaD_calln(2, 1);
- if (ttype(L->stack.top-1) != LUA_T_NIL)
- return;
- L->stack.top--;
- }
-}
-
-
-static void luaB_foreach (void) {
- Hash *a = gethash(1);
- int i;
- TObject f; /* see comment in 'foreachi' */
- f = *luaA_Address(luaL_functionarg(2));
- luaD_checkstack(3); /* for f, ref, and val */
- for (i=0; i<a->nhash; i++) {
- Node *nd = &(a->node[i]);
- if (ttype(val(nd)) != LUA_T_NIL) {
- *(L->stack.top++) = f;
- *(L->stack.top++) = *ref(nd);
- *(L->stack.top++) = *val(nd);
- luaD_calln(2, 1);
- if (ttype(L->stack.top-1) != LUA_T_NIL)
- return;
- L->stack.top--; /* remove result */
- }
- }
-}
-
-
-static void luaB_foreachvar (void) {
- GCnode *g;
- TObject f; /* see comment in 'foreachi' */
- f = *luaA_Address(luaL_functionarg(1));
- luaD_checkstack(4); /* for extra var name, f, var name, and globalval */
- for (g = L->rootglobal.next; g; g = g->next) {
- TaggedString *s = (TaggedString *)g;
- if (s->u.s.globalval.ttype != LUA_T_NIL) {
- pushtagstring(s); /* keep (extra) s on stack to avoid GC */
- *(L->stack.top++) = f;
- pushtagstring(s);
- *(L->stack.top++) = s->u.s.globalval;
- luaD_calln(2, 1);
- if (ttype(L->stack.top-1) != LUA_T_NIL) {
- L->stack.top--;
- *(L->stack.top-1) = *L->stack.top; /* remove extra s */
- return;
- }
- L->stack.top-=2; /* remove result and extra s */
- }
- }
-}
-
-
-static void luaB_getn (void) {
- lua_pushnumber(getnarg(gethash(1)));
-}
-
-
-static void luaB_tinsert (void) {
- Hash *a = gethash(1);
- lua_Object v = lua_getparam(3);
- int n = (int)getnarg(a);
- int pos;
- if (v != LUA_NOOBJECT)
- pos = luaL_check_int(2);
- else { /* called with only 2 arguments */
- v = luaL_nonnullarg(2);
- pos = n+1;
- }
- luaV_setn(a, n+1); /* a.n = n+1 */
- for ( ;n>=pos; n--)
- luaH_move(a, n, n+1); /* a[n+1] = a[n] */
- luaH_setint(a, pos, luaA_Address(v)); /* a[pos] = v */
-}
-
-
-static void luaB_tremove (void) {
- Hash *a = gethash(1);
- int n = (int)getnarg(a);
- int pos = luaL_opt_int(2, n);
- if (n <= 0) return; /* table is "empty" */
- luaA_pushobject(luaH_getint(a, pos)); /* result = a[pos] */
- for ( ;pos<n; pos++)
- luaH_move(a, pos+1, pos); /* a[pos] = a[pos+1] */
- luaV_setn(a, n-1); /* a.n = n-1 */
- luaH_setint(a, n, &luaO_nilobject); /* a[n] = nil */
-}
-
-
-/* {
-** Quicksort
-*/
-
-static void swap (Hash *a, int i, int j) {
- TObject temp;
- temp = *luaH_getint(a, i);
- luaH_move(a, j, i);
- luaH_setint(a, j, &temp);
-}
-
-static int sort_comp (lua_Object f, TObject *a, TObject *b) {
- /* notice: the caller (auxsort) must check stack space */
- if (f != LUA_NOOBJECT) {
- *(L->stack.top) = *luaA_Address(f);
- *(L->stack.top+1) = *a;
- *(L->stack.top+2) = *b;
- L->stack.top += 3;
- luaD_calln(2, 1);
- }
- else { /* a < b? */
- *(L->stack.top) = *a;
- *(L->stack.top+1) = *b;
- L->stack.top += 2;
- luaV_comparison(LUA_T_NUMBER, LUA_T_NIL, LUA_T_NIL, IM_LT);
- }
- return ttype(--(L->stack.top)) != LUA_T_NIL;
-}
-
-static void auxsort (Hash *a, int l, int u, lua_Object f) {
- while (l < u) { /* for tail recursion */
- TObject *P;
- int i, j;
- /* sort elements a[l], a[(l+u)/2] and a[u] */
- if (sort_comp(f, luaH_getint(a, u), luaH_getint(a, l))) /* a[l]>a[u]? */
- swap(a, l, u);
- if (u-l == 1) break; /* only 2 elements */
- i = (l+u)/2;
- P = luaH_getint(a, i);
- if (sort_comp(f, P, luaH_getint(a, l))) /* a[l]>a[i]? */
- swap(a, l, i);
- else if (sort_comp(f, luaH_getint(a, u), P)) /* a[i]>a[u]? */
- swap(a, i, u);
- if (u-l == 2) break; /* only 3 elements */
- P = L->stack.top++;
- *P = *luaH_getint(a, i); /* save pivot on stack (for GC) */
- swap(a, i, u-1); /* put median element as pivot (a[u-1]) */
- /* a[l] <= P == a[u-1] <= a[u], only needs to sort from l+1 to u-2 */
- i = l; j = u-1;
- for (;;) {
- /* invariant: a[l..i] <= P <= a[j..u] */
- while (sort_comp(f, luaH_getint(a, ++i), P)) /* stop when a[i] >= P */
- if (i>u) lua_error("invalid order function for sorting");
- while (sort_comp(f, P, luaH_getint(a, --j))) /* stop when a[j] <= P */
- if (j<l) lua_error("invalid order function for sorting");
- if (j<i) break;
- swap(a, i, j);
- }
- swap(a, u-1, i); /* swap pivot (a[u-1]) with a[i] */
- L->stack.top--; /* remove pivot from stack */
- /* a[l..i-1] <= a[i] == P <= a[i+1..u] */
- /* adjust so that smaller "half" is in [j..i] and larger one in [l..u] */
- if (i-l < u-i) {
- j=l; i=i-1; l=i+2;
- }
- else {
- j=i+1; i=u; u=j-2;
- }
- auxsort(a, j, i, f); /* call recursively the smaller one */
- } /* repeat the routine for the larger one */
-}
-
-static void luaB_sort (void) {
- lua_Object t = lua_getparam(1);
- Hash *a = gethash(1);
- int n = (int)getnarg(a);
- lua_Object func = lua_getparam(2);
- luaL_arg_check(func == LUA_NOOBJECT || lua_isfunction(func), 2,
- "function expected");
- luaD_checkstack(4); /* for Pivot, f, a, b (sort_comp) */
- auxsort(a, 1, n, func);
- lua_pushobject(t);
-}
-
-/* }}===================================================== */
-
-
-/*
-** ====================================================== */
-
-
-
-#ifdef DEBUG
-/*
-** {======================================================
-** some DEBUG functions
-** =======================================================
-*/
-
-static void mem_query (void) {
- lua_pushnumber(totalmem);
- lua_pushnumber(numblocks);
-}
-
-
-static void query_strings (void) {
- lua_pushnumber(L->string_root[luaL_check_int(1)].nuse);
-}
-
-
-static void countlist (void) {
- char *s = luaL_check_string(1);
- GCnode *l = (s[0]=='t') ? L->roottable.next : (s[0]=='c') ? L->rootcl.next :
- (s[0]=='p') ? L->rootproto.next : L->rootglobal.next;
- int i=0;
- while (l) {
- i++;
- l = l->next;
- }
- lua_pushnumber(i);
-}
-
-
-static void testC (void) {
-#define getnum(s) ((*s++) - '0')
-#define getname(s) (nome[0] = *s++, nome)
-
- static int locks[10];
- lua_Object reg[10];
- char nome[2];
- char *s = luaL_check_string(1);
- nome[1] = 0;
- for (;;) {
- switch (*s++) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- lua_pushnumber(*(s-1) - '0');
- break;
-
- case 'c': reg[getnum(s)] = lua_createtable(); break;
- case 'C': { lua_CFunction f = lua_getcfunction(lua_getglobal(getname(s)));
- lua_pushcclosure(f, getnum(s));
- break;
- }
- case 'P': reg[getnum(s)] = lua_pop(); break;
- case 'g': { int n=getnum(s); reg[n]=lua_getglobal(getname(s)); break; }
- case 'G': { int n = getnum(s);
- reg[n] = lua_rawgetglobal(getname(s));
- break;
- }
- case 'l': locks[getnum(s)] = lua_ref(1); break;
- case 'L': locks[getnum(s)] = lua_ref(0); break;
- case 'r': { int n=getnum(s); reg[n]=lua_getref(locks[getnum(s)]); break; }
- case 'u': lua_unref(locks[getnum(s)]); break;
- case 'p': { int n = getnum(s); reg[n] = lua_getparam(getnum(s)); break; }
- case '=': lua_setglobal(getname(s)); break;
- case 's': lua_pushstring(getname(s)); break;
- case 'o': lua_pushobject(reg[getnum(s)]); break;
- case 'f': lua_call(getname(s)); break;
- case 'i': reg[getnum(s)] = lua_gettable(); break;
- case 'I': reg[getnum(s)] = lua_rawgettable(); break;
- case 't': lua_settable(); break;
- case 'T': lua_rawsettable(); break;
- case 'N' : lua_pushstring(lua_nextvar(lua_getstring(reg[getnum(s)])));
- break;
- case 'n' : { int n=getnum(s);
- n=lua_next(reg[n], (int)lua_getnumber(reg[getnum(s)]));
- lua_pushnumber(n); break;
- }
- default: luaL_verror("unknown command in `testC': %c", *(s-1));
- }
- if (*s == 0) return;
- if (*s++ != ' ') lua_error("missing ` ' between commands in `testC'");
- }
-}
-
-/* }====================================================== */
-#endif
-
-
-
-static struct luaL_reg builtin_funcs[] = {
-#ifdef LUA_COMPAT2_5
- {"setfallback", luaT_setfallback},
-#endif
-#ifdef DEBUG
- {"testC", testC},
- {"totalmem", mem_query},
- {"count", countlist},
- {"querystr", query_strings},
-#endif
- {"_ALERT", luaB_alert},
- {"_ERRORMESSAGE", error_message},
- {"call", luaB_call},
- {"collectgarbage", luaB_collectgarbage},
- {"copytagmethods", luaB_copytagmethods},
- {"dofile", luaB_dofile},
- {"dostring", luaB_dostring},
- {"error", luaB_error},
- {"getglobal", luaB_getglobal},
- {"gettagmethod", luaB_gettagmethod},
- {"newtag", luaB_newtag},
- {"next", luaB_next},
- {"nextvar", luaB_nextvar},
- {"print", luaB_print},
- {"rawgetglobal", luaB_rawgetglobal},
- {"rawgettable", luaB_rawgettable},
- {"rawsetglobal", luaB_rawsetglobal},
- {"rawsettable", luaB_rawsettable},
- {"seterrormethod", luaB_seterrormethod},
- {"setglobal", luaB_setglobal},
- {"settag", luaB_settag},
- {"settagmethod", luaB_settagmethod},
- {"tag", luaB_luatag},
- {"tonumber", luaB_tonumber},
- {"tostring", luaB_tostring},
- {"type", luaB_type},
- /* "Extra" functions */
- {"assert", luaB_assert},
- {"foreach", luaB_foreach},
- {"foreachi", luaB_foreachi},
- {"foreachvar", luaB_foreachvar},
- {"getn", luaB_getn},
- {"sort", luaB_sort},
- {"tinsert", luaB_tinsert},
- {"tremove", luaB_tremove}
-};
-
-
-#define INTFUNCSIZE (sizeof(builtin_funcs)/sizeof(builtin_funcs[0]))
-
-
-void luaB_predefine (void) {
- /* pre-register mem error messages, to avoid loop when error arises */
- luaS_newfixedstring(tableEM);
- luaS_newfixedstring(memEM);
- luaL_openlib(builtin_funcs, (sizeof(builtin_funcs)/sizeof(builtin_funcs[0])));
- lua_pushstring(LUA_VERSION);
- lua_setglobal("_VERSION");
-}
-
diff --git a/src/lbuiltin.h b/src/lbuiltin.h
deleted file mode 100644
index bcb11fc0..00000000
--- a/src/lbuiltin.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
-** $Id: lbuiltin.h,v 1.1 1997/09/16 19:25:59 roberto Exp $
-** Built-in functions
-** See Copyright Notice in lua.h
-*/
-
-#ifndef lbuiltin_h
-#define lbuiltin_h
-
-
-void luaB_predefine (void);
-
-
-#endif
diff --git a/src/lcode.c b/src/lcode.c
new file mode 100644
index 00000000..6882240d
--- /dev/null
+++ b/src/lcode.c
@@ -0,0 +1,701 @@
+/*
+** $Id: lcode.c,v 1.51 2000/09/29 12:42:13 roberto Exp $
+** Code generator for Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#include "stdlib.h"
+
+#include "lua.h"
+
+#include "lcode.h"
+#include "ldo.h"
+#include "llex.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+
+
+void luaK_error (LexState *ls, const char *msg) {
+ luaX_error(ls, msg, ls->t.token);
+}
+
+
+/*
+** Returns the the previous instruction, for optimizations.
+** If there is a jump target between this and the current instruction,
+** returns a dummy instruction to avoid wrong optimizations.
+*/
+static Instruction previous_instruction (FuncState *fs) {
+ if (fs->pc > fs->lasttarget) /* no jumps to current position? */
+ return fs->f->code[fs->pc-1]; /* returns previous instruction */
+ else
+ return CREATE_0(OP_END); /* no optimizations after an `END' */
+}
+
+
+int luaK_jump (FuncState *fs) {
+ int j = luaK_code1(fs, OP_JMP, NO_JUMP);
+ if (j == fs->lasttarget) { /* possible jumps to this jump? */
+ luaK_concat(fs, &j, fs->jlt); /* keep them on hold */
+ fs->jlt = NO_JUMP;
+ }
+ return j;
+}
+
+
+static void luaK_fixjump (FuncState *fs, int pc, int dest) {
+ Instruction *jmp = &fs->f->code[pc];
+ if (dest == NO_JUMP)
+ SETARG_S(*jmp, NO_JUMP); /* point to itself to represent end of list */
+ else { /* jump is relative to position following jump instruction */
+ int offset = dest-(pc+1);
+ if (abs(offset) > MAXARG_S)
+ luaK_error(fs->ls, "control structure too long");
+ SETARG_S(*jmp, offset);
+ }
+}
+
+
+static int luaK_getjump (FuncState *fs, int pc) {
+ int offset = GETARG_S(fs->f->code[pc]);
+ if (offset == NO_JUMP) /* point to itself represents end of list */
+ return NO_JUMP; /* end of list */
+ else
+ return (pc+1)+offset; /* turn offset into absolute position */
+}
+
+
+/*
+** returns current `pc' and marks it as a jump target (to avoid wrong
+** optimizations with consecutive instructions not in the same basic block).
+** discharge list of jumps to last target.
+*/
+int luaK_getlabel (FuncState *fs) {
+ if (fs->pc != fs->lasttarget) {
+ int lasttarget = fs->lasttarget;
+ fs->lasttarget = fs->pc;
+ luaK_patchlist(fs, fs->jlt, lasttarget); /* discharge old list `jlt' */
+ fs->jlt = NO_JUMP; /* nobody jumps to this new label (yet) */
+ }
+ return fs->pc;
+}
+
+
+void luaK_deltastack (FuncState *fs, int delta) {
+ fs->stacklevel += delta;
+ if (fs->stacklevel > fs->f->maxstacksize) {
+ if (fs->stacklevel > MAXSTACK)
+ luaK_error(fs->ls, "function or expression too complex");
+ fs->f->maxstacksize = fs->stacklevel;
+ }
+}
+
+
+void luaK_kstr (LexState *ls, int c) {
+ luaK_code1(ls->fs, OP_PUSHSTRING, c);
+}
+
+
+static int number_constant (FuncState *fs, Number r) {
+ /* check whether `r' has appeared within the last LOOKBACKNUMS entries */
+ Proto *f = fs->f;
+ int c = f->nknum;
+ int lim = c < LOOKBACKNUMS ? 0 : c-LOOKBACKNUMS;
+ while (--c >= lim)
+ if (f->knum[c] == r) return c;
+ /* not found; create a new entry */
+ luaM_growvector(fs->L, f->knum, f->nknum, 1, Number,
+ "constant table overflow", MAXARG_U);
+ c = f->nknum++;
+ f->knum[c] = r;
+ return c;
+}
+
+
+void luaK_number (FuncState *fs, Number f) {
+ if (f <= (Number)MAXARG_S && (Number)(int)f == f)
+ luaK_code1(fs, OP_PUSHINT, (int)f); /* f has a short integer value */
+ else
+ luaK_code1(fs, OP_PUSHNUM, number_constant(fs, f));
+}
+
+
+void luaK_adjuststack (FuncState *fs, int n) {
+ if (n > 0)
+ luaK_code1(fs, OP_POP, n);
+ else
+ luaK_code1(fs, OP_PUSHNIL, -n);
+}
+
+
+int luaK_lastisopen (FuncState *fs) {
+ /* check whether last instruction is an open function call */
+ Instruction i = previous_instruction(fs);
+ if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET)
+ return 1;
+ else return 0;
+}
+
+
+void luaK_setcallreturns (FuncState *fs, int nresults) {
+ if (luaK_lastisopen(fs)) { /* expression is an open function call? */
+ SETARG_B(fs->f->code[fs->pc-1], nresults); /* set number of results */
+ luaK_deltastack(fs, nresults); /* push results */
+ }
+}
+
+
+static int discharge (FuncState *fs, expdesc *var) {
+ switch (var->k) {
+ case VLOCAL:
+ luaK_code1(fs, OP_GETLOCAL, var->u.index);
+ break;
+ case VGLOBAL:
+ luaK_code1(fs, OP_GETGLOBAL, var->u.index);
+ break;
+ case VINDEXED:
+ luaK_code0(fs, OP_GETTABLE);
+ break;
+ case VEXP:
+ return 0; /* nothing to do */
+ }
+ var->k = VEXP;
+ var->u.l.t = var->u.l.f = NO_JUMP;
+ return 1;
+}
+
+
+static void discharge1 (FuncState *fs, expdesc *var) {
+ discharge(fs, var);
+ /* if it has jumps then it is already discharged */
+ if (var->u.l.t == NO_JUMP && var->u.l.f == NO_JUMP)
+ luaK_setcallreturns(fs, 1); /* call must return 1 value */
+}
+
+
+void luaK_storevar (LexState *ls, const expdesc *var) {
+ FuncState *fs = ls->fs;
+ switch (var->k) {
+ case VLOCAL:
+ luaK_code1(fs, OP_SETLOCAL, var->u.index);
+ break;
+ case VGLOBAL:
+ luaK_code1(fs, OP_SETGLOBAL, var->u.index);
+ break;
+ case VINDEXED: /* table is at top-3; pop 3 elements after operation */
+ luaK_code2(fs, OP_SETTABLE, 3, 3);
+ break;
+ default:
+ LUA_INTERNALERROR("invalid var kind to store");
+ }
+}
+
+
+static OpCode invertjump (OpCode op) {
+ switch (op) {
+ case OP_JMPNE: return OP_JMPEQ;
+ case OP_JMPEQ: return OP_JMPNE;
+ case OP_JMPLT: return OP_JMPGE;
+ case OP_JMPLE: return OP_JMPGT;
+ case OP_JMPGT: return OP_JMPLE;
+ case OP_JMPGE: return OP_JMPLT;
+ case OP_JMPT: case OP_JMPONT: return OP_JMPF;
+ case OP_JMPF: case OP_JMPONF: return OP_JMPT;
+ default:
+ LUA_INTERNALERROR("invalid jump instruction");
+ return OP_END; /* to avoid warnings */
+ }
+}
+
+
+static void luaK_patchlistaux (FuncState *fs, int list, int target,
+ OpCode special, int special_target) {
+ Instruction *code = fs->f->code;
+ while (list != NO_JUMP) {
+ int next = luaK_getjump(fs, list);
+ Instruction *i = &code[list];
+ OpCode op = GET_OPCODE(*i);
+ if (op == special) /* this `op' already has a value */
+ luaK_fixjump(fs, list, special_target);
+ else {
+ luaK_fixjump(fs, list, target); /* do the patch */
+ if (op == OP_JMPONT) /* remove eventual values */
+ SET_OPCODE(*i, OP_JMPT);
+ else if (op == OP_JMPONF)
+ SET_OPCODE(*i, OP_JMPF);
+ }
+ list = next;
+ }
+}
+
+
+void luaK_patchlist (FuncState *fs, int list, int target) {
+ if (target == fs->lasttarget) /* same target that list `jlt'? */
+ luaK_concat(fs, &fs->jlt, list); /* delay fixing */
+ else
+ luaK_patchlistaux(fs, list, target, OP_END, 0);
+}
+
+
+static int need_value (FuncState *fs, int list, OpCode hasvalue) {
+ /* check whether list has a jump without a value */
+ for (; list != NO_JUMP; list = luaK_getjump(fs, list))
+ if (GET_OPCODE(fs->f->code[list]) != hasvalue) return 1;
+ return 0; /* not found */
+}
+
+
+void luaK_concat (FuncState *fs, int *l1, int l2) {
+ if (*l1 == NO_JUMP)
+ *l1 = l2;
+ else {
+ int list = *l1;
+ for (;;) { /* traverse `l1' */
+ int next = luaK_getjump(fs, list);
+ if (next == NO_JUMP) { /* end of list? */
+ luaK_fixjump(fs, list, l2);
+ return;
+ }
+ list = next;
+ }
+ }
+}
+
+
+static void luaK_testgo (FuncState *fs, expdesc *v, int invert, OpCode jump) {
+ int prevpos; /* position of last instruction */
+ Instruction *previous;
+ int *golist, *exitlist;
+ if (!invert) {
+ golist = &v->u.l.f; /* go if false */
+ exitlist = &v->u.l.t; /* exit if true */
+ }
+ else {
+ golist = &v->u.l.t; /* go if true */
+ exitlist = &v->u.l.f; /* exit if false */
+ }
+ discharge1(fs, v);
+ prevpos = fs->pc-1;
+ previous = &fs->f->code[prevpos];
+ LUA_ASSERT(*previous==previous_instruction(fs), "no jump allowed here");
+ if (!ISJUMP(GET_OPCODE(*previous)))
+ prevpos = luaK_code1(fs, jump, NO_JUMP);
+ else { /* last instruction is already a jump */
+ if (invert)
+ SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous)));
+ }
+ luaK_concat(fs, exitlist, prevpos); /* insert last jump in `exitlist' */
+ luaK_patchlist(fs, *golist, luaK_getlabel(fs));
+ *golist = NO_JUMP;
+}
+
+
+void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue) {
+ luaK_testgo(fs, v, 1, keepvalue ? OP_JMPONF : OP_JMPF);
+}
+
+
+static void luaK_goiffalse (FuncState *fs, expdesc *v, int keepvalue) {
+ luaK_testgo(fs, v, 0, keepvalue ? OP_JMPONT : OP_JMPT);
+}
+
+
+static int code_label (FuncState *fs, OpCode op, int arg) {
+ luaK_getlabel(fs); /* those instructions may be jump targets */
+ return luaK_code1(fs, op, arg);
+}
+
+
+void luaK_tostack (LexState *ls, expdesc *v, int onlyone) {
+ FuncState *fs = ls->fs;
+ if (!discharge(fs, v)) { /* `v' is an expression? */
+ OpCode previous = GET_OPCODE(fs->f->code[fs->pc-1]);
+ if (!ISJUMP(previous) && v->u.l.f == NO_JUMP && v->u.l.t == NO_JUMP) {
+ /* expression has no jumps */
+ if (onlyone)
+ luaK_setcallreturns(fs, 1); /* call must return 1 value */
+ }
+ else { /* expression has jumps */
+ int final; /* position after whole expression */
+ int j = NO_JUMP; /* eventual jump over values */
+ int p_nil = NO_JUMP; /* position of an eventual PUSHNIL */
+ int p_1 = NO_JUMP; /* position of an eventual PUSHINT */
+ if (ISJUMP(previous) || need_value(fs, v->u.l.f, OP_JMPONF)
+ || need_value(fs, v->u.l.t, OP_JMPONT)) {
+ /* expression needs values */
+ if (ISJUMP(previous))
+ luaK_concat(fs, &v->u.l.t, fs->pc-1); /* put `previous' in t. list */
+ else {
+ j = code_label(fs, OP_JMP, NO_JUMP); /* to jump over both pushes */
+ /* correct stack for compiler and symbolic execution */
+ luaK_adjuststack(fs, 1);
+ }
+ p_nil = code_label(fs, OP_PUSHNILJMP, 0);
+ p_1 = code_label(fs, OP_PUSHINT, 1);
+ luaK_patchlist(fs, j, luaK_getlabel(fs));
+ }
+ final = luaK_getlabel(fs);
+ luaK_patchlistaux(fs, v->u.l.f, p_nil, OP_JMPONF, final);
+ luaK_patchlistaux(fs, v->u.l.t, p_1, OP_JMPONT, final);
+ v->u.l.f = v->u.l.t = NO_JUMP;
+ }
+ }
+}
+
+
+void luaK_prefix (LexState *ls, UnOpr op, expdesc *v) {
+ FuncState *fs = ls->fs;
+ if (op == OPR_MINUS) {
+ luaK_tostack(ls, v, 1);
+ luaK_code0(fs, OP_MINUS);
+ }
+ else { /* op == NOT */
+ Instruction *previous;
+ discharge1(fs, v);
+ previous = &fs->f->code[fs->pc-1];
+ if (ISJUMP(GET_OPCODE(*previous)))
+ SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous)));
+ else
+ luaK_code0(fs, OP_NOT);
+ /* interchange true and false lists */
+ { int temp = v->u.l.f; v->u.l.f = v->u.l.t; v->u.l.t = temp; }
+ }
+}
+
+
+void luaK_infix (LexState *ls, BinOpr op, expdesc *v) {
+ FuncState *fs = ls->fs;
+ switch (op) {
+ case OPR_AND:
+ luaK_goiftrue(fs, v, 1);
+ break;
+ case OPR_OR:
+ luaK_goiffalse(fs, v, 1);
+ break;
+ default:
+ luaK_tostack(ls, v, 1); /* all other binary operators need a value */
+ }
+}
+
+
+
+static const struct {
+ OpCode opcode; /* opcode for each binary operator */
+ int arg; /* default argument for the opcode */
+} codes[] = { /* ORDER OPR */
+ {OP_ADD, 0}, {OP_SUB, 0}, {OP_MULT, 0}, {OP_DIV, 0},
+ {OP_POW, 0}, {OP_CONCAT, 2},
+ {OP_JMPNE, NO_JUMP}, {OP_JMPEQ, NO_JUMP},
+ {OP_JMPLT, NO_JUMP}, {OP_JMPLE, NO_JUMP},
+ {OP_JMPGT, NO_JUMP}, {OP_JMPGE, NO_JUMP}
+};
+
+
+void luaK_posfix (LexState *ls, BinOpr op, expdesc *v1, expdesc *v2) {
+ FuncState *fs = ls->fs;
+ switch (op) {
+ case OPR_AND: {
+ LUA_ASSERT(v1->u.l.t == NO_JUMP, "list must be closed");
+ discharge1(fs, v2);
+ v1->u.l.t = v2->u.l.t;
+ luaK_concat(fs, &v1->u.l.f, v2->u.l.f);
+ break;
+ }
+ case OPR_OR: {
+ LUA_ASSERT(v1->u.l.f == NO_JUMP, "list must be closed");
+ discharge1(fs, v2);
+ v1->u.l.f = v2->u.l.f;
+ luaK_concat(fs, &v1->u.l.t, v2->u.l.t);
+ break;
+ }
+ default: {
+ luaK_tostack(ls, v2, 1); /* `v2' must be a value */
+ luaK_code1(fs, codes[op].opcode, codes[op].arg);
+ }
+ }
+}
+
+
+static void codelineinfo (FuncState *fs) {
+ Proto *f = fs->f;
+ LexState *ls = fs->ls;
+ if (ls->lastline > fs->lastline) {
+ luaM_growvector(fs->L, f->lineinfo, f->nlineinfo, 2, int,
+ "line info overflow", MAX_INT);
+ if (ls->lastline > fs->lastline+1)
+ f->lineinfo[f->nlineinfo++] = -(ls->lastline - (fs->lastline+1));
+ f->lineinfo[f->nlineinfo++] = fs->pc;
+ fs->lastline = ls->lastline;
+ }
+}
+
+
+int luaK_code0 (FuncState *fs, OpCode o) {
+ return luaK_code2(fs, o, 0, 0);
+}
+
+
+int luaK_code1 (FuncState *fs, OpCode o, int arg1) {
+ return luaK_code2(fs, o, arg1, 0);
+}
+
+
+int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
+ Instruction i = previous_instruction(fs);
+ int delta = luaK_opproperties[o].push - luaK_opproperties[o].pop;
+ int optm = 0; /* 1 when there is an optimization */
+ switch (o) {
+ case OP_CLOSURE: {
+ delta = -arg2+1;
+ break;
+ }
+ case OP_SETTABLE: {
+ delta = -arg2;
+ break;
+ }
+ case OP_SETLIST: {
+ if (arg2 == 0) return NO_JUMP; /* nothing to do */
+ delta = -arg2;
+ break;
+ }
+ case OP_SETMAP: {
+ if (arg1 == 0) return NO_JUMP; /* nothing to do */
+ delta = -2*arg1;
+ break;
+ }
+ case OP_RETURN: {
+ if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET) {
+ SET_OPCODE(i, OP_TAILCALL);
+ SETARG_B(i, arg1);
+ optm = 1;
+ }
+ break;
+ }
+ case OP_PUSHNIL: {
+ if (arg1 == 0) return NO_JUMP; /* nothing to do */
+ delta = arg1;
+ switch(GET_OPCODE(i)) {
+ case OP_PUSHNIL: SETARG_U(i, GETARG_U(i)+arg1); optm = 1; break;
+ default: break;
+ }
+ break;
+ }
+ case OP_POP: {
+ if (arg1 == 0) return NO_JUMP; /* nothing to do */
+ delta = -arg1;
+ switch(GET_OPCODE(i)) {
+ case OP_SETTABLE: SETARG_B(i, GETARG_B(i)+arg1); optm = 1; break;
+ default: break;
+ }
+ break;
+ }
+ case OP_GETTABLE: {
+ switch(GET_OPCODE(i)) {
+ case OP_PUSHSTRING: /* `t.x' */
+ SET_OPCODE(i, OP_GETDOTTED);
+ optm = 1;
+ break;
+ case OP_GETLOCAL: /* `t[i]' */
+ SET_OPCODE(i, OP_GETINDEXED);
+ optm = 1;
+ break;
+ default: break;
+ }
+ break;
+ }
+ case OP_ADD: {
+ switch(GET_OPCODE(i)) {
+ case OP_PUSHINT: SET_OPCODE(i, OP_ADDI); optm = 1; break; /* `a+k' */
+ default: break;
+ }
+ break;
+ }
+ case OP_SUB: {
+ switch(GET_OPCODE(i)) {
+ case OP_PUSHINT: /* `a-k' */
+ i = CREATE_S(OP_ADDI, -GETARG_S(i));
+ optm = 1;
+ break;
+ default: break;
+ }
+ break;
+ }
+ case OP_CONCAT: {
+ delta = -arg1+1;
+ switch(GET_OPCODE(i)) {
+ case OP_CONCAT: /* `a..b..c' */
+ SETARG_U(i, GETARG_U(i)+1);
+ optm = 1;
+ break;
+ default: break;
+ }
+ break;
+ }
+ case OP_MINUS: {
+ switch(GET_OPCODE(i)) {
+ case OP_PUSHINT: /* `-k' */
+ SETARG_S(i, -GETARG_S(i));
+ optm = 1;
+ break;
+ case OP_PUSHNUM: /* `-k' */
+ SET_OPCODE(i, OP_PUSHNEGNUM);
+ optm = 1;
+ break;
+ default: break;
+ }
+ break;
+ }
+ case OP_JMPNE: {
+ if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a~=nil' */
+ i = CREATE_S(OP_JMPT, NO_JUMP);
+ optm = 1;
+ }
+ break;
+ }
+ case OP_JMPEQ: {
+ if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a==nil' */
+ i = CREATE_0(OP_NOT);
+ delta = -1; /* just undo effect of previous PUSHNIL */
+ optm = 1;
+ }
+ break;
+ }
+ case OP_JMPT:
+ case OP_JMPONT: {
+ switch (GET_OPCODE(i)) {
+ case OP_NOT: {
+ i = CREATE_S(OP_JMPF, NO_JUMP);
+ optm = 1;
+ break;
+ }
+ case OP_PUSHINT: {
+ if (o == OP_JMPT) { /* JMPONT must keep original integer value */
+ i = CREATE_S(OP_JMP, NO_JUMP);
+ optm = 1;
+ }
+ break;
+ }
+ case OP_PUSHNIL: {
+ if (GETARG_U(i) == 1) {
+ fs->pc--; /* erase previous instruction */
+ luaK_deltastack(fs, -1); /* correct stack */
+ return NO_JUMP;
+ }
+ break;
+ }
+ default: break;
+ }
+ break;
+ }
+ case OP_JMPF:
+ case OP_JMPONF: {
+ switch (GET_OPCODE(i)) {
+ case OP_NOT: {
+ i = CREATE_S(OP_JMPT, NO_JUMP);
+ optm = 1;
+ break;
+ }
+ case OP_PUSHINT: { /* `while 1 do ...' */
+ fs->pc--; /* erase previous instruction */
+ luaK_deltastack(fs, -1); /* correct stack */
+ return NO_JUMP;
+ }
+ case OP_PUSHNIL: { /* `repeat ... until nil' */
+ if (GETARG_U(i) == 1) {
+ i = CREATE_S(OP_JMP, NO_JUMP);
+ optm = 1;
+ }
+ break;
+ }
+ default: break;
+ }
+ break;
+ }
+ case OP_GETDOTTED:
+ case OP_GETINDEXED:
+ case OP_TAILCALL:
+ case OP_ADDI: {
+ LUA_INTERNALERROR("instruction used only for optimizations");
+ break;
+ }
+ default: {
+ LUA_ASSERT(delta != VD, "invalid delta");
+ break;
+ }
+ }
+ luaK_deltastack(fs, delta);
+ if (optm) { /* optimize: put instruction in place of last one */
+ fs->f->code[fs->pc-1] = i; /* change previous instruction */
+ return fs->pc-1; /* do not generate new instruction */
+ }
+ /* else build new instruction */
+ switch ((enum Mode)luaK_opproperties[o].mode) {
+ case iO: i = CREATE_0(o); break;
+ case iU: i = CREATE_U(o, arg1); break;
+ case iS: i = CREATE_S(o, arg1); break;
+ case iAB: i = CREATE_AB(o, arg1, arg2); break;
+ }
+ codelineinfo(fs);
+ /* put new instruction in code array */
+ luaM_growvector(fs->L, fs->f->code, fs->pc, 1, Instruction,
+ "code size overflow", MAX_INT);
+ fs->f->code[fs->pc] = i;
+ return fs->pc++;
+}
+
+
+const struct OpProperties luaK_opproperties[NUM_OPCODES] = {
+ {iO, 0, 0}, /* OP_END */
+ {iU, 0, 0}, /* OP_RETURN */
+ {iAB, 0, 0}, /* OP_CALL */
+ {iAB, 0, 0}, /* OP_TAILCALL */
+ {iU, VD, 0}, /* OP_PUSHNIL */
+ {iU, VD, 0}, /* OP_POP */
+ {iS, 1, 0}, /* OP_PUSHINT */
+ {iU, 1, 0}, /* OP_PUSHSTRING */
+ {iU, 1, 0}, /* OP_PUSHNUM */
+ {iU, 1, 0}, /* OP_PUSHNEGNUM */
+ {iU, 1, 0}, /* OP_PUSHUPVALUE */
+ {iU, 1, 0}, /* OP_GETLOCAL */
+ {iU, 1, 0}, /* OP_GETGLOBAL */
+ {iO, 1, 2}, /* OP_GETTABLE */
+ {iU, 1, 1}, /* OP_GETDOTTED */
+ {iU, 1, 1}, /* OP_GETINDEXED */
+ {iU, 2, 1}, /* OP_PUSHSELF */
+ {iU, 1, 0}, /* OP_CREATETABLE */
+ {iU, 0, 1}, /* OP_SETLOCAL */
+ {iU, 0, 1}, /* OP_SETGLOBAL */
+ {iAB, VD, 0}, /* OP_SETTABLE */
+ {iAB, VD, 0}, /* OP_SETLIST */
+ {iU, VD, 0}, /* OP_SETMAP */
+ {iO, 1, 2}, /* OP_ADD */
+ {iS, 1, 1}, /* OP_ADDI */
+ {iO, 1, 2}, /* OP_SUB */
+ {iO, 1, 2}, /* OP_MULT */
+ {iO, 1, 2}, /* OP_DIV */
+ {iO, 1, 2}, /* OP_POW */
+ {iU, VD, 0}, /* OP_CONCAT */
+ {iO, 1, 1}, /* OP_MINUS */
+ {iO, 1, 1}, /* OP_NOT */
+ {iS, 0, 2}, /* OP_JMPNE */
+ {iS, 0, 2}, /* OP_JMPEQ */
+ {iS, 0, 2}, /* OP_JMPLT */
+ {iS, 0, 2}, /* OP_JMPLE */
+ {iS, 0, 2}, /* OP_JMPGT */
+ {iS, 0, 2}, /* OP_JMPGE */
+ {iS, 0, 1}, /* OP_JMPT */
+ {iS, 0, 1}, /* OP_JMPF */
+ {iS, 0, 1}, /* OP_JMPONT */
+ {iS, 0, 1}, /* OP_JMPONF */
+ {iS, 0, 0}, /* OP_JMP */
+ {iO, 0, 0}, /* OP_PUSHNILJMP */
+ {iS, 0, 0}, /* OP_FORPREP */
+ {iS, 0, 3}, /* OP_FORLOOP */
+ {iS, 2, 0}, /* OP_LFORPREP */
+ {iS, 0, 3}, /* OP_LFORLOOP */
+ {iAB, VD, 0} /* OP_CLOSURE */
+};
+
diff --git a/src/lcode.h b/src/lcode.h
new file mode 100644
index 00000000..3f0a209a
--- /dev/null
+++ b/src/lcode.h
@@ -0,0 +1,70 @@
+/*
+** $Id: lcode.h,v 1.16 2000/08/09 14:49:13 roberto Exp $
+** Code generator for Lua
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lcode_h
+#define lcode_h
+
+#include "llex.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+
+
+/*
+** Marks the end of a patch list. It is an invalid value both as an absolute
+** address, and as a list link (would link an element to itself).
+*/
+#define NO_JUMP (-1)
+
+
+/*
+** grep "ORDER OPR" if you change these enums
+*/
+typedef enum BinOpr {
+ OPR_ADD, OPR_SUB, OPR_MULT, OPR_DIV, OPR_POW,
+ OPR_CONCAT,
+ OPR_NE, OPR_EQ, OPR_LT, OPR_LE, OPR_GT, OPR_GE,
+ OPR_AND, OPR_OR,
+ OPR_NOBINOPR
+} BinOpr;
+
+typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr;
+
+
+enum Mode {iO, iU, iS, iAB}; /* instruction format */
+
+#define VD 100 /* flag for variable delta */
+
+extern const struct OpProperties {
+ char mode;
+ unsigned char push;
+ unsigned char pop;
+} luaK_opproperties[];
+
+
+void luaK_error (LexState *ls, const char *msg);
+int luaK_code0 (FuncState *fs, OpCode o);
+int luaK_code1 (FuncState *fs, OpCode o, int arg1);
+int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2);
+int luaK_jump (FuncState *fs);
+void luaK_patchlist (FuncState *fs, int list, int target);
+void luaK_concat (FuncState *fs, int *l1, int l2);
+void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue);
+int luaK_getlabel (FuncState *fs);
+void luaK_deltastack (FuncState *fs, int delta);
+void luaK_kstr (LexState *ls, int c);
+void luaK_number (FuncState *fs, Number f);
+void luaK_adjuststack (FuncState *fs, int n);
+int luaK_lastisopen (FuncState *fs);
+void luaK_setcallreturns (FuncState *fs, int nresults);
+void luaK_tostack (LexState *ls, expdesc *v, int onlyone);
+void luaK_storevar (LexState *ls, const expdesc *var);
+void luaK_prefix (LexState *ls, UnOpr op, expdesc *v);
+void luaK_infix (LexState *ls, BinOpr op, expdesc *v);
+void luaK_posfix (LexState *ls, BinOpr op, expdesc *v1, expdesc *v2);
+
+
+#endif
diff --git a/src/ldebug.c b/src/ldebug.c
new file mode 100644
index 00000000..a5a2ab1d
--- /dev/null
+++ b/src/ldebug.c
@@ -0,0 +1,466 @@
+/*
+** $Id: ldebug.c,v 1.50 2000/10/30 12:38:50 roberto Exp $
+** Debug Interface
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdlib.h>
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "luadebug.h"
+
+
+
+static const char *getfuncname (lua_State *L, StkId f, const char **name);
+
+
+static void setnormalized (TObject *d, const TObject *s) {
+ if (ttype(s) == LUA_TMARK) {
+ clvalue(d) = infovalue(s)->func;
+ ttype(d) = LUA_TFUNCTION;
+ }
+ else *d = *s;
+}
+
+
+static int isLmark (StkId o) {
+ return (o && ttype(o) == LUA_TMARK && !infovalue(o)->func->isC);
+}
+
+
+LUA_API lua_Hook lua_setcallhook (lua_State *L, lua_Hook func) {
+ lua_Hook oldhook = L->callhook;
+ L->callhook = func;
+ return oldhook;
+}
+
+
+LUA_API lua_Hook lua_setlinehook (lua_State *L, lua_Hook func) {
+ lua_Hook oldhook = L->linehook;
+ L->linehook = func;
+ return oldhook;
+}
+
+
+static StkId aux_stackedfunction (lua_State *L, int level, StkId top) {
+ int i;
+ for (i = (top-1) - L->stack; i>=0; i--) {
+ if (is_T_MARK(L->stack[i].ttype)) {
+ if (level == 0)
+ return L->stack+i;
+ level--;
+ }
+ }
+ return NULL;
+}
+
+
+LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
+ StkId f = aux_stackedfunction(L, level, L->top);
+ if (f == NULL) return 0; /* there is no such level */
+ else {
+ ar->_func = f;
+ return 1;
+ }
+}
+
+
+static int nups (StkId f) {
+ switch (ttype(f)) {
+ case LUA_TFUNCTION:
+ return clvalue(f)->nupvalues;
+ case LUA_TMARK:
+ return infovalue(f)->func->nupvalues;
+ default:
+ return 0;
+ }
+}
+
+
+int luaG_getline (int *lineinfo, int pc, int refline, int *prefi) {
+ int refi;
+ if (lineinfo == NULL || pc == -1)
+ return -1; /* no line info or function is not active */
+ refi = prefi ? *prefi : 0;
+ if (lineinfo[refi] < 0)
+ refline += -lineinfo[refi++];
+ LUA_ASSERT(lineinfo[refi] >= 0, "invalid line info");
+ while (lineinfo[refi] > pc) {
+ refline--;
+ refi--;
+ if (lineinfo[refi] < 0)
+ refline -= -lineinfo[refi--];
+ LUA_ASSERT(lineinfo[refi] >= 0, "invalid line info");
+ }
+ for (;;) {
+ int nextline = refline + 1;
+ int nextref = refi + 1;
+ if (lineinfo[nextref] < 0)
+ nextline += -lineinfo[nextref++];
+ LUA_ASSERT(lineinfo[nextref] >= 0, "invalid line info");
+ if (lineinfo[nextref] > pc)
+ break;
+ refline = nextline;
+ refi = nextref;
+ }
+ if (prefi) *prefi = refi;
+ return refline;
+}
+
+
+static int currentpc (StkId f) {
+ CallInfo *ci = infovalue(f);
+ LUA_ASSERT(isLmark(f), "function has no pc");
+ if (ci->pc)
+ return (*ci->pc - ci->func->f.l->code) - 1;
+ else
+ return -1; /* function is not active */
+}
+
+
+static int currentline (StkId f) {
+ if (!isLmark(f))
+ return -1; /* only active lua functions have current-line information */
+ else {
+ CallInfo *ci = infovalue(f);
+ int *lineinfo = ci->func->f.l->lineinfo;
+ return luaG_getline(lineinfo, currentpc(f), 1, NULL);
+ }
+}
+
+
+
+static Proto *getluaproto (StkId f) {
+ return (isLmark(f) ? infovalue(f)->func->f.l : NULL);
+}
+
+
+LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
+ const char *name;
+ StkId f = ar->_func;
+ Proto *fp = getluaproto(f);
+ if (!fp) return NULL; /* `f' is not a Lua function? */
+ name = luaF_getlocalname(fp, n, currentpc(f));
+ if (!name) return NULL;
+ luaA_pushobject(L, (f+1)+(n-1)); /* push value */
+ return name;
+}
+
+
+LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
+ const char *name;
+ StkId f = ar->_func;
+ Proto *fp = getluaproto(f);
+ L->top--; /* pop new value */
+ if (!fp) return NULL; /* `f' is not a Lua function? */
+ name = luaF_getlocalname(fp, n, currentpc(f));
+ if (!name || name[0] == '(') return NULL; /* `(' starts private locals */
+ *((f+1)+(n-1)) = *L->top;
+ return name;
+}
+
+
+static void infoLproto (lua_Debug *ar, Proto *f) {
+ ar->source = f->source->str;
+ ar->linedefined = f->lineDefined;
+ ar->what = "Lua";
+}
+
+
+static void funcinfo (lua_State *L, lua_Debug *ar, StkId func) {
+ Closure *cl = NULL;
+ switch (ttype(func)) {
+ case LUA_TFUNCTION:
+ cl = clvalue(func);
+ break;
+ case LUA_TMARK:
+ cl = infovalue(func)->func;
+ break;
+ default:
+ lua_error(L, "value for `lua_getinfo' is not a function");
+ }
+ if (cl->isC) {
+ ar->source = "=C";
+ ar->linedefined = -1;
+ ar->what = "C";
+ }
+ else
+ infoLproto(ar, cl->f.l);
+ luaO_chunkid(ar->short_src, ar->source, sizeof(ar->short_src));
+ if (ar->linedefined == 0)
+ ar->what = "main";
+}
+
+
+static const char *travtagmethods (lua_State *L, const TObject *o) {
+ if (ttype(o) == LUA_TFUNCTION) {
+ int e;
+ for (e=0; e<TM_N; e++) {
+ int t;
+ for (t=0; t<=L->last_tag; t++)
+ if (clvalue(o) == luaT_gettm(L, t, e))
+ return luaT_eventname[e];
+ }
+ }
+ return NULL;
+}
+
+
+static const char *travglobals (lua_State *L, const TObject *o) {
+ Hash *g = L->gt;
+ int i;
+ for (i=0; i<g->size; i++) {
+ if (luaO_equalObj(o, val(node(g, i))) &&
+ ttype(key(node(g, i))) == LUA_TSTRING)
+ return tsvalue(key(node(g, i)))->str;
+ }
+ return NULL;
+}
+
+
+static void getname (lua_State *L, StkId f, lua_Debug *ar) {
+ TObject o;
+ setnormalized(&o, f);
+ /* try to find a name for given function */
+ if ((ar->name = travglobals(L, &o)) != NULL)
+ ar->namewhat = "global";
+ /* not found: try tag methods */
+ else if ((ar->name = travtagmethods(L, &o)) != NULL)
+ ar->namewhat = "tag-method";
+ else ar->namewhat = ""; /* not found at all */
+}
+
+
+LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
+ StkId func;
+ int isactive = (*what != '>');
+ if (isactive)
+ func = ar->_func;
+ else {
+ what++; /* skip the '>' */
+ func = L->top - 1;
+ }
+ for (; *what; what++) {
+ switch (*what) {
+ case 'S': {
+ funcinfo(L, ar, func);
+ break;
+ }
+ case 'l': {
+ ar->currentline = currentline(func);
+ break;
+ }
+ case 'u': {
+ ar->nups = nups(func);
+ break;
+ }
+ case 'n': {
+ ar->namewhat = (isactive) ? getfuncname(L, func, &ar->name) : NULL;
+ if (ar->namewhat == NULL)
+ getname(L, func, ar);
+ break;
+ }
+ case 'f': {
+ setnormalized(L->top, func);
+ incr_top; /* push function */
+ break;
+ }
+ default: return 0; /* invalid option */
+ }
+ }
+ if (!isactive) L->top--; /* pop function */
+ return 1;
+}
+
+
+/*
+** {======================================================
+** Symbolic Execution
+** =======================================================
+*/
+
+
+static int pushpc (int *stack, int pc, int top, int n) {
+ while (n--)
+ stack[top++] = pc-1;
+ return top;
+}
+
+
+static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) {
+ int stack[MAXSTACK]; /* stores last instruction that changed a stack entry */
+ const Instruction *code = pt->code;
+ int top = pt->numparams;
+ int pc = 0;
+ if (pt->is_vararg) /* varargs? */
+ top++; /* `arg' */
+ while (pc < lastpc) {
+ const Instruction i = code[pc++];
+ LUA_ASSERT(0 <= top && top <= pt->maxstacksize, "wrong stack");
+ switch (GET_OPCODE(i)) {
+ case OP_RETURN: {
+ LUA_ASSERT(top >= GETARG_U(i), "wrong stack");
+ top = GETARG_U(i);
+ break;
+ }
+ case OP_TAILCALL: {
+ LUA_ASSERT(top >= GETARG_A(i), "wrong stack");
+ top = GETARG_B(i);
+ break;
+ }
+ case OP_CALL: {
+ int nresults = GETARG_B(i);
+ if (nresults == MULT_RET) nresults = 1;
+ LUA_ASSERT(top >= GETARG_A(i), "wrong stack");
+ top = pushpc(stack, pc, GETARG_A(i), nresults);
+ break;
+ }
+ case OP_PUSHNIL: {
+ top = pushpc(stack, pc, top, GETARG_U(i));
+ break;
+ }
+ case OP_POP: {
+ top -= GETARG_U(i);
+ break;
+ }
+ case OP_SETTABLE:
+ case OP_SETLIST: {
+ top -= GETARG_B(i);
+ break;
+ }
+ case OP_SETMAP: {
+ top -= 2*GETARG_U(i);
+ break;
+ }
+ case OP_CONCAT: {
+ top -= GETARG_U(i);
+ stack[top++] = pc-1;
+ break;
+ }
+ case OP_CLOSURE: {
+ top -= GETARG_B(i);
+ stack[top++] = pc-1;
+ break;
+ }
+ case OP_JMPONT:
+ case OP_JMPONF: {
+ int newpc = pc + GETARG_S(i);
+ /* jump is forward and do not skip `lastpc'? */
+ if (pc < newpc && newpc <= lastpc) {
+ stack[top-1] = pc-1; /* value comes from `and'/`or' */
+ pc = newpc; /* do the jump */
+ }
+ else
+ top--; /* do not jump; pop value */
+ break;
+ }
+ default: {
+ OpCode op = GET_OPCODE(i);
+ LUA_ASSERT(luaK_opproperties[op].push != VD,
+ "invalid opcode for default");
+ top -= luaK_opproperties[op].pop;
+ LUA_ASSERT(top >= 0, "wrong stack");
+ top = pushpc(stack, pc, top, luaK_opproperties[op].push);
+ }
+ }
+ }
+ return code[stack[stackpos]];
+}
+
+
+static const char *getobjname (lua_State *L, StkId obj, const char **name) {
+ StkId func = aux_stackedfunction(L, 0, obj);
+ if (!isLmark(func))
+ return NULL; /* not an active Lua function */
+ else {
+ Proto *p = infovalue(func)->func->f.l;
+ int pc = currentpc(func);
+ int stackpos = obj - (func+1); /* func+1 == function base */
+ Instruction i = luaG_symbexec(p, pc, stackpos);
+ LUA_ASSERT(pc != -1, "function must be active");
+ switch (GET_OPCODE(i)) {
+ case OP_GETGLOBAL: {
+ *name = p->kstr[GETARG_U(i)]->str;
+ return "global";
+ }
+ case OP_GETLOCAL: {
+ *name = luaF_getlocalname(p, GETARG_U(i)+1, pc);
+ LUA_ASSERT(*name, "local must exist");
+ return "local";
+ }
+ case OP_PUSHSELF:
+ case OP_GETDOTTED: {
+ *name = p->kstr[GETARG_U(i)]->str;
+ return "field";
+ }
+ default:
+ return NULL; /* no useful name found */
+ }
+ }
+}
+
+
+static const char *getfuncname (lua_State *L, StkId f, const char **name) {
+ StkId func = aux_stackedfunction(L, 0, f); /* calling function */
+ if (!isLmark(func))
+ return NULL; /* not an active Lua function */
+ else {
+ Proto *p = infovalue(func)->func->f.l;
+ int pc = currentpc(func);
+ Instruction i;
+ if (pc == -1) return NULL; /* function is not activated */
+ i = p->code[pc];
+ switch (GET_OPCODE(i)) {
+ case OP_CALL: case OP_TAILCALL:
+ return getobjname(L, (func+1)+GETARG_A(i), name);
+ default:
+ return NULL; /* no useful name found */
+ }
+ }
+}
+
+
+/* }====================================================== */
+
+
+void luaG_typeerror (lua_State *L, StkId o, const char *op) {
+ const char *name;
+ const char *kind = getobjname(L, o, &name);
+ const char *t = luaO_typename(o);
+ if (kind)
+ luaO_verror(L, "attempt to %.30s %.20s `%.40s' (a %.10s value)",
+ op, kind, name, t);
+ else
+ luaO_verror(L, "attempt to %.30s a %.10s value", op, t);
+}
+
+
+void luaG_binerror (lua_State *L, StkId p1, int t, const char *op) {
+ if (ttype(p1) == t) p1++;
+ LUA_ASSERT(ttype(p1) != t, "must be an error");
+ luaG_typeerror(L, p1, op);
+}
+
+
+void luaG_ordererror (lua_State *L, StkId top) {
+ const char *t1 = luaO_typename(top-2);
+ const char *t2 = luaO_typename(top-1);
+ if (t1[2] == t2[2])
+ luaO_verror(L, "attempt to compare two %.10s values", t1);
+ else
+ luaO_verror(L, "attempt to compare %.10s with %.10s", t1, t2);
+}
+
diff --git a/src/ldebug.h b/src/ldebug.h
new file mode 100644
index 00000000..d4b2d3b0
--- /dev/null
+++ b/src/ldebug.h
@@ -0,0 +1,21 @@
+/*
+** $Id: ldebug.h,v 1.7 2000/10/05 12:14:08 roberto Exp $
+** Auxiliary functions from Debug Interface module
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ldebug_h
+#define ldebug_h
+
+
+#include "lstate.h"
+#include "luadebug.h"
+
+
+void luaG_typeerror (lua_State *L, StkId o, const char *op);
+void luaG_binerror (lua_State *L, StkId p1, int t, const char *op);
+int luaG_getline (int *lineinfo, int pc, int refline, int *refi);
+void luaG_ordererror (lua_State *L, StkId top);
+
+
+#endif
diff --git a/src/ldo.c b/src/ldo.c
index 281a4ec4..fbb892a5 100644
--- a/src/ldo.c
+++ b/src/ldo.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.c,v 1.45b 1999/06/22 20:37:23 roberto Exp $
+** $Id: ldo.c,v 1.109 2000/10/30 12:38:50 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -10,378 +10,376 @@
#include <stdlib.h>
#include <string.h>
-#include "lauxlib.h"
+#include "lua.h"
+
+#include "ldebug.h"
#include "ldo.h"
-#include "lfunc.h"
#include "lgc.h"
#include "lmem.h"
#include "lobject.h"
#include "lparser.h"
#include "lstate.h"
#include "lstring.h"
+#include "ltable.h"
#include "ltm.h"
-#include "lua.h"
-#include "luadebug.h"
#include "lundump.h"
#include "lvm.h"
#include "lzio.h"
+/* space to handle stack overflow errors */
+#define EXTRA_STACK (2*LUA_MINSTACK)
-#ifndef STACK_LIMIT
-#define STACK_LIMIT 6000 /* arbitrary limit */
-#endif
-
-
-
-#define STACK_UNIT 128
-
-#ifdef DEBUG
-#undef STACK_UNIT
-#define STACK_UNIT 2
-#endif
-
-
-void luaD_init (void) {
- L->stack.stack = luaM_newvector(STACK_UNIT, TObject);
- L->stack.top = L->stack.stack;
- L->stack.last = L->stack.stack+(STACK_UNIT-1);
+void luaD_init (lua_State *L, int stacksize) {
+ L->stack = luaM_newvector(L, stacksize+EXTRA_STACK, TObject);
+ L->nblocks += stacksize*sizeof(TObject);
+ L->stack_last = L->stack+(stacksize-1);
+ L->stacksize = stacksize;
+ L->Cbase = L->top = L->stack;
}
-void luaD_checkstack (int n) {
- struct Stack *S = &L->stack;
- if (S->last-S->top <= n) {
- StkId top = S->top-S->stack;
- int stacksize = (S->last-S->stack)+STACK_UNIT+n;
- luaM_reallocvector(S->stack, stacksize, TObject);
- S->last = S->stack+(stacksize-1);
- S->top = S->stack + top;
- if (stacksize >= STACK_LIMIT) { /* stack overflow? */
- if (lua_stackedfunction(100) == LUA_NOOBJECT) /* 100 funcs on stack? */
- lua_error("Lua2C - C2Lua overflow"); /* doesn't look like a rec. loop */
- else
- lua_error("stack size overflow");
+void luaD_checkstack (lua_State *L, int n) {
+ if (L->stack_last - L->top <= n) { /* stack overflow? */
+ if (L->stack_last-L->stack > (L->stacksize-1)) {
+ /* overflow while handling overflow */
+ luaD_breakrun(L, LUA_ERRERR); /* break run without error message */
+ }
+ else {
+ L->stack_last += EXTRA_STACK; /* to be used by error message */
+ lua_error(L, "stack overflow");
}
}
}
+static void restore_stack_limit (lua_State *L) {
+ if (L->top - L->stack < L->stacksize - 1)
+ L->stack_last = L->stack + (L->stacksize-1);
+}
+
+
/*
-** Adjust stack. Set top to the given value, pushing NILs if needed.
+** Adjust stack. Set top to base+extra, pushing NILs if needed.
+** (we cannot add base+extra unless we are sure it fits in the stack;
+** otherwise the result of such operation on pointers is undefined)
*/
-void luaD_adjusttop (StkId newtop) {
- int diff = newtop-(L->stack.top-L->stack.stack);
+void luaD_adjusttop (lua_State *L, StkId base, int extra) {
+ int diff = extra-(L->top-base);
if (diff <= 0)
- L->stack.top += diff;
+ L->top = base+extra;
else {
- luaD_checkstack(diff);
+ luaD_checkstack(L, diff);
while (diff--)
- ttype(L->stack.top++) = LUA_T_NIL;
+ ttype(L->top++) = LUA_TNIL;
}
}
/*
-** Open a hole below "nelems" from the L->stack.top.
+** Open a hole inside the stack at `pos'
*/
-void luaD_openstack (int nelems) {
- luaO_memup(L->stack.top-nelems+1, L->stack.top-nelems,
- nelems*sizeof(TObject));
+static void luaD_openstack (lua_State *L, StkId pos) {
+ int i = L->top-pos;
+ while (i--) pos[i+1] = pos[i];
incr_top;
}
-void luaD_lineHook (int line) {
- struct C_Lua_Stack oldCLS = L->Cstack;
- StkId old_top = L->Cstack.lua2C = L->Cstack.base = L->stack.top-L->stack.stack;
- L->Cstack.num = 0;
- (*L->linehook)(line);
- L->stack.top = L->stack.stack+old_top;
- L->Cstack = oldCLS;
+static void dohook (lua_State *L, lua_Debug *ar, lua_Hook hook) {
+ StkId old_Cbase = L->Cbase;
+ StkId old_top = L->Cbase = L->top;
+ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
+ L->allowhooks = 0; /* cannot call hooks inside a hook */
+ (*hook)(L, ar);
+ LUA_ASSERT(L->allowhooks == 0, "invalid allow");
+ L->allowhooks = 1;
+ L->top = old_top;
+ L->Cbase = old_Cbase;
}
-void luaD_callHook (StkId base, TProtoFunc *tf, int isreturn) {
- struct C_Lua_Stack oldCLS = L->Cstack;
- StkId old_top = L->Cstack.lua2C = L->Cstack.base = L->stack.top-L->stack.stack;
- L->Cstack.num = 0;
- if (isreturn)
- (*L->callhook)(LUA_NOOBJECT, "(return)", 0);
- else {
- TObject *f = L->stack.stack+base-1;
- if (tf)
- (*L->callhook)(Ref(f), tf->source->str, tf->lineDefined);
- else
- (*L->callhook)(Ref(f), "(C)", -1);
+void luaD_lineHook (lua_State *L, StkId func, int line, lua_Hook linehook) {
+ if (L->allowhooks) {
+ lua_Debug ar;
+ ar._func = func;
+ ar.event = "line";
+ ar.currentline = line;
+ dohook(L, &ar, linehook);
}
- L->stack.top = L->stack.stack+old_top;
- L->Cstack = oldCLS;
}
-/*
-** Call a C function.
-** Cstack.num is the number of arguments; Cstack.lua2C points to the
-** first argument. Returns an index to the first result from C.
-*/
-static StkId callC (lua_CFunction f, StkId base) {
- struct C_Lua_Stack *cls = &L->Cstack;
- struct C_Lua_Stack oldCLS = *cls;
- StkId firstResult;
- int numarg = (L->stack.top-L->stack.stack) - base;
- cls->num = numarg;
- cls->lua2C = base;
- cls->base = base+numarg; /* == top-stack */
- if (L->callhook)
- luaD_callHook(base, NULL, 0);
- (*f)(); /* do the actual call */
- if (L->callhook) /* func may have changed callhook */
- luaD_callHook(base, NULL, 1);
- firstResult = cls->base;
- *cls = oldCLS;
- return firstResult;
+static void luaD_callHook (lua_State *L, StkId func, lua_Hook callhook,
+ const char *event) {
+ if (L->allowhooks) {
+ lua_Debug ar;
+ ar._func = func;
+ ar.event = event;
+ infovalue(func)->pc = NULL; /* function is not active */
+ dohook(L, &ar, callhook);
+ }
}
-static StkId callCclosure (struct Closure *cl, lua_CFunction f, StkId base) {
- TObject *pbase;
- int nup = cl->nelems; /* number of upvalues */
- luaD_checkstack(nup);
- pbase = L->stack.stack+base; /* care: previous call may change this */
- /* open space for upvalues as extra arguments */
- luaO_memup(pbase+nup, pbase, (L->stack.top-pbase)*sizeof(TObject));
- /* copy upvalues into stack */
- memcpy(pbase, cl->consts+1, nup*sizeof(TObject));
- L->stack.top += nup;
- return callC(f, base);
+static StkId callCclosure (lua_State *L, const struct Closure *cl, StkId base) {
+ int nup = cl->nupvalues; /* number of upvalues */
+ StkId old_Cbase = L->Cbase;
+ int n;
+ L->Cbase = base; /* new base for C function */
+ luaD_checkstack(L, nup+LUA_MINSTACK); /* ensure minimum stack size */
+ for (n=0; n<nup; n++) /* copy upvalues as extra arguments */
+ *(L->top++) = cl->upvalue[n];
+ n = (*cl->f.c)(L); /* do the actual call */
+ L->Cbase = old_Cbase; /* restore old C base */
+ return L->top - n; /* return index of first result */
}
-void luaD_callTM (TObject *f, int nParams, int nResults) {
- luaD_openstack(nParams);
- *(L->stack.top-nParams-1) = *f;
- luaD_calln(nParams, nResults);
+void luaD_callTM (lua_State *L, Closure *f, int nParams, int nResults) {
+ StkId base = L->top - nParams;
+ luaD_openstack(L, base);
+ clvalue(base) = f;
+ ttype(base) = LUA_TFUNCTION;
+ luaD_call(L, base, nResults);
}
/*
-** Call a function (C or Lua). The parameters must be on the stack,
-** between [top-nArgs,top). The function to be called is right below the
-** arguments.
-** When returns, the results are on the stack, between [top-nArgs-1,top).
-** The number of results is nResults, unless nResults=MULT_RET.
-*/
-void luaD_calln (int nArgs, int nResults) {
- struct Stack *S = &L->stack; /* to optimize */
- StkId base = (S->top-S->stack)-nArgs;
- TObject *func = S->stack+base-1;
+** Call a function (C or Lua). The function to be called is at *func.
+** The arguments are on the stack, right after the function.
+** When returns, the results are on the stack, starting at the original
+** function position.
+** The number of results is nResults, unless nResults=LUA_MULTRET.
+*/
+void luaD_call (lua_State *L, StkId func, int nResults) {
+ lua_Hook callhook;
StkId firstResult;
- int i;
- switch (ttype(func)) {
- case LUA_T_CPROTO:
- ttype(func) = LUA_T_CMARK;
- firstResult = callC(fvalue(func), base);
- break;
- case LUA_T_PROTO:
- ttype(func) = LUA_T_PMARK;
- firstResult = luaV_execute(NULL, tfvalue(func), base);
- break;
- case LUA_T_CLOSURE: {
- Closure *c = clvalue(func);
- TObject *proto = &(c->consts[0]);
- ttype(func) = LUA_T_CLMARK;
- firstResult = (ttype(proto) == LUA_T_CPROTO) ?
- callCclosure(c, fvalue(proto), base) :
- luaV_execute(c, tfvalue(proto), base);
- break;
- }
- default: { /* func is not a function */
- /* Check the tag method for invalid functions */
- TObject *im = luaT_getimbyObj(func, IM_FUNCTION);
- if (ttype(im) == LUA_T_NIL)
- lua_error("call expression not a function");
- luaD_callTM(im, (S->top-S->stack)-(base-1), nResults);
- return;
+ CallInfo ci;
+ Closure *cl;
+ if (ttype(func) != LUA_TFUNCTION) {
+ /* `func' is not a function; check the `function' tag method */
+ Closure *tm = luaT_gettmbyObj(L, func, TM_FUNCTION);
+ if (tm == NULL)
+ luaG_typeerror(L, func, "call");
+ luaD_openstack(L, func);
+ clvalue(func) = tm; /* tag method is the new function to be called */
+ ttype(func) = LUA_TFUNCTION;
+ }
+ cl = clvalue(func);
+ ci.func = cl;
+ infovalue(func) = &ci;
+ ttype(func) = LUA_TMARK;
+ callhook = L->callhook;
+ if (callhook)
+ luaD_callHook(L, func, callhook, "call");
+ firstResult = (cl->isC ? callCclosure(L, cl, func+1) :
+ luaV_execute(L, cl, func+1));
+ if (callhook) /* same hook that was active at entry */
+ luaD_callHook(L, func, callhook, "return");
+ LUA_ASSERT(ttype(func) == LUA_TMARK, "invalid tag");
+ /* move results to `func' (to erase parameters and function) */
+ if (nResults == LUA_MULTRET) {
+ while (firstResult < L->top) /* copy all results */
+ *func++ = *firstResult++;
+ L->top = func;
+ }
+ else { /* copy at most `nResults' */
+ for (; nResults > 0 && firstResult < L->top; nResults--)
+ *func++ = *firstResult++;
+ L->top = func;
+ for (; nResults > 0; nResults--) { /* if there are not enough results */
+ ttype(L->top) = LUA_TNIL; /* adjust the stack */
+ incr_top; /* must check stack space */
}
}
- /* adjust the number of results */
- if (nResults == MULT_RET)
- nResults = (S->top-S->stack)-firstResult;
- else
- luaD_adjusttop(firstResult+nResults);
- /* move results to base-1 (to erase parameters and function) */
- base--;
- for (i=0; i<nResults; i++)
- *(S->stack+base+i) = *(S->stack+firstResult+i);
- S->top -= firstResult-base;
+ luaC_checkGC(L);
}
/*
-** Traverse all objects on L->stack.stack
+** Execute a protected call.
*/
-void luaD_travstack (int (*fn)(TObject *))
-{
- StkId i;
- for (i = (L->stack.top-1)-L->stack.stack; i>=0; i--)
- fn(L->stack.stack+i);
+struct CallS { /* data to `f_call' */
+ StkId func;
+ int nresults;
+};
+
+static void f_call (lua_State *L, void *ud) {
+ struct CallS *c = (struct CallS *)ud;
+ luaD_call(L, c->func, c->nresults);
}
-
-static void message (char *s) {
- TObject *em = &(luaS_new("_ERRORMESSAGE")->u.s.globalval);
- if (ttype(em) == LUA_T_PROTO || ttype(em) == LUA_T_CPROTO ||
- ttype(em) == LUA_T_CLOSURE) {
- *L->stack.top = *em;
- incr_top;
- lua_pushstring(s);
- luaD_calln(1, 0);
- }
-}
-
-/*
-** Reports an error, and jumps up to the available recover label
-*/
-void lua_error (char *s) {
- if (s) message(s);
- if (L->errorJmp)
- longjmp(L->errorJmp->b, 1);
- else {
- message("exit(1). Unable to recover.\n");
- exit(1);
- }
-}
-
-
-/*
-** Execute a protected call. Assumes that function is at L->Cstack.base and
-** parameters are on top of it. Leave nResults on the stack.
-*/
-int luaD_protectedrun (void) {
- volatile struct C_Lua_Stack oldCLS = L->Cstack;
- struct lua_longjmp myErrorJmp;
- volatile int status;
- struct lua_longjmp *volatile oldErr = L->errorJmp;
- L->errorJmp = &myErrorJmp;
- if (setjmp(myErrorJmp.b) == 0) {
- StkId base = L->Cstack.base;
- luaD_calln((L->stack.top-L->stack.stack)-base-1, MULT_RET);
- L->Cstack.lua2C = base; /* position of the new results */
- L->Cstack.num = (L->stack.top-L->stack.stack) - base;
- L->Cstack.base = base + L->Cstack.num; /* incorporate results on stack */
- status = 0;
- }
- else { /* an error occurred: restore L->Cstack and L->stack.top */
- L->Cstack = oldCLS;
- L->stack.top = L->stack.stack+L->Cstack.base;
- status = 1;
- }
- L->errorJmp = oldErr;
+LUA_API int lua_call (lua_State *L, int nargs, int nresults) {
+ StkId func = L->top - (nargs+1); /* function to be called */
+ struct CallS c;
+ int status;
+ c.func = func; c.nresults = nresults;
+ status = luaD_runprotected(L, f_call, &c);
+ if (status != 0) /* an error occurred? */
+ L->top = func; /* remove parameters from the stack */
return status;
}
/*
-** returns 0 = chunk loaded; 1 = error; 2 = no more chunks to load
+** Execute a protected parser.
*/
-static int protectedparser (ZIO *z, int bin) {
- volatile struct C_Lua_Stack oldCLS = L->Cstack;
- struct lua_longjmp myErrorJmp;
- volatile int status;
- TProtoFunc *volatile tf;
- struct lua_longjmp *volatile oldErr = L->errorJmp;
- L->errorJmp = &myErrorJmp;
- if (setjmp(myErrorJmp.b) == 0) {
- tf = bin ? luaU_undump1(z) : luaY_parser(z);
- status = 0;
- }
- else { /* an error occurred: restore L->Cstack and L->stack.top */
- L->Cstack = oldCLS;
- L->stack.top = L->stack.stack+L->Cstack.base;
- tf = NULL;
- status = 1;
- }
- L->errorJmp = oldErr;
- if (status) return 1; /* error code */
- if (tf == NULL) return 2; /* 'natural' end */
- luaD_adjusttop(L->Cstack.base+1); /* one slot for the pseudo-function */
- L->stack.stack[L->Cstack.base].ttype = LUA_T_PROTO;
- L->stack.stack[L->Cstack.base].value.tf = tf;
- luaV_closure(0);
- return 0;
-}
-
+struct ParserS { /* data to `f_parser' */
+ ZIO *z;
+ int bin;
+};
-static int do_main (ZIO *z, int bin) {
- int status;
- int debug = L->debug; /* save debug status */
- do {
- long old_blocks = (luaC_checkGC(), L->nblocks);
- status = protectedparser(z, bin);
- if (status == 1) return 1; /* error */
- else if (status == 2) return 0; /* 'natural' end */
- else {
- unsigned long newelems2 = 2*(L->nblocks-old_blocks);
- L->GCthreshold += newelems2;
- status = luaD_protectedrun();
- L->GCthreshold -= newelems2;
- }
- } while (bin && status == 0);
- L->debug = debug; /* restore debug status */
- return status;
+static void f_parser (lua_State *L, void *ud) {
+ struct ParserS *p = (struct ParserS *)ud;
+ Proto *tf = p->bin ? luaU_undump(L, p->z) : luaY_parser(L, p->z);
+ luaV_Lclosure(L, tf, 0);
}
-void luaD_gcIM (TObject *o)
-{
- TObject *im = luaT_getimbyObj(o, IM_GC);
- if (ttype(im) != LUA_T_NIL) {
- *L->stack.top = *o;
- incr_top;
- luaD_callTM(im, 1, 0);
+static int protectedparser (lua_State *L, ZIO *z, int bin) {
+ struct ParserS p;
+ unsigned long old_blocks;
+ int status;
+ p.z = z; p.bin = bin;
+ luaC_checkGC(L);
+ old_blocks = L->nblocks;
+ status = luaD_runprotected(L, f_parser, &p);
+ if (status == 0) {
+ /* add new memory to threshold (as it probably will stay) */
+ L->GCthreshold += (L->nblocks - old_blocks);
}
+ else if (status == LUA_ERRRUN) /* an error occurred: correct error code */
+ status = LUA_ERRSYNTAX;
+ return status;
}
-#define MAXFILENAME 260 /* maximum part of a file name kept */
-
-int lua_dofile (char *filename) {
+static int parse_file (lua_State *L, const char *filename) {
ZIO z;
int status;
- int c;
- int bin;
- char source[MAXFILENAME];
+ int bin; /* flag for file mode */
+ int c; /* look ahead char */
FILE *f = (filename == NULL) ? stdin : fopen(filename, "r");
- if (f == NULL)
- return 2;
- luaL_filesource(source, filename, sizeof(source));
+ if (f == NULL) return LUA_ERRFILE; /* unable to open file */
c = fgetc(f);
ungetc(c, f);
bin = (c == ID_CHUNK);
if (bin && f != stdin) {
f = freopen(filename, "rb", f); /* set binary mode */
- if (f == NULL) return 2;
+ if (f == NULL) return LUA_ERRFILE; /* unable to reopen file */
}
- luaZ_Fopen(&z, f, source);
- status = do_main(&z, bin);
+ lua_pushstring(L, "@");
+ lua_pushstring(L, (filename == NULL) ? "(stdin)" : filename);
+ lua_concat(L, 2);
+ filename = lua_tostring(L, -1); /* filename = '@'..filename */
+ lua_pop(L, 1); /* OK: there is no GC during parser */
+ luaZ_Fopen(&z, f, filename);
+ status = protectedparser(L, &z, bin);
if (f != stdin)
fclose(f);
return status;
}
-int lua_dostring (char *str) {
- return lua_dobuffer(str, strlen(str), str);
+LUA_API int lua_dofile (lua_State *L, const char *filename) {
+ int status = parse_file(L, filename);
+ if (status == 0) /* parse OK? */
+ status = lua_call(L, 0, LUA_MULTRET); /* call main */
+ return status;
}
-int lua_dobuffer (char *buff, int size, char *name) {
+static int parse_buffer (lua_State *L, const char *buff, size_t size,
+ const char *name) {
ZIO z;
if (!name) name = "?";
luaZ_mopen(&z, buff, size, name);
- return do_main(&z, buff[0]==ID_CHUNK);
+ return protectedparser(L, &z, buff[0]==ID_CHUNK);
}
+
+LUA_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, const char *name) {
+ int status = parse_buffer(L, buff, size, name);
+ if (status == 0) /* parse OK? */
+ status = lua_call(L, 0, LUA_MULTRET); /* call main */
+ return status;
+}
+
+
+LUA_API int lua_dostring (lua_State *L, const char *str) {
+ return lua_dobuffer(L, str, strlen(str), str);
+}
+
+
+/*
+** {======================================================
+** Error-recover functions (based on long jumps)
+** =======================================================
+*/
+
+/* chain list of long jump buffers */
+struct lua_longjmp {
+ jmp_buf b;
+ struct lua_longjmp *previous;
+ volatile int status; /* error code */
+};
+
+
+static void message (lua_State *L, const char *s) {
+ const TObject *em = luaH_getglobal(L, LUA_ERRORMESSAGE);
+ if (ttype(em) == LUA_TFUNCTION) {
+ *L->top = *em;
+ incr_top;
+ lua_pushstring(L, s);
+ luaD_call(L, L->top-2, 0);
+ }
+}
+
+
+/*
+** Reports an error, and jumps up to the available recovery label
+*/
+LUA_API void lua_error (lua_State *L, const char *s) {
+ if (s) message(L, s);
+ luaD_breakrun(L, LUA_ERRRUN);
+}
+
+
+void luaD_breakrun (lua_State *L, int errcode) {
+ if (L->errorJmp) {
+ L->errorJmp->status = errcode;
+ longjmp(L->errorJmp->b, 1);
+ }
+ else {
+ if (errcode != LUA_ERRMEM)
+ message(L, "unable to recover; exiting\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+
+int luaD_runprotected (lua_State *L, void (*f)(lua_State *, void *), void *ud) {
+ StkId oldCbase = L->Cbase;
+ StkId oldtop = L->top;
+ struct lua_longjmp lj;
+ int allowhooks = L->allowhooks;
+ lj.status = 0;
+ lj.previous = L->errorJmp; /* chain new error handler */
+ L->errorJmp = &lj;
+ if (setjmp(lj.b) == 0)
+ (*f)(L, ud);
+ else { /* an error occurred: restore the state */
+ L->allowhooks = allowhooks;
+ L->Cbase = oldCbase;
+ L->top = oldtop;
+ restore_stack_limit(L);
+ }
+ L->errorJmp = lj.previous; /* restore old error handler */
+ return lj.status;
+}
+
+/* }====================================================== */
+
diff --git a/src/ldo.h b/src/ldo.h
index 01eec540..3fba1f56 100644
--- a/src/ldo.h
+++ b/src/ldo.h
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.h,v 1.6 1999/06/22 20:37:23 roberto Exp $
+** $Id: ldo.h,v 1.28 2000/10/06 12:45:25 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -12,35 +12,22 @@
#include "lstate.h"
-#define MULT_RET 255
-
-
-
/*
** macro to increment stack top.
** There must be always an empty slot at the L->stack.top
*/
-#define incr_top { if (L->stack.top >= L->stack.last) luaD_checkstack(1); \
- L->stack.top++; }
-
-
-/* macros to convert from lua_Object to (TObject *) and back */
+#define incr_top {if (L->top == L->stack_last) luaD_checkstack(L, 1); L->top++;}
-#define Address(lo) ((lo)+L->stack.stack-1)
-#define Ref(st) ((st)-L->stack.stack+1)
+void luaD_init (lua_State *L, int stacksize);
+void luaD_adjusttop (lua_State *L, StkId base, int extra);
+void luaD_lineHook (lua_State *L, StkId func, int line, lua_Hook linehook);
+void luaD_call (lua_State *L, StkId func, int nResults);
+void luaD_callTM (lua_State *L, Closure *f, int nParams, int nResults);
+void luaD_checkstack (lua_State *L, int n);
-void luaD_init (void);
-void luaD_adjusttop (StkId newtop);
-void luaD_openstack (int nelems);
-void luaD_lineHook (int line);
-void luaD_callHook (StkId base, TProtoFunc *tf, int isreturn);
-void luaD_calln (int nArgs, int nResults);
-void luaD_callTM (TObject *f, int nParams, int nResults);
-int luaD_protectedrun (void);
-void luaD_gcIM (TObject *o);
-void luaD_travstack (int (*fn)(TObject *));
-void luaD_checkstack (int n);
+void luaD_breakrun (lua_State *L, int errcode);
+int luaD_runprotected (lua_State *L, void (*f)(lua_State *, void *), void *ud);
#endif
diff --git a/src/lfunc.c b/src/lfunc.c
index 7494e2cd..6841ef71 100644
--- a/src/lfunc.c
+++ b/src/lfunc.c
@@ -1,5 +1,5 @@
/*
-** $Id: lfunc.c,v 1.10 1999/03/04 21:17:26 roberto Exp $
+** $Id: lfunc.c,v 1.34 2000/10/30 12:20:29 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@@ -7,92 +7,103 @@
#include <stdlib.h>
+#include "lua.h"
+
#include "lfunc.h"
#include "lmem.h"
#include "lstate.h"
-#define gcsizeproto(p) 5 /* approximate "weight" for a prototype */
-#define gcsizeclosure(c) 1 /* approximate "weight" for a closure */
+#define sizeclosure(n) ((int)sizeof(Closure) + (int)sizeof(TObject)*((n)-1))
-Closure *luaF_newclosure (int nelems)
-{
- Closure *c = (Closure *)luaM_malloc(sizeof(Closure)+nelems*sizeof(TObject));
- luaO_insertlist(&(L->rootcl), (GCnode *)c);
- L->nblocks += gcsizeclosure(c);
- c->nelems = nelems;
+Closure *luaF_newclosure (lua_State *L, int nelems) {
+ int size = sizeclosure(nelems);
+ Closure *c = (Closure *)luaM_malloc(L, size);
+ c->next = L->rootcl;
+ L->rootcl = c;
+ c->mark = c;
+ c->nupvalues = nelems;
+ L->nblocks += size;
return c;
}
-TProtoFunc *luaF_newproto (void)
-{
- TProtoFunc *f = luaM_new(TProtoFunc);
+Proto *luaF_newproto (lua_State *L) {
+ Proto *f = luaM_new(L, Proto);
+ f->knum = NULL;
+ f->nknum = 0;
+ f->kstr = NULL;
+ f->nkstr = 0;
+ f->kproto = NULL;
+ f->nkproto = 0;
f->code = NULL;
+ f->ncode = 0;
+ f->numparams = 0;
+ f->is_vararg = 0;
+ f->maxstacksize = 0;
+ f->marked = 0;
+ f->lineinfo = NULL;
+ f->nlineinfo = 0;
+ f->nlocvars = 0;
+ f->locvars = NULL;
f->lineDefined = 0;
f->source = NULL;
- f->consts = NULL;
- f->nconsts = 0;
- f->locvars = NULL;
- luaO_insertlist(&(L->rootproto), (GCnode *)f);
- L->nblocks += gcsizeproto(f);
+ f->next = L->rootproto; /* chain in list of protos */
+ L->rootproto = f;
return f;
}
+static size_t protosize (Proto *f) {
+ return sizeof(Proto)
+ + f->nknum*sizeof(Number)
+ + f->nkstr*sizeof(TString *)
+ + f->nkproto*sizeof(Proto *)
+ + f->ncode*sizeof(Instruction)
+ + f->nlocvars*sizeof(struct LocVar)
+ + f->nlineinfo*sizeof(int);
+}
-static void freefunc (TProtoFunc *f)
-{
- luaM_free(f->code);
- luaM_free(f->locvars);
- luaM_free(f->consts);
- luaM_free(f);
+
+void luaF_protook (lua_State *L, Proto *f, int pc) {
+ f->ncode = pc; /* signal that proto was properly created */
+ L->nblocks += protosize(f);
}
-void luaF_freeproto (TProtoFunc *l)
-{
- while (l) {
- TProtoFunc *next = (TProtoFunc *)l->head.next;
- L->nblocks -= gcsizeproto(l);
- freefunc(l);
- l = next;
- }
+void luaF_freeproto (lua_State *L, Proto *f) {
+ if (f->ncode > 0) /* function was properly created? */
+ L->nblocks -= protosize(f);
+ luaM_free(L, f->code);
+ luaM_free(L, f->locvars);
+ luaM_free(L, f->kstr);
+ luaM_free(L, f->knum);
+ luaM_free(L, f->kproto);
+ luaM_free(L, f->lineinfo);
+ luaM_free(L, f);
}
-void luaF_freeclosure (Closure *l)
-{
- while (l) {
- Closure *next = (Closure *)l->head.next;
- L->nblocks -= gcsizeclosure(l);
- luaM_free(l);
- l = next;
- }
+void luaF_freeclosure (lua_State *L, Closure *c) {
+ L->nblocks -= sizeclosure(c->nupvalues);
+ luaM_free(L, c);
}
/*
-** Look for n-th local variable at line "line" in function "func".
+** Look for n-th local variable at line `line' in function `func'.
** Returns NULL if not found.
*/
-char *luaF_getlocalname (TProtoFunc *func, int local_number, int line)
-{
- int count = 0;
- char *varname = NULL;
- LocVar *lv = func->locvars;
- if (lv == NULL)
- return NULL;
- for (; lv->line != -1 && lv->line < line; lv++) {
- if (lv->varname) { /* register */
- if (++count == local_number)
- varname = lv->varname->str;
+const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
+ int i;
+ for (i = 0; i<f->nlocvars && f->locvars[i].startpc <= pc; i++) {
+ if (pc < f->locvars[i].endpc) { /* is variable active? */
+ local_number--;
+ if (local_number == 0)
+ return f->locvars[i].varname->str;
}
- else /* unregister */
- if (--count < local_number)
- varname = NULL;
}
- return varname;
+ return NULL; /* not found */
}
diff --git a/src/lfunc.h b/src/lfunc.h
index cade80a2..32afbc5d 100644
--- a/src/lfunc.h
+++ b/src/lfunc.h
@@ -1,6 +1,6 @@
/*
-** $Id: lfunc.h,v 1.5 1997/12/15 16:17:20 roberto Exp $
-** Lua Function structures
+** $Id: lfunc.h,v 1.13 2000/09/29 12:42:13 roberto Exp $
+** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@@ -12,12 +12,13 @@
-TProtoFunc *luaF_newproto (void);
-Closure *luaF_newclosure (int nelems);
-void luaF_freeproto (TProtoFunc *l);
-void luaF_freeclosure (Closure *l);
+Proto *luaF_newproto (lua_State *L);
+void luaF_protook (lua_State *L, Proto *f, int pc);
+Closure *luaF_newclosure (lua_State *L, int nelems);
+void luaF_freeproto (lua_State *L, Proto *f);
+void luaF_freeclosure (lua_State *L, Closure *c);
-char *luaF_getlocalname (TProtoFunc *func, int local_number, int line);
+const char *luaF_getlocalname (const Proto *func, int local_number, int pc);
#endif
diff --git a/src/lgc.c b/src/lgc.c
index e153ce8c..6b916a8b 100644
--- a/src/lgc.c
+++ b/src/lgc.c
@@ -1,9 +1,10 @@
/*
-** $Id: lgc.c,v 1.23 1999/03/04 21:17:26 roberto Exp $
+** $Id: lgc.c,v 1.72 2000/10/26 12:47:05 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
+#include "lua.h"
#include "ldo.h"
#include "lfunc.h"
@@ -14,262 +15,339 @@
#include "lstring.h"
#include "ltable.h"
#include "ltm.h"
-#include "lua.h"
+typedef struct GCState {
+ Hash *tmark; /* list of marked tables to be visited */
+ Closure *cmark; /* list of marked closures to be visited */
+} GCState;
-static int markobject (TObject *o);
+static void markobject (GCState *st, TObject *o);
-/*
-** =======================================================
-** REF mechanism
-** =======================================================
-*/
+/* mark a string; marks larger than 1 cannot be changed */
+#define strmark(s) {if ((s)->marked == 0) (s)->marked = 1;}
-int luaC_ref (TObject *o, int lock) {
- int ref;
- if (ttype(o) == LUA_T_NIL)
- ref = -1; /* special ref for nil */
- else {
- for (ref=0; ref<L->refSize; ref++)
- if (L->refArray[ref].status == FREE)
- break;
- if (ref == L->refSize) { /* no more empty spaces? */
- luaM_growvector(L->refArray, L->refSize, 1, struct ref, refEM, MAX_INT);
- L->refSize++;
- }
- L->refArray[ref].o = *o;
- L->refArray[ref].status = lock ? LOCK : HOLD;
+
+
+static void protomark (Proto *f) {
+ if (!f->marked) {
+ int i;
+ f->marked = 1;
+ strmark(f->source);
+ for (i=0; i<f->nkstr; i++)
+ strmark(f->kstr[i]);
+ for (i=0; i<f->nkproto; i++)
+ protomark(f->kproto[i]);
+ for (i=0; i<f->nlocvars; i++) /* mark local-variable names */
+ strmark(f->locvars[i].varname);
}
- return ref;
}
-void lua_unref (int ref)
-{
- if (ref >= 0 && ref < L->refSize)
- L->refArray[ref].status = FREE;
+static void markstack (lua_State *L, GCState *st) {
+ StkId o;
+ for (o=L->stack; o<L->top; o++)
+ markobject(st, o);
}
-TObject* luaC_getref (int ref)
-{
- if (ref == -1)
- return &luaO_nilobject;
- if (ref >= 0 && ref < L->refSize &&
- (L->refArray[ref].status == LOCK || L->refArray[ref].status == HOLD))
- return &L->refArray[ref].o;
- else
- return NULL;
+static void marklock (lua_State *L, GCState *st) {
+ int i;
+ for (i=0; i<L->refSize; i++) {
+ if (L->refArray[i].st == LOCK)
+ markobject(st, &L->refArray[i].o);
+ }
}
-static void travlock (void)
-{
- int i;
- for (i=0; i<L->refSize; i++)
- if (L->refArray[i].status == LOCK)
- markobject(&L->refArray[i].o);
+static void markclosure (GCState *st, Closure *cl) {
+ if (!ismarked(cl)) {
+ if (!cl->isC)
+ protomark(cl->f.l);
+ cl->mark = st->cmark; /* chain it for later traversal */
+ st->cmark = cl;
+ }
+}
+
+
+static void marktagmethods (lua_State *L, GCState *st) {
+ int e;
+ for (e=0; e<TM_N; e++) {
+ int t;
+ for (t=0; t<=L->last_tag; t++) {
+ Closure *cl = luaT_gettm(L, t, e);
+ if (cl) markclosure(st, cl);
+ }
+ }
+}
+
+
+static void markobject (GCState *st, TObject *o) {
+ switch (ttype(o)) {
+ case LUA_TUSERDATA: case LUA_TSTRING:
+ strmark(tsvalue(o));
+ break;
+ case LUA_TMARK:
+ markclosure(st, infovalue(o)->func);
+ break;
+ case LUA_TFUNCTION:
+ markclosure(st, clvalue(o));
+ break;
+ case LUA_TTABLE: {
+ if (!ismarked(hvalue(o))) {
+ hvalue(o)->mark = st->tmark; /* chain it in list of marked */
+ st->tmark = hvalue(o);
+ }
+ break;
+ }
+ default: break; /* numbers, etc */
+ }
+}
+
+
+static void markall (lua_State *L) {
+ GCState st;
+ st.cmark = NULL;
+ st.tmark = L->gt; /* put table of globals in mark list */
+ L->gt->mark = NULL;
+ marktagmethods(L, &st); /* mark tag methods */
+ markstack(L, &st); /* mark stack objects */
+ marklock(L, &st); /* mark locked objects */
+ for (;;) { /* mark tables and closures */
+ if (st.cmark) {
+ int i;
+ Closure *f = st.cmark; /* get first closure from list */
+ st.cmark = f->mark; /* remove it from list */
+ for (i=0; i<f->nupvalues; i++) /* mark its upvalues */
+ markobject(&st, &f->upvalue[i]);
+ }
+ else if (st.tmark) {
+ int i;
+ Hash *h = st.tmark; /* get first table from list */
+ st.tmark = h->mark; /* remove it from list */
+ for (i=0; i<h->size; i++) {
+ Node *n = node(h, i);
+ if (ttype(key(n)) != LUA_TNIL) {
+ if (ttype(val(n)) == LUA_TNIL)
+ luaH_remove(h, key(n)); /* dead element; try to remove it */
+ markobject(&st, &n->key);
+ markobject(&st, &n->val);
+ }
+ }
+ }
+ else break; /* nothing else to mark */
+ }
}
-static int ismarked (TObject *o)
-{
+static int hasmark (const TObject *o) {
/* valid only for locked objects */
switch (o->ttype) {
- case LUA_T_STRING: case LUA_T_USERDATA:
- return o->value.ts->head.marked;
- case LUA_T_ARRAY:
- return o->value.a->head.marked;
- case LUA_T_CLOSURE:
- return o->value.cl->head.marked;
- case LUA_T_PROTO:
- return o->value.tf->head.marked;
-#ifdef DEBUG
- case LUA_T_LINE: case LUA_T_CLMARK:
- case LUA_T_CMARK: case LUA_T_PMARK:
- LUA_INTERNALERROR("invalid type");
-#endif
- default: /* nil, number or cproto */
+ case LUA_TSTRING: case LUA_TUSERDATA:
+ return tsvalue(o)->marked;
+ case LUA_TTABLE:
+ return ismarked(hvalue(o));
+ case LUA_TFUNCTION:
+ return ismarked(clvalue(o));
+ default: /* number */
return 1;
}
}
-static void invalidaterefs (void)
-{
+/* macro for internal debugging; check if a link of free refs is valid */
+#define VALIDLINK(L, st,n) (NONEXT <= (st) && (st) < (n))
+
+static void invalidaterefs (lua_State *L) {
+ int n = L->refSize;
int i;
- for (i=0; i<L->refSize; i++)
- if (L->refArray[i].status == HOLD && !ismarked(&L->refArray[i].o))
- L->refArray[i].status = COLLECTED;
+ for (i=0; i<n; i++) {
+ struct Ref *r = &L->refArray[i];
+ if (r->st == HOLD && !hasmark(&r->o))
+ r->st = COLLECTED;
+ LUA_ASSERT((r->st == LOCK && hasmark(&r->o)) ||
+ (r->st == HOLD && hasmark(&r->o)) ||
+ r->st == COLLECTED ||
+ r->st == NONEXT ||
+ (r->st < n && VALIDLINK(L, L->refArray[r->st].st, n)),
+ "inconsistent ref table");
+ }
+ LUA_ASSERT(VALIDLINK(L, L->refFree, n), "inconsistent ref table");
}
-void luaC_hashcallIM (Hash *l)
-{
- TObject t;
- ttype(&t) = LUA_T_ARRAY;
- for (; l; l=(Hash *)l->head.next) {
- avalue(&t) = l;
- luaD_gcIM(&t);
+static void collectproto (lua_State *L) {
+ Proto **p = &L->rootproto;
+ Proto *next;
+ while ((next = *p) != NULL) {
+ if (next->marked) {
+ next->marked = 0;
+ p = &next->next;
+ }
+ else {
+ *p = next->next;
+ luaF_freeproto(L, next);
+ }
}
}
-void luaC_strcallIM (TaggedString *l)
-{
- TObject o;
- ttype(&o) = LUA_T_USERDATA;
- for (; l; l=(TaggedString *)l->head.next)
- if (l->constindex == -1) { /* is userdata? */
- tsvalue(&o) = l;
- luaD_gcIM(&o);
+static void collectclosure (lua_State *L) {
+ Closure **p = &L->rootcl;
+ Closure *next;
+ while ((next = *p) != NULL) {
+ if (ismarked(next)) {
+ next->mark = next; /* unmark */
+ p = &next->next;
+ }
+ else {
+ *p = next->next;
+ luaF_freeclosure(L, next);
}
+ }
}
-
-static GCnode *listcollect (GCnode *l)
-{
- GCnode *frees = NULL;
- while (l) {
- GCnode *next = l->next;
- l->marked = 0;
- while (next && !next->marked) {
- l->next = next->next;
- next->next = frees;
- frees = next;
- next = l->next;
+static void collecttable (lua_State *L) {
+ Hash **p = &L->roottable;
+ Hash *next;
+ while ((next = *p) != NULL) {
+ if (ismarked(next)) {
+ next->mark = next; /* unmark */
+ p = &next->next;
+ }
+ else {
+ *p = next->next;
+ luaH_free(L, next);
}
- l = next;
}
- return frees;
}
-static void strmark (TaggedString *s)
-{
- if (!s->head.marked)
- s->head.marked = 1;
+static void checktab (lua_State *L, stringtable *tb) {
+ if (tb->nuse < (lint32)(tb->size/4) && tb->size > 10)
+ luaS_resize(L, tb, tb->size/2); /* table is too big */
}
-static void protomark (TProtoFunc *f) {
- if (!f->head.marked) {
- int i;
- f->head.marked = 1;
- strmark(f->source);
- for (i=0; i<f->nconsts; i++)
- markobject(&f->consts[i]);
+static void collectstrings (lua_State *L, int all) {
+ int i;
+ for (i=0; i<L->strt.size; i++) { /* for each list */
+ TString **p = &L->strt.hash[i];
+ TString *next;
+ while ((next = *p) != NULL) {
+ if (next->marked && !all) { /* preserve? */
+ if (next->marked < FIXMARK) /* does not change FIXMARKs */
+ next->marked = 0;
+ p = &next->nexthash;
+ }
+ else { /* collect */
+ *p = next->nexthash;
+ L->strt.nuse--;
+ L->nblocks -= sizestring(next->len);
+ luaM_free(L, next);
+ }
+ }
}
+ checktab(L, &L->strt);
}
-static void closuremark (Closure *f)
-{
- if (!f->head.marked) {
- int i;
- f->head.marked = 1;
- for (i=f->nelems; i>=0; i--)
- markobject(&f->consts[i]);
+static void collectudata (lua_State *L, int all) {
+ int i;
+ for (i=0; i<L->udt.size; i++) { /* for each list */
+ TString **p = &L->udt.hash[i];
+ TString *next;
+ while ((next = *p) != NULL) {
+ LUA_ASSERT(next->marked <= 1, "udata cannot be fixed");
+ if (next->marked && !all) { /* preserve? */
+ next->marked = 0;
+ p = &next->nexthash;
+ }
+ else { /* collect */
+ int tag = next->u.d.tag;
+ *p = next->nexthash;
+ next->nexthash = L->TMtable[tag].collected; /* chain udata */
+ L->TMtable[tag].collected = next;
+ L->nblocks -= sizestring(next->len);
+ L->udt.nuse--;
+ }
+ }
}
+ checktab(L, &L->udt);
}
-static void hashmark (Hash *h)
-{
- if (!h->head.marked) {
- int i;
- h->head.marked = 1;
- for (i=0; i<nhash(h); i++) {
- Node *n = node(h,i);
- if (ttype(ref(n)) != LUA_T_NIL) {
- markobject(&n->ref);
- markobject(&n->val);
- }
- }
+#define MINBUFFER 256
+static void checkMbuffer (lua_State *L) {
+ if (L->Mbuffsize > MINBUFFER*2) { /* is buffer too big? */
+ size_t newsize = L->Mbuffsize/2; /* still larger than MINBUFFER */
+ L->nblocks += (newsize - L->Mbuffsize)*sizeof(char);
+ L->Mbuffsize = newsize;
+ luaM_reallocvector(L, L->Mbuffer, newsize, char);
}
}
-static void globalmark (void)
-{
- TaggedString *g;
- for (g=(TaggedString *)L->rootglobal.next; g; g=(TaggedString *)g->head.next){
- LUA_ASSERT(g->constindex >= 0, "userdata in global list");
- if (g->u.s.globalval.ttype != LUA_T_NIL) {
- markobject(&g->u.s.globalval);
- strmark(g); /* cannot collect non nil global variables */
- }
+static void callgcTM (lua_State *L, const TObject *o) {
+ Closure *tm = luaT_gettmbyObj(L, o, TM_GC);
+ if (tm != NULL) {
+ int oldah = L->allowhooks;
+ L->allowhooks = 0; /* stop debug hooks during GC tag methods */
+ luaD_checkstack(L, 2);
+ clvalue(L->top) = tm;
+ ttype(L->top) = LUA_TFUNCTION;
+ *(L->top+1) = *o;
+ L->top += 2;
+ luaD_call(L, L->top-2, 0);
+ L->allowhooks = oldah; /* restore hooks */
}
}
-static int markobject (TObject *o)
-{
- switch (ttype(o)) {
- case LUA_T_USERDATA: case LUA_T_STRING:
- strmark(tsvalue(o));
- break;
- case LUA_T_ARRAY:
- hashmark(avalue(o));
- break;
- case LUA_T_CLOSURE: case LUA_T_CLMARK:
- closuremark(o->value.cl);
- break;
- case LUA_T_PROTO: case LUA_T_PMARK:
- protomark(o->value.tf);
- break;
- default: break; /* numbers, cprotos, etc */
+static void callgcTMudata (lua_State *L) {
+ int tag;
+ TObject o;
+ ttype(&o) = LUA_TUSERDATA;
+ L->GCthreshold = 2*L->nblocks; /* avoid GC during tag methods */
+ for (tag=L->last_tag; tag>=0; tag--) { /* for each tag (in reverse order) */
+ TString *udata;
+ while ((udata = L->TMtable[tag].collected) != NULL) {
+ L->TMtable[tag].collected = udata->nexthash; /* remove it from list */
+ tsvalue(&o) = udata;
+ callgcTM(L, &o);
+ luaM_free(L, udata);
+ }
}
- return 0;
}
-
-static void markall (void)
-{
- luaD_travstack(markobject); /* mark stack objects */
- globalmark(); /* mark global variable values and names */
- travlock(); /* mark locked objects */
- luaT_travtagmethods(markobject); /* mark fallbacks */
+void luaC_collect (lua_State *L, int all) {
+ collectudata(L, all);
+ callgcTMudata(L);
+ collectstrings(L, all);
+ collecttable(L);
+ collectproto(L);
+ collectclosure(L);
}
-long lua_collectgarbage (long limit)
-{
- unsigned long recovered = L->nblocks; /* to subtract nblocks after gc */
- Hash *freetable;
- TaggedString *freestr;
- TProtoFunc *freefunc;
- Closure *freeclos;
- markall();
- invalidaterefs();
- freestr = luaS_collector();
- freetable = (Hash *)listcollect(&(L->roottable));
- freefunc = (TProtoFunc *)listcollect(&(L->rootproto));
- freeclos = (Closure *)listcollect(&(L->rootcl));
- L->GCthreshold *= 4; /* to avoid GC during GC */
- luaC_hashcallIM(freetable); /* GC tag methods for tables */
- luaC_strcallIM(freestr); /* GC tag methods for userdata */
- luaD_gcIM(&luaO_nilobject); /* GC tag method for nil (signal end of GC) */
- luaH_free(freetable);
- luaS_free(freestr);
- luaF_freeproto(freefunc);
- luaF_freeclosure(freeclos);
- recovered = recovered-L->nblocks;
- L->GCthreshold = (limit == 0) ? 2*L->nblocks : L->nblocks+limit;
- return recovered;
+static void luaC_collectgarbage (lua_State *L) {
+ markall(L);
+ invalidaterefs(L); /* check unlocked references */
+ luaC_collect(L, 0);
+ checkMbuffer(L);
+ L->GCthreshold = 2*L->nblocks; /* set new threshold */
+ callgcTM(L, &luaO_nilobject);
}
-void luaC_checkGC (void)
-{
+void luaC_checkGC (lua_State *L) {
if (L->nblocks >= L->GCthreshold)
- lua_collectgarbage(0);
+ luaC_collectgarbage(L);
}
diff --git a/src/lgc.h b/src/lgc.h
index 38b09553..87a14d16 100644
--- a/src/lgc.h
+++ b/src/lgc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.h,v 1.4 1997/12/01 20:31:25 roberto Exp $
+** $Id: lgc.h,v 1.8 2000/10/02 14:47:43 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -11,11 +11,8 @@
#include "lobject.h"
-void luaC_checkGC (void);
-TObject* luaC_getref (int ref);
-int luaC_ref (TObject *o, int lock);
-void luaC_hashcallIM (Hash *l);
-void luaC_strcallIM (TaggedString *l);
+void luaC_collect (lua_State *L, int all);
+void luaC_checkGC (lua_State *L);
#endif
diff --git a/src/lib/Makefile b/src/lib/Makefile
index 5d8664c9..081b8867 100644
--- a/src/lib/Makefile
+++ b/src/lib/Makefile
@@ -1,4 +1,4 @@
-# makefile for lua standard library
+# makefile for Lua standard library
LUA= ../..
@@ -7,8 +7,8 @@ include $(LUA)/config
# actually only used in liolib.c
EXTRA_DEFS= $(POPEN)
-OBJS= linit.o ldblib.o liolib.o lmathlib.o lstrlib.o
-SRCS= linit.c ldblib.c liolib.c lmathlib.c lstrlib.c
+OBJS= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o lstrlib.o
+SRCS= lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c lstrlib.c
T= $(LIB)/liblualib.a
diff --git a/src/lib/README b/src/lib/README
index e8e599c8..c04a12e2 100644
--- a/src/lib/README
+++ b/src/lib/README
@@ -1,4 +1,6 @@
This is the standard Lua library.
It is implemented entirely on top of the official Lua API as declared in lua.h,
-using src/lauxlib.c, which contains several useful functions.
-The code can be read as an example of how to export C functions to Lua.
+using lauxlib.c, which contains several useful functions for writing libraries.
+We encourage developers to use lauxlib.c in their own libraries.
+The code of the standard library can be read as an example of how to export
+C functions to Lua.
diff --git a/src/lib/lauxlib.c b/src/lib/lauxlib.c
new file mode 100644
index 00000000..4bdaeeff
--- /dev/null
+++ b/src/lib/lauxlib.c
@@ -0,0 +1,216 @@
+/*
+** $Id: lauxlib.c,v 1.43 2000/10/30 13:07:48 roberto Exp $
+** Auxiliary functions for building Lua libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+/* This file uses only the official API of Lua.
+** Any function declared here could be written as an application function.
+** With care, these functions can be used by other libraries.
+*/
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "luadebug.h"
+
+
+
+LUALIB_API int luaL_findstring (const char *name, const char *const list[]) {
+ int i;
+ for (i=0; list[i]; i++)
+ if (strcmp(list[i], name) == 0)
+ return i;
+ return -1; /* name not found */
+}
+
+LUALIB_API void luaL_argerror (lua_State *L, int narg, const char *extramsg) {
+ lua_Debug ar;
+ lua_getstack(L, 0, &ar);
+ lua_getinfo(L, "n", &ar);
+ if (ar.name == NULL)
+ ar.name = "?";
+ luaL_verror(L, "bad argument #%d to `%.50s' (%.100s)",
+ narg, ar.name, extramsg);
+}
+
+
+static void type_error (lua_State *L, int narg, int t) {
+ char buff[50];
+ sprintf(buff, "%.8s expected, got %.8s", lua_typename(L, t),
+ lua_typename(L, lua_type(L, narg)));
+ luaL_argerror(L, narg, buff);
+}
+
+
+LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) {
+ if (space > lua_stackspace(L))
+ luaL_verror(L, "stack overflow (%.30s)", mes);
+}
+
+
+LUALIB_API void luaL_checktype(lua_State *L, int narg, int t) {
+ if (lua_type(L, narg) != t)
+ type_error(L, narg, t);
+}
+
+
+LUALIB_API void luaL_checkany (lua_State *L, int narg) {
+ if (lua_type(L, narg) == LUA_TNONE)
+ luaL_argerror(L, narg, "value expected");
+}
+
+
+LUALIB_API const char *luaL_check_lstr (lua_State *L, int narg, size_t *len) {
+ const char *s = lua_tostring(L, narg);
+ if (!s) type_error(L, narg, LUA_TSTRING);
+ if (len) *len = lua_strlen(L, narg);
+ return s;
+}
+
+
+LUALIB_API const char *luaL_opt_lstr (lua_State *L, int narg, const char *def, size_t *len) {
+ if (lua_isnull(L, narg)) {
+ if (len)
+ *len = (def ? strlen(def) : 0);
+ return def;
+ }
+ else return luaL_check_lstr(L, narg, len);
+}
+
+
+LUALIB_API double luaL_check_number (lua_State *L, int narg) {
+ double d = lua_tonumber(L, narg);
+ if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */
+ type_error(L, narg, LUA_TNUMBER);
+ return d;
+}
+
+
+LUALIB_API double luaL_opt_number (lua_State *L, int narg, double def) {
+ if (lua_isnull(L, narg)) return def;
+ else return luaL_check_number(L, narg);
+}
+
+
+LUALIB_API void luaL_openlib (lua_State *L, const struct luaL_reg *l, int n) {
+ int i;
+ for (i=0; i<n; i++)
+ lua_register(L, l[i].name, l[i].func);
+}
+
+
+LUALIB_API void luaL_verror (lua_State *L, const char *fmt, ...) {
+ char buff[500];
+ va_list argp;
+ va_start(argp, fmt);
+ vsprintf(buff, fmt, argp);
+ va_end(argp);
+ lua_error(L, buff);
+}
+
+
+/*
+** {======================================================
+** Generic Buffer manipulation
+** =======================================================
+*/
+
+
+#define buffempty(B) ((B)->p == (B)->buffer)
+#define bufflen(B) ((B)->p - (B)->buffer)
+#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
+
+#define LIMIT (LUA_MINSTACK/2)
+
+
+static int emptybuffer (luaL_Buffer *B) {
+ size_t l = bufflen(B);
+ if (l == 0) return 0; /* put nothing on stack */
+ else {
+ lua_pushlstring(B->L, B->buffer, l);
+ B->p = B->buffer;
+ B->level++;
+ return 1;
+ }
+}
+
+
+static void adjuststack (luaL_Buffer *B) {
+ if (B->level > 1) {
+ lua_State *L = B->L;
+ int toget = 1; /* number of levels to concat */
+ size_t toplen = lua_strlen(L, -1);
+ do {
+ size_t l = lua_strlen(L, -(toget+1));
+ if (B->level - toget + 1 >= LIMIT || toplen > l) {
+ toplen += l;
+ toget++;
+ }
+ else break;
+ } while (toget < B->level);
+ if (toget >= 2) {
+ lua_concat(L, toget);
+ B->level = B->level - toget + 1;
+ }
+ }
+}
+
+
+LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) {
+ if (emptybuffer(B))
+ adjuststack(B);
+ return B->buffer;
+}
+
+
+LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
+ while (l--)
+ luaL_putchar(B, *s++);
+}
+
+
+LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
+ luaL_addlstring(B, s, strlen(s));
+}
+
+
+LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
+ emptybuffer(B);
+ if (B->level == 0)
+ lua_pushlstring(B->L, NULL, 0);
+ else if (B->level > 1)
+ lua_concat(B->L, B->level);
+ B->level = 1;
+}
+
+
+LUALIB_API void luaL_addvalue (luaL_Buffer *B) {
+ lua_State *L = B->L;
+ size_t vl = lua_strlen(L, -1);
+ if (vl <= bufffree(B)) { /* fit into buffer? */
+ memcpy(B->p, lua_tostring(L, -1), vl); /* put it there */
+ B->p += vl;
+ lua_pop(L, 1); /* remove from stack */
+ }
+ else {
+ if (emptybuffer(B))
+ lua_insert(L, -2); /* put buffer before new value */
+ B->level++; /* add new value into B stack */
+ adjuststack(B);
+ }
+}
+
+
+LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
+ B->L = L;
+ B->p = B->buffer;
+ B->level = 0;
+}
+
+/* }====================================================== */
diff --git a/src/lib/lbaselib.c b/src/lib/lbaselib.c
new file mode 100644
index 00000000..1ff475f9
--- /dev/null
+++ b/src/lib/lbaselib.c
@@ -0,0 +1,651 @@
+/*
+** $Id: lbaselib.c,v 1.17 2000/11/06 13:45:18 roberto Exp $
+** Basic library
+** See Copyright Notice in lua.h
+*/
+
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "luadebug.h"
+#include "lualib.h"
+
+
+
+/*
+** If your system does not support `stderr', redefine this function, or
+** redefine _ERRORMESSAGE so that it won't need _ALERT.
+*/
+static int luaB__ALERT (lua_State *L) {
+ fputs(luaL_check_string(L, 1), stderr);
+ return 0;
+}
+
+
+/*
+** Basic implementation of _ERRORMESSAGE.
+** The library `liolib' redefines _ERRORMESSAGE for better error information.
+*/
+static int luaB__ERRORMESSAGE (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TSTRING);
+ lua_getglobal(L, LUA_ALERT);
+ if (lua_isfunction(L, -1)) { /* avoid error loop if _ALERT is not defined */
+ lua_Debug ar;
+ lua_pushstring(L, "error: ");
+ lua_pushvalue(L, 1);
+ if (lua_getstack(L, 1, &ar)) {
+ lua_getinfo(L, "Sl", &ar);
+ if (ar.source && ar.currentline > 0) {
+ char buff[100];
+ sprintf(buff, "\n <%.70s: line %d>", ar.short_src, ar.currentline);
+ lua_pushstring(L, buff);
+ lua_concat(L, 2);
+ }
+ }
+ lua_pushstring(L, "\n");
+ lua_concat(L, 3);
+ lua_rawcall(L, 1, 0);
+ }
+ return 0;
+}
+
+
+/*
+** 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");
+ for (i=1; i<=n; i++) {
+ const char *s;
+ lua_pushvalue(L, -1); /* function to be called */
+ lua_pushvalue(L, i); /* value to print */
+ lua_rawcall(L, 1, 1);
+ s = lua_tostring(L, -1); /* get result */
+ if (s == NULL)
+ lua_error(L, "`tostring' must return a string to `print'");
+ if (i>1) fputs("\t", stdout);
+ fputs(s, stdout);
+ lua_pop(L, 1); /* pop result */
+ }
+ fputs("\n", stdout);
+ return 0;
+}
+
+
+static int luaB_tonumber (lua_State *L) {
+ int base = luaL_opt_int(L, 2, 10);
+ if (base == 10) { /* standard conversion */
+ luaL_checkany(L, 1);
+ if (lua_isnumber(L, 1)) {
+ lua_pushnumber(L, lua_tonumber(L, 1));
+ return 1;
+ }
+ }
+ else {
+ const char *s1 = luaL_check_string(L, 1);
+ char *s2;
+ unsigned long n;
+ luaL_arg_check(L, 2 <= base && base <= 36, 2, "base out of range");
+ n = strtoul(s1, &s2, base);
+ if (s1 != s2) { /* at least one valid digit? */
+ while (isspace((unsigned char)*s2)) s2++; /* skip trailing spaces */
+ if (*s2 == '\0') { /* no invalid trailing characters? */
+ lua_pushnumber(L, n);
+ return 1;
+ }
+ }
+ }
+ lua_pushnil(L); /* else not a number */
+ return 1;
+}
+
+
+static int luaB_error (lua_State *L) {
+ lua_error(L, luaL_opt_string(L, 1, NULL));
+ return 0; /* to avoid warnings */
+}
+
+static int luaB_setglobal (lua_State *L) {
+ luaL_checkany(L, 2);
+ lua_setglobal(L, luaL_check_string(L, 1));
+ return 0;
+}
+
+static int luaB_getglobal (lua_State *L) {
+ lua_getglobal(L, luaL_check_string(L, 1));
+ return 1;
+}
+
+static int luaB_tag (lua_State *L) {
+ luaL_checkany(L, 1);
+ lua_pushnumber(L, lua_tag(L, 1));
+ return 1;
+}
+
+static int luaB_settag (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ lua_pushvalue(L, 1); /* push table */
+ lua_settag(L, luaL_check_int(L, 2));
+ return 1; /* return table */
+}
+
+static int luaB_newtag (lua_State *L) {
+ lua_pushnumber(L, lua_newtag(L));
+ return 1;
+}
+
+static int luaB_copytagmethods (lua_State *L) {
+ lua_pushnumber(L, lua_copytagmethods(L, luaL_check_int(L, 1),
+ luaL_check_int(L, 2)));
+ return 1;
+}
+
+static int luaB_globals (lua_State *L) {
+ lua_getglobals(L); /* value to be returned */
+ if (!lua_isnull(L, 1)) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ lua_pushvalue(L, 1); /* new table of globals */
+ lua_setglobals(L);
+ }
+ return 1;
+}
+
+static int luaB_rawget (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_checkany(L, 2);
+ lua_rawget(L, -2);
+ return 1;
+}
+
+static int luaB_rawset (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_checkany(L, 2);
+ luaL_checkany(L, 3);
+ lua_rawset(L, -3);
+ return 1;
+}
+
+static int luaB_settagmethod (lua_State *L) {
+ int tag = luaL_check_int(L, 1);
+ const char *event = luaL_check_string(L, 2);
+ luaL_arg_check(L, lua_isfunction(L, 3) || lua_isnil(L, 3), 3,
+ "function or nil expected");
+ if (strcmp(event, "gc") == 0)
+ lua_error(L, "deprecated use: cannot set the `gc' tag method from Lua");
+ lua_gettagmethod(L, tag, event);
+ lua_pushvalue(L, 3);
+ lua_settagmethod(L, tag, event);
+ return 1;
+}
+
+
+static int luaB_gettagmethod (lua_State *L) {
+ int tag = luaL_check_int(L, 1);
+ const char *event = luaL_check_string(L, 2);
+ if (strcmp(event, "gc") == 0)
+ lua_error(L, "deprecated use: cannot get the `gc' tag method from Lua");
+ lua_gettagmethod(L, tag, event);
+ return 1;
+}
+
+
+static int luaB_gcinfo (lua_State *L) {
+ lua_pushnumber(L, lua_getgccount(L));
+ lua_pushnumber(L, lua_getgcthreshold(L));
+ return 2;
+}
+
+
+static int luaB_collectgarbage (lua_State *L) {
+ lua_setgcthreshold(L, luaL_opt_int(L, 1, 0));
+ return 0;
+}
+
+
+static int luaB_type (lua_State *L) {
+ luaL_checkany(L, 1);
+ lua_pushstring(L, lua_typename(L, lua_type(L, 1)));
+ return 1;
+}
+
+
+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 */
+ if (lua_next(L, 1))
+ return 2;
+ else {
+ lua_pushnil(L);
+ return 1;
+ }
+}
+
+
+static int passresults (lua_State *L, int status, int oldtop) {
+ static const char *const errornames[] =
+ {"ok", "run-time error", "file error", "syntax error",
+ "memory error", "error in error handling"};
+ if (status == 0) {
+ int nresults = lua_gettop(L) - oldtop;
+ if (nresults > 0)
+ return nresults; /* results are already on the stack */
+ else {
+ lua_pushuserdata(L, NULL); /* at least one result to signal no errors */
+ return 1;
+ }
+ }
+ else { /* error */
+ lua_pushnil(L);
+ lua_pushstring(L, errornames[status]); /* error code */
+ return 2;
+ }
+}
+
+static int luaB_dostring (lua_State *L) {
+ int oldtop = lua_gettop(L);
+ size_t l;
+ const char *s = luaL_check_lstr(L, 1, &l);
+ if (*s == '\27') /* binary files start with ESC... */
+ lua_error(L, "`dostring' cannot run pre-compiled code");
+ return passresults(L, lua_dobuffer(L, s, l, luaL_opt_string(L, 2, s)), oldtop);
+}
+
+
+static int luaB_dofile (lua_State *L) {
+ int oldtop = lua_gettop(L);
+ const char *fname = luaL_opt_string(L, 1, NULL);
+ return passresults(L, lua_dofile(L, fname), oldtop);
+}
+
+
+static int luaB_call (lua_State *L) {
+ int oldtop;
+ const char *options = luaL_opt_string(L, 3, "");
+ int err = 0; /* index of old error method */
+ int i, status;
+ int n;
+ luaL_checktype(L, 2, LUA_TTABLE);
+ n = lua_getn(L, 2);
+ if (!lua_isnull(L, 4)) { /* set new error method */
+ lua_getglobal(L, LUA_ERRORMESSAGE);
+ err = lua_gettop(L); /* get index */
+ lua_pushvalue(L, 4);
+ lua_setglobal(L, LUA_ERRORMESSAGE);
+ }
+ oldtop = lua_gettop(L); /* top before function-call preparation */
+ /* push function */
+ lua_pushvalue(L, 1);
+ luaL_checkstack(L, n, "too many arguments");
+ for (i=0; i<n; i++) /* push arg[1...n] */
+ lua_rawgeti(L, 2, i+1);
+ status = lua_call(L, n, LUA_MULTRET);
+ if (err != 0) { /* restore old error method */
+ lua_pushvalue(L, err);
+ lua_setglobal(L, LUA_ERRORMESSAGE);
+ }
+ if (status != 0) { /* error in call? */
+ if (strchr(options, 'x'))
+ lua_pushnil(L); /* return nil to signal the error */
+ else
+ lua_error(L, NULL); /* propagate error without additional messages */
+ return 1;
+ }
+ if (strchr(options, 'p')) /* pack results? */
+ lua_error(L, "deprecated option `p' in `call'");
+ return lua_gettop(L) - oldtop; /* results are already on the stack */
+}
+
+
+static int luaB_tostring (lua_State *L) {
+ char buff[64];
+ switch (lua_type(L, 1)) {
+ case LUA_TNUMBER:
+ lua_pushstring(L, lua_tostring(L, 1));
+ return 1;
+ case LUA_TSTRING:
+ lua_pushvalue(L, 1);
+ return 1;
+ case LUA_TTABLE:
+ sprintf(buff, "table: %p", lua_topointer(L, 1));
+ break;
+ case LUA_TFUNCTION:
+ sprintf(buff, "function: %p", lua_topointer(L, 1));
+ break;
+ case LUA_TUSERDATA:
+ sprintf(buff, "userdata(%d): %p", lua_tag(L, 1), lua_touserdata(L, 1));
+ break;
+ case LUA_TNIL:
+ lua_pushstring(L, "nil");
+ return 1;
+ default:
+ luaL_argerror(L, 1, "value expected");
+ }
+ lua_pushstring(L, buff);
+ return 1;
+}
+
+
+static int luaB_foreachi (lua_State *L) {
+ int n, i;
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+ n = lua_getn(L, 1);
+ for (i=1; i<=n; i++) {
+ lua_pushvalue(L, 2); /* function */
+ lua_pushnumber(L, i); /* 1st argument */
+ lua_rawgeti(L, 1, i); /* 2nd argument */
+ lua_rawcall(L, 2, 1);
+ if (!lua_isnil(L, -1))
+ return 1;
+ lua_pop(L, 1); /* remove nil result */
+ }
+ return 0;
+}
+
+
+static int luaB_foreach (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+ lua_pushnil(L); /* first index */
+ for (;;) {
+ if (lua_next(L, 1) == 0)
+ return 0;
+ lua_pushvalue(L, 2); /* function */
+ lua_pushvalue(L, -3); /* key */
+ lua_pushvalue(L, -3); /* value */
+ lua_rawcall(L, 2, 1);
+ if (!lua_isnil(L, -1))
+ return 1;
+ lua_pop(L, 2); /* remove value and result */
+ }
+}
+
+
+static int luaB_assert (lua_State *L) {
+ luaL_checkany(L, 1);
+ if (lua_isnil(L, 1))
+ luaL_verror(L, "assertion failed! %.90s", luaL_opt_string(L, 2, ""));
+ return 0;
+}
+
+
+static int luaB_getn (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ lua_pushnumber(L, lua_getn(L, 1));
+ return 1;
+}
+
+
+static int luaB_tinsert (lua_State *L) {
+ int v = lua_gettop(L); /* last argument: to be inserted */
+ int n, pos;
+ luaL_checktype(L, 1, LUA_TTABLE);
+ n = lua_getn(L, 1);
+ if (v == 2) /* called with only 2 arguments */
+ pos = n+1;
+ else
+ pos = luaL_check_int(L, 2); /* 2nd argument is the position */
+ lua_pushstring(L, "n");
+ lua_pushnumber(L, n+1);
+ lua_rawset(L, 1); /* t.n = n+1 */
+ for (; n>=pos; n--) {
+ lua_rawgeti(L, 1, n);
+ lua_rawseti(L, 1, n+1); /* t[n+1] = t[n] */
+ }
+ lua_pushvalue(L, v);
+ lua_rawseti(L, 1, pos); /* t[pos] = v */
+ return 0;
+}
+
+
+static int luaB_tremove (lua_State *L) {
+ int pos, n;
+ luaL_checktype(L, 1, LUA_TTABLE);
+ n = lua_getn(L, 1);
+ pos = luaL_opt_int(L, 2, n);
+ if (n <= 0) return 0; /* table is "empty" */
+ lua_rawgeti(L, 1, pos); /* result = t[pos] */
+ for ( ;pos<n; pos++) {
+ lua_rawgeti(L, 1, pos+1);
+ lua_rawseti(L, 1, pos); /* a[pos] = a[pos+1] */
+ }
+ lua_pushstring(L, "n");
+ lua_pushnumber(L, n-1);
+ lua_rawset(L, 1); /* t.n = n-1 */
+ lua_pushnil(L);
+ lua_rawseti(L, 1, n); /* t[n] = nil */
+ return 1;
+}
+
+
+
+
+/*
+** {======================================================
+** Quicksort
+** (based on `Algorithms in MODULA-3', Robert Sedgewick;
+** Addison-Wesley, 1993.)
+*/
+
+
+static void set2 (lua_State *L, int i, int j) {
+ lua_rawseti(L, 1, i);
+ lua_rawseti(L, 1, j);
+}
+
+static int sort_comp (lua_State *L, int a, int b) {
+ /* WARNING: the caller (auxsort) must ensure stack space */
+ if (!lua_isnil(L, 2)) { /* function? */
+ int res;
+ lua_pushvalue(L, 2);
+ lua_pushvalue(L, a-1); /* -1 to compensate function */
+ lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */
+ lua_rawcall(L, 2, 1);
+ res = !lua_isnil(L, -1);
+ lua_pop(L, 1);
+ return res;
+ }
+ else /* a < b? */
+ return lua_lessthan(L, a, b);
+}
+
+static void auxsort (lua_State *L, int l, int u) {
+ while (l < u) { /* for tail recursion */
+ int i, j;
+ /* sort elements a[l], a[(l+u)/2] and a[u] */
+ lua_rawgeti(L, 1, l);
+ lua_rawgeti(L, 1, u);
+ if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */
+ set2(L, l, u); /* swap a[l] - a[u] */
+ else
+ lua_pop(L, 2);
+ if (u-l == 1) break; /* only 2 elements */
+ i = (l+u)/2;
+ lua_rawgeti(L, 1, i);
+ lua_rawgeti(L, 1, l);
+ if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */
+ set2(L, i, l);
+ else {
+ lua_pop(L, 1); /* remove a[l] */
+ lua_rawgeti(L, 1, u);
+ if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */
+ set2(L, i, u);
+ else
+ lua_pop(L, 2);
+ }
+ if (u-l == 2) break; /* only 3 elements */
+ lua_rawgeti(L, 1, i); /* Pivot */
+ lua_pushvalue(L, -1);
+ lua_rawgeti(L, 1, u-1);
+ set2(L, i, u-1);
+ /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
+ i = l; j = u-1;
+ 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) lua_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) lua_error(L, "invalid order function for sorting");
+ lua_pop(L, 1); /* remove a[j] */
+ }
+ if (j<i) {
+ lua_pop(L, 3); /* pop pivot, a[i], a[j] */
+ break;
+ }
+ set2(L, i, j);
+ }
+ lua_rawgeti(L, 1, u-1);
+ lua_rawgeti(L, 1, i);
+ set2(L, u-1, i); /* swap pivot (a[u-1]) with a[i] */
+ /* a[l..i-1] <= a[i] == P <= a[i+1..u] */
+ /* adjust so that smaller "half" is in [j..i] and larger one in [l..u] */
+ if (i-l < u-i) {
+ j=l; i=i-1; l=i+2;
+ }
+ else {
+ j=i+1; i=u; u=j-2;
+ }
+ auxsort(L, j, i); /* call recursively the smaller one */
+ } /* repeat the routine for the larger one */
+}
+
+static int luaB_sort (lua_State *L) {
+ int n;
+ luaL_checktype(L, 1, LUA_TTABLE);
+ n = lua_getn(L, 1);
+ if (!lua_isnull(L, 2)) /* is there a 2nd argument? */
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+ lua_settop(L, 2); /* make sure there is two arguments */
+ auxsort(L, 1, n);
+ return 0;
+}
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** Deprecated functions to manipulate global environment.
+** =======================================================
+*/
+
+
+#define num_deprecated 4
+
+static const struct luaL_reg deprecated_names [num_deprecated] = {
+ {"foreachvar", luaB_foreach},
+ {"nextvar", luaB_next},
+ {"rawgetglobal", luaB_rawget},
+ {"rawsetglobal", luaB_rawset}
+};
+
+
+#ifdef LUA_DEPRECATEDFUNCS
+
+/*
+** call corresponding function inserting `globals' as first argument
+*/
+static int deprecated_func (lua_State *L) {
+ lua_insert(L, 1); /* upvalue is the function to be called */
+ lua_getglobals(L);
+ lua_insert(L, 2); /* table of globals is 1o argument */
+ lua_rawcall(L, lua_gettop(L)-1, LUA_MULTRET);
+ return lua_gettop(L); /* return all results */
+}
+
+
+static void deprecated_funcs (lua_State *L) {
+ int i;
+ for (i=0; i<num_deprecated; i++) {
+ lua_pushcfunction(L, deprecated_names[i].func);
+ lua_pushcclosure(L, deprecated_func, 1);
+ lua_setglobal(L, deprecated_names[i].name);
+ }
+}
+
+
+#else
+
+/*
+** gives an explicit error in any attempt to call a deprecated function
+*/
+static int deprecated_func (lua_State *L) {
+ luaL_verror(L, "function `%.20s' is deprecated", lua_tostring(L, -1));
+ return 0; /* to avoid warnings */
+}
+
+
+static void deprecated_funcs (lua_State *L) {
+ int i;
+ for (i=0; i<num_deprecated; i++) {
+ lua_pushstring(L, deprecated_names[i].name);
+ lua_pushcclosure(L, deprecated_func, 1);
+ lua_setglobal(L, deprecated_names[i].name);
+ }
+}
+
+#endif
+
+/* }====================================================== */
+
+static const struct luaL_reg base_funcs[] = {
+ {LUA_ALERT, luaB__ALERT},
+ {LUA_ERRORMESSAGE, luaB__ERRORMESSAGE},
+ {"call", luaB_call},
+ {"collectgarbage", luaB_collectgarbage},
+ {"copytagmethods", luaB_copytagmethods},
+ {"dofile", luaB_dofile},
+ {"dostring", luaB_dostring},
+ {"error", luaB_error},
+ {"foreach", luaB_foreach},
+ {"foreachi", luaB_foreachi},
+ {"gcinfo", luaB_gcinfo},
+ {"getglobal", luaB_getglobal},
+ {"gettagmethod", luaB_gettagmethod},
+ {"globals", luaB_globals},
+ {"newtag", luaB_newtag},
+ {"next", luaB_next},
+ {"print", luaB_print},
+ {"rawget", luaB_rawget},
+ {"rawset", luaB_rawset},
+ {"rawgettable", luaB_rawget}, /* for compatibility */
+ {"rawsettable", luaB_rawset}, /* for compatibility */
+ {"setglobal", luaB_setglobal},
+ {"settag", luaB_settag},
+ {"settagmethod", luaB_settagmethod},
+ {"tag", luaB_tag},
+ {"tonumber", luaB_tonumber},
+ {"tostring", luaB_tostring},
+ {"type", luaB_type},
+ {"assert", luaB_assert},
+ {"getn", luaB_getn},
+ {"sort", luaB_sort},
+ {"tinsert", luaB_tinsert},
+ {"tremove", luaB_tremove}
+};
+
+
+
+LUALIB_API void lua_baselibopen (lua_State *L) {
+ luaL_openl(L, base_funcs);
+ lua_pushstring(L, LUA_VERSION);
+ lua_setglobal(L, "_VERSION");
+ deprecated_funcs(L);
+}
+
diff --git a/src/lib/ldblib.c b/src/lib/ldblib.c
index 388a2f2d..636dbe05 100644
--- a/src/lib/ldblib.c
+++ b/src/lib/ldblib.c
@@ -1,217 +1,188 @@
/*
-** $Id: ldblib.c,v 1.5 1999/03/04 21:17:26 roberto Exp $
+** $Id: ldblib.c,v 1.29 2000/11/06 17:58:38 roberto Exp $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "lauxlib.h"
#include "lua.h"
+
+#include "lauxlib.h"
#include "luadebug.h"
#include "lualib.h"
-static void settabss (lua_Object t, char *i, char *v) {
- lua_pushobject(t);
- lua_pushstring(i);
- lua_pushstring(v);
- lua_settable();
+static void settabss (lua_State *L, const char *i, const char *v) {
+ lua_pushstring(L, i);
+ lua_pushstring(L, v);
+ lua_settable(L, -3);
}
-static void settabsi (lua_Object t, char *i, int v) {
- lua_pushobject(t);
- lua_pushstring(i);
- lua_pushnumber(v);
- lua_settable();
+static void settabsi (lua_State *L, const char *i, int v) {
+ lua_pushstring(L, i);
+ lua_pushnumber(L, v);
+ lua_settable(L, -3);
}
-static lua_Object getfuncinfo (lua_Object func) {
- lua_Object result = lua_createtable();
- char *str;
- int line;
- lua_funcinfo(func, &str, &line);
- if (line == -1) /* C function? */
- settabss(result, "kind", "C");
- else if (line == 0) { /* "main"? */
- settabss(result, "kind", "chunk");
- settabss(result, "source", str);
+static int getinfo (lua_State *L) {
+ lua_Debug ar;
+ const char *options = luaL_opt_string(L, 2, "flnSu");
+ char buff[20];
+ if (lua_isnumber(L, 1)) {
+ if (!lua_getstack(L, (int)lua_tonumber(L, 1), &ar)) {
+ lua_pushnil(L); /* level out of range */
+ return 1;
}
- else { /* Lua function */
- settabss(result, "kind", "Lua");
- settabsi(result, "def_line", line);
- settabss(result, "source", str);
}
- if (line != 0) { /* is it not a "main"? */
- char *kind = lua_getobjname(func, &str);
- if (*kind) {
- settabss(result, "name", str);
- settabss(result, "where", kind);
+ else if (lua_isfunction(L, 1)) {
+ lua_pushvalue(L, 1);
+ sprintf(buff, ">%.10s", options);
+ options = buff;
+ }
+ else
+ luaL_argerror(L, 1, "function or level expected");
+ if (!lua_getinfo(L, options, &ar))
+ luaL_argerror(L, 2, "invalid option");
+ lua_newtable(L);
+ for (; *options; options++) {
+ switch (*options) {
+ case 'S':
+ settabss(L, "source", ar.source);
+ if (ar.source)
+ settabss(L, "short_src", ar.short_src);
+ settabsi(L, "linedefined", ar.linedefined);
+ settabss(L, "what", ar.what);
+ break;
+ case 'l':
+ settabsi(L, "currentline", ar.currentline);
+ break;
+ case 'u':
+ settabsi(L, "nups", ar.nups);
+ break;
+ case 'n':
+ settabss(L, "name", ar.name);
+ settabss(L, "namewhat", ar.namewhat);
+ break;
+ case 'f':
+ lua_pushstring(L, "func");
+ lua_pushvalue(L, -3);
+ lua_settable(L, -3);
+ break;
}
}
- return result;
+ return 1; /* return table */
}
-
-
-static void getstack (void) {
- lua_Object func = lua_stackedfunction(luaL_check_int(1));
- if (func == LUA_NOOBJECT) /* level out of range? */
- return;
- else {
- lua_Object result = getfuncinfo(func);
- int currline = lua_currentline(func);
- if (currline > 0)
- settabsi(result, "current", currline);
- lua_pushobject(result);
- lua_pushstring("func");
- lua_pushobject(func);
- lua_settable(); /* result.func = func */
- lua_pushobject(result);
+
+
+static int getlocal (lua_State *L) {
+ lua_Debug ar;
+ const char *name;
+ if (!lua_getstack(L, luaL_check_int(L, 1), &ar)) /* level out of range? */
+ luaL_argerror(L, 1, "level out of range");
+ name = lua_getlocal(L, &ar, luaL_check_int(L, 2));
+ if (name) {
+ lua_pushstring(L, name);
+ lua_pushvalue(L, -2);
+ return 2;
}
-}
-
-
-static void funcinfo (void) {
- lua_pushobject(getfuncinfo(luaL_functionarg(1)));
-}
-
-
-static int findlocal (lua_Object func, int arg) {
- lua_Object v = lua_getparam(arg);
- if (lua_isnumber(v))
- return (int)lua_getnumber(v);
else {
- char *name = luaL_check_string(arg);
- int i = 0;
- int result = -1;
- char *vname;
- while (lua_getlocal(func, ++i, &vname) != LUA_NOOBJECT) {
- if (strcmp(name, vname) == 0)
- result = i; /* keep looping to get the last var with this name */
- }
- if (result == -1)
- luaL_verror("no local variable `%.50s' at given level", name);
- return result;
+ lua_pushnil(L);
+ return 1;
}
}
-static void getlocal (void) {
- lua_Object func = lua_stackedfunction(luaL_check_int(1));
- lua_Object val;
- char *name;
- if (func == LUA_NOOBJECT) /* level out of range? */
- return; /* return nil */
- else if (lua_getparam(2) != LUA_NOOBJECT) { /* 2nd argument? */
- if ((val = lua_getlocal(func, findlocal(func, 2), &name)) != LUA_NOOBJECT) {
- lua_pushobject(val);
- lua_pushstring(name);
- }
- /* else return nil */
- }
- else { /* collect all locals in a table */
- lua_Object result = lua_createtable();
- int i;
- for (i=1; ;i++) {
- if ((val = lua_getlocal(func, i, &name)) == LUA_NOOBJECT)
- break;
- lua_pushobject(result);
- lua_pushstring(name);
- lua_pushobject(val);
- lua_settable(); /* result[name] = value */
- }
- lua_pushobject(result);
- }
+static int setlocal (lua_State *L) {
+ lua_Debug ar;
+ if (!lua_getstack(L, luaL_check_int(L, 1), &ar)) /* level out of range? */
+ luaL_argerror(L, 1, "level out of range");
+ luaL_checkany(L, 3);
+ lua_pushstring(L, lua_setlocal(L, &ar, luaL_check_int(L, 2)));
+ return 1;
}
-static void setlocal (void) {
- lua_Object func = lua_stackedfunction(luaL_check_int(1));
- int numvar;
- luaL_arg_check(func != LUA_NOOBJECT, 1, "level out of range");
- numvar = findlocal(func, 2);
- lua_pushobject(luaL_nonnullarg(3));
- if (!lua_setlocal(func, numvar))
- lua_error("no such local variable");
-}
+/* dummy variables (to define unique addresses) */
+static char key1, key2;
+#define KEY_CALLHOOK (&key1)
+#define KEY_LINEHOOK (&key2)
-static int linehook = -1; /* Lua reference to line hook function */
-static int callhook = -1; /* Lua reference to call hook function */
+static void hookf (lua_State *L, void *key) {
+ lua_getregistry(L);
+ lua_pushuserdata(L, key);
+ lua_gettable(L, -2);
+ if (lua_isfunction(L, -1)) {
+ lua_pushvalue(L, 1);
+ lua_rawcall(L, 1, 0);
+ }
+ else
+ lua_pop(L, 1); /* pop result from gettable */
+ lua_pop(L, 1); /* pop table */
+}
-static void dohook (int ref) {
- lua_LHFunction oldlinehook = lua_setlinehook(NULL);
- lua_CHFunction oldcallhook = lua_setcallhook(NULL);
- lua_callfunction(lua_getref(ref));
- lua_setlinehook(oldlinehook);
- lua_setcallhook(oldcallhook);
+static void callf (lua_State *L, lua_Debug *ar) {
+ lua_pushstring(L, ar->event);
+ hookf(L, KEY_CALLHOOK);
}
-static void linef (int line) {
- lua_pushnumber(line);
- dohook(linehook);
+static void linef (lua_State *L, lua_Debug *ar) {
+ lua_pushnumber(L, ar->currentline);
+ hookf(L, KEY_LINEHOOK);
}
-static void callf (lua_Function func, char *file, int line) {
- if (func != LUA_NOOBJECT) {
- lua_pushobject(func);
- lua_pushstring(file);
- lua_pushnumber(line);
- }
- dohook(callhook);
+static void sethook (lua_State *L, void *key, lua_Hook hook,
+ lua_Hook (*sethookf)(lua_State * L, lua_Hook h)) {
+ lua_settop(L, 1);
+ if (lua_isnil(L, 1))
+ (*sethookf)(L, NULL);
+ else if (lua_isfunction(L, 1))
+ (*sethookf)(L, hook);
+ else
+ luaL_argerror(L, 1, "function expected");
+ lua_getregistry(L);
+ lua_pushuserdata(L, key);
+ lua_pushvalue(L, -1); /* dup key */
+ lua_gettable(L, -3); /* get old value */
+ lua_pushvalue(L, -2); /* key (again) */
+ lua_pushvalue(L, 1);
+ lua_settable(L, -5); /* set new value */
}
-static void setcallhook (void) {
- lua_Object f = lua_getparam(1);
- lua_unref(callhook);
- if (f == LUA_NOOBJECT) {
- callhook = -1;
- lua_setcallhook(NULL);
- }
- else {
- lua_pushobject(f);
- callhook = lua_ref(1);
- lua_setcallhook(callf);
- }
+static int setcallhook (lua_State *L) {
+ sethook(L, KEY_CALLHOOK, callf, lua_setcallhook);
+ return 1;
}
-static void setlinehook (void) {
- lua_Object f = lua_getparam(1);
- lua_unref(linehook);
- if (f == LUA_NOOBJECT) {
- linehook = -1;
- lua_setlinehook(NULL);
- }
- else {
- lua_pushobject(f);
- linehook = lua_ref(1);
- lua_setlinehook(linef);
- }
+static int setlinehook (lua_State *L) {
+ sethook(L, KEY_LINEHOOK, linef, lua_setlinehook);
+ return 1;
}
-static struct luaL_reg dblib[] = {
- {"funcinfo", funcinfo},
+static const struct luaL_reg dblib[] = {
{"getlocal", getlocal},
- {"getstack", getstack},
+ {"getinfo", getinfo},
{"setcallhook", setcallhook},
{"setlinehook", setlinehook},
{"setlocal", setlocal}
};
-void lua_dblibopen (void) {
- luaL_openlib(dblib, (sizeof(dblib)/sizeof(dblib[0])));
+LUALIB_API void lua_dblibopen (lua_State *L) {
+ luaL_openl(L, dblib);
}
diff --git a/src/lib/linit.c b/src/lib/linit.c
deleted file mode 100644
index be57aae7..00000000
--- a/src/lib/linit.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
-** $Id: linit.c,v 1.1 1999/01/08 16:49:32 roberto Exp $
-** Initialization of libraries for lua.c
-** See Copyright Notice in lua.h
-*/
-
-#include "lua.h"
-#include "lualib.h"
-
-
-void lua_userinit (void) {
- lua_iolibopen();
- lua_strlibopen();
- lua_mathlibopen();
- lua_dblibopen();
-}
-
diff --git a/src/lib/liolib.c b/src/lib/liolib.c
index d833cec5..70f8057a 100644
--- a/src/lib/liolib.c
+++ b/src/lib/liolib.c
@@ -1,67 +1,78 @@
/*
-** $Id: liolib.c,v 1.41 1999/06/23 13:48:39 roberto Exp $
+** $Id: liolib.c,v 1.91 2000/10/31 13:10:24 roberto Exp $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
-#include <errno.h>
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include "lauxlib.h"
#include "lua.h"
+
+#include "lauxlib.h"
#include "luadebug.h"
#include "lualib.h"
#ifndef OLD_ANSI
+#include <errno.h>
#include <locale.h>
+#define realloc(b,s) ((b) == NULL ? malloc(s) : (realloc)(b, s))
+#define free(b) if (b) (free)(b)
#else
/* no support for locale and for strerror: fake them */
-#define setlocale(a,b) 0
+#define setlocale(a,b) ((void)a, strcmp((b),"C")==0?"C":NULL)
#define LC_ALL 0
#define LC_COLLATE 0
#define LC_CTYPE 0
#define LC_MONETARY 0
#define LC_NUMERIC 0
#define LC_TIME 0
-#define strerror(e) "(no error message provided by operating system)"
+#define strerror(e) "generic I/O error"
+#define errno (-1)
#endif
-#define IOTAG 1
-
-#define FIRSTARG 2 /* 1st is upvalue */
-
-#define CLOSEDTAG(tag) ((tag)-1) /* assume that CLOSEDTAG = iotag-1 */
-
-
-#define FINPUT "_INPUT"
-#define FOUTPUT "_OUTPUT"
-
#ifdef POPEN
-FILE *popen();
-int pclose();
-#define CLOSEFILE(f) {if (pclose(f) == -1) fclose(f);}
+/* FILE *popen();
+int pclose(); */
+#define CLOSEFILE(L, f) ((pclose(f) == -1) ? fclose(f) : 0)
#else
/* no support for popen */
#define popen(x,y) NULL /* that is, popen always fails */
-#define CLOSEFILE(f) {fclose(f);}
+#define CLOSEFILE(L, f) (fclose(f))
#endif
+#define INFILE 0
+#define OUTFILE 1
+
+typedef struct IOCtrl {
+ int ref[2]; /* ref for strings _INPUT/_OUTPUT */
+ int iotag; /* tag for file handles */
+ int closedtag; /* tag for closed handles */
+} IOCtrl;
+
+
+
+static const char *const filenames[] = {"_INPUT", "_OUTPUT"};
-static void pushresult (int i) {
- if (i)
- lua_pushuserdata(NULL);
+
+static int pushresult (lua_State *L, int i) {
+ if (i) {
+ lua_pushuserdata(L, NULL);
+ return 1;
+ }
else {
- lua_pushnil();
- lua_pushstring(strerror(errno));
- lua_pushnumber(errno);
+ lua_pushnil(L);
+ lua_pushstring(L, strerror(errno));
+ lua_pushnumber(L, errno);
+ return 3;;
}
}
@@ -72,138 +83,138 @@ static void pushresult (int i) {
** =======================================================
*/
-static int gettag (void) {
- return (int)lua_getnumber(lua_getparam(IOTAG));
-}
-
-static int ishandle (lua_Object f) {
- if (lua_isuserdata(f)) {
- int tag = gettag();
- if (lua_tag(f) == CLOSEDTAG(tag))
- lua_error("cannot access a closed file");
- return lua_tag(f) == tag;
+static FILE *gethandle (lua_State *L, IOCtrl *ctrl, int f) {
+ void *p = lua_touserdata(L, f);
+ if (p != NULL) { /* is `f' a userdata ? */
+ int ftag = lua_tag(L, f);
+ if (ftag == ctrl->iotag) /* does it have the correct tag? */
+ return (FILE *)p;
+ else if (ftag == ctrl->closedtag)
+ lua_error(L, "cannot access a closed file");
+ /* else go through */
}
- else return 0;
+ return NULL;
}
-static FILE *getfilebyname (char *name) {
- lua_Object f = lua_getglobal(name);
- if (!ishandle(f))
- luaL_verror("global variable `%.50s' is not a file handle", name);
- return lua_getuserdata(f);
-}
-
-
-static FILE *getfile (int arg) {
- lua_Object f = lua_getparam(arg);
- return (ishandle(f)) ? lua_getuserdata(f) : NULL;
+static FILE *getnonullfile (lua_State *L, IOCtrl *ctrl, int arg) {
+ FILE *f = gethandle(L, ctrl, arg);
+ luaL_arg_check(L, f, arg, "invalid file handle");
+ return f;
}
-static FILE *getnonullfile (int arg) {
- FILE *f = getfile(arg);
- luaL_arg_check(f, arg, "invalid file handle");
+static FILE *getfilebyref (lua_State *L, IOCtrl *ctrl, int inout) {
+ FILE *f;
+ lua_getglobals(L);
+ lua_getref(L, ctrl->ref[inout]);
+ lua_rawget(L, -2);
+ f = gethandle(L, ctrl, -1);
+ if (f == NULL)
+ luaL_verror(L, "global variable `%.10s' is not a file handle",
+ filenames[inout]);
return f;
}
-static FILE *getfileparam (char *name, int *arg) {
- FILE *f = getfile(*arg);
- if (f) {
- (*arg)++;
- return f;
- }
- else
- return getfilebyname(name);
+static void setfilebyname (lua_State *L, IOCtrl *ctrl, FILE *f,
+ const char *name) {
+ lua_pushusertag(L, f, ctrl->iotag);
+ lua_setglobal(L, name);
}
-static void closefile (FILE *f) {
- if (f != stdin && f != stdout) {
- int tag = gettag();
- CLOSEFILE(f);
- lua_pushusertag(f, tag);
- lua_settag(CLOSEDTAG(tag));
- }
-}
+#define setfile(L,ctrl,f,inout) (setfilebyname(L,ctrl,f,filenames[inout]))
-static void io_close (void) {
- closefile(getnonullfile(FIRSTARG));
+static int setreturn (lua_State *L, IOCtrl *ctrl, FILE *f, int inout) {
+ if (f == NULL)
+ return pushresult(L, 0);
+ else {
+ setfile(L, ctrl, f, inout);
+ lua_pushusertag(L, f, ctrl->iotag);
+ return 1;
+ }
}
-static void gc_close (void) {
- FILE *f = getnonullfile(FIRSTARG);
- if (f != stdin && f != stdout && f != stderr) {
- CLOSEFILE(f);
+static int closefile (lua_State *L, IOCtrl *ctrl, FILE *f) {
+ if (f == stdin || f == stdout || f == stderr)
+ return 1;
+ else {
+ lua_pushusertag(L, f, ctrl->iotag);
+ lua_settag(L, ctrl->closedtag);
+ return (CLOSEFILE(L, f) == 0);
}
}
-static void io_open (void) {
- FILE *f = fopen(luaL_check_string(FIRSTARG), luaL_check_string(FIRSTARG+1));
- if (f) lua_pushusertag(f, gettag());
- else pushresult(0);
+static int io_close (lua_State *L) {
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ lua_pop(L, 1); /* remove upvalue */
+ return pushresult(L, closefile(L, ctrl, getnonullfile(L, ctrl, 1)));
}
-static void setfile (FILE *f, char *name, int tag) {
- lua_pushusertag(f, tag);
- lua_setglobal(name);
+static int file_collect (lua_State *L) {
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ FILE *f = getnonullfile(L, ctrl, 1);
+ if (f != stdin && f != stdout && f != stderr)
+ CLOSEFILE(L, f);
+ return 0;
}
-static void setreturn (FILE *f, char *name) {
- if (f == NULL)
- pushresult(0);
- else {
- int tag = gettag();
- setfile(f, name, tag);
- lua_pushusertag(f, tag);
+static int io_open (lua_State *L) {
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ FILE *f;
+ lua_pop(L, 1); /* remove upvalue */
+ f = fopen(luaL_check_string(L, 1), luaL_check_string(L, 2));
+ if (f) {
+ lua_pushusertag(L, f, ctrl->iotag);
+ return 1;
}
+ else
+ return pushresult(L, 0);
}
-static void io_readfrom (void) {
+
+static int io_fromto (lua_State *L, int inout, const char *mode) {
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
FILE *current;
- lua_Object f = lua_getparam(FIRSTARG);
- if (f == LUA_NOOBJECT) {
- closefile(getfilebyname(FINPUT));
- current = stdin;
+ lua_pop(L, 1); /* remove upvalue */
+ if (lua_isnull(L, 1)) {
+ closefile(L, ctrl, getfilebyref(L, ctrl, inout));
+ current = (inout == 0) ? stdin : stdout;
}
- else if (lua_tag(f) == gettag()) /* deprecated option */
- current = lua_getuserdata(f);
+ else if (lua_tag(L, 1) == ctrl->iotag) /* deprecated option */
+ current = (FILE *)lua_touserdata(L, 1);
else {
- char *s = luaL_check_string(FIRSTARG);
- current = (*s == '|') ? popen(s+1, "r") : fopen(s, "r");
+ const char *s = luaL_check_string(L, 1);
+ current = (*s == '|') ? popen(s+1, mode) : fopen(s, mode);
}
- setreturn(current, FINPUT);
+ return setreturn(L, ctrl, current, inout);
}
-static void io_writeto (void) {
- FILE *current;
- lua_Object f = lua_getparam(FIRSTARG);
- if (f == LUA_NOOBJECT) {
- closefile(getfilebyname(FOUTPUT));
- current = stdout;
- }
- else if (lua_tag(f) == gettag()) /* deprecated option */
- current = lua_getuserdata(f);
- else {
- char *s = luaL_check_string(FIRSTARG);
- current = (*s == '|') ? popen(s+1,"w") : fopen(s, "w");
- }
- setreturn(current, FOUTPUT);
+static int io_readfrom (lua_State *L) {
+ return io_fromto(L, INFILE, "r");
}
-static void io_appendto (void) {
- FILE *current = fopen(luaL_check_string(FIRSTARG), "a");
- setreturn(current, FOUTPUT);
+static int io_writeto (lua_State *L) {
+ return io_fromto(L, OUTFILE, "w");
+}
+
+
+static int io_appendto (lua_State *L) {
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ FILE *current;
+ lua_pop(L, 1); /* remove upvalue */
+ current = fopen(luaL_check_string(L, 1), "a");
+ return setreturn(L, ctrl, current, OUTFILE);
}
@@ -215,6 +226,9 @@ static void io_appendto (void) {
*/
+
+#ifdef LUA_COMPAT_READPATTERN
+
/*
** We cannot lookahead without need, because this can lock stdin.
** This flag signals when we need to read a next char.
@@ -222,9 +236,11 @@ static void io_appendto (void) {
#define NEED_OTHER (EOF-1) /* just some flag different from EOF */
-static int read_pattern (FILE *f, char *p) {
+static int read_pattern (lua_State *L, FILE *f, const char *p) {
int inskip = 0; /* {skip} level */
int c = NEED_OTHER;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
while (*p != '\0') {
switch (*p) {
case '{':
@@ -232,17 +248,17 @@ static int read_pattern (FILE *f, char *p) {
p++;
continue;
case '}':
- if (!inskip) lua_error("unbalanced braces in read pattern");
+ if (!inskip) lua_error(L, "unbalanced braces in read pattern");
inskip--;
p++;
continue;
default: {
- char *ep = luaI_classend(p); /* get what is next */
+ const char *ep = luaI_classend(L, p); /* get what is next */
int m; /* match result */
if (c == NEED_OTHER) c = getc(f);
m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep);
if (m) {
- if (!inskip) luaL_addchar(c);
+ if (!inskip) luaL_putchar(&b, c);
c = NEED_OTHER;
}
switch (*ep) {
@@ -253,7 +269,7 @@ static int read_pattern (FILE *f, char *p) {
while (m) { /* reads the same item until it fails */
c = getc(f);
m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep);
- if (m && !inskip) luaL_addchar(c);
+ if (m && !inskip) luaL_putchar(&b, c);
}
/* go through to continue reading the pattern */
case '?': /* optional */
@@ -267,116 +283,210 @@ static int read_pattern (FILE *f, char *p) {
}
} break_while:
if (c != NEED_OTHER) ungetc(c, f);
+ luaL_pushresult(&b); /* close buffer */
return (*p == '\0');
}
+#else
+
+#define read_pattern(L, f, p) (lua_error(L, "read patterns are deprecated"), 0)
-static int read_number (FILE *f) {
+#endif
+
+
+static int read_number (lua_State *L, FILE *f) {
double d;
if (fscanf(f, "%lf", &d) == 1) {
- lua_pushnumber(d);
+ lua_pushnumber(L, d);
return 1;
}
else return 0; /* read fails */
}
-#define HUNK_LINE 1024
-#define HUNK_FILE BUFSIZ
+static int read_word (lua_State *L, FILE *f) {
+ int c;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ do { c = fgetc(f); } while (isspace(c)); /* skip spaces */
+ while (c != EOF && !isspace(c)) {
+ luaL_putchar(&b, c);
+ c = fgetc(f);
+ }
+ ungetc(c, f);
+ luaL_pushresult(&b); /* close buffer */
+ return (lua_strlen(L, -1) > 0);
+}
-static int read_line (FILE *f) {
- /* equivalent to: return read_pattern(f, "[^\n]*{\n}"); */
- int n;
- char *b;
- do {
- b = luaL_openspace(HUNK_LINE);
- if (!fgets(b, HUNK_LINE, f)) return 0; /* read fails */
- n = strlen(b);
- luaL_addsize(n);
- } while (b[n-1] != '\n');
- luaL_addsize(-1); /* remove '\n' */
- return 1;
+
+static int read_line (lua_State *L, FILE *f) {
+ int n = 0;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ for (;;) {
+ char *p = luaL_prepbuffer(&b);
+ if (!fgets(p, LUAL_BUFFERSIZE, f)) /* read fails? */
+ break;
+ n = strlen(p);
+ if (p[n-1] != '\n')
+ luaL_addsize(&b, n);
+ else {
+ luaL_addsize(&b, n-1); /* do not add the `\n' */
+ break;
+ }
+ }
+ luaL_pushresult(&b); /* close buffer */
+ return (n > 0); /* read something? */
}
-static void read_file (FILE *f) {
- /* equivalent to: return read_pattern(f, ".*"); */
- int n;
- do {
- char *b = luaL_openspace(HUNK_FILE);
- n = fread(b, sizeof(char), HUNK_FILE, f);
- luaL_addsize(n);
- } while (n==HUNK_FILE);
+static void read_file (lua_State *L, FILE *f) {
+ size_t len = 0;
+ size_t size = BUFSIZ;
+ char *buffer = NULL;
+ for (;;) {
+ char *newbuffer = (char *)realloc(buffer, size);
+ if (newbuffer == NULL) {
+ free(buffer);
+ lua_error(L, "not enough memory to read a file");
+ }
+ buffer = newbuffer;
+ len += fread(buffer+len, sizeof(char), size-len, f);
+ if (len < size) break; /* did not read all it could */
+ size *= 2;
+ }
+ lua_pushlstring(L, buffer, len);
+ free(buffer);
}
-static void io_read (void) {
- static char *options[] = {"*n", "*l", "*a", ".*", "*w", NULL};
- int arg = FIRSTARG;
- FILE *f = getfileparam(FINPUT, &arg);
- char *p = luaL_opt_string(arg++, "*l");
- do { /* repeat for each part */
- long l;
+static int read_chars (lua_State *L, FILE *f, size_t n) {
+ char *buffer;
+ size_t n1;
+ char statbuff[BUFSIZ];
+ if (n <= BUFSIZ)
+ buffer = statbuff;
+ else {
+ buffer = (char *)malloc(n);
+ if (buffer == NULL)
+ lua_error(L, "not enough memory to read a file");
+ }
+ n1 = fread(buffer, sizeof(char), n, f);
+ lua_pushlstring(L, buffer, n1);
+ if (buffer != statbuff) free(buffer);
+ return (n1 > 0 || n == 0);
+}
+
+
+static int io_read (lua_State *L) {
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ int lastarg = lua_gettop(L) - 1;
+ int firstarg = 1;
+ FILE *f = gethandle(L, ctrl, firstarg);
+ int n;
+ if (f) firstarg++;
+ else f = getfilebyref(L, ctrl, INFILE); /* get _INPUT */
+ lua_pop(L, 1);
+ if (firstarg > lastarg) { /* no arguments? */
+ lua_settop(L, 0); /* erase upvalue and other eventual garbage */
+ firstarg = lastarg = 1; /* correct indices */
+ lua_pushstring(L, "*l"); /* push default argument */
+ }
+ else /* ensure stack space for all results and for auxlib's buffer */
+ luaL_checkstack(L, lastarg-firstarg+1+LUA_MINSTACK, "too many arguments");
+ for (n = firstarg; n<=lastarg; n++) {
int success;
- luaL_resetbuffer();
- switch (luaL_findstring(p, options)) {
- case 0: /* number */
- if (!read_number(f)) return; /* read fails */
- continue; /* number is already pushed; avoid the "pushstring" */
- case 1: /* line */
- success = read_line(f);
- break;
- case 2: case 3: /* file */
- read_file(f);
- success = 1; /* always success */
- break;
- case 4: /* word */
- success = read_pattern(f, "{%s*}%S+");
- break;
- default:
- success = read_pattern(f, p);
+ if (lua_isnumber(L, n))
+ success = read_chars(L, f, (size_t)lua_tonumber(L, n));
+ else {
+ const char *p = luaL_check_string(L, n);
+ if (p[0] != '*')
+ success = read_pattern(L, f, p); /* deprecated! */
+ else {
+ switch (p[1]) {
+ case 'n': /* number */
+ if (!read_number(L, f)) goto endloop; /* read fails */
+ continue; /* number is already pushed; avoid the "pushstring" */
+ case 'l': /* line */
+ success = read_line(L, f);
+ break;
+ case 'a': /* file */
+ read_file(L, f);
+ success = 1; /* always success */
+ break;
+ case 'w': /* word */
+ success = read_word(L, f);
+ break;
+ default:
+ luaL_argerror(L, n, "invalid format");
+ success = 0; /* to avoid warnings */
+ }
+ }
}
- l = luaL_getsize();
- if (!success && l==0) return; /* read fails */
- lua_pushlstring(luaL_buffer(), l);
- } while ((p = luaL_opt_string(arg++, NULL)) != NULL);
+ if (!success) {
+ lua_pop(L, 1); /* remove last result */
+ break; /* read fails */
+ }
+ } endloop:
+ return n - firstarg;
}
/* }====================================================== */
-static void io_write (void) {
- int arg = FIRSTARG;
- FILE *f = getfileparam(FOUTPUT, &arg);
+static int io_write (lua_State *L) {
+ int lastarg = lua_gettop(L) - 1;
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ int arg = 1;
int status = 1;
- char *s;
- long l;
- while ((s = luaL_opt_lstr(arg++, NULL, &l)) != NULL)
- status = status && ((long)fwrite(s, 1, l, f) == l);
- pushresult(status);
+ FILE *f = gethandle(L, ctrl, arg);
+ if (f) arg++;
+ else f = getfilebyref(L, ctrl, OUTFILE); /* get _OUTPUT */
+ for (; arg <= lastarg; arg++) {
+ if (lua_type(L, arg) == LUA_TNUMBER) { /* LUA_NUMBER */
+ /* optimization: could be done exactly as for strings */
+ status = status && fprintf(f, "%.16g", lua_tonumber(L, arg)) > 0;
+ }
+ else {
+ size_t l;
+ const char *s = luaL_check_lstr(L, arg, &l);
+ status = status && (fwrite(s, sizeof(char), l, f) == l);
+ }
+ }
+ pushresult(L, status);
+ return 1;
}
-static void io_seek (void) {
- static int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
- static char *modenames[] = {"set", "cur", "end", NULL};
- FILE *f = getnonullfile(FIRSTARG);
- int op = luaL_findstring(luaL_opt_string(FIRSTARG+1, "cur"), modenames);
- long offset = luaL_opt_long(FIRSTARG+2, 0);
- luaL_arg_check(op != -1, FIRSTARG+1, "invalid mode");
+static int io_seek (lua_State *L) {
+ static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
+ static const char *const modenames[] = {"set", "cur", "end", NULL};
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ FILE *f;
+ int op;
+ long offset;
+ lua_pop(L, 1); /* remove upvalue */
+ f = getnonullfile(L, ctrl, 1);
+ op = luaL_findstring(luaL_opt_string(L, 2, "cur"), modenames);
+ offset = luaL_opt_long(L, 3, 0);
+ luaL_arg_check(L, op != -1, 2, "invalid mode");
op = fseek(f, offset, mode[op]);
if (op)
- pushresult(0); /* error */
- else
- lua_pushnumber(ftell(f));
+ return pushresult(L, 0); /* error */
+ else {
+ lua_pushnumber(L, ftell(f));
+ return 1;
+ }
}
-static void io_flush (void) {
- FILE *f = getfile(FIRSTARG);
- luaL_arg_check(f || lua_getparam(FIRSTARG) == LUA_NOOBJECT, FIRSTARG,
- "invalid file handle");
- pushresult(fflush(f) == 0);
+static int io_flush (lua_State *L) {
+ IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
+ FILE *f;
+ lua_pop(L, 1); /* remove upvalue */
+ f = gethandle(L, ctrl, 1);
+ luaL_arg_check(L, f || lua_isnull(L, 1), 1, "invalid file handle");
+ return pushresult(L, fflush(f) == 0);
}
/* }====================================================== */
@@ -388,145 +498,165 @@ static void io_flush (void) {
** =======================================================
*/
-static void io_execute (void) {
- lua_pushnumber(system(luaL_check_string(1)));
+static int io_execute (lua_State *L) {
+ lua_pushnumber(L, system(luaL_check_string(L, 1)));
+ return 1;
}
-static void io_remove (void) {
- pushresult(remove(luaL_check_string(1)) == 0);
+static int io_remove (lua_State *L) {
+ return pushresult(L, remove(luaL_check_string(L, 1)) == 0);
}
-static void io_rename (void) {
- pushresult(rename(luaL_check_string(1),
- luaL_check_string(2)) == 0);
+static int io_rename (lua_State *L) {
+ return pushresult(L, rename(luaL_check_string(L, 1),
+ luaL_check_string(L, 2)) == 0);
}
-static void io_tmpname (void) {
- lua_pushstring(tmpnam(NULL));
+static int io_tmpname (lua_State *L) {
+ lua_pushstring(L, tmpnam(NULL));
+ return 1;
}
-static void io_getenv (void) {
- lua_pushstring(getenv(luaL_check_string(1))); /* if NULL push nil */
+static int io_getenv (lua_State *L) {
+ lua_pushstring(L, getenv(luaL_check_string(L, 1))); /* if NULL push nil */
+ return 1;
}
-static void io_clock (void) {
- lua_pushnumber(((double)clock())/CLOCKS_PER_SEC);
+static int io_clock (lua_State *L) {
+ lua_pushnumber(L, ((double)clock())/CLOCKS_PER_SEC);
+ return 1;
}
-static void io_date (void) {
+static int io_date (lua_State *L) {
char b[256];
- char *s = luaL_opt_string(1, "%c");
- struct tm *tm;
+ const char *s = luaL_opt_string(L, 1, "%c");
+ struct tm *stm;
time_t t;
- time(&t); tm = localtime(&t);
- if (strftime(b,sizeof(b),s,tm))
- lua_pushstring(b);
+ time(&t); stm = localtime(&t);
+ if (strftime(b, sizeof(b), s, stm))
+ lua_pushstring(L, b);
else
- lua_error("invalid `date' format");
+ lua_error(L, "invalid `date' format");
+ return 1;
}
-static void setloc (void) {
- static int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC,
- LC_TIME};
- static char *catnames[] = {"all", "collate", "ctype", "monetary",
+static int setloc (lua_State *L) {
+ static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY,
+ LC_NUMERIC, LC_TIME};
+ static const char *const catnames[] = {"all", "collate", "ctype", "monetary",
"numeric", "time", NULL};
- int op = luaL_findstring(luaL_opt_string(2, "all"), catnames);
- luaL_arg_check(op != -1, 2, "invalid option");
- lua_pushstring(setlocale(cat[op], luaL_check_string(1)));
+ int op = luaL_findstring(luaL_opt_string(L, 2, "all"), catnames);
+ luaL_arg_check(L, op != -1, 2, "invalid option");
+ lua_pushstring(L, setlocale(cat[op], luaL_check_string(L, 1)));
+ return 1;
}
-static void io_exit (void) {
- lua_Object o = lua_getparam(1);
- exit(lua_isnumber(o) ? (int)lua_getnumber(o) : 1);
+static int io_exit (lua_State *L) {
+ exit(luaL_opt_int(L, 1, EXIT_SUCCESS));
+ return 0; /* to avoid warnings */
}
/* }====================================================== */
-static void io_debug (void) {
+static int io_debug (lua_State *L) {
for (;;) {
char buffer[250];
fprintf(stderr, "lua_debug> ");
if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
strcmp(buffer, "cont\n") == 0)
- return;
- lua_dostring(buffer);
+ return 0;
+ lua_dostring(L, buffer);
+ lua_settop(L, 0); /* remove eventual returns */
}
}
+#define LEVELS1 12 /* size of the first part of the stack */
+#define LEVELS2 10 /* size of the second part of the stack */
-#define MESSAGESIZE 150
-#define MAXMESSAGE (MESSAGESIZE*10)
-
-
-#define MAXSRC 60
-
-
-static void errorfb (void) {
- char buff[MAXMESSAGE];
+static int errorfb (lua_State *L) {
int level = 1; /* skip level 0 (it's this function) */
- lua_Object func;
- sprintf(buff, "lua error: %.200s\n", lua_getstring(lua_getparam(1)));
- while ((func = lua_stackedfunction(level++)) != LUA_NOOBJECT) {
- char *name;
- int currentline;
- char *chunkname;
- char buffchunk[MAXSRC];
- int linedefined;
- lua_funcinfo(func, &chunkname, &linedefined);
- luaL_chunkid(buffchunk, chunkname, sizeof(buffchunk));
- if (level == 2) strcat(buff, "Active Stack:\n");
- strcat(buff, " ");
- if (strlen(buff) > MAXMESSAGE-MESSAGESIZE) {
- strcat(buff, "...\n");
- break; /* buffer is full */
+ int firstpart = 1; /* still before eventual `...' */
+ lua_Debug ar;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ luaL_addstring(&b, "error: ");
+ luaL_addstring(&b, luaL_check_string(L, 1));
+ luaL_addstring(&b, "\n");
+ while (lua_getstack(L, level++, &ar)) {
+ char buff[120]; /* enough to fit following `sprintf's */
+ if (level == 2)
+ luaL_addstring(&b, "stack traceback:\n");
+ else if (level > LEVELS1 && firstpart) {
+ /* no more than `LEVELS2' more levels? */
+ if (!lua_getstack(L, level+LEVELS2, &ar))
+ level--; /* keep going */
+ else {
+ luaL_addstring(&b, " ...\n"); /* too many levels */
+ while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */
+ level++;
+ }
+ firstpart = 0;
+ continue;
}
- switch (*lua_getobjname(func, &name)) {
- case 'g':
- sprintf(buff+strlen(buff), "function `%.50s'", name);
+ sprintf(buff, "%4d: ", level-1);
+ luaL_addstring(&b, buff);
+ lua_getinfo(L, "Snl", &ar);
+ switch (*ar.namewhat) {
+ case 'g': case 'l': /* global, local */
+ sprintf(buff, "function `%.50s'", ar.name);
break;
- case 't':
- sprintf(buff+strlen(buff), "`%.50s' tag method", name);
+ case 'f': /* field */
+ sprintf(buff, "method `%.50s'", ar.name);
+ break;
+ case 't': /* tag method */
+ sprintf(buff, "`%.50s' tag method", ar.name);
break;
default: {
- if (linedefined == 0)
- sprintf(buff+strlen(buff), "main of %.70s", buffchunk);
- else if (linedefined < 0)
- sprintf(buff+strlen(buff), "%.70s", buffchunk);
+ if (*ar.what == 'm') /* main? */
+ sprintf(buff, "main of %.70s", ar.short_src);
+ else if (*ar.what == 'C') /* C function? */
+ sprintf(buff, "%.70s", ar.short_src);
else
- sprintf(buff+strlen(buff), "function <%d:%.70s>",
- linedefined, buffchunk);
- chunkname = NULL;
+ sprintf(buff, "function <%d:%.70s>", ar.linedefined, ar.short_src);
+ ar.source = NULL; /* do not print source again */
}
}
- if ((currentline = lua_currentline(func)) > 0)
- sprintf(buff+strlen(buff), " at line %d", currentline);
- if (chunkname)
- sprintf(buff+strlen(buff), " [%.70s]", buffchunk);
- strcat(buff, "\n");
+ luaL_addstring(&b, buff);
+ if (ar.currentline > 0) {
+ sprintf(buff, " at line %d", ar.currentline);
+ luaL_addstring(&b, buff);
+ }
+ if (ar.source) {
+ sprintf(buff, " [%.70s]", ar.short_src);
+ luaL_addstring(&b, buff);
+ }
+ luaL_addstring(&b, "\n");
}
- func = lua_rawgetglobal("_ALERT");
- if (lua_isfunction(func)) { /* avoid error loop if _ALERT is not defined */
- lua_pushstring(buff);
- lua_callfunction(func);
+ luaL_pushresult(&b);
+ lua_getglobal(L, LUA_ALERT);
+ if (lua_isfunction(L, -1)) { /* avoid loop if _ALERT is not defined */
+ lua_pushvalue(L, -2); /* error message */
+ lua_rawcall(L, 1, 0);
}
+ return 0;
}
-static struct luaL_reg iolib[] = {
- {"_ERRORMESSAGE", errorfb},
+static const struct luaL_reg iolib[] = {
+ {LUA_ERRORMESSAGE, errorfb},
{"clock", io_clock},
{"date", io_date},
{"debug", io_debug},
@@ -540,7 +670,7 @@ static struct luaL_reg iolib[] = {
};
-static struct luaL_reg iolibtag[] = {
+static const struct luaL_reg iolibtag[] = {
{"appendto", io_appendto},
{"closefile", io_close},
{"flush", io_flush},
@@ -553,31 +683,36 @@ static struct luaL_reg iolibtag[] = {
};
-static void openwithtags (void) {
- int i;
- int iotag = lua_newtag();
- lua_newtag(); /* alloc CLOSEDTAG: assume that CLOSEDTAG = iotag-1 */
+static void openwithcontrol (lua_State *L) {
+ IOCtrl *ctrl = (IOCtrl *)lua_newuserdata(L, sizeof(IOCtrl));
+ unsigned int i;
+ ctrl->iotag = lua_newtag(L);
+ ctrl->closedtag = lua_newtag(L);
for (i=0; i<sizeof(iolibtag)/sizeof(iolibtag[0]); i++) {
- /* put iotag as upvalue for these functions */
- lua_pushnumber(iotag);
- lua_pushcclosure(iolibtag[i].func, 1);
- lua_setglobal(iolibtag[i].name);
+ /* put `ctrl' as upvalue for these functions */
+ lua_pushvalue(L, -1);
+ lua_pushcclosure(L, iolibtag[i].func, 1);
+ lua_setglobal(L, iolibtag[i].name);
}
+ /* create references to variable names */
+ lua_pushstring(L, filenames[INFILE]);
+ ctrl->ref[INFILE] = lua_ref(L, 1);
+ lua_pushstring(L, filenames[OUTFILE]);
+ ctrl->ref[OUTFILE] = lua_ref(L, 1);
/* predefined file handles */
- setfile(stdin, FINPUT, iotag);
- setfile(stdout, FOUTPUT, iotag);
- setfile(stdin, "_STDIN", iotag);
- setfile(stdout, "_STDOUT", iotag);
- setfile(stderr, "_STDERR", iotag);
- /* close file when collected */
- lua_pushnumber(iotag);
- lua_pushcclosure(gc_close, 1);
- lua_settagmethod(iotag, "gc");
-}
-
-void lua_iolibopen (void) {
- /* register lib functions */
- luaL_openlib(iolib, (sizeof(iolib)/sizeof(iolib[0])));
- openwithtags();
+ setfile(L, ctrl, stdin, INFILE);
+ setfile(L, ctrl, stdout, OUTFILE);
+ setfilebyname(L, ctrl, stdin, "_STDIN");
+ setfilebyname(L, ctrl, stdout, "_STDOUT");
+ setfilebyname(L, ctrl, stderr, "_STDERR");
+ /* close files when collected */
+ lua_pushcclosure(L, file_collect, 1); /* pops `ctrl' from stack */
+ lua_settagmethod(L, ctrl->iotag, "gc");
+}
+
+
+LUALIB_API void lua_iolibopen (lua_State *L) {
+ luaL_openl(L, iolib);
+ openwithcontrol(L);
}
diff --git a/src/lib/lmathlib.c b/src/lib/lmathlib.c
index 19cb11c2..c062cf49 100644
--- a/src/lib/lmathlib.c
+++ b/src/lib/lmathlib.c
@@ -1,6 +1,6 @@
/*
-** $Id: lmathlib.c,v 1.17 1999/07/07 17:54:08 roberto Exp $
-** Lua standard mathematical library
+** $Id: lmathlib.c,v 1.32 2000/10/31 13:10:24 roberto Exp $
+** Standard mathematical library
** See Copyright Notice in lua.h
*/
@@ -8,14 +8,15 @@
#include <stdlib.h>
#include <math.h>
-#include "lauxlib.h"
#include "lua.h"
+
+#include "lauxlib.h"
#include "lualib.h"
#undef PI
-#define PI (3.14159265358979323846)
-#define RADIANS_PER_DEGREE (PI/180.0)
+#define PI (3.14159265358979323846)
+#define RADIANS_PER_DEGREE (PI/180.0)
@@ -32,139 +33,173 @@
#endif
-static void math_abs (void) {
- lua_pushnumber(fabs(luaL_check_number(1)));
+static int math_abs (lua_State *L) {
+ lua_pushnumber(L, fabs(luaL_check_number(L, 1)));
+ return 1;
}
-static void math_sin (void) {
- lua_pushnumber(sin(TORAD(luaL_check_number(1))));
+static int math_sin (lua_State *L) {
+ lua_pushnumber(L, sin(TORAD(luaL_check_number(L, 1))));
+ return 1;
}
-static void math_cos (void) {
- lua_pushnumber(cos(TORAD(luaL_check_number(1))));
+static int math_cos (lua_State *L) {
+ lua_pushnumber(L, cos(TORAD(luaL_check_number(L, 1))));
+ return 1;
}
-static void math_tan (void) {
- lua_pushnumber(tan(TORAD(luaL_check_number(1))));
+static int math_tan (lua_State *L) {
+ lua_pushnumber(L, tan(TORAD(luaL_check_number(L, 1))));
+ return 1;
}
-static void math_asin (void) {
- lua_pushnumber(FROMRAD(asin(luaL_check_number(1))));
+static int math_asin (lua_State *L) {
+ lua_pushnumber(L, FROMRAD(asin(luaL_check_number(L, 1))));
+ return 1;
}
-static void math_acos (void) {
- lua_pushnumber(FROMRAD(acos(luaL_check_number(1))));
+static int math_acos (lua_State *L) {
+ lua_pushnumber(L, FROMRAD(acos(luaL_check_number(L, 1))));
+ return 1;
}
-static void math_atan (void) {
- lua_pushnumber(FROMRAD(atan(luaL_check_number(1))));
+static int math_atan (lua_State *L) {
+ lua_pushnumber(L, FROMRAD(atan(luaL_check_number(L, 1))));
+ return 1;
}
-static void math_atan2 (void) {
- lua_pushnumber(FROMRAD(atan2(luaL_check_number(1), luaL_check_number(2))));
+static int math_atan2 (lua_State *L) {
+ lua_pushnumber(L, FROMRAD(atan2(luaL_check_number(L, 1), luaL_check_number(L, 2))));
+ return 1;
}
-static void math_ceil (void) {
- lua_pushnumber(ceil(luaL_check_number(1)));
+static int math_ceil (lua_State *L) {
+ lua_pushnumber(L, ceil(luaL_check_number(L, 1)));
+ return 1;
}
-static void math_floor (void) {
- lua_pushnumber(floor(luaL_check_number(1)));
+static int math_floor (lua_State *L) {
+ lua_pushnumber(L, floor(luaL_check_number(L, 1)));
+ return 1;
}
-static void math_mod (void) {
- lua_pushnumber(fmod(luaL_check_number(1), luaL_check_number(2)));
+static int math_mod (lua_State *L) {
+ lua_pushnumber(L, fmod(luaL_check_number(L, 1), luaL_check_number(L, 2)));
+ return 1;
}
-static void math_sqrt (void) {
- lua_pushnumber(sqrt(luaL_check_number(1)));
+static int math_sqrt (lua_State *L) {
+ lua_pushnumber(L, sqrt(luaL_check_number(L, 1)));
+ return 1;
}
-static void math_pow (void) {
- lua_pushnumber(pow(luaL_check_number(1), luaL_check_number(2)));
+static int math_pow (lua_State *L) {
+ lua_pushnumber(L, pow(luaL_check_number(L, 1), luaL_check_number(L, 2)));
+ return 1;
}
-static void math_log (void) {
- lua_pushnumber(log(luaL_check_number(1)));
+static int math_log (lua_State *L) {
+ lua_pushnumber(L, log(luaL_check_number(L, 1)));
+ return 1;
}
-static void math_log10 (void) {
- lua_pushnumber(log10(luaL_check_number(1)));
+static int math_log10 (lua_State *L) {
+ lua_pushnumber(L, log10(luaL_check_number(L, 1)));
+ return 1;
}
-static void math_exp (void) {
- lua_pushnumber(exp(luaL_check_number(1)));
+static int math_exp (lua_State *L) {
+ lua_pushnumber(L, exp(luaL_check_number(L, 1)));
+ return 1;
}
-static void math_deg (void) {
- lua_pushnumber(luaL_check_number(1)/RADIANS_PER_DEGREE);
+static int math_deg (lua_State *L) {
+ lua_pushnumber(L, luaL_check_number(L, 1)/RADIANS_PER_DEGREE);
+ return 1;
}
-static void math_rad (void) {
- lua_pushnumber(luaL_check_number(1)*RADIANS_PER_DEGREE);
+static int math_rad (lua_State *L) {
+ lua_pushnumber(L, luaL_check_number(L, 1)*RADIANS_PER_DEGREE);
+ return 1;
}
-static void math_frexp (void) {
+static int math_frexp (lua_State *L) {
int e;
- lua_pushnumber(frexp(luaL_check_number(1), &e));
- lua_pushnumber(e);
+ lua_pushnumber(L, frexp(luaL_check_number(L, 1), &e));
+ lua_pushnumber(L, e);
+ return 2;
}
-static void math_ldexp (void) {
- lua_pushnumber(ldexp(luaL_check_number(1), luaL_check_int(2)));
+static int math_ldexp (lua_State *L) {
+ lua_pushnumber(L, ldexp(luaL_check_number(L, 1), luaL_check_int(L, 2)));
+ return 1;
}
-static void math_min (void) {
- int i = 1;
- double dmin = luaL_check_number(i);
- while (lua_getparam(++i) != LUA_NOOBJECT) {
- double d = luaL_check_number(i);
+static int math_min (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ double dmin = luaL_check_number(L, 1);
+ int i;
+ for (i=2; i<=n; i++) {
+ double d = luaL_check_number(L, i);
if (d < dmin)
dmin = d;
}
- lua_pushnumber(dmin);
+ lua_pushnumber(L, dmin);
+ return 1;
}
-static void math_max (void) {
- int i = 1;
- double dmax = luaL_check_number(i);
- while (lua_getparam(++i) != LUA_NOOBJECT) {
- double d = luaL_check_number(i);
+static int math_max (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ double dmax = luaL_check_number(L, 1);
+ int i;
+ for (i=2; i<=n; i++) {
+ double d = luaL_check_number(L, i);
if (d > dmax)
dmax = d;
}
- lua_pushnumber(dmax);
+ lua_pushnumber(L, dmax);
+ return 1;
}
-static void math_random (void) {
+static int math_random (lua_State *L) {
/* the '%' avoids the (rare) case of r==1, and is needed also because on
- some systems (SunOS!) "rand()" may return a value bigger than RAND_MAX */
+ some systems (SunOS!) "rand()" may return a value larger than RAND_MAX */
double r = (double)(rand()%RAND_MAX) / (double)RAND_MAX;
- int l = luaL_opt_int(1, 0);
- if (l == 0)
- lua_pushnumber(r);
- else {
- int u = luaL_opt_int(2, 0);
- if (u == 0) {
- u = l;
- l = 1;
+ switch (lua_gettop(L)) { /* check number of arguments */
+ case 0: { /* no arguments */
+ lua_pushnumber(L, r); /* Number between 0 and 1 */
+ break;
+ }
+ case 1: { /* only upper limit */
+ int u = luaL_check_int(L, 1);
+ luaL_arg_check(L, 1<=u, 1, "interval is empty");
+ lua_pushnumber(L, (int)(r*u)+1); /* integer between 1 and `u' */
+ break;
+ }
+ case 2: { /* lower and upper limits */
+ int l = luaL_check_int(L, 1);
+ int u = luaL_check_int(L, 2);
+ luaL_arg_check(L, l<=u, 2, "interval is empty");
+ lua_pushnumber(L, (int)(r*(u-l+1))+l); /* integer between `l' and `u' */
+ break;
}
- luaL_arg_check(l<=u, 1, "interval is empty");
- lua_pushnumber((int)(r*(u-l+1))+l);
+ default: lua_error(L, "wrong number of arguments");
}
+ return 1;
}
-static void math_randomseed (void) {
- srand(luaL_check_int(1));
+static int math_randomseed (lua_State *L) {
+ srand(luaL_check_int(L, 1));
+ return 0;
}
-static struct luaL_reg mathlib[] = {
+static const struct luaL_reg mathlib[] = {
{"abs", math_abs},
{"sin", math_sin},
{"cos", math_cos},
@@ -193,11 +228,11 @@ static struct luaL_reg mathlib[] = {
/*
** Open math library
*/
-void lua_mathlibopen (void) {
- luaL_openlib(mathlib, (sizeof(mathlib)/sizeof(mathlib[0])));
- lua_pushcfunction(math_pow);
- lua_pushnumber(0); /* to get its tag */
- lua_settagmethod(lua_tag(lua_pop()), "pow");
- lua_pushnumber(PI); lua_setglobal("PI");
+LUALIB_API void lua_mathlibopen (lua_State *L) {
+ luaL_openl(L, mathlib);
+ lua_pushcfunction(L, math_pow);
+ lua_settagmethod(L, LUA_TNUMBER, "pow");
+ lua_pushnumber(L, PI);
+ lua_setglobal(L, "PI");
}
diff --git a/src/lib/lstrlib.c b/src/lib/lstrlib.c
index b47e21d3..8f286982 100644
--- a/src/lib/lstrlib.c
+++ b/src/lib/lstrlib.c
@@ -1,112 +1,111 @@
/*
-** $Id: lstrlib.c,v 1.32 1999/06/17 17:04:03 roberto Exp $
-** Standard library for strings and pattern-matching
+** $Id: lstrlib.c,v 1.56 2000/10/27 16:15:53 roberto Exp $
+** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
#include <ctype.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "lauxlib.h"
#include "lua.h"
-#include "lualib.h"
-
-
-
-static void addnchar (char *s, int n)
-{
- char *b = luaL_openspace(n);
- memcpy(b, s, n);
- luaL_addsize(n);
-}
+#include "lauxlib.h"
+#include "lualib.h"
-static void str_len (void)
-{
- long l;
- luaL_check_lstr(1, &l);
- lua_pushnumber(l);
-}
-static void closeandpush (void) {
- lua_pushlstring(luaL_buffer(), luaL_getsize());
+static int str_len (lua_State *L) {
+ size_t l;
+ luaL_check_lstr(L, 1, &l);
+ lua_pushnumber(L, l);
+ return 1;
}
-static long posrelat (long pos, long len) {
+static long posrelat (long pos, size_t len) {
/* relative string position: negative means back from end */
- return (pos>=0) ? pos : len+pos+1;
+ return (pos>=0) ? pos : (long)len+pos+1;
}
-static void str_sub (void) {
- long l;
- char *s = luaL_check_lstr(1, &l);
- long start = posrelat(luaL_check_long(2), l);
- long end = posrelat(luaL_opt_long(3, -1), l);
+static int str_sub (lua_State *L) {
+ size_t l;
+ const char *s = luaL_check_lstr(L, 1, &l);
+ long start = posrelat(luaL_check_long(L, 2), l);
+ long end = posrelat(luaL_opt_long(L, 3, -1), l);
if (start < 1) start = 1;
- if (end > l) end = l;
+ if (end > (long)l) end = l;
if (start <= end)
- lua_pushlstring(s+start-1, end-start+1);
- else lua_pushstring("");
+ lua_pushlstring(L, s+start-1, end-start+1);
+ else lua_pushstring(L, "");
+ return 1;
}
-static void str_lower (void) {
- long l;
- int i;
- char *s = luaL_check_lstr(1, &l);
- luaL_resetbuffer();
+static int str_lower (lua_State *L) {
+ size_t l;
+ size_t i;
+ luaL_Buffer b;
+ const char *s = luaL_check_lstr(L, 1, &l);
+ luaL_buffinit(L, &b);
for (i=0; i<l; i++)
- luaL_addchar(tolower((unsigned char)(s[i])));
- closeandpush();
+ luaL_putchar(&b, tolower((unsigned char)(s[i])));
+ luaL_pushresult(&b);
+ return 1;
}
-static void str_upper (void) {
- long l;
- int i;
- char *s = luaL_check_lstr(1, &l);
- luaL_resetbuffer();
+static int str_upper (lua_State *L) {
+ size_t l;
+ size_t i;
+ luaL_Buffer b;
+ const char *s = luaL_check_lstr(L, 1, &l);
+ luaL_buffinit(L, &b);
for (i=0; i<l; i++)
- luaL_addchar(toupper((unsigned char)(s[i])));
- closeandpush();
+ luaL_putchar(&b, toupper((unsigned char)(s[i])));
+ luaL_pushresult(&b);
+ return 1;
}
-static void str_rep (void)
-{
- long l;
- char *s = luaL_check_lstr(1, &l);
- int n = luaL_check_int(2);
- luaL_resetbuffer();
+static int str_rep (lua_State *L) {
+ size_t l;
+ luaL_Buffer b;
+ const char *s = luaL_check_lstr(L, 1, &l);
+ int n = luaL_check_int(L, 2);
+ luaL_buffinit(L, &b);
while (n-- > 0)
- addnchar(s, l);
- closeandpush();
+ luaL_addlstring(&b, s, l);
+ luaL_pushresult(&b);
+ return 1;
}
-static void str_byte (void) {
- long l;
- char *s = luaL_check_lstr(1, &l);
- long pos = posrelat(luaL_opt_long(2, 1), l);
- luaL_arg_check(0<pos && pos<=l, 2, "out of range");
- lua_pushnumber((unsigned char)s[pos-1]);
+static int str_byte (lua_State *L) {
+ size_t l;
+ const char *s = luaL_check_lstr(L, 1, &l);
+ long pos = posrelat(luaL_opt_long(L, 2, 1), l);
+ luaL_arg_check(L, 0<pos && (size_t)pos<=l, 2, "out of range");
+ lua_pushnumber(L, (unsigned char)s[pos-1]);
+ return 1;
}
-static void str_char (void) {
- int i = 0;
- luaL_resetbuffer();
- while (lua_getparam(++i) != LUA_NOOBJECT) {
- double c = luaL_check_number(i);
- luaL_arg_check((unsigned char)c == c, i, "invalid value");
- luaL_addchar((unsigned char)c);
+static int str_char (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ int i;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ for (i=1; i<=n; i++) {
+ int c = luaL_check_int(L, i);
+ luaL_arg_check(L, (unsigned char)c == c, i, "invalid value");
+ luaL_putchar(&b, (unsigned char)c);
}
- closeandpush();
+ luaL_pushresult(&b);
+ return 1;
}
@@ -117,63 +116,53 @@ static void str_char (void) {
** =======================================================
*/
-#ifndef MAX_CAPT
-#define MAX_CAPT 32 /* arbitrary limit */
+#ifndef MAX_CAPTURES
+#define MAX_CAPTURES 32 /* arbitrary limit */
#endif
struct Capture {
- char *src_end; /* end ('\0') of source string */
+ const char *src_end; /* end ('\0') of source string */
int level; /* total number of captures (finished or unfinished) */
struct {
- char *init;
- int len; /* -1 signals unfinished capture */
- } capture[MAX_CAPT];
+ const char *init;
+ long len; /* -1 signals unfinished capture */
+ } capture[MAX_CAPTURES];
};
-#define ESC '%'
-#define SPECIALS "^$*+?.([%-"
+#define ESC '%'
+#define SPECIALS "^$*+?.([%-"
-static void push_captures (struct Capture *cap) {
- int i;
- for (i=0; i<cap->level; i++) {
- int l = cap->capture[i].len;
- if (l == -1) lua_error("unfinished capture");
- lua_pushlstring(cap->capture[i].init, l);
- }
-}
-
-
-static int check_cap (int l, struct Capture *cap) {
+static int check_capture (lua_State *L, int l, struct Capture *cap) {
l -= '1';
if (!(0 <= l && l < cap->level && cap->capture[l].len != -1))
- lua_error("invalid capture index");
+ lua_error(L, "invalid capture index");
return l;
}
-static int capture_to_close (struct Capture *cap) {
+static int capture_to_close (lua_State *L, struct Capture *cap) {
int level = cap->level;
for (level--; level>=0; level--)
if (cap->capture[level].len == -1) return level;
- lua_error("invalid pattern capture");
+ lua_error(L, "invalid pattern capture");
return 0; /* to avoid warnings */
}
-char *luaI_classend (char *p) {
+const char *luaI_classend (lua_State *L, const char *p) {
switch (*p++) {
case ESC:
- if (*p == '\0')
- luaL_verror("incorrect pattern (ends with `%c')", ESC);
+ if (*p == '\0') lua_error(L, "malformed pattern (ends with `%')");
return p+1;
case '[':
if (*p == '^') p++;
- if (*p == ']') p++;
- p = strchr(p, ']');
- if (!p) lua_error("incorrect pattern (missing `]')");
+ do { /* look for a ']' */
+ if (*p == '\0') lua_error(L, "malformed pattern (missing `]')");
+ if (*(p++) == ESC && *p != '\0') p++; /* skip escapes (e.g. '%]') */
+ } while (*p != ']');
return p+1;
default:
return p;
@@ -181,7 +170,7 @@ char *luaI_classend (char *p) {
}
-static int matchclass (int c, int cl) {
+static int match_class (int c, int cl) {
int res;
switch (tolower(cl)) {
case 'a' : res = isalpha(c); break;
@@ -201,36 +190,36 @@ static int matchclass (int c, int cl) {
-static int matchbracketclass (int c, char *p, char *end) {
+static int matchbracketclass (int c, const char *p, const char *endclass) {
int sig = 1;
if (*(p+1) == '^') {
sig = 0;
p++; /* skip the '^' */
}
- while (++p < end) {
+ while (++p < endclass) {
if (*p == ESC) {
p++;
- if ((p < end) && matchclass(c, (unsigned char)*p))
+ if (match_class(c, (unsigned char)*p))
return sig;
}
- else if ((*(p+1) == '-') && (p+2 < end)) {
+ else if ((*(p+1) == '-') && (p+2 < endclass)) {
p+=2;
if ((int)(unsigned char)*(p-2) <= c && c <= (int)(unsigned char)*p)
return sig;
}
- else if ((unsigned char)*p == c) return sig;
+ else if ((int)(unsigned char)*p == c) return sig;
}
return !sig;
}
-int luaI_singlematch (int c, char *p, char *ep) {
+int luaI_singlematch (int c, const char *p, const char *ep) {
switch (*p) {
case '.': /* matches any char */
return 1;
case ESC:
- return matchclass(c, (unsigned char)*(p+1));
+ return match_class(c, (unsigned char)*(p+1));
case '[':
return matchbracketclass(c, p, ep-1);
default:
@@ -239,12 +228,14 @@ int luaI_singlematch (int c, char *p, char *ep) {
}
-static char *match (char *s, char *p, struct Capture *cap);
+static const char *match (lua_State *L, const char *s, const char *p,
+ struct Capture *cap);
-static char *matchbalance (char *s, char *p, struct Capture *cap) {
+static const char *matchbalance (lua_State *L, const char *s, const char *p,
+ struct Capture *cap) {
if (*p == 0 || *(p+1) == 0)
- lua_error("unbalanced pattern");
+ lua_error(L, "unbalanced pattern");
if (*s != *p) return NULL;
else {
int b = *p;
@@ -261,13 +252,14 @@ static char *matchbalance (char *s, char *p, struct Capture *cap) {
}
-static char *max_expand (char *s, char *p, char *ep, struct Capture *cap) {
- int i = 0; /* counts maximum expand for item */
+static const char *max_expand (lua_State *L, const char *s, const char *p,
+ const char *ep, struct Capture *cap) {
+ long i = 0; /* counts maximum expand for item */
while ((s+i)<cap->src_end && luaI_singlematch((unsigned char)*(s+i), p, ep))
i++;
- /* keeps trying to match mith the maximum repetitions */
+ /* keeps trying to match with the maximum repetitions */
while (i>=0) {
- char *res = match((s+i), ep+1, cap);
+ const char *res = match(L, (s+i), ep+1, cap);
if (res) return res;
i--; /* else didn't match; reduce 1 repetition to try again */
}
@@ -275,9 +267,10 @@ static char *max_expand (char *s, char *p, char *ep, struct Capture *cap) {
}
-static char *min_expand (char *s, char *p, char *ep, struct Capture *cap) {
+static const char *min_expand (lua_State *L, const char *s, const char *p,
+ const char *ep, struct Capture *cap) {
for (;;) {
- char *res = match(s, ep+1, cap);
+ const char *res = match(L, s, ep+1, cap);
if (res != NULL)
return res;
else if (s<cap->src_end && luaI_singlematch((unsigned char)*s, p, ep))
@@ -287,56 +280,60 @@ static char *min_expand (char *s, char *p, char *ep, struct Capture *cap) {
}
-static char *start_capt (char *s, char *p, struct Capture *cap) {
- char *res;
+static const char *start_capture (lua_State *L, const char *s, const char *p,
+ struct Capture *cap) {
+ const char *res;
int level = cap->level;
- if (level >= MAX_CAPT) lua_error("too many captures");
+ if (level >= MAX_CAPTURES) lua_error(L, "too many captures");
cap->capture[level].init = s;
cap->capture[level].len = -1;
cap->level = level+1;
- if ((res=match(s, p+1, cap)) == NULL) /* match failed? */
+ if ((res=match(L, s, p+1, cap)) == NULL) /* match failed? */
cap->level--; /* undo capture */
return res;
}
-static char *end_capt (char *s, char *p, struct Capture *cap) {
- int l = capture_to_close(cap);
- char *res;
+static const char *end_capture (lua_State *L, const char *s, const char *p,
+ struct Capture *cap) {
+ int l = capture_to_close(L, cap);
+ const char *res;
cap->capture[l].len = s - cap->capture[l].init; /* close capture */
- if ((res = match(s, p+1, cap)) == NULL) /* match failed? */
+ if ((res = match(L, s, p+1, cap)) == NULL) /* match failed? */
cap->capture[l].len = -1; /* undo capture */
return res;
}
-static char *match_capture (char *s, int level, struct Capture *cap) {
- int l = check_cap(level, cap);
- int len = cap->capture[l].len;
- if (cap->src_end-s >= len &&
+static const char *match_capture (lua_State *L, const char *s, int level,
+ struct Capture *cap) {
+ int l = check_capture(L, level, cap);
+ size_t len = cap->capture[l].len;
+ if ((size_t)(cap->src_end-s) >= len &&
memcmp(cap->capture[l].init, s, len) == 0)
return s+len;
else return NULL;
}
-static char *match (char *s, char *p, struct Capture *cap) {
+static const char *match (lua_State *L, const char *s, const char *p,
+ struct Capture *cap) {
init: /* using goto's to optimize tail recursion */
switch (*p) {
case '(': /* start capture */
- return start_capt(s, p, cap);
+ return start_capture(L, s, p, cap);
case ')': /* end capture */
- return end_capt(s, p, cap);
+ return end_capture(L, s, p, cap);
case ESC: /* may be %[0-9] or %b */
if (isdigit((unsigned char)(*(p+1)))) { /* capture? */
- s = match_capture(s, *(p+1), cap);
+ s = match_capture(L, s, *(p+1), cap);
if (s == NULL) return NULL;
- p+=2; goto init; /* else return match(p+2, s, cap) */
+ p+=2; goto init; /* else return match(L, s, p+2, cap) */
}
else if (*(p+1) == 'b') { /* balanced string? */
- s = matchbalance(s, p+2, cap);
+ s = matchbalance(L, s, p+2, cap);
if (s == NULL) return NULL;
- p+=4; goto init; /* else return match(p+4, s, cap); */
+ p+=4; goto init; /* else return match(L, s, p+4, cap); */
}
else goto dflt; /* case default */
case '\0': /* end of pattern */
@@ -346,178 +343,208 @@ static char *match (char *s, char *p, struct Capture *cap) {
return (s == cap->src_end) ? s : NULL; /* check end of string */
else goto dflt;
default: dflt: { /* it is a pattern item */
- char *ep = luaI_classend(p); /* points to what is next */
+ const char *ep = luaI_classend(L, p); /* points to what is next */
int m = s<cap->src_end && luaI_singlematch((unsigned char)*s, p, ep);
switch (*ep) {
case '?': { /* optional */
- char *res;
- if (m && ((res=match(s+1, ep+1, cap)) != NULL))
+ const char *res;
+ if (m && ((res=match(L, s+1, ep+1, cap)) != NULL))
return res;
- p=ep+1; goto init; /* else return match(s, ep+1, cap); */
+ p=ep+1; goto init; /* else return match(L, s, ep+1, cap); */
}
case '*': /* 0 or more repetitions */
- return max_expand(s, p, ep, cap);
+ return max_expand(L, s, p, ep, cap);
case '+': /* 1 or more repetitions */
- return (m ? max_expand(s+1, p, ep, cap) : NULL);
+ return (m ? max_expand(L, s+1, p, ep, cap) : NULL);
case '-': /* 0 or more repetitions (minimum) */
- return min_expand(s, p, ep, cap);
+ return min_expand(L, s, p, ep, cap);
default:
if (!m) return NULL;
- s++; p=ep; goto init; /* else return match(s+1, ep, cap); */
+ s++; p=ep; goto init; /* else return match(L, s+1, ep, cap); */
+ }
+ }
+ }
+}
+
+
+
+static const char *lmemfind (const char *s1, size_t l1,
+ const char *s2, size_t l2) {
+ if (l2 == 0) return s1; /* empty strings are everywhere */
+ else if (l2 > l1) return NULL; /* avoids a negative `l1' */
+ else {
+ const char *init; /* to search for a `*s2' inside `s1' */
+ l2--; /* 1st char will be checked by `memchr' */
+ l1 = l1-l2; /* `s2' cannot be found after that */
+ while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
+ init++; /* 1st char is already checked */
+ if (memcmp(init, s2+1, l2) == 0)
+ return init-1;
+ else { /* correct `l1' and `s1' to try again */
+ l1 -= init-s1;
+ s1 = init;
}
}
+ return NULL; /* not found */
}
}
-static void str_find (void) {
- long l;
- char *s = luaL_check_lstr(1, &l);
- char *p = luaL_check_string(2);
- long init = posrelat(luaL_opt_long(3, 1), l) - 1;
+static int push_captures (lua_State *L, struct Capture *cap) {
+ int i;
+ luaL_checkstack(L, cap->level, "too many captures");
+ for (i=0; i<cap->level; i++) {
+ int l = cap->capture[i].len;
+ if (l == -1) lua_error(L, "unfinished capture");
+ lua_pushlstring(L, cap->capture[i].init, l);
+ }
+ return cap->level; /* number of strings pushed */
+}
+
+
+static int str_find (lua_State *L) {
+ size_t l1, l2;
+ const char *s = luaL_check_lstr(L, 1, &l1);
+ const char *p = luaL_check_lstr(L, 2, &l2);
+ long init = posrelat(luaL_opt_long(L, 3, 1), l1) - 1;
struct Capture cap;
- luaL_arg_check(0 <= init && init <= l, 3, "out of range");
- if (lua_getparam(4) != LUA_NOOBJECT ||
- strpbrk(p, SPECIALS) == NULL) { /* no special characters? */
- char *s2 = strstr(s+init, p);
+ luaL_arg_check(L, 0 <= init && (size_t)init <= l1, 3, "out of range");
+ if (lua_gettop(L) > 3 || /* extra argument? */
+ strpbrk(p, SPECIALS) == NULL) { /* or no special characters? */
+ const char *s2 = lmemfind(s+init, l1-init, p, l2);
if (s2) {
- lua_pushnumber(s2-s+1);
- lua_pushnumber(s2-s+strlen(p));
- return;
+ lua_pushnumber(L, s2-s+1);
+ lua_pushnumber(L, s2-s+l2);
+ return 2;
}
}
else {
int anchor = (*p == '^') ? (p++, 1) : 0;
- char *s1=s+init;
- cap.src_end = s+l;
+ const char *s1=s+init;
+ cap.src_end = s+l1;
do {
- char *res;
+ const char *res;
cap.level = 0;
- if ((res=match(s1, p, &cap)) != NULL) {
- lua_pushnumber(s1-s+1); /* start */
- lua_pushnumber(res-s); /* end */
- push_captures(&cap);
- return;
+ if ((res=match(L, s1, p, &cap)) != NULL) {
+ lua_pushnumber(L, s1-s+1); /* start */
+ lua_pushnumber(L, res-s); /* end */
+ return push_captures(L, &cap) + 2;
}
} while (s1++<cap.src_end && !anchor);
}
- lua_pushnil(); /* if arrives here, it didn't find */
+ lua_pushnil(L); /* not found */
+ return 1;
}
-static void add_s (lua_Object newp, struct Capture *cap) {
- if (lua_isstring(newp)) {
- char *news = lua_getstring(newp);
- int l = lua_strlen(newp);
- int i;
+static void add_s (lua_State *L, luaL_Buffer *b, struct Capture *cap) {
+ if (lua_isstring(L, 3)) {
+ const char *news = lua_tostring(L, 3);
+ size_t l = lua_strlen(L, 3);
+ size_t i;
for (i=0; i<l; i++) {
if (news[i] != ESC)
- luaL_addchar(news[i]);
+ luaL_putchar(b, news[i]);
else {
i++; /* skip ESC */
if (!isdigit((unsigned char)news[i]))
- luaL_addchar(news[i]);
+ luaL_putchar(b, news[i]);
else {
- int level = check_cap(news[i], cap);
- addnchar(cap->capture[level].init, cap->capture[level].len);
+ int level = check_capture(L, news[i], cap);
+ luaL_addlstring(b, cap->capture[level].init, cap->capture[level].len);
}
}
}
}
else { /* is a function */
- lua_Object res;
- int status;
- int oldbuff;
- lua_beginblock();
- push_captures(cap);
- /* function may use buffer, so save it and create a new one */
- oldbuff = luaL_newbuffer(0);
- status = lua_callfunction(newp);
- /* restore old buffer */
- luaL_oldbuffer(oldbuff);
- if (status != 0) {
- lua_endblock();
- lua_error(NULL);
- }
- res = lua_getresult(1);
- if (lua_isstring(res))
- addnchar(lua_getstring(res), lua_strlen(res));
- lua_endblock();
+ int n;
+ lua_pushvalue(L, 3);
+ n = push_captures(L, cap);
+ lua_rawcall(L, n, 1);
+ if (lua_isstring(L, -1))
+ luaL_addvalue(b); /* add return to accumulated result */
+ else
+ lua_pop(L, 1); /* function result is not a string: pop it */
}
}
-static void str_gsub (void) {
- long srcl;
- char *src = luaL_check_lstr(1, &srcl);
- char *p = luaL_check_string(2);
- lua_Object newp = lua_getparam(3);
- int max_s = luaL_opt_int(4, srcl+1);
+static int str_gsub (lua_State *L) {
+ size_t srcl;
+ const char *src = luaL_check_lstr(L, 1, &srcl);
+ const char *p = luaL_check_string(L, 2);
+ int max_s = luaL_opt_int(L, 4, srcl+1);
int anchor = (*p == '^') ? (p++, 1) : 0;
int n = 0;
struct Capture cap;
- luaL_arg_check(lua_isstring(newp) || lua_isfunction(newp), 3,
- "string or function expected");
- luaL_resetbuffer();
+ luaL_Buffer b;
+ luaL_arg_check(L,
+ lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)),
+ 3, "string or function expected");
+ luaL_buffinit(L, &b);
cap.src_end = src+srcl;
while (n < max_s) {
- char *e;
+ const char *e;
cap.level = 0;
- e = match(src, p, &cap);
+ e = match(L, src, p, &cap);
if (e) {
n++;
- add_s(newp, &cap);
+ add_s(L, &b, &cap);
}
if (e && e>src) /* non empty match? */
src = e; /* skip it */
else if (src < cap.src_end)
- luaL_addchar(*src++);
+ luaL_putchar(&b, *src++);
else break;
if (anchor) break;
}
- addnchar(src, cap.src_end-src);
- closeandpush();
- lua_pushnumber(n); /* number of substitutions */
+ luaL_addlstring(&b, src, cap.src_end-src);
+ luaL_pushresult(&b);
+ lua_pushnumber(L, n); /* number of substitutions */
+ return 2;
}
/* }====================================================== */
-static void luaI_addquoted (int arg) {
- long l;
- char *s = luaL_check_lstr(arg, &l);
- luaL_addchar('"');
+static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) {
+ size_t l;
+ const char *s = luaL_check_lstr(L, arg, &l);
+ luaL_putchar(b, '"');
while (l--) {
switch (*s) {
case '"': case '\\': case '\n':
- luaL_addchar('\\');
- luaL_addchar(*s);
+ luaL_putchar(b, '\\');
+ luaL_putchar(b, *s);
break;
- case '\0': addnchar("\\000", 4); break;
- default: luaL_addchar(*s);
+ case '\0': luaL_addlstring(b, "\\000", 4); break;
+ default: luaL_putchar(b, *s);
}
s++;
}
- luaL_addchar('"');
+ luaL_putchar(b, '"');
}
+/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
+#define MAX_ITEM 512
/* maximum size of each format specification (such as '%-099.99d') */
-#define MAX_FORMAT 20 /* arbitrary limit */
+#define MAX_FORMAT 20
-static void str_format (void) {
+static int str_format (lua_State *L) {
int arg = 1;
- char *strfrmt = luaL_check_string(arg);
- luaL_resetbuffer();
+ const char *strfrmt = luaL_check_string(L, arg);
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
while (*strfrmt) {
if (*strfrmt != '%')
- luaL_addchar(*strfrmt++);
+ luaL_putchar(&b, *strfrmt++);
else if (*++strfrmt == '%')
- luaL_addchar(*strfrmt++); /* %% */
+ luaL_putchar(&b, *strfrmt++); /* %% */
else { /* format item */
struct Capture cap;
char form[MAX_FORMAT]; /* to store the format ('%...') */
- char *buff; /* to store the formatted item */
- char *initf = strfrmt;
+ char buff[MAX_ITEM]; /* to store the formatted item */
+ const char *initf = strfrmt;
form[0] = '%';
if (isdigit((unsigned char)*initf) && *(initf+1) == '$') {
arg = *initf - '0';
@@ -526,33 +553,33 @@ static void str_format (void) {
arg++;
cap.src_end = strfrmt+strlen(strfrmt)+1;
cap.level = 0;
- strfrmt = match(initf, "[-+ #0]*(%d*)%.?(%d*)", &cap);
+ strfrmt = match(L, initf, "[-+ #0]*(%d*)%.?(%d*)", &cap);
if (cap.capture[0].len > 2 || cap.capture[1].len > 2 || /* < 100? */
strfrmt-initf > MAX_FORMAT-2)
- lua_error("invalid format (width or precision too long)");
+ lua_error(L, "invalid format (width or precision too long)");
strncpy(form+1, initf, strfrmt-initf+1); /* +1 to include conversion */
form[strfrmt-initf+2] = 0;
- buff = luaL_openspace(512); /* 512 > size of format('%99.99f', -1e308) */
switch (*strfrmt++) {
case 'c': case 'd': case 'i':
- sprintf(buff, form, luaL_check_int(arg));
+ sprintf(buff, form, luaL_check_int(L, arg));
break;
case 'o': case 'u': case 'x': case 'X':
- sprintf(buff, form, (unsigned int)luaL_check_number(arg));
+ sprintf(buff, form, (unsigned int)luaL_check_number(L, arg));
break;
case 'e': case 'E': case 'f': case 'g': case 'G':
- sprintf(buff, form, luaL_check_number(arg));
+ sprintf(buff, form, luaL_check_number(L, arg));
break;
case 'q':
- luaI_addquoted(arg);
+ luaI_addquoted(L, &b, arg);
continue; /* skip the "addsize" at the end */
case 's': {
- long l;
- char *s = luaL_check_lstr(arg, &l);
+ size_t l;
+ const char *s = luaL_check_lstr(L, arg, &l);
if (cap.capture[1].len == 0 && l >= 100) {
- /* no precision and string is too big to be formatted;
+ /* no precision and string is too long to be formatted;
keep original string */
- addnchar(s, l);
+ lua_pushvalue(L, arg);
+ luaL_addvalue(&b);
continue; /* skip the "addsize" at the end */
}
else {
@@ -561,16 +588,17 @@ static void str_format (void) {
}
}
default: /* also treat cases 'pnLlh' */
- lua_error("invalid option in `format'");
+ lua_error(L, "invalid option in `format'");
}
- luaL_addsize(strlen(buff));
+ luaL_addlstring(&b, buff, strlen(buff));
}
}
- closeandpush(); /* push the result */
+ luaL_pushresult(&b);
+ return 1;
}
-static struct luaL_reg strlib[] = {
+static const struct luaL_reg strlib[] = {
{"strlen", str_len},
{"strsub", str_sub},
{"strlower", str_lower},
@@ -588,7 +616,6 @@ static struct luaL_reg strlib[] = {
/*
** Open string library
*/
-void strlib_open (void)
-{
- luaL_openlib(strlib, (sizeof(strlib)/sizeof(strlib[0])));
+LUALIB_API void lua_strlibopen (lua_State *L) {
+ luaL_openl(L, strlib);
}
diff --git a/src/llex.c b/src/llex.c
index 2d607d99..4f511ab9 100644
--- a/src/llex.c
+++ b/src/llex.c
@@ -1,71 +1,85 @@
/*
-** $Id: llex.c,v 1.36 1999/06/17 17:04:03 roberto Exp $
+** $Id: llex.c,v 1.72 2000/10/20 16:39:03 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
#include <ctype.h>
+#include <stdio.h>
#include <string.h>
-#include "lauxlib.h"
+#include "lua.h"
+
#include "llex.h"
#include "lmem.h"
#include "lobject.h"
#include "lparser.h"
#include "lstate.h"
#include "lstring.h"
+#include "ltable.h"
#include "luadebug.h"
#include "lzio.h"
-#define next(LS) (LS->current = zgetc(LS->lex_z))
-
+#define next(LS) (LS->current = zgetc(LS->z))
-#define save(c) luaL_addchar(c)
-#define save_and_next(LS) (save(LS->current), next(LS))
-char *reserved [] = {"and", "do", "else", "elseif", "end", "function",
- "if", "local", "nil", "not", "or", "repeat", "return", "then",
- "until", "while"};
+/* ORDER RESERVED */
+static const char *const token2string [] = {
+ "and", "break", "do", "else", "elseif", "end", "for",
+ "function", "if", "local", "nil", "not", "or", "repeat", "return", "then",
+ "until", "while", "", "..", "...", "==", ">=", "<=", "~=", "", "", "<eof>"};
-void luaX_init (void) {
+void luaX_init (lua_State *L) {
int i;
- for (i=0; i<(sizeof(reserved)/sizeof(reserved[0])); i++) {
- TaggedString *ts = luaS_new(reserved[i]);
- ts->head.marked = FIRST_RESERVED+i; /* reserved word (always > 255) */
+ for (i=0; i<NUM_RESERVED; i++) {
+ TString *ts = luaS_new(L, token2string[i]);
+ ts->marked = (unsigned char)(RESERVEDMARK+i); /* reserved word */
}
}
#define MAXSRC 80
-void luaX_syntaxerror (LexState *ls, char *s, char *token) {
+
+void luaX_checklimit (LexState *ls, int val, int limit, const char *msg) {
+ if (val > limit) {
+ char buff[100];
+ sprintf(buff, "too many %.50s (limit=%d)", msg, limit);
+ luaX_error(ls, buff, ls->t.token);
+ }
+}
+
+
+void luaX_syntaxerror (LexState *ls, const char *s, const char *token) {
char buff[MAXSRC];
- luaL_chunkid(buff, zname(ls->lex_z), sizeof(buff));
- if (token[0] == '\0')
- token = "<eof>";
- luaL_verror("%.100s;\n last token read: `%.50s' at line %d in %.80s",
+ luaO_chunkid(buff, ls->source->str, sizeof(buff));
+ luaO_verror(ls->L, "%.99s;\n last token read: `%.30s' at line %d in %.80s",
s, token, ls->linenumber, buff);
}
-void luaX_error (LexState *ls, char *s) {
- save('\0');
- luaX_syntaxerror(ls, s, luaL_buffer());
+void luaX_error (LexState *ls, const char *s, int token) {
+ char buff[TOKEN_LEN];
+ luaX_token2str(token, buff);
+ if (buff[0] == '\0')
+ luaX_syntaxerror(ls, s, ls->L->Mbuffer);
+ else
+ luaX_syntaxerror(ls, s, buff);
}
void luaX_token2str (int token, char *s) {
- if (token < 255) {
+ if (token < 256) {
s[0] = (char)token;
s[1] = '\0';
}
else
- strcpy(s, reserved[token-FIRST_RESERVED]);
+ strcpy(s, token2string[token-FIRST_RESERVED]);
}
@@ -76,200 +90,199 @@ static void luaX_invalidchar (LexState *ls, int c) {
}
-static void firstline (LexState *LS)
-{
- int c = zgetc(LS->lex_z);
- if (c == '#')
- while ((c=zgetc(LS->lex_z)) != '\n' && c != EOZ) /* skip first line */;
- zungetc(LS->lex_z);
+static void inclinenumber (LexState *LS) {
+ next(LS); /* skip '\n' */
+ ++LS->linenumber;
+ luaX_checklimit(LS, LS->linenumber, MAX_INT, "lines in a chunk");
}
-void luaX_setinput (LexState *LS, ZIO *z)
-{
- LS->current = '\n';
- LS->linenumber = 0;
- LS->iflevel = 0;
- LS->ifstate[0].skip = 0;
- LS->ifstate[0].elsepart = 1; /* to avoid a free $else */
- LS->lex_z = z;
+void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source) {
+ LS->L = L;
+ LS->lookahead.token = TK_EOS; /* no look-ahead token */
+ LS->z = z;
LS->fs = NULL;
- firstline(LS);
- luaL_resetbuffer();
+ LS->linenumber = 1;
+ LS->lastline = 1;
+ LS->source = source;
+ next(LS); /* read first char */
+ if (LS->current == '#') {
+ do { /* skip first line */
+ next(LS);
+ } while (LS->current != '\n' && LS->current != EOZ);
+ }
}
/*
** =======================================================
-** PRAGMAS
+** LEXICAL ANALYZER
** =======================================================
*/
-#ifndef PRAGMASIZE
-#define PRAGMASIZE 80 /* arbitrary limit */
-#endif
-static void skipspace (LexState *LS) {
- while (LS->current == ' ' || LS->current == '\t' || LS->current == '\r')
- next(LS);
-}
+/* use Mbuffer to store names, literal strings and numbers */
+#define EXTRABUFF 128
+#define checkbuffer(L, n, len) if ((len)+(n) > L->Mbuffsize) \
+ luaO_openspace(L, (len)+(n)+EXTRABUFF)
-static int checkcond (LexState *LS, char *buff) {
- static char *opts[] = {"nil", "1", NULL};
- int i = luaL_findstring(buff, opts);
- if (i >= 0) return i;
- else if (isalpha((unsigned char)buff[0]) || buff[0] == '_')
- return luaS_globaldefined(buff);
- else {
- luaX_syntaxerror(LS, "invalid $if condition", buff);
- return 0; /* to avoid warnings */
- }
-}
+#define save(L, c, l) (L->Mbuffer[l++] = (char)c)
+#define save_and_next(L, LS, l) (save(L, LS->current, l), next(LS))
-static void readname (LexState *LS, char *buff) {
- int i = 0;
- skipspace(LS);
- while (isalnum(LS->current) || LS->current == '_') {
- if (i >= PRAGMASIZE) {
- buff[PRAGMASIZE] = 0;
- luaX_syntaxerror(LS, "pragma too long", buff);
- }
- buff[i++] = (char)LS->current;
- next(LS);
- }
- buff[i] = 0;
+static const char *readname (LexState *LS) {
+ lua_State *L = LS->L;
+ size_t l = 0;
+ checkbuffer(L, 10, l);
+ do {
+ checkbuffer(L, 10, l);
+ save_and_next(L, LS, l);
+ } while (isalnum(LS->current) || LS->current == '_');
+ save(L, '\0', l);
+ return L->Mbuffer;
}
-static void inclinenumber (LexState *LS);
-
-
-static void ifskip (LexState *LS) {
- while (LS->ifstate[LS->iflevel].skip) {
- if (LS->current == '\n')
- inclinenumber(LS);
- else if (LS->current == EOZ)
- luaX_error(LS, "input ends inside a $if");
- else next(LS);
+/* LUA_NUMBER */
+static void read_number (LexState *LS, int comma, SemInfo *seminfo) {
+ lua_State *L = LS->L;
+ size_t l = 0;
+ checkbuffer(L, 10, l);
+ if (comma) save(L, '.', l);
+ while (isdigit(LS->current)) {
+ checkbuffer(L, 10, l);
+ save_and_next(L, LS, l);
}
-}
-
-
-static void inclinenumber (LexState *LS) {
- static char *pragmas [] =
- {"debug", "nodebug", "endinput", "end", "ifnot", "if", "else", NULL};
- next(LS); /* skip '\n' */
- ++LS->linenumber;
- if (LS->current == '$') { /* is a pragma? */
- char buff[PRAGMASIZE+1];
- int ifnot = 0;
- int skip = LS->ifstate[LS->iflevel].skip;
- next(LS); /* skip $ */
- readname(LS, buff);
- switch (luaL_findstring(buff, pragmas)) {
- case 0: /* debug */
- if (!skip) L->debug = 1;
- break;
- case 1: /* nodebug */
- if (!skip) L->debug = 0;
- break;
- case 2: /* endinput */
- if (!skip) {
- LS->current = EOZ;
- LS->iflevel = 0; /* to allow $endinput inside a $if */
- }
- break;
- case 3: /* end */
- if (LS->iflevel-- == 0)
- luaX_syntaxerror(LS, "unmatched $end", "$end");
- break;
- case 4: /* ifnot */
- ifnot = 1;
- /* go through */
- case 5: /* if */
- if (LS->iflevel == MAX_IFS-1)
- luaX_syntaxerror(LS, "too many nested $ifs", "$if");
- readname(LS, buff);
- LS->iflevel++;
- LS->ifstate[LS->iflevel].elsepart = 0;
- LS->ifstate[LS->iflevel].condition = checkcond(LS, buff) ? !ifnot : ifnot;
- LS->ifstate[LS->iflevel].skip = skip || !LS->ifstate[LS->iflevel].condition;
- break;
- case 6: /* else */
- if (LS->ifstate[LS->iflevel].elsepart)
- luaX_syntaxerror(LS, "unmatched $else", "$else");
- LS->ifstate[LS->iflevel].elsepart = 1;
- LS->ifstate[LS->iflevel].skip = LS->ifstate[LS->iflevel-1].skip ||
- LS->ifstate[LS->iflevel].condition;
- break;
- default:
- luaX_syntaxerror(LS, "unknown pragma", buff);
+ if (LS->current == '.') {
+ save_and_next(L, LS, l);
+ if (LS->current == '.') {
+ save_and_next(L, LS, l);
+ save(L, '\0', l);
+ luaX_error(LS, "ambiguous syntax"
+ " (decimal point x string concatenation)", TK_NUMBER);
}
- skipspace(LS);
- if (LS->current == '\n') /* pragma must end with a '\n' ... */
- inclinenumber(LS);
- else if (LS->current != EOZ) /* or eof */
- luaX_syntaxerror(LS, "invalid pragma format", buff);
- ifskip(LS);
}
+ while (isdigit(LS->current)) {
+ checkbuffer(L, 10, l);
+ save_and_next(L, LS, l);
+ }
+ if (LS->current == 'e' || LS->current == 'E') {
+ save_and_next(L, LS, l); /* read 'E' */
+ if (LS->current == '+' || LS->current == '-')
+ save_and_next(L, LS, l); /* optional exponent sign */
+ while (isdigit(LS->current)) {
+ checkbuffer(L, 10, l);
+ save_and_next(L, LS, l);
+ }
+ }
+ save(L, '\0', l);
+ if (!luaO_str2d(L->Mbuffer, &seminfo->r))
+ luaX_error(LS, "malformed number", TK_NUMBER);
}
-
-/*
-** =======================================================
-** LEXICAL ANALIZER
-** =======================================================
-*/
-
-
-
-static int read_long_string (LexState *LS) {
+static void read_long_string (LexState *LS, SemInfo *seminfo) {
+ lua_State *L = LS->L;
int cont = 0;
+ size_t l = 0;
+ checkbuffer(L, 10, l);
+ save(L, '[', l); /* save first '[' */
+ save_and_next(L, LS, l); /* pass the second '[' */
for (;;) {
+ checkbuffer(L, 10, l);
switch (LS->current) {
case EOZ:
- luaX_error(LS, "unfinished long string");
- return EOS; /* to avoid warnings */
+ save(L, '\0', l);
+ luaX_error(LS, "unfinished long string", TK_STRING);
+ break; /* to avoid warnings */
case '[':
- save_and_next(LS);
+ save_and_next(L, LS, l);
if (LS->current == '[') {
cont++;
- save_and_next(LS);
+ save_and_next(L, LS, l);
}
continue;
case ']':
- save_and_next(LS);
+ save_and_next(L, LS, l);
if (LS->current == ']') {
if (cont == 0) goto endloop;
cont--;
- save_and_next(LS);
+ save_and_next(L, LS, l);
}
continue;
case '\n':
- save('\n');
+ save(L, '\n', l);
inclinenumber(LS);
continue;
default:
- save_and_next(LS);
+ save_and_next(L, LS, l);
}
} endloop:
- save_and_next(LS); /* skip the second ']' */
- LS->seminfo.ts = luaS_newlstr(L->Mbuffer+(L->Mbuffbase+2),
- L->Mbuffnext-L->Mbuffbase-4);
- return STRING;
+ save_and_next(L, LS, l); /* skip the second ']' */
+ save(L, '\0', l);
+ seminfo->ts = luaS_newlstr(L, L->Mbuffer+2, l-5);
}
-int luaX_lex (LexState *LS) {
- luaL_resetbuffer();
+static void read_string (LexState *LS, int del, SemInfo *seminfo) {
+ lua_State *L = LS->L;
+ size_t l = 0;
+ checkbuffer(L, 10, l);
+ save_and_next(L, LS, l);
+ while (LS->current != del) {
+ checkbuffer(L, 10, l);
+ switch (LS->current) {
+ case EOZ: case '\n':
+ save(L, '\0', l);
+ luaX_error(LS, "unfinished string", TK_STRING);
+ break; /* to avoid warnings */
+ case '\\':
+ next(LS); /* do not save the '\' */
+ switch (LS->current) {
+ case 'a': save(L, '\a', l); next(LS); break;
+ case 'b': save(L, '\b', l); next(LS); break;
+ case 'f': save(L, '\f', l); next(LS); break;
+ case 'n': save(L, '\n', l); next(LS); break;
+ case 'r': save(L, '\r', l); next(LS); break;
+ case 't': save(L, '\t', l); next(LS); break;
+ case 'v': save(L, '\v', l); next(LS); break;
+ case '\n': save(L, '\n', l); inclinenumber(LS); break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9': {
+ int c = 0;
+ int i = 0;
+ do {
+ c = 10*c + (LS->current-'0');
+ next(LS);
+ } while (++i<3 && isdigit(LS->current));
+ if (c != (unsigned char)c) {
+ save(L, '\0', l);
+ luaX_error(LS, "escape sequence too large", TK_STRING);
+ }
+ save(L, c, l);
+ break;
+ }
+ default: /* handles \\, \", \', and \? */
+ save_and_next(L, LS, l);
+ }
+ break;
+ default:
+ save_and_next(L, LS, l);
+ }
+ }
+ save_and_next(L, LS, l); /* skip delimiter */
+ save(L, '\0', l);
+ seminfo->ts = luaS_newlstr(L, L->Mbuffer+1, l-3);
+}
+
+
+int luaX_lex (LexState *LS, SemInfo *seminfo) {
for (;;) {
switch (LS->current) {
- case ' ': case '\t': case '\r': /* CR: to avoid problems with DOS */
+ case ' ': case '\t': case '\r': /* `\r' to avoid problems with DOS */
next(LS);
continue;
@@ -277,159 +290,89 @@ int luaX_lex (LexState *LS) {
inclinenumber(LS);
continue;
+ case '$':
+ luaX_error(LS, "unexpected `$' (pragmas are no longer supported)", '$');
+ break;
+
case '-':
- save_and_next(LS);
+ next(LS);
if (LS->current != '-') return '-';
do { next(LS); } while (LS->current != '\n' && LS->current != EOZ);
- luaL_resetbuffer();
continue;
case '[':
- save_and_next(LS);
+ next(LS);
if (LS->current != '[') return '[';
else {
- save_and_next(LS); /* pass the second '[' */
- return read_long_string(LS);
+ read_long_string(LS, seminfo);
+ return TK_STRING;
}
case '=':
- save_and_next(LS);
+ next(LS);
if (LS->current != '=') return '=';
- else { save_and_next(LS); return EQ; }
+ else { next(LS); return TK_EQ; }
case '<':
- save_and_next(LS);
+ next(LS);
if (LS->current != '=') return '<';
- else { save_and_next(LS); return LE; }
+ else { next(LS); return TK_LE; }
case '>':
- save_and_next(LS);
+ next(LS);
if (LS->current != '=') return '>';
- else { save_and_next(LS); return GE; }
+ else { next(LS); return TK_GE; }
case '~':
- save_and_next(LS);
+ next(LS);
if (LS->current != '=') return '~';
- else { save_and_next(LS); return NE; }
+ else { next(LS); return TK_NE; }
case '"':
- case '\'': {
- int del = LS->current;
- save_and_next(LS);
- while (LS->current != del) {
- switch (LS->current) {
- case EOZ:
- case '\n':
- luaX_error(LS, "unfinished string");
- return EOS; /* to avoid warnings */
- case '\\':
- next(LS); /* do not save the '\' */
- switch (LS->current) {
- case 'a': save('\a'); next(LS); break;
- case 'b': save('\b'); next(LS); break;
- case 'f': save('\f'); next(LS); break;
- case 'n': save('\n'); next(LS); break;
- case 'r': save('\r'); next(LS); break;
- case 't': save('\t'); next(LS); break;
- case 'v': save('\v'); next(LS); break;
- case '\n': save('\n'); inclinenumber(LS); break;
- default : {
- if (isdigit(LS->current)) {
- int c = 0;
- int i = 0;
- do {
- c = 10*c + (LS->current-'0');
- next(LS);
- } while (++i<3 && isdigit(LS->current));
- if (c != (unsigned char)c)
- luaX_error(LS, "escape sequence too large");
- save(c);
- }
- else { /* handles \, ", ', and ? */
- save(LS->current);
- next(LS);
- }
- break;
- }
- }
- break;
- default:
- save_and_next(LS);
- }
- }
- save_and_next(LS); /* skip delimiter */
- LS->seminfo.ts = luaS_newlstr(L->Mbuffer+(L->Mbuffbase+1),
- L->Mbuffnext-L->Mbuffbase-2);
- return STRING;
- }
+ case '\'':
+ read_string(LS, LS->current, seminfo);
+ return TK_STRING;
case '.':
- save_and_next(LS);
- if (LS->current == '.')
- {
- save_and_next(LS);
- if (LS->current == '.')
- {
- save_and_next(LS);
- return DOTS; /* ... */
+ next(LS);
+ if (LS->current == '.') {
+ next(LS);
+ if (LS->current == '.') {
+ next(LS);
+ return TK_DOTS; /* ... */
}
- else return CONC; /* .. */
+ else return TK_CONCAT; /* .. */
}
else if (!isdigit(LS->current)) return '.';
- goto fraction; /* LS->current is a digit: goes through to number */
+ else {
+ read_number(LS, 1, seminfo);
+ return TK_NUMBER;
+ }
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- do {
- save_and_next(LS);
- } while (isdigit(LS->current));
- if (LS->current == '.') {
- save_and_next(LS);
- if (LS->current == '.') {
- save('.');
- luaX_error(LS,
- "ambiguous syntax (decimal point x string concatenation)");
- }
- }
- fraction:
- while (isdigit(LS->current))
- save_and_next(LS);
- if (toupper(LS->current) == 'E') {
- save_and_next(LS); /* read 'E' */
- save_and_next(LS); /* read '+', '-' or first digit */
- while (isdigit(LS->current))
- save_and_next(LS);
- }
- save('\0');
- LS->seminfo.r = luaO_str2d(L->Mbuffer+L->Mbuffbase);
- if (LS->seminfo.r < 0)
- luaX_error(LS, "invalid numeric format");
- return NUMBER;
+ read_number(LS, 0, seminfo);
+ return TK_NUMBER;
case EOZ:
- if (LS->iflevel > 0)
- luaX_error(LS, "input ends inside a $if");
- return EOS;
+ return TK_EOS;
+
+ case '_': goto tname;
default:
- if (LS->current != '_' && !isalpha(LS->current)) {
+ if (!isalpha(LS->current)) {
int c = LS->current;
if (iscntrl(c))
luaX_invalidchar(LS, c);
- save_and_next(LS);
+ next(LS);
return c;
}
- else { /* identifier or reserved word */
- TaggedString *ts;
- do {
- save_and_next(LS);
- } while (isalnum(LS->current) || LS->current == '_');
- save('\0');
- ts = luaS_new(L->Mbuffer+L->Mbuffbase);
- if (ts->head.marked >= FIRST_RESERVED)
- return ts->head.marked; /* reserved word */
- LS->seminfo.ts = ts;
- return NAME;
+ tname: { /* identifier or reserved word */
+ TString *ts = luaS_new(LS->L, readname(LS));
+ if (ts->marked >= RESERVEDMARK) /* reserved word? */
+ return ts->marked-RESERVEDMARK+FIRST_RESERVED;
+ seminfo->ts = ts;
+ return TK_NAME;
}
}
}
diff --git a/src/llex.h b/src/llex.h
index 7c1a4be1..3b379960 100644
--- a/src/llex.h
+++ b/src/llex.h
@@ -1,5 +1,5 @@
/*
-** $Id: llex.h,v 1.12 1999/06/17 17:04:03 roberto Exp $
+** $Id: llex.h,v 1.31 2000/09/27 17:41:58 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -11,53 +11,61 @@
#include "lzio.h"
-#define FIRST_RESERVED 260
+#define FIRST_RESERVED 257
-/* maximum length of a reserved word (+1 for terminal 0) */
+/* maximum length of a reserved word (+1 for final 0) */
#define TOKEN_LEN 15
+
+/*
+* WARNING: if you change the order of this enumeration,
+* grep "ORDER RESERVED"
+*/
enum RESERVED {
/* terminal symbols denoted by reserved words */
- AND = FIRST_RESERVED,
- DO, ELSE, ELSEIF, END, FUNCTION, IF, LOCAL, NIL, NOT, OR,
- REPEAT, RETURN, THEN, UNTIL, WHILE,
+ TK_AND = FIRST_RESERVED, TK_BREAK,
+ TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FOR, TK_FUNCTION, TK_IF, TK_LOCAL,
+ TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_UNTIL, TK_WHILE,
/* other terminal symbols */
- NAME, CONC, DOTS, EQ, GE, LE, NE, NUMBER, STRING, EOS};
+ TK_NAME, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER,
+ TK_STRING, TK_EOS
+};
+/* number of reserved words */
+#define NUM_RESERVED ((int)(TK_WHILE-FIRST_RESERVED+1))
-#ifndef MAX_IFS
-#define MAX_IFS 5 /* arbitrary limit */
-#endif
-/* "ifstate" keeps the state of each nested $if the lexical is dealing with. */
+typedef union {
+ Number r;
+ TString *ts;
+} SemInfo; /* semantics information */
-struct ifState {
- int elsepart; /* true if it's in the $else part */
- int condition; /* true if $if condition is true */
- int skip; /* true if part must be skipped */
-};
+
+typedef struct Token {
+ int token;
+ SemInfo seminfo;
+} Token;
typedef struct LexState {
- int current; /* look ahead character */
- int token; /* look ahead token */
- struct FuncState *fs; /* 'FuncState' is private for the parser */
- union {
- real r;
- TaggedString *ts;
- } seminfo; /* semantics information */
- struct zio *lex_z; /* input stream */
+ int current; /* current character */
+ Token t; /* current token */
+ Token lookahead; /* look ahead token */
+ struct FuncState *fs; /* `FuncState' is private to the parser */
+ struct lua_State *L;
+ struct zio *z; /* input stream */
int linenumber; /* input line counter */
- int iflevel; /* level of nested $if's (for lexical analysis) */
- struct ifState ifstate[MAX_IFS];
+ int lastline; /* line of last token `consumed' */
+ TString *source; /* current source name */
} LexState;
-void luaX_init (void);
-void luaX_setinput (LexState *LS, ZIO *z);
-int luaX_lex (LexState *LS);
-void luaX_syntaxerror (LexState *ls, char *s, char *token);
-void luaX_error (LexState *ls, char *s);
+void luaX_init (lua_State *L);
+void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source);
+int luaX_lex (LexState *LS, SemInfo *seminfo);
+void luaX_checklimit (LexState *ls, int val, int limit, const char *msg);
+void luaX_syntaxerror (LexState *ls, const char *s, const char *token);
+void luaX_error (LexState *ls, const char *s, int token);
void luaX_token2str (int token, char *s);
diff --git a/src/llimits.h b/src/llimits.h
new file mode 100644
index 00000000..b3f5de47
--- /dev/null
+++ b/src/llimits.h
@@ -0,0 +1,204 @@
+/*
+** $Id: llimits.h,v 1.19 2000/10/26 12:47:05 roberto Exp $
+** Limits, basic types, and some other "installation-dependent" definitions
+** See Copyright Notice in lua.h
+*/
+
+#ifndef llimits_h
+#define llimits_h
+
+
+#include <limits.h>
+#include <stddef.h>
+
+
+
+/*
+** try to find number of bits in an integer
+*/
+#ifndef BITS_INT
+/* avoid overflows in comparison */
+#if INT_MAX-20 < 32760
+#define BITS_INT 16
+#else
+#if INT_MAX > 2147483640L
+/* machine has at least 32 bits */
+#define BITS_INT 32
+#else
+#error "you must define BITS_INT with number of bits in an integer"
+#endif
+#endif
+#endif
+
+
+/*
+** Define the type `number' of Lua
+** GREP LUA_NUMBER to change that
+*/
+#ifndef LUA_NUM_TYPE
+#define LUA_NUM_TYPE double
+#endif
+
+typedef LUA_NUM_TYPE Number;
+
+/* function to convert a Number to a string */
+#define NUMBER_FMT "%.16g" /* LUA_NUMBER */
+#define lua_number2str(s,n) sprintf((s), NUMBER_FMT, (n))
+
+/* function to convert a string to a Number */
+#define lua_str2number(s,p) strtod((s), (p))
+
+
+
+typedef unsigned long lint32; /* unsigned int with at least 32 bits */
+
+
+#define MAX_SIZET ((size_t)(~(size_t)0)-2)
+
+
+#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */
+
+/*
+** conversion of pointer to int (for hashing only)
+** (the shift removes bits that are usually 0 because of alignment)
+*/
+#define IntPoint(p) (((unsigned long)(p)) >> 3)
+
+
+
+#define MINPOWER2 4 /* minimum size for "growing" vectors */
+
+
+
+#ifndef DEFAULT_STACK_SIZE
+#define DEFAULT_STACK_SIZE 1024
+#endif
+
+
+
+/* type to ensure maximum alignment */
+union L_Umaxalign { double d; char *s; long l; };
+
+
+
+/*
+** type for virtual-machine instructions
+** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
+** For a very small machine, you may change that to 2 bytes (and adjust
+** the following limits accordingly)
+*/
+typedef unsigned long Instruction;
+
+
+/*
+** size and position of opcode arguments.
+** For an instruction with 2 bytes, size is 16, and size_b can be 5
+** (accordingly, size_u will be 10, and size_a will be 5)
+*/
+#define SIZE_INSTRUCTION 32
+#define SIZE_B 9
+
+#define SIZE_OP 6
+#define SIZE_U (SIZE_INSTRUCTION-SIZE_OP)
+#define POS_U SIZE_OP
+#define POS_B SIZE_OP
+#define SIZE_A (SIZE_INSTRUCTION-(SIZE_OP+SIZE_B))
+#define POS_A (SIZE_OP+SIZE_B)
+
+
+/*
+** limits for opcode arguments.
+** we use (signed) int to manipulate most arguments,
+** so they must fit in BITS_INT-1 bits (-1 for sign)
+*/
+#if SIZE_U < BITS_INT-1
+#define MAXARG_U ((1<<SIZE_U)-1)
+#define MAXARG_S (MAXARG_U>>1) /* `S' is signed */
+#else
+#define MAXARG_U MAX_INT
+#define MAXARG_S MAX_INT
+#endif
+
+#if SIZE_A < BITS_INT-1
+#define MAXARG_A ((1<<SIZE_A)-1)
+#else
+#define MAXARG_A MAX_INT
+#endif
+
+#if SIZE_B < BITS_INT-1
+#define MAXARG_B ((1<<SIZE_B)-1)
+#else
+#define MAXARG_B MAX_INT
+#endif
+
+
+/* maximum stack size in a function */
+#ifndef MAXSTACK
+#define MAXSTACK 250
+#endif
+
+#if MAXSTACK > MAXARG_B
+#undef MAXSTACK
+#define MAXSTACK MAXARG_B
+#endif
+
+
+/* maximum number of local variables */
+#ifndef MAXLOCALS
+#define MAXLOCALS 200 /* arbitrary limit (<MAXSTACK) */
+#endif
+#if MAXLOCALS>=MAXSTACK
+#undef MAXLOCALS
+#define MAXLOCALS (MAXSTACK-1)
+#endif
+
+
+/* maximum number of upvalues */
+#ifndef MAXUPVALUES
+#define MAXUPVALUES 32 /* arbitrary limit (<=MAXARG_B) */
+#endif
+#if MAXUPVALUES>MAXARG_B
+#undef MAXUPVALUES
+#define MAXUPVALUES MAXARG_B
+#endif
+
+
+/* maximum number of variables in the left side of an assignment */
+#ifndef MAXVARSLH
+#define MAXVARSLH 100 /* arbitrary limit (<MULT_RET) */
+#endif
+#if MAXVARSLH>=MULT_RET
+#undef MAXVARSLH
+#define MAXVARSLH (MULT_RET-1)
+#endif
+
+
+/* maximum number of parameters in a function */
+#ifndef MAXPARAMS
+#define MAXPARAMS 100 /* arbitrary limit (<MAXLOCALS) */
+#endif
+#if MAXPARAMS>=MAXLOCALS
+#undef MAXPARAMS
+#define MAXPARAMS (MAXLOCALS-1)
+#endif
+
+
+/* number of list items to accumulate before a SETLIST instruction */
+#define LFIELDS_PER_FLUSH 64
+#if LFIELDS_PER_FLUSH>(MAXSTACK/4)
+#undef LFIELDS_PER_FLUSH
+#define LFIELDS_PER_FLUSH (MAXSTACK/4)
+#endif
+
+/* number of record items to accumulate before a SETMAP instruction */
+/* (each item counts 2 elements on the stack: an index and a value) */
+#define RFIELDS_PER_FLUSH (LFIELDS_PER_FLUSH/2)
+
+
+/* maximum lookback to find a real constant (for code generation) */
+#ifndef LOOKBACKNUMS
+#define LOOKBACKNUMS 20 /* arbitrary constant */
+#endif
+
+
+#endif
diff --git a/src/lmem.c b/src/lmem.c
index 5f840b00..03a804c9 100644
--- a/src/lmem.c
+++ b/src/lmem.c
@@ -1,5 +1,5 @@
/*
-** $Id: lmem.c,v 1.17 1999/05/24 17:51:05 roberto Exp $
+** $Id: lmem.c,v 1.39 2000/10/30 16:29:59 roberto Exp $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
@@ -7,134 +7,144 @@
#include <stdlib.h>
-#include "lmem.h"
-#include "lstate.h"
#include "lua.h"
+#include "ldo.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
-/*
-** real ANSI systems do not need these tests;
-** but some systems (Sun OS) are not that ANSI...
-*/
-#ifdef OLD_ANSI
-#define realloc(b,s) ((b) == NULL ? malloc(s) : (realloc)(b, s))
-#define free(b) if (b) (free)(b)
-#endif
-
-
-#define MINSIZE 8 /* minimum size for "growing" vectors */
-
-
-
-
-static unsigned long power2 (unsigned long n) {
- unsigned long p = MINSIZE;
- while (p<=n) p<<=1;
- return p;
-}
-
-
-void *luaM_growaux (void *block, unsigned long nelems, int inc, int size,
- char *errormsg, unsigned long limit) {
- unsigned long newn = nelems+inc;
- if (newn >= limit) lua_error(errormsg);
- if ((newn ^ nelems) <= nelems || /* still the same power of 2 limit? */
- (nelems > 0 && newn < MINSIZE)) /* or block already is MINSIZE? */
- return block; /* do not need to reallocate */
- else /* it crossed a power of 2 boundary; grow to next power */
- return luaM_realloc(block, power2(newn)*size);
-}
-#ifndef DEBUG
+#ifdef LUA_DEBUG
/*
-** generic allocation routine.
+** {======================================================================
+** Controlled version for realloc.
+** =======================================================================
*/
-void *luaM_realloc (void *block, unsigned long size) {
- size_t s = (size_t)size;
- if (s != size)
- lua_error("memory allocation error: block too big");
- if (size == 0) {
- free(block); /* block may be NULL, that is OK for free */
- return NULL;
- }
- block = realloc(block, s);
- if (block == NULL)
- lua_error(memEM);
- return block;
-}
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
-#else
-/* DEBUG */
+#define realloc(b, s) debug_realloc(b, s)
+#define malloc(b) debug_realloc(NULL, b)
+#define free(b) debug_realloc(b, 0)
-#include <string.h>
+/* ensures maximum alignment for HEADER */
+#define HEADER (sizeof(union L_Umaxalign))
-#define HEADER (sizeof(double))
#define MARKSIZE 16
-
-#define MARK 55
+#define MARK 0x55 /* 01010101 (a nice pattern) */
#define blocksize(b) ((unsigned long *)((char *)(b) - HEADER))
-unsigned long numblocks = 0;
-unsigned long totalmem = 0;
+unsigned long memdebug_numblocks = 0;
+unsigned long memdebug_total = 0;
+unsigned long memdebug_maxmem = 0;
+unsigned long memdebug_memlimit = LONG_MAX;
static void *checkblock (void *block) {
- if (block == NULL)
- return NULL;
- else {
- unsigned long *b = blocksize(block);
- unsigned long size = *b;
- int i;
- for (i=0;i<MARKSIZE;i++)
- LUA_ASSERT(*(((char *)b)+HEADER+size+i) == MARK+i, "corrupted block");
- numblocks--;
- totalmem -= size;
- return b;
- }
+ unsigned long *b = blocksize(block);
+ unsigned long size = *b;
+ int i;
+ for (i=0;i<MARKSIZE;i++)
+ assert(*(((char *)b)+HEADER+size+i) == MARK+i); /* corrupted block? */
+ memdebug_numblocks--;
+ memdebug_total -= size;
+ return b;
}
static void freeblock (void *block) {
- if (block)
- memset(block, -1, *blocksize(block)); /* erase block */
- free(checkblock(block));
+ if (block) {
+ size_t size = *blocksize(block);
+ block = checkblock(block);
+ memset(block, -1, size+HEADER+MARKSIZE); /* erase block */
+ (free)(block); /* free original block */
+ }
}
-void *luaM_realloc (void *block, unsigned long size) {
- unsigned long realsize = HEADER+size+MARKSIZE;
- if (realsize != (size_t)realsize)
- lua_error("memory allocation error: block too big");
+static void *debug_realloc (void *block, size_t size) {
if (size == 0) {
freeblock(block);
return NULL;
}
+ else if (memdebug_total+size > memdebug_memlimit)
+ return NULL; /* to test memory allocation errors */
else {
- char *newblock = malloc(realsize);
+ size_t realsize = HEADER+size+MARKSIZE;
+ char *newblock = (char *)(malloc)(realsize); /* alloc a new block */
int i;
+ if (realsize < size) return NULL; /* overflow! */
+ if (newblock == NULL) return NULL;
if (block) {
- unsigned long oldsize = *blocksize(block);
+ size_t oldsize = *blocksize(block);
if (oldsize > size) oldsize = size;
memcpy(newblock+HEADER, block, oldsize);
freeblock(block); /* erase (and check) old copy */
}
- if (newblock == NULL)
- lua_error(memEM);
- totalmem += size;
- numblocks++;
+ memdebug_total += size;
+ if (memdebug_total > memdebug_maxmem) memdebug_maxmem = memdebug_total;
+ memdebug_numblocks++;
*(unsigned long *)newblock = size;
for (i=0;i<MARKSIZE;i++)
- *(newblock+HEADER+size+i) = MARK+i;
+ *(newblock+HEADER+size+i) = (char)(MARK+i);
return newblock+HEADER;
}
}
+/* }====================================================================== */
+#endif
+
+
+
+/*
+** Real ISO (ANSI) systems do not need these tests;
+** but some systems (Sun OS) are not that ISO...
+*/
+#ifdef OLD_ANSI
+#define realloc(b,s) ((b) == NULL ? malloc(s) : (realloc)(b, s))
+#define free(b) if (b) (free)(b)
#endif
+
+
+void *luaM_growaux (lua_State *L, void *block, size_t nelems,
+ int inc, size_t size, const char *errormsg, size_t limit) {
+ size_t newn = nelems+inc;
+ if (nelems >= limit-inc) lua_error(L, errormsg);
+ if ((newn ^ nelems) <= nelems || /* still the same power-of-2 limit? */
+ (nelems > 0 && newn < MINPOWER2)) /* or block already is MINPOWER2? */
+ return block; /* do not need to reallocate */
+ else /* it crossed a power-of-2 boundary; grow to next power */
+ return luaM_realloc(L, block, luaO_power2(newn)*size);
+}
+
+
+/*
+** generic allocation routine.
+*/
+void *luaM_realloc (lua_State *L, void *block, lint32 size) {
+ if (size == 0) {
+ free(block); /* block may be NULL; that is OK for free */
+ return NULL;
+ }
+ else if (size >= MAX_SIZET)
+ lua_error(L, "memory allocation error: block too big");
+ block = realloc(block, size);
+ if (block == NULL) {
+ if (L)
+ luaD_breakrun(L, LUA_ERRMEM); /* break run without error message */
+ else return NULL; /* error before creating state! */
+ }
+ return block;
+}
+
+
diff --git a/src/lmem.h b/src/lmem.h
index 967899c9..9e7c829d 100644
--- a/src/lmem.h
+++ b/src/lmem.h
@@ -1,5 +1,5 @@
/*
-** $Id: lmem.h,v 1.8 1999/02/26 15:48:55 roberto Exp $
+** $Id: lmem.h,v 1.16 2000/10/30 16:29:59 roberto Exp $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
@@ -8,32 +8,33 @@
#define lmem_h
-#include <stdlib.h>
+#include <stddef.h>
-/* memory error messages */
-#define codeEM "code size overflow"
-#define constantEM "constant table overflow"
-#define refEM "reference table overflow"
-#define tableEM "table overflow"
-#define memEM "not enough memory"
-#define arrEM "internal array bigger than `int' limit"
+#include "llimits.h"
+#include "lua.h"
-void *luaM_realloc (void *oldblock, unsigned long size);
-void *luaM_growaux (void *block, unsigned long nelems, int inc, int size,
- char *errormsg, unsigned long limit);
+void *luaM_realloc (lua_State *L, void *oldblock, lint32 size);
+void *luaM_growaux (lua_State *L, void *block, size_t nelems,
+ int inc, size_t size, const char *errormsg,
+ size_t limit);
-#define luaM_free(b) luaM_realloc((b), 0)
-#define luaM_malloc(t) luaM_realloc(NULL, (t))
-#define luaM_new(t) ((t *)luaM_malloc(sizeof(t)))
-#define luaM_newvector(n,t) ((t *)luaM_malloc((n)*sizeof(t)))
-#define luaM_growvector(v,nelems,inc,t,e,l) \
- ((v)=(t *)luaM_growaux(v,nelems,inc,sizeof(t),e,l))
-#define luaM_reallocvector(v,n,t) ((v)=(t *)luaM_realloc(v,(n)*sizeof(t)))
+#define luaM_free(L, b) luaM_realloc(L, (b), 0)
+#define luaM_malloc(L, t) luaM_realloc(L, NULL, (t))
+#define luaM_new(L, t) ((t *)luaM_malloc(L, sizeof(t)))
+#define luaM_newvector(L, n,t) ((t *)luaM_malloc(L, (n)*(lint32)sizeof(t)))
+#define luaM_growvector(L, v,nelems,inc,t,e,l) \
+ ((v)=(t *)luaM_growaux(L, v,nelems,inc,sizeof(t),e,l))
-#ifdef DEBUG
-extern unsigned long numblocks;
-extern unsigned long totalmem;
+#define luaM_reallocvector(L, v,n,t) \
+ ((v)=(t *)luaM_realloc(L, v,(n)*(lint32)sizeof(t)))
+
+
+#ifdef LUA_DEBUG
+extern unsigned long memdebug_numblocks;
+extern unsigned long memdebug_total;
+extern unsigned long memdebug_maxmem;
+extern unsigned long memdebug_memlimit;
#endif
diff --git a/src/lobject.c b/src/lobject.c
index 0225e2d8..e787fbe8 100644
--- a/src/lobject.c
+++ b/src/lobject.c
@@ -1,129 +1,125 @@
/*
-** $Id: lobject.c,v 1.19 1999/04/13 19:28:49 roberto Exp $
+** $Id: lobject.c,v 1.55 2000/10/20 16:36:32 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>
+#include <string.h>
-#include "lobject.h"
#include "lua.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
-char *luaO_typenames[] = { /* ORDER LUA_T */
- "userdata", "number", "string", "table", "function", "function",
- "nil", "function", "mark", "mark", "mark", "line", NULL
-};
-TObject luaO_nilobject = {LUA_T_NIL, {NULL}};
+const TObject luaO_nilobject = {LUA_TNIL, {NULL}};
+const char *const luaO_typenames[] = {
+ "userdata", "nil", "number", "string", "table", "function"
+};
-/* hash dimensions values */
-static long dimensions[] =
- {5L, 11L, 23L, 47L, 97L, 197L, 397L, 797L, 1597L, 3203L, 6421L,
- 12853L, 25717L, 51437L, 102811L, 205619L, 411233L, 822433L,
- 1644817L, 3289613L, 6579211L, 13158023L, MAX_INT};
-int luaO_redimension (int oldsize)
-{
- int i;
- for (i=0; dimensions[i]<MAX_INT; i++) {
- if (dimensions[i] > oldsize)
- return dimensions[i];
- }
- lua_error("tableEM");
- return 0; /* to avoid warnings */
+/*
+** returns smaller power of 2 larger than `n' (minimum is MINPOWER2)
+*/
+lint32 luaO_power2 (lint32 n) {
+ lint32 p = MINPOWER2;
+ while (p<=n) p<<=1;
+ return p;
}
-int luaO_equalval (TObject *t1, TObject *t2) {
+int luaO_equalObj (const TObject *t1, const TObject *t2) {
+ if (ttype(t1) != ttype(t2)) return 0;
switch (ttype(t1)) {
- case LUA_T_NIL: return 1;
- case LUA_T_NUMBER: return nvalue(t1) == nvalue(t2);
- case LUA_T_STRING: case LUA_T_USERDATA: return svalue(t1) == svalue(t2);
- case LUA_T_ARRAY: return avalue(t1) == avalue(t2);
- case LUA_T_PROTO: return tfvalue(t1) == tfvalue(t2);
- case LUA_T_CPROTO: return fvalue(t1) == fvalue(t2);
- case LUA_T_CLOSURE: return t1->value.cl == t2->value.cl;
+ case LUA_TNUMBER:
+ return nvalue(t1) == nvalue(t2);
+ case LUA_TSTRING: case LUA_TUSERDATA:
+ return tsvalue(t1) == tsvalue(t2);
+ case LUA_TTABLE:
+ return hvalue(t1) == hvalue(t2);
+ case LUA_TFUNCTION:
+ return clvalue(t1) == clvalue(t2);
default:
- LUA_INTERNALERROR("invalid type");
- return 0; /* UNREACHABLE */
+ LUA_ASSERT(ttype(t1) == LUA_TNIL, "invalid type");
+ return 1; /* LUA_TNIL */
}
}
-void luaO_insertlist (GCnode *root, GCnode *node)
-{
- node->next = root->next;
- root->next = node;
- node->marked = 0;
+char *luaO_openspace (lua_State *L, size_t n) {
+ if (n > L->Mbuffsize) {
+ luaM_reallocvector(L, L->Mbuffer, n, char);
+ L->nblocks += (n - L->Mbuffsize)*sizeof(char);
+ L->Mbuffsize = n;
+ }
+ return L->Mbuffer;
}
-#ifdef OLD_ANSI
-void luaO_memup (void *dest, void *src, int size) {
- while (size--)
- ((char *)dest)[size]=((char *)src)[size];
-}
-
-void luaO_memdown (void *dest, void *src, int size) {
- int i;
- for (i=0; i<size; i++)
- ((char *)dest)[i]=((char *)src)[i];
+int luaO_str2d (const char *s, Number *result) { /* LUA_NUMBER */
+ char *endptr;
+ Number res = lua_str2number(s, &endptr);
+ if (endptr == s) return 0; /* no conversion */
+ while (isspace((unsigned char)*endptr)) endptr++;
+ if (*endptr != '\0') return 0; /* invalid trailing characters? */
+ *result = res;
+ return 1;
}
-#endif
+/* maximum length of a string format for `luaO_verror' */
+#define MAX_VERROR 280
-static double expten (unsigned int e) {
- double exp = 10.0;
- double res = 1.0;
- for (; e; e>>=1) {
- if (e & 1) res *= exp;
- exp *= exp;
- }
- return res;
+/* this function needs to handle only '%d' and '%.XXs' formats */
+void luaO_verror (lua_State *L, const char *fmt, ...) {
+ va_list argp;
+ char buff[MAX_VERROR]; /* to hold formatted message */
+ va_start(argp, fmt);
+ vsprintf(buff, fmt, argp);
+ va_end(argp);
+ lua_error(L, buff);
}
-double luaO_str2d (char *s) { /* LUA_NUMBER */
- double a = 0.0;
- int point = 0;
- while (isdigit((unsigned char)*s)) {
- a = 10.0*a + (*(s++)-'0');
+void luaO_chunkid (char *out, const char *source, int bufflen) {
+ if (*source == '=') {
+ strncpy(out, source+1, bufflen); /* remove first char */
+ out[bufflen-1] = '\0'; /* ensures null termination */
}
- if (*s == '.') {
- s++;
- while (isdigit((unsigned char)*s)) {
- a = 10.0*a + (*(s++)-'0');
- point++;
+ else {
+ if (*source == '@') {
+ int l;
+ source++; /* skip the `@' */
+ bufflen -= sizeof("file `...%s'");
+ l = strlen(source);
+ if (l>bufflen) {
+ source += (l-bufflen); /* get last part of file name */
+ sprintf(out, "file `...%.99s'", source);
+ }
+ else
+ sprintf(out, "file `%.99s'", source);
}
- }
- if (toupper((unsigned char)*s) == 'E') {
- int e = 0;
- int sig = 1;
- s++;
- if (*s == '-') {
- s++;
- sig = -1;
+ else {
+ int len = strcspn(source, "\n"); /* stop at first newline */
+ bufflen -= sizeof("string \"%.*s...\"");
+ if (len > bufflen) len = bufflen;
+ if (source[len] != '\0') { /* must truncate? */
+ strcpy(out, "string \"");
+ out += strlen(out);
+ strncpy(out, source, len);
+ strcpy(out+len, "...\"");
+ }
+ else
+ sprintf(out, "string \"%.99s\"", source);
}
- else if (*s == '+') s++;
- if (!isdigit((unsigned char)*s)) return -1; /* no digit in the exponent? */
- do {
- e = 10*e + (*(s++)-'0');
- } while (isdigit((unsigned char)*s));
- point -= sig*e;
}
- while (isspace((unsigned char)*s)) s++;
- if (*s != '\0') return -1; /* invalid trailing characters? */
- if (point > 0)
- a /= expten(point);
- else if (point < 0)
- a *= expten(-point);
- return a;
}
-
diff --git a/src/lobject.h b/src/lobject.h
index f3b21477..cb232c77 100644
--- a/src/lobject.h
+++ b/src/lobject.h
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.h,v 1.28 1999/03/16 16:43:27 roberto Exp $
+** $Id: lobject.h,v 1.82 2000/10/30 17:49:19 roberto Exp $
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
@@ -8,197 +8,197 @@
#define lobject_h
-#include <limits.h>
-
+#include "llimits.h"
#include "lua.h"
-#ifdef DEBUG
-#include "lauxlib.h"
-#define LUA_INTERNALERROR(s) \
- luaL_verror("INTERNAL ERROR - %s [%s:%d]",(s),__FILE__,__LINE__)
-#define LUA_ASSERT(c,s) { if (!(c)) LUA_INTERNALERROR(s); }
+#ifdef LUA_DEBUG
+#undef NDEBUG
+#include <assert.h>
+#define LUA_INTERNALERROR(s) assert(((void)s,0))
+#define LUA_ASSERT(c,s) assert(((void)s,(c)))
#else
-#define LUA_INTERNALERROR(s) /* empty */
-#define LUA_ASSERT(c,s) /* empty */
+#define LUA_INTERNALERROR(s) /* empty */
+#define LUA_ASSERT(c,s) /* empty */
#endif
-/*
-** "real" is the type "number" of Lua
-** GREP LUA_NUMBER to change that
-*/
-#ifndef LUA_NUM_TYPE
-#define LUA_NUM_TYPE double
+#ifdef LUA_DEBUG
+/* to avoid warnings, and make sure value is really unused */
+#define UNUSED(x) (x=0, (void)(x))
+#else
+#define UNUSED(x) ((void)(x)) /* to avoid warnings */
#endif
-typedef LUA_NUM_TYPE real;
-
-#define Byte lua_Byte /* some systems have Byte as a predefined type */
-typedef unsigned char Byte; /* unsigned 8 bits */
-
+/* mark for closures active in the stack */
+#define LUA_TMARK 6
-#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */
-typedef unsigned int IntPoint; /* unsigned with same size as a pointer (for hashing) */
+/* tags for values visible from Lua == first user-created tag */
+#define NUM_TAGS 6
-/*
-** Lua TYPES
-** WARNING: if you change the order of this enumeration,
-** grep "ORDER LUA_T"
-*/
-typedef enum {
- LUA_T_USERDATA = 0, /* tag default for userdata */
- LUA_T_NUMBER = -1, /* fixed tag for numbers */
- LUA_T_STRING = -2, /* fixed tag for strings */
- LUA_T_ARRAY = -3, /* tag default for tables (or arrays) */
- LUA_T_PROTO = -4, /* fixed tag for functions */
- LUA_T_CPROTO = -5, /* fixed tag for Cfunctions */
- LUA_T_NIL = -6, /* last "pre-defined" tag */
- LUA_T_CLOSURE = -7,
- LUA_T_CLMARK = -8, /* mark for closures */
- LUA_T_PMARK = -9, /* mark for Lua prototypes */
- LUA_T_CMARK = -10, /* mark for C prototypes */
- LUA_T_LINE = -11
-} lua_Type;
-
-#define NUM_TAGS 7
+/* check whether `t' is a mark */
+#define is_T_MARK(t) ((t) == LUA_TMARK)
typedef union {
- lua_CFunction f; /* LUA_T_CPROTO, LUA_T_CMARK */
- real n; /* LUA_T_NUMBER */
- struct TaggedString *ts; /* LUA_T_STRING, LUA_T_USERDATA */
- struct TProtoFunc *tf; /* LUA_T_PROTO, LUA_T_PMARK */
- struct Closure *cl; /* LUA_T_CLOSURE, LUA_T_CLMARK */
- struct Hash *a; /* LUA_T_ARRAY */
- int i; /* LUA_T_LINE */
+ struct TString *ts; /* LUA_TSTRING, LUA_TUSERDATA */
+ struct Closure *cl; /* LUA_TFUNCTION */
+ struct Hash *a; /* LUA_TTABLE */
+ struct CallInfo *i; /* LUA_TLMARK */
+ Number n; /* LUA_TNUMBER */
} Value;
-typedef struct TObject {
- lua_Type ttype;
+/* Macros to access values */
+#define ttype(o) ((o)->ttype)
+#define nvalue(o) ((o)->value.n)
+#define tsvalue(o) ((o)->value.ts)
+#define clvalue(o) ((o)->value.cl)
+#define hvalue(o) ((o)->value.a)
+#define infovalue(o) ((o)->value.i)
+#define svalue(o) (tsvalue(o)->str)
+
+
+typedef struct lua_TObject {
+ int ttype;
Value value;
} TObject;
-
/*
-** generic header for garbage collector lists
+** String headers for string table
*/
-typedef struct GCnode {
- struct GCnode *next;
- int marked;
-} GCnode;
-
/*
-** String headers for string table
+** most `malloc' libraries allocate memory in blocks of 8 bytes. TSPACK
+** tries to make sizeof(TString) a multiple of this granularity, to reduce
+** waste of space.
*/
+#define TSPACK ((int)sizeof(int))
-typedef struct TaggedString {
- GCnode head;
- unsigned long hash;
- int constindex; /* hint to reuse constants (= -1 if this is a userdata) */
+typedef struct TString {
union {
- struct {
- TObject globalval;
- long len; /* if this is a string, here is its length */
+ struct { /* for strings */
+ unsigned long hash;
+ int constindex; /* hint to reuse constants */
} s;
- struct {
+ struct { /* for userdata */
int tag;
- void *v; /* if this is a userdata, here is its value */
+ void *value;
} d;
} u;
- char str[1]; /* \0 byte already reserved */
-} TaggedString;
-
-
+ size_t len;
+ struct TString *nexthash; /* chain for hash table */
+ int marked;
+ char str[TSPACK]; /* variable length string!! must be the last field! */
+} TString;
/*
** Function Prototypes
*/
-typedef struct TProtoFunc {
- GCnode head;
- struct TObject *consts;
- int nconsts;
- Byte *code; /* ends with opcode ENDCODE */
+typedef struct Proto {
+ Number *knum; /* Number numbers used by the function */
+ int nknum; /* size of `knum' */
+ struct TString **kstr; /* strings used by the function */
+ int nkstr; /* size of `kstr' */
+ struct Proto **kproto; /* functions defined inside the function */
+ int nkproto; /* size of `kproto' */
+ Instruction *code;
+ int ncode; /* size of `code'; when 0 means an incomplete `Proto' */
+ short numparams;
+ short is_vararg;
+ short maxstacksize;
+ short marked;
+ struct Proto *next;
+ /* debug information */
+ int *lineinfo; /* map from opcodes to source lines */
+ int nlineinfo; /* size of `lineinfo' */
+ int nlocvars;
+ struct LocVar *locvars; /* information about local variables */
int lineDefined;
- TaggedString *source;
- struct LocVar *locvars; /* ends with line = -1 */
-} TProtoFunc;
+ TString *source;
+} Proto;
+
typedef struct LocVar {
- TaggedString *varname; /* NULL signals end of scope */
- int line;
+ TString *varname;
+ int startpc; /* first point where variable is active */
+ int endpc; /* first point where variable is dead */
} LocVar;
-
-
-
-/* Macros to access structure members */
-#define ttype(o) ((o)->ttype)
-#define nvalue(o) ((o)->value.n)
-#define svalue(o) ((o)->value.ts->str)
-#define tsvalue(o) ((o)->value.ts)
-#define clvalue(o) ((o)->value.cl)
-#define avalue(o) ((o)->value.a)
-#define fvalue(o) ((o)->value.f)
-#define tfvalue(o) ((o)->value.tf)
-
-#define protovalue(o) ((o)->value.cl->consts)
-
-
/*
** Closures
*/
typedef struct Closure {
- GCnode head;
- int nelems; /* not included the first one (always the prototype) */
- TObject consts[1]; /* at least one for prototype */
+ union {
+ lua_CFunction c; /* C functions */
+ struct Proto *l; /* Lua functions */
+ } f;
+ struct Closure *next;
+ struct Closure *mark; /* marked closures (point to itself when not marked) */
+ short isC; /* 0 for Lua functions, 1 for C functions */
+ short nupvalues;
+ TObject upvalue[1];
} Closure;
+#define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->isC)
+
-typedef struct node {
- TObject ref;
+typedef struct Node {
+ TObject key;
TObject val;
+ struct Node *next; /* for chaining */
} Node;
typedef struct Hash {
- GCnode head;
Node *node;
- int nhash;
- int nuse;
int htag;
+ int size;
+ Node *firstfree; /* this position is free; all positions after it are full */
+ struct Hash *next;
+ struct Hash *mark; /* marked tables (point to itself when not marked) */
} Hash;
-extern char *luaO_typenames[];
+/* unmarked tables and closures are represented by pointing `mark' to
+** themselves
+*/
+#define ismarked(x) ((x)->mark != (x))
+
-#define luaO_typename(o) luaO_typenames[-ttype(o)]
+/*
+** informations about a call (for debugging)
+*/
+typedef struct CallInfo {
+ struct Closure *func; /* function being called */
+ const Instruction **pc; /* current pc of called function */
+ int lastpc; /* last pc traced */
+ int line; /* current line */
+ int refi; /* current index in `lineinfo' */
+} CallInfo;
-extern TObject luaO_nilobject;
+extern const TObject luaO_nilobject;
+extern const char *const luaO_typenames[];
-#define luaO_equalObj(t1,t2) ((ttype(t1) != ttype(t2)) ? 0 \
- : luaO_equalval(t1,t2))
-int luaO_equalval (TObject *t1, TObject *t2);
-int luaO_redimension (int oldsize);
-void luaO_insertlist (GCnode *root, GCnode *node);
-double luaO_str2d (char *s);
-#ifdef OLD_ANSI
-void luaO_memup (void *dest, void *src, int size);
-void luaO_memdown (void *dest, void *src, int size);
-#else
-#include <string.h>
-#define luaO_memup(d,s,n) memmove(d,s,n)
-#define luaO_memdown(d,s,n) memmove(d,s,n)
-#endif
+#define luaO_typename(o) (luaO_typenames[ttype(o)])
+
+
+lint32 luaO_power2 (lint32 n);
+char *luaO_openspace (lua_State *L, size_t n);
+
+int luaO_equalObj (const TObject *t1, const TObject *t2);
+int luaO_str2d (const char *s, Number *result);
+
+void luaO_verror (lua_State *L, const char *fmt, ...);
+void luaO_chunkid (char *out, const char *source, int len);
+
#endif
diff --git a/src/lopcodes.h b/src/lopcodes.h
index 6a59b39e..2df72ce7 100644
--- a/src/lopcodes.h
+++ b/src/lopcodes.h
@@ -1,5 +1,5 @@
/*
-** $Id: lopcodes.h,v 1.33 1999/06/17 17:04:03 roberto Exp $
+** $Id: lopcodes.h,v 1.68 2000/10/24 16:05:59 roberto Exp $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -7,132 +7,162 @@
#ifndef lopcodes_h
#define lopcodes_h
+#include "llimits.h"
-/*
-** NOTICE: variants of the same opcode must be consecutive: First, those
-** with word parameter, then with byte parameter.
-*/
+/*===========================================================================
+ We assume that instructions are unsigned numbers.
+ All instructions have an opcode in the first 6 bits. Moreover,
+ an instruction can have 0, 1, or 2 arguments. Instructions can
+ have the following types:
+ type 0: no arguments
+ type 1: 1 unsigned argument in the higher bits (called `U')
+ type 2: 1 signed argument in the higher bits (`S')
+ type 3: 1st unsigned argument in the higher bits (`A')
+ 2nd unsigned argument in the middle bits (`B')
-typedef enum {
-/* name parm before after side effect
------------------------------------------------------------------------------*/
-ENDCODE,/* - - (return) */
-RETCODE,/* b - (return) */
+ A signed argument is represented in excess K; that is, the number
+ value is the unsigned value minus K. K is exactly the maximum value
+ for that argument (so that -max is represented by 0, and +max is
+ represented by 2*max), which is half the maximum for the corresponding
+ unsigned argument.
-CALL,/* b c v_c...v_1 f r_b...r_1 f(v1,...,v_c) */
+ The size of each argument is defined in `llimits.h'. The usual is an
+ instruction with 32 bits, U arguments with 26 bits (32-6), B arguments
+ with 9 bits, and A arguments with 17 bits (32-6-9). For small
+ installations, the instruction size can be 16, so U has 10 bits,
+ and A and B have 5 bits each.
+===========================================================================*/
-TAILCALL,/* b c v_c...v_1 f (return) f(v1,...,v_c) */
-PUSHNIL,/* b - nil_0...nil_b */
-POP,/* b a_b...a_1 - */
-PUSHNUMBERW,/* w - (float)w */
-PUSHNUMBER,/* b - (float)b */
-PUSHNUMBERNEGW,/* w - (float)-w */
-PUSHNUMBERNEG,/* b - (float)-b */
+/* creates a mask with `n' 1 bits at position `p' */
+#define MASK1(n,p) ((~((~(Instruction)0)<<n))<<p)
-PUSHCONSTANTW,/*w - CNST[w] */
-PUSHCONSTANT,/* b - CNST[b] */
+/* creates a mask with `n' 0 bits at position `p' */
+#define MASK0(n,p) (~MASK1(n,p))
-PUSHUPVALUE,/* b - Closure[b] */
+/*
+** the following macros help to manipulate instructions
+*/
-PUSHLOCAL,/* b - LOC[b] */
+#define CREATE_0(o) ((Instruction)(o))
+#define GET_OPCODE(i) ((OpCode)((i)&MASK1(SIZE_OP,0)))
+#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,0)) | (Instruction)(o)))
-GETGLOBALW,/* w - VAR[CNST[w]] */
-GETGLOBAL,/* b - VAR[CNST[b]] */
+#define CREATE_U(o,u) ((Instruction)(o) | ((Instruction)(u)<<POS_U))
+#define GETARG_U(i) ((int)((i)>>POS_U))
+#define SETARG_U(i,u) ((i) = (((i)&MASK0(SIZE_U,POS_U)) | \
+ ((Instruction)(u)<<POS_U)))
-GETTABLE,/* - i t t[i] */
+#define CREATE_S(o,s) CREATE_U((o),(s)+MAXARG_S)
+#define GETARG_S(i) (GETARG_U(i)-MAXARG_S)
+#define SETARG_S(i,s) SETARG_U((i),(s)+MAXARG_S)
-GETDOTTEDW,/* w t t[CNST[w]] */
-GETDOTTED,/* b t t[CNST[b]] */
-PUSHSELFW,/* w t t t[CNST[w]] */
-PUSHSELF,/* b t t t[CNST[b]] */
+#define CREATE_AB(o,a,b) ((Instruction)(o) | ((Instruction)(a)<<POS_A) \
+ | ((Instruction)(b)<<POS_B))
+#define GETARG_A(i) ((int)((i)>>POS_A))
+#define SETARG_A(i,a) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \
+ ((Instruction)(a)<<POS_A)))
+#define GETARG_B(i) ((int)(((i)>>POS_B) & MASK1(SIZE_B,0)))
+#define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \
+ ((Instruction)(b)<<POS_B)))
-CREATEARRAYW,/* w - newarray(size = w) */
-CREATEARRAY,/* b - newarray(size = b) */
-SETLOCAL,/* b x - LOC[b]=x */
+/*
+** K = U argument used as index to `kstr'
+** J = S argument used as jump offset (relative to pc of next instruction)
+** L = unsigned argument used as index of local variable
+** N = U argument used as index to `knum'
+*/
-SETGLOBALW,/* w x - VAR[CNST[w]]=x */
-SETGLOBAL,/* b x - VAR[CNST[b]]=x */
+typedef enum {
+/*----------------------------------------------------------------------
+name args stack before stack after side effects
+------------------------------------------------------------------------*/
+OP_END,/* - - (return) no results */
+OP_RETURN,/* U v_n-v_x(at u) (return) returns v_x-v_n */
-SETTABLEPOP,/* - v i t - t[i]=v */
+OP_CALL,/* A B v_n-v_1 f(at a) r_b-r_1 f(v1,...,v_n) */
+OP_TAILCALL,/* A B v_n-v_1 f(at a) (return) f(v1,...,v_n) */
-SETTABLE,/* b v a_b...a_1 i t a_b...a_1 i t t[i]=v */
+OP_PUSHNIL,/* U - nil_1-nil_u */
+OP_POP,/* U a_u-a_1 - */
-SETLISTW,/* w c v_c...v_1 t t t[i+w*FPF]=v_i */
-SETLIST,/* b c v_c...v_1 t t t[i+b*FPF]=v_i */
+OP_PUSHINT,/* S - (Number)s */
+OP_PUSHSTRING,/* K - KSTR[k] */
+OP_PUSHNUM,/* N - KNUM[n] */
+OP_PUSHNEGNUM,/* N - -KNUM[n] */
-SETMAP,/* b v_b k_b ...v_0 k_0 t t t[k_i]=v_i */
+OP_PUSHUPVALUE,/* U - Closure[u] */
-NEQOP,/* - y x (x~=y)? 1 : nil */
-EQOP,/* - y x (x==y)? 1 : nil */
-LTOP,/* - y x (x<y)? 1 : nil */
-LEOP,/* - y x (x<y)? 1 : nil */
-GTOP,/* - y x (x>y)? 1 : nil */
-GEOP,/* - y x (x>=y)? 1 : nil */
-ADDOP,/* - y x x+y */
-SUBOP,/* - y x x-y */
-MULTOP,/* - y x x*y */
-DIVOP,/* - y x x/y */
-POWOP,/* - y x x^y */
-CONCOP,/* - y x x..y */
-MINUSOP,/* - x -x */
-NOTOP,/* - x (x==nil)? 1 : nil */
+OP_GETLOCAL,/* L - LOC[l] */
+OP_GETGLOBAL,/* K - VAR[KSTR[k]] */
-ONTJMPW,/* w x (x!=nil)? x : - (x!=nil)? PC+=w */
-ONTJMP,/* b x (x!=nil)? x : - (x!=nil)? PC+=b */
-ONFJMPW,/* w x (x==nil)? x : - (x==nil)? PC+=w */
-ONFJMP,/* b x (x==nil)? x : - (x==nil)? PC+=b */
-JMPW,/* w - - PC+=w */
-JMP,/* b - - PC+=b */
-IFFJMPW,/* w x - (x==nil)? PC+=w */
-IFFJMP,/* b x - (x==nil)? PC+=b */
-IFTUPJMPW,/* w x - (x!=nil)? PC-=w */
-IFTUPJMP,/* b x - (x!=nil)? PC-=b */
-IFFUPJMPW,/* w x - (x==nil)? PC-=w */
-IFFUPJMP,/* b x - (x==nil)? PC-=b */
+OP_GETTABLE,/* - i t t[i] */
+OP_GETDOTTED,/* K t t[KSTR[k]] */
+OP_GETINDEXED,/* L t t[LOC[l]] */
+OP_PUSHSELF,/* K t t t[KSTR[k]] */
-CLOSUREW,/* w c v_c...v_1 closure(CNST[w], v_c...v_1) */
-CLOSURE,/* b c v_c...v_1 closure(CNST[b], v_c...v_1) */
+OP_CREATETABLE,/* U - newarray(size = u) */
-SETLINEW,/* w - - LINE=w */
-SETLINE,/* b - - LINE=b */
+OP_SETLOCAL,/* L x - LOC[l]=x */
+OP_SETGLOBAL,/* K x - VAR[KSTR[k]]=x */
+OP_SETTABLE,/* A B v a_a-a_1 i t (pops b values) t[i]=v */
-LONGARGW,/* w (add w*(1<<16) to arg of next instruction) */
-LONGARG,/* b (add b*(1<<16) to arg of next instruction) */
+OP_SETLIST,/* A B v_b-v_1 t t t[i+a*FPF]=v_i */
+OP_SETMAP,/* U v_u k_u - v_1 k_1 t t t[k_i]=v_i */
-CHECKSTACK /* b (assert #temporaries == b; only for internal debuging!) */
+OP_ADD,/* - y x x+y */
+OP_ADDI,/* S x x+s */
+OP_SUB,/* - y x x-y */
+OP_MULT,/* - y x x*y */
+OP_DIV,/* - y x x/y */
+OP_POW,/* - y x x^y */
+OP_CONCAT,/* U v_u-v_1 v1..-..v_u */
+OP_MINUS,/* - x -x */
+OP_NOT,/* - x (x==nil)? 1 : nil */
-} OpCode;
+OP_JMPNE,/* J y x - (x~=y)? PC+=s */
+OP_JMPEQ,/* J y x - (x==y)? PC+=s */
+OP_JMPLT,/* J y x - (x<y)? PC+=s */
+OP_JMPLE,/* J y x - (x<y)? PC+=s */
+OP_JMPGT,/* J y x - (x>y)? PC+=s */
+OP_JMPGE,/* J y x - (x>=y)? PC+=s */
+OP_JMPT,/* J x - (x~=nil)? PC+=s */
+OP_JMPF,/* J x - (x==nil)? PC+=s */
+OP_JMPONT,/* J x (x~=nil)? x : - (x~=nil)? PC+=s */
+OP_JMPONF,/* J x (x==nil)? x : - (x==nil)? PC+=s */
+OP_JMP,/* J - - PC+=s */
-#define RFIELDS_PER_FLUSH 32 /* records (SETMAP) */
-#define LFIELDS_PER_FLUSH 64 /* FPF - lists (SETLIST) */
+OP_PUSHNILJMP,/* - - nil PC++; */
-#define ZEROVARARG 128
+OP_FORPREP,/* J */
+OP_FORLOOP,/* J */
+OP_LFORPREP,/* J */
+OP_LFORLOOP,/* J */
-/* maximum value of an arg of 3 bytes; must fit in an "int" */
-#if MAX_INT < (1<<24)
-#define MAX_ARG MAX_INT
-#else
-#define MAX_ARG ((1<<24)-1)
-#endif
+OP_CLOSURE/* A B v_b-v_1 closure(KPROTO[a], v_1-v_b) */
-/* maximum value of a word of 2 bytes; cannot be bigger than MAX_ARG */
-#if MAX_ARG < (1<<16)
-#define MAX_WORD MAX_ARG
-#else
-#define MAX_WORD ((1<<16)-1)
-#endif
+} OpCode;
+
+#define NUM_OPCODES ((int)OP_CLOSURE+1)
-/* maximum value of a byte */
-#define MAX_BYTE ((1<<8)-1)
+#define ISJUMP(o) (OP_JMPNE <= (o) && (o) <= OP_JMP)
+
+
+
+/* special code to fit a LUA_MULTRET inside an argB */
+#define MULT_RET 255 /* (<=MAXARG_B) */
+#if MULT_RET>MAXARG_B
+#undef MULT_RET
+#define MULT_RET MAXARG_B
+#endif
#endif
diff --git a/src/lparser.c b/src/lparser.c
index b0aa13f5..b792c956 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.c,v 1.37a 1999/06/17 17:04:03 roberto Exp $
+** $Id: lparser.c,v 1.116 2000/10/27 11:39:52 roberto Exp $
** LL(1) Parser and code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -8,1385 +8,1117 @@
#include <stdio.h>
#include <string.h>
-#include "lauxlib.h"
-#include "ldo.h"
+#include "lua.h"
+
+#include "lcode.h"
#include "lfunc.h"
#include "llex.h"
#include "lmem.h"
+#include "lobject.h"
#include "lopcodes.h"
#include "lparser.h"
#include "lstate.h"
#include "lstring.h"
-#include "lua.h"
-#include "luadebug.h"
-#include "lzio.h"
-
-
-
-/* size of a "normal" jump instruction: OpCode + 1 byte */
-#define JMPSIZE 2
-
-/* maximum number of local variables */
-#ifndef MAXLOCALS
-#define MAXLOCALS 200 /* arbitrary limit (<256) */
-#endif
-
-
-/* maximum number of upvalues */
-#ifndef MAXUPVALUES
-#define MAXUPVALUES 32 /* arbitrary limit (<256) */
-#endif
-
-
-/* maximum number of variables in the left side of an assignment */
-#ifndef MAXVARSLH
-#define MAXVARSLH 100 /* arbitrary limit (<255) */
-#endif
-
-
-/* maximum number of parameters in a function */
-#ifndef MAXPARAMS
-#define MAXPARAMS 100 /* arbitrary limit (<ZEROVARARG) */
-#endif
-
-
-/*
-** Variable descriptor:
-** must include an "exp" option because LL(1) cannot distinguish
-** between variables, upvalues and function calls on first sight.
-*/
-typedef enum {
- VGLOBAL, /* info is constant index of global name */
- VLOCAL, /* info is stack index */
- VDOT, /* info is constant index of index name */
- VINDEXED, /* no info (table and index are on the stack) */
- VEXP /* info is pc index of "nparam" of a call (or 0 if exp is closed) */
-} varkind;
-
-typedef struct vardesc {
- varkind k;
- int info;
-} vardesc;
-
-
-/*
-** Expression List descriptor:
-** tells number of expressions in the list,
-** and, if last expression is open (a function call),
-** where is its pc index of "nparam"
-*/
-typedef struct listdesc {
- int n;
- int pc; /* 0 if last expression is closed */
-} listdesc;
/*
** Constructors descriptor:
-** "n" indicates number of elements, and "k" signals whether
+** `n' indicates number of elements, and `k' signals whether
** it is a list constructor (k = 0) or a record constructor (k = 1)
** or empty (k = ';' or '}')
*/
-typedef struct constdesc {
+typedef struct Constdesc {
int n;
int k;
-} constdesc;
+} Constdesc;
+
+
+typedef struct Breaklabel {
+ struct Breaklabel *previous; /* chain */
+ int breaklist;
+ int stacklevel;
+} Breaklabel;
-/* state needed to generate code for a given function */
-typedef struct FuncState {
- TProtoFunc *f; /* current function header */
- struct FuncState *prev; /* enclosuring function */
- int pc; /* next position to code */
- int stacksize; /* number of values on activation register */
- int maxstacksize; /* maximum number of values on activation register */
- int nlocalvar; /* number of active local variables */
- int nupvalues; /* number of upvalues */
- int nvars; /* number of entries in f->locvars (-1 if no debug information) */
- int lastsetline; /* line where last SETLINE was issued */
- vardesc upvalues[MAXUPVALUES]; /* upvalues */
- TaggedString *localvar[MAXLOCALS]; /* store local variable names */
-} FuncState;
/*
-** prototypes for non-terminal functions
+** prototypes for recursive non-terminal functions
*/
-static int assignment (LexState *ls, vardesc *v, int nvars);
-static int cond (LexState *ls);
-static int funcname (LexState *ls, vardesc *v);
-static int funcparams (LexState *ls, int slf);
-static int listfields (LexState *ls);
-static int localnamelist (LexState *ls);
-static int optional (LexState *ls, int c);
-static int recfields (LexState *ls);
-static int stat (LexState *ls);
-static void block (LexState *ls);
static void body (LexState *ls, int needself, int line);
static void chunk (LexState *ls);
static void constructor (LexState *ls);
-static void decinit (LexState *ls, listdesc *d);
-static void exp0 (LexState *ls, vardesc *v);
+static void expr (LexState *ls, expdesc *v);
static void exp1 (LexState *ls);
-static void exp2 (LexState *ls, vardesc *v);
-static void explist (LexState *ls, listdesc *e);
-static void explist1 (LexState *ls, listdesc *e);
-static void ifpart (LexState *ls, int line);
-static void parlist (LexState *ls);
-static void part (LexState *ls, constdesc *cd);
-static void recfield (LexState *ls);
-static void ret (LexState *ls);
-static void statlist (LexState *ls);
-static void var_or_func (LexState *ls, vardesc *v);
-static void var_or_func_tail (LexState *ls, vardesc *v);
-
-
-
-static void checklimit (LexState *ls, int val, int limit, char *msg) {
- if (val > limit) {
- char buff[100];
- sprintf(buff, "too many %s (limit=%d)", msg, limit);
- luaX_error(ls, buff);
- }
-}
-
-static void check_pc (FuncState *fs, int n) {
- luaM_growvector(fs->f->code, fs->pc, n, Byte, codeEM, MAX_INT);
-}
-
-
-static void code_byte (FuncState *fs, Byte c) {
- check_pc(fs, 1);
- fs->f->code[fs->pc++] = c;
-}
-static void deltastack (LexState *ls, int delta) {
- FuncState *fs = ls->fs;
- fs->stacksize += delta;
- if (fs->stacksize > fs->maxstacksize) {
- if (fs->stacksize > MAX_BYTE)
- luaX_error(ls, "function/expression too complex");
- fs->maxstacksize = fs->stacksize;
- }
-}
-
-
-static void code_oparg_at (LexState *ls, int pc, OpCode op,
- int arg, int delta) {
- Byte *code = ls->fs->f->code;
- deltastack(ls, delta);
- if (arg <= MAX_BYTE) {
- code[pc] = (Byte)op;
- code[pc+1] = (Byte)arg;
- }
- else if (arg > MAX_ARG)
- luaX_error(ls, "code too long");
- else { /* MAX_BYTE < arg < MAX_ARG */
- if (arg > MAX_WORD) {
- code[pc] = (Byte)LONGARG;
- code[pc+1] = (Byte)(arg>>16);
- pc += 2;
- }
- code[pc] = (Byte)(op-1); /* opcode for word argument */
- code[pc+1] = (Byte)((arg&0xFFFF)>>8);
- code[pc+2] = (Byte)(arg&0xFF);
+static void next (LexState *ls) {
+ ls->lastline = ls->linenumber;
+ if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */
+ ls->t = ls->lookahead; /* use this one */
+ ls->lookahead.token = TK_EOS; /* and discharge it */
}
+ else
+ ls->t.token = luaX_lex(ls, &ls->t.seminfo); /* read next token */
}
-static int codesize (int arg) {
- if (arg <= MAX_BYTE) return 2; /* opcode + 1 byte */
- else if (arg <= MAX_WORD) return 3; /* opcode + 1 word (2 bytes) */
- else return 5; /* LONGARG + 1 byte + opcode + 1 word (2 bytes) */
+static void lookahead (LexState *ls) {
+ LUA_ASSERT(ls->lookahead.token == TK_EOS, "two look-aheads");
+ ls->lookahead.token = luaX_lex(ls, &ls->lookahead.seminfo);
}
-static int fix_opcode (LexState *ls, int pc, OpCode op, int arg) {
- int tomove = codesize(arg)-2;
- if (tomove > 0) { /* need to open space? */
- FuncState *fs = ls->fs;
- TProtoFunc *f = fs->f;
- check_pc(fs, tomove);
- luaO_memup(f->code+pc+tomove, f->code+pc, fs->pc-pc);
- fs->pc += tomove;
- }
- code_oparg_at(ls, pc, op, arg, 0);
- return tomove;
+static void error_expected (LexState *ls, int token) {
+ char buff[100], t[TOKEN_LEN];
+ luaX_token2str(token, t);
+ sprintf(buff, "`%.20s' expected", t);
+ luaK_error(ls, buff);
}
-static void code_oparg (LexState *ls, OpCode op, int arg, int delta) {
- int size = codesize(arg);
- check_pc(ls->fs, size);
- code_oparg_at(ls, ls->fs->pc, op, arg, delta);
- ls->fs->pc += size;
+static void check (LexState *ls, int c) {
+ if (ls->t.token != c)
+ error_expected(ls, c);
+ next(ls);
}
-static void code_opcode (LexState *ls, OpCode op, int delta) {
- deltastack(ls, delta);
- code_byte(ls->fs, (Byte)op);
+static void check_condition (LexState *ls, int c, const char *msg) {
+ if (!c) luaK_error(ls, msg);
}
-static void code_constant (LexState *ls, int c) {
- code_oparg(ls, PUSHCONSTANT, c, 1);
+static int optional (LexState *ls, int c) {
+ if (ls->t.token == c) {
+ next(ls);
+ return 1;
+ }
+ else return 0;
}
-static int next_constant (FuncState *fs) {
- TProtoFunc *f = fs->f;
- luaM_growvector(f->consts, f->nconsts, 1, TObject, constantEM, MAX_ARG);
- return f->nconsts++;
+static void check_match (LexState *ls, int what, int who, int where) {
+ if (ls->t.token != what) {
+ if (where == ls->linenumber)
+ error_expected(ls, what);
+ else {
+ char buff[100];
+ char t_what[TOKEN_LEN], t_who[TOKEN_LEN];
+ luaX_token2str(what, t_what);
+ luaX_token2str(who, t_who);
+ sprintf(buff, "`%.20s' expected (to close `%.20s' at line %d)",
+ t_what, t_who, where);
+ luaK_error(ls, buff);
+ }
+ }
+ next(ls);
}
-static int string_constant (FuncState *fs, TaggedString *s) {
- TProtoFunc *f = fs->f;
- int c = s->constindex;
- if (!(c < f->nconsts &&
- ttype(&f->consts[c]) == LUA_T_STRING && tsvalue(&f->consts[c]) == s)) {
- c = next_constant(fs);
- ttype(&f->consts[c]) = LUA_T_STRING;
- tsvalue(&f->consts[c]) = s;
- s->constindex = c; /* hint for next time */
+static int string_constant (FuncState *fs, TString *s) {
+ Proto *f = fs->f;
+ int c = s->u.s.constindex;
+ if (c >= f->nkstr || f->kstr[c] != s) {
+ luaM_growvector(fs->L, f->kstr, f->nkstr, 1, TString *,
+ "constant table overflow", MAXARG_U);
+ c = f->nkstr++;
+ f->kstr[c] = s;
+ s->u.s.constindex = c; /* hint for next time */
}
return c;
}
-static void code_string (LexState *ls, TaggedString *s) {
- code_constant(ls, string_constant(ls->fs, s));
+static void code_string (LexState *ls, TString *s) {
+ luaK_kstr(ls, string_constant(ls->fs, s));
}
-#define LIM 20
-static int real_constant (FuncState *fs, real r) {
- /* check whether 'r' has appeared within the last LIM entries */
- TObject *cnt = fs->f->consts;
- int c = fs->f->nconsts;
- int lim = c < LIM ? 0 : c-LIM;
- while (--c >= lim) {
- if (ttype(&cnt[c]) == LUA_T_NUMBER && nvalue(&cnt[c]) == r)
- return c;
- }
- /* not found; create a new entry */
- c = next_constant(fs);
- cnt = fs->f->consts; /* 'next_constant' may have reallocated this vector */
- ttype(&cnt[c]) = LUA_T_NUMBER;
- nvalue(&cnt[c]) = r;
- return c;
-}
-
-
-static void code_number (LexState *ls, real f) {
- real af = (f<0) ? -f : f;
- if (0 <= af && af <= (real)MAX_WORD && (int)af == af) {
- /* abs(f) has a short integer value */
- code_oparg(ls, (f<0) ? PUSHNUMBERNEG : PUSHNUMBER, (int)af, 1);
- }
- else
- code_constant(ls, real_constant(ls->fs, f));
+static TString *str_checkname (LexState *ls) {
+ TString *ts;
+ check_condition(ls, (ls->t.token == TK_NAME), "<name> expected");
+ ts = ls->t.seminfo.ts;
+ next(ls);
+ return ts;
}
-static void flush_record (LexState *ls, int n) {
- if (n > 0)
- code_oparg(ls, SETMAP, n-1, -2*n);
+static int checkname (LexState *ls) {
+ return string_constant(ls->fs, str_checkname(ls));
}
-static void flush_list (LexState *ls, int m, int n) {
- if (n > 0) {
- code_oparg(ls, SETLIST, m, -n);
- code_byte(ls->fs, (Byte)n);
- }
+static int luaI_registerlocalvar (LexState *ls, TString *varname) {
+ Proto *f = ls->fs->f;
+ luaM_growvector(ls->L, f->locvars, f->nlocvars, 1, LocVar, "", MAX_INT);
+ f->locvars[f->nlocvars].varname = varname;
+ return f->nlocvars++;
}
-static void luaI_registerlocalvar (FuncState *fs, TaggedString *varname,
- int line) {
- if (fs->nvars != -1) { /* debug information? */
- TProtoFunc *f = fs->f;
- luaM_growvector(f->locvars, fs->nvars, 1, LocVar, "", MAX_INT);
- f->locvars[fs->nvars].varname = varname;
- f->locvars[fs->nvars].line = line;
- fs->nvars++;
- }
+static void new_localvar (LexState *ls, TString *name, int n) {
+ FuncState *fs = ls->fs;
+ luaX_checklimit(ls, fs->nactloc+n+1, MAXLOCALS, "local variables");
+ fs->actloc[fs->nactloc+n] = luaI_registerlocalvar(ls, name);
}
-static void luaI_unregisterlocalvar (FuncState *fs, int line) {
- luaI_registerlocalvar(fs, NULL, line);
+static void adjustlocalvars (LexState *ls, int nvars) {
+ FuncState *fs = ls->fs;
+ while (nvars--)
+ fs->f->locvars[fs->actloc[fs->nactloc++]].startpc = fs->pc;
}
-static void store_localvar (LexState *ls, TaggedString *name, int n) {
+static void removelocalvars (LexState *ls, int nvars) {
FuncState *fs = ls->fs;
- checklimit(ls, fs->nlocalvar+n+1, MAXLOCALS, "local variables");
- fs->localvar[fs->nlocalvar+n] = name;
- luaI_registerlocalvar(fs, name, ls->linenumber);
+ while (nvars--)
+ fs->f->locvars[fs->actloc[--fs->nactloc]].endpc = fs->pc;
}
-static void add_localvar (LexState *ls, TaggedString *name) {
- store_localvar(ls, name, 0);
- ls->fs->nlocalvar++;
+static void new_localvarstr (LexState *ls, const char *name, int n) {
+ new_localvar(ls, luaS_newfixed(ls->L, name), n);
}
-static void correctvarlines (LexState *ls, int nvars) {
- FuncState *fs = ls->fs;
- if (fs->nvars != -1) { /* debug information? */
- for (; nvars; nvars--) { /* correct line information */
- fs->f->locvars[fs->nvars-nvars].line = fs->lastsetline;
+static int search_local (LexState *ls, TString *n, expdesc *var) {
+ FuncState *fs;
+ int level = 0;
+ for (fs=ls->fs; fs; fs=fs->prev) {
+ int i;
+ for (i=fs->nactloc-1; i >= 0; i--) {
+ if (n == fs->f->locvars[fs->actloc[i]].varname) {
+ var->k = VLOCAL;
+ var->u.index = i;
+ return level;
+ }
}
+ level++; /* `var' not found; check outer level */
}
+ var->k = VGLOBAL; /* not found in any level; must be global */
+ return -1;
}
-static int aux_localname (FuncState *fs, TaggedString *n) {
- int i;
- for (i=fs->nlocalvar-1; i >= 0; i--)
- if (n == fs->localvar[i]) return i; /* local var index */
- return -1; /* not found */
-}
-
-
-static void singlevar (LexState *ls, TaggedString *n, vardesc *var, int prev) {
- FuncState *fs = prev ? ls->fs->prev : ls->fs;
- int i = aux_localname(fs, n);
- if (i >= 0) { /* local value? */
- var->k = VLOCAL;
- var->info = i;
- }
- else {
- FuncState *level = fs;
- while ((level = level->prev) != NULL) /* check shadowing */
- if (aux_localname(level, n) >= 0)
- luaX_syntaxerror(ls, "cannot access a variable in outer scope", n->str);
- var->k = VGLOBAL;
- var->info = string_constant(fs, n);
- }
+static void singlevar (LexState *ls, TString *n, expdesc *var) {
+ int level = search_local(ls, n, var);
+ if (level >= 1) /* neither local (0) nor global (-1)? */
+ luaX_syntaxerror(ls, "cannot access a variable in outer scope", n->str);
+ else if (level == -1) /* global? */
+ var->u.index = string_constant(ls->fs, n);
}
-static int indexupvalue (LexState *ls, TaggedString *n) {
+static int indexupvalue (LexState *ls, expdesc *v) {
FuncState *fs = ls->fs;
- vardesc v;
int i;
- singlevar(ls, n, &v, 1);
for (i=0; i<fs->nupvalues; i++) {
- if (fs->upvalues[i].k == v.k && fs->upvalues[i].info == v.info)
+ if (fs->upvalues[i].k == v->k && fs->upvalues[i].u.index == v->u.index)
return i;
}
/* new one */
- ++(fs->nupvalues);
- checklimit(ls, fs->nupvalues, MAXUPVALUES, "upvalues");
- fs->upvalues[i] = v; /* i = fs->nupvalues - 1 */
- return i;
-}
-
-
-static void pushupvalue (LexState *ls, TaggedString *n) {
- if (ls->fs->prev == NULL)
- luaX_syntaxerror(ls, "cannot access upvalue in main", n->str);
- if (aux_localname(ls->fs, n) >= 0)
- luaX_syntaxerror(ls, "cannot access an upvalue in current scope", n->str);
- code_oparg(ls, PUSHUPVALUE, indexupvalue(ls, n), 1);
-}
-
-
-
-static void check_debugline (LexState *ls) {
- if (L->debug && ls->linenumber != ls->fs->lastsetline) {
- code_oparg(ls, SETLINE, ls->linenumber, 0);
- ls->fs->lastsetline = ls->linenumber;
- }
-}
-
-
-static void adjuststack (LexState *ls, int n) {
- if (n > 0)
- code_oparg(ls, POP, n, -n);
- else if (n < 0)
- code_oparg(ls, PUSHNIL, (-n)-1, -n);
+ luaX_checklimit(ls, fs->nupvalues+1, MAXUPVALUES, "upvalues");
+ fs->upvalues[fs->nupvalues] = *v;
+ return fs->nupvalues++;
}
-static void close_exp (LexState *ls, int pc, int nresults) {
- if (pc > 0) { /* expression is an open function call? */
- Byte *code = ls->fs->f->code;
- code[pc-1] = (Byte)nresults; /* set nresults */
- /* push results, pop params (at code[pc]) and function */
- deltastack(ls, nresults-(code[pc]+1));
+static void pushupvalue (LexState *ls, TString *n) {
+ FuncState *fs = ls->fs;
+ expdesc v;
+ int level = search_local(ls, n, &v);
+ if (level == -1) { /* global? */
+ if (fs->prev == NULL)
+ luaX_syntaxerror(ls, "cannot access upvalue in main", n->str);
+ v.u.index = string_constant(fs->prev, n);
}
-#ifdef DEBUG
- code_oparg(ls, CHECKSTACK, ls->fs->stacksize, 0);
-#endif
+ else if (level != 1)
+ luaX_syntaxerror(ls,
+ "upvalue must be global or local to immediately outer scope", n->str);
+ luaK_code1(fs, OP_PUSHUPVALUE, indexupvalue(ls, &v));
}
-static void adjust_mult_assign (LexState *ls, int nvars, listdesc *d) {
- int diff = d->n - nvars;
- if (d->pc == 0) { /* list is closed */
- /* push or pop eventual difference between list lengths */
- adjuststack(ls, diff);
- }
- else { /* must correct function call */
+static void adjust_mult_assign (LexState *ls, int nvars, int nexps) {
+ FuncState *fs = ls->fs;
+ int diff = nexps - nvars;
+ if (nexps > 0 && luaK_lastisopen(fs)) { /* list ends in a function call */
diff--; /* do not count function call itself */
if (diff <= 0) { /* more variables than values? */
- /* function call must provide extra values */
- close_exp(ls, d->pc, -diff);
- }
- else { /* more values than variables */
- close_exp(ls, d->pc, 0); /* call should provide no value */
- adjuststack(ls, diff); /* pop eventual extra values */
+ luaK_setcallreturns(fs, -diff); /* function call provide extra values */
+ diff = 0; /* no more difference */
}
+ else /* more values than variables */
+ luaK_setcallreturns(fs, 0); /* call should provide no value */
}
+ /* push or pop eventual difference between list lengths */
+ luaK_adjuststack(fs, diff);
}
-static void code_args (LexState *ls, int nparams, int dots) {
+static void code_params (LexState *ls, int nparams, int dots) {
FuncState *fs = ls->fs;
- fs->nlocalvar += nparams; /* "self" may already be there */
- checklimit(ls, fs->nlocalvar, MAXPARAMS, "parameters");
- nparams = fs->nlocalvar;
- if (!dots) {
- fs->f->code[1] = (Byte)nparams; /* fill-in arg information */
- deltastack(ls, nparams);
- }
- else {
- fs->f->code[1] = (Byte)(nparams+ZEROVARARG);
- deltastack(ls, nparams+1);
- add_localvar(ls, luaS_new("arg"));
+ adjustlocalvars(ls, nparams);
+ luaX_checklimit(ls, fs->nactloc, MAXPARAMS, "parameters");
+ fs->f->numparams = fs->nactloc; /* `self' could be there already */
+ fs->f->is_vararg = dots;
+ if (dots) {
+ new_localvarstr(ls, "arg", 0);
+ adjustlocalvars(ls, 1);
}
+ luaK_deltastack(fs, fs->nactloc); /* count parameters in the stack */
}
-static void unloaddot (LexState *ls, vardesc *v) {
- /* dotted variables <a.x> must be stored like regular indexed vars <a["x"]> */
- if (v->k == VDOT) {
- code_constant(ls, v->info);
- v->k = VINDEXED;
- }
+static void enterbreak (FuncState *fs, Breaklabel *bl) {
+ bl->stacklevel = fs->stacklevel;
+ bl->breaklist = NO_JUMP;
+ bl->previous = fs->bl;
+ fs->bl = bl;
}
-static void lua_pushvar (LexState *ls, vardesc *var) {
- switch (var->k) {
- case VLOCAL:
- code_oparg(ls, PUSHLOCAL, var->info, 1);
- break;
- case VGLOBAL:
- code_oparg(ls, GETGLOBAL, var->info, 1);
- break;
- case VDOT:
- code_oparg(ls, GETDOTTED, var->info, 0);
- break;
- case VINDEXED:
- code_opcode(ls, GETTABLE, -1);
- break;
- case VEXP:
- close_exp(ls, var->info, 1); /* function must return 1 value */
- break;
- }
- var->k = VEXP;
- var->info = 0; /* now this is a closed expression */
-}
-
-
-static void storevar (LexState *ls, vardesc *var) {
- switch (var->k) {
- case VLOCAL:
- code_oparg(ls, SETLOCAL, var->info, -1);
- break;
- case VGLOBAL:
- code_oparg(ls, SETGLOBAL, var->info, -1);
- break;
- case VINDEXED:
- code_opcode(ls, SETTABLEPOP, -3);
- break;
- default:
- LUA_INTERNALERROR("invalid var kind to store");
- }
-}
-
-
-static int fix_jump (LexState *ls, int pc, OpCode op, int n) {
- /* jump is relative to position following jump instruction */
- return fix_opcode(ls, pc, op, n-(pc+JMPSIZE));
-}
-
-
-static void fix_upjmp (LexState *ls, OpCode op, int pos) {
- int delta = ls->fs->pc+JMPSIZE - pos; /* jump is relative */
- code_oparg(ls, op, delta+(codesize(delta)-2), 0);
+static void leavebreak (FuncState *fs, Breaklabel *bl) {
+ fs->bl = bl->previous;
+ LUA_ASSERT(bl->stacklevel == fs->stacklevel, "wrong levels");
+ luaK_patchlist(fs, bl->breaklist, luaK_getlabel(fs));
}
-static void codeIf (LexState *ls, int thenAdd, int elseAdd) {
- FuncState *fs = ls->fs;
- int elseinit = elseAdd+JMPSIZE;
- if (fs->pc == elseinit) { /* no else part? */
- fs->pc -= JMPSIZE;
- elseinit = fs->pc;
- }
- else
- elseinit += fix_jump(ls, elseAdd, JMP, fs->pc);
- fix_jump(ls, thenAdd, IFFJMP, elseinit);
-}
-
-
-static void func_onstack (LexState *ls, FuncState *func) {
+static void pushclosure (LexState *ls, FuncState *func) {
FuncState *fs = ls->fs;
+ Proto *f = fs->f;
int i;
- int c = next_constant(fs);
- ttype(&fs->f->consts[c]) = LUA_T_PROTO;
- fs->f->consts[c].value.tf = func->f;
- if (func->nupvalues == 0)
- code_constant(ls, c);
- else {
- for (i=0; i<func->nupvalues; i++)
- lua_pushvar(ls, &func->upvalues[i]);
- deltastack(ls, 1); /* CLOSURE puts one extra element (before poping) */
- code_oparg(ls, CLOSURE, c, -func->nupvalues);
- code_byte(fs, (Byte)func->nupvalues);
- }
+ for (i=0; i<func->nupvalues; i++)
+ luaK_tostack(ls, &func->upvalues[i], 1);
+ luaM_growvector(ls->L, f->kproto, f->nkproto, 1, Proto *,
+ "constant table overflow", MAXARG_A);
+ f->kproto[f->nkproto++] = func->f;
+ luaK_code2(fs, OP_CLOSURE, f->nkproto-1, func->nupvalues);
}
-static void init_state (LexState *ls, FuncState *fs, TaggedString *source) {
- TProtoFunc *f = luaF_newproto();
+static void open_func (LexState *ls, FuncState *fs) {
+ Proto *f = luaF_newproto(ls->L);
fs->prev = ls->fs; /* linked list of funcstates */
+ fs->ls = ls;
+ fs->L = ls->L;
ls->fs = fs;
- fs->stacksize = 0;
- fs->maxstacksize = 0;
- fs->nlocalvar = 0;
+ fs->stacklevel = 0;
+ fs->nactloc = 0;
fs->nupvalues = 0;
- fs->lastsetline = 0;
+ fs->bl = NULL;
fs->f = f;
- f->source = source;
+ f->source = ls->source;
fs->pc = 0;
+ fs->lasttarget = 0;
+ fs->lastline = 0;
+ fs->jlt = NO_JUMP;
f->code = NULL;
- fs->nvars = (L->debug) ? 0 : -1; /* flag no debug information? */
- code_byte(fs, 0); /* to be filled with maxstacksize */
- code_byte(fs, 0); /* to be filled with arg information */
- /* push function (to avoid GC) */
- tfvalue(L->stack.top) = f; ttype(L->stack.top) = LUA_T_PROTO;
- incr_top;
+ f->maxstacksize = 0;
+ f->numparams = 0; /* default for main chunk */
+ f->is_vararg = 0; /* default for main chunk */
}
static void close_func (LexState *ls) {
+ lua_State *L = ls->L;
FuncState *fs = ls->fs;
- TProtoFunc *f = fs->f;
- code_opcode(ls, ENDCODE, 0);
- f->code[0] = (Byte)fs->maxstacksize;
- luaM_reallocvector(f->code, fs->pc, Byte);
- luaM_reallocvector(f->consts, f->nconsts, TObject);
- if (fs->nvars != -1) { /* debug information? */
- luaI_registerlocalvar(fs, NULL, -1); /* flag end of vector */
- luaM_reallocvector(f->locvars, fs->nvars, LocVar);
- }
+ Proto *f = fs->f;
+ luaK_code0(fs, OP_END);
+ luaK_getlabel(fs); /* close eventual list of pending jumps */
+ luaM_reallocvector(L, f->code, fs->pc, Instruction);
+ luaM_reallocvector(L, f->kstr, f->nkstr, TString *);
+ luaM_reallocvector(L, f->knum, f->nknum, Number);
+ luaM_reallocvector(L, f->kproto, f->nkproto, Proto *);
+ removelocalvars(ls, fs->nactloc);
+ luaM_reallocvector(L, f->locvars, f->nlocvars, LocVar);
+ luaM_reallocvector(L, f->lineinfo, f->nlineinfo+1, int);
+ f->lineinfo[f->nlineinfo++] = MAX_INT; /* end flag */
+ luaF_protook(L, f, fs->pc); /* proto is ok now */
ls->fs = fs->prev;
- L->stack.top--; /* pop function */
+ LUA_ASSERT(fs->bl == NULL, "wrong list end");
}
-
-static int expfollow [] = {ELSE, ELSEIF, THEN, IF, WHILE, REPEAT, DO, NAME,
- LOCAL, FUNCTION, END, UNTIL, RETURN, ')', ']', '}', ';', EOS, ',', 0};
-
-
-static int is_in (int tok, int *toks) {
- int *t;
- for (t=toks; *t; t++)
- if (*t == tok) return t-toks;
- return -1;
-}
-
-
-static void next (LexState *ls) {
- ls->token = luaX_lex(ls);
-}
-
-
-static void error_expected (LexState *ls, int token) {
- char buff[100], t[TOKEN_LEN];
- luaX_token2str(token, t);
- sprintf(buff, "`%s' expected", t);
- luaX_error(ls, buff);
-}
-
-
-static void error_unexpected (LexState *ls) {
- luaX_error(ls, "unexpected token");
-}
-
-
-static void error_unmatched (LexState *ls, int what, int who, int where) {
- if (where == ls->linenumber)
- error_expected(ls, what);
- else {
- char buff[100];
- char t_what[TOKEN_LEN], t_who[TOKEN_LEN];
- luaX_token2str(what, t_what);
- luaX_token2str(who, t_who);
- sprintf(buff, "`%s' expected (to close `%s' at line %d)",
- t_what, t_who, where);
- luaX_error(ls, buff);
- }
-}
-
-static void check (LexState *ls, int c) {
- if (ls->token != c)
- error_expected(ls, c);
- next(ls);
-}
-
-static void check_match (LexState *ls, int what, int who, int where) {
- if (ls->token != what)
- error_unmatched(ls, what, who, where);
- check_debugline(ls); /* to 'mark' the 'what' */
- next(ls);
-}
-
-static int checkname (LexState *ls) {
- int sc;
- if (ls->token != NAME)
- luaX_error(ls, "`NAME' expected");
- sc = string_constant(ls->fs, ls->seminfo.ts);
- next(ls);
- return sc;
-}
-
-
-static TaggedString *str_checkname (LexState *ls) {
- int i = checkname(ls); /* this call may realloc `f->consts' */
- return tsvalue(&ls->fs->f->consts[i]);
-}
-
-
-static int optional (LexState *ls, int c) {
- if (ls->token == c) {
- next(ls);
- return 1;
- }
- else return 0;
-}
-
-
-TProtoFunc *luaY_parser (ZIO *z) {
+Proto *luaY_parser (lua_State *L, ZIO *z) {
struct LexState lexstate;
struct FuncState funcstate;
- luaX_setinput(&lexstate, z);
- init_state(&lexstate, &funcstate, luaS_new(zname(z)));
+ luaX_setinput(L, &lexstate, z, luaS_new(L, zname(z)));
+ open_func(&lexstate, &funcstate);
next(&lexstate); /* read first token */
chunk(&lexstate);
- if (lexstate.token != EOS)
- luaX_error(&lexstate, "<eof> expected");
+ check_condition(&lexstate, (lexstate.t.token == TK_EOS), "<eof> expected");
close_func(&lexstate);
+ LUA_ASSERT(funcstate.prev == NULL, "wrong list end");
+ LUA_ASSERT(funcstate.nupvalues == 0, "no upvalues in main");
return funcstate.f;
}
/*============================================================*/
-/* GRAMAR RULES */
+/* GRAMMAR RULES */
/*============================================================*/
-static void chunk (LexState *ls) {
- /* chunk -> statlist ret */
- statlist(ls);
- ret(ls);
-}
-static void statlist (LexState *ls) {
- /* statlist -> { stat [;] } */
- while (stat(ls)) {
- LUA_ASSERT(ls->fs->stacksize == ls->fs->nlocalvar,
- "stack size != # local vars");
- optional(ls, ';');
+static int explist1 (LexState *ls) {
+ /* explist1 -> expr { ',' expr } */
+ int n = 1; /* at least one expression */
+ expdesc v;
+ expr(ls, &v);
+ while (ls->t.token == ',') {
+ luaK_tostack(ls, &v, 1); /* gets only 1 value from previous expression */
+ next(ls); /* skip comma */
+ expr(ls, &v);
+ n++;
}
+ luaK_tostack(ls, &v, 0); /* keep open number of values of last expression */
+ return n;
}
-static int stat (LexState *ls) {
- int line = ls->linenumber; /* may be needed for error messages */
- FuncState *fs = ls->fs;
- switch (ls->token) {
- case IF: /* stat -> IF ifpart END */
- ifpart(ls, line);
- return 1;
- case WHILE: { /* stat -> WHILE cond DO block END */
- TProtoFunc *f = fs->f;
- int while_init = fs->pc;
- int cond_end, cond_size;
+static void funcargs (LexState *ls, int slf) {
+ FuncState *fs = ls->fs;
+ int slevel = fs->stacklevel - slf - 1; /* where is func in the stack */
+ switch (ls->t.token) {
+ case '(': { /* funcargs -> '(' [ explist1 ] ')' */
+ int line = ls->linenumber;
+ int nargs = 0;
next(ls);
- cond_end = cond(ls);
- check(ls, DO);
- block(ls);
- check_match(ls, END, WHILE, line);
- cond_size = cond_end-while_init;
- check_pc(fs, cond_size);
- memcpy(f->code+fs->pc, f->code+while_init, cond_size);
- luaO_memdown(f->code+while_init, f->code+cond_end, fs->pc-while_init);
- while_init += JMPSIZE + fix_jump(ls, while_init, JMP, fs->pc-cond_size);
- fix_upjmp(ls, IFTUPJMP, while_init);
- return 1;
+ if (ls->t.token != ')') /* arg list not empty? */
+ nargs = explist1(ls);
+ check_match(ls, ')', '(', line);
+#ifdef LUA_COMPAT_ARGRET
+ if (nargs > 0) /* arg list is not empty? */
+ luaK_setcallreturns(fs, 1); /* last call returns only 1 value */
+#else
+ UNUSED(nargs); /* to avoid warnings */
+#endif
+ break;
}
-
- case DO: { /* stat -> DO block END */
- next(ls);
- block(ls);
- check_match(ls, END, DO, line);
- return 1;
+ case '{': { /* funcargs -> constructor */
+ constructor(ls);
+ break;
}
-
- case REPEAT: { /* stat -> REPEAT block UNTIL exp1 */
- int repeat_init = fs->pc;
+ case TK_STRING: { /* funcargs -> STRING */
+ code_string(ls, ls->t.seminfo.ts); /* must use `seminfo' before `next' */
next(ls);
- block(ls);
- check_match(ls, UNTIL, REPEAT, line);
- exp1(ls);
- fix_upjmp(ls, IFFUPJMP, repeat_init);
- deltastack(ls, -1); /* pops condition */
- return 1;
+ break;
}
-
- case FUNCTION: { /* stat -> FUNCTION funcname body */
- int needself;
- vardesc v;
- if (ls->fs->prev) /* inside other function? */
- return 0;
- check_debugline(ls);
- next(ls);
- needself = funcname(ls, &v);
- body(ls, needself, line);
- storevar(ls, &v);
- return 1;
+ default: {
+ luaK_error(ls, "function arguments expected");
+ break;
}
+ }
+ fs->stacklevel = slevel; /* call will remove function and arguments */
+ luaK_code2(fs, OP_CALL, slevel, MULT_RET);
+}
- case LOCAL: { /* stat -> LOCAL localnamelist decinit */
- listdesc d;
- int nvars;
- check_debugline(ls);
- next(ls);
- nvars = localnamelist(ls);
- decinit(ls, &d);
- fs->nlocalvar += nvars;
- correctvarlines(ls, nvars); /* vars will be alive only after decinit */
- adjust_mult_assign(ls, nvars, &d);
- return 1;
- }
- case NAME: case '%': { /* stat -> func | ['%'] NAME assignment */
- vardesc v;
- check_debugline(ls);
- var_or_func(ls, &v);
- if (v.k == VEXP) { /* stat -> func */
- if (v.info == 0) /* is just an upper value? */
- luaX_error(ls, "syntax error");
- close_exp(ls, v.info, 0);
+static void var_or_func_tail (LexState *ls, expdesc *v) {
+ for (;;) {
+ switch (ls->t.token) {
+ case '.': { /* var_or_func_tail -> '.' NAME */
+ next(ls);
+ luaK_tostack(ls, v, 1); /* `v' must be on stack */
+ luaK_kstr(ls, checkname(ls));
+ v->k = VINDEXED;
+ break;
+ }
+ case '[': { /* var_or_func_tail -> '[' exp1 ']' */
+ next(ls);
+ luaK_tostack(ls, v, 1); /* `v' must be on stack */
+ v->k = VINDEXED;
+ exp1(ls);
+ check(ls, ']');
+ break;
}
- else { /* stat -> ['%'] NAME assignment */
- int left = assignment(ls, &v, 1);
- adjuststack(ls, left); /* remove eventual 'garbage' left on stack */
+ case ':': { /* var_or_func_tail -> ':' NAME funcargs */
+ int name;
+ next(ls);
+ name = checkname(ls);
+ luaK_tostack(ls, v, 1); /* `v' must be on stack */
+ luaK_code1(ls->fs, OP_PUSHSELF, name);
+ funcargs(ls, 1);
+ v->k = VEXP;
+ v->u.l.t = v->u.l.f = NO_JUMP;
+ break;
}
- return 1;
+ case '(': case TK_STRING: case '{': { /* var_or_func_tail -> funcargs */
+ luaK_tostack(ls, v, 1); /* `v' must be on stack */
+ funcargs(ls, 0);
+ v->k = VEXP;
+ v->u.l.t = v->u.l.f = NO_JUMP;
+ break;
+ }
+ default: return; /* should be follow... */
}
+ }
+}
- case RETURN: case ';': case ELSE: case ELSEIF:
- case END: case UNTIL: case EOS: /* 'stat' follow */
- return 0;
- default:
- error_unexpected(ls);
- return 0; /* to avoid warnings */
+static void var_or_func (LexState *ls, expdesc *v) {
+ /* var_or_func -> ['%'] NAME var_or_func_tail */
+ if (optional(ls, '%')) { /* upvalue? */
+ pushupvalue(ls, str_checkname(ls));
+ v->k = VEXP;
+ v->u.l.t = v->u.l.f = NO_JUMP;
}
+ else /* variable name */
+ singlevar(ls, str_checkname(ls), v);
+ var_or_func_tail(ls, v);
}
-static int SaveWord (LexState *ls) {
- int res = ls->fs->pc;
- check_pc(ls->fs, JMPSIZE);
- ls->fs->pc += JMPSIZE; /* open space */
- return res;
-}
-static int SaveWordPop (LexState *ls) {
- deltastack(ls, -1); /* pop condition */
- return SaveWord(ls);
-}
-static int cond (LexState *ls) {
- /* cond -> exp1 */
+/*
+** {======================================================================
+** Rules for Constructors
+** =======================================================================
+*/
+
+
+static void recfield (LexState *ls) {
+ /* recfield -> (NAME | '['exp1']') = exp1 */
+ switch (ls->t.token) {
+ case TK_NAME: {
+ luaK_kstr(ls, checkname(ls));
+ break;
+ }
+ case '[': {
+ next(ls);
+ exp1(ls);
+ check(ls, ']');
+ break;
+ }
+ default: luaK_error(ls, "<name> or `[' expected");
+ }
+ check(ls, '=');
exp1(ls);
- return SaveWordPop(ls);
}
-static void block (LexState *ls) {
- /* block -> chunk */
- FuncState *fs = ls->fs;
- int nlocalvar = fs->nlocalvar;
- chunk(ls);
- adjuststack(ls, fs->nlocalvar - nlocalvar);
- for (; fs->nlocalvar > nlocalvar; fs->nlocalvar--)
- luaI_unregisterlocalvar(fs, fs->lastsetline);
-}
-static int funcname (LexState *ls, vardesc *v) {
- /* funcname -> NAME [':' NAME | '.' NAME] */
- int needself = 0;
- singlevar(ls, str_checkname(ls), v, 0);
- if (ls->token == ':' || ls->token == '.') {
- needself = (ls->token == ':');
+static int recfields (LexState *ls) {
+ /* recfields -> recfield { ',' recfield } [','] */
+ FuncState *fs = ls->fs;
+ int n = 1; /* at least one element */
+ recfield(ls);
+ while (ls->t.token == ',') {
next(ls);
- lua_pushvar(ls, v);
- code_constant(ls, checkname(ls));
- v->k = VINDEXED;
+ if (ls->t.token == ';' || ls->t.token == '}')
+ break;
+ recfield(ls);
+ n++;
+ if (n%RFIELDS_PER_FLUSH == 0)
+ luaK_code1(fs, OP_SETMAP, RFIELDS_PER_FLUSH);
}
- return needself;
-}
-
-static void body (LexState *ls, int needself, int line) {
- /* body -> '(' parlist ')' chunk END */
- FuncState newfs;
- init_state(ls, &newfs, ls->fs->f->source);
- newfs.f->lineDefined = line;
- check(ls, '(');
- if (needself)
- add_localvar(ls, luaS_new("self"));
- parlist(ls);
- check(ls, ')');
- chunk(ls);
- check_match(ls, END, FUNCTION, line);
- close_func(ls);
- func_onstack(ls, &newfs);
+ luaK_code1(fs, OP_SETMAP, n%RFIELDS_PER_FLUSH);
+ return n;
}
-static void ifpart (LexState *ls, int line) {
- /* ifpart -> cond THEN block [ELSE block | ELSEIF ifpart] */
- int c;
- int e;
- next(ls); /* skip IF or ELSEIF */
- c = cond(ls);
- check(ls, THEN);
- block(ls);
- e = SaveWord(ls);
- if (ls->token == ELSEIF)
- ifpart(ls, line);
- else {
- if (optional(ls, ELSE))
- block(ls);
- check_match(ls, END, IF, line);
+static int listfields (LexState *ls) {
+ /* listfields -> exp1 { ',' exp1 } [','] */
+ FuncState *fs = ls->fs;
+ int n = 1; /* at least one element */
+ exp1(ls);
+ while (ls->t.token == ',') {
+ next(ls);
+ if (ls->t.token == ';' || ls->t.token == '}')
+ break;
+ exp1(ls);
+ n++;
+ luaX_checklimit(ls, n/LFIELDS_PER_FLUSH, MAXARG_A,
+ "`item groups' in a list initializer");
+ if (n%LFIELDS_PER_FLUSH == 0)
+ luaK_code2(fs, OP_SETLIST, n/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH);
}
- codeIf(ls, c, e);
+ luaK_code2(fs, OP_SETLIST, n/LFIELDS_PER_FLUSH, n%LFIELDS_PER_FLUSH);
+ return n;
}
-static void ret (LexState *ls) {
- /* ret -> [RETURN explist sc] */
- if (optional(ls, RETURN)) {
- listdesc e;
- check_debugline(ls);
- explist(ls, &e);
- if (e.pc > 0) { /* expression is an open function call? */
- Byte *code = ls->fs->f->code;
- code[e.pc-2] = TAILCALL; /* instead of a conventional CALL */
- code[e.pc-1] = (Byte)ls->fs->nlocalvar;
+
+static void constructor_part (LexState *ls, Constdesc *cd) {
+ switch (ls->t.token) {
+ case ';': case '}': { /* constructor_part -> empty */
+ cd->n = 0;
+ cd->k = ls->t.token;
+ break;
+ }
+ case TK_NAME: { /* may be listfields or recfields */
+ lookahead(ls);
+ if (ls->lookahead.token != '=') /* expression? */
+ goto case_default;
+ /* else go through to recfields */
+ }
+ case '[': { /* constructor_part -> recfields */
+ cd->n = recfields(ls);
+ cd->k = 1; /* record */
+ break;
+ }
+ default: { /* constructor_part -> listfields */
+ case_default:
+ cd->n = listfields(ls);
+ cd->k = 0; /* list */
+ break;
}
- else
- code_oparg(ls, RETCODE, ls->fs->nlocalvar, 0);
- ls->fs->stacksize = ls->fs->nlocalvar; /* removes all temp values */
- optional(ls, ';');
}
}
-/*
-** For parsing expressions, we use a classic stack with priorities.
-** Each binary operator is represented by its index in "binop" + FIRSTBIN
-** (EQ=2, NE=3, ... '^'=13). The unary NOT is 0 and UNMINUS is 1.
-*/
-
-#define INDNOT 0
-#define INDMINUS 1
-
-/* code of first binary operator */
-#define FIRSTBIN 2
-
-/* code for power operator (last operator)
-** '^' needs special treatment because it is right associative
-*/
-#define POW 13
-
-static int binop [] = {EQ, NE, '>', '<', LE, GE, CONC,
- '+', '-', '*', '/', '^', 0};
-
-static int priority [POW+1] = {5, 5, 1, 1, 1, 1, 1, 1, 2, 3, 3, 4, 4, 6};
-
-static OpCode opcodes [POW+1] = {NOTOP, MINUSOP, EQOP, NEQOP, GTOP, LTOP,
- LEOP, GEOP, CONCOP, ADDOP, SUBOP, MULTOP, DIVOP, POWOP};
-
-#define MAXOPS 20 /* op's stack size (arbitrary limit) */
-
-typedef struct stack_op {
- int ops[MAXOPS];
- int top;
-} stack_op;
-
-
-static void exp1 (LexState *ls) {
- vardesc v;
- exp0(ls, &v);
- lua_pushvar(ls, &v);
- if (is_in(ls->token, expfollow) < 0)
- luaX_error(ls, "ill-formed expression");
+static void constructor (LexState *ls) {
+ /* constructor -> '{' constructor_part [';' constructor_part] '}' */
+ FuncState *fs = ls->fs;
+ int line = ls->linenumber;
+ int pc = luaK_code1(fs, OP_CREATETABLE, 0);
+ int nelems;
+ Constdesc cd;
+ check(ls, '{');
+ constructor_part(ls, &cd);
+ nelems = cd.n;
+ if (optional(ls, ';')) {
+ Constdesc other_cd;
+ constructor_part(ls, &other_cd);
+ check_condition(ls, (cd.k != other_cd.k), "invalid constructor syntax");
+ nelems += other_cd.n;
+ }
+ check_match(ls, '}', '{', line);
+ luaX_checklimit(ls, nelems, MAXARG_U, "elements in a table constructor");
+ SETARG_U(fs->f->code[pc], nelems); /* set initial table size */
}
+/* }====================================================================== */
-static void exp0 (LexState *ls, vardesc *v) {
- /* exp0 -> exp2 {(AND | OR) exp2} */
- exp2(ls, v);
- while (ls->token == AND || ls->token == OR) {
- int op = (ls->token == AND) ? ONFJMP : ONTJMP;
- int pc;
- lua_pushvar(ls, v);
- next(ls);
- pc = SaveWordPop(ls);
- exp2(ls, v);
- lua_pushvar(ls, v);
- fix_jump(ls, pc, op, ls->fs->pc);
- }
-}
-static void push (LexState *ls, stack_op *s, int op) {
- if (s->top >= MAXOPS)
- luaX_error(ls, "expression too complex");
- s->ops[s->top++] = op;
-}
+/*
+** {======================================================================
+** Expression parsing
+** =======================================================================
+*/
-static void pop_to (LexState *ls, stack_op *s, int prio) {
- int op;
- while (s->top > 0 && priority[(op=s->ops[s->top-1])] >= prio) {
- code_opcode(ls, opcodes[op], op<FIRSTBIN?0:-1);
- s->top--;
- }
-}
-static void simpleexp (LexState *ls, vardesc *v, stack_op *s) {
- check_debugline(ls);
- switch (ls->token) {
- case NUMBER: { /* simpleexp -> NUMBER */
- real r = ls->seminfo.r;
+static void simpleexp (LexState *ls, expdesc *v) {
+ FuncState *fs = ls->fs;
+ switch (ls->t.token) {
+ case TK_NUMBER: { /* simpleexp -> NUMBER */
+ Number r = ls->t.seminfo.r;
next(ls);
- /* dirty trick: check whether it is a -NUMBER not followed by '^' */
- /* (because the priority of '^' is closer than '-'...) */
- if (s->top > 0 && s->ops[s->top-1] == INDMINUS && ls->token != '^') {
- s->top--; /* remove '-' from stack */
- r = -r;
- }
- code_number(ls, r);
+ luaK_number(fs, r);
break;
}
-
- case STRING: /* simpleexp -> STRING */
- code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before "next" */
+ case TK_STRING: { /* simpleexp -> STRING */
+ code_string(ls, ls->t.seminfo.ts); /* must use `seminfo' before `next' */
next(ls);
break;
-
- case NIL: /* simpleexp -> NIL */
- adjuststack(ls, -1);
+ }
+ case TK_NIL: { /* simpleexp -> NIL */
+ luaK_adjuststack(fs, -1);
next(ls);
break;
-
- case '{': /* simpleexp -> constructor */
+ }
+ case '{': { /* simpleexp -> constructor */
constructor(ls);
break;
-
- case FUNCTION: /* simpleexp -> FUNCTION body */
+ }
+ case TK_FUNCTION: { /* simpleexp -> FUNCTION body */
next(ls);
body(ls, 0, ls->linenumber);
break;
-
- case '(': /* simpleexp -> '(' exp0 ')' */
+ }
+ case '(': { /* simpleexp -> '(' expr ')' */
next(ls);
- exp0(ls, v);
+ expr(ls, v);
check(ls, ')');
return;
-
- case NAME: case '%':
+ }
+ case TK_NAME: case '%': {
var_or_func(ls, v);
return;
-
- default:
- luaX_error(ls, "<expression> expected");
+ }
+ default: {
+ luaK_error(ls, "<expression> expected");
return;
+ }
}
- v->k = VEXP; v->info = 0;
+ v->k = VEXP;
+ v->u.l.t = v->u.l.f = NO_JUMP;
}
-static void prefixexp (LexState *ls, vardesc *v, stack_op *s) {
- /* prefixexp -> {NOT | '-'} simpleexp */
- while (ls->token == NOT || ls->token == '-') {
- push(ls, s, (ls->token==NOT)?INDNOT:INDMINUS);
- next(ls);
- }
- simpleexp(ls, v, s);
+static void exp1 (LexState *ls) {
+ expdesc v;
+ expr(ls, &v);
+ luaK_tostack(ls, &v, 1);
}
-static void exp2 (LexState *ls, vardesc *v) {
- stack_op s;
- int op;
- s.top = 0;
- prefixexp(ls, v, &s);
- while ((op = is_in(ls->token, binop)) >= 0) {
- op += FIRSTBIN;
- lua_pushvar(ls, v);
- /* '^' is right associative, so must 'simulate' a higher priority */
- pop_to(ls, &s, (op == POW)?priority[op]+1:priority[op]);
- push(ls, &s, op);
- next(ls);
- prefixexp(ls, v, &s);
- lua_pushvar(ls, v);
- }
- if (s.top > 0) {
- lua_pushvar(ls, v);
- pop_to(ls, &s, 0);
+static UnOpr getunopr (int op) {
+ switch (op) {
+ case TK_NOT: return OPR_NOT;
+ case '-': return OPR_MINUS;
+ default: return OPR_NOUNOPR;
}
}
-static void var_or_func (LexState *ls, vardesc *v) {
- /* var_or_func -> ['%'] NAME var_or_func_tail */
- if (optional(ls, '%')) { /* upvalue? */
- pushupvalue(ls, str_checkname(ls));
- v->k = VEXP;
- v->info = 0; /* closed expression */
+static BinOpr getbinopr (int op) {
+ switch (op) {
+ case '+': return OPR_ADD;
+ case '-': return OPR_SUB;
+ case '*': return OPR_MULT;
+ case '/': return OPR_DIV;
+ case '^': return OPR_POW;
+ case TK_CONCAT: return OPR_CONCAT;
+ case TK_NE: return OPR_NE;
+ case TK_EQ: return OPR_EQ;
+ case '<': return OPR_LT;
+ case TK_LE: return OPR_LE;
+ case '>': return OPR_GT;
+ case TK_GE: return OPR_GE;
+ case TK_AND: return OPR_AND;
+ case TK_OR: return OPR_OR;
+ default: return OPR_NOBINOPR;
}
- else /* variable name */
- singlevar(ls, str_checkname(ls), v, 0);
- var_or_func_tail(ls, v);
}
-static void var_or_func_tail (LexState *ls, vardesc *v) {
- for (;;) {
- switch (ls->token) {
- case '.': /* var_or_func_tail -> '.' NAME */
- next(ls);
- lua_pushvar(ls, v); /* 'v' must be on stack */
- v->k = VDOT;
- v->info = checkname(ls);
- break;
+static const struct {
+ char left; /* left priority for each binary operator */
+ char right; /* right priority */
+} priority[] = { /* ORDER OPR */
+ {5, 5}, {5, 5}, {6, 6}, {6, 6}, /* arithmetic */
+ {9, 8}, {4, 3}, /* power and concat (right associative) */
+ {2, 2}, {2, 2}, /* equality */
+ {2, 2}, {2, 2}, {2, 2}, {2, 2}, /* order */
+ {1, 1}, {1, 1} /* logical */
+};
- case '[': /* var_or_func_tail -> '[' exp1 ']' */
- next(ls);
- lua_pushvar(ls, v); /* 'v' must be on stack */
- exp1(ls);
- check(ls, ']');
- v->k = VINDEXED;
- break;
+#define UNARY_PRIORITY 7 /* priority for unary operators */
- case ':': /* var_or_func_tail -> ':' NAME funcparams */
- next(ls);
- lua_pushvar(ls, v); /* 'v' must be on stack */
- code_oparg(ls, PUSHSELF, checkname(ls), 1);
- v->k = VEXP;
- v->info = funcparams(ls, 1);
- break;
-
- case '(': case STRING: case '{': /* var_or_func_tail -> funcparams */
- lua_pushvar(ls, v); /* 'v' must be on stack */
- v->k = VEXP;
- v->info = funcparams(ls, 0);
- break;
- default: return; /* should be follow... */
- }
+/*
+** subexpr -> (simplexep | unop subexpr) { binop subexpr }
+** where `binop' is any binary operator with a priority higher than `limit'
+*/
+static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
+ BinOpr op;
+ UnOpr uop = getunopr(ls->t.token);
+ if (uop != OPR_NOUNOPR) {
+ next(ls);
+ subexpr(ls, v, UNARY_PRIORITY);
+ luaK_prefix(ls, uop, v);
+ }
+ else simpleexp(ls, v);
+ /* expand while operators have priorities higher than `limit' */
+ op = getbinopr(ls->t.token);
+ while (op != OPR_NOBINOPR && priority[op].left > limit) {
+ expdesc v2;
+ BinOpr nextop;
+ next(ls);
+ luaK_infix(ls, op, v);
+ /* read sub-expression with higher priority */
+ nextop = subexpr(ls, &v2, priority[op].right);
+ luaK_posfix(ls, op, v, &v2);
+ op = nextop;
}
+ return op; /* return first untreated operator */
}
-static int funcparams (LexState *ls, int slf) {
- FuncState *fs = ls->fs;
- int nparams = 1; /* in cases STRING and constructor */
- switch (ls->token) {
- case '(': { /* funcparams -> '(' explist ')' */
- int line = ls->linenumber;
- listdesc e;
- next(ls);
- explist(ls, &e);
- check_match(ls, ')', '(', line);
- close_exp(ls, e.pc, 1);
- nparams = e.n;
- break;
- }
- case '{': /* funcparams -> constructor */
- constructor(ls);
- break;
+static void expr (LexState *ls, expdesc *v) {
+ subexpr(ls, v, -1);
+}
- case STRING: /* funcparams -> STRING */
- code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before "next" */
- next(ls);
- break;
+/* }==================================================================== */
- default:
- luaX_error(ls, "function arguments expected");
- break;
- }
- code_byte(fs, CALL);
- code_byte(fs, 0); /* save space for nresult */
- code_byte(fs, (Byte)(nparams+slf));
- return fs->pc-1;
-}
-
-static void explist (LexState *ls, listdesc *d) {
- switch (ls->token) {
- case ELSE: case ELSEIF: case END: case UNTIL:
- case EOS: case ';': case ')':
- d->pc = 0;
- d->n = 0;
- break;
- default:
- explist1(ls, d);
+/*
+** {======================================================================
+** Rules for Statements
+** =======================================================================
+*/
+
+
+static int block_follow (int token) {
+ switch (token) {
+ case TK_ELSE: case TK_ELSEIF: case TK_END:
+ case TK_UNTIL: case TK_EOS:
+ return 1;
+ default: return 0;
}
}
-static void explist1 (LexState *ls, listdesc *d) {
- vardesc v;
- exp0(ls, &v);
- d->n = 1;
- while (ls->token == ',') {
- d->n++;
- lua_pushvar(ls, &v);
+
+static void block (LexState *ls) {
+ /* block -> chunk */
+ FuncState *fs = ls->fs;
+ int nactloc = fs->nactloc;
+ chunk(ls);
+ luaK_adjuststack(fs, fs->nactloc - nactloc); /* remove local variables */
+ removelocalvars(ls, fs->nactloc - nactloc);
+}
+
+
+static int assignment (LexState *ls, expdesc *v, int nvars) {
+ int left = 0; /* number of values left in the stack after assignment */
+ luaX_checklimit(ls, nvars, MAXVARSLH, "variables in a multiple assignment");
+ if (ls->t.token == ',') { /* assignment -> ',' NAME assignment */
+ expdesc nv;
next(ls);
- exp0(ls, &v);
+ var_or_func(ls, &nv);
+ check_condition(ls, (nv.k != VEXP), "syntax error");
+ left = assignment(ls, &nv, nvars+1);
+ }
+ else { /* assignment -> '=' explist1 */
+ int nexps;
+ check(ls, '=');
+ nexps = explist1(ls);
+ adjust_mult_assign(ls, nvars, nexps);
}
- if (v.k == VEXP)
- d->pc = v.info;
- else {
- lua_pushvar(ls, &v);
- d->pc = 0;
+ if (v->k != VINDEXED)
+ luaK_storevar(ls, v);
+ else { /* there may be garbage between table-index and value */
+ luaK_code2(ls->fs, OP_SETTABLE, left+nvars+2, 1);
+ left += 2;
}
+ return left;
}
-static void parlist (LexState *ls) {
- int nparams = 0;
- int dots = 0;
- switch (ls->token) {
- case DOTS: /* parlist -> DOTS */
- next(ls);
- dots = 1;
- break;
- case NAME: /* parlist, tailparlist -> NAME [',' tailparlist] */
- init:
- store_localvar(ls, str_checkname(ls), nparams++);
- if (ls->token == ',') {
- next(ls);
- switch (ls->token) {
- case DOTS: /* tailparlist -> DOTS */
- next(ls);
- dots = 1;
- break;
+static void cond (LexState *ls, expdesc *v) {
+ /* cond -> exp */
+ expr(ls, v); /* read condition */
+ luaK_goiftrue(ls->fs, v, 0);
+}
- case NAME: /* tailparlist -> NAME [',' tailparlist] */
- goto init;
- default: luaX_error(ls, "NAME or `...' expected");
- }
- }
- break;
+static void whilestat (LexState *ls, int line) {
+ /* whilestat -> WHILE cond DO block END */
+ FuncState *fs = ls->fs;
+ int while_init = luaK_getlabel(fs);
+ expdesc v;
+ Breaklabel bl;
+ enterbreak(fs, &bl);
+ next(ls);
+ cond(ls, &v);
+ check(ls, TK_DO);
+ block(ls);
+ luaK_patchlist(fs, luaK_jump(fs), while_init);
+ luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs));
+ check_match(ls, TK_END, TK_WHILE, line);
+ leavebreak(fs, &bl);
+}
- case ')': break; /* parlist -> empty */
- default: luaX_error(ls, "NAME or `...' expected");
- }
- code_args(ls, nparams, dots);
+static void repeatstat (LexState *ls, int line) {
+ /* repeatstat -> REPEAT block UNTIL cond */
+ FuncState *fs = ls->fs;
+ int repeat_init = luaK_getlabel(fs);
+ expdesc v;
+ Breaklabel bl;
+ enterbreak(fs, &bl);
+ next(ls);
+ block(ls);
+ check_match(ls, TK_UNTIL, TK_REPEAT, line);
+ cond(ls, &v);
+ luaK_patchlist(fs, v.u.l.f, repeat_init);
+ leavebreak(fs, &bl);
}
-static int localnamelist (LexState *ls) {
- /* localnamelist -> NAME {',' NAME} */
- int i = 1;
- store_localvar(ls, str_checkname(ls), 0);
- while (ls->token == ',') {
- next(ls);
- store_localvar(ls, str_checkname(ls), i++);
+
+static void forbody (LexState *ls, int nvar, OpCode prepfor, OpCode loopfor) {
+ /* forbody -> DO block END */
+ FuncState *fs = ls->fs;
+ int prep = luaK_code1(fs, prepfor, NO_JUMP);
+ int blockinit = luaK_getlabel(fs);
+ check(ls, TK_DO);
+ adjustlocalvars(ls, nvar); /* scope for control variables */
+ block(ls);
+ luaK_patchlist(fs, luaK_code1(fs, loopfor, NO_JUMP), blockinit);
+ luaK_patchlist(fs, prep, luaK_getlabel(fs));
+ removelocalvars(ls, nvar);
+}
+
+
+static void fornum (LexState *ls, TString *varname) {
+ /* fornum -> NAME = exp1,exp1[,exp1] forbody */
+ FuncState *fs = ls->fs;
+ check(ls, '=');
+ exp1(ls); /* initial value */
+ check(ls, ',');
+ exp1(ls); /* limit */
+ if (optional(ls, ','))
+ exp1(ls); /* optional step */
+ else
+ luaK_code1(fs, OP_PUSHINT, 1); /* default step */
+ new_localvar(ls, varname, 0);
+ new_localvarstr(ls, "(limit)", 1);
+ new_localvarstr(ls, "(step)", 2);
+ forbody(ls, 3, OP_FORPREP, OP_FORLOOP);
+}
+
+
+static void forlist (LexState *ls, TString *indexname) {
+ /* forlist -> NAME,NAME IN exp1 forbody */
+ TString *valname;
+ check(ls, ',');
+ valname = str_checkname(ls);
+ /* next test is dirty, but avoids `in' being a reserved word */
+ check_condition(ls,
+ (ls->t.token == TK_NAME && ls->t.seminfo.ts == luaS_new(ls->L, "in")),
+ "`in' expected");
+ next(ls); /* skip `in' */
+ exp1(ls); /* table */
+ new_localvarstr(ls, "(table)", 0);
+ new_localvar(ls, indexname, 1);
+ new_localvar(ls, valname, 2);
+ forbody(ls, 3, OP_LFORPREP, OP_LFORLOOP);
+}
+
+
+static void forstat (LexState *ls, int line) {
+ /* forstat -> fornum | forlist */
+ FuncState *fs = ls->fs;
+ TString *varname;
+ Breaklabel bl;
+ enterbreak(fs, &bl);
+ next(ls); /* skip `for' */
+ varname = str_checkname(ls); /* first variable name */
+ switch (ls->t.token) {
+ case '=': fornum(ls, varname); break;
+ case ',': forlist(ls, varname); break;
+ default: luaK_error(ls, "`=' or `,' expected");
}
- return i;
+ check_match(ls, TK_END, TK_FOR, line);
+ leavebreak(fs, &bl);
}
-static void decinit (LexState *ls, listdesc *d) {
- /* decinit -> ['=' explist1] */
- if (ls->token == '=') {
- next(ls);
- explist1(ls, d);
+
+static void test_then_block (LexState *ls, expdesc *v) {
+ /* test_then_block -> [IF | ELSEIF] cond THEN block */
+ next(ls); /* skip IF or ELSEIF */
+ cond(ls, v);
+ check(ls, TK_THEN);
+ block(ls); /* `then' part */
+}
+
+
+static void ifstat (LexState *ls, int line) {
+ /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */
+ FuncState *fs = ls->fs;
+ expdesc v;
+ int escapelist = NO_JUMP;
+ test_then_block(ls, &v); /* IF cond THEN block */
+ while (ls->t.token == TK_ELSEIF) {
+ luaK_concat(fs, &escapelist, luaK_jump(fs));
+ luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs));
+ test_then_block(ls, &v); /* ELSEIF cond THEN block */
}
- else {
- d->n = 0;
- d->pc = 0;
+ if (ls->t.token == TK_ELSE) {
+ luaK_concat(fs, &escapelist, luaK_jump(fs));
+ luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs));
+ next(ls); /* skip ELSE */
+ block(ls); /* `else' part */
}
+ else
+ luaK_concat(fs, &escapelist, v.u.l.f);
+ luaK_patchlist(fs, escapelist, luaK_getlabel(fs));
+ check_match(ls, TK_END, TK_IF, line);
+}
+
+
+static void localstat (LexState *ls) {
+ /* stat -> LOCAL NAME {',' NAME} ['=' explist1] */
+ int nvars = 0;
+ int nexps;
+ do {
+ next(ls); /* skip LOCAL or ',' */
+ new_localvar(ls, str_checkname(ls), nvars++);
+ } while (ls->t.token == ',');
+ if (optional(ls, '='))
+ nexps = explist1(ls);
+ else
+ nexps = 0;
+ adjust_mult_assign(ls, nvars, nexps);
+ adjustlocalvars(ls, nvars);
}
-static int assignment (LexState *ls, vardesc *v, int nvars) {
- int left = 0;
- checklimit(ls, nvars, MAXVARSLH, "variables in a multiple assignment");
- unloaddot(ls, v);
- if (ls->token == ',') { /* assignment -> ',' NAME assignment */
- vardesc nv;
+static int funcname (LexState *ls, expdesc *v) {
+ /* funcname -> NAME [':' NAME | '.' NAME] */
+ int needself = 0;
+ singlevar(ls, str_checkname(ls), v);
+ if (ls->t.token == ':' || ls->t.token == '.') {
+ needself = (ls->t.token == ':');
next(ls);
- var_or_func(ls, &nv);
- if (nv.k == VEXP)
- luaX_error(ls, "syntax error");
- left = assignment(ls, &nv, nvars+1);
- }
- else { /* assignment -> '=' explist1 */
- listdesc d;
- check(ls, '=');
- explist1(ls, &d);
- adjust_mult_assign(ls, nvars, &d);
+ luaK_tostack(ls, v, 1);
+ luaK_kstr(ls, checkname(ls));
+ v->k = VINDEXED;
}
- if (v->k != VINDEXED || left+(nvars-1) == 0) {
- /* global/local var or indexed var without values in between */
- storevar(ls, v);
+ return needself;
+}
+
+
+static void funcstat (LexState *ls, int line) {
+ /* funcstat -> FUNCTION funcname body */
+ int needself;
+ expdesc v;
+ next(ls); /* skip FUNCTION */
+ needself = funcname(ls, &v);
+ body(ls, needself, line);
+ luaK_storevar(ls, &v);
+}
+
+
+static void namestat (LexState *ls) {
+ /* stat -> func | ['%'] NAME assignment */
+ FuncState *fs = ls->fs;
+ expdesc v;
+ var_or_func(ls, &v);
+ if (v.k == VEXP) { /* stat -> func */
+ check_condition(ls, luaK_lastisopen(fs), "syntax error"); /* an upvalue? */
+ luaK_setcallreturns(fs, 0); /* call statement uses no results */
}
- else { /* indexed var with values in between*/
- code_oparg(ls, SETTABLE, left+(nvars-1), -1);
- left += 2; /* table&index are not popped, because they aren't on top */
+ else { /* stat -> ['%'] NAME assignment */
+ int left = assignment(ls, &v, 1);
+ luaK_adjuststack(fs, left); /* remove eventual garbage left on stack */
}
- return left;
}
-static void constructor (LexState *ls) {
- /* constructor -> '{' part [';' part] '}' */
- int line = ls->linenumber;
- int pc = SaveWord(ls);
- int nelems;
- constdesc cd;
- deltastack(ls, 1);
- check(ls, '{');
- part(ls, &cd);
- nelems = cd.n;
- if (ls->token == ';') {
- constdesc other_cd;
- next(ls);
- part(ls, &other_cd);
- if (cd.k == other_cd.k) /* repeated parts? */
- luaX_error(ls, "invalid constructor syntax");
- nelems += other_cd.n;
- }
- check_match(ls, '}', '{', line);
- fix_opcode(ls, pc, CREATEARRAY, nelems);
+static void retstat (LexState *ls) {
+ /* stat -> RETURN explist */
+ FuncState *fs = ls->fs;
+ next(ls); /* skip RETURN */
+ if (!block_follow(ls->t.token))
+ explist1(ls); /* optional return values */
+ luaK_code1(fs, OP_RETURN, ls->fs->nactloc);
+ fs->stacklevel = fs->nactloc; /* removes all temp values */
}
-static void part (LexState *ls, constdesc *cd) {
- switch (ls->token) {
- case ';': case '}': /* part -> empty */
- cd->n = 0;
- cd->k = ls->token;
- return;
- case NAME: {
- vardesc v;
- exp0(ls, &v);
- if (ls->token == '=') {
- switch (v.k) {
- case VGLOBAL:
- code_constant(ls, v.info);
- break;
- case VLOCAL:
- code_string(ls, ls->fs->localvar[v.info]);
- break;
- default:
- error_unexpected(ls);
- }
- next(ls);
- exp1(ls);
- cd->n = recfields(ls);
- cd->k = 1; /* record */
- }
- else {
- lua_pushvar(ls, &v);
- cd->n = listfields(ls);
- cd->k = 0; /* list */
- }
- break;
- }
+static void breakstat (LexState *ls) {
+ /* stat -> BREAK [NAME] */
+ FuncState *fs = ls->fs;
+ int currentlevel = fs->stacklevel;
+ Breaklabel *bl = fs->bl;
+ if (!bl)
+ luaK_error(ls, "no loop to break");
+ next(ls); /* skip BREAK */
+ luaK_adjuststack(fs, currentlevel - bl->stacklevel);
+ luaK_concat(fs, &bl->breaklist, luaK_jump(fs));
+ /* correct stack for compiler and symbolic execution */
+ luaK_adjuststack(fs, bl->stacklevel - currentlevel);
+}
- case '[': /* part -> recfield recfields */
- recfield(ls);
- cd->n = recfields(ls);
- cd->k = 1; /* record */
- break;
- default: /* part -> exp1 listfields */
- exp1(ls);
- cd->n = listfields(ls);
- cd->k = 0; /* list */
- break;
+static int stat (LexState *ls) {
+ int line = ls->linenumber; /* may be needed for error messages */
+ switch (ls->t.token) {
+ case TK_IF: { /* stat -> ifstat */
+ ifstat(ls, line);
+ return 0;
+ }
+ case TK_WHILE: { /* stat -> whilestat */
+ whilestat(ls, line);
+ return 0;
+ }
+ case TK_DO: { /* stat -> DO block END */
+ next(ls); /* skip DO */
+ block(ls);
+ check_match(ls, TK_END, TK_DO, line);
+ return 0;
+ }
+ case TK_FOR: { /* stat -> forstat */
+ forstat(ls, line);
+ return 0;
+ }
+ case TK_REPEAT: { /* stat -> repeatstat */
+ repeatstat(ls, line);
+ return 0;
+ }
+ case TK_FUNCTION: { /* stat -> funcstat */
+ funcstat(ls, line);
+ return 0;
+ }
+ case TK_LOCAL: { /* stat -> localstat */
+ localstat(ls);
+ return 0;
+ }
+ case TK_NAME: case '%': { /* stat -> namestat */
+ namestat(ls);
+ return 0;
+ }
+ case TK_RETURN: { /* stat -> retstat */
+ retstat(ls);
+ return 1; /* must be last statement */
+ }
+ case TK_BREAK: { /* stat -> breakstat */
+ breakstat(ls);
+ return 1; /* must be last statement */
+ }
+ default: {
+ luaK_error(ls, "<statement> expected");
+ return 0; /* to avoid warnings */
+ }
}
}
-static int recfields (LexState *ls) {
- /* recfields -> { ',' recfield } [','] */
- int n = 1; /* one has been read before */
- while (ls->token == ',') {
- next(ls);
- if (ls->token == ';' || ls->token == '}')
- break;
- recfield(ls);
- n++;
- if (n%RFIELDS_PER_FLUSH == 0)
- flush_record(ls, RFIELDS_PER_FLUSH);
+
+static void parlist (LexState *ls) {
+ /* parlist -> [ param { ',' param } ] */
+ int nparams = 0;
+ int dots = 0;
+ if (ls->t.token != ')') { /* is `parlist' not empty? */
+ do {
+ switch (ls->t.token) {
+ case TK_DOTS: next(ls); dots = 1; break;
+ case TK_NAME: new_localvar(ls, str_checkname(ls), nparams++); break;
+ default: luaK_error(ls, "<name> or `...' expected");
+ }
+ } while (!dots && optional(ls, ','));
}
- flush_record(ls, n%RFIELDS_PER_FLUSH);
- return n;
+ code_params(ls, nparams, dots);
}
-static int listfields (LexState *ls) {
- /* listfields -> { ',' exp1 } [','] */
- int n = 1; /* one has been read before */
- while (ls->token == ',') {
- next(ls);
- if (ls->token == ';' || ls->token == '}')
- break;
- exp1(ls);
- n++;
- if (n%LFIELDS_PER_FLUSH == 0)
- flush_list(ls, n/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH);
+
+static void body (LexState *ls, int needself, int line) {
+ /* body -> '(' parlist ')' chunk END */
+ FuncState new_fs;
+ open_func(ls, &new_fs);
+ new_fs.f->lineDefined = line;
+ check(ls, '(');
+ if (needself) {
+ new_localvarstr(ls, "self", 0);
+ adjustlocalvars(ls, 1);
}
- flush_list(ls, n/LFIELDS_PER_FLUSH, n%LFIELDS_PER_FLUSH);
- return n;
+ parlist(ls);
+ check(ls, ')');
+ chunk(ls);
+ check_match(ls, TK_END, TK_FUNCTION, line);
+ close_func(ls);
+ pushclosure(ls, &new_fs);
}
-static void recfield (LexState *ls) {
- /* recfield -> (NAME | '['exp1']') = exp1 */
- switch (ls->token) {
- case NAME:
- code_constant(ls, checkname(ls));
- break;
- case '[':
- next(ls);
- exp1(ls);
- check(ls, ']');
- break;
+/* }====================================================================== */
- default: luaX_error(ls, "NAME or `[' expected");
+
+static void chunk (LexState *ls) {
+ /* chunk -> { stat [';'] } */
+ int islast = 0;
+ while (!islast && !block_follow(ls->t.token)) {
+ islast = stat(ls);
+ optional(ls, ';');
+ LUA_ASSERT(ls->fs->stacklevel == ls->fs->nactloc,
+ "stack size != # local vars");
}
- check(ls, '=');
- exp1(ls);
}
diff --git a/src/lparser.h b/src/lparser.h
index 9825ec57..445acea6 100644
--- a/src/lparser.h
+++ b/src/lparser.h
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.h,v 1.3 1999/02/25 19:13:56 roberto Exp $
+** $Id: lparser.h,v 1.26 2000/10/09 13:47:46 roberto Exp $
** LL(1) Parser and code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -11,10 +11,50 @@
#include "lzio.h"
-void luaY_codedebugline (int line);
-TProtoFunc *luaY_parser (ZIO *z);
-void luaY_error (char *s);
-void luaY_syntaxerror (char *s, char *token);
+/*
+** Expression descriptor
+*/
+
+typedef enum {
+ VGLOBAL,
+ VLOCAL,
+ VINDEXED,
+ VEXP
+} expkind;
+
+typedef struct expdesc {
+ expkind k;
+ union {
+ int index; /* VGLOBAL: `kstr' index of global name; VLOCAL: stack index */
+ struct {
+ int t; /* patch list of `exit when true' */
+ int f; /* patch list of `exit when false' */
+ } l;
+ } u;
+} expdesc;
+
+
+
+/* state needed to generate code for a given function */
+typedef struct FuncState {
+ Proto *f; /* current function header */
+ struct FuncState *prev; /* enclosing function */
+ struct LexState *ls; /* lexical state */
+ struct lua_State *L; /* copy of the Lua state */
+ int pc; /* next position to code */
+ int lasttarget; /* `pc' of last `jump target' */
+ int jlt; /* list of jumps to `lasttarget' */
+ short stacklevel; /* number of values on activation register */
+ short nactloc; /* number of active local variables */
+ short nupvalues; /* number of upvalues */
+ int lastline; /* line where last `lineinfo' was generated */
+ struct Breaklabel *bl; /* chain of breakable blocks */
+ expdesc upvalues[MAXUPVALUES]; /* upvalues */
+ int actloc[MAXLOCALS]; /* local-variable stack (indices to locvars) */
+} FuncState;
+
+
+Proto *luaY_parser (lua_State *L, ZIO *z);
#endif
diff --git a/src/lstate.c b/src/lstate.c
index 3b98d729..586c1085 100644
--- a/src/lstate.c
+++ b/src/lstate.c
@@ -1,13 +1,15 @@
/*
-** $Id: lstate.c,v 1.12 1999/05/11 20:08:20 roberto Exp $
+** $Id: lstate.c,v 1.48 2000/10/30 16:29:59 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
-#include "lbuiltin.h"
+#include <stdio.h>
+
+#include "lua.h"
+
#include "ldo.h"
-#include "lfunc.h"
#include "lgc.h"
#include "llex.h"
#include "lmem.h"
@@ -17,70 +19,103 @@
#include "ltm.h"
-lua_State *lua_state = NULL;
+#ifdef LUA_DEBUG
+static lua_State *lua_state = NULL;
+void luaB_opentests (lua_State *L);
+#endif
-void lua_open (void)
-{
- if (lua_state) return;
- lua_state = luaM_new(lua_State);
- L->Cstack.base = 0;
- L->Cstack.lua2C = 0;
- L->Cstack.num = 0;
- L->errorJmp = NULL;
+/*
+** built-in implementation for ERRORMESSAGE. In a "correct" environment
+** ERRORMESSAGE should have an external definition, and so this function
+** would not be used.
+*/
+static int errormessage (lua_State *L) {
+ const char *s = lua_tostring(L, 1);
+ if (s == NULL) s = "(no message)";
+ fprintf(stderr, "error: %s\n", s);
+ return 0;
+}
+
+
+/*
+** open parts that may cause memory-allocation errors
+*/
+static void f_luaopen (lua_State *L, void *ud) {
+ int stacksize = *(int *)ud;
+ if (stacksize == 0)
+ stacksize = DEFAULT_STACK_SIZE;
+ else
+ stacksize += LUA_MINSTACK;
+ L->gt = luaH_new(L, 10); /* table of globals */
+ luaD_init(L, stacksize);
+ luaS_init(L);
+ luaX_init(L);
+ luaT_init(L);
+ lua_newtable(L);
+ lua_ref(L, 1); /* create registry */
+ lua_register(L, LUA_ERRORMESSAGE, errormessage);
+#ifdef LUA_DEBUG
+ luaB_opentests(L);
+ if (lua_state == NULL) lua_state = L; /* keep first state to be opened */
+#endif
+ LUA_ASSERT(lua_gettop(L) == 0, "wrong API stack");
+}
+
+
+LUA_API lua_State *lua_open (int stacksize) {
+ lua_State *L = luaM_new(NULL, lua_State);
+ if (L == NULL) return NULL; /* memory allocation error */
+ L->stack = NULL;
+ L->strt.size = L->udt.size = 0;
+ L->strt.nuse = L->udt.nuse = 0;
+ L->strt.hash = NULL;
+ L->udt.hash = NULL;
L->Mbuffer = NULL;
- L->Mbuffbase = 0;
L->Mbuffsize = 0;
- L->Mbuffnext = 0;
- L->Cblocks = NULL;
- L->numCblocks = 0;
- L->debug = 0;
- L->callhook = NULL;
- L->linehook = NULL;
- L->rootproto.next = NULL;
- L->rootproto.marked = 0;
- L->rootcl.next = NULL;
- L->rootcl.marked = 0;
- L->rootglobal.next = NULL;
- L->rootglobal.marked = 0;
- L->roottable.next = NULL;
- L->roottable.marked = 0;
- L->IMtable = NULL;
+ L->rootproto = NULL;
+ L->rootcl = NULL;
+ L->roottable = NULL;
+ L->TMtable = NULL;
+ L->last_tag = -1;
L->refArray = NULL;
L->refSize = 0;
- L->GCthreshold = GARBAGE_BLOCK;
- L->nblocks = 0;
- luaD_init();
- luaS_init();
- luaX_init();
- luaT_init();
- luaB_predefine();
+ L->refFree = NONEXT;
+ L->nblocks = sizeof(lua_State);
+ L->GCthreshold = MAX_INT; /* to avoid GC during pre-definitions */
+ L->callhook = NULL;
+ L->linehook = NULL;
+ L->allowhooks = 1;
+ L->errorJmp = NULL;
+ if (luaD_runprotected(L, f_luaopen, &stacksize) != 0) {
+ /* memory allocation error: free partial state */
+ lua_close(L);
+ return NULL;
+ }
+ L->GCthreshold = 2*L->nblocks;
+ return L;
}
-void lua_close (void)
-{
- TaggedString *alludata = luaS_collectudata();
- L->GCthreshold = MAX_INT; /* to avoid GC during GC */
- luaC_hashcallIM((Hash *)L->roottable.next); /* GC t.methods for tables */
- luaC_strcallIM(alludata); /* GC tag methods for userdata */
- luaD_gcIM(&luaO_nilobject); /* GC tag method for nil (signal end of GC) */
- luaH_free((Hash *)L->roottable.next);
- luaF_freeproto((TProtoFunc *)L->rootproto.next);
- luaF_freeclosure((Closure *)L->rootcl.next);
- luaS_free(alludata);
- luaS_freeall();
- luaM_free(L->stack.stack);
- luaM_free(L->IMtable);
- luaM_free(L->refArray);
- luaM_free(L->Mbuffer);
- luaM_free(L->Cblocks);
- luaM_free(L);
- L = NULL;
-#ifdef DEBUG
- printf("total de blocos: %ld\n", numblocks);
- printf("total de memoria: %ld\n", totalmem);
-#endif
+LUA_API void lua_close (lua_State *L) {
+ LUA_ASSERT(L != lua_state || lua_gettop(L) == 0, "garbage in C stack");
+ luaC_collect(L, 1); /* collect all elements */
+ LUA_ASSERT(L->rootproto == NULL, "list should be empty");
+ LUA_ASSERT(L->rootcl == NULL, "list should be empty");
+ LUA_ASSERT(L->roottable == NULL, "list should be empty");
+ luaS_freeall(L);
+ if (L->stack)
+ L->nblocks -= (L->stack_last - L->stack + 1)*sizeof(TObject);
+ luaM_free(L, L->stack);
+ L->nblocks -= (L->last_tag+1)*sizeof(struct TM);
+ luaM_free(L, L->TMtable);
+ L->nblocks -= (L->refSize)*sizeof(struct Ref);
+ luaM_free(L, L->refArray);
+ L->nblocks -= (L->Mbuffsize)*sizeof(char);
+ luaM_free(L, L->Mbuffer);
+ LUA_ASSERT(L->nblocks == sizeof(lua_State), "wrong count for nblocks");
+ luaM_free(L, L);
+ LUA_ASSERT(L != lua_state || memdebug_numblocks == 0, "memory leak!");
+ LUA_ASSERT(L != lua_state || memdebug_total == 0,"memory leak!");
}
-
diff --git a/src/lstate.h b/src/lstate.h
index 168257dd..0c8f5521 100644
--- a/src/lstate.h
+++ b/src/lstate.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.h,v 1.19 1999/05/11 20:08:20 roberto Exp $
+** $Id: lstate.h,v 1.41 2000/10/05 13:00:17 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -7,88 +7,71 @@
#ifndef lstate_h
#define lstate_h
-#include <setjmp.h>
-
#include "lobject.h"
#include "lua.h"
#include "luadebug.h"
-#define GARBAGE_BLOCK 150
-
-typedef int StkId; /* index to stack elements */
+typedef TObject *StkId; /* index to stack elements */
/*
-** "jmp_buf" may be an array, so it is better to make sure it has an
-** address (and not that it *is* an address...)
+** marks for Reference array
*/
-struct lua_longjmp {
- jmp_buf b;
-};
+#define NONEXT -1 /* to end the free list */
+#define HOLD -2
+#define COLLECTED -3
+#define LOCK -4
-struct Stack {
- TObject *top;
- TObject *stack;
- TObject *last;
+struct Ref {
+ TObject o;
+ int st; /* can be LOCK, HOLD, COLLECTED, or next (for free list) */
};
-struct C_Lua_Stack {
- StkId base; /* when Lua calls C or C calls Lua, points to */
- /* the first slot after the last parameter. */
- StkId lua2C; /* points to first element of "array" lua2C */
- int num; /* size of "array" lua2C */
-};
+
+struct lua_longjmp; /* defined in ldo.c */
+struct TM; /* defined in ltm.h */
typedef struct stringtable {
int size;
- int nuse; /* number of elements (including EMPTYs) */
- TaggedString **hash;
+ lint32 nuse; /* number of elements */
+ TString **hash;
} stringtable;
-enum Status {LOCK, HOLD, FREE, COLLECTED};
-
-struct ref {
- TObject o;
- enum Status status;
-};
-
struct lua_State {
/* thread-specific state */
- struct Stack stack; /* Lua stack */
- struct C_Lua_Stack Cstack; /* C2lua struct */
+ StkId top; /* first free slot in the stack */
+ StkId stack; /* stack base */
+ StkId stack_last; /* last free slot in the stack */
+ int stacksize;
+ StkId Cbase; /* base for current C function */
struct lua_longjmp *errorJmp; /* current error recover point */
char *Mbuffer; /* global buffer */
- int Mbuffbase; /* current first position of Mbuffer */
- int Mbuffsize; /* size of Mbuffer */
- int Mbuffnext; /* next position to fill in Mbuffer */
- struct C_Lua_Stack *Cblocks;
- int numCblocks; /* number of nested Cblocks */
- int debug;
- lua_CHFunction callhook;
- lua_LHFunction linehook;
+ size_t Mbuffsize; /* size of Mbuffer */
/* global state */
- GCnode rootproto; /* list of all prototypes */
- GCnode rootcl; /* list of all closures */
- GCnode roottable; /* list of all tables */
- GCnode rootglobal; /* list of strings with global values */
- stringtable *string_root; /* array of hash tables for strings and udata */
- struct IM *IMtable; /* table for tag methods */
- int last_tag; /* last used tag in IMtable */
- struct ref *refArray; /* locked objects */
+ Proto *rootproto; /* list of all prototypes */
+ Closure *rootcl; /* list of all closures */
+ Hash *roottable; /* list of all tables */
+ stringtable strt; /* hash table for strings */
+ stringtable udt; /* hash table for udata */
+ Hash *gt; /* table for globals */
+ struct TM *TMtable; /* table for tag methods */
+ int last_tag; /* last used tag in TMtable */
+ struct Ref *refArray; /* locked objects */
int refSize; /* size of refArray */
+ int refFree; /* list of free positions in refArray */
unsigned long GCthreshold;
- unsigned long nblocks; /* number of 'blocks' currently allocated */
+ unsigned long nblocks; /* number of `bytes' currently allocated */
+ lua_Hook callhook;
+ lua_Hook linehook;
+ int allowhooks;
};
-#define L lua_state
-
-
#endif
diff --git a/src/lstring.c b/src/lstring.c
index fa974ae9..e4c7e26c 100644
--- a/src/lstring.c
+++ b/src/lstring.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstring.c,v 1.19 1999/02/26 15:49:53 roberto Exp $
+** $Id: lstring.c,v 1.45 2000/10/30 17:49:19 roberto Exp $
** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -7,292 +7,149 @@
#include <string.h>
+#include "lua.h"
+
#include "lmem.h"
#include "lobject.h"
#include "lstate.h"
#include "lstring.h"
-#include "lua.h"
-
-
-#define NUM_HASHSTR 31
-#define NUM_HASHUDATA 31
-#define NUM_HASHS (NUM_HASHSTR+NUM_HASHUDATA)
-#define gcsizestring(l) (1+(l/64)) /* "weight" for a string with length 'l' */
+/*
+** type equivalent to TString, but with maximum alignment requirements
+*/
+union L_UTString {
+ TString ts;
+ union L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */
+};
-static TaggedString EMPTY = {{NULL, 2}, 0L, 0,
- {{{LUA_T_NIL, {NULL}}, 0L}}, {0}};
+void luaS_init (lua_State *L) {
+ L->strt.hash = luaM_newvector(L, 1, TString *);
+ L->udt.hash = luaM_newvector(L, 1, TString *);
+ L->nblocks += 2*sizeof(TString *);
+ L->strt.size = L->udt.size = 1;
+ L->strt.nuse = L->udt.nuse = 0;
+ L->strt.hash[0] = L->udt.hash[0] = NULL;
+}
-void luaS_init (void) {
- int i;
- L->string_root = luaM_newvector(NUM_HASHS, stringtable);
- for (i=0; i<NUM_HASHS; i++) {
- L->string_root[i].size = 0;
- L->string_root[i].nuse = 0;
- L->string_root[i].hash = NULL;
- }
+void luaS_freeall (lua_State *L) {
+ LUA_ASSERT(L->strt.nuse==0, "non-empty string table");
+ L->nblocks -= (L->strt.size + L->udt.size)*sizeof(TString *);
+ luaM_free(L, L->strt.hash);
+ LUA_ASSERT(L->udt.nuse==0, "non-empty udata table");
+ luaM_free(L, L->udt.hash);
}
-static unsigned long hash_s (char *s, long l) {
- unsigned long h = 0; /* seed */
- while (l--)
- h = h ^ ((h<<5)+(h>>2)+(unsigned char)*(s++));
+static unsigned long hash_s (const char *s, size_t l) {
+ unsigned long h = l; /* seed */
+ size_t step = (l>>5)|1; /* if string is too long, don't hash all its chars */
+ for (; l>=step; l-=step)
+ h = h ^ ((h<<5)+(h>>2)+(unsigned char)*(s++));
return h;
}
-static int newsize (stringtable *tb) {
- int size = tb->size;
- int realuse = 0;
- int i;
- /* count how many entries are really in use */
- for (i=0; i<size; i++)
- if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY)
- realuse++;
- return luaO_redimension((realuse+1)*2); /* +1 is the new element */
-}
-
-static void grow (stringtable *tb) {
- int ns = newsize(tb);
- TaggedString **newhash = luaM_newvector(ns, TaggedString *);
+void luaS_resize (lua_State *L, stringtable *tb, int newsize) {
+ TString **newhash = luaM_newvector(L, newsize, TString *);
int i;
- for (i=0; i<ns; i++)
- newhash[i] = NULL;
+ for (i=0; i<newsize; i++) newhash[i] = NULL;
/* rehash */
- tb->nuse = 0;
for (i=0; i<tb->size; i++) {
- if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY) {
- unsigned long h = tb->hash[i]->hash;
- int h1 = h%ns;
- while (newhash[h1]) {
- h1 += (h&(ns-2)) + 1; /* double hashing */
- if (h1 >= ns) h1 -= ns;
- }
- newhash[h1] = tb->hash[i];
- tb->nuse++;
+ TString *p = tb->hash[i];
+ while (p) { /* for each node in the list */
+ TString *next = p->nexthash; /* save next */
+ unsigned long h = (tb == &L->strt) ? p->u.s.hash : IntPoint(p->u.d.value);
+ int h1 = h&(newsize-1); /* new position */
+ LUA_ASSERT(h%newsize == (h&(newsize-1)),
+ "a&(x-1) == a%x, for x power of 2");
+ p->nexthash = newhash[h1]; /* chain it in new position */
+ newhash[h1] = p;
+ p = next;
}
}
- luaM_free(tb->hash);
- tb->size = ns;
+ luaM_free(L, tb->hash);
+ L->nblocks += (newsize - tb->size)*sizeof(TString *);
+ tb->size = newsize;
tb->hash = newhash;
}
-static TaggedString *newone_s (char *str, long l, unsigned long h) {
- TaggedString *ts = (TaggedString *)luaM_malloc(sizeof(TaggedString)+l);
- memcpy(ts->str, str, l);
- ts->str[l] = 0; /* ending 0 */
- ts->u.s.globalval.ttype = LUA_T_NIL; /* initialize global value */
- ts->u.s.len = l;
- ts->constindex = 0;
- L->nblocks += gcsizestring(l);
- ts->head.marked = 0;
- ts->head.next = (GCnode *)ts; /* signal it is in no list */
- ts->hash = h;
- return ts;
+static void newentry (lua_State *L, stringtable *tb, TString *ts, int h) {
+ ts->nexthash = tb->hash[h]; /* chain new entry */
+ tb->hash[h] = ts;
+ tb->nuse++;
+ if (tb->nuse > (lint32)tb->size && tb->size < MAX_INT/2) /* too crowded? */
+ luaS_resize(L, tb, tb->size*2);
}
-static TaggedString *newone_u (char *buff, int tag, unsigned long h) {
- TaggedString *ts = luaM_new(TaggedString);
- ts->u.d.v = buff;
- ts->u.d.tag = (tag == LUA_ANYTAG) ? 0 : tag;
- ts->constindex = -1; /* tag -> this is a userdata */
- L->nblocks++;
- ts->head.marked = 0;
- ts->head.next = (GCnode *)ts; /* signal it is in no list */
- ts->hash = h;
- return ts;
-}
-static TaggedString *insert_s (char *str, long l, stringtable *tb) {
- TaggedString *ts;
+
+TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
unsigned long h = hash_s(str, l);
- int size = tb->size;
- int j = -1;
- int h1;
- if ((long)tb->nuse*3 >= (long)size*2) {
- grow(tb);
- size = tb->size;
- }
- h1 = h%size;
- while ((ts = tb->hash[h1]) != NULL) {
- if (ts == &EMPTY)
- j = h1;
- else if (ts->u.s.len == l && (memcmp(str, ts->str, l) == 0))
+ int h1 = h & (L->strt.size-1);
+ TString *ts;
+ for (ts = L->strt.hash[h1]; ts; ts = ts->nexthash) {
+ if (ts->len == l && (memcmp(str, ts->str, l) == 0))
return ts;
- h1 += (h&(size-2)) + 1; /* double hashing */
- if (h1 >= size) h1 -= size;
}
/* not found */
- if (j != -1) /* is there an EMPTY space? */
- h1 = j;
- else
- tb->nuse++;
- ts = tb->hash[h1] = newone_s(str, l, h);
+ ts = (TString *)luaM_malloc(L, sizestring(l));
+ ts->marked = 0;
+ ts->nexthash = NULL;
+ ts->len = l;
+ ts->u.s.hash = h;
+ ts->u.s.constindex = 0;
+ memcpy(ts->str, str, l);
+ ts->str[l] = 0; /* ending 0 */
+ L->nblocks += sizestring(l);
+ newentry(L, &L->strt, ts, h1); /* insert it on table */
return ts;
}
-static TaggedString *insert_u (void *buff, int tag, stringtable *tb) {
- TaggedString *ts;
- unsigned long h = (unsigned long)buff;
- int size = tb->size;
- int j = -1;
- int h1;
- if ((long)tb->nuse*3 >= (long)size*2) {
- grow(tb);
- size = tb->size;
- }
- h1 = h%size;
- while ((ts = tb->hash[h1]) != NULL) {
- if (ts == &EMPTY)
- j = h1;
- else if ((tag == ts->u.d.tag || tag == LUA_ANYTAG) && buff == ts->u.d.v)
- return ts;
- h1 += (h&(size-2)) + 1; /* double hashing */
- if (h1 >= size) h1 -= size;
- }
- /* not found */
- if (j != -1) /* is there an EMPTY space? */
- h1 = j;
- else
- tb->nuse++;
- ts = tb->hash[h1] = newone_u(buff, tag, h);
+TString *luaS_newudata (lua_State *L, size_t s, void *udata) {
+ union L_UTString *uts = (union L_UTString *)luaM_malloc(L,
+ (lint32)sizeof(union L_UTString)+s);
+ TString *ts = &uts->ts;
+ ts->marked = 0;
+ ts->nexthash = NULL;
+ ts->len = s;
+ ts->u.d.tag = 0;
+ ts->u.d.value = (udata == NULL) ? uts+1 : udata;
+ L->nblocks += sizestring(s);
+ /* insert it on table */
+ newentry(L, &L->udt, ts, IntPoint(ts->u.d.value) & (L->udt.size-1));
return ts;
}
-TaggedString *luaS_createudata (void *udata, int tag) {
- int t = ((unsigned)udata%NUM_HASHUDATA)+NUM_HASHSTR;
- return insert_u(udata, tag, &L->string_root[t]);
-}
-
-TaggedString *luaS_newlstr (char *str, long l) {
- int t = (l==0) ? 0 : ((int)((unsigned char)str[0]*l))%NUM_HASHSTR;
- return insert_s(str, l, &L->string_root[t]);
-}
-
-TaggedString *luaS_new (char *str) {
- return luaS_newlstr(str, strlen(str));
-}
-
-TaggedString *luaS_newfixedstring (char *str) {
- TaggedString *ts = luaS_new(str);
- if (ts->head.marked == 0)
- ts->head.marked = 2; /* avoid GC */
- return ts;
-}
-
-
-void luaS_free (TaggedString *l) {
- while (l) {
- TaggedString *next = (TaggedString *)l->head.next;
- L->nblocks -= (l->constindex == -1) ? 1 : gcsizestring(l->u.s.len);
- luaM_free(l);
- l = next;
- }
-}
-
-
-/*
-** Garbage collection functions.
-*/
-
-static void remove_from_list (GCnode *l) {
- while (l) {
- GCnode *next = l->next;
- while (next && !next->marked)
- next = l->next = next->next;
- l = next;
- }
-}
-
-
-TaggedString *luaS_collector (void) {
- TaggedString *frees = NULL;
- int i;
- remove_from_list(&(L->rootglobal));
- for (i=0; i<NUM_HASHS; i++) {
- stringtable *tb = &L->string_root[i];
- int j;
- for (j=0; j<tb->size; j++) {
- TaggedString *t = tb->hash[j];
- if (t == NULL) continue;
- if (t->head.marked == 1)
- t->head.marked = 0;
- else if (!t->head.marked) {
- t->head.next = (GCnode *)frees;
- frees = t;
- tb->hash[j] = &EMPTY;
- }
- }
- }
- return frees;
-}
-
-
-TaggedString *luaS_collectudata (void) {
- TaggedString *frees = NULL;
- int i;
- L->rootglobal.next = NULL; /* empty list of globals */
- for (i=NUM_HASHSTR; i<NUM_HASHS; i++) {
- stringtable *tb = &L->string_root[i];
- int j;
- for (j=0; j<tb->size; j++) {
- TaggedString *t = tb->hash[j];
- if (t == NULL || t == &EMPTY)
- continue;
- LUA_ASSERT(t->constindex == -1, "must be userdata");
- t->head.next = (GCnode *)frees;
- frees = t;
- tb->hash[j] = &EMPTY;
- }
- }
- return frees;
-}
-
-
-void luaS_freeall (void) {
- int i;
- for (i=0; i<NUM_HASHS; i++) {
- stringtable *tb = &L->string_root[i];
- int j;
- for (j=0; j<tb->size; j++) {
- TaggedString *t = tb->hash[j];
- if (t == &EMPTY) continue;
- luaM_free(t);
- }
- luaM_free(tb->hash);
- }
- luaM_free(L->string_root);
-}
-
-
-void luaS_rawsetglobal (TaggedString *ts, TObject *newval) {
- ts->u.s.globalval = *newval;
- if (ts->head.next == (GCnode *)ts) { /* is not in list? */
- ts->head.next = L->rootglobal.next;
- L->rootglobal.next = (GCnode *)ts;
+TString *luaS_createudata (lua_State *L, void *udata, int tag) {
+ int h1 = IntPoint(udata) & (L->udt.size-1);
+ TString *ts;
+ for (ts = L->udt.hash[h1]; ts; ts = ts->nexthash) {
+ if (udata == ts->u.d.value && (tag == ts->u.d.tag || tag == LUA_ANYTAG))
+ return ts;
}
+ /* not found */
+ ts = luaS_newudata(L, 0, udata);
+ if (tag != LUA_ANYTAG)
+ ts->u.d.tag = tag;
+ return ts;
}
-char *luaS_travsymbol (int (*fn)(TObject *)) {
- TaggedString *g;
- for (g=(TaggedString *)L->rootglobal.next; g; g=(TaggedString *)g->head.next)
- if (fn(&g->u.s.globalval))
- return g->str;
- return NULL;
+TString *luaS_new (lua_State *L, const char *str) {
+ return luaS_newlstr(L, str, strlen(str));
}
-int luaS_globaldefined (char *name) {
- TaggedString *ts = luaS_new(name);
- return ts->u.s.globalval.ttype != LUA_T_NIL;
+TString *luaS_newfixed (lua_State *L, const char *str) {
+ TString *ts = luaS_new(L, str);
+ if (ts->marked == 0) ts->marked = FIXMARK; /* avoid GC */
+ return ts;
}
diff --git a/src/lstring.h b/src/lstring.h
index 6b214a21..67ede68d 100644
--- a/src/lstring.h
+++ b/src/lstring.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstring.h,v 1.7 1998/03/06 16:54:42 roberto Exp $
+** $Id: lstring.h,v 1.24 2000/10/30 17:49:19 roberto Exp $
** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -9,20 +9,29 @@
#include "lobject.h"
+#include "lstate.h"
-void luaS_init (void);
-TaggedString *luaS_createudata (void *udata, int tag);
-TaggedString *luaS_collector (void);
-void luaS_free (TaggedString *l);
-TaggedString *luaS_newlstr (char *str, long l);
-TaggedString *luaS_new (char *str);
-TaggedString *luaS_newfixedstring (char *str);
-void luaS_rawsetglobal (TaggedString *ts, TObject *newval);
-char *luaS_travsymbol (int (*fn)(TObject *));
-int luaS_globaldefined (char *name);
-TaggedString *luaS_collectudata (void);
-void luaS_freeall (void);
+/*
+** any TString with mark>=FIXMARK is never collected.
+** Marks>=RESERVEDMARK are used to identify reserved words.
+*/
+#define FIXMARK 2
+#define RESERVEDMARK 3
+
+
+#define sizestring(l) ((long)sizeof(TString) + \
+ ((long)(l+1)-TSPACK)*(long)sizeof(char))
+
+
+void luaS_init (lua_State *L);
+void luaS_resize (lua_State *L, stringtable *tb, int newsize);
+TString *luaS_newudata (lua_State *L, size_t s, void *udata);
+TString *luaS_createudata (lua_State *L, void *udata, int tag);
+void luaS_freeall (lua_State *L);
+TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
+TString *luaS_new (lua_State *L, const char *str);
+TString *luaS_newfixed (lua_State *L, const char *str);
#endif
diff --git a/src/ltable.c b/src/ltable.c
index d768ba0b..b28712d9 100644
--- a/src/ltable.c
+++ b/src/ltable.c
@@ -1,177 +1,303 @@
/*
-** $Id: ltable.c,v 1.22 1999/05/21 19:41:49 roberto Exp $
+** $Id: ltable.c,v 1.58 2000/10/26 12:47:05 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
-#include <stdlib.h>
-#include "lauxlib.h"
+/*
+** Implementation of tables (aka arrays, objects, or hash tables);
+** uses a mix of chained scatter table with Brent's variation.
+** A main invariant of these tables is that, if an element is not
+** in its main position (i.e. the `original' position that its hash gives
+** to it), then the colliding element is in its own main position.
+** In other words, there are collisions only when two elements have the
+** same main position (i.e. the same hash values for that table size).
+** Because of that, the load factor of these tables can be 100% without
+** performance penalties.
+*/
+
+
+#include "lua.h"
+
#include "lmem.h"
#include "lobject.h"
#include "lstate.h"
+#include "lstring.h"
#include "ltable.h"
-#include "lua.h"
-#define gcsize(n) (1+(n/16))
+#define gcsize(L, n) (sizeof(Hash)+(n)*sizeof(Node))
-#define nuse(t) ((t)->nuse)
-#define nodevector(t) ((t)->node)
-#define TagDefault LUA_T_ARRAY;
+#define TagDefault LUA_TTABLE
-static long int hashindex (TObject *ref) {
- long int h;
- switch (ttype(ref)) {
- case LUA_T_NUMBER:
- h = (long int)nvalue(ref);
- break;
- case LUA_T_STRING: case LUA_T_USERDATA:
- h = (IntPoint)tsvalue(ref);
+/*
+** returns the `main' position of an element in a table (that is, the index
+** of its hash value)
+*/
+Node *luaH_mainposition (const Hash *t, const TObject *key) {
+ unsigned long h;
+ switch (ttype(key)) {
+ case LUA_TNUMBER:
+ h = (unsigned long)(long)nvalue(key);
break;
- case LUA_T_ARRAY:
- h = (IntPoint)avalue(ref);
+ case LUA_TSTRING:
+ h = tsvalue(key)->u.s.hash;
break;
- case LUA_T_PROTO:
- h = (IntPoint)tfvalue(ref);
+ case LUA_TUSERDATA:
+ h = IntPoint(tsvalue(key));
break;
- case LUA_T_CPROTO:
- h = (IntPoint)fvalue(ref);
+ case LUA_TTABLE:
+ h = IntPoint(hvalue(key));
break;
- case LUA_T_CLOSURE:
- h = (IntPoint)clvalue(ref);
+ case LUA_TFUNCTION:
+ h = IntPoint(clvalue(key));
break;
default:
- lua_error("unexpected type to index table");
- h = 0; /* to avoid warnings */
+ return NULL; /* invalid key */
}
- return (h >= 0 ? h : -(h+1));
+ LUA_ASSERT(h%(unsigned int)t->size == (h&((unsigned int)t->size-1)),
+ "a&(x-1) == a%x, for x power of 2");
+ return &t->node[h&(t->size-1)];
+}
+
+
+static const TObject *luaH_getany (lua_State *L, const Hash *t,
+ const TObject *key) {
+ Node *n = luaH_mainposition(t, key);
+ if (!n)
+ lua_error(L, "table index is nil");
+ else do {
+ if (luaO_equalObj(key, &n->key))
+ return &n->val;
+ n = n->next;
+ } while (n);
+ return &luaO_nilobject; /* key not found */
+}
+
+
+/* specialized version for numbers */
+const TObject *luaH_getnum (const Hash *t, Number key) {
+ Node *n = &t->node[(unsigned long)(long)key&(t->size-1)];
+ do {
+ if (ttype(&n->key) == LUA_TNUMBER && nvalue(&n->key) == key)
+ return &n->val;
+ n = n->next;
+ } while (n);
+ return &luaO_nilobject; /* key not found */
}
-Node *luaH_present (Hash *t, TObject *key) {
- int tsize = nhash(t);
- long int h = hashindex(key);
- int h1 = h%tsize;
- Node *n = node(t, h1);
- /* keep looking until an entry with "ref" equal to key or nil */
- while ((ttype(ref(n)) == ttype(key)) ? !luaO_equalval(key, ref(n))
- : ttype(ref(n)) != LUA_T_NIL) {
- h1 += (h&(tsize-2)) + 1; /* double hashing */
- if (h1 >= tsize) h1 -= tsize;
- n = node(t, h1);
+/* specialized version for strings */
+const TObject *luaH_getstr (const Hash *t, TString *key) {
+ Node *n = &t->node[key->u.s.hash&(t->size-1)];
+ do {
+ if (ttype(&n->key) == LUA_TSTRING && tsvalue(&n->key) == key)
+ return &n->val;
+ n = n->next;
+ } while (n);
+ return &luaO_nilobject; /* key not found */
+}
+
+
+const TObject *luaH_get (lua_State *L, const Hash *t, const TObject *key) {
+ switch (ttype(key)) {
+ case LUA_TNUMBER: return luaH_getnum(t, nvalue(key));
+ case LUA_TSTRING: return luaH_getstr(t, tsvalue(key));
+ default: return luaH_getany(L, t, key);
}
- return n;
}
-void luaH_free (Hash *frees) {
- while (frees) {
- Hash *next = (Hash *)frees->head.next;
- L->nblocks -= gcsize(frees->nhash);
- luaM_free(nodevector(frees));
- luaM_free(frees);
- frees = next;
+Node *luaH_next (lua_State *L, const Hash *t, const TObject *key) {
+ int i;
+ if (ttype(key) == LUA_TNIL)
+ i = 0; /* first iteration */
+ else {
+ const TObject *v = luaH_get(L, t, key);
+ if (v == &luaO_nilobject)
+ lua_error(L, "invalid key for `next'");
+ i = (int)(((const char *)v -
+ (const char *)(&t->node[0].val)) / sizeof(Node)) + 1;
+ }
+ for (; i<t->size; i++) {
+ Node *n = node(t, i);
+ if (ttype(val(n)) != LUA_TNIL)
+ return n;
}
+ return NULL; /* no more elements */
}
-static Node *hashnodecreate (int nhash) {
- Node *v = luaM_newvector(nhash, Node);
+/*
+** try to remove a key without value from a table. To avoid problems with
+** hash, change `key' for a number with the same hash.
+*/
+void luaH_remove (Hash *t, TObject *key) {
+ if (ttype(key) == LUA_TNUMBER ||
+ (ttype(key) == LUA_TSTRING && tsvalue(key)->len <= 30))
+ return; /* do not remove numbers nor small strings */
+ else {
+ /* try to find a number `n' with the same hash as `key' */
+ Node *mp = luaH_mainposition(t, key);
+ int n = mp - &t->node[0];
+ /* make sure `n' is not in `t' */
+ while (luaH_getnum(t, n) != &luaO_nilobject) {
+ if (n >= MAX_INT - t->size)
+ return; /* give up; (to avoid overflow) */
+ n += t->size;
+ }
+ ttype(key) = LUA_TNUMBER;
+ nvalue(key) = n;
+ LUA_ASSERT(luaH_mainposition(t, key) == mp, "cannot change hash");
+ }
+}
+
+
+static void setnodevector (lua_State *L, Hash *t, lint32 size) {
int i;
- for (i=0; i<nhash; i++)
- ttype(ref(&v[i])) = ttype(val(&v[i])) = LUA_T_NIL;
- return v;
+ if (size > MAX_INT)
+ lua_error(L, "table overflow");
+ t->node = luaM_newvector(L, size, Node);
+ for (i=0; i<(int)size; i++) {
+ ttype(&t->node[i].key) = ttype(&t->node[i].val) = LUA_TNIL;
+ t->node[i].next = NULL;
+ }
+ L->nblocks += gcsize(L, size) - gcsize(L, t->size);
+ t->size = size;
+ t->firstfree = &t->node[size-1]; /* first free position to be used */
}
-Hash *luaH_new (int nhash) {
- Hash *t = luaM_new(Hash);
- nhash = luaO_redimension(nhash*3/2);
- nodevector(t) = hashnodecreate(nhash);
- nhash(t) = nhash;
- nuse(t) = 0;
+Hash *luaH_new (lua_State *L, int size) {
+ Hash *t = luaM_new(L, Hash);
t->htag = TagDefault;
- luaO_insertlist(&(L->roottable), (GCnode *)t);
- L->nblocks += gcsize(nhash);
+ t->next = L->roottable;
+ L->roottable = t;
+ t->mark = t;
+ t->size = 0;
+ L->nblocks += gcsize(L, 0);
+ t->node = NULL;
+ setnodevector(L, t, luaO_power2(size));
return t;
}
-static int newsize (Hash *t) {
+void luaH_free (lua_State *L, Hash *t) {
+ L->nblocks -= gcsize(L, t->size);
+ luaM_free(L, t->node);
+ luaM_free(L, t);
+}
+
+
+static int numuse (const Hash *t) {
Node *v = t->node;
- int size = nhash(t);
+ int size = t->size;
int realuse = 0;
int i;
for (i=0; i<size; i++) {
- if (ttype(val(v+i)) != LUA_T_NIL)
+ if (ttype(&v[i].val) != LUA_TNIL)
realuse++;
}
- return luaO_redimension((realuse+1)*2); /* +1 is the new element */
+ return realuse;
}
-static void rehash (Hash *t) {
- int nold = nhash(t);
- Node *vold = nodevector(t);
- int nnew = newsize(t);
+static void rehash (lua_State *L, Hash *t) {
+ int oldsize = t->size;
+ Node *nold = t->node;
+ int nelems = numuse(t);
int i;
- nodevector(t) = hashnodecreate(nnew);
- nhash(t) = nnew;
- nuse(t) = 0;
- for (i=0; i<nold; i++) {
- Node *n = vold+i;
- if (ttype(val(n)) != LUA_T_NIL) {
- *luaH_present(t, ref(n)) = *n; /* copy old node to new hash */
- nuse(t)++;
- }
+ LUA_ASSERT(nelems<=oldsize, "wrong count");
+ if (nelems >= oldsize-oldsize/4) /* using more than 3/4? */
+ setnodevector(L, t, (lint32)oldsize*2);
+ else if (nelems <= oldsize/4 && /* less than 1/4? */
+ oldsize > MINPOWER2)
+ setnodevector(L, t, oldsize/2);
+ else
+ setnodevector(L, t, oldsize);
+ for (i=0; i<oldsize; i++) {
+ Node *old = nold+i;
+ if (ttype(&old->val) != LUA_TNIL)
+ *luaH_set(L, t, &old->key) = old->val;
}
- L->nblocks += gcsize(nnew)-gcsize(nold);
- luaM_free(vold);
+ luaM_free(L, nold); /* free old array */
}
-void luaH_set (Hash *t, TObject *ref, TObject *val) {
- Node *n = luaH_present(t, ref);
- if (ttype(ref(n)) != LUA_T_NIL)
- *val(n) = *val;
- else {
- TObject buff;
- buff = *val; /* rehash may invalidate this address */
- if ((long)nuse(t)*3L > (long)nhash(t)*2L) {
- rehash(t);
- n = luaH_present(t, ref);
+/*
+** inserts a key into a hash table; first, check whether key is
+** already present; if not, 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.
+*/
+TObject *luaH_set (lua_State *L, Hash *t, const TObject *key) {
+ Node *mp = luaH_mainposition(t, key);
+ Node *n = mp;
+ if (!mp)
+ lua_error(L, "table index is nil");
+ do { /* check whether `key' is somewhere in the chain */
+ if (luaO_equalObj(key, &n->key))
+ return &n->val; /* that's all */
+ else n = n->next;
+ } while (n);
+ /* `key' not found; must insert it */
+ if (ttype(&mp->key) != LUA_TNIL) { /* main position is not free? */
+ Node *othern; /* main position of colliding node */
+ n = t->firstfree; /* get a free place */
+ /* is colliding node out of its main position? (can only happens if
+ its position is after "firstfree") */
+ if (mp > n && (othern=luaH_mainposition(t, &mp->key)) != mp) {
+ /* yes; move colliding node into free position */
+ while (othern->next != mp) othern = othern->next; /* find previous */
+ othern->next = n; /* redo the chain with `n' in place of `mp' */
+ *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */
+ mp->next = NULL; /* now `mp' is free */
}
- nuse(t)++;
- *ref(n) = *ref;
- *val(n) = buff;
+ else { /* colliding node is in its own main position */
+ /* new node will go into free position */
+ n->next = mp->next; /* chain new position */
+ mp->next = n;
+ mp = n;
+ }
+ }
+ mp->key = *key;
+ for (;;) { /* correct `firstfree' */
+ if (ttype(&t->firstfree->key) == LUA_TNIL)
+ return &mp->val; /* OK; table still has a free place */
+ else if (t->firstfree == t->node) break; /* cannot decrement from here */
+ else (t->firstfree)--;
}
+ rehash(L, t); /* no more free places */
+ return luaH_set(L, t, key); /* `rehash' invalidates this insertion */
}
-int luaH_pos (Hash *t, TObject *r) {
- Node *n = luaH_present(t, r);
- luaL_arg_check(ttype(val(n)) != LUA_T_NIL, 2, "key not found");
- return n-(t->node);
+TObject *luaH_setint (lua_State *L, Hash *t, int key) {
+ TObject index;
+ ttype(&index) = LUA_TNUMBER;
+ nvalue(&index) = key;
+ return luaH_set(L, t, &index);
}
-void luaH_setint (Hash *t, int ref, TObject *val) {
- TObject index;
- ttype(&index) = LUA_T_NUMBER;
- nvalue(&index) = ref;
- luaH_set(t, &index, val);
+void luaH_setstrnum (lua_State *L, Hash *t, TString *key, Number val) {
+ TObject *value, index;
+ ttype(&index) = LUA_TSTRING;
+ tsvalue(&index) = key;
+ value = luaH_set(L, t, &index);
+ ttype(value) = LUA_TNUMBER;
+ nvalue(value) = val;
}
-TObject *luaH_getint (Hash *t, int ref) {
- TObject index;
- ttype(&index) = LUA_T_NUMBER;
- nvalue(&index) = ref;
- return luaH_get(t, &index);
+const TObject *luaH_getglobal (lua_State *L, const char *name) {
+ return luaH_getstr(L->gt, luaS_new(L, name));
}
diff --git a/src/ltable.h b/src/ltable.h
index 49b485f2..8ee41a81 100644
--- a/src/ltable.h
+++ b/src/ltable.h
@@ -1,5 +1,5 @@
/*
-** $Id: ltable.h,v 1.11 1999/02/23 14:57:28 roberto Exp $
+** $Id: ltable.h,v 1.24 2000/08/31 14:08:27 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -10,21 +10,25 @@
#include "lobject.h"
-#define node(t,i) (&(t)->node[i])
-#define ref(n) (&(n)->ref)
+#define node(t,i) (&(t)->node[i])
+#define key(n) (&(n)->key)
#define val(n) (&(n)->val)
-#define nhash(t) ((t)->nhash)
-
-#define luaH_get(t,ref) (val(luaH_present((t), (ref))))
-#define luaH_move(t,from,to) (luaH_setint(t, to, luaH_getint(t, from)))
-
-Hash *luaH_new (int nhash);
-void luaH_free (Hash *frees);
-Node *luaH_present (Hash *t, TObject *key);
-void luaH_set (Hash *t, TObject *ref, TObject *val);
-int luaH_pos (Hash *t, TObject *r);
-void luaH_setint (Hash *t, int ref, TObject *val);
-TObject *luaH_getint (Hash *t, int ref);
+
+Hash *luaH_new (lua_State *L, int nhash);
+void luaH_free (lua_State *L, Hash *t);
+const TObject *luaH_get (lua_State *L, const Hash *t, const TObject *key);
+const TObject *luaH_getnum (const Hash *t, Number key);
+const TObject *luaH_getstr (const Hash *t, TString *key);
+void luaH_remove (Hash *t, TObject *key);
+TObject *luaH_set (lua_State *L, Hash *t, const TObject *key);
+Node * luaH_next (lua_State *L, const Hash *t, const TObject *r);
+TObject *luaH_setint (lua_State *L, Hash *t, int key);
+void luaH_setstrnum (lua_State *L, Hash *t, TString *key, Number val);
+unsigned long luaH_hash (lua_State *L, const TObject *key);
+const TObject *luaH_getglobal (lua_State *L, const char *name);
+
+/* exported only for debugging */
+Node *luaH_mainposition (const Hash *t, const TObject *key);
#endif
diff --git a/src/ltests.c b/src/ltests.c
new file mode 100644
index 00000000..c27c7c81
--- /dev/null
+++ b/src/ltests.c
@@ -0,0 +1,543 @@
+/*
+** $Id: ltests.c,v 1.54 2000/10/31 13:10:24 roberto Exp $
+** Internal Module for Debugging of the Lua Implementation
+** See Copyright Notice in lua.h
+*/
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "lauxlib.h"
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lmem.h"
+#include "lopcodes.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "luadebug.h"
+#include "lualib.h"
+
+
+void luaB_opentests (lua_State *L);
+
+
+/*
+** The whole module only makes sense with LUA_DEBUG on
+*/
+#ifdef LUA_DEBUG
+
+
+
+static void setnameval (lua_State *L, const char *name, int val) {
+ lua_pushstring(L, name);
+ lua_pushnumber(L, val);
+ lua_settable(L, -3);
+}
+
+
+/*
+** {======================================================
+** Disassembler
+** =======================================================
+*/
+
+
+static const char *const instrname[NUM_OPCODES] = {
+ "END", "RETURN", "CALL", "TAILCALL", "PUSHNIL", "POP", "PUSHINT",
+ "PUSHSTRING", "PUSHNUM", "PUSHNEGNUM", "PUSHUPVALUE", "GETLOCAL",
+ "GETGLOBAL", "GETTABLE", "GETDOTTED", "GETINDEXED", "PUSHSELF",
+ "CREATETABLE", "SETLOCAL", "SETGLOBAL", "SETTABLE", "SETLIST", "SETMAP",
+ "ADD", "ADDI", "SUB", "MULT", "DIV", "POW", "CONCAT", "MINUS", "NOT",
+ "JMPNE", "JMPEQ", "JMPLT", "JMPLE", "JMPGT", "JMPGE", "JMPT", "JMPF",
+ "JMPONT", "JMPONF", "JMP", "PUSHNILJMP", "FORPREP", "FORLOOP", "LFORPREP",
+ "LFORLOOP", "CLOSURE"
+};
+
+
+static int pushop (lua_State *L, Proto *p, int pc) {
+ char buff[100];
+ Instruction i = p->code[pc];
+ OpCode o = GET_OPCODE(i);
+ const char *name = instrname[o];
+ sprintf(buff, "%5d - ", luaG_getline(p->lineinfo, pc, 1, NULL));
+ switch ((enum Mode)luaK_opproperties[o].mode) {
+ case iO:
+ sprintf(buff+8, "%-12s", name);
+ break;
+ case iU:
+ sprintf(buff+8, "%-12s%4u", name, GETARG_U(i));
+ break;
+ case iS:
+ sprintf(buff+8, "%-12s%4d", name, GETARG_S(i));
+ break;
+ case iAB:
+ sprintf(buff+8, "%-12s%4d %4d", name, GETARG_A(i), GETARG_B(i));
+ break;
+ }
+ lua_pushstring(L, buff);
+ return (o != OP_END);
+}
+
+
+static int listcode (lua_State *L) {
+ int pc;
+ Proto *p;
+ int res;
+ luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = clvalue(luaA_index(L, 1))->f.l;
+ lua_newtable(L);
+ setnameval(L, "maxstack", p->maxstacksize);
+ setnameval(L, "numparams", p->numparams);
+ pc = 0;
+ do {
+ lua_pushnumber(L, pc+1);
+ res = pushop(L, p, pc++);
+ lua_settable(L, -3);
+ } while (res);
+ return 1;
+}
+
+
+static int liststrings (lua_State *L) {
+ Proto *p;
+ int i;
+ luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = clvalue(luaA_index(L, 1))->f.l;
+ lua_newtable(L);
+ for (i=0; i<p->nkstr; i++) {
+ lua_pushnumber(L, i+1);
+ lua_pushstring(L, p->kstr[i]->str);
+ lua_settable(L, -3);
+ }
+ return 1;
+}
+
+
+static int listlocals (lua_State *L) {
+ Proto *p;
+ int pc = luaL_check_int(L, 2) - 1;
+ int i = 0;
+ const char *name;
+ luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = clvalue(luaA_index(L, 1))->f.l;
+ while ((name = luaF_getlocalname(p, ++i, pc)) != NULL)
+ lua_pushstring(L, name);
+ return i-1;
+}
+
+/* }====================================================== */
+
+
+
+static int get_limits (lua_State *L) {
+ lua_newtable(L);
+ setnameval(L, "BITS_INT", BITS_INT);
+ setnameval(L, "LFPF", LFIELDS_PER_FLUSH);
+ setnameval(L, "MAXARG_A", MAXARG_A);
+ setnameval(L, "MAXARG_B", MAXARG_B);
+ setnameval(L, "MAXARG_S", MAXARG_S);
+ setnameval(L, "MAXARG_U", MAXARG_U);
+ setnameval(L, "MAXLOCALS", MAXLOCALS);
+ setnameval(L, "MAXPARAMS", MAXPARAMS);
+ setnameval(L, "MAXSTACK", MAXSTACK);
+ setnameval(L, "MAXUPVALUES", MAXUPVALUES);
+ setnameval(L, "MAXVARSLH", MAXVARSLH);
+ setnameval(L, "RFPF", RFIELDS_PER_FLUSH);
+ setnameval(L, "SIZE_A", SIZE_A);
+ setnameval(L, "SIZE_B", SIZE_B);
+ setnameval(L, "SIZE_OP", SIZE_OP);
+ setnameval(L, "SIZE_U", SIZE_U);
+ return 1;
+}
+
+
+static int mem_query (lua_State *L) {
+ if (lua_isnull(L, 1)) {
+ lua_pushnumber(L, memdebug_total);
+ lua_pushnumber(L, memdebug_numblocks);
+ lua_pushnumber(L, memdebug_maxmem);
+ return 3;
+ }
+ else {
+ memdebug_memlimit = luaL_check_int(L, 1);
+ return 0;
+ }
+}
+
+
+static int hash_query (lua_State *L) {
+ if (lua_isnull(L, 2)) {
+ luaL_arg_check(L, lua_tag(L, 1) == LUA_TSTRING, 1, "string expected");
+ lua_pushnumber(L, tsvalue(luaA_index(L, 1))->u.s.hash);
+ }
+ else {
+ Hash *t;
+ luaL_checktype(L, 2, LUA_TTABLE);
+ t = hvalue(luaA_index(L, 2));
+ lua_pushnumber(L, luaH_mainposition(t, luaA_index(L, 1)) - t->node);
+ }
+ return 1;
+}
+
+
+static int table_query (lua_State *L) {
+ const Hash *t;
+ int i = luaL_opt_int(L, 2, -1);
+ luaL_checktype(L, 1, LUA_TTABLE);
+ t = hvalue(luaA_index(L, 1));
+ if (i == -1) {
+ lua_pushnumber(L, t->size);
+ lua_pushnumber(L, t->firstfree - t->node);
+ return 2;
+ }
+ else if (i < t->size) {
+ luaA_pushobject(L, &t->node[i].key);
+ luaA_pushobject(L, &t->node[i].val);
+ if (t->node[i].next) {
+ lua_pushnumber(L, t->node[i].next - t->node);
+ return 3;
+ }
+ else
+ return 2;
+ }
+ return 0;
+}
+
+
+static int string_query (lua_State *L) {
+ stringtable *tb = (*luaL_check_string(L, 1) == 's') ? &L->strt : &L->udt;
+ int s = luaL_opt_int(L, 2, 0) - 1;
+ if (s==-1) {
+ lua_pushnumber(L ,tb->nuse);
+ lua_pushnumber(L ,tb->size);
+ return 2;
+ }
+ else if (s < tb->size) {
+ TString *ts;
+ int n = 0;
+ for (ts = tb->hash[s]; ts; ts = ts->nexthash) {
+ ttype(L->top) = LUA_TSTRING;
+ tsvalue(L->top) = ts;
+ incr_top;
+ n++;
+ }
+ return n;
+ }
+ return 0;
+}
+
+
+static int tref (lua_State *L) {
+ luaL_checkany(L, 1);
+ lua_pushvalue(L, 1);
+ lua_pushnumber(L, lua_ref(L, luaL_opt_int(L, 2, 1)));
+ return 1;
+}
+
+static int getref (lua_State *L) {
+ if (lua_getref(L, luaL_check_int(L, 1)))
+ return 1;
+ else
+ return 0;
+}
+
+static int unref (lua_State *L) {
+ lua_unref(L, luaL_check_int(L, 1));
+ return 0;
+}
+
+static int newuserdata (lua_State *L) {
+ if (lua_isnumber(L, 2))
+ lua_pushusertag(L, (void *)luaL_check_int(L, 1), luaL_check_int(L, 2));
+ else
+ lua_newuserdata(L, luaL_check_int(L, 1));
+ return 1;
+}
+
+static int udataval (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TUSERDATA);
+ lua_pushnumber(L, (int)lua_touserdata(L, 1));
+ return 1;
+}
+
+static int newstate (lua_State *L) {
+ lua_State *L1 = lua_open(luaL_check_int(L, 1));
+ if (L1)
+ lua_pushuserdata(L, L1);
+ else
+ lua_pushnil(L);
+ return 1;
+}
+
+static int loadlib (lua_State *L) {
+ lua_State *L1 = (lua_State *)lua_touserdata(L, 1);
+ switch (*luaL_check_string(L, 2)) {
+ case 'm': lua_mathlibopen(L1); break;
+ case 's': lua_strlibopen(L1); break;
+ case 'i': lua_iolibopen(L1); break;
+ case 'd': lua_dblibopen(L1); break;
+ case 'b': lua_baselibopen(L1); break;
+ default: luaL_argerror(L, 2, "invalid option");
+ }
+ return 0;
+}
+
+static int closestate (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TUSERDATA);
+ lua_close((lua_State *)lua_touserdata(L, 1));
+ return 0;
+}
+
+static int doremote (lua_State *L) {
+ lua_State *L1;
+ const char *code = luaL_check_string(L, 2);
+ int status;
+ luaL_checktype(L, 1, LUA_TUSERDATA);
+ L1 = (lua_State *)lua_touserdata(L, 1);
+ status = lua_dostring(L1, code);
+ if (status != 0) {
+ lua_pushnil(L);
+ lua_pushnumber(L, status);
+ return 2;
+ }
+ else {
+ int i = 0;
+ while (!lua_isnull(L1, ++i))
+ lua_pushstring(L, lua_tostring(L1, i));
+ return i-1;
+ }
+}
+
+static int settagmethod (lua_State *L) {
+ int tag = luaL_check_int(L, 1);
+ const char *event = luaL_check_string(L, 2);
+ luaL_checkany(L, 3);
+ lua_gettagmethod(L, tag, event);
+ lua_pushvalue(L, 3);
+ lua_settagmethod(L, tag, event);
+ return 1;
+}
+
+static int pushbool (lua_State *L, int b) {
+ if (b) lua_pushnumber(L, 1);
+ else lua_pushnil(L);
+ return 1;
+}
+
+static int equal (lua_State *L) {
+ return pushbool(L, lua_equal(L, 1, 2));
+}
+
+
+
+/*
+** {======================================================
+** function to test the API with C. It interprets a kind of "assembler"
+** language with calls to the API, so the test can be driven by Lua code
+** =======================================================
+*/
+
+static const char *const delimits = " \t\n,;";
+
+static void skip (const char **pc) {
+ while (**pc != '\0' && strchr(delimits, **pc)) (*pc)++;
+}
+
+static int getnum (lua_State *L, const char **pc) {
+ int res = 0;
+ int sig = 1;
+ skip(pc);
+ if (**pc == '.') {
+ res = (int)lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ (*pc)++;
+ return res;
+ }
+ else if (**pc == '-') {
+ sig = -1;
+ (*pc)++;
+ }
+ while (isdigit(**pc)) res = res*10 + (*(*pc)++) - '0';
+ return sig*res;
+}
+
+static const char *getname (char *buff, const char **pc) {
+ int i = 0;
+ skip(pc);
+ while (**pc != '\0' && !strchr(delimits, **pc))
+ buff[i++] = *(*pc)++;
+ buff[i] = '\0';
+ return buff;
+}
+
+
+#define EQ(s1) (strcmp(s1, inst) == 0)
+
+#define getnum ((getnum)(L, &pc))
+#define getname ((getname)(buff, &pc))
+
+
+static int testC (lua_State *L) {
+ char buff[30];
+ const char *pc = luaL_check_string(L, 1);
+ for (;;) {
+ const char *inst = getname;
+ if EQ("") return 0;
+ else if EQ("isnumber") {
+ lua_pushnumber(L, lua_isnumber(L, getnum));
+ }
+ else if EQ("isstring") {
+ lua_pushnumber(L, lua_isstring(L, getnum));
+ }
+ else if EQ("istable") {
+ lua_pushnumber(L, lua_istable(L, getnum));
+ }
+ else if EQ("iscfunction") {
+ lua_pushnumber(L, lua_iscfunction(L, getnum));
+ }
+ else if EQ("isfunction") {
+ lua_pushnumber(L, lua_isfunction(L, getnum));
+ }
+ else if EQ("isuserdata") {
+ lua_pushnumber(L, lua_isuserdata(L, getnum));
+ }
+ else if EQ("isnil") {
+ lua_pushnumber(L, lua_isnil(L, getnum));
+ }
+ else if EQ("isnull") {
+ lua_pushnumber(L, lua_isnull(L, getnum));
+ }
+ else if EQ("tonumber") {
+ lua_pushnumber(L, lua_tonumber(L, getnum));
+ }
+ else if EQ("tostring") {
+ lua_pushstring(L, lua_tostring(L, getnum));
+ }
+ else if EQ("tonumber") {
+ lua_pushnumber(L, lua_tonumber(L, getnum));
+ }
+ else if EQ("strlen") {
+ lua_pushnumber(L, lua_strlen(L, getnum));
+ }
+ else if EQ("tocfunction") {
+ lua_pushcfunction(L, lua_tocfunction(L, getnum));
+ }
+ else if EQ("return") {
+ return getnum;
+ }
+ else if EQ("gettop") {
+ lua_pushnumber(L, lua_gettop(L));
+ }
+ else if EQ("settop") {
+ lua_settop(L, getnum);
+ }
+ else if EQ("pop") {
+ lua_pop(L, getnum);
+ }
+ else if EQ("pushnum") {
+ lua_pushnumber(L, getnum);
+ }
+ else if EQ("pushvalue") {
+ lua_pushvalue(L, getnum);
+ }
+ else if EQ("remove") {
+ lua_remove(L, getnum);
+ }
+ else if EQ("insert") {
+ lua_insert(L, getnum);
+ }
+ else if EQ("gettable") {
+ lua_gettable(L, getnum);
+ }
+ else if EQ("settable") {
+ lua_settable(L, getnum);
+ }
+ else if EQ("next") {
+ lua_next(L, -2);
+ }
+ else if EQ("concat") {
+ lua_concat(L, getnum);
+ }
+ else if EQ("rawcall") {
+ int narg = getnum;
+ int nres = getnum;
+ lua_rawcall(L, narg, nres);
+ }
+ else if EQ("call") {
+ int narg = getnum;
+ int nres = getnum;
+ lua_call(L, narg, nres);
+ }
+ else if EQ("dostring") {
+ lua_dostring(L, luaL_check_string(L, getnum));
+ }
+ else if EQ("settagmethod") {
+ int tag = getnum;
+ const char *event = getname;
+ lua_settagmethod(L, tag, event);
+ }
+ else if EQ("gettagmethod") {
+ int tag = getnum;
+ const char *event = getname;
+ lua_gettagmethod(L, tag, event);
+ }
+ else if EQ("type") {
+ lua_pushstring(L, lua_typename(L, lua_type(L, getnum)));
+ }
+ else luaL_verror(L, "unknown instruction %.30s", buff);
+ }
+ return 0;
+}
+
+/* }====================================================== */
+
+
+
+static const struct luaL_reg tests_funcs[] = {
+ {"hash", hash_query},
+ {"limits", get_limits},
+ {"listcode", listcode},
+ {"liststrings", liststrings},
+ {"listlocals", listlocals},
+ {"loadlib", loadlib},
+ {"querystr", string_query},
+ {"querytab", table_query},
+ {"testC", testC},
+ {"ref", tref},
+ {"getref", getref},
+ {"unref", unref},
+ {"newuserdata", newuserdata},
+ {"udataval", udataval},
+ {"newstate", newstate},
+ {"closestate", closestate},
+ {"doremote", doremote},
+ {"settagmethod", settagmethod},
+ {"equal", equal},
+ {"totalmem", mem_query}
+};
+
+
+void luaB_opentests (lua_State *L) {
+ lua_newtable(L);
+ lua_getglobals(L);
+ lua_pushvalue(L, -2);
+ lua_setglobals(L);
+ luaL_openl(L, tests_funcs); /* open functions inside new table */
+ lua_setglobals(L); /* restore old table of globals */
+ lua_setglobal(L, "T"); /* set new table as global T */
+}
+
+#endif
diff --git a/src/ltm.c b/src/ltm.c
index 709d5e5f..a20909a1 100644
--- a/src/ltm.c
+++ b/src/ltm.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.c,v 1.25 1999/05/21 19:41:49 roberto Exp $
+** $Id: ltm.c,v 1.56 2000/10/31 13:10:24 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -8,241 +8,156 @@
#include <stdio.h>
#include <string.h>
-#include "lauxlib.h"
+#include "lua.h"
+
+#include "ldo.h"
#include "lmem.h"
#include "lobject.h"
#include "lstate.h"
#include "ltm.h"
-char *luaT_eventname[] = { /* ORDER IM */
- "gettable", "settable", "index", "getglobal", "setglobal", "add",
- "sub", "mul", "div", "pow", "unm", "lt", "le", "gt", "ge",
- "concat", "gc", "function", NULL
+const char *const luaT_eventname[] = { /* ORDER TM */
+ "gettable", "settable", "index", "getglobal", "setglobal", "add", "sub",
+ "mul", "div", "pow", "unm", "lt", "concat", "gc", "function",
+ "le", "gt", "ge", /* deprecated options!! */
+ NULL
};
-static int luaI_checkevent (char *name, char *list[]) {
- int e = luaL_findstring(name, list);
+static int findevent (const char *name) {
+ int i;
+ for (i=0; luaT_eventname[i]; i++)
+ if (strcmp(luaT_eventname[i], name) == 0)
+ return i;
+ return -1; /* name not found */
+}
+
+
+static int luaI_checkevent (lua_State *L, const char *name, int t) {
+ int e = findevent(name);
+ if (e >= TM_N)
+ luaO_verror(L, "event `%.50s' is deprecated", name);
+ if (e == TM_GC && t == LUA_TTABLE)
+ luaO_verror(L, "event `gc' for tables is deprecated");
if (e < 0)
- luaL_verror("`%.50s' is not a valid event name", name);
+ luaO_verror(L, "`%.50s' is not a valid event name", name);
return e;
}
-/* events in LUA_T_NIL are all allowed, since this is used as a
+/* events in LUA_TNIL are all allowed, since this is used as a
* 'placeholder' for "default" fallbacks
*/
-static char luaT_validevents[NUM_TAGS][IM_N] = { /* ORDER LUA_T, ORDER IM */
-{1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /* LUA_T_USERDATA */
-{1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_T_NUMBER */
-{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_T_STRING */
-{0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* LUA_T_ARRAY */
-{1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, /* LUA_T_PROTO */
-{1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, /* LUA_T_CPROTO */
-{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} /* LUA_T_NIL */
+/* ORDER LUA_T, ORDER TM */
+static const char luaT_validevents[NUM_TAGS][TM_N] = {
+ {1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /* LUA_TUSERDATA */
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* LUA_TNIL */
+ {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, /* LUA_TNUMBER */
+ {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_TSTRING */
+ {0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /* LUA_TTABLE */
+ {1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0} /* LUA_TFUNCTION */
};
-static int luaT_validevent (int t, int e) { /* ORDER LUA_T */
- return (t < LUA_T_NIL) ? 1 : luaT_validevents[-t][e];
+int luaT_validevent (int t, int e) { /* ORDER LUA_T */
+ return (t >= NUM_TAGS) ? 1 : luaT_validevents[t][e];
}
-static void init_entry (int tag) {
+static void init_entry (lua_State *L, int tag) {
int i;
- for (i=0; i<IM_N; i++)
- ttype(luaT_getim(tag, i)) = LUA_T_NIL;
+ for (i=0; i<TM_N; i++)
+ luaT_gettm(L, tag, i) = NULL;
+ L->TMtable[tag].collected = NULL;
}
-void luaT_init (void) {
+void luaT_init (lua_State *L) {
int t;
- L->last_tag = -(NUM_TAGS-1);
- luaM_growvector(L->IMtable, 0, NUM_TAGS, struct IM, arrEM, MAX_INT);
- for (t=L->last_tag; t<=0; t++)
- init_entry(t);
+ luaM_growvector(L, L->TMtable, 0, NUM_TAGS, struct TM, "", MAX_INT);
+ L->nblocks += NUM_TAGS*sizeof(struct TM);
+ L->last_tag = NUM_TAGS-1;
+ for (t=0; t<=L->last_tag; t++)
+ init_entry(L, t);
}
-int lua_newtag (void) {
- --L->last_tag;
- luaM_growvector(L->IMtable, -(L->last_tag), 1, struct IM, arrEM, MAX_INT);
- init_entry(L->last_tag);
+LUA_API int lua_newtag (lua_State *L) {
+ luaM_growvector(L, L->TMtable, L->last_tag, 1, struct TM,
+ "tag table overflow", MAX_INT);
+ L->nblocks += sizeof(struct TM);
+ L->last_tag++;
+ init_entry(L, L->last_tag);
return L->last_tag;
}
-static void checktag (int tag) {
- if (!(L->last_tag <= tag && tag <= 0))
- luaL_verror("%d is not a valid tag", tag);
+static void checktag (lua_State *L, int tag) {
+ if (!(0 <= tag && tag <= L->last_tag))
+ luaO_verror(L, "%d is not a valid tag", tag);
}
-void luaT_realtag (int tag) {
- if (!(L->last_tag <= tag && tag < LUA_T_NIL))
- luaL_verror("tag %d was not created by `newtag'", tag);
+void luaT_realtag (lua_State *L, int tag) {
+ if (!validtag(tag))
+ luaO_verror(L, "tag %d was not created by `newtag'", tag);
}
-int lua_copytagmethods (int tagto, int tagfrom) {
+LUA_API int lua_copytagmethods (lua_State *L, int tagto, int tagfrom) {
int e;
- checktag(tagto);
- checktag(tagfrom);
- for (e=0; e<IM_N; e++) {
+ checktag(L, tagto);
+ checktag(L, tagfrom);
+ for (e=0; e<TM_N; e++) {
if (luaT_validevent(tagto, e))
- *luaT_getim(tagto, e) = *luaT_getim(tagfrom, e);
+ luaT_gettm(L, tagto, e) = luaT_gettm(L, tagfrom, e);
}
return tagto;
}
-int luaT_effectivetag (TObject *o) {
- int t;
- switch (t = ttype(o)) {
- case LUA_T_ARRAY:
- return o->value.a->htag;
- case LUA_T_USERDATA: {
- int tag = o->value.ts->u.d.tag;
- return (tag >= 0) ? LUA_T_USERDATA : tag;
- }
- case LUA_T_CLOSURE:
- return o->value.cl->consts[0].ttype;
-#ifdef DEBUG
- case LUA_T_PMARK: case LUA_T_CMARK:
- case LUA_T_CLMARK: case LUA_T_LINE:
- LUA_INTERNALERROR("invalid type");
-#endif
- default:
- return t;
+int luaT_tag (const TObject *o) {
+ int t = ttype(o);
+ switch (t) {
+ case LUA_TUSERDATA: return tsvalue(o)->u.d.tag;
+ case LUA_TTABLE: return hvalue(o)->htag;
+ default: return t;
}
}
-TObject *luaT_gettagmethod (int t, char *event) {
- int e = luaI_checkevent(event, luaT_eventname);
- checktag(t);
- if (luaT_validevent(t, e))
- return luaT_getim(t,e);
- else
- return &luaO_nilobject;
-}
-
-
-void luaT_settagmethod (int t, char *event, TObject *func) {
- TObject temp;
- int e = luaI_checkevent(event, luaT_eventname);
- checktag(t);
- if (!luaT_validevent(t, e))
- luaL_verror("cannot change tag method `%.20s' for type `%.20s'%.20s",
- luaT_eventname[e], luaO_typenames[-t],
- (t == LUA_T_ARRAY || t == LUA_T_USERDATA) ? " with default tag"
- : "");
- temp = *func;
- *func = *luaT_getim(t,e);
- *luaT_getim(t, e) = temp;
-}
-
-
-char *luaT_travtagmethods (int (*fn)(TObject *)) { /* ORDER IM */
+LUA_API void lua_gettagmethod (lua_State *L, int t, const char *event) {
int e;
- for (e=IM_GETTABLE; e<=IM_FUNCTION; e++) {
- int t;
- for (t=0; t>=L->last_tag; t--)
- if (fn(luaT_getim(t,e)))
- return luaT_eventname[e];
+ e = luaI_checkevent(L, event, t);
+ checktag(L, t);
+ if (luaT_validevent(t, e) && luaT_gettm(L, t, e)) {
+ clvalue(L->top) = luaT_gettm(L, t, e);
+ ttype(L->top) = LUA_TFUNCTION;
}
- return NULL;
-}
-
-
-/*
-* ===================================================================
-* compatibility with old fallback system
-*/
-#ifdef LUA_COMPAT2_5
-
-#include "lapi.h"
-#include "lstring.h"
-
-static void errorFB (void)
-{
- lua_Object o = lua_getparam(1);
- if (lua_isstring(o))
- fprintf(stderr, "lua: %s\n", lua_getstring(o));
else
- fprintf(stderr, "lua: unknown error\n");
-}
-
-
-static void nilFB (void) { }
-
-
-static void typeFB (void) {
- lua_error("unexpected type");
+ ttype(L->top) = LUA_TNIL;
+ incr_top;
}
-static void fillvalids (IMS e, TObject *func) {
- int t;
- for (t=LUA_T_NIL; t<=LUA_T_USERDATA; t++)
- if (luaT_validevent(t, e))
- *luaT_getim(t, e) = *func;
-}
-
-
-void luaT_setfallback (void) {
- static char *oldnames [] = {"error", "getglobal", "arith", "order", NULL};
- TObject oldfunc;
- lua_CFunction replace;
- char *name = luaL_check_string(1);
- lua_Object func = lua_getparam(2);
- luaL_arg_check(lua_isfunction(func), 2, "function expected");
- switch (luaL_findstring(name, oldnames)) {
- case 0: { /* old error fallback */
- TObject *em = &(luaS_new("_ERRORMESSAGE")->u.s.globalval);
- oldfunc = *em;
- *em = *luaA_Address(func);
- replace = errorFB;
- break;
- }
- case 1: /* old getglobal fallback */
- oldfunc = *luaT_getim(LUA_T_NIL, IM_GETGLOBAL);
- *luaT_getim(LUA_T_NIL, IM_GETGLOBAL) = *luaA_Address(func);
- replace = nilFB;
- break;
- case 2: { /* old arith fallback */
- int i;
- oldfunc = *luaT_getim(LUA_T_NUMBER, IM_POW);
- for (i=IM_ADD; i<=IM_UNM; i++) /* ORDER IM */
- fillvalids(i, luaA_Address(func));
- replace = typeFB;
+LUA_API void lua_settagmethod (lua_State *L, int t, const char *event) {
+ int e = luaI_checkevent(L, event, t);
+ checktag(L, t);
+ if (!luaT_validevent(t, e))
+ luaO_verror(L, "cannot change `%.20s' tag method for type `%.20s'%.20s",
+ luaT_eventname[e], luaO_typenames[t],
+ (t == LUA_TTABLE || t == LUA_TUSERDATA) ?
+ " with default tag" : "");
+ switch (ttype(L->top - 1)) {
+ case LUA_TNIL:
+ luaT_gettm(L, t, e) = NULL;
break;
- }
- case 3: { /* old order fallback */
- int i;
- oldfunc = *luaT_getim(LUA_T_NIL, IM_LT);
- for (i=IM_LT; i<=IM_GE; i++) /* ORDER IM */
- fillvalids(i, luaA_Address(func));
- replace = typeFB;
+ case LUA_TFUNCTION:
+ luaT_gettm(L, t, e) = clvalue(L->top - 1);
break;
- }
- default: {
- int e;
- if ((e = luaL_findstring(name, luaT_eventname)) >= 0) {
- oldfunc = *luaT_getim(LUA_T_NIL, e);
- fillvalids(e, luaA_Address(func));
- replace = (e == IM_GC || e == IM_INDEX) ? nilFB : typeFB;
- }
- else {
- luaL_verror("`%.50s' is not a valid fallback name", name);
- replace = NULL; /* to avoid warnings */
- }
- }
+ default:
+ lua_error(L, "tag method must be a function (or nil)");
}
- if (oldfunc.ttype != LUA_T_NIL)
- luaA_pushobject(&oldfunc);
- else
- lua_pushcfunction(replace);
+ L->top--;
}
-#endif
diff --git a/src/ltm.h b/src/ltm.h
index 845ea153..3bd8e827 100644
--- a/src/ltm.h
+++ b/src/ltm.h
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.h,v 1.5 1999/01/15 13:11:57 roberto Exp $
+** $Id: ltm.h,v 1.18 2000/10/05 13:00:17 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -13,50 +13,47 @@
/*
* WARNING: if you change the order of this enumeration,
-* grep "ORDER IM"
+* grep "ORDER TM"
*/
typedef enum {
- IM_GETTABLE = 0,
- IM_SETTABLE,
- IM_INDEX,
- IM_GETGLOBAL,
- IM_SETGLOBAL,
- IM_ADD,
- IM_SUB,
- IM_MUL,
- IM_DIV,
- IM_POW,
- IM_UNM,
- IM_LT,
- IM_LE,
- IM_GT,
- IM_GE,
- IM_CONCAT,
- IM_GC,
- IM_FUNCTION
-} IMS;
-
-#define IM_N 18
-
-
-struct IM {
- TObject int_method[IM_N];
+ TM_GETTABLE = 0,
+ TM_SETTABLE,
+ TM_INDEX,
+ TM_GETGLOBAL,
+ TM_SETGLOBAL,
+ TM_ADD,
+ TM_SUB,
+ TM_MUL,
+ TM_DIV,
+ TM_POW,
+ TM_UNM,
+ TM_LT,
+ TM_CONCAT,
+ TM_GC,
+ TM_FUNCTION,
+ TM_N /* number of elements in the enum */
+} TMS;
+
+
+struct TM {
+ Closure *method[TM_N];
+ TString *collected; /* list of garbage-collected udata with this tag */
};
-#define luaT_getim(tag,event) (&L->IMtable[-(tag)].int_method[event])
-#define luaT_getimbyObj(o,e) (luaT_getim(luaT_effectivetag(o),(e)))
+#define luaT_gettm(L,tag,event) (L->TMtable[tag].method[event])
+#define luaT_gettmbyObj(L,o,e) (luaT_gettm((L),luaT_tag(o),(e)))
-extern char *luaT_eventname[];
+#define validtag(t) (NUM_TAGS <= (t) && (t) <= L->last_tag)
-void luaT_init (void);
-void luaT_realtag (int tag);
-int luaT_effectivetag (TObject *o);
-void luaT_settagmethod (int t, char *event, TObject *func);
-TObject *luaT_gettagmethod (int t, char *event);
-char *luaT_travtagmethods (int (*fn)(TObject *));
+extern const char *const luaT_eventname[];
+
+
+void luaT_init (lua_State *L);
+void luaT_realtag (lua_State *L, int tag);
+int luaT_tag (const TObject *o);
+int luaT_validevent (int t, int e); /* used by compatibility module */
-void luaT_setfallback (void); /* only if LUA_COMPAT2_5 */
#endif
diff --git a/src/lua/Makefile b/src/lua/Makefile
index cf5d31b6..5b47161f 100644
--- a/src/lua/Makefile
+++ b/src/lua/Makefile
@@ -1,4 +1,4 @@
-# makefile for lua interpreter
+# makefile for Lua interpreter
LUA= ../..
@@ -14,7 +14,7 @@ T= $(BIN)/lua
all: $T
$T: $(OBJS) $(LIB)/liblua.a $(LIB)/liblualib.a
- $(CC) -o $@ $(OBJS) -L$(LIB) -llua -llualib -lm
+ $(CC) -o $@ $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS)
$(LIB)/liblua.a:
cd ..; $(MAKE)
diff --git a/src/lua/README b/src/lua/README
index db2eafb7..832fb5bf 100644
--- a/src/lua/README
+++ b/src/lua/README
@@ -1,38 +1,40 @@
-This client is a sample lua interpreter.
+This is lua, a sample Lua interpreter.
It can be used as a batch interpreter and also interactively.
-
-Here are the options it understands:
-
+There are man pages for it in both nroff and html in ../../doc.
+
+Here are the options that it understands:
+ - execute stdin as a file
+ -c close Lua when exiting
+ -e stat execute string `stat'
+ -f name execute file `name' with remaining arguments in table `arg'
+ -i enter interactive mode with prompt
+ -q enter interactive mode without prompt
+ -sNUM set stack size to NUM (must be the first option)
-v print version information
- -d turn debug on
- -e stat dostring `stat'
- -q interactive mode without prompt
- -i interactive mode with prompt
- - executes stdin as a file
- a=b sets global `a' with string `b' (no need to quote b)
- name dofile `name'
+ a=b set global `a' to string `b'
+ name execute file `name'
If no options are given, then it reads lines from stdin and executes them
-as they are read. So, each line must contain a complete statement.
+as they are read -- so, each line must contain a complete statement.
To span a statement across several lines, end each line with a backslash '\'.
To change the prompt, set the global variable _PROMPT to whatever you want.
-You can do after calling the interpreter or on the command line with
- _PROMPT="lua: "
-for example.
+You can do this after calling the interpreter or on the command line with
+ lua _PROMPT="lua: " -i
+for example. Note that you need "-i" in this case.
You must be careful when using quotes on the command line because they are
usually handled by the shell.
This interpreter is good for using Lua as a standalone language.
-For a minimal interpreter, see etc/min.c.
+For a minimal interpreter, see ../../etc/min.c.
If your application simply exports new functions to Lua (which is common),
-then you can use this interpreter unmodified: just define a function
-
- void lua_userinit (void)
-
-in your code. In this function, you should do whatever initializations are
-need, typically exporting your functions to Lua.
-If you use this scheme, you must explicily open any standard libraries you need.
-See ../lib/linit.c
+then you can use this interpreter (almost) unmodified, as follows:
+First, define a function
+ void myinit (lua_State *L)
+in your own code. In this function, you should do whatever initializations
+are needed by your application, typically exporting your functions to Lua.
+Then, add a call "myinit(L)" in lua.c after the place marked
+ "add your libraries here"
+Of course, you can use any name instead of "myinit".
diff --git a/src/lua/lua.c b/src/lua/lua.c
index 5acd6173..2da857e1 100644
--- a/src/lua/lua.c
+++ b/src/lua/lua.c
@@ -1,5 +1,5 @@
/*
-** $Id: lua.c,v 1.21 1999/07/02 18:22:38 roberto Exp $
+** $Id: lua.c,v 1.55 2000/10/20 16:36:32 roberto Exp $
** Lua stand-alone interpreter
** See Copyright Notice in lua.h
*/
@@ -11,24 +11,51 @@
#include <string.h>
#include "lua.h"
+
#include "luadebug.h"
#include "lualib.h"
+static lua_State *L = NULL;
+
+
+#ifndef PROMPT
+#define PROMPT "> "
+#endif
+
#ifdef _POSIX_SOURCE
#include <unistd.h>
#else
-#define isatty(x) (x==0) /* assume stdin is a tty */
+static int isatty (int x) { return x==0; } /* assume stdin is a tty */
#endif
+/*
+** global options
+*/
+struct Options {
+ int toclose;
+ int stacksize;
+};
+
+
typedef void (*handler)(int); /* type for signal actions */
static void laction (int i);
-static lua_LHFunction old_linehook = NULL;
-static lua_CHFunction old_callhook = NULL;
+static lua_Hook old_linehook = NULL;
+static lua_Hook old_callhook = NULL;
+
+
+static void userinit (void) {
+ lua_baselibopen(L);
+ lua_iolibopen(L);
+ lua_strlibopen(L);
+ lua_mathlibopen(L);
+ lua_dblibopen(L);
+ /* add your libraries here */
+}
static handler lreset (void) {
@@ -37,66 +64,125 @@ static handler lreset (void) {
static void lstop (void) {
- lua_setlinehook(old_linehook);
- lua_setcallhook(old_callhook);
+ lua_setlinehook(L, old_linehook);
+ lua_setcallhook(L, old_callhook);
lreset();
- lua_error("interrupted!");
+ lua_error(L, "interrupted!");
}
static void laction (int i) {
+ (void)i; /* to avoid warnings */
signal(SIGINT, SIG_DFL); /* if another SIGINT happens before lstop,
terminate process (default action) */
- old_linehook = lua_setlinehook((lua_LHFunction)lstop);
- old_callhook = lua_setcallhook((lua_CHFunction)lstop);
+ old_linehook = lua_setlinehook(L, (lua_Hook)lstop);
+ old_callhook = lua_setcallhook(L, (lua_Hook)lstop);
}
-static int ldo (int (*f)(char *), char *name) {
+static int ldo (int (*f)(lua_State *l, const char *), const char *name) {
int res;
handler h = lreset();
- res = f(name); /* dostring | dofile */
+ int top = lua_gettop(L);
+ res = f(L, name); /* dostring | dofile */
+ lua_settop(L, top); /* remove eventual results */
signal(SIGINT, h); /* restore old action */
+ /* Lua gives no message in such cases, so lua.c provides one */
+ if (res == LUA_ERRMEM) {
+ fprintf(stderr, "lua: memory allocation error\n");
+ }
+ else if (res == LUA_ERRERR)
+ fprintf(stderr, "lua: error in error message\n");
return res;
}
static void print_message (void) {
fprintf(stderr,
-"Lua: command line options:\n"
-" -v print version information\n"
-" -d turn debug on\n"
-" -e stat dostring `stat'\n"
-" -q interactive mode without prompt\n"
-" -i interactive mode with prompt\n"
-" - executes stdin as a file\n"
-" a=b sets global `a' with string `b'\n"
-" name dofile `name'\n\n");
+ "usage: lua [options]. Available options are:\n"
+ " - execute stdin as a file\n"
+ " -c close Lua when exiting\n"
+ " -e stat execute string `stat'\n"
+ " -f name execute file `name' with remaining arguments in table `arg'\n"
+ " -i enter interactive mode with prompt\n"
+ " -q enter interactive mode without prompt\n"
+ " -sNUM set stack size to NUM (must be the first option)\n"
+ " -v print version information\n"
+ " a=b set global `a' to string `b'\n"
+ " name execute file `name'\n"
+);
+}
+
+
+static void print_version (void) {
+ printf("%.80s %.80s\n", LUA_VERSION, LUA_COPYRIGHT);
}
static void assign (char *arg) {
- if (strlen(arg) >= 500)
- fprintf(stderr, "lua: shell argument too long");
- else {
- char buffer[500];
- char *eq = strchr(arg, '=');
- lua_pushstring(eq+1);
- strncpy(buffer, arg, eq-arg);
- buffer[eq-arg] = 0;
- lua_setglobal(buffer);
+ char *eq = strchr(arg, '=');
+ *eq = '\0'; /* spilt `arg' in two strings (name & value) */
+ lua_pushstring(L, eq+1);
+ lua_setglobal(L, arg);
+}
+
+
+static void getargs (char *argv[]) {
+ int i;
+ lua_newtable(L);
+ for (i=0; argv[i]; i++) {
+ /* arg[i] = argv[i] */
+ lua_pushnumber(L, i);
+ lua_pushstring(L, argv[i]);
+ lua_settable(L, -3);
+ }
+ /* arg.n = maximum index in table `arg' */
+ lua_pushstring(L, "n");
+ lua_pushnumber(L, i-1);
+ lua_settable(L, -3);
+}
+
+
+static int l_getargs (lua_State *l) {
+ char **argv = (char **)lua_touserdata(l, -1);
+ getargs(argv);
+ return 1;
+}
+
+
+static int file_input (const char *argv) {
+ int result = ldo(lua_dofile, argv);
+ if (result) {
+ if (result == LUA_ERRFILE) {
+ fprintf(stderr, "lua: cannot execute file ");
+ perror(argv);
+ }
+ return EXIT_FAILURE;
}
+ else
+ return EXIT_SUCCESS;
}
-static void manual_input (int prompt) {
+/* maximum length of an input string */
+#ifndef MAXINPUT
+#define MAXINPUT BUFSIZ
+#endif
+
+static void manual_input (int version, int prompt) {
int cont = 1;
+ if (version) print_version();
while (cont) {
- char buffer[BUFSIZ];
+ char buffer[MAXINPUT];
int i = 0;
- lua_beginblock();
- if (prompt)
- printf("%s", lua_getstring(lua_getglobal("_PROMPT")));
+ if (prompt) {
+ const char *s;
+ lua_getglobal(L, "_PROMPT");
+ s = lua_tostring(L, -1);
+ if (!s) s = PROMPT;
+ fputs(s, stdout);
+ lua_pop(L, 1); /* remove global */
+ }
for(;;) {
int c = getchar();
if (c == EOF) {
@@ -108,81 +194,129 @@ static void manual_input (int prompt) {
buffer[i-1] = '\n';
else break;
}
- else if (i >= BUFSIZ-1) {
- fprintf(stderr, "lua: argument line too long\n");
+ else if (i >= MAXINPUT-1) {
+ fprintf(stderr, "lua: input line too long\n");
break;
}
else buffer[i++] = (char)c;
}
buffer[i] = '\0';
ldo(lua_dostring, buffer);
- lua_endblock();
+ lua_settop(L, 0); /* remove eventual results */
}
printf("\n");
}
-int main (int argc, char *argv[])
-{
- int i;
- lua_open();
- lua_pushstring("> "); lua_setglobal("_PROMPT");
- lua_userinit();
- if (argc < 2) { /* no arguments? */
+static int handle_argv (char *argv[], struct Options *opt) {
+ if (opt->stacksize > 0) argv++; /* skip option `-s' (if present) */
+ if (*argv == NULL) { /* no more arguments? */
if (isatty(0)) {
- printf("%s %s\n", LUA_VERSION, LUA_COPYRIGHT);
- manual_input(1);
+ manual_input(1, 1);
}
else
ldo(lua_dofile, NULL); /* executes stdin as a file */
}
- else for (i=1; i<argc; i++) {
- if (argv[i][0] == '-') { /* option? */
- switch (argv[i][1]) {
- case 0:
- ldo(lua_dofile, NULL); /* executes stdin as a file */
- break;
- case 'i':
- manual_input(1);
- break;
- case 'q':
- manual_input(0);
- break;
- case 'd':
- lua_setdebug(1);
- break;
- case 'v':
- printf("%s %s\n(written by %s)\n\n",
- LUA_VERSION, LUA_COPYRIGHT, LUA_AUTHORS);
- break;
- case 'e':
- i++;
- if (ldo(lua_dostring, argv[i]) != 0) {
- fprintf(stderr, "lua: error running argument `%s'\n", argv[i]);
- return 1;
+ else { /* other arguments; loop over them */
+ int i;
+ for (i = 0; argv[i] != NULL; i++) {
+ if (argv[i][0] != '-') { /* not an option? */
+ if (strchr(argv[i], '='))
+ assign(argv[i]);
+ else
+ if (file_input(argv[i]) != EXIT_SUCCESS)
+ return EXIT_FAILURE; /* stop if file fails */
+ }
+ else switch (argv[i][1]) { /* option */
+ case 0: {
+ ldo(lua_dofile, NULL); /* executes stdin as a file */
+ break;
+ }
+ case 'i': {
+ manual_input(0, 1);
+ break;
+ }
+ case 'q': {
+ manual_input(0, 0);
+ break;
+ }
+ case 'c': {
+ opt->toclose = 1;
+ break;
+ }
+ case 'v': {
+ print_version();
+ break;
+ }
+ case 'e': {
+ i++;
+ if (argv[i] == NULL) {
+ print_message();
+ return EXIT_FAILURE;
+ }
+ if (ldo(lua_dostring, argv[i]) != 0) {
+ fprintf(stderr, "lua: error running argument `%.99s'\n", argv[i]);
+ return EXIT_FAILURE;
+ }
+ break;
+ }
+ case 'f': {
+ i++;
+ if (argv[i] == NULL) {
+ print_message();
+ return EXIT_FAILURE;
+ }
+ getargs(argv+i); /* collect remaining arguments */
+ lua_setglobal(L, "arg");
+ return file_input(argv[i]); /* stop scanning arguments */
+ }
+ case 's': {
+ fprintf(stderr, "lua: stack size (`-s') must be the first option\n");
+ return EXIT_FAILURE;
+ }
+ default: {
+ print_message();
+ return EXIT_FAILURE;
}
- break;
- default:
- print_message();
- exit(1);
- }
- }
- else if (strchr(argv[i], '='))
- assign(argv[i]);
- else {
- int result = ldo(lua_dofile, argv[i]);
- if (result) {
- if (result == 2) {
- fprintf(stderr, "lua: cannot execute file ");
- perror(argv[i]);
}
- exit(1);
- }
}
}
-#ifdef DEBUG
- lua_close();
-#endif
- return 0;
+ return EXIT_SUCCESS;
+}
+
+
+static void getstacksize (int argc, char *argv[], struct Options *opt) {
+ if (argc >= 2 && argv[1][0] == '-' && argv[1][1] == 's') {
+ int stacksize = atoi(&argv[1][2]);
+ if (stacksize <= 0) {
+ fprintf(stderr, "lua: invalid stack size ('%.20s')\n", &argv[1][2]);
+ exit(EXIT_FAILURE);
+ }
+ opt->stacksize = stacksize;
+ }
+ else
+ opt->stacksize = 0; /* no stack size */
+}
+
+
+static void register_getargs (char *argv[]) {
+ lua_pushuserdata(L, argv);
+ lua_pushcclosure(L, l_getargs, 1);
+ lua_setglobal(L, "getargs");
+}
+
+
+int main (int argc, char *argv[]) {
+ struct Options opt;
+ int status;
+ opt.toclose = 0;
+ getstacksize(argc, argv, &opt); /* handle option `-s' */
+ L = lua_open(opt.stacksize); /* create state */
+ userinit(); /* open libraries */
+ register_getargs(argv); /* create `getargs' function */
+ status = handle_argv(argv+1, &opt);
+ if (opt.toclose)
+ lua_close(L);
+ return status;
}
diff --git a/src/luac/Makefile b/src/luac/Makefile
index e2950e60..4517d82b 100644
--- a/src/luac/Makefile
+++ b/src/luac/Makefile
@@ -1,12 +1,12 @@
-# makefile for lua compiler
+# makefile for Lua compiler
LUA= ../..
include $(LUA)/config
INCS= -I$(INC) $(EXTRA_INCS) -I..
-OBJS= dump.o luac.o opcode.o opt.o print.o stubs.o test.o
-SRCS= dump.c luac.c opcode.c opt.c print.c stubs.c test.c luac.h opcode.h
+OBJS= dump.o luac.o opt.o print.o stubs.o
+SRCS= dump.c luac.c opt.c print.c stubs.c luac.h print.h
T= $(BIN)/luac
diff --git a/src/luac/README b/src/luac/README
index 9fba74bb..8d8bb491 100644
--- a/src/luac/README
+++ b/src/luac/README
@@ -1,28 +1,22 @@
+This is luac, the Lua compiler.
+There are man pages for it in both nroff and html in ../../doc.
+
luac translates Lua programs into binary files that can be loaded and executed
with lua_dofile in C or with dofile in Lua.
-The main advantages of pre-compiling chunks are: faster loading,
-protecting source code from user changes, off-line syntax error detection.
+The main advantages of pre-compiling chunks are: faster loading, protecting
+source code from user changes, and off-line syntax error detection.
luac can also be used to learn about the Lua virtual machine.
Here are the options that luac understands:
- -c compile (default)
- -d generate debugging information
- -D name predefine 'name' for conditional compilation
- -l list (default for -u)
- -n save numbers in native format (file may not be portable)
- -o file output file for -c (default is "luac.out")
- -O optimize
- -p parse only
- -q quiet (default for -c)
- -t test code integrity
- -u undump
- -U name undefine 'name' for conditional compilation
- -v show version information
- -V verbose
- - compile "stdin"
+ - process stdin
+ -l list
+ -o file output file (default is "luac.out")
+ -p parse only
+ -s strip debug information
+ -t test code integrity
+ -v show version information
-Finally, luac is an example of how to use the internals of Lua (politely).
-Also, luac does not need the runtime code and stubs.c makes sure it is not
+luac is also an example of how to use the internals of Lua (politely).
+Finally, luac does not need the runtime code, and stubs.c makes sure it is not
linked into luac. This file also shows how to avoid linking the parser.
-
diff --git a/src/luac/dump.c b/src/luac/dump.c
index 479ce5d4..149469ba 100644
--- a/src/luac/dump.c
+++ b/src/luac/dump.c
@@ -1,154 +1,121 @@
/*
-** $Id: dump.c,v 1.20 1999/07/02 19:34:26 lhf Exp $
+** $Id: dump.c,v 1.30 2000/10/31 16:57:23 lhf Exp $
** save bytecodes to file
** See Copyright Notice in lua.h
*/
-#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-#include "luac.h"
+#include <string.h>
-#ifdef OLD_ANSI
-#define strerror(e) "(no error message provided by operating system)"
-#endif
+#include "luac.h"
+#define DumpVector(b,n,size,D) fwrite(b,size,n,D)
#define DumpBlock(b,size,D) fwrite(b,size,1,D)
-#define DumpInt DumpLong
+#define DumpByte fputc
-static void DumpWord(int i, FILE* D)
+static void DumpInt(int x, FILE* D)
{
- int hi= 0x0000FF & (i>>8);
- int lo= 0x0000FF & i;
- fputc(hi,D);
- fputc(lo,D);
+ DumpBlock(&x,sizeof(x),D);
}
-static void DumpLong(long i, FILE* D)
+static void DumpSize(size_t x, FILE* D)
{
- int hi= 0x00FFFF & (i>>16);
- int lo= 0x00FFFF & i;
- DumpWord(hi,D);
- DumpWord(lo,D);
+ DumpBlock(&x,sizeof(x),D);
}
-static void DumpNumber(real x, FILE* D, int native, TProtoFunc* tf)
+static void DumpNumber(Number x, FILE* D)
{
- if (native)
- DumpBlock(&x,sizeof(x),D);
- else
- {
- char b[256];
- int n;
- sprintf(b,NUMBER_FMT"%n",x,&n);
- luaU_str2d(b,tf->source->str); /* help lundump not to fail */
- fputc(n,D);
- DumpBlock(b,n,D);
- }
+ DumpBlock(&x,sizeof(x),D);
}
-static void DumpCode(TProtoFunc* tf, FILE* D)
+static void DumpString(const TString* s, FILE* D)
{
- int size=luaU_codesize(tf);
- DumpLong(size,D);
- DumpBlock(tf->code,size,D);
-}
-
-static void DumpString(char* s, int size, FILE* D)
-{
- if (s==NULL)
- DumpLong(0,D);
+ if (s==NULL || s->str==NULL)
+ DumpSize(0,D);
else
{
- DumpLong(size,D);
- DumpBlock(s,size,D);
+ size_t size=s->len+1; /* include trailing '\0' */
+ DumpSize(size,D);
+ DumpBlock(s->str,size,D);
}
}
-static void DumpTString(TaggedString* s, FILE* D)
+static void DumpCode(const Proto* tf, FILE* D)
{
- if (s==NULL)
- DumpString(NULL,0,D);
- else
- DumpString(s->str,s->u.s.len+1,D);
+ DumpInt(tf->ncode,D);
+ DumpVector(tf->code,tf->ncode,sizeof(*tf->code),D);
}
-static void DumpLocals(TProtoFunc* tf, FILE* D)
+static void DumpLocals(const Proto* tf, FILE* D)
{
- if (tf->locvars==NULL)
- DumpInt(0,D);
- else
+ int i,n=tf->nlocvars;
+ DumpInt(n,D);
+ for (i=0; i<n; i++)
{
- LocVar* v;
- int n=0;
- for (v=tf->locvars; v->line>=0; v++)
- ++n;
- DumpInt(n,D);
- for (v=tf->locvars; v->line>=0; v++)
- {
- DumpInt(v->line,D);
- DumpTString(v->varname,D);
- }
+ DumpString(tf->locvars[i].varname,D);
+ DumpInt(tf->locvars[i].startpc,D);
+ DumpInt(tf->locvars[i].endpc,D);
}
}
-static void DumpFunction(TProtoFunc* tf, FILE* D, int native);
+static void DumpLines(const Proto* tf, FILE* D)
+{
+ DumpInt(tf->nlineinfo,D);
+ DumpVector(tf->lineinfo,tf->nlineinfo,sizeof(*tf->lineinfo),D);
+}
+
+static void DumpFunction(const Proto* tf, FILE* D);
-static void DumpConstants(TProtoFunc* tf, FILE* D, int native)
+static void DumpConstants(const Proto* tf, FILE* D)
{
- int i,n=tf->nconsts;
- DumpInt(n,D);
+ int i,n;
+ DumpInt(n=tf->nkstr,D);
for (i=0; i<n; i++)
- {
- TObject* o=tf->consts+i;
- fputc(-ttype(o),D); /* ttype(o) is negative - ORDER LUA_T */
- switch (ttype(o))
- {
- case LUA_T_NUMBER:
- DumpNumber(nvalue(o),D,native,tf);
- break;
- case LUA_T_STRING:
- DumpTString(tsvalue(o),D);
- break;
- case LUA_T_PROTO:
- DumpFunction(tfvalue(o),D,native);
- break;
- case LUA_T_NIL:
- break;
- default: /* cannot happen */
- luaU_badconstant("dump",i,o,tf);
- break;
- }
- }
+ DumpString(tf->kstr[i],D);
+ DumpInt(tf->nknum,D);
+ DumpVector(tf->knum,tf->nknum,sizeof(*tf->knum),D);
+ DumpInt(n=tf->nkproto,D);
+ for (i=0; i<n; i++)
+ DumpFunction(tf->kproto[i],D);
}
-static void DumpFunction(TProtoFunc* tf, FILE* D, int native)
+static void DumpFunction(const Proto* tf, FILE* D)
{
+ DumpString(tf->source,D);
DumpInt(tf->lineDefined,D);
- DumpTString(tf->source,D);
- DumpCode(tf,D);
+ DumpInt(tf->numparams,D);
+ DumpByte(tf->is_vararg,D);
+ DumpInt(tf->maxstacksize,D);
DumpLocals(tf,D);
- DumpConstants(tf,D,native);
+ DumpLines(tf,D);
+ DumpConstants(tf,D);
+ DumpCode(tf,D);
if (ferror(D))
- luaL_verror("write error" IN ": %s (errno=%d)",INLOC,strerror(errno),errno);
+ {
+ perror("luac: write error");
+ exit(1);
+ }
}
-static void DumpHeader(TProtoFunc* Main, FILE* D, int native)
+static void DumpHeader(FILE* D)
{
- fputc(ID_CHUNK,D);
+ DumpByte(ID_CHUNK,D);
fputs(SIGNATURE,D);
- fputc(VERSION,D);
- if (native)
- {
- fputc(sizeof(real),D);
- DumpNumber(TEST_NUMBER,D,native,Main);
- }
- else
- fputc(0,D);
+ DumpByte(VERSION,D);
+ DumpByte(luaU_endianess(),D);
+ DumpByte(sizeof(int),D);
+ DumpByte(sizeof(size_t),D);
+ DumpByte(sizeof(Instruction),D);
+ DumpByte(SIZE_INSTRUCTION,D);
+ DumpByte(SIZE_OP,D);
+ DumpByte(SIZE_B,D);
+ DumpByte(sizeof(Number),D);
+ DumpNumber(TEST_NUMBER,D);
}
-void luaU_dumpchunk(TProtoFunc* Main, FILE* D, int native)
+void luaU_dumpchunk(const Proto* Main, FILE* D)
{
- DumpHeader(Main,D,native);
- DumpFunction(Main,D,native);
+ DumpHeader(D);
+ DumpFunction(Main,D);
}
diff --git a/src/luac/luac.c b/src/luac/luac.c
index 68af1c76..8832de62 100644
--- a/src/luac/luac.c
+++ b/src/luac/luac.c
@@ -1,5 +1,5 @@
/*
-** $Id: luac.c,v 1.17 1999/07/02 19:34:26 lhf Exp $
+** $Id: luac.c,v 1.28 2000/11/06 20:06:27 lhf Exp $
** lua compiler (saves bytecodes to files; also list binary files)
** See Copyright Notice in lua.h
*/
@@ -7,181 +7,197 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "luac.h"
+
#include "lparser.h"
#include "lstate.h"
#include "lzio.h"
+#include "luac.h"
#define OUTPUT "luac.out" /* default output file */
-static FILE* efopen(char* name, char* mode);
-static void doit(int undump, char* filename);
+static void usage(const char* message, const char* arg);
+static int doargs(int argc, const char* argv[]);
+static Proto* load(const char* filename);
+static FILE* efopen(const char* name, const char* mode);
+static void strip(Proto* tf);
+static Proto* combine(Proto** P, int n);
+
+lua_State* lua_state=NULL; /* lazy! */
static int listing=0; /* list bytecodes? */
-static int debugging=0; /* emit debug information? */
static int dumping=1; /* dump bytecodes? */
-static int undumping=0; /* undump bytecodes? */
-static int optimizing=0; /* optimize? */
-static int parsing=0; /* parse only? */
+static int stripping=0; /* strip debug information? */
static int testing=0; /* test integrity? */
-static int verbose=0; /* tell user what is done */
-static int native=0; /* save numbers in native format? */
-static FILE* D; /* output file */
+static const char* output=OUTPUT; /* output file name */
-static void usage(char* op)
+#define IS(s) (strcmp(argv[i],s)==0)
+
+int main(int argc, const char* argv[])
{
- if (op) fprintf(stderr,"luac: unrecognized option '%s'\n",op);
+ Proto** P,*tf;
+ int i=doargs(argc,argv);
+ argc-=i; argv+=i;
+ if (argc<=0) usage("no input files given",NULL);
+ L=lua_open(0);
+ P=luaM_newvector(L,argc,Proto*);
+ for (i=0; i<argc; i++)
+ P[i]=load(IS("-")? NULL : argv[i]);
+ tf=combine(P,argc);
+ if (dumping) luaU_optchunk(tf);
+ if (listing) luaU_printchunk(tf);
+ if (testing) luaU_testchunk(tf);
+ if (dumping)
+ {
+ if (stripping) strip(tf);
+ luaU_dumpchunk(tf,efopen(output,"wb"));
+ }
+ return 0;
+}
+
+static void usage(const char* message, const char* arg)
+{
+ if (message!=NULL)
+ {
+ fprintf(stderr,"luac: "); fprintf(stderr,message,arg); fprintf(stderr,"\n");
+ }
fprintf(stderr,
"usage: luac [options] [filenames]. Available options are:\n"
- " -c\t\tcompile (default)\n"
- " -d\t\tgenerate debugging information\n"
- " -D name\tpredefine 'name' for conditional compilation\n"
- " -l\t\tlist (default for -u)\n"
- " -n\t\tsave numbers in native format (file may not be portable)\n"
- " -o file\toutput file for -c (default is \"" OUTPUT "\")\n"
- " -O\t\toptimize\n"
- " -p\t\tparse only\n"
- " -q\t\tquiet (default for -c)\n"
- " -t\t\ttest code integrity\n"
- " -u\t\tundump\n"
- " -U name\tundefine 'name' for conditional compilation\n"
- " -v\t\tshow version information\n"
- " -V\t\tverbose\n"
- " -\t\tcompile \"stdin\"\n"
+ " - process stdin\n"
+ " -l list\n"
+ " -o file output file (default is \"" OUTPUT "\")\n"
+ " -p parse only\n"
+ " -s strip debug information\n"
+ " -t test code integrity\n"
+ " -v show version information\n"
);
exit(1);
}
-#define IS(s) (strcmp(argv[i],s)==0)
-
-int main(int argc, char* argv[])
+static int doargs(int argc, const char* argv[])
{
- char* d=OUTPUT; /* output file name */
int i;
- lua_open();
for (i=1; i<argc; i++)
{
- if (argv[i][0]!='-') /* end of options */
+ if (*argv[i]!='-') /* end of options */
break;
else if (IS("-")) /* end of options; use stdin */
- break;
- else if (IS("-c")) /* compile (and dump) */
- {
- dumping=1;
- undumping=0;
- }
- else if (IS("-D")) /* $define */
- {
- TaggedString* s=luaS_new(argv[++i]);
- s->u.s.globalval.ttype=LUA_T_NUMBER;
- s->u.s.globalval.value.n=1;
- }
- else if (IS("-d")) /* debug */
- debugging=1;
+ return i;
else if (IS("-l")) /* list */
listing=1;
- else if (IS("-n")) /* native */
- native=1;
else if (IS("-o")) /* output file */
- d=argv[++i];
- else if (IS("-O")) /* optimize */
- optimizing=1;
- else if (IS("-p")) /* parse only */
{
- dumping=0;
- parsing=1;
+ output=argv[++i];
+ if (output==NULL) usage(NULL,NULL);
}
- else if (IS("-q")) /* quiet */
- listing=0;
+ else if (IS("-p")) /* parse only */
+ dumping=0;
+ else if (IS("-s")) /* strip debug information */
+ stripping=1;
else if (IS("-t")) /* test */
- testing=1;
- else if (IS("-u")) /* undump */
{
+ testing=1;
dumping=0;
- undumping=1;
- listing=1;
- }
- else if (IS("-U")) /* undefine */
- {
- TaggedString* s=luaS_new(argv[++i]);
- s->u.s.globalval.ttype=LUA_T_NIL;
}
else if (IS("-v")) /* show version */
- printf("%s %s\n(written by %s)\n\n",LUA_VERSION,LUA_COPYRIGHT,LUA_AUTHORS);
- else if (IS("-V")) /* verbose */
- verbose=1;
- else /* unknown option */
- usage(argv[i]);
- }
- --i; /* fake new argv[0] */
- argc-=i;
- argv+=i;
- if (dumping || parsing)
- {
- if (argc<2) usage(NULL);
- if (dumping)
{
- for (i=1; i<argc; i++) /* play safe with output file */
- if (IS(d)) luaL_verror("will not overwrite input file \"%s\"",d);
- D=efopen(d,"wb"); /* must open in binary mode */
+ printf("%s %s\n",LUA_VERSION,LUA_COPYRIGHT);
+ if (argc==2) exit(0);
}
- for (i=1; i<argc; i++) doit(0,IS("-")? NULL : argv[i]);
- if (dumping) fclose(D);
+ else /* unknown option */
+ usage("unrecognized option `%s'",argv[i]);
}
- if (undumping)
+ if (i==argc && (listing || testing))
{
- if (argc<2)
- doit(1,OUTPUT);
- else
- for (i=1; i<argc; i++) doit(1,IS("-")? NULL : argv[i]);
+ dumping=0;
+ argv[--i]=OUTPUT;
}
- return 0;
+ return i;
}
-static void do_compile(ZIO* z)
+static Proto* load(const char* filename)
{
- TProtoFunc* Main;
- if (optimizing) L->debug=0;
- if (debugging) L->debug=1;
- Main=luaY_parser(z);
- if (optimizing) luaU_optchunk(Main);
- if (listing) luaU_printchunk(Main);
- if (testing) luaU_testchunk(Main);
- if (dumping) luaU_dumpchunk(Main,D,native);
+ Proto* tf;
+ ZIO z;
+ char source[512];
+ FILE* f;
+ int c,undump;
+ if (filename==NULL)
+ {
+ f=stdin;
+ filename="(stdin)";
+ }
+ else
+ f=efopen(filename,"r");
+ c=ungetc(fgetc(f),f);
+ if (ferror(f))
+ {
+ fprintf(stderr,"luac: cannot read from ");
+ perror(filename);
+ exit(1);
+ }
+ undump=(c==ID_CHUNK);
+ if (undump && f!=stdin)
+ {
+ fclose(f);
+ f=efopen(filename,"rb");
+ }
+ sprintf(source,"@%.*s",Sizeof(source)-2,filename);
+ luaZ_Fopen(&z,f,source);
+ tf = undump ? luaU_undump(L,&z) : luaY_parser(L,&z);
+ if (f!=stdin) fclose(f);
+ return tf;
}
-static void do_undump(ZIO* z)
+static Proto* combine(Proto** P, int n)
{
- for (;;)
+ if (n==1)
+ return P[0];
+ else
{
- TProtoFunc* Main=luaU_undump1(z);
- if (Main==NULL) break;
- if (optimizing) luaU_optchunk(Main);
- if (listing) luaU_printchunk(Main);
- if (testing) luaU_testchunk(Main);
+ int i,pc=0;
+ Proto* tf=luaF_newproto(L);
+ tf->source=luaS_new(L,"=(luac)");
+ tf->maxstacksize=1;
+ tf->kproto=P;
+ tf->nkproto=n;
+ tf->ncode=2*n+1;
+ tf->code=luaM_newvector(L,tf->ncode,Instruction);
+ for (i=0; i<n; i++)
+ {
+ tf->code[pc++]=CREATE_AB(OP_CLOSURE,i,0);
+ tf->code[pc++]=CREATE_AB(OP_CALL,0,0);
+ }
+ tf->code[pc++]=OP_END;
+ return tf;
}
}
-static void doit(int undump, char* filename)
+static void strip(Proto* tf)
{
- FILE* f= (filename==NULL) ? stdin : efopen(filename, undump ? "rb" : "r");
- ZIO z;
- char source[255+2]; /* +2 for '@' and '\0' */
- luaL_filesource(source,filename,sizeof(source));
- zFopen(&z,f,source);
- if (verbose) fprintf(stderr,"%s\n",source+1);
- if (undump) do_undump(&z); else do_compile(&z);
- if (f!=stdin) fclose(f);
+ int i,n=tf->nkproto;
+ tf->lineinfo=NULL;
+ tf->nlineinfo=0;
+ tf->source=luaS_new(L,"=(none)");
+ tf->locvars=NULL;
+ tf->nlocvars=0;
+ for (i=0; i<n; i++) strip(tf->kproto[i]);
}
-static FILE* efopen(char* name, char* mode)
+static FILE* efopen(const char* name, const char* mode)
{
FILE* f=fopen(name,mode);
if (f==NULL)
{
- fprintf(stderr,"luac: cannot open %sput file ",mode[0]=='r' ? "in" : "out");
+ fprintf(stderr,"luac: cannot open %sput file ",*mode=='r' ? "in" : "out");
perror(name);
exit(1);
}
return f;
}
+
+void luaU_testchunk(const Proto* Main)
+{
+ UNUSED(Main);
+ fprintf(stderr,"luac: -t not operational in this version\n");
+ exit(1);
+}
diff --git a/src/luac/luac.h b/src/luac/luac.h
index 1ae5267b..f8987cf2 100644
--- a/src/luac/luac.h
+++ b/src/luac/luac.h
@@ -1,48 +1,31 @@
/*
-** $Id: luac.h,v 1.11 1999/07/02 19:34:26 lhf Exp $
+** $Id: luac.h,v 1.18 2000/10/31 16:57:23 lhf Exp $
** definitions for luac
** See Copyright Notice in lua.h
*/
-#include "lauxlib.h"
+#include "ldebug.h"
#include "lfunc.h"
#include "lmem.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lstring.h"
+#include "ltable.h"
#include "lundump.h"
-typedef struct
-{
- char* name; /* name of opcode */
- int op; /* value of opcode */
- int class; /* class of opcode (byte variant) */
- int args; /* types of arguments (operands) */
- int arg; /* arg #1 */
- int arg2; /* arg #2 */
-} Opcode;
+extern lua_State *lua_state;
+#define L lua_state /* lazy! */
/* from dump.c */
-void luaU_dumpchunk(TProtoFunc* Main, FILE* D, int native);
-
-/* from opcode.c */
-int luaU_opcodeinfo(TProtoFunc* tf, Byte* p, Opcode* I, char* xFILE, int xLINE);
-int luaU_codesize(TProtoFunc* tf);
+void luaU_dumpchunk(const Proto* Main, FILE* D);
/* from opt.c */
-void luaU_optchunk(TProtoFunc* Main);
+void luaU_optchunk(Proto* Main);
/* from print.c */
-void luaU_printchunk(TProtoFunc* Main);
+void luaU_printchunk(const Proto* Main);
/* from test.c */
-void luaU_testchunk(TProtoFunc* Main);
-TObject* luaU_getconstant(TProtoFunc* tf, int i, int at);
-
-#define INFO(tf,p,I) luaU_opcodeinfo(tf,p,I,__FILE__,__LINE__)
+void luaU_testchunk(const Proto* Main);
-/* fake (but convenient) opcodes */
-#define NOP 255
-#define STACK (-1)
-#define ARGS (-2)
-#define VARARGS (-3)
+#define Sizeof(x) ((int)sizeof(x))
diff --git a/src/luac/opcode.c b/src/luac/opcode.c
deleted file mode 100644
index c2d4ae7d..00000000
--- a/src/luac/opcode.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
-** $Id: opcode.c,v 1.9 1999/05/25 19:58:55 lhf Exp $
-** opcode information
-** See Copyright Notice in lua.h
-*/
-
-#include "luac.h"
-
-enum { /* for Opcode.args */
- ARGS_NONE,
- ARGS_B,
- ARGS_W,
- ARGS_BB,
- ARGS_WB
-};
-
-static Opcode Info[]= /* ORDER lopcodes.h */
-{
-#include "opcode.h"
-};
-
-static Opcode Fake[]= /* ORDER luac.h */
-{
-{ "NOP", NOP, NOP, ARGS_NONE, -1, -1 },
-{ "STACK", STACK, STACK, ARGS_B, -1, -1 },
-{ "ARGS", ARGS, ARGS, ARGS_B, -1, -1 },
-{ "VARARGS", VARARGS, VARARGS, ARGS_B, -1, -1 },
-};
-
-#define NOPCODES (sizeof(Info)/sizeof(Info[0]))
-
-int luaU_opcodeinfo(TProtoFunc* tf, Byte* p, Opcode* I, char* xFILE, int xLINE)
-{
- Opcode OP;
- Byte* code=tf->code;
- int op=*p;
- int size=1;
- if (p==code) /* first byte is STACK */
- {
- OP=Fake[-STACK];
- OP.arg=op;
- }
- else if (p==code+1) /* second byte is ARGS or VARARGS */
- {
- if (op<ZEROVARARG)
- {
- OP=Fake[-ARGS];
- OP.arg=op;
- }
- else
- {
- OP=Fake[-VARARGS];
- OP.arg=op-ZEROVARARG;
- }
- }
- else if (op==NOP) /* NOP is fake */
- {
- OP=Fake[0];
- }
- else if (op>=NOPCODES) /* cannot happen */
- {
- luaL_verror("[%s:%d] bad opcode %d at pc=%d" IN,
- xFILE,xLINE,op,(int)(p-code),INLOC);
- return 0;
- }
- else /* ordinary opcode */
- {
- OP=Info[op];
- switch (OP.args)
- {
- case ARGS_NONE: size=1;
- break;
- case ARGS_B: size=2; OP.arg=p[1];
- break;
- case ARGS_W: size=3; OP.arg=(p[1]<<8)+p[2];
- break;
- case ARGS_BB: size=3; OP.arg=p[1]; OP.arg2=p[2];
- break;
- case ARGS_WB: size=4; OP.arg=(p[1]<<8)+p[2]; OP.arg2=p[3];
- break;
- default: /* cannot happen */
- luaL_verror("[%s:%d] bad args %d for %s at pc=%d" IN,
- __FILE__,__LINE__,OP.args,OP.name,(int)(p-code),INLOC);
- break;
- }
- }
- *I=OP;
- return size;
-}
-
-int luaU_codesize(TProtoFunc* tf)
-{
- Byte* code=tf->code;
- Byte* p=code;
- for (;;)
- {
- Opcode OP;
- p+=INFO(tf,p,&OP);
- if (OP.op==ENDCODE) break;
- }
- return p-code;
-}
diff --git a/src/luac/opcode.h b/src/luac/opcode.h
deleted file mode 100644
index 4ae910f5..00000000
--- a/src/luac/opcode.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-** $Id: opcode.h,v 1.1 1999/03/25 13:43:05 lhf Exp $
-** opcode info to be #included into opcode.c
-** extracted automatically from lopcodes.h by mkopcodeh -- DO NOT EDIT
-** See Copyright Notice in lua.h
-*/
-{ "ENDCODE", ENDCODE, ENDCODE, ARGS_NONE, -1, -1 },
-{ "RETCODE", RETCODE, RETCODE, ARGS_B, -1, -1 },
-{ "CALL", CALL, CALL, ARGS_BB, -1, -1 },
-{ "TAILCALL", TAILCALL, TAILCALL, ARGS_BB, -1, -1 },
-{ "PUSHNIL", PUSHNIL, PUSHNIL, ARGS_B, -1, -1 },
-{ "POP", POP, POP, ARGS_B, -1, -1 },
-{ "PUSHNUMBERW", PUSHNUMBERW, PUSHNUMBER, ARGS_W, -1, -1 },
-{ "PUSHNUMBER", PUSHNUMBER, PUSHNUMBER, ARGS_B, -1, -1 },
-{ "PUSHNUMBERNEGW", PUSHNUMBERNEGW, PUSHNUMBERNEG, ARGS_W, -1, -1 },
-{ "PUSHNUMBERNEG", PUSHNUMBERNEG, PUSHNUMBERNEG, ARGS_B, -1, -1 },
-{ "PUSHCONSTANTW", PUSHCONSTANTW, PUSHCONSTANT, ARGS_W, -1, -1 },
-{ "PUSHCONSTANT", PUSHCONSTANT, PUSHCONSTANT, ARGS_B, -1, -1 },
-{ "PUSHUPVALUE", PUSHUPVALUE, PUSHUPVALUE, ARGS_B, -1, -1 },
-{ "PUSHLOCAL", PUSHLOCAL, PUSHLOCAL, ARGS_B, -1, -1 },
-{ "GETGLOBALW", GETGLOBALW, GETGLOBAL, ARGS_W, -1, -1 },
-{ "GETGLOBAL", GETGLOBAL, GETGLOBAL, ARGS_B, -1, -1 },
-{ "GETTABLE", GETTABLE, GETTABLE, ARGS_NONE, -1, -1 },
-{ "GETDOTTEDW", GETDOTTEDW, GETDOTTED, ARGS_W, -1, -1 },
-{ "GETDOTTED", GETDOTTED, GETDOTTED, ARGS_B, -1, -1 },
-{ "PUSHSELFW", PUSHSELFW, PUSHSELF, ARGS_W, -1, -1 },
-{ "PUSHSELF", PUSHSELF, PUSHSELF, ARGS_B, -1, -1 },
-{ "CREATEARRAYW", CREATEARRAYW, CREATEARRAY, ARGS_W, -1, -1 },
-{ "CREATEARRAY", CREATEARRAY, CREATEARRAY, ARGS_B, -1, -1 },
-{ "SETLOCAL", SETLOCAL, SETLOCAL, ARGS_B, -1, -1 },
-{ "SETGLOBALW", SETGLOBALW, SETGLOBAL, ARGS_W, -1, -1 },
-{ "SETGLOBAL", SETGLOBAL, SETGLOBAL, ARGS_B, -1, -1 },
-{ "SETTABLEPOP", SETTABLEPOP, SETTABLEPOP, ARGS_NONE, -1, -1 },
-{ "SETTABLE", SETTABLE, SETTABLE, ARGS_B, -1, -1 },
-{ "SETLISTW", SETLISTW, SETLIST, ARGS_WB, -1, -1 },
-{ "SETLIST", SETLIST, SETLIST, ARGS_BB, -1, -1 },
-{ "SETMAP", SETMAP, SETMAP, ARGS_B, -1, -1 },
-{ "NEQOP", NEQOP, NEQOP, ARGS_NONE, -1, -1 },
-{ "EQOP", EQOP, EQOP, ARGS_NONE, -1, -1 },
-{ "LTOP", LTOP, LTOP, ARGS_NONE, -1, -1 },
-{ "LEOP", LEOP, LEOP, ARGS_NONE, -1, -1 },
-{ "GTOP", GTOP, GTOP, ARGS_NONE, -1, -1 },
-{ "GEOP", GEOP, GEOP, ARGS_NONE, -1, -1 },
-{ "ADDOP", ADDOP, ADDOP, ARGS_NONE, -1, -1 },
-{ "SUBOP", SUBOP, SUBOP, ARGS_NONE, -1, -1 },
-{ "MULTOP", MULTOP, MULTOP, ARGS_NONE, -1, -1 },
-{ "DIVOP", DIVOP, DIVOP, ARGS_NONE, -1, -1 },
-{ "POWOP", POWOP, POWOP, ARGS_NONE, -1, -1 },
-{ "CONCOP", CONCOP, CONCOP, ARGS_NONE, -1, -1 },
-{ "MINUSOP", MINUSOP, MINUSOP, ARGS_NONE, -1, -1 },
-{ "NOTOP", NOTOP, NOTOP, ARGS_NONE, -1, -1 },
-{ "ONTJMPW", ONTJMPW, ONTJMP, ARGS_W, -1, -1 },
-{ "ONTJMP", ONTJMP, ONTJMP, ARGS_B, -1, -1 },
-{ "ONFJMPW", ONFJMPW, ONFJMP, ARGS_W, -1, -1 },
-{ "ONFJMP", ONFJMP, ONFJMP, ARGS_B, -1, -1 },
-{ "JMPW", JMPW, JMP, ARGS_W, -1, -1 },
-{ "JMP", JMP, JMP, ARGS_B, -1, -1 },
-{ "IFFJMPW", IFFJMPW, IFFJMP, ARGS_W, -1, -1 },
-{ "IFFJMP", IFFJMP, IFFJMP, ARGS_B, -1, -1 },
-{ "IFTUPJMPW", IFTUPJMPW, IFTUPJMP, ARGS_W, -1, -1 },
-{ "IFTUPJMP", IFTUPJMP, IFTUPJMP, ARGS_B, -1, -1 },
-{ "IFFUPJMPW", IFFUPJMPW, IFFUPJMP, ARGS_W, -1, -1 },
-{ "IFFUPJMP", IFFUPJMP, IFFUPJMP, ARGS_B, -1, -1 },
-{ "CLOSUREW", CLOSUREW, CLOSURE, ARGS_WB, -1, -1 },
-{ "CLOSURE", CLOSURE, CLOSURE, ARGS_BB, -1, -1 },
-{ "SETLINEW", SETLINEW, SETLINE, ARGS_W, -1, -1 },
-{ "SETLINE", SETLINE, SETLINE, ARGS_B, -1, -1 },
-{ "LONGARGW", LONGARGW, LONGARG, ARGS_W, -1, -1 },
-{ "LONGARG", LONGARG, LONGARG, ARGS_B, -1, -1 },
-{ "CHECKSTACK", CHECKSTACK, CHECKSTACK, ARGS_B, -1, -1 },
diff --git a/src/luac/opt.c b/src/luac/opt.c
index e2becc2a..e51a0868 100644
--- a/src/luac/opt.c
+++ b/src/luac/opt.c
@@ -1,5 +1,5 @@
/*
-** $Id: opt.c,v 1.12 1999/07/02 19:34:26 lhf Exp $
+** $Id: opt.c,v 1.22 2000/10/31 16:57:23 lhf Exp $
** optimize bytecodes
** See Copyright Notice in lua.h
*/
@@ -7,275 +7,121 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "luac.h"
-static void FixArg(Byte* p, int i, int j, int isconst)
-{
- if (j==i)
- ;
- else if (i<=MAX_BYTE) /* j<i, so j fits where i did */
- p[1]=j;
- else if (i<=MAX_WORD)
- {
- if (isconst && j<=MAX_BYTE) /* may use byte variant instead */
- {
- p[0]++; /* byte variant follows word variant */
- p[1]=j;
- p[2]=NOP;
- }
- else /* stuck with word variant */
- {
- p[1]=j>>8;
- p[2]=j;
- }
- }
- else /* previous instruction must've been LONGARG */
- {
- if (isconst && j<=MAX_WORD) p[-2]=p[-1]=NOP; else p[-1]=j>>16;
- p[1]=j>>8;
- p[2]=j;
- }
-}
+#include "luac.h"
-static void FixConstants(TProtoFunc* tf, int* C)
+static int MapConstant(Hash* t, int j, const TObject* key)
{
- Byte* code=tf->code;
- Byte* p=code;
- int longarg=0;
- for (;;)
+ const TObject* o=luaH_get(L,t,key);
+ if (ttype(o)==LUA_TNUMBER)
+ return (int) nvalue(o);
+ else
{
- Opcode OP;
- int n=INFO(tf,p,&OP);
- int op=OP.class;
- int i=OP.arg+longarg;
- longarg=0;
- if (op==PUSHCONSTANT || op==GETGLOBAL || op==GETDOTTED ||
- op==PUSHSELF || op==SETGLOBAL || op==CLOSURE)
- FixArg(p,i,C[i],1);
- else if (op==LONGARG) longarg=i<<16;
- else if (op==ENDCODE) break;
- p+=n;
+ TObject val;
+ ttype(&val)=LUA_TNUMBER;
+ nvalue(&val)=j;
+ *luaH_set(L,t,key)=val;
+ LUA_ASSERT(j>=0,"MapConstant returns negative!");
+ return j;
}
}
-#define UNREF 1 /* "type" of unused constants */
-#define BIAS 128 /* mark for used constants */
-
-static void NoUnrefs(TProtoFunc* tf)
+static int MapConstants(Proto* tf, Hash* map)
{
- int i,n=tf->nconsts;
- Byte* code=tf->code;
- Byte* p=code;
- int longarg=0;
- for (;;) /* mark all used constants */
- {
- Opcode OP;
- int n=INFO(tf,p,&OP);
- int op=OP.class;
- int i=OP.arg+longarg;
- longarg=0;
- if (op==PUSHCONSTANT || op==GETGLOBAL || op==GETDOTTED ||
- op==PUSHSELF || op==SETGLOBAL || op==CLOSURE)
- {
- TObject* o=tf->consts+i;
- if (ttype(o)<=0) ttype(o)+=BIAS; /* mark as used */
- }
- else if (op==LONGARG) longarg=i<<16;
- else if (op==ENDCODE) break;
- p+=n;
- }
- for (i=0; i<n; i++) /* mark all unused constants */
+ int i,j,k,n,m=0;
+ TObject o;
+ j=0; n=tf->nknum; ttype(&o)=LUA_TNUMBER;
+ for (i=0; i<n; i++)
{
- TObject* o=tf->consts+i;
- if (ttype(o)<=0)
- ttype(o)=UNREF; /* mark as unused */
- else
- ttype(o)-=BIAS; /* unmark used constant */
+ nvalue(&o)=tf->knum[i];
+ k=MapConstant(map,j,&o);
+ if (k==j) j++;
}
-}
-
-#define CMP(oa,ob,f) memcmp(&f(oa),&f(ob),sizeof(f(oa)))
-
-static int compare(TProtoFunc* tf, int ia, int ib)
-{
- TObject* oa=tf->consts+ia;
- TObject* ob=tf->consts+ib;
- int t=ttype(oa)-ttype(ob);
- if (t) return t;
- switch (ttype(oa))
+ m=j;
+ j=0; n=tf->nkstr; ttype(&o)=LUA_TSTRING;
+ for (i=0; i<n; i++)
{
- case LUA_T_NUMBER: return CMP(oa,ob,nvalue);
- case LUA_T_STRING: return CMP(oa,ob,tsvalue);
- case LUA_T_PROTO: return CMP(oa,ob,tfvalue);
- case LUA_T_NIL: return 0;
- case UNREF: return 0;
- default: return ia-ib; /* cannot happen */
+ tsvalue(&o)=tf->kstr[i];
+ k=MapConstant(map,j,&o);
+ if (k==j) j++;
}
+ return m+j;
}
-static TProtoFunc* TF; /* for sort */
-
-static int compare1(const void* a, const void* b)
-{
- int ia=*(int*)a;
- int ib=*(int*)b;
- int t=compare(TF,ia,ib);
- return (t) ? t : ia-ib;
-}
-
-static void OptConstants(TProtoFunc* tf)
+static void PackConstants(Proto* tf, Hash* map)
{
- static int* C=NULL;
- static int* D=NULL;
- int i,k;
- int n=tf->nconsts;
- if (n==0) return;
- luaM_reallocvector(C,n,int);
- luaM_reallocvector(D,n,int);
- NoUnrefs(tf);
- for (i=0; i<n; i++) C[i]=D[i]=i; /* group duplicates */
- TF=tf; qsort(C,n,sizeof(C[0]),compare1);
- k=C[0]; /* build duplicate table */
- for (i=1; i<n; i++)
- {
- int j=C[i];
- if (compare(tf,k,j)==0) D[j]=k; else k=j;
- }
- k=0; /* build rename map & pack constants */
+ int i,j,k,n;
+ TObject o;
+#ifdef DEBUG
+ printf("%p before pack nknum=%d nkstr=%d\n",tf,tf->nknum,tf->nkstr);
+#endif
+ j=0; n=tf->nknum; ttype(&o)=LUA_TNUMBER;
for (i=0; i<n; i++)
{
- if (D[i]==i) /* new value */
- {
- TObject* o=tf->consts+i;
- if (ttype(o)!=UNREF)
- {
- tf->consts[k]=tf->consts[i];
- C[i]=k++;
- }
- }
- else C[i]=C[D[i]];
+ nvalue(&o)=tf->knum[i];
+ k=MapConstant(map,-1,&o);
+ if (k==j) tf->knum[j++]=tf->knum[i];
}
- if (k<n)
+ tf->nknum=j;
+ j=0; n=tf->nkstr; ttype(&o)=LUA_TSTRING;
+ for (i=0; i<n; i++)
{
-printf("\t" SOURCE " reduced constants from %d to %d\n",
- tf->source->str,tf->lineDefined,n,k);
- FixConstants(tf,C);
- tf->nconsts=k;
+ tsvalue(&o)=tf->kstr[i];
+ k=MapConstant(map,-1,&o);
+ if (k==j) tf->kstr[j++]=tf->kstr[i];
}
+ tf->nkstr=j;
+#ifdef DEBUG
+ printf("%p after pack nknum=%d nkstr=%d\n",tf,tf->nknum,tf->nkstr);
+#endif
}
-static int NoDebug(TProtoFunc* tf)
+static void OptConstants(Proto* tf)
{
- Byte* code=tf->code;
- Byte* p=code;
- int lop=NOP; /* last opcode */
- int nop=0;
- for (;;) /* change SETLINE to NOP */
+ Instruction* p;
+ int n=tf->nknum+tf->nkstr;
+ Hash* map=luaH_new(L,n);
+ int m=MapConstants(tf,map);
+#ifdef DEBUG
+ printf("%p n=%d m=%d %s\n",tf,n,m,(m==n)?"nothing to optimize":"yes!");
+#endif
+ if (m==n) return;
+ for (p=tf->code;; p++)
{
- Opcode OP;
- int n=INFO(tf,p,&OP);
- int op=OP.class;
- if (op==NOP) ++nop;
- else if (op==SETLINE)
+ Instruction i=*p;
+ int op=GET_OPCODE(i);
+ switch (op)
{
- int m;
- if (lop==LONGARG) m=2; else if (lop==LONGARGW) m=3; else m=0;
- nop+=n+m; memset(p-m,NOP,n+m);
+ TObject o;
+ int j,k;
+ case OP_PUSHNUM: case OP_PUSHNEGNUM:
+ j=GETARG_U(i);
+ ttype(&o)=LUA_TNUMBER; nvalue(&o)=tf->knum[j];
+ k=MapConstant(map,-1,&o);
+ if (k!=j) *p=CREATE_U(op,k);
+ break;
+ case OP_PUSHSTRING: case OP_GETGLOBAL: case OP_GETDOTTED:
+ case OP_PUSHSELF: case OP_SETGLOBAL:
+ j=GETARG_U(i);
+ ttype(&o)=LUA_TSTRING; tsvalue(&o)=tf->kstr[j];
+ k=MapConstant(map,-1,&o);
+ if (k!=j) *p=CREATE_U(op,k);
+ break;
+ case OP_END:
+ PackConstants(tf,map);
+ luaH_free(L,map);
+ return;
+ default:
+ break;
}
- else if (op==ENDCODE) break;
- lop=OP.op;
- p+=n;
}
- return nop;
}
-static int FixJump(TProtoFunc* tf, Byte* a, Byte* b)
-{
- Byte* p;
- int nop=0;
- for (p=a; p<b; )
- {
- Opcode OP;
- int n=INFO(tf,p,&OP);
- int op=OP.class;
- if (op==NOP) ++nop;
- else if (op==ENDCODE) break;
- p+=n;
- }
- return nop;
-}
+#define OptFunction luaU_optchunk
-static void FixJumps(TProtoFunc* tf)
-{
- Byte* code=tf->code;
- Byte* p=code;
- int longarg=0;
- for (;;)
- {
- Opcode OP;
- int n=INFO(tf,p,&OP);
- int op=OP.class;
- int i=OP.arg+longarg;
- int nop=0;
- longarg=0;
- if (op==ENDCODE) break;
- else if (op==IFTUPJMP || op==IFFUPJMP)
- nop=FixJump(tf,p-i+n,p);
- else if (op==ONTJMP || op==ONFJMP || op==JMP || op==IFFJMP)
- nop=FixJump(tf,p,p+i+n);
- else if (op==LONGARG) longarg=i<<16;
- if (nop>0) FixArg(p,i,i-nop,0);
- p+=n;
- }
-}
-
-static void PackCode(TProtoFunc* tf)
-{
- Byte* code=tf->code;
- Byte* p=code;
- Byte* q=code;
- for (;;)
- {
- Opcode OP;
- int n=INFO(tf,p,&OP);
- int op=OP.class;
- if (op!=NOP) { memcpy(q,p,n); q+=n; }
- p+=n;
- if (op==ENDCODE) break;
- }
-printf("\t" SOURCE " reduced code from %d to %d\n",
- tf->source->str,tf->lineDefined,(int)(p-code),(int)(q-code));
-}
-
-static void OptCode(TProtoFunc* tf)
-{
- if (NoDebug(tf)==0) return; /* cannot improve code */
- FixJumps(tf);
- PackCode(tf);
-}
-
-static void OptFunction(TProtoFunc* tf);
-
-static void OptFunctions(TProtoFunc* tf)
-{
- int i,n=tf->nconsts;
- for (i=0; i<n; i++)
- {
- TObject* o=tf->consts+i;
- if (ttype(o)==LUA_T_PROTO) OptFunction(tfvalue(o));
- }
-}
-
-static void OptFunction(TProtoFunc* tf)
+void OptFunction(Proto* tf)
{
+ int i,n=tf->nkproto;
OptConstants(tf);
- OptCode(tf);
- OptFunctions(tf);
- tf->source=luaS_new("");
- tf->locvars=NULL;
-}
-
-void luaU_optchunk(TProtoFunc* Main)
-{
- OptFunction(Main);
+ for (i=0; i<n; i++) OptFunction(tf->kproto[i]);
}
diff --git a/src/luac/print.c b/src/luac/print.c
index b1ee8934..4ffc8b3d 100644
--- a/src/luac/print.c
+++ b/src/luac/print.c
@@ -1,223 +1,99 @@
/*
-** $Id: print.c,v 1.21 1999/05/25 19:58:55 lhf Exp $
+** $Id: print.c,v 1.32 2000/11/06 20:04:36 lhf Exp $
** print bytecodes
** See Copyright Notice in lua.h
*/
#include <stdio.h>
#include <stdlib.h>
+
#include "luac.h"
-#ifdef DEBUG
-static void PrintConstants(TProtoFunc* tf)
+/* macros used in print.h, included in PrintCode */
+#define P_OP(x) printf("%-11s\t",x)
+#define P_NONE
+#define P_AB printf("%d %d",GETARG_A(i),GETARG_B(i))
+#define P_F printf("%d %d\t; %p",GETARG_A(i),GETARG_B(i),tf->kproto[GETARG_A(i)])
+#define P_J printf("%d\t; to %d",GETARG_S(i),GETARG_S(i)+at+1)
+#define P_Q PrintString(tf,GETARG_U(i))
+#define P_K printf("%d\t; %s",GETARG_U(i),tf->kstr[GETARG_U(i)]->str)
+#define P_L PrintLocal(tf,GETARG_U(i),at-1)
+#define P_N printf("%d\t; " NUMBER_FMT,GETARG_U(i),tf->knum[GETARG_U(i)])
+#define P_S printf("%d",GETARG_S(i))
+#define P_U printf("%u",GETARG_U(i))
+
+static void PrintString(const Proto* tf, int n)
{
- int i,n=tf->nconsts;
- printf("constants (%d) for %p:\n",n,tf);
- for (i=0; i<n; i++)
+ const char* s=tf->kstr[n]->str;
+ printf("%d\t; ",n);
+ putchar('"');
+ for (; *s; s++)
{
- TObject* o=tf->consts+i;
- printf("%6d ",i);
- switch (ttype(o))
+ switch (*s)
{
- case LUA_T_NUMBER:
- printf("N " NUMBER_FMT "\n",(double)nvalue(o));
- break;
- case LUA_T_STRING:
- printf("S %p\t\"%s\"\n",tsvalue(o),svalue(o));
- break;
- case LUA_T_PROTO:
- printf("F %p\n",tfvalue(o));
- break;
- case LUA_T_NIL:
- printf("nil\n");
- break;
- default: /* cannot happen */
- printf("? type=%d\n",ttype(o));
- break;
+ case '"': printf("\\\""); break;
+ case '\a': printf("\\a"); break;
+ case '\b': printf("\\b"); break;
+ case '\f': printf("\\f"); break;
+ case '\n': printf("\\n"); break;
+ case '\r': printf("\\r"); break;
+ case '\t': printf("\\t"); break;
+ case '\v': printf("\\v"); break;
+ default: putchar(*s); break;
}
}
+ putchar('"');
}
-#endif
-static void PrintConstant(TProtoFunc* tf, int i, int at)
+static void PrintLocal(const Proto* tf, int n, int pc)
{
- TObject* o=luaU_getconstant(tf,i,at);
- switch (ttype(o))
- {
- case LUA_T_NUMBER:
- printf(NUMBER_FMT,(double)nvalue(o));
- break;
- case LUA_T_STRING:
- printf("\"%s\"",svalue(o));
- break;
- case LUA_T_PROTO:
- printf("function at %p",(void*)tfvalue(o));
- break;
- case LUA_T_NIL:
- printf("(nil)");
- break;
- default: /* cannot happen */
- luaU_badconstant("print",i,o,tf);
- break;
- }
+ const char* s=luaF_getlocalname(tf,n+1,pc);
+ printf("%u",n);
+ if (s!=NULL) printf("\t; %s",s);
}
-static void PrintCode(TProtoFunc* tf)
+static void PrintCode(const Proto* tf)
{
- Byte* code=tf->code;
- Byte* p=code;
- int line=0;
- int longarg=0;
+ const Instruction* code=tf->code;
+ const Instruction* p=code;
for (;;)
{
- Opcode OP;
- int n=INFO(tf,p,&OP);
- int i=OP.arg+longarg;
- int at=p-code;
- longarg=0;
- printf("%6d ",at);
- {
- Byte* q=p;
- int j=n;
- while (j--) printf("%02X",*q++);
- }
- printf("%*s%-14s ",2*(5-n),"",OP.name);
- if (OP.arg >=0) printf("%d",i);
- if (OP.arg2>=0) printf(" %d",OP.arg2);
-
- switch (OP.class)
- {
-
- case ENDCODE:
- printf("\n");
- return;
-
- case PUSHCONSTANT:
- case GETGLOBAL:
- case SETGLOBAL:
- case GETDOTTED:
- case PUSHSELF:
- case CLOSURE:
- printf("\t; ");
- PrintConstant(tf,i,at);
- break;
-
- case PUSHLOCAL:
- case SETLOCAL:
- {
- char* s=luaF_getlocalname(tf,i+1,line);
- if (s) printf("\t; %s",s);
- break;
- }
-
- case SETLINE:
- printf("\t; " SOURCE,tf->source->str,line=i);
- break;
-
- case LONGARG:
- longarg=i<<16;
- break;
-
-/* suggested by Norman Ramsey <nr@cs.virginia.edu> */
- case ONTJMP:
- case ONFJMP:
- case JMP:
- case IFFJMP:
- printf("\t; to %d",at+i+n);
- break;
- case IFTUPJMP:
- case IFFUPJMP:
- printf("\t; to %d",at-i+n);
- break;
-
- }
- printf("\n");
- p+=n;
- }
-}
-
-static void PrintLocals(TProtoFunc* tf)
-{
- LocVar* v=tf->locvars;
- int n,i;
- if (v==NULL || v->line<0) return;
- n=tf->code[1]; if (n>=ZEROVARARG) n-=ZEROVARARG;
- printf("locals:");
- for (i=0; i<n; v++,i++) /* arguments */
- printf(" %s",v->varname->str);
- for (; v->line>=0; v++)
- {
- if (v->varname==NULL)
- {
- --i; if (i<0) luaL_verror("bad locvars[%d]",v-tf->locvars); else printf(")");
- }
- else
- {
- ++i; printf(" (%s",v->varname->str);
+ int at=p-code+1;
+ Instruction i=*p;
+ int line=luaG_getline(tf->lineinfo,at-1,1,NULL);
+ printf("%6d\t",at);
+ if (line>=0) printf("[%d]\t",line); else printf("[-]\t");
+ switch (GET_OPCODE(i)) {
+#include "print.h"
}
+ printf("\n");
+ if (i==OP_END) break;
+ p++;
}
- i-=n;
- while (i--) printf(")");
- printf("\n");
}
#define IsMain(tf) (tf->lineDefined==0)
-static void PrintHeader(TProtoFunc* tf, TProtoFunc* Main, int at)
-{
- int size=luaU_codesize(tf);
- if (IsMain(tf))
- printf("\nmain " SOURCE " (%d bytes at %p)\n",
- tf->source->str,tf->lineDefined,size,tf);
- else
- {
- printf("\nfunction " SOURCE " (%d bytes at %p); used at ",
- tf->source->str,tf->lineDefined,size,tf);
- if (Main && IsMain(Main))
- printf("main");
- else
- printf("%p",Main);
- printf("+%d\n",at);
- }
-}
-
-static void PrintFunction(TProtoFunc* tf, TProtoFunc* Main, int at);
+#define SS(x) (x==1)?"":"s"
+#define S(x) x,SS(x)
-static void PrintFunctions(TProtoFunc* Main)
+static void PrintHeader(const Proto* tf)
{
- Byte* code=Main->code;
- Byte* p=code;
- int longarg=0;
- for (;;)
- {
- Opcode OP;
- int n=INFO(Main,p,&OP);
- int op=OP.class;
- int i=OP.arg+longarg;
- longarg=0;
- if (op==PUSHCONSTANT || op==CLOSURE)
- {
- TObject* o=Main->consts+i;
- if (ttype(o)==LUA_T_PROTO) PrintFunction(tfvalue(o),Main,(int)(p-code));
- }
- else if (op==LONGARG) longarg=i<<16;
- else if (op==ENDCODE) break;
- p+=n;
- }
+ printf("\n%s " SOURCE_FMT " (%d instruction%s/%d bytes at %p)\n",
+ IsMain(tf)?"main":"function",SOURCE,
+ S(tf->ncode),tf->ncode*Sizeof(Instruction),tf);
+ printf("%d%s param%s, %d stack%s, ",
+ tf->numparams,tf->is_vararg?"+":"",SS(tf->numparams),S(tf->maxstacksize));
+ printf("%d local%s, %d string%s, %d number%s, %d function%s, %d line%s\n",
+ S(tf->nlocvars),S(tf->nkstr),S(tf->nknum),S(tf->nkproto),S(tf->nlineinfo));
}
-static void PrintFunction(TProtoFunc* tf, TProtoFunc* Main, int at)
-{
- PrintHeader(tf,Main,at);
- PrintLocals(tf);
- PrintCode(tf);
-#ifdef DEBUG
- PrintConstants(tf);
-#endif
- PrintFunctions(tf);
-}
+#define PrintFunction luaU_printchunk
-void luaU_printchunk(TProtoFunc* Main)
+void PrintFunction(const Proto* tf)
{
- PrintFunction(Main,0,0);
+ int i,n=tf->nkproto;
+ PrintHeader(tf);
+ PrintCode(tf);
+ for (i=0; i<n; i++) PrintFunction(tf->kproto[i]);
}
diff --git a/src/luac/print.h b/src/luac/print.h
new file mode 100644
index 00000000..5f74e149
--- /dev/null
+++ b/src/luac/print.h
@@ -0,0 +1,55 @@
+/*
+** $Id: print.h,v 1.1 2000/11/06 20:03:12 lhf Exp $
+** extracted automatically from lopcodes.h by mkprint.lua -- DO NOT EDIT
+** See Copyright Notice in lua.h
+*/
+
+ case OP_END: P_OP("END"); P_NONE; break;
+ case OP_RETURN: P_OP("RETURN"); P_U; break;
+ case OP_CALL: P_OP("CALL"); P_AB; break;
+ case OP_TAILCALL: P_OP("TAILCALL"); P_AB; break;
+ case OP_PUSHNIL: P_OP("PUSHNIL"); P_U; break;
+ case OP_POP: P_OP("POP"); P_U; break;
+ case OP_PUSHINT: P_OP("PUSHINT"); P_S; break;
+ case OP_PUSHSTRING: P_OP("PUSHSTRING"); P_Q; break;
+ case OP_PUSHNUM: P_OP("PUSHNUM"); P_N; break;
+ case OP_PUSHNEGNUM: P_OP("PUSHNEGNUM"); P_N; break;
+ case OP_PUSHUPVALUE: P_OP("PUSHUPVALUE"); P_U; break;
+ case OP_GETLOCAL: P_OP("GETLOCAL"); P_L; break;
+ case OP_GETGLOBAL: P_OP("GETGLOBAL"); P_K; break;
+ case OP_GETTABLE: P_OP("GETTABLE"); P_NONE; break;
+ case OP_GETDOTTED: P_OP("GETDOTTED"); P_K; break;
+ case OP_GETINDEXED: P_OP("GETINDEXED"); P_L; break;
+ case OP_PUSHSELF: P_OP("PUSHSELF"); P_K; break;
+ case OP_CREATETABLE: P_OP("CREATETABLE"); P_U; break;
+ case OP_SETLOCAL: P_OP("SETLOCAL"); P_L; break;
+ case OP_SETGLOBAL: P_OP("SETGLOBAL"); P_K; break;
+ case OP_SETTABLE: P_OP("SETTABLE"); P_AB; break;
+ case OP_SETLIST: P_OP("SETLIST"); P_AB; break;
+ case OP_SETMAP: P_OP("SETMAP"); P_U; break;
+ case OP_ADD: P_OP("ADD"); P_NONE; break;
+ case OP_ADDI: P_OP("ADDI"); P_S; break;
+ case OP_SUB: P_OP("SUB"); P_NONE; break;
+ case OP_MULT: P_OP("MULT"); P_NONE; break;
+ case OP_DIV: P_OP("DIV"); P_NONE; break;
+ case OP_POW: P_OP("POW"); P_NONE; break;
+ case OP_CONCAT: P_OP("CONCAT"); P_U; break;
+ case OP_MINUS: P_OP("MINUS"); P_NONE; break;
+ case OP_NOT: P_OP("NOT"); P_NONE; break;
+ case OP_JMPNE: P_OP("JMPNE"); P_J; break;
+ case OP_JMPEQ: P_OP("JMPEQ"); P_J; break;
+ case OP_JMPLT: P_OP("JMPLT"); P_J; break;
+ case OP_JMPLE: P_OP("JMPLE"); P_J; break;
+ case OP_JMPGT: P_OP("JMPGT"); P_J; break;
+ case OP_JMPGE: P_OP("JMPGE"); P_J; break;
+ case OP_JMPT: P_OP("JMPT"); P_J; break;
+ case OP_JMPF: P_OP("JMPF"); P_J; break;
+ case OP_JMPONT: P_OP("JMPONT"); P_J; break;
+ case OP_JMPONF: P_OP("JMPONF"); P_J; break;
+ case OP_JMP: P_OP("JMP"); P_J; break;
+ case OP_PUSHNILJMP: P_OP("PUSHNILJMP"); P_NONE; break;
+ case OP_FORPREP: P_OP("FORPREP"); P_J; break;
+ case OP_FORLOOP: P_OP("FORLOOP"); P_J; break;
+ case OP_LFORPREP: P_OP("LFORPREP"); P_J; break;
+ case OP_LFORLOOP: P_OP("LFORLOOP"); P_J; break;
+ case OP_CLOSURE: P_OP("CLOSURE"); P_F; break;
diff --git a/src/luac/stubs.c b/src/luac/stubs.c
index 5f38940e..74f509eb 100644
--- a/src/luac/stubs.c
+++ b/src/luac/stubs.c
@@ -1,68 +1,109 @@
/*
-** $Id: stubs.c,v 1.11 1999/03/11 17:09:10 lhf Exp $
+** $Id: stubs.c,v 1.20 2000/10/31 16:57:23 lhf Exp $
** avoid runtime modules in luac
** See Copyright Notice in lua.h
*/
-#ifdef NOSTUBS
-
-/* according to gcc, ANSI C forbids an empty source file */
-void luaU_dummy(void);
-void luaU_dummy(void){}
-
-#else
-
-#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
+
+#include "ldo.h"
+#include "llex.h"
#include "luac.h"
+#undef L
+
+#ifndef NOSTUBS
+
+const char luac_ident[] = "$luac: " LUA_VERSION " " LUA_COPYRIGHT " $\n"
+ "$Authors: " LUA_AUTHORS " $";
/*
-* avoid lapi lauxlib lbuiltin ldo lgc ltable ltm lvm
-* use only lbuffer lfunc llex lmem lobject lparser lstate lstring lzio
+* avoid lapi ldebug ldo lgc lstate ltm lvm
+* use only lcode lfunc llex lmem lobject lparser lstring ltable lzio
*/
/* simplified from ldo.c */
-void lua_error(char* s)
-{
- if (s) fprintf(stderr,"luac: %s\n",s);
- exit(1);
+void lua_error (lua_State* L, const char* s) {
+ UNUSED(L);
+ if (s) fprintf(stderr,"luac: %s\n",s);
+ exit(1);
}
-/* copied from lauxlib.c */
-void luaL_verror (char *fmt, ...)
-{
- char buff[500];
- va_list argp;
- va_start(argp, fmt);
- vsprintf(buff, fmt, argp);
- va_end(argp);
- lua_error(buff);
+/* simplified from ldo.c */
+void luaD_breakrun (lua_State *L, int errcode) {
+ UNUSED(errcode);
+ lua_error(L,"memory allocation error");
}
-/* copied from lauxlib.c */
-void luaL_filesource (char *out, char *filename, int len) {
- if (filename == NULL) filename = "(stdin)";
- sprintf(out, "@%.*s", len-2, filename); /* -2 for '@' and '\0' */
+/* simplified from lstate.c */
+lua_State *lua_open (int stacksize) {
+ lua_State *L = luaM_new(NULL, lua_State);
+ if (L == NULL) return NULL; /* memory allocation error */
+ L->stack = NULL;
+ L->strt.size = L->udt.size = 0;
+ L->strt.nuse = L->udt.nuse = 0;
+ L->strt.hash = NULL;
+ L->udt.hash = NULL;
+ L->Mbuffer = NULL;
+ L->Mbuffsize = 0;
+ L->rootproto = NULL;
+ L->rootcl = NULL;
+ L->roottable = NULL;
+ L->TMtable = NULL;
+ L->last_tag = -1;
+ L->refArray = NULL;
+ L->refSize = 0;
+ L->refFree = NONEXT;
+ L->nblocks = sizeof(lua_State);
+ L->GCthreshold = MAX_INT; /* to avoid GC during pre-definitions */
+ L->callhook = NULL;
+ L->linehook = NULL;
+ L->allowhooks = 1;
+ L->errorJmp = NULL;
+ if (stacksize == 0)
+ stacksize = DEFAULT_STACK_SIZE;
+ else
+ stacksize += LUA_MINSTACK;
+ L->gt = luaH_new(L, 10); /* table of globals */
+ luaS_init(L);
+ luaX_init(L);
+ L->GCthreshold = 2*L->nblocks;
+ return L;
}
-/* avoid runtime modules in lstate.c */
-
-#include "lbuiltin.h"
-#include "ldo.h"
-#include "lgc.h"
-#include "ltable.h"
-#include "ltm.h"
-
-void luaB_predefine(void){}
-void luaC_hashcallIM(Hash *l){}
-void luaC_strcallIM(TaggedString *l){}
-void luaD_gcIM(TObject *o){}
-void luaH_free(Hash *frees){}
-void luaT_init(void){}
+/* copied from ldebug.c */
+int luaG_getline (int *lineinfo, int pc, int refline, int *prefi) {
+ int refi;
+ if (lineinfo == NULL || pc == -1)
+ return -1; /* no line info or function is not active */
+ refi = prefi ? *prefi : 0;
+ if (lineinfo[refi] < 0)
+ refline += -lineinfo[refi++];
+ LUA_ASSERT(lineinfo[refi] >= 0, "invalid line info");
+ while (lineinfo[refi] > pc) {
+ refline--;
+ refi--;
+ if (lineinfo[refi] < 0)
+ refline -= -lineinfo[refi--];
+ LUA_ASSERT(lineinfo[refi] >= 0, "invalid line info");
+ }
+ for (;;) {
+ int nextline = refline + 1;
+ int nextref = refi + 1;
+ if (lineinfo[nextref] < 0)
+ nextline += -lineinfo[nextref++];
+ LUA_ASSERT(lineinfo[nextref] >= 0, "invalid line info");
+ if (lineinfo[nextref] > pc)
+ break;
+ refline = nextline;
+ refi = nextref;
+ }
+ if (prefi) *prefi = refi;
+ return refline;
+}
/*
-* the code below avoids the lexer and the parser (llex lparser).
+* the code below avoids the lexer and the parser (llex lparser lcode).
* it is useful if you only want to load binary files.
* this works for interpreters like lua.c too.
*/
@@ -72,49 +113,14 @@ void luaT_init(void){}
#include "llex.h"
#include "lparser.h"
-void luaX_init(void){}
-void luaD_init(void){}
-
-TProtoFunc* luaY_parser(ZIO *z) {
- lua_error("parser not loaded");
- return NULL;
-}
-
-#else
-
-/* copied from lauxlib.c */
-int luaL_findstring (char *name, char *list[]) {
- int i;
- for (i=0; list[i]; i++)
- if (strcmp(list[i], name) == 0)
- return i;
- return -1; /* name not found */
-}
-
-/* copied from lauxlib.c */
-void luaL_chunkid (char *out, char *source, int len) {
- len -= 13; /* 13 = strlen("string ''...\0") */
- if (*source == '@')
- sprintf(out, "file `%.*s'", len, source+1);
- else if (*source == '(')
- strcpy(out, "(C code)");
- else {
- char *b = strchr(source , '\n'); /* stop string at first new line */
- int lim = (b && (b-source)<len) ? b-source : len;
- sprintf(out, "string `%.*s'", lim, source);
- strcpy(out+lim+(13-5), "...'"); /* 5 = strlen("...'\0") */
- }
+void luaX_init(lua_State *L) {
+ UNUSED(L);
}
-void luaD_checkstack(int n){}
-
-#define STACK_UNIT 128
-
-/* copied from ldo.c */
-void luaD_init (void) {
- L->stack.stack = luaM_newvector(STACK_UNIT, TObject);
- L->stack.top = L->stack.stack;
- L->stack.last = L->stack.stack+(STACK_UNIT-1);
+Proto *luaY_parser(lua_State *L, ZIO *z) {
+ UNUSED(z);
+ lua_error(L,"parser not loaded");
+ return NULL;
}
#endif
diff --git a/src/luac/test.c b/src/luac/test.c
deleted file mode 100644
index 78ba4556..00000000
--- a/src/luac/test.c
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
-** $Id: test.c,v 1.10 1999/07/02 19:34:26 lhf Exp $
-** test integrity
-** See Copyright Notice in lua.h
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "luac.h"
-
-#define AT "pc=%d"
-#define ATLOC 0)
-#define UNSAFE(s) \
- luaL_verror("unsafe code at " AT IN "\n " s,at,INLOC
-
-TObject* luaU_getconstant(TProtoFunc* tf, int i, int at)
-{
- if (i>=tf->nconsts) UNSAFE("bad constant #%d (max=%d)"),i,tf->nconsts-1,ATLOC;
- return tf->consts+i;
-}
-
-static int check(int n, TProtoFunc* tf, int at, int sp, int ss)
-{
- if (n==0) return sp;
- sp+=n;
- if (sp<00) UNSAFE("stack underflow (sp=%d)"),sp,ATLOC;
- if (sp>ss) UNSAFE("stack overflow (sp=%d ss=%d)"),sp,ss,ATLOC;
- return sp;
-}
-
-#define CHECK(before,after) \
- sp=check(-(before),tf,at,sp,ss), sp=check(after,tf,at,sp,ss)
-
-static int jmpok(TProtoFunc* tf, int size, int at, int d)
-{
- int to=at+d;
- if (to<2 || to>=size)
- UNSAFE("invalid jump to %d (valid range is 2..%d)"),to,size-1,ATLOC;
- return to;
-}
-
-static void TestStack(TProtoFunc* tf, int size, int* SP, int* JP)
-{
- Byte* code=tf->code;
- Byte* p=code;
- int longarg=0;
- int ss=0;
- int sp=0;
- for (;;)
- {
- Opcode OP;
- int n=INFO(tf,p,&OP);
- int op=OP.class;
- int i=OP.arg+longarg;
- int at=p-code;
- longarg=0;
- switch (op) /* test sanity of operands */
- {
- case PUSHCONSTANT:
- case GETGLOBAL:
- case GETDOTTED:
- case PUSHSELF:
- case SETGLOBAL:
- case CLOSURE:
- {
- TObject* o=luaU_getconstant(tf,i,at);
- if ((op==CLOSURE && ttype(o)!=LUA_T_PROTO)
- || (op==GETGLOBAL && ttype(o)!=LUA_T_STRING)
- || (op==SETGLOBAL && ttype(o)!=LUA_T_STRING))
- UNSAFE("bad operand to %s"),OP.name,ATLOC;
- break;
- }
- case PUSHLOCAL:
- if (i>=sp) UNSAFE("bad local #%d (max=%d)"),i,sp-1,ATLOC;
- break;
- case SETLOCAL:
- if (i>=(sp-1)) UNSAFE("bad local #%d (max=%d)"),i,sp-2,ATLOC;
- break;
- case ONTJMP:
- case ONFJMP: /* negate to remember ON?JMP */
- JP[at]=-jmpok(tf,size,at,i+n);
- break;
- case JMP: /* remember JMP targets */
- case IFFJMP:
- JP[at]= jmpok(tf,size,at,i+n);
- break;
- case IFTUPJMP:
- case IFFUPJMP:
- JP[at]= jmpok(tf,size,at,-i+n);
- break;
- }
-
- SP[at]=sp; /* remember depth before instruction */
-
- switch (op)
- {
- case STACK: ss=i; break;
- case ARGS: CHECK(0,i); break;
- case VARARGS: break;
- case ENDCODE: return;
- case RETCODE: CHECK(i,0); sp=i; break;
- case CALL: CHECK(OP.arg2+1,i); break;
- case TAILCALL: CHECK(OP.arg2,0); sp=i; break;
- case PUSHNIL: CHECK(0,i+1); break;
- case POP: CHECK(0,-i); break;
- case PUSHNUMBER:
- case PUSHNUMBERNEG:
- case PUSHCONSTANT:
- case PUSHUPVALUE:
- case PUSHLOCAL:
- case GETGLOBAL: CHECK(0,1); break;
- case GETTABLE: CHECK(2,1); break;
- case GETDOTTED: CHECK(1,1); break;
- case PUSHSELF: CHECK(1,2); break;
- case CREATEARRAY: CHECK(0,1); break;
- case SETLOCAL: CHECK(1,0); break;
- case SETGLOBAL: CHECK(1,0); break;
- case SETTABLEPOP: CHECK(3,0); break;
- case SETTABLE: CHECK(i+3,i+2); break;
- case SETLIST: CHECK(OP.arg2+1,1); break;
- case SETMAP: CHECK(2*(i+1)+1,1); break;
- case NEQOP:
- case EQOP:
- case LTOP:
- case LEOP:
- case GTOP:
- case GEOP:
- case ADDOP:
- case SUBOP:
- case MULTOP:
- case DIVOP:
- case POWOP:
- case CONCOP: CHECK(2,1); break;
- case MINUSOP:
- case NOTOP: CHECK(1,1); break;
- case ONTJMP:
- case ONFJMP:
- case IFFJMP:
- case IFTUPJMP:
- case IFFUPJMP: CHECK(1,0); break;
- case JMP: break;
- case CLOSURE: CHECK(OP.arg2,1); break;
- case SETLINE: break;
- case LONGARG:
- longarg=i<<16;
- if (longarg<0) UNSAFE("longarg overflow"),ATLOC;
- break;
- case CHECKSTACK: break;
- default: /* cannot happen */
- UNSAFE("cannot test opcode %d [%s]"),OP.op,OP.name,ATLOC;
- break;
- }
- p+=n;
- }
-}
-
-static void TestJumps(TProtoFunc* tf, int size, int* SP, int* JP)
-{
- int i;
- for (i=0; i<size; i++)
- {
- int to=JP[i];
- if (to!=0)
- {
- int at=i; /* for ATLOC */
- int a,b,j;
- int on=(to<0); /* ON?JMP */
- if (on) to=-to;
- a=SP[to];
- if (a<0)
- UNSAFE("invalid jump to %d (not an instruction)"),to,ATLOC;
- for (j=i; SP[++j]<0; ) /* find next instruction */
- ;
- b=SP[j]+on;
- if (a!=b)
- UNSAFE("stack inconsistency in jump to %d (expected %d, found %d)"),
- to,a,b,ATLOC;
- }
- }
-}
-
-static void TestCode(TProtoFunc* tf)
-{
- static int* SP=NULL;
- static int* JP=NULL;
- int size=luaU_codesize(tf);
- luaM_reallocvector(SP,size,int); memset(SP,-1,size*sizeof(int));
- luaM_reallocvector(JP,size,int); memset(JP, 0,size*sizeof(int));
- TestStack(tf,size,SP,JP);
- TestJumps(tf,size,SP,JP);
-}
-
-#undef AT
-#define AT "locvars[%d]"
-static void TestLocals(TProtoFunc* tf)
-{
- LocVar* v;
- int l=1;
- int d=0;
- if (tf->locvars==NULL) return;
- for (v=tf->locvars; v->line>=0; v++)
- {
- int at=v-tf->locvars; /* for ATLOC */
- if (l>v->line)
- UNSAFE("bad line number %d; expected at least %d"),v->line,l,ATLOC;
- l=v->line;
- if (v->varname==NULL)
- {
- if (--d<0) UNSAFE("no scope to close"),ATLOC;
- }
- else
- ++d;
- }
-}
-
-static void TestFunction(TProtoFunc* tf);
-
-static void TestConstants(TProtoFunc* tf)
-{
- int i,n=tf->nconsts;
- for (i=0; i<n; i++)
- {
- TObject* o=tf->consts+i;
- switch (ttype(o))
- {
- case LUA_T_NUMBER:
- break;
- case LUA_T_STRING:
- break;
- case LUA_T_PROTO:
- TestFunction(tfvalue(o));
- break;
- case LUA_T_NIL:
- break;
- default: /* cannot happen */
- luaU_badconstant("print",i,o,tf);
- break;
- }
- }
-}
-
-static void TestFunction(TProtoFunc* tf)
-{
- TestCode(tf);
- TestLocals(tf);
- TestConstants(tf);
-}
-
-void luaU_testchunk(TProtoFunc* Main)
-{
- TestFunction(Main);
-}
diff --git a/src/lundump.c b/src/lundump.c
index 0c3b5fd7..a8d06106 100644
--- a/src/lundump.c
+++ b/src/lundump.c
@@ -1,239 +1,244 @@
/*
-** $Id: lundump.c,v 1.21 1999/07/02 19:34:26 lhf Exp $
+** $Id: lundump.c,v 1.33 2000/10/31 16:57:23 lhf Exp $
** load bytecodes from files
** See Copyright Notice in lua.h
*/
#include <stdio.h>
#include <string.h>
-#include "lauxlib.h"
+
#include "lfunc.h"
#include "lmem.h"
#include "lopcodes.h"
#include "lstring.h"
#include "lundump.h"
-#define LoadBlock(b,size,Z) ezread(Z,b,size)
+#define LoadByte ezgetc
-static void unexpectedEOZ (ZIO* Z)
+static const char* ZNAME (ZIO* Z)
{
- luaL_verror("unexpected end of file in %s",zname(Z));
+ const char* s=zname(Z);
+ return (*s=='@') ? s+1 : s;
}
-static int ezgetc (ZIO* Z)
+static void unexpectedEOZ (lua_State* L, ZIO* Z)
{
- int c=zgetc(Z);
- if (c==EOZ) unexpectedEOZ(Z);
- return c;
+ luaO_verror(L,"unexpected end of file in `%.99s'",ZNAME(Z));
}
-static void ezread (ZIO* Z, void* b, int n)
+static int ezgetc (lua_State* L, ZIO* Z)
{
- int r=zread(Z,b,n);
- if (r!=0) unexpectedEOZ(Z);
+ int c=zgetc(Z);
+ if (c==EOZ) unexpectedEOZ(L,Z);
+ return c;
}
-static unsigned int LoadWord (ZIO* Z)
+static void ezread (lua_State* L, ZIO* Z, void* b, int n)
{
- unsigned int hi=ezgetc(Z);
- unsigned int lo=ezgetc(Z);
- return (hi<<8)|lo;
+ int r=zread(Z,b,n);
+ if (r!=0) unexpectedEOZ(L,Z);
}
-static unsigned long LoadLong (ZIO* Z)
+static void LoadBlock (lua_State* L, void* b, size_t size, ZIO* Z, int swap)
{
- unsigned long hi=LoadWord(Z);
- unsigned long lo=LoadWord(Z);
- return (hi<<16)|lo;
-}
-
-/*
-* convert number from text
-*/
-double luaU_str2d (char* b, char* where)
-{
- int negative=(b[0]=='-');
- double x=luaO_str2d(b+negative);
- if (x<0) luaL_verror("cannot convert number '%s' in %s",b,where);
- return negative ? -x : x;
+ if (swap)
+ {
+ char *p=(char *) b+size-1;
+ int n=size;
+ while (n--) *p--=(char)ezgetc(L,Z);
+ }
+ else
+ ezread(L,Z,b,size);
}
-static real LoadNumber (ZIO* Z, int native)
+static void LoadVector (lua_State* L, void* b, int m, size_t size, ZIO* Z, int swap)
{
- real x;
- if (native)
+ if (swap)
{
- LoadBlock(&x,sizeof(x),Z);
- return x;
+ char *q=(char *) b;
+ while (m--)
+ {
+ char *p=q+size-1;
+ int n=size;
+ while (n--) *p--=(char)ezgetc(L,Z);
+ q+=size;
+ }
}
else
- {
- char b[256];
- int size=ezgetc(Z);
- LoadBlock(b,size,Z);
- b[size]=0;
- return luaU_str2d(b,zname(Z));
- }
+ ezread(L,Z,b,m*size);
}
-static int LoadInt (ZIO* Z, char* message)
+static int LoadInt (lua_State* L, ZIO* Z, int swap)
{
- unsigned long l=LoadLong(Z);
- unsigned int i=l;
- if (i!=l) luaL_verror(message,l,zname(Z));
- return i;
+ int x;
+ LoadBlock(L,&x,sizeof(x),Z,swap);
+ return x;
}
-#define PAD 5 /* two word operands plus opcode */
+static size_t LoadSize (lua_State* L, ZIO* Z, int swap)
+{
+ size_t x;
+ LoadBlock(L,&x,sizeof(x),Z,swap);
+ return x;
+}
-static Byte* LoadCode (ZIO* Z)
+static Number LoadNumber (lua_State* L, ZIO* Z, int swap)
{
- int size=LoadInt(Z,"code too long (%ld bytes) in %s");
- Byte* b=luaM_malloc(size+PAD);
- LoadBlock(b,size,Z);
- if (b[size-1]!=ENDCODE) luaL_verror("bad code in %s",zname(Z));
- memset(b+size,ENDCODE,PAD); /* pad code for safety */
- return b;
+ Number x;
+ LoadBlock(L,&x,sizeof(x),Z,swap);
+ return x;
}
-static TaggedString* LoadTString (ZIO* Z)
+static TString* LoadString (lua_State* L, ZIO* Z, int swap)
{
- long size=LoadLong(Z);
+ size_t size=LoadSize(L,Z,swap);
if (size==0)
return NULL;
else
{
- char* s=luaL_openspace(size);
- LoadBlock(s,size,Z);
- return luaS_newlstr(s,size-1);
+ char* s=luaO_openspace(L,size);
+ LoadBlock(L,s,size,Z,0);
+ return luaS_newlstr(L,s,size-1); /* remove trailing '\0' */
}
}
-static void LoadLocals (TProtoFunc* tf, ZIO* Z)
+static void LoadCode (lua_State* L, Proto* tf, ZIO* Z, int swap)
{
- int i,n=LoadInt(Z,"too many locals (%ld) in %s");
- if (n==0) return;
- tf->locvars=luaM_newvector(n+1,LocVar);
+ int size=LoadInt(L,Z,swap);
+ tf->code=luaM_newvector(L,size,Instruction);
+ LoadVector(L,tf->code,size,sizeof(*tf->code),Z,swap);
+ if (tf->code[size-1]!=OP_END) luaO_verror(L,"bad code in `%.99s'",ZNAME(Z));
+ luaF_protook(L,tf,size);
+}
+
+static void LoadLocals (lua_State* L, Proto* tf, ZIO* Z, int swap)
+{
+ int i,n;
+ tf->nlocvars=n=LoadInt(L,Z,swap);
+ tf->locvars=luaM_newvector(L,n,LocVar);
for (i=0; i<n; i++)
{
- tf->locvars[i].line=LoadInt(Z,"too many lines (%ld) in %s");
- tf->locvars[i].varname=LoadTString(Z);
+ tf->locvars[i].varname=LoadString(L,Z,swap);
+ tf->locvars[i].startpc=LoadInt(L,Z,swap);
+ tf->locvars[i].endpc=LoadInt(L,Z,swap);
}
- tf->locvars[i].line=-1; /* flag end of vector */
- tf->locvars[i].varname=NULL;
}
-static TProtoFunc* LoadFunction (ZIO* Z, int native);
+static void LoadLines (lua_State* L, Proto* tf, ZIO* Z, int swap)
+{
+ int n;
+ tf->nlineinfo=n=LoadInt(L,Z,swap);
+ tf->lineinfo=luaM_newvector(L,n,int);
+ LoadVector(L,tf->lineinfo,n,sizeof(*tf->lineinfo),Z,swap);
+}
+
+static Proto* LoadFunction (lua_State* L, ZIO* Z, int swap);
-static void LoadConstants (TProtoFunc* tf, ZIO* Z, int native)
+static void LoadConstants (lua_State* L, Proto* tf, ZIO* Z, int swap)
{
- int i,n=LoadInt(Z,"too many constants (%ld) in %s");
- tf->nconsts=n;
- if (n==0) return;
- tf->consts=luaM_newvector(n,TObject);
+ int i,n;
+ tf->nkstr=n=LoadInt(L,Z,swap);
+ tf->kstr=luaM_newvector(L,n,TString*);
for (i=0; i<n; i++)
- {
- TObject* o=tf->consts+i;
- ttype(o)=-ezgetc(Z); /* ttype(o) is negative - ORDER LUA_T */
- switch (ttype(o))
- {
- case LUA_T_NUMBER:
- nvalue(o)=LoadNumber(Z,native);
- break;
- case LUA_T_STRING:
- tsvalue(o)=LoadTString(Z);
- break;
- case LUA_T_PROTO:
- tfvalue(o)=LoadFunction(Z,native);
- break;
- case LUA_T_NIL:
- break;
- default: /* cannot happen */
- luaU_badconstant("load",i,o,tf);
- break;
- }
- }
+ tf->kstr[i]=LoadString(L,Z,swap);
+ tf->nknum=n=LoadInt(L,Z,swap);
+ tf->knum=luaM_newvector(L,n,Number);
+ LoadVector(L,tf->knum,n,sizeof(*tf->knum),Z,swap);
+ tf->nkproto=n=LoadInt(L,Z,swap);
+ tf->kproto=luaM_newvector(L,n,Proto*);
+ for (i=0; i<n; i++)
+ tf->kproto[i]=LoadFunction(L,Z,swap);
}
-static TProtoFunc* LoadFunction (ZIO* Z, int native)
+static Proto* LoadFunction (lua_State* L, ZIO* Z, int swap)
{
- TProtoFunc* tf=luaF_newproto();
- tf->lineDefined=LoadInt(Z,"lineDefined too large (%ld) in %s");
- tf->source=LoadTString(Z);
- if (tf->source==NULL) tf->source=luaS_new(zname(Z));
- tf->code=LoadCode(Z);
- LoadLocals(tf,Z);
- LoadConstants(tf,Z,native);
+ Proto* tf=luaF_newproto(L);
+ tf->source=LoadString(L,Z,swap);
+ tf->lineDefined=LoadInt(L,Z,swap);
+ tf->numparams=LoadInt(L,Z,swap);
+ tf->is_vararg=LoadByte(L,Z);
+ tf->maxstacksize=LoadInt(L,Z,swap);
+ LoadLocals(L,tf,Z,swap);
+ LoadLines(L,tf,Z,swap);
+ LoadConstants(L,tf,Z,swap);
+ LoadCode(L,tf,Z,swap);
return tf;
}
-static void LoadSignature (ZIO* Z)
+static void LoadSignature (lua_State* L, ZIO* Z)
{
- char* s=SIGNATURE;
- while (*s!=0 && ezgetc(Z)==*s)
+ const char* s=SIGNATURE;
+ while (*s!=0 && ezgetc(L,Z)==*s)
++s;
- if (*s!=0) luaL_verror("bad signature in %s",zname(Z));
+ if (*s!=0) luaO_verror(L,"bad signature in `%.99s'",ZNAME(Z));
}
-static int LoadHeader (ZIO* Z)
+static void TestSize (lua_State* L, int s, const char* what, ZIO* Z)
+{
+ int r=ezgetc(L,Z);
+ if (r!=s)
+ luaO_verror(L,"virtual machine mismatch in `%.99s':\n"
+ " %.20s is %d but read %d",ZNAME(Z),what,s,r);
+}
+
+#define TESTSIZE(s) TestSize(L,s,#s,Z)
+#define V(v) v/16,v%16
+
+static int LoadHeader (lua_State* L, ZIO* Z)
{
- int version,sizeofR;
- int native;
- LoadSignature(Z);
- version=ezgetc(Z);
+ int version,swap;
+ Number f=0,tf=TEST_NUMBER;
+ LoadSignature(L,Z);
+ version=ezgetc(L,Z);
if (version>VERSION)
- luaL_verror(
- "%s too new: version=0x%02x; expected at most 0x%02x",
- zname(Z),version,VERSION);
+ luaO_verror(L,"`%.99s' too new:\n"
+ " read version %d.%d; expected at most %d.%d",
+ ZNAME(Z),V(version),V(VERSION));
if (version<VERSION0) /* check last major change */
- luaL_verror(
- "%s too old: version=0x%02x; expected at least 0x%02x",
- zname(Z),version,VERSION0);
- sizeofR=ezgetc(Z);
- native=(sizeofR!=0);
- if (native) /* test number representation */
- {
- if (sizeofR!=sizeof(real))
- luaL_verror("unknown number size in %s: read %d; expected %d",
- zname(Z),sizeofR,sizeof(real));
- else
- {
- real tf=TEST_NUMBER;
- real f=LoadNumber(Z,native);
- if ((long)f!=(long)tf)
- luaL_verror("unknown number format in %s: "
- "read " NUMBER_FMT "; expected " NUMBER_FMT,
- zname(Z),f,tf);
- }
- }
- return native;
+ luaO_verror(L,"`%.99s' too old:\n"
+ " read version %d.%d; expected at least %d.%d",
+ ZNAME(Z),V(version),V(VERSION));
+ swap=(luaU_endianess()!=ezgetc(L,Z)); /* need to swap bytes? */
+ TESTSIZE(sizeof(int));
+ TESTSIZE(sizeof(size_t));
+ TESTSIZE(sizeof(Instruction));
+ TESTSIZE(SIZE_INSTRUCTION);
+ TESTSIZE(SIZE_OP);
+ TESTSIZE(SIZE_B);
+ TESTSIZE(sizeof(Number));
+ f=LoadNumber(L,Z,swap);
+ if ((long)f!=(long)tf) /* disregard errors in last bit of fraction */
+ luaO_verror(L,"unknown number format in `%.99s':\n"
+ " read " NUMBER_FMT "; expected " NUMBER_FMT, ZNAME(Z),f,tf);
+ return swap;
}
-static TProtoFunc* LoadChunk (ZIO* Z)
+static Proto* LoadChunk (lua_State* L, ZIO* Z)
{
- return LoadFunction(Z,LoadHeader(Z));
+ return LoadFunction(L,Z,LoadHeader(L,Z));
}
/*
** load one chunk from a file or buffer
** return main if ok and NULL at EOF
*/
-TProtoFunc* luaU_undump1 (ZIO* Z)
+Proto* luaU_undump (lua_State* L, ZIO* Z)
{
+ Proto* tf=NULL;
int c=zgetc(Z);
if (c==ID_CHUNK)
- return LoadChunk(Z);
- else if (c!=EOZ)
- luaL_verror("%s is not a Lua binary file",zname(Z));
- return NULL;
+ tf=LoadChunk(L,Z);
+ c=zgetc(Z);
+ if (c!=EOZ)
+ luaO_verror(L,"`%.99s' apparently contains more than one chunk",ZNAME(Z));
+ return tf;
}
/*
-* handle constants that cannot happen
+** find byte order
*/
-void luaU_badconstant (char* s, int i, TObject* o, TProtoFunc* tf)
+int luaU_endianess (void)
{
- int t=ttype(o);
- char* name= (t>0 || t<LUA_T_LINE) ? "?" : luaO_typenames[-t];
- luaL_verror("cannot %s constant #%d: type=%d [%s]" IN,s,i,t,name,INLOC);
+ int x=1;
+ return *(char*)&x;
}
diff --git a/src/lundump.h b/src/lundump.h
index 3f905cb0..446d2de9 100644
--- a/src/lundump.h
+++ b/src/lundump.h
@@ -1,5 +1,5 @@
/*
-** $Id: lundump.h,v 1.15 1999/07/02 19:34:26 lhf Exp $
+** $Id: lundump.h,v 1.21 2000/10/31 16:57:23 lhf Exp $
** load pre-compiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -10,27 +10,23 @@
#include "lobject.h"
#include "lzio.h"
-TProtoFunc* luaU_undump1 (ZIO* Z); /* load one chunk */
-void luaU_badconstant (char* s, int i, TObject* o, TProtoFunc* tf);
- /* handle cases that cannot happen */
-double luaU_str2d (char* b, char* where);
- /* convert number from text */
+/* load one chunk */
+Proto* luaU_undump (lua_State* L, ZIO* Z);
+
+/* find byte order */
+int luaU_endianess (void);
/* definitions for headers of binary files */
-#define VERSION 0x32 /* last format change was in 3.2 */
-#define VERSION0 0x32 /* last major change was in 3.2 */
+#define VERSION 0x40 /* last format change was in 4.0 */
+#define VERSION0 0x40 /* last major change was in 4.0 */
#define ID_CHUNK 27 /* binary files start with ESC... */
#define SIGNATURE "Lua" /* ...followed by this signature */
/* formats for error messages */
-#define SOURCE "<%s:%d>"
-#define IN " in %p " SOURCE
-#define INLOC tf,tf->source->str,tf->lineDefined
-
-/* format for numbers in listings and error messages */
-#ifndef NUMBER_FMT
-#define NUMBER_FMT "%.16g" /* LUA_NUMBER */
-#endif
+#define SOURCE_FMT "<%d:%.99s>"
+#define SOURCE tf->lineDefined,tf->source->str
+#define IN_FMT " in %p " SOURCE_FMT
+#define IN tf,SOURCE
/* a multiple of PI for testing native format */
/* multiplying by 1E8 gives non-trivial integer values */
diff --git a/src/lvm.c b/src/lvm.c
index 670642b9..63e42efb 100644
--- a/src/lvm.c
+++ b/src/lvm.c
@@ -1,28 +1,27 @@
/*
-** $Id: lvm.c,v 1.58 1999/06/22 20:37:23 roberto Exp $
+** $Id: lvm.c,v 1.146 2000/10/26 12:47:05 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
-#include <ctype.h>
-#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "lauxlib.h"
+#include "lua.h"
+
+#include "lapi.h"
+#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "lgc.h"
-#include "lmem.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "ltm.h"
-#include "luadebug.h"
#include "lvm.h"
@@ -31,605 +30,681 @@
#endif
-#define highbyte(x) ((x)<<8)
-
-
-/* Extra stack size to run a function: LUA_T_LINE(1), TM calls(2), ... */
-#define EXTRA_STACK 5
-
+/*
+** Extra stack size to run a function:
+** TAG_LINE(1), NAME(1), TM calls(3) (plus some extra...)
+*/
+#define EXTRA_STACK 8
-static TaggedString *strconc (TaggedString *l, TaggedString *r) {
- long nl = l->u.s.len;
- long nr = r->u.s.len;
- char *buffer = luaL_openspace(nl+nr);
- memcpy(buffer, l->str, nl);
- memcpy(buffer+nl, r->str, nr);
- return luaS_newlstr(buffer, nl+nr);
-}
-int luaV_tonumber (TObject *obj) { /* LUA_NUMBER */
- if (ttype(obj) != LUA_T_STRING)
+int luaV_tonumber (TObject *obj) {
+ if (ttype(obj) != LUA_TSTRING)
return 1;
else {
- double t;
- char *e = svalue(obj);
- int sig = 1;
- while (isspace((unsigned char)*e)) e++;
- if (*e == '-') {
- e++;
- sig = -1;
- }
- else if (*e == '+') e++;
- /* no digit before or after decimal point? */
- if (!isdigit((unsigned char)*e) && !isdigit((unsigned char)*(e+1)))
+ if (!luaO_str2d(svalue(obj), &nvalue(obj)))
return 2;
- t = luaO_str2d(e);
- if (t<0) return 2;
- nvalue(obj) = (real)t*sig;
- ttype(obj) = LUA_T_NUMBER;
+ ttype(obj) = LUA_TNUMBER;
return 0;
}
}
-int luaV_tostring (TObject *obj) { /* LUA_NUMBER */
- if (ttype(obj) != LUA_T_NUMBER)
+int luaV_tostring (lua_State *L, TObject *obj) { /* LUA_NUMBER */
+ if (ttype(obj) != LUA_TNUMBER)
return 1;
else {
- char s[32]; /* 16 digits, signal, point and \0 (+ some extra...) */
- sprintf(s, "%.16g", (double)nvalue(obj));
- tsvalue(obj) = luaS_new(s);
- ttype(obj) = LUA_T_STRING;
+ char s[32]; /* 16 digits, sign, point and \0 (+ some extra...) */
+ lua_number2str(s, nvalue(obj)); /* convert `s' to number */
+ tsvalue(obj) = luaS_new(L, s);
+ ttype(obj) = LUA_TSTRING;
return 0;
}
}
-void luaV_setn (Hash *t, int val) {
- TObject index, value;
- ttype(&index) = LUA_T_STRING; tsvalue(&index) = luaS_new("n");
- ttype(&value) = LUA_T_NUMBER; nvalue(&value) = val;
- luaH_set(t, &index, &value);
+static void traceexec (lua_State *L, StkId base, StkId top, lua_Hook linehook) {
+ CallInfo *ci = infovalue(base-1);
+ int *lineinfo = ci->func->f.l->lineinfo;
+ int pc = (*ci->pc - ci->func->f.l->code) - 1;
+ int newline;
+ if (pc == 0) { /* may be first time? */
+ ci->line = 1;
+ ci->refi = 0;
+ ci->lastpc = pc+1; /* make sure it will call linehook */
+ }
+ newline = luaG_getline(lineinfo, pc, ci->line, &ci->refi);
+ /* calls linehook when enters a new line or jumps back (loop) */
+ if (newline != ci->line || pc <= ci->lastpc) {
+ ci->line = newline;
+ L->top = top;
+ luaD_lineHook(L, base-2, newline, linehook);
+ }
+ ci->lastpc = pc;
+}
+
+
+static Closure *luaV_closure (lua_State *L, int nelems) {
+ Closure *c = luaF_newclosure(L, nelems);
+ L->top -= nelems;
+ while (nelems--)
+ c->upvalue[nelems] = *(L->top+nelems);
+ clvalue(L->top) = c;
+ ttype(L->top) = LUA_TFUNCTION;
+ incr_top;
+ return c;
}
-void luaV_closure (int nelems) {
- if (nelems > 0) {
- struct Stack *S = &L->stack;
- Closure *c = luaF_newclosure(nelems);
- c->consts[0] = *(S->top-1);
- memcpy(&c->consts[1], S->top-(nelems+1), nelems*sizeof(TObject));
- S->top -= nelems;
- ttype(S->top-1) = LUA_T_CLOSURE;
- (S->top-1)->value.cl = c;
- }
+void luaV_Cclosure (lua_State *L, lua_CFunction c, int nelems) {
+ Closure *cl = luaV_closure(L, nelems);
+ cl->f.c = c;
+ cl->isC = 1;
+}
+
+
+void luaV_Lclosure (lua_State *L, Proto *l, int nelems) {
+ Closure *cl = luaV_closure(L, nelems);
+ cl->f.l = l;
+ cl->isC = 0;
}
/*
** Function to index a table.
-** Receives the table at top-2 and the index at top-1.
+** Receives the table at `t' and the key at top.
*/
-void luaV_gettable (void) {
- TObject *table = L->stack.top-2;
- TObject *im;
- if (ttype(table) != LUA_T_ARRAY) { /* not a table, get gettable method */
- im = luaT_getimbyObj(table, IM_GETTABLE);
- if (ttype(im) == LUA_T_NIL)
- lua_error("indexed expression not a table");
+const TObject *luaV_gettable (lua_State *L, StkId t) {
+ Closure *tm;
+ int tg;
+ if (ttype(t) == LUA_TTABLE && /* `t' is a table? */
+ ((tg = hvalue(t)->htag) == LUA_TTABLE || /* with default tag? */
+ luaT_gettm(L, tg, TM_GETTABLE) == NULL)) { /* or no TM? */
+ /* do a primitive get */
+ const TObject *h = luaH_get(L, hvalue(t), L->top-1);
+ /* result is no nil or there is no `index' tag method? */
+ if (ttype(h) != LUA_TNIL || ((tm=luaT_gettm(L, tg, TM_INDEX)) == NULL))
+ return h; /* return result */
+ /* else call `index' tag method */
}
- else { /* object is a table... */
- int tg = table->value.a->htag;
- im = luaT_getim(tg, IM_GETTABLE);
- if (ttype(im) == LUA_T_NIL) { /* and does not have a "gettable" method */
- TObject *h = luaH_get(avalue(table), table+1);
- if (ttype(h) == LUA_T_NIL &&
- (ttype(im=luaT_getim(tg, IM_INDEX)) != LUA_T_NIL)) {
- /* result is nil and there is an "index" tag method */
- luaD_callTM(im, 2, 1); /* calls it */
- }
- else {
- L->stack.top--;
- *table = *h; /* "push" result into table position */
- }
- return;
- }
- /* else it has a "gettable" method, go through to next command */
+ else { /* try a `gettable' tag method */
+ tm = luaT_gettmbyObj(L, t, TM_GETTABLE);
+ }
+ if (tm != NULL) { /* is there a tag method? */
+ luaD_checkstack(L, 2);
+ *(L->top+1) = *(L->top-1); /* key */
+ *L->top = *t; /* table */
+ clvalue(L->top-1) = tm; /* tag method */
+ ttype(L->top-1) = LUA_TFUNCTION;
+ L->top += 2;
+ luaD_call(L, L->top - 3, 1);
+ return L->top - 1; /* call result */
+ }
+ else { /* no tag method */
+ luaG_typeerror(L, t, "index");
+ return NULL; /* to avoid warnings */
}
- /* object is not a table, or it has a "gettable" method */
- luaD_callTM(im, 2, 1);
}
/*
-** Receives table at *t, index at *(t+1) and value at top.
+** Receives table at `t', key at `key' and value at top.
*/
-void luaV_settable (TObject *t) {
- struct Stack *S = &L->stack;
- TObject *im;
- if (ttype(t) != LUA_T_ARRAY) { /* not a table, get "settable" method */
- im = luaT_getimbyObj(t, IM_SETTABLE);
- if (ttype(im) == LUA_T_NIL)
- lua_error("indexed expression not a table");
- }
- else { /* object is a table... */
- im = luaT_getim(avalue(t)->htag, IM_SETTABLE);
- if (ttype(im) == LUA_T_NIL) { /* and does not have a "settable" method */
- luaH_set(avalue(t), t+1, S->top-1);
- S->top--; /* pop value */
- return;
+void luaV_settable (lua_State *L, StkId t, StkId key) {
+ int tg;
+ if (ttype(t) == LUA_TTABLE && /* `t' is a table? */
+ ((tg = hvalue(t)->htag) == LUA_TTABLE || /* with default tag? */
+ luaT_gettm(L, tg, TM_SETTABLE) == NULL)) /* or no TM? */
+ *luaH_set(L, hvalue(t), key) = *(L->top-1); /* do a primitive set */
+ else { /* try a `settable' tag method */
+ Closure *tm = luaT_gettmbyObj(L, t, TM_SETTABLE);
+ if (tm != NULL) {
+ luaD_checkstack(L, 3);
+ *(L->top+2) = *(L->top-1);
+ *(L->top+1) = *key;
+ *(L->top) = *t;
+ clvalue(L->top-1) = tm;
+ ttype(L->top-1) = LUA_TFUNCTION;
+ L->top += 3;
+ luaD_call(L, L->top - 4, 0); /* call `settable' tag method */
}
- /* else it has a "settable" method, go through to next command */
+ else /* no tag method... */
+ luaG_typeerror(L, t, "index");
}
- /* object is not a table, or it has a "settable" method */
- /* prepare arguments and call the tag method */
- *(S->top+1) = *(L->stack.top-1);
- *(S->top) = *(t+1);
- *(S->top-1) = *t;
- S->top += 2; /* WARNING: caller must assure stack space */
- luaD_callTM(im, 3, 0);
}
-void luaV_rawsettable (TObject *t) {
- if (ttype(t) != LUA_T_ARRAY)
- lua_error("indexed expression not a table");
- else {
- struct Stack *S = &L->stack;
- luaH_set(avalue(t), t+1, S->top-1);
- S->top -= 3;
+const TObject *luaV_getglobal (lua_State *L, TString *s) {
+ const TObject *value = luaH_getstr(L->gt, s);
+ Closure *tm = luaT_gettmbyObj(L, value, TM_GETGLOBAL);
+ if (tm == NULL) /* is there a tag method? */
+ return value; /* default behavior */
+ else { /* tag method */
+ luaD_checkstack(L, 3);
+ clvalue(L->top) = tm;
+ ttype(L->top) = LUA_TFUNCTION;
+ tsvalue(L->top+1) = s; /* global name */
+ ttype(L->top+1) = LUA_TSTRING;
+ *(L->top+2) = *value;
+ L->top += 3;
+ luaD_call(L, L->top - 3, 1);
+ return L->top - 1;
}
}
-void luaV_getglobal (TaggedString *ts) {
- /* WARNING: caller must assure stack space */
- /* only userdata, tables and nil can have getglobal tag methods */
- static char valid_getglobals[] = {1, 0, 0, 1, 0, 0, 1, 0}; /* ORDER LUA_T */
- TObject *value = &ts->u.s.globalval;
- if (valid_getglobals[-ttype(value)]) {
- TObject *im = luaT_getimbyObj(value, IM_GETGLOBAL);
- if (ttype(im) != LUA_T_NIL) { /* is there a tag method? */
- struct Stack *S = &L->stack;
- ttype(S->top) = LUA_T_STRING;
- tsvalue(S->top) = ts;
- S->top++;
- *S->top++ = *value;
- luaD_callTM(im, 2, 1);
- return;
+void luaV_setglobal (lua_State *L, TString *s) {
+ const TObject *oldvalue = luaH_getstr(L->gt, s);
+ Closure *tm = luaT_gettmbyObj(L, oldvalue, TM_SETGLOBAL);
+ if (tm == NULL) { /* is there a tag method? */
+ if (oldvalue != &luaO_nilobject) {
+ /* cast to remove `const' is OK, because `oldvalue' != luaO_nilobject */
+ *(TObject *)oldvalue = *(L->top - 1);
+ }
+ else {
+ TObject key;
+ ttype(&key) = LUA_TSTRING;
+ tsvalue(&key) = s;
+ *luaH_set(L, L->gt, &key) = *(L->top - 1);
}
- /* else no tag method: go through to default behavior */
}
- *L->stack.top++ = *value; /* default behavior */
-}
-
-
-void luaV_setglobal (TaggedString *ts) {
- TObject *oldvalue = &ts->u.s.globalval;
- TObject *im = luaT_getimbyObj(oldvalue, IM_SETGLOBAL);
- if (ttype(im) == LUA_T_NIL) /* is there a tag method? */
- luaS_rawsetglobal(ts, --L->stack.top);
else {
- /* WARNING: caller must assure stack space */
- struct Stack *S = &L->stack;
- TObject newvalue;
- newvalue = *(S->top-1);
- ttype(S->top-1) = LUA_T_STRING;
- tsvalue(S->top-1) = ts;
- *S->top++ = *oldvalue;
- *S->top++ = newvalue;
- luaD_callTM(im, 3, 0);
+ luaD_checkstack(L, 3);
+ *(L->top+2) = *(L->top-1); /* new value */
+ *(L->top+1) = *oldvalue;
+ ttype(L->top) = LUA_TSTRING;
+ tsvalue(L->top) = s;
+ clvalue(L->top-1) = tm;
+ ttype(L->top-1) = LUA_TFUNCTION;
+ L->top += 3;
+ luaD_call(L, L->top - 4, 0);
}
}
-static void call_binTM (IMS event, char *msg)
-{
- TObject *im = luaT_getimbyObj(L->stack.top-2, event);/* try first operand */
- if (ttype(im) == LUA_T_NIL) {
- im = luaT_getimbyObj(L->stack.top-1, event); /* try second operand */
- if (ttype(im) == LUA_T_NIL) {
- im = luaT_getim(0, event); /* try a 'global' i.m. */
- if (ttype(im) == LUA_T_NIL)
- lua_error(msg);
+static int call_binTM (lua_State *L, StkId top, TMS event) {
+ /* try first operand */
+ Closure *tm = luaT_gettmbyObj(L, top-2, event);
+ L->top = top;
+ if (tm == NULL) {
+ tm = luaT_gettmbyObj(L, top-1, event); /* try second operand */
+ if (tm == NULL) {
+ tm = luaT_gettm(L, 0, event); /* try a `global' method */
+ if (tm == NULL)
+ return 0; /* error */
}
}
- lua_pushstring(luaT_eventname[event]);
- luaD_callTM(im, 3, 1);
+ lua_pushstring(L, luaT_eventname[event]);
+ luaD_callTM(L, tm, 3, 1);
+ return 1;
}
-static void call_arith (IMS event)
-{
- call_binTM(event, "unexpected type in arithmetic operation");
+static void call_arith (lua_State *L, StkId top, TMS event) {
+ if (!call_binTM(L, top, event))
+ luaG_binerror(L, top-2, LUA_TNUMBER, "perform arithmetic on");
}
-static int luaV_strcomp (char *l, long ll, char *r, long lr)
-{
+static int luaV_strcomp (const TString *ls, const TString *rs) {
+ const char *l = ls->str;
+ size_t ll = ls->len;
+ const char *r = rs->str;
+ size_t lr = rs->len;
for (;;) {
- long temp = strcoll(l, r);
+ int temp = strcoll(l, r);
if (temp != 0) return temp;
- /* strings are equal up to a '\0' */
- temp = strlen(l); /* index of first '\0' in both strings */
- if (temp == ll) /* l is finished? */
- return (temp == lr) ? 0 : -1; /* l is equal or smaller than r */
- else if (temp == lr) /* r is finished? */
- return 1; /* l is greater than r (because l is not finished) */
- /* both strings longer than temp; go on comparing (after the '\0') */
- temp++;
- l += temp; ll -= temp; r += temp; lr -= temp;
+ else { /* strings are equal up to a '\0' */
+ size_t len = strlen(l); /* index of first '\0' in both strings */
+ if (len == ll) /* l is finished? */
+ return (len == lr) ? 0 : -1; /* l is equal or smaller than r */
+ else if (len == lr) /* r is finished? */
+ return 1; /* l is greater than r (because l is not finished) */
+ /* both strings longer than `len'; go on comparing (after the '\0') */
+ len++;
+ l += len; ll -= len; r += len; lr -= len;
+ }
}
}
-void luaV_comparison (lua_Type ttype_less, lua_Type ttype_equal,
- lua_Type ttype_great, IMS op) {
- struct Stack *S = &L->stack;
- TObject *l = S->top-2;
- TObject *r = S->top-1;
- real result;
- if (ttype(l) == LUA_T_NUMBER && ttype(r) == LUA_T_NUMBER)
- result = nvalue(l)-nvalue(r);
- else if (ttype(l) == LUA_T_STRING && ttype(r) == LUA_T_STRING)
- result = luaV_strcomp(svalue(l), tsvalue(l)->u.s.len,
- svalue(r), tsvalue(r)->u.s.len);
- else {
- call_binTM(op, "unexpected type in comparison");
- return;
+
+int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r, StkId top) {
+ if (ttype(l) == LUA_TNUMBER && ttype(r) == LUA_TNUMBER)
+ return (nvalue(l) < nvalue(r));
+ else if (ttype(l) == LUA_TSTRING && ttype(r) == LUA_TSTRING)
+ return (luaV_strcomp(tsvalue(l), tsvalue(r)) < 0);
+ else { /* call TM */
+ luaD_checkstack(L, 2);
+ *top++ = *l;
+ *top++ = *r;
+ if (!call_binTM(L, top, TM_LT))
+ luaG_ordererror(L, top-2);
+ L->top--;
+ return (ttype(L->top) != LUA_TNIL);
}
- S->top--;
- nvalue(S->top-1) = 1;
- ttype(S->top-1) = (result < 0) ? ttype_less :
- (result == 0) ? ttype_equal : ttype_great;
}
-void luaV_pack (StkId firstel, int nvararg, TObject *tab) {
- TObject *firstelem = L->stack.stack+firstel;
+void luaV_strconc (lua_State *L, int total, StkId top) {
+ do {
+ int n = 2; /* number of elements handled in this pass (at least 2) */
+ if (tostring(L, top-2) || tostring(L, top-1)) {
+ if (!call_binTM(L, top, TM_CONCAT))
+ luaG_binerror(L, top-2, LUA_TSTRING, "concat");
+ }
+ else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */
+ /* at least two string values; get as many as possible */
+ lint32 tl = (lint32)tsvalue(top-1)->len +
+ (lint32)tsvalue(top-2)->len;
+ char *buffer;
+ int i;
+ while (n < total && !tostring(L, top-n-1)) { /* collect total length */
+ tl += tsvalue(top-n-1)->len;
+ n++;
+ }
+ if (tl > MAX_SIZET) lua_error(L, "string size overflow");
+ buffer = luaO_openspace(L, tl);
+ tl = 0;
+ for (i=n; i>0; i--) { /* concat all strings */
+ size_t l = tsvalue(top-i)->len;
+ memcpy(buffer+tl, tsvalue(top-i)->str, l);
+ tl += l;
+ }
+ tsvalue(top-n) = luaS_newlstr(L, buffer, tl);
+ }
+ total -= n-1; /* got `n' strings to create 1 new */
+ top -= n-1;
+ } while (total > 1); /* repeat until only 1 result left */
+}
+
+
+static void luaV_pack (lua_State *L, StkId firstelem) {
int i;
- Hash *htab;
- if (nvararg < 0) nvararg = 0;
- htab = avalue(tab) = luaH_new(nvararg+1); /* +1 for field 'n' */
- ttype(tab) = LUA_T_ARRAY;
- for (i=0; i<nvararg; i++)
- luaH_setint(htab, i+1, firstelem+i);
- luaV_setn(htab, nvararg); /* store counter in field "n" */
+ Hash *htab = luaH_new(L, 0);
+ for (i=0; firstelem+i<L->top; i++)
+ *luaH_setint(L, htab, i+1) = *(firstelem+i);
+ /* store counter in field `n' */
+ luaH_setstrnum(L, htab, luaS_new(L, "n"), i);
+ L->top = firstelem; /* remove elements from the stack */
+ ttype(L->top) = LUA_TTABLE;
+ hvalue(L->top) = htab;
+ incr_top;
}
-static void adjust_varargs (StkId first_extra_arg)
-{
- TObject arg;
- luaV_pack(first_extra_arg,
- (L->stack.top-L->stack.stack)-first_extra_arg, &arg);
- luaD_adjusttop(first_extra_arg);
- *L->stack.top++ = arg;
+static void adjust_varargs (lua_State *L, StkId base, int nfixargs) {
+ int nvararg = (L->top-base) - nfixargs;
+ if (nvararg < 0)
+ luaD_adjusttop(L, base, nfixargs);
+ luaV_pack(L, base+nfixargs);
}
+#define dojump(pc, i) { int d = GETARG_S(i); pc += d; }
+
/*
-** Execute the given opcode, until a RET. Parameters are between
-** [stack+base,top). Returns n such that the the results are between
-** [stack+n,top).
+** Executes the given Lua function. Parameters are between [base,top).
+** Returns n such that the the results are between [n,top).
*/
-StkId luaV_execute (Closure *cl, TProtoFunc *tf, StkId base) {
- struct Stack *S = &L->stack; /* to optimize */
- register Byte *pc = tf->code;
- TObject *consts = tf->consts;
- if (L->callhook)
- luaD_callHook(base, tf, 0);
- luaD_checkstack((*pc++)+EXTRA_STACK);
- if (*pc < ZEROVARARG)
- luaD_adjusttop(base+*(pc++));
- else { /* varargs */
- luaC_checkGC();
- adjust_varargs(base+(*pc++)-ZEROVARARG);
- }
+StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) {
+ const Proto *const tf = cl->f.l;
+ StkId top; /* keep top local, for performance */
+ const Instruction *pc = tf->code;
+ TString **const kstr = tf->kstr;
+ const lua_Hook linehook = L->linehook;
+ infovalue(base-1)->pc = &pc;
+ luaD_checkstack(L, tf->maxstacksize+EXTRA_STACK);
+ if (tf->is_vararg) /* varargs? */
+ adjust_varargs(L, base, tf->numparams);
+ else
+ luaD_adjusttop(L, base, tf->numparams);
+ top = L->top;
+ /* main loop of interpreter */
for (;;) {
- register int aux = 0;
- switchentry:
- switch ((OpCode)*pc++) {
-
- case ENDCODE:
- S->top = S->stack + base;
- goto ret;
-
- case RETCODE:
- base += *pc++;
- goto ret;
-
- case CALL: aux = *pc++;
- luaD_calln(*pc++, aux);
+ const Instruction i = *pc++;
+ if (linehook)
+ traceexec(L, base, top, linehook);
+ switch (GET_OPCODE(i)) {
+ case OP_END: {
+ L->top = top;
+ return top;
+ }
+ case OP_RETURN: {
+ L->top = top;
+ return base+GETARG_U(i);
+ }
+ case OP_CALL: {
+ int nres = GETARG_B(i);
+ if (nres == MULT_RET) nres = LUA_MULTRET;
+ L->top = top;
+ luaD_call(L, base+GETARG_A(i), nres);
+ top = L->top;
break;
-
- case TAILCALL: aux = *pc++;
- luaD_calln(*pc++, MULT_RET);
- base += aux;
- goto ret;
-
- case PUSHNIL: aux = *pc++;
+ }
+ case OP_TAILCALL: {
+ L->top = top;
+ luaD_call(L, base+GETARG_A(i), LUA_MULTRET);
+ return base+GETARG_B(i);
+ }
+ case OP_PUSHNIL: {
+ int n = GETARG_U(i);
+ LUA_ASSERT(n>0, "invalid argument");
do {
- ttype(S->top++) = LUA_T_NIL;
- } while (aux--);
+ ttype(top++) = LUA_TNIL;
+ } while (--n > 0);
break;
-
- case POP: aux = *pc++;
- S->top -= aux;
+ }
+ case OP_POP: {
+ top -= GETARG_U(i);
break;
-
- case PUSHNUMBERW: aux += highbyte(*pc++);
- case PUSHNUMBER: aux += *pc++;
- ttype(S->top) = LUA_T_NUMBER;
- nvalue(S->top) = aux;
- S->top++;
+ }
+ case OP_PUSHINT: {
+ ttype(top) = LUA_TNUMBER;
+ nvalue(top) = (Number)GETARG_S(i);
+ top++;
break;
-
- case PUSHNUMBERNEGW: aux += highbyte(*pc++);
- case PUSHNUMBERNEG: aux += *pc++;
- ttype(S->top) = LUA_T_NUMBER;
- nvalue(S->top) = -aux;
- S->top++;
+ }
+ case OP_PUSHSTRING: {
+ ttype(top) = LUA_TSTRING;
+ tsvalue(top) = kstr[GETARG_U(i)];
+ top++;
break;
-
- case PUSHCONSTANTW: aux += highbyte(*pc++);
- case PUSHCONSTANT: aux += *pc++;
- *S->top++ = consts[aux];
+ }
+ case OP_PUSHNUM: {
+ ttype(top) = LUA_TNUMBER;
+ nvalue(top) = tf->knum[GETARG_U(i)];
+ top++;
break;
-
- case PUSHUPVALUE: aux = *pc++;
- *S->top++ = cl->consts[aux+1];
+ }
+ case OP_PUSHNEGNUM: {
+ ttype(top) = LUA_TNUMBER;
+ nvalue(top) = -tf->knum[GETARG_U(i)];
+ top++;
break;
-
- case PUSHLOCAL: aux = *pc++;
- *S->top++ = *((S->stack+base) + aux);
+ }
+ case OP_PUSHUPVALUE: {
+ *top++ = cl->upvalue[GETARG_U(i)];
break;
-
- case GETGLOBALW: aux += highbyte(*pc++);
- case GETGLOBAL: aux += *pc++;
- luaV_getglobal(tsvalue(&consts[aux]));
+ }
+ case OP_GETLOCAL: {
+ *top++ = *(base+GETARG_U(i));
break;
-
- case GETTABLE:
- luaV_gettable();
+ }
+ case OP_GETGLOBAL: {
+ L->top = top;
+ *top = *luaV_getglobal(L, kstr[GETARG_U(i)]);
+ top++;
break;
-
- case GETDOTTEDW: aux += highbyte(*pc++);
- case GETDOTTED: aux += *pc++;
- *S->top++ = consts[aux];
- luaV_gettable();
+ }
+ case OP_GETTABLE: {
+ L->top = top;
+ top--;
+ *(top-1) = *luaV_gettable(L, top-1);
break;
-
- case PUSHSELFW: aux += highbyte(*pc++);
- case PUSHSELF: aux += *pc++; {
- TObject receiver;
- receiver = *(S->top-1);
- *S->top++ = consts[aux];
- luaV_gettable();
- *S->top++ = receiver;
+ }
+ case OP_GETDOTTED: {
+ ttype(top) = LUA_TSTRING;
+ tsvalue(top) = kstr[GETARG_U(i)];
+ L->top = top+1;
+ *(top-1) = *luaV_gettable(L, top-1);
break;
}
-
- case CREATEARRAYW: aux += highbyte(*pc++);
- case CREATEARRAY: aux += *pc++;
- luaC_checkGC();
- avalue(S->top) = luaH_new(aux);
- ttype(S->top) = LUA_T_ARRAY;
- S->top++;
+ case OP_GETINDEXED: {
+ *top = *(base+GETARG_U(i));
+ L->top = top+1;
+ *(top-1) = *luaV_gettable(L, top-1);
break;
-
- case SETLOCAL: aux = *pc++;
- *((S->stack+base) + aux) = *(--S->top);
+ }
+ case OP_PUSHSELF: {
+ TObject receiver;
+ receiver = *(top-1);
+ ttype(top) = LUA_TSTRING;
+ tsvalue(top++) = kstr[GETARG_U(i)];
+ L->top = top;
+ *(top-2) = *luaV_gettable(L, top-2);
+ *(top-1) = receiver;
break;
-
- case SETGLOBALW: aux += highbyte(*pc++);
- case SETGLOBAL: aux += *pc++;
- luaV_setglobal(tsvalue(&consts[aux]));
+ }
+ case OP_CREATETABLE: {
+ L->top = top;
+ luaC_checkGC(L);
+ hvalue(top) = luaH_new(L, GETARG_U(i));
+ ttype(top) = LUA_TTABLE;
+ top++;
break;
-
- case SETTABLEPOP:
- luaV_settable(S->top-3);
- S->top -= 2; /* pop table and index */
+ }
+ case OP_SETLOCAL: {
+ *(base+GETARG_U(i)) = *(--top);
break;
-
- case SETTABLE:
- luaV_settable(S->top-3-(*pc++));
+ }
+ case OP_SETGLOBAL: {
+ L->top = top;
+ luaV_setglobal(L, kstr[GETARG_U(i)]);
+ top--;
break;
-
- case SETLISTW: aux += highbyte(*pc++);
- case SETLIST: aux += *pc++; {
- int n = *(pc++);
- Hash *arr = avalue(S->top-n-1);
- aux *= LFIELDS_PER_FLUSH;
+ }
+ case OP_SETTABLE: {
+ StkId t = top-GETARG_A(i);
+ L->top = top;
+ luaV_settable(L, t, t+1);
+ top -= GETARG_B(i); /* pop values */
+ break;
+ }
+ case OP_SETLIST: {
+ int aux = GETARG_A(i) * LFIELDS_PER_FLUSH;
+ int n = GETARG_B(i);
+ Hash *arr = hvalue(top-n-1);
+ L->top = top-n; /* final value of `top' (in case of errors) */
for (; n; n--)
- luaH_setint(arr, n+aux, --S->top);
+ *luaH_setint(L, arr, n+aux) = *(--top);
break;
}
-
- case SETMAP: aux = *pc++; {
- Hash *arr = avalue(S->top-(2*aux)-3);
- do {
- luaH_set(arr, S->top-2, S->top-1);
- S->top-=2;
- } while (aux--);
+ case OP_SETMAP: {
+ int n = GETARG_U(i);
+ StkId finaltop = top-2*n;
+ Hash *arr = hvalue(finaltop-1);
+ L->top = finaltop; /* final value of `top' (in case of errors) */
+ for (; n; n--) {
+ top-=2;
+ *luaH_set(L, arr, top) = *(top+1);
+ }
break;
}
-
- case NEQOP: aux = 1;
- case EQOP: {
- int res = luaO_equalObj(S->top-2, S->top-1);
- if (aux) res = !res;
- S->top--;
- ttype(S->top-1) = res ? LUA_T_NUMBER : LUA_T_NIL;
- nvalue(S->top-1) = 1;
+ case OP_ADD: {
+ if (tonumber(top-2) || tonumber(top-1))
+ call_arith(L, top, TM_ADD);
+ else
+ nvalue(top-2) += nvalue(top-1);
+ top--;
break;
}
-
- case LTOP:
- luaV_comparison(LUA_T_NUMBER, LUA_T_NIL, LUA_T_NIL, IM_LT);
- break;
-
- case LEOP:
- luaV_comparison(LUA_T_NUMBER, LUA_T_NUMBER, LUA_T_NIL, IM_LE);
+ case OP_ADDI: {
+ if (tonumber(top-1)) {
+ ttype(top) = LUA_TNUMBER;
+ nvalue(top) = (Number)GETARG_S(i);
+ call_arith(L, top+1, TM_ADD);
+ }
+ else
+ nvalue(top-1) += (Number)GETARG_S(i);
break;
-
- case GTOP:
- luaV_comparison(LUA_T_NIL, LUA_T_NIL, LUA_T_NUMBER, IM_GT);
+ }
+ case OP_SUB: {
+ if (tonumber(top-2) || tonumber(top-1))
+ call_arith(L, top, TM_SUB);
+ else
+ nvalue(top-2) -= nvalue(top-1);
+ top--;
break;
-
- case GEOP:
- luaV_comparison(LUA_T_NIL, LUA_T_NUMBER, LUA_T_NUMBER, IM_GE);
+ }
+ case OP_MULT: {
+ if (tonumber(top-2) || tonumber(top-1))
+ call_arith(L, top, TM_MUL);
+ else
+ nvalue(top-2) *= nvalue(top-1);
+ top--;
break;
-
- case ADDOP: {
- TObject *l = S->top-2;
- TObject *r = S->top-1;
- if (tonumber(r) || tonumber(l))
- call_arith(IM_ADD);
- else {
- nvalue(l) += nvalue(r);
- --S->top;
- }
+ }
+ case OP_DIV: {
+ if (tonumber(top-2) || tonumber(top-1))
+ call_arith(L, top, TM_DIV);
+ else
+ nvalue(top-2) /= nvalue(top-1);
+ top--;
break;
}
-
- case SUBOP: {
- TObject *l = S->top-2;
- TObject *r = S->top-1;
- if (tonumber(r) || tonumber(l))
- call_arith(IM_SUB);
- else {
- nvalue(l) -= nvalue(r);
- --S->top;
- }
+ case OP_POW: {
+ if (!call_binTM(L, top, TM_POW))
+ lua_error(L, "undefined operation");
+ top--;
break;
}
-
- case MULTOP: {
- TObject *l = S->top-2;
- TObject *r = S->top-1;
- if (tonumber(r) || tonumber(l))
- call_arith(IM_MUL);
- else {
- nvalue(l) *= nvalue(r);
- --S->top;
- }
+ case OP_CONCAT: {
+ int n = GETARG_U(i);
+ luaV_strconc(L, n, top);
+ top -= n-1;
+ L->top = top;
+ luaC_checkGC(L);
break;
}
-
- case DIVOP: {
- TObject *l = S->top-2;
- TObject *r = S->top-1;
- if (tonumber(r) || tonumber(l))
- call_arith(IM_DIV);
- else {
- nvalue(l) /= nvalue(r);
- --S->top;
+ case OP_MINUS: {
+ if (tonumber(top-1)) {
+ ttype(top) = LUA_TNIL;
+ call_arith(L, top+1, TM_UNM);
}
+ else
+ nvalue(top-1) = -nvalue(top-1);
break;
}
-
- case POWOP:
- call_binTM(IM_POW, "undefined operation");
+ case OP_NOT: {
+ ttype(top-1) =
+ (ttype(top-1) == LUA_TNIL) ? LUA_TNUMBER : LUA_TNIL;
+ nvalue(top-1) = 1;
break;
-
- case CONCOP: {
- TObject *l = S->top-2;
- TObject *r = S->top-1;
- if (tostring(l) || tostring(r))
- call_binTM(IM_CONCAT, "unexpected type for concatenation");
- else {
- tsvalue(l) = strconc(tsvalue(l), tsvalue(r));
- --S->top;
- }
- luaC_checkGC();
+ }
+ case OP_JMPNE: {
+ top -= 2;
+ if (!luaO_equalObj(top, top+1)) dojump(pc, i);
break;
}
-
- case MINUSOP:
- if (tonumber(S->top-1)) {
- ttype(S->top) = LUA_T_NIL;
- S->top++;
- call_arith(IM_UNM);
- }
- else
- nvalue(S->top-1) = - nvalue(S->top-1);
+ case OP_JMPEQ: {
+ top -= 2;
+ if (luaO_equalObj(top, top+1)) dojump(pc, i);
break;
-
- case NOTOP:
- ttype(S->top-1) =
- (ttype(S->top-1) == LUA_T_NIL) ? LUA_T_NUMBER : LUA_T_NIL;
- nvalue(S->top-1) = 1;
+ }
+ case OP_JMPLT: {
+ top -= 2;
+ if (luaV_lessthan(L, top, top+1, top+2)) dojump(pc, i);
break;
-
- case ONTJMPW: aux += highbyte(*pc++);
- case ONTJMP: aux += *pc++;
- if (ttype(S->top-1) != LUA_T_NIL) pc += aux;
- else S->top--;
+ }
+ case OP_JMPLE: { /* a <= b === !(b<a) */
+ top -= 2;
+ if (!luaV_lessthan(L, top+1, top, top+2)) dojump(pc, i);
break;
-
- case ONFJMPW: aux += highbyte(*pc++);
- case ONFJMP: aux += *pc++;
- if (ttype(S->top-1) == LUA_T_NIL) pc += aux;
- else S->top--;
+ }
+ case OP_JMPGT: { /* a > b === (b<a) */
+ top -= 2;
+ if (luaV_lessthan(L, top+1, top, top+2)) dojump(pc, i);
break;
-
- case JMPW: aux += highbyte(*pc++);
- case JMP: aux += *pc++;
- pc += aux;
+ }
+ case OP_JMPGE: { /* a >= b === !(a<b) */
+ top -= 2;
+ if (!luaV_lessthan(L, top, top+1, top+2)) dojump(pc, i);
break;
-
- case IFFJMPW: aux += highbyte(*pc++);
- case IFFJMP: aux += *pc++;
- if (ttype(--S->top) == LUA_T_NIL) pc += aux;
+ }
+ case OP_JMPT: {
+ if (ttype(--top) != LUA_TNIL) dojump(pc, i);
break;
-
- case IFTUPJMPW: aux += highbyte(*pc++);
- case IFTUPJMP: aux += *pc++;
- if (ttype(--S->top) != LUA_T_NIL) pc -= aux;
+ }
+ case OP_JMPF: {
+ if (ttype(--top) == LUA_TNIL) dojump(pc, i);
break;
-
- case IFFUPJMPW: aux += highbyte(*pc++);
- case IFFUPJMP: aux += *pc++;
- if (ttype(--S->top) == LUA_T_NIL) pc -= aux;
+ }
+ case OP_JMPONT: {
+ if (ttype(top-1) == LUA_TNIL) top--;
+ else dojump(pc, i);
break;
-
- case CLOSUREW: aux += highbyte(*pc++);
- case CLOSURE: aux += *pc++;
- *S->top++ = consts[aux];
- luaV_closure(*pc++);
- luaC_checkGC();
+ }
+ case OP_JMPONF: {
+ if (ttype(top-1) != LUA_TNIL) top--;
+ else dojump(pc, i);
break;
-
- case SETLINEW: aux += highbyte(*pc++);
- case SETLINE: aux += *pc++;
- if ((S->stack+base-1)->ttype != LUA_T_LINE) {
- /* open space for LINE value */
- luaD_openstack((S->top-S->stack)-base);
- base++;
- (S->stack+base-1)->ttype = LUA_T_LINE;
+ }
+ case OP_JMP: {
+ dojump(pc, i);
+ break;
+ }
+ case OP_PUSHNILJMP: {
+ ttype(top++) = LUA_TNIL;
+ pc++;
+ break;
+ }
+ case OP_FORPREP: {
+ if (tonumber(top-1))
+ lua_error(L, "`for' step must be a number");
+ if (tonumber(top-2))
+ lua_error(L, "`for' limit must be a number");
+ if (tonumber(top-3))
+ lua_error(L, "`for' initial value must be a number");
+ if (nvalue(top-1) > 0 ?
+ nvalue(top-3) > nvalue(top-2) :
+ nvalue(top-3) < nvalue(top-2)) { /* `empty' loop? */
+ top -= 3; /* remove control variables */
+ dojump(pc, i); /* jump to loop end */
}
- (S->stack+base-1)->value.i = aux;
- if (L->linehook)
- luaD_lineHook(aux);
break;
-
- case LONGARGW: aux += highbyte(*pc++);
- case LONGARG: aux += *pc++;
- aux = highbyte(highbyte(aux));
- goto switchentry; /* do not reset "aux" */
-
- case CHECKSTACK: aux = *pc++;
- LUA_ASSERT((S->top-S->stack)-base == aux && S->last >= S->top,
- "wrong stack size");
+ }
+ case OP_FORLOOP: {
+ LUA_ASSERT(ttype(top-1) == LUA_TNUMBER, "invalid step");
+ LUA_ASSERT(ttype(top-2) == LUA_TNUMBER, "invalid limit");
+ if (ttype(top-3) != LUA_TNUMBER)
+ lua_error(L, "`for' index must be a number");
+ nvalue(top-3) += nvalue(top-1); /* increment index */
+ if (nvalue(top-1) > 0 ?
+ nvalue(top-3) > nvalue(top-2) :
+ nvalue(top-3) < nvalue(top-2))
+ top -= 3; /* end loop: remove control variables */
+ else
+ dojump(pc, i); /* repeat loop */
break;
-
+ }
+ case OP_LFORPREP: {
+ Node *node;
+ if (ttype(top-1) != LUA_TTABLE)
+ lua_error(L, "`for' table must be a table");
+ node = luaH_next(L, hvalue(top-1), &luaO_nilobject);
+ if (node == NULL) { /* `empty' loop? */
+ top--; /* remove table */
+ dojump(pc, i); /* jump to loop end */
+ }
+ else {
+ top += 2; /* index,value */
+ *(top-2) = *key(node);
+ *(top-1) = *val(node);
+ }
+ break;
+ }
+ case OP_LFORLOOP: {
+ Node *node;
+ LUA_ASSERT(ttype(top-3) == LUA_TTABLE, "invalid table");
+ node = luaH_next(L, hvalue(top-3), top-2);
+ if (node == NULL) /* end loop? */
+ top -= 3; /* remove table, key, and value */
+ else {
+ *(top-2) = *key(node);
+ *(top-1) = *val(node);
+ dojump(pc, i); /* repeat loop */
+ }
+ break;
+ }
+ case OP_CLOSURE: {
+ L->top = top;
+ luaV_Lclosure(L, tf->kproto[GETARG_A(i)], GETARG_B(i));
+ top = L->top;
+ luaC_checkGC(L);
+ break;
+ }
}
- } ret:
- if (L->callhook)
- luaD_callHook(0, NULL, 1);
- return base;
+ }
}
-
diff --git a/src/lvm.h b/src/lvm.h
index d6a639e2..ace07c82 100644
--- a/src/lvm.h
+++ b/src/lvm.h
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.h,v 1.8 1999/02/08 17:07:59 roberto Exp $
+** $Id: lvm.h,v 1.27 2000/10/05 12:14:08 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -13,22 +13,20 @@
#include "ltm.h"
-#define tonumber(o) ((ttype(o) != LUA_T_NUMBER) && (luaV_tonumber(o) != 0))
-#define tostring(o) ((ttype(o) != LUA_T_STRING) && (luaV_tostring(o) != 0))
+#define tonumber(o) ((ttype(o) != LUA_TNUMBER) && (luaV_tonumber(o) != 0))
+#define tostring(L,o) ((ttype(o) != LUA_TSTRING) && (luaV_tostring(L, o) != 0))
-void luaV_pack (StkId firstel, int nvararg, TObject *tab);
int luaV_tonumber (TObject *obj);
-int luaV_tostring (TObject *obj);
-void luaV_setn (Hash *t, int val);
-void luaV_gettable (void);
-void luaV_settable (TObject *t);
-void luaV_rawsettable (TObject *t);
-void luaV_getglobal (TaggedString *ts);
-void luaV_setglobal (TaggedString *ts);
-StkId luaV_execute (Closure *cl, TProtoFunc *tf, StkId base);
-void luaV_closure (int nelems);
-void luaV_comparison (lua_Type ttype_less, lua_Type ttype_equal,
- lua_Type ttype_great, IMS op);
+int luaV_tostring (lua_State *L, TObject *obj);
+const TObject *luaV_gettable (lua_State *L, StkId t);
+void luaV_settable (lua_State *L, StkId t, StkId key);
+const TObject *luaV_getglobal (lua_State *L, TString *s);
+void luaV_setglobal (lua_State *L, TString *s);
+StkId luaV_execute (lua_State *L, const Closure *cl, StkId base);
+void luaV_Cclosure (lua_State *L, lua_CFunction c, int nelems);
+void luaV_Lclosure (lua_State *L, Proto *l, int nelems);
+int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r, StkId top);
+void luaV_strconc (lua_State *L, int total, StkId top);
#endif
diff --git a/src/lzio.c b/src/lzio.c
index 865d9c5e..c958fe46 100644
--- a/src/lzio.c
+++ b/src/lzio.c
@@ -1,5 +1,5 @@
/*
-** $Id: lzio.c,v 1.7 1999/03/05 13:15:50 roberto Exp $
+** $Id: lzio.c,v 1.13 2000/06/12 13:52:05 roberto Exp $
** a generic input stream interface
** See Copyright Notice in lua.h
*/
@@ -9,6 +9,8 @@
#include <stdio.h>
#include <string.h>
+#include "lua.h"
+
#include "lzio.h"
@@ -16,62 +18,60 @@
/* ----------------------------------------------------- memory buffers --- */
static int zmfilbuf (ZIO* z) {
- return EOZ;
+ (void)z; /* to avoid warnings */
+ return EOZ;
}
-ZIO* zmopen (ZIO* z, char* b, int size, char *name)
-{
- if (b==NULL) return NULL;
- z->n=size;
- z->p= (unsigned char *)b;
- z->filbuf=zmfilbuf;
- z->u=NULL;
- z->name=name;
- return z;
+ZIO* zmopen (ZIO* z, const char* b, size_t size, const char *name) {
+ if (b==NULL) return NULL;
+ z->n = size;
+ z->p = (const unsigned char *)b;
+ z->filbuf = zmfilbuf;
+ z->u = NULL;
+ z->name = name;
+ return z;
}
/* ------------------------------------------------------------ strings --- */
-ZIO* zsopen (ZIO* z, char* s, char *name)
-{
- if (s==NULL) return NULL;
- return zmopen(z,s,strlen(s),name);
+ZIO* zsopen (ZIO* z, const char* s, const char *name) {
+ if (s==NULL) return NULL;
+ return zmopen(z, s, strlen(s), name);
}
/* -------------------------------------------------------------- FILEs --- */
static int zffilbuf (ZIO* z) {
- int n;
- if (feof((FILE *)z->u)) return EOZ;
- n=fread(z->buffer,1,ZBSIZE,z->u);
- if (n==0) return EOZ;
- z->n=n-1;
- z->p=z->buffer;
- return *(z->p++);
+ size_t n;
+ if (feof((FILE *)z->u)) return EOZ;
+ n = fread(z->buffer, 1, ZBSIZE, (FILE *)z->u);
+ if (n==0) return EOZ;
+ z->n = n-1;
+ z->p = z->buffer;
+ return *(z->p++);
}
-ZIO* zFopen (ZIO* z, FILE* f, char *name)
-{
- if (f==NULL) return NULL;
- z->n=0;
- z->p=z->buffer;
- z->filbuf=zffilbuf;
- z->u=f;
- z->name=name;
- return z;
+ZIO* zFopen (ZIO* z, FILE* f, const char *name) {
+ if (f==NULL) return NULL;
+ z->n = 0;
+ z->p = z->buffer;
+ z->filbuf = zffilbuf;
+ z->u = f;
+ z->name = name;
+ return z;
}
/* --------------------------------------------------------------- read --- */
-int zread (ZIO *z, void *b, int n) {
+size_t zread (ZIO *z, void *b, size_t n) {
while (n) {
- int m;
+ size_t m;
if (z->n == 0) {
if (z->filbuf(z) == EOZ)
return n; /* return number of missing bytes */
- zungetc(z); /* put result from 'filbuf' in the buffer */
+ zungetc(z); /* put result from `filbuf' in the buffer */
}
m = (n <= z->n) ? n : z->n; /* min. between n and z->n */
memcpy(b, z->p, m);
diff --git a/src/lzio.h b/src/lzio.h
index d7edd263..5f4b43de 100644
--- a/src/lzio.h
+++ b/src/lzio.h
@@ -1,5 +1,5 @@
/*
-** $Id: lzio.h,v 1.4 1998/01/09 14:57:43 roberto Exp $
+** $Id: lzio.h,v 1.7 2000/10/20 16:36:32 roberto Exp $
** Buffered streams
** See Copyright Notice in lua.h
*/
@@ -22,28 +22,31 @@
typedef struct zio ZIO;
-ZIO* zFopen (ZIO* z, FILE* f, char *name); /* open FILEs */
-ZIO* zsopen (ZIO* z, char* s, char *name); /* string */
-ZIO* zmopen (ZIO* z, char* b, int size, char *name); /* memory */
+ZIO* zFopen (ZIO* z, FILE* f, const char *name); /* open FILEs */
+ZIO* zsopen (ZIO* z, const char* s, const char *name); /* string */
+ZIO* zmopen (ZIO* z, const char* b, size_t size, const char *name); /* memory */
-int zread (ZIO* z, void* b, int n); /* read next n bytes */
+size_t zread (ZIO* z, void* b, size_t n); /* read next n bytes */
-#define zgetc(z) (--(z)->n>=0 ? ((int)*(z)->p++): (z)->filbuf(z))
+#define zgetc(z) (((z)->n--)>0 ? ((int)*(z)->p++): (z)->filbuf(z))
#define zungetc(z) (++(z)->n,--(z)->p)
#define zname(z) ((z)->name)
+
/* --------- Private Part ------------------ */
+#ifndef ZBSIZE
#define ZBSIZE 256 /* buffer size */
+#endif
struct zio {
- int n; /* bytes still unread */
- unsigned char* p; /* current position in buffer */
- int (*filbuf)(ZIO* z);
- void* u; /* additional data */
- char *name;
- unsigned char buffer[ZBSIZE]; /* buffer */
+ size_t n; /* bytes still unread */
+ const unsigned char* p; /* current position in buffer */
+ int (*filbuf)(ZIO* z);
+ void* u; /* additional data */
+ const char *name;
+ unsigned char buffer[ZBSIZE]; /* buffer */
};
diff --git a/test/array.lua b/test/array.lua
deleted file mode 100644
index 728a0b27..00000000
--- a/test/array.lua
+++ /dev/null
@@ -1,13 +0,0 @@
-a = {}
-
-local i=0
-while i<10 do
- a[i] = i*i
- i=i+1
-end
-
-local r,v = next(a,nil)
-while r ~= nil do
- write ("array[",r,"] = ",v,"\n")
- r,v = next(a,r)
-end
diff --git a/test/bisect.lua b/test/bisect.lua
index 4de9e99b..9e1d8f70 100644
--- a/test/bisect.lua
+++ b/test/bisect.lua
@@ -18,9 +18,12 @@ function solve(f,a,b)
write(format("after %d steps, root is %.10g, f=%g\n",n,z,f(z)))
end
+-- an example
+
-- our function
function f(x)
return x*x*x-x-1
end
+-- find zero in [1,2]
solve(f,1,2)
diff --git a/test/cf-for.lua b/test/cf-for.lua
new file mode 100644
index 00000000..1bd0ab27
--- /dev/null
+++ b/test/cf-for.lua
@@ -0,0 +1,19 @@
+-- temperature conversion table
+-- now using the new "for" statement
+
+-- celsius to farenheit
+
+for c0=-20,50-1,10 do
+ write("C ")
+ for c=c0,c0+10-1 do
+ write(format("%3.0f ",c))
+ end
+ write("\n")
+
+ write("F ")
+ for c=c0,c0+10-1 do
+ f=(9/5)*c+32
+ write(format("%3.0f ",f))
+ end
+ write("\n\n")
+end
diff --git a/test/examples/ps/hilbert.lua b/test/examples/ps/hilbert.lua
index b1042b57..dbcec963 100644
--- a/test/examples/ps/hilbert.lua
+++ b/test/examples/ps/hilbert.lua
@@ -3,8 +3,6 @@
-- Luiz Henrique de Figueiredo (lhf@csg.uwaterloo.ca)
-- 10 Nov 95
-$debug
-
dofile("ps.lua")
function p()
diff --git a/test/examples/www/staff.lua b/test/examples/www/staff.lua
index 7fa5b810..f36df4ad 100644
--- a/test/examples/www/staff.lua
+++ b/test/examples/www/staff.lua
@@ -1,7 +1,5 @@
-$debug
-
readfrom("template.html")
-TEMPLATE=read(".*")
+TEMPLATE=read("*a")
readfrom()
PAT="|(%a%a*)|"
@@ -17,10 +15,8 @@ function get(i)
end
function global(t)
- local i,v=next(t,nil)
- while i do
+ for i,v in t do
GLOBAL[i]=v
- i,v=next(t,i)
end
end
diff --git a/test/fib.lua b/test/fib.lua
index 881cbdc3..d946946a 100644
--- a/test/fib.lua
+++ b/test/fib.lua
@@ -1,6 +1,7 @@
-- very inefficient fibonacci function
function fib(n)
+ N=N+1
if n<2 then
return n
else
@@ -8,4 +9,31 @@ function fib(n)
end
end
-print(fib(20))
+-- a much faster cached version
+
+function cache(f)
+ local c={}
+ return function (x)
+ local y=%c[x]
+ if not y then
+ y=%f(x)
+ %c[x]=y
+ end
+ return y
+ end
+end
+
+function test(s)
+ N=0
+ local c=clock()
+ local v=fib(n)
+ local t=clock()-c
+ print(s,n,v,t,N)
+end
+
+n=n or 24 -- for other values, do lua -e n=XX fib.lua
+n=tonumber(n)
+print("","n","value","time","evals")
+test("plain")
+fib=cache(fib)
+test("cached")
diff --git a/test/globals.lua b/test/globals.lua
index 03b977c3..baa75049 100644
--- a/test/globals.lua
+++ b/test/globals.lua
@@ -1,20 +1,19 @@
--- globals.lua
-- reads the output of luac -d -l -p and reports global variable usage
--- typical usage: luac -p -l -d file.lua | lua globals.lua | sort
+-- lines where a global is written to are marked with "*"
+-- typical usage: luac -p -l file.lua | lua globals.lua | sort
local P="^.*; " -- pattern to extract comments
-local l="" -- last line seen
while 1 do
local s=read()
if s==nil then return end
- if strfind(s,"%sSETLINE") then
- l=gsub(s,P,"")
- elseif strfind(s,"%sGETGLOBAL") then
+ if strfind(s,"%sGETGLOBAL") then
local g=gsub(s,P,"")
+ local _,_,l=strfind(s,"(%d+)")
write(g,"\t",l,"\n")
elseif strfind(s,"%sSETGLOBAL") then
local g=gsub(s,P,"")
- write(g,"*\t",l,"\n")
+ local _,_,l=strfind(s,"(%d+)")
+ write(g,"\t",l,"*\n")
end
end
diff --git a/test/life.lua b/test/life.lua
new file mode 100644
index 00000000..7c817a04
--- /dev/null
+++ b/test/life.lua
@@ -0,0 +1,121 @@
+-- life.lua
+-- original by Dave Bollinger <DBollinger@compuserve.com> posted to lua-l
+-- modified to use ANSI terminal escape sequences
+
+ALIVE="O"
+DEAD="-"
+
+function delay() -- NOTE: SYSTEM-DEPENDENT, adjust as necessary
+ local i=10000
+ while i>0 do i=i-1 end
+ -- local i=clock()+1 while(clock()<i) do end
+end
+
+function ARRAY2D(w,h)
+ local t = {}
+ t.w=w
+ t.h=h
+ while h>0 do
+ t[h] = {}
+ local x=w
+ while x>0 do
+ t[h][x]=0
+ x=x-1
+ end
+ h=h-1
+ end
+ return t
+end
+
+_CELLS = {}
+
+-- give birth to a "shape" within the cell array
+function _CELLS:spawn(shape,left,top)
+ local y=0
+ while y<shape.h do
+ local x=0
+ while x<shape.w do
+ self[top+y][left+x] = shape[y*shape.w+x+1]
+ x=x+1
+ end
+ y=y+1
+ end
+end
+
+-- run the CA and produce the next generation
+function _CELLS:evolve(next)
+ local ym1,y,yp1,yi=self.h-1,self.h,1,self.h
+ while yi > 0 do
+ local xm1,x,xp1,xi=self.w-1,self.w,1,self.w
+ while xi > 0 do
+ local sum = self[ym1][xm1] + self[ym1][x] + self[ym1][xp1] +
+ self[y][xm1] + self[y][xp1] +
+ self[yp1][xm1] + self[yp1][x] + self[yp1][xp1]
+ next[y][x] = ((sum==2) and self[y][x]) or ((sum==3) and 1) or 0
+ xm1,x,xp1,xi = x,xp1,xp1+1,xi-1
+ end
+ ym1,y,yp1,yi = y,yp1,yp1+1,yi-1
+ end
+end
+
+-- output the array to screen
+function _CELLS:draw()
+ local out="" -- accumulate to reduce flicker
+ local y=1
+ while y <= self.h do
+ local x=1
+ while x <= self.w do
+ out=out..(((self[y][x]>0) and ALIVE) or DEAD)
+ x=x+1
+ end
+ out=out.."\n"
+ y=y+1
+ end
+ write(out)
+end
+
+-- constructor
+function CELLS(w,h)
+ local c = ARRAY2D(w,h)
+ c.spawn = _CELLS.spawn
+ c.evolve = _CELLS.evolve
+ c.draw = _CELLS.draw
+ return c
+end
+
+--
+-- shapes suitable for use with spawn() above
+--
+HEART = { 1,0,1,1,0,1,1,1,1; w=3,h=3 }
+GLIDER = { 0,0,1,1,0,1,0,1,1; w=3,h=3 }
+EXPLODE = { 0,1,0,1,1,1,1,0,1,0,1,0; w=3,h=4 }
+FISH = { 0,1,1,1,1,1,0,0,0,1,0,0,0,0,1,1,0,0,1,0; w=5,h=4 }
+BUTTERFLY = { 1,0,0,0,1,0,1,1,1,0,1,0,0,0,1,1,0,1,0,1,1,0,0,0,1; w=5,h=5 }
+
+-- the main routine
+function LIFE(w,h)
+ -- create two arrays
+ local thisgen = CELLS(w,h)
+ local nextgen = CELLS(w,h)
+
+ -- create some life
+ -- about 1000 generations of fun, then a glider steady-state
+ thisgen:spawn(GLIDER,5,4)
+ thisgen:spawn(EXPLODE,25,10)
+ thisgen:spawn(FISH,4,12)
+
+ -- run until break
+ local gen=1
+ write("\027[2J") -- ANSI clear screen
+ while 1 do
+ thisgen:evolve(nextgen)
+ thisgen,nextgen = nextgen,thisgen
+ write("\027[H") -- ANSI home cursor
+ thisgen:draw()
+ write("Generation: "..gen.."\n")
+ gen=gen+1
+ --delay() -- no delay
+ end
+end
+
+LIFE(40,20)
diff --git a/test/lisp.lua b/test/lisp.lua
new file mode 100644
index 00000000..e6bcd084
--- /dev/null
+++ b/test/lisp.lua
@@ -0,0 +1,22 @@
+-- a simple LISP evaluator
+
+function eval(x)
+ if type(x)=="table" then
+ return eval(x[1])(eval(x[2]),eval(x[3]))
+ else
+ return x
+ end
+end
+
+function add(x,y) return x+y end
+function sub(x,y) return x-y end
+function mul(x,y) return x*y end
+function div(x,y) return x/y end
+function pow(x,y) return x^y end
+
+-- an example
+
+function E(x) print(eval(x)) end
+
+E{add,1,{mul,2,3}}
+E{sin,60}
diff --git a/test/old.lua b/test/old.lua
new file mode 100644
index 00000000..ebb4e70b
--- /dev/null
+++ b/test/old.lua
@@ -0,0 +1,42 @@
+-- implementation of old functions
+
+function foreach(t,f)
+ for i,v in t do
+ local r=f(i,v)
+ if r then return r end
+ end
+end
+
+function foreachi(t,f)
+ for i=1,getn(t) do
+ local r=f(i,t[i])
+ if r then return r end
+ end
+end
+
+function foreachvar(f)
+ return foreach(globals(),f)
+end
+
+function nextvar(n)
+ return next(globals(),n)
+end
+
+function rawgetglobal(n)
+ return rawget(globals(),n)
+end
+
+function rawsetglobal(n,v)
+ return rawset(globals(),n,v)
+end
+
+rawsettable=rawset
+rawgettable=rawget
+
+function getglobal(n)
+ return globals()[n]
+end
+
+function setglobal(n,v)
+ globals()[n]=v
+end
diff --git a/test/qp.lua b/test/qp.lua
new file mode 100644
index 00000000..eb6b3205
--- /dev/null
+++ b/test/qp.lua
@@ -0,0 +1,6 @@
+-- decode quoted-printable text
+
+T=read"*a"
+T=gsub(T,"=\n","")
+T=gsub(T,"=(%x%x)",function (x) return strchar(tonumber(x,16)) end)
+write(T)
diff --git a/test/save.lua b/test/save.lua
index ce2e5b34..855e4c19 100644
--- a/test/save.lua
+++ b/test/save.lua
@@ -12,9 +12,7 @@ function savevar (n,v)
else
write("{}\n")
v.__visited__ = n
- local r,f
- r,f = next(v,nil)
- while r ~= nil do
+ for r,f in v do
if r ~= "__visited__" then
if type(r) == 'string' then
savevar(n.."."..r,f)
@@ -22,7 +20,6 @@ function savevar (n,v)
savevar(n.."["..r.."]",f)
end
end
- r,f = next(v,r)
end
end
else write(tostring(v)) end
@@ -31,14 +28,10 @@ end
function save ()
write("\n-- global environment\n")
- local n,v = nextvar(nil)
- while n ~= nil do
- savevar(n,v)
- n,v = nextvar(n)
- end
+ foreach(globals(),savevar)
end
--- ow some examples
+-- an example
a = 3
x = {a = 4, b = "name", l={4,5,67}}
diff --git a/test/sort.lua b/test/sort.lua
index 41473f4a..1d50ad47 100644
--- a/test/sort.lua
+++ b/test/sort.lua
@@ -1,3 +1,6 @@
+-- two implementations of a sort function
+-- this is an example only. Lua has now a built-in function "sort"
+
-- extracted from Programming Pearls, page 110
function qsort(x,l,u,f)
if l<u then
@@ -57,7 +60,7 @@ function testsorts(x)
show("after quicksort again",x)
end
--- array t be sorted
+-- array to be sorted
x={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}
testsorts(x)
diff --git a/test/table.lua b/test/table.lua
new file mode 100644
index 00000000..2c2dd90a
--- /dev/null
+++ b/test/table.lua
@@ -0,0 +1,7 @@
+local A
+while 1 do
+ local a,b=read("*w","*w")
+ if a==nil then break end
+ if a~=A then A=a write("\n",a,":\n") end
+ write(b," ")
+end
diff --git a/test/trace-calls.lua b/test/trace-calls.lua
new file mode 100644
index 00000000..a073cc20
--- /dev/null
+++ b/test/trace-calls.lua
@@ -0,0 +1,23 @@
+-- trace calls
+-- example: lua trace-calls.lua hello.lua bisect.lua
+
+function callhook(func)
+ local t=getinfo(2)
+ write(">>> ")
+--foreach(t,print)
+ if t.what=="main" then
+ if func=="call" then
+ write("begin ",t.source)
+ else
+ write("end ",t.source)
+ end
+ elseif t.what=="Lua" then
+ write(func," ",t.name," <",t.linedefined,":",t.source,">")
+ else
+ write(func," ",t.name," [",t.what,"] ")
+ end
+ if t.currentline>=0 then write(":",t.currentline) end
+ write("\n")
+end
+
+setcallhook(callhook)
diff --git a/test/trace-globals.lua b/test/trace-globals.lua
new file mode 100644
index 00000000..566e1106
--- /dev/null
+++ b/test/trace-globals.lua
@@ -0,0 +1,75 @@
+-- shows how to trace assigments to global variables
+
+-- a tostring that quotes strings. note the use of the original tostring.
+local tostring=function(a)
+ if tag(a)==tag("") then
+ return format("%q",a)
+ else
+ return %tostring(a)
+ end
+end
+
+local T=newtag()
+
+local Tlog=function (name,old,new)
+ local t=getinfo(3,"Sl")
+ local line=t.currentline
+ write(t.source)
+ if line>=0 then write(":",line) end
+ write(" -- ",name," is now ",%tostring(new)," (was ",%tostring(old),")","\n")
+end
+
+local Tgetnew=function (name)
+ local t=settag({},%T)
+ rawset(globals(),name,t)
+ return nil
+end
+
+local Tsetnew=function (name,old,new)
+ %Tlog(name,old,new)
+ local t=settag({value=new},%T)
+ rawset(globals(),name,t)
+ return t
+end
+
+local Tsetglobal=function (name,old,new)
+ %Tlog(name,old.value,new)
+ old.value=new
+end
+
+local Tgetglobal=function (x,value)
+ return value.value
+end
+
+settagmethod(T,"getglobal",Tgetglobal)
+settagmethod(T,"setglobal",Tsetglobal)
+
+-- to trace only selected variables, use the following function
+-- and comment the next two calls to settagmethod
+
+function trace(name)
+ local t=settag({value=rawget(globals(),name)},%T)
+ rawset(globals(),name,t)
+end
+
+settagmethod(tag(nil),"getglobal",Tgetnew)
+settagmethod(tag(nil),"setglobal",Tsetnew)
+
+-- an example
+
+trace"a"
+print(a)
+a=1
+b=2
+c=3
+a=10
+b=20
+c=30
+trace"b"
+b="lua"
+c={}
+a=print
+c=nil
+c=100
+
+print(a,b,c,d)
diff --git a/test/trace.lua b/test/trace.lua
deleted file mode 100644
index 5f32a8f9..00000000
--- a/test/trace.lua
+++ /dev/null
@@ -1,33 +0,0 @@
--- shows how to trace assigments to global variables
-
-T=newtag() -- tag for tracing
-
-function Ttrace(name) -- trace a global variable
- local t={}
- settag(t,T)
- rawsetglobal(name,t)
-end
-
-function Tsetglobal(name,old,new)
- write("tracing: ",name," now is ",new,"\n")
- old.value=new
-end
-
-function Tgetglobal(x,value) -- get the actual value
- return value.value
-end
-
-settagmethod(T,"getglobal",Tgetglobal)
-settagmethod(T,"setglobal",Tsetglobal)
-
--- now show it working
-
-Ttrace("a")
-Ttrace("c")
-
-a=1
-b=2
-c=3
-a=10
-b=20
-c=30
diff --git a/test/undefined.lua b/test/undefined.lua
new file mode 100644
index 00000000..bbecffe3
--- /dev/null
+++ b/test/undefined.lua
@@ -0,0 +1,20 @@
+-- catch "undefined" global variables. see FAQ.
+
+do
+ local f=function(name)
+ local v=rawget(globals(),name)
+ if v then
+ return v
+ else
+ error("undefined global variable `"..name.."'")
+ end
+ end
+
+ settagmethod(tag(nil),"getglobal",f)
+end
+
+-- an example
+
+a=1
+c=3
+print(a,b,c) -- 'b' is undefined
diff --git a/test/webform.lua b/test/webform.lua
new file mode 100644
index 00000000..3e4c3ce4
--- /dev/null
+++ b/test/webform.lua
@@ -0,0 +1,8 @@
+-- convert POST data to Lua table
+
+T=read"*a" -- for GET, use T=getenv"QUERY_STRING"
+T=gsub(T,"=","=[[")
+T=gsub(T,"&","]],\n")
+T=gsub(T,"+"," ")
+T=gsub(T,"%%(%x%x)",function (x) return strchar(tonumber(x,16)) end)
+write("form{\n",T,"]]}\n")