summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--README2
-rw-r--r--doc/amazon.gifbin797 -> 0 bytes
-rw-r--r--doc/contents.html158
-rw-r--r--doc/cover.pngbin3305 -> 0 bytes
-rw-r--r--doc/manual.html2676
-rw-r--r--doc/readme.html76
-rw-r--r--etc/Makefile48
-rw-r--r--etc/README13
-rw-r--r--etc/dummy.c11
-rw-r--r--etc/one.c6
-rw-r--r--src/Makefile10
-rw-r--r--src/lapi.c240
-rw-r--r--src/lauxlib.c201
-rw-r--r--src/lauxlib.h39
-rw-r--r--src/lbaselib.c95
-rw-r--r--src/lbitlib.c34
-rw-r--r--src/lcode.c51
-rw-r--r--src/lcode.h8
-rw-r--r--src/ldblib.c30
-rw-r--r--src/ldebug.c116
-rw-r--r--src/ldo.c75
-rw-r--r--src/ldump.c3
-rw-r--r--src/lfunc.c23
-rw-r--r--src/lfunc.h6
-rw-r--r--src/lgc.c692
-rw-r--r--src/lgc.h91
-rw-r--r--src/linit.c9
-rw-r--r--src/liolib.c129
-rw-r--r--src/llex.c116
-rw-r--r--src/llex.h3
-rw-r--r--src/llimits.h13
-rw-r--r--src/lmem.c29
-rw-r--r--src/lmem.h4
-rw-r--r--src/loadlib.c31
-rw-r--r--src/lobject.c38
-rw-r--r--src/lobject.h58
-rw-r--r--src/lopcodes.c10
-rw-r--r--src/lopcodes.h9
-rw-r--r--src/lparser.c184
-rw-r--r--src/lparser.h11
-rw-r--r--src/lstate.c80
-rw-r--r--src/lstate.h34
-rw-r--r--src/lstring.c8
-rw-r--r--src/lstring.h12
-rw-r--r--src/lstrlib.c132
-rw-r--r--src/ltable.c7
-rw-r--r--src/ltablib.c20
-rw-r--r--src/ltm.c4
-rw-r--r--src/ltm.h5
-rw-r--r--src/lua.c52
-rw-r--r--src/lua.h30
-rw-r--r--src/luac.c31
-rw-r--r--src/luaconf.h71
-rw-r--r--src/lundump.c3
-rw-r--r--src/lvm.c334
-rw-r--r--src/print.c21
-rw-r--r--test/ALL.lua26
-rw-r--r--test/README26
-rw-r--r--test/bisect.lua27
-rw-r--r--test/cf.lua16
-rw-r--r--test/echo.lua5
-rw-r--r--test/env.lua7
-rw-r--r--test/factorial.lua32
-rw-r--r--test/fib.lua40
-rw-r--r--test/fibfor.lua13
-rw-r--r--test/globals.lua13
-rw-r--r--test/life.lua111
-rw-r--r--test/luac.lua7
-rw-r--r--test/printf.lua7
-rw-r--r--test/readonly.lua12
-rw-r--r--test/sieve.lua29
-rw-r--r--test/sort.lua66
-rw-r--r--test/table.lua12
-rw-r--r--test/trace-calls.lua32
-rw-r--r--test/trace-globals.lua38
-rw-r--r--test/xd.lua15
77 files changed, 3302 insertions, 3426 deletions
diff --git a/Makefile b/Makefile
index 3e8b4b98..db263e66 100644
--- a/Makefile
+++ b/Makefile
@@ -81,7 +81,7 @@ none:
@echo " $(PLATS)"
@echo "See doc/readme.html for complete instructions."
-# make may get confused with test/ and install/ in a case-insensitive OS
+# make may get confused with test/ and install/
dummy:
# echo config parameters
diff --git a/README b/README
index 678a301a..91530230 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-This is Lua 5.2 (work2), released on 13 Jan 2010.
+This is Lua 5.2 (work3), released on 18 May 2010.
For information about Lua, including installation instructions and
license details, see doc/readme.html.
diff --git a/doc/amazon.gif b/doc/amazon.gif
deleted file mode 100644
index f2586d57..00000000
--- a/doc/amazon.gif
+++ /dev/null
Binary files differ
diff --git a/doc/contents.html b/doc/contents.html
index 66d967e3..b9ae2340 100644
--- a/doc/contents.html
+++ b/doc/contents.html
@@ -20,6 +20,11 @@ ul {
Lua 5.2 Reference Manual
</H1>
+<IMG SRC="alert.png" ALIGN="absbottom">
+<EM>This is a work version of Lua 5.2.
+Everything may change in the final version.</EM>
+<P>
+
The reference manual is the official definition of the Lua language.
For a complete introduction to Lua programming, see the book
<A HREF="http://www.lua.org/docs.html#books">Programming in Lua</A>.
@@ -42,94 +47,95 @@ Freely available under the terms of the
<UL style="padding: 0">
<LI><A HREF="manual.html">1 - Introduction</A>
<P>
-<LI><A HREF="manual.html#2">2 - The Language</A>
+<LI><A HREF="manual.html#2">2 - Basic Concepts</A>
<UL>
-<LI><A HREF="manual.html#2.1">2.1 - Lexical Conventions</A>
-<LI><A HREF="manual.html#2.2">2.2 - Values and Types</A>
+<LI><A HREF="manual.html#2.1">2.1 - Values and Types</A>
+<LI><A HREF="manual.html#2.2">2.2 - Environments and the Global Environment</A>
+<LI><A HREF="manual.html#2.3">2.3 - Error Handling</A>
+<LI><A HREF="manual.html#2.4">2.4 - Metatables</A>
+<LI><A HREF="manual.html#2.5">2.5 - Garbage Collection</A>
<UL>
-<LI><A HREF="manual.html#2.2.1">2.2.1 - Coercion</A>
+<LI><A HREF="manual.html#2.5.1">2.5.1 - Garbage-Collection Metamethods</A>
+<LI><A HREF="manual.html#2.5.2">2.5.2 - Weak Tables</A>
</UL>
-<LI><A HREF="manual.html#2.3">2.3 - Variables</A>
-<LI><A HREF="manual.html#2.4">2.4 - Statements</A>
-<UL>
-<LI><A HREF="manual.html#2.4.1">2.4.1 - Chunks</A>
-<LI><A HREF="manual.html#2.4.2">2.4.2 - Blocks</A>
-<LI><A HREF="manual.html#2.4.3">2.4.3 - Assignment</A>
-<LI><A HREF="manual.html#2.4.4">2.4.4 - Control Structures</A>
-<LI><A HREF="manual.html#2.4.5">2.4.5 - For Statement</A>
-<LI><A HREF="manual.html#2.4.6">2.4.6 - Function Calls as Statements</A>
-<LI><A HREF="manual.html#2.4.7">2.4.7 - Local Declarations</A>
-<LI><A HREF="manual.html#2.4.8">2.4.8 - Lexical Environments</A>
+<LI><A HREF="manual.html#2.6">2.6 - Coroutines</A>
</UL>
-<LI><A HREF="manual.html#2.5">2.5 - Expressions</A>
+<P>
+<LI><A HREF="manual.html#3">3 - The Language</A>
+<UL>
+<LI><A HREF="manual.html#3.1">3.1 - Lexical Conventions</A>
+<LI><A HREF="manual.html#3.2">3.2 - Variables</A>
+<LI><A HREF="manual.html#3.3">3.3 - Statements</A>
<UL>
-<LI><A HREF="manual.html#2.5.1">2.5.1 - Arithmetic Operators</A>
-<LI><A HREF="manual.html#2.5.2">2.5.2 - Relational Operators</A>
-<LI><A HREF="manual.html#2.5.3">2.5.3 - Logical Operators</A>
-<LI><A HREF="manual.html#2.5.4">2.5.4 - Concatenation</A>
-<LI><A HREF="manual.html#2.5.5">2.5.5 - The Length Operator</A>
-<LI><A HREF="manual.html#2.5.6">2.5.6 - Precedence</A>
-<LI><A HREF="manual.html#2.5.7">2.5.7 - Table Constructors</A>
-<LI><A HREF="manual.html#2.5.8">2.5.8 - Function Calls</A>
-<LI><A HREF="manual.html#2.5.9">2.5.9 - Function Definitions</A>
+<LI><A HREF="manual.html#3.3.1">3.3.1 - Chunks</A>
+<LI><A HREF="manual.html#3.3.2">3.3.2 - Blocks</A>
+<LI><A HREF="manual.html#3.3.3">3.3.3 - Assignment</A>
+<LI><A HREF="manual.html#3.3.4">3.3.4 - Control Structures</A>
+<LI><A HREF="manual.html#3.3.5">3.3.5 - For Statement</A>
+<LI><A HREF="manual.html#3.3.6">3.3.6 - Function Calls as Statements</A>
+<LI><A HREF="manual.html#3.3.7">3.3.7 - Local Declarations</A>
</UL>
-<LI><A HREF="manual.html#2.6">2.6 - Visibility Rules</A>
-<LI><A HREF="manual.html#2.7">2.7 - Error Handling</A>
-<LI><A HREF="manual.html#2.8">2.8 - Metatables</A>
-<LI><A HREF="manual.html#2.9">2.9 - Environments</A>
-<LI><A HREF="manual.html#2.10">2.10 - Garbage Collection</A>
+<LI><A HREF="manual.html#3.4">3.4 - Expressions</A>
<UL>
-<LI><A HREF="manual.html#2.10.1">2.10.1 - Garbage-Collection Metamethods</A>
-<LI><A HREF="manual.html#2.10.2">2.10.2 - Weak Tables</A>
+<LI><A HREF="manual.html#3.4.1">3.4.1 - Arithmetic Operators</A>
+<LI><A HREF="manual.html#3.4.2">3.4.2 - Coercion</A>
+<LI><A HREF="manual.html#3.4.3">3.4.3 - Relational Operators</A>
+<LI><A HREF="manual.html#3.4.4">3.4.4 - Logical Operators</A>
+<LI><A HREF="manual.html#3.4.5">3.4.5 - Concatenation</A>
+<LI><A HREF="manual.html#3.4.6">3.4.6 - The Length Operator</A>
+<LI><A HREF="manual.html#3.4.7">3.4.7 - Precedence</A>
+<LI><A HREF="manual.html#3.4.8">3.4.8 - Table Constructors</A>
+<LI><A HREF="manual.html#3.4.9">3.4.9 - Function Calls</A>
+<LI><A HREF="manual.html#3.4.10">3.4.10 - Function Definitions</A>
</UL>
-<LI><A HREF="manual.html#2.11">2.11 - Coroutines</A>
+<LI><A HREF="manual.html#3.5">3.5 - Visibility Rules</A>
</UL>
<P>
-<LI><A HREF="manual.html#3">3 - The Application Program Interface</A>
+<LI><A HREF="manual.html#4">4 - The Application Program Interface</A>
<UL>
-<LI><A HREF="manual.html#3.1">3.1 - The Stack</A>
-<LI><A HREF="manual.html#3.2">3.2 - Stack Size</A>
-<LI><A HREF="manual.html#3.3">3.3 - Pseudo-Indices</A>
-<LI><A HREF="manual.html#3.4">3.4 - C Closures</A>
-<LI><A HREF="manual.html#3.5">3.5 - Registry</A>
-<LI><A HREF="manual.html#3.6">3.6 - Error Handling in C</A>
-<LI><A HREF="manual.html#3.7">3.7 - Handling Yields in C</A>
-<LI><A HREF="manual.html#3.8">3.8 - Functions and Types</A>
-<LI><A HREF="manual.html#3.9">3.9 - The Debug Interface</A>
+<LI><A HREF="manual.html#4.1">4.1 - The Stack</A>
+<LI><A HREF="manual.html#4.2">4.2 - Stack Size</A>
+<LI><A HREF="manual.html#4.3">4.3 - Pseudo-Indices</A>
+<LI><A HREF="manual.html#4.4">4.4 - C Closures</A>
+<LI><A HREF="manual.html#4.5">4.5 - Registry</A>
+<LI><A HREF="manual.html#4.6">4.6 - Error Handling in C</A>
+<LI><A HREF="manual.html#4.7">4.7 - Handling Yields in C</A>
+<LI><A HREF="manual.html#4.8">4.8 - Functions and Types</A>
+<LI><A HREF="manual.html#4.9">4.9 - The Debug Interface</A>
</UL>
<P>
-<LI><A HREF="manual.html#4">4 - The Auxiliary Library</A>
+<LI><A HREF="manual.html#5">5 - The Auxiliary Library</A>
<UL>
-<LI><A HREF="manual.html#4.1">4.1 - Functions and Types</A>
+<LI><A HREF="manual.html#5.1">5.1 - Functions and Types</A>
</UL>
<P>
-<LI><A HREF="manual.html#5">5 - Standard Libraries</A>
+<LI><A HREF="manual.html#6">6 - Standard Libraries</A>
<UL>
-<LI><A HREF="manual.html#5.1">5.1 - Basic Functions</A>
-<LI><A HREF="manual.html#5.2">5.2 - Coroutine Manipulation</A>
-<LI><A HREF="manual.html#5.3">5.3 - Modules</A>
-<LI><A HREF="manual.html#5.4">5.4 - String Manipulation</A>
+<LI><A HREF="manual.html#6.1">6.1 - Basic Functions</A>
+<LI><A HREF="manual.html#6.2">6.2 - Coroutine Manipulation</A>
+<LI><A HREF="manual.html#6.3">6.3 - Modules</A>
+<LI><A HREF="manual.html#6.4">6.4 - String Manipulation</A>
<UL>
-<LI><A HREF="manual.html#5.4.1">5.4.1 - Patterns</A>
+<LI><A HREF="manual.html#6.4.1">6.4.1 - Patterns</A>
</UL>
-<LI><A HREF="manual.html#5.5">5.5 - Table Manipulation</A>
-<LI><A HREF="manual.html#5.6">5.6 - Mathematical Functions</A>
-<LI><A HREF="manual.html#5.7">5.7 - Bitwise operations</A>
-<LI><A HREF="manual.html#5.8">5.8 - Input and Output Facilities</A>
-<LI><A HREF="manual.html#5.9">5.9 - Operating System Facilities</A>
-<LI><A HREF="manual.html#5.10">5.10 - The Debug Library</A>
+<LI><A HREF="manual.html#6.5">6.5 - Table Manipulation</A>
+<LI><A HREF="manual.html#6.6">6.6 - Mathematical Functions</A>
+<LI><A HREF="manual.html#6.7">6.7 - Bitwise operations</A>
+<LI><A HREF="manual.html#6.8">6.8 - Input and Output Facilities</A>
+<LI><A HREF="manual.html#6.9">6.9 - Operating System Facilities</A>
+<LI><A HREF="manual.html#6.10">6.10 - The Debug Library</A>
</UL>
<P>
-<LI><A HREF="manual.html#6">6 - Lua Stand-alone</A>
+<LI><A HREF="manual.html#7">7 - Lua Stand-alone</A>
<P>
-<LI><A HREF="manual.html#7">7 - Incompatibilities with the Previous Version</A>
+<LI><A HREF="manual.html#8">8 - Incompatibilities with the Previous Version</A>
<UL>
-<LI><A HREF="manual.html#7.1">7.1 - Changes in the Language</A>
-<LI><A HREF="manual.html#7.2">7.2 - Changes in the Libraries</A>
-<LI><A HREF="manual.html#7.3">7.3 - Changes in the API</A>
+<LI><A HREF="manual.html#8.1">8.1 - Changes in the Language</A>
+<LI><A HREF="manual.html#8.2">8.2 - Changes in the Libraries</A>
+<LI><A HREF="manual.html#8.3">8.3 - Changes in the API</A>
</UL>
<P>
-<LI><A HREF="manual.html#8">8 - The Complete Syntax of Lua</A>
+<LI><A HREF="manual.html#9">9 - The Complete Syntax of Lua</A>
</UL>
<H2><A NAME="index">Index</A></H2>
@@ -144,7 +150,6 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-dofile">dofile</A><BR>
<A HREF="manual.html#pdf-error">error</A><BR>
<A HREF="manual.html#pdf-getmetatable">getmetatable</A><BR>
-<A HREF="manual.html#pdf-ipairs">ipairs</A><BR>
<A HREF="manual.html#pdf-load">load</A><BR>
<A HREF="manual.html#pdf-loadin">loadin</A><BR>
<A HREF="manual.html#pdf-loadfile">loadfile</A><BR>
@@ -169,10 +174,12 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-bit.band">bit.band</A><BR>
<A HREF="manual.html#pdf-bit.bnot">bit.bnot</A><BR>
<A HREF="manual.html#pdf-bit.bor">bit.bor</A><BR>
-<A HREF="manual.html#pdf-bit.brotate">bit.brotate</A><BR>
-<A HREF="manual.html#pdf-bit.bshift">bit.bshift</A><BR>
<A HREF="manual.html#pdf-bit.btest">bit.btest</A><BR>
<A HREF="manual.html#pdf-bit.bxor">bit.bxor</A><BR>
+<A HREF="manual.html#pdf-bit.lshift">bit.lshift</A><BR>
+<A HREF="manual.html#pdf-bit.rol">bit.rol</A><BR>
+<A HREF="manual.html#pdf-bit.ror">bit.ror</A><BR>
+<A HREF="manual.html#pdf-bit.rshift">bit.rshift</A><BR>
<P>
<A HREF="manual.html#pdf-coroutine.create">coroutine.create</A><BR>
@@ -199,10 +206,8 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-debug.traceback">debug.traceback</A><BR>
<A HREF="manual.html#pdf-debug.upvalueid">debug.upvalueid</A><BR>
<A HREF="manual.html#pdf-debug.upvaluejoin">debug.upvaluejoin</A><BR>
+<P>
-</TD>
-<TD>
-<H3>&nbsp;</H3>
<A HREF="manual.html#pdf-file:close">file:close</A><BR>
<A HREF="manual.html#pdf-file:flush">file:flush</A><BR>
<A HREF="manual.html#pdf-file:lines">file:lines</A><BR>
@@ -228,6 +233,9 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-io.write">io.write</A><BR>
<P>
+</TD>
+<TD>
+<H3>&nbsp;</H3>
<A HREF="manual.html#pdf-math.abs">math.abs</A><BR>
<A HREF="manual.html#pdf-math.acos">math.acos</A><BR>
<A HREF="manual.html#pdf-math.asin">math.asin</A><BR>
@@ -320,6 +328,7 @@ Freely available under the terms of the
<A HREF="manual.html#lua_Writer">lua_Writer</A><BR>
<P>
+<A HREF="manual.html#lua_absindex">lua_absindex</A><BR>
<A HREF="manual.html#lua_atpanic">lua_atpanic</A><BR>
<A HREF="manual.html#lua_call">lua_call</A><BR>
<A HREF="manual.html#lua_callk">lua_callk</A><BR>
@@ -337,8 +346,8 @@ Freely available under the terms of the
<A HREF="manual.html#lua_getfenv">lua_getfenv</A><BR>
<A HREF="manual.html#lua_getfield">lua_getfield</A><BR>
<A HREF="manual.html#lua_getglobal">lua_getglobal</A><BR>
-<A HREF="manual.html#lua_gethookcount">lua_gethookcount</A><BR>
<A HREF="manual.html#lua_gethook">lua_gethook</A><BR>
+<A HREF="manual.html#lua_gethookcount">lua_gethookcount</A><BR>
<A HREF="manual.html#lua_gethookmask">lua_gethookmask</A><BR>
<A HREF="manual.html#lua_getinfo">lua_getinfo</A><BR>
<A HREF="manual.html#lua_getlocal">lua_getlocal</A><BR>
@@ -385,11 +394,11 @@ Freely available under the terms of the
<A HREF="manual.html#lua_pushvalue">lua_pushvalue</A><BR>
<A HREF="manual.html#lua_pushvfstring">lua_pushvfstring</A><BR>
<A HREF="manual.html#lua_rawequal">lua_rawequal</A><BR>
-<A HREF="manual.html#lua_rawgeti">lua_rawgeti</A><BR>
<A HREF="manual.html#lua_rawget">lua_rawget</A><BR>
+<A HREF="manual.html#lua_rawgeti">lua_rawgeti</A><BR>
<A HREF="manual.html#lua_rawlen">lua_rawlen</A><BR>
-<A HREF="manual.html#lua_rawseti">lua_rawseti</A><BR>
<A HREF="manual.html#lua_rawset">lua_rawset</A><BR>
+<A HREF="manual.html#lua_rawseti">lua_rawseti</A><BR>
<A HREF="manual.html#lua_register">lua_register</A><BR>
<A HREF="manual.html#lua_remove">lua_remove</A><BR>
<A HREF="manual.html#lua_replace">lua_replace</A><BR>
@@ -464,6 +473,7 @@ Freely available under the terms of the
<A HREF="manual.html#luaL_loadstring">luaL_loadstring</A><BR>
<A HREF="manual.html#luaL_newmetatable">luaL_newmetatable</A><BR>
<A HREF="manual.html#luaL_newstate">luaL_newstate</A><BR>
+<A HREF="manual.html#luaL_openlib">luaL_openlib</A><BR>
<A HREF="manual.html#luaL_openlibs">luaL_openlibs</A><BR>
<A HREF="manual.html#luaL_optint">luaL_optint</A><BR>
<A HREF="manual.html#luaL_optinteger">luaL_optinteger</A><BR>
@@ -491,10 +501,10 @@ Freely available under the terms of the
<HR>
<SMALL>
Last update:
-Wed Jan 13 15:31:47 BRST 2010
+Mon May 17 16:58:54 BRT 2010
</SMALL>
<!--
-Last change: revised for Lua 5.2.0 (work2)
+Last change: revised for Lua 5.2.0 (work3)
-->
</BODY>
diff --git a/doc/cover.png b/doc/cover.png
deleted file mode 100644
index 2dbb1981..00000000
--- a/doc/cover.png
+++ /dev/null
Binary files differ
diff --git a/doc/manual.html b/doc/manual.html
index 6ebd0740..aed41ceb 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -16,6 +16,11 @@
Lua 5.2 Reference Manual
</h1>
+<IMG SRC="alert.png" ALIGN="absbottom">
+<EM>This is a work version of Lua 5.2.
+Everything may change in the final version.</EM>
+<P>
+
by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
<p>
<small>
@@ -33,7 +38,7 @@ Freely available under the terms of the
<!-- ====================================================================== -->
<p>
-<!-- $Id: manual.of,v 1.54 2010/01/13 16:50:58 roberto Exp roberto $ -->
+<!-- $Id: manual.of,v 1.56 2010/05/17 18:28:03 roberto Exp $ -->
@@ -84,7 +89,892 @@ see Roberto's book, <em>Programming in Lua (Second Edition)</em>.
-<h1>2 - <a name="2">The Language</a></h1>
+<h1>2 - <a name="2">Basic Concepts</a></h1>
+
+<p>
+This section describes some basic concepts of the language.
+
+
+
+<h2>2.1 - <a name="2.1">Values and Types</a></h2>
+
+<p>
+Lua is a <em>dynamically typed language</em>.
+This means that
+variables do not have types; only values do.
+There are no type definitions in the language.
+All values carry their own type.
+
+
+<p>
+All values in Lua are <em>first-class values</em>.
+This means that all values can be stored in variables,
+passed as arguments to other functions, and returned as results.
+
+
+<p>
+There are eight basic types in Lua:
+<em>nil</em>, <em>boolean</em>, <em>number</em>,
+<em>string</em>, <em>function</em>, <em>userdata</em>,
+<em>thread</em>, and <em>table</em>.
+<em>Nil</em> is the type of the value <b>nil</b>,
+whose main property is to be different from any other value;
+it usually represents the absence of a useful value.
+<em>Boolean</em> is the type of the values <b>false</b> and <b>true</b>.
+Both <b>nil</b> and <b>false</b> make a condition false;
+any other value makes it true.
+<em>Number</em> represents real (double-precision floating-point) numbers.
+(It is easy to build Lua interpreters that use other
+internal representations for numbers,
+such as single-precision float or long integers;
+see file <code>luaconf.h</code>.)
+<em>String</em> represents arrays of characters.
+
+Lua is 8-bit clean:
+strings can contain any 8-bit value,
+including embedded zeros ('<code>\0</code>').
+
+
+<p>
+Lua can call (and manipulate) functions written in Lua and
+functions written in C
+(see <a href="#3.4.9">&sect;3.4.9</a>).
+
+
+<p>
+The type <em>userdata</em> is provided to allow arbitrary C&nbsp;data to
+be stored in Lua variables.
+This type corresponds to a block of raw memory
+and has no pre-defined operations in Lua,
+except assignment and identity test.
+However, by using <em>metatables</em>,
+the programmer can define operations for userdata values
+(see <a href="#2.4">&sect;2.4</a>).
+Userdata values cannot be created or modified in Lua,
+only through the C&nbsp;API.
+This guarantees the integrity of data owned by the host program.
+
+
+<p>
+The type <em>thread</em> represents independent threads of execution
+and it is used to implement coroutines (see <a href="#2.6">&sect;2.6</a>).
+Do not confuse Lua threads with operating-system threads.
+Lua supports coroutines on all systems,
+even those that do not support threads.
+
+
+<p>
+The type <em>table</em> implements associative arrays,
+that is, arrays that can be indexed not only with numbers,
+but with any value (except <b>nil</b>).
+Tables can be <em>heterogeneous</em>;
+that is, they can contain values of all types (except <b>nil</b>).
+Tables are the sole data structuring mechanism in Lua;
+they can be used to represent ordinary arrays,
+symbol tables, sets, records, graphs, trees, etc.
+To represent records, 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>.
+There are several convenient ways to create tables in Lua
+(see <a href="#3.4.8">&sect;3.4.8</a>).
+
+
+<p>
+Like indices,
+the value of a table field can be of any type (except <b>nil</b>).
+In particular,
+because functions are first-class values,
+table fields can contain functions.
+Thus tables can also carry <em>methods</em> (see <a href="#3.4.10">&sect;3.4.10</a>).
+
+
+<p>
+Tables, functions, threads, and (full) userdata values are <em>objects</em>:
+variables do not actually <em>contain</em> these values,
+only <em>references</em> to them.
+Assignment, parameter passing, and function returns
+always manipulate references to such values;
+these operations do not imply any kind of copy.
+
+
+<p>
+The library function <a href="#pdf-type"><code>type</code></a> returns a string describing the type
+of a given value.
+
+
+
+
+
+<h2>2.2 - <a name="2.2">Environments and the Global Environment</a></h2>
+
+<p>
+As discussed in <a href="#3.2">&sect;3.2</a> and <a href="#3.3.3">&sect;3.3.3</a>,
+any reference to a global name <code>var</code> is syntactically translated
+to <code>_ENV.var</code>.
+Moreover, any chunk is compiled in the scope of an external
+variable called <code>_ENV</code> (see <a href="#3.3.1">&sect;3.3.1</a>).
+Any table used as the value of <code>_ENV</code> is usually called
+an <em>environment</em>.
+
+
+<p>
+Lua keeps a distinguished environment called the <em>global environment</em>.
+This value is kept at a special index in the C registry (see <a href="#4.5">&sect;4.5</a>).
+In Lua, the variable <a href="#pdf-_G"><code>_G</code></a> is initialized with this same value.
+
+
+<p>
+When Lua compiles a chunk,
+it initializes the value of its <code>_ENV</code> variable
+with the global environment (see <a href="#pdf-load"><code>load</code></a>).
+Therefore, by default,
+global variables in Lua code refer to entries in the global environment.
+Moreover, all standard libraries are loaded in the global environment,
+and several functions there operate on that environment.
+You can use <a href="#pdf-loadin"><code>loadin</code></a> to load a chunk with a different environment.
+(In C, you have to load the chunk and then change the value
+of its first upvalue.)
+
+
+<p>
+If you change the global environment in the registry
+(through C code or the debug library),
+all chunks loaded after the change will get the new environment.
+Previously loaded chunks are not affected, however,
+as each has its own copy of the environment in its <code>_ENV</code> variable.
+Moreover, the variable <a href="#pdf-_G"><code>_G</code></a>
+(which is stored in the original global environment)
+is never updated by Lua.
+
+
+
+
+
+<h2>2.3 - <a name="2.3">Error Handling</a></h2>
+
+<p>
+Because Lua is an embedded extension language,
+all Lua actions start from C&nbsp;code in the host program
+calling a function from the Lua library (see <a href="#lua_pcall"><code>lua_pcall</code></a>).
+Whenever an error occurs during Lua compilation or execution,
+control returns to C,
+which can take appropriate measures
+(such as printing an error message).
+
+
+<p>
+Lua code can explicitly generate an error by calling the
+<a href="#pdf-error"><code>error</code></a> function.
+If you need to catch errors in Lua,
+you can use the <a href="#pdf-pcall"><code>pcall</code></a> function.
+
+
+
+
+
+<h2>2.4 - <a name="2.4">Metatables</a></h2>
+
+<p>
+Every value in Lua can have a <em>metatable</em>.
+This <em>metatable</em> is an ordinary Lua table
+that defines the behavior of the original value
+under certain special operations.
+You can change several aspects of the behavior
+of operations over a value by setting specific fields in its metatable.
+For instance, when a non-numeric value is the operand of an addition,
+Lua checks for a function in the field <code>"__add"</code> in its metatable.
+If it finds one,
+Lua calls this function to perform the addition.
+
+
+<p>
+We call the keys in a metatable <em>events</em>
+and the values <em>metamethods</em>.
+In the previous example, the event is <code>"add"</code>
+and the metamethod is the function that performs the addition.
+
+
+<p>
+You can query the metatable of any value
+through the <a href="#pdf-getmetatable"><code>getmetatable</code></a> function.
+
+
+<p>
+You can replace the metatable of tables
+through the <a href="#pdf-setmetatable"><code>setmetatable</code></a>
+function.
+You cannot change the metatable of other types from Lua
+(except by using the debug library);
+you must use the C&nbsp;API for that.
+
+
+<p>
+Tables and full userdata have individual metatables
+(although multiple tables and userdata can share their metatables).
+Values of all other types share one single metatable per type;
+that is, there is one single metatable for all numbers,
+one for all strings, etc.
+By default, a value has no metatable,
+but the string library sets a metatable for the string type (see <a href="#6.4">&sect;6.4</a>).
+
+
+<p>
+A metatable controls how an object behaves in arithmetic operations,
+order comparisons, concatenation, length operation, and indexing.
+A metatable also can define a function to be called when a userdata
+is garbage collected.
+For each of these operations Lua associates a specific key
+called an <em>event</em>.
+When Lua performs one of these operations over a value,
+it checks whether this value has a metatable with the corresponding event.
+If so, the value associated with that key (the metamethod)
+controls how Lua will perform the operation.
+
+
+<p>
+Metatables control the operations listed next.
+Each operation is identified by its corresponding name.
+The key for each operation is a string with its name prefixed by
+two underscores, '<code>__</code>';
+for instance, the key for operation "add" is the
+string <code>"__add"</code>.
+The semantics of these operations is better explained by a Lua function
+describing how the interpreter executes the operation.
+
+
+<p>
+The code shown here in Lua is only illustrative;
+the real behavior is hard coded in the interpreter
+and it is much more efficient than this simulation.
+All functions used in these descriptions
+(<a href="#pdf-rawget"><code>rawget</code></a>, <a href="#pdf-tonumber"><code>tonumber</code></a>, etc.)
+are described in <a href="#6.1">&sect;6.1</a>.
+In particular, to retrieve the metamethod of a given object,
+we use the expression
+
+<pre>
+ metatable(obj)[event]
+</pre><p>
+This should be read as
+
+<pre>
+ rawget(getmetatable(obj) or {}, event)
+</pre><p>
+
+That is, the access to a metamethod does not invoke other metamethods,
+and the access to objects with no metatables does not fail
+(it simply results in <b>nil</b>).
+
+
+<p>
+For the unary <code>-</code> and <code>#</code> operators,
+the metamethod is called repeating the first argument as a second argument.
+This extra argument is only to simplify Lua's internals;
+it may be removed in future versions and therefore it is not present
+in the following code.
+(For most uses this extra argument is irrelevant.)
+
+
+
+<ul>
+
+<li><b>"add":</b>
+the <code>+</code> operation.
+
+
+
+<p>
+The function <code>getbinhandler</code> below defines how Lua chooses a handler
+for a binary operation.
+First, Lua tries the first operand.
+If its type does not define a handler for the operation,
+then Lua tries the second operand.
+
+<pre>
+ function getbinhandler (op1, op2, event)
+ return metatable(op1)[event] or metatable(op2)[event]
+ end
+</pre><p>
+By using this function,
+the behavior of the <code>op1 + op2</code> 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 h = getbinhandler(op1, op2, "__add")
+ if h then
+ -- call the handler with both operands
+ return (h(op1, op2))
+ else -- no handler available: default behavior
+ error(&middot;&middot;&middot;)
+ end
+ end
+ end
+</pre><p>
+</li>
+
+<li><b>"sub":</b>
+the <code>-</code> operation.
+
+Behavior similar to the "add" operation.
+</li>
+
+<li><b>"mul":</b>
+the <code>*</code> operation.
+
+Behavior similar to the "add" operation.
+</li>
+
+<li><b>"div":</b>
+the <code>/</code> operation.
+
+Behavior similar to the "add" operation.
+</li>
+
+<li><b>"mod":</b>
+the <code>%</code> operation.
+
+Behavior similar to the "add" operation,
+with the operation
+<code>o1 - floor(o1/o2)*o2</code> as the primitive operation.
+</li>
+
+<li><b>"pow":</b>
+the <code>^</code> (exponentiation) operation.
+
+Behavior similar to the "add" operation,
+with the function <code>pow</code> (from the C&nbsp;math library)
+as the primitive operation.
+</li>
+
+<li><b>"unm":</b>
+the unary <code>-</code> operation.
+
+
+<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 handler from the operand
+ local h = metatable(op).__unm
+ if h then
+ -- call the handler with the operand
+ return (h(op))
+ else -- no handler available: default behavior
+ error(&middot;&middot;&middot;)
+ end
+ end
+ end
+</pre><p>
+</li>
+
+<li><b>"concat":</b>
+the <code>..</code> (concatenation) operation.
+
+
+<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 h = getbinhandler(op1, op2, "__concat")
+ if h then
+ return (h(op1, op2))
+ else
+ error(&middot;&middot;&middot;)
+ end
+ end
+ end
+</pre><p>
+</li>
+
+<li><b>"len":</b>
+the <code>#</code> operation.
+
+
+<pre>
+ function len_event (op)
+ if type(op) == "string" then
+ return strlen(op) -- primitive string length
+ else
+ local h = metatable(op).__len
+ if h then
+ return (h(op)) -- call handler with the operand
+ elseif type(op) == "table" then
+ return #op -- primitive table length
+ else -- no handler available: error
+ error(&middot;&middot;&middot;)
+ end
+ end
+ end
+</pre><p>
+See <a href="#3.4.6">&sect;3.4.6</a> for a description of the length of a table.
+</li>
+
+<li><b>"eq":</b>
+the <code>==</code> operation.
+
+The function <code>getequalhandler</code> defines how Lua chooses a metamethod
+for equality.
+A metamethod is selected only when both values
+being compared have the same type
+and the same metamethod for the selected operation.
+
+<pre>
+ function getequalhandler (op1, op2, event)
+ if type(op1) ~= type(op2) then return nil end
+ local mm1 = metatable(op1)[event]
+ local mm2 = metatable(op2)[event]
+ if mm1 == mm2 then return mm1 else return nil end
+ end
+</pre><p>
+The "eq" event is defined as follows:
+
+<pre>
+ function eq_event (op1, op2)
+ if type(op1) ~= type(op2) then -- different types?
+ return false -- different values
+ end
+ if op1 == op2 then -- primitive equal?
+ return true -- values are equal
+ end
+ -- try metamethod
+ local h = getequalhandler(op1, op2, "__eq")
+ if h then
+ return (h(op1, op2))
+ else
+ return false
+ end
+ end
+</pre><p>
+</li>
+
+<li><b>"lt":</b>
+the <code>&lt;</code> operation.
+
+
+<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 h = getbinhandler(op1, op2, "__lt")
+ if h then
+ return (h(op1, op2))
+ else
+ error(&middot;&middot;&middot;)
+ end
+ end
+ end
+</pre><p>
+</li>
+
+<li><b>"le":</b>
+the <code>&lt;=</code> operation.
+
+
+<pre>
+ function le_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 h = getbinhandler(op1, op2, "__le")
+ if h then
+ return (h(op1, op2))
+ else
+ h = getbinhandler(op1, op2, "__lt")
+ if h then
+ return not h(op2, op1)
+ else
+ error(&middot;&middot;&middot;)
+ end
+ end
+ end
+ end
+</pre><p>
+Note that, in the absence of a "le" metamethod,
+Lua tries the "lt", assuming that <code>a &lt;= b</code> is
+equivalent to <code>not (b &lt; a)</code>.
+</li>
+
+<li><b>"index":</b>
+The indexing access <code>table[key]</code>.
+
+
+<pre>
+ function gettable_event (table, key)
+ local h
+ if type(table) == "table" then
+ local v = rawget(table, key)
+ if v ~= nil then return v end
+ h = metatable(table).__index
+ if h == nil then return nil end
+ else
+ h = metatable(table).__index
+ if h == nil then
+ error(&middot;&middot;&middot;)
+ end
+ end
+ if type(h) == "function" then
+ return (h(table, key)) -- call the handler
+ else return h[key] -- or repeat operation on it
+ end
+ end
+</pre><p>
+</li>
+
+<li><b>"newindex":</b>
+The indexing assignment <code>table[key] = value</code>.
+
+
+<pre>
+ function settable_event (table, key, value)
+ local h
+ if type(table) == "table" then
+ local v = rawget(table, key)
+ if v ~= nil then rawset(table, key, value); return end
+ h = metatable(table).__newindex
+ if h == nil then rawset(table, key, value); return end
+ else
+ h = metatable(table).__newindex
+ if h == nil then
+ error(&middot;&middot;&middot;)
+ end
+ end
+ if type(h) == "function" then
+ h(table, key,value) -- call the handler
+ else h[key] = value -- or repeat operation on it
+ end
+ end
+</pre><p>
+</li>
+
+<li><b>"call":</b>
+called when Lua calls a value.
+
+
+<pre>
+ function function_event (func, ...)
+ if type(func) == "function" then
+ return func(...) -- primitive call
+ else
+ local h = metatable(func).__call
+ if h then
+ return h(func, ...)
+ else
+ error(&middot;&middot;&middot;)
+ end
+ end
+ end
+</pre><p>
+</li>
+
+</ul>
+
+
+
+
+<h2>2.5 - <a name="2.5">Garbage Collection</a></h2>
+
+<p>
+Lua performs automatic memory management.
+This means that
+you have to worry neither about allocating memory for new objects
+nor about freeing it when the objects are no longer needed.
+Lua manages memory automatically by running
+a <em>garbage collector</em> to collect all <em>dead objects</em>
+(that is, objects that are no longer accessible from Lua).
+All memory used by Lua is subject to automatic management:
+tables, userdata, functions, threads, strings, etc.
+
+
+<p>
+Lua implements an incremental mark-and-sweep collector.
+It uses two numbers to control its garbage-collection cycles:
+the <em>garbage-collector pause</em> and
+the <em>garbage-collector step multiplier</em>.
+Both use percentage points as units
+(so that a value of 100 means an internal value of 1).
+
+
+<p>
+The garbage-collector pause
+controls how long the collector waits before starting a new cycle.
+Larger values make the collector less aggressive.
+Values smaller than 100 mean the collector will not wait to
+start a new cycle.
+A value of 200 means that the collector waits for the total memory in use
+to double before starting a new cycle.
+
+
+<p>
+The step multiplier
+controls the relative speed of the collector relative to
+memory allocation.
+Larger values make the collector more aggressive but also increase
+the size of each incremental step.
+Values smaller than 100 make the collector too slow and
+can result in the collector never finishing a cycle.
+The default, 200, means that the collector runs at "twice"
+the speed of memory allocation.
+
+
+<p>
+If you set the step multiplier to a very large number
+(larger than 10% of the maximum number of
+bytes that the program may use),
+the collector behaves like a stop-the-world collector.
+If you then set the pause to 200,
+the collector behaves as in old Lua versions,
+doing a complete collection every time Lua doubles its
+memory usage.
+
+
+<p>
+You can change these numbers by calling <a href="#lua_gc"><code>lua_gc</code></a> in C
+or <a href="#pdf-collectgarbage"><code>collectgarbage</code></a> in Lua.
+With these functions you can also control
+the collector directly (e.g., stop and restart it).
+
+
+
+<h3>2.5.1 - <a name="2.5.1">Garbage-Collection Metamethods</a></h3>
+
+<p>
+Using the C&nbsp;API,
+you can set garbage-collector metamethods for userdata (see <a href="#2.4">&sect;2.4</a>).
+These metamethods are also called <em>finalizers</em>.
+Finalizers allow you to coordinate Lua's garbage collection
+with external resource management
+(such as closing files, network or database connections,
+or freeing your own memory).
+
+
+<p>
+Garbage userdata with a field <code>__gc</code> in their metatables are not
+collected immediately by the garbage collector.
+Instead, Lua puts them in a list.
+After the collection,
+Lua does the equivalent of the following function
+for each userdata in that list:
+
+<pre>
+ function gc_event (udata)
+ local h = metatable(udata).__gc
+ if h then
+ h(udata)
+ end
+ end
+</pre>
+
+<p>
+At the end of each garbage-collection cycle,
+the finalizers for userdata are called in <em>reverse</em>
+order of their creation,
+among those collected in that cycle.
+That is, the first finalizer to be called is the one associated
+with the userdata created last in the program.
+The userdata itself is freed only in the next garbage-collection cycle.
+
+
+
+
+
+<h3>2.5.2 - <a name="2.5.2">Weak Tables</a></h3>
+
+<p>
+A <em>weak table</em> is a table whose elements are
+<em>weak references</em>.
+A weak reference is ignored by the garbage collector.
+In other words,
+if the only references to an object are weak references,
+then the garbage collector will collect this object.
+
+
+<p>
+A weak table can have weak keys, weak values, or both.
+A table with weak keys allows the collection of its keys,
+but prevents the collection of its values.
+A table with both weak keys and weak values allows the collection of
+both keys and values.
+In any case, if either the key or the value is collected,
+the whole pair is removed from the table.
+The weakness of a table is controlled by the
+<code>__mode</code> field of its metatable.
+If the <code>__mode</code> field is a string containing the character&nbsp;'<code>k</code>',
+the keys in the table are weak.
+If <code>__mode</code> contains '<code>v</code>',
+the values in the table are weak.
+
+
+<p>
+A table with weak keys and strong values
+is also called an <em>ephemeron table</em>.
+In an ephemeron table,
+a value is considered reachable only if its key is reachable.
+In particular,
+if the only reference to a key comes from its value,
+the pair is removed.
+
+
+<p>
+After you use a table as a metatable,
+you should not change the value of its <code>__mode</code> field.
+Otherwise, the weak behavior of the tables controlled by this
+metatable is undefined.
+
+
+<p>
+Only objects that have an explicit construction
+can be removed from weak tables.
+Values, such as numbers and booleans,
+are not subject to garbage collection,
+and therefore are not removed from weak tables
+(unless its associated value is collected).
+Lua treats strings and light C functions as non-object values.
+
+
+<p>
+Userdata with finalizers has a special behavior in weak tables.
+When a userdata is a value in a weak table,
+it is removed from the table the first time it is collected,
+before running its finalizer.
+When it is a key, however,
+it is removed from the table only when it is really freed,
+after running its finalizer.
+This behavior allows the finalizer to access values
+associated with the userdata through weak tables.
+
+
+
+
+
+
+
+<h2>2.6 - <a name="2.6">Coroutines</a></h2>
+
+<p>
+Lua supports coroutines,
+also called <em>collaborative multithreading</em>.
+A coroutine in Lua represents an independent thread of execution.
+Unlike threads in multithread systems, however,
+a coroutine only suspends its execution by explicitly calling
+a yield function.
+
+
+<p>
+You create a coroutine with a call to <a href="#pdf-coroutine.create"><code>coroutine.create</code></a>.
+Its sole argument is a function
+that is the main function of the coroutine.
+The <code>create</code> function only creates a new coroutine and
+returns a handle to it (an object of type <em>thread</em>);
+it does not start the coroutine execution.
+
+
+<p>
+When you first call <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>,
+passing as its first argument
+a thread returned by <a href="#pdf-coroutine.create"><code>coroutine.create</code></a>,
+the coroutine starts its execution,
+at the first line of its main function.
+Extra arguments passed to <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> are passed on
+to the coroutine main function.
+After the coroutine starts running,
+it runs until it terminates or <em>yields</em>.
+
+
+<p>
+A coroutine can terminate its execution in two ways:
+normally, when its main function returns
+(explicitly or implicitly, after the last instruction);
+and abnormally, if there is an unprotected error.
+In the first case, <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> returns <b>true</b>,
+plus any values returned by the coroutine main function.
+In case of errors, <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> returns <b>false</b>
+plus an error message.
+
+
+<p>
+A coroutine yields by calling <a href="#pdf-coroutine.yield"><code>coroutine.yield</code></a>.
+When a coroutine yields,
+the corresponding <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> returns immediately,
+even if the yield happens inside nested function calls
+(that is, not in the main function,
+but in a function directly or indirectly called by the main function).
+In the case of a yield, <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> also returns <b>true</b>,
+plus any values passed to <a href="#pdf-coroutine.yield"><code>coroutine.yield</code></a>.
+The next time you resume the same coroutine,
+it continues its execution from the point where it yielded,
+with the call to <a href="#pdf-coroutine.yield"><code>coroutine.yield</code></a> returning any extra
+arguments passed to <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>.
+
+
+<p>
+Like <a href="#pdf-coroutine.create"><code>coroutine.create</code></a>,
+the <a href="#pdf-coroutine.wrap"><code>coroutine.wrap</code></a> function also creates a coroutine,
+but instead of returning the coroutine itself,
+it returns a function that, when called, resumes the coroutine.
+Any arguments passed to this function
+go as extra arguments to <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>.
+<a href="#pdf-coroutine.wrap"><code>coroutine.wrap</code></a> returns all the values returned by <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>,
+except the first one (the boolean error code).
+Unlike <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>,
+<a href="#pdf-coroutine.wrap"><code>coroutine.wrap</code></a> does not catch errors;
+any error is propagated to the caller.
+
+
+<p>
+As an example,
+consider the following code:
+
+<pre>
+ function foo (a)
+ print("foo", a)
+ return coroutine.yield(2*a)
+ end
+
+ co = coroutine.create(function (a,b)
+ print("co-body", a, b)
+ local r = foo(a+1)
+ print("co-body", r)
+ local r, s = coroutine.yield(a+b, a-b)
+ print("co-body", r, s)
+ return b, "end"
+ end)
+
+ print("main", coroutine.resume(co, 1, 10))
+ print("main", coroutine.resume(co, "r"))
+ print("main", coroutine.resume(co, "x", "y"))
+ print("main", coroutine.resume(co, "x", "y"))
+</pre><p>
+When you run it, it produces the following output:
+
+<pre>
+ co-body 1 10
+ foo 2
+
+ main true 4
+ co-body r
+ main true 11 -9
+ co-body x y
+ main true 10 end
+ main false cannot resume dead coroutine
+</pre>
+
+
+
+
+<h1>3 - <a name="3">The Language</a></h1>
<p>
This section describes the lexis, the syntax, and the semantics of Lua.
@@ -102,13 +992,13 @@ in which
[<em>a</em>]&nbsp;means an optional <em>a</em>.
Non-terminals are shown like non-terminal,
keywords are shown like <b>kword</b>,
-and other terminal symbols are shown like `<b>=</b>&acute;.
-The complete syntax of Lua can be found in <a href="#8">&sect;8</a>
+and other terminal symbols are shown like &lsquo<b>=</b>&rsquo;.
+The complete syntax of Lua can be found in <a href="#9">&sect;9</a>
at the end of this manual.
-<h2>2.1 - <a name="2.1">Lexical Conventions</a></h2>
+<h2>3.1 - <a name="3.1">Lexical Conventions</a></h2>
<p>
Lua is a free-form language.
@@ -145,7 +1035,7 @@ Lua is a case-sensitive language:
are two different, valid names.
As a convention, names starting with an underscore followed by
uppercase letters (such as <a href="#pdf-_VERSION"><code>_VERSION</code></a>)
-are reserved for internal global variables used by Lua.
+are reserved for variables used by Lua.
<p>
@@ -172,12 +1062,21 @@ and can contain the following C-like escape sequences:
'<code>\\</code>' (backslash),
'<code>\"</code>' (quotation mark [double quote]),
and '<code>\'</code>' (apostrophe [single quote]).
-Moreover, a backslash followed by a real newline
+A backslash followed by a real newline
results in a newline in the string.
-A character in a string can also be specified by its numerical value.
+The escape sequence '<code>\*</code>' skips the following span
+of white-space characters,
+including line breaks;
+it is particularly useful to break and ident a string
+into multiple lines without adding the newlines and spaces
+into the string contents.
+
+
+<p>
+A character in a literal string can also be specified by its numerical value.
This can be done with the escape sequence <code>\x<em>XX</em></code>,
where <em>XX</em> is a sequence of exactly two hexadecimal digits,
-and with the escape sequence <code>\<em>ddd</em></code>,
+or with the escape sequence <code>\<em>ddd</em></code>,
where <em>ddd</em> is a sequence of up to three decimal digits.
(Note that if a decimal escape is to be followed by a digit,
it must be expressed using exactly three digits.)
@@ -256,133 +1155,7 @@ Long comments are frequently used to disable code temporarily.
-<h2>2.2 - <a name="2.2">Values and Types</a></h2>
-
-<p>
-Lua is a <em>dynamically typed language</em>.
-This means that
-variables do not have types; only values do.
-There are no type definitions in the language.
-All values carry their own type.
-
-
-<p>
-All values in Lua are <em>first-class values</em>.
-This means that all values can be stored in variables,
-passed as arguments to other functions, and returned as results.
-
-
-<p>
-There are eight basic types in Lua:
-<em>nil</em>, <em>boolean</em>, <em>number</em>,
-<em>string</em>, <em>function</em>, <em>userdata</em>,
-<em>thread</em>, and <em>table</em>.
-<em>Nil</em> is the type of the value <b>nil</b>,
-whose main property is to be different from any other value;
-it usually represents the absence of a useful value.
-<em>Boolean</em> is the type of the values <b>false</b> and <b>true</b>.
-Both <b>nil</b> and <b>false</b> make a condition false;
-any other value makes it true.
-<em>Number</em> represents real (double-precision floating-point) numbers.
-(It is easy to build Lua interpreters that use other
-internal representations for numbers,
-such as single-precision float or long integers;
-see file <code>luaconf.h</code>.)
-<em>String</em> represents arrays of characters.
-
-Lua is 8-bit clean:
-strings can contain any 8-bit character,
-including embedded zeros ('<code>\0</code>') (see <a href="#2.1">&sect;2.1</a>).
-
-
-<p>
-Lua can call (and manipulate) functions written in Lua and
-functions written in C
-(see <a href="#2.5.8">&sect;2.5.8</a>).
-
-
-<p>
-The type <em>userdata</em> is provided to allow arbitrary C&nbsp;data to
-be stored in Lua variables.
-This type corresponds to a block of raw memory
-and has no pre-defined operations in Lua,
-except assignment and identity test.
-However, by using <em>metatables</em>,
-the programmer can define operations for userdata values
-(see <a href="#2.8">&sect;2.8</a>).
-Userdata values cannot be created or modified in Lua,
-only through the C&nbsp;API.
-This guarantees the integrity of data owned by the host program.
-
-
-<p>
-The type <em>thread</em> represents independent threads of execution
-and it is used to implement coroutines (see <a href="#2.11">&sect;2.11</a>).
-Do not confuse Lua threads with operating-system threads.
-Lua supports coroutines on all systems,
-even those that do not support threads.
-
-
-<p>
-The type <em>table</em> implements associative arrays,
-that is, arrays that can be indexed not only with numbers,
-but with any value (except <b>nil</b>).
-Tables can be <em>heterogeneous</em>;
-that is, they can contain values of all types (except <b>nil</b>).
-Tables are the sole data structuring mechanism in Lua;
-they can be used to represent ordinary arrays,
-symbol tables, sets, records, graphs, trees, etc.
-To represent records, 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>.
-There are several convenient ways to create tables in Lua
-(see <a href="#2.5.7">&sect;2.5.7</a>).
-
-
-<p>
-Like indices,
-the value of a table field can be of any type (except <b>nil</b>).
-In particular,
-because functions are first-class values,
-table fields can contain functions.
-Thus tables can also carry <em>methods</em> (see <a href="#2.5.9">&sect;2.5.9</a>).
-
-
-<p>
-Tables, functions, threads, and (full) userdata values are <em>objects</em>:
-variables do not actually <em>contain</em> these values,
-only <em>references</em> to them.
-Assignment, parameter passing, and function returns
-always manipulate references to such values;
-these operations do not imply any kind of copy.
-
-
-<p>
-The library function <a href="#pdf-type"><code>type</code></a> returns a string describing the type
-of a given value.
-
-
-
-<h3>2.2.1 - <a name="2.2.1">Coercion</a></h3>
-
-<p>
-Lua provides automatic conversion between
-string and number values at run time.
-Any arithmetic operation applied to a string tries to convert
-this string to a number, following the usual conversion rules.
-Conversely, whenever a number is used where a string is expected,
-the number is converted to a string, in a reasonable format.
-For complete control over how numbers are converted to strings,
-use the <code>format</code> function from the string library
-(see <a href="#pdf-string.format"><code>string.format</code></a>).
-
-
-
-
-
-
-
-<h2>2.3 - <a name="2.3">Variables</a></h2>
+<h2>3.2 - <a name="3.2">Variables</a></h2>
<p>
Variables are places that store values.
@@ -399,15 +1172,15 @@ which is a particular kind of local variable):
<pre>
var ::= Name
</pre><p>
-Name denotes identifiers, as defined in <a href="#2.1">&sect;2.1</a>.
+Name denotes identifiers, as defined in <a href="#3.1">&sect;3.1</a>.
<p>
-Any variable is assumed to be global unless explicitly declared
-as a local (see <a href="#2.4.7">&sect;2.4.7</a>).
+Any variable name is assumed to be global unless explicitly declared
+as a local (see <a href="#3.3.7">&sect;3.3.7</a>).
Local variables are <em>lexically scoped</em>:
local variables can be freely accessed by functions
-defined inside their scope (see <a href="#2.6">&sect;2.6</a>).
+defined inside their scope (see <a href="#3.5">&sect;3.5</a>).
<p>
@@ -418,13 +1191,12 @@ Before the first assignment to a variable, its value is <b>nil</b>.
Square brackets are used to index a table:
<pre>
- var ::= prefixexp `<b>[</b>&acute; exp `<b>]</b>&acute;
+ var ::= prefixexp &lsquo<b>[</b>&rsquo; exp &lsquo<b>]</b>&rsquo;
</pre><p>
-The meaning of accesses to global variables
-and table fields can be changed via metatables.
+The meaning of accesses to table fields can be changed via metatables.
An access to an indexed variable <code>t[i]</code> is equivalent to
a call <code>gettable_event(t,i)</code>.
-(See <a href="#2.8">&sect;2.8</a> for a complete description of the
+(See <a href="#2.4">&sect;2.4</a> for a complete description of the
<code>gettable_event</code> function.
This function is not defined or callable in Lua.
We use it here only for explanatory purposes.)
@@ -435,32 +1207,20 @@ The syntax <code>var.Name</code> is just syntactic sugar for
<code>var["Name"]</code>:
<pre>
- var ::= prefixexp `<b>.</b>&acute; Name
+ var ::= prefixexp &lsquo<b>.</b>&rsquo; Name
</pre>
<p>
-All global variables live as fields in ordinary Lua tables,
-called <em>environment tables</em> or simply
-<em>environments</em> (see <a href="#2.9">&sect;2.9</a>).
An access to a global variable <code>x</code>
-is equivalent to <code>_env.x</code>,
-which in turn is equivalent to
-
-<pre>
- gettable_event(_env, "x")
-</pre><p>
-where <code>_env</code> is the current environment (see <a href="#2.9">&sect;2.9</a>).
-(See <a href="#2.8">&sect;2.8</a> for a complete description of the
-<code>gettable_event</code> function.
-This function is not defined or callable in Lua.
-Similarly, the <code>_env</code> variable is not defined in Lua.
-We use them here only for explanatory purposes.)
+is equivalent to <code>_ENV.x</code>.
+Due to the way that chunks are compiled,
+<code>_ENV</code> is never a global name (see <a href="#2.2">&sect;2.2</a>).
-<h2>2.4 - <a name="2.4">Statements</a></h2>
+<h2>3.3 - <a name="3.3">Statements</a></h2>
<p>
Lua supports an almost conventional set of statements,
@@ -471,26 +1231,33 @@ and variable declarations.
-<h3>2.4.1 - <a name="2.4.1">Chunks</a></h3>
+<h3>3.3.1 - <a name="3.3.1">Chunks</a></h3>
<p>
The unit of execution of Lua is called a <em>chunk</em>.
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>&acute;]}
+ chunk ::= {stat }
</pre><p>
-There are no empty statements and thus '<code>;;</code>' is not legal.
+Lua has <em>empty statements</em>
+that allow you to separate statements with semicolons,
+start a chunk with a semicolon
+or write two semicolons in sequence:
+<pre>
+ stat ::= &lsquo<b>;</b>&rsquo;
+</pre>
<p>
Lua handles a chunk as the body of an anonymous function
with a variable number of arguments
-(see <a href="#2.5.9">&sect;2.5.9</a>).
+(see <a href="#3.4.10">&sect;3.4.10</a>).
As such, chunks can define local variables,
receive arguments, and return values.
+Moreover, such anonymous function is compiled as in the
+scope of an external local variable called <code>_ENV</code> (see <a href="#2.2">&sect;2.2</a>).
<p>
@@ -512,7 +1279,7 @@ Lua automatically detects the file type and acts accordingly.
-<h3>2.4.2 - <a name="2.4.2">Blocks</a></h3><p>
+<h3>3.3.2 - <a name="3.3.2">Blocks</a></h3><p>
A block is a list of statements;
syntactically, a block is the same as a chunk:
@@ -530,13 +1297,13 @@ Explicit blocks are useful
to control the scope of variable declarations.
Explicit blocks are also sometimes used to
add a <b>return</b> or <b>break</b> statement in the middle
-of another block (see <a href="#2.4.4">&sect;2.4.4</a>).
+of another block (see <a href="#3.3.4">&sect;3.3.4</a>).
-<h3>2.4.3 - <a name="2.4.3">Assignment</a></h3>
+<h3>3.3.3 - <a name="3.3.3">Assignment</a></h3>
<p>
Lua allows multiple assignments.
@@ -546,11 +1313,11 @@ and a list of expressions on the right side.
The elements in both lists are separated by commas:
<pre>
- stat ::= varlist `<b>=</b>&acute; explist
- varlist ::= var {`<b>,</b>&acute; var}
- explist ::= exp {`<b>,</b>&acute; exp}
+ stat ::= varlist &lsquo<b>=</b>&rsquo; explist
+ varlist ::= var {&lsquo<b>,</b>&rsquo; var}
+ explist ::= exp {&lsquo<b>,</b>&rsquo; exp}
</pre><p>
-Expressions are discussed in <a href="#2.5">&sect;2.5</a>.
+Expressions are discussed in <a href="#3.4">&sect;3.4</a>.
<p>
@@ -564,7 +1331,7 @@ the list is extended with as many <b>nil</b>'s as needed.
If the list of expressions ends with a function call,
then all values returned by that call enter the list of values,
before the adjustment
-(except when the call is enclosed in parentheses; see <a href="#2.5">&sect;2.5</a>).
+(except when the call is enclosed in parentheses; see <a href="#3.4">&sect;3.4</a>).
<p>
@@ -598,7 +1365,7 @@ The meaning of assignments to global variables
and table fields can be changed via metatables.
An assignment to an indexed variable <code>t[i] = val</code> is equivalent to
<code>settable_event(t,i,val)</code>.
-(See <a href="#2.8">&sect;2.8</a> for a complete description of the
+(See <a href="#2.4">&sect;2.4</a> for a complete description of the
<code>settable_event</code> function.
This function is not defined or callable in Lua.
We use it here only for explanatory purposes.)
@@ -607,21 +1374,13 @@ We use it here only for explanatory purposes.)
<p>
An assignment to a global variable <code>x = val</code>
is equivalent to the assignment
-<code>_env.x = val</code>,
-which in turn is equivalent to
-
-<pre>
- settable_event(_env, "x", val)
-</pre><p>
-where <code>_env</code> is the environment of the running function.
-(The <code>_env</code> variable is not defined in Lua.
-We use it here only for explanatory purposes.)
+<code>_ENV.x = val</code> (see <a href="#2.2">&sect;2.2</a>).
-<h3>2.4.4 - <a name="2.4.4">Control Structures</a></h3><p>
+<h3>3.3.4 - <a name="3.3.4">Control Structures</a></h3><p>
The control structures
<b>if</b>, <b>while</b>, and <b>repeat</b> have the usual meaning and
familiar syntax:
@@ -634,7 +1393,7 @@ familiar syntax:
stat ::= <b>repeat</b> block <b>until</b> exp
stat ::= <b>if</b> exp <b>then</b> block {<b>elseif</b> exp <b>then</b> block} [<b>else</b> block] <b>end</b>
</pre><p>
-Lua also has a <b>for</b> statement, in two flavors (see <a href="#2.4.5">&sect;2.4.5</a>).
+Lua also has a <b>for</b> statement, in two flavors (see <a href="#3.3.5">&sect;3.3.5</a>).
<p>
@@ -661,7 +1420,7 @@ Functions and chunks can return more than one value,
and so the syntax for the <b>return</b> statement is
<pre>
- stat ::= <b>return</b> [explist]
+ stat ::= <b>return</b> [explist] [&lsquo<b>;</b>&rsquo;]
</pre>
<p>
@@ -671,7 +1430,7 @@ skipping to the next statement after the loop:
<pre>
- stat ::= <b>break</b>
+ stat ::= <b>break</b> [&lsquo<b>;</b>&rsquo;]
</pre><p>
A <b>break</b> ends the innermost enclosing loop.
@@ -691,7 +1450,7 @@ their (inner) blocks.
-<h3>2.4.5 - <a name="2.4.5">For Statement</a></h3>
+<h3>3.3.5 - <a name="3.3.5">For Statement</a></h3>
<p>
@@ -705,7 +1464,7 @@ control variable runs through an arithmetic progression.
It has the following syntax:
<pre>
- stat ::= <b>for</b> Name `<b>=</b>&acute; exp `<b>,</b>&acute; exp [`<b>,</b>&acute; exp] <b>do</b> block <b>end</b>
+ stat ::= <b>for</b> Name &lsquo<b>=</b>&rsquo; exp &lsquo<b>,</b>&rsquo; exp [&lsquo<b>,</b>&rsquo; exp] <b>do</b> block <b>end</b>
</pre><p>
The <em>block</em> is repeated for <em>name</em> starting at the value of
the first <em>exp</em>, until it passes the second <em>exp</em> by steps of the
@@ -770,7 +1529,7 @@ The generic <b>for</b> loop has the following syntax:
<pre>
stat ::= <b>for</b> namelist <b>in</b> explist <b>do</b> block <b>end</b>
- namelist ::= Name {`<b>,</b>&acute; Name}
+ namelist ::= Name {&lsquo<b>,</b>&rsquo; Name}
</pre><p>
A <b>for</b> statement like
@@ -822,7 +1581,7 @@ then assign them to other variables before breaking or exiting the loop.
-<h3>2.4.6 - <a name="2.4.6">Function Calls as Statements</a></h3><p>
+<h3>3.3.6 - <a name="3.3.6">Function Calls as Statements</a></h3><p>
To allow possible side-effects,
function calls can be executed as statements:
@@ -830,77 +1589,40 @@ function calls can be executed as statements:
stat ::= functioncall
</pre><p>
In this case, all returned values are thrown away.
-Function calls are explained in <a href="#2.5.8">&sect;2.5.8</a>.
+Function calls are explained in <a href="#3.4.9">&sect;3.4.9</a>.
-<h3>2.4.7 - <a name="2.4.7">Local Declarations</a></h3><p>
+<h3>3.3.7 - <a name="3.3.7">Local Declarations</a></h3><p>
Local variables can be declared anywhere inside a block.
The declaration can include an initial assignment:
<pre>
- stat ::= <b>local</b> namelist [`<b>=</b>&acute; explist]
+ stat ::= <b>local</b> namelist [&lsquo<b>=</b>&rsquo; explist]
</pre><p>
If present, an initial assignment has the same semantics
-of a multiple assignment (see <a href="#2.4.3">&sect;2.4.3</a>).
+of a multiple assignment (see <a href="#3.3.3">&sect;3.3.3</a>).
Otherwise, all variables are initialized with <b>nil</b>.
<p>
-A chunk is also a block (see <a href="#2.4.1">&sect;2.4.1</a>),
+A chunk is also a block (see <a href="#3.3.1">&sect;3.3.1</a>),
and so local variables can be declared in a chunk outside any explicit block.
The scope of such local variables extends until the end of the chunk.
<p>
-The visibility rules for local variables are explained in <a href="#2.6">&sect;2.6</a>.
+The visibility rules for local variables are explained in <a href="#3.5">&sect;3.5</a>.
-<h3>2.4.8 - <a name="2.4.8">Lexical Environments</a></h3>
-<p>
-A lexical environment defines a new current environment (see <a href="#2.9">&sect;2.9</a>)
-for the code inside its block:
-
-<pre>
- stat ::= <b>in</b> exp <b>do</b> block <b>end</b>
-</pre><p>
-That is, a lexical environment changes the
-table used to resolve all accesses
-to global (free) variables inside a block.
-
-<p>
-Inside a lexical environment,
-the result of <code><em>exp</em></code> becomes the current environment.
-Expression <code><em>exp</em></code> is evaluated only once in the beginning of
-the statement and it is stored in a hidden local variable named
-<a name="pdf-(environment)"><code>(environment)</code></a>.
-Then, any global variable
-(that is, a variable not declared as a local)
-<code>var</code> inside <code><em>block</em></code> is accessed as
-<code>(environment).<em>var</em></code>.
-Moreover, functions defined inside the block also use the
-current environment as their environments (see <a href="#2.9">&sect;2.9</a>).
-
-
-<p>
-A lexical environment does not shadow local declarations.
-That is, any local variable that is visible just before
-a lexical environment is still visible inside the environment.
-
-
-
-
-
-
-
-<h2>2.5 - <a name="2.5">Expressions</a></h2>
+<h2>3.4 - <a name="3.4">Expressions</a></h2>
<p>
The basic expressions in Lua are the following:
@@ -912,37 +1634,37 @@ The basic expressions in Lua are the following:
exp ::= String
exp ::= function
exp ::= tableconstructor
- exp ::= `<b>...</b>&acute;
+ exp ::= &lsquo<b>...</b>&rsquo;
exp ::= exp binop exp
exp ::= unop exp
- prefixexp ::= var | functioncall | `<b>(</b>&acute; exp `<b>)</b>&acute;
+ prefixexp ::= var | functioncall | &lsquo<b>(</b>&rsquo; exp &lsquo<b>)</b>&rsquo;
</pre>
<p>
-Numbers and literal strings are explained in <a href="#2.1">&sect;2.1</a>;
-variables are explained in <a href="#2.3">&sect;2.3</a>;
-function definitions are explained in <a href="#2.5.9">&sect;2.5.9</a>;
-function calls are explained in <a href="#2.5.8">&sect;2.5.8</a>;
-table constructors are explained in <a href="#2.5.7">&sect;2.5.7</a>.
+Numbers and literal strings are explained in <a href="#3.1">&sect;3.1</a>;
+variables are explained in <a href="#3.2">&sect;3.2</a>;
+function definitions are explained in <a href="#3.4.10">&sect;3.4.10</a>;
+function calls are explained in <a href="#3.4.9">&sect;3.4.9</a>;
+table constructors are explained in <a href="#3.4.8">&sect;3.4.8</a>.
Vararg expressions,
denoted by three dots ('<code>...</code>'), can only be used when
directly inside a vararg function;
-they are explained in <a href="#2.5.9">&sect;2.5.9</a>.
+they are explained in <a href="#3.4.10">&sect;3.4.10</a>.
<p>
-Binary operators comprise arithmetic operators (see <a href="#2.5.1">&sect;2.5.1</a>),
-relational operators (see <a href="#2.5.2">&sect;2.5.2</a>), logical operators (see <a href="#2.5.3">&sect;2.5.3</a>),
-and the concatenation operator (see <a href="#2.5.4">&sect;2.5.4</a>).
-Unary operators comprise the unary minus (see <a href="#2.5.1">&sect;2.5.1</a>),
-the unary <b>not</b> (see <a href="#2.5.3">&sect;2.5.3</a>),
-and the unary <em>length operator</em> (see <a href="#2.5.5">&sect;2.5.5</a>).
+Binary operators comprise arithmetic operators (see <a href="#3.4.1">&sect;3.4.1</a>),
+relational operators (see <a href="#3.4.3">&sect;3.4.3</a>), logical operators (see <a href="#3.4.4">&sect;3.4.4</a>),
+and the concatenation operator (see <a href="#3.4.5">&sect;3.4.5</a>).
+Unary operators comprise the unary minus (see <a href="#3.4.1">&sect;3.4.1</a>),
+the unary <b>not</b> (see <a href="#3.4.4">&sect;3.4.4</a>),
+and the unary <em>length operator</em> (see <a href="#3.4.6">&sect;3.4.6</a>).
<p>
Both function calls and vararg expressions can result in multiple values.
If an expression is used as a statement
-(only possible for function calls (see <a href="#2.4.6">&sect;2.4.6</a>)),
+(only possible for function calls (see <a href="#3.3.6">&sect;3.3.6</a>)),
then its return list is adjusted to zero elements,
thus discarding all returned values.
If an expression is used as the last (or the only) element
@@ -986,14 +1708,14 @@ or <b>nil</b> if <code>f</code> does not return any values.)
-<h3>2.5.1 - <a name="2.5.1">Arithmetic Operators</a></h3><p>
+<h3>3.4.1 - <a name="3.4.1">Arithmetic Operators</a></h3><p>
Lua supports the usual arithmetic operators:
the binary <code>+</code> (addition),
<code>-</code> (subtraction), <code>*</code> (multiplication),
<code>/</code> (division), <code>%</code> (modulo), and <code>^</code> (exponentiation);
and unary <code>-</code> (negation).
If the operands are numbers, or strings that can be converted to
-numbers (see <a href="#2.2.1">&sect;2.2.1</a>),
+numbers (see <a href="#3.4.2">&sect;3.4.2</a>),
then all operations have the usual meaning.
Exponentiation works for any exponent.
For instance, <code>x^(-0.5)</code> computes the inverse of the square root of <code>x</code>.
@@ -1009,7 +1731,24 @@ the quotient towards minus infinity.
-<h3>2.5.2 - <a name="2.5.2">Relational Operators</a></h3><p>
+<h3>3.4.2 - <a name="3.4.2">Coercion</a></h3>
+
+<p>
+Lua provides automatic conversion between
+string and number values at run time.
+Any arithmetic operation applied to a string tries to convert
+this string to a number, following the usual conversion rules.
+Conversely, whenever a number is used where a string is expected,
+the number is converted to a string, in a reasonable format.
+For complete control over how numbers are converted to strings,
+use the <code>format</code> function from the string library
+(see <a href="#pdf-string.format"><code>string.format</code></a>).
+
+
+
+
+
+<h3>3.4.3 - <a name="3.4.3">Relational Operators</a></h3><p>
The relational operators in Lua are
<pre>
@@ -1033,11 +1772,11 @@ this new object is different from any previously existing object.
<p>
You can change the way that Lua compares tables and userdata
-by using the "eq" metamethod (see <a href="#2.8">&sect;2.8</a>).
+by using the "eq" metamethod (see <a href="#2.4">&sect;2.4</a>).
<p>
-The conversion rules of <a href="#2.2.1">&sect;2.2.1</a>
+The conversion rules of <a href="#3.4.2">&sect;3.4.2</a>
<em>do not</em> apply to equality comparisons.
Thus, <code>"0"==0</code> evaluates to <b>false</b>,
and <code>t[0]</code> and <code>t["0"]</code> denote different
@@ -1054,7 +1793,7 @@ If both arguments are numbers, then they are compared as such.
Otherwise, if both arguments are strings,
then their values are compared according to the current locale.
Otherwise, Lua tries to call the "lt" or the "le"
-metamethod (see <a href="#2.8">&sect;2.8</a>).
+metamethod (see <a href="#2.4">&sect;2.4</a>).
A comparison <code>a &gt; b</code> is translated to <code>b &lt; a</code>
and <code>a &gt;= b</code> is translated to <code>b &lt;= a</code>.
@@ -1062,10 +1801,10 @@ and <code>a &gt;= b</code> is translated to <code>b &lt;= a</code>.
-<h3>2.5.3 - <a name="2.5.3">Logical Operators</a></h3><p>
+<h3>3.4.4 - <a name="3.4.4">Logical Operators</a></h3><p>
The logical operators in Lua are
<b>and</b>, <b>or</b>, and <b>not</b>.
-Like the control structures (see <a href="#2.4.4">&sect;2.4.4</a>),
+Like the control structures (see <a href="#3.3.4">&sect;3.3.4</a>),
all logical operators consider both <b>false</b> and <b>nil</b> as false
and anything else as true.
@@ -1100,18 +1839,18 @@ Here are some examples:
-<h3>2.5.4 - <a name="2.5.4">Concatenation</a></h3><p>
+<h3>3.4.5 - <a name="3.4.5">Concatenation</a></h3><p>
The string concatenation operator in Lua is
denoted by two dots ('<code>..</code>').
If both operands are strings or numbers, then they are converted to
-strings according to the rules mentioned in <a href="#2.2.1">&sect;2.2.1</a>.
-Otherwise, the "concat" metamethod is called (see <a href="#2.8">&sect;2.8</a>).
+strings according to the rules mentioned in <a href="#3.4.2">&sect;3.4.2</a>.
+Otherwise, the "concat" metamethod is called (see <a href="#2.4">&sect;2.4</a>).
-<h3>2.5.5 - <a name="2.5.5">The Length Operator</a></h3>
+<h3>3.4.6 - <a name="3.4.6">The Length Operator</a></h3>
<p>
The length operator is denoted by the unary prefix operator <code>#</code>.
@@ -1139,13 +1878,13 @@ the array).
<p>
A program can modify the behavior of the length operator for
-any value but strings through metamethods (see <a href="#2.8">&sect;2.8</a>).
+any value but strings through metamethods (see <a href="#2.4">&sect;2.4</a>).
-<h3>2.5.6 - <a name="2.5.6">Precedence</a></h3><p>
+<h3>3.4.7 - <a name="3.4.7">Precedence</a></h3><p>
Operator precedence in Lua follows the table below,
from lower to higher priority:
@@ -1169,7 +1908,7 @@ All other binary operators are left associative.
-<h3>2.5.7 - <a name="2.5.7">Table Constructors</a></h3><p>
+<h3>3.4.8 - <a name="3.4.8">Table Constructors</a></h3><p>
Table constructors are expressions that create tables.
Every time a constructor is evaluated, a new table is created.
A constructor can be used to create an empty table
@@ -1177,10 +1916,10 @@ or to create a table and initialize some of its fields.
The general syntax for constructors is
<pre>
- tableconstructor ::= `<b>{</b>&acute; [fieldlist] `<b>}</b>&acute;
+ tableconstructor ::= &lsquo<b>{</b>&rsquo; [fieldlist] &lsquo<b>}</b>&rsquo;
fieldlist ::= field {fieldsep field} [fieldsep]
- field ::= `<b>[</b>&acute; exp `<b>]</b>&acute; `<b>=</b>&acute; exp | Name `<b>=</b>&acute; exp | exp
- fieldsep ::= `<b>,</b>&acute; | `<b>;</b>&acute;
+ field ::= &lsquo<b>[</b>&rsquo; exp &lsquo<b>]</b>&rsquo; &lsquo<b>=</b>&rsquo; exp | Name &lsquo<b>=</b>&rsquo; exp | exp
+ fieldsep ::= &lsquo<b>,</b>&rsquo; | &lsquo<b>;</b>&rsquo;
</pre>
<p>
@@ -1217,10 +1956,10 @@ is equivalent to
If the last field in the list has the form <code>exp</code>
and the expression is a function call or a vararg expression,
then all values returned by this expression enter the list consecutively
-(see <a href="#2.5.8">&sect;2.5.8</a>).
+(see <a href="#3.4.9">&sect;3.4.9</a>).
To avoid this,
enclose the function call or the vararg expression
-in parentheses (see <a href="#2.5">&sect;2.5</a>).
+in parentheses (see <a href="#3.4">&sect;3.4</a>).
<p>
@@ -1231,7 +1970,7 @@ as a convenience for machine-generated code.
-<h3>2.5.8 - <a name="2.5.8">Function Calls</a></h3><p>
+<h3>3.4.9 - <a name="3.4.9">Function Calls</a></h3><p>
A function call in Lua has the following syntax:
<pre>
@@ -1245,14 +1984,14 @@ with the given arguments.
Otherwise, the prefixexp "call" metamethod is called,
having as first parameter the value of prefixexp,
followed by the original call arguments
-(see <a href="#2.8">&sect;2.8</a>).
+(see <a href="#2.4">&sect;2.4</a>).
<p>
The form
<pre>
- functioncall ::= prefixexp `<b>:</b>&acute; Name args
+ functioncall ::= prefixexp &lsquo<b>:</b>&rsquo; Name args
</pre><p>
can be used to call "methods".
A call <code>v:name(<em>args</em>)</code>
@@ -1264,7 +2003,7 @@ except that <code>v</code> is evaluated only once.
Arguments have the following syntax:
<pre>
- args ::= `<b>(</b>&acute; [explist] `<b>)</b>&acute;
+ args ::= &lsquo<b>(</b>&rsquo; [explist] &lsquo<b>)</b>&rsquo;
args ::= tableconstructor
args ::= String
</pre><p>
@@ -1279,23 +2018,6 @@ that is, the argument list is a single literal string.
<p>
-As an exception to the free-form character of Lua,
-you cannot put a line break before the '<code>(</code>' in a function call.
-This restriction avoids some ambiguities in the language.
-If you write
-
-<pre>
- a = f
- (g).x(a)
-</pre><p>
-Lua would see that as a single statement, <code>a = f(g).x(a)</code>.
-In this case, if you want two statements,
-you must add a semi-colon between them.
-If you actually want to call <code>f</code>,
-you must remove the line break before <code>(g)</code>.
-
-
-<p>
A call of the form <code>return</code> <em>functioncall</em> is called
a <em>tail call</em>.
Lua implements <em>proper tail calls</em>
@@ -1323,14 +2045,14 @@ So, none of the following examples are tail calls:
-<h3>2.5.9 - <a name="2.5.9">Function Definitions</a></h3>
+<h3>3.4.10 - <a name="3.4.10">Function Definitions</a></h3>
<p>
The syntax for function definition is
<pre>
function ::= <b>function</b> funcbody
- funcbody ::= `<b>(</b>&acute; [parlist] `<b>)</b>&acute; block <b>end</b>
+ funcbody ::= &lsquo<b>(</b>&rsquo; [parlist] &lsquo<b>)</b>&rsquo; block <b>end</b>
</pre>
<p>
@@ -1339,7 +2061,7 @@ The following syntactic sugar simplifies function definitions:
<pre>
stat ::= <b>function</b> funcname funcbody
stat ::= <b>local</b> <b>function</b> Name funcbody
- funcname ::= Name {`<b>.</b>&acute; Name} [`<b>:</b>&acute; Name]
+ funcname ::= Name {&lsquo<b>.</b>&rsquo; Name} [&lsquo<b>:</b>&rsquo; Name]
</pre><p>
The statement
@@ -1399,7 +2121,7 @@ Parameters act as local variables that are
initialized with the argument values:
<pre>
- parlist ::= namelist [`<b>,</b>&acute; `<b>...</b>&acute;] | `<b>...</b>&acute;
+ parlist ::= namelist [&lsquo<b>,</b>&rsquo; &lsquo<b>...</b>&rsquo;] | &lsquo<b>...</b>&rsquo;
</pre><p>
When a function is called,
the list of arguments is adjusted to
@@ -1448,7 +2170,7 @@ to the vararg expression:
</pre>
<p>
-Results are returned using the <b>return</b> statement (see <a href="#2.4.4">&sect;2.4.4</a>).
+Results are returned using the <b>return</b> statement (see <a href="#3.3.4">&sect;3.3.4</a>).
If control reaches the end of a function
without encountering a <b>return</b> statement,
then the function returns with no results.
@@ -1474,7 +2196,7 @@ is syntactic sugar for
-<h2>2.6 - <a name="2.6">Visibility Rules</a></h2>
+<h2>3.5 - <a name="3.5">Visibility Rules</a></h2>
<p>
@@ -1536,767 +2258,7 @@ while all of them share the same <code>x</code>.
-<h2>2.7 - <a name="2.7">Error Handling</a></h2>
-
-<p>
-Because Lua is an embedded extension language,
-all Lua actions start from C&nbsp;code in the host program
-calling a function from the Lua library (see <a href="#lua_pcall"><code>lua_pcall</code></a>).
-Whenever an error occurs during Lua compilation or execution,
-control returns to C,
-which can take appropriate measures
-(such as printing an error message).
-
-
-<p>
-Lua code can explicitly generate an error by calling the
-<a href="#pdf-error"><code>error</code></a> function.
-If you need to catch errors in Lua,
-you can use the <a href="#pdf-pcall"><code>pcall</code></a> function.
-
-
-
-
-
-<h2>2.8 - <a name="2.8">Metatables</a></h2>
-
-<p>
-Every value in Lua can have a <em>metatable</em>.
-This <em>metatable</em> is an ordinary Lua table
-that defines the behavior of the original value
-under certain special operations.
-You can change several aspects of the behavior
-of operations over a value by setting specific fields in its metatable.
-For instance, when a non-numeric value is the operand of an addition,
-Lua checks for a function in the field <code>"__add"</code> in its metatable.
-If it finds one,
-Lua calls this function to perform the addition.
-
-
-<p>
-We call the keys in a metatable <em>events</em>
-and the values <em>metamethods</em>.
-In the previous example, the event is <code>"add"</code>
-and the metamethod is the function that performs the addition.
-
-
-<p>
-You can query the metatable of any value
-through the <a href="#pdf-getmetatable"><code>getmetatable</code></a> function.
-
-
-<p>
-You can replace the metatable of tables
-through the <a href="#pdf-setmetatable"><code>setmetatable</code></a>
-function.
-You cannot change the metatable of other types from Lua
-(except by using the debug library);
-you must use the C&nbsp;API for that.
-
-
-<p>
-Tables and full userdata have individual metatables
-(although multiple tables and userdata can share their metatables).
-Values of all other types share one single metatable per type;
-that is, there is one single metatable for all numbers,
-one for all strings, etc.
-By default, a value has no metatable,
-but the string library sets a metatable for the string type (see <a href="#5.4">&sect;5.4</a>).
-
-
-<p>
-A metatable controls how an object behaves in arithmetic operations,
-order comparisons, concatenation, length operation, and indexing.
-A metatable also can define a function to be called when a userdata
-is garbage collected.
-For each of these operations Lua associates a specific key
-called an <em>event</em>.
-When Lua performs one of these operations over a value,
-it checks whether this value has a metatable with the corresponding event.
-If so, the value associated with that key (the metamethod)
-controls how Lua will perform the operation.
-
-
-<p>
-Metatables control the operations listed next.
-Each operation is identified by its corresponding name.
-The key for each operation is a string with its name prefixed by
-two underscores, '<code>__</code>';
-for instance, the key for operation "add" is the
-string <code>"__add"</code>.
-The semantics of these operations is better explained by a Lua function
-describing how the interpreter executes the operation.
-
-
-<p>
-The code shown here in Lua is only illustrative;
-the real behavior is hard coded in the interpreter
-and it is much more efficient than this simulation.
-All functions used in these descriptions
-(<a href="#pdf-rawget"><code>rawget</code></a>, <a href="#pdf-tonumber"><code>tonumber</code></a>, etc.)
-are described in <a href="#5.1">&sect;5.1</a>.
-In particular, to retrieve the metamethod of a given object,
-we use the expression
-
-<pre>
- metatable(obj)[event]
-</pre><p>
-This should be read as
-
-<pre>
- rawget(getmetatable(obj) or {}, event)
-</pre><p>
-
-That is, the access to a metamethod does not invoke other metamethods,
-and the access to objects with no metatables does not fail
-(it simply results in <b>nil</b>).
-
-
-
-<ul>
-
-<li><b>"add":</b>
-the <code>+</code> operation.
-
-
-
-<p>
-The function <code>getbinhandler</code> below defines how Lua chooses a handler
-for a binary operation.
-First, Lua tries the first operand.
-If its type does not define a handler for the operation,
-then Lua tries the second operand.
-
-<pre>
- function getbinhandler (op1, op2, event)
- return metatable(op1)[event] or metatable(op2)[event]
- end
-</pre><p>
-By using this function,
-the behavior of the <code>op1 + op2</code> 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 h = getbinhandler(op1, op2, "__add")
- if h then
- -- call the handler with both operands
- return (h(op1, op2))
- else -- no handler available: default behavior
- error(&middot;&middot;&middot;)
- end
- end
- end
-</pre><p>
-</li>
-
-<li><b>"sub":</b>
-the <code>-</code> operation.
-
-Behavior similar to the "add" operation.
-</li>
-
-<li><b>"mul":</b>
-the <code>*</code> operation.
-
-Behavior similar to the "add" operation.
-</li>
-
-<li><b>"div":</b>
-the <code>/</code> operation.
-
-Behavior similar to the "add" operation.
-</li>
-
-<li><b>"mod":</b>
-the <code>%</code> operation.
-
-Behavior similar to the "add" operation,
-with the operation
-<code>o1 - floor(o1/o2)*o2</code> as the primitive operation.
-</li>
-
-<li><b>"pow":</b>
-the <code>^</code> (exponentiation) operation.
-
-Behavior similar to the "add" operation,
-with the function <code>pow</code> (from the C&nbsp;math library)
-as the primitive operation.
-</li>
-
-<li><b>"unm":</b>
-the unary <code>-</code> operation.
-
-
-<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 handler from the operand
- local h = metatable(op).__unm
- if h then
- -- call the handler with the operand
- return (h(op))
- else -- no handler available: default behavior
- error(&middot;&middot;&middot;)
- end
- end
- end
-</pre><p>
-</li>
-
-<li><b>"concat":</b>
-the <code>..</code> (concatenation) operation.
-
-
-<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 h = getbinhandler(op1, op2, "__concat")
- if h then
- return (h(op1, op2))
- else
- error(&middot;&middot;&middot;)
- end
- end
- end
-</pre><p>
-</li>
-
-<li><b>"len":</b>
-the <code>#</code> operation.
-
-
-<pre>
- function len_event (op)
- if type(op) == "string" then
- return strlen(op) -- primitive string length
- else
- local h = metatable(op).__len
- if h then
- return (h(op)) -- call handler with the operand
- elseif type(op) == "table" then
- return #op -- primitive table length
- else -- no handler available: error
- error(&middot;&middot;&middot;)
- end
- end
- end
-</pre><p>
-See <a href="#2.5.5">&sect;2.5.5</a> for a description of the length of a table.
-</li>
-
-<li><b>"eq":</b>
-the <code>==</code> operation.
-
-The function <code>getcomphandler</code> defines how Lua chooses a metamethod
-for comparison operators.
-A metamethod only is selected when both objects
-being compared have the same type
-and the same metamethod for the selected operation.
-
-<pre>
- function getcomphandler (op1, op2, event)
- if type(op1) ~= type(op2) then return nil end
- local mm1 = metatable(op1)[event]
- local mm2 = metatable(op2)[event]
- if mm1 == mm2 then return mm1 else return nil end
- end
-</pre><p>
-The "eq" event is defined as follows:
-
-<pre>
- function eq_event (op1, op2)
- if type(op1) ~= type(op2) then -- different types?
- return false -- different objects
- end
- if op1 == op2 then -- primitive equal?
- return true -- objects are equal
- end
- -- try metamethod
- local h = getcomphandler(op1, op2, "__eq")
- if h then
- return (h(op1, op2))
- else
- return false
- end
- end
-</pre><p>
-<code>a ~= b</code> is equivalent to <code>not (a == b)</code>.
-</li>
-
-<li><b>"lt":</b>
-the <code>&lt;</code> operation.
-
-
-<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 h = getcomphandler(op1, op2, "__lt")
- if h then
- return (h(op1, op2))
- else
- error(&middot;&middot;&middot;)
- end
- end
- end
-</pre><p>
-<code>a &gt; b</code> is equivalent to <code>b &lt; a</code>.
-</li>
-
-<li><b>"le":</b>
-the <code>&lt;=</code> operation.
-
-
-<pre>
- function le_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 h = getcomphandler(op1, op2, "__le")
- if h then
- return (h(op1, op2))
- else
- h = getcomphandler(op1, op2, "__lt")
- if h then
- return not h(op2, op1)
- else
- error(&middot;&middot;&middot;)
- end
- end
- end
- end
-</pre><p>
-<code>a &gt;= b</code> is equivalent to <code>b &lt;= a</code>.
-Note that, in the absence of a "le" metamethod,
-Lua tries the "lt", assuming that <code>a &lt;= b</code> is
-equivalent to <code>not (b &lt; a)</code>.
-</li>
-
-<li><b>"index":</b>
-The indexing access <code>table[key]</code>.
-
-
-<pre>
- function gettable_event (table, key)
- local h
- if type(table) == "table" then
- local v = rawget(table, key)
- if v ~= nil then return v end
- h = metatable(table).__index
- if h == nil then return nil end
- else
- h = metatable(table).__index
- if h == nil then
- error(&middot;&middot;&middot;)
- end
- end
- if type(h) == "function" then
- return (h(table, key)) -- call the handler
- else return h[key] -- or repeat operation on it
- end
- end
-</pre><p>
-</li>
-
-<li><b>"newindex":</b>
-The indexing assignment <code>table[key] = value</code>.
-
-
-<pre>
- function settable_event (table, key, value)
- local h
- if type(table) == "table" then
- local v = rawget(table, key)
- if v ~= nil then rawset(table, key, value); return end
- h = metatable(table).__newindex
- if h == nil then rawset(table, key, value); return end
- else
- h = metatable(table).__newindex
- if h == nil then
- error(&middot;&middot;&middot;)
- end
- end
- if type(h) == "function" then
- h(table, key,value) -- call the handler
- else h[key] = value -- or repeat operation on it
- end
- end
-</pre><p>
-</li>
-
-<li><b>"call":</b>
-called when Lua calls a value.
-
-
-<pre>
- function function_event (func, ...)
- if type(func) == "function" then
- return func(...) -- primitive call
- else
- local h = metatable(func).__call
- if h then
- return h(func, ...)
- else
- error(&middot;&middot;&middot;)
- end
- end
- end
-</pre><p>
-</li>
-
-</ul>
-
-
-
-
-<h2>2.9 - <a name="2.9">Environments</a></h2>
-
-<p>
-Each function and userdata in Lua
-has a table associated with it,
-called its <em>environment</em>.
-Like metatables, environments are regular tables and
-multiple objects can share the same environment.
->From Lua,
-you can manipulate the environment of an object
-only through the debug library (see <a href="#5.10">&sect;5.10</a>).
-
-
-<p>
-Userdata and C&nbsp;functions are created sharing the environment
-of the creating C&nbsp;function.
-Non-nested Lua functions
-(created by <a href="#pdf-loadfile"><code>loadfile</code></a>, <a href="#pdf-loadstring"><code>loadstring</code></a> or <a href="#pdf-load"><code>load</code></a>)
-are created sharing the global environment.
-Nested Lua functions are created sharing the current environment
-of where it is defined.
-
-
-<p>
-Environments associated with userdata have no meaning for Lua.
-It is only a convenience feature for programmers to associate a table to
-a userdata.
-
-
-<p>
-The environment associated with a C&nbsp;function can be directly
-accessed by C&nbsp;code (see <a href="#3.3">&sect;3.3</a>).
-It is used as the default environment for other C&nbsp;functions
-and userdata created by the function.
-
-
-<p>
-The environment associated with a Lua function is used as the
-current environment of all code in the function outside
-a lexical environment (see <a href="#2.4.8">&sect;2.4.8</a>).
-A lexical environment changes the
-current environment inside its scope.
-In any case,
-the <em>current environment</em> is the table
-Lua uses to resolve global variables and to initialize
-the environment of nested functions.
-
-
-
-
-
-<h2>2.10 - <a name="2.10">Garbage Collection</a></h2>
-
-<p>
-Lua performs automatic memory management.
-This means that
-you have to worry neither about allocating memory for new objects
-nor about freeing it when the objects are no longer needed.
-Lua manages memory automatically by running
-a <em>garbage collector</em> from time to time
-to collect all <em>dead objects</em>
-(that is, objects that are no longer accessible from Lua).
-All memory used by Lua is subject to automatic management:
-tables, userdata, functions, threads, strings, etc.
-
-
-<p>
-Lua implements an incremental mark-and-sweep collector.
-It uses two numbers to control its garbage-collection cycles:
-the <em>garbage-collector pause</em> and
-the <em>garbage-collector step multiplier</em>.
-Both use percentage points as units
-(so that a value of 100 means an internal value of 1).
-
-
-<p>
-The garbage-collector pause
-controls how long the collector waits before starting a new cycle.
-Larger values make the collector less aggressive.
-Values smaller than 100 mean the collector will not wait to
-start a new cycle.
-A value of 200 means that the collector waits for the total memory in use
-to double before starting a new cycle.
-
-
-<p>
-The step multiplier
-controls the relative speed of the collector relative to
-memory allocation.
-Larger values make the collector more aggressive but also increase
-the size of each incremental step.
-Values smaller than 100 make the collector too slow and
-can result in the collector never finishing a cycle.
-The default, 200, means that the collector runs at "twice"
-the speed of memory allocation.
-
-
-<p>
-If you set the step multiplier to a very large number
-(larger than 10% of the maximum number of
-bytes that the program may use),
-the collector behaves like a stop-the-world collector.
-If you then set the pause to 200,
-the collector behaves as in old Lua versions,
-doing a complete collection every time Lua doubles its
-memory usage.
-
-
-<p>
-You can change these numbers by calling <a href="#lua_gc"><code>lua_gc</code></a> in C
-or <a href="#pdf-collectgarbage"><code>collectgarbage</code></a> in Lua.
-With these functions you can also control
-the collector directly (e.g., stop and restart it).
-
-
-
-<h3>2.10.1 - <a name="2.10.1">Garbage-Collection Metamethods</a></h3>
-
-<p>
-Using the C&nbsp;API,
-you can set garbage-collector metamethods for userdata (see <a href="#2.8">&sect;2.8</a>).
-These metamethods are also called <em>finalizers</em>.
-Finalizers allow you to coordinate Lua's garbage collection
-with external resource management
-(such as closing files, network or database connections,
-or freeing your own memory).
-
-
-<p>
-Garbage userdata with a field <code>__gc</code> in their metatables are not
-collected immediately by the garbage collector.
-Instead, Lua puts them in a list.
-After the collection,
-Lua does the equivalent of the following function
-for each userdata in that list:
-
-<pre>
- function gc_event (udata)
- local h = metatable(udata).__gc
- if h then
- h(udata)
- end
- end
-</pre>
-
-<p>
-At the end of each garbage-collection cycle,
-the finalizers for userdata are called in <em>reverse</em>
-order of their creation,
-among those collected in that cycle.
-That is, the first finalizer to be called is the one associated
-with the userdata created last in the program.
-The userdata itself is freed only in the next garbage-collection cycle.
-
-
-
-
-
-<h3>2.10.2 - <a name="2.10.2">Weak Tables</a></h3>
-
-<p>
-A <em>weak table</em> is a table whose elements are
-<em>weak references</em>.
-A weak reference is ignored by the garbage collector.
-In other words,
-if the only references to an object are weak references,
-then the garbage collector will collect this object.
-
-
-<p>
-A weak table can have weak keys, weak values, or both.
-A table with weak keys allows the collection of its keys,
-but prevents the collection of its values.
-A table with both weak keys and weak values allows the collection of
-both keys and values.
-In any case, if either the key or the value is collected,
-the whole pair is removed from the table.
-The weakness of a table is controlled by the
-<code>__mode</code> field of its metatable.
-If the <code>__mode</code> field is a string containing the character&nbsp;'<code>k</code>',
-the keys in the table are weak.
-If <code>__mode</code> contains '<code>v</code>',
-the values in the table are weak.
-
-
-<p>
-Userdata with finalizers has a special behavior in weak tables.
-When a userdata is a value in a weak table,
-it is removed from the table the first time it is collected,
-before running its finalizer.
-When it is a key, however,
-it is removed from the table only when it is really freed,
-after running its finalizer.
-This behavior allows the finalizer to access values
-associated with the userdata through weak tables.
-
-
-<p>
-A table with weak keys and strong values
-is also called an <em>ephemeron table</em>.
-In an ephemeron table,
-a value is considered reachable only if its key is reachable.
-In particular,
-if the only reference to a key comes from its value,
-the pair is removed.
-
-
-<p>
-After you use a table as a metatable,
-you should not change the value of its <code>__mode</code> field.
-Otherwise, the weak behavior of the tables controlled by this
-metatable is undefined.
-
-
-
-
-
-
-
-<h2>2.11 - <a name="2.11">Coroutines</a></h2>
-
-<p>
-Lua supports coroutines,
-also called <em>collaborative multithreading</em>.
-A coroutine in Lua represents an independent thread of execution.
-Unlike threads in multithread systems, however,
-a coroutine only suspends its execution by explicitly calling
-a yield function.
-
-
-<p>
-You create a coroutine with a call to <a href="#pdf-coroutine.create"><code>coroutine.create</code></a>.
-Its sole argument is a function
-that is the main function of the coroutine.
-The <code>create</code> function only creates a new coroutine and
-returns a handle to it (an object of type <em>thread</em>);
-it does not start the coroutine execution.
-
-
-<p>
-When you first call <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>,
-passing as its first argument
-a thread returned by <a href="#pdf-coroutine.create"><code>coroutine.create</code></a>,
-the coroutine starts its execution,
-at the first line of its main function.
-Extra arguments passed to <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> are passed on
-to the coroutine main function.
-After the coroutine starts running,
-it runs until it terminates or <em>yields</em>.
-
-
-<p>
-A coroutine can terminate its execution in two ways:
-normally, when its main function returns
-(explicitly or implicitly, after the last instruction);
-and abnormally, if there is an unprotected error.
-In the first case, <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> returns <b>true</b>,
-plus any values returned by the coroutine main function.
-In case of errors, <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> returns <b>false</b>
-plus an error message.
-
-
-<p>
-A coroutine yields by calling <a href="#pdf-coroutine.yield"><code>coroutine.yield</code></a>.
-When a coroutine yields,
-the corresponding <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> returns immediately,
-even if the yield happens inside nested function calls
-(that is, not in the main function,
-but in a function directly or indirectly called by the main function).
-In the case of a yield, <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> also returns <b>true</b>,
-plus any values passed to <a href="#pdf-coroutine.yield"><code>coroutine.yield</code></a>.
-The next time you resume the same coroutine,
-it continues its execution from the point where it yielded,
-with the call to <a href="#pdf-coroutine.yield"><code>coroutine.yield</code></a> returning any extra
-arguments passed to <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>.
-
-
-<p>
-Like <a href="#pdf-coroutine.create"><code>coroutine.create</code></a>,
-the <a href="#pdf-coroutine.wrap"><code>coroutine.wrap</code></a> function also creates a coroutine,
-but instead of returning the coroutine itself,
-it returns a function that, when called, resumes the coroutine.
-Any arguments passed to this function
-go as extra arguments to <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>.
-<a href="#pdf-coroutine.wrap"><code>coroutine.wrap</code></a> returns all the values returned by <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>,
-except the first one (the boolean error code).
-Unlike <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>,
-<a href="#pdf-coroutine.wrap"><code>coroutine.wrap</code></a> does not catch errors;
-any error is propagated to the caller.
-
-
-<p>
-As an example,
-consider the following code:
-
-<pre>
- function foo (a)
- print("foo", a)
- return coroutine.yield(2*a)
- end
-
- co = coroutine.create(function (a,b)
- print("co-body", a, b)
- local r = foo(a+1)
- print("co-body", r)
- local r, s = coroutine.yield(a+b, a-b)
- print("co-body", r, s)
- return b, "end"
- end)
-
- print("main", coroutine.resume(co, 1, 10))
- print("main", coroutine.resume(co, "r"))
- print("main", coroutine.resume(co, "x", "y"))
- print("main", coroutine.resume(co, "x", "y"))
-</pre><p>
-When you run it, it produces the following output:
-
-<pre>
- co-body 1 10
- foo 2
-
- main true 4
- co-body r
- main true 11 -9
- co-body x y
- main true 10 end
- main false cannot resume dead coroutine
-</pre>
-
-
-
-
-<h1>3 - <a name="3">The Application Program Interface</a></h1>
+<h1>4 - <a name="4">The Application Program Interface</a></h1>
<p>
@@ -2324,7 +2286,7 @@ in file <code>luaconf.h</code>.
-<h2>3.1 - <a name="3.1">The Stack</a></h2>
+<h2>4.1 - <a name="4.1">The Stack</a></h2>
<p>
Lua uses a <em>virtual stack</em> to pass values to and from C.
@@ -2366,7 +2328,7 @@ if it lies between&nbsp;1 and the stack top
-<h2>3.2 - <a name="3.2">Stack Size</a></h2>
+<h2>4.2 - <a name="4.2">Stack Size</a></h2>
<p>
When you interact with Lua API,
@@ -2412,37 +2374,22 @@ Note that 0 is never an acceptable index.
-<h2>3.3 - <a name="3.3">Pseudo-Indices</a></h2>
+<h2>4.3 - <a name="4.3">Pseudo-Indices</a></h2>
<p>
Unless otherwise noted,
any function that accepts valid indices also accepts <em>pseudo-indices</em>,
which represent some Lua values that are accessible to C&nbsp;code
but which are not in the stack.
-Pseudo-indices are used to access the thread environment,
-the function environment,
-the registry,
-and the upvalues of a C&nbsp;function (see <a href="#3.4">&sect;3.4</a>).
+Pseudo-indices are used to access
+the registry
+and the upvalues of a C&nbsp;function (see <a href="#4.4">&sect;4.4</a>).
-<p>
-The environment of the running C&nbsp;function is always
-at pseudo-index <a name="pdf-LUA_ENVIRONINDEX"><code>LUA_ENVIRONINDEX</code></a>.
-<p>
-To access and change the value of global variables,
-you can use regular table operations over an environment table.
-For instance, to access the value of a global variable, do
-
-<pre>
- lua_getfield(L, LUA_ENVIRONINDEX, varname);
-</pre>
-
-
-
-<h2>3.4 - <a name="3.4">C Closures</a></h2>
+<h2>4.4 - <a name="4.4">C Closures</a></h2>
<p>
When a C&nbsp;function is created,
@@ -2469,7 +2416,7 @@ produces an acceptable (but invalid) index.
-<h2>3.5 - <a name="3.5">Registry</a></h2>
+<h2>4.5 - <a name="4.5">Registry</a></h2>
<p>
Lua provides a <em>registry</em>,
@@ -2503,29 +2450,6 @@ The following constants are defined:
the main thread of the state.
(The main thread is the one created together with the state.)
</li>
-<li><b>LUA_RIDX_CPCALL:</b> At this index the registry has
-the <a name="pdf-cpcall"><code>cpcall</code></a> function.
-This function allows you to call any
-<a href="#lua_CFunction"><code>lua_CFunction</code></a> without creating a closure for it,
-therefore preventing an unprotected memory allocation error.
-
-
-<p>
-The address of the function to be called must be stored in a variable,
-whose address is passed as the first argument to <code>cpcall</code>,
-as a light userdata.
-Note that the light userdata in the first argument should not
-point to the function to be called,
-but to a variable containing the pointer to the function.
-ANSI&nbsp;C does not allow the direct assignment of a function address to
-the <code>void*</code> in a light userdata.
-
-
-<p>
-Other arguments to <code>cpcall</code> are passed to the called function.
-The <code>cpcall</code> function itself should be called with <a href="#lua_pcall"><code>lua_pcall</code></a>,
-like any C function.
-</li>
<li><b>LUA_RIDX_GLOBALS:</b> At this index the registry has
the global environment.
@@ -2536,7 +2460,7 @@ This is the C&nbsp;equivalent to the <a href="#pdf-_G"><code>_G</code></a> globa
-<h2>3.6 - <a name="3.6">Error Handling in C</a></h2>
+<h2>4.6 - <a name="4.6">Error Handling in C</a></h2>
<p>
Internally, Lua uses the C <code>longjmp</code> facility to handle errors.
@@ -2575,7 +2499,7 @@ Inside a C&nbsp;function you can throw an error by calling <a href="#lua_error">
-<h2>3.7 - <a name="3.7">Handling Yields in C</a></h2>
+<h2>4.7 - <a name="4.7">Handling Yields in C</a></h2>
<p>
Internally, Lua uses the C <code>longjmp</code> facility to yield a coroutine.
@@ -2600,10 +2524,10 @@ To explain continuations,
let us set some terminology.
We have a C function called from Lua which we will call
the <em>original function</em>.
-This original function may call one of those three functions in the C API,
+This original function then calls one of those three functions in the C API,
which we will call the <em>callee function</em>,
-that may yield the current thread.
-(This will happen when the callee function is <a href="#lua_yieldk"><code>lua_yieldk</code></a>,
+that then yields the current thread.
+(This can happen when the callee function is <a href="#lua_yieldk"><code>lua_yieldk</code></a>,
or when the callee function is either <a href="#lua_callk"><code>lua_callk</code></a> or <a href="#lua_pcallk"><code>lua_pcallk</code></a>
and the function called by them yields.)
@@ -2643,7 +2567,7 @@ and its continuation is the result of a call to <a href="#lua_getctx"><code>lua_
-<h2>3.8 - <a name="3.8">Functions and Types</a></h2>
+<h2>4.8 - <a name="4.8">Functions and Types</a></h2>
<p>
Here we list all functions and types from the C&nbsp;API in
@@ -2675,6 +2599,18 @@ only due to not enough memory;
+<hr><h3><a name="lua_absindex"><code>lua_absindex</code></a></h3><p>
+<span class="apii">[-0, +0, <em>-</em>]</span>
+<pre>void lua_absindex (lua_State *L, int idx);</pre>
+
+<p>
+Converts the acceptable index <code>idx</code> into an absolute index
+(that is, one that does not depend on the stack top).
+
+
+
+
+
<hr><h3><a name="lua_Alloc"><code>lua_Alloc</code></a></h3>
<pre>typedef void * (*lua_Alloc) (void *ud,
void *ptr,
@@ -2768,12 +2704,12 @@ but it seems a safe assumption.)
<pre>lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);</pre>
<p>
-Sets a new panic function and returns the old one (see <a href="#3.6">&sect;3.6</a>).
+Sets a new panic function and returns the old one (see <a href="#4.6">&sect;4.6</a>).
<p>
The panic function should not try to run anything on the failed Lua state.
-However, it can still use the debug API (see <a href="#3.9">&sect;3.9</a>)
+However, it can still use the debug API (see <a href="#4.9">&sect;4.9</a>)
to gather information about the state.
In particular, the error message is at the top of the stack.
@@ -2824,14 +2760,14 @@ equivalent to this Lua code:
Here it is in&nbsp;C:
<pre>
- lua_getfield(L, LUA_ENVIRONINDEX, "f"); /* function to be called */
+ lua_getglobal(L, "f"); /* function to be called */
lua_pushstring(L, "how"); /* 1st argument */
- lua_getfield(L, LUA_ENVIRONINDEX, "t"); /* table to be indexed */
+ lua_getglobal(L, "t"); /* table to be indexed */
lua_getfield(L, -1, "x"); /* push result of t.x (2nd arg) */
lua_remove(L, -2); /* remove 't' from the stack */
lua_pushinteger(L, 14); /* 3rd argument */
lua_call(L, 3, 1); /* call 'f' with 3 arguments and 1 result */
- lua_setfield(L, LUA_ENVIRONINDEX, "a"); /* set global 'a' */
+ lua_setglobal(L, "a"); /* set global 'a' */
</pre><p>
Note that the code above is "balanced":
at its end, the stack is back to its original configuration.
@@ -2848,7 +2784,7 @@ This is considered good programming practice.
<p>
This function behaves exactly like <a href="#lua_call"><code>lua_call</code></a>,
-but allows the called function to yield (see <a href="#3.7">&sect;3.7</a>).
+but allows the called function to yield (see <a href="#4.7">&sect;4.7</a>).
@@ -2980,7 +2916,7 @@ If <code>n</code>&nbsp;is&nbsp;1, the result is the single value on the stack
(that is, the function does nothing);
if <code>n</code> is 0, the result is the empty string.
Concatenation is performed following the usual semantics of Lua
-(see <a href="#2.5.4">&sect;2.5.4</a>).
+(see <a href="#3.4.5">&sect;3.4.5</a>).
@@ -3108,13 +3044,13 @@ garbage-collection cycle.
<li><b><code>LUA_GCSETPAUSE</code>:</b>
sets <code>data</code> as the new value
-for the <em>pause</em> of the collector (see <a href="#2.10">&sect;2.10</a>).
+for the <em>pause</em> of the collector (see <a href="#2.5">&sect;2.5</a>).
The function returns the previous value of the pause.
</li>
<li><b><code>LUA_GCSETSTEPMUL</code>:</b>
sets <code>data</code> as the new value for the <em>step multiplier</em> of
-the collector (see <a href="#2.10">&sect;2.10</a>).
+the collector (see <a href="#2.5">&sect;2.5</a>).
The function returns the previous value of the step multiplier.
</li>
@@ -3146,7 +3082,7 @@ opaque pointer passed to <a href="#lua_newstate"><code>lua_newstate</code></a>.
<pre>int lua_getctx (lua_State *L, int *ctx);</pre>
<p>
-This function is called by a continuation function (see <a href="#3.7">&sect;3.7</a>)
+This function is called by a continuation function (see <a href="#4.7">&sect;4.7</a>)
to retrieve the status of the thread and a context information.
@@ -3197,7 +3133,7 @@ the value at the given index.
Pushes onto the stack the value <code>t[k]</code>,
where <code>t</code> is the value at the given valid index.
As in Lua, this function may trigger a metamethod
-for the "index" event (see <a href="#2.8">&sect;2.8</a>).
+for the "index" event (see <a href="#2.4">&sect;2.4</a>).
@@ -3209,11 +3145,8 @@ for the "index" event (see <a href="#2.8">&sect;2.8</a>).
<p>
Pushes onto the stack the value of the global <code>name</code>.
-It is defined as a macro:
+It is defined as a macro.
-<pre>
- #define lua_getglobal(L,s) lua_getfield(L, LUA_ENVIRONINDEX, s)
-</pre>
@@ -3247,7 +3180,7 @@ and <code>k</code> is the value at the top of the stack.
This function pops the key from the stack
(putting the resulting value in its place).
As in Lua, this function may trigger a metamethod
-for the "index" event (see <a href="#2.8">&sect;2.8</a>).
+for the "index" event (see <a href="#2.4">&sect;2.4</a>).
@@ -3452,7 +3385,7 @@ Returns 1 if the value at the given acceptable index is a userdata
<p>
Returns the "length" of the value at the given acceptable index;
-it is equivalent to the '<code>#</code>' operator in Lua (see <a href="#2.5.5">&sect;2.5.5</a>).
+it is equivalent to the '<code>#</code>' operator in Lua (see <a href="#3.4.6">&sect;3.4.6</a>).
The result is pushed on the stack.
@@ -3510,7 +3443,15 @@ The <code>data</code> argument is an opaque value passed to the reader function.
<p>
The <code>source</code> argument gives a name to the chunk,
-which is used for error messages and in debug information (see <a href="#3.9">&sect;3.9</a>).
+which is used for error messages and in debug information (see <a href="#4.9">&sect;4.9</a>).
+
+
+<p>
+If the resulting function has upvalues,
+the first upvalue is set to the value of the global environment
+stored at index <code>LUA_RIDX_GLOBALS</code> in the registry (see <a href="#4.5">&sect;4.5</a>).
+(When loading main chunks,
+this upvalue will be the <code>_ENV</code> variable (see <a href="#2.2">&sect;2.2</a>).)
@@ -3729,7 +3670,7 @@ It is generated by the garbage collector.)
<p>
This function behaves exactly like <a href="#lua_pcall"><code>lua_pcall</code></a>,
-but allows the called function to yield (see <a href="#3.7">&sect;3.7</a>).
+but allows the called function to yield (see <a href="#4.7">&sect;4.7</a>).
@@ -3768,7 +3709,7 @@ Pushes a new C&nbsp;closure onto the stack.
<p>
When a C&nbsp;function is created,
it is possible to associate some values with it,
-thus creating a C&nbsp;closure (see <a href="#3.4">&sect;3.4</a>);
+thus creating a C&nbsp;closure (see <a href="#4.4">&sect;4.4</a>);
these values are then accessible to the function whenever it is called.
To associate values with a C&nbsp;function,
first these values should be pushed onto the stack
@@ -3784,11 +3725,18 @@ associated with the function.
The maximum value for <code>n</code> is 255.
+<p>
+When <code>n</code> is zero,
+this function creates a <em>light C function</em>,
+which is just a pointer to the C&nbsp;function.
+In that case, it cannot throw a memory error.
+
+
<hr><h3><a name="lua_pushcfunction"><code>lua_pushcfunction</code></a></h3><p>
-<span class="apii">[-0, +1, <em>m</em>]</span>
+<span class="apii">[-0, +1, <em>-</em>]</span>
<pre>void lua_pushcfunction (lua_State *L, lua_CFunction f);</pre>
<p>
@@ -3946,7 +3894,7 @@ onto the stack.
Lua makes (or reuses) an internal copy of the given string,
so the memory at <code>s</code> can be freed or reused immediately after
the function returns.
-The string cannot contain embedded zeros;
+The string should not contain embedded zeros;
it is assumed to end at the first zero.
@@ -3954,6 +3902,10 @@ it is assumed to end at the first zero.
Returns a pointer to the internal copy of the string.
+<p>
+If <code>s</code> is <code>NULL</code>, pushes <b>nil</b> and returns <code>NULL</code>.
+
+
@@ -4232,7 +4184,7 @@ and <code>v</code> is the value at the top of the stack.
<p>
This function pops the value from the stack.
As in Lua, this function may trigger a metamethod
-for the "newindex" event (see <a href="#2.8">&sect;2.8</a>).
+for the "newindex" event (see <a href="#2.4">&sect;2.4</a>).
@@ -4245,11 +4197,8 @@ for the "newindex" event (see <a href="#2.8">&sect;2.8</a>).
<p>
Pops a value from the stack and
sets it as the new value of global <code>name</code>.
-It is defined as a macro:
+It is defined as a macro.
-<pre>
- #define lua_setglobal(L,s) lua_setfield(L, LUA_ENVIRONINDEX, s)
-</pre>
@@ -4281,7 +4230,7 @@ and <code>k</code> is the value just below the top.
<p>
This function pops both the key and the value from the stack.
As in Lua, this function may trigger a metamethod
-for the "newindex" event (see <a href="#2.8">&sect;2.8</a>).
+for the "newindex" event (see <a href="#2.4">&sect;2.4</a>).
@@ -4379,7 +4328,7 @@ otherwise, returns <code>NULL</code>.
Converts the Lua value at the given acceptable index
to the signed integral type <a href="#lua_Integer"><code>lua_Integer</code></a>.
The Lua value must be a number or a string convertible to a number
-(see <a href="#2.2.1">&sect;2.2.1</a>);
+(see <a href="#3.4.2">&sect;3.4.2</a>);
otherwise, <a href="#lua_tointeger"><code>lua_tointeger</code></a> returns&nbsp;0.
@@ -4430,7 +4379,7 @@ will be valid after the corresponding value is removed from the stack.
Converts the Lua value at the given acceptable index
to the C&nbsp;type <a href="#lua_Number"><code>lua_Number</code></a> (see <a href="#lua_Number"><code>lua_Number</code></a>).
The Lua value must be a number or a string convertible to a number
-(see <a href="#2.2.1">&sect;2.2.1</a>);
+(see <a href="#3.4.2">&sect;3.4.2</a>);
otherwise, <a href="#lua_tonumber"><code>lua_tonumber</code></a> returns&nbsp;0.
@@ -4596,7 +4545,7 @@ and pushes them onto the stack <code>to</code>.
<p>
This function is equivalent to <a href="#lua_yieldk"><code>lua_yieldk</code></a>,
-but it has no continuation (see <a href="#3.7">&sect;3.7</a>).
+but it has no continuation (see <a href="#4.7">&sect;4.7</a>).
Therefore, when the thread resumes,
it returns to the function that called
the function calling <code>lua_yield</code>.
@@ -4631,7 +4580,7 @@ that are passed as results to <a href="#lua_resume"><code>lua_resume</code></a>.
<p>
When the coroutine is resumed again,
Lua calls the given continuation function <code>k</code> to continue
-the execution of the C function that yielded (see <a href="#3.7">&sect;3.7</a>).
+the execution of the C function that yielded (see <a href="#4.7">&sect;4.7</a>).
This continuation function receives the same stack
from the previous function,
with the results removed and
@@ -4646,7 +4595,7 @@ by calling <a href="#lua_getctx"><code>lua_getctx</code></a>.
-<h2>3.9 - <a name="3.9">The Debug Interface</a></h2>
+<h2>4.9 - <a name="4.9">The Debug Interface</a></h2>
<p>
Lua has no built-in debugging facilities.
@@ -4830,7 +4779,7 @@ you can write the following code:
<pre>
lua_Debug ar;
- lua_getfield(L, LUA_ENVIRONINDEX, "f"); /* get global 'f' */
+ lua_getglobal(L, "f"); /* get global 'f' */
lua_getinfo(L, "&gt;S", &amp;ar);
printf("%d\n", ar.linedefined);
</pre>
@@ -5126,7 +5075,7 @@ TO BE DONE!!
-<h1>4 - <a name="4">The Auxiliary Library</a></h1>
+<h1>5 - <a name="5">The Auxiliary Library</a></h1>
<p>
@@ -5151,6 +5100,14 @@ and so they provide nothing that cannot be done with that API.
<p>
+Several functions in the auxiliary library use internally some
+extra stack slots.
+When a function in the auxiliary library uses less than five slots,
+it does not check the stack size;
+it simply assumes that there are enough slots.
+
+
+<p>
Several functions in the auxiliary library are used to
check C&nbsp;function arguments.
Because the error message is formatted for arguments
@@ -5164,7 +5121,7 @@ always throw an error if the check is not satisfied.
-<h2>4.1 - <a name="4.1">Functions and Types</a></h2>
+<h2>5.1 - <a name="5.1">Functions and Types</a></h2>
<p>
Here we list all functions and types from the auxiliary library
@@ -5192,7 +5149,7 @@ Adds the character <code>c</code> to the buffer <code>B</code>
Adds the string pointed to by <code>s</code> with length <code>l</code> to
the buffer <code>B</code>
(see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>).
-The string may contain embedded zeros.
+The string can contain embedded zeros.
@@ -5219,7 +5176,7 @@ buffer area (see <a href="#luaL_prepbuffer"><code>luaL_prepbuffer</code></a>).
Adds the zero-terminated string pointed to by <code>s</code>
to the buffer <code>B</code>
(see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>).
-The string may not contain embedded zeros.
+The string should not contain embedded zeros.
@@ -5661,9 +5618,9 @@ Pushes the resulting string on the stack and returns it.
<p>
Returns the "length" of the value at the given acceptable index
as a number;
-it is equivalent to the '<code>#</code>' operator in Lua (see <a href="#2.5.5">&sect;2.5.5</a>).
+it is equivalent to the '<code>#</code>' operator in Lua (see <a href="#3.4.6">&sect;3.4.6</a>).
Raises an error if the result of the operation is not a number.
-(This only may happen through metamethods.)
+(This only can happen through metamethods.)
@@ -5769,7 +5726,7 @@ with <code>tname</code> in the registry.
Creates a new Lua state.
It calls <a href="#lua_newstate"><code>lua_newstate</code></a> with an
allocator based on the standard&nbsp;C <code>realloc</code> function
-and then sets a panic function (see <a href="#3.6">&sect;3.6</a>) that prints
+and then sets a panic function (see <a href="#4.6">&sect;4.6</a>) that prints
an error message to the standard error output in case of fatal
errors.
@@ -5782,8 +5739,54 @@ or <code>NULL</code> if there is a memory allocation error.
+<hr><h3><a name="luaL_openlib"><code>luaL_openlib</code></a></h3><p>
+<span class="apii">[-(nup + (0|1)), +1, <em>e</em>]</span>
+<pre>void luaL_openlib (lua_State *L,
+ const char *libname,
+ const luaL_Reg *l,
+ int nup);</pre>
+
+<p>
+Opens a library.
+
+
+<p>
+When called with <code>libname</code> equal to <code>NULL</code>,
+it simply registers all functions in the array <code>l</code>
+(see <a href="#luaL_Reg"><code>luaL_Reg</code></a>) into the table on the top of the stack.
+The pointer <code>l</code> may be <code>NULL</code>,
+representing an empty list.
+
+
+<p>
+When called with a non-null <code>libname</code>,
+<code>luaL_openlib</code> creates a new table <code>t</code>,
+sets it as the value of the global variable <code>libname</code>,
+sets it as the value of <code>package.loaded[libname]</code>,
+and registers on it all functions in the list <code>l</code>.
+If there is a table in <code>package.loaded[libname]</code> or
+in global variable <code>libname</code>,
+reuses this table instead of creating a new one.
+
+
+<p>
+In any case the function leaves the table
+on the top of the stack.
+
+
+<p>
+When <code>nup</code> is not zero,
+all functions are created sharing <code>nup</code> upvalues,
+which must be previously pushed on the stack
+(on top of the library table, if present).
+These values are popped from the stack after the registration.
+
+
+
+
+
<hr><h3><a name="luaL_openlibs"><code>luaL_openlibs</code></a></h3><p>
-<span class="apii">[-0, +0, <em>m</em>]</span>
+<span class="apii">[-0, +0, <em>e</em>]</span>
<pre>void luaL_openlibs (lua_State *L);</pre>
<p>
@@ -5960,7 +5963,7 @@ from any reference returned by <a href="#luaL_ref"><code>luaL_ref</code></a>.
<p>
Type for arrays of functions to be registered by
-<a href="#luaL_register"><code>luaL_register</code></a>.
+<a href="#luaL_openlib"><code>luaL_openlib</code></a>.
<code>name</code> is the function name and <code>func</code> is a pointer to
the function.
Any array of <a href="#luaL_Reg"><code>luaL_Reg</code></a> must end with an sentinel entry
@@ -5977,31 +5980,8 @@ in which both <code>name</code> and <code>func</code> are <code>NULL</code>.
const luaL_Reg *l);</pre>
<p>
-Opens a library.
-
-
-<p>
-When called with <code>libname</code> equal to <code>NULL</code>,
-it simply registers all functions in the array <code>l</code>
-(see <a href="#luaL_Reg"><code>luaL_Reg</code></a>) into the table on the top of the stack.
-The pointer <code>l</code> may be <code>NULL</code>,
-representing an empty list.
-
-
-<p>
-When called with a non-null <code>libname</code>,
-<code>luaL_register</code> creates a new table <code>t</code>,
-sets it as the value of the global variable <code>libname</code>,
-sets it as the value of <code>package.loaded[libname]</code>,
-and registers on it all functions in the list <code>l</code>.
-If there is a table in <code>package.loaded[libname]</code> or in
-variable <code>libname</code>,
-reuses this table instead of creating a new one.
-
-
-<p>
-In any case the function leaves the table
-on the top of the stack.
+This macro is equivalent to calling <a href="#luaL_openlib"><code>luaL_openlib</code></a>
+with no upvalues.
@@ -6134,7 +6114,7 @@ This function is used to build a prefix for error messages.
-<h1>5 - <a name="5">Standard Libraries</a></h1>
+<h1>6 - <a name="6">Standard Libraries</a></h1>
<p>
The standard Lua libraries provide useful functions
@@ -6200,7 +6180,7 @@ e.g., by using <a href="#lua_call"><code>lua_call</code></a>.
-<h2>5.1 - <a name="5.1">Basic Functions</a></h2>
+<h2>6.1 - <a name="6.1">Basic Functions</a></h2>
<p>
The basic library provides some core functions to Lua.
@@ -6266,13 +6246,13 @@ Returns <b>true</b> if the step finished a collection cycle.
<li><b>"setpause":</b>
sets <code>arg</code> as the new value for the <em>pause</em> of
-the collector (see <a href="#2.10">&sect;2.10</a>).
+the collector (see <a href="#2.5">&sect;2.5</a>).
Returns the previous value for <em>pause</em>.
</li>
<li><b>"setstepmul":</b>
sets <code>arg</code> as the new value for the <em>step multiplier</em> of
-the collector (see <a href="#2.10">&sect;2.10</a>).
+the collector (see <a href="#2.5">&sect;2.5</a>).
Returns the previous value for <em>step</em>.
</li>
@@ -6321,7 +6301,7 @@ to the message.
<p>
<hr><h3><a name="pdf-_G"><code>_G</code></a></h3>
A global variable (not a function) that
-holds the global environment (so that <code>_G._G = _G</code>).
+holds the global environment (see <a href="#2.2">&sect;2.2</a>).
Lua itself does not use this variable;
changing its value does not affect any environment,
nor vice-versa.
@@ -6344,31 +6324,6 @@ Otherwise, returns the metatable of the given object.
<p>
-<hr><h3><a name="pdf-ipairs"><code>ipairs (t)</code></a></h3>
-
-
-<p>
-If <code>t</code> has a metamethod <code>__ipairs</code>,
-calls it with <code>t</code> as argument and returns the first three
-results from the call.
-
-
-<p>
-Otherwise,
-returns three values: an iterator function, the table <code>t</code>, and 0,
-so that the construction
-
-<pre>
- for i,v in ipairs(t) do <em>body</em> end
-</pre><p>
-will iterate over the pairs (<code>1,t[1]</code>), (<code>2,t[2]</code>), &middot;&middot;&middot;,
-up to the length of the table,
-as defined by the length operator (see <a href="#2.5.5">&sect;2.5.5</a>).
-
-
-
-
-<p>
<hr><h3><a name="pdf-load"><code>load (ld [, source [, mode]])</code></a></h3>
@@ -6392,12 +6347,15 @@ If <code>ld</code> is a string, the chunk is this string.
If there are no errors,
returns the compiled chunk as a function;
otherwise, returns <b>nil</b> plus the error message.
-The environment of the returned function is the global environment.
+If the resulting function has upvalues,
+the first upvalue is set to the value of the global environment
+(When loading main chunks,
+this upvalue will be the <code>_ENV</code> variable (see <a href="#2.2">&sect;2.2</a>).)
<p>
<code>source</code> is used as the source of the chunk for error messages
-and debug information (see <a href="#3.9">&sect;3.9</a>).
+and debug information (see <a href="#4.9">&sect;4.9</a>).
When absent,
it defaults to "<code>=(load)</code>".
@@ -6418,8 +6376,9 @@ The default is "<code>bt</code>".
<p>
This function is similar to <a href="#pdf-load"><code>load</code></a>,
-but sets <code>env</code> as the environment
+but sets <code>env</code> as the value of the first upvalue
of the created function in case of success.
+(Usually this first upvalue will be <code>_ENV</code> (see <a href="#2.2">&sect;2.2</a>).)
The parameters after <code>env</code> are similar to those of <a href="#pdf-load"><code>load</code></a>, too.
@@ -6486,7 +6445,7 @@ you can use <code>next(t)</code> to check whether a table is empty.
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 numerical <b>for</b> or the <a href="#pdf-ipairs"><code>ipairs</code></a> function.)
+use a numerical <b>for</b>.)
<p>
@@ -6641,7 +6600,7 @@ In bases above&nbsp;10, the letter '<code>A</code>' (in either upper or lower ca
represents&nbsp;10, '<code>B</code>' represents&nbsp;11, and so forth,
with '<code>Z</code>' representing 35.
In base 10 (the default), the number can have a decimal part,
-as well as an optional exponent part (see <a href="#2.1">&sect;2.1</a>).
+as well as an optional exponent part (see <a href="#3.1">&sect;3.1</a>).
In other bases, only unsigned integers are accepted.
@@ -6703,12 +6662,12 @@ except that it sets a new error handler <code>err</code>.
-<h2>5.2 - <a name="5.2">Coroutine Manipulation</a></h2>
+<h2>6.2 - <a name="6.2">Coroutine Manipulation</a></h2>
<p>
The operations related to coroutines comprise a sub-library of
the basic library and come inside the table <a name="pdf-coroutine"><code>coroutine</code></a>.
-See <a href="#2.11">&sect;2.11</a> for a general description of coroutines.
+See <a href="#2.6">&sect;2.6</a> for a general description of coroutines.
<p>
@@ -6813,7 +6772,7 @@ Any arguments to <code>yield</code> are passed as extra results to <code>resume<
-<h2>5.3 - <a name="5.3">Modules</a></h2>
+<h2>6.3 - <a name="6.3">Modules</a></h2>
<p>
The package library provides basic
@@ -7194,7 +7153,7 @@ To be used as an option to function <a href="#pdf-module"><code>module</code></a
-<h2>5.4 - <a name="5.4">String Manipulation</a></h2>
+<h2>6.4 - <a name="6.4">String Manipulation</a></h2>
<p>
This library provides generic functions for string manipulation,
@@ -7377,6 +7336,7 @@ replaced by a replacement string specified by <code>repl</code>,
which can be a string, a table, or a function.
<code>gsub</code> also returns, as its second value,
the total number of matches that occurred.
+The name <code>gsub</code> comes from <em>Global SUBstitution</em>.
<p>
@@ -7517,7 +7477,7 @@ The definition of what a lowercase letter is depends on the current locale.
-<h3>5.4.1 - <a name="5.4.1">Patterns</a></h3>
+<h3>6.4.1 - <a name="6.4.1">Patterns</a></h3>
<h4>Character Class:</h4><p>
@@ -7552,8 +7512,6 @@ represents the character <em>x</em> itself.
<li><b><code>%x</code>:</b> represents all hexadecimal digits.</li>
-<li><b><code>%z</code>:</b> represents the character with representation 0.</li>
-
<li><b><code>%<em>x</em></code>:</b> (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.
@@ -7702,8 +7660,6 @@ For instance, if we apply the pattern <code>"()aa()"</code> on the
string <code>"flaaap"</code>, there will be two captures: 3&nbsp;and&nbsp;5.
-<p>
-A pattern cannot contain embedded zeros. Use <code>%z</code> instead.
@@ -7713,9 +7669,7 @@ A pattern cannot contain embedded zeros. Use <code>%z</code> instead.
-
-
-<h2>5.5 - <a name="5.5">Table Manipulation</a></h2><p>
+<h2>6.5 - <a name="6.5">Table Manipulation</a></h2><p>
This library provides generic functions for table manipulation.
It provides all its functions inside the table <a name="pdf-table"><code>table</code></a>.
@@ -7747,7 +7701,7 @@ If <code>i</code> is greater than <code>j</code>, returns the empty string.
Inserts element <code>value</code> at position <code>pos</code> in <code>table</code>,
shifting up 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 length of the table (see <a href="#2.5.5">&sect;2.5.5</a>),
+where <code>n</code> is the length of the table (see <a href="#3.4.6">&sect;3.4.6</a>),
so that a call <code>table.insert(t,x)</code> inserts <code>x</code> at the end
of table <code>t</code>.
@@ -7788,9 +7742,9 @@ 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 length of the table.
If <code>comp</code> is given,
-then it must be a function that receives two table elements,
-and returns true
-when the first is less than the second
+then it must be a function that receives two table elements
+and returns true when the first element must come
+before the second in the final order
(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.
@@ -7815,7 +7769,7 @@ This function is equivalent to
except that the above code can be written only for a fixed number
of elements.
By default, <code>i</code> is&nbsp;1 and <code>j</code> is the length of the list,
-as defined by the length operator (see <a href="#2.5.5">&sect;2.5.5</a>).
+as defined by the length operator (see <a href="#3.4.6">&sect;3.4.6</a>).
@@ -7823,7 +7777,7 @@ as defined by the length operator (see <a href="#2.5.5">&sect;2.5.5</a>).
-<h2>5.6 - <a name="5.6">Mathematical Functions</a></h2>
+<h2>6.6 - <a name="6.6">Mathematical Functions</a></h2>
<p>
This library is an interface to the standard C&nbsp;math library.
@@ -8036,7 +7990,7 @@ the integral part of <code>x</code> and the fractional part of <code>x</code>.
<p>
-The value of <em>pi</em>.
+The value of <em>&pi;</em>.
@@ -8152,7 +8106,7 @@ Returns the hyperbolic tangent of <code>x</code>.
-<h2>5.7 - <a name="5.7">Bitwise operations</a></h2>
+<h2>6.7 - <a name="6.7">Bitwise operations</a></h2>
<p>
This library provides bitwise operations.
@@ -8202,29 +8156,28 @@ Returns the bitwise or of its operands.
<p>
-<hr><h3><a name="pdf-bit.brotate"><code>bit.brotate (x, disp)</code></a></h3>
+<hr><h3><a name="pdf-bit.btest"><code>bit.btest (&middot;&middot;&middot;)</code></a></h3>
<p>
-Returns the number <code>x</code> rotated <code>disp</code> bits to the left.
-The number <code>disp</code> may be any representable integer.
+Returns a boolean signaling
+whether the bitwise and of its operands is different from zero.
+
+
<p>
-For any valid displacement,
-the following identity holds:
+<hr><h3><a name="pdf-bit.bxor"><code>bit.bxor (&middot;&middot;&middot;)</code></a></h3>
-<pre>
- assert(bit.rotate(x, disp) == bit.rotate(x, disp % 32))
-</pre><p>
-This allows you to consider that
-negative displacements rotate to the right.
+
+<p>
+Returns the bitwise exclusive or of its operands.
<p>
-<hr><h3><a name="pdf-bit.bshift"><code>bit.bshift (x, disp)</code></a></h3>
+<hr><h3><a name="pdf-bit.lshift"><code>bit.lshift (x, disp)</code></a></h3>
<p>
@@ -8243,42 +8196,82 @@ For positive displacements,
the following equality holds:
<pre>
- assert(bit.bshift(b, disp) == (b * 2^disp) % 2^32)
+ assert(bit.lshift(b, disp) == (b * 2^disp) % 2^32)
</pre>
+
+
<p>
-For negative displacements,
-the following equality holds:
+<hr><h3><a name="pdf-bit.rol"><code>bit.rol (x, disp)</code></a></h3>
+
+
+<p>
+Returns the number <code>x</code> rotated <code>disp</code> bits to the left.
+The number <code>disp</code> may be any representable integer.
+
+
+<p>
+For any valid displacement,
+the following identity holds:
<pre>
- assert(bit.bshift(b, disp) == math.floor(b * 2^disp))
-</pre>
+ assert(bit.rol(x, disp) == bit.rol(x, disp % 32))
+</pre><p>
+In particular,
+negative displacements rotate to the right.
+
+
+
<p>
-This shift operation is what is called logical shift.
-For an arithmetic shift,
-you should use the arithmetic operators.
+<hr><h3><a name="pdf-bit.ror"><code>bit.ror (x, disp)</code></a></h3>
+<p>
+Returns the number <code>x</code> rotated <code>disp</code> bits to the right.
+The number <code>disp</code> may be any representable integer.
<p>
-<hr><h3><a name="pdf-bit.btest"><code>bit.btest (&middot;&middot;&middot;)</code></a></h3>
+For any valid displacement,
+the following identity holds:
+
+<pre>
+ assert(bit.ror(x, disp) == bit.ror(x, disp % 32))
+</pre><p>
+In particular,
+negative displacements rotate to the left.
+
+
<p>
-Returns a boolean signaling
-whether the bitwise and of its operands is different from zero.
+<hr><h3><a name="pdf-bit.rshift"><code>bit.rshift (x, disp)</code></a></h3>
+<p>
+Returns the number <code>x</code> shifted <code>disp</code> bits to the right.
+The number <code>disp</code> may be any representable integer.
+Negative displacements shift to the left.
+In any direction, vacant bits are filled with zeros.
+In particular,
+displacements with absolute values higher than
+the total number of bits in the representation of <code>x</code>
+result in zero (all bits are shifted out).
<p>
-<hr><h3><a name="pdf-bit.bxor"><code>bit.bxor (&middot;&middot;&middot;)</code></a></h3>
+For positive displacements,
+the following equality holds:
+<pre>
+ assert(bit.rshift(b, disp) == math.floor(b * 2^-disp))
+</pre>
<p>
-Returns the bitwise exclusive or of its operands.
+This shift operation is what is called logical shift.
+For an arithmetic shift,
+you should use the arithmetic operators.
@@ -8286,7 +8279,7 @@ Returns the bitwise exclusive or of its operands.
-<h2>5.8 - <a name="5.8">Input and Output Facilities</a></h2>
+<h2>6.8 - <a name="6.8">Input and Output Facilities</a></h2>
<p>
The I/O library provides two different styles for file manipulation.
@@ -8362,7 +8355,7 @@ instead of returning an error code.
<p>
-<hr><h3><a name="pdf-io.lines"><code>io.lines ([filename])</code></a></h3>
+<hr><h3><a name="pdf-io.lines"><code>io.lines ([filename] [, keepNL])</code></a></h3>
<p>
@@ -8387,6 +8380,11 @@ that is, it iterates over the lines of the default input file.
In this case it does not close the file when the loop ends.
+<p>
+By default, <code>lines</code> removes the newline at the end of each line.
+If <code>keepNL</code> is <b>true</b>, it will keep the newlines.
+
+
<p>
@@ -8521,7 +8519,7 @@ Saves any written data to <code>file</code>.
<p>
-<hr><h3><a name="pdf-file:lines"><code>file:lines ()</code></a></h3>
+<hr><h3><a name="pdf-file:lines"><code>file:lines ([keepNL])</code></a></h3>
<p>
@@ -8533,11 +8531,17 @@ Therefore, the construction
<pre>
for line in file:lines() do <em>body</em> end
</pre><p>
-will iterate over all lines of the file.
+will iterate over all lines of the file,
+starting at the current position.
(Unlike <a href="#pdf-io.lines"><code>io.lines</code></a>, this function does not close the file
when the loop ends.)
+<p>
+By default, <code>lines</code> removes the newline at the end of each line.
+If <code>keepNL</code> is <b>true</b>, it will keep the newlines.
+
+
<p>
@@ -8551,7 +8555,7 @@ 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 entire next line
+it uses a default format that reads the next line
(see below).
@@ -8571,11 +8575,16 @@ On end of file, it returns the empty string.
</li>
<li><b>"*l":</b>
-reads the next line (skipping the end of line),
+reads the next line skipping the end of line,
returning <b>nil</b> on end of file.
This is the default format.
</li>
+<li><b>"*L":</b>
+reads the next line keeping the end of line (if present),
+returning <b>nil</b> on end of file.
+</li>
+
<li><b><em>number</em>:</b>
reads a string with up to this number of characters,
returning <b>nil</b> on end of file.
@@ -8678,7 +8687,7 @@ Otherwise it returns <b>nil</b> plus a string describing the error.
-<h2>5.9 - <a name="5.9">Operating System Facilities</a></h2>
+<h2>6.9 - <a name="6.9">Operating System Facilities</a></h2>
<p>
This library is implemented through table <a name="pdf-os"><code>os</code></a>.
@@ -8904,23 +8913,20 @@ which automatically removes the file when the program ends.
-<h2>5.10 - <a name="5.10">The Debug Library</a></h2>
+<h2>6.10 - <a name="6.10">The Debug Library</a></h2>
<p>
This library provides
the functionality of the debug interface to Lua programs.
You should exert care when using this library.
-The functions provided here should be used exclusively for debugging
-and similar tasks, such as profiling.
-Please resist the temptation to use them as a
-usual programming tool:
-they can be very slow.
-Moreover, several of these functions
-violate some assumptions about Lua code
+Several of these functions
+violate basic assumptions about Lua code
(e.g., that variables local to a function
-cannot be accessed from outside or
-that userdata metatables cannot be changed by Lua code)
+cannot be accessed from outside;
+that userdata metatables cannot be changed by Lua code;
+that Lua programs do not crash)
and therefore can compromise otherwise secure code.
+Moreover, some functions in this library may be slow.
<p>
@@ -9055,7 +9061,7 @@ or <b>nil</b> if it does not have a metatable.
<p>
-Returns the registry table (see <a href="#3.5">&sect;3.5</a>).
+Returns the registry table (see <a href="#4.5">&sect;4.5</a>).
@@ -9217,7 +9223,7 @@ TO BE DONE!!
-<h1>6 - <a name="6">Lua Stand-alone</a></h1>
+<h1>7 - <a name="7">Lua Stand-alone</a></h1>
<p>
Although Lua has been designed as an extension language,
@@ -9268,7 +9274,7 @@ For instance, an invocation like
</pre><p>
will first set <code>a</code> to 1, then print the value of <code>a</code> (which is '<code>1</code>'),
and finally run the file <code>script.lua</code> with no arguments.
-(Here <code>$</code> is the shell prompt. Your prompt may be different.)
+(Here <code>$</code> is the shell prompt. Your prompt can be different.)
<p>
@@ -9352,7 +9358,7 @@ as in
#!/usr/local/bin/lua
</pre><p>
(Of course,
-the location of the Lua interpreter may be different in your machine.
+the location of the Lua interpreter can be different in your machine.
If <code>lua</code> is in your <code>PATH</code>,
then
@@ -9363,10 +9369,10 @@ is a more portable solution.)
-<h1>7 - <a name="7">Incompatibilities with the Previous Version</a></h1>
+<h1>8 - <a name="8">Incompatibilities with the Previous Version</a></h1>
<p>
-Here we list the incompatibilities that you may find when moving a program
+Here we list the incompatibilities that you can find when moving a program
from Lua&nbsp;5.1 to Lua&nbsp;5.2.
You can avoid some incompatibilities compiling Lua with
appropriate options (see file <code>luaconf.h</code>).
@@ -9375,7 +9381,7 @@ all these compatibility options will be removed in the next version of Lua.
-<h2>7.1 - <a name="7.1">Changes in the Language</a></h2>
+<h2>8.1 - <a name="8.1">Changes in the Language</a></h2>
<ul>
<li>
@@ -9396,12 +9402,19 @@ Threads do not have individual environments.
All threads share a single fixed environment.
</li>
+<li>
+The event <em>tail return</em> in debug hooks was removed.
+Instead, tail calls generate a special new event,
+<em>tail call</em>, so that the debuger can know there will
+not be a corresponding return event.
+</li>
+
</ul>
-<h2>7.2 - <a name="7.2">Changes in the Libraries</a></h2>
+<h2>8.2 - <a name="8.2">Changes in the Libraries</a></h2>
<ul>
<li>
@@ -9412,9 +9425,13 @@ You must explicitly require it.
<li>
Functions <code>setfenv</code> and <code>getfenv</code> are deprecated.
To set the environment of a Lua function,
-use lexical environments or the new function <a href="#pdf-loadin"><code>loadin</code></a>.
-(If you really need them,
-you may use their equivalents in the debug library.)
+use the variable <code>_ENV</code> or the new function <a href="#pdf-loadin"><code>loadin</code></a>.
+</li>
+
+<li>
+Function <code>ipairs</code> is deprecated.
+Use a numerical for loop instead,
+or write it in Lua.
</li>
<li>
@@ -9432,20 +9449,44 @@ Function <code>unpack</code> was moved into the table library
and therefore must be called as <a href="#pdf-table.unpack"><code>table.unpack</code></a>.
</li>
+<li>
+Character class <code>%z</code> in patterns is deprecated,
+as now patterns may contain '<code>\0</code>' as a regular character.
+</li>
+
+<li>
+Lua does not have bytecode verification anymore.
+So, all functions that load code
+(<a href="#pdf-load"><code>load</code></a>, <a href="#pdf-loadfile"><code>loadfile</code></a>, <a href="#pdf-loadstring"><code>loadstring</code></a>)
+are potentially insecure when loading untrusted binary data.
+(Actually, those functions were already insecure because
+of bugs in the verification algorithm.)
+When in doubt,
+use the <code>mode</code> argument in function <a href="#pdf-load"><code>load</code></a>
+to restrict it to loading textual chunks.
+</li>
+
</ul>
-<h2>7.3 - <a name="7.3">Changes in the API</a></h2>
+<h2>8.3 - <a name="8.3">Changes in the API</a></h2>
<ul>
<li>
Pseudoindex <code>LUA_GLOBALSINDEX</code> was removed.
-You may use the pseudoindex <a href="#pdf-LUA_ENVIRONINDEX"><code>LUA_ENVIRONINDEX</code></a> instead,
-if the C&nbsp;function does not change its standard environment.
-Otherwise, you should get the global environment from the registry
-(see <a href="#3.5">&sect;3.5</a>).
+You must get the global environment from the registry
+(see <a href="#4.5">&sect;4.5</a>).
+</li>
+
+<li>
+Pseudoindex <code>LUA_ENVIRONINDEX</code> was removed.
+C functions do not have environments any more.
+Use an upvalue with a shared table if you need to keep
+shared state among several C functions.
+(You may use <a href="#luaL_openlib"><code>luaL_openlib</code></a> to open a C library
+with all functions sharing a common upvalue.)
</li>
<li>
@@ -9462,8 +9503,8 @@ to have a correct spelling.
<li>
Function <code>lua_cpcall</code> is deprecated.
-Use the new <code>cpcall</code> function defined in the registry instead
-(see <a href="#3.5">&sect;3.5</a>).
+You can simply push the function with <a href="#lua_pushcfunction"><code>lua_pushcfunction</code></a>
+and call it with <a href="#lua_pcall"><code>lua_pcall</code></a>.
</li>
<li>
@@ -9480,7 +9521,7 @@ Function <code>lua_objlen</code> was renamed <a href="#lua_rawlen"><code>lua_raw
-<h1>8 - <a name="8">The Complete Syntax of Lua</a></h1>
+<h1>9 - <a name="9">The Complete Syntax of Lua</a></h1>
<p>
Here is the complete syntax of Lua in extended BNF.
@@ -9491,63 +9532,64 @@ Here is the complete syntax of Lua in extended BNF.
<pre>
- chunk ::= {stat [`<b>;</b>&acute;]} [laststat [`<b>;</b>&acute;]]
+ chunk ::= {stat} [laststat [&lsquo<b>;</b>&rsquo;]]
block ::= chunk
- stat ::= varlist `<b>=</b>&acute; explist |
+ stat ::= &lsquo<b>;</b>&rsquo; |
+ varlist &lsquo<b>=</b>&rsquo; explist |
functioncall |
<b>do</b> block <b>end</b> |
<b>while</b> exp <b>do</b> block <b>end</b> |
<b>repeat</b> block <b>until</b> exp |
<b>if</b> exp <b>then</b> block {<b>elseif</b> exp <b>then</b> block} [<b>else</b> block] <b>end</b> |
- <b>for</b> Name `<b>=</b>&acute; exp `<b>,</b>&acute; exp [`<b>,</b>&acute; exp] <b>do</b> block <b>end</b> |
+ <b>for</b> Name &lsquo<b>=</b>&rsquo; exp &lsquo<b>,</b>&rsquo; exp [&lsquo<b>,</b>&rsquo; exp] <b>do</b> block <b>end</b> |
<b>for</b> namelist <b>in</b> explist <b>do</b> block <b>end</b> |
<b>function</b> funcname funcbody |
<b>local</b> <b>function</b> Name funcbody |
- <b>local</b> namelist [`<b>=</b>&acute; explist] |
+ <b>local</b> namelist [&lsquo<b>=</b>&rsquo; explist] |
<b>in</b> exp <b>do</b> block <b>end</b>
laststat ::= <b>return</b> [explist] | <b>break</b>
- funcname ::= Name {`<b>.</b>&acute; Name} [`<b>:</b>&acute; Name]
+ funcname ::= Name {&lsquo<b>.</b>&rsquo; Name} [&lsquo<b>:</b>&rsquo; Name]
- varlist ::= var {`<b>,</b>&acute; var}
+ varlist ::= var {&lsquo<b>,</b>&rsquo; var}
- var ::= Name | prefixexp `<b>[</b>&acute; exp `<b>]</b>&acute; | prefixexp `<b>.</b>&acute; Name
+ var ::= Name | prefixexp &lsquo<b>[</b>&rsquo; exp &lsquo<b>]</b>&rsquo; | prefixexp &lsquo<b>.</b>&rsquo; Name
- namelist ::= Name {`<b>,</b>&acute; Name}
+ namelist ::= Name {&lsquo<b>,</b>&rsquo; Name}
- explist ::= {exp `<b>,</b>&acute;} exp
+ explist ::= {exp &lsquo<b>,</b>&rsquo;} exp
- exp ::= <b>nil</b> | <b>false</b> | <b>true</b> | Number | String | `<b>...</b>&acute; | function |
+ exp ::= <b>nil</b> | <b>false</b> | <b>true</b> | Number | String | &lsquo<b>...</b>&rsquo; | function |
prefixexp | tableconstructor | exp binop exp | unop exp
- prefixexp ::= var | functioncall | `<b>(</b>&acute; exp `<b>)</b>&acute;
+ prefixexp ::= var | functioncall | &lsquo<b>(</b>&rsquo; exp &lsquo<b>)</b>&rsquo;
- functioncall ::= prefixexp args | prefixexp `<b>:</b>&acute; Name args
+ functioncall ::= prefixexp args | prefixexp &lsquo<b>:</b>&rsquo; Name args
- args ::= `<b>(</b>&acute; [explist] `<b>)</b>&acute; | tableconstructor | String
+ args ::= &lsquo<b>(</b>&rsquo; [explist] &lsquo<b>)</b>&rsquo; | tableconstructor | String
function ::= <b>function</b> funcbody
- funcbody ::= `<b>(</b>&acute; [parlist] `<b>)</b>&acute; block <b>end</b>
+ funcbody ::= &lsquo<b>(</b>&rsquo; [parlist] &lsquo<b>)</b>&rsquo; block <b>end</b>
- parlist ::= namelist [`<b>,</b>&acute; `<b>...</b>&acute;] | `<b>...</b>&acute;
+ parlist ::= namelist [&lsquo<b>,</b>&rsquo; &lsquo<b>...</b>&rsquo;] | &lsquo<b>...</b>&rsquo;
- tableconstructor ::= `<b>{</b>&acute; [fieldlist] `<b>}</b>&acute;
+ tableconstructor ::= &lsquo<b>{</b>&rsquo; [fieldlist] &lsquo<b>}</b>&rsquo;
fieldlist ::= field {fieldsep field} [fieldsep]
- field ::= `<b>[</b>&acute; exp `<b>]</b>&acute; `<b>=</b>&acute; exp | Name `<b>=</b>&acute; exp | exp
+ field ::= &lsquo<b>[</b>&rsquo; exp &lsquo<b>]</b>&rsquo; &lsquo<b>=</b>&rsquo; exp | Name &lsquo<b>=</b>&rsquo; exp | exp
- fieldsep ::= `<b>,</b>&acute; | `<b>;</b>&acute;
+ fieldsep ::= &lsquo<b>,</b>&rsquo; | &lsquo<b>;</b>&rsquo;
- binop ::= `<b>+</b>&acute; | `<b>-</b>&acute; | `<b>*</b>&acute; | `<b>/</b>&acute; | `<b>^</b>&acute; | `<b>%</b>&acute; | `<b>..</b>&acute; |
- `<b>&lt;</b>&acute; | `<b>&lt;=</b>&acute; | `<b>&gt;</b>&acute; | `<b>&gt;=</b>&acute; | `<b>==</b>&acute; | `<b>~=</b>&acute; |
+ binop ::= &lsquo<b>+</b>&rsquo; | &lsquo<b>-</b>&rsquo; | &lsquo<b>*</b>&rsquo; | &lsquo<b>/</b>&rsquo; | &lsquo<b>^</b>&rsquo; | &lsquo<b>%</b>&rsquo; | &lsquo<b>..</b>&rsquo; |
+ &lsquo<b>&lt;</b>&rsquo; | &lsquo<b>&lt;=</b>&rsquo; | &lsquo<b>&gt;</b>&rsquo; | &lsquo<b>&gt;=</b>&rsquo; | &lsquo<b>==</b>&rsquo; | &lsquo<b>~=</b>&rsquo; |
<b>and</b> | <b>or</b>
- unop ::= `<b>-</b>&acute; | <b>not</b> | `<b>#</b>&acute;
+ unop ::= &lsquo<b>-</b>&rsquo; | <b>not</b> | &lsquo<b>#</b>&rsquo;
</pre>
@@ -9562,10 +9604,10 @@ Here is the complete syntax of Lua in extended BNF.
<HR>
<SMALL>
Last update:
-Wed Jan 13 15:29:29 BRST 2010
+Mon May 17 16:24:08 BRT 2010
</SMALL>
<!--
-Last change: revised for Lua 5.2.0 (work2)
+Last change: revised for Lua 5.2.0 (work3)
-->
</body></html>
diff --git a/doc/readme.html b/doc/readme.html
index 6d9e601e..076dd81f 100644
--- a/doc/readme.html
+++ b/doc/readme.html
@@ -9,25 +9,31 @@ blockquote, .display {
color: black ;
padding: 8px ;
border: solid #a0a0a0 2px ;
- background-color: #EFEFFF ;
+ xbackground-color: #EFEFFF ;
margin-left: 0px ;
}
-.review {
- color: red ;
-}
-
.external {
padding-right: 15px;
background: transparent url(external.png) no-repeat center right;
}
-tt, kbd {
+tt, kbd, code {
font-size: 120% ;
xcolor: black ;
xpadding: 4px ;
xbackground-color: #E0E0E0 ;
}
+
+kbd {
+ color: black ;
+ background-color: #E8E8E8 ;
+}
+
+.review {
+ color: red ;
+}
+
</STYLE>
</HEAD>
@@ -39,6 +45,11 @@ tt, kbd {
Welcome to Lua 5.2
</H1>
+<IMG SRC="alert.png" ALIGN="absbottom">
+<EM>This is a work version of Lua 5.2.
+Everything may change in the final version.</EM>
+<P>
+
<A HREF="#about">about</A>
&middot;
<A HREF="#install">installation</A>
@@ -51,11 +62,6 @@ Welcome to Lua 5.2
<HR>
<P>
-<P>
-<IMG SRC="alert.png" ALIGN="absbottom">
-<EM>This is a work version of Lua 5.2.
-All details may change in the final version.</EM>
-
<H2><A NAME="about">About Lua</A></H2>
Lua is a powerful, fast, lightweight, embeddable scripting language
@@ -270,6 +276,24 @@ compiler:
<H2><A NAME="changes">Changes since Lua 5.1</A></H2>
+<IMG SRC="alert.png" ALIGN="absbottom">
+<EM>Everything may change in the final version.</EM>
+<P>
+
+Here are the main changes since the previous work version:
+<UL>
+<LI> new <CODE>_ENV</CODE> proposal
+<LI> generational collector (very experimental)
+<LI> light C functions
+
+<LI> order tag methods follow the same rules of other binary operators
+<LI> <CODE>lua_absindex</CODE>
+<LI> \0 in patterns
+<LI> empty statement
+<LI> options in <CODE>io.lines</CODE>
+</UL>
+<P>
+
Here are the main changes in Lua since its last release.
The
<A HREF="contents.html">reference manual</A>
@@ -281,13 +305,13 @@ lists the
<UL>
<LI> new lexical environments.
<LI> no more fenv for threads.
-<LI> ephemeron tables.
-<LI> yieldable pcall/metamethods.
+<LI> ephemeron tables
+ (tables with weak keys only visit value when key is accessible).
+<LI> yieldable pcall and metamethods.
<LI> tables honor the <CODE>__len</CODE> metamethod.
<LI> max constants per function raised to 2^26.
<LI> hex escapes in strings.
<LI> no more verification of opcode consistency.
-
</UL>
<H3>Libraries</H3>
@@ -299,27 +323,39 @@ lists the
<LI> <CODE>loadlib</CODE> may load libraries with global names (RTLD_GLOBAL).
<LI> new function <CODE>package.searchpath</CODE>.
<LI> optional base in <CODE>math.log</CODE>.
-<LI> <CODE>file:write</CODE> returns file.
+<LI> <CODE>file:write</CODE> returns <CODE>file</CODE>.
<LI> closing a pipe returns exit status.
<LI> <CODE>os.exit</CODE> may close state.
<LI> new option 'isrunning' for <CODE>collectgarbage</CODE> and <CODE>lua_gc</CODE>.
<LI> frontier patterns.
<LI> <CODE>ipairs</CODE> now goes until #t.
+</UL>
+<H3>C API</H3>
+<UL>
+<LI> mainthread predefined in the registry.
+<LI> <CODE>lua_cpcall</CODE> changed to a predefined function in the registry.
+<LI> new constants <CODE>LUA_OK</CODE> and <CODE>LUA_ERRGCMM</CODE>.
+<LI> new <CODE>lua_compare</CODE>, <CODE>lua_arith</CODE>, and <CODE>lua_len</CODE>.
+<LI> new <CODE>lua_version</CODE> and <CODE>luaL_version</CODE>.
+<LI> <CODE>lua_pushstring</CODE> and <CODE>pushlstring</CODE> return string.
+<LI> new <CODE>luaL_testudata</CODE>.
+<LI> new <CODE>luaL_tolstring</CODE>.
+<LI> new <CODE>lua_copy</CODE>.
+<LI> new <CODE>lua_upvalueid</CODE> and <CODE>lua_upvaluejoin</CODE>.
+<LI> <CODE>nparams</CODE> and <CODE>isvarag</CODE> available in debug API.
</UL>
<H3>Implementation</H3>
<UL>
<LI> emergency garbage collector
(core forces a full collection when allocation fails).
-<LI> ephemeron tables
- (tables with weak keys only visit value when key is accessible)
-<LI> handling of non-string error messages in the standalone interpreter.
<LI> udata with finalizers are kept in a separated list for the GC.
<LI> CallInfo stack now is a linked list.
<LI> internal (immutable) version of ctypes.
<LI> parser uses much less C-stack space (no more auto arrays).
<LI> new hash for floats.
+<LI> handling of non-string error messages in the standalone interpreter.
</UL>
@@ -372,10 +408,10 @@ THE SOFTWARE.
<HR>
<SMALL>
Last update:
-Wed Jan 13 15:35:05 BRST 2010
+Tue May 18 13:59:06 BRT 2010
</SMALL>
<!--
-Last change: revised for Lua 5.2.0 (work2)
+Last change: revised for Lua 5.2.0 (work3)
-->
</BODY>
diff --git a/etc/Makefile b/etc/Makefile
index 5f6ed872..34d8571a 100644
--- a/etc/Makefile
+++ b/etc/Makefile
@@ -7,32 +7,48 @@ BIN= $(TOP)/src
SRC= $(TOP)/src
TST= $(TOP)/test
+T= test
CC= gcc
CFLAGS= -O2 -Wall -I$(INC) $(MYCFLAGS)
MYCFLAGS=
-MYLDFLAGS= -Wl,-E
-MYLIBS= -lm
-#MYLIBS= -lm -Wl,-E -ldl -lreadline -lhistory -lncurses
+MYLIBS= -lm # -ldl -lreadline -lncurses -Wl,-E
RM= rm -f
+
default:
- @echo 'Please choose a target: min noparser one strict clean'
+ @echo 'Please choose a target: min noparser one one-lua one-lib one-luac so strict clean'
min: min.c
- $(CC) $(CFLAGS) $@.c -L$(LIB) -llua $(MYLIBS)
- echo 'print"Hello there!"' | ./a.out
- ./a.out $(TST)/hello.lua
- echo 'print("Hello world, from",_VERSION,"!")' | ./a.out
+ $(CC) $(CFLAGS) -o $T min.c -L$(LIB) -llua $(MYLIBS)
+ echo 'print"Hello there!"' | ./$T
+ ./$T $(TST)/hello.lua
+ echo 'print("Hello world, from",_VERSION,"!")' | ./$T
noparser: noparser.o
- $(CC) noparser.o $(SRC)/lua.o -L$(LIB) -llua $(MYLIBS)
+ $(CC) -o $T noparser.o $(SRC)/lua.o -L$(LIB) -llua $(MYLIBS)
$(BIN)/luac $(TST)/hello.lua
- -./a.out luac.out
- -./a.out -e'a=1'
+ -./$T luac.out
+ -./$T -e'a=1'
+
+one: one-lua one-lib one-luac
+
+one-lua:
+ $(CC) $(CFLAGS) -o $T one.c $(MYLIBS)
+ ./$T $(TST)/hello.lua
+
+one-lib:
+ $(CC) $(CFLAGS) -DMAKE_LIB -o liblua.o -c one.c
+ $(CC) $(CFLAGS) -o $T min.c liblua.o $(MYLIBS)
+ ./$T $(TST)/hello.lua
+
+one-luac:
+ $(CC) $(CFLAGS) -o $T -DMAKE_LUAC one.c $(MYLIBS)
+ ./$T -l $(TST)/hello.lua
-one:
- $(CC) $(CFLAGS) one.c $(MYLIBS)
- ./a.out $(TST)/hello.lua
+so:
+ $(CC) $(CFLAGS) -shared -o dummy.so dummy.c
+ @#env MACOSX_DEPLOYMENT_TARGET=10.3 $(CC) $(CFLAGS) -bundle -undefined dynamic_lookup -o dummy.so dummy.c
+ $(BIN)/lua -v -ldummy
strict:
-$(BIN)/lua -e 'print(a);b=2'
@@ -41,6 +57,6 @@ strict:
-$(BIN)/lua -lstrict -e 'function f() b=2 end f()'
clean:
- $(RM) a.out core core.* *.o luac.out
+ $(RM) $T a.out core core.* *.o luac.out dummy.so
-.PHONY: default min noparser one strict clean
+.PHONY: default min noparser one one-lua one-lib one-luac so strict clean
diff --git a/etc/README b/etc/README
index 300257ae..0eda3bd3 100644
--- a/etc/README
+++ b/etc/README
@@ -4,23 +4,26 @@ Unlike the code in ../src, everything here is in the public domain.
If any of the makes fail, you're probably not using the same libraries used
to build Lua. Set MYLIBS in Makefile or in the command line accordingly.
-one.c
- Full Lua interpreter in a single file.
- Do "make one" for a demo.
+dummy.c:
+ A minimal Lua library for testing dynamic loading.
+ Do "make so" for a demo.
luavs.bat
Script to build Lua under "Visual Studio .NET Command Prompt".
Run it from the toplevel as etc\luavs.bat.
min.c
- A minimal Lua interpreter.
- Good for learning and for starting your own.
+ A minimal Lua interpreter for learning and for starting your own.
Do "make min" for a demo.
noparser.c
Linking with noparser.o avoids loading the parsing modules in lualib.a.
Do "make noparser" for a demo.
+one.c
+ Full Lua interpreter in a single file. Also library and compiler.
+ Do "make one" for a demo.
+
strict.lua
Traps uses of undeclared global variables.
Do "make strict" for a demo.
diff --git a/etc/dummy.c b/etc/dummy.c
new file mode 100644
index 00000000..1d40e8be
--- /dev/null
+++ b/etc/dummy.c
@@ -0,0 +1,11 @@
+/*
+* dummy.c -- a minimal Lua library for testing dynamic loading
+*/
+
+#include <stdio.h>
+#include "lua.h"
+
+int luaopen_dummy (lua_State *L) {
+ puts("Hello from dummy");
+ return 0;
+}
diff --git a/etc/one.c b/etc/one.c
index be1f3a40..372543a6 100644
--- a/etc/one.c
+++ b/etc/one.c
@@ -5,10 +5,11 @@
/* default is to build the full interpreter */
#ifndef MAKE_LIB
#ifndef MAKE_LUAC
-#undef MAKE_LUA
+#ifndef MAKE_LUA
#define MAKE_LUA
#endif
#endif
+#endif
/* choose suitable platform-specific features */
/* some of these may need extra libraries such as -ldl -lreadline -lncurses */
@@ -16,7 +17,6 @@
#define LUA_USE_LINUX
#define LUA_USE_MACOSX
#define LUA_USE_POSIX
-#define LUA_USE_DLOPEN
#define LUA_ANSI
#endif
@@ -58,11 +58,11 @@
#include "loslib.c"
#include "lstrlib.c"
#include "ltablib.c"
+#include "linit.c"
#endif
/* lua */
#ifdef MAKE_LUA
-#include "linit.c"
#include "lua.c"
#endif
diff --git a/src/Makefile b/src/Makefile
index a3942a5b..83185e34 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -27,7 +27,7 @@ CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \
lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o \
ltm.o lundump.o lvm.o lzio.o
LIB_O= lauxlib.o lbaselib.o lbitlib.o ldblib.o liolib.o lmathlib.o loslib.o \
- ltablib.o lstrlib.o loadlib.o linit.o
+ lstrlib.o ltablib.o loadlib.o linit.o
LUA_T= lua
LUA_O= lua.o
@@ -103,7 +103,7 @@ macosx:
$(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_MACOSX" MYLIBS="-lreadline"
mingw:
- $(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \
+ $(MAKE) "LUA_A=lua52.dll" "LUA_T=lua.exe" \
"AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \
"MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe
@@ -137,8 +137,8 @@ ldo.o: ldo.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \
lstring.h ltable.h lundump.h lvm.h
ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \
lzio.h lmem.h lundump.h
-lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h lmem.h \
- lopcodes.h lstate.h ltm.h lzio.h
+lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h \
+ lstate.h ltm.h lzio.h lmem.h lopcodes.h
lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h
@@ -163,7 +163,7 @@ lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \
ltm.h lzio.h lstring.h lgc.h
lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h
ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
- ltm.h lzio.h lmem.h ldo.h lgc.h ltable.h
+ ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h
ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h
ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \
lmem.h lstring.h lgc.h ltable.h
diff --git a/src/lapi.c b/src/lapi.c
index 56c0c1e9..8a0378f9 100644
--- a/src/lapi.c
+++ b/src/lapi.c
@@ -1,5 +1,5 @@
/*
-** $Id: lapi.c,v 2.111 2010/01/13 16:18:25 roberto Exp $
+** $Id: lapi.c,v 2.129 2010/05/14 13:15:26 roberto Exp $
** Lua API
** See Copyright Notice in lua.h
*/
@@ -39,16 +39,6 @@ const char lua_ident[] =
"invalid index")
-static Table *getcurrenv (lua_State *L) {
- if (L->ci->previous == NULL) /* no enclosing function? */
- return G(L)->l_gt; /* use global table as environment */
- else {
- Closure *func = curr_func(L);
- return func->c.env;
- }
-}
-
-
static TValue *index2addr (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
@@ -61,26 +51,25 @@ static TValue *index2addr (lua_State *L, int idx) {
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
return L->top + idx;
}
- else switch (idx) { /* pseudo-indices */
- case LUA_REGISTRYINDEX: return &G(L)->l_registry;
- case LUA_ENVIRONINDEX: {
- sethvalue(L, &L->env, getcurrenv(L));
- return &L->env;
- }
- default: {
- Closure *func = curr_func(L);
- idx = LUA_ENVIRONINDEX - idx;
- api_check(L, idx <= UCHAR_MAX + 1, "upvalue index too large");
+ else if (idx == LUA_REGISTRYINDEX)
+ return &G(L)->l_registry;
+ else { /* upvalues */
+ idx = LUA_REGISTRYINDEX - idx;
+ api_check(L, idx <= UCHAR_MAX + 1, "upvalue index too large");
+ if (ttislcf(ci->func)) /* light C function? */
+ return cast(TValue *, luaO_nilobject); /* it has no upvalues */
+ else {
+ Closure *func = clvalue(ci->func);
return (idx <= func->c.nupvalues)
- ? &func->c.upvalue[idx-1]
- : cast(TValue *, luaO_nilobject);
+ ? &func->c.upvalue[idx-1]
+ : cast(TValue *, luaO_nilobject);
}
}
}
/*
-** to be caled by 'lua_checkstack' in protected mode, to grow stack
+** to be called by 'lua_checkstack' in protected mode, to grow stack
** capturing memory errors
*/
static void growstack (lua_State *L, void *ud) {
@@ -147,6 +136,16 @@ LUA_API const lua_Number *lua_version (lua_State *L) {
*/
+/*
+** convert an acceptable stack index into an absolute index
+*/
+LUA_API int lua_absindex (lua_State *L, int idx) {
+ return (idx > 0 || idx <= LUA_REGISTRYINDEX)
+ ? idx
+ : cast_int(L->top - L->ci->func + idx);
+}
+
+
LUA_API int lua_gettop (lua_State *L) {
return cast_int(L->top - (L->ci->func + 1));
}
@@ -195,16 +194,10 @@ LUA_API void lua_insert (lua_State *L, int idx) {
static void moveto (lua_State *L, TValue *fr, int idx) {
TValue *to = index2addr(L, idx);
api_checkvalidindex(L, to);
- if (idx == LUA_ENVIRONINDEX) {
- Closure *func = curr_func(L);
- api_check(L, ttistable(fr), "table expected");
- func->c.env = hvalue(fr);
- luaC_barrier(L, func, fr);
- }
- else {
- setobj(L, to, fr);
- if (idx < LUA_ENVIRONINDEX) /* function upvalue? */
- luaC_barrier(L, curr_func(L), fr);
+ setobj(L, to, fr);
+ if (idx < LUA_REGISTRYINDEX) { /* function upvalue? */
+ lua_assert(ttisclosure(L->ci->func));
+ luaC_barrier(L, clvalue(L->ci->func), fr);
}
/* LUA_REGISTRYINDEX does not need gc barrier
(collector revisits it before finishing collection) */
@@ -213,9 +206,6 @@ static void moveto (lua_State *L, TValue *fr, int idx) {
LUA_API void lua_replace (lua_State *L, int idx) {
lua_lock(L);
- /* explicit test for incompatible code */
- if (idx == LUA_ENVIRONINDEX && L->ci->previous == NULL)
- luaG_runerror(L, "no calling environment");
api_checknelems(L, 1);
moveto(L, L->top - 1, idx);
L->top--;
@@ -249,19 +239,19 @@ LUA_API void lua_pushvalue (lua_State *L, int idx) {
LUA_API int lua_type (lua_State *L, int idx) {
StkId o = index2addr(L, idx);
- return (o == luaO_nilobject) ? LUA_TNONE : ttype(o);
+ return (o == luaO_nilobject) ? LUA_TNONE : ttypenv(o);
}
LUA_API const char *lua_typename (lua_State *L, int t) {
UNUSED(L);
- return typename(t);
+ return ttypename(t);
}
LUA_API int lua_iscfunction (lua_State *L, int idx) {
StkId o = index2addr(L, idx);
- return iscfunction(o);
+ return (ttislcf(o) || (ttisclosure(o) && clvalue(o)->c.isC));
}
@@ -387,7 +377,10 @@ LUA_API size_t lua_rawlen (lua_State *L, int idx) {
LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) {
StkId o = index2addr(L, idx);
- return (!iscfunction(o)) ? NULL : clvalue(o)->c.f;
+ if (ttislcf(o)) return fvalue(o);
+ else if (ttisclosure(o) && clvalue(o)->c.isC)
+ return clvalue(o)->c.f;
+ else return NULL; /* not a C function */
}
@@ -412,6 +405,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
switch (ttype(o)) {
case LUA_TTABLE: return hvalue(o);
case LUA_TFUNCTION: return clvalue(o);
+ case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o)));
case LUA_TTHREAD: return thvalue(o);
case LUA_TUSERDATA:
case LUA_TLIGHTUSERDATA:
@@ -468,8 +462,16 @@ LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
lua_pushnil(L);
return NULL;
}
- else
- return lua_pushlstring(L, s, strlen(s));
+ else {
+ TString *ts;
+ lua_lock(L);
+ luaC_checkGC(L);
+ ts = luaS_new(L, s);
+ setsvalue2s(L, L->top, ts);
+ api_incr_top(L);
+ lua_unlock(L);
+ return getstr(ts);
+ }
}
@@ -498,18 +500,22 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
- Closure *cl;
lua_lock(L);
- api_checknelems(L, n);
- api_check(L, n <= UCHAR_MAX, "upvalue index too large");
- luaC_checkGC(L);
- cl = luaF_newCclosure(L, n, getcurrenv(L));
- cl->c.f = fn;
- L->top -= n;
- while (n--)
- setobj2n(L, &cl->c.upvalue[n], L->top+n);
- setclvalue(L, L->top, cl);
- lua_assert(iswhite(obj2gco(cl)));
+ if (n == 0) {
+ setfvalue(L->top, fn);
+ }
+ else {
+ Closure *cl;
+ api_checknelems(L, n);
+ api_check(L, n <= UCHAR_MAX, "upvalue index too large");
+ luaC_checkGC(L);
+ cl = luaF_newCclosure(L, n);
+ cl->c.f = fn;
+ L->top -= n;
+ while (n--)
+ setobj2n(L, &cl->c.upvalue[n], L->top + n);
+ setclvalue(L, L->top, cl);
+ }
api_incr_top(L);
lua_unlock(L);
}
@@ -616,7 +622,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
mt = uvalue(obj)->metatable;
break;
default:
- mt = G(L)->mt[ttype(obj)];
+ mt = G(L)->mt[ttypenv(obj)];
break;
}
if (mt == NULL)
@@ -631,22 +637,16 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
}
-LUA_API void lua_getfenv (lua_State *L, int idx) {
+LUA_API void lua_getenv (lua_State *L, int idx) {
StkId o;
lua_lock(L);
o = index2addr(L, idx);
api_checkvalidindex(L, o);
- switch (ttype(o)) {
- case LUA_TFUNCTION:
- sethvalue(L, L->top, clvalue(o)->c.env);
- break;
- case LUA_TUSERDATA:
- sethvalue(L, L->top, uvalue(o)->env);
- break;
- default:
- setnilvalue(L->top);
- break;
- }
+ api_check(L, ttisuserdata(o), "userdata expected");
+ if (uvalue(o)->env) {
+ sethvalue(L, L->top, uvalue(o)->env);
+ } else
+ setnilvalue(L->top);
api_incr_top(L);
lua_unlock(L);
}
@@ -737,7 +737,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
break;
}
default: {
- G(L)->mt[ttype(obj)] = mt;
+ G(L)->mt[ttypenv(obj)] = mt;
break;
}
}
@@ -747,29 +747,22 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
}
-LUA_API int lua_setfenv (lua_State *L, int idx) {
+LUA_API void lua_setenv (lua_State *L, int idx) {
StkId o;
- int res = 1;
lua_lock(L);
api_checknelems(L, 1);
o = index2addr(L, idx);
api_checkvalidindex(L, o);
- api_check(L, ttistable(L->top - 1), "table expected");
- switch (ttype(o)) {
- case LUA_TFUNCTION:
- clvalue(o)->c.env = hvalue(L->top - 1);
- break;
- case LUA_TUSERDATA:
- uvalue(o)->env = hvalue(L->top - 1);
- break;
- default:
- res = 0;
- break;
+ api_check(L, ttisuserdata(o), "userdata expected");
+ if (ttisnil(L->top - 1))
+ uvalue(o)->env = NULL;
+ else {
+ api_check(L, ttistable(L->top - 1), "table expected");
+ uvalue(o)->env = hvalue(L->top - 1);
+ luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1));
}
- if (res) luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1));
L->top--;
lua_unlock(L);
- return res;
}
@@ -857,7 +850,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
ci->u.c.k = k; /* save continuation */
ci->u.c.ctx = ctx; /* save context */
/* save information for error recovery */
- ci->u.c.oldtop = savestack(L, c.func);
+ ci->u.c.extra = savestack(L, c.func);
ci->u.c.old_allowhook = L->allowhook;
ci->u.c.old_errfunc = L->errfunc;
L->errfunc = func;
@@ -882,6 +875,18 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
if (!chunkname) chunkname = "?";
luaZ_init(L, &z, reader, data);
status = luaD_protectedparser(L, &z, chunkname);
+ if (status == LUA_OK) { /* no errors? */
+ Closure *f = clvalue(L->top - 1); /* get newly created function */
+ lua_assert(!f->c.isC);
+ if (f->l.nupvalues == 1) { /* does it have one upvalue? */
+ /* get global table from registry */
+ Table *reg = hvalue(&G(L)->l_registry);
+ const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
+ /* set global table as 1st upvalue of 'f' (may be _ENV) */
+ setobj(L, f->l.upvals[0]->v, gt);
+ luaC_barrier(L, f->l.upvals[0], gt);
+ }
+ }
lua_unlock(L);
return status;
}
@@ -918,11 +923,11 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
g = G(L);
switch (what) {
case LUA_GCSTOP: {
- g->GCthreshold = MAX_LUMEM;
+ stopgc(g);
break;
}
case LUA_GCRESTART: {
- g->GCthreshold = g->totalbytes;
+ g->GCdebt = 0;
break;
}
case LUA_GCCOLLECT: {
@@ -939,18 +944,22 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
break;
}
case LUA_GCSTEP: {
- lu_mem oldts = g->GCthreshold;
- lu_mem a = (cast(lu_mem, data) << 10);
- g->GCthreshold = (a <= g->totalbytes) ? g->totalbytes - a : 0;
- while (g->GCthreshold <= g->totalbytes) {
- luaC_step(L);
- if (g->gcstate == GCSpause) { /* end of cycle? */
- res = 1; /* signal it */
- break;
+ int stopped = gcstopped(g);
+ if (g->gckind == KGC_GEN) { /* generational mode? */
+ res = (g->lastmajormem == 0); /* 1 if will do major collection */
+ luaC_step(L); /* do a single step */
+ }
+ else {
+ while (data-- >= 0) {
+ luaC_step(L);
+ if (g->gcstate == GCSpause) { /* end of cycle? */
+ res = 1; /* signal it */
+ break;
+ }
}
}
- if (oldts == MAX_LUMEM) /* collector was stopped? */
- g->GCthreshold = oldts; /* keep it that way */
+ if (stopped) /* collector was stopped? */
+ stopgc(g); /* keep it that way */
break;
}
case LUA_GCSETPAUSE: {
@@ -964,7 +973,15 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
break;
}
case LUA_GCISRUNNING: {
- res = (g->GCthreshold != MAX_LUMEM);
+ res = !gcstopped(g);
+ break;
+ }
+ case LUA_GCGEN: { /* change collector to generational mode */
+ luaC_changemode(L, KGC_GEN);
+ break;
+ }
+ case LUA_GCINC: { /* change collector to incremental mode */
+ luaC_changemode(L, KGC_NORMAL);
break;
}
default: res = -1; /* invalid option */
@@ -1054,7 +1071,7 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
Udata *u;
lua_lock(L);
luaC_checkGC(L);
- u = luaS_newudata(L, size, getcurrenv(L));
+ u = luaS_newudata(L, size, NULL);
setuvalue(L, L->top, u);
api_incr_top(L);
lua_unlock(L);
@@ -1064,19 +1081,22 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
-static const char *aux_upvalue (StkId fi, int n, TValue **val) {
+static const char *aux_upvalue (StkId fi, int n, TValue **val,
+ GCObject **owner) {
Closure *f;
- if (!ttisfunction(fi)) return NULL;
+ if (!ttisclosure(fi)) return NULL;
f = clvalue(fi);
if (f->c.isC) {
if (!(1 <= n && n <= f->c.nupvalues)) return NULL;
*val = &f->c.upvalue[n-1];
+ if (owner) *owner = obj2gco(f);
return "";
}
else {
Proto *p = f->l.p;
if (!(1 <= n && n <= p->sizeupvalues)) return NULL;
*val = f->l.upvals[n-1]->v;
+ if (owner) *owner = obj2gco(f->l.upvals[n - 1]);
return getstr(p->upvalues[n-1].name);
}
}
@@ -1086,7 +1106,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
const char *name;
TValue *val;
lua_lock(L);
- name = aux_upvalue(index2addr(L, funcindex), n, &val);
+ name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL);
if (name) {
setobj2s(L, L->top, val);
api_incr_top(L);
@@ -1099,15 +1119,16 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
const char *name;
TValue *val;
+ GCObject *owner;
StkId fi;
lua_lock(L);
fi = index2addr(L, funcindex);
api_checknelems(L, 1);
- name = aux_upvalue(fi, n, &val);
+ name = aux_upvalue(fi, n, &val, &owner);
if (name) {
L->top--;
setobj(L, val, L->top);
- luaC_barrier(L, clvalue(fi), L->top);
+ luaC_barrier(L, owner, L->top);
}
lua_unlock(L);
return name;
@@ -1118,7 +1139,7 @@ static UpVal **getupvalref (lua_State *L, int fidx, int n, Closure **pf) {
Closure *f;
Proto *p;
StkId fi = index2addr(L, fidx);
- api_check(L, ttisfunction(fi), "function expected");
+ api_check(L, ttisclosure(fi), "Lua function expected");
f = clvalue(fi);
api_check(L, !f->c.isC, "Lua function expected");
p = f->l.p;
@@ -1131,7 +1152,7 @@ static UpVal **getupvalref (lua_State *L, int fidx, int n, Closure **pf) {
LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) {
Closure *f;
StkId fi = index2addr(L, fidx);
- api_check(L, ttisfunction(fi), "function expected");
+ api_check(L, ttisclosure(fi), "function expected");
f = clvalue(fi);
if (f->c.isC) {
api_check(L, 1 <= n && n <= f->c.nupvalues, "invalid upvalue index");
@@ -1150,12 +1171,3 @@ LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
luaC_objbarrier(L, f1, *up2);
}
-
-#if defined(LUA_COMPAT_CPCALL)
-LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) {
- lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_CPCALL);
- lua_pushlightuserdata(L, &func);
- lua_pushlightuserdata(L, ud);
- return lua_pcall(L, 2, 0, 0);
-}
-#endif
diff --git a/src/lauxlib.c b/src/lauxlib.c
index 9972555e..8ebc18fa 100644
--- a/src/lauxlib.c
+++ b/src/lauxlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lauxlib.c,v 1.196 2009/12/22 15:32:50 roberto Exp $
+** $Id: lauxlib.c,v 1.212 2010/05/18 17:21:24 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -24,11 +24,6 @@
#include "lauxlib.h"
-/* convert a stack index to positive */
-#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \
- lua_gettop(L) + (i) + 1)
-
-
/*
** {======================================================
** Traceback
@@ -347,54 +342,40 @@ LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg,
** =======================================================
*/
-
-#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->lvl++;
- return 1;
- }
-}
+/*
+** check whether buffer is using a userdata on the stack as a temporary
+** buffer
+*/
+#define buffonstack(B) ((B)->b != (B)->initb)
-static void adjuststack (luaL_Buffer *B) {
- if (B->lvl > 1) {
- lua_State *L = B->L;
- int toget = 1; /* number of levels to concat */
- size_t toplen = lua_rawlen(L, -1);
- do {
- size_t l = lua_rawlen(L, -(toget+1));
- if (B->lvl - toget + 1 >= LIMIT || toplen > l) {
- toplen += l;
- toget++;
- }
- else break;
- } while (toget < B->lvl);
- lua_concat(L, toget);
- B->lvl = B->lvl - toget + 1;
+/*
+** returns a pointer to a free area with at least 'sz' bytes
+*/
+LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
+ lua_State *L = B->L;
+ if (B->size - B->n < sz) { /* not enough space? */
+ char *newbuff;
+ size_t newsize = B->size * 2; /* double buffer size */
+ if (newsize - B->n < sz) /* not bit enough? */
+ newsize = B->n + sz;
+ if (newsize < B->n || newsize - B->n < sz)
+ luaL_error(L, "string too large");
+ newbuff = (char *)lua_newuserdata(L, newsize); /* create larger buffer */
+ memcpy(newbuff, B->b, B->n); /* move content to new buffer */
+ if (buffonstack(B))
+ lua_remove(L, -2); /* remove old buffer */
+ B->b = newbuff;
+ B->size = newsize;
}
-}
-
-
-LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) {
- if (emptybuffer(B))
- adjuststack(B);
- return B->buffer;
+ return &B->b[B->n];
}
LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
- while (l--)
- luaL_addchar(B, *s++);
+ char *b = luaL_prepbuffsize(B, l);
+ memcpy(b, s, l);
+ luaL_addsize(B, l);
}
@@ -404,35 +385,41 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
- emptybuffer(B);
- lua_concat(B->L, B->lvl);
- B->lvl = 1;
+ lua_State *L = B->L;
+ lua_pushlstring(L, B->b, B->n);
+ if (buffonstack(B))
+ lua_remove(L, -2); /* remove old buffer */
+}
+
+
+LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
+ luaL_addsize(B, sz);
+ luaL_pushresult(B);
}
LUALIB_API void luaL_addvalue (luaL_Buffer *B) {
lua_State *L = B->L;
- size_t vl;
- const char *s = lua_tolstring(L, -1, &vl);
- if (vl <= bufffree(B)) { /* fit into buffer? */
- memcpy(B->p, s, 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->lvl++; /* add new value into B stack */
- adjuststack(B);
- }
+ size_t l;
+ const char *s = lua_tolstring(L, -1, &l);
+ if (buffonstack(B))
+ lua_insert(L, -2); /* put value below buffer */
+ luaL_addlstring(B, s, l);
+ lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */
}
LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
- luaL_checkstack(L, LIMIT + LUA_MINSTACK, "no space for new buffer");
B->L = L;
- B->p = B->buffer;
- B->lvl = 0;
+ B->b = B->initb;
+ B->n = 0;
+ B->size = LUAL_BUFFERSIZE;
+}
+
+
+LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {
+ luaL_buffinit(L, B);
+ return luaL_prepbuffsize(B, sz);
}
/* }====================================================== */
@@ -444,32 +431,26 @@ LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
** =======================================================
*/
-/* number of prereserved references (for internal use) */
-#define FREELIST_REF (LUA_RIDX_LAST + 1) /* free list of references */
+/* index of free-list header */
+#define freelist "lua-freelist"
LUALIB_API int luaL_ref (lua_State *L, int t) {
int ref;
- t = abs_index(L, t);
+ t = lua_absindex(L, t);
if (lua_isnil(L, -1)) {
lua_pop(L, 1); /* remove from stack */
return LUA_REFNIL; /* `nil' has a unique fixed reference */
}
- lua_rawgeti(L, t, FREELIST_REF); /* get first free element */
+ lua_getfield(L, t, freelist); /* get first free element */
ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */
lua_pop(L, 1); /* remove it from stack */
if (ref != 0) { /* any free element? */
lua_rawgeti(L, t, ref); /* remove it from list */
- lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */
+ lua_setfield(L, t, freelist); /* (t[freelist] = t[ref]) */
}
- else { /* no free elements */
+ else /* no free elements */
ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */
- if (ref == FREELIST_REF) { /* FREELIST_REF not initialized? */
- lua_pushinteger(L, 0);
- lua_rawseti(L, t, FREELIST_REF);
- ref = FREELIST_REF + 1;
- }
- }
lua_rawseti(L, t, ref);
return ref;
}
@@ -477,11 +458,11 @@ LUALIB_API int luaL_ref (lua_State *L, int t) {
LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
if (ref >= 0) {
- t = abs_index(L, t);
- lua_rawgeti(L, t, FREELIST_REF);
- lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */
+ t = lua_absindex(L, t);
+ lua_getfield(L, t, freelist);
+ lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */
lua_pushinteger(L, ref);
- lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */
+ lua_setfield(L, t, freelist); /* t[freelist] = ref */
}
}
@@ -495,7 +476,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
*/
typedef struct LoadF {
- int extraline;
+ int first;
FILE *f;
char buff[LUAL_BUFFERSIZE];
} LoadF;
@@ -504,17 +485,19 @@ typedef struct LoadF {
static const char *getF (lua_State *L, void *ud, size_t *size) {
LoadF *lf = (LoadF *)ud;
(void)L;
- if (lf->extraline) {
- lf->extraline = 0;
+ if (lf->first != EOF) {
*size = 1;
- return "\n";
+ lf->buff[0] = (char)lf->first;
+ lf->first = EOF;
+ }
+ else {
+ /* 'fread' can return > 0 *and* set the EOF flag. If next call to
+ 'getF' called 'fread', it might still wait for user input.
+ The next check avoids this problem. */
+ if (feof(lf->f)) return NULL;
+ *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);
}
- /* 'fread' can return > 0 *and* set the EOF flag. If next call to
- 'getF' calls 'fread', terminal may still wait for user input.
- The next check avoids this problem. */
- if (feof(lf->f)) return NULL;
- *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);
- return (*size > 0) ? lf->buff : NULL;
+ return lf->buff;
}
@@ -532,7 +515,6 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {
int status, readstatus;
int c;
int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */
- lf.extraline = 0;
if (filename == NULL) {
lua_pushliteral(L, "=stdin");
lf.f = stdin;
@@ -544,18 +526,14 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {
}
c = getc(lf.f);
if (c == '#') { /* Unix exec. file? */
- lf.extraline = 1;
while ((c = getc(lf.f)) != EOF && c != '\n') ; /* skip first line */
- if (c == '\n') c = getc(lf.f);
}
- if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
+ else if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
- /* skip eventual `#!...' */
- while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ;
- lf.extraline = 0;
+ c = getc(lf.f); /* re-read first character */
}
- ungetc(c, lf.f);
+ lf.first = c; /* 'c' is the first character of the stream */
status = lua_load(L, getF, &lf, lua_tostring(L, -1));
readstatus = ferror(lf.f);
if (filename) fclose(lf.f); /* close file (even in case of errors) */
@@ -618,7 +596,7 @@ LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) {
- obj = abs_index(L, obj);
+ obj = lua_absindex(L, obj);
if (!luaL_getmetafield(L, obj, event)) /* no metafield? */
return 0;
lua_pushvalue(L, obj);
@@ -663,13 +641,13 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
static int libsize (const luaL_Reg *l) {
int size = 0;
- for (; l->name; l++) size++;
+ for (; l && l->name; l++) size++;
return size;
}
-LUALIB_API void luaL_register (lua_State *L, const char *libname,
- const luaL_Reg *l) {
+LUALIB_API void luaL_openlib (lua_State *L, const char *libname,
+ const luaL_Reg *l, int nup) {
luaL_checkversion(L);
if (libname) {
/* check whether lib already exists */
@@ -685,12 +663,17 @@ LUALIB_API void luaL_register (lua_State *L, const char *libname,
lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */
}
lua_remove(L, -2); /* remove _LOADED table */
+ lua_insert(L, -(nup + 1)); /* move library table to below upvalues */
}
- if (l == NULL) return; /* nothing to register? */
- for (; l->name; l++) { /* else fill the table with given functions */
- lua_pushcfunction(L, l->func);
- lua_setfield(L, -2, l->name);
+ luaL_checkstack(L, nup, "too many upvalues");
+ for (; l && l->name; l++) { /* fill the table with given functions */
+ int i;
+ for (i = 0; i < nup; i++) /* copy upvalues to the top */
+ lua_pushvalue(L, -nup);
+ lua_pushcclosure(L, l->func, nup);
+ lua_setfield(L, -(nup + 2), l->name);
}
+ lua_pop(L, nup); /* remove upvalues */
}
@@ -751,7 +734,7 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
static int panic (lua_State *L) {
- fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n",
+ luai_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
lua_tostring(L, -1));
return 0; /* return to Lua to abort */
}
diff --git a/src/lauxlib.h b/src/lauxlib.h
index b8f2e2e5..ae2e2c75 100644
--- a/src/lauxlib.h
+++ b/src/lauxlib.h
@@ -1,5 +1,5 @@
/*
-** $Id: lauxlib.h,v 1.99 2010/01/11 16:00:45 roberto Exp $
+** $Id: lauxlib.h,v 1.105 2010/05/04 17:21:08 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -29,11 +29,11 @@ typedef struct luaL_Reg {
LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver);
#define luaL_checkversion(L) luaL_checkversion_(L, LUA_VERSION_NUM)
-LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
- const luaL_Reg *l);
+LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
+ const luaL_Reg *l, int nup);
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
-LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len);
+LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);
LUALIB_API int (luaL_typeerror) (lua_State *L, int narg, const char *tname);
LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
@@ -71,7 +71,7 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
LUALIB_API lua_State *(luaL_newstate) (void);
-LUALIB_API int luaL_len (lua_State *L, int idx);
+LUALIB_API int (luaL_len) (lua_State *L, int idx);
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
const char *r);
@@ -79,9 +79,8 @@ LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx,
const char *fname, int szhint);
-LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
- const char *msg, int level);
-
+LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,
+ const char *msg, int level);
/*
@@ -111,34 +110,40 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
+#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0))
+
+
/*
** {======================================================
** Generic Buffer manipulation
** =======================================================
*/
-
-
typedef struct luaL_Buffer {
- char *p; /* current position in buffer */
- int lvl; /* number of strings in the stack (level) */
+ char *b; /* buffer address */
+ size_t size; /* buffer size */
+ size_t n; /* number of characters in buffer */
lua_State *L;
- char buffer[LUAL_BUFFERSIZE];
+ char initb[LUAL_BUFFERSIZE]; /* initial buffer */
} luaL_Buffer;
+
#define luaL_addchar(B,c) \
- ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
- (*(B)->p++ = (char)(c)))
+ ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \
+ ((B)->b[(B)->n++] = (c)))
-#define luaL_addsize(B,n) ((B)->p += (n))
+#define luaL_addsize(B,s) ((B)->n += (s))
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
-LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B);
+LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
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);
+LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz);
+LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz);
+#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
/* }====================================================== */
diff --git a/src/lbaselib.c b/src/lbaselib.c
index 162c06f2..946ecea5 100644
--- a/src/lbaselib.c
+++ b/src/lbaselib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lbaselib.c,v 1.235 2009/12/28 16:30:31 roberto Exp $
+** $Id: lbaselib.c,v 1.243 2010/04/19 17:02:02 roberto Exp $
** Basic library
** See Copyright Notice in lua.h
*/
@@ -23,7 +23,7 @@
static int luaB_print (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
int i;
- lua_getfield(L, LUA_ENVIRONINDEX, "tostring");
+ lua_getglobal(L, "tostring");
for (i=1; i<=n; i++) {
const char *s;
size_t l;
@@ -107,50 +107,12 @@ static int luaB_setmetatable (lua_State *L) {
}
-
-#if defined(LUA_COMPAT_FENV)
-
-static void getfunc (lua_State *L, int opt) {
- if (lua_isfunction(L, 1)) lua_pushvalue(L, 1);
- else {
- lua_Debug ar;
- int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1);
- luaL_argcheck(L, level >= 0, 1, "level must be non-negative");
- if (lua_getstack(L, level, &ar) == 0)
- luaL_argerror(L, 1, "invalid level");
- lua_getinfo(L, "f", &ar);
- }
-}
-
-static int luaB_getfenv (lua_State *L) {
- getfunc(L, 1);
- if (lua_iscfunction(L, -1)) /* is a C function? */
- lua_pushglobaltable(L); /* return the global env. */
- else
- lua_getfenv(L, -1);
- return 1;
-}
-
-static int luaB_setfenv (lua_State *L) {
- luaL_checktype(L, 2, LUA_TTABLE);
- getfunc(L, 0);
- lua_pushvalue(L, 2);
- if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0)
- return luaL_error(L,
- LUA_QL("setfenv") " cannot change environment of given object");
- return 1;
-}
-
-#else
-
static int luaB_getfenv (lua_State *L) {
return luaL_error(L, "getfenv/setfenv deprecated");
}
#define luaB_setfenv luaB_getfenv
-#endif
-
static int luaB_rawequal (lua_State *L) {
luaL_checkany(L, 1);
@@ -178,18 +140,13 @@ static int luaB_rawset (lua_State *L) {
}
-static int luaB_gcinfo (lua_State *L) {
- lua_pushinteger(L, lua_gc(L, LUA_GCCOUNT, 0));
- return 1;
-}
-
-
static int luaB_collectgarbage (lua_State *L) {
static const char *const opts[] = {"stop", "restart", "collect",
- "count", "step", "setpause", "setstepmul", "isrunning", NULL};
+ "count", "step", "setpause", "setstepmul", "isrunning",
+ "gen", "inc", NULL};
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
- LUA_GCISRUNNING};
+ LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC};
int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
int ex = luaL_optint(L, 2, 0);
int res = lua_gc(L, o, ex);
@@ -219,10 +176,11 @@ static int luaB_type (lua_State *L) {
}
-static int pairsmeta (lua_State *L, const char *method, int iszero) {
+static int pairsmeta (lua_State *L, const char *method, int iszero,
+ lua_CFunction iter) {
if (!luaL_getmetafield(L, 1, method)) { /* no metamethod? */
luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */
- lua_pushvalue(L, lua_upvalueindex(1)); /* will return generator, */
+ lua_pushcfunction(L, iter); /* will return generator, */
lua_pushvalue(L, 1); /* state, */
if (iszero) lua_pushinteger(L, 0); /* and initial value */
else lua_pushnil(L);
@@ -248,10 +206,12 @@ static int luaB_next (lua_State *L) {
static int luaB_pairs (lua_State *L) {
- return pairsmeta(L, "__pairs", 0);
+ return pairsmeta(L, "__pairs", 0, luaB_next);
}
+#if defined(LUA_COMPAT_IPAIRS)
+
static int ipairsaux (lua_State *L) {
int i = luaL_checkint(L, 2);
luaL_checktype(L, 1, LUA_TTABLE);
@@ -263,9 +223,17 @@ static int ipairsaux (lua_State *L) {
static int luaB_ipairs (lua_State *L) {
- return pairsmeta(L, "__ipairs", 1);
+ return pairsmeta(L, "__ipairs", 1, ipairsaux);
+}
+
+#else
+
+static int luaB_ipairs (lua_State *L) {
+ return luaL_error(L, "'ipairs' deprecated");
}
+#endif
+
static int load_aux (lua_State *L, int status) {
if (status == LUA_OK)
@@ -376,7 +344,7 @@ static int luaB_loadin (lua_State *L) {
n = luaB_load_aux(L, 2);
if (n == 1) { /* success? */
lua_pushvalue(L, 1); /* environment for loaded function */
- lua_setfenv(L, -2);
+ lua_setupvalue(L, -2, 1);
}
return n;
}
@@ -507,14 +475,15 @@ static const luaL_Reg base_funcs[] = {
{"collectgarbage", luaB_collectgarbage},
{"dofile", luaB_dofile},
{"error", luaB_error},
- {"gcinfo", luaB_gcinfo},
{"getfenv", luaB_getfenv},
{"getmetatable", luaB_getmetatable},
+ {"ipairs", luaB_ipairs},
{"loadfile", luaB_loadfile},
{"load", luaB_load},
{"loadin", luaB_loadin},
{"loadstring", luaB_loadstring},
{"next", luaB_next},
+ {"pairs", luaB_pairs},
{"pcall", luaB_pcall},
{"print", luaB_print},
{"rawequal", luaB_rawequal},
@@ -668,25 +637,15 @@ static const luaL_Reg co_funcs[] = {
/* }====================================================== */
-static void auxopen (lua_State *L, const char *name,
- lua_CFunction f, lua_CFunction u) {
- lua_pushcfunction(L, u);
- lua_pushcclosure(L, f, 1);
- lua_setfield(L, -2, name);
-}
-
-
static void base_open (lua_State *L) {
/* set global _G */
lua_pushglobaltable(L);
- lua_setfield(L, LUA_ENVIRONINDEX, "_G");
+ lua_pushglobaltable(L);
+ lua_setfield(L, -2, "_G");
/* open lib into global table */
luaL_register(L, "_G", base_funcs);
lua_pushliteral(L, LUA_VERSION);
- lua_setfield(L, LUA_ENVIRONINDEX, "_VERSION"); /* set global _VERSION */
- /* `ipairs' and `pairs' need auxiliary functions as upvalues */
- auxopen(L, "ipairs", luaB_ipairs, ipairsaux);
- auxopen(L, "pairs", luaB_pairs, luaB_next);
+ lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */
/* `newproxy' needs a weaktable as upvalue */
lua_createtable(L, 0, 1); /* new table `w' */
lua_pushvalue(L, -1); /* `w' will be its own metatable */
@@ -694,7 +653,7 @@ static void base_open (lua_State *L) {
lua_pushliteral(L, "kv");
lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */
lua_pushcclosure(L, luaB_newproxy, 1);
- lua_setfield(L, LUA_ENVIRONINDEX, "newproxy"); /* set global `newproxy' */
+ lua_setfield(L, -2, "newproxy"); /* set global `newproxy' */
}
diff --git a/src/lbitlib.c b/src/lbitlib.c
index 1d5a2642..b367d0c6 100644
--- a/src/lbitlib.c
+++ b/src/lbitlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lbitlib.c,v 1.3 2010/01/12 19:40:02 roberto Exp $
+** $Id: lbitlib.c,v 1.4 2010/02/11 15:55:29 roberto Exp $
** Standard library for bitwise operations
** See Copyright Notice in lua.h
*/
@@ -80,9 +80,8 @@ static int b_not (lua_State *L) {
}
-static int b_shift (lua_State *L) {
+static int b_shift (lua_State *L, int i) {
b_uint r = getuintarg(L, 1);
- lua_Integer i = luaL_checkinteger(L, 2);
if (i < 0) { /* shift right? */
i = -i;
if (i >= NBITS) r = 0;
@@ -97,9 +96,18 @@ static int b_shift (lua_State *L) {
}
-static int b_rotate (lua_State *L) {
+static int b_lshift (lua_State *L) {
+ return b_shift(L, luaL_checkint(L, 2));
+}
+
+
+static int b_rshift (lua_State *L) {
+ return b_shift(L, -luaL_checkint(L, 2));
+}
+
+
+static int b_rot (lua_State *L, int i) {
b_uint r = getuintarg(L, 1);
- lua_Integer i = luaL_checkinteger(L, 2);
i &= (NBITS - 1); /* i = i % NBITS */
r = (r << i) | (r >> (NBITS - i));
lua_pushnumber(L, lua_uint2number(r));
@@ -107,14 +115,26 @@ static int b_rotate (lua_State *L) {
}
+static int b_rol (lua_State *L) {
+ return b_rot(L, luaL_checkint(L, 2));
+}
+
+
+static int b_ror (lua_State *L) {
+ return b_rot(L, -luaL_checkint(L, 2));
+}
+
+
static const luaL_Reg bitlib[] = {
{"band", b_and},
{"btest", b_test},
{"bor", b_or},
{"bxor", b_xor},
{"bnot", b_not},
- {"bshift", b_shift},
- {"brotate", b_rotate},
+ {"lshift", b_lshift},
+ {"rshift", b_rshift},
+ {"rol", b_rol},
+ {"ror", b_ror},
{NULL, NULL}
};
diff --git a/src/lcode.c b/src/lcode.c
index c55ebd54..d060b5f0 100644
--- a/src/lcode.c
+++ b/src/lcode.c
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.c,v 2.43 2010/01/11 17:38:30 roberto Exp $
+** $Id: lcode.c,v 2.46 2010/04/17 12:46:32 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -372,11 +372,6 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
e->k = VRELOCABLE;
break;
}
- case VGLOBAL: {
- e->u.s.info = luaK_codeABxX(fs, OP_GETGLOBAL, 0, e->u.s.info);
- e->k = VRELOCABLE;
- break;
- }
case VINDEXED: {
freereg(fs, e->u.s.aux);
freereg(fs, e->u.s.info);
@@ -384,6 +379,12 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
e->k = VRELOCABLE;
break;
}
+ case VINDEXEDUP: {
+ freereg(fs, e->u.s.aux);
+ e->u.s.info = luaK_codeABC(fs, OP_GETTABUP, 0, e->u.s.info, e->u.s.aux);
+ e->k = VRELOCABLE;
+ break;
+ }
case VVARARG:
case VCALL: {
luaK_setoneret(fs, e);
@@ -493,6 +494,12 @@ int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
}
+void luaK_exp2anyregup (FuncState *fs, expdesc *e) {
+ if (e->k != VUPVAL || hasjumps(e))
+ luaK_exp2anyreg(fs, e);
+}
+
+
void luaK_exp2val (FuncState *fs, expdesc *e) {
if (hasjumps(e))
luaK_exp2anyreg(fs, e);
@@ -543,16 +550,16 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0);
break;
}
- case VGLOBAL: {
- int e = luaK_exp2anyreg(fs, ex);
- luaK_codeABxX(fs, OP_SETGLOBAL, e, var->u.s.info);
- break;
- }
case VINDEXED: {
int e = luaK_exp2RK(fs, ex);
luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e);
break;
}
+ case VINDEXEDUP: {
+ int e = luaK_exp2RK(fs, ex);
+ luaK_codeABC(fs, OP_SETTABUP, var->u.s.info, var->u.s.aux, e);
+ break;
+ }
default: {
lua_assert(0); /* invalid var kind to store */
break;
@@ -567,9 +574,9 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
luaK_exp2anyreg(fs, e);
freeexp(fs, e);
func = fs->freereg;
- luaK_reserveregs(fs, 2);
luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key));
freeexp(fs, key);
+ luaK_reserveregs(fs, 2);
e->u.s.info = func;
e->k = VNONRELOC;
}
@@ -695,8 +702,9 @@ static void codenot (FuncState *fs, expdesc *e) {
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
+ lua_assert(!hasjumps(t));
t->u.s.aux = luaK_exp2RK(fs, k);
- t->k = VINDEXED;
+ t->k = (t->k == VUPVAL) ? VINDEXEDUP : VINDEXED;
}
@@ -711,7 +719,8 @@ static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
}
-static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
+static void codearith (FuncState *fs, OpCode op,
+ expdesc *e1, expdesc *e2, int line) {
if (constfolding(op, e1, e2))
return;
else {
@@ -727,6 +736,7 @@ static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
}
e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2);
e1->k = VRELOCABLE;
+ luaK_fixline(fs, line);
}
}
@@ -747,7 +757,7 @@ static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
}
-void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
+void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
expdesc e2;
e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
switch (op) {
@@ -756,14 +766,14 @@ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
e->u.nval = luai_numunm(NULL, e->u.nval); /* fold it */
else {
luaK_exp2anyreg(fs, e);
- codearith(fs, OP_UNM, e, &e2);
+ codearith(fs, OP_UNM, e, &e2, line);
}
break;
}
case OPR_NOT: codenot(fs, e); break;
case OPR_LEN: {
luaK_exp2anyreg(fs, e); /* cannot operate on constants */
- codearith(fs, OP_LEN, e, &e2);
+ codearith(fs, OP_LEN, e, &e2, line);
break;
}
default: lua_assert(0);
@@ -798,7 +808,8 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
}
-void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
+void luaK_posfix (FuncState *fs, BinOpr op,
+ expdesc *e1, expdesc *e2, int line) {
switch (op) {
case OPR_AND: {
lua_assert(e1->t == NO_JUMP); /* list must be closed */
@@ -824,13 +835,13 @@ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
}
else {
luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
- codearith(fs, OP_CONCAT, e1, e2);
+ codearith(fs, OP_CONCAT, e1, e2, line);
}
break;
}
case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
case OPR_MOD: case OPR_POW: {
- codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2);
+ codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2, line);
break;
}
case OPR_EQ: case OPR_LT: case OPR_LE: {
diff --git a/src/lcode.h b/src/lcode.h
index 8ef67e55..d7f7dd62 100644
--- a/src/lcode.h
+++ b/src/lcode.h
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.h,v 1.52 2009/09/23 20:33:05 roberto Exp $
+** $Id: lcode.h,v 1.54 2010/04/17 12:46:32 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -57,6 +57,7 @@ LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s);
LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r);
LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
@@ -72,9 +73,10 @@ LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);
LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);
LUAI_FUNC int luaK_getlabel (FuncState *fs);
-LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v);
+LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line);
LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
-LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2);
+LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1,
+ expdesc *v2, int line);
LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
diff --git a/src/ldblib.c b/src/ldblib.c
index eeaedc1f..28e671df 100644
--- a/src/ldblib.c
+++ b/src/ldblib.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldblib.c,v 1.119 2010/01/06 14:42:35 roberto Exp $
+** $Id: ldblib.c,v 1.121 2010/03/26 20:58:11 roberto Exp $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
@@ -44,19 +44,19 @@ static int db_setmetatable (lua_State *L) {
}
-static int db_getfenv (lua_State *L) {
- luaL_checkany(L, 1);
- lua_getfenv(L, 1);
+static int db_getenv (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TUSERDATA);
+ lua_getenv(L, 1);
return 1;
}
-static int db_setfenv (lua_State *L) {
- luaL_checktype(L, 2, LUA_TTABLE);
+static int db_setenv (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TUSERDATA);
+ if (!lua_isnoneornil(L, 2))
+ luaL_checktype(L, 2, LUA_TTABLE);
lua_settop(L, 2);
- if (lua_setfenv(L, 1) == 0)
- luaL_error(L, LUA_QL("setfenv")
- " cannot change environment of given object");
+ lua_setenv(L, 1);
return 1;
}
@@ -339,15 +339,13 @@ static int db_gethook (lua_State *L) {
static int db_debug (lua_State *L) {
for (;;) {
char buffer[250];
- fputs("lua_debug> ", stderr);
+ luai_writestringerror("%s", "lua_debug> ");
if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
strcmp(buffer, "cont\n") == 0)
return 0;
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
- lua_pcall(L, 0, 0, 0)) {
- fputs(lua_tostring(L, -1), stderr);
- fputs("\n", stderr);
- }
+ lua_pcall(L, 0, 0, 0))
+ luai_writestringerror("%s\n", lua_tostring(L, -1));
lua_settop(L, 0); /* remove eventual returns */
}
}
@@ -369,7 +367,7 @@ static int db_traceback (lua_State *L) {
static const luaL_Reg dblib[] = {
{"debug", db_debug},
- {"getfenv", db_getfenv},
+ {"getenv", db_getenv},
{"gethook", db_gethook},
{"getinfo", db_getinfo},
{"getlocal", db_getlocal},
@@ -378,7 +376,7 @@ static const luaL_Reg dblib[] = {
{"getupvalue", db_getupvalue},
{"upvaluejoin", db_upvaluejoin},
{"upvalueid", db_upvalueid},
- {"setfenv", db_setfenv},
+ {"setenv", db_setenv},
{"sethook", db_sethook},
{"setlocal", db_setlocal},
{"setmetatable", db_setmetatable},
diff --git a/src/ldebug.c b/src/ldebug.c
index 2544a5dd..dcc8ca99 100644
--- a/src/ldebug.c
+++ b/src/ldebug.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldebug.c,v 2.63 2010/01/13 16:18:25 roberto Exp $
+** $Id: ldebug.c,v 2.70 2010/04/13 20:48:12 roberto Exp $
** Debug Interface
** See Copyright Notice in lua.h
*/
@@ -144,7 +144,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
static void funcinfo (lua_Debug *ar, Closure *cl) {
- if (cl->c.isC) {
+ if (cl == NULL || cl->c.isC) {
ar->source = "=[C]";
ar->linedefined = -1;
ar->lastlinedefined = -1;
@@ -191,8 +191,8 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
break;
}
case 'u': {
- ar->nups = f->c.nupvalues;
- if (f->c.isC) {
+ ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
+ if (f == NULL || f->c.isC) {
ar->isvararg = 1;
ar->nparams = 0;
}
@@ -226,28 +226,30 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
int status;
- Closure *f = NULL;
- CallInfo *ci = NULL;
+ Closure *cl;
+ CallInfo *ci;
+ StkId func;
lua_lock(L);
if (*what == '>') {
- StkId func = L->top - 1;
+ ci = NULL;
+ func = L->top - 1;
luai_apicheck(L, ttisfunction(func));
what++; /* skip the '>' */
- f = clvalue(func);
L->top--; /* pop function */
}
else {
ci = ar->i_ci;
+ func = ci->func;
lua_assert(ttisfunction(ci->func));
- f = clvalue(ci->func);
}
- status = auxgetinfo(L, what, ar, f, ci);
+ cl = ttisclosure(func) ? clvalue(func) : NULL;
+ status = auxgetinfo(L, what, ar, cl, ci);
if (strchr(what, 'f')) {
- setclvalue(L, L->top, f);
+ setobjs2s(L, L->top, func);
incr_top(L);
}
if (strchr(what, 'L'))
- collectvalidlines(L, f);
+ collectvalidlines(L, cl);
lua_unlock(L);
return status;
}
@@ -260,22 +262,23 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
*/
-static const char *kname (Proto *p, int c) {
- if (ISK(c) && ttisstring(&p->k[INDEXK(c)]))
- return svalue(&p->k[INDEXK(c)]);
+static void kname (Proto *p, int c, int reg, const char *what,
+ const char **name) {
+ if (c == reg && *what == 'c')
+ return; /* index is a constant; name already correct */
+ else if (ISK(c) && ttisstring(&p->k[INDEXK(c)]))
+ *name = svalue(&p->k[INDEXK(c)]);
else
- return "?";
+ *name = "?";
}
static const char *getobjname (lua_State *L, CallInfo *ci, int reg,
const char **name) {
- Proto *p;
- int lastpc, pc;
+ Proto *p = ci_func(ci)->l.p;
const char *what = NULL;
- lua_assert(isLua(ci));
- p = ci_func(ci)->l.p;
- lastpc = currentpc(ci);
+ int lastpc = currentpc(ci);
+ int pc;
*name = luaF_getlocalname(p, reg + 1, lastpc);
if (*name) /* is a local? */
return "local";
@@ -285,17 +288,6 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg,
OpCode op = GET_OPCODE(i);
int a = GETARG_A(i);
switch (op) {
- case OP_GETGLOBAL: {
- if (reg == a) {
- int g = GETARG_Bx(i);
- if (g != 0) g--;
- else g = GETARG_Ax(p->code[++pc]);
- lua_assert(ttisstring(&p->k[g]));
- *name = svalue(&p->k[g]);
- what = "global";
- }
- break;
- }
case OP_MOVE: {
if (reg == a) {
int b = GETARG_B(i); /* move from 'b' to 'a' */
@@ -305,11 +297,16 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg,
}
break;
}
+ case OP_GETTABUP:
case OP_GETTABLE: {
if (reg == a) {
int k = GETARG_C(i); /* key index */
- *name = kname(p, k);
- what = "field";
+ int t = GETARG_B(i);
+ const char *vn = (op == OP_GETTABLE) /* name of indexed variable */
+ ? luaF_getlocalname(p, t + 1, pc)
+ : getstr(p->upvalues[t].name);
+ kname(p, k, a, what, name);
+ what = (vn && strcmp(vn, "_ENV") == 0) ? "global" : "field";
}
break;
}
@@ -322,6 +319,17 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg,
}
break;
}
+ case OP_LOADK: {
+ if (reg == a) {
+ int b = GETARG_Bx(i);
+ b = (b > 0) ? b - 1 : GETARG_Ax(p->code[pc + 1]);
+ if (ttisstring(&p->k[b])) {
+ what = "constant";
+ *name = svalue(&p->k[b]);
+ }
+ }
+ break;
+ }
case OP_LOADNIL: {
int b = GETARG_B(i); /* move from 'b' to 'a' */
if (a <= reg && reg <= b) /* set registers from 'a' to 'b' */
@@ -331,7 +339,7 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg,
case OP_SELF: {
if (reg == a) {
int k = GETARG_C(i); /* key index */
- *name = kname(p, k);
+ kname(p, k, a, what, name);
what = "method";
}
break;
@@ -374,12 +382,15 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
switch (GET_OPCODE(i)) {
case OP_CALL:
case OP_TAILCALL:
- case OP_TFORLOOP:
return getobjname(L, ci, GETARG_A(i), name);
- case OP_GETGLOBAL:
+ case OP_TFORCALL: {
+ *name = "for iterator";
+ return "for iterator";
+ }
case OP_SELF:
+ case OP_GETTABUP:
case OP_GETTABLE: tm = TM_INDEX; break;
- case OP_SETGLOBAL:
+ case OP_SETTABUP:
case OP_SETTABLE: tm = TM_NEWINDEX; break;
case OP_EQ: tm = TM_EQ; break;
case OP_ADD: tm = TM_ADD; break;
@@ -413,13 +424,30 @@ static int isinstack (CallInfo *ci, const TValue *o) {
}
+static const char *getupvalname (CallInfo *ci, const TValue *o,
+ const char **name) {
+ LClosure *c = &ci_func(ci)->l;
+ int i;
+ for (i = 0; i < c->nupvalues; i++) {
+ if (c->upvals[i]->v == o) {
+ *name = getstr(c->p->upvalues[i].name);
+ return "upvalue";
+ }
+ }
+ return NULL;
+}
+
+
void luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
CallInfo *ci = L->ci;
const char *name = NULL;
- const char *t = typename(ttype(o));
- const char *kind = (isLua(ci) && isinstack(ci, o)) ?
- getobjname(L, ci, cast_int(o - ci->u.l.base), &name) :
- NULL;
+ const char *t = objtypename(o);
+ const char *kind = NULL;
+ if (isLua(ci)) {
+ kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
+ if (!kind && isinstack(ci, o)) /* no? try a register */
+ kind = getobjname(L, ci, cast_int(o - ci->u.l.base), &name);
+ }
if (kind)
luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)",
op, kind, name, t);
@@ -444,8 +472,8 @@ void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) {
int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
- const char *t1 = typename(ttype(p1));
- const char *t2 = typename(ttype(p2));
+ const char *t1 = objtypename(p1);
+ const char *t2 = objtypename(p2);
if (t1 == t2)
luaG_runerror(L, "attempt to compare two %s values", t1);
else
diff --git a/src/ldo.c b/src/ldo.c
index 4890ce21..5b0e766e 100644
--- a/src/ldo.c
+++ b/src/ldo.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.c,v 2.80 2010/01/13 16:17:32 roberto Exp $
+** $Id: ldo.c,v 2.87 2010/05/05 18:49:56 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -48,7 +48,7 @@
*/
#if !defined(LUAI_THROW)
-#if defined(__cplusplus)
+#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP)
/* C++ exceptions */
#define LUAI_THROW(L,c) throw(c)
#define LUAI_TRY(L,c,a) \
@@ -83,8 +83,8 @@ struct lua_longjmp {
static void seterrorobj (lua_State *L, int errcode, StkId oldtop) {
switch (errcode) {
- case LUA_ERRMEM: {
- setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG));
+ case LUA_ERRMEM: { /* memory error? */
+ setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */
break;
}
case LUA_ERRERR: {
@@ -293,18 +293,43 @@ static StkId tryfuncTM (lua_State *L, StkId func) {
** returns true if function has been executed (C function)
*/
int luaD_precall (lua_State *L, StkId func, int nresults) {
- LClosure *cl;
+ Closure *cl;
+ lua_CFunction f;
ptrdiff_t funcr;
if (!ttisfunction(func)) /* `func' is not a function? */
func = tryfuncTM(L, func); /* check the `function' tag method */
funcr = savestack(L, func);
- cl = &clvalue(func)->l;
L->ci->nresults = nresults;
- if (!cl->isC) { /* Lua function? prepare its call */
+ if (ttislcf(func)) { /* light C function? */
+ f = fvalue(func); /* get it */
+ goto isCfunc; /* go to call it */
+ }
+ cl = clvalue(func);
+ if (cl->c.isC) { /* C closure? */
+ CallInfo *ci;
+ int n;
+ f = cl->c.f;
+ isCfunc: /* call C function 'f' */
+ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
+ ci = next_ci(L); /* now 'enter' new function */
+ ci->func = restorestack(L, funcr);
+ ci->top = L->top + LUA_MINSTACK;
+ lua_assert(ci->top <= L->stack_last);
+ ci->callstatus = 0;
+ if (L->hookmask & LUA_MASKCALL)
+ luaD_hook(L, LUA_HOOKCALL, -1);
+ lua_unlock(L);
+ n = (*f)(L); /* do the actual call */
+ lua_lock(L);
+ api_checknelems(L, n);
+ luaD_poscall(L, L->top - n);
+ return 1;
+ }
+ else { /* Lua function: prepare its call */
CallInfo *ci;
int nparams, nargs;
StkId base;
- Proto *p = cl->p;
+ Proto *p = cl->l.p;
luaD_checkstack(L, p->maxstacksize);
func = restorestack(L, funcr);
nargs = cast_int(L->top - func) - 1; /* number of real arguments */
@@ -327,24 +352,6 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
callhook(L, ci);
return 0;
}
- else { /* if is a C function, call it */
- CallInfo *ci;
- int n;
- luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
- ci = next_ci(L); /* now 'enter' new function */
- ci->func = restorestack(L, funcr);
- ci->top = L->top + LUA_MINSTACK;
- lua_assert(ci->top <= L->stack_last);
- ci->callstatus = 0;
- if (L->hookmask & LUA_MASKCALL)
- luaD_hook(L, LUA_HOOKCALL, -1);
- lua_unlock(L);
- n = (*curr_func(L)->c.f)(L); /* do the actual call */
- lua_lock(L);
- api_checknelems(L, n);
- luaD_poscall(L, L->top - n);
- return 1;
- }
}
@@ -452,7 +459,7 @@ static int recover (lua_State *L, int status) {
CallInfo *ci = findpcall(L);
if (ci == NULL) return 0; /* no recovery point */
/* "finish" luaD_pcall */
- oldtop = restorestack(L, ci->u.c.oldtop);
+ oldtop = restorestack(L, ci->u.c.extra);
luaF_close(L, oldtop);
seterrorobj(L, status, oldtop);
L->ci = ci;
@@ -469,7 +476,7 @@ static int recover (lua_State *L, int status) {
/*
** signal an error in the call to 'resume', not in the execution of the
** coroutine itself. (Such errors should not be handled by any coroutine
-** error hanlder and should not kill the coroutine.)
+** error handler and should not kill the coroutine.)
*/
static void resume_error (lua_State *L, const char *msg, StkId firstArg) {
L->top = firstArg; /* remove args from the stack */
@@ -501,11 +508,11 @@ static void resume (lua_State *L, void *ud) {
if (isLua(ci)) /* yielded inside a hook? */
luaV_execute(L); /* just continue running Lua code */
else { /* 'common' yield */
+ ci->func = restorestack(L, ci->u.c.extra);
if (ci->u.c.k != NULL) { /* does it have a continuation? */
int n;
ci->u.c.status = LUA_YIELD; /* 'default' status */
ci->callstatus |= CIST_YIELDED;
- ci->func = restorestack(L, ci->u.c.oldtop);
lua_unlock(L);
n = (*ci->u.c.k)(L); /* call continuation */
lua_lock(L);
@@ -526,6 +533,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) {
luai_userstateresume(L, nargs);
++G(L)->nCcalls; /* count resume */
L->nny = 0; /* allow yields */
+ api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
status = luaD_rawrunprotected(L, resume, L->top - nargs);
if (status == -1) /* error calling 'lua_resume'? */
status = LUA_ERRRUN;
@@ -565,11 +573,10 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) {
api_check(L, k == NULL, "hooks cannot continue after yielding");
}
else {
- if ((ci->u.c.k = k) != NULL) { /* is there a continuation? */
+ if ((ci->u.c.k = k) != NULL) /* is there a continuation? */
ci->u.c.ctx = ctx; /* save context */
- ci->u.c.oldtop = savestack(L, ci->func); /* save current 'func' */
- }
- ci->func = L->top - nresults - 1; /* protect stack slots below */
+ ci->u.c.extra = savestack(L, ci->func); /* save current 'func' */
+ ci->func = L->top - nresults - 1; /* protect stack below results */
luaD_throw(L, LUA_YIELD);
}
lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */
@@ -623,7 +630,7 @@ static void f_parser (lua_State *L, void *ud) {
: luaY_parser(L, p->z, &p->buff, &p->varl, p->name);
setptvalue2s(L, L->top, tf);
incr_top(L);
- cl = luaF_newLclosure(L, tf->sizeupvalues, G(L)->l_gt);
+ cl = luaF_newLclosure(L, tf->sizeupvalues);
cl->l.p = tf;
setclvalue(L, L->top - 1, cl);
for (i = 0; i < tf->sizeupvalues; i++) /* initialize upvalues */
diff --git a/src/ldump.c b/src/ldump.c
index f95381ab..b2c1e709 100644
--- a/src/ldump.c
+++ b/src/ldump.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldump.c,v 2.12 2009/09/30 15:38:37 roberto Exp $
+** $Id: ldump.c,v 2.13 2010/03/12 19:14:06 roberto Exp $
** save precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -145,7 +145,6 @@ static void DumpFunction(const Proto* f, const TString* p, DumpState* D)
DumpChar(f->numparams,D);
DumpChar(f->is_vararg,D);
DumpChar(f->maxstacksize,D);
- DumpChar(f->envreg,D);
DumpCode(f,D);
DumpConstants(f,D);
DumpUpvalues(f,D);
diff --git a/src/lfunc.c b/src/lfunc.c
index afc097c6..e95dad01 100644
--- a/src/lfunc.c
+++ b/src/lfunc.c
@@ -1,5 +1,5 @@
/*
-** $Id: lfunc.c,v 2.19 2009/12/16 16:42:58 roberto Exp $
+** $Id: lfunc.c,v 2.24 2010/05/10 18:23:45 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@@ -21,19 +21,17 @@
-Closure *luaF_newCclosure (lua_State *L, int n, Table *e) {
+Closure *luaF_newCclosure (lua_State *L, int n) {
Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeCclosure(n), NULL, 0)->cl;
c->c.isC = 1;
- c->c.env = e;
c->c.nupvalues = cast_byte(n);
return c;
}
-Closure *luaF_newLclosure (lua_State *L, int n, Table *e) {
+Closure *luaF_newLclosure (lua_State *L, int n) {
Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeLclosure(n), NULL, 0)->cl;
c->l.isC = 0;
- c->l.env = e;
c->l.nupvalues = cast_byte(n);
while (n--) c->l.upvals[n] = NULL;
return c;
@@ -54,12 +52,14 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
UpVal *p;
UpVal *uv;
while (*pp != NULL && (p = gco2uv(*pp))->v >= level) {
+ GCObject *o = obj2gco(p);
lua_assert(p->v != &p->u.value);
if (p->v == level) { /* found a corresponding upvalue? */
- if (isdead(g, obj2gco(p))) /* is it dead? */
- changewhite(obj2gco(p)); /* ressurrect it */
+ if (isdead(g, o)) /* is it dead? */
+ changewhite(o); /* ressurrect it */
return p;
}
+ resetoldbit(o); /* may create a newer upval after this one */
pp = &p->next;
}
/* not found: create a new one */
@@ -98,10 +98,12 @@ void luaF_close (lua_State *L, StkId level) {
if (isdead(g, o))
luaF_freeupval(L, uv); /* free upvalue */
else {
- unlinkupval(uv);
- setobj(L, &uv->u.value, uv->v);
+ unlinkupval(uv); /* remove upvalue from 'uvhead' list */
+ setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */
uv->v = &uv->u.value; /* now current value lives here */
- luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */
+ gch(o)->next = g->allgc; /* link upvalue into 'allgc' list */
+ g->allgc = o;
+ luaC_checkupvalcolor(g, uv);
}
}
}
@@ -127,7 +129,6 @@ Proto *luaF_newproto (lua_State *L) {
f->linedefined = 0;
f->lastlinedefined = 0;
f->source = NULL;
- f->envreg = NO_REG;
return f;
}
diff --git a/src/lfunc.h b/src/lfunc.h
index 2e02419b..d11182b0 100644
--- a/src/lfunc.h
+++ b/src/lfunc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lfunc.h,v 2.4 2005/04/25 19:24:10 roberto Exp $
+** $Id: lfunc.h,v 2.5 2010/03/26 20:58:11 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@@ -19,8 +19,8 @@
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
-LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e);
-LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e);
+LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems);
+LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems);
LUAI_FUNC UpVal *luaF_newupval (lua_State *L);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (lua_State *L, StkId level);
diff --git a/src/lgc.c b/src/lgc.c
index 2094d386..276edacd 100644
--- a/src/lgc.c
+++ b/src/lgc.c
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.c,v 2.67 2009/12/22 15:32:50 roberto Exp $
+** $Id: lgc.c,v 2.96 2010/05/17 20:39:31 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -23,21 +23,49 @@
#include "ltm.h"
-#define GCSTEPSIZE 1024u
+
+/* how much to allocate before next GC step */
+#define GCSTEPSIZE 1024
+
+/* maximum numer of elements to sweep in each single step */
#define GCSWEEPMAX 40
-#define GCSWEEPCOST 10
-#define GCFINALIZECOST 100
+/* cost of sweeping one element */
+#define GCSWEEPCOST 1
+
+/* maximum number of finalizers to call in each GC step */
+#define GCFINALIZENUM 4
+
+/* cost of marking the root set */
+#define GCROOTCOST 10
+
+/* cost of atomic step */
+#define GCATOMICCOST 1000
+
+/* basic cost to traverse one object (to be added to the links the
+ object may have) */
+#define TRAVCOST 5
-#define maskcolors cast_byte(~(bitmask(BLACKBIT)|WHITEBITS))
+/*
+** standard negative debt for GC; a reasonable "time" to wait before
+** starting a new cycle
+*/
+#define stddebt(g) (-cast(l_mem, g->totalbytes/100) * g->gcpause)
+
+
+/*
+** 'makewhite' erases all color bits plus the old bit and then
+** sets only the current white bit
+*/
+#define maskcolors (~(bit2mask(BLACKBIT, OLDBIT) | WHITEBITS))
#define makewhite(g,x) \
(gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g)))
#define white2gray(x) resetbits(gch(x)->marked, WHITEBITS)
#define black2gray(x) resetbit(gch(x)->marked, BLACKBIT)
-#define stringmark(s) resetbits((s)->tsv.marked, WHITEBITS)
+#define stringmark(s) ((void)((s) && resetbits((s)->tsv.marked, WHITEBITS)))
#define isfinalized(u) testbit((u)->marked, FINALIZEDBIT)
@@ -51,7 +79,6 @@
#define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \
reallymarkobject(g, obj2gco(t)); }
-
static void reallymarkobject (global_State *g, GCObject *o);
@@ -61,12 +88,16 @@ static void reallymarkobject (global_State *g, GCObject *o);
** =======================================================
*/
-static void linktable (Table *h, GCObject **p) {
- h->gclist = *p;
- *p = obj2gco(h);
-}
+
+/*
+** link table 'h' into list pointed by 'p'
+*/
+#define linktable(h,p) ((h)->gclist = *(p), *(p) = obj2gco(h))
+/*
+** mark a table entry as dead (therefore removing it from the table)
+*/
static void removeentry (Node *n) {
lua_assert(ttisnil(gval(n)));
if (iscollectable(gkey(n)))
@@ -75,8 +106,8 @@ static void removeentry (Node *n) {
/*
-** The next function tells whether a key or value can be cleared from
-** a weak table. Non-collectable objects are never removed from weak
+** tells whether a key or value can be cleared from a weak
+** table. Non-collectable objects are never removed from weak
** tables. Strings behave as `values', so are never removed too. for
** other objects: if really collected, cannot keep them; for objects
** being finalized, keep them in keys, but not in values
@@ -92,24 +123,32 @@ static int iscleared (const TValue *o, int iskey) {
}
+/*
+** barrier that moves collector forward, that is, mark the white object
+** being pointed by a black object.
+*/
void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
global_State *g = G(L);
lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
- lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
+ lua_assert(isgenerational(g) || g->gcstate != GCSpause);
lua_assert(gch(o)->tt != LUA_TTABLE);
- /* must keep invariant? */
- if (g->gcstate == GCSpropagate)
+ if (keepinvariant(g)) /* must keep invariant? */
reallymarkobject(g, v); /* restore invariant */
- else /* don't mind */
- makewhite(g, o); /* mark as white just to avoid other barriers */
+ else { /* sweep phase */
+ lua_assert(issweepphase(g));
+ makewhite(g, o); /* mark main obj. as white to avoid other barriers */
+ }
}
+/*
+** barrier that moves collector backward, that is, mark the black object
+** pointing to a white object as gray again.
+*/
void luaC_barrierback (lua_State *L, Table *t) {
global_State *g = G(L);
GCObject *o = obj2gco(t);
lua_assert(isblack(o) && !isdead(g, o));
- lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
black2gray(o); /* make table gray (again) */
t->gclist = g->grayagain;
g->grayagain = o;
@@ -117,14 +156,37 @@ void luaC_barrierback (lua_State *L, Table *t) {
/*
-** create a new collectable object and link it to '*list'
+** check color (and invariants) for an upvalue that was closed,
+** i.e., moved into the 'allgc' list
+*/
+void luaC_checkupvalcolor (global_State *g, UpVal *uv) {
+ GCObject *o = obj2gco(uv);
+ lua_assert(!isblack(o)); /* open upvalues are never black */
+ if (isgray(o)) {
+ if (keepinvariant(g)) {
+ resetoldbit(o); /* see MOVE OLD rule */
+ gray2black(o); /* it is being visited now */
+ markvalue(g, uv->v);
+ }
+ else {
+ lua_assert(issweepphase(g));
+ makewhite(g, o);
+ }
+ }
+}
+
+
+/*
+** create a new collectable object (with given type and size) and link
+** it to '*list'. 'offset' tells how many bytes to allocate before the
+** object itself (used only by states).
*/
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
int offset) {
global_State *g = G(L);
GCObject *o = obj2gco(cast(char *, luaM_newobject(L, tt, sz)) + offset);
if (list == NULL)
- list = &g->rootgc; /* standard list for collectable objects */
+ list = &g->allgc; /* standard list for collectable objects */
gch(o)->marked = luaC_white(g);
gch(o)->tt = tt;
gch(o)->next = *list;
@@ -132,24 +194,6 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
return o;
}
-
-void luaC_linkupval (lua_State *L, UpVal *uv) {
- global_State *g = G(L);
- GCObject *o = obj2gco(uv);
- gch(o)->next = g->rootgc; /* link upvalue into `rootgc' list */
- g->rootgc = o;
- if (isgray(o)) {
- if (g->gcstate == GCSpropagate) {
- gray2black(o); /* closed upvalues need barrier */
- luaC_barrier(L, uv, uv->v);
- }
- else { /* sweep phase: sweep it (turning it into white) */
- makewhite(g, o);
- lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
- }
- }
-}
-
/* }====================================================== */
@@ -160,25 +204,33 @@ void luaC_linkupval (lua_State *L, UpVal *uv) {
** =======================================================
*/
+
+/*
+** mark an object. Userdata and closed upvalues are visited and turned
+** black here. Strings remain gray (it is the same as making them
+** black). Other objects are marked gray and added to appropriate list
+** to be visited (and turned black) later. (Open upvalues are already
+** linked in 'headuv' list.)
+*/
static void reallymarkobject (global_State *g, GCObject *o) {
lua_assert(iswhite(o) && !isdead(g, o));
white2gray(o);
switch (gch(o)->tt) {
case LUA_TSTRING: {
- return;
+ return; /* for strings, gray is as good as black */
}
case LUA_TUSERDATA: {
Table *mt = gco2u(o)->metatable;
- gray2black(o); /* udata are never gray */
markobject(g, mt);
markobject(g, gco2u(o)->env);
+ gray2black(o); /* all pointers marked */
return;
}
case LUA_TUPVAL: {
UpVal *uv = gco2uv(o);
markvalue(g, uv->v);
- if (uv->v == &uv->u.value) /* closed? */
- gray2black(o); /* open upvalues are never black */
+ if (uv->v == &uv->u.value) /* closed? (open upvalues remain gray) */
+ gray2black(o); /* make it black */
return;
}
case LUA_TFUNCTION: {
@@ -205,48 +257,55 @@ static void reallymarkobject (global_State *g, GCObject *o) {
}
+/*
+** mark tag methods for basic types
+*/
static void markmt (global_State *g) {
int i;
- for (i=0; i<NUM_TAGS; i++)
+ for (i=0; i < LUA_NUMTAGS; i++)
markobject(g, g->mt[i]);
}
+/*
+** mark all objects in list of being-finalized
+*/
static void markbeingfnz (global_State *g) {
GCObject *o;
for (o = g->tobefnz; o != NULL; o = gch(o)->next) {
- lua_assert(testbit(gch(o)->marked, SEPARATED));
makewhite(g, o);
reallymarkobject(g, o);
}
}
-/* mark root set */
-static void markroot (lua_State *L) {
- global_State *g = G(L);
- g->gray = NULL;
- g->grayagain = NULL;
- g->weak = g->ephemeron = g->allweak = NULL;
- markobject(g, g->mainthread);
- /* make global table and registry to be traversed before main stack */
- markobject(g, g->l_gt);
- markvalue(g, &g->l_registry);
- markmt(g);
- markbeingfnz(g); /* mark any finalizing object left from previous cycle */
- g->gcstate = GCSpropagate;
-}
-
-
+/*
+** mark all values stored in marked open upvalues. (See comment in
+** 'lstate.h'.)
+*/
static void remarkupvals (global_State *g) {
UpVal *uv;
for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
- lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
if (isgray(obj2gco(uv)))
markvalue(g, uv->v);
}
}
+
+/*
+** mark root set and reset all gray lists, to start a new
+** incremental (or full) collection
+*/
+static void markroot (lua_State *L) {
+ global_State *g = G(L);
+ g->gray = g->grayagain = NULL;
+ g->weak = g->allweak = g->ephemeron = NULL;
+ markobject(g, g->mainthread);
+ markvalue(g, &g->l_registry);
+ markmt(g);
+ markbeingfnz(g); /* mark any finalizing object left from previous cycle */
+}
+
/* }====================================================== */
@@ -257,49 +316,48 @@ static void remarkupvals (global_State *g) {
*/
static void traverseweakvalue (global_State *g, Table *h) {
- int i = sizenode(h);
- while (i--) {
- Node *n = gnode(h, i);
+ Node *n, *limit = gnode(h, sizenode(h));
+ for (n = gnode(h, 0); n < limit; n++) {
checkdeadkey(n);
- if (ttisnil(gval(n)))
- removeentry(n); /* remove empty entries */
+ if (ttisnil(gval(n))) /* entry is empty? */
+ removeentry(n); /* remove it */
else {
lua_assert(!ttisnil(gkey(n)));
- markvalue(g, gkey(n));
+ markvalue(g, gkey(n)); /* mark key */
}
}
- linktable(h, &g->weak);
+ linktable(h, &g->weak); /* link into appropriate list */
}
static int traverseephemeron (global_State *g, Table *h) {
- int marked = 0;
- int hasclears = 0;
- int i = h->sizearray;
- while (i--) { /* mark array part (numeric keys are 'strong') */
+ int marked = 0; /* true if an object is marked in this traversal */
+ int hasclears = 0; /* true if table has unmarked pairs */
+ Node *n, *limit = gnode(h, sizenode(h));
+ int i;
+ /* traverse array part (numeric keys are 'strong') */
+ for (i = 0; i < h->sizearray; i++) {
if (valiswhite(&h->array[i])) {
marked = 1;
reallymarkobject(g, gcvalue(&h->array[i]));
}
}
- i = sizenode(h);
- while (i--) {
- Node *n = gnode(h, i);
+ /* traverse hash part */
+ for (n = gnode(h, 0); n < limit; n++) {
checkdeadkey(n);
if (ttisnil(gval(n))) /* entry is empty? */
removeentry(n); /* remove it */
- else if (valiswhite(gval(n))) {
- /* value is not marked yet */
+ else if (valiswhite(gval(n))) { /* value not marked yet? */
if (iscleared(key2tval(n), 1)) /* key is not marked (yet)? */
hasclears = 1; /* may have to propagate mark from key to value */
- else { /* mark value only if key is marked */
- marked = 1; /* some mark changed status */
+ else { /* key is marked, so mark value */
+ marked = 1; /* value was not marked */
reallymarkobject(g, gcvalue(gval(n)));
}
}
}
- if (hasclears)
- linktable(h, &g->ephemeron);
+ if (hasclears) /* does table have unmarked pairs? */
+ linktable(h, &g->ephemeron); /* will have to propagate again */
else /* nothing to propagate */
linktable(h, &g->weak); /* avoid convergence phase */
return marked;
@@ -307,26 +365,24 @@ static int traverseephemeron (global_State *g, Table *h) {
static void traversestrongtable (global_State *g, Table *h) {
+ Node *n, *limit = gnode(h, sizenode(h));
int i;
- i = h->sizearray;
- while (i--)
+ for (i = 0; i < h->sizearray; i++) /* traverse array part */
markvalue(g, &h->array[i]);
- i = sizenode(h);
- while (i--) {
- Node *n = gnode(h, i);
+ for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */
checkdeadkey(n);
- if (ttisnil(gval(n)))
- removeentry(n); /* remove empty entries */
+ if (ttisnil(gval(n))) /* entry is empty? */
+ removeentry(n); /* remove it */
else {
lua_assert(!ttisnil(gkey(n)));
- markvalue(g, gkey(n));
- markvalue(g, gval(n));
+ markvalue(g, gkey(n)); /* mark key */
+ markvalue(g, gval(n)); /* mark value */
}
}
}
-static void traversetable (global_State *g, Table *h) {
+static int traversetable (global_State *g, Table *h) {
const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
markobject(g, h->metatable);
if (mode && ttisstring(mode)) { /* is there a weak mode? */
@@ -334,43 +390,41 @@ static void traversetable (global_State *g, Table *h) {
int weakvalue = (strchr(svalue(mode), 'v') != NULL);
if (weakkey || weakvalue) { /* is really weak? */
black2gray(obj2gco(h)); /* keep table gray */
- if (!weakkey) /* strong keys? */
+ if (!weakkey) { /* strong keys? */
traverseweakvalue(g, h);
- else if (!weakvalue) /* strong values? */
+ return TRAVCOST + sizenode(h);
+ }
+ else if (!weakvalue) { /* strong values? */
traverseephemeron(g, h);
- else
+ return TRAVCOST + h->sizearray + sizenode(h);
+ }
+ else {
linktable(h, &g->allweak); /* nothing to traverse now */
- return;
+ return TRAVCOST;
+ }
} /* else go through */
}
traversestrongtable(g, h);
+ return TRAVCOST + h->sizearray + (2 * sizenode(h));
}
-/*
-** All marks are conditional because a GC may happen while the
-** prototype is still being created
-*/
-static void traverseproto (global_State *g, Proto *f) {
+static int traverseproto (global_State *g, Proto *f) {
int i;
- if (f->source) stringmark(f->source);
- for (i=0; i<f->sizek; i++) /* mark literals */
+ stringmark(f->source);
+ for (i = 0; i < f->sizek; i++) /* mark literals */
markvalue(g, &f->k[i]);
- for (i=0; i<f->sizeupvalues; i++) { /* mark upvalue names */
- if (f->upvalues[i].name)
- stringmark(f->upvalues[i].name);
- }
- for (i=0; i<f->sizep; i++) /* mark nested protos */
+ for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */
+ stringmark(f->upvalues[i].name);
+ for (i = 0; i < f->sizep; i++) /* mark nested protos */
markobject(g, f->p[i]);
- for (i=0; i<f->sizelocvars; i++) { /* mark local-variable names */
- if (f->locvars[i].varname)
- stringmark(f->locvars[i].varname);
- }
+ for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
+ stringmark(f->locvars[i].varname);
+ return TRAVCOST + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars;
}
-static void traverseclosure (global_State *g, Closure *cl) {
- markobject(g, cl->c.env);
+static l_mem traverseclosure (global_State *g, Closure *cl) {
if (cl->c.isC) {
int i;
for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */
@@ -379,32 +433,35 @@ static void traverseclosure (global_State *g, Closure *cl) {
else {
int i;
lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues);
- markobject(g, cl->l.p);
+ markobject(g, cl->l.p); /* mark its prototype */
for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */
markobject(g, cl->l.upvals[i]);
}
+ return TRAVCOST + cl->c.nupvalues;
}
-static void traversestack (global_State *g, lua_State *L) {
- StkId o;
- if (L->stack == NULL)
- return; /* stack not completely built yet */
- for (o = L->stack; o < L->top; o++)
+static int traversestack (global_State *g, lua_State *L) {
+ StkId o = L->stack;
+ if (o == NULL)
+ return 1; /* stack not completely built yet */
+ for (; o < L->top; o++)
markvalue(g, o);
if (g->gcstate == GCSatomic) { /* final traversal? */
StkId lim = L->stack + L->stacksize; /* real end of stack */
for (; o < lim; o++) /* clear not-marked stack slice */
setnilvalue(o);
}
+ return TRAVCOST + cast_int(o - L->stack);
}
/*
-** traverse one gray object, turning it to black.
-** Returns `quantity' traversed.
+** traverse one gray object, turning it to black (except for threads,
+** which are always gray).
+** Returns number of values traversed.
*/
-static l_mem propagatemark (global_State *g) {
+static int propagatemark (global_State *g) {
GCObject *o = g->gray;
lua_assert(isgray(o));
gray2black(o);
@@ -412,16 +469,12 @@ static l_mem propagatemark (global_State *g) {
case LUA_TTABLE: {
Table *h = gco2t(o);
g->gray = h->gclist;
- traversetable(g, h);
- return sizeof(Table) + sizeof(TValue) * h->sizearray +
- sizeof(Node) * sizenode(h);
+ return traversetable(g, h);
}
case LUA_TFUNCTION: {
Closure *cl = gco2cl(o);
g->gray = cl->c.gclist;
- traverseclosure(g, cl);
- return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) :
- sizeLclosure(cl->l.nupvalues);
+ return traverseclosure(g, cl);
}
case LUA_TTHREAD: {
lua_State *th = gco2th(o);
@@ -429,19 +482,12 @@ static l_mem propagatemark (global_State *g) {
th->gclist = g->grayagain;
g->grayagain = o;
black2gray(o);
- traversestack(g, th);
- return sizeof(lua_State) + sizeof(TValue) * th->stacksize;
+ return traversestack(g, th);
}
case LUA_TPROTO: {
Proto *p = gco2p(o);
g->gray = p->gclist;
- traverseproto(g, p);
- return sizeof(Proto) + sizeof(Instruction) * p->sizecode +
- sizeof(Proto *) * p->sizep +
- sizeof(TValue) * p->sizek +
- sizeof(int) * p->sizelineinfo +
- sizeof(LocVar) * p->sizelocvars +
- sizeof(TString *) * p->sizeupvalues;
+ return traverseproto(g, p);
}
default: lua_assert(0); return 0;
}
@@ -465,14 +511,14 @@ static void convergeephemerons (global_State *g) {
int changed;
do {
GCObject *w;
- GCObject *next = g->ephemeron;
- g->ephemeron = NULL;
+ GCObject *next = g->ephemeron; /* get ephemeron list */
+ g->ephemeron = NULL; /* tables will return to this list when traversed */
changed = 0;
while ((w = next) != NULL) {
next = gco2t(w)->gclist;
- if (traverseephemeron(g, gco2t(w))) {
- changed = 1;
- propagateall(g);
+ if (traverseephemeron(g, gco2t(w))) { /* traverse marked some value? */
+ propagateall(g); /* propagate changes */
+ changed = 1; /* will have to revisit all ephemeron tables */
}
}
} while (changed);
@@ -487,26 +533,26 @@ static void convergeephemerons (global_State *g) {
** =======================================================
*/
-/* clear collected entries from weaktables */
+/*
+** clear collected entries from all weaktables in list 'l'
+*/
static void cleartable (GCObject *l) {
- while (l) {
+ for (; l != NULL; l = gco2t(l)->gclist) {
Table *h = gco2t(l);
- int i = h->sizearray;
- while (i--) {
+ Node *n, *limit = gnode(h, sizenode(h));
+ int i;
+ for (i = 0; i < h->sizearray; i++) {
TValue *o = &h->array[i];
if (iscleared(o, 0)) /* value was collected? */
setnilvalue(o); /* remove value */
}
- i = sizenode(h);
- while (i--) {
- Node *n = gnode(h, i);
+ for (n = gnode(h, 0); n < limit; n++) {
if (!ttisnil(gval(n)) && /* non-empty entry? */
(iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) {
setnilvalue(gval(n)); /* remove value ... */
- removeentry(n); /* remove entry from table */
+ removeentry(n); /* and remove entry from table */
}
}
- l = h->gclist;
}
}
@@ -533,33 +579,63 @@ static void freeobj (lua_State *L, GCObject *o) {
static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count);
-static void sweepthread (lua_State *L, lua_State *L1, int alive) {
+/*
+** sweep the (open) upvalues of a thread and resize its stack and
+** list of call-info structures.
+*/
+static void sweepthread (lua_State *L, lua_State *L1) {
if (L1->stack == NULL) return; /* stack not completely built yet */
sweepwholelist(L, &L1->openupval); /* sweep open upvalues */
luaE_freeCI(L1); /* free extra CallInfo slots */
/* should not change the stack during an emergency gc cycle */
- if (alive && G(L)->gckind != KGC_EMERGENCY)
+ if (G(L)->gckind != KGC_EMERGENCY)
luaD_shrinkstack(L1);
}
+/*
+** sweep at most 'count' elements from a list of GCObjects erasing dead
+** objects, where a dead (not alive) object is one marked with the "old"
+** (non current) white and not fixed.
+** In non-generational mode, change all non-dead objects back to white,
+** preparing for next collection cycle.
+** In generational mode, keep black objects black, and also mark them as
+** old; stop when hitting an old object, as all objects after that
+** one will be old too.
+** When object is a thread, sweep its list of open upvalues too.
+*/
static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
- GCObject *curr;
global_State *g = G(L);
- int deadmask = otherwhite(g);
- while ((curr = *p) != NULL && count-- > 0) {
- int alive = (gch(curr)->marked ^ WHITEBITS) & deadmask;
- if (gch(curr)->tt == LUA_TTHREAD)
- sweepthread(L, gco2th(curr), alive);
- if (alive) {
- lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT));
- makewhite(g, curr); /* make it white (for next cycle) */
- p = &gch(curr)->next;
- }
- else { /* must erase `curr' */
- lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
+ int ow = otherwhite(g);
+ int toclear, toset; /* bits to clear and to set in all live objects */
+ int tostop; /* stop sweep when this is true */
+ if (isgenerational(g)) { /* generational mode? */
+ toclear = ~0; /* clear nothing */
+ toset = bitmask(OLDBIT); /* set the old bit of all surviving objects */
+ tostop = bitmask(OLDBIT); /* do not sweep old generation */
+ }
+ else { /* normal mode */
+ toclear = maskcolors; /* clear all color bits + old bit */
+ toset = luaC_white(g); /* make object white */
+ tostop = 0; /* do not stop */
+ }
+ while (*p != NULL && count-- > 0) {
+ GCObject *curr = *p;
+ int marked = gch(curr)->marked;
+ if (isdeadm(ow, marked)) { /* is 'curr' dead? */
*p = gch(curr)->next; /* remove 'curr' from list */
- freeobj(L, curr);
+ freeobj(L, curr); /* erase 'curr' */
+ }
+ else {
+ if (gch(curr)->tt == LUA_TTHREAD)
+ sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */
+ if (testbits(marked, tostop)) {
+ static GCObject *nullp = NULL;
+ return &nullp; /* stop sweeping this list */
+ }
+ /* update marks */
+ gch(curr)->marked = cast_byte((marked & toclear) | toset);
+ p = &gch(curr)->next; /* go to next element */
}
}
return p;
@@ -576,25 +652,28 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
static void checkSizes (lua_State *L) {
global_State *g = G(L);
- if (g->strt.nuse < cast(lu_int32, g->strt.size)) {
- /* string-table size could be the smaller power of 2 larger than 'nuse' */
- int size = 1 << luaO_ceillog2(g->strt.nuse);
- if (size < g->strt.size) /* current table too large? */
- luaS_resize(L, size); /* shrink it */
+ if (g->gckind != KGC_EMERGENCY) { /* do not change sizes in emergency */
+ int hs = g->strt.size / 2; /* half the size of the string table */
+ if (g->strt.nuse < cast(lu_int32, hs)) /* using less than that half? */
+ luaS_resize(L, hs); /* halve its size */
+ luaZ_freebuffer(L, &g->buff); /* free concatenation buffer */
}
- luaZ_freebuffer(L, &g->buff);
}
static Udata *udata2finalize (global_State *g) {
GCObject *o = g->tobefnz; /* get first element */
- g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */
- gch(o)->next = g->rootgc; /* return it to `root' list */
- g->rootgc = o;
- lua_assert(isfinalized(gch(o)));
- resetbit(gch(o)->marked, SEPARATED); /* mark it as such */
- makewhite(g, o);
- return rawgco2u(o);
+ Udata *u = rawgco2u(o);
+ lua_assert(isfinalized(&u->uv));
+ lua_assert(!isold(o));
+ g->tobefnz = u->uv.next; /* remove it from 'tobefnz' list */
+ u->uv.next = g->allgc; /* return it to 'allgc' list */
+ g->allgc = o;
+ resetbit(u->uv.marked, SEPARATED); /* mark that it is not in 'tobefnz' */
+ resetoldbit(o); /* see MOVE OLD rule */
+ if (!keepinvariant(g)) /* not keeping invariant? */
+ makewhite(g, o); /* "sweep" object */
+ return u;
}
@@ -608,18 +687,18 @@ static void GCTM (lua_State *L, int propagateerrors) {
global_State *g = G(L);
Udata *udata = udata2finalize(g);
const TValue *tm = gfasttm(g, udata->uv.metatable, TM_GC);
- if (tm != NULL && ttisfunction(tm)) {
+ if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */
int status;
lu_byte oldah = L->allowhook;
- lu_mem oldt = g->GCthreshold;
+ lu_mem oldd = g->GCdebt;
L->allowhook = 0; /* stop debug hooks during GC tag method */
- g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */
- setobj2s(L, L->top, tm);
- setuvalue(L, L->top+1, udata);
- L->top += 2;
+ stopgc(g); /* avoid GC steps */
+ setobj2s(L, L->top, tm); /* push finalizer... */
+ setuvalue(L, L->top+1, udata); /* ... and its argument */
+ L->top += 2; /* and (next line) call the finalizer */
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
L->allowhook = oldah; /* restore hooks */
- g->GCthreshold = oldt; /* restore threshold */
+ g->GCdebt = oldd; /* restore threshold */
if (status != LUA_OK && propagateerrors) { /* error while running __gc? */
if (status == LUA_ERRRUN) { /* is there an error msg.? */
luaO_pushfstring(L, "error in __gc tag method (%s)",
@@ -632,14 +711,18 @@ static void GCTM (lua_State *L, int propagateerrors) {
}
-/* move 'dead' udata that need finalization to list 'tobefnz' */
+/*
+** move all unreachable udata that need finalization from list 'udgc' to
+** list 'tobefnz'
+*/
void luaC_separateudata (lua_State *L, int all) {
global_State *g = G(L);
- GCObject **p = &g->mainthread->next;
+ GCObject **p = &g->udgc;
GCObject *curr;
GCObject **lastnext = &g->tobefnz;
- /* find last 'next' field in 'tobefnz' list (to insert elements in its end) */
- while (*lastnext != NULL) lastnext = &gch(*lastnext)->next;
+ /* find last 'next' field in 'tobefnz' list (to add elements in its end) */
+ while (*lastnext != NULL)
+ lastnext = &gch(*lastnext)->next;
while ((curr = *p) != NULL) { /* traverse all finalizable objects */
lua_assert(gch(curr)->tt == LUA_TUSERDATA && !isfinalized(gco2u(curr)));
lua_assert(testbit(gch(curr)->marked, SEPARATED));
@@ -647,9 +730,8 @@ void luaC_separateudata (lua_State *L, int all) {
p = &gch(curr)->next; /* don't bother with it */
else {
l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */
- *p = gch(curr)->next; /* remove 'curr' from 'rootgc' list */
- /* link 'curr' at the end of 'tobefnz' list */
- gch(curr)->next = *lastnext;
+ *p = gch(curr)->next; /* remove 'curr' from 'udgc' list */
+ gch(curr)->next = *lastnext; /* link at the end of 'tobefnz' list */
*lastnext = curr;
lastnext = &gch(curr)->next;
}
@@ -657,20 +739,24 @@ void luaC_separateudata (lua_State *L, int all) {
}
+/*
+** if userdata 'u' has a finalizer, remove it from 'allgc' list (must
+** search the list to find it) and link it in 'udgc' list.
+*/
void luaC_checkfinalizer (lua_State *L, Udata *u) {
global_State *g = G(L);
- if (testbit(u->uv.marked, SEPARATED) || /* userdata is already separated... */
- isfinalized(&u->uv) || /* ... or is finalized... */
- gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */
+ if (testbit(u->uv.marked, SEPARATED) || /* udata is already separated... */
+ isfinalized(&u->uv) || /* ... or is finalized... */
+ gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalizer? */
return; /* nothing to be done */
- else { /* move 'u' to 2nd part of root list */
+ else { /* move 'u' to 'udgc' list */
GCObject **p;
- for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next)
- lua_assert(*p != obj2gco(g->mainthread)); /* 'u' must be in this list */
+ for (p = &g->allgc; *p != obj2gco(u); p = &gch(*p)->next) ;
*p = u->uv.next; /* remove 'u' from root list */
- u->uv.next = g->mainthread->next; /* re-link it in list */
- g->mainthread->next = obj2gco(u);
+ u->uv.next = g->udgc; /* link it in list 'udgc' */
+ g->udgc = obj2gco(u);
l_setbit(u->uv.marked, SEPARATED); /* mark it as such */
+ resetoldbit(obj2gco(u)); /* see MOVE OLD rule */
}
}
@@ -683,15 +769,52 @@ void luaC_checkfinalizer (lua_State *L, Udata *u) {
** =======================================================
*/
+
+#define sweepphases \
+ (bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep))
+
+/*
+** change GC mode
+*/
+void luaC_changemode (lua_State *L, int mode) {
+ global_State *g = G(L);
+ if (mode == g->gckind) return; /* nothing to change */
+ if (mode == KGC_GEN) { /* change to generational mode */
+ /* make sure gray lists are consistent */
+ luaC_runtilstate(L, bitmask(GCSpropagate));
+ g->lastmajormem = g->totalbytes;
+ g->gckind = KGC_GEN;
+ }
+ else { /* change to incremental mode */
+ /* sweep all objects to turn them back to white
+ (as white has not changed, nothing extra will be collected) */
+ g->sweepstrgc = 0;
+ g->gcstate = GCSsweepstring;
+ g->gckind = KGC_NORMAL;
+ luaC_runtilstate(L, ~sweepphases);
+ }
+}
+
+
+/*
+** call all pending finalizers */
+static void callallpendingfinalizers (lua_State *L, int propagateerrors) {
+ global_State *g = G(L);
+ while (g->tobefnz) GCTM(L, propagateerrors);
+}
+
+
void luaC_freeallobjects (lua_State *L) {
global_State *g = G(L);
int i;
- while (g->tobefnz) GCTM(L, 0); /* Call all pending finalizers */
+ callallpendingfinalizers(L, 0);
/* following "white" makes all objects look dead */
- g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT);
- sweepwholelist(L, &g->rootgc);
- lua_assert(g->rootgc == obj2gco(g->mainthread) &&
- g->mainthread->next == NULL);
+ g->currentwhite = WHITEBITS;
+ g->gckind = KGC_NORMAL;
+ sweepwholelist(L, &g->udgc);
+ lua_assert(g->udgc == NULL);
+ sweepwholelist(L, &g->allgc);
+ lua_assert(g->allgc == NULL);
for (i = 0; i < g->strt.size; i++) /* free all string lists */
sweepwholelist(L, &g->strt.hash[i]);
lua_assert(g->strt.nuse == 0);
@@ -700,7 +823,6 @@ void luaC_freeallobjects (lua_State *L) {
static void atomic (lua_State *L) {
global_State *g = G(L);
- g->gcstate = GCSatomic;
lua_assert(!iswhite(obj2gco(g->mainthread)));
markobject(g, L); /* mark running thread */
/* registry and global metatables may be changed by API */
@@ -710,12 +832,11 @@ static void atomic (lua_State *L) {
remarkupvals(g);
/* traverse objects caught by write barrier and by 'remarkupvals' */
propagateall(g);
- /* at this point, all strongly accessible objects are marked.
- Start marking weakly accessible objects. */
traverselistofgrays(g, &g->weak); /* remark weak tables */
traverselistofgrays(g, &g->ephemeron); /* remark ephemeron tables */
traverselistofgrays(g, &g->grayagain); /* remark gray again */
convergeephemerons(g);
+ /* at this point, all strongly accessible objects are marked. */
luaC_separateudata(L, 0); /* separate userdata to be finalized */
markbeingfnz(g); /* mark userdata that will be finalized */
propagateall(g); /* remark, to propagate `preserveness' */
@@ -724,51 +845,68 @@ static void atomic (lua_State *L) {
cleartable(g->weak);
cleartable(g->ephemeron);
cleartable(g->allweak);
- g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
- g->sweepstrgc = 0; /* go to sweep phase */
+ g->sweepstrgc = 0; /* prepare to sweep strings */
g->gcstate = GCSsweepstring;
+ g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
+ /*lua_checkmemory(L);*/
}
static l_mem singlestep (lua_State *L) {
global_State *g = G(L);
- /*lua_checkmemory(L);*/
switch (g->gcstate) {
case GCSpause: {
- markroot(L); /* start a new collection */
- return 0;
+ if (!isgenerational(g))
+ markroot(L); /* start a new collection */
+ /* in any case, root must be marked */
+ lua_assert(!iswhite(obj2gco(g->mainthread))
+ && !iswhite(gcvalue(&g->l_registry)));
+ g->gcstate = GCSpropagate;
+ return GCROOTCOST;
}
case GCSpropagate: {
if (g->gray)
return propagatemark(g);
else { /* no more `gray' objects */
- atomic(L); /* finish mark phase */
- return 0;
+ g->gcstate = GCSatomic; /* finish mark phase */
+ atomic(L);
+ return GCATOMICCOST;
}
}
case GCSsweepstring: {
- sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
- if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */
- g->sweepgc = &g->rootgc;
- g->gcstate = GCSsweep; /* sweep all other objects */
+ if (g->sweepstrgc < g->strt.size) {
+ sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
+ return GCSWEEPCOST;
+ }
+ else { /* no more strings to sweep */
+ g->sweepgc = &g->udgc; /* prepare to sweep userdata */
+ g->gcstate = GCSsweepudata;
+ return 0;
}
- return GCSWEEPCOST;
}
- case GCSsweep: {
- g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
- if (*g->sweepgc == NULL) /* nothing more to sweep? */
- g->gcstate = GCSfinalize; /* end sweep phase */
- return GCSWEEPMAX*GCSWEEPCOST;
+ case GCSsweepudata: {
+ if (*g->sweepgc) {
+ g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
+ return GCSWEEPMAX*GCSWEEPCOST;
+ }
+ else {
+ g->sweepgc = &g->allgc; /* go to next phase */
+ g->gcstate = GCSsweep;
+ return GCSWEEPCOST;
+ }
}
- case GCSfinalize: {
- if (g->tobefnz) {
- GCTM(L, 1);
- return GCFINALIZECOST;
+ case GCSsweep: {
+ if (*g->sweepgc) {
+ g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
+ return GCSWEEPMAX*GCSWEEPCOST;
}
else {
+ /* sweep main thread */
+ GCObject *mt = obj2gco(g->mainthread);
+ sweeplist(L, &mt, 1);
checkSizes(L);
- g->gcstate = GCSpause; /* end collection */
- return 0;
+ g->gcstate = GCSpause; /* finish collection */
+ return GCSWEEPCOST;
}
}
default: lua_assert(0); return 0;
@@ -776,22 +914,6 @@ static l_mem singlestep (lua_State *L) {
}
-void luaC_step (lua_State *L) {
- global_State *g = G(L);
- l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; /* how much to work */
- lu_mem debt = g->totalbytes - g->GCthreshold;
- lua_assert(g->gckind == KGC_NORMAL);
- do { /* always perform at least one single step */
- lim -= singlestep(L);
- } while (lim > 0 && g->gcstate != GCSpause);
- g->GCthreshold = (g->gcstate != GCSpause)
- ? g->totalbytes + GCSTEPSIZE
- : (g->totalbytes/100) * g->gcpause;
- /* compensate if GC is "behind schedule" (has some debt to pay) */
- if (g->GCthreshold > debt) g->GCthreshold -= debt;
-}
-
-
/*
** advances the garbage collector until it reaches a state allowed
** by 'statemask'
@@ -803,29 +925,73 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
}
+static void generationalcollection (lua_State *L) {
+ global_State *g = G(L);
+ if (g->lastmajormem == 0) { /* signal for another major collection? */
+ luaC_fullgc(L, 0); /* perform a full regular collection */
+ g->lastmajormem = g->totalbytes; /* update control */
+ }
+ else {
+ luaC_runtilstate(L, bitmask(GCSpause)); /* run collection */
+ if (g->totalbytes > g->lastmajormem/100 * g->gcpause)
+ g->lastmajormem = 0; /* signal for a major collection */
+ }
+ g->GCdebt = stddebt(g);
+}
+
+
+static void step (lua_State *L) {
+ global_State *g = G(L);
+ l_mem lim = g->gcstepmul; /* how much to work */
+ do { /* always perform at least one single step */
+ lim -= singlestep(L);
+ } while (lim > 0 && g->gcstate != GCSpause);
+ if (g->gcstate != GCSpause)
+ g->GCdebt -= GCSTEPSIZE;
+ else
+ g->GCdebt = stddebt(g);
+}
+
+
+void luaC_step (lua_State *L) {
+ int i;
+ if (isgenerational(G(L))) generationalcollection(L);
+ else step(L);
+ for (i = 0; i < GCFINALIZENUM && G(L)->tobefnz; i++)
+ GCTM(L, 1); /* Call a few pending finalizers */
+}
+
+
/*
-** performs a full GC cycle; if "isememrgency", does not call
+** performs a full GC cycle; if "isemergency", does not call
** finalizers (which could change stack positions)
*/
void luaC_fullgc (lua_State *L, int isemergency) {
global_State *g = G(L);
- lua_assert(g->gckind == KGC_NORMAL);
- g->gckind = isemergency ? KGC_EMERGENCY : KGC_FORCED;
- if (g->gcstate == GCSpropagate) { /* marking phase? */
+ int origkind = g->gckind;
+ lua_assert(origkind != KGC_EMERGENCY);
+ if (!isemergency) /* do not run finalizers during emergency GC */
+ callallpendingfinalizers(L, 1);
+ if (keepinvariant(g)) { /* marking phase? */
/* must sweep all objects to turn them back to white
- (as white does not change, nothing will be collected) */
+ (as white has not changed, nothing will be collected) */
g->sweepstrgc = 0;
g->gcstate = GCSsweepstring;
}
- /* finish any pending sweep phase */
- luaC_runtilstate(L, ~bit2mask(GCSsweepstring, GCSsweep));
- markroot(L); /* start a new collection */
- /* run collector up to finalizers */
- luaC_runtilstate(L, bitmask(GCSfinalize));
- g->gckind = KGC_NORMAL;
+ g->gckind = isemergency ? KGC_EMERGENCY : KGC_NORMAL;
+ /* finish any pending sweep phase to start a new cycle */
+ luaC_runtilstate(L, bitmask(GCSpause));
+ /* run entire collector */
+ luaC_runtilstate(L, ~bitmask(GCSpause));
+ luaC_runtilstate(L, bitmask(GCSpause));
+ if (origkind == KGC_GEN) { /* generational mode? */
+ /* generational mode must always start in propagate phase */
+ luaC_runtilstate(L, bitmask(GCSpropagate));
+ }
+ g->gckind = origkind;
+ g->GCdebt = stddebt(g);
if (!isemergency) /* do not run finalizers during emergency GC */
- luaC_runtilstate(L, ~bitmask(GCSfinalize));
- g->GCthreshold = (g->totalbytes/100) * g->gcpause;
+ callallpendingfinalizers(L, 1);
}
/* }====================================================== */
diff --git a/src/lgc.h b/src/lgc.h
index bab2e850..18eb70fd 100644
--- a/src/lgc.h
+++ b/src/lgc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.h,v 2.27 2009/12/16 16:42:58 roberto Exp $
+** $Id: lgc.h,v 2.41 2010/05/10 18:23:45 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -9,18 +9,51 @@
#include "lobject.h"
+#include "lstate.h"
+
+/*
+** Collectable objects may have one of three colors: white, which
+** means the object is not marked; gray, which means the
+** object is marked, but its references may be not marked; and
+** black, which means that the object and all its references are marked.
+** The main invariant of the garbage collector, while marking objects,
+** is that a black object can never point to a white one. Moreover,
+** any gray object must be in a "gray list" (gray, grayagain, weak,
+** allweak, ephemeron) so that it can be visited again before finishing
+** the collection cycle. These lists have no meaning when the invariant
+** is not being enforced (e.g., sweep phase).
+*/
/*
** Possible states of the Garbage Collector
*/
-#define GCSpause 0
-#define GCSpropagate 1
-#define GCSatomic 2
-#define GCSsweepstring 3
+#define GCSpropagate 0
+#define GCSatomic 1
+#define GCSsweepstring 2
+#define GCSsweepudata 3
#define GCSsweep 4
-#define GCSfinalize 5
+#define GCSpause 5
+
+
+#define issweepphase(g) \
+ (GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep)
+
+#define isgenerational(g) ((g)->gckind == KGC_GEN)
+
+/*
+** macro to tell when main invariant (white objects cannot point to black
+** ones) must be kept. During a non-generational collection, the sweep
+** phase may brak the invariant, as objects turned white may point to
+** still-black objects. The invariant is restored when sweep ends and
+** all objects are white again. During a generational collection, the
+** invariant must be kept all times.
+*/
+#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic)
+
+#define gcstopped(g) ((g)->GCdebt == MIN_LMEM)
+#define stopgc(g) ((g)->GCdebt = MIN_LMEM)
/*
@@ -39,34 +72,33 @@
-/*
-** Layout for bit use in `marked' field:
-** bit 0 - object is white (type 0)
-** bit 1 - object is white (type 1)
-** bit 2 - object is black
-** bit 3 - for userdata: has been finalized
-** bit 4 - for userdata: it's in 2nd part of rootgc list or in tobefnz
-** bit 5 - object is fixed (should not be collected)
-** bit 6 - object is "super" fixed (only the main thread)
-*/
-
+/* Layout for bit use in `marked' field: */
+#define WHITE0BIT 0 /* object is white (type 0) */
+#define WHITE1BIT 1 /* object is white (type 1) */
+#define BLACKBIT 2 /* object is black */
+#define FINALIZEDBIT 3 /* for userdata: has been finalized */
+#define SEPARATED 4 /* " ": it's in 'udgc' list or in 'tobefnz' */
+#define FIXEDBIT 5 /* object is fixed (should not be collected) */
+#define OLDBIT 6 /* object is old (only in generational mode) */
+/* bit 7 is currently used by tests (luaL_checkmemory) */
-#define WHITE0BIT 0
-#define WHITE1BIT 1
-#define BLACKBIT 2
-#define FINALIZEDBIT 3
-#define SEPARATED 4
-#define FIXEDBIT 5
-#define SFIXEDBIT 6
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
#define iswhite(x) testbits((x)->gch.marked, WHITEBITS)
#define isblack(x) testbit((x)->gch.marked, BLACKBIT)
-#define isgray(x) (!isblack(x) && !iswhite(x))
+#define isgray(x) /* neither white nor black */ \
+ (!testbits((x)->gch.marked, WHITEBITS | bitmask(BLACKBIT)))
+
+#define isold(x) testbit((x)->gch.marked, OLDBIT)
+
+/* MOVE OLD rule: whenever an object is moved to the beginning of
+ a GC list, its old bit must be cleared */
+#define resetoldbit(o) resetbit((o)->gch.marked, OLDBIT)
#define otherwhite(g) (g->currentwhite ^ WHITEBITS)
-#define isdead(g,v) ((v)->gch.marked & otherwhite(g) & WHITEBITS)
+#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow)))
+#define isdead(g,v) isdeadm(otherwhite(g), (v)->gch.marked)
#define changewhite(x) ((x)->gch.marked ^= WHITEBITS)
#define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT)
@@ -76,8 +108,7 @@
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
-#define luaC_checkGC(L) \
- {condchangemem(L); if (G(L)->totalbytes >= G(L)->GCthreshold) luaC_step(L);}
+#define luaC_checkGC(L) {condchangemem(L); if (G(L)->GCdebt > 0) luaC_step(L);}
#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \
@@ -100,10 +131,10 @@ LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz,
GCObject **list, int offset);
-LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv);
LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, Udata *u);
-
+LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv);
+LUAI_FUNC void luaC_changemode (lua_State *L, int mode);
#endif
diff --git a/src/linit.c b/src/linit.c
index a9430605..ff296cd7 100644
--- a/src/linit.c
+++ b/src/linit.c
@@ -1,5 +1,5 @@
/*
-** $Id: linit.c,v 1.23 2009/12/22 15:32:50 roberto Exp $
+** $Id: linit.c,v 1.24 2010/03/26 20:58:11 roberto Exp $
** Initialization of libraries for lua.c and other clients
** See Copyright Notice in lua.h
*/
@@ -52,9 +52,9 @@ LUALIB_API void luaL_openlibs (lua_State *L) {
const luaL_Reg *lib;
/* call open functions from 'loadedlibs' */
for (lib = loadedlibs; lib->func; lib++) {
- lua_pushcfunction(L, lib->func);
+ lua_settop(L, 0);
lua_pushstring(L, lib->name);
- lua_call(L, 1, 0);
+ (lib->func)(L);
}
/* add open functions from 'preloadedlibs' into 'package.preload' table */
lua_pushglobaltable(L);
@@ -65,8 +65,7 @@ LUALIB_API void luaL_openlibs (lua_State *L) {
}
lua_pop(L, 1); /* remove package.preload table */
#if defined(LUA_COMPAT_DEBUGLIB)
- lua_pushglobaltable(L);
- lua_getfield(L, -1, "require");
+ lua_getglobal(L, "require");
lua_pushliteral(L, LUA_DBLIBNAME);
lua_call(L, 1, 0); /* call 'require"debug"' */
lua_pop(L, 1); /* remove global table */
diff --git a/src/liolib.c b/src/liolib.c
index 64fa43b4..c453cb95 100644
--- a/src/liolib.c
+++ b/src/liolib.c
@@ -1,5 +1,5 @@
/*
-** $Id: liolib.c,v 2.85 2009/12/17 16:20:01 roberto Exp $
+** $Id: liolib.c,v 2.88 2010/03/26 20:58:11 roberto Exp $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
@@ -103,13 +103,12 @@ static FILE *tofile (lua_State *L) {
}
-
/*
** When creating file handles, always creates a `closed' file handle
** before opening the actual file; so, if there is a memory error, the
** file is not left opened.
*/
-static FILE **newfile (lua_State *L) {
+static FILE **newprefile (lua_State *L) {
FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *));
*pf = NULL; /* file handle is currently `closed' */
luaL_getmetatable(L, LUA_FILEHANDLE);
@@ -118,6 +117,14 @@ static FILE **newfile (lua_State *L) {
}
+static FILE **newfile (lua_State *L) {
+ FILE **pf = newprefile(L);
+ lua_pushvalue(L, lua_upvalueindex(1)); /* set upvalue... */
+ lua_setenv(L, -2); /* ... as environment for new file */
+ return pf;
+}
+
+
/*
** function to (not) close the standard files stdin, stdout, and stderr
*/
@@ -156,7 +163,7 @@ static int io_fclose (lua_State *L) {
static int aux_close (lua_State *L) {
- lua_getfenv(L, 1);
+ lua_getenv(L, 1);
lua_getfield(L, -1, "__close");
return (lua_tocfunction(L, -1))(L);
}
@@ -164,7 +171,7 @@ static int aux_close (lua_State *L) {
static int io_close (lua_State *L) {
if (lua_isnone(L, 1))
- lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT);
+ lua_rawgeti(L, lua_upvalueindex(1), IO_OUTPUT);
tofile(L); /* make sure argument is a file */
return aux_close(L);
}
@@ -229,7 +236,7 @@ static int io_tmpfile (lua_State *L) {
static FILE *getiofile (lua_State *L, int findex) {
FILE *f;
- lua_rawgeti(L, LUA_ENVIRONINDEX, findex);
+ lua_rawgeti(L, lua_upvalueindex(1), findex);
f = *(FILE **)lua_touserdata(L, -1);
if (f == NULL)
luaL_error(L, "standard %s file is closed", fnames[findex - 1]);
@@ -250,10 +257,10 @@ static int g_iofile (lua_State *L, int f, const char *mode) {
tofile(L); /* check that it's a valid file handle */
lua_pushvalue(L, 1);
}
- lua_rawseti(L, LUA_ENVIRONINDEX, f);
+ lua_rawseti(L, lua_upvalueindex(1), f);
}
/* return current value */
- lua_rawgeti(L, LUA_ENVIRONINDEX, f);
+ lua_rawgeti(L, lua_upvalueindex(1), f);
return 1;
}
@@ -271,35 +278,46 @@ static int io_output (lua_State *L) {
static int io_readline (lua_State *L);
-static void aux_lines (lua_State *L, int idx, int toclose) {
- lua_pushvalue(L, idx);
+static void aux_lines (lua_State *L, int toclose) {
+ int i;
+ int n = lua_gettop(L) - 1; /* number of arguments to read */
+ /* ensure that arguments will fit here and into 'io_readline' stack */
+ luaL_argcheck(L, n <= LUA_MINSTACK - 3, LUA_MINSTACK - 3, "too many options");
+ lua_pushvalue(L, 1); /* file handle */
+ lua_pushinteger(L, n); /* number of arguments to read */
lua_pushboolean(L, toclose); /* close/not close file when finished */
- lua_pushcclosure(L, io_readline, 2);
+ for (i = 1; i <= n; i++) lua_pushvalue(L, i + 1); /* copy arguments */
+ lua_pushcclosure(L, io_readline, 3 + n);
}
static int f_lines (lua_State *L) {
tofile(L); /* check that it's a valid file handle */
- aux_lines(L, 1, 0);
+ aux_lines(L, 0);
return 1;
}
static int io_lines (lua_State *L) {
- if (lua_isnoneornil(L, 1)) { /* no arguments? */
- /* will iterate over default input */
- lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT);
- return f_lines(L);
+ int toclose;
+ if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */
+ if (lua_isnil(L, 1)) { /* no file name? */
+ lua_rawgeti(L, lua_upvalueindex(1), IO_INPUT); /* get default input */
+ lua_replace(L, 1); /* put it at index 1 */
+ tofile(L); /* check that it's a valid file handle */
+ toclose = 0; /* do not close it after iteration */
}
- else {
+ else { /* open a new file */
const char *filename = luaL_checkstring(L, 1);
FILE **pf = newfile(L);
*pf = fopen(filename, "r");
if (*pf == NULL)
fileerror(L, 1, filename);
- aux_lines(L, lua_gettop(L), 1);
- return 1;
+ lua_replace(L, 1); /* put file at index 1 */
+ toclose = 1; /* close it after iteration */
}
+ aux_lines(L, toclose);
+ return 1;
}
@@ -316,7 +334,10 @@ static int read_number (lua_State *L, FILE *f) {
lua_pushnumber(L, d);
return 1;
}
- else return 0; /* read fails */
+ else {
+ lua_pushnil(L); /* "result" to be removed */
+ return 0; /* read fails */
+ }
}
@@ -328,7 +349,7 @@ static int test_eof (lua_State *L, FILE *f) {
}
-static int read_line (lua_State *L, FILE *f) {
+static int read_line (lua_State *L, FILE *f, int chop) {
luaL_Buffer b;
luaL_buffinit(L, &b);
for (;;) {
@@ -342,7 +363,7 @@ static int read_line (lua_State *L, FILE *f) {
if (l == 0 || p[l-1] != '\n')
luaL_addsize(&b, l);
else {
- luaL_addsize(&b, l - 1); /* do not include `eol' */
+ luaL_addsize(&b, l - chop); /* chop 'eol' if needed */
luaL_pushresult(&b); /* close buffer */
return 1; /* read at least an `eol' */
}
@@ -375,7 +396,7 @@ static int g_read (lua_State *L, FILE *f, int first) {
int n;
clearerr(f);
if (nargs == 0) { /* no arguments? */
- success = read_line(L, f);
+ success = read_line(L, f, 1);
n = first+1; /* to return 1 result */
}
else { /* ensure stack space for all results and for auxlib's buffer */
@@ -394,7 +415,10 @@ static int g_read (lua_State *L, FILE *f, int first) {
success = read_number(L, f);
break;
case 'l': /* line */
- success = read_line(L, f);
+ success = read_line(L, f, 1);
+ break;
+ case 'L': /* line with end-of-line */
+ success = read_line(L, f, 0);
break;
case 'a': /* file */
read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */
@@ -428,15 +452,22 @@ static int f_read (lua_State *L) {
static int io_readline (lua_State *L) {
FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1));
- int success;
+ int i;
+ int n = lua_tointeger(L, lua_upvalueindex(2));
if (f == NULL) /* file is already closed? */
luaL_error(L, "file is already closed");
- success = read_line(L, f);
- if (ferror(f))
- return luaL_error(L, "%s", strerror(errno));
- if (success) return 1;
- else { /* EOF */
- if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */
+ lua_settop(L , 1);
+ for (i = 1; i <= n; i++) /* push arguments to 'g_read' */
+ lua_pushvalue(L, lua_upvalueindex(3 + i));
+ n = g_read(L, f, 2); /* 'n' is number of results */
+ lua_assert(n > 0); /* should return at least a nil */
+ if (!lua_isnil(L, -n)) /* read at least one value? */
+ return n; /* return them */
+ else { /* first result is nil: EOF or error */
+ if (!lua_isnil(L, -1)) /* is there error information? */
+ return luaL_error(L, "%s", lua_tostring(L, -1)); /* error */
+ /* else EOF */
+ if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */
lua_settop(L, 0);
lua_pushvalue(L, lua_upvalueindex(1));
aux_close(L); /* close it */
@@ -552,23 +583,27 @@ static void createmeta (lua_State *L) {
luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */
lua_pushvalue(L, -1); /* push metatable */
lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
- luaL_register(L, NULL, flib); /* file methods */
+ luaL_register(L, NULL, flib); /* add file methods to new metatable */
+ lua_pop(L, 1); /* pop new metatable */
}
static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) {
- *newfile(L) = f;
+ *newprefile(L) = f;
if (k > 0) {
- lua_pushvalue(L, -1);
- lua_rawseti(L, LUA_ENVIRONINDEX, k);
+ lua_pushvalue(L, -1); /* copy new file */
+ lua_rawseti(L, 1, k); /* add it to common upvalue */
}
- lua_pushvalue(L, -2); /* copy environment */
- lua_setfenv(L, -2); /* set it */
- lua_setfield(L, -3, fname);
+ lua_pushvalue(L, 3); /* get environment for default files */
+ lua_setenv(L, -2); /* set it as environment for file */
+ lua_setfield(L, 2, fname); /* add file to module */
}
-static void newfenv (lua_State *L, lua_CFunction cls) {
+/*
+** pushes a new table with {__close = cls}
+*/
+static void newenv (lua_State *L, lua_CFunction cls) {
lua_createtable(L, 0, 1);
lua_pushcfunction(L, cls);
lua_setfield(L, -2, "__close");
@@ -576,21 +611,21 @@ static void newfenv (lua_State *L, lua_CFunction cls) {
LUAMOD_API int luaopen_io (lua_State *L) {
+ lua_settop(L, 0);
createmeta(L);
/* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */
- newfenv(L, io_fclose);
- lua_replace(L, LUA_ENVIRONINDEX);
- /* open library */
- luaL_register(L, LUA_IOLIBNAME, iolib);
+ newenv(L, io_fclose); /* upvalue for all io functions at index 1 */
+ lua_pushvalue(L, -1); /* copy to be consumed by 'openlib' */
+ luaL_openlib(L, LUA_IOLIBNAME, iolib, 1); /* new module at index 2 */
/* create (and set) default files */
- newfenv(L, io_noclose); /* close function for default files */
+ newenv(L, io_noclose); /* environment for default files at index 3 */
createstdfile(L, stdin, IO_INPUT, "stdin");
createstdfile(L, stdout, IO_OUTPUT, "stdout");
createstdfile(L, stderr, 0, "stderr");
lua_pop(L, 1); /* pop environment for default files */
- lua_getfield(L, -1, "popen");
- newfenv(L, io_pclose); /* create environment for 'popen' */
- lua_setfenv(L, -2); /* set fenv for 'popen' */
+ lua_getfield(L, 2, "popen");
+ newenv(L, io_pclose); /* create environment for 'popen' streams */
+ lua_setupvalue(L, -2, 1); /* set it as upvalue for 'popen' */
lua_pop(L, 1); /* pop 'popen' */
return 1;
}
diff --git a/src/llex.c b/src/llex.c
index 3cfdbca1..e380910d 100644
--- a/src/llex.c
+++ b/src/llex.c
@@ -1,5 +1,5 @@
/*
-** $Id: llex.c,v 2.34 2009/11/17 16:33:38 roberto Exp $
+** $Id: llex.c,v 2.37 2010/04/16 12:31:07 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -117,21 +117,30 @@ void luaX_syntaxerror (LexState *ls, const char *msg) {
}
+/*
+** creates a new string and anchors it in function's table so that
+** it will not be collected until the end of the function's compilation
+** (by that time it should be anchored in function's prototype)
+*/
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
lua_State *L = ls->L;
TValue *o; /* entry for `str' */
- TString *ts = luaS_newlstr(L, str, l);
- setsvalue2s(L, L->top++, ts); /* anchor string */
- o = luaH_setstr(L, ls->fs->h, ts);
+ TString *ts = luaS_newlstr(L, str, l); /* create new string */
+ setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */
+ o = luaH_setstr(L, ls->fs->h, ts);
if (ttisnil(o)) {
- setbvalue(o, 1); /* make sure `str' will not be collected */
+ setbvalue(o, 1); /* t[string] = true */
luaC_checkGC(L);
}
- L->top--;
+ L->top--; /* remove string from stack */
return ts;
}
+/*
+** increment line number and skips newline sequence (any of
+** \n, \r, \n\r, or \r\n)
+*/
static void inclinenumber (LexState *ls) {
int old = ls->current;
lua_assert(currIsNewline(ls));
@@ -152,6 +161,8 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) {
ls->linenumber = 1;
ls->lastline = 1;
ls->source = source;
+ ls->envn = luaS_new(L, "_ENV"); /* create env name */
+ luaS_fix(ls->envn); /* never collect this name */
luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
next(ls); /* read first char */
}
@@ -174,6 +185,9 @@ static int check_next (LexState *ls, const char *set) {
}
+/*
+** change all characters 'from' in buffer to 'to'
+*/
static void buffreplace (LexState *ls, char from, char to) {
size_t n = luaZ_bufflen(ls->buff);
char *p = luaZ_buffer(ls->buff);
@@ -186,11 +200,14 @@ static void buffreplace (LexState *ls, char from, char to) {
#define getlocaledecpoint() (localeconv()->decimal_point[0])
#endif
+/*
+** in case of format error, try to change decimal point separator to
+** the one defined in the current locale and check again
+*/
static void trydecpoint (LexState *ls, SemInfo *seminfo) {
- /* format error: try to update decimal point separator */
char old = ls->decpoint;
ls->decpoint = getlocaledecpoint();
- buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */
+ buffreplace(ls, old, ls->decpoint); /* try new decimal separator */
if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) {
/* format error with correct decimal point: no more options */
buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */
@@ -216,6 +233,10 @@ static void read_numeral (LexState *ls, SemInfo *seminfo) {
}
+/*
+** skip a sequence '[=*=[' or ']=*]' and return its number of '='s or
+** -1 if sequence is malformed
+*/
static int skip_sep (LexState *ls) {
int count = 0;
int s = ls->current;
@@ -246,8 +267,7 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
}
break;
}
- case '\n':
- case '\r': {
+ case '\n': case '\r': {
save(ls, '\n');
inclinenumber(ls);
if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */
@@ -308,16 +328,16 @@ static int readdecesc (LexState *ls) {
static void read_string (LexState *ls, int del, SemInfo *seminfo) {
- save_and_next(ls);
+ save_and_next(ls); /* keep delimiter (for error messages) */
while (ls->current != del) {
switch (ls->current) {
case EOZ:
lexerror(ls, "unfinished string", TK_EOS);
- continue; /* to avoid warnings */
+ break; /* to avoid warnings */
case '\n':
case '\r':
lexerror(ls, "unfinished string", TK_STRING);
- continue; /* to avoid warnings */
+ break; /* to avoid warnings */
case '\\': { /* escape sequences */
int c; /* final character to be saved */
next(ls); /* do not save the `\' */
@@ -333,6 +353,14 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) {
case '\n':
case '\r': save(ls, '\n'); inclinenumber(ls); continue;
case EOZ: continue; /* will raise an error next loop */
+ case '*': { /* skip following span of spaces */
+ next(ls); /* skip the '*' */
+ while (lisspace(ls->current)) {
+ if (currIsNewline(ls)) inclinenumber(ls);
+ else next(ls);
+ }
+ continue; /* do not save 'c' */
+ }
default: {
if (!lisdigit(ls->current))
c = ls->current; /* handles \\, \", \', and \? */
@@ -343,7 +371,7 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) {
}
next(ls);
save(ls, c);
- continue;
+ break;
}
default:
save_and_next(ls);
@@ -359,31 +387,34 @@ static int llex (LexState *ls, SemInfo *seminfo) {
luaZ_resetbuffer(ls->buff);
for (;;) {
switch (ls->current) {
- case '\n':
- case '\r': {
+ case '\n': case '\r': { /* line breaks */
inclinenumber(ls);
- continue;
+ break;
}
- case '-': {
+ case ' ': case '\f': case '\t': case '\v': { /* spaces */
+ next(ls);
+ break;
+ }
+ case '-': { /* '-' or '--' (comment) */
next(ls);
if (ls->current != '-') return '-';
/* else is a comment */
next(ls);
- if (ls->current == '[') {
+ if (ls->current == '[') { /* long comment? */
int sep = skip_sep(ls);
luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */
if (sep >= 0) {
- read_long_string(ls, NULL, sep); /* long comment */
- luaZ_resetbuffer(ls->buff);
- continue;
+ read_long_string(ls, NULL, sep); /* skip long comment */
+ luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */
+ break;
}
}
/* else short comment */
while (!currIsNewline(ls) && ls->current != EOZ)
- next(ls);
- continue;
+ next(ls); /* skip until end of line (or end of file) */
+ break;
}
- case '[': {
+ case '[': { /* long string or simply '[' */
int sep = skip_sep(ls);
if (sep >= 0) {
read_long_string(ls, seminfo, sep);
@@ -412,39 +443,30 @@ static int llex (LexState *ls, SemInfo *seminfo) {
if (ls->current != '=') return '~';
else { next(ls); return TK_NE; }
}
- case '"':
- case '\'': {
+ case '"': case '\'': { /* short literal strings */
read_string(ls, ls->current, seminfo);
return TK_STRING;
}
- case '.': {
+ case '.': { /* '.', '..', '...', or number */
save_and_next(ls);
if (check_next(ls, ".")) {
if (check_next(ls, "."))
- return TK_DOTS; /* ... */
- else return TK_CONCAT; /* .. */
+ return TK_DOTS; /* '...' */
+ else return TK_CONCAT; /* '..' */
}
else if (!lisdigit(ls->current)) return '.';
- else {
- read_numeral(ls, seminfo);
- return TK_NUMBER;
- }
+ /* else go through */
+ }
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9': {
+ read_numeral(ls, seminfo);
+ return TK_NUMBER;
}
case EOZ: {
return TK_EOS;
}
default: {
- if (lisspace(ls->current)) {
- lua_assert(!currIsNewline(ls));
- next(ls);
- continue;
- }
- else if (lisdigit(ls->current)) {
- read_numeral(ls, seminfo);
- return TK_NUMBER;
- }
- else if (lislalpha(ls->current)) {
- /* identifier or reserved word */
+ if (lislalpha(ls->current)) { /* identifier or reserved word? */
TString *ts;
do {
save_and_next(ls);
@@ -458,10 +480,10 @@ static int llex (LexState *ls, SemInfo *seminfo) {
return TK_NAME;
}
}
- else {
+ else { /* single-char tokens (+ - / ...) */
int c = ls->current;
next(ls);
- return c; /* single-char tokens (+ - / ...) */
+ return c;
}
}
}
diff --git a/src/llex.h b/src/llex.h
index d687fb8d..1a811dce 100644
--- a/src/llex.h
+++ b/src/llex.h
@@ -1,5 +1,5 @@
/*
-** $Id: llex.h,v 1.62 2009/10/11 20:02:19 roberto Exp $
+** $Id: llex.h,v 1.65 2010/04/05 16:35:37 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -60,6 +60,7 @@ typedef struct LexState {
Mbuffer *buff; /* buffer for tokens */
struct Varlist *varl; /* list of all active local variables */
TString *source; /* current source name */
+ TString *envn; /* environment variable name */
char decpoint; /* locale decimal point */
} LexState;
diff --git a/src/llimits.h b/src/llimits.h
index 6bf49840..02be816e 100644
--- a/src/llimits.h
+++ b/src/llimits.h
@@ -1,5 +1,5 @@
/*
-** $Id: llimits.h,v 1.77 2009/12/17 12:50:20 roberto Exp $
+** $Id: llimits.h,v 1.80 2010/05/07 18:44:12 roberto Exp $
** Limits, basic types, and some other `installation-dependent' definitions
** See Copyright Notice in lua.h
*/
@@ -30,6 +30,7 @@ typedef unsigned char lu_byte;
#define MAX_SIZET ((size_t)(~(size_t)0)-2)
#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2)
+#define MIN_LMEM ((l_mem)~((~(lu_mem)0)>>1))
#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */
@@ -59,7 +60,7 @@ typedef LUAI_UACNUMBER l_uacNumber;
#if defined(lua_assert)
#define check_exp(c,e) (lua_assert(c), (e))
#else
-#define lua_assert(c) ((void)0)
+#define lua_assert(c) /* empty */
#define check_exp(c,e) (e)
#endif
@@ -139,19 +140,19 @@ typedef lu_int32 Instruction;
** created/deleted/resumed/yielded.
*/
#if !defined(luai_userstateopen)
-#define luai_userstateopen(L) ((void)L)
+#define luai_userstateopen(L) ((void)L)
#endif
#if !defined(luai_userstateclose)
-#define luai_userstateclose(L) ((void)L)
+#define luai_userstateclose(L) ((void)L)
#endif
#if !defined(luai_userstatethread)
-#define luai_userstatethread(L,L1) ((void)L)
+#define luai_userstatethread(L,L1) ((void)L)
#endif
#if !defined(luai_userstatefree)
-#define luai_userstatefree(L) ((void)L)
+#define luai_userstatefree(L,L1) ((void)L)
#endif
#if !defined(luai_userstateresume)
diff --git a/src/lmem.c b/src/lmem.c
index 022ccfd3..0f3178a2 100644
--- a/src/lmem.c
+++ b/src/lmem.c
@@ -1,5 +1,5 @@
/*
-** $Id: lmem.c,v 1.74 2009/12/16 16:42:58 roberto Exp $
+** $Id: lmem.c,v 1.79 2010/05/05 18:49:56 roberto Exp $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
@@ -79,13 +79,14 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
size_t realosize = (block) ? osize : 0;
lua_assert((realosize == 0) == (block == NULL));
#if defined(HARDMEMTESTS)
- if (nsize > realosize && g->GCthreshold != MAX_LUMEM)
+ if (nsize > realosize && !gcstopped(g))
luaC_fullgc(L, 1); /* force a GC whenever possible */
#endif
newblock = (*g->frealloc)(g->ud, block, osize, nsize);
if (newblock == NULL && nsize > 0) {
- lua_assert(nsize > realosize); /* cannot fail when shrinking a block */
- if (g->GCthreshold != MAX_LUMEM) {
+ api_check(L, nsize > realosize,
+ "realloc cannot fail when shrinking a block");
+ if (!gcstopped(g)) {
luaC_fullgc(L, 1); /* try to free some memory... */
newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
}
@@ -94,6 +95,26 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
}
lua_assert((nsize == 0) == (newblock == NULL));
g->totalbytes = (g->totalbytes - realosize) + nsize;
+ if (!gcstopped(g))
+ g->GCdebt += nsize; /* give some credit to garbage collector */
+#if defined(TRACEMEM)
+ { /* auxiliary patch to monitor garbage collection.
+ ** To plot, gnuplot with following command:
+ ** plot TRACEMEM using 1:2 with lines, TRACEMEM using 1:3 with lines
+ */
+ static unsigned long total = 0; /* our "time" */
+ static FILE *f = NULL; /* output file */
+ total++; /* "time" always grows */
+ if ((total % 200) == 0) {
+ if (f == NULL) f = fopen(TRACEMEM, "w");
+ fprintf(f, "%lu %u %d %d\n", total,
+ g->totalbytes,
+ gcstopped(g) ? 0 : g->GCdebt,
+ g->gcstate * 1000);
+ }
+ }
+#endif
+
return newblock;
}
diff --git a/src/lmem.h b/src/lmem.h
index b8b3bae9..ff324f89 100644
--- a/src/lmem.h
+++ b/src/lmem.h
@@ -1,5 +1,5 @@
/*
-** $Id: lmem.h,v 1.35 2009/12/16 16:42:58 roberto Exp $
+** $Id: lmem.h,v 1.36 2010/04/08 17:16:46 roberto Exp $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
@@ -13,8 +13,6 @@
#include "llimits.h"
#include "lua.h"
-#define MEMERRMSG "not enough memory"
-
#define luaM_reallocv(L,b,on,n,e) \
((cast(size_t, (n)+1) <= MAX_SIZET/(e)) ? /* +1 to avoid warnings */ \
diff --git a/src/loadlib.c b/src/loadlib.c
index 90c785dc..793c658e 100644
--- a/src/loadlib.c
+++ b/src/loadlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: loadlib.c,v 1.80 2010/01/13 16:30:27 roberto Exp $
+** $Id: loadlib.c,v 1.82 2010/03/19 15:02:34 roberto Exp $
** Dynamic library loader for Lua
** See Copyright Notice in lua.h
**
@@ -353,9 +353,7 @@ static int ll_loadfunc (lua_State *L, const char *path, const char *sym) {
lua_CFunction f = ll_sym(L, *reg, sym);
if (f == NULL)
return ERRFUNC; /* unable to find function */
- lua_pushcfunction(L, f); /* else create new function... */
- lua_pushglobaltable(L); /* ... and set the standard global table... */
- lua_setfenv(L, -2); /* ... as its environment */
+ lua_pushcfunction(L, f); /* else create new function */
return 0; /* no errors */
}
}
@@ -435,7 +433,7 @@ static int ll_searchpath (lua_State *L) {
static const char *findfile (lua_State *L, const char *name,
const char *pname) {
const char *path;
- lua_getfield(L, LUA_ENVIRONINDEX, pname);
+ lua_getfield(L, lua_upvalueindex(1), pname);
path = lua_tostring(L, -1);
if (path == NULL)
luaL_error(L, LUA_QL("package.%s") " must be a string", pname);
@@ -509,7 +507,7 @@ static int loader_Croot (lua_State *L) {
static int loader_preload (lua_State *L) {
const char *name = luaL_checkstring(L, 1);
- lua_getfield(L, LUA_ENVIRONINDEX, "preload");
+ lua_getfield(L, lua_upvalueindex(1), "preload");
if (!lua_istable(L, -1))
luaL_error(L, LUA_QL("package.preload") " must be a table");
lua_getfield(L, -1, name);
@@ -535,7 +533,7 @@ static int ll_require (lua_State *L) {
return 1; /* package is already loaded */
}
/* else must load it; iterate over available loaders */
- lua_getfield(L, LUA_ENVIRONINDEX, "loaders");
+ lua_getfield(L, lua_upvalueindex(1), "loaders");
if (!lua_istable(L, -1))
luaL_error(L, LUA_QL("package.loaders") " must be a table");
lua_pushliteral(L, ""); /* error message accumulator */
@@ -579,14 +577,18 @@ static int ll_require (lua_State *L) {
*/
-static void setfenv (lua_State *L) {
+/*
+** FOR COMPATIBILITY ONLY: changes the _ENV variable of
+** calling function
+*/
+static void set_env (lua_State *L) {
lua_Debug ar;
if (lua_getstack(L, 1, &ar) == 0 ||
lua_getinfo(L, "f", &ar) == 0 || /* get calling function */
lua_iscfunction(L, -1))
luaL_error(L, LUA_QL("module") " not called from a Lua function");
lua_pushvalue(L, -2); /* copy new environment table to top */
- lua_setfenv(L, -2);
+ lua_setupvalue(L, -2, 1);
lua_pop(L, 1); /* remove function */
}
@@ -639,7 +641,7 @@ static int ll_module (lua_State *L) {
modinit(L, modname);
}
lua_pushvalue(L, -1);
- setfenv(L);
+ set_env(L);
dooptions(L, loaded - 1);
return 1;
}
@@ -709,12 +711,12 @@ LUAMOD_API int luaopen_package (lua_State *L) {
lua_setfield(L, -2, "__gc");
/* create `package' table */
luaL_register(L, LUA_LOADLIBNAME, pk_funcs);
- lua_copy(L, -1, LUA_ENVIRONINDEX);
/* create `loaders' table */
lua_createtable(L, sizeof(loaders)/sizeof(loaders[0]) - 1, 0);
/* fill it with pre-defined loaders */
for (i=0; loaders[i] != NULL; i++) {
- lua_pushcfunction(L, loaders[i]);
+ lua_pushvalue(L, -2); /* set 'package' as upvalue for all loaders */
+ lua_pushcclosure(L, loaders[i], 1);
lua_rawseti(L, -2, i+1);
}
lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */
@@ -731,8 +733,9 @@ LUAMOD_API int luaopen_package (lua_State *L) {
lua_newtable(L);
lua_setfield(L, -2, "preload");
lua_pushglobaltable(L);
- luaL_register(L, NULL, ll_funcs); /* open lib into global table */
- lua_pop(L, 1);
+ lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */
+ luaL_openlib(L, NULL, ll_funcs, 1); /* open lib into global table */
+ lua_pop(L, 1); /* pop global table */
return 1; /* return 'package' table */
}
diff --git a/src/lobject.c b/src/lobject.c
index 8f5c5691..d4fff394 100644
--- a/src/lobject.c
+++ b/src/lobject.c
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.c,v 2.34 2009/11/26 11:39:20 roberto Exp $
+** $Id: lobject.c,v 2.40 2010/04/18 13:22:48 roberto Exp $
** Some generic functions over Lua objects
** See Copyright Notice in lua.h
*/
@@ -81,6 +81,10 @@ int luaO_rawequalObj (const TValue *t1, const TValue *t2) {
return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */
case LUA_TLIGHTUSERDATA:
return pvalue(t1) == pvalue(t2);
+ case LUA_TSTRING:
+ return rawtsvalue(t1) == rawtsvalue(t2);
+ case LUA_TLCF:
+ return fvalue(t1) == fvalue(t2);
default:
lua_assert(iscollectable(t1));
return gcvalue(t1) == gcvalue(t2);
@@ -96,7 +100,7 @@ lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) {
case LUA_OPDIV: return luai_numdiv(NULL, v1, v2);
case LUA_OPMOD: return luai_nummod(NULL, v1, v2);
case LUA_OPPOW: return luai_numpow(NULL, v1, v2);
- case LUA_OPUNM: return luai_numunm(N, v1);
+ case LUA_OPUNM: return luai_numunm(NULL, v1);
default: lua_assert(0); return 0;
}
}
@@ -108,24 +112,21 @@ int luaO_str2d (const char *s, lua_Number *result) {
if (endptr == s) return 0; /* conversion failed */
if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */
*result = cast_num(strtoul(s, &endptr, 16));
- if (*endptr == '\0') return 1; /* most common case */
while (lisspace(cast(unsigned char, *endptr))) endptr++;
- if (*endptr != '\0') return 0; /* invalid trailing characters? */
- return 1;
+ return (*endptr == '\0'); /* OK if no trailing characters */
}
-static void pushstr (lua_State *L, const char *str) {
- setsvalue2s(L, L->top, luaS_new(L, str));
+static void pushstr (lua_State *L, const char *str, size_t l) {
+ setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
incr_top(L);
}
/* this function handles only `%d', `%c', %f, %p, and `%s' formats */
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
- int n = 1;
- pushstr(L, "");
+ int n = 0;
for (;;) {
const char *e = strchr(fmt, '%');
if (e == NULL) break;
@@ -135,14 +136,13 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
case 's': {
const char *s = va_arg(argp, char *);
if (s == NULL) s = "(null)";
- pushstr(L, s);
+ pushstr(L, s, strlen(s));
break;
}
case 'c': {
- char buff[2];
- buff[0] = cast(char, va_arg(argp, int));
- buff[1] = '\0';
- pushstr(L, buff);
+ char buff;
+ buff = cast(char, va_arg(argp, int));
+ pushstr(L, &buff, 1);
break;
}
case 'd': {
@@ -157,12 +157,12 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
}
case 'p': {
char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */
- sprintf(buff, "%p", va_arg(argp, void *));
- pushstr(L, buff);
+ int l = sprintf(buff, "%p", va_arg(argp, void *));
+ pushstr(L, buff, l);
break;
}
case '%': {
- pushstr(L, "%");
+ pushstr(L, "%", 1);
break;
}
default: {
@@ -175,8 +175,8 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
n += 2;
fmt = e+2;
}
- pushstr(L, fmt);
- luaV_concat(L, n+1);
+ pushstr(L, fmt, strlen(fmt));
+ if (n > 0) luaV_concat(L, n + 1);
return svalue(L->top - 1);
}
diff --git a/src/lobject.h b/src/lobject.h
index 2969fe7d..73634220 100644
--- a/src/lobject.h
+++ b/src/lobject.h
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.h,v 2.34 2010/01/08 20:00:20 roberto Exp $
+** $Id: lobject.h,v 2.40 2010/05/07 18:44:46 roberto Exp $
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
@@ -16,21 +16,21 @@
#include "lua.h"
-/* tags for values visible from Lua */
-#define LAST_TAG LUA_TTHREAD
-
-#define NUM_TAGS (LAST_TAG+1)
-
-
/*
** Extra tags for non-values
*/
-#define LUA_TPROTO (LAST_TAG+1)
-#define LUA_TUPVAL (LAST_TAG+2)
-#define LUA_TDEADKEY (LAST_TAG+3)
+#define LUA_TPROTO LUA_NUMTAGS
+#define LUA_TUPVAL (LUA_NUMTAGS+1)
+#define LUA_TDEADKEY (LUA_NUMTAGS+2)
/*
+** Variant tag for light C functions (negative to be considered
+** non collectable by 'iscollectable')
+*/
+#define LUA_TLCF (~0x0F | LUA_TFUNCTION)
+
+/*
** Union of all collectable objects
*/
typedef union GCObject GCObject;
@@ -60,6 +60,7 @@ typedef union {
void *p;
lua_Number n;
int b;
+ lua_CFunction f;
} Value;
@@ -79,12 +80,26 @@ typedef struct lua_TValue {
#define NILCONSTANT {NULL}, LUA_TNIL
+/*
+** type tag of a TValue
+*/
+#define ttype(o) ((o)->tt_)
+
+
+/*
+** type tag of a TValue with no variants
+*/
+#define ttypenv(o) (ttype(o) & 0x0F)
+
+
/* Macros to test type */
#define ttisnil(o) (ttype(o) == LUA_TNIL)
#define ttisnumber(o) (ttype(o) == LUA_TNUMBER)
#define ttisstring(o) (ttype(o) == LUA_TSTRING)
#define ttistable(o) (ttype(o) == LUA_TTABLE)
-#define ttisfunction(o) (ttype(o) == LUA_TFUNCTION)
+#define ttisfunction(o) (ttypenv(o) == LUA_TFUNCTION)
+#define ttisclosure(o) (ttype(o) == LUA_TFUNCTION)
+#define ttislcf(o) (ttype(o) == LUA_TLCF)
#define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN)
#define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA)
#define ttisthread(o) (ttype(o) == LUA_TTHREAD)
@@ -92,7 +107,6 @@ typedef struct lua_TValue {
#define ttisdeadkey(o) (ttype(o) == LUA_TDEADKEY)
/* Macros to access values */
-#define ttype(o) ((o)->tt_)
#define gcvalue(o) check_exp(iscollectable(o), (o)->value_.gc)
#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value_.p)
#define nvalue(o) check_exp(ttisnumber(o), (o)->value_.n)
@@ -100,16 +114,15 @@ typedef struct lua_TValue {
#define tsvalue(o) (&rawtsvalue(o)->tsv)
#define rawuvalue(o) check_exp(ttisuserdata(o), &(o)->value_.gc->u)
#define uvalue(o) (&rawuvalue(o)->uv)
-#define clvalue(o) check_exp(ttisfunction(o), &(o)->value_.gc->cl)
+#define clvalue(o) check_exp(ttisclosure(o), &(o)->value_.gc->cl)
+#define fvalue(o) check_exp(ttislcf(o), (o)->value_.f)
#define hvalue(o) check_exp(ttistable(o), &(o)->value_.gc->h)
#define bvalue(o) check_exp(ttisboolean(o), (o)->value_.b)
#define thvalue(o) check_exp(ttisthread(o), &(o)->value_.gc->th)
#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
-/*
-** for internal debug only
-*/
+
#define iscollectable(o) (ttype(o) >= LUA_TSTRING)
#define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt)
@@ -126,8 +139,10 @@ typedef struct lua_TValue {
#define setnvalue(obj,x) \
{ TValue *i_o=(obj); i_o->value_.n=(x); i_o->tt_=LUA_TNUMBER; }
-#define changenvalue(obj,x) \
- ( lua_assert((obj)->tt_==LUA_TNUMBER), (obj)->value_.n=(x) )
+#define setfvalue(obj,x) \
+ { TValue *i_o=(obj); i_o->value_.f=(x); i_o->tt_=LUA_TLCF; }
+
+#define changenvalue(o,x) check_exp((o)->tt_==LUA_TNUMBER, (o)->value_.n=(x))
#define setpvalue(obj,x) \
{ TValue *i_o=(obj); i_o->value_.p=(x); i_o->tt_=LUA_TLIGHTUSERDATA; }
@@ -264,7 +279,6 @@ typedef struct Proto {
lu_byte numparams;
lu_byte is_vararg;
lu_byte maxstacksize;
- lu_byte envreg; /* register in outer function with initial environment */
} Proto;
@@ -298,8 +312,7 @@ typedef struct UpVal {
*/
#define ClosureHeader \
- CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \
- struct Table *env
+ CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist
typedef struct CClosure {
ClosureHeader;
@@ -321,8 +334,7 @@ typedef union Closure {
} Closure;
-#define iscfunction(o) (ttisfunction(o) && clvalue(o)->c.isC)
-#define isLfunction(o) (ttisfunction(o) && !clvalue(o)->c.isC)
+#define isLfunction(o) (ttisclosure(o) && !clvalue(o)->c.isC)
#define getproto(o) (clvalue(o)->l.p)
diff --git a/src/lopcodes.c b/src/lopcodes.c
index 188c7a55..cc1acb13 100644
--- a/src/lopcodes.c
+++ b/src/lopcodes.c
@@ -1,5 +1,5 @@
/*
-** $Id: lopcodes.c,v 1.41 2009/11/19 19:06:52 roberto Exp $
+** $Id: lopcodes.c,v 1.43 2010/03/12 19:14:06 roberto Exp $
** See Copyright Notice in lua.h
*/
@@ -19,9 +19,9 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
"LOADBOOL",
"LOADNIL",
"GETUPVAL",
- "GETGLOBAL",
+ "GETTABUP",
"GETTABLE",
- "SETGLOBAL",
+ "SETTABUP",
"SETUPVAL",
"SETTABLE",
"NEWTABLE",
@@ -67,9 +67,9 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */
,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LOADNIL */
,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */
- ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_GETGLOBAL */
+ ,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */
,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */
- ,opmode(0, 0, OpArgK, OpArgN, iABx) /* OP_SETGLOBAL */
+ ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABUP */
,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */
,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */
,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */
diff --git a/src/lopcodes.h b/src/lopcodes.h
index 19ddfea3..4140db3a 100644
--- a/src/lopcodes.h
+++ b/src/lopcodes.h
@@ -1,5 +1,5 @@
/*
-** $Id: lopcodes.h,v 1.133 2009/11/19 19:06:52 roberto Exp $
+** $Id: lopcodes.h,v 1.135 2010/03/12 19:14:06 roberto Exp $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -171,10 +171,10 @@ OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */
OP_LOADNIL,/* A B R(A) := ... := R(B) := nil */
OP_GETUPVAL,/* A B R(A) := UpValue[B] */
-OP_GETGLOBAL,/* A Bx R(A) := Gbl[Kst(Bx - 1)] */
+OP_GETTABUP,/* A B C R(A) := UpValue[B][RK(C)] */
OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */
-OP_SETGLOBAL,/* A Bx Gbl[Kst(Bx - 1)] := R(A) */
+OP_SETTABUP,/* A B C UpValue[A][RK(B)] := RK(C) */
OP_SETUPVAL,/* A B UpValue[B] := R(A) */
OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */
@@ -243,8 +243,7 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
(*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next
'instruction' is EXTRAARG(real C).
- (*) In OP_LOADK, OP_GETGLOBAL, and OP_SETGLOBAL, if (Bx == 0) then next
- 'instruction' is EXTRAARG(real Bx).
+ (*) In OP_LOADK, if (Bx == 0) then next 'instruction' is EXTRAARG(real Bx).
(*) For comparisons, A specifies what condition the test should accept
(true or false).
diff --git a/src/lparser.c b/src/lparser.c
index cc21f67f..762cb4fc 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.c,v 2.75 2010/01/06 11:48:02 roberto Exp $
+** $Id: lparser.c,v 2.86 2010/05/15 13:32:02 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -74,9 +74,10 @@ static void error_expected (LexState *ls, int token) {
static void errorlimit (FuncState *fs, int limit, const char *what) {
const char *msg;
- const char *where = (fs->f->linedefined == 0) ?
- "main function" :
- luaO_pushfstring(fs->L, "function at line %d", fs->f->linedefined);
+ int line = fs->f->linedefined;
+ const char *where = (line == 0)
+ ? "main function"
+ : luaO_pushfstring(fs->L, "function at line %d", line);
msg = luaO_pushfstring(fs->L, "too many %s (limit is %d) in %s",
what, limit, where);
luaX_syntaxerror(fs->ls, msg);
@@ -207,27 +208,27 @@ static void removevars (FuncState *fs, int tolevel) {
}
-static int indexupvalue (FuncState *fs, TString *name, expdesc *v) {
+static int searchupvalue (FuncState *fs, TString *name) {
int i;
+ Upvaldesc *up = fs->f->upvalues;
+ for (i = 0; i < fs->nups; i++) {
+ if (eqstr(up[i].name, name)) return i;
+ }
+ return -1; /* not found */
+}
+
+
+static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
Proto *f = fs->f;
int oldsize = f->sizeupvalues;
- int instk = (v->k == VLOCAL);
- lua_assert(instk || v->k == VUPVAL);
- for (i=0; i<fs->nups; i++) {
- if (f->upvalues[i].instack == instk && f->upvalues[i].idx == v->u.s.info) {
- lua_assert(f->upvalues[i].name == name);
- return i;
- }
- }
- /* new one */
checklimit(fs, fs->nups + 1, UCHAR_MAX, "upvalues");
luaM_growvector(fs->L, f->upvalues, fs->nups, f->sizeupvalues,
Upvaldesc, UCHAR_MAX, "upvalues");
while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL;
+ f->upvalues[fs->nups].instack = (v->k == VLOCAL);
+ f->upvalues[fs->nups].idx = cast_byte(v->u.s.info);
f->upvalues[fs->nups].name = name;
luaC_objbarrier(fs->L, f, name);
- f->upvalues[fs->nups].instack = cast_byte(instk);
- f->upvalues[fs->nups].idx = cast_byte(v->u.s.info);
return fs->nups++;
}
@@ -235,13 +236,17 @@ static int indexupvalue (FuncState *fs, TString *name, expdesc *v) {
static int searchvar (FuncState *fs, TString *n) {
int i;
for (i=fs->nactvar-1; i >= 0; i--) {
- if (n == getlocvar(fs, i)->varname)
+ if (eqstr(n, getlocvar(fs, i)->varname))
return i;
}
return -1; /* not found */
}
+/*
+ Mark block where variable at given level was defined
+ (to emit OP_CLOSE later).
+*/
static void markupval (FuncState *fs, int level) {
BlockCnt *bl = fs->bl;
while (bl && bl->nactvar > level) bl = bl->previous;
@@ -249,22 +254,30 @@ static void markupval (FuncState *fs, int level) {
}
+/*
+ Find variable with given name 'n'. If it is an upvalue, add this
+ upvalue into all intermediate functions.
+*/
static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
if (fs == NULL) /* no more levels? */
- return VGLOBAL; /* default is global variable */
+ return VVOID; /* default is global */
else {
- int v = searchvar(fs, n); /* look up at current level */
- if (v >= 0) {
- init_exp(var, VLOCAL, v);
+ int v = searchvar(fs, n); /* look up locals at current level */
+ if (v >= 0) { /* found? */
+ init_exp(var, VLOCAL, v); /* variable is local */
if (!base)
markupval(fs, v); /* local will be used as an upval */
return VLOCAL;
}
- else { /* not found at current level; try upper one */
- if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL)
- return VGLOBAL;
- var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */
- var->k = VUPVAL; /* upvalue in this level */
+ else { /* not found as local at current level; try upvalues */
+ int idx = searchupvalue(fs, n); /* try existing upvalues */
+ if (idx < 0) { /* not found? */
+ if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */
+ return VVOID; /* not found; is a global */
+ /* else was LOCAL or UPVAL */
+ idx = newupvalue(fs, n, var); /* will be a new upvalue */
+ }
+ init_exp(var, VUPVAL, idx);
return VUPVAL;
}
}
@@ -274,15 +287,12 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
static void singlevar (LexState *ls, expdesc *var) {
TString *varname = str_checkname(ls);
FuncState *fs = ls->fs;
- if (singlevaraux(fs, varname, var, 1) == VGLOBAL) {
- if (fs->envreg == NO_REG) /* regular global? */
- init_exp(var, VGLOBAL, luaK_stringK(fs, varname));
- else { /* "globals" are in current lexical environment */
- expdesc key;
- init_exp(var, VLOCAL, fs->envreg); /* current environment */
- codestring(ls, &key, varname); /* key is variable name */
- luaK_indexed(fs, var, &key); /* env[varname] */
- }
+ if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */
+ expdesc key;
+ singlevaraux(fs, ls->envn, var, 1); /* get _ENV variable */
+ lua_assert(var->k == VLOCAL || var->k == VUPVAL);
+ codestring(ls, &key, varname); /* key is variable name */
+ luaK_indexed(fs, var, &key); /* env[varname] */
}
}
@@ -351,7 +361,6 @@ static void pushclosure (LexState *ls, Proto *clp, expdesc *v) {
while (oldsize < f->sizep) f->p[oldsize++] = NULL;
f->p[fs->np++] = clp;
/* initial environment for new function is current lexical environment */
- clp->envreg = fs->envreg;
luaC_objbarrier(ls->L, f, clp);
init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1));
}
@@ -374,7 +383,6 @@ static void open_func (LexState *ls, FuncState *fs) {
fs->nlocvars = 0;
fs->nactvar = 0;
fs->firstlocal = ls->varl->nactvar;
- fs->envreg = NO_REG;
fs->bl = NULL;
f = luaF_newproto(L);
fs->f = f;
@@ -418,26 +426,36 @@ static void close_func (LexState *ls) {
}
+/*
+** opens the main function, which is a regular vararg function with an
+** upvalue named '_ENV'
+*/
+static void open_mainfunc (LexState *ls, FuncState *fs) {
+ expdesc v;
+ open_func(ls, fs);
+ fs->f->is_vararg = 1; /* main function is always vararg */
+ init_exp(&v, VLOCAL, 0);
+ newupvalue(fs, ls->envn, &v); /* create '_ENV' upvalue */
+}
+
+
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Varlist *varl,
const char *name) {
- struct LexState lexstate;
- struct FuncState funcstate;
+ LexState lexstate;
+ FuncState funcstate;
TString *tname = luaS_new(L, name);
setsvalue2s(L, L->top, tname); /* push name to protect it */
incr_top(L);
lexstate.buff = buff;
lexstate.varl = varl;
luaX_setinput(L, &lexstate, z, tname);
- open_func(&lexstate, &funcstate);
- funcstate.f->is_vararg = 1; /* main function is always vararg */
+ open_mainfunc(&lexstate, &funcstate);
luaX_next(&lexstate); /* read first token */
- chunk(&lexstate);
+ chunk(&lexstate); /* read main chunk */
check(&lexstate, TK_EOS);
close_func(&lexstate);
L->top--; /* pop name */
- lua_assert(funcstate.prev == NULL);
- lua_assert(funcstate.nups == 0);
- lua_assert(lexstate.fs == NULL);
+ lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
return funcstate.f;
}
@@ -452,7 +470,7 @@ static void fieldsel (LexState *ls, expdesc *v) {
/* fieldsel -> ['.' | ':'] NAME */
FuncState *fs = ls->fs;
expdesc key;
- luaK_exp2anyreg(fs, v);
+ luaK_exp2anyregup(fs, v);
luaX_next(ls); /* skip the dot or colon */
checkname(ls, &key);
luaK_indexed(fs, v, &key);
@@ -653,15 +671,12 @@ static int explist1 (LexState *ls, expdesc *v) {
}
-static void funcargs (LexState *ls, expdesc *f) {
+static void funcargs (LexState *ls, expdesc *f, int line) {
FuncState *fs = ls->fs;
expdesc args;
int base, nparams;
- int line = ls->linenumber;
switch (ls->t.token) {
case '(': { /* funcargs -> `(' [ explist1 ] `)' */
- if (line != ls->lastline)
- luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)");
luaX_next(ls);
if (ls->t.token == ')') /* arg list is empty? */
args.k = VVOID;
@@ -738,6 +753,7 @@ static void primaryexp (LexState *ls, expdesc *v) {
/* primaryexp ->
prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */
FuncState *fs = ls->fs;
+ int line = ls->linenumber;
prefixexp(ls, v);
for (;;) {
switch (ls->t.token) {
@@ -747,7 +763,7 @@ static void primaryexp (LexState *ls, expdesc *v) {
}
case '[': { /* `[' exp1 `]' */
expdesc key;
- luaK_exp2anyreg(fs, v);
+ luaK_exp2anyregup(fs, v);
yindex(ls, &key);
luaK_indexed(fs, v, &key);
break;
@@ -757,12 +773,12 @@ static void primaryexp (LexState *ls, expdesc *v) {
luaX_next(ls);
checkname(ls, &key);
luaK_self(fs, v, &key);
- funcargs(ls, v);
+ funcargs(ls, v, line);
break;
}
case '(': case TK_STRING: case '{': { /* funcargs */
luaK_exp2nextreg(fs, v);
- funcargs(ls, v);
+ funcargs(ls, v, line);
break;
}
default: return;
@@ -877,9 +893,10 @@ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) {
enterlevel(ls);
uop = getunopr(ls->t.token);
if (uop != OPR_NOUNOPR) {
+ int line = ls->linenumber;
luaX_next(ls);
subexpr(ls, v, UNARY_PRIORITY);
- luaK_prefix(ls->fs, uop, v);
+ luaK_prefix(ls->fs, uop, v, line);
}
else simpleexp(ls, v);
/* expand while operators have priorities higher than `limit' */
@@ -887,11 +904,12 @@ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) {
while (op != OPR_NOBINOPR && priority[op].left > limit) {
expdesc v2;
BinOpr nextop;
+ int line = ls->linenumber;
luaX_next(ls);
luaK_infix(ls->fs, op, v);
/* read sub-expression with higher priority */
nextop = subexpr(ls, &v2, priority[op].right);
- luaK_posfix(ls->fs, op, v, &v2);
+ luaK_posfix(ls->fs, op, v, &v2, line);
op = nextop;
}
leavelevel(ls);
@@ -951,24 +969,27 @@ struct LHS_assign {
** local value in a safe place and use this safe copy in the previous
** assignment.
*/
-static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
+static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v,
+ expkind ix, OpCode op) {
FuncState *fs = ls->fs;
int extra = fs->freereg; /* eventual position to save local variable */
int conflict = 0;
for (; lh; lh = lh->prev) {
- if (lh->v.k == VINDEXED) {
+ if (lh->v.k == ix) {
if (lh->v.u.s.info == v->u.s.info) { /* conflict? */
conflict = 1;
+ lh->v.k = VINDEXED;
lh->v.u.s.info = extra; /* previous assignment will use safe copy */
}
- if (lh->v.u.s.aux == v->u.s.info) { /* conflict? */
+ if (v->k == VLOCAL && lh->v.u.s.aux == v->u.s.info) { /* conflict? */
conflict = 1;
+ lua_assert(lh->v.k == VINDEXED);
lh->v.u.s.aux = extra; /* previous assignment will use safe copy */
}
}
}
if (conflict) {
- luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0); /* make copy */
+ luaK_codeABC(fs, op, fs->freereg, v->u.s.info, 0); /* make copy */
luaK_reserveregs(fs, 1);
}
}
@@ -976,14 +997,16 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
expdesc e;
- check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED,
+ check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXEDUP,
"syntax error");
if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */
struct LHS_assign nv;
nv.prev = lh;
primaryexp(ls, &nv.v);
if (nv.v.k == VLOCAL)
- check_conflict(ls, lh, &nv.v);
+ check_conflict(ls, lh, &nv.v, VINDEXED, OP_MOVE);
+ else if (nv.v.k == VUPVAL)
+ check_conflict(ls, lh, &nv.v, VINDEXEDUP, OP_GETUPVAL);
checklimit(ls->fs, nvars, LUAI_MAXCCALLS - G(ls->L)->nCcalls,
"variable names");
assignment(ls, &nv, nvars+1);
@@ -1274,24 +1297,6 @@ static void funcstat (LexState *ls, int line) {
}
-static void instat (LexState *ls, int line) {
- /* instat -> IN exp DO block END */
- FuncState *fs = ls->fs;
- int oldenv = fs->envreg; /* save current environment */
- BlockCnt bl;
- luaX_next(ls); /* skip IN */
- enterblock(fs, &bl, 0); /* scope for environment variable */
- new_localvarliteral(ls, "(environment)");
- fs->envreg = exp1(ls); /* new environment */
- adjustlocalvars(ls, 1);
- checknext(ls, TK_DO);
- block(ls);
- leaveblock(fs);
- check_match(ls, TK_END, TK_IN, line);
- fs->envreg = oldenv; /* restore outer environment */
-}
-
-
static void exprstat (LexState *ls) {
/* stat -> func | assignment */
FuncState *fs = ls->fs;
@@ -1311,7 +1316,6 @@ static void retstat (LexState *ls) {
FuncState *fs = ls->fs;
expdesc e;
int first, nret; /* registers with returned values */
- luaX_next(ls); /* skip RETURN */
if (block_follow(ls->t.token) || ls->t.token == ';')
first = nret = 0; /* return no values */
else {
@@ -1342,6 +1346,10 @@ static void retstat (LexState *ls) {
static int statement (LexState *ls) {
int line = ls->linenumber; /* may be needed for error messages */
switch (ls->t.token) {
+ case ';': { /* stat -> ';' (empty statement) */
+ luaX_next(ls); /* skip ';' */
+ return 0;
+ }
case TK_IF: { /* stat -> ifstat */
ifstat(ls, line);
return 0;
@@ -1356,10 +1364,6 @@ static int statement (LexState *ls) {
check_match(ls, TK_END, TK_DO, line);
return 0;
}
- case TK_IN: {
- instat(ls, line);
- return 0;
- }
case TK_FOR: { /* stat -> forstat */
forstat(ls, line);
return 0;
@@ -1368,8 +1372,8 @@ static int statement (LexState *ls) {
repeatstat(ls, line);
return 0;
}
- case TK_FUNCTION: {
- funcstat(ls, line); /* stat -> funcstat */
+ case TK_FUNCTION: { /* stat -> funcstat */
+ funcstat(ls, line);
return 0;
}
case TK_LOCAL: { /* stat -> localstat */
@@ -1381,6 +1385,7 @@ static int statement (LexState *ls) {
return 0;
}
case TK_RETURN: { /* stat -> retstat */
+ luaX_next(ls); /* skip RETURN */
retstat(ls);
return 1; /* must be last statement */
}
@@ -1389,9 +1394,9 @@ static int statement (LexState *ls) {
breakstat(ls);
return 1; /* must be last statement */
}
- default: {
+ default: { /* stat -> func | assignment */
exprstat(ls);
- return 0; /* to avoid warnings */
+ return 0;
}
}
}
@@ -1403,7 +1408,8 @@ static void chunk (LexState *ls) {
enterlevel(ls);
while (!islast && !block_follow(ls->t.token)) {
islast = statement(ls);
- testnext(ls, ';');
+ if (islast)
+ testnext(ls, ';');
lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
ls->fs->freereg >= ls->fs->nactvar);
ls->fs->freereg = ls->fs->nactvar; /* free registers */
diff --git a/src/lparser.h b/src/lparser.h
index 2ad0a509..9e406a7b 100644
--- a/src/lparser.h
+++ b/src/lparser.h
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.h,v 1.61 2009/10/11 20:02:19 roberto Exp $
+** $Id: lparser.h,v 1.63 2010/03/12 19:14:06 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -23,10 +23,10 @@ typedef enum {
VFALSE,
VK, /* info = index of constant in `k' */
VKNUM, /* nval = numerical value */
- VLOCAL, /* info = local register; aux = read only */
- VUPVAL, /* info = index of upvalue in 'upvalues'; aux = read only */
- VGLOBAL, /* info = index of table; aux = index of global name in `k' */
- VINDEXED, /* info = table register; aux = index register (or `k') */
+ VLOCAL, /* info = local register */
+ VUPVAL, /* info = index of upvalue in 'upvalues' */
+ VINDEXED, /* info = table R/K; aux = index R/K */
+ VINDEXEDUP, /* info = table upvalue; aux = R/K */
VJMP, /* info = instruction pc */
VRELOCABLE, /* info = instruction pc */
VNONRELOC, /* info = result register */
@@ -80,7 +80,6 @@ typedef struct FuncState {
short nlocvars; /* number of elements in `locvars' */
lu_byte nactvar; /* number of active local variables */
lu_byte nups; /* number of upvalues */
- lu_byte envreg; /* register holding current lexical environment */
} FuncState;
diff --git a/src/lstate.c b/src/lstate.c
index 426fdec6..6ea00b62 100644
--- a/src/lstate.c
+++ b/src/lstate.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.c,v 2.68 2009/12/22 15:32:50 roberto Exp $
+** $Id: lstate.c,v 2.85 2010/04/30 18:36:22 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -26,7 +26,7 @@
#if !defined(LUAI_GCPAUSE)
-#define LUAI_GCPAUSE 162 /* 162% (wait memory to double before next GC) */
+#define LUAI_GCPAUSE 200 /* 200% */
#endif
#if !defined(LUAI_GCMUL)
@@ -34,6 +34,9 @@
#endif
+#define MEMERRMSG "not enough memory"
+
+
/*
** thread state + extra space
*/
@@ -87,7 +90,7 @@ void luaE_freeCI (lua_State *L) {
static void stack_init (lua_State *L1, lua_State *L) {
- int i;
+ int i; CallInfo *ci;
/* initialize stack array */
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue);
L1->stacksize = BASIC_STACK_SIZE;
@@ -96,32 +99,22 @@ static void stack_init (lua_State *L1, lua_State *L) {
L1->top = L1->stack;
L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK;
/* initialize first ci */
- L1->ci->func = L1->top;
+ ci = &L1->base_ci;
+ ci->next = ci->previous = NULL;
+ ci->callstatus = 0;
+ ci->func = L1->top;
setnilvalue(L1->top++); /* 'function' entry for this 'ci' */
- L1->ci->top = L1->top + LUA_MINSTACK;
- L1->ci->callstatus = 0;
+ ci->top = L1->top + LUA_MINSTACK;
+ L1->ci = ci;
}
static void freestack (lua_State *L) {
- L->ci = &L->base_ci; /* reset 'ci' list */
+ if (L->stack == NULL)
+ return; /* stack not completely built yet */
+ L->ci = &L->base_ci; /* free the entire 'ci' list */
luaE_freeCI(L);
- luaM_freearray(L, L->stack, L->stacksize);
-}
-
-
-/*
-** Calls the function in variable pointed to by userdata in first argument
-** (Userdata cannot point directly to the function because pointer to
-** function is not compatible with void*.)
-*/
-static int cpcall (lua_State *L) {
- lua_CFunction f = *(lua_CFunction *)lua_touserdata(L, 1);
- lua_remove(L, 1); /* remove f from stack */
- /* restore original environment for 'cpcall' */
- lua_pushglobaltable(L);
- lua_replace(L, LUA_ENVIRONINDEX);
- return f(L);
+ luaM_freearray(L, L->stack, L->stacksize); /* free stack array */
}
@@ -129,7 +122,6 @@ static int cpcall (lua_State *L) {
** Create registry table and its predefined values
*/
static void init_registry (lua_State *L, global_State *g) {
- Closure *cp;
TValue mt;
/* create registry */
Table *registry = luaH_new(L);
@@ -138,13 +130,8 @@ static void init_registry (lua_State *L, global_State *g) {
/* registry[LUA_RIDX_MAINTHREAD] = L */
setthvalue(L, &mt, L);
setobj2t(L, luaH_setint(L, registry, LUA_RIDX_MAINTHREAD), &mt);
- /* registry[LUA_RIDX_CPCALL] = cpcall */
- cp = luaF_newCclosure(L, 0, g->l_gt);
- cp->c.f = cpcall;
- setclvalue(L, &mt, cp);
- setobj2t(L, luaH_setint(L, registry, LUA_RIDX_CPCALL), &mt);
- /* registry[LUA_RIDX_GLOBALS] = l_gt */
- sethvalue(L, &mt, g->l_gt);
+ /* registry[LUA_RIDX_GLOBALS] = table of globals */
+ sethvalue(L, &mt, luaH_new(L));
setobj2t(L, luaH_setint(L, registry, LUA_RIDX_GLOBALS), &mt);
}
@@ -156,13 +143,14 @@ static void f_luaopen (lua_State *L, void *ud) {
global_State *g = G(L);
UNUSED(ud);
stack_init(L, L); /* init stack */
- g->l_gt = luaH_new(L); /* table of globals */
init_registry(L, g);
luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
luaT_init(L);
luaX_init(L);
- luaS_fix(luaS_newliteral(L, MEMERRMSG));
- g->GCthreshold = 4*g->totalbytes;
+ /* pre-create memory-error message */
+ g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
+ luaS_fix(g->memerrmsg); /* it should never be collected */
+ g->GCdebt = 0;
}
@@ -173,6 +161,7 @@ static void f_luaopen (lua_State *L, void *ud) {
static void preinit_state (lua_State *L, global_State *g) {
G(L) = g;
L->stack = NULL;
+ L->ci = NULL;
L->stacksize = 0;
L->errorJmp = NULL;
L->hook = NULL;
@@ -183,8 +172,6 @@ static void preinit_state (lua_State *L, global_State *g) {
L->openupval = NULL;
L->nny = 1;
L->status = LUA_OK;
- L->base_ci.next = L->base_ci.previous = NULL;
- L->ci = &L->base_ci;
L->errfunc = 0;
}
@@ -209,14 +196,13 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
setthvalue(L, L->top, L1);
api_incr_top(L);
preinit_state(L1, G(L));
- stack_init(L1, L); /* init stack */
L1->hookmask = L->hookmask;
L1->basehookcount = L->basehookcount;
L1->hook = L->hook;
resethookcount(L1);
- lua_assert(iswhite(obj2gco(L1)));
- lua_unlock(L);
luai_userstatethread(L, L1);
+ stack_init(L1, L); /* init stack */
+ lua_unlock(L);
return L1;
}
@@ -225,7 +211,7 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
LX *l = fromstate(L1);
luaF_close(L1, L1->stack); /* close all upvalues for this thread */
lua_assert(L1->openupval == NULL);
- luai_userstatefree(L1);
+ luai_userstatefree(L, L1);
freestack(L1);
luaM_free(L, l);
}
@@ -235,7 +221,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
int i;
lua_State *L;
global_State *g;
- LG *l = cast(LG *, (*f)(ud, NULL, 0, sizeof(LG)));
+ LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG)));
if (l == NULL) return NULL;
L = &l->l.l;
g = &l->g;
@@ -245,29 +231,31 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
L->marked = luaC_white(g);
g->gckind = KGC_NORMAL;
g->nCcalls = 0;
- set2bits(L->marked, FIXEDBIT, SFIXEDBIT);
preinit_state(L, g);
g->frealloc = f;
g->ud = ud;
g->mainthread = L;
g->uvhead.u.l.prev = &g->uvhead;
g->uvhead.u.l.next = &g->uvhead;
- g->GCthreshold = MAX_LUMEM; /* no GC while building state */
+ stopgc(g); /* no GC while building state */
+ g->lastmajormem = 0;
g->strt.size = 0;
g->strt.nuse = 0;
g->strt.hash = NULL;
setnilvalue(&g->l_registry);
- g->l_gt = NULL;
luaZ_initbuffer(L, &g->buff);
g->panic = NULL;
g->version = lua_version(NULL);
g->gcstate = GCSpause;
- g->rootgc = obj2gco(L);
+ g->allgc = NULL;
+ g->udgc = NULL;
g->tobefnz = NULL;
+ g->gray = g->grayagain = NULL;
+ g->weak = g->ephemeron = g->allweak = NULL;
g->totalbytes = sizeof(LG);
g->gcpause = LUAI_GCPAUSE;
g->gcstepmul = LUAI_GCMUL;
- for (i=0; i<NUM_TAGS; i++) g->mt[i] = NULL;
+ for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL;
if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {
/* memory allocation error: free partial state */
close_state(L);
diff --git a/src/lstate.h b/src/lstate.h
index 4ca3e02f..e829ed4a 100644
--- a/src/lstate.h
+++ b/src/lstate.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.h,v 2.52 2009/12/22 15:32:50 roberto Exp $
+** $Id: lstate.h,v 2.65 2010/05/03 17:39:48 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -19,7 +19,7 @@
** Some notes about garbage-collected objects: All objects in Lua must
** be kept somehow accessible until being freed.
**
-** Lua keeps most objects linked in list g->rootgc. The link uses field
+** Lua keeps most objects linked in list g->allgc. The link uses field
** 'next' of the CommonHeader.
**
** Strings are kept in several lists headed by the array g->strt.hash.
@@ -32,9 +32,7 @@
** when traversing the respective threads, but the thread may already be
** dead, while the upvalue is still accessible through closures.)
**
-** Userdata with finalizers are kept in the list g->rootgc, but after
-** the mainthread, which should be otherwise the last element in the
-** list, as it was the first one inserted there.
+** Userdata with finalizers are kept in the list g->udgc.
**
** The list g->tobefnz links all userdata being finalized.
@@ -56,8 +54,8 @@ struct lua_longjmp; /* defined in ldo.c */
/* kinds of Garbage Collection */
#define KGC_NORMAL 0
-#define KGC_FORCED 1 /* gc was forced by the program */
-#define KGC_EMERGENCY 2 /* gc was forced by an allocation failure */
+#define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */
+#define KGC_GEN 2 /* generational collection */
typedef struct stringtable {
@@ -85,7 +83,7 @@ typedef struct CallInfo {
int ctx; /* context info. in case of yields */
lua_CFunction k; /* continuation in case of yields */
ptrdiff_t old_errfunc;
- ptrdiff_t oldtop;
+ ptrdiff_t extra;
lu_byte old_allowhook;
lu_byte status;
} c;
@@ -106,7 +104,6 @@ typedef struct CallInfo {
#define CIST_TAIL (1<<6) /* call was tail called */
-#define curr_func(L) (clvalue(L->ci->func))
#define ci_func(ci) (clvalue((ci)->func))
#define isLua(ci) ((ci)->callstatus & CIST_LUA)
@@ -115,15 +112,20 @@ typedef struct CallInfo {
** `global state', shared by all threads of this state
*/
typedef struct global_State {
- stringtable strt; /* hash table for strings */
lua_Alloc frealloc; /* function to reallocate memory */
void *ud; /* auxiliary data to `frealloc' */
+ lu_mem totalbytes; /* number of bytes currently allocated */
+ l_mem GCdebt; /* when positive, run a GC step */
+ lu_mem lastmajormem; /* memory in use after last major collection */
+ stringtable strt; /* hash table for strings */
+ TValue l_registry;
unsigned short nCcalls; /* number of nested C calls */
lu_byte currentwhite;
lu_byte gcstate; /* state of garbage collector */
lu_byte gckind; /* kind of GC running */
int sweepstrgc; /* position of sweep in `strt' */
- GCObject *rootgc; /* list of all collectable objects */
+ GCObject *allgc; /* list of all collectable objects */
+ GCObject *udgc; /* list of collectable userdata with finalizers */
GCObject **sweepgc; /* current position of sweep */
GCObject *gray; /* list of gray objects */
GCObject *grayagain; /* list of objects to be traversed atomically */
@@ -131,19 +133,16 @@ typedef struct global_State {
GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
GCObject *allweak; /* list of all-weak tables */
GCObject *tobefnz; /* list of userdata to be GC */
+ UpVal uvhead; /* head of double-linked list of all open upvalues */
Mbuffer buff; /* temporary buffer for string concatenation */
- lu_mem GCthreshold; /* when totalbytes > GCthreshold, run GC step */
- lu_mem totalbytes; /* number of bytes currently allocated */
int gcpause; /* size of pause between successive GCs */
int gcstepmul; /* GC `granularity' */
lua_CFunction panic; /* to be called in unprotected errors */
- TValue l_registry;
- struct Table *l_gt; /* table of globals */
struct lua_State *mainthread;
- UpVal uvhead; /* head of double-linked list of all open upvalues */
const lua_Number *version; /* pointer to version number */
- struct Table *mt[NUM_TAGS]; /* metatables for basic types */
+ TString *memerrmsg; /* memory-error message */
TString *tmname[TM_N]; /* array with tag-method names */
+ struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
} global_State;
@@ -166,7 +165,6 @@ struct lua_State {
int basehookcount;
int hookcount;
lua_Hook hook;
- TValue env; /* temporary place for environments */
GCObject *openupval; /* list of open upvalues in this stack */
GCObject *gclist;
struct lua_longjmp *errorJmp; /* current error recover point */
diff --git a/src/lstring.c b/src/lstring.c
index 69b96d02..145621b6 100644
--- a/src/lstring.c
+++ b/src/lstring.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstring.c,v 2.16 2009/12/16 16:42:58 roberto Exp $
+** $Id: lstring.c,v 2.18 2010/05/10 18:23:45 roberto Exp $
** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -37,6 +37,7 @@ void luaS_resize (lua_State *L, int newsize) {
unsigned int h = lmod(gco2ts(p)->hash, newsize); /* new position */
gch(p)->next = tb->hash[h]; /* chain it */
tb->hash[h] = p;
+ resetoldbit(p); /* see MOVE OLD rule */
p = next;
}
}
@@ -94,6 +95,11 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
}
+TString *luaS_new (lua_State *L, const char *str) {
+ return luaS_newlstr(L, str, strlen(str));
+}
+
+
Udata *luaS_newudata (lua_State *L, size_t s, Table *e) {
Udata *u;
if (s > MAX_SIZET - sizeof(Udata))
diff --git a/src/lstring.h b/src/lstring.h
index 1d2e91ea..d708a1b0 100644
--- a/src/lstring.h
+++ b/src/lstring.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstring.h,v 1.43 2005/04/25 19:24:10 roberto Exp $
+** $Id: lstring.h,v 1.46 2010/04/05 16:26:37 roberto Exp $
** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -7,7 +7,6 @@
#ifndef lstring_h
#define lstring_h
-
#include "lgc.h"
#include "lobject.h"
#include "lstate.h"
@@ -17,15 +16,22 @@
#define sizeudata(u) (sizeof(union Udata)+(u)->len)
-#define luaS_new(L, s) (luaS_newlstr(L, s, strlen(s)))
#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \
(sizeof(s)/sizeof(char))-1))
#define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT)
+
+/*
+** as all string are internalized, string equality becomes
+** pointer equality
+*/
+#define eqstr(a,b) ((a) == (b))
+
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e);
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
+LUAI_FUNC TString *luaS_new (lua_State *L, const char *str);
#endif
diff --git a/src/lstrlib.c b/src/lstrlib.c
index 0c03b493..a5c3a204 100644
--- a/src/lstrlib.c
+++ b/src/lstrlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstrlib.c,v 1.148 2010/01/04 16:37:19 roberto Exp $
+** $Id: lstrlib.c,v 1.152 2010/05/04 17:20:33 roberto Exp $
** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
@@ -65,12 +65,13 @@ static int str_sub (lua_State *L) {
static int str_reverse (lua_State *L) {
- size_t l;
+ size_t l, i;
luaL_Buffer b;
const char *s = luaL_checklstring(L, 1, &l);
- luaL_buffinit(L, &b);
- while (l--) luaL_addchar(&b, s[l]);
- luaL_pushresult(&b);
+ char *p = luaL_buffinitsize(L, &b, l);
+ for (i = 0; i < l; i++)
+ p[i] = s[l - i - 1];
+ luaL_pushresultsize(&b, l);
return 1;
}
@@ -80,10 +81,10 @@ static int str_lower (lua_State *L) {
size_t i;
luaL_Buffer b;
const char *s = luaL_checklstring(L, 1, &l);
- luaL_buffinit(L, &b);
+ char *p = luaL_buffinitsize(L, &b, l);
for (i=0; i<l; i++)
- luaL_addchar(&b, tolower(uchar(s[i])));
- luaL_pushresult(&b);
+ p[i] = tolower(uchar(s[i]));
+ luaL_pushresultsize(&b, l);
return 1;
}
@@ -93,10 +94,10 @@ static int str_upper (lua_State *L) {
size_t i;
luaL_Buffer b;
const char *s = luaL_checklstring(L, 1, &l);
- luaL_buffinit(L, &b);
+ char *p = luaL_buffinitsize(L, &b, l);
for (i=0; i<l; i++)
- luaL_addchar(&b, toupper(uchar(s[i])));
- luaL_pushresult(&b);
+ p[i] = toupper(uchar(s[i]));
+ luaL_pushresultsize(&b, l);
return 1;
}
@@ -136,13 +137,13 @@ static int str_char (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
int i;
luaL_Buffer b;
- luaL_buffinit(L, &b);
+ char *p = luaL_buffinitsize(L, &b, n);
for (i=1; i<=n; i++) {
int c = luaL_checkint(L, i);
luaL_argcheck(L, uchar(c) == c, i, "invalid value");
- luaL_addchar(&b, uchar(c));
+ p[i - 1] = uchar(c);
}
- luaL_pushresult(&b);
+ luaL_pushresultsize(&b, n);
return 1;
}
@@ -179,7 +180,8 @@ static int str_dump (lua_State *L) {
typedef struct MatchState {
const char *src_init; /* init of source string */
- const char *src_end; /* end (`\0') of source string */
+ const char *src_end; /* end ('\0') of source string */
+ const char *p_end; /* end ('\0') of pattern */
lua_State *L;
int level; /* total number of captures (finished or unfinished) */
struct {
@@ -212,16 +214,16 @@ static int capture_to_close (MatchState *ms) {
static const char *classend (MatchState *ms, const char *p) {
switch (*p++) {
case L_ESC: {
- if (*p == '\0')
+ if (p == ms->p_end)
luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")");
return p+1;
}
case '[': {
if (*p == '^') p++;
do { /* look for a `]' */
- if (*p == '\0')
+ if (p == ms->p_end)
luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")");
- if (*(p++) == L_ESC && *p != '\0')
+ if (*(p++) == L_ESC && p < ms->p_end)
p++; /* skip escapes (e.g. `%]') */
} while (*p != ']');
return p+1;
@@ -245,7 +247,7 @@ static int match_class (int c, int cl) {
case 'u' : res = isupper(c); break;
case 'w' : res = isalnum(c); break;
case 'x' : res = isxdigit(c); break;
- case 'z' : res = (c == 0); break;
+ case 'z' : res = (c == 0); break; /* deprecated option */
default: return (cl == c);
}
return (islower(cl) ? res : !res);
@@ -290,8 +292,9 @@ static const char *match (MatchState *ms, const char *s, const char *p);
static const char *matchbalance (MatchState *ms, const char *s,
const char *p) {
- if (*p == 0 || *(p+1) == 0)
- luaL_error(ms->L, "unbalanced pattern");
+ if (p >= ms->p_end - 1)
+ luaL_error(ms->L, "malformed pattern "
+ "(missing arguments to " LUA_QL("%%b") ")");
if (*s != *p) return NULL;
else {
int b = *p;
@@ -374,6 +377,8 @@ static const char *match_capture (MatchState *ms, const char *s, int l) {
static const char *match (MatchState *ms, const char *s, const char *p) {
init: /* using goto's to optimize tail recursion */
+ if (p == ms->p_end) /* end of pattern? */
+ return s; /* match succeeded */
switch (*p) {
case '(': { /* start capture */
if (*(p+1) == ')') /* position capture? */
@@ -384,11 +389,8 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
case ')': { /* end capture */
return end_capture(ms, s, p+1);
}
- case '\0': { /* end of pattern */
- return s; /* match succeeded */
- }
case '$': {
- if (*(p+1) == '\0') /* is the `$' the last char in pattern? */
+ if ((p+1) == ms->p_end) /* is the `$' the last char in pattern? */
return (s == ms->src_end) ? s : NULL; /* check end of string */
else goto dflt;
}
@@ -418,12 +420,12 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
if (s == NULL) return NULL;
p+=2; goto init; /* else return match(ms, s, p+2) */
}
- default: break; /* go through to 'dflt' */
+ default: goto dflt;
}
}
default: dflt: { /* pattern class plus optional sufix */
const char *ep = classend(ms, p); /* points to what is next */
- int m = s<ms->src_end && singlematch(uchar(*s), p, ep);
+ int m = s < ms->src_end && singlematch(uchar(*s), p, ep);
switch (*ep) {
case '?': { /* optional */
const char *res;
@@ -503,32 +505,36 @@ static int push_captures (MatchState *ms, const char *s, const char *e) {
static int str_find_aux (lua_State *L, int find) {
- size_t l1, l2;
- const char *s = luaL_checklstring(L, 1, &l1);
- const char *p = luaL_checklstring(L, 2, &l2);
- size_t init = posrelat(luaL_optinteger(L, 3, 1), l1);
+ size_t ls, lp;
+ const char *s = luaL_checklstring(L, 1, &ls);
+ const char *p = luaL_checklstring(L, 2, &lp);
+ size_t init = posrelat(luaL_optinteger(L, 3, 1), ls);
if (init < 1) init = 1;
- else if (init > l1 + 1) { /* start after string's end? */
+ else if (init > ls + 1) { /* start after string's end? */
lua_pushnil(L); /* cannot find anything */
return 1;
}
if (find && (lua_toboolean(L, 4) || /* explicit request? */
strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */
/* do a plain search */
- const char *s2 = lmemfind(s + init - 1, l1 - init + 1, p, l2);
+ const char *s2 = lmemfind(s + init - 1, ls - init + 1, p, lp);
if (s2) {
lua_pushinteger(L, s2 - s + 1);
- lua_pushinteger(L, s2 - s + l2);
+ lua_pushinteger(L, s2 - s + lp);
return 2;
}
}
else {
MatchState ms;
- int anchor = (*p == '^') ? (p++, 1) : 0;
const char *s1 = s + init - 1;
+ int anchor = (*p == '^');
+ if (anchor) {
+ p++; lp--; /* skip anchor character */
+ }
ms.L = L;
ms.src_init = s;
- ms.src_end = s + l1;
+ ms.src_end = s + ls;
+ ms.p_end = p + lp;
do {
const char *res;
ms.level = 0;
@@ -560,13 +566,14 @@ static int str_match (lua_State *L) {
static int gmatch_aux (lua_State *L) {
MatchState ms;
- size_t ls;
+ size_t ls, lp;
const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
- const char *p = lua_tostring(L, lua_upvalueindex(2));
+ const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp);
const char *src;
ms.L = L;
ms.src_init = s;
ms.src_end = s+ls;
+ ms.p_end = p + lp;
for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3));
src <= ms.src_end;
src++) {
@@ -658,12 +665,12 @@ static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
static int str_gsub (lua_State *L) {
- size_t srcl;
+ size_t srcl, lp;
const char *src = luaL_checklstring(L, 1, &srcl);
- const char *p = luaL_checkstring(L, 2);
+ const char *p = luaL_checklstring(L, 2, &lp);
int tr = lua_type(L, 3);
size_t max_s = luaL_optinteger(L, 4, srcl+1);
- int anchor = (*p == '^') ? (p++, 1) : 0;
+ int anchor = (*p == '^');
size_t n = 0;
MatchState ms;
luaL_Buffer b;
@@ -671,9 +678,13 @@ static int str_gsub (lua_State *L) {
tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
"string/function/table expected");
luaL_buffinit(L, &b);
+ if (anchor) {
+ p++; lp--; /* skip anchor character */
+ }
ms.L = L;
ms.src_init = src;
ms.src_end = src+srcl;
+ ms.p_end = p + lp;
while (n < max_s) {
const char *e;
ms.level = 0;
@@ -698,11 +709,18 @@ static int str_gsub (lua_State *L) {
/* }====================================================== */
+
/*
-** length modifier for integer conversions ** in 'string.format' and
-** integer type corresponding to the previous length
+** {======================================================
+** STRING FORMAT
+** =======================================================
*/
+/*
+** LUA_INTFRMLEN is the length modifier for integer conversions in
+** 'string.format'; LUA_INTFRM_T is the integer type corresponding to
+** the previous length
+*/
#if defined(LUA_USELONGLONG)
#define LUA_INTFRMLEN "ll"
@@ -738,7 +756,7 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
}
else if (*s == '\0' || iscntrl(uchar(*s))) {
char buff[10];
- if (*s != '\0' && !isdigit(uchar(*(s+1))))
+ if (!isdigit(uchar(*(s+1))))
sprintf(buff, "\\%d", uchar(*s));
else
sprintf(buff, "\\%03d", uchar(*s));
@@ -773,6 +791,9 @@ static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
}
+/*
+** add length modifier into integer formats
+*/
static void addintlen (char *form) {
size_t l = strlen(form);
char spec = form[l - 1];
@@ -783,6 +804,7 @@ static void addintlen (char *form) {
static int str_format (lua_State *L) {
+ int top = lua_gettop(L);
int arg = 1;
size_t sfl;
const char *strfrmt = luaL_checklstring(L, arg, &sfl);
@@ -796,12 +818,14 @@ static int str_format (lua_State *L) {
luaL_addchar(&b, *strfrmt++); /* %% */
else { /* format item */
char form[MAX_FORMAT]; /* to store the format (`%...') */
- char buff[MAX_ITEM]; /* to store the formatted item */
- arg++;
+ char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */
+ int nb = 0; /* number of bytes in added item */
+ if (++arg > top)
+ luaL_argerror(L, arg, "no value");
strfrmt = scanformat(L, strfrmt, form);
switch (*strfrmt++) {
case 'c': {
- sprintf(buff, form, luaL_checkint(L, arg));
+ nb = sprintf(buff, form, luaL_checkint(L, arg));
break;
}
case 'd': case 'i':
@@ -810,17 +834,17 @@ static int str_format (lua_State *L) {
LUA_INTFRM_T r = (n < 0) ? (LUA_INTFRM_T)n :
(LUA_INTFRM_T)(unsigned LUA_INTFRM_T)n;
addintlen(form);
- sprintf(buff, form, r);
+ nb = sprintf(buff, form, r);
break;
}
case 'e': case 'E': case 'f':
case 'g': case 'G': {
- sprintf(buff, form, (double)luaL_checknumber(L, arg));
+ nb = sprintf(buff, form, (double)luaL_checknumber(L, arg));
break;
}
case 'q': {
addquoted(L, &b, arg);
- continue; /* skip the 'addsize' at the end */
+ break;
}
case 's': {
size_t l;
@@ -830,10 +854,10 @@ static int str_format (lua_State *L) {
keep original string */
lua_pushvalue(L, arg);
luaL_addvalue(&b);
- continue; /* skip the `addsize' at the end */
+ break;
}
else {
- sprintf(buff, form, s);
+ nb = sprintf(buff, form, s);
break;
}
}
@@ -842,13 +866,15 @@ static int str_format (lua_State *L) {
LUA_QL("format"), *(strfrmt - 1));
}
}
- luaL_addlstring(&b, buff, strlen(buff));
+ luaL_addsize(&b, nb);
}
}
luaL_pushresult(&b);
return 1;
}
+/* }====================================================== */
+
static const luaL_Reg strlib[] = {
{"byte", str_byte},
diff --git a/src/ltable.c b/src/ltable.c
index 78ff1d74..dc6604dd 100644
--- a/src/ltable.c
+++ b/src/ltable.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltable.c,v 2.47 2009/12/17 15:46:44 roberto Exp $
+** $Id: ltable.c,v 2.50 2010/04/18 13:22:48 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -31,6 +31,7 @@
#include "lmem.h"
#include "lobject.h"
#include "lstate.h"
+#include "lstring.h"
#include "ltable.h"
@@ -108,6 +109,8 @@ static Node *mainposition (const Table *t, const TValue *key) {
return hashboolean(t, bvalue(key));
case LUA_TLIGHTUSERDATA:
return hashpointer(t, pvalue(key));
+ case LUA_TLCF:
+ return hashpointer(t, fvalue(key));
default:
return hashpointer(t, gcvalue(key));
}
@@ -452,7 +455,7 @@ const TValue *luaH_getint (Table *t, int key) {
const TValue *luaH_getstr (Table *t, TString *key) {
Node *n = hashstr(t, key);
do { /* check whether `key' is somewhere in the chain */
- if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key)
+ if (ttisstring(gkey(n)) && eqstr(rawtsvalue(gkey(n)), key))
return gval(n); /* that's it */
else n = gnext(n);
} while (n);
diff --git a/src/ltablib.c b/src/ltablib.c
index 6ad6b8e0..2e00da29 100644
--- a/src/ltablib.c
+++ b/src/ltablib.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltablib.c,v 1.54 2010/01/13 19:59:10 roberto Exp $
+** $Id: ltablib.c,v 1.55 2010/03/13 03:57:46 roberto Exp $
** Library for Table Manipulation
** See Copyright Notice in lua.h
*/
@@ -171,15 +171,15 @@ static int tconcat (lua_State *L) {
static int pack (lua_State *L) {
int top = lua_gettop(L);
lua_createtable(L, top, 1); /* create result table */
- /* use function environment as a temporary place to keep new table */
- lua_replace(L, LUA_ENVIRONINDEX);
lua_pushinteger(L, top); /* number of elements */
- lua_setfield(L, LUA_ENVIRONINDEX, "n"); /* t.n = number of elements */
- for (; top >= 1; top--) /* assign elements */
- lua_rawseti(L, LUA_ENVIRONINDEX, top);
- lua_pushvalue(L, LUA_ENVIRONINDEX); /* return new table */
- /* remove new table from environment to allow its later collection */
- lua_copy(L, LUA_REGISTRYINDEX, LUA_ENVIRONINDEX);
+ lua_setfield(L, -2, "n"); /* t.n = number of elements */
+ if (top > 0) { /* at least one element? */
+ lua_pushvalue(L, 1);
+ lua_rawseti(L, -2, 1); /* insert first element */
+ lua_replace(L, 1); /* move table into its position (index 1) */
+ for (; top >= 2; top--) /* assign other elements */
+ lua_rawseti(L, 1, top);
+ }
return 1;
}
@@ -328,7 +328,7 @@ LUAMOD_API int luaopen_table (lua_State *L) {
#if defined(LUA_COMPAT_UNPACK)
/* _G.unpack = table.unpack */
lua_getfield(L, -1, "unpack");
- lua_setfield(L, LUA_ENVIRONINDEX, "unpack");
+ lua_setglobal(L, "unpack");
#endif
return 1;
}
diff --git a/src/ltm.c b/src/ltm.c
index 3a9e73ca..faa8f57d 100644
--- a/src/ltm.c
+++ b/src/ltm.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.c,v 2.11 2010/01/13 16:18:25 roberto Exp $
+** $Id: ltm.c,v 2.12 2010/04/13 20:48:12 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -70,7 +70,7 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
mt = uvalue(o)->metatable;
break;
default:
- mt = G(L)->mt[ttype(o)];
+ mt = G(L)->mt[ttypenv(o)];
}
return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject);
}
diff --git a/src/ltm.h b/src/ltm.h
index 732aa12d..05abc40b 100644
--- a/src/ltm.h
+++ b/src/ltm.h
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.h,v 2.9 2010/01/13 16:18:25 roberto Exp $
+** $Id: ltm.h,v 2.10 2010/04/13 20:48:12 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -43,7 +43,8 @@ typedef enum {
#define fasttm(l,et,e) gfasttm(G(l), et, e)
-#define typename(x) luaT_typenames_[(x) + 1]
+#define ttypename(x) luaT_typenames_[(x) + 1]
+#define objtypename(x) ttypename(ttypenv(x))
LUAI_DDEC const char *const luaT_typenames_[];
diff --git a/src/lua.c b/src/lua.c
index 757adb6c..2b1c6161 100644
--- a/src/lua.c
+++ b/src/lua.c
@@ -1,5 +1,5 @@
/*
-** $Id: lua.c,v 1.182 2009/12/22 16:47:12 roberto Exp $
+** $Id: lua.c,v 1.190 2010/04/14 15:14:21 roberto Exp $
** Lua stand-alone interpreter
** See Copyright Notice in lua.h
*/
@@ -102,26 +102,31 @@ static void laction (int i) {
}
-static void print_usage (void) {
- fprintf(stderr,
+static void print_usage (const char *badoption) {
+ if (badoption[1] == 'e' || badoption[1] == 'l') {
+ luai_writestringerror("%s: ", progname);
+ luai_writestringerror("'%s' needs argument\n", badoption);
+ } else {
+ luai_writestringerror("%s: ", progname);
+ luai_writestringerror("unrecognized option '%s'\n", badoption);
+ }
+ luai_writestringerror(
"usage: %s [options] [script [args]]\n"
"Available options are:\n"
" -e stat execute string " LUA_QL("stat") "\n"
- " -l name require library " LUA_QL("name") "\n"
" -i enter interactive mode after executing " LUA_QL("script") "\n"
+ " -l name require library " LUA_QL("name") "\n"
" -v show version information\n"
" -- stop handling options\n"
- " - execute stdin and stop handling options\n"
+ " - stop handling options and execute stdin\n"
,
progname);
- fflush(stderr);
}
static void l_message (const char *pname, const char *msg) {
- if (pname) fprintf(stderr, "%s: ", pname);
- fprintf(stderr, "%s\n", msg);
- fflush(stderr);
+ if (pname) luai_writestringerror("%s: ", pname);
+ luai_writestringerror("%s\n", msg);
}
@@ -214,7 +219,7 @@ static int dostring (lua_State *L, const char *s, const char *name) {
static int dolibrary (lua_State *L, const char *name) {
- lua_getfield(L, LUA_ENVIRONINDEX, "require");
+ lua_getglobal(L, "require");
lua_pushstring(L, name);
return report(L, docall(L, 1, 1));
}
@@ -222,7 +227,7 @@ static int dolibrary (lua_State *L, const char *name) {
static const char *get_prompt (lua_State *L, int firstline) {
const char *p;
- lua_getfield(L, LUA_ENVIRONINDEX, firstline ? "_PROMPT" : "_PROMPT2");
+ lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2");
p = lua_tostring(L, -1);
if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
lua_pop(L, 1); /* remove global */
@@ -296,7 +301,7 @@ static void dotty (lua_State *L) {
report(L, status);
if (status == LUA_OK && lua_gettop(L) > 0) { /* any result to print? */
luaL_checkstack(L, LUA_MINSTACK, "too many results to print");
- lua_getfield(L, LUA_ENVIRONINDEX, "print");
+ lua_getglobal(L, "print");
lua_insert(L, 1);
if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != LUA_OK)
l_message(progname, lua_pushfstring(L,
@@ -306,7 +311,6 @@ static void dotty (lua_State *L) {
}
lua_settop(L, 0); /* clear stack */
luai_writestring("\n", 1);
- fflush(stdout);
progname = oldprogname;
}
@@ -315,7 +319,7 @@ static int handle_script (lua_State *L, char **argv, int n) {
int status;
const char *fname;
int narg = getargs(L, argv, n); /* collect arguments */
- lua_setfield(L, LUA_ENVIRONINDEX, "arg");
+ lua_setglobal(L, "arg");
fname = argv[n];
if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0)
fname = NULL; /* stdin */
@@ -356,10 +360,11 @@ static int collectargs (char **argv, int *pi, int *pv, int *pe) {
case 'l':
if (argv[i][2] == '\0') {
i++;
- if (argv[i] == NULL) return -1;
+ if (argv[i] == NULL) return -(i - 1);
}
break;
- default: return -1; /* invalid option */
+ default: /* invalid option; return its index... */
+ return -i; /* ...as a negative value */
}
}
return 0;
@@ -369,7 +374,6 @@ static int collectargs (char **argv, int *pi, int *pv, int *pe) {
static int runargs (lua_State *L, char **argv, int n) {
int i;
for (i = 1; i < n; i++) {
- if (argv[i] == NULL) continue;
lua_assert(argv[i][0] == '-');
switch (argv[i][1]) { /* option */
case 'e': {
@@ -412,8 +416,8 @@ static int pmain (lua_State *L) {
int has_i = 0, has_v = 0, has_e = 0;
if (argv[0] && argv[0][0]) progname = argv[0];
script = collectargs(argv, &has_i, &has_v, &has_e);
- if (script < 0) { /* invalid args? */
- print_usage();
+ if (script < 0) { /* invalid arg? */
+ print_usage(argv[-script]);
return 0;
}
if (has_v) print_version();
@@ -443,7 +447,6 @@ static int pmain (lua_State *L) {
int main (int argc, char **argv) {
- static lua_CFunction ppmain = &pmain;
int status, result;
lua_State *L = luaL_newstate(); /* create state */
if (L == NULL) {
@@ -451,11 +454,10 @@ int main (int argc, char **argv) {
return EXIT_FAILURE;
}
/* call 'pmain' in protected mode */
- lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_CPCALL); /* calling function */
- lua_pushlightuserdata(L, &ppmain);
- lua_pushinteger(L, argc);
- lua_pushlightuserdata(L, argv);
- status = lua_pcall(L, 3, 1, 0);
+ lua_pushcfunction(L, &pmain);
+ lua_pushinteger(L, argc); /* 1st argument */
+ lua_pushlightuserdata(L, argv); /* 2nd argument */
+ status = lua_pcall(L, 2, 1, 0);
result = lua_toboolean(L, -1); /* get result */
finalreport(L, status);
lua_close(L);
diff --git a/src/lua.h b/src/lua.h
index f79df970..09a9ab76 100644
--- a/src/lua.h
+++ b/src/lua.h
@@ -1,5 +1,5 @@
/*
-** $Id: lua.h,v 1.261 2010/01/11 17:15:11 roberto Exp $
+** $Id: lua.h,v 1.270 2010/05/12 14:09:20 roberto Exp $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
@@ -17,7 +17,7 @@
#define LUA_VERSION "Lua 5.2"
-#define LUA_RELEASE "Lua 5.2.0 (work2)"
+#define LUA_RELEASE "Lua 5.2.0 (work3)"
#define LUA_VERSION_NUM 502
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2010 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -34,8 +34,7 @@
** pseudo-indices
*/
#define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX
-#define LUA_ENVIRONINDEX (LUA_REGISTRYINDEX - 1)
-#define lua_upvalueindex(i) (LUA_ENVIRONINDEX - (i))
+#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
/* thread status */
@@ -82,6 +81,8 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
#define LUA_TUSERDATA 7
#define LUA_TTHREAD 8
+#define LUA_NUMTAGS 9
+
/* minimum Lua stack available to a C function */
@@ -90,8 +91,7 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
/* predefined values in the registry */
#define LUA_RIDX_MAINTHREAD 1
-#define LUA_RIDX_CPCALL 2
-#define LUA_RIDX_GLOBALS 3
+#define LUA_RIDX_GLOBALS 2
#define LUA_RIDX_LAST LUA_RIDX_GLOBALS
@@ -129,6 +129,7 @@ LUA_API const lua_Number *(lua_version) (lua_State *L);
/*
** basic stack manipulation
*/
+LUA_API int (lua_absindex) (lua_State *L, int idx);
LUA_API int (lua_gettop) (lua_State *L);
LUA_API void (lua_settop) (lua_State *L, int idx);
LUA_API void (lua_pushvalue) (lua_State *L, int idx);
@@ -212,7 +213,7 @@ LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n);
LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
-LUA_API void (lua_getfenv) (lua_State *L, int idx);
+LUA_API void (lua_getenv) (lua_State *L, int idx);
/*
@@ -223,7 +224,7 @@ LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
LUA_API void (lua_rawset) (lua_State *L, int idx);
LUA_API void (lua_rawseti) (lua_State *L, int idx, int n);
LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
-LUA_API int (lua_setfenv) (lua_State *L, int idx);
+LUA_API void (lua_setenv) (lua_State *L, int idx);
/*
@@ -267,6 +268,8 @@ LUA_API int (lua_status) (lua_State *L);
#define LUA_GCSETPAUSE 6
#define LUA_GCSETSTEPMUL 7
#define LUA_GCISRUNNING 8
+#define LUA_GCGEN 9
+#define LUA_GCINC 10
LUA_API int (lua_gc) (lua_State *L, int what, int data);
@@ -297,11 +300,14 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
#define lua_newtable(L) lua_createtable(L, 0, 0)
-#define lua_setglobal(L,s) lua_setfield(L, LUA_ENVIRONINDEX, (s))
-#define lua_getglobal(L,s) lua_getfield(L, LUA_ENVIRONINDEX, (s))
+#define lua_setglobal(L,s) \
+ (lua_pushglobaltable(L), lua_pushvalue(L, -2), \
+ lua_setfield(L, -2, (s)), lua_pop(L, 2))
+
+#define lua_getglobal(L,s) \
+ (lua_pushglobaltable(L), lua_getfield(L, -1, (s)), lua_remove(L, -2))
-#define lua_register(L,n,f) \
- (lua_pushcfunction(L, (f)), lua_setfield(L, LUA_ENVIRONINDEX, (n)))
+#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
diff --git a/src/luac.c b/src/luac.c
index 451bfffc..ee2026ba 100644
--- a/src/luac.c
+++ b/src/luac.c
@@ -1,5 +1,5 @@
/*
-** $Id: luac.c,v 1.57 2008/03/26 13:40:18 lhf Exp $
+** $Id: luac.c,v 1.61 2010/05/14 11:40:22 lhf Exp $
** Lua compiler (saves bytecodes to files; also list bytecodes)
** See Copyright Notice in lua.h
*/
@@ -60,7 +60,7 @@ static void usage(const char* message)
" -s strip debug information\n"
" -v show version information\n"
" -- stop handling options\n"
- " - process stdin and stop handling options\n"
+ " - stop handling options and process stdin\n"
,progname,Output);
exit(EXIT_FAILURE);
}
@@ -89,7 +89,7 @@ static int doargs(int argc, char* argv[])
else if (IS("-o")) /* output file */
{
output=argv[++i];
- if (output==NULL || *output==0) usage(LUA_QL("-o") " needs argument");
+ if (output==NULL || *output==0 || *output=='-') usage(LUA_QL("-o") " needs argument");
if (IS("-")) output=NULL;
}
else if (IS("-p")) /* parse only */
@@ -150,16 +150,10 @@ static int writer(lua_State* L, const void* p, size_t size, void* u)
return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0);
}
-struct Smain {
- int argc;
- char** argv;
-};
-
static int pmain(lua_State* L)
{
- struct Smain* s = (struct Smain*)lua_touserdata(L, 1);
- int argc=s->argc;
- char** argv=s->argv;
+ int argc=lua_tointeger(L,1);
+ char** argv=lua_touserdata(L,2);
const Proto* f;
int i;
if (!lua_checkstack(L,argc)) fatal("too many input files");
@@ -183,25 +177,18 @@ static int pmain(lua_State* L)
return 0;
}
-LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) {
- lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_CPCALL);
- lua_pushlightuserdata(L, &func);
- lua_pushlightuserdata(L, ud);
- return lua_pcall(L, 2, 0, 0);
-}
-
int main(int argc, char* argv[])
{
lua_State* L;
- struct Smain s;
int i=doargs(argc,argv);
argc-=i; argv+=i;
if (argc<=0) usage("no input files given");
L=luaL_newstate();
if (L==NULL) fatal("not enough memory for state");
- s.argc=argc;
- s.argv=argv;
- if (lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1));
+ lua_pushcfunction(L,&pmain);
+ lua_pushinteger(L,argc);
+ lua_pushlightuserdata(L,argv);
+ if (lua_pcall(L,2,0,0)!=0) fatal(lua_tostring(L,-1));
lua_close(L);
return EXIT_SUCCESS;
}
diff --git a/src/luaconf.h b/src/luaconf.h
index b16e9991..0606230d 100644
--- a/src/luaconf.h
+++ b/src/luaconf.h
@@ -1,5 +1,5 @@
/*
-** $Id: luaconf.h,v 1.130 2010/01/11 17:15:30 roberto Exp $
+** $Id: luaconf.h,v 1.137 2010/05/12 14:17:36 roberto Exp $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
@@ -89,7 +89,7 @@
#define LUA_CPATH_DEFAULT \
LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll;" ".\\?.dll"
-#else
+#else /* _WIN32 */
#define LUA_ROOT "/usr/local/"
#define LUA_LDIR LUA_ROOT "share/lua/5.2/"
#define LUA_CDIR LUA_ROOT "lib/lua/5.2/"
@@ -98,7 +98,7 @@
LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" "./?.lua"
#define LUA_CPATH_DEFAULT \
LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so"
-#endif
+#endif /* _WIN32 */
/*
@@ -130,11 +130,12 @@
#define LUA_API __declspec(dllimport)
#endif
-#else
+#else /* LUA_BUILD_AS_DLL */
#define LUA_API extern
-#endif
+#endif /* LUA_BUILD_AS_DLL */
+
/* more often than not the libs go together with the core */
#define LUALIB_API LUA_API
@@ -166,11 +167,11 @@
#define LUAI_DDEC LUAI_FUNC
#define LUAI_DDEF /* empty */
-#else
+#else /* luaall_c */
#define LUAI_FUNC extern
#define LUAI_DDEC extern
#define LUAI_DDEF /* empty */
-#endif
+#endif /* luaall_c */
@@ -192,10 +193,17 @@
/*
@@ luai_writestring defines how 'print' prints its results.
-** CHANGE it if your system does not have a useful stdout.
*/
+#include <stdio.h>
#define luai_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
+/*
+@@ luai_writestringerror defines how to print error messages.
+** (A format string with one argument is enough for Lua...)
+*/
+#define luai_writestringerror(s,p) \
+ (fprintf(stderr, (s), (p)), fflush(stderr))
+
@@ -220,18 +228,12 @@
#define LUA_COMPAT_UNPACK
/*
-@@ LUA_COMPAT_CPCALL controls the presence of function 'lua_cpcall'.
+@@ LUA_COMPAT_CPCALL controls the presence of macro 'lua_cpcall'.
** You can replace it with the preregistered function 'cpcall'.
*/
-#define LUA_COMPAT_CPCALL
-LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud);
+#define lua_cpcall(L,f,u) \
+ (lua_pushlightuserdata(L,(u)), luaL_cpcall(L,(f),1,0))
-/*
-@@ LUA_COMPAT_FENV controls the presence of functions 'setfenv/getfenv'.
-** You can replace them with lexical environments, 'loadin', or the
-** debug library.
-*/
-#define LUA_COMPAT_FENV
/*
@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library.
@@ -267,7 +269,7 @@ LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud);
/* compatibility with previous wrong spelling */
#define luaL_typerror luaL_typeerror
-#endif
+#endif /* LUA_COMPAT_ALL */
/* }================================================================== */
@@ -421,7 +423,7 @@ LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud);
/*
@@ lua_number2int is a macro to convert lua_Number to int.
-@@ lua_number2integer is a macro to convert lua_Number to lUA_INTEGER.
+@@ lua_number2integer is a macro to convert lua_Number to LUA_INTEGER.
@@ lua_number2uint is a macro to convert a lua_Number to an unsigned
@* LUA_INT32.
@@ lua_uint2number is a macro to convert an unsigned LUA_INT32
@@ -439,30 +441,31 @@ LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud);
/* On a Microsoft compiler, use assembler */
#if defined(_MSC_VER)
-#define lua_number2int(i,d) {__asm fld d __asm fistp i}
+#define lua_number2int(i,n) __asm {__asm fld n __asm fistp i}
#define lua_number2integer(i,n) lua_number2int(i, n)
-#define lua_number2uint(i,n) lua_number2int(i, n)
+#define lua_number2uint(i,n) \
+ {__int64 l; __asm {__asm fld n __asm fistp l} i = (unsigned int)l;}
-#else
+#else /* _MSC_VER */
/* the next trick should work on any Pentium, but sometimes clashes
with a DirectX idiosyncrasy */
union luai_Cast { double l_d; long l_l; };
-#define lua_number2int(i,d) \
- { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; }
+#define lua_number2int(i,n) \
+ { volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; (i) = u.l_l; }
#define lua_number2integer(i,n) lua_number2int(i, n)
#define lua_number2uint(i,n) lua_number2int(i, n)
-#endif
+#endif /* _MSC_VER */
-#else
+#else /* LUA_NUMBER_DOUBLE ... (Pentium) */
/* this option always works, but may be slow */
-#define lua_number2int(i,d) ((i)=(int)(d))
-#define lua_number2integer(i,d) ((i)=(LUA_INTEGER)(d))
-#define lua_number2uint(i,d) ((i)=(unsigned LUA_INT32)(d))
+#define lua_number2int(i,n) ((i)=(int)(n))
+#define lua_number2integer(i,n) ((i)=(LUA_INTEGER)(n))
+#define lua_number2uint(i,n) ((i)=(unsigned LUA_INT32)(n))
-#endif
+#endif /* LUA_NUMBER_DOUBLE ... (Pentium) */
/* on several machines, coercion from unsigned to double is too slow,
@@ -483,11 +486,11 @@ union luai_Cast { double l_d; long l_l; };
#include <float.h>
#include <math.h>
-#define luai_hashnum(i,d) { int e; \
- d = frexp(d, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \
- lua_number2int(i, d); i += e; }
+#define luai_hashnum(i,n) { int e; \
+ n = frexp(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \
+ lua_number2int(i, n); i += e; }
-#endif
+#endif /* ltable_c */
/* }================================================================== */
diff --git a/src/lundump.c b/src/lundump.c
index 244d6e52..e82e1951 100644
--- a/src/lundump.c
+++ b/src/lundump.c
@@ -1,5 +1,5 @@
/*
-** $Id: lundump.c,v 2.12 2009/09/30 15:38:37 roberto Exp $
+** $Id: lundump.c,v 2.13 2010/03/12 19:14:06 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -180,7 +180,6 @@ static Proto* LoadFunction(LoadState* S, TString* p)
f->numparams=LoadByte(S);
f->is_vararg=LoadByte(S);
f->maxstacksize=LoadByte(S);
- f->envreg=LoadByte(S);
LoadCode(S,f);
LoadConstants(S,f);
LoadUpvalues(S,f);
diff --git a/src/lvm.c b/src/lvm.c
index a3150888..518a16ba 100644
--- a/src/lvm.c
+++ b/src/lvm.c
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.c,v 2.102 2009/12/17 16:20:01 roberto Exp $
+** $Id: lvm.c,v 2.120 2010/05/13 19:53:05 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -50,8 +50,8 @@ int luaV_tostring (lua_State *L, StkId obj) {
else {
char s[LUAI_MAXNUMBER2STR];
lua_Number n = nvalue(obj);
- lua_number2str(s, n);
- setsvalue2s(L, obj, luaS_new(L, s));
+ int l = lua_number2str(s, n);
+ setsvalue2s(L, obj, luaS_newlstr(L, s, l));
return 1;
}
}
@@ -74,6 +74,10 @@ static void traceexec (lua_State *L) {
luaD_hook(L, LUA_HOOKLINE, newline);
}
L->oldpc = ci->u.l.savedpc;
+ if (L->status == LUA_YIELD) { /* did hook yield? */
+ ci->u.l.savedpc--; /* undo increment (resume will increment it again) */
+ luaD_throw(L, LUA_YIELD);
+ }
}
@@ -102,7 +106,7 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
if (ttistable(t)) { /* `t' is a table? */
Table *h = hvalue(t);
const TValue *res = luaH_get(h, key); /* do a primitive get */
- if (!ttisnil(res) || /* result is no nil? */
+ if (!ttisnil(res) || /* result is not nil? */
(tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */
setobj2s(L, val, res);
return;
@@ -129,7 +133,7 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
if (ttistable(t)) { /* `t' is a table? */
Table *h = hvalue(t);
TValue *oldval = luaH_set(L, h, key); /* do a primitive set */
- if (!ttisnil(oldval) || /* result is no nil? */
+ if (!ttisnil(oldval) || /* result is not nil? */
(tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */
setobj2t(L, oldval, val);
luaC_barriert(L, h, val);
@@ -157,12 +161,13 @@ static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2,
if (ttisnil(tm))
tm = luaT_gettmbyobj(L, p2, event); /* try second operand */
if (ttisnil(tm)) return 0;
+ if (event == TM_UNM) p2 = luaO_nilobject;
callTM(L, tm, p1, p2, res, 1);
return 1;
}
-static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2,
+static const TValue *get_equalTM (lua_State *L, Table *mt1, Table *mt2,
TMS event) {
const TValue *tm1 = fasttm(L, mt1, event);
const TValue *tm2;
@@ -178,14 +183,10 @@ static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2,
static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2,
TMS event) {
- const TValue *tm1 = luaT_gettmbyobj(L, p1, event);
- const TValue *tm2;
- if (ttisnil(tm1)) return -1; /* no metamethod? */
- tm2 = luaT_gettmbyobj(L, p2, event);
- if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */
- return -1;
- callTM(L, tm1, p1, p2, L->top, 1);
- return !l_isfalse(L->top);
+ if (!call_binTM(L, p1, p2, L->top, event))
+ return -1; /* no metamethod */
+ else
+ return !l_isfalse(L->top);
}
@@ -213,11 +214,9 @@ static int l_strcmp (const TString *ls, const TString *rs) {
int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
int res;
- if (ttype(l) != ttype(r))
- return luaG_ordererror(L, l, r);
- else if (ttisnumber(l))
+ if (ttisnumber(l) && ttisnumber(r))
return luai_numlt(L, nvalue(l), nvalue(r));
- else if (ttisstring(l))
+ else if (ttisstring(l) && ttisstring(r))
return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0;
else if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
return res;
@@ -227,11 +226,9 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
int res;
- if (ttype(l) != ttype(r))
- return luaG_ordererror(L, l, r);
- else if (ttisnumber(l))
+ if (ttisnumber(l) && ttisnumber(r))
return luai_numle(L, nvalue(l), nvalue(r));
- else if (ttisstring(l))
+ else if (ttisstring(l) && ttisstring(r))
return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0;
else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */
return res;
@@ -249,14 +246,16 @@ int luaV_equalval_ (lua_State *L, const TValue *t1, const TValue *t2) {
case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2));
case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */
case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
+ case LUA_TLCF: return fvalue(t1) == fvalue(t2);
+ case LUA_TSTRING: return eqstr(rawtsvalue(t1), rawtsvalue(t2));
case LUA_TUSERDATA: {
if (uvalue(t1) == uvalue(t2)) return 1;
- tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ);
+ tm = get_equalTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ);
break; /* will try TM */
}
case LUA_TTABLE: {
if (hvalue(t1) == hvalue(t2)) return 1;
- tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ);
+ tm = get_equalTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ);
break; /* will try TM */
}
default: return gcvalue(t1) == gcvalue(t2);
@@ -354,14 +353,10 @@ void luaV_finishOp (lua_State *L) {
StkId base = ci->u.l.base;
Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */
OpCode op = GET_OPCODE(inst);
- if (op == OP_EXTRAARG) { /* extra argument? */
- inst = *(ci->u.l.savedpc - 2); /* get its 'main' instruction */
- op = GET_OPCODE(inst);
- }
switch (op) { /* finish its execution */
case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV:
case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN:
- case OP_GETGLOBAL: case OP_GETTABLE: case OP_SELF: {
+ case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: {
setobjs2s(L, base + GETARG_A(inst), --L->top);
break;
}
@@ -402,7 +397,7 @@ void luaV_finishOp (lua_State *L) {
L->top = ci->top; /* adjust results */
break;
}
- case OP_TAILCALL: case OP_SETGLOBAL: case OP_SETTABLE:
+ case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE:
break;
default: lua_assert(0);
}
@@ -426,11 +421,13 @@ void luaV_finishOp (lua_State *L) {
(k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++)))
-#define dojump(i) { ci->u.l.savedpc += (i); luai_threadyield(L);}
+#define dojump(i) (ci->u.l.savedpc += (i))
#define Protect(x) { {x;}; base = ci->u.l.base; }
+#define checkGC(L) Protect(luaC_checkGC(L); luai_threadyield(L);)
+
#define arith_op(op,tm) { \
TValue *rb = RKB(i); \
@@ -439,133 +436,109 @@ void luaV_finishOp (lua_State *L) {
lua_Number nb = nvalue(rb), nc = nvalue(rc); \
setnvalue(ra, op(L, nb, nc)); \
} \
- else \
- Protect(luaV_arith(L, ra, rb, rc, tm)); \
- }
+ else { Protect(luaV_arith(L, ra, rb, rc, tm)); } }
+#define vmdispatch(o) switch(o)
+#define vmcase(l,b) case l: {b} break;
void luaV_execute (lua_State *L) {
CallInfo *ci = L->ci;
- LClosure *cl = &clvalue(ci->func)->l;
- TValue *k = cl->p->k;
- StkId base = ci->u.l.base;
+ LClosure *cl;
+ TValue *k;
+ StkId base;
+ newframe: /* reentry point when frame changes (call/return) */
lua_assert(isLua(ci));
+ lua_assert(ci == L->ci);
+ cl = &clvalue(ci->func)->l;
+ k = cl->p->k;
+ base = ci->u.l.base;
/* main loop of interpreter */
for (;;) {
Instruction i = *(ci->u.l.savedpc++);
StkId ra;
if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
(--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
- traceexec(L);
- if (L->status == LUA_YIELD) { /* did hook yield? */
- ci->u.l.savedpc--; /* undo increment */
- luaD_throw(L, LUA_YIELD);
- }
- base = ci->u.l.base;
+ Protect(traceexec(L));
}
/* warning!! several calls may realloc the stack and invalidate `ra' */
ra = RA(i);
lua_assert(base == ci->u.l.base);
lua_assert(base <= L->top && L->top < L->stack + L->stacksize);
- switch (GET_OPCODE(i)) {
- case OP_MOVE: {
+ vmdispatch (GET_OPCODE(i)) {
+ vmcase(OP_MOVE,
setobjs2s(L, ra, RB(i));
- continue;
- }
- case OP_LOADK: {
+ )
+ vmcase(OP_LOADK,
TValue *rb = KBx(i);
setobj2s(L, ra, rb);
- continue;
- }
- case OP_LOADBOOL: {
+ )
+ vmcase(OP_LOADBOOL,
setbvalue(ra, GETARG_B(i));
if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */
- continue;
- }
- case OP_LOADNIL: {
+ )
+ vmcase(OP_LOADNIL,
TValue *rb = RB(i);
do {
setnilvalue(rb--);
} while (rb >= ra);
- continue;
- }
- case OP_GETUPVAL: {
+ )
+ vmcase(OP_GETUPVAL,
int b = GETARG_B(i);
setobj2s(L, ra, cl->upvals[b]->v);
- continue;
- }
- case OP_GETGLOBAL: {
- TValue g;
- TValue *rb = KBx(i);
- sethvalue(L, &g, cl->env);
- lua_assert(ttisstring(rb));
- Protect(luaV_gettable(L, &g, rb, ra));
- continue;
- }
- case OP_GETTABLE: {
+ )
+ vmcase(OP_GETTABUP,
+ int b = GETARG_B(i);
+ Protect(luaV_gettable(L, cl->upvals[b]->v, RKC(i), ra));
+ )
+ vmcase(OP_GETTABLE,
Protect(luaV_gettable(L, RB(i), RKC(i), ra));
- continue;
- }
- case OP_SETGLOBAL: {
- TValue g;
- TValue *rb = KBx(i);
- sethvalue(L, &g, cl->env);
- lua_assert(ttisstring(rb));
- Protect(luaV_settable(L, &g, rb, ra));
- continue;
- }
- case OP_SETUPVAL: {
+ )
+ vmcase(OP_SETTABUP,
+ int a = GETARG_A(i);
+ Protect(luaV_settable(L, cl->upvals[a]->v, RKB(i), RKC(i)));
+ )
+ vmcase(OP_SETUPVAL,
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra);
luaC_barrier(L, uv, ra);
- continue;
- }
- case OP_SETTABLE: {
+ )
+ vmcase(OP_SETTABLE,
Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
- continue;
- }
- case OP_NEWTABLE: {
+ )
+ vmcase(OP_NEWTABLE,
int b = GETARG_B(i);
int c = GETARG_C(i);
Table *t = luaH_new(L);
sethvalue(L, ra, t);
if (b != 0 || c != 0)
luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c));
- Protect(luaC_checkGC(L));
- continue;
- }
- case OP_SELF: {
+ checkGC(L);
+ )
+ vmcase(OP_SELF,
StkId rb = RB(i);
setobjs2s(L, ra+1, rb);
Protect(luaV_gettable(L, rb, RKC(i), ra));
- continue;
- }
- case OP_ADD: {
+ )
+ vmcase(OP_ADD,
arith_op(luai_numadd, TM_ADD);
- continue;
- }
- case OP_SUB: {
+ )
+ vmcase(OP_SUB,
arith_op(luai_numsub, TM_SUB);
- continue;
- }
- case OP_MUL: {
+ )
+ vmcase(OP_MUL,
arith_op(luai_nummul, TM_MUL);
- continue;
- }
- case OP_DIV: {
+ )
+ vmcase(OP_DIV,
arith_op(luai_numdiv, TM_DIV);
- continue;
- }
- case OP_MOD: {
+ )
+ vmcase(OP_MOD,
arith_op(luai_nummod, TM_MOD);
- continue;
- }
- case OP_POW: {
+ )
+ vmcase(OP_POW,
arith_op(luai_numpow, TM_POW);
- continue;
- }
- case OP_UNM: {
+ )
+ vmcase(OP_UNM,
TValue *rb = RB(i);
if (ttisnumber(rb)) {
lua_Number nb = nvalue(rb);
@@ -574,31 +547,26 @@ void luaV_execute (lua_State *L) {
else {
Protect(luaV_arith(L, ra, rb, rb, TM_UNM));
}
- continue;
- }
- case OP_NOT: {
+ )
+ vmcase(OP_NOT,
int res = l_isfalse(RB(i)); /* next assignment may change this value */
setbvalue(ra, res);
- continue;
- }
- case OP_LEN: {
+ )
+ vmcase(OP_LEN,
Protect(luaV_objlen(L, ra, RB(i)));
- continue;
- }
- case OP_CONCAT: {
+ )
+ vmcase(OP_CONCAT,
int b = GETARG_B(i);
int c = GETARG_C(i);
L->top = base + c + 1; /* mark the end of concat operands */
- Protect(luaV_concat(L, c-b+1); luaC_checkGC(L));
+ Protect(luaV_concat(L, c-b+1); checkGC(L);)
L->top = ci->top; /* restore top */
setobjs2s(L, RA(i), base+b);
- continue;
- }
- case OP_JMP: {
+ )
+ vmcase(OP_JMP,
dojump(GETARG_sBx(i));
- continue;
- }
- case OP_EQ: {
+ )
+ vmcase(OP_EQ,
TValue *rb = RKB(i);
TValue *rc = RKC(i);
Protect(
@@ -606,62 +574,54 @@ void luaV_execute (lua_State *L) {
dojump(GETARG_sBx(*ci->u.l.savedpc));
)
ci->u.l.savedpc++;
- continue;
- }
- case OP_LT: {
+ )
+ vmcase(OP_LT,
Protect(
if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i))
dojump(GETARG_sBx(*ci->u.l.savedpc));
)
ci->u.l.savedpc++;
- continue;
- }
- case OP_LE: {
+ )
+ vmcase(OP_LE,
Protect(
if (luaV_lessequal(L, RKB(i), RKC(i)) == GETARG_A(i))
dojump(GETARG_sBx(*ci->u.l.savedpc));
)
ci->u.l.savedpc++;
- continue;
- }
- case OP_TEST: {
+ )
+ vmcase(OP_TEST,
if (GETARG_C(i) ? !l_isfalse(ra) : l_isfalse(ra))
dojump(GETARG_sBx(*ci->u.l.savedpc));
ci->u.l.savedpc++;
- continue;
- }
- case OP_TESTSET: {
+ )
+ vmcase(OP_TESTSET,
TValue *rb = RB(i);
if (GETARG_C(i) ? !l_isfalse(rb) : l_isfalse(rb)) {
setobjs2s(L, ra, rb);
dojump(GETARG_sBx(*ci->u.l.savedpc));
}
ci->u.l.savedpc++;
- continue;
- }
- case OP_CALL: {
+ )
+ vmcase(OP_CALL,
int b = GETARG_B(i);
int nresults = GETARG_C(i) - 1;
if (b != 0) L->top = ra+b; /* else previous instruction set top */
if (luaD_precall(L, ra, nresults)) { /* C function? */
if (nresults >= 0) L->top = ci->top; /* adjust results */
base = ci->u.l.base;
- continue;
}
else { /* Lua function */
ci = L->ci;
ci->callstatus |= CIST_REENTRY;
- break; /* restart luaV_execute over new Lua function */
+ goto newframe; /* restart luaV_execute over new Lua function */
}
- }
- case OP_TAILCALL: {
+ )
+ vmcase(OP_TAILCALL,
int b = GETARG_B(i);
if (b != 0) L->top = ra+b; /* else previous instruction set top */
lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
- if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */
+ if (luaD_precall(L, ra, LUA_MULTRET)) /* C function? */
base = ci->u.l.base;
- continue;
- }
else {
/* tail call: put called frame (n) in place of caller one (o) */
CallInfo *nci = L->ci; /* called frame */
@@ -682,10 +642,10 @@ void luaV_execute (lua_State *L) {
oci->callstatus |= CIST_TAIL; /* function was tail called */
ci = L->ci = oci; /* remove new frame */
lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize);
- break; /* restart luaV_execute over new Lua function */
+ goto newframe; /* restart luaV_execute over new Lua function */
}
- }
- case OP_RETURN: {
+ )
+ vmcase(OP_RETURN,
int b = GETARG_B(i);
if (b != 0) L->top = ra+b-1;
if (cl->p->sizep > 0) luaF_close(L, base);
@@ -697,10 +657,10 @@ void luaV_execute (lua_State *L) {
if (b) L->top = ci->top;
lua_assert(isLua(ci));
lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL);
- break; /* restart luaV_execute over new Lua function */
+ goto newframe; /* restart luaV_execute over new Lua function */
}
- }
- case OP_FORLOOP: {
+ )
+ vmcase(OP_FORLOOP,
lua_Number step = nvalue(ra+2);
lua_Number idx = luai_numadd(L, nvalue(ra), step); /* increment index */
lua_Number limit = nvalue(ra+1);
@@ -710,9 +670,8 @@ void luaV_execute (lua_State *L) {
setnvalue(ra, idx); /* update internal index... */
setnvalue(ra+3, idx); /* ...and external index */
}
- continue;
- }
- case OP_FORPREP: {
+ )
+ vmcase(OP_FORPREP,
const TValue *init = ra;
const TValue *plimit = ra+1;
const TValue *pstep = ra+2;
@@ -724,9 +683,8 @@ void luaV_execute (lua_State *L) {
luaG_runerror(L, LUA_QL("for") " step must be a number");
setnvalue(ra, luai_numsub(L, nvalue(ra), nvalue(pstep)));
dojump(GETARG_sBx(i));
- continue;
- }
- case OP_TFORCALL: {
+ )
+ vmcase(OP_TFORCALL,
StkId cb = ra + 3; /* call base */
setobjs2s(L, cb+2, ra+2);
setobjs2s(L, cb+1, ra+1);
@@ -737,16 +695,16 @@ void luaV_execute (lua_State *L) {
i = *(ci->u.l.savedpc++); /* go to next instruction */
ra = RA(i);
lua_assert(GET_OPCODE(i) == OP_TFORLOOP);
- /* go through */
- }
- case OP_TFORLOOP: {
+ goto l_tforloop;
+ )
+ vmcase(OP_TFORLOOP,
+ l_tforloop:
if (!ttisnil(ra + 1)) { /* continue loop? */
setobjs2s(L, ra, ra + 1); /* save control variable */
dojump(GETARG_sBx(i)); /* jump back */
}
- continue;
- }
- case OP_SETLIST: {
+ )
+ vmcase(OP_SETLIST,
int n = GETARG_B(i);
int c = GETARG_C(i);
int last;
@@ -759,45 +717,34 @@ void luaV_execute (lua_State *L) {
h = hvalue(ra);
last = ((c-1)*LFIELDS_PER_FLUSH) + n;
if (last > h->sizearray) /* needs more space? */
- luaH_resizearray(L, h, last); /* pre-alloc it at once */
+ luaH_resizearray(L, h, last); /* pre-allocate it at once */
for (; n > 0; n--) {
TValue *val = ra+n;
setobj2t(L, luaH_setint(L, h, last--), val);
luaC_barriert(L, h, val);
}
L->top = ci->top; /* correct top (in case of previous open call) */
- continue;
- }
- case OP_CLOSE: {
+ )
+ vmcase(OP_CLOSE,
luaF_close(L, ra);
- continue;
- }
- case OP_CLOSURE: {
+ )
+ vmcase(OP_CLOSURE,
Proto *p = cl->p->p[GETARG_Bx(i)]; /* prototype for new closure */
int nup = p->sizeupvalues;
- Closure *ncl = luaF_newLclosure(L, nup, cl->env);
+ Closure *ncl = luaF_newLclosure(L, nup);
Upvaldesc *uv = p->upvalues;
int j;
ncl->l.p = p;
setclvalue(L, ra, ncl); /* anchor new closure in stack */
- if (p->envreg != NO_REG) { /* lexical environment? */
- StkId env = base + p->envreg;
- if (!ttistable(env))
- luaG_runerror(L, "environment is not a table: "
- "cannot create closure");
- else
- ncl->l.env = hvalue(env);
- }
for (j = 0; j < nup; j++) { /* fill in upvalues */
if (uv[j].instack) /* upvalue refers to local variable? */
ncl->l.upvals[j] = luaF_findupval(L, base + uv[j].idx);
else /* get upvalue from enclosing function */
ncl->l.upvals[j] = cl->upvals[uv[j].idx];
}
- Protect(luaC_checkGC(L));
- continue;
- }
- case OP_VARARG: {
+ checkGC(L);
+ )
+ vmcase(OP_VARARG,
int b = GETARG_B(i) - 1;
int j;
int n = cast_int(base - ci->func) - cl->p->numparams - 1;
@@ -815,18 +762,11 @@ void luaV_execute (lua_State *L) {
setnilvalue(ra + j);
}
}
- continue;
- }
- case OP_EXTRAARG: {
- luaG_runerror(L, "bad opcode");
- return;
- }
+ )
+ vmcase(OP_EXTRAARG,
+ lua_assert(0);
+ )
}
- /* function changed (call/return): update pointers */
- lua_assert(ci == L->ci);
- cl = &clvalue(ci->func)->l;
- k = cl->p->k;
- base = ci->u.l.base;
}
}
diff --git a/src/print.c b/src/print.c
index fb491e7e..6a5b05db 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1,5 +1,5 @@
/*
-** $Id: print.c,v 1.58 2008/09/11 12:05:06 lhf Exp $
+** $Id: print.c,v 1.60 2010/05/17 22:27:10 lhf Exp $
** print bytecodes
** See Copyright Notice in lua.h
*/
@@ -82,6 +82,7 @@ static void PrintCode(const Proto* f)
int a=GETARG_A(i);
int b=GETARG_B(i);
int c=GETARG_C(i);
+ int ax=GETARG_Ax(i);
int bx=GETARG_Bx(i);
int sbx=GETARG_sBx(i);
int line=getfuncline(f,pc);
@@ -99,24 +100,32 @@ static void PrintCode(const Proto* f)
if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c);
break;
case iABx:
- if (getBMode(o)==OpArgK) printf("%d %d",a,-1-bx); else printf("%d %d",a,bx);
+ if (getBMode(o)==OpArgK) printf("%d %d",a,-bx); else printf("%d %d",a,bx);
break;
case iAsBx:
if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx);
break;
+ case iAx:
+ printf("%d",ax);
+ break;
}
switch (o)
{
case OP_LOADK:
- printf("\t; "); PrintConstant(f,bx);
+ printf("\t; "); PrintConstant(f,bx-1);
break;
case OP_GETUPVAL:
case OP_SETUPVAL:
printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b].name) : "-");
break;
- case OP_GETGLOBAL:
- case OP_SETGLOBAL:
- printf("\t; %s",svalue(&f->k[bx]));
+ case OP_GETTABUP:
+ printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b].name) : "-");
+ if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); }
+ break;
+ case OP_SETTABUP:
+ printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[a].name) : "-");
+ if (ISK(b)) { printf(" "); PrintConstant(f,INDEXK(b)); }
+ if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); }
break;
case OP_GETTABLE:
case OP_SELF:
diff --git a/test/ALL.lua b/test/ALL.lua
deleted file mode 100644
index 0045fc36..00000000
--- a/test/ALL.lua
+++ /dev/null
@@ -1,26 +0,0 @@
-function run(x)
- print("\n-------------------------------------------------------------")
- print(x)
- os.execute("../src/lua "..x)
- print("DONE",x)
-end
-
-run"bisect.lua"
-run"cf.lua"
-run"echo.lua jan feb mar apr may jun jul aug sep oct nov dec"
-run"env.lua"
-run"factorial.lua"
-run"fib.lua"
-run"fibfor.lua"
---run"globals.lua"
-run"hello.lua"
-run"luac.lua"
-run"printf.lua"
-run"readonly.lua"
-run"sieve.lua"
-run"sort.lua"
-run"table.lua"
-run"trace-calls.lua"
-run"trace-globals.lua"
-run"xd.lua < hello.lua"
-run"life.lua"
diff --git a/test/README b/test/README
deleted file mode 100644
index 0c7f38bc..00000000
--- a/test/README
+++ /dev/null
@@ -1,26 +0,0 @@
-These are simple tests for Lua. Some of them contain useful code.
-They are meant to be run to make sure Lua is built correctly and also
-to be read, to see how Lua programs look.
-
-Here is a one-line summary of each program:
-
- bisect.lua bisection method for solving non-linear equations
- cf.lua temperature conversion table (celsius to farenheit)
- echo.lua echo command line arguments
- env.lua environment variables as automatic global variables
- factorial.lua factorial without recursion
- fib.lua fibonacci function with cache
- fibfor.lua fibonacci numbers with coroutines and generators
- globals.lua report global variable usage
- hello.lua the first program in every language
- life.lua Conway's Game of Life
- luac.lua bare-bones luac
- printf.lua an implementation of printf
- readonly.lua make global variables readonly
- sieve.lua the sieve of of Eratosthenes programmed with coroutines
- sort.lua two implementations of a sort function
- table.lua make table, grouping all data for the same item
- trace-calls.lua trace calls
- trace-globals.lua trace assigments to global variables
- xd.lua hex dump
-
diff --git a/test/bisect.lua b/test/bisect.lua
deleted file mode 100644
index f91e69bf..00000000
--- a/test/bisect.lua
+++ /dev/null
@@ -1,27 +0,0 @@
--- bisection method for solving non-linear equations
-
-delta=1e-6 -- tolerance
-
-function bisect(f,a,b,fa,fb)
- local c=(a+b)/2
- io.write(n," c=",c," a=",a," b=",b,"\n")
- if c==a or c==b or math.abs(a-b)<delta then return c,b-a end
- n=n+1
- local fc=f(c)
- if fa*fc<0 then return bisect(f,a,c,fa,fc) else return bisect(f,c,b,fc,fb) end
-end
-
--- find root of f in the inverval [a,b]. needs f(a)*f(b)<0
-function solve(f,a,b)
- n=0
- local z,e=bisect(f,a,b,f(a),f(b))
- io.write(string.format("after %d steps, root is %.17g with error %.1e, f=%.1e\n",n,z,e,f(z)))
-end
-
--- 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.lua b/test/cf.lua
deleted file mode 100644
index 8cda54b9..00000000
--- a/test/cf.lua
+++ /dev/null
@@ -1,16 +0,0 @@
--- temperature conversion table (celsius to farenheit)
-
-for c0=-20,50-1,10 do
- io.write("C ")
- for c=c0,c0+10-1 do
- io.write(string.format("%3.0f ",c))
- end
- io.write("\n")
-
- io.write("F ")
- for c=c0,c0+10-1 do
- f=(9/5)*c+32
- io.write(string.format("%3.0f ",f))
- end
- io.write("\n\n")
-end
diff --git a/test/echo.lua b/test/echo.lua
deleted file mode 100644
index 4313439a..00000000
--- a/test/echo.lua
+++ /dev/null
@@ -1,5 +0,0 @@
--- echo command line arguments
-
-for i=0,table.getn(arg) do
- print(i,arg[i])
-end
diff --git a/test/env.lua b/test/env.lua
deleted file mode 100644
index 9e62a57f..00000000
--- a/test/env.lua
+++ /dev/null
@@ -1,7 +0,0 @@
--- read environment variables as if they were global variables
-
-local f=function (t,i) return os.getenv(i) end
-setmetatable(getfenv(),{__index=f})
-
--- an example
-print(a,USER,PATH)
diff --git a/test/factorial.lua b/test/factorial.lua
deleted file mode 100644
index 7c4cf0fa..00000000
--- a/test/factorial.lua
+++ /dev/null
@@ -1,32 +0,0 @@
--- function closures are powerful
-
--- traditional fixed-point operator from functional programming
-Y = function (g)
- local a = function (f) return f(f) end
- return a(function (f)
- return g(function (x)
- local c=f(f)
- return c(x)
- end)
- end)
-end
-
-
--- factorial without recursion
-F = function (f)
- return function (n)
- if n == 0 then return 1
- else return n*f(n-1) end
- end
- end
-
-factorial = Y(F) -- factorial is the fixed point of F
-
--- now test it
-function test(x)
- io.write(x,"! = ",factorial(x),"\n")
-end
-
-for n=0,16 do
- test(n)
-end
diff --git a/test/fib.lua b/test/fib.lua
deleted file mode 100644
index 97a921b1..00000000
--- a/test/fib.lua
+++ /dev/null
@@ -1,40 +0,0 @@
--- fibonacci function with cache
-
--- very inefficient fibonacci function
-function fib(n)
- N=N+1
- if n<2 then
- return n
- else
- return fib(n-1)+fib(n-2)
- end
-end
-
--- a general-purpose value cache
-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
-
--- run and time it
-function test(s,f)
- N=0
- local c=os.clock()
- local v=f(n)
- local t=os.clock()-c
- print(s,n,v,t,N)
-end
-
-n=arg[1] or 24 -- for other values, do lua fib.lua XX
-n=tonumber(n)
-print("","n","value","time","evals")
-test("plain",fib)
-fib=cache(fib)
-test("cached",fib)
diff --git a/test/fibfor.lua b/test/fibfor.lua
deleted file mode 100644
index 8bbba39c..00000000
--- a/test/fibfor.lua
+++ /dev/null
@@ -1,13 +0,0 @@
--- example of for with generator functions
-
-function generatefib (n)
- return coroutine.wrap(function ()
- local a,b = 1, 1
- while a <= n do
- coroutine.yield(a)
- a, b = b, a+b
- end
- end)
-end
-
-for i in generatefib(1000) do print(i) end
diff --git a/test/globals.lua b/test/globals.lua
deleted file mode 100644
index d4c20e15..00000000
--- a/test/globals.lua
+++ /dev/null
@@ -1,13 +0,0 @@
--- reads luac listings and reports global variable usage
--- lines where a global is written to are marked with "*"
--- typical usage: luac -p -l file.lua | lua globals.lua | sort | lua table.lua
-
-while 1 do
- local s=io.read()
- if s==nil then break end
- local ok,_,l,op,g=string.find(s,"%[%-?(%d*)%]%s*([GS])ETGLOBAL.-;%s+(.*)$")
- if ok then
- if op=="S" then op="*" else op="" end
- io.write(g,"\t",l,op,"\n")
- end
-end
diff --git a/test/life.lua b/test/life.lua
deleted file mode 100644
index 911d9fe1..00000000
--- a/test/life.lua
+++ /dev/null
@@ -1,111 +0,0 @@
--- life.lua
--- original by Dave Bollinger <DBollinger@compuserve.com> posted to lua-l
--- modified to use ANSI terminal escape sequences
--- modified to use for instead of while
-
-local write=io.write
-
-ALIVE="¥" DEAD="þ"
-ALIVE="O" DEAD="-"
-
-function delay() -- NOTE: SYSTEM-DEPENDENT, adjust as necessary
- for i=1,10000 do end
- -- local i=os.clock()+1 while(os.clock()<i) do end
-end
-
-function ARRAY2D(w,h)
- local t = {w=w,h=h}
- for y=1,h do
- t[y] = {}
- for x=1,w do
- t[y][x]=0
- end
- end
- return t
-end
-
-_CELLS = {}
-
--- give birth to a "shape" within the cell array
-function _CELLS:spawn(shape,left,top)
- for y=0,shape.h-1 do
- for x=0,shape.w-1 do
- self[top+y][left+x] = shape[y*shape.w+x+1]
- end
- 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
- for y=1,self.h do
- for x=1,self.w do
- out=out..(((self[y][x]>0) and ALIVE) or DEAD)
- end
- out=out.."\n"
- 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("Life - generation ",gen,"\n")
- gen=gen+1
- if gen>2000 then break end
- --delay() -- no delay
- end
-end
-
-LIFE(40,20)
diff --git a/test/luac.lua b/test/luac.lua
deleted file mode 100644
index 96a0a97c..00000000
--- a/test/luac.lua
+++ /dev/null
@@ -1,7 +0,0 @@
--- bare-bones luac in Lua
--- usage: lua luac.lua file.lua
-
-assert(arg[1]~=nil and arg[2]==nil,"usage: lua luac.lua file.lua")
-f=assert(io.open("luac.out","wb"))
-assert(f:write(string.dump(assert(loadfile(arg[1])))))
-assert(f:close())
diff --git a/test/printf.lua b/test/printf.lua
deleted file mode 100644
index 58c63ff5..00000000
--- a/test/printf.lua
+++ /dev/null
@@ -1,7 +0,0 @@
--- an implementation of printf
-
-function printf(...)
- io.write(string.format(...))
-end
-
-printf("Hello %s from %s on %s\n",os.getenv"USER" or "there",_VERSION,os.date())
diff --git a/test/readonly.lua b/test/readonly.lua
deleted file mode 100644
index 85c0b4e0..00000000
--- a/test/readonly.lua
+++ /dev/null
@@ -1,12 +0,0 @@
--- make global variables readonly
-
-local f=function (t,i) error("cannot redefine global variable `"..i.."'",2) end
-local g={}
-local G=getfenv()
-setmetatable(g,{__index=G,__newindex=f})
-setfenv(1,g)
-
--- an example
-rawset(g,"x",3)
-x=2
-y=1 -- cannot redefine `y'
diff --git a/test/sieve.lua b/test/sieve.lua
deleted file mode 100644
index e27c1a20..00000000
--- a/test/sieve.lua
+++ /dev/null
@@ -1,29 +0,0 @@
--- the sieve of of Eratosthenes programmed with coroutines
--- typical usage: lua -e N=1000 sieve.lua | column
-
--- generate all the numbers from 2 to n
-function gen (n)
- return coroutine.wrap(function ()
- for i=2,n do coroutine.yield(i) end
- end)
-end
-
--- filter the numbers generated by `g', removing multiples of `p'
-function filter (p, g)
- return coroutine.wrap(function ()
- while 1 do
- local n = g()
- if n == nil then return end
- if n % p ~= 0 then coroutine.yield(n) end
- end
- end)
-end
-
-N=N or 1000 -- from command line
-x = gen(N) -- generate primes up to N
-while 1 do
- local n = x() -- pick a number until done
- if n == nil then break end
- print(n) -- must be a prime number
- x = filter(n, x) -- now remove its multiples
-end
diff --git a/test/sort.lua b/test/sort.lua
deleted file mode 100644
index 0bcb15f8..00000000
--- a/test/sort.lua
+++ /dev/null
@@ -1,66 +0,0 @@
--- 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
- local m=math.random(u-(l-1))+l-1 -- choose a random pivot in range l..u
- x[l],x[m]=x[m],x[l] -- swap pivot to first position
- local t=x[l] -- pivot value
- m=l
- local i=l+1
- while i<=u do
- -- invariant: x[l+1..m] < t <= x[m+1..i-1]
- if f(x[i],t) then
- m=m+1
- x[m],x[i]=x[i],x[m] -- swap x[i] and x[m]
- end
- i=i+1
- end
- x[l],x[m]=x[m],x[l] -- swap pivot to a valid place
- -- x[l+1..m-1] < x[m] <= x[m+1..u]
- qsort(x,l,m-1,f)
- qsort(x,m+1,u,f)
- end
-end
-
-function selectionsort(x,n,f)
- local i=1
- while i<=n do
- local m,j=i,i+1
- while j<=n do
- if f(x[j],x[m]) then m=j end
- j=j+1
- end
- x[i],x[m]=x[m],x[i] -- swap x[i] and x[m]
- i=i+1
- end
-end
-
-function show(m,x)
- io.write(m,"\n\t")
- local i=1
- while x[i] do
- io.write(x[i])
- i=i+1
- if x[i] then io.write(",") end
- end
- io.write("\n")
-end
-
-function testsorts(x)
- local n=1
- while x[n] do n=n+1 end; n=n-1 -- count elements
- show("original",x)
- qsort(x,1,n,function (x,y) return x<y end)
- show("after quicksort",x)
- selectionsort(x,n,function (x,y) return x>y end)
- show("after reverse selection sort",x)
- qsort(x,1,n,function (x,y) return x<y end)
- show("after quicksort again",x)
-end
-
--- 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
deleted file mode 100644
index 235089c0..00000000
--- a/test/table.lua
+++ /dev/null
@@ -1,12 +0,0 @@
--- make table, grouping all data for the same item
--- input is 2 columns (item, data)
-
-local A
-while 1 do
- local l=io.read()
- if l==nil then break end
- local _,_,a,b=string.find(l,'"?([_%w]+)"?%s*(.*)$')
- if a~=A then A=a io.write("\n",a,":") end
- io.write(" ",b)
-end
-io.write("\n")
diff --git a/test/trace-calls.lua b/test/trace-calls.lua
deleted file mode 100644
index 6d7a7b3b..00000000
--- a/test/trace-calls.lua
+++ /dev/null
@@ -1,32 +0,0 @@
--- trace calls
--- example: lua -ltrace-calls bisect.lua
-
-local level=0
-
-local function hook(event)
- local t=debug.getinfo(3)
- io.write(level," >>> ",string.rep(" ",level))
- if t~=nil and t.currentline>=0 then io.write(t.short_src,":",t.currentline," ") end
- t=debug.getinfo(2)
- if event=="call" then
- level=level+1
- else
- level=level-1 if level<0 then level=0 end
- end
- if t.what=="main" then
- if event=="call" then
- io.write("begin ",t.short_src)
- else
- io.write("end ",t.short_src)
- end
- elseif t.what=="Lua" then
--- table.foreach(t,print)
- io.write(event," ",t.name or "(Lua)"," <",t.linedefined,":",t.short_src,">")
- else
- io.write(event," ",t.name or "(C)"," [",t.what,"] ")
- end
- io.write("\n")
-end
-
-debug.sethook(hook,"cr")
-level=0
diff --git a/test/trace-globals.lua b/test/trace-globals.lua
deleted file mode 100644
index 295e670c..00000000
--- a/test/trace-globals.lua
+++ /dev/null
@@ -1,38 +0,0 @@
--- trace assigments to global variables
-
-do
- -- a tostring that quotes strings. note the use of the original tostring.
- local _tostring=tostring
- local tostring=function(a)
- if type(a)=="string" then
- return string.format("%q",a)
- else
- return _tostring(a)
- end
- end
-
- local log=function (name,old,new)
- local t=debug.getinfo(3,"Sl")
- local line=t.currentline
- io.write(t.short_src)
- if line>=0 then io.write(":",line) end
- io.write(": ",name," is now ",tostring(new)," (was ",tostring(old),")","\n")
- end
-
- local g={}
- local set=function (t,name,value)
- log(name,g[name],value)
- g[name]=value
- end
- setmetatable(getfenv(),{__index=g,__newindex=set})
-end
-
--- an example
-
-a=1
-b=2
-a=10
-b=20
-b=nil
-b=200
-print(a,b,c)
diff --git a/test/xd.lua b/test/xd.lua
deleted file mode 100644
index 8b420394..00000000
--- a/test/xd.lua
+++ /dev/null
@@ -1,15 +0,0 @@
--- hex dump
--- usage: lua xd.lua < file
-
-local N=16
-local offset=0
-while true do
- local s=io.read(N)
- if s==nil then return end
- io.write(string.format("%08X ",offset))
- string.gsub(s,"(.)",
- function (c) io.write(string.format("%02X ",string.byte(c))) end)
- io.write(string.rep(" ",3*(N-string.len(s))))
- io.write(" ",string.gsub(s,"%c","."),"\n")
- offset=offset+N
-end