summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLua Team <team@lua.org>2014-03-21 12:00:00 +0000
committerrepogen <>2014-03-21 12:00:00 +0000
commit05a6ab2dd30e7707c7d5424b905eb93a1dd5c5b2 (patch)
treef24db6e4692bebf7031418ff9c3b51b345016023
parent87cc247b6b22184fba47184c218a642ea7a49e96 (diff)
downloadlua-github-5.3.0-work2.tar.gz
Lua 5.3.0-work25.3.0-work2
-rw-r--r--README2
-rw-r--r--doc/alert.pngbin0 -> 1411 bytes
-rw-r--r--doc/contents.html71
-rw-r--r--doc/lua.css31
-rw-r--r--doc/manual.css9
-rw-r--r--doc/manual.html1625
-rw-r--r--doc/readme.html93
-rw-r--r--src/.fix2
-rw-r--r--src/Makefile9
-rw-r--r--src/lapi.c136
-rw-r--r--src/lauxlib.c130
-rw-r--r--src/lauxlib.h30
-rw-r--r--src/lbaselib.c16
-rw-r--r--src/lbitlib.c59
-rw-r--r--src/lcode.c101
-rw-r--r--src/lcode.h10
-rw-r--r--src/ldblib.c10
-rw-r--r--src/ldebug.c33
-rw-r--r--src/ldebug.h4
-rw-r--r--src/ldo.c43
-rw-r--r--src/ldump.c287
-rw-r--r--src/lfunc.c93
-rw-r--r--src/lfunc.h27
-rw-r--r--src/lgc.c623
-rw-r--r--src/lgc.h79
-rw-r--r--src/linit.c3
-rw-r--r--src/liolib.c119
-rw-r--r--src/llex.c122
-rw-r--r--src/llex.h4
-rw-r--r--src/llimits.h11
-rw-r--r--src/lmathlib.c15
-rw-r--r--src/loadlib.c34
-rw-r--r--src/lobject.c126
-rw-r--r--src/lobject.h45
-rw-r--r--src/lopcodes.c22
-rw-r--r--src/lopcodes.h12
-rw-r--r--src/loslib.c60
-rw-r--r--src/lparser.c74
-rw-r--r--src/lparser.h3
-rw-r--r--src/lstate.c85
-rw-r--r--src/lstate.h49
-rw-r--r--src/lstring.c101
-rw-r--r--src/lstring.h8
-rw-r--r--src/lstrlib.c227
-rw-r--r--src/ltable.c74
-rw-r--r--src/ltable.h7
-rw-r--r--src/ltablib.c4
-rw-r--r--src/ltm.c29
-rw-r--r--src/ltm.h14
-rw-r--r--src/lua.c100
-rw-r--r--src/lua.h46
-rw-r--r--src/luac.c2
-rw-r--r--src/luaconf.h120
-rw-r--r--src/lualib.h5
-rw-r--r--src/lundump.c416
-rw-r--r--src/lundump.h27
-rw-r--r--src/lutf8lib.c240
-rw-r--r--src/lvm.c181
-rw-r--r--src/lvm.h5
-rw-r--r--src/lzio.h3
60 files changed, 3262 insertions, 2654 deletions
diff --git a/README b/README
index 70ec4137..2d5ee2c9 100644
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
-This is Lua 5.3.0 (work1), released on 5 Jul 2013.
+This is Lua 5.3.0 (work2), released on 21 Mar 2014.
For installation instructions, license details, and
further information about Lua, see doc/readme.html.
diff --git a/doc/alert.png b/doc/alert.png
new file mode 100644
index 00000000..49380746
--- /dev/null
+++ b/doc/alert.png
Binary files differ
diff --git a/doc/contents.html b/doc/contents.html
index fb115939..f157545d 100644
--- a/doc/contents.html
+++ b/doc/contents.html
@@ -21,6 +21,10 @@ Lua 5.3 Reference Manual
</H1>
<P>
+<IMG SRC="alert.png" ALIGN="absbottom">
+<EM>All details 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/pil/">Programming in Lua</A>.
@@ -33,7 +37,7 @@ For a complete introduction to Lua programming, see the book
<A HREF="#index">index</A>
<HR>
<SMALL>
-Copyright &copy; 2011&ndash;2013 Lua.org, PUC-Rio.
+Copyright &copy; 2011&ndash;2014 Lua.org, PUC-Rio.
Freely available under the terms of the
<A HREF="http://www.lua.org/license.html">Lua license</A>.
</SMALL>
@@ -73,15 +77,16 @@ Freely available under the terms of the
<LI><A HREF="manual.html#3.4">3.4 &ndash; Expressions</A>
<UL>
<LI><A HREF="manual.html#3.4.1">3.4.1 &ndash; Arithmetic Operators</A>
-<LI><A HREF="manual.html#3.4.2">3.4.2 &ndash; Coercions and Conversions</A>
-<LI><A HREF="manual.html#3.4.3">3.4.3 &ndash; Relational Operators</A>
-<LI><A HREF="manual.html#3.4.4">3.4.4 &ndash; Logical Operators</A>
-<LI><A HREF="manual.html#3.4.5">3.4.5 &ndash; Concatenation</A>
-<LI><A HREF="manual.html#3.4.6">3.4.6 &ndash; The Length Operator</A>
-<LI><A HREF="manual.html#3.4.7">3.4.7 &ndash; Precedence</A>
-<LI><A HREF="manual.html#3.4.8">3.4.8 &ndash; Table Constructors</A>
-<LI><A HREF="manual.html#3.4.9">3.4.9 &ndash; Function Calls</A>
-<LI><A HREF="manual.html#3.4.10">3.4.10 &ndash; Function Definitions</A>
+<LI><A HREF="manual.html#3.4.2">3.4.2 &ndash; Bitwise Operators</A>
+<LI><A HREF="manual.html#3.4.3">3.4.3 &ndash; Coercions and Conversions</A>
+<LI><A HREF="manual.html#3.4.4">3.4.4 &ndash; Relational Operators</A>
+<LI><A HREF="manual.html#3.4.5">3.4.5 &ndash; Logical Operators</A>
+<LI><A HREF="manual.html#3.4.6">3.4.6 &ndash; Concatenation</A>
+<LI><A HREF="manual.html#3.4.7">3.4.7 &ndash; The Length Operator</A>
+<LI><A HREF="manual.html#3.4.8">3.4.8 &ndash; Precedence</A>
+<LI><A HREF="manual.html#3.4.9">3.4.9 &ndash; Table Constructors</A>
+<LI><A HREF="manual.html#3.4.10">3.4.10 &ndash; Function Calls</A>
+<LI><A HREF="manual.html#3.4.11">3.4.11 &ndash; Function Definitions</A>
</UL>
<LI><A HREF="manual.html#3.5">3.5 &ndash; Visibility Rules</A>
</UL>
@@ -113,9 +118,9 @@ Freely available under the terms of the
<UL>
<LI><A HREF="manual.html#6.4.1">6.4.1 &ndash; Patterns</A>
</UL>
-<LI><A HREF="manual.html#6.5">6.5 &ndash; Table Manipulation</A>
-<LI><A HREF="manual.html#6.6">6.6 &ndash; Mathematical Functions</A>
-<LI><A HREF="manual.html#6.7">6.7 &ndash; Bitwise Operations</A>
+<LI><A HREF="manual.html#6.5">6.5 &ndash; UTF-8 Support</A>
+<LI><A HREF="manual.html#6.6">6.6 &ndash; Table Manipulation</A>
+<LI><A HREF="manual.html#6.7">6.7 &ndash; Mathematical Functions</A>
<LI><A HREF="manual.html#6.8">6.8 &ndash; Input and Output Facilities</A>
<LI><A HREF="manual.html#6.9">6.9 &ndash; Operating System Facilities</A>
<LI><A HREF="manual.html#6.10">6.10 &ndash; The Debug Library</A>
@@ -168,20 +173,6 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-xpcall">xpcall</A><BR>
<P>
-<A HREF="manual.html#pdf-bit32.arshift">bit32.arshift</A><BR>
-<A HREF="manual.html#pdf-bit32.band">bit32.band</A><BR>
-<A HREF="manual.html#pdf-bit32.bnot">bit32.bnot</A><BR>
-<A HREF="manual.html#pdf-bit32.bor">bit32.bor</A><BR>
-<A HREF="manual.html#pdf-bit32.btest">bit32.btest</A><BR>
-<A HREF="manual.html#pdf-bit32.bxor">bit32.bxor</A><BR>
-<A HREF="manual.html#pdf-bit32.extract">bit32.extract</A><BR>
-<A HREF="manual.html#pdf-bit32.lrotate">bit32.lrotate</A><BR>
-<A HREF="manual.html#pdf-bit32.lshift">bit32.lshift</A><BR>
-<A HREF="manual.html#pdf-bit32.replace">bit32.replace</A><BR>
-<A HREF="manual.html#pdf-bit32.rrotate">bit32.rrotate</A><BR>
-<A HREF="manual.html#pdf-bit32.rshift">bit32.rshift</A><BR>
-
-<P>
<A HREF="manual.html#pdf-coroutine.create">coroutine.create</A><BR>
<A HREF="manual.html#pdf-coroutine.resume">coroutine.resume</A><BR>
<A HREF="manual.html#pdf-coroutine.running">coroutine.running</A><BR>
@@ -191,18 +182,19 @@ Freely available under the terms of the
<P>
<A HREF="manual.html#pdf-debug.debug">debug.debug</A><BR>
-<A HREF="manual.html#pdf-debug.getuservalue">debug.getuservalue</A><BR>
<A HREF="manual.html#pdf-debug.gethook">debug.gethook</A><BR>
<A HREF="manual.html#pdf-debug.getinfo">debug.getinfo</A><BR>
<A HREF="manual.html#pdf-debug.getlocal">debug.getlocal</A><BR>
<A HREF="manual.html#pdf-debug.getmetatable">debug.getmetatable</A><BR>
<A HREF="manual.html#pdf-debug.getregistry">debug.getregistry</A><BR>
<A HREF="manual.html#pdf-debug.getupvalue">debug.getupvalue</A><BR>
-<A HREF="manual.html#pdf-debug.setuservalue">debug.setuservalue</A><BR>
+<A HREF="manual.html#pdf-debug.getuservalue">debug.getuservalue</A><BR>
+<A HREF="manual.html#pdf-debug.numbits">debug.numbits</A><BR>
<A HREF="manual.html#pdf-debug.sethook">debug.sethook</A><BR>
<A HREF="manual.html#pdf-debug.setlocal">debug.setlocal</A><BR>
<A HREF="manual.html#pdf-debug.setmetatable">debug.setmetatable</A><BR>
<A HREF="manual.html#pdf-debug.setupvalue">debug.setupvalue</A><BR>
+<A HREF="manual.html#pdf-debug.setuservalue">debug.setuservalue</A><BR>
<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>
@@ -267,6 +259,8 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-math.sqrt">math.sqrt</A><BR>
<A HREF="manual.html#pdf-math.tan">math.tan</A><BR>
<A HREF="manual.html#pdf-math.tanh">math.tanh</A><BR>
+<A HREF="manual.html#pdf-math.type">math.type</A><BR>
+
<P>
<A HREF="manual.html#pdf-os.clock">os.clock</A><BR>
@@ -302,9 +296,13 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-string.len">string.len</A><BR>
<A HREF="manual.html#pdf-string.lower">string.lower</A><BR>
<A HREF="manual.html#pdf-string.match">string.match</A><BR>
+<A HREF="manual.html#pdf-string.packfloat">string.packfloat</A><BR>
+<A HREF="manual.html#pdf-string.packint">string.packint</A><BR>
<A HREF="manual.html#pdf-string.rep">string.rep</A><BR>
<A HREF="manual.html#pdf-string.reverse">string.reverse</A><BR>
<A HREF="manual.html#pdf-string.sub">string.sub</A><BR>
+<A HREF="manual.html#pdf-string.unpackfloat">string.unpackfloat</A><BR>
+<A HREF="manual.html#pdf-string.unpackint">string.unpackint</A><BR>
<A HREF="manual.html#pdf-string.upper">string.upper</A><BR>
<P>
@@ -315,6 +313,14 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-table.sort">table.sort</A><BR>
<A HREF="manual.html#pdf-table.unpack">table.unpack</A><BR>
+<P>
+<A HREF="manual.html#pdf-utf8.char">utf8.char</A><BR>
+<A HREF="manual.html#pdf-utf8.charpatt">utf8.charpatt</A><BR>
+<A HREF="manual.html#pdf-utf8.codepoint">utf8.codepoint</A><BR>
+<A HREF="manual.html#pdf-utf8.codes">utf8.codes</A><BR>
+<A HREF="manual.html#pdf-utf8.len">utf8.len</A><BR>
+<A HREF="manual.html#pdf-utf8.offset">utf8.offset</A><BR>
+
</TD>
<TD>
<H3>C API</H3>
@@ -364,6 +370,7 @@ Freely available under the terms of the
<A HREF="manual.html#lua_isboolean">lua_isboolean</A><BR>
<A HREF="manual.html#lua_iscfunction">lua_iscfunction</A><BR>
<A HREF="manual.html#lua_isfunction">lua_isfunction</A><BR>
+<A HREF="manual.html#lua_isinteger">lua_isinteger</A><BR>
<A HREF="manual.html#lua_islightuserdata">lua_islightuserdata</A><BR>
<A HREF="manual.html#lua_isnil">lua_isnil</A><BR>
<A HREF="manual.html#lua_isnone">lua_isnone</A><BR>
@@ -422,6 +429,7 @@ Freely available under the terms of the
<A HREF="manual.html#lua_setupvalue">lua_setupvalue</A><BR>
<A HREF="manual.html#lua_setuservalue">lua_setuservalue</A><BR>
<A HREF="manual.html#lua_status">lua_status</A><BR>
+<A HREF="manual.html#lua_strtonum">lua_strtonum</A><BR>
<A HREF="manual.html#lua_toboolean">lua_toboolean</A><BR>
<A HREF="manual.html#lua_tocfunction">lua_tocfunction</A><BR>
<A HREF="manual.html#lua_tointeger">lua_tointeger</A><BR>
@@ -451,6 +459,7 @@ Freely available under the terms of the
<P>
<A HREF="manual.html#luaL_Buffer">luaL_Buffer</A><BR>
<A HREF="manual.html#luaL_Reg">luaL_Reg</A><BR>
+<A HREF="manual.html#luaL_Stream">luaL_Stream</A><BR>
<P>
<A HREF="manual.html#luaL_addchar">luaL_addchar</A><BR>
@@ -525,10 +534,10 @@ Freely available under the terms of the
<HR>
<SMALL CLASS="footer">
Last update:
-Fri Jul 5 23:06:54 BRT 2013
+Fri Mar 21 17:34:12 BRT 2014
</SMALL>
<!--
-Last change: updated for Lua 5.3.0 (work1)
+Last change: updated for Lua 5.3.0 (work2)
-->
</BODY>
diff --git a/doc/lua.css b/doc/lua.css
index 240e85eb..3d2443ac 100644
--- a/doc/lua.css
+++ b/doc/lua.css
@@ -1,30 +1,37 @@
+html {
+ background-color: #F8F8F8 ;
+}
+
body {
+ border: solid #a0a0a0 1px ;
+ border-radius: 20px ;
+ padding: 26px ;
+ margin: 16px ;
color: #000000 ;
background-color: #FFFFFF ;
font-family: Helvetica, Arial, sans-serif ;
text-align: justify ;
- margin-right: 30px ;
- margin-left: 30px ;
}
h1, h2, h3, h4 {
font-family: Verdana, Geneva, sans-serif ;
font-weight: normal ;
- font-style: italic ;
+ font-style: normal ;
}
h2 {
padding-top: 0.4em ;
padding-bottom: 0.4em ;
- padding-left: 1em ;
- padding-right: 1em ;
- background-color: #E0E0FF ;
+ padding-left: 0.8em ;
+ padding-right: 0.8em ;
+ background-color: #D0D0FF ;
border-radius: 8px ;
+ border: solid #a0a0a0 1px ;
}
h3 {
padding-left: 0.5em ;
- border-left: solid #E0E0FF 1em ;
+ border-left: solid #D0D0FF 1em ;
}
table h3 {
@@ -45,7 +52,7 @@ a:visited {
a:link:hover, a:visited:hover {
color: #000080 ;
- background-color: #E0E0FF ;
+ background-color: #D0D0FF ;
}
a:link:active, a:visited:active {
@@ -57,17 +64,23 @@ hr {
height: 1px ;
color: #a0a0a0 ;
background-color: #a0a0a0 ;
+ display: none ;
+}
+
+table hr {
+ display: block ;
}
:target {
background-color: #F8F8F8 ;
padding: 8px ;
border: solid #a0a0a0 2px ;
+ border-radius: 8px ;
}
.footer {
color: gray ;
- font-size: small ;
+ font-size: x-small ;
}
input[type=text] {
diff --git a/doc/manual.css b/doc/manual.css
index 269bd435..ca613cd9 100644
--- a/doc/manual.css
+++ b/doc/manual.css
@@ -16,11 +16,12 @@ span.apii {
}
p+h1, ul+h1 {
+ font-style: normal ;
padding-top: 0.4em ;
padding-bottom: 0.4em ;
- padding-left: 24px ;
- margin-left: -24px ;
- background-color: #E0E0FF ;
+ padding-left: 16px ;
+ margin-left: -16px ;
+ background-color: #D0D0FF ;
border-radius: 8px ;
+ border: solid #000080 1px ;
}
-
diff --git a/doc/manual.html b/doc/manual.html
index eeacdcc9..aa1afa28 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -16,10 +16,15 @@
Lua 5.3 Reference Manual
</h1>
+<P>
+<IMG SRC="alert.png" ALIGN="absbottom">
+<EM>All details may change in the final version.</EM>
+<P>
+
by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
<p>
<small>
-Copyright &copy; 2011&ndash;2013 Lua.org, PUC-Rio.
+Copyright &copy; 2011&ndash;2014 Lua.org, PUC-Rio.
Freely available under the terms of the
<a href="http://www.lua.org/license.html">Lua license</a>.
</small>
@@ -33,7 +38,7 @@ Freely available under the terms of the
<!-- ====================================================================== -->
<p>
-<!-- $Id: manual.of,v 1.105 2013/07/05 18:48:52 roberto Exp $ -->
+<!-- $Id: manual.of,v 1.114 2014/03/21 18:32:52 roberto Exp $ -->
@@ -119,11 +124,8 @@ 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 both integer numbers and
-real (floating-point) numbers.
-Standard Lua uses 64-bit integers and double-precision floats,
-but it is easy to compile Lua so that it
-uses 32-bit integers and single-precision floats.
+<em>Number</em> represents both
+integral numbers and real (floating-point) numbers.
<em>String</em> represents immutable sequences of bytes.
Lua is 8-bit clean:
@@ -132,9 +134,26 @@ including embedded zeros ('<code>\0</code>').
<p>
+The type <em>number</em> uses two internal representations,
+one called <em>integer</em> and the other called <em>float</em>.
+Lua has explicit rules about when each representation is used,
+but it also converts between them automatically as needed (see <a href="#3.4.3">&sect;3.4.3</a>).
+Therefore,
+the programmer has the option of mostly ignore the difference
+between integers and floats
+or assume complete control about the representation of each value.
+Standard Lua uses 64-bit integers and double-precision (64-bit) floats,
+but you can also compile Lua so that it
+uses 32-bit integers and/or single-precision (32-bit) floats.
+The option with 32 bits both for integers and floats
+(what is called <em>Small Lua</em>) is particularly attractive
+for small machines.
+
+
+<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>).
+(see <a href="#3.4.10">&sect;3.4.10</a>).
<p>
@@ -183,14 +202,14 @@ 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>).
+(see <a href="#3.4.9">&sect;3.4.9</a>).
<p>
We use the term <em>sequence</em> to denote a table where
the set of all positive numeric keys is equal to <em>{1..n}</em>
for some integer <em>n</em>,
-which is called the length of the sequence (see <a href="#3.4.6">&sect;3.4.6</a>).
+which is called the length of the sequence (see <a href="#3.4.7">&sect;3.4.7</a>).
<p>
@@ -199,7 +218,7 @@ the values of table fields can be of any type.
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>).
+Thus tables can also carry <em>methods</em> (see <a href="#3.4.11">&sect;3.4.11</a>).
<p>
@@ -212,6 +231,18 @@ if and only if <code>i</code> and <code>j</code> are raw equal
<p>
+In particular, floats with integral values
+are equal to their respective integers
+(e.g., <code>1.0 == 1</code>).
+To avoid ambiguities,
+any float with integral value used as a key
+is converted to its respective integer.
+For instance, if you write <code>a[2.0] = true</code>,
+the actual key inserted into the table will be the
+integer <code>2</code>.
+
+
+<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.
@@ -382,57 +413,37 @@ but the string library sets a metatable for the string type (see <a href="#6.4">
<p>
-A metatable controls how an object behaves in arithmetic operations,
-order comparisons, concatenation, length operation, and indexing.
+A metatable controls how an object behaves in
+arithmetic and bitwise operations,
+order comparisons, concatenation, length operation, calls, and indexing.
A metatable also can define a function to be called
when a userdata or a table is garbage collected.
-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
+A detailed list of events controlled by metatables is given next.
+Each operation is identified by its corresponding event name.
+The key for each event 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>".
-
-
-<p>
-The semantics of these operations is better explained by a Lua function
-describing how the interpreter executes the operation.
-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
+Note that queries for metamethods are always raw;
+the access to a metamethod does not invoke other metamethods.
+You can emulate how Lua queries a metamethod for an object <code>obj</code>
+with the following code:
<pre>
- metatable(obj)[event]
-</pre><p>
-This should be read as
-
-<pre>
- rawget(getmetatable(obj) or {}, event)
-</pre><p>
-This means that the access to a metamethod does not invoke other metamethods,
-and access to objects with no metatables does not fail
-(it simply results in <b>nil</b>).
-
+ rawget(getmetatable(obj) or {}, event_name)
+</pre>
<p>
-For the unary <code>-</code> and <code>#</code> operators,
-the metamethod is called with a dummy 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.)
+For the unary minus and the bitwise not operators,
+the metamethod is computed and called with a dummy second operand,
+equal to the first one.
+This extra operand is only to simplify Lua's internals
+(by making these operators behave like a binary operation)
+and may be removed in future versions.
+(For most uses this extra operand is irrelevant.)
@@ -441,39 +452,19 @@ in the following code.
<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>
+If any operand for an addition is not a number
+(nor a string coercible to a number),
+Lua will try to call a metamethod.
+First, Lua will check the first operand (even if it is valid).
+If that operand does not define a metamethod for the "<code>__add</code>" event,
+then Lua will check the second operand.
+If Lua cannot find a metamethod,
+it raises an error.
+Otherwise,
+it calls the metamethod with the two operands as arguments,
+and the result of the call
+(adjusted to one value)
+is the result of the operation.
</li>
<li><b>"sub": </b>
@@ -497,263 +488,177 @@ Behavior similar to the "add" operation.
<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.
+Behavior similar to the "add" 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.
+Behavior similar to the "add" operation.
</li>
<li><b>"unm": </b>
-the unary <code>-</code> operation.
+the <code>-</code> (unary minus) operation.
+Behavior similar to the "add" operation.
+</li>
-<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><b>"idiv": </b>
+the <code>//</code> (integer division) operation.
+
+Behavior similar to the "add" operation,
+except that Lua will try a metamethod
+if any operator is neither an integer
+nor a value coercible to an integer (see <a href="#3.4.3">&sect;3.4.3</a>).
</li>
-<li><b>"concat": </b>
-the <code>..</code> (concatenation) operation.
+<li><b>"band": </b>
+the <code>&amp;</code> (bitwise and) operation.
+Behavior similar to the "idiv" operation.
+</li>
-<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><b>"bor": </b>
+the <code>|</code> (bitwise or) operation.
+
+Behavior similar to the "band" operation.
</li>
-<li><b>"len": </b>
-the <code>#</code> operation.
+<li><b>"bxor": </b>
+the <code>~</code> (bitwise exclusive or) operation.
+Behavior similar to the "band" operation.
+</li>
-<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><b>"bnot": </b>
+the <code>~</code> (bitwise unary not) operation.
+
+Behavior similar to the "band" operation.
</li>
-<li><b>"eq": </b>
-the <code>==</code> operation.
+<li><b>"shl": </b>
+the <code>&lt;&lt;</code> (bitwise left shift) 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,
-and the values are either tables or full userdata.
+Behavior similar to the "band" operation.
+</li>
-<pre>
- function getequalhandler (op1, op2)
- if type(op1) ~= type(op2) or
- (type(op1) ~= "table" and type(op1) ~= "userdata") then
- return nil -- different values
- end
- local mm1 = metatable(op1).__eq
- local mm2 = metatable(op2).__eq
- if mm1 == mm2 then return mm1 else return nil end
- end
-</pre><p>
-The "eq" event is defined as follows:
+<li><b>"shr": </b>
+the <code>&gt;&gt;</code> (bitwise right shift) operation.
-<pre>
- function eq_event (op1, op2)
- if op1 == op2 then -- primitive equal?
- return true -- values are equal
- end
- -- try metamethod
- local h = getequalhandler(op1, op2)
- if h then
- return not not h(op1, op2)
- else
- return false
- end
- end
-</pre><p>
-Note that the result is always a boolean.
+Behavior similar to the "band" operation.
</li>
-<li><b>"lt": </b>
-the <code>&lt;</code> operation.
+<li><b>"concat": </b>
+the <code>..</code> (concatenation) operation.
+Behavior similar to the "add" operation,
+except that Lua will try a metamethod
+if any operator is neither a string nor a number
+(which is always coercible to a string).
+</li>
-<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 not not h(op1, op2)
- else
- error(&middot;&middot;&middot;)
- end
- end
- end
-</pre><p>
-Note that the result is always a boolean.
+<li><b>"len": </b>
+the <code>#</code> (length) operation.
+
+If the object is not a string,
+Lua will try its metamethod.
+If there is a metamethod,
+Lua calls it with the object as argument,
+and the result of the call
+(always adjusted to one value)
+is the result of the operation.
+If there is no metamethod but the object is a table,
+then Lua uses the table length operation (see <a href="#3.4.7">&sect;3.4.7</a>).
+Otherwise, Lua raises an error.
</li>
-<li><b>"le": </b>
-the <code>&lt;=</code> operation.
+<li><b>"eq": </b>
+the <code>==</code> (equal) operation.
+Lua will try a metamethod only when the values
+being compared are both either tables or full userdata,
+both have the same metamethod,
+and they are not primitively equal.
+The result of the call is always converted to a boolean.
+</li>
-<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 not not 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><b>"lt": </b>
+the <code>&lt;</code> (less than) operation.
+Behavior similar to the "add" operation,
+except that the result of the call is always converted to a boolean.
+</li>
-<p>
+<li><b>"le": </b>
+the <code>&lt;=</code> (less equal) operation.
+
+Unlike other operations,
+The less-equal operation can use two different events.
+First, Lua looks for the "<code>__le</code>" metamethod in both operands,
+like in the "add" operation.
+If it cannot find such a metamethod,
+then it will try the "<code>__lt</code>" event,
+assuming that <code>a &lt;= b</code> is equivalent to <code>not (b &lt; a)</code>.
As with the other comparison operators,
the result is always a boolean.
</li>
<li><b>"index": </b>
The indexing access <code>table[key]</code>.
-Note that the metamethod is tried only
+
+This event happens when <code>table</code> is not a table or
when <code>key</code> is not present in <code>table</code>.
-(When <code>table</code> is not a table,
-no key is ever present,
-so the metamethod is always tried.)
+The metamethod is looked up in <code>table</code>.
-<pre>
- function gettable_event (table, key)
- local h
- if type(table) == "table" then
- local v = rawget(table, key)
- -- if key is present, return raw value
- 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>
+<p>
+Despite the name,
+the metamethod for this event can be either a function or a table.
+If it is a function,
+it is called with <code>table</code> and <code>key</code> as arguments.
+If it is a table,
+the final result is the result of indexing this table with <code>key</code>.
+(This indexing is regular, not raw,
+and therefore can trigger another metamethod.)
</li>
<li><b>"newindex": </b>
The indexing assignment <code>table[key] = value</code>.
-Note that the metamethod is tried only
+
+Like the index event,
+this event happens when <code>table</code> is not a table or
when <code>key</code> is not present in <code>table</code>.
+The metamethod is looked up in <code>table</code>.
-<pre>
- function settable_event (table, key, value)
- local h
- if type(table) == "table" then
- local v = rawget(table, key)
- -- if key is present, do raw assignment
- 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>
+<p>
+Again like with indexing,
+the metamethod for this event can be either a function or a table.
+If it is a function,
+it is called with <code>table</code>, <code>key</code>, and <code>value</code> as arguments.
+If it is a table,
+Lua does an indexing assignment to this table with the same key and value.
+(This assignment is regular, not raw,
+and therefore can trigger another metamethod.)
+
+
+<p>
+Whenever there is a metamethod,
+Lua does not perform the primitive assignment.
+(If necessary,
+the metamethod itself can call <a href="#pdf-rawset"><code>rawset</code></a>
+to do the assignment.)
</li>
<li><b>"call": </b>
-called when Lua calls a value.
+The call operation <code>func(args)</code>.
-
-<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>
+This event happens when Lua tries to call a non-function value
+(that is, <code>func</code> is not a function).
+The metamethod is looked up in <code>func</code>.
+If present,
+the metamethod is called with <code>func</code> as its first argument,
+followed by the arguments of the original call (<code>args</code>).
</li>
</ul>
@@ -800,7 +705,8 @@ 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
+You should not use values smaller than 100,
+as they make the collector too slow and
can result in the collector never finishing a cycle.
The default is 200,
which means that the collector runs at "twice"
@@ -825,21 +731,6 @@ You can also use these functions to control
the collector directly (e.g., stop and restart it).
-<p>
-As an experimental feature in Lua 5.3,
-you can change the collector's operation mode
-from incremental to <em>generational</em>.
-A <em>generational collector</em> assumes that most objects die young,
-and therefore it traverses only young (recently created) objects.
-This behavior can reduce the time used by the collector,
-but also increases memory usage (as old dead objects may accumulate).
-To mitigate this second problem,
-from time to time the generational collector performs a full collection.
-Remember that this is an experimental feature;
-you are welcome to try it,
-but check your gains.
-
-
<h3>2.5.1 &ndash; <a name="2.5.1">Garbage-Collection Metamethods</a></h3>
@@ -872,17 +763,14 @@ When a marked object becomes garbage,
it is not collected immediately by the garbage collector.
Instead, Lua puts it in a list.
After the collection,
-Lua does the equivalent of the following function
-for each object in that list:
+Lua goes through that list:
+For each object,
+it checks the object's <code>__gc</code> metamethod;
+if it is a function,
+Lua calls it with the object as its single argument.
+(If the metamethod is not a function,
+Lua simply ignores it.)
-<pre>
- function gc_event (obj)
- local h = metatable(obj).__gc
- if type(h) == "function" then
- h(obj)
- end
- end
-</pre>
<p>
At the end of each garbage-collection cycle,
@@ -1228,6 +1116,15 @@ which can be specified as '<code>\0</code>'.
<p>
+The UTF-8 encoding of a Unicode character
+can be inserted in a literal string with
+the escape sequence <code>\u{<em>XXX</em>}</code>
+(note the mandatory enclosing brackets),
+where <em>XXX</em> is a sequence of one or more hexadecimal digits
+representing the character code point.
+
+
+<p>
Literal strings can also be defined using a long format
enclosed by <em>long brackets</em>.
We define an <em>opening long bracket of level <em>n</em></em> as an opening
@@ -1290,15 +1187,15 @@ which start with <code>0x</code> or <code>0X</code>.
Hexadecimal constants also accept an optional fractional part
plus an optional binary exponent,
marked by a letter '<code>p</code>' or '<code>P</code>'.
-A numeric constant with an fractional dot or an exponent
-denotes a floating-point number;
-otherwise it denotes an integer number.
+A numeric constant with a fractional dot or an exponent
+denotes a float;
+otherwise it denotes an integer.
Examples of valid integer constants are
<pre>
3 345 0xff 0xBEBADA
</pre><p>
-Examples of valid floating-point constants are
+Examples of valid float constants are
<pre>
3.0 3.1416 314.16e-2 0.31416E1 34e1
@@ -1471,7 +1368,7 @@ a chunk is simply a block:
<p>
Lua handles a chunk as the body of an anonymous function
with a variable number of arguments
-(see <a href="#3.4.10">&sect;3.4.10</a>).
+(see <a href="#3.4.11">&sect;3.4.11</a>).
As such, chunks can define local variables,
receive arguments, and return values.
Moreover, such anonymous function is compiled as in the
@@ -1490,10 +1387,9 @@ with an interpreter for the virtual machine.
<p>
Chunks can also be precompiled into binary form;
-see program <code>luac</code> for details.
+see program <code>luac</code> and function <a href="#pdf-string.dump"><code>string.dump</code></a> for details.
Programs in source and compiled forms are interchangeable;
-Lua automatically detects the file type and acts accordingly.
-
+Lua automatically detects the file type and acts accordingly (see <a href="#pdf-load"><code>load</code></a>).
@@ -1698,7 +1594,7 @@ is equivalent to the code:
<pre>
do
- local <em>var</em>, <em>limit</em>, <em>step</em> = tonumber(<em>e1</em>), tonumber(<em>e2</em>), tonumber(<em>e3</em>)
+ local <em>var</em>, <em>limit</em>, <em>step</em> = convert(<em>e1</em>, <em>e2</em>, <em>e3</em>)
if not (<em>var</em> and <em>limit</em> and <em>step</em>) then error() end
while (<em>step</em> &gt; 0 and <em>var</em> &lt;= <em>limit</em>) or (<em>step</em> &lt;= 0 and <em>var</em> &gt;= <em>limit</em>) do
local v = <em>var</em>
@@ -1707,6 +1603,13 @@ is equivalent to the code:
end
end
</pre><p>
+where <code>convert</code> returns
+its three arguments unaltered
+if they are all integers,
+otherwise it converts them to floats.
+
+
+<p>
Note the following:
<ul>
@@ -1718,6 +1621,12 @@ They must all result in numbers.
</li>
<li>
+If any of the three control values is not an integer,
+all three values are converted to floats,
+so that the loop is done with floats.
+</li>
+
+<li>
<code><em>var</em></code>, <code><em>limit</em></code>, and <code><em>step</em></code> are invisible variables.
The names shown here are for explanatory purposes only.
</li>
@@ -1728,14 +1637,14 @@ then a step of&nbsp;1 is used.
</li>
<li>
-You can use <b>break</b> to exit a <b>for</b> loop.
+You can use <b>break</b> and <b>goto</b> to exit a <b>for</b> loop.
</li>
<li>
The loop variable <code>v</code> is local to the loop;
you cannot use its value after the <b>for</b> ends or is broken.
-If you need this value,
-assign it to another variable before breaking or exiting the loop.
+If you need its value,
+assign it to another variable before exiting the loop.
</li>
</ul>
@@ -1809,7 +1718,7 @@ 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="#3.4.9">&sect;3.4.9</a>.
+Function calls are explained in <a href="#3.4.10">&sect;3.4.10</a>.
@@ -1862,22 +1771,24 @@ The basic expressions in Lua are the following:
<p>
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>.
+function definitions are explained in <a href="#3.4.11">&sect;3.4.11</a>;
+function calls are explained in <a href="#3.4.10">&sect;3.4.10</a>;
+table constructors are explained in <a href="#3.4.9">&sect;3.4.9</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="#3.4.10">&sect;3.4.10</a>.
+they are explained in <a href="#3.4.11">&sect;3.4.11</a>.
<p>
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>).
+bitwise operators (see <a href="#3.4.2">&sect;3.4.2</a>),
+relational operators (see <a href="#3.4.4">&sect;3.4.4</a>), logical operators (see <a href="#3.4.5">&sect;3.4.5</a>),
+and the concatenation operator (see <a href="#3.4.6">&sect;3.4.6</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>).
+the unary bitwise not (see <a href="#3.4.2">&sect;3.4.2</a>),
+the unary logic <b>not</b> (see <a href="#3.4.5">&sect;3.4.5</a>),
+and the unary <em>length operator</em> (see <a href="#3.4.7">&sect;3.4.7</a>).
<p>
@@ -1939,41 +1850,33 @@ that rounds the quotient towards minus infinite (floor).
<p>
-With the exception of division, integer division, and exponentiation,
+With the exception of division and integer division,
the arithmetic operators work as follows:
If both operands are integers,
the operation is performed over integers and the result is an integer.
Otherwise, if both operands are numbers
or strings that can be converted to
-numbers (see <a href="#3.4.2">&sect;3.4.2</a>),
-then they are converted to floating-point numbers,
+numbers (see <a href="#3.4.3">&sect;3.4.3</a>),
+then they are converted to floats,
the operation is performed following the usual rules
for floating-point arithmetic
-(usually following the IEEE 754 standard),
-and the result is a floating-point number.
+(usually the IEEE 754 standard),
+and the result is a float.
<p>
-Division (<code>/</code>) always converts its operands to floating-point numbers
-and its result is always a floating-point number.
+Division (<code>/</code>) always converts its operands to floats
+and its result is always a float.
<p>
-Integer division (<code>//</code>) converts its operands to integer numbers
-(see <a href="#3.4.2">&sect;3.4.2</a>)
-and its result is always an integer number.
+Integer division (<code>//</code>) converts its operands to integers
+(see <a href="#3.4.3">&sect;3.4.3</a>)
+and its result is always an integer.
The result is always rounded towards minus infinite (floor).
<p>
-Exponentiation (<code>^</code>) checks whether both operands are integers and
-the exponent is non-negative.
-In that case, the exponentiation is performed as an integer operation
-and the result is an integer number.
-Otherwise, it is performed as a floatint-point operation (<code>pow</code>).
-
-
-<p>
In case of overflows in integer arithmetic,
all operations <em>wrap around</em>,
according to the usual rules of two-complement arithmetic.
@@ -1982,15 +1885,41 @@ according to the usual rules of two-complement arithmetic.
-<h3>3.4.2 &ndash; <a name="3.4.2">Coercions and Conversions</a></h3>
+<h3>3.4.2 &ndash; <a name="3.4.2">Bitwise Operators</a></h3><p>
+Lua supports the following bitwise operators:
+the binary <code>&amp;</code> (bitwise and),
+<code>|</code> (bitwise or), <code>~</code> (bitwise exclusive or),
+<code>&gt;&gt;</code> (right shift), <code>&lt;&lt;</code> (left shift),
+and unary <code>~</code> (bitwise not).
+
+
+<p>
+All bitwise operations convert its operands to integers
+(see <a href="#3.4.3">&sect;3.4.3</a>),
+operate on all bits of those integers,
+and result in an integer.
+
<p>
-Lua provides some automatic conversions between types at run time.
-Most binary operations applied to mixed numbers
+Both right and left shifts fill with zeros the vacant bits.
+Negative displacements shift to the other direction;
+displacements with absolute values equal to or higher than
+the number of bits in an integer
+result in zero (all bits are shifted out).
+
+
+
+
+
+<h3>3.4.3 &ndash; <a name="3.4.3">Coercions and Conversions</a></h3><p>
+Lua provides some automatic conversions between some
+types and representations at run time.
+Most arithmetic operations applied to mixed numbers
(integers and floats) convert the integer operand to a float;
this is called the <em>usual rule</em>.
-Division always convert integer operands to floats,
-and integer division always convert floating operands to integers.
+Division always convert integer operands to floats;
+integer division and bitwise operators
+always convert float operands to integers.
The C API also converts both integers to floats and
floats to integers, as needed.
Moreover, string concatenation accepts numbers as arguments,
@@ -2015,8 +1944,8 @@ This kind of conversion never fails.
<p>
The conversion from float to integer
first takes the floor of the float number.
-If that value can be represented as an integer number
-(that is, it is in the range of integer numbers),
+If that value can be represented as an integer
+(that is, it is in the range of integer representation),
that is the result.
Otherwise, the conversion fails.
@@ -2027,14 +1956,12 @@ follows the rules of the Lua lexer.
(The string may have leading and trailing spaces and a sign.)
There is no direct conversion from strings to integers:
If a string is provided where an integer is needed,
-Lua converts the string to a float an then the float to an integer.
+Lua converts the string to a float and then the float to an integer.
<p>
-The conversion from numbers to strings use a reasonable,
+The conversion from numbers to strings use a human-readable,
non-specified format.
-Floating-point numbers always produce strings with some
-floating-point indication (either a decimal dot or an exponent).
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>).
@@ -2043,7 +1970,7 @@ use the <code>format</code> function from the string library
-<h3>3.4.3 &ndash; <a name="3.4.3">Relational Operators</a></h3><p>
+<h3>3.4.4 &ndash; <a name="3.4.4">Relational Operators</a></h3><p>
The relational operators in Lua are
<pre>
@@ -2060,7 +1987,7 @@ Strings are compared in the obvious way.
Numbers follow the usual rule for binary operations:
if both operands are integers,
the are compared as integers.
-Otherwise, they are converted to floating-point numbers
+Otherwise, they are converted to floats
and compared as such.
@@ -2109,7 +2036,7 @@ and <code>a &gt;= b</code> is translated to <code>b &lt;= a</code>.
-<h3>3.4.4 &ndash; <a name="3.4.4">Logical Operators</a></h3><p>
+<h3>3.4.5 &ndash; <a name="3.4.5">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="#3.3.4">&sect;3.3.4</a>),
@@ -2125,7 +2052,7 @@ otherwise, <b>and</b> returns its second argument.
The disjunction operator <b>or</b> returns its first argument
if this value is different from <b>nil</b> and <b>false</b>;
otherwise, <b>or</b> returns its second argument.
-Both <b>and</b> and <b>or</b> use short-cut evaluation;
+Both <b>and</b> and <b>or</b> use short-circuit evaluation;
that is,
the second operand is evaluated only if necessary.
Here are some examples:
@@ -2147,18 +2074,18 @@ Here are some examples:
-<h3>3.4.5 &ndash; <a name="3.4.5">Concatenation</a></h3><p>
+<h3>3.4.6 &ndash; <a name="3.4.6">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="#3.4.2">&sect;3.4.2</a>.
+strings according to the rules described in <a href="#3.4.3">&sect;3.4.3</a>.
Otherwise, the <code>__concat</code> metamethod is called (see <a href="#2.4">&sect;2.4</a>).
-<h3>3.4.6 &ndash; <a name="3.4.6">The Length Operator</a></h3>
+<h3>3.4.7 &ndash; <a name="3.4.7">The Length Operator</a></h3>
<p>
The length operator is denoted by the unary prefix operator <code>#</code>.
@@ -2196,7 +2123,7 @@ with whether a table is a sequence.
-<h3>3.4.7 &ndash; <a name="3.4.7">Precedence</a></h3><p>
+<h3>3.4.8 &ndash; <a name="3.4.8">Precedence</a></h3><p>
Operator precedence in Lua follows the table below,
from lower to higher priority:
@@ -2220,7 +2147,7 @@ All other binary operators are left associative.
-<h3>3.4.8 &ndash; <a name="3.4.8">Table Constructors</a></h3><p>
+<h3>3.4.9 &ndash; <a name="3.4.9">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
@@ -2268,7 +2195,7 @@ 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="#3.4.9">&sect;3.4.9</a>).
+(see <a href="#3.4.10">&sect;3.4.10</a>).
<p>
@@ -2279,7 +2206,7 @@ as a convenience for machine-generated code.
-<h3>3.4.9 &ndash; <a name="3.4.9">Function Calls</a></h3><p>
+<h3>3.4.10 &ndash; <a name="3.4.10">Function Calls</a></h3><p>
A function call in Lua has the following syntax:
<pre>
@@ -2354,7 +2281,7 @@ So, none of the following examples are tail calls:
-<h3>3.4.10 &ndash; <a name="3.4.10">Function Definitions</a></h3>
+<h3>3.4.11 &ndash; <a name="3.4.11">Function Definitions</a></h3>
<p>
The syntax for function definition is
@@ -3046,8 +2973,8 @@ it seems to be a safe assumption.)
<pre>void lua_arith (lua_State *L, int op);</pre>
<p>
-Performs an arithmetic operation over the two values
-(or one, in the case of negation)
+Performs an arithmetic or bitwise operation over the two values
+(or one, in the case of negations)
at the top of the stack,
with the value at the top being the second operand,
pops these values, and pushes the result of the operation.
@@ -3064,9 +2991,16 @@ The value of <code>op</code> must be one of the following constants:
<li><b><a name="pdf-LUA_OPSUB"><code>LUA_OPSUB</code></a>: </b> performs subtraction (<code>-</code>)</li>
<li><b><a name="pdf-LUA_OPMUL"><code>LUA_OPMUL</code></a>: </b> performs multiplication (<code>*</code>)</li>
<li><b><a name="pdf-LUA_OPDIV"><code>LUA_OPDIV</code></a>: </b> performs division (<code>/</code>)</li>
+<li><b><a name="pdf-LUA_OPIDIV"><code>LUA_OPIDIV</code></a>: </b> performs integer division (<code>//</code>)</li>
<li><b><a name="pdf-LUA_OPMOD"><code>LUA_OPMOD</code></a>: </b> performs modulo (<code>%</code>)</li>
<li><b><a name="pdf-LUA_OPPOW"><code>LUA_OPPOW</code></a>: </b> performs exponentiation (<code>^</code>)</li>
<li><b><a name="pdf-LUA_OPUNM"><code>LUA_OPUNM</code></a>: </b> performs mathematical negation (unary <code>-</code>)</li>
+<li><b><a name="pdf-LUA_OPBNOT"><code>LUA_OPBNOT</code></a>: </b> performs bitwise negation (<code>~</code>)</li>
+<li><b><a name="pdf-LUA_OPBAND"><code>LUA_OPBAND</code></a>: </b> performs bitwise and (<code>&amp;</code>)</li>
+<li><b><a name="pdf-LUA_OPBOR"><code>LUA_OPBOR</code></a>: </b> performs bitwise or (<code>|</code>)</li>
+<li><b><a name="pdf-LUA_OPBXOR"><code>LUA_OPBXOR</code></a>: </b> performs bitwise exclusive or (<code>~</code>)</li>
+<li><b><a name="pdf-LUA_OPSHL"><code>LUA_OPSHL</code></a>: </b> performs left shift (<code>&lt;&lt;</code>)</li>
+<li><b><a name="pdf-LUA_OPSHR"><code>LUA_OPSHR</code></a>: </b> performs right shift (<code>&gt;&gt;</code>)</li>
</ul>
@@ -3283,7 +3217,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="#3.4.5">&sect;3.4.5</a>).
+(see <a href="#3.4.6">&sect;3.4.6</a>).
@@ -3404,24 +3338,18 @@ memory in use by Lua by 1024.
<li><b><code>LUA_GCSTEP</code>: </b>
performs an incremental step of garbage collection.
-The step "size" is controlled by <code>data</code>
-(larger values mean more steps) in a non-specified way.
-If you want to control the step size
-you must experimentally tune the value of <code>data</code>.
-The function returns 1 if the step finished a
-garbage-collection cycle.
</li>
<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.5">&sect;2.5</a>).
-The function returns the previous value of the pause.
+for the <em>pause</em> of the collector (see <a href="#2.5">&sect;2.5</a>)
+and 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.5">&sect;2.5</a>).
-The function returns the previous value of the step multiplier.
+the collector (see <a href="#2.5">&sect;2.5</a>)
+and returns the previous value of the step multiplier.
</li>
<li><b><code>LUA_GCISRUNNING</code>: </b>
@@ -3429,16 +3357,6 @@ returns a boolean that tells whether the collector is running
(i.e., not stopped).
</li>
-<li><b><code>LUA_GCGEN</code>: </b>
-changes the collector to generational mode
-(see <a href="#2.5">&sect;2.5</a>).
-</li>
-
-<li><b><code>LUA_GCINC</code>: </b>
-changes the collector to incremental mode.
-This is the default mode.
-</li>
-
</ul>
<p>
@@ -3514,10 +3432,11 @@ for the "index" event (see <a href="#2.4">&sect;2.4</a>).
<hr><h3><a name="lua_getglobal"><code>lua_getglobal</code></a></h3><p>
<span class="apii">[-0, +1, <em>e</em>]</span>
-<pre>void lua_getglobal (lua_State *L, const char *name);</pre>
+<pre>int lua_getglobal (lua_State *L, const char *name);</pre>
<p>
Pushes onto the stack the value of the global <code>name</code>.
+Returns the type of that value.
@@ -3538,7 +3457,7 @@ the function returns&nbsp;0 and pushes nothing on the stack.
<hr><h3><a name="lua_gettable"><code>lua_gettable</code></a></h3><p>
<span class="apii">[-1, +1, <em>e</em>]</span>
-<pre>void lua_gettable (lua_State *L, int index);</pre>
+<pre>int lua_gettable (lua_State *L, int index);</pre>
<p>
Pushes onto the stack the value <code>t[k]</code>,
@@ -3553,6 +3472,10 @@ As in Lua, this function may trigger a metamethod
for the "index" event (see <a href="#2.4">&sect;2.4</a>).
+<p>
+Returns the type of the pushed value.
+
+
@@ -3577,7 +3500,6 @@ this result is equal to the number of elements in the stack
<p>
Pushes onto the stack the Lua value associated with the userdata
at the given index.
-This Lua value must be a table or <b>nil</b>.
@@ -3598,17 +3520,18 @@ because a pseudo-index is not an actual stack position.
<hr><h3><a name="lua_Integer"><code>lua_Integer</code></a></h3>
-<pre>typedef ptrdiff_t lua_Integer;</pre>
+<pre>typedef long long int lua_Integer;</pre>
<p>
-The type of integer numbers in Lua.
+The type of integers in Lua.
<p>
-By default it is defined as <code>long long</code>,
-usually a 64-bit two-complement integer,
-but it can also be <code>long</code> or <code>int</code>,
-usually a 32-bit two-complement integer.
+By default this type is <code>long long</code>
+(usually a 64-bit two-complement integer),
+but that can be changed in <code>luaconf.h</code>
+to <code>long</code> or <code>int</code>
+(usually a 32-bit two-complement integer).
@@ -3780,7 +3703,7 @@ Returns 1 if the value at the given index is a userdata
<p>
Returns the "length" of the value at the given index;
-it is equivalent to the '<code>#</code>' operator in Lua (see <a href="#3.4.6">&sect;3.4.6</a>).
+it is equivalent to the '<code>#</code>' operator in Lua (see <a href="#3.4.7">&sect;3.4.7</a>).
The result is pushed on the stack.
@@ -3973,8 +3896,11 @@ the table during its traversal.
<pre>typedef double lua_Number;</pre>
<p>
-The type of floating-point numbers in Lua.
-By default, it is double,
+The type of floats in Lua.
+
+
+<p>
+By default this type is double,
but that can be changed in <code>luaconf.h</code> to a single float.
@@ -4183,12 +4109,14 @@ the result is a Lua string and Lua takes care of memory allocation
The conversion specifiers are quite restricted.
There are no flags, widths, or precisions.
The conversion specifiers can only be
-'<code>%%</code>' (inserts a '<code>%</code>' in the string),
+'<code>%%</code>' (inserts the character '<code>%</code>'),
'<code>%s</code>' (inserts a zero-terminated string, with no size restrictions),
'<code>%f</code>' (inserts a <a href="#lua_Number"><code>lua_Number</code></a>),
+'<code>%L</code>' (inserts a <a href="#lua_Integer"><code>lua_Integer</code></a>),
'<code>%p</code>' (inserts a pointer as a hexadecimal numeral),
-'<code>%d</code>' (inserts an <code>int</code>), and
-'<code>%c</code>' (inserts an <code>int</code> as a byte).
+'<code>%d</code>' (inserts an <code>int</code>),
+'<code>%c</code>' (inserts an <code>int</code> as a one-byte character), and
+'<code>%U</code>' (inserts an <code>int</code> as a UTF-8 byte sequence).
</li>
</ul>
@@ -4289,7 +4217,7 @@ Pushes a nil value onto the stack.
<pre>void lua_pushnumber (lua_State *L, lua_Number n);</pre>
<p>
-Pushes a number with value <code>n</code> onto the stack.
+Pushes a float with value <code>n</code> onto the stack.
@@ -4335,7 +4263,7 @@ Returns 1 if this thread is the main thread of its state.
<pre>void lua_pushunsigned (lua_State *L, lua_Unsigned n);</pre>
<p>
-Pushes a number with value <code>n</code> onto the stack.
+Pushes an integer with value <code>n</code> onto the stack.
@@ -4384,7 +4312,7 @@ Also returns&nbsp;0 if any of the indices are non valid.
<hr><h3><a name="lua_rawget"><code>lua_rawget</code></a></h3><p>
<span class="apii">[-1, +1, &ndash;]</span>
-<pre>void lua_rawget (lua_State *L, int index);</pre>
+<pre>int lua_rawget (lua_State *L, int index);</pre>
<p>
Similar to <a href="#lua_gettable"><code>lua_gettable</code></a>, but does a raw access
@@ -4396,7 +4324,7 @@ Similar to <a href="#lua_gettable"><code>lua_gettable</code></a>, but does a raw
<hr><h3><a name="lua_rawgeti"><code>lua_rawgeti</code></a></h3><p>
<span class="apii">[-0, +1, &ndash;]</span>
-<pre>void lua_rawgeti (lua_State *L, int index, lua_Integer n);</pre>
+<pre>int lua_rawgeti (lua_State *L, int index, lua_Integer n);</pre>
<p>
Pushes onto the stack the value <code>t[n]</code>,
@@ -4405,12 +4333,16 @@ The access is raw;
that is, it does not invoke metamethods.
+<p>
+Returns the type of the pushed value.
+
+
<hr><h3><a name="lua_rawgetp"><code>lua_rawgetp</code></a></h3><p>
<span class="apii">[-0, +1, &ndash;]</span>
-<pre>void lua_rawgetp (lua_State *L, int index, const void *p);</pre>
+<pre>int lua_rawgetp (lua_State *L, int index, const void *p);</pre>
<p>
Pushes onto the stack the value <code>t[k]</code>,
@@ -4420,6 +4352,10 @@ The access is raw;
that is, it does not invoke metamethods.
+<p>
+Returns the type of the pushed value.
+
+
@@ -4699,7 +4635,7 @@ If <code>index</code> is&nbsp;0, then all stack elements are removed.
<pre>void lua_setuservalue (lua_State *L, int index);</pre>
<p>
-Pops a table or <b>nil</b> from the stack and sets it as
+Pops a value from the stack and sets it as
the new value associated to the userdata at the given index.
@@ -4818,7 +4754,7 @@ Equivalent to <a href="#lua_tointegerx"><code>lua_tointegerx</code></a> with <co
Converts the Lua value at the given index
to the signed integral type <a href="#lua_Integer"><code>lua_Integer</code></a>.
The Lua value must be an integer,
-or a number or string convertible to an integer (see <a href="#3.4.2">&sect;3.4.2</a>);
+or a number or string convertible to an integer (see <a href="#3.4.3">&sect;3.4.3</a>);
otherwise, <code>lua_tointegerx</code> returns&nbsp;0.
@@ -4881,7 +4817,7 @@ Equivalent to <a href="#lua_tonumberx"><code>lua_tonumberx</code></a> with <code
Converts the Lua value at the given 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="#3.4.2">&sect;3.4.2</a>);
+(see <a href="#3.4.3">&sect;3.4.3</a>);
otherwise, <a href="#lua_tonumberx"><code>lua_tonumberx</code></a> returns&nbsp;0.
@@ -4960,7 +4896,7 @@ to the unsigned integral type <a href="#lua_Unsigned"><code>lua_Unsigned</code><
The Lua value must be an integer,
or a float,
or a string convertible to a number
-(see <a href="#3.4.2">&sect;3.4.2</a>);
+(see <a href="#3.4.3">&sect;3.4.3</a>);
otherwise, <code>lua_tounsignedx</code> returns&nbsp;0.
@@ -5544,7 +5480,7 @@ calling <a href="#lua_yield"><code>lua_yield</code></a> with <code>nresults</cod
<hr><h3><a name="lua_sethook"><code>lua_sethook</code></a></h3><p>
<span class="apii">[-0, +0, &ndash;]</span>
-<pre>int lua_sethook (lua_State *L, lua_Hook f, int mask, int count);</pre>
+<pre>void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);</pre>
<p>
Sets the debugging hook function.
@@ -5779,7 +5715,6 @@ 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 cannot contain embedded zeros.
@@ -5814,7 +5749,7 @@ which is the value to be added to the buffer.
<p>
Checks whether <code>cond</code> is true.
-If not, raises an error with a standard message.
+If it is not, raises an error with a standard message (see <a href="#luaL_argerror"><code>luaL_argerror</code></a>).
@@ -5825,14 +5760,15 @@ If not, raises an error with a standard message.
<pre>int luaL_argerror (lua_State *L, int arg, const char *extramsg);</pre>
<p>
-Raises an error with a standard message
-that includes <code>extramsg</code> as a comment.
+Raises an error reporting a problem with argument <code>arg</code>
+of the C function that called it,
+using a standard message
+that includes <code>extramsg</code> as a comment:
-
-<p>
-This function never returns,
-but it is an idiom to use it in C&nbsp;functions
-as <code>return luaL_argerror(<em>args</em>)</code>.
+<pre>
+ bad argument #<em>arg</em> to '<em>funcname</em>' (<em>extramsg</em>)
+</pre><p>
+This function never returns.
@@ -6304,7 +6240,7 @@ Pushes the resulting string on the stack and returns it.
<p>
Returns the "length" of the value at the given index
as a number;
-it is equivalent to the '<code>#</code>' operator in Lua (see <a href="#3.4.6">&sect;3.4.6</a>).
+it is equivalent to the '<code>#</code>' operator in Lua (see <a href="#3.4.7">&sect;3.4.7</a>).
Raises an error if the result of the operation is not an integer.
(This case only can happen through metamethods.)
@@ -6461,7 +6397,8 @@ If the registry already has the key <code>tname</code>,
returns 0.
Otherwise,
creates a new table to be used as a metatable for userdata,
-adds it to the registry with key <code>tname</code>,
+adds to this new table the pair <code>__name = tname</code>,
+adds to the registry the pair <code></code>[tname] = new table,
and returns 1.
@@ -6781,6 +6718,43 @@ in the registry (see <a href="#luaL_newmetatable"><code>luaL_newmetatable</code>
+<hr><h3><a name="luaL_Stream"><code>luaL_Stream</code></a></h3>
+<pre>typedef struct luaL_Stream {
+ FILE *f;
+ lua_CFunction closef;
+} luaL_Stream;</pre>
+
+<p>
+The standard representation for file handles,
+which is used by the standard I/O library.
+
+
+<p>
+A file handle is implemented as a full userdata,
+with a metatable called <code>LUA_FILEHANDLE</code>.
+<code>LUA_FILEHANDLE</code> is a macro with the actual metatable's name.
+The metatable is created by the I/O library
+(see <a href="#luaL_newmetatable"><code>luaL_newmetatable</code></a>).
+
+
+<p>
+This userdata must start with the structure <code>luaL_Stream</code>;
+it can contain other data after this initial structure.
+Field <code>f</code> points to the corresponding C stream
+(or it can be <code>NULL</code> to indicate an incompletely created handle).
+Field <code>closef</code> points to a Lua function
+that will be called to close the stream
+when the handle is closed or collected;
+this function receives the file handle as its sole argument and
+must return either <b>true</b> (in case of success)
+or <b>nil</b> plus an error message (in case of error).
+Once Lua calls this field,
+the field value is changed to <b>nil</b> to signal that the handle is closed.
+
+
+
+
+
<hr><h3><a name="luaL_testudata"><code>luaL_testudata</code></a></h3><p>
<span class="apii">[-0, +0, <em>e</em>]</span>
<pre>void *luaL_testudata (lua_State *L, int arg, const char *tname);</pre>
@@ -6888,8 +6862,6 @@ This function is used to build a prefix for error messages.
-
-
<h1>6 &ndash; <a name="6">Standard Libraries</a></h1>
<p>
@@ -6918,11 +6890,11 @@ Currently, Lua has the following standard libraries:
<li>string manipulation (<a href="#6.4">&sect;6.4</a>);</li>
-<li>table manipulation (<a href="#6.5">&sect;6.5</a>);</li>
+<li>basic UTF-8 support (<a href="#6.5">&sect;6.5</a>);</li>
-<li>mathematical functions (<a href="#6.6">&sect;6.6</a>) (sin, log, etc.);</li>
+<li>table manipulation (<a href="#6.6">&sect;6.6</a>);</li>
-<li>bitwise operations (<a href="#6.7">&sect;6.7</a>);</li>
+<li>mathematical functions (<a href="#6.7">&sect;6.7</a>) (sin, log, etc.);</li>
<li>input and output (<a href="#6.8">&sect;6.8</a>);</li>
@@ -6949,7 +6921,6 @@ the host program can open them individually by using
<a name="pdf-luaopen_string"><code>luaopen_string</code></a> (for the string library),
<a name="pdf-luaopen_table"><code>luaopen_table</code></a> (for the table library),
<a name="pdf-luaopen_math"><code>luaopen_math</code></a> (for the mathematical library),
-<a name="pdf-luaopen_bit32"><code>luaopen_bit32</code></a> (for the bit library),
<a name="pdf-luaopen_io"><code>luaopen_io</code></a> (for the I/O library),
<a name="pdf-luaopen_os"><code>luaopen_os</code></a> (for the Operating System library),
and <a name="pdf-luaopen_debug"><code>luaopen_debug</code></a> (for the debug library).
@@ -7003,25 +6974,21 @@ restarts automatic execution of the garbage collector.
</li>
<li><b>"<code>count</code>": </b>
-returns the total memory in use by Lua (in Kbytes) and
-a second value with the total memory in bytes modulo 1024.
-The first value has a fractional part,
-so the following equality is always true:
-
-<pre>
- k, b = collectgarbage("count")
- assert(k*1024 == math.floor(k)*1024 + b)
-</pre><p>
-(The second result is useful when Lua is compiled
-with a non floating-point type for numbers.)
+returns the total memory in use by Lua in Kbytes.
+The value has a fractional part,
+so that it multiplied by 1024
+gives the exact number of bytes in use by Lua
+(except for overflows).
</li>
<li><b>"<code>step</code>": </b>
performs a garbage-collection step.
-The step "size" is controlled by <code>arg</code>
-(larger values mean more steps) in a non-specified way.
-If you want to control the step size
-you must experimentally tune the value of <code>arg</code>.
+The step "size" is controlled by <code>arg</code>.
+With a zero value,
+the collector will perform one basic (indivisible) step.
+For non-zero values,
+the collector will perform as if that amount of memory
+(in KBytes) had been allocated by Lua.
Returns <b>true</b> if the step finished a collection cycle.
</li>
@@ -7095,7 +7062,7 @@ A global variable (not a function) that
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.
+nor vice versa.
@@ -7190,6 +7157,12 @@ or "<code>bt</code>" (both binary and text).
The default is "<code>bt</code>".
+<p>
+Lua does not check the consistency of binary chunks.
+Maliciously crafted binary chunks can crash
+the interpreter.
+
+
<p>
@@ -7328,7 +7301,7 @@ without invoking any metamethod.
Returns the length of the object <code>v</code>,
which must be a table or a string,
without invoking any metamethod.
-Returns an integer number.
+Returns an integer.
@@ -7417,7 +7390,9 @@ the function returns <b>nil</b>.
<p>
<hr><h3><a name="pdf-tostring"><code>tostring (v)</code></a></h3>
Receives a value of any type and
-converts it to a string in a reasonable format.
+converts it to a string in a human-readable format.
+Floats always produce strings with some
+floating-point indication (either a decimal dot or an exponent).
(For complete control of how numbers are converted,
use <a href="#pdf-string.format"><code>string.format</code></a>.)
@@ -7451,7 +7426,7 @@ and "<code>userdata</code>".
<hr><h3><a name="pdf-_VERSION"><code>_VERSION</code></a></h3>
A global variable (not a function) that
holds a string containing the current interpreter version.
-The current contents of this variable is "<code>Lua 5.3</code>".
+The current value of this variable is "<code>Lua 5.3</code>".
@@ -7981,13 +7956,19 @@ Numerical codes are not necessarily portable across platforms.
<p>
-<hr><h3><a name="pdf-string.dump"><code>string.dump (function)</code></a></h3>
+<hr><h3><a name="pdf-string.dump"><code>string.dump (function [, strip])</code></a></h3>
<p>
-Returns a string containing a binary representation of the given function,
+Returns a string containing a binary representation
+(a <em>binary chunk</em>)
+of the given function,
so that a later <a href="#pdf-load"><code>load</code></a> on this string returns
a copy of the function (but with new upvalues).
+If <code>strip</code> is a true value,
+the binary representation is created without debug information
+about the function
+(local variable names, lines, etc.).
@@ -8055,11 +8036,7 @@ Options
<code>G</code>, and <code>g</code> all expect a number as argument.
Options <code>c</code>, <code>d</code>,
<code>i</code>, <code>o</code>, <code>u</code>, <code>X</code>, and <code>x</code>
-also expect a number,
-but the range of that number may be limited by
-the underlying C&nbsp;implementation.
-For options <code>o</code>, <code>u</code>, <code>X</code>, and <code>x</code>,
-the number cannot be negative.
+expect an integer.
Option <code>q</code> expects a string;
option <code>s</code> expects a string without embedded zeros.
If the argument to option <code>s</code> is not a string,
@@ -8175,9 +8152,9 @@ Here are some examples:
end)
--&gt; x="4+5 = 9"
- local t = {name="lua", version="5.2"}
+ local t = {name="lua", version="5.3"}
x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
- --&gt; x="lua-5.2.tar.gz"
+ --&gt; x="lua-5.3.tar.gz"
</pre>
@@ -8219,6 +8196,45 @@ its default value is&nbsp;1 and can be negative.
<p>
+<hr><h3><a name="pdf-string.packfloat"><code>string.packfloat (n [, size [, endianess]])</code></a></h3>
+Returns a string with the machine representation of float <code>n</code>,
+with given size and endianess.
+The <code>size</code> is the string "<code>f</code>" (single precision),
+"<code>d</code>" (double precision), or "<code>n</code>",
+which means the size of a <a href="#lua_Number"><code>lua_Number</code></a>;
+its default is St{n}.
+The endianess is the string "<code>l</code>" (little endian), "<code>b</code>" (big endian),
+or "<code>n</code>" (native);
+the default is the native endianess.
+
+
+<p>
+(This function may not work correctly for non-native endianess
+in mixed-endian architectures.)
+
+
+
+
+<p>
+<hr><h3><a name="pdf-string.packint"><code>string.packint (n [, size [, endianess]])</code></a></h3>
+Returns a string with the machine representation of integer <code>n</code>,
+with <code>size</code> bytes and given endianess.
+The <code>size</code> can be any value from 1 to 8 or 0,
+which means the size of a <a href="#lua_Integer"><code>lua_Integer</code></a>;
+its default is zero.
+The endianess is the string "<code>l</code>" (little endian), "<code>b</code>" (big endian),
+or "<code>n</code>" (native);
+the default is the native endianess.
+
+
+<p>
+(This function may not work correctly for native endianess
+in mixed-endian architectures.)
+
+
+
+
+<p>
<hr><h3><a name="pdf-string.rep"><code>string.rep (s, n [, sep])</code></a></h3>
Returns a string that is the concatenation of <code>n</code> copies of
the string <code>s</code> separated by the string <code>sep</code>.
@@ -8263,6 +8279,28 @@ the function returns the empty string.
<p>
+<hr><h3><a name="pdf-string.unpackfloat"><code>string.unpackfloat (s [, pos [, size [, endianess]]])</code></a></h3>
+Reads the machine representation of a float starting at position
+<code>pos</code> in string <code>s</code> and returns that number.
+See <a href="#pdf-string.packfloat"><code>string.packfloat</code></a> for details about <code>size</code> and <code>endianess</code>.
+
+
+
+
+<p>
+<hr><h3><a name="pdf-string.unpackint"><code>string.unpackint (s [, pos [, size [, endianess]]])</code></a></h3>
+Reads the machine representation of an integer starting at position
+<code>pos</code> in string <code>s</code> and returns that integer.
+See <a href="#pdf-string.packint"><code>string.packint</code></a> for details about <code>size</code> and <code>endianess</code>.
+
+
+<p>
+Integers are always read as signed.
+
+
+
+
+<p>
<hr><h3><a name="pdf-string.upper"><code>string.upper (s)</code></a></h3>
Receives a string and returns a copy of this string with all
lowercase letters changed to uppercase.
@@ -8321,7 +8359,7 @@ represents the class which is the union of all
characters in <em>set</em>.
A range of characters can be specified by
separating the end characters of the range,
-in ascending order, with a '<code>-</code>',
+in ascending order, with a '<code>-</code>'.
All classes <code>%</code><em>x</em> described above can also be used as
components in <em>set</em>.
All other characters in <em>set</em> represent themselves.
@@ -8466,7 +8504,110 @@ string <code>"flaaap"</code>, there will be two captures: 3&nbsp;and&nbsp;5.
-<h2>6.5 &ndash; <a name="6.5">Table Manipulation</a></h2>
+<h2>6.5 &ndash; <a name="6.5">UTF-8 Support</a></h2>
+
+<p>
+This library provides basic support for UTF-8 encoding.
+It provides all its functions inside the table <a name="pdf-utf8"><code>utf8</code></a>.
+This library does not provide any support for Unicode other
+than the handling of the encoding.
+Any operation that needs the meaning of a character,
+such as character classification, is outside its scope.
+
+
+<p>
+Unless stated otherwise,
+all functions that expect a byte index as a parameter
+assume that the given position is either the start of a byte sequence
+or one plus the length of the subject string.
+As in the string library,
+negative indices count from the end of the string.
+
+
+<p>
+<hr><h3><a name="pdf-utf8.char"><code>utf8.char (&middot;&middot;&middot;)</code></a></h3>
+Receives zero or more integers,
+converts each one to its corresponding UTF-8 byte sequence
+and returns a string with the concatenation of all these sequences.
+
+
+
+
+<p>
+<hr><h3><a name="pdf-utf8.charpatt"><code>utf8.charpatt</code></a></h3>
+The pattern (a string, not a function) "<code>[\0-\x7F\xC2-\xF4][\x80-\xBF]*</code>"
+(see <a href="#6.4.1">&sect;6.4.1</a>),
+which matches exactly one UTF-8 byte sequence,
+assuming that the subject is a valid UTF-8 string.
+
+
+
+
+<p>
+<hr><h3><a name="pdf-utf8.codes"><code>utf8.codes (s)</code></a></h3>
+
+
+<p>
+Returns values so that the construction
+
+<pre>
+ for p, c in utf8.codes(s) do <em>body</em> end
+</pre><p>
+will iterate over all characters in string <code>s</code>,
+with <code>p</code> being the position (in bytes) and <code>c</code> the code point
+of each character.
+It raises an error if it meets any invalid byte sequence.
+
+
+
+
+<p>
+<hr><h3><a name="pdf-utf8.codepoint"><code>utf8.codepoint (s [, i [, j]])</code></a></h3>
+Returns the codepoints (as integers) from all characters in <code>s</code>
+that start between byte position <code>i</code> and <code>j</code> (both included).
+The default for <code>i</code> is 1 and for <code>j</code> is <code>i</code>.
+It raises an error if it meets any invalid byte sequence.
+
+
+
+
+<p>
+<hr><h3><a name="pdf-utf8.len"><code>utf8.len (s [, i])</code></a></h3>
+Returns the number of UTF-8 characters in string <code>s</code>,
+starting from position <code>i</code>.
+The default for <code>i</code> is 1.
+Returns <b>nil</b> if the sufix of <code>s</code> starting at <code>i</code>
+contains any invalid byte sequence.
+
+
+
+
+<p>
+<hr><h3><a name="pdf-utf8.offset"><code>utf8.offset (s, n [, i])</code></a></h3>
+Returns the byte index where the encoding of the
+<code>n</code>-th character of <code>s</code> starts,
+counting from position <code>i</code>.
+A negative <code>n</code> gets characters before position <code>i</code>.
+The default for <code>i</code> is 1.
+Returns <b>nil</b> if the subject does not have such character.
+
+
+<p>
+As a special case,
+when <code>n</code> is 0 the function returns the start of the encoding
+of the character that contains the <code>i</code>-th byte of <code>s</code>.
+
+
+<p>
+This function assumes that <code>s</code> is a valid UTF-8 string.
+
+
+
+
+
+
+
+<h2>6.6 &ndash; <a name="6.6">Table Manipulation</a></h2>
<p>
This library provides generic functions for table manipulation.
@@ -8476,7 +8617,7 @@ It provides all its functions inside the table <a name="pdf-table"><code>table</
<p>
Remember that, whenever an operation needs the length of a table,
the table should be a proper sequence
-or have a <code>__len</code> metamethod (see <a href="#3.4.6">&sect;3.4.6</a>).
+or have a <code>__len</code> metamethod (see <a href="#3.4.7">&sect;3.4.7</a>).
All functions ignore non-numeric keys
in tables given as arguments.
@@ -8546,8 +8687,8 @@ in those cases, the function erases the element <code>list[pos]</code>.
<p>
The default value for <code>pos</code> is <code>#list</code>,
-so that a call <code>table.remove(t)</code> removes the last element
-of list <code>t</code>.
+so that a call <code>table.remove(l)</code> removes the last element
+of list <code>l</code>.
@@ -8581,7 +8722,7 @@ may have their relative positions changed by the sort.
<p>
-Returns the elements from the given table.
+Returns the elements from the given list.
This function is equivalent to
<pre>
@@ -8595,14 +8736,13 @@ By default, <code>i</code> is&nbsp;1 and <code>j</code> is <code>#list</code>.
-<h2>6.6 &ndash; <a name="6.6">Mathematical Functions</a></h2>
+<h2>6.7 &ndash; <a name="6.7">Mathematical Functions</a></h2>
<p>
This library is an interface to the standard C&nbsp;math library.
It provides all its functions inside the table <a name="pdf-math"><code>math</code></a>.
Unless stated otherwise,
-all functions in this library operate with and return
-floating-point numbers.
+all functions in this library operate with and return floats.
<p>
@@ -8713,7 +8853,8 @@ Returns the value <em>e<sup>x</sup></em>.
<p>
-Returns the largest integer smaller than or equal to <code>x</code>.
+Returns a float with the largest
+integral value smaller than or equal to <code>x</code>.
@@ -8758,8 +8899,7 @@ a value larger than or equal to any other numerical value.
<p>
-Returns the largest integer smaller than or equal to <code>x</code>
-as an integer number.
+Returns the largest integer smaller than or equal to <code>x</code>.
If the value does not fit in an integer,
returns <b>nil</b>.
@@ -8767,16 +8907,6 @@ returns <b>nil</b>.
<p>
-<hr><h3><a name="pdf-math.isfloat"><code>math.isfloat (x)</code></a></h3>
-
-
-<p>
-Returns whether <code>x</code> is a floating-point number.
-
-
-
-
-<p>
<hr><h3><a name="pdf-math.ldexp"><code>math.ldexp (m, e)</code></a></h3>
@@ -8872,11 +9002,11 @@ pseudo-random generator function <code>rand</code> provided by Standard&nbsp;C.
<p>
When called without arguments,
-returns a uniform pseudo-random float number
+returns a uniform pseudo-random float
in the range <em>[0,1)</em>.
-When called with two integer values <code>m</code> and <code>n</code>,
+When called with two integers <code>m</code> and <code>n</code>,
<code>math.random</code> returns a uniform pseudo-random
-integer number in the range <em>[m, n]</em>.
+integer in the range <em>[m, n]</em>.
The call <code>math.random(n)</code> is equivalent to <code>math.random(1,n)</code>.
@@ -8945,229 +9075,14 @@ Returns the hyperbolic tangent of <code>x</code>.
-
-
-
-<h2>6.7 &ndash; <a name="6.7">Bitwise Operations</a></h2>
-
-<p>
-This library provides bitwise operations.
-It provides all its functions inside the table <a name="pdf-bit32"><code>bit32</code></a>.
-
-
-<p>
-Unless otherwise stated,
-all functions accept numeric arguments in the range
-<em>(-2<sup>51</sup>,+2<sup>51</sup>)</em>;
-each argument is normalized to
-the remainder of its division by <em>2<sup>32</sup></em>
-and truncated to an integer (in some unspecified way),
-so that its final value falls in the range <em>[0,2<sup>32</sup> - 1]</em>.
-Similarly, all results are in the range <em>[0,2<sup>32</sup> - 1]</em>.
-Note that <code>bit32.bnot(0)</code> is <code>0xFFFFFFFF</code>,
-which is different from <code>-1</code>.
-
-
-<p>
-<hr><h3><a name="pdf-bit32.arshift"><code>bit32.arshift (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.
-
-
-<p>
-This shift operation is what is called arithmetic shift.
-Vacant bits on the left are filled
-with copies of the higher bit of <code>x</code>;
-vacant bits on the right are filled with zeros.
-In particular,
-displacements with absolute values higher than 31
-result in zero or <code>0xFFFFFFFF</code> (all original bits are shifted out).
-
-
-
-
-<p>
-<hr><h3><a name="pdf-bit32.band"><code>bit32.band (&middot;&middot;&middot;)</code></a></h3>
-
-
-<p>
-Returns the bitwise <em>and</em> of its operands.
-
-
-
-
-<p>
-<hr><h3><a name="pdf-bit32.bnot"><code>bit32.bnot (x)</code></a></h3>
-
-
-<p>
-Returns the bitwise negation of <code>x</code>.
-For any integer <code>x</code>,
-the following identity holds:
-
-<pre>
- assert(bit32.bnot(x) == (-1 - x) % 2^32)
-</pre>
-
-
-
-<p>
-<hr><h3><a name="pdf-bit32.bor"><code>bit32.bor (&middot;&middot;&middot;)</code></a></h3>
-
-
-<p>
-Returns the bitwise <em>or</em> of its operands.
-
-
-
-
-<p>
-<hr><h3><a name="pdf-bit32.btest"><code>bit32.btest (&middot;&middot;&middot;)</code></a></h3>
-
-
-<p>
-Returns a boolean signaling
-whether the bitwise <em>and</em> of its operands is different from zero.
-
-
-
-
-<p>
-<hr><h3><a name="pdf-bit32.bxor"><code>bit32.bxor (&middot;&middot;&middot;)</code></a></h3>
-
-
-<p>
-Returns the bitwise <em>exclusive or</em> of its operands.
-
-
-
-
-<p>
-<hr><h3><a name="pdf-bit32.extract"><code>bit32.extract (n, field [, width])</code></a></h3>
-
-
-<p>
-Returns the unsigned number formed by the bits
-<code>field</code> to <code>field + width - 1</code> from <code>n</code>.
-Bits are numbered from 0 (least significant) to 31 (most significant).
-All accessed bits must be in the range <em>[0, 31]</em>.
-
-
-<p>
-The default for <code>width</code> is 1.
-
-
-
-
-<p>
-<hr><h3><a name="pdf-bit32.replace"><code>bit32.replace (n, v, field [, width])</code></a></h3>
-
-
-<p>
-Returns a copy of <code>n</code> with
-the bits <code>field</code> to <code>field + width - 1</code>
-replaced by the value <code>v</code>.
-See <a href="#pdf-bit32.extract"><code>bit32.extract</code></a> for details about <code>field</code> and <code>width</code>.
-
-
-
-
-<p>
-<hr><h3><a name="pdf-bit32.lrotate"><code>bit32.lrotate (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(bit32.lrotate(x, disp) == bit32.lrotate(x, disp % 32))
-</pre><p>
-In particular,
-negative displacements rotate to the right.
-
-
-
-
-<p>
-<hr><h3><a name="pdf-bit32.lshift"><code>bit32.lshift (x, disp)</code></a></h3>
-
-
-<p>
-Returns the number <code>x</code> shifted <code>disp</code> bits to the left.
-The number <code>disp</code> may be any representable integer.
-Negative displacements shift to the right.
-In any direction, vacant bits are filled with zeros.
-In particular,
-displacements with absolute values higher than 31
-result in zero (all bits are shifted out).
-
-
-<p>
-For positive displacements,
-the following equality holds:
-
-<pre>
- assert(bit32.lshift(b, disp) == (b * 2^disp) % 2^32)
-</pre>
-
-
-
-<p>
-<hr><h3><a name="pdf-bit32.rrotate"><code>bit32.rrotate (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>
-For any valid displacement,
-the following identity holds:
-
-<pre>
- assert(bit32.rrotate(x, disp) == bit32.rrotate(x, disp % 32))
-</pre><p>
-In particular,
-negative displacements rotate to the left.
-
-
-
-
-<p>
-<hr><h3><a name="pdf-bit32.rshift"><code>bit32.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 31
-result in zero (all bits are shifted out).
-
+<hr><h3><a name="pdf-math.type"><code>math.type (x)</code></a></h3>
-<p>
-For positive displacements,
-the following equality holds:
-
-<pre>
- assert(bit32.rshift(b, disp) == math.floor(b % 2^32 / 2^disp))
-</pre>
<p>
-This shift operation is what is called logical shift.
+Returns "<code>integer</code>" if <code>x</code> is an integer,
+"<code>float</code>" if it is a float,
+or <b>nil</b> if <code>x</code> is not a number.
@@ -9179,24 +9094,24 @@ This shift operation is what is called logical shift.
<p>
The I/O library provides two different styles for file manipulation.
-The first one uses implicit file descriptors;
+The first one uses implicit file handles;
that is, there are operations to set a default input file and a
default output file,
and all input/output operations are over these default files.
-The second style uses explicit file descriptors.
+The second style uses explicit file handles.
<p>
-When using implicit file descriptors,
+When using implicit file handles,
all operations are supplied by table <a name="pdf-io"><code>io</code></a>.
-When using explicit file descriptors,
-the operation <a href="#pdf-io.open"><code>io.open</code></a> returns a file descriptor
-and then all operations are supplied as methods of the file descriptor.
+When using explicit file handles,
+the operation <a href="#pdf-io.open"><code>io.open</code></a> returns a file handle
+and then all operations are supplied as methods of the file handle.
<p>
The table <code>io</code> also provides
-three predefined file descriptors with their usual meanings from C:
+three predefined file handles with their usual meanings from C:
<a name="pdf-io.stdin"><code>io.stdin</code></a>, <a name="pdf-io.stdout"><code>io.stdout</code></a>, and <a name="pdf-io.stderr"><code>io.stderr</code></a>.
The I/O library never closes these files.
@@ -9207,7 +9122,7 @@ all I/O functions return <b>nil</b> on failure
(plus an error message as a second result and
a system-dependent error code as a third result)
and some value different from <b>nil</b> on success.
-On non-Posix systems,
+On non-POSIX systems,
the computation of the error message and error code
in case of errors
may be not thread safe,
@@ -9264,12 +9179,12 @@ Opens the given file name in read mode
and returns an iterator function that
works like <code>file:lines(&middot;&middot;&middot;)</code> over the opened file.
When the iterator function detects the end of file,
-it returns <b>nil</b> (to finish the loop) and automatically closes the file.
+it returns no values (to finish the loop) and automatically closes the file.
<p>
The call <code>io.lines()</code> (with no file name) is equivalent
-to <code>io.input():lines()</code>;
+to <code>io.input():lines("*l")</code>;
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.
@@ -9449,7 +9364,7 @@ instead of returning an error code.
Reads the file <code>file</code>,
according to the given formats, which specify what to read.
For each format,
-the function returns a string (or a number) with the characters read,
+the function returns a string or a number with the characters read,
or <b>nil</b> if it cannot read data with the specified format.
When called without formats,
it uses a default format that reads the next line
@@ -9462,8 +9377,15 @@ The available formats are
<ul>
<li><b>"<code>*n</code>": </b>
-reads a number;
-this is the only format that returns a number instead of a string.
+reads a number and returns it as a float.
+If the input has only a prefix of a valid number
+(e.g., "<code>0x</code>" or "<code>3.4e-</code>"),
+this format can read the entire prefix
+even when returning <b>nil</b>.
+</li>
+
+<li><b>"<code>*i</code>": </b>
+reads an integral number and returns it as an integer.
</li>
<li><b>"<code>*a</code>": </b>
@@ -9478,19 +9400,21 @@ This is the default format.
</li>
<li><b>"<code>*L</code>": </b>
-reads the next line keeping the end of line (if present),
+reads the next line keeping the end-of-line character (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 bytes,
returning <b>nil</b> on end of file.
-If number is zero,
+If <code>number</code> is zero,
it reads nothing and returns an empty string,
or <b>nil</b> on end of file.
</li>
-</ul>
+</ul><p>
+The formats "<code>*l</code>" and "<code>*L</code>" should be used only for text files.
+
@@ -9643,7 +9567,7 @@ the host system and on the current locale
<p>
-On non-Posix systems,
+On non-POSIX systems,
this function may be not thread safe
because of its reliance on C&nbsp;function <code>gmtime</code> and C&nbsp;function <code>localtime</code>.
@@ -9673,7 +9597,7 @@ Its first result is <b>true</b>
if the command terminated successfully,
or <b>nil</b> otherwise.
After this first result
-the function returns a string and a number,
+the function returns a string plus a number,
as follows:
<ul>
@@ -9975,8 +9899,9 @@ and raises an error when called with a level out of range.
<p>
Variable names starting with '<code>(</code>' (open parenthesis)
-represent internal variables
-(loop control variables, temporaries, varargs, and C&nbsp;function locals).
+represent variables with no known names
+(internal variables like loop control variables,
+and variables from chunks saved without debug information).
<p>
@@ -10017,6 +9942,12 @@ with index <code>up</code> of the function <code>f</code>.
The function returns <b>nil</b> if there is no upvalue with the given index.
+<p>
+Variable names starting with '<code>(</code>' (open parenthesis)
+represent variables with no known names
+(variables from chunks saved without debug information).
+
+
<p>
@@ -10037,8 +9968,8 @@ returns <b>nil</b>.
<p>
Returns the number of bits in the underlying representation
-of integer (if <code>t</code> is "<code>i</code>")
-or float numbers (if <code>t</code> is "<code>f</code>").
+of an integer (if <code>t</code> is "<code>i</code>")
+or a float (if <code>t</code> is "<code>f</code>").
@@ -10140,7 +10071,6 @@ Otherwise, it returns the name of the upvalue.
<p>
Sets the given <code>value</code> as
the Lua value associated to the given <code>udata</code>.
-<code>value</code> must be a table or <b>nil</b>;
<code>udata</code> must be a full userdata.
@@ -10352,139 +10282,65 @@ is a more portable solution.)
<p>
Here we list the incompatibilities that you may find when moving a program
-from Lua&nbsp;5.1 to Lua&nbsp;5.2.
+from Lua&nbsp;5.2 to Lua&nbsp;5.3.
You can avoid some incompatibilities by compiling Lua with
appropriate options (see file <code>luaconf.h</code>).
However,
-all these compatibility options will be removed in the next version of Lua.
-Similarly,
-all features marked as deprecated in Lua&nbsp;5.1
-have been removed in Lua&nbsp;5.2.
-
-
-
-<h2>8.1 &ndash; <a name="8.1">Changes in the Language</a></h2>
-<ul>
-
-<li>
-The concept of <em>environment</em> changed.
-Only Lua functions have environments.
-To set the environment of a Lua function,
-use the variable <code>_ENV</code> or the function <a href="#pdf-load"><code>load</code></a>.
+all these compatibility options will be removed in the future.
<p>
-C functions no longer have environments.
-Use an upvalue with a shared table if you need to keep
-shared state among several C functions.
-(You may use <a href="#luaL_setfuncs"><code>luaL_setfuncs</code></a> to open a C library
-with all functions sharing a common upvalue.)
+Lua versions can always change the C API in ways that
+do not imply source-code changes in a program,
+such as the numeric values for constants
+or the implementation of functions as macros.
+Therefore,
+you should never assume that binaries are compatible between
+different Lua versions.
+Always recompile clients of the Lua API when
+using a new version.
<p>
-To manipulate the "environment" of a userdata
-(which is now called user value),
-use the new functions
-<a href="#lua_getuservalue"><code>lua_getuservalue</code></a> and <a href="#lua_setuservalue"><code>lua_setuservalue</code></a>.
-</li>
-
-<li>
-Lua identifiers cannot use locale-dependent letters.
-</li>
-
-<li>
-Doing a step or a full collection in the garbage collector
-does not restart the collector if it has been stopped.
-</li>
-
-<li>
-Weak tables with weak keys now perform like <em>ephemeron tables</em>.
-</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 debugger can know that
-there will not be a corresponding return event.
-</li>
-
-<li>
-Equality between function values has changed.
-Now, a function definition may not create a new value;
-it may reuse some previous value if there is no
-observable difference to the new function.
-</li>
-
-</ul>
-
+The standard paths in the official distribution may
+change between versions.
-<h2>8.2 &ndash; <a name="8.2">Changes in the Libraries</a></h2>
+<h2>8.1 &ndash; <a name="8.1">Changes in the Language</a></h2>
<ul>
<li>
-Function <code>module</code> is deprecated.
-It is easy to set up a module with regular Lua code.
-Modules are not expected to set global variables.
-</li>
+The main difference between Lua&nbsp;5.2 and Lua&nbsp;5.3 is the
+introduction of an integer subtype for numbers.
+Although this change should not affect "normal" computations,
+some computations
+(mainly those that involve some kind of overflow)
+can give different results.
-<li>
-Functions <code>setfenv</code> and <code>getfenv</code> were removed,
-because of the changes in environments.
-</li>
-
-<li>
-Function <code>math.log10</code> is deprecated.
-Use <a href="#pdf-math.log"><code>math.log</code></a> with 10 as its second argument, instead.
-</li>
-
-<li>
-Function <code>loadstring</code> is deprecated.
-Use <code>load</code> instead; it now accepts string arguments
-and are exactly equivalent to <code>loadstring</code>.
-</li>
-
-<li>
-Function <code>table.maxn</code> is deprecated.
-Write it in Lua if you really need it.
-</li>
-
-<li>
-Function <code>os.execute</code> now returns <b>true</b> when command
-terminates successfully and <b>nil</b> plus error information
-otherwise.
-</li>
-
-<li>
-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>
+<p>
+You can fix these differences by forcing a number to be a float
+(in Lua&nbsp;5.2 all numbers were float),
+in particular writing constants with an ending <code>.0</code>
+or using <code>x = x + 0.0</code> to convert a variable.
+(This recommendation is only for a quick fix
+for an occasional incompatibility,
+not as a general guideline for good programming.
+For good programming,
+use floats where you need floats
+and integers where you need integers.)
-<li>
-The table <code>package.loaders</code> was renamed <code>package.searchers</code>.
-</li>
-<li>
-Lua does not have bytecode verification anymore.
-So, all functions that load code
-(<a href="#pdf-load"><code>load</code></a> and <a href="#pdf-loadfile"><code>loadfile</code></a>)
-are potentially insecure when loading untrusted binary data.
-(Actually, those functions were already insecure because
-of flaws in the verification algorithm.)
-When in doubt,
-use the <code>mode</code> argument of those functions
-to restrict them to loading textual chunks.
+<p>
+Although not formally an incompatibility,
+the proper differentiation between floats and integers
+can sometimes have a big impact on performance.
</li>
<li>
-The standard paths in the official distribution may
-change between versions.
+The generational mode for the garbage collector was removed.
+(It was an experimental feature in Lua&nbsp;5.2.)
</li>
</ul>
@@ -10492,76 +10348,39 @@ change between versions.
-<h2>8.3 &ndash; <a name="8.3">Changes in the API</a></h2>
+<h2>8.2 &ndash; <a name="8.2">Changes in the Libraries</a></h2>
<ul>
<li>
-Pseudoindex <code>LUA_GLOBALSINDEX</code> was removed.
-You must get the global environment from the registry
-(see <a href="#4.5">&sect;4.5</a>).
+The conversion of a float to a string through <a href="#pdf-tostring"><code>tostring</code></a>
+(which is used by <a href="#pdf-print"><code>print</code></a>) now adds a <code>.0</code> suffix if the
+number has an integral value.
+(For instance, the float 2.0 will be printed as <code>2.0</code>,
+not as <code>2</code>.)
+You should always use an explicit format
+when you need a specific format for numbers.
</li>
<li>
-Pseudoindex <code>LUA_ENVIRONINDEX</code>
-and functions <code>lua_getfenv</code>/<code>lua_setfenv</code>
-were removed,
-as C&nbsp;functions no longer have environments.
+The <code>bit32</code> library has been deprecated.
+It is easy to require a compatible external library or,
+better yet, to replace its functions with appropriate bitwise operations.
+(Just keep in mind that <code>bit32</code> operates on 32-bit integers,
+while the bitwise operators in Standard Lua operate on 64-bit integers.)
</li>
-<li>
-Function <code>luaL_register</code> is deprecated.
-Use <a href="#luaL_setfuncs"><code>luaL_setfuncs</code></a> so that your module does not create globals.
-(Modules are not expected to set global variables anymore.)
-</li>
+</ul>
-<li>
-The <code>osize</code> argument to the allocation function
-may not be zero when creating a new block,
-that is, when <code>ptr</code> is <code>NULL</code>
-(see <a href="#lua_Alloc"><code>lua_Alloc</code></a>).
-Use only the test <code>ptr == NULL</code> to check whether
-the block is new.
-</li>
-<li>
-Finalizers (<code>__gc</code> metamethods) for userdata are called in the
-reverse order that they were marked for finalization,
-not that they were created (see <a href="#2.5.1">&sect;2.5.1</a>).
-(Most userdata are marked immediately after they are created.)
-Moreover,
-if the metatable does not have a <code>__gc</code> field when set,
-the finalizer will not be called,
-even if it is set later.
-</li>
-
-<li>
-<code>luaL_typerror</code> was removed.
-Write your own version if you need it.
-</li>
-<li>
-Function <code>lua_cpcall</code> is deprecated.
-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>
-Functions <code>lua_equal</code> and <code>lua_lessthan</code> are deprecated.
-Use the new <a href="#lua_compare"><code>lua_compare</code></a> with appropriate options instead.
-</li>
+<h2>8.3 &ndash; <a name="8.3">Changes in the API</a></h2>
-<li>
-Function <code>lua_objlen</code> was renamed <a href="#lua_rawlen"><code>lua_rawlen</code></a>.
-</li>
-<li>
-Function <a href="#lua_load"><code>lua_load</code></a> has an extra parameter, <code>mode</code>.
-Pass <code>NULL</code> to simulate the old behavior.
-</li>
+<ul>
<li>
-Function <a href="#lua_resume"><code>lua_resume</code></a> has an extra parameter, <code>from</code>.
-Pass <code>NULL</code> or the thread doing the call.
+No changes (yet).
</li>
</ul>
@@ -10649,17 +10468,17 @@ Here is the complete syntax of Lua in extended BNF.
-
+}
<HR>
<SMALL CLASS="footer">
Last update:
-Fri Jul 5 23:09:01 BRT 2013
+Fri Mar 21 17:33:56 BRT 2014
</SMALL>
<!--
-Last change: updated for Lua 5.3.0 (work1)
+Last change: updated for Lua 5.3.0 (work2)
-->
</body></html>
diff --git a/doc/readme.html b/doc/readme.html
index e3ff5850..edb319d3 100644
--- a/doc/readme.html
+++ b/doc/readme.html
@@ -9,6 +9,7 @@ blockquote, .display {
border: solid #a0a0a0 2px ;
padding: 1em ;
margin: 0px ;
+ border-radius: 8px ;
}
.display {
@@ -30,10 +31,14 @@ tt, kbd, code {
<HR>
<H1>
<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua" BORDER=0></A>
-Welcome to Lua 5.3 (work1)
+Welcome to Lua 5.3 (work2)
</H1>
<P>
+<IMG SRC="alert.png" ALIGN="absbottom">
+<EM>All details may change in the final version.</EM>
+
+<P>
<A HREF="#about">about</A>
&middot;
<A HREF="#install">installation</A>
@@ -232,7 +237,7 @@ lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c
lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c
ltm.c lundump.c lvm.c lzio.c
lauxlib.c lbaselib.c lbitlib.c lcorolib.c ldblib.c liolib.c
-lmathlib.c loslib.c lstrlib.c ltablib.c loadlib.c linit.c
+lmathlib.c loslib.c lstrlib.c ltablib.c lutf8lib.c loadlib.c linit.c
<DT>
interpreter:
<DD>
@@ -258,7 +263,7 @@ compiler:
As mentioned above, you may edit <TT>src/luaconf.h</TT> to customize
some features before building Lua.
-<H2><A NAME="changes">Changes since Lua 5.1</A></H2>
+<H2><A NAME="changes">Changes since Lua 5.2</A></H2>
<P>
Here are the main changes introduced in Lua 5.3.
@@ -269,90 +274,40 @@ lists the
<H3>Main changes</H3>
<UL>
-<LI> yieldable pcall and metamethods
-<LI> new lexical scheme for globals
-<LI> ephemeron tables
-<LI> new library for bitwise operations
-<LI> light C functions
-<LI> emergency garbage collector
-<LI> <CODE>goto</CODE> statement
-<LI> finalizers for tables
+<LI> support for integers (64-bit by default)
+<LI> better support for small architectures ("Small Lua" with 32-bit numbers)
+<LI> bitwise operators
+<LI> basic utf-8 library
+<LI> utf-8 escapes in literal strings
+<LI> functions for packing/unpacking numbers
+<LI> userdata can have any Lua value as uservalue
+<LI> strip option in <CODE>lua_dump</CODE>/<CODE>string.dump</CODE>
</UL>
Here are the other changes introduced in Lua 5.3:
<H3>Language</H3>
<UL>
-<LI> no more fenv for threads or functions
-<LI> tables honor the <CODE>__len</CODE> metamethod
-<LI> hex and <CODE>\z</CODE> escapes in strings
-<LI> support for hexadecimal floats
-<LI> order metamethods work for different types
-<LI> no more verification of opcode consistency
-<LI> hook event "tail return" replaced by "tail call"
-<LI> empty statement
-<LI> <CODE>break</CODE> statement may appear in the middle of a block
+<LI>
</UL>
<H3>Libraries</H3>
<UL>
-<LI> arguments for function called through <CODE>xpcall</CODE>
-<LI> optional 'mode' argument to load and loadfile (to control binary x text)
-<LI> optional 'env' argument to load and loadfile (environment for loaded chunk)
-<LI> <CODE>loadlib</CODE> may load libraries with global names (RTLD_GLOBAL)
-<LI> new function <CODE>package.searchpath</CODE>
-<LI> modules receive their paths when loaded
-<LI> optional base in <CODE>math.log</CODE>
-<LI> optional separator in <CODE>string.rep</CODE>
-<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 metamethods <CODE>__pairs</CODE> and <CODE>__ipairs</CODE>
-<LI> new option 'isrunning' for <CODE>collectgarbage</CODE> and <CODE>lua_gc</CODE>
-<LI> frontier patterns
-<LI> <CODE>\0</CODE> in patterns
-<LI> new option <CODE>*L</CODE> for <CODE>io.read</CODE>
-<LI> options for <CODE>io.lines</CODE>
-<LI> <CODE>debug.getlocal</CODE> can access function varargs
+<LI>
</UL>
<H3>C API</H3>
<UL>
-<LI> main thread predefined in the registry
-<LI> new functions
-<CODE>lua_absindex</CODE>,
-<CODE>lua_arith</CODE>,
-<CODE>lua_compare</CODE>,
-<CODE>lua_copy</CODE>,
-<CODE>lua_len</CODE>,
-<CODE>lua_rawgetp</CODE>,
-<CODE>lua_rawsetp</CODE>,
-<CODE>lua_upvalueid</CODE>,
-<CODE>lua_upvaluejoin</CODE>,
-<CODE>lua_version</CODE>.
-<LI> new functions
-<CODE>luaL_checkversion</CODE>,
-<CODE>luaL_setmetatable</CODE>,
-<CODE>luaL_testudata</CODE>,
-<CODE>luaL_tolstring</CODE>.
-<LI> <CODE>lua_pushstring</CODE> and <CODE>pushlstring</CODE> return string
-<LI> <CODE>nparams</CODE> and <CODE>isvararg</CODE> available in debug API
-<LI> new <CODE>lua_Unsigned</CODE>
+<LI>
</UL>
<H3>Implementation</H3>
<UL>
-<LI> max constants per function raised to 2<SUP>26</SUP>
-<LI> generational mode for garbage collection (experimental)
-<LI> NaN trick (experimental)
-<LI> internal (immutable) version of ctypes
-<LI> simpler implementation for string buffers
-<LI> parser uses much less C-stack space (no more auto arrays)
+<LI>
</UL>
<H3>Lua standalone interpreter</H3>
<UL>
-<LI> new <CODE>-E</CODE> option to avoid environment variables
-<LI> handling of non-string error messages
+<LI> Can be used as calculator; no need to prefix with '='
</UL>
<H2><A NAME="license">License</A></H2>
@@ -374,7 +329,7 @@ For details, see
<A HREF="http://www.lua.org/license.html">this</A>.
<BLOCKQUOTE STYLE="padding-bottom: 0em">
-Copyright &copy; 1994&ndash;2013 Lua.org, PUC-Rio.
+Copyright &copy; 1994&ndash;2014 Lua.org, PUC-Rio.
<P>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -402,10 +357,10 @@ THE SOFTWARE.
<HR>
<SMALL CLASS="footer">
Last update:
-Mon Jun 3 23:13:40 BRT 2013
+Fri Mar 21 17:33:08 BRT 2014
</SMALL>
<!--
-Last change: revised for Lua 5.3.0
+Last change: updated for Lua 5.3.0 (work2)
-->
</BODY>
diff --git a/src/.fix b/src/.fix
index b390c3ca..16915891 100644
--- a/src/.fix
+++ b/src/.fix
@@ -1,2 +1,2 @@
-#define nvalue(x) 0
+#define nvalue(x) ((lua_Number)0)
#define ttypenv(x) ttnov(x)
diff --git a/src/Makefile b/src/Makefile
index ca156758..45e1ac9e 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -33,7 +33,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 lcorolib.o ldblib.o liolib.o \
- lmathlib.o loslib.o lstrlib.o ltablib.o loadlib.o linit.o
+ lmathlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o loadlib.o linit.o
BASE_O= $(CORE_O) $(LIB_O) $(MYOBJS)
LUA_T= lua
@@ -152,7 +152,7 @@ lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h
liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h
llex.o: llex.c lua.h luaconf.h lctype.h llimits.h ldo.h lobject.h \
- lstate.h ltm.h lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h
+ lstate.h ltm.h lzio.h lmem.h lgc.h llex.h lparser.h lstring.h ltable.h
lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h
lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
ltm.h lzio.h lmem.h ldo.h lgc.h
@@ -167,8 +167,8 @@ lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \
lstate.o: lstate.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h \
ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h lstring.h \
ltable.h
-lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \
- ltm.h lzio.h lstring.h lgc.h
+lstring.o: lstring.c lua.h luaconf.h ldebug.h lstate.h lobject.h \
+ llimits.h ltm.h lzio.h lmem.h ldo.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 lstring.h ltable.h lvm.h
@@ -180,6 +180,7 @@ luac.o: luac.c lua.h luaconf.h lauxlib.h lobject.h llimits.h lstate.h \
ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h
lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h lundump.h
+lutf8lib.o: lutf8lib.c lua.h luaconf.h lauxlib.h lualib.h
lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h
lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \
diff --git a/src/lapi.c b/src/lapi.c
index a8c3e1c8..923297dc 100644
--- a/src/lapi.c
+++ b/src/lapi.c
@@ -1,5 +1,5 @@
/*
-** $Id: lapi.c,v 2.185 2013/07/05 14:29:51 roberto Exp $
+** $Id: lapi.c,v 2.201 2014/03/12 20:57:40 roberto Exp $
** Lua API
** See Copyright Notice in lua.h
*/
@@ -286,7 +286,7 @@ LUA_API int lua_isstring (lua_State *L, int idx) {
LUA_API int lua_isuserdata (lua_State *L, int idx) {
const TValue *o = index2addr(L, idx);
- return (ttisuserdata(o) || ttislightuserdata(o));
+ return (ttisfulluserdata(o) || ttislightuserdata(o));
}
@@ -299,9 +299,9 @@ LUA_API int lua_rawequal (lua_State *L, int index1, int index2) {
LUA_API void lua_arith (lua_State *L, int op) {
lua_lock(L);
- if (op != LUA_OPUNM) /* all other operations expect two operands */
- api_checknelems(L, 2);
- else { /* for unary minus, add fake 2nd operand */
+ if (op != LUA_OPUNM && op != LUA_OPBNOT)
+ api_checknelems(L, 2); /* all other operations expect two operands */
+ else { /* for unary operations, add fake 2nd operand */
api_checknelems(L, 1);
setobjs2s(L, L->top, L->top - 1);
L->top++;
@@ -379,20 +379,20 @@ LUA_API lua_Unsigned lua_tounsignedx (lua_State *L, int idx, int *pisnum) {
isnum = 1;
break;
}
- case LUA_TNUMFLT: {
- const lua_Number twop = (~(lua_Unsigned)0) + cast_num(1);
- lua_Number n = fltvalue(o);
+ case LUA_TNUMFLT: { /* compute floor(n) % 2^(numbits in an integer) */
+ const lua_Number twop = cast_num(MAX_UINTEGER) + cast_num(1); /* 2^n */
+ lua_Number n = fltvalue(o); /* get value */
int neg = 0;
- n = l_floor(n);
+ n = l_floor(n); /* get its floor */
if (n < 0) {
neg = 1;
- n = -n;
+ n = -n; /* make 'n' positive, so that 'fmod' is the same as '%' */
}
- n = l_mathop(fmod)(n, twop);
- if (luai_numisnan(L,n)) /* not a number? */
+ n = l_mathop(fmod)(n, twop); /* n = n % 2^(numbits in an integer) */
+ if (luai_numisnan(n)) /* not a number? */
break; /* not an integer, too */
- res = cast_unsigned(n);
- if (neg) res = 0u - res;
+ res = cast_unsigned(n); /* 'n' now must fit in an unsigned */
+ if (neg) res = 0u - res; /* back to negative, if needed */
isnum = 1;
break;
}
@@ -586,8 +586,10 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
cl = luaF_newCclosure(L, n);
cl->c.f = fn;
L->top -= n;
- while (n--)
+ while (n--) {
setobj2n(L, &cl->c.upvalue[n], L->top + n);
+ /* does not need barrier because closure is white */
+ }
setclCvalue(L, L->top, cl);
}
api_incr_top(L);
@@ -626,7 +628,7 @@ LUA_API int lua_pushthread (lua_State *L) {
*/
-LUA_API void lua_getglobal (lua_State *L, const char *var) {
+LUA_API int lua_getglobal (lua_State *L, const char *var) {
Table *reg = hvalue(&G(L)->l_registry);
const TValue *gt; /* global table */
lua_lock(L);
@@ -634,19 +636,21 @@ LUA_API void lua_getglobal (lua_State *L, const char *var) {
setsvalue2s(L, L->top++, luaS_new(L, var));
luaV_gettable(L, gt, L->top - 1, L->top - 1);
lua_unlock(L);
+ return ttnov(L->top - 1);
}
-LUA_API void lua_gettable (lua_State *L, int idx) {
+LUA_API int lua_gettable (lua_State *L, int idx) {
StkId t;
lua_lock(L);
t = index2addr(L, idx);
luaV_gettable(L, t, L->top - 1, L->top - 1);
lua_unlock(L);
+ return ttnov(L->top - 1);
}
-LUA_API void lua_getfield (lua_State *L, int idx, const char *k) {
+LUA_API int lua_getfield (lua_State *L, int idx, const char *k) {
StkId t;
lua_lock(L);
t = index2addr(L, idx);
@@ -654,20 +658,22 @@ LUA_API void lua_getfield (lua_State *L, int idx, const char *k) {
api_incr_top(L);
luaV_gettable(L, t, L->top - 1, L->top - 1);
lua_unlock(L);
+ return ttnov(L->top - 1);
}
-LUA_API void lua_rawget (lua_State *L, int idx) {
+LUA_API int lua_rawget (lua_State *L, int idx) {
StkId t;
lua_lock(L);
t = index2addr(L, idx);
api_check(L, ttistable(t), "table expected");
setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1));
lua_unlock(L);
+ return ttnov(L->top - 1);
}
-LUA_API void lua_rawgeti (lua_State *L, int idx, lua_Integer n) {
+LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) {
StkId t;
lua_lock(L);
t = index2addr(L, idx);
@@ -675,10 +681,11 @@ LUA_API void lua_rawgeti (lua_State *L, int idx, lua_Integer n) {
setobj2s(L, L->top, luaH_getint(hvalue(t), n));
api_incr_top(L);
lua_unlock(L);
+ return ttnov(L->top - 1);
}
-LUA_API void lua_rawgetp (lua_State *L, int idx, const void *p) {
+LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
StkId t;
TValue k;
lua_lock(L);
@@ -688,6 +695,7 @@ LUA_API void lua_rawgetp (lua_State *L, int idx, const void *p) {
setobj2s(L, L->top, luaH_get(hvalue(t), &k));
api_incr_top(L);
lua_unlock(L);
+ return ttnov(L->top - 1);
}
@@ -737,11 +745,8 @@ LUA_API void lua_getuservalue (lua_State *L, int idx) {
StkId o;
lua_lock(L);
o = index2addr(L, idx);
- api_check(L, ttisuserdata(o), "userdata expected");
- if (uvalue(o)->env) {
- sethvalue(L, L->top, uvalue(o)->env);
- } else
- setnilvalue(L->top);
+ api_check(L, ttisfulluserdata(o), "full userdata expected");
+ getuservalue(L, rawuvalue(o), L->top);
api_incr_top(L);
lua_unlock(L);
}
@@ -846,7 +851,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
case LUA_TTABLE: {
hvalue(obj)->metatable = mt;
if (mt) {
- luaC_objbarrierback(L, gcvalue(obj), mt);
+ luaC_objbarrier(L, gcvalue(obj), mt);
luaC_checkfinalizer(L, gcvalue(obj), mt);
}
break;
@@ -875,14 +880,9 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 1);
o = index2addr(L, idx);
- 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));
- }
+ api_check(L, ttisfulluserdata(o), "full userdata expected");
+ setuservalue(L, rawuvalue(o), L->top - 1);
+ luaC_barrier(L, gcvalue(o), L->top - 1);
L->top--;
lua_unlock(L);
}
@@ -1015,14 +1015,14 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
}
-LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) {
+LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {
int status;
TValue *o;
lua_lock(L);
api_checknelems(L, 1);
o = L->top - 1;
if (isLfunction(o))
- status = luaU_dump(L, getproto(o), writer, data, 0);
+ status = luaU_dump(L, getproto(o), writer, data, strip);
else
status = 1;
lua_unlock(L);
@@ -1068,19 +1068,21 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
break;
}
case LUA_GCSTEP: {
- if (g->gckind == KGC_GEN) { /* generational mode? */
- res = (g->GCestimate == 0); /* true if it will do major collection */
- luaC_forcestep(L); /* do a single step */
+ l_mem debt = 1; /* =1 to signal that it did an actual step */
+ int oldrunning = g->gcrunning;
+ g->gcrunning = 1; /* force GC to run */
+ if (data == 0) {
+ luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */
+ luaC_step(L);
}
- else {
- lu_mem debt = cast(lu_mem, data) * 1024 - GCSTEPSIZE;
- if (g->gcrunning)
- debt += g->GCdebt; /* include current debt */
- luaE_setdebt(g, debt);
- luaC_forcestep(L);
- if (g->gcstate == GCSpause) /* end of cycle? */
- res = 1; /* signal it */
+ else { /* add 'data' to total debt */
+ debt = cast(l_mem, data) * 1024 + g->GCdebt;
+ luaE_setdebt(g, debt);
+ luaC_checkGC(L);
}
+ g->gcrunning = oldrunning; /* restore previous state */
+ if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */
+ res = 1; /* signal it */
break;
}
case LUA_GCSETPAUSE: {
@@ -1088,13 +1090,9 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
g->gcpause = data;
break;
}
- case LUA_GCSETMAJORINC: {
- res = g->gcmajorinc;
- g->gcmajorinc = data;
- break;
- }
case LUA_GCSETSTEPMUL: {
res = g->gcstepmul;
+ if (data < 40) data = 40; /* avoid ridiculous low values (and 0) */
g->gcstepmul = data;
break;
}
@@ -1102,14 +1100,6 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
res = g->gcrunning;
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 */
}
lua_unlock(L);
@@ -1197,7 +1187,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, NULL);
+ u = luaS_newudata(L, size);
setuvalue(L, L->top, u);
api_incr_top(L);
lua_unlock(L);
@@ -1207,7 +1197,7 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
static const char *aux_upvalue (StkId fi, int n, TValue **val,
- GCObject **owner) {
+ GCObject **owner, UpVal **uv) {
switch (ttype(fi)) {
case LUA_TCCL: { /* C closure */
CClosure *f = clCvalue(fi);
@@ -1222,9 +1212,9 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val,
Proto *p = f->p;
if (!(1 <= n && n <= p->sizeupvalues)) return NULL;
*val = f->upvals[n-1]->v;
- if (owner) *owner = obj2gco(f->upvals[n - 1]);
+ if (uv) *uv = f->upvals[n - 1];
name = p->upvalues[n-1].name;
- return (name == NULL) ? "" : getstr(name);
+ return (name == NULL) ? "(*no name)" : getstr(name);
}
default: return NULL; /* not a closure */
}
@@ -1235,7 +1225,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
const char *name;
TValue *val = NULL; /* to avoid warnings */
lua_lock(L);
- name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL);
+ name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL);
if (name) {
setobj2s(L, L->top, val);
api_incr_top(L);
@@ -1248,16 +1238,18 @@ 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 = NULL; /* to avoid warnings */
- GCObject *owner = NULL; /* to avoid warnings */
+ GCObject *owner = NULL;
+ UpVal *uv = NULL;
StkId fi;
lua_lock(L);
fi = index2addr(L, funcindex);
api_checknelems(L, 1);
- name = aux_upvalue(fi, n, &val, &owner);
+ name = aux_upvalue(fi, n, &val, &owner, &uv);
if (name) {
L->top--;
setobj(L, val, L->top);
- luaC_barrier(L, owner, L->top);
+ if (owner) { luaC_barrier(L, owner, L->top); }
+ else if (uv) { luaC_upvalbarrier(L, uv); }
}
lua_unlock(L);
return name;
@@ -1299,7 +1291,11 @@ LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
LClosure *f1;
UpVal **up1 = getupvalref(L, fidx1, n1, &f1);
UpVal **up2 = getupvalref(L, fidx2, n2, NULL);
+ luaC_upvdeccount(L, *up1);
*up1 = *up2;
- luaC_objbarrier(L, f1, *up2);
+ (*up1)->refcount++;
+ if (upisopen(*up1)) (*up1)->u.open.touched = 1;
+ luaC_upvalbarrier(L, *up1);
}
+
diff --git a/src/lauxlib.c b/src/lauxlib.c
index 68373b0a..8007c1fb 100644
--- a/src/lauxlib.c
+++ b/src/lauxlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lauxlib.c,v 1.255 2013/06/27 18:32:33 roberto Exp $
+** $Id: lauxlib.c,v 1.260 2014/03/12 20:57:40 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -150,33 +150,40 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
** =======================================================
*/
-LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) {
+LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) {
lua_Debug ar;
if (!lua_getstack(L, 0, &ar)) /* no stack frame? */
- return luaL_error(L, "bad argument #%d (%s)", narg, extramsg);
+ return luaL_error(L, "bad argument #%d (%s)", arg, extramsg);
lua_getinfo(L, "n", &ar);
if (strcmp(ar.namewhat, "method") == 0) {
- narg--; /* do not count `self' */
- if (narg == 0) /* error is in the self argument itself? */
+ arg--; /* do not count `self' */
+ if (arg == 0) /* error is in the self argument itself? */
return luaL_error(L, "calling " LUA_QS " on bad self (%s)",
ar.name, extramsg);
}
if (ar.name == NULL)
ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)",
- narg, ar.name, extramsg);
+ arg, ar.name, extramsg);
}
-static int typeerror (lua_State *L, int narg, const char *tname) {
- const char *msg = lua_pushfstring(L, "%s expected, got %s",
- tname, luaL_typename(L, narg));
- return luaL_argerror(L, narg, msg);
+static int typeerror (lua_State *L, int arg, const char *tname) {
+ const char *msg;
+ const char *typearg = luaL_typename(L, arg);
+ if (lua_getmetatable(L, arg)) {
+ if (lua_getfield(L, -1, "__name") == LUA_TSTRING)
+ typearg = lua_tostring(L, -1);
+ }
+ else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA)
+ typearg = "light userdata";
+ msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg);
+ return luaL_argerror(L, arg, msg);
}
-static void tag_error (lua_State *L, int narg, int tag) {
- typeerror(L, narg, lua_typename(L, tag));
+static void tag_error (lua_State *L, int arg, int tag) {
+ typeerror(L, arg, lua_typename(L, tag));
}
@@ -275,6 +282,8 @@ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
return 0; /* leave previous value on top, but return 0 */
lua_pop(L, 1);
lua_newtable(L); /* create metatable */
+ lua_pushstring(L, tname);
+ lua_setfield(L, -2, "__name"); /* metatable.__name = tname */
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */
return 1;
@@ -317,15 +326,15 @@ LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {
** =======================================================
*/
-LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def,
+LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def,
const char *const lst[]) {
- const char *name = (def) ? luaL_optstring(L, narg, def) :
- luaL_checkstring(L, narg);
+ const char *name = (def) ? luaL_optstring(L, arg, def) :
+ luaL_checkstring(L, arg);
int i;
for (i=0; lst[i]; i++)
if (strcmp(lst[i], name) == 0)
return i;
- return luaL_argerror(L, narg,
+ return luaL_argerror(L, arg,
lua_pushfstring(L, "invalid option " LUA_QS, name));
}
@@ -342,86 +351,86 @@ LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
}
-LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) {
- if (lua_type(L, narg) != t)
- tag_error(L, narg, t);
+LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) {
+ if (lua_type(L, arg) != t)
+ tag_error(L, arg, t);
}
-LUALIB_API void luaL_checkany (lua_State *L, int narg) {
- if (lua_type(L, narg) == LUA_TNONE)
- luaL_argerror(L, narg, "value expected");
+LUALIB_API void luaL_checkany (lua_State *L, int arg) {
+ if (lua_type(L, arg) == LUA_TNONE)
+ luaL_argerror(L, arg, "value expected");
}
-LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) {
- const char *s = lua_tolstring(L, narg, len);
- if (!s) tag_error(L, narg, LUA_TSTRING);
+LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) {
+ const char *s = lua_tolstring(L, arg, len);
+ if (!s) tag_error(L, arg, LUA_TSTRING);
return s;
}
-LUALIB_API const char *luaL_optlstring (lua_State *L, int narg,
+LUALIB_API const char *luaL_optlstring (lua_State *L, int arg,
const char *def, size_t *len) {
- if (lua_isnoneornil(L, narg)) {
+ if (lua_isnoneornil(L, arg)) {
if (len)
*len = (def ? strlen(def) : 0);
return def;
}
- else return luaL_checklstring(L, narg, len);
+ else return luaL_checklstring(L, arg, len);
}
-LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) {
+LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) {
int isnum;
- lua_Number d = lua_tonumberx(L, narg, &isnum);
+ lua_Number d = lua_tonumberx(L, arg, &isnum);
if (!isnum)
- tag_error(L, narg, LUA_TNUMBER);
+ tag_error(L, arg, LUA_TNUMBER);
return d;
}
-LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) {
- return luaL_opt(L, luaL_checknumber, narg, def);
+LUALIB_API lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number def) {
+ return luaL_opt(L, luaL_checknumber, arg, def);
}
-static void interror (lua_State *L, int narg) {
- if (lua_type(L, narg) == LUA_TNUMBER)
- luaL_argerror(L, narg, "float value out of range");
+static void interror (lua_State *L, int arg) {
+ if (lua_type(L, arg) == LUA_TNUMBER)
+ luaL_argerror(L, arg, "float value out of range");
else
- tag_error(L, narg, LUA_TNUMBER);
+ tag_error(L, arg, LUA_TNUMBER);
}
-LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) {
+LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) {
int isnum;
- lua_Integer d = lua_tointegerx(L, narg, &isnum);
+ lua_Integer d = lua_tointegerx(L, arg, &isnum);
if (!isnum) {
- interror(L, narg);
+ interror(L, arg);
}
return d;
}
-LUALIB_API lua_Unsigned luaL_checkunsigned (lua_State *L, int narg) {
+LUALIB_API lua_Unsigned luaL_checkunsigned (lua_State *L, int arg) {
int isnum;
- lua_Unsigned d = lua_tounsignedx(L, narg, &isnum);
+ lua_Unsigned d = lua_tounsignedx(L, arg, &isnum);
if (!isnum)
- interror(L, narg);
+ interror(L, arg);
return d;
}
-LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg,
+LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg,
lua_Integer def) {
- return luaL_opt(L, luaL_checkinteger, narg, def);
+ return luaL_opt(L, luaL_checkinteger, arg, def);
}
-LUALIB_API lua_Unsigned luaL_optunsigned (lua_State *L, int narg,
+LUALIB_API lua_Unsigned luaL_optunsigned (lua_State *L, int arg,
lua_Unsigned def) {
- return luaL_opt(L, luaL_checkunsigned, narg, def);
+ return luaL_opt(L, luaL_checkunsigned, arg, def);
}
/* }====================================================== */
@@ -709,8 +718,7 @@ LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
if (!lua_getmetatable(L, obj)) /* no metatable? */
return 0;
lua_pushstring(L, event);
- lua_rawget(L, -2);
- if (lua_isnil(L, -1)) {
+ if (lua_rawget(L, -2) == LUA_TNIL) { /* is metafield nil? */
lua_pop(L, 2); /* remove metatable and metafield */
return 0;
}
@@ -746,10 +754,16 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */
switch (lua_type(L, idx)) {
- case LUA_TNUMBER: { /* concatenate with empty string to convert */
- lua_pushvalue(L, idx);
- lua_pushliteral(L, "");
- lua_concat(L, 2);
+ case LUA_TNUMBER: {
+ if (lua_isinteger(L, idx))
+ lua_pushfstring(L, "%I", lua_tointeger(L, idx));
+ else {
+ const char *s = lua_pushfstring(L, "%f", lua_tonumber(L, idx));
+ if (s[strspn(s, "-0123456789")] == '\0') { /* looks like an int? */
+ lua_pushliteral(L, ".0"); /* add a '.0' to result */
+ lua_concat(L, 2);
+ }
+ }
break;
}
case LUA_TSTRING:
@@ -786,8 +800,7 @@ static const char *luaL_findtable (lua_State *L, int idx,
e = strchr(fname, '.');
if (e == NULL) e = fname + strlen(fname);
lua_pushlstring(L, fname, e - fname);
- lua_rawget(L, -2);
- if (lua_isnil(L, -1)) { /* no such field? */
+ if (lua_rawget(L, -2) == LUA_TNIL) { /* no such field? */
lua_pop(L, 1); /* remove this nil */
lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
lua_pushlstring(L, fname, e - fname);
@@ -824,8 +837,7 @@ static int libsize (const luaL_Reg *l) {
LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
int sizehint) {
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */
- lua_getfield(L, -1, modname); /* get _LOADED[modname] */
- if (!lua_istable(L, -1)) { /* not found? */
+ if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no _LOADED[modname]? */
lua_pop(L, 1); /* remove previous result */
/* try global variable (and create one if it does not exist) */
lua_pushglobaltable(L);
@@ -877,8 +889,8 @@ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
** into the stack
*/
LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
- lua_getfield(L, idx, fname);
- if (lua_istable(L, -1)) return 1; /* table already there */
+ if (lua_getfield(L, idx, fname) == LUA_TTABLE)
+ return 1; /* table already there */
else {
lua_pop(L, 1); /* remove previous result */
idx = lua_absindex(L, idx);
diff --git a/src/lauxlib.h b/src/lauxlib.h
index 6b345e28..55871c5a 100644
--- a/src/lauxlib.h
+++ b/src/lauxlib.h
@@ -1,5 +1,5 @@
/*
-** $Id: lauxlib.h,v 1.122 2013/06/27 18:32:33 roberto Exp $
+** $Id: lauxlib.h,v 1.123 2014/01/05 14:04:46 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -35,24 +35,24 @@ LUALIB_API void (luaL_checkversion_) (lua_State *L, int ver, size_t sz);
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 int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
-LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
+LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg);
+LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg,
size_t *l);
-LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
+LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg,
const char *def, size_t *l);
-LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
-LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);
+LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg);
+LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def);
-LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
-LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
+LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg);
+LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg,
lua_Integer def);
-LUALIB_API lua_Unsigned (luaL_checkunsigned) (lua_State *L, int numArg);
-LUALIB_API lua_Unsigned (luaL_optunsigned) (lua_State *L, int numArg,
+LUALIB_API lua_Unsigned (luaL_checkunsigned) (lua_State *L, int arg);
+LUALIB_API lua_Unsigned (luaL_optunsigned) (lua_State *L, int arg,
lua_Unsigned def);
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
-LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
-LUALIB_API void (luaL_checkany) (lua_State *L, int narg);
+LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t);
+LUALIB_API void (luaL_checkany) (lua_State *L, int arg);
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
@@ -62,7 +62,7 @@ LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
-LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
+LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
const char *const lst[]);
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
@@ -114,8 +114,8 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
#define luaL_newlib(L,l) \
(luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
-#define luaL_argcheck(L, cond,numarg,extramsg) \
- ((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
+#define luaL_argcheck(L, cond,arg,extramsg) \
+ ((void)((cond) || luaL_argerror(L, (arg), (extramsg))))
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
diff --git a/src/lbaselib.c b/src/lbaselib.c
index d074b92d..4f43824c 100644
--- a/src/lbaselib.c
+++ b/src/lbaselib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lbaselib.c,v 1.279 2013/07/05 14:39:15 roberto Exp $
+** $Id: lbaselib.c,v 1.285 2014/03/12 20:57:40 roberto Exp $
** Basic library
** See Copyright Notice in lua.h
*/
@@ -63,7 +63,7 @@ static int b_str2int (const char *s, const char *e, int base, lua_Integer *pn) {
s += strspn(s, SPACECHARS); /* skip trailing spaces */
if (s != e) /* invalid trailing characters? */
return 0;
- *pn = (neg) ? -(lua_Integer)n : (lua_Integer)n;
+ *pn = (lua_Integer)((neg) ? (0u - n) : n);
return 1;
}
@@ -175,19 +175,18 @@ static int luaB_rawset (lua_State *L) {
static int luaB_collectgarbage (lua_State *L) {
static const char *const opts[] = {"stop", "restart", "collect",
"count", "step", "setpause", "setstepmul",
- "setmajorinc", "isrunning", "generational", "incremental", NULL};
+ "isrunning", NULL};
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
- LUA_GCSETMAJORINC, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC};
+ LUA_GCISRUNNING};
int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
int ex = luaL_optint(L, 2, 0);
int res = lua_gc(L, o, ex);
switch (o) {
case LUA_GCCOUNT: {
int b = lua_gc(L, LUA_GCCOUNTB, 0);
- lua_pushnumber(L, res + ((lua_Number)b/1024));
- lua_pushinteger(L, b);
- return 2;
+ lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024));
+ return 1;
}
case LUA_GCSTEP: case LUA_GCISRUNNING: {
lua_pushboolean(L, res);
@@ -247,8 +246,7 @@ static int ipairsaux (lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
i++; /* next value */
lua_pushinteger(L, i);
- lua_rawgeti(L, 1, i);
- return (lua_isnil(L, -1)) ? 1 : 2;
+ return (lua_rawgeti(L, 1, i) == LUA_TNIL) ? 1 : 2;
}
diff --git a/src/lbitlib.c b/src/lbitlib.c
index d6d436bc..ce5f0b0f 100644
--- a/src/lbitlib.c
+++ b/src/lbitlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lbitlib.c,v 1.20 2013/06/21 17:27:24 roberto Exp $
+** $Id: lbitlib.c,v 1.25 2014/03/20 19:22:16 roberto Exp $
** Standard library for bitwise operations
** See Copyright Notice in lua.h
*/
@@ -13,17 +13,21 @@
#include "lualib.h"
+#if defined(LUA_COMPAT_BITLIB) /* { */
+
+
/* number of bits to consider in a number */
#if !defined(LUA_NBITS)
#define LUA_NBITS 32
#endif
-/* type with (at least) LUA_NBITS bits */
-typedef unsigned long b_uint;
-
-
-#define ALLONES (~(((~(b_uint)0) << (LUA_NBITS - 1)) << 1))
+/*
+** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must
+** be made in two parts to avoid problems when LUA_NBITS is equal to the
+** number of bits in a lua_Unsigned.)
+*/
+#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1))
/* macro to trim extra bits */
@@ -35,9 +39,9 @@ typedef unsigned long b_uint;
-static b_uint andaux (lua_State *L) {
+static lua_Unsigned andaux (lua_State *L) {
int i, n = lua_gettop(L);
- b_uint r = ~(b_uint)0;
+ lua_Unsigned r = ~(lua_Unsigned)0;
for (i = 1; i <= n; i++)
r &= luaL_checkunsigned(L, i);
return trim(r);
@@ -45,14 +49,14 @@ static b_uint andaux (lua_State *L) {
static int b_and (lua_State *L) {
- b_uint r = andaux(L);
+ lua_Unsigned r = andaux(L);
lua_pushunsigned(L, r);
return 1;
}
static int b_test (lua_State *L) {
- b_uint r = andaux(L);
+ lua_Unsigned r = andaux(L);
lua_pushboolean(L, r != 0);
return 1;
}
@@ -60,7 +64,7 @@ static int b_test (lua_State *L) {
static int b_or (lua_State *L) {
int i, n = lua_gettop(L);
- b_uint r = 0;
+ lua_Unsigned r = 0;
for (i = 1; i <= n; i++)
r |= luaL_checkunsigned(L, i);
lua_pushunsigned(L, trim(r));
@@ -70,7 +74,7 @@ static int b_or (lua_State *L) {
static int b_xor (lua_State *L) {
int i, n = lua_gettop(L);
- b_uint r = 0;
+ lua_Unsigned r = 0;
for (i = 1; i <= n; i++)
r ^= luaL_checkunsigned(L, i);
lua_pushunsigned(L, trim(r));
@@ -79,13 +83,13 @@ static int b_xor (lua_State *L) {
static int b_not (lua_State *L) {
- b_uint r = ~luaL_checkunsigned(L, 1);
+ lua_Unsigned r = ~luaL_checkunsigned(L, 1);
lua_pushunsigned(L, trim(r));
return 1;
}
-static int b_shift (lua_State *L, b_uint r, int i) {
+static int b_shift (lua_State *L, lua_Unsigned r, int i) {
if (i < 0) { /* shift right? */
i = -i;
r = trim(r);
@@ -113,14 +117,14 @@ static int b_rshift (lua_State *L) {
static int b_arshift (lua_State *L) {
- b_uint r = luaL_checkunsigned(L, 1);
+ lua_Unsigned r = luaL_checkunsigned(L, 1);
int i = luaL_checkint(L, 2);
- if (i < 0 || !(r & ((b_uint)1 << (LUA_NBITS - 1))))
+ if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1))))
return b_shift(L, r, -i);
else { /* arithmetic shift for 'negative' number */
if (i >= LUA_NBITS) r = ALLONES;
else
- r = trim((r >> i) | ~(trim(~(b_uint)0) >> i)); /* add signal bit */
+ r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */
lua_pushunsigned(L, r);
return 1;
}
@@ -128,10 +132,11 @@ static int b_arshift (lua_State *L) {
static int b_rot (lua_State *L, int i) {
- b_uint r = luaL_checkunsigned(L, 1);
+ lua_Unsigned r = luaL_checkunsigned(L, 1);
i &= (LUA_NBITS - 1); /* i = i % NBITS */
r = trim(r);
- r = (r << i) | (r >> (LUA_NBITS - i));
+ if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */
+ r = (r << i) | (r >> (LUA_NBITS - i));
lua_pushunsigned(L, trim(r));
return 1;
}
@@ -167,7 +172,7 @@ static int fieldargs (lua_State *L, int farg, int *width) {
static int b_extract (lua_State *L) {
int w;
- b_uint r = trim(luaL_checkunsigned(L, 1));
+ lua_Unsigned r = trim(luaL_checkunsigned(L, 1));
int f = fieldargs(L, 2, &w);
r = (r >> f) & mask(w);
lua_pushunsigned(L, r);
@@ -177,8 +182,8 @@ static int b_extract (lua_State *L) {
static int b_replace (lua_State *L) {
int w;
- b_uint r = trim(luaL_checkunsigned(L, 1));
- b_uint v = luaL_checkunsigned(L, 2);
+ lua_Unsigned r = trim(luaL_checkunsigned(L, 1));
+ lua_Unsigned v = luaL_checkunsigned(L, 2);
int f = fieldargs(L, 3, &w);
int m = mask(w);
v &= m; /* erase bits outside given width */
@@ -211,3 +216,13 @@ LUAMOD_API int luaopen_bit32 (lua_State *L) {
return 1;
}
+
+#else /* }{ */
+
+
+LUAMOD_API int luaopen_bit32 (lua_State *L) {
+ lua_pushnil(L);
+ return 1;
+}
+
+#endif /* } */
diff --git a/src/lcode.c b/src/lcode.c
index 261090e0..2e8b3fb4 100644
--- a/src/lcode.c
+++ b/src/lcode.c
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.c,v 2.71 2013/06/25 18:57:18 roberto Exp $
+** $Id: lcode.c,v 2.85 2014/03/21 13:52:33 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -307,17 +307,21 @@ static void freeexp (FuncState *fs, expdesc *e) {
}
+/*
+** Use scanner's table to cache position of constants in constant list
+** and try to reuse constants
+*/
static int addk (FuncState *fs, TValue *key, TValue *v) {
lua_State *L = fs->ls->L;
- TValue *idx = luaH_set(L, fs->h, key);
Proto *f = fs->f;
+ TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */
int k, oldsize;
- if (ttisinteger(idx)) {
+ if (ttisinteger(idx)) { /* is there an index there? */
k = ivalue(idx);
- if (luaV_rawequalobj(&f->k[k], v))
- return k;
- /* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0");
- go through and create a new entry for this value */
+ /* correct value? (warning: must distinguish floats from integers!) */
+ if (k < fs->nk && ttype(&f->k[k]) == ttype(v) &&
+ luaV_rawequalobj(&f->k[k], v))
+ return k; /* reuse index */
}
/* constant not found; create a new entry */
oldsize = f->sizek;
@@ -360,7 +364,7 @@ int luaK_intK (FuncState *fs, lua_Integer n) {
*/
static int luaK_numberK (FuncState *fs, lua_Number r) {
TValue o;
- lua_assert(!luai_numisnan(NULL, r) && !isminuszero(r));
+ lua_assert(!luai_numisnan(r) && !isminuszero(r));
setnvalue(&o, r);
return addk(fs, &o, &o);
}
@@ -377,7 +381,7 @@ static int nilK (FuncState *fs) {
TValue k, v;
setnilvalue(&v);
/* cannot use nil as key; instead use table itself to represent nil */
- sethvalue(fs->ls->L, &k, fs->h);
+ sethvalue(fs->ls->L, &k, fs->ls->h);
return addk(fs, &k, &v);
}
@@ -746,24 +750,46 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
}
-static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
- TValue v1, v2, res;
+/*
+** return false if folding can raise an error
+*/
+static int validop (int op, TValue *v1, TValue *v2) {
+ lua_Number a, b;
lua_Integer i;
- if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2))
+ cast_void(a); cast_void(b); /* macro may not use its arguments */
+ if (luai_numinvalidop(op, (cast_void(tonumber(v1, &a)), a),
+ (cast_void(tonumber(v2, &b)), b)))
return 0;
- if (op == OP_IDIV &&
- (!tointeger(&v1, &i) || !tointeger(&v2, &i) || i == 0))
- return 0; /* avoid division by 0 and conversion errors */
- if (op == OP_MOD && ttisinteger(&v1) && ttisinteger(&v2) && ivalue(&v2) == 0)
- return 0; /* avoid module by 0 at compile time */
- luaO_arith(NULL, op - OP_ADD + LUA_OPADD, &v1, &v2, &res);
+ switch (op) {
+ case LUA_OPIDIV: /* division by 0 and conversion errors */
+ return (tointeger(v1, &i) && tointeger(v2, &i) && i != 0);
+ case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR:
+ case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: /* conversion errors */
+ return (tointeger(v1, &i) && tointeger(v2, &i));
+ case LUA_OPMOD: /* integer module by 0 */
+ return !(ttisinteger(v1) && ttisinteger(v2) && ivalue(v2) == 0);
+ case LUA_OPPOW: /* negative integer exponentiation */
+ return !(ttisinteger(v1) && ttisinteger(v2) && ivalue(v2) < 0);
+ default: return 1; /* everything else is valid */
+ }
+}
+
+
+/*
+** Try to "constant-fold" an operation; return 1 iff successful
+*/
+static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) {
+ TValue v1, v2, res;
+ if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2))
+ return 0; /* non-numeric operands or not safe to fold */
+ luaO_arith(fs->ls->L, op, &v1, &v2, &res);
if (ttisinteger(&res)) {
e1->k = VKINT;
e1->u.ival = ivalue(&res);
}
else {
lua_Number n = fltvalue(&res);
- if (luai_numisnan(NULL, n) || isminuszero(n))
+ if (luai_numisnan(n) || isminuszero(n))
return 0; /* folds neither NaN nor -0 */
e1->k = VKFLT;
e1->u.nval = n;
@@ -774,9 +800,16 @@ static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
static void codearith (FuncState *fs, OpCode op,
expdesc *e1, expdesc *e2, int line) {
- if (!constfolding(op, e1, e2)) { /* could not fold operation? */
- int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0;
- int o1 = luaK_exp2RK(fs, e1);
+ if (!constfolding(fs, op - OP_ADD + LUA_OPADD, e1, e2)) {
+ int o1, o2;
+ if (op == OP_UNM || op == OP_BNOT || op == OP_LEN) {
+ o2 = 0;
+ o1 = luaK_exp2anyreg(fs, e1); /* cannot operate on constants */
+ }
+ else { /* regular case (binary operators) */
+ o2 = luaK_exp2RK(fs, e2);
+ o1 = luaK_exp2RK(fs, e1);
+ }
if (o1 > o2) {
freeexp(fs, e1);
freeexp(fs, e2);
@@ -810,21 +843,13 @@ static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
expdesc e2;
- e2.t = e2.f = NO_JUMP; e2.k = VKFLT; e2.u.nval = 0;
+ e2.t = e2.f = NO_JUMP; e2.k = VKINT; e2.u.ival = 0;
switch (op) {
- case OPR_MINUS: {
- if (!constfolding(OP_UNM, e, e)) { /* cannot fold it? */
- luaK_exp2anyreg(fs, e);
- codearith(fs, OP_UNM, e, &e2, line);
- }
+ case OPR_MINUS: case OPR_BNOT: case OPR_LEN: {
+ codearith(fs, cast(OpCode, (op - OPR_MINUS) + 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, line);
- break;
- }
default: lua_assert(0);
}
}
@@ -846,7 +871,9 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
}
case OPR_ADD: case OPR_SUB:
case OPR_MUL: case OPR_DIV: case OPR_IDIV:
- case OPR_MOD: case OPR_POW: {
+ case OPR_MOD: case OPR_POW:
+ case OPR_BAND: case OPR_BOR: case OPR_BXOR:
+ case OPR_SHL: case OPR_SHR: {
if (!tonumeral(v, NULL)) luaK_exp2RK(fs, v);
break;
}
@@ -890,8 +917,10 @@ void luaK_posfix (FuncState *fs, BinOpr op,
break;
}
case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
- case OPR_IDIV: case OPR_MOD: case OPR_POW: {
- codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2, line);
+ case OPR_IDIV: case OPR_MOD: case OPR_POW:
+ case OPR_BAND: case OPR_BOR: case OPR_BXOR:
+ case OPR_SHL: case OPR_SHR: {
+ 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 07d451b4..43ab86db 100644
--- a/src/lcode.h
+++ b/src/lcode.h
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.h,v 1.60 2013/04/26 13:07:53 roberto Exp $
+** $Id: lcode.h,v 1.63 2013/12/30 20:47:58 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -24,7 +24,11 @@
** grep "ORDER OPR" if you change these enums (ORDER OP)
*/
typedef enum BinOpr {
- OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_IDIV, OPR_MOD, OPR_POW,
+ OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW,
+ OPR_DIV,
+ OPR_IDIV,
+ OPR_BAND, OPR_BOR, OPR_BXOR,
+ OPR_SHL, OPR_SHR,
OPR_CONCAT,
OPR_EQ, OPR_LT, OPR_LE,
OPR_NE, OPR_GT, OPR_GE,
@@ -33,7 +37,7 @@ typedef enum BinOpr {
} BinOpr;
-typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
+typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
#define getcode(fs,e) ((fs)->f->code[(e)->u.info])
diff --git a/src/ldblib.c b/src/ldblib.c
index 30499a62..8a724a1e 100644
--- a/src/ldblib.c
+++ b/src/ldblib.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldblib.c,v 1.133 2013/06/25 19:37:00 roberto Exp $
+** $Id: ldblib.c,v 1.137 2014/03/12 20:57:40 roberto Exp $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
@@ -69,11 +69,8 @@ static int db_getuservalue (lua_State *L) {
static int db_setuservalue (lua_State *L) {
- if (lua_type(L, 1) == LUA_TLIGHTUSERDATA)
- luaL_argerror(L, 1, "full userdata expected, got light userdata");
luaL_checktype(L, 1, LUA_TUSERDATA);
- if (!lua_isnoneornil(L, 2))
- luaL_checktype(L, 2, LUA_TTABLE);
+ luaL_checkany(L, 2);
lua_settop(L, 2);
lua_setuservalue(L, 1);
return 1;
@@ -273,8 +270,7 @@ static void hookf (lua_State *L, lua_Debug *ar) {
{"call", "return", "line", "count", "tail call"};
gethooktable(L);
lua_pushthread(L);
- lua_rawget(L, -2);
- if (lua_isfunction(L, -1)) {
+ if (lua_rawget(L, -2) == LUA_TFUNCTION) {
lua_pushstring(L, hooknames[(int)ar->event]);
if (ar->currentline >= 0)
lua_pushinteger(L, ar->currentline);
diff --git a/src/ldebug.c b/src/ldebug.c
index c9b88803..c1f8c3f2 100644
--- a/src/ldebug.c
+++ b/src/ldebug.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldebug.c,v 2.95 2013/05/06 17:21:59 roberto Exp $
+** $Id: ldebug.c,v 2.97 2013/12/09 14:21:10 roberto Exp $
** Debug Interface
** See Copyright Notice in lua.h
*/
@@ -50,7 +50,7 @@ static int currentline (CallInfo *ci) {
/*
** this function can be called asynchronous (e.g. during a signal)
*/
-LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
+LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
if (func == NULL || mask == 0) { /* turn off hooks? */
mask = 0;
func = NULL;
@@ -61,7 +61,6 @@ LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
L->basehookcount = count;
resethookcount(L);
L->hookmask = cast_byte(mask);
- return 1;
}
@@ -327,12 +326,20 @@ static void kname (Proto *p, int pc, int c, const char **name) {
}
+static int filterpc (int pc, int jmptarget) {
+ if (pc < jmptarget) /* is code conditional (inside a jump)? */
+ return -1; /* cannot know who sets that register */
+ else return pc; /* current position sets that register */
+}
+
+
/*
** try to find last instruction before 'lastpc' that modified register 'reg'
*/
static int findsetreg (Proto *p, int lastpc, int reg) {
int pc;
int setreg = -1; /* keep last instruction that changed 'reg' */
+ int jmptarget = 0; /* any code before this address is conditional */
for (pc = 0; pc < lastpc; pc++) {
Instruction i = p->code[pc];
OpCode op = GET_OPCODE(i);
@@ -341,33 +348,33 @@ static int findsetreg (Proto *p, int lastpc, int reg) {
case OP_LOADNIL: {
int b = GETARG_B(i);
if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */
- setreg = pc;
+ setreg = filterpc(pc, jmptarget);
break;
}
case OP_TFORCALL: {
- if (reg >= a + 2) setreg = pc; /* affect all regs above its base */
+ if (reg >= a + 2) /* affect all regs above its base */
+ setreg = filterpc(pc, jmptarget);
break;
}
case OP_CALL:
case OP_TAILCALL: {
- if (reg >= a) setreg = pc; /* affect all registers above base */
+ if (reg >= a) /* affect all registers above base */
+ setreg = filterpc(pc, jmptarget);
break;
}
case OP_JMP: {
int b = GETARG_sBx(i);
int dest = pc + 1 + b;
/* jump is forward and do not skip `lastpc'? */
- if (pc < dest && dest <= lastpc)
- pc += b; /* do the jump */
- break;
- }
- case OP_TEST: {
- if (reg == a) setreg = pc; /* jumped code can change 'a' */
+ if (pc < dest && dest <= lastpc) {
+ if (dest > jmptarget)
+ jmptarget = dest; /* update 'jmptarget' */
+ }
break;
}
default:
if (testAMode(op) && reg == a) /* any instruction that set A */
- setreg = pc;
+ setreg = filterpc(pc, jmptarget);
break;
}
}
diff --git a/src/ldebug.h b/src/ldebug.h
index c668e1e4..1f3bf6cf 100644
--- a/src/ldebug.h
+++ b/src/ldebug.h
@@ -1,5 +1,5 @@
/*
-** $Id: ldebug.h,v 2.10 2013/05/06 17:19:11 roberto Exp $
+** $Id: ldebug.h,v 2.11 2014/02/25 14:31:16 roberto Exp $
** Auxiliary functions from Debug Interface module
** See Copyright Notice in lua.h
*/
@@ -13,7 +13,7 @@
#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1)
-#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0)
+#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : -1)
#define resethookcount(L) (L->hookcount = L->basehookcount)
diff --git a/src/ldo.c b/src/ldo.c
index abf082d4..5075ce39 100644
--- a/src/ldo.c
+++ b/src/ldo.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.c,v 2.109 2013/04/19 21:05:04 roberto Exp $
+** $Id: ldo.c,v 2.115 2014/03/21 13:52:33 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -46,30 +46,33 @@
** C++ code, with _longjmp/_setjmp when asked to use them, and with
** longjmp/setjmp otherwise.
*/
-#if !defined(LUAI_THROW)
+#if !defined(LUAI_THROW) /* { */
+
+#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* { */
-#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP)
/* C++ exceptions */
#define LUAI_THROW(L,c) throw(c)
#define LUAI_TRY(L,c,a) \
try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; }
#define luai_jmpbuf int /* dummy variable */
-#elif defined(LUA_USE_ULONGJMP)
-/* in Unix, try _longjmp/_setjmp (more efficient) */
+#elif defined(LUA_USE_POSIX) /* }{ */
+
+/* in POSIX, try _longjmp/_setjmp (more efficient) */
#define LUAI_THROW(L,c) _longjmp((c)->b, 1)
#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a }
#define luai_jmpbuf jmp_buf
-#else
-/* default handling with long jumps */
+#else /* }{ */
+
+/* ANSI handling with long jumps */
#define LUAI_THROW(L,c) longjmp((c)->b, 1)
#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a }
#define luai_jmpbuf jmp_buf
-#endif
+#endif /* } */
-#endif
+#endif /* } */
@@ -141,10 +144,10 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
static void correctstack (lua_State *L, TValue *oldstack) {
CallInfo *ci;
- GCObject *up;
+ UpVal *up;
L->top = (L->top - oldstack) + L->stack;
- for (up = L->openupval; up != NULL; up = up->gch.next)
- gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;
+ for (up = L->openupval; up != NULL; up = up->u.open.next)
+ up->v = (up->v - oldstack) + L->stack;
for (ci = L->ci; ci != NULL; ci = ci->previous) {
ci->top = (ci->top - oldstack) + L->stack;
ci->func = (ci->func - oldstack) + L->stack;
@@ -206,7 +209,11 @@ void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L);
int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK;
- if (inuse > LUAI_MAXSTACK || /* handling stack overflow? */
+ if (L->stacksize > LUAI_MAXSTACK) /* was handling stack overflow? */
+ luaE_freeCI(L); /* free all CIs (list grew because of an error) */
+ else
+ luaE_shrinkCI(L); /* shrink list */
+ if (inuse > LUAI_MAXSTACK || /* still handling stack overflow? */
goodsize >= L->stacksize) /* would grow instead of shrink? */
condmovestack(L); /* don't change stack (change only for debugging) */
else
@@ -534,6 +541,7 @@ static void resume (lua_State *L, void *ud) {
LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
int status;
+ int oldnny = L->nny; /* save 'nny' */
lua_lock(L);
luai_userstateresume(L, nargs);
L->nCcalls = (from) ? from->nCcalls + 1 : 1;
@@ -555,7 +563,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
}
lua_assert(status == L->status);
}
- L->nny = 1; /* do not allow yields */
+ L->nny = oldnny; /* restore 'nny' */
L->nCcalls--;
lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0));
lua_unlock(L);
@@ -637,7 +645,6 @@ static void checkmode (lua_State *L, const char *mode, const char *x) {
static void f_parser (lua_State *L, void *ud) {
- int i;
Closure *cl;
struct SParser *p = cast(struct SParser *, ud);
int c = zgetc(p->z); /* read first character */
@@ -650,11 +657,7 @@ static void f_parser (lua_State *L, void *ud) {
cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
}
lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues);
- for (i = 0; i < cl->l.nupvalues; i++) { /* initialize upvalues */
- UpVal *up = luaF_newupval(L);
- cl->l.upvals[i] = up;
- luaC_objbarrier(L, cl, up);
- }
+ luaF_initupvals(L, &cl->l);
}
diff --git a/src/ldump.c b/src/ldump.c
index b3a25624..a4c96416 100644
--- a/src/ldump.c
+++ b/src/ldump.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldump.c,v 2.19 2013/04/26 18:48:35 roberto Exp $
+** $Id: ldump.c,v 2.27 2014/03/11 18:56:27 roberto Exp $
** save precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -15,167 +15,188 @@
#include "lstate.h"
#include "lundump.h"
+
typedef struct {
- lua_State* L;
- lua_Writer writer;
- void* data;
- int strip;
- int status;
+ lua_State *L;
+ lua_Writer writer;
+ void *data;
+ int strip;
+ int status;
} DumpState;
-#define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D)
-#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D)
-
-static void DumpBlock(const void* b, size_t size, DumpState* D)
-{
- if (D->status==0)
- {
- lua_unlock(D->L);
- D->status=(*D->writer)(D->L,b,size,D->data);
- lua_lock(D->L);
- }
+
+/*
+** All high-level dumps go through DumpVector; you can change it to
+** change the endianess of the result
+*/
+#define DumpVector(v,n,D) DumpBlock(v,(n)*sizeof((v)[0]),D)
+
+#define DumpLiteral(s,D) DumpBlock(s, sizeof(s) - sizeof(char), D)
+
+
+static void DumpBlock (const void *b, size_t size, DumpState *D) {
+ if (D->status == 0) {
+ lua_unlock(D->L);
+ D->status = (*D->writer)(D->L, b, size, D->data);
+ lua_lock(D->L);
+ }
}
-static void DumpChar(int y, DumpState* D)
-{
- char x=(char)y;
- DumpVar(x,D);
+
+#define DumpVar(x,D) DumpVector(&x,1,D)
+
+
+static void DumpByte (int y, DumpState *D) {
+ lu_byte x = (lu_byte)y;
+ DumpVar(x, D);
}
-static void DumpInt(int x, DumpState* D)
-{
- DumpVar(x,D);
+
+static void DumpInt (int x, DumpState *D) {
+ DumpVar(x, D);
}
-static void DumpNumber(lua_Number x, DumpState* D)
-{
- DumpVar(x,D);
+
+static void DumpNumber (lua_Number x, DumpState *D) {
+ DumpVar(x, D);
}
-static void DumpInteger(lua_Integer x, DumpState* D)
-{
- DumpVar(x,D);
+
+static void DumpInteger (lua_Integer x, DumpState *D) {
+ DumpVar(x, D);
}
-static void DumpVector(const void* b, int n, size_t size, DumpState* D)
-{
- DumpInt(n,D);
- DumpMem(b,n,size,D);
+
+static void DumpString (const TString *s, DumpState *D) {
+ if (s == NULL)
+ DumpByte(0, D);
+ else {
+ size_t size = s->tsv.len + 1; /* include trailing '\0' */
+ if (size < 0xFF)
+ DumpByte(size, D);
+ else {
+ DumpByte(0xFF, D);
+ DumpVar(size, D);
+ }
+ DumpVector(getstr(s), size - 1, D); /* no need to save '\0' */
+ }
}
-static void DumpString(const TString* s, DumpState* D)
-{
- if (s==NULL)
- {
- size_t size=0;
- DumpVar(size,D);
- }
- else
- {
- size_t size=s->tsv.len+1; /* include trailing '\0' */
- DumpVar(size,D);
- DumpBlock(getstr(s),size*sizeof(char),D);
- }
+
+static void DumpCode (const Proto *f, DumpState *D) {
+ DumpInt(f->sizecode, D);
+ DumpVector(f->code, f->sizecode, D);
}
-#define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D)
-
-static void DumpFunction(const Proto* f, DumpState* D);
-
-static void DumpConstants(const Proto* f, DumpState* D)
-{
- int i,n=f->sizek;
- DumpInt(n,D);
- for (i=0; i<n; i++)
- {
- const TValue* o=&f->k[i];
- DumpChar(ttype(o),D);
- switch (ttype(o))
- {
- case LUA_TNIL:
- break;
- case LUA_TBOOLEAN:
- DumpChar(bvalue(o),D);
- break;
- case LUA_TNUMFLT:
- DumpNumber(fltvalue(o),D);
- break;
- case LUA_TNUMINT:
- DumpInteger(ivalue(o),D);
- break;
- case LUA_TSHRSTR: case LUA_TLNGSTR:
- DumpString(rawtsvalue(o),D);
- break;
- default: lua_assert(0);
+
+static void DumpFunction(const Proto *f, DumpState *D);
+
+static void DumpConstants (const Proto *f, DumpState *D) {
+ int i;
+ int n = f->sizek;
+ DumpInt(n, D);
+ for (i = 0; i < n; i++) {
+ const TValue *o = &f->k[i];
+ DumpByte(ttype(o), D);
+ switch (ttype(o)) {
+ case LUA_TNIL:
+ break;
+ case LUA_TBOOLEAN:
+ DumpByte(bvalue(o), D);
+ break;
+ case LUA_TNUMFLT:
+ DumpNumber(fltvalue(o), D);
+ break;
+ case LUA_TNUMINT:
+ DumpInteger(ivalue(o), D);
+ break;
+ case LUA_TSHRSTR:
+ case LUA_TLNGSTR:
+ DumpString(rawtsvalue(o), D);
+ break;
+ default:
+ lua_assert(0);
+ }
}
- }
- n=f->sizep;
- DumpInt(n,D);
- for (i=0; i<n; i++) DumpFunction(f->p[i],D);
+ n = f->sizep;
+ DumpInt(n, D);
+ for (i = 0; i < n; i++)
+ DumpFunction(f->p[i], D);
}
-static void DumpUpvalues(const Proto* f, DumpState* D)
-{
- int i,n=f->sizeupvalues;
- DumpInt(n,D);
- for (i=0; i<n; i++)
- {
- DumpChar(f->upvalues[i].instack,D);
- DumpChar(f->upvalues[i].idx,D);
- }
+
+static void DumpUpvalues (const Proto *f, DumpState *D) {
+ int i, n = f->sizeupvalues;
+ DumpInt(n, D);
+ for (i = 0; i < n; i++) {
+ DumpByte(f->upvalues[i].instack, D);
+ DumpByte(f->upvalues[i].idx, D);
+ }
}
-static void DumpDebug(const Proto* f, DumpState* D)
-{
- int i,n;
- DumpString((D->strip) ? NULL : f->source,D);
- n= (D->strip) ? 0 : f->sizelineinfo;
- DumpVector(f->lineinfo,n,sizeof(int),D);
- n= (D->strip) ? 0 : f->sizelocvars;
- DumpInt(n,D);
- for (i=0; i<n; i++)
- {
- DumpString(f->locvars[i].varname,D);
- DumpInt(f->locvars[i].startpc,D);
- DumpInt(f->locvars[i].endpc,D);
- }
- n= (D->strip) ? 0 : f->sizeupvalues;
- DumpInt(n,D);
- for (i=0; i<n; i++) DumpString(f->upvalues[i].name,D);
+
+static void DumpDebug (const Proto *f, DumpState *D) {
+ int i, n;
+ DumpString((D->strip) ? NULL : f->source, D);
+ n = (D->strip) ? 0 : f->sizelineinfo;
+ DumpInt(n, D);
+ DumpVector(f->lineinfo, n, D);
+ n = (D->strip) ? 0 : f->sizelocvars;
+ DumpInt(n, D);
+ for (i = 0; i < n; i++) {
+ DumpString(f->locvars[i].varname, D);
+ DumpInt(f->locvars[i].startpc, D);
+ DumpInt(f->locvars[i].endpc, D);
+ }
+ n = (D->strip) ? 0 : f->sizeupvalues;
+ DumpInt(n, D);
+ for (i = 0; i < n; i++)
+ DumpString(f->upvalues[i].name, D);
}
-static void DumpFunction(const Proto* f, DumpState* D)
-{
- DumpInt(f->linedefined,D);
- DumpInt(f->lastlinedefined,D);
- DumpChar(f->numparams,D);
- DumpChar(f->is_vararg,D);
- DumpChar(f->maxstacksize,D);
- DumpCode(f,D);
- DumpConstants(f,D);
- DumpUpvalues(f,D);
- DumpDebug(f,D);
+
+static void DumpFunction (const Proto *f, DumpState *D) {
+ DumpInt(f->linedefined, D);
+ DumpInt(f->lastlinedefined, D);
+ DumpByte(f->numparams, D);
+ DumpByte(f->is_vararg, D);
+ DumpByte(f->maxstacksize, D);
+ DumpCode(f, D);
+ DumpConstants(f, D);
+ DumpUpvalues(f, D);
+ DumpDebug(f, D);
}
-static void DumpHeader(DumpState* D)
-{
- lu_byte h[LUAC_HEADERSIZE];
- luaU_header(h);
- DumpBlock(h,LUAC_HEADERSIZE,D);
+
+static void DumpHeader (DumpState *D) {
+ DumpLiteral(LUA_SIGNATURE, D);
+ DumpByte(LUAC_VERSION, D);
+ DumpByte(LUAC_FORMAT, D);
+ DumpLiteral(LUAC_DATA, D);
+ DumpByte(sizeof(int), D);
+ DumpByte(sizeof(size_t), D);
+ DumpByte(sizeof(Instruction), D);
+ DumpByte(sizeof(lua_Integer), D);
+ DumpByte(sizeof(lua_Number), D);
+ DumpInteger(LUAC_INT, D);
+ DumpNumber(LUAC_NUM, D);
}
+
/*
** dump Lua function as precompiled chunk
*/
-int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
-{
- DumpState D;
- D.L=L;
- D.writer=w;
- D.data=data;
- D.strip=strip;
- D.status=0;
- DumpHeader(&D);
- DumpFunction(f,&D);
- return D.status;
+int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data,
+ int strip) {
+ DumpState D;
+ D.L = L;
+ D.writer = w;
+ D.data = data;
+ D.strip = strip;
+ D.status = 0;
+ DumpHeader(&D);
+ DumpByte(f->sizeupvalues, &D);
+ DumpFunction(f, &D);
+ return D.status;
}
+
diff --git a/src/lfunc.c b/src/lfunc.c
index c2128405..c78daf1e 100644
--- a/src/lfunc.c
+++ b/src/lfunc.c
@@ -1,5 +1,5 @@
/*
-** $Id: lfunc.c,v 2.30 2012/10/03 12:36:46 roberto Exp $
+** $Id: lfunc.c,v 2.41 2014/02/18 13:39:37 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@@ -21,94 +21,79 @@
Closure *luaF_newCclosure (lua_State *L, int n) {
- Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), NULL, 0)->cl;
+ Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n))->cl;
c->c.nupvalues = cast_byte(n);
return c;
}
Closure *luaF_newLclosure (lua_State *L, int n) {
- Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl;
+ Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n))->cl;
c->l.p = NULL;
c->l.nupvalues = cast_byte(n);
while (n--) c->l.upvals[n] = NULL;
return c;
}
-
-UpVal *luaF_newupval (lua_State *L) {
- UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), NULL, 0)->uv;
- uv->v = &uv->u.value;
- setnilvalue(uv->v);
- return uv;
+/*
+** fill a closure with new closed upvalues
+*/
+void luaF_initupvals (lua_State *L, LClosure *cl) {
+ int i;
+ for (i = 0; i < cl->nupvalues; i++) {
+ UpVal *uv = luaM_new(L, UpVal);
+ uv->refcount = 1;
+ uv->v = &uv->u.value; /* make it closed */
+ setnilvalue(uv->v);
+ cl->upvals[i] = uv;
+ }
}
UpVal *luaF_findupval (lua_State *L, StkId level) {
- global_State *g = G(L);
- GCObject **pp = &L->openupval;
+ UpVal **pp = &L->openupval;
UpVal *p;
UpVal *uv;
- while (*pp != NULL && (p = gco2uv(*pp))->v >= level) {
- GCObject *o = obj2gco(p);
- lua_assert(p->v != &p->u.value);
- lua_assert(!isold(o) || isold(obj2gco(L)));
- if (p->v == level) { /* found a corresponding upvalue? */
- if (isdead(g, o)) /* is it dead? */
- changewhite(o); /* resurrect it */
- return p;
- }
- pp = &p->next;
+ lua_assert(isintwups(L) || L->openupval == NULL);
+ while (*pp != NULL && (p = *pp)->v >= level) {
+ lua_assert(upisopen(p));
+ if (p->v == level) /* found a corresponding upvalue? */
+ return p; /* return it */
+ pp = &p->u.open.next;
}
- /* not found: create a new one */
- uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv;
+ /* not found: create a new upvalue */
+ uv = luaM_new(L, UpVal);
+ uv->refcount = 0;
+ uv->u.open.next = *pp; /* link it to list of open upvalues */
+ uv->u.open.touched = 1;
+ *pp = uv;
uv->v = level; /* current value lives in the stack */
- uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */
- uv->u.l.next = g->uvhead.u.l.next;
- uv->u.l.next->u.l.prev = uv;
- g->uvhead.u.l.next = uv;
- lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
+ if (!isintwups(L)) { /* thread not in list of threads with upvalues? */
+ L->twups = G(L)->twups; /* link it to the list */
+ G(L)->twups = L;
+ }
return uv;
}
-static void unlinkupval (UpVal *uv) {
- lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
- uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */
- uv->u.l.prev->u.l.next = uv->u.l.next;
-}
-
-
-void luaF_freeupval (lua_State *L, UpVal *uv) {
- if (uv->v != &uv->u.value) /* is it open? */
- unlinkupval(uv); /* remove from open list */
- luaM_free(L, uv); /* free upvalue */
-}
-
-
void luaF_close (lua_State *L, StkId level) {
UpVal *uv;
- global_State *g = G(L);
- while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) {
- GCObject *o = obj2gco(uv);
- lua_assert(!isblack(o) && uv->v != &uv->u.value);
- L->openupval = uv->next; /* remove from `open' list */
- if (isdead(g, o))
- luaF_freeupval(L, uv); /* free upvalue */
+ while (L->openupval != NULL && (uv = L->openupval)->v >= level) {
+ lua_assert(upisopen(uv));
+ L->openupval = uv->u.open.next; /* remove from `open' list */
+ if (uv->refcount == 0) /* no references? */
+ luaM_free(L, uv); /* free upvalue */
else {
- 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 */
- gch(o)->next = g->allgc; /* link upvalue into 'allgc' list */
- g->allgc = o;
- luaC_checkupvalcolor(g, uv);
+ luaC_upvalbarrier(L, uv);
}
}
}
Proto *luaF_newproto (lua_State *L) {
- Proto *f = &luaC_newobj(L, LUA_TPROTO, sizeof(Proto), NULL, 0)->p;
+ Proto *f = &luaC_newobj(L, LUA_TPROTO, sizeof(Proto))->p;
f->k = NULL;
f->sizek = 0;
f->p = NULL;
diff --git a/src/lfunc.h b/src/lfunc.h
index e236a717..dce699bc 100644
--- a/src/lfunc.h
+++ b/src/lfunc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lfunc.h,v 2.8 2012/05/08 13:53:33 roberto Exp $
+** $Id: lfunc.h,v 2.13 2014/02/18 13:39:37 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@@ -18,14 +18,35 @@
cast(int, sizeof(TValue *)*((n)-1)))
+/* test whether thread is in 'twups' list */
+#define isintwups(L) (L->twups != L)
+
+
+/*
+** Upvalues for Lua closures
+*/
+struct UpVal {
+ TValue *v; /* points to stack or to its own value */
+ lu_mem refcount; /* reference counter */
+ union {
+ struct { /* (when open) */
+ UpVal *next; /* linked list */
+ int touched; /* mark to avoid cycles with dead threads */
+ } open;
+ TValue value; /* the value (when closed) */
+ } u;
+};
+
+#define upisopen(up) ((up)->v != &(up)->u.value)
+
+
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
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 void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (lua_State *L, StkId level);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
-LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv);
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
int pc);
diff --git a/src/lgc.c b/src/lgc.c
index 5e305fb3..9ecfd3b9 100644
--- a/src/lgc.c
+++ b/src/lgc.c
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.c,v 2.141 2013/04/26 18:26:49 roberto Exp $
+** $Id: lgc.c,v 2.179 2014/03/21 13:52:33 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -23,6 +23,11 @@
#include "ltm.h"
+/*
+** internal state for collector while inside the atomic phase. The
+** collector should never be in this state while running regular code.
+*/
+#define GCSinsideatomic (GCSpause + 1)
/*
** cost of sweeping one element (the size of a small object divided
@@ -33,8 +38,8 @@
/* maximum number of elements to sweep in each single step */
#define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4))
-/* maximum number of finalizers to call in each GC step */
-#define GCFINALIZENUM 4
+/* cost of calling one finalizer */
+#define GCFINALIZECOST GCSWEEPCOST
/*
@@ -52,10 +57,10 @@
/*
-** 'makewhite' erases all color bits plus the old bit and then
-** sets only the current white bit
+** 'makewhite' erases all color bits then sets only the current white
+** bit
*/
-#define maskcolors (~(bit2mask(BLACKBIT, OLDBIT) | WHITEBITS))
+#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS))
#define makewhite(g,x) \
(gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g)))
@@ -63,7 +68,7 @@
#define black2gray(x) resetbit(gch(x)->marked, BLACKBIT)
-#define isfinalized(x) testbit(gch(x)->marked, FINALIZEDBIT)
+#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x)))
#define checkdeadkey(n) lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n)))
@@ -75,8 +80,8 @@
#define markvalue(g,o) { checkconsistency(o); \
if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }
-#define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \
- reallymarkobject(g, obj2gco(t)); }
+#define markobject(g,t) \
+ { if ((t) && iswhite(obj2gco(t))) reallymarkobject(g, obj2gco(t)); }
static void reallymarkobject (global_State *g, GCObject *o);
@@ -136,8 +141,8 @@ void luaC_barrier_ (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 != GCSpause);
- lua_assert(gch(o)->tt != LUA_TTABLE);
- if (keepinvariantout(g)) /* must keep invariant? */
+ lua_assert(gch(o)->tt != LUA_TTABLE); /* tables use a back barrier */
+ if (keepinvariant(g)) /* must keep invariant? */
reallymarkobject(g, v); /* restore invariant */
else { /* sweep phase */
lua_assert(issweepphase(g));
@@ -162,64 +167,41 @@ void luaC_barrierback_ (lua_State *L, GCObject *o) {
/*
-** barrier for prototypes. When creating first closure (cache is
-** NULL), use a forward barrier; this may be the only closure of the
-** prototype (if it is a "regular" function, with a single instance)
-** and the prototype may be big, so it is better to avoid traversing
-** it again. Otherwise, use a backward barrier, to avoid marking all
-** possible instances.
+** barrier for assignments to closed upvalues. Because upvalues are
+** shared among closures, it is impossible to know the color of all
+** closures pointing to it. So, we assume that the object being assigned
+** must be marked.
*/
-LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c) {
+LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) {
global_State *g = G(L);
- lua_assert(isblack(obj2gco(p)));
- if (p->cache == NULL) { /* first time? */
- luaC_objbarrier(L, p, c);
- }
- else { /* use a backward barrier */
- black2gray(obj2gco(p)); /* make prototype gray (again) */
- p->gclist = g->grayagain;
- g->grayagain = obj2gco(p);
- }
+ GCObject *o = gcvalue(uv->v);
+ lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */
+ if (keepinvariant(g))
+ markobject(g, o);
}
-/*
-** 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);
- }
- }
+void luaC_fix (lua_State *L, GCObject *o) {
+ global_State *g = G(L);
+ lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */
+ white2gray(o); /* they will be gray forever */
+ g->allgc = o->gch.next; /* remove object from 'allgc' list */
+ o->gch.next = g->fixedgc; /* link it to 'fixedgc' list */
+ g->fixedgc = 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).
+** it to 'allgc' list.
*/
-GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
- int offset) {
+GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
global_State *g = G(L);
- char *raw = cast(char *, luaM_newobject(L, novariant(tt), sz));
- GCObject *o = obj2gco(raw + offset);
- if (list == NULL)
- list = &g->allgc; /* standard list for collectable objects */
+ GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz));
gch(o)->marked = luaC_white(g);
gch(o)->tt = tt;
- gch(o)->next = *list;
- *list = o;
+ gch(o)->next = g->allgc;
+ g->allgc = o;
return o;
}
@@ -241,57 +223,53 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
** upvalues are already linked in 'headuv' list.)
*/
static void reallymarkobject (global_State *g, GCObject *o) {
- lu_mem size;
+ reentry:
white2gray(o);
switch (gch(o)->tt) {
case LUA_TSHRSTR:
case LUA_TLNGSTR: {
- size = sizestring(gco2ts(o));
- break; /* nothing else to mark; make it black */
- }
- case LUA_TUSERDATA: {
- Table *mt = gco2u(o)->metatable;
- markobject(g, mt);
- markobject(g, gco2u(o)->env);
- size = sizeudata(gco2u(o));
+ gray2black(o);
+ g->GCmemtrav += sizestring(gco2ts(o));
break;
}
- case LUA_TUPVAL: {
- UpVal *uv = gco2uv(o);
- markvalue(g, uv->v);
- if (uv->v != &uv->u.value) /* open? */
- return; /* open upvalues remain gray */
- size = sizeof(UpVal);
+ case LUA_TUSERDATA: {
+ TValue uvalue;
+ markobject(g, gco2u(o)->metatable); /* mark its metatable */
+ gray2black(o);
+ g->GCmemtrav += sizeudata(gco2u(o));
+ getuservalue(g->mainthread, rawgco2u(o), &uvalue);
+ if (valiswhite(&uvalue)) { /* markvalue(g, &uvalue); */
+ o = gcvalue(&uvalue);
+ goto reentry;
+ }
break;
}
case LUA_TLCL: {
gco2lcl(o)->gclist = g->gray;
g->gray = o;
- return;
+ break;
}
case LUA_TCCL: {
gco2ccl(o)->gclist = g->gray;
g->gray = o;
- return;
+ break;
}
case LUA_TTABLE: {
linktable(gco2t(o), &g->gray);
- return;
+ break;
}
case LUA_TTHREAD: {
gco2th(o)->gclist = g->gray;
g->gray = o;
- return;
+ break;
}
case LUA_TPROTO: {
gco2p(o)->gclist = g->gray;
g->gray = o;
- return;
+ break;
}
- default: lua_assert(0); return;
+ default: lua_assert(0); break;
}
- gray2black(o);
- g->GCmemtrav += size;
}
@@ -310,29 +288,41 @@ static void markmt (global_State *g) {
*/
static void markbeingfnz (global_State *g) {
GCObject *o;
- for (o = g->tobefnz; o != NULL; o = gch(o)->next) {
- makewhite(g, o);
- reallymarkobject(g, o);
- }
+ for (o = g->tobefnz; o != NULL; o = gch(o)->next)
+ markobject(g, o);
}
/*
-** mark all values stored in marked open upvalues. (See comment in
-** 'lstate.h'.)
+** Mark all values stored in marked open upvalues from non-marked threads.
+** (Values from marked threads were already marked when traversing the
+** thread.) Remove from the list threads that no longer have upvalues and
+** not-marked threads.
*/
static void remarkupvals (global_State *g) {
- UpVal *uv;
- for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
- if (isgray(obj2gco(uv)))
- markvalue(g, uv->v);
+ lua_State *thread;
+ lua_State **p = &g->twups;
+ while ((thread = *p) != NULL) {
+ lua_assert(!isblack(obj2gco(thread))); /* threads are never black */
+ if (isgray(obj2gco(thread)) && thread->openupval != NULL)
+ p = &thread->twups; /* keep marked thread with upvalues in the list */
+ else { /* thread is not marked or without upvalues */
+ UpVal *uv;
+ *p = thread->twups; /* remove thread from the list */
+ thread->twups = thread; /* mark that it is out of list */
+ for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) {
+ if (uv->u.open.touched) {
+ markvalue(g, uv->v); /* remark upvalue's value */
+ uv->u.open.touched = 0;
+ }
+ }
+ }
}
}
/*
-** mark root set and reset all gray lists, to start a new
-** incremental (or full) collection
+** mark root set and reset all gray lists, to start a new collection
*/
static void restartcollection (global_State *g) {
g->gray = g->grayagain = NULL;
@@ -483,11 +473,24 @@ static lu_mem traverseCclosure (global_State *g, CClosure *cl) {
return sizeCclosure(cl->nupvalues);
}
+/*
+** open upvalues point to values in a thread, so those values should
+** be marked when the thread is traversed except in the atomic phase
+** (because then the value cannot be changed by the thread and the
+** thread may not be traversed again)
+*/
static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
int i;
markobject(g, cl->p); /* mark its prototype */
- for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */
- markobject(g, cl->upvals[i]);
+ for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */
+ UpVal *uv = cl->upvals[i];
+ if (uv != NULL) {
+ if (upisopen(uv) && g->gcstate != GCSinsideatomic)
+ uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */
+ else
+ markvalue(g, uv->v);
+ }
+ }
return sizeLclosure(cl->nupvalues);
}
@@ -497,17 +500,27 @@ static lu_mem traversestack (global_State *g, lua_State *th) {
StkId o = th->stack;
if (o == NULL)
return 1; /* stack not completely built yet */
+ lua_assert(g->gcstate == GCSinsideatomic ||
+ th->openupval == NULL || isintwups(th));
for (; o < th->top; o++) /* mark live elements in the stack */
markvalue(g, o);
- if (g->gcstate == GCSatomic) { /* final traversal? */
+ if (g->gcstate == GCSinsideatomic) { /* final traversal? */
StkId lim = th->stack + th->stacksize; /* real end of stack */
for (; o < lim; o++) /* clear not-marked stack slice */
setnilvalue(o);
+ /* 'remarkupvals' may have removed thread from 'twups' list */
+ if (!isintwups(th) && th->openupval != NULL) {
+ th->twups = g->twups; /* link it back to the list */
+ g->twups = th;
+ }
}
- else { /* count call infos to compute size */
+ else {
CallInfo *ci;
for (ci = &th->base_ci; ci != th->ci; ci = ci->next)
- n++;
+ n++; /* count call infos to compute size */
+ /* should not change the stack during an emergency gc cycle */
+ if (g->gckind != KGC_EMERGENCY)
+ luaD_shrinkstack(th);
}
return sizeof(lua_State) + sizeof(TValue) * th->stacksize +
sizeof(CallInfo) * n;
@@ -660,23 +673,41 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) {
}
+void luaC_upvdeccount (lua_State *L, UpVal *uv) {
+ lua_assert(uv->refcount > 0);
+ uv->refcount--;
+ if (uv->refcount == 0 && !upisopen(uv))
+ luaM_free(L, uv);
+}
+
+
+static void freeLclosure (lua_State *L, LClosure *cl) {
+ int i;
+ for (i = 0; i < cl->nupvalues; i++) {
+ UpVal *uv = cl->upvals[i];
+ if (uv)
+ luaC_upvdeccount(L, uv);
+ }
+ luaM_freemem(L, cl, sizeLclosure(cl->nupvalues));
+}
+
+
static void freeobj (lua_State *L, GCObject *o) {
switch (gch(o)->tt) {
case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
case LUA_TLCL: {
- luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues));
+ freeLclosure(L, gco2lcl(o));
break;
}
case LUA_TCCL: {
luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues));
break;
}
- case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;
case LUA_TTABLE: luaH_free(L, gco2t(o)); break;
case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break;
case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;
case LUA_TSHRSTR:
- G(L)->strt.nuse--;
+ luaS_remove(L, rawgco2ts(o)); /* remove it from hash table */
/* go through */
case LUA_TLNGSTR: {
luaM_freemem(L, o, sizestring(gco2ts(o)));
@@ -692,45 +723,16 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count);
/*
-** 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 (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.
+** (non current) white and not fixed; change all non-dead objects back
+** to white, preparing for next collection cycle.
** When object is a thread, sweep its list of open upvalues too.
*/
static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
global_State *g = G(L);
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 */
- }
+ int white = luaC_white(g); /* current white */
while (*p != NULL && count-- > 0) {
GCObject *curr = *p;
int marked = gch(curr)->marked;
@@ -738,13 +740,8 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
*p = gch(curr)->next; /* remove 'curr' from list */
freeobj(L, curr); /* erase 'curr' */
}
- else {
- if (testbits(marked, tostop))
- return NULL; /* stop sweeping this list */
- if (gch(curr)->tt == LUA_TTHREAD)
- sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */
- /* update marks */
- gch(curr)->marked = cast_byte((marked & toclear) | toset);
+ else { /* update marks */
+ gch(curr)->marked = cast_byte((marked & maskcolors) | white);
p = &gch(curr)->next; /* go to next element */
}
}
@@ -756,7 +753,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
** sweep a list until a live object (or end of list)
*/
static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) {
- GCObject ** old = p;
+ GCObject **old = p;
int i = 0;
do {
i++;
@@ -775,26 +772,26 @@ static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) {
** =======================================================
*/
-static void checkSizes (lua_State *L) {
- global_State *g = G(L);
- 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 */
+/*
+** If possible, free concatenation buffer and shrink string table
+*/
+static void checkSizes (lua_State *L, global_State *g) {
+ if (g->gckind != KGC_EMERGENCY) {
luaZ_freebuffer(L, &g->buff); /* free concatenation buffer */
+ if (g->strt.nuse < g->strt.size / 4) /* string table too big? */
+ luaS_resize(L, g->strt.size / 2); /* shrink it a little */
}
}
static GCObject *udata2finalize (global_State *g) {
GCObject *o = g->tobefnz; /* get first element */
- lua_assert(isfinalized(o));
+ lua_assert(tofinalize(o));
g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */
gch(o)->next = g->allgc; /* return it to 'allgc' list */
g->allgc = o;
- resetbit(gch(o)->marked, SEPARATED); /* mark that it is not in 'tobefnz' */
- lua_assert(!isold(o)); /* see MOVE OLD rule */
- if (!keepinvariantout(g)) /* not keeping invariant? */
+ resetbit(gch(o)->marked, FINALIZEDBIT); /* object is "normal" again */
+ if (issweepphase(g))
makewhite(g, o); /* "sweep" object */
return o;
}
@@ -839,25 +836,39 @@ static void GCTM (lua_State *L, int propagateerrors) {
/*
-** move all unreachable objects (or 'all' objects) that need
-** finalization from list 'finobj' to list 'tobefnz' (to be finalized)
+** call all pending finalizers
*/
-static void separatetobefnz (lua_State *L, int all) {
+static void callallpendingfinalizers (lua_State *L, int propagateerrors) {
global_State *g = G(L);
- GCObject **p = &g->finobj;
+ while (g->tobefnz)
+ GCTM(L, propagateerrors);
+}
+
+
+/*
+** find last 'next' field in list 'p' list (to add elements in its end)
+*/
+static GCObject **findlast (GCObject **p) {
+ while (*p != NULL)
+ p = &gch(*p)->next;
+ return p;
+}
+
+
+/*
+** move all unreachable objects (or 'all' objects) that need
+** finalization from list 'p' to list 'tobefnz' (to be finalized)
+*/
+static void separatetobefnz (global_State *g, int all) {
GCObject *curr;
- GCObject **lastnext = &g->tobefnz;
- /* find last 'next' field in 'tobefnz' list (to add elements in its end) */
- while (*lastnext != NULL)
- lastnext = &gch(*lastnext)->next;
+ GCObject **p = &g->finobj;
+ GCObject **lastnext = findlast(&g->tobefnz);
while ((curr = *p) != NULL) { /* traverse all finalizable objects */
- lua_assert(!isfinalized(curr));
- lua_assert(testbit(gch(curr)->marked, SEPARATED));
+ lua_assert(tofinalize(curr));
if (!(iswhite(curr) || all)) /* not being collected? */
p = &gch(curr)->next; /* don't bother with it */
else {
- l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */
- *p = gch(curr)->next; /* remove 'curr' from 'finobj' list */
+ *p = gch(curr)->next; /* remove 'curr' from "fin" list */
gch(curr)->next = *lastnext; /* link at the end of 'tobefnz' list */
*lastnext = curr;
lastnext = &gch(curr)->next;
@@ -872,33 +883,30 @@ static void separatetobefnz (lua_State *L, int all) {
*/
void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
global_State *g = G(L);
- if (testbit(gch(o)->marked, SEPARATED) || /* obj. is already separated... */
- isfinalized(o) || /* ... or is finalized... */
- gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */
+ if (tofinalize(o) || /* obj. is already marked... */
+ gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */
return; /* nothing to be done */
else { /* move 'o' to 'finobj' list */
GCObject **p;
- GCheader *ho = gch(o);
- if (g->sweepgc == &ho->next) { /* avoid removing current sweep object */
+ if (g->sweepgc == &o->gch.next) { /* avoid removing current sweep object */
lua_assert(issweepphase(g));
g->sweepgc = sweeptolive(L, g->sweepgc, NULL);
}
/* search for pointer pointing to 'o' */
for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ }
- *p = ho->next; /* remove 'o' from root list */
- ho->next = g->finobj; /* link it in list 'finobj' */
+ *p = o->gch.next; /* remove 'o' from its list */
+ o->gch.next = g->finobj; /* link it in "fin" list */
g->finobj = o;
- l_setbit(ho->marked, SEPARATED); /* mark it as such */
- if (!keepinvariantout(g)) /* not keeping invariant? */
+ l_setbit(o->gch.marked, FINALIZEDBIT); /* mark it as such */
+ if (issweepphase(g))
makewhite(g, o); /* "sweep" object */
- else
- resetoldbit(o); /* see MOVE OLD rule */
}
}
/* }====================================================== */
+
/*
** {======================================================
** GC control
@@ -911,87 +919,45 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
** cycle will start when memory use hits threshold
*/
static void setpause (global_State *g, l_mem estimate) {
- l_mem debt, threshold;
+ l_mem threshold, debt;
estimate = estimate / PAUSEADJ; /* adjust 'estimate' */
threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */
? estimate * g->gcpause /* no overflow */
: MAX_LMEM; /* overflow; truncate to maximum */
- debt = -cast(l_mem, threshold - gettotalbytes(g));
+ debt = gettotalbytes(g) - threshold;
luaE_setdebt(g, debt);
}
-#define sweepphases \
- (bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep))
-
-
/*
-** enter first sweep phase (strings) and prepare pointers for other
-** sweep phases. The calls to 'sweeptolive' make pointers point to an
-** object inside the list (instead of to the header), so that the real
-** sweep do not need to skip objects created between "now" and the start
-** of the real sweep.
+** Enter first sweep phase.
+** The call to 'sweeptolive' makes pointer point to an object inside
+** the list (instead of to the header), so that the real sweep do not
+** need to skip objects created between "now" and the start of the real
+** sweep.
** Returns how many objects it swept.
*/
static int entersweep (lua_State *L) {
global_State *g = G(L);
int n = 0;
- g->gcstate = GCSsweepstring;
- lua_assert(g->sweepgc == NULL && g->sweepfin == NULL);
- /* prepare to sweep strings, finalizable objects, and regular objects */
- g->sweepstrgc = 0;
- g->sweepfin = sweeptolive(L, &g->finobj, &n);
+ g->gcstate = GCSswpallgc;
+ lua_assert(g->sweepgc == NULL);
g->sweepgc = sweeptolive(L, &g->allgc, &n);
return n;
}
-/*
-** 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->GCestimate = gettotalbytes(g);
- 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->gckind = KGC_NORMAL;
- entersweep(L);
- luaC_runtilstate(L, ~sweepphases);
- }
-}
-
-
-/*
-** call all pending finalizers
-*/
-static void callallpendingfinalizers (lua_State *L, int propagateerrors) {
- global_State *g = G(L);
- while (g->tobefnz) {
- resetoldbit(g->tobefnz);
- GCTM(L, propagateerrors);
- }
-}
-
-
void luaC_freeallobjects (lua_State *L) {
global_State *g = G(L);
- int i;
- separatetobefnz(L, 1); /* separate all objects with finalizers */
+ separatetobefnz(g, 1); /* separate all objects with finalizers */
lua_assert(g->finobj == NULL);
callallpendingfinalizers(L, 0);
+ lua_assert(g->tobefnz == NULL);
g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */
g->gckind = KGC_NORMAL;
- sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */
+ sweepwholelist(L, &g->finobj);
sweepwholelist(L, &g->allgc);
- for (i = 0; i < g->strt.size; i++) /* free all string lists */
- sweepwholelist(L, &g->strt.hash[i]);
+ sweepwholelist(L, &g->fixedgc); /* collect fixed objects */
lua_assert(g->strt.nuse == 0);
}
@@ -1001,6 +967,7 @@ static l_mem atomic (lua_State *L) {
l_mem work = -cast(l_mem, g->GCmemtrav); /* start counting work */
GCObject *origweak, *origall;
lua_assert(!iswhite(obj2gco(g->mainthread)));
+ g->gcstate = GCSinsideatomic;
markobject(g, L); /* mark running thread */
/* registry and global metatables may be changed by API */
markvalue(g, &g->l_registry);
@@ -1014,14 +981,15 @@ static l_mem atomic (lua_State *L) {
work -= g->GCmemtrav; /* restart counting */
convergeephemerons(g);
/* at this point, all strongly accessible objects are marked. */
- /* clear values from weak tables, before checking finalizers */
+ /* Clear values from weak tables, before checking finalizers */
clearvalues(g, g->weak, NULL);
clearvalues(g, g->allweak, NULL);
origweak = g->weak; origall = g->allweak;
work += g->GCmemtrav; /* stop counting (objects being finalized) */
- separatetobefnz(L, 0); /* separate objects to be finalized */
+ separatetobefnz(g, 0); /* separate objects to be finalized */
+ g->gcfinnum = 1; /* there may be objects to be finalized */
markbeingfnz(g); /* mark objects that will be finalized */
- propagateall(g); /* remark, to propagate `preserveness' */
+ propagateall(g); /* remark, to propagate 'resurrection' */
work -= g->GCmemtrav; /* restart counting */
convergeephemerons(g);
/* at this point, all resurrected objects are marked. */
@@ -1037,66 +1005,67 @@ static l_mem atomic (lua_State *L) {
}
+static lu_mem sweepstep (lua_State *L, global_State *g,
+ int nextstate, GCObject **nextlist) {
+ if (g->sweepgc) {
+ g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
+ if (g->sweepgc) /* is there still something to sweep? */
+ return (GCSWEEPMAX * GCSWEEPCOST);
+ }
+ /* else enter next state */
+ g->gcstate = nextstate;
+ g->sweepgc = nextlist;
+ return 0;
+}
+
+
static lu_mem singlestep (lua_State *L) {
global_State *g = G(L);
switch (g->gcstate) {
case GCSpause: {
/* start to count memory traversed */
g->GCmemtrav = g->strt.size * sizeof(GCObject*);
- lua_assert(!isgenerational(g));
restartcollection(g);
g->gcstate = GCSpropagate;
return g->GCmemtrav;
}
case GCSpropagate: {
- if (g->gray) {
- lu_mem oldtrav = g->GCmemtrav;
- propagatemark(g);
- return g->GCmemtrav - oldtrav; /* memory traversed in this step */
- }
- else { /* no more `gray' objects */
- lu_mem work;
- int sw;
- g->gcstate = GCSatomic; /* finish mark phase */
- g->GCestimate = g->GCmemtrav; /* save what was counted */;
- work = atomic(L); /* add what was traversed by 'atomic' */
- g->GCestimate += work; /* estimate of total memory traversed */
- sw = entersweep(L);
- return work + sw * GCSWEEPCOST;
- }
+ lu_mem oldtrav = g->GCmemtrav;
+ lua_assert(g->gray);
+ propagatemark(g);
+ if (g->gray == NULL) /* no more `gray' objects? */
+ g->gcstate = GCSatomic; /* finish propagate phase */
+ return g->GCmemtrav - oldtrav; /* memory traversed in this step */
}
- case GCSsweepstring: {
- int i;
- for (i = 0; i < GCSWEEPMAX && g->sweepstrgc + i < g->strt.size; i++)
- sweepwholelist(L, &g->strt.hash[g->sweepstrgc + i]);
- g->sweepstrgc += i;
- if (g->sweepstrgc >= g->strt.size) /* no more strings to sweep? */
- g->gcstate = GCSsweepudata;
- return i * GCSWEEPCOST;
+ case GCSatomic: {
+ lu_mem work;
+ int sw;
+ propagateall(g); /* make sure gray list is empty */
+ g->GCestimate = g->GCmemtrav; /* save what was counted */;
+ work = atomic(L); /* work is what was traversed by 'atomic' */
+ g->GCestimate += work; /* estimate of total memory traversed */
+ sw = entersweep(L);
+ return work + sw * GCSWEEPCOST;
}
- case GCSsweepudata: {
- if (g->sweepfin) {
- g->sweepfin = sweeplist(L, g->sweepfin, GCSWEEPMAX);
- return GCSWEEPMAX*GCSWEEPCOST;
- }
- else {
- g->gcstate = GCSsweep;
- return 0;
- }
+ case GCSswpallgc: { /* sweep "regular" objects */
+ return sweepstep(L, g, GCSswpfinobj, &g->finobj);
}
- 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; /* finish collection */
- return GCSWEEPCOST;
- }
+ case GCSswpfinobj: { /* sweep objects with finalizers */
+ return sweepstep(L, g, GCSswptobefnz, &g->tobefnz);
+ }
+ case GCSswptobefnz: { /* sweep objects to be finalized */
+ return sweepstep(L, g, GCSswpend, NULL);
+ }
+ case GCSswpend: { /* finish sweeps */
+ makewhite(g, obj2gco(g->mainthread)); /* sweep main thread */
+ checkSizes(L, g);
+ g->gcstate = GCScallfin;
+ return 0;
+ }
+ case GCScallfin: { /* state to finish calling finalizers */
+ /* do nothing here; should be handled by 'luaC_forcestep' */
+ g->gcstate = GCSpause; /* finish collection */
+ return 0;
}
default: lua_assert(0); return 0;
}
@@ -1114,88 +1083,74 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
}
-static void generationalcollection (lua_State *L) {
+/*
+** run a few (up to 'g->gcfinnum') finalizers
+*/
+static int runafewfinalizers (lua_State *L) {
global_State *g = G(L);
- lua_assert(g->gcstate == GCSpropagate);
- if (g->GCestimate == 0) { /* signal for another major collection? */
- luaC_fullgc(L, 0); /* perform a full regular collection */
- g->GCestimate = gettotalbytes(g); /* update control */
- }
- else {
- lu_mem estimate = g->GCestimate;
- luaC_runtilstate(L, bitmask(GCSpause)); /* run complete (minor) cycle */
- g->gcstate = GCSpropagate; /* skip restart */
- if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc)
- g->GCestimate = 0; /* signal for a major collection */
- else
- g->GCestimate = estimate; /* keep estimate from last major coll. */
-
- }
- setpause(g, gettotalbytes(g));
- lua_assert(g->gcstate == GCSpropagate);
+ unsigned int i;
+ lua_assert(!g->tobefnz || g->gcfinnum > 0);
+ for (i = 0; g->tobefnz && i < g->gcfinnum; i++)
+ GCTM(L, 1); /* call one finalizer */
+ g->gcfinnum = (!g->tobefnz) ? 0 /* nothing more to finalize? */
+ : g->gcfinnum * 2; /* else call a few more next time */
+ return i;
}
-static void incstep (lua_State *L) {
- global_State *g = G(L);
+/*
+** get GC debt and convert it from Kb to 'work units' (avoid zero debt
+** and overflows)
+*/
+static l_mem getdebt (global_State *g) {
l_mem debt = g->GCdebt;
int stepmul = g->gcstepmul;
- if (stepmul < 40) stepmul = 40; /* avoid ridiculous low values (and 0) */
- /* convert debt from Kb to 'work units' (avoid zero debt and overflows) */
debt = (debt / STEPMULADJ) + 1;
debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
- do { /* always perform at least one single step */
- lu_mem work = singlestep(L); /* do some work */
- debt -= work;
- } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause);
- if (g->gcstate == GCSpause)
- setpause(g, g->GCestimate); /* pause until next cycle */
- else {
- debt = (debt / stepmul) * STEPMULADJ; /* convert 'work units' to Kb */
- luaE_setdebt(g, debt);
- }
+ return debt;
}
-
/*
-** performs a basic GC step
-*/
-void luaC_forcestep (lua_State *L) {
- global_State *g = G(L);
- int i;
- if (isgenerational(g)) generationalcollection(L);
- else incstep(L);
- /* run a few finalizers (or all of them at the end of a collect cycle) */
- for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++)
- GCTM(L, 1); /* call one finalizer */
-}
-
-
-/*
-** performs a basic GC step only if collector is running
+** performs a basic GC step when collector is running
*/
void luaC_step (lua_State *L) {
global_State *g = G(L);
- if (g->gcrunning) luaC_forcestep(L);
- else luaE_setdebt(g, -GCSTEPSIZE); /* avoid being called too often */
+ l_mem debt = getdebt(g);
+ if (!g->gcrunning) { /* not running? */
+ luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */
+ return;
+ }
+ do {
+ if (g->gcstate == GCScallfin && g->tobefnz) {
+ unsigned int n = runafewfinalizers(L);
+ debt -= (n * GCFINALIZECOST);
+ }
+ else { /* perform one single step */
+ lu_mem work = singlestep(L);
+ debt -= work;
+ }
+ } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause);
+ if (g->gcstate == GCSpause)
+ setpause(g, g->GCestimate); /* pause until next cycle */
+ else {
+ debt = (debt / g->gcstepmul) * STEPMULADJ; /* convert 'work units' to Kb */
+ luaE_setdebt(g, debt);
+ runafewfinalizers(L);
+ }
}
-
/*
** 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);
- int origkind = g->gckind;
- lua_assert(origkind != KGC_EMERGENCY);
+ lua_assert(g->gckind == KGC_NORMAL);
if (isemergency) /* do not run finalizers during emergency GC */
g->gckind = KGC_EMERGENCY;
- else {
- g->gckind = KGC_NORMAL;
+ else
callallpendingfinalizers(L, 1);
- }
if (keepinvariant(g)) { /* may there be some black objects? */
/* must sweep all objects to turn them back to white
(as white has not changed, nothing will be collected) */
@@ -1205,11 +1160,7 @@ void luaC_fullgc (lua_State *L, int isemergency) {
luaC_runtilstate(L, bitmask(GCSpause));
luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */
luaC_runtilstate(L, bitmask(GCSpause)); /* run entire collection */
- if (origkind == KGC_GEN) { /* generational mode? */
- /* generational mode must be kept in propagate phase */
- luaC_runtilstate(L, bitmask(GCSpropagate));
- }
- g->gckind = origkind;
+ g->gckind = KGC_NORMAL;
setpause(g, gettotalbytes(g));
if (!isemergency) /* do not run finalizers during emergency GC */
callallpendingfinalizers(L, 1);
diff --git a/src/lgc.h b/src/lgc.h
index dee270b4..5ba91082 100644
--- a/src/lgc.h
+++ b/src/lgc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.h,v 2.58 2012/09/11 12:53:08 roberto Exp $
+** $Id: lgc.h,v 2.82 2014/03/19 18:51:16 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -38,36 +38,27 @@
*/
#define GCSpropagate 0
#define GCSatomic 1
-#define GCSsweepstring 2
-#define GCSsweepudata 3
-#define GCSsweep 4
-#define GCSpause 5
+#define GCSswpallgc 2
+#define GCSswpfinobj 3
+#define GCSswptobefnz 4
+#define GCSswpend 5
+#define GCScallfin 6
+#define GCSpause 7
#define issweepphase(g) \
- (GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep)
+ (GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend)
-#define isgenerational(g) ((g)->gckind == KGC_GEN)
/*
-** macros to tell when main invariant (white objects cannot point to black
-** ones) must be kept. During a non-generational collection, the sweep
+** macro to tell when main invariant (white objects cannot point to black
+** ones) must be kept. During a collection, the sweep
** phase may break 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.
+** all objects are white again.
*/
-#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic)
-
-
-/*
-** Outside the collector, the state in generational mode is kept in
-** 'propagate', so 'keepinvariant' is always true.
-*/
-#define keepinvariantout(g) \
- check_exp(g->gcstate == GCSpropagate || !isgenerational(g), \
- g->gcstate <= GCSatomic)
+#define keepinvariant(g) ((g)->gcstate <= GCSatomic)
/*
@@ -87,10 +78,7 @@
#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 /* object has been separated for finalization */
-#define SEPARATED 4 /* object is in 'finobj' list or in 'tobefnz' */
-#define FIXEDBIT 5 /* object is fixed (should not be collected) */
-#define OLDBIT 6 /* object is old (only in generational mode) */
+#define FINALIZEDBIT 3 /* object has been marked for finalization */
/* bit 7 is currently used by tests (luaL_checkmemory) */
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
@@ -101,21 +89,15 @@
#define isgray(x) /* neither white nor black */ \
(!testbits((x)->gch.marked, WHITEBITS | bitmask(BLACKBIT)))
-#define isold(x) testbit((x)->gch.marked, OLDBIT)
+#define tofinalize(x) testbit((x)->gch.marked, FINALIZEDBIT)
-/* 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 otherwhite(g) ((g)->currentwhite ^ 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)
-#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x)))
-
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
@@ -124,34 +106,33 @@
#define luaC_checkGC(L) luaC_condGC(L, luaC_step(L);)
-#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \
+#define luaC_barrier(L,p,v) { \
+ if (iscollectable(v) && isblack(obj2gco(p)) && iswhite(gcvalue(v))) \
luaC_barrier_(L,obj2gco(p),gcvalue(v)); }
-#define luaC_barrierback(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \
- luaC_barrierback_(L,p); }
+#define luaC_barrierback(L,p,v) { \
+ if (iscollectable(v) && isblack(obj2gco(p)) && iswhite(gcvalue(v))) \
+ luaC_barrierback_(L,obj2gco(p)); }
-#define luaC_objbarrier(L,p,o) \
- { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \
+#define luaC_objbarrier(L,p,o) { \
+ if (isblack(obj2gco(p)) && iswhite(obj2gco(o))) \
luaC_barrier_(L,obj2gco(p),obj2gco(o)); }
-#define luaC_objbarrierback(L,p,o) \
- { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) luaC_barrierback_(L,p); }
-
-#define luaC_barrierproto(L,p,c) \
- { if (isblack(obj2gco(p))) luaC_barrierproto_(L,p,c); }
+#define luaC_upvalbarrier(L,uv) \
+ { if (iscollectable((uv)->v) && !upisopen(uv)) \
+ luaC_upvalbarrier_(L,uv); }
+LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L);
-LUAI_FUNC void luaC_forcestep (lua_State *L);
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 GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
-LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c);
+LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
-LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv);
-LUAI_FUNC void luaC_changemode (lua_State *L, int mode);
+LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv);
+
#endif
diff --git a/src/linit.c b/src/linit.c
index 8d3aa657..2b48be8b 100644
--- a/src/linit.c
+++ b/src/linit.c
@@ -1,5 +1,5 @@
/*
-** $Id: linit.c,v 1.32 2011/04/08 19:17:36 roberto Exp $
+** $Id: linit.c,v 1.33 2014/02/06 17:32:33 roberto Exp $
** Initialization of libraries for lua.c and other clients
** See Copyright Notice in lua.h
*/
@@ -34,6 +34,7 @@ static const luaL_Reg loadedlibs[] = {
{LUA_IOLIBNAME, luaopen_io},
{LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string},
+ {LUA_UTF8LIBNAME, luaopen_utf8},
{LUA_BITLIBNAME, luaopen_bit32},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_DBLIBNAME, luaopen_debug},
diff --git a/src/liolib.c b/src/liolib.c
index 2c6202af..d1605024 100644
--- a/src/liolib.c
+++ b/src/liolib.c
@@ -1,5 +1,5 @@
/*
-** $Id: liolib.c,v 2.114 2013/06/07 19:01:35 roberto Exp $
+** $Id: liolib.c,v 2.120 2014/03/19 18:57:42 roberto Exp $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
@@ -29,14 +29,14 @@
#include "lualib.h"
-#if !defined(lua_checkmode)
+#if !defined(l_checkmode)
/*
** Check whether 'mode' matches '[rwa]%+?b?'.
** Change this macro to accept other modes for 'fopen' besides
** the standard ones.
*/
-#define lua_checkmode(mode) \
+#define l_checkmode(mode) \
(*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \
(*mode != '+' || ++mode) && /* skip if char is '+' */ \
(*mode != 'b' || ++mode) && /* skip if char is 'b' */ \
@@ -46,45 +46,61 @@
/*
** {======================================================
-** lua_popen spawns a new process connected to the current
+** l_popen spawns a new process connected to the current
** one through the file streams.
** =======================================================
*/
-#if !defined(lua_popen) /* { */
+#if !defined(l_popen) /* { */
-#if defined(LUA_USE_POPEN) /* { */
+#if defined(LUA_USE_POSIX) /* { */
-#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m))
-#define lua_pclose(L,file) ((void)L, pclose(file))
+#define l_popen(L,c,m) (fflush(NULL), popen(c,m))
+#define l_pclose(L,file) (pclose(file))
#elif defined(LUA_WIN) /* }{ */
-#define lua_popen(L,c,m) ((void)L, _popen(c,m))
-#define lua_pclose(L,file) ((void)L, _pclose(file))
-
+#define l_popen(L,c,m) (_popen(c,m))
+#define l_pclose(L,file) (_pclose(file))
#else /* }{ */
-#define lua_popen(L,c,m) ((void)((void)c, m), \
- luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0)
-#define lua_pclose(L,file) ((void)((void)L, file), -1)
-
+/* ANSI definitions */
+#define l_popen(L,c,m) \
+ ((void)((void)c, m), \
+ luaL_error(L, LUA_QL("popen") " not supported"), \
+ (FILE*)0)
+#define l_pclose(L,file) ((void)L, (void)file, -1)
#endif /* } */
-#endif /* } */
+#endif /* } */
/* }====================================================== */
+#if !defined(l_getc) /* { */
+
+#if defined(LUA_USE_POSIX)
+#define l_getc(f) getc_unlocked(f)
+#define l_lockfile(f) flockfile(f)
+#define l_unlockfile(f) funlockfile(f)
+#else
+#define l_getc(f) getc(f)
+#define l_lockfile(f) ((void)0)
+#define l_unlockfile(f) ((void)0)
+#endif
+
+#endif /* } */
+
+
/*
** {======================================================
-** lua_fseek: configuration for longer offsets
+** l_fseek: configuration for longer offsets
** =======================================================
*/
-#if !defined(lua_fseek) && !defined(LUA_ANSI) /* { */
+#if !defined(l_fseek) /* { */
#if defined(LUA_USE_POSIX) /* { */
@@ -94,22 +110,22 @@
#elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) \
&& defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */
-/* Windows (but not DDK) and Visual C++ 2005 or higher */
+/* Windows (but not DDK) and Visual C++ 2005 or higher */
#define l_fseek(f,o,w) _fseeki64(f,o,w)
#define l_ftell(f) _ftelli64(f)
#define l_seeknum __int64
-#endif /* } */
-
-#endif /* } */
-
+#else /* }{ */
-#if !defined(l_fseek) /* default definitions */
+/* ANSI definitions */
#define l_fseek(f,o,w) fseek(f,o,w)
#define l_ftell(f) ftell(f)
#define l_seeknum long
-#endif
+
+#endif /* } */
+
+#endif /* } */
/* }====================================================== */
@@ -228,7 +244,7 @@ static int io_open (lua_State *L) {
const char *mode = luaL_optstring(L, 2, "r");
LStream *p = newfile(L);
const char *md = mode; /* to traverse/check mode */
- luaL_argcheck(L, lua_checkmode(md), 2, "invalid mode");
+ luaL_argcheck(L, l_checkmode(md), 2, "invalid mode");
p->f = fopen(filename, mode);
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
}
@@ -239,7 +255,7 @@ static int io_open (lua_State *L) {
*/
static int io_pclose (lua_State *L) {
LStream *p = tolstream(L);
- return luaL_execresult(L, lua_pclose(L, p->f));
+ return luaL_execresult(L, l_pclose(L, p->f));
}
@@ -247,7 +263,7 @@ static int io_popen (lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r");
LStream *p = newprefile(L);
- p->f = lua_popen(L, filename, mode);
+ p->f = l_popen(L, filename, mode);
p->closef = &io_pclose;
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
}
@@ -375,7 +391,7 @@ static int read_number (lua_State *L, FILE *f) {
static int test_eof (lua_State *L, FILE *f) {
int c = getc(f);
- ungetc(c, f);
+ ungetc(c, f); /* no-op when c == EOF */
lua_pushlstring(L, NULL, 0);
return (c != EOF);
}
@@ -383,40 +399,27 @@ static int test_eof (lua_State *L, FILE *f) {
static int read_line (lua_State *L, FILE *f, int chop) {
luaL_Buffer b;
+ int c;
luaL_buffinit(L, &b);
- for (;;) {
- size_t l;
- char *p = luaL_prepbuffer(&b);
- if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */
- luaL_pushresult(&b); /* close buffer */
- return (lua_rawlen(L, -1) > 0); /* check whether read something */
- }
- l = strlen(p);
- if (l == 0 || p[l-1] != '\n')
- luaL_addsize(&b, l);
- else {
- luaL_addsize(&b, l - chop); /* chop 'eol' if needed */
- luaL_pushresult(&b); /* close buffer */
- return 1; /* read at least an `eol' */
- }
- }
+ l_lockfile(f);
+ while ((c = l_getc(f)) != EOF && c != '\n')
+ luaL_addchar(&b, c);
+ l_unlockfile(f);
+ if (!chop && c == '\n') luaL_addchar(&b, c);
+ luaL_pushresult(&b); /* close buffer */
+ return (c == '\n' || lua_rawlen(L, -1) > 0);
}
-#define MAX_SIZE_T (~(size_t)0)
-
static void read_all (lua_State *L, FILE *f) {
- size_t rlen = LUAL_BUFFERSIZE; /* how much to read in each cycle */
+ size_t nr;
luaL_Buffer b;
luaL_buffinit(L, &b);
- for (;;) {
- char *p = luaL_prepbuffsize(&b, rlen);
- size_t nr = fread(p, sizeof(char), rlen, f);
+ do { /* read file in chunks of LUAL_BUFFERSIZE bytes */
+ char *p = luaL_prepbuffsize(&b, LUAL_BUFFERSIZE);
+ nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f);
luaL_addsize(&b, nr);
- if (nr < rlen) break; /* eof? */
- else if (rlen <= (MAX_SIZE_T / 4)) /* avoid buffers too large */
- rlen *= 2; /* double buffer size at each iteration */
- }
+ } while (nr == LUAL_BUFFERSIZE);
luaL_pushresult(&b); /* close buffer */
}
@@ -566,15 +569,15 @@ static int f_seek (lua_State *L) {
static const char *const modenames[] = {"set", "cur", "end", NULL};
FILE *f = tofile(L);
int op = luaL_checkoption(L, 2, "cur", modenames);
- lua_Number p3 = luaL_optnumber(L, 3, 0);
+ lua_Integer p3 = luaL_optinteger(L, 3, 0);
l_seeknum offset = (l_seeknum)p3;
- luaL_argcheck(L, (lua_Number)offset == p3, 3,
+ luaL_argcheck(L, (lua_Integer)offset == p3, 3,
"not an integer in proper range");
op = l_fseek(f, offset, mode[op]);
if (op)
return luaL_fileresult(L, 0, NULL); /* error */
else {
- lua_pushnumber(L, (lua_Number)l_ftell(f));
+ lua_pushinteger(L, (lua_Integer)l_ftell(f));
return 1;
}
}
diff --git a/src/llex.c b/src/llex.c
index e1a54c7d..6ca0f42b 100644
--- a/src/llex.c
+++ b/src/llex.c
@@ -1,5 +1,5 @@
/*
-** $Id: llex.c,v 2.67 2013/06/19 14:27:00 roberto Exp $
+** $Id: llex.c,v 2.74 2014/02/14 15:23:51 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -15,6 +15,7 @@
#include "lctype.h"
#include "ldo.h"
+#include "lgc.h"
#include "llex.h"
#include "lobject.h"
#include "lparser.h"
@@ -38,7 +39,8 @@ static const char *const luaX_tokens [] = {
"end", "false", "for", "function", "goto", "if",
"in", "local", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while",
- "//", "..", "...", "==", ">=", "<=", "~=", "::", "<eof>",
+ "//", "..", "...", "==", ">=", "<=", "~=",
+ "<<", ">>", "::", "<eof>",
"<number>", "<number>", "<name>", "<string>"
};
@@ -64,9 +66,11 @@ static void save (LexState *ls, int c) {
void luaX_init (lua_State *L) {
int i;
+ TString *e = luaS_new(L, LUA_ENV); /* create env name */
+ luaC_fix(L, obj2gco(e)); /* never collect this name */
for (i=0; i<NUM_RESERVED; i++) {
TString *ts = luaS_new(L, luaX_tokens[i]);
- luaS_fix(ts); /* reserved words are never collected */
+ luaC_fix(L, obj2gco(ts)); /* reserved words are never collected */
ts->tsv.extra = cast_byte(i+1); /* reserved word */
}
}
@@ -116,22 +120,25 @@ l_noret 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)
+** creates a new string and anchors it in scanner's table so that
+** it will not be collected until the end of the compilation
+** (by that time it should be anchored somewhere)
*/
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); /* create new string */
setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */
- o = luaH_set(L, ls->fs->h, L->top - 1);
- if (ttisnil(o)) { /* not in use yet? (see 'addK') */
+ o = luaH_set(L, ls->h, L->top - 1);
+ if (ttisnil(o)) { /* not in use yet? */
/* boolean value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */
setbvalue(o, 1); /* t[string] = true */
luaC_checkGC(L);
}
+ else { /* string already present */
+ ts = rawtsvalue(keyfromval(o)); /* re-use value previously stored */
+ }
L->top--; /* remove string from stack */
return ts;
}
@@ -163,8 +170,7 @@ 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, LUA_ENV); /* create env name */
- luaS_fix(ls->envn); /* never collect this name */
+ ls->envn = luaS_new(L, LUA_ENV); /* get env name */
luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
}
@@ -314,40 +320,65 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
}
-static void escerror (LexState *ls, int *c, int n, const char *msg) {
- int i;
- luaZ_resetbuffer(ls->buff); /* prepare error message */
- save(ls, '\\');
- for (i = 0; i < n && c[i] != EOZ; i++)
- save(ls, c[i]);
- lexerror(ls, msg, TK_STRING);
+static void esccheck (LexState *ls, int c, const char *msg) {
+ if (!c) {
+ if (ls->current != EOZ)
+ save_and_next(ls); /* add current to buffer for error message */
+ lexerror(ls, msg, TK_STRING);
+ }
+}
+
+
+static int gethexa (LexState *ls) {
+ save_and_next(ls);
+ esccheck (ls, lisxdigit(ls->current), "hexadecimal digit expected");
+ return luaO_hexavalue(ls->current);
}
static int readhexaesc (LexState *ls) {
- int c[3], i; /* keep input for error message */
- int r = 0; /* result accumulator */
- c[0] = 'x'; /* for error message */
- for (i = 1; i < 3; i++) { /* read two hexadecimal digits */
- c[i] = next(ls);
- if (!lisxdigit(c[i]))
- escerror(ls, c, i + 1, "hexadecimal digit expected");
- r = (r << 4) + luaO_hexavalue(c[i]);
+ int r = gethexa(ls);
+ r = (r << 4) + gethexa(ls);
+ luaZ_buffremove(ls->buff, 2); /* remove saved chars from buffer */
+ return r;
+}
+
+
+static unsigned int readutf8esc (LexState *ls) {
+ unsigned int r;
+ int i = 4; /* chars to be removed: '\', 'u', '{', and first digit */
+ save_and_next(ls); /* skip 'u' */
+ esccheck(ls, ls->current == '{', "missing '{'");
+ r = gethexa(ls); /* must have at least one digit */
+ while ((save_and_next(ls), lisxdigit(ls->current))) {
+ i++;
+ r = (r << 4) + luaO_hexavalue(ls->current);
+ esccheck(ls, r <= 0x10FFFF, "UTF-8 value too large");
}
+ esccheck(ls, ls->current == '}', "missing '}'");
+ next(ls); /* skip '}' */
+ luaZ_buffremove(ls->buff, i); /* remove saved chars from buffer */
return r;
}
+static void utf8esc (LexState *ls) {
+ char buff[UTF8BUFFSZ];
+ int n = luaO_utf8esc(buff, readutf8esc(ls));
+ for (; n > 0; n--) /* add 'buff' to string */
+ save(ls, buff[UTF8BUFFSZ - n]);
+}
+
+
static int readdecesc (LexState *ls) {
- int c[3], i;
+ int i;
int r = 0; /* result accumulator */
for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */
- c[i] = ls->current;
- r = 10*r + c[i] - '0';
- next(ls);
+ r = 10*r + ls->current - '0';
+ save_and_next(ls);
}
- if (r > UCHAR_MAX)
- escerror(ls, c, i, "decimal escape too large");
+ esccheck(ls, r <= UCHAR_MAX, "decimal escape too large");
+ luaZ_buffremove(ls->buff, i); /* remove read digits from buffer */
return r;
}
@@ -365,7 +396,7 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) {
break; /* to avoid warnings */
case '\\': { /* escape sequences */
int c; /* final character to be saved */
- next(ls); /* do not save the `\' */
+ save_and_next(ls); /* keep '\\' for error messages */
switch (ls->current) {
case 'a': c = '\a'; goto read_save;
case 'b': c = '\b'; goto read_save;
@@ -375,12 +406,14 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) {
case 't': c = '\t'; goto read_save;
case 'v': c = '\v'; goto read_save;
case 'x': c = readhexaesc(ls); goto read_save;
+ case 'u': utf8esc(ls); goto no_save;
case '\n': case '\r':
inclinenumber(ls); c = '\n'; goto only_save;
case '\\': case '\"': case '\'':
c = ls->current; goto read_save;
case EOZ: goto no_save; /* will raise an error next loop */
case 'z': { /* zap following span of spaces */
+ luaZ_buffremove(ls->buff, 1); /* remove '\\' */
next(ls); /* skip the 'z' */
while (lisspace(ls->current)) {
if (currIsNewline(ls)) inclinenumber(ls);
@@ -389,15 +422,18 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) {
goto no_save;
}
default: {
- if (!lisdigit(ls->current))
- escerror(ls, &ls->current, 1, "invalid escape sequence");
- /* digital escape \ddd */
- c = readdecesc(ls);
+ esccheck(ls, lisdigit(ls->current), "invalid escape sequence");
+ c = readdecesc(ls); /* digital escape \ddd */
goto only_save;
}
}
- read_save: next(ls); /* read next character */
- only_save: save(ls, c); /* save 'c' */
+ read_save:
+ next(ls);
+ /* go through */
+ only_save:
+ luaZ_buffremove(ls->buff, 1); /* remove '\\' */
+ save(ls, c);
+ /* go through */
no_save: break;
}
default:
@@ -457,13 +493,15 @@ static int llex (LexState *ls, SemInfo *seminfo) {
}
case '<': {
next(ls);
- if (ls->current != '=') return '<';
- else { next(ls); return TK_LE; }
+ if (ls->current == '=') { next(ls); return TK_LE; }
+ if (ls->current == '<') { next(ls); return TK_SHL; }
+ return '<';
}
case '>': {
next(ls);
- if (ls->current != '=') return '>';
- else { next(ls); return TK_GE; }
+ if (ls->current == '=') { next(ls); return TK_GE; }
+ if (ls->current == '>') { next(ls); return TK_SHR; }
+ return '>';
}
case '/': {
next(ls);
diff --git a/src/llex.h b/src/llex.h
index 7cba9906..4a5d5286 100644
--- a/src/llex.h
+++ b/src/llex.h
@@ -1,5 +1,5 @@
/*
-** $Id: llex.h,v 1.74 2013/04/26 13:07:53 roberto Exp $
+** $Id: llex.h,v 1.76 2013/12/30 20:47:58 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -27,6 +27,7 @@ enum RESERVED {
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
/* other terminal symbols */
TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE,
+ TK_SHL, TK_SHR,
TK_DBCOLON, TK_EOS,
TK_FLT, TK_INT, TK_NAME, TK_STRING
};
@@ -60,6 +61,7 @@ typedef struct LexState {
struct lua_State *L;
ZIO *z; /* input stream */
Mbuffer *buff; /* buffer for tokens */
+ Table *h; /* to avoid collection/reuse strings */
struct Dyndata *dyd; /* dynamic structures used by the parser */
TString *source; /* current source name */
TString *envn; /* environment variable name */
diff --git a/src/llimits.h b/src/llimits.h
index c4416f89..80a5d2a0 100644
--- a/src/llimits.h
+++ b/src/llimits.h
@@ -1,5 +1,5 @@
/*
-** $Id: llimits.h,v 1.108 2013/06/19 14:27:00 roberto Exp $
+** $Id: llimits.h,v 1.111 2014/03/07 16:19:00 roberto Exp $
** Limits, basic types, and some other `installation-dependent' definitions
** See Copyright Notice in lua.h
*/
@@ -43,11 +43,13 @@ typedef unsigned char lu_byte;
#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */
+/* maximum value for a lua_Unsigned */
+#define MAX_UINTEGER (~(lua_Unsigned)0)
+
/* minimum and maximum values for lua_Integer */
-#define MAX_INTEGER ((lua_Integer)(~(lua_Unsigned)0 >> 1))
+#define MAX_INTEGER ((lua_Integer)(MAX_UINTEGER >> 1))
#define MIN_INTEGER (~MAX_INTEGER)
-
/*
** conversion of pointer to integer
** this is for hashing only; there is no problem if the integer
@@ -104,6 +106,7 @@ typedef LUAI_UACNUMBER l_uacNumber;
#define cast(t, exp) ((t)(exp))
+#define cast_void(i) cast(void, (i))
#define cast_byte(i) cast(lu_byte, (i))
#define cast_num(i) cast(lua_Number, (i))
#define cast_int(i) cast(int, (i))
@@ -155,7 +158,7 @@ typedef lu_int32 Instruction;
/* minimum size for the string table (must be power of 2) */
#if !defined(MINSTRTABSIZE)
-#define MINSTRTABSIZE 32
+#define MINSTRTABSIZE 64 /* minimum size for "predefined" strings */
#endif
diff --git a/src/lmathlib.c b/src/lmathlib.c
index f26b05ca..a40a6fb6 100644
--- a/src/lmathlib.c
+++ b/src/lmathlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lmathlib.c,v 1.90 2013/07/03 17:23:19 roberto Exp $
+** $Id: lmathlib.c,v 1.92 2013/07/22 16:05:53 roberto Exp $
** Standard mathematical library
** See Copyright Notice in lua.h
*/
@@ -251,9 +251,16 @@ static int math_randomseed (lua_State *L) {
}
-static int math_isfloat (lua_State *L) {
+static int math_type (lua_State *L) {
luaL_checkany(L, 1);
- lua_pushboolean(L, (lua_type(L, 1) == LUA_TNUMBER && !lua_isinteger(L, 1)));
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ if (lua_isinteger(L, 1))
+ lua_pushliteral(L, "integer");
+ else
+ lua_pushliteral(L, "float");
+ }
+ else
+ lua_pushnil(L);
return 1;
}
@@ -273,7 +280,6 @@ static const luaL_Reg mathlib[] = {
{"ifloor", math_ifloor},
{"fmod", math_fmod},
{"frexp", math_frexp},
- {"isfloat", math_isfloat},
{"ldexp", math_ldexp},
#if defined(LUA_COMPAT_LOG10)
{"log10", math_log10},
@@ -291,6 +297,7 @@ static const luaL_Reg mathlib[] = {
{"sqrt", math_sqrt},
{"tanh", math_tanh},
{"tan", math_tan},
+ {"type", math_type},
{NULL, NULL}
};
diff --git a/src/loadlib.c b/src/loadlib.c
index a9959277..5333311d 100644
--- a/src/loadlib.c
+++ b/src/loadlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: loadlib.c,v 1.111 2012/05/30 12:33:44 roberto Exp $
+** $Id: loadlib.c,v 1.113 2014/03/12 20:57:40 roberto Exp $
** Dynamic library loader for Lua
** See Copyright Notice in lua.h
**
@@ -31,21 +31,21 @@
/*
-** LUA_PATH and LUA_CPATH are the names of the environment
+** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment
** variables that Lua check to set its paths.
*/
-#if !defined(LUA_PATH)
-#define LUA_PATH "LUA_PATH"
+#if !defined(LUA_PATH_VAR)
+#define LUA_PATH_VAR "LUA_PATH"
#endif
-#if !defined(LUA_CPATH)
-#define LUA_CPATH "LUA_CPATH"
+#if !defined(LUA_CPATH_VAR)
+#define LUA_CPATH_VAR "LUA_CPATH"
#endif
#define LUA_PATHSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
-#define LUA_PATHVERSION LUA_PATH LUA_PATHSUFFIX
-#define LUA_CPATHVERSION LUA_CPATH LUA_PATHSUFFIX
+#define LUA_PATHVARVERSION LUA_PATH_VAR LUA_PATHSUFFIX
+#define LUA_CPATHVARVERSION LUA_CPATH_VAR LUA_PATHSUFFIX
/*
** LUA_PATH_SEP is the character that separates templates in a path.
@@ -468,8 +468,7 @@ static int searcher_Croot (lua_State *L) {
static int searcher_preload (lua_State *L) {
const char *name = luaL_checkstring(L, 1);
lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD");
- lua_getfield(L, -1, name);
- if (lua_isnil(L, -1)) /* not found? */
+ if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */
lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
return 1;
}
@@ -484,8 +483,7 @@ static void findloader (lua_State *L, const char *name) {
luaL_error(L, LUA_QL("package.searchers") " must be a table");
/* iterate over available searchers to find a loader */
for (i = 1; ; i++) {
- lua_rawgeti(L, 3, i); /* get a searcher */
- if (lua_isnil(L, -1)) { /* no more searchers? */
+ if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */
lua_pop(L, 1); /* remove nil */
luaL_pushresult(&msg); /* create error message */
luaL_error(L, "module " LUA_QS " not found:%s",
@@ -520,8 +518,7 @@ static int ll_require (lua_State *L) {
lua_call(L, 2, 1); /* run loader to load module */
if (!lua_isnil(L, -1)) /* non-nil return? */
lua_setfield(L, 2, name); /* _LOADED[name] = returned value */
- lua_getfield(L, 2, name);
- if (lua_isnil(L, -1)) { /* module did not set a value? */
+ if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */
lua_pushboolean(L, 1); /* use true as result */
lua_pushvalue(L, -1); /* extra copy to be returned */
lua_setfield(L, 2, name); /* _LOADED[name] = true */
@@ -587,9 +584,8 @@ static int ll_module (lua_State *L) {
int lastarg = lua_gettop(L); /* last parameter */
luaL_pushmodule(L, modname, 1); /* get/create module table */
/* check whether table already has a _NAME field */
- lua_getfield(L, -1, "_NAME");
- if (!lua_isnil(L, -1)) /* is table an initialized module? */
- lua_pop(L, 1);
+ if (lua_getfield(L, -1, "_NAME") != LUA_TNIL)
+ lua_pop(L, 1); /* table is an initialized module */
else { /* no; initialize it */
lua_pop(L, 1);
modinit(L, modname);
@@ -703,9 +699,9 @@ LUAMOD_API int luaopen_package (lua_State *L) {
#endif
lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */
/* set field 'path' */
- setpath(L, "path", LUA_PATHVERSION, LUA_PATH, LUA_PATH_DEFAULT);
+ setpath(L, "path", LUA_PATHVARVERSION, LUA_PATH_VAR, LUA_PATH_DEFAULT);
/* set field 'cpath' */
- setpath(L, "cpath", LUA_CPATHVERSION, LUA_CPATH, LUA_CPATH_DEFAULT);
+ setpath(L, "cpath", LUA_CPATHVARVERSION, LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
/* store config information */
lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n"
LUA_EXEC_DIR "\n" LUA_IGMARK "\n");
diff --git a/src/lobject.c b/src/lobject.c
index edb0efeb..41bde947 100644
--- a/src/lobject.c
+++ b/src/lobject.c
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.c,v 2.67 2013/06/25 18:58:32 roberto Exp $
+** $Id: lobject.c,v 2.76 2014/03/21 13:52:33 roberto Exp $
** Some generic functions over Lua objects
** See Copyright Notice in lua.h
*/
@@ -77,22 +77,30 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
case LUA_OPSUB:return intop(-, v1, v2);
case LUA_OPMUL:return intop(*, v1, v2);
case LUA_OPMOD: return luaV_mod(L, v1, v2);
- case LUA_OPPOW: return luaV_pow(v1, v2);
- case LUA_OPUNM: return -v1;
+ case LUA_OPPOW: return luaV_pow(L, v1, v2);
+ case LUA_OPIDIV: return luaV_div(L, v1, v2);
+ case LUA_OPBAND: return intop(&, v1, v2);
+ case LUA_OPBOR: return intop(|, v1, v2);
+ case LUA_OPBXOR: return intop(^, v1, v2);
+ case LUA_OPSHL: return luaV_shiftl(v1, v2);
+ case LUA_OPSHR: return luaV_shiftl(v1, -v2);
+ case LUA_OPUNM: return intop(-, 0, v1);
+ case LUA_OPBNOT: return intop(^, cast_integer(-1), v1);
default: lua_assert(0); return 0;
}
}
-static lua_Number numarith (int op, lua_Number v1, lua_Number v2) {
+static lua_Number numarith (lua_State *L, int op, lua_Number v1,
+ lua_Number v2) {
switch (op) {
- case LUA_OPADD: return luai_numadd(NULL, v1, v2);
- case LUA_OPSUB: return luai_numsub(NULL, v1, v2);
- case LUA_OPMUL: return luai_nummul(NULL, v1, v2);
- case LUA_OPDIV: return luai_numdiv(NULL, v1, v2);
- case LUA_OPMOD: return luai_nummod(NULL, v1, v2);
- case LUA_OPPOW: return luai_numpow(NULL, v1, v2);
- case LUA_OPUNM: return luai_numunm(NULL, v1);
+ case LUA_OPADD: return luai_numadd(L, v1, v2);
+ case LUA_OPSUB: return luai_numsub(L, v1, v2);
+ case LUA_OPMUL: return luai_nummul(L, v1, v2);
+ case LUA_OPDIV: return luai_numdiv(L, v1, v2);
+ case LUA_OPMOD: return luai_nummod(L, v1, v2);
+ case LUA_OPPOW: return luai_numpow(L, v1, v2);
+ case LUA_OPUNM: return luai_numunm(L, v1);
default: lua_assert(0); return 0;
}
}
@@ -100,29 +108,40 @@ static lua_Number numarith (int op, lua_Number v1, lua_Number v2) {
void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2,
TValue *res) {
- if (op == LUA_OPIDIV) { /* operates only on integers */
- lua_Integer i1; lua_Integer i2;
- if (tointeger(p1, &i1) && tointeger(p2, &i2)) {
- setivalue(res, luaV_div(L, i1, i2));
- return;
+ switch (op) {
+ case LUA_OPIDIV: case LUA_OPBAND: case LUA_OPBOR:
+ case LUA_OPBXOR: case LUA_OPSHL: case LUA_OPSHR:
+ case LUA_OPBNOT: { /* operates only on integers */
+ lua_Integer i1; lua_Integer i2;
+ if (tointeger(p1, &i1) && tointeger(p2, &i2)) {
+ setivalue(res, intarith(L, op, i1, i2));
+ return;
+ }
+ else break; /* go to the end */
}
- /* else go to the end */
- }
- else { /* other operations */
- lua_Number n1; lua_Number n2;
- if (ttisinteger(p1) && ttisinteger(p2) && op != LUA_OPDIV &&
- (op != LUA_OPPOW || ivalue(p2) >= 0)) {
- setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2)));
- return;
+ case LUA_OPDIV: { /* operates only on floats */
+ lua_Number n1; lua_Number n2;
+ if (tonumber(p1, &n1) && tonumber(p2, &n2)) {
+ setnvalue(res, numarith(L, op, n1, n2));
+ return;
+ }
+ else break; /* go to the end */
}
- else if (tonumber(p1, &n1) && tonumber(p2, &n2)) {
- setnvalue(res, numarith(op, n1, n2));
- return;
+ default: { /* other operations */
+ lua_Number n1; lua_Number n2;
+ if (ttisinteger(p1) && ttisinteger(p2)) {
+ setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2)));
+ return;
+ }
+ else if (tonumber(p1, &n1) && tonumber(p2, &n2)) {
+ setnvalue(res, numarith(L, op, n1, n2));
+ return;
+ }
+ else break; /* go to the end */
}
- /* else go to the end */
}
- /* could not perform raw operation; try metmethod */
- lua_assert(L != NULL); /* cannot fail when folding (compile time) */
+ /* could not perform raw operation; try metamethod */
+ lua_assert(L != NULL); /* should not fail when folding (compile time) */
luaT_trybinTM(L, p1, p2, res, cast(TMS, op - LUA_OPADD + TM_ADD));
}
@@ -141,22 +160,26 @@ static int isneg (const char **s) {
/*
+** {======================================================
** lua_strx2number converts an hexadecimal numeric string to a number.
** In C99, 'strtod' does both conversions. C89, however, has no function
** to convert floating hexadecimal strings to numbers. For these
** systems, you can leave 'lua_strx2number' undefined and Lua will
** provide its own implementation.
+** =======================================================
*/
-#if defined(LUA_USE_STRTODHEX)
+#if !defined(lua_strx2number) /* { */
+
+#if defined(LUA_USE_C99) /* { */
+
#define lua_strx2number(s,p) lua_str2number(s,p)
-#endif
+#else /* }{ */
-#if !defined(lua_strx2number)
+/* Lua's implementation for 'lua_strx2number' */
#include <math.h>
-
/* maximum number of significant digits to read (to avoid overflows
even with single floats) */
#define MAXSIGDIG 30
@@ -219,7 +242,11 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
return l_mathop(ldexp)(r, e);
}
-#endif
+#endif /* } */
+
+#endif /* } */
+
+/* }====================================================== */
int luaO_str2d (const char *s, size_t len, lua_Number *result) {
@@ -260,19 +287,36 @@ int luaO_str2int (const char *s, size_t len, lua_Integer *result) {
while (lisspace(cast_uchar(*s))) s++; /* skip trailing spaces */
if (empty || s != ends) return 0; /* something wrong in the numeral */
else {
- if (neg) *result = -cast(lua_Integer, a);
- else *result = cast(lua_Integer, a);
+ *result = cast_integer((neg) ? 0u - a : a);
return 1;
}
}
+int luaO_utf8esc (char *buff, unsigned int x) {
+ int n = 1; /* number of bytes put in buffer (backwards) */
+ if (x < 0x80) /* ascii? */
+ buff[UTF8BUFFSZ - 1] = x;
+ else { /* need continuation bytes */
+ unsigned int mfb = 0x3f; /* maximum that fits in first byte */
+ do {
+ buff[UTF8BUFFSZ - (n++)] = 0x80 | (x & 0x3f); /* add continuation byte */
+ x >>= 6; /* remove added bits */
+ mfb >>= 1; /* now there is one less bit available in first byte */
+ } while (x > mfb); /* still needs continuation byte? */
+ buff[UTF8BUFFSZ - n] = (~mfb << 1) | x; /* add first byte */
+ }
+ return n;
+}
+
+
static void pushstr (lua_State *L, const char *str, size_t l) {
setsvalue2s(L, L->top++, luaS_newlstr(L, str, l));
}
-/* this function handles only `%d', `%c', %f, %p, and `%s' formats */
+/* this function handles only '%d', '%c', '%f', '%p', and '%s'
+ conventional formats, plus Lua-specific '%L' and '%U' */
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
int n = 0;
for (;;) {
@@ -311,6 +355,12 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
pushstr(L, buff, l);
break;
}
+ case 'U': {
+ char buff[UTF8BUFFSZ];
+ int l = luaO_utf8esc(buff, va_arg(argp, int));
+ pushstr(L, buff + UTF8BUFFSZ - l, l);
+ break;
+ }
case '%': {
pushstr(L, "%", 1);
break;
diff --git a/src/lobject.h b/src/lobject.h
index 55b4e240..b8b621f9 100644
--- a/src/lobject.h
+++ b/src/lobject.h
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.h,v 2.78 2013/05/14 15:59:04 roberto Exp $
+** $Id: lobject.h,v 2.86 2014/02/19 13:52:42 roberto Exp $
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
@@ -20,13 +20,12 @@
** Extra tags for non-values
*/
#define LUA_TPROTO LUA_NUMTAGS
-#define LUA_TUPVAL (LUA_NUMTAGS+1)
-#define LUA_TDEADKEY (LUA_NUMTAGS+2)
+#define LUA_TDEADKEY (LUA_NUMTAGS+1)
/*
** number of all possible tags (including LUA_TNONE but excluding DEADKEY)
*/
-#define LUA_TOTALTAGS (LUA_TUPVAL+2)
+#define LUA_TOTALTAGS (LUA_TPROTO + 2)
/*
@@ -147,7 +146,7 @@ typedef struct lua_TValue TValue;
#define ttisCclosure(o) checktag((o), ctb(LUA_TCCL))
#define ttisLclosure(o) checktag((o), ctb(LUA_TLCL))
#define ttislcf(o) checktag((o), LUA_TLCF)
-#define ttisuserdata(o) checktag((o), ctb(LUA_TUSERDATA))
+#define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA))
#define ttisthread(o) checktag((o), ctb(LUA_TTHREAD))
#define ttisdeadkey(o) checktag((o), LUA_TDEADKEY)
@@ -159,7 +158,7 @@ typedef struct lua_TValue TValue;
#define pvalue(o) check_exp(ttislightuserdata(o), val_(o).p)
#define rawtsvalue(o) check_exp(ttisstring(o), &val_(o).gc->ts)
#define tsvalue(o) (&rawtsvalue(o)->tsv)
-#define rawuvalue(o) check_exp(ttisuserdata(o), &val_(o).gc->u)
+#define rawuvalue(o) check_exp(ttisfulluserdata(o), &val_(o).gc->u)
#define uvalue(o) (&rawuvalue(o)->uv)
#define clvalue(o) check_exp(ttisclosure(o), &val_(o).gc->cl)
#define clLvalue(o) check_exp(ttisLclosure(o), &val_(o).gc->cl.l)
@@ -311,8 +310,9 @@ typedef union TString {
struct {
CommonHeader;
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
- unsigned int hash;
size_t len; /* number of characters in string */
+ union TString *hnext; /* linked list for hash table */
+ unsigned int hash;
} tsv;
} TString;
@@ -331,13 +331,25 @@ typedef union Udata {
L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */
struct {
CommonHeader;
+ lu_byte ttuv_; /* user value's tag */
struct Table *metatable;
- struct Table *env;
size_t len; /* number of bytes */
+ union Value user_; /* user value */
} uv;
} Udata;
+#define setuservalue(L,u,o) \
+ { const TValue *io=(o); Udata *iu = (u); \
+ iu->uv.user_ = io->value_; iu->uv.ttuv_ = io->tt_; \
+ checkliveness(G(L),io); }
+
+
+#define getuservalue(L,u,o) \
+ { TValue *io=(o); const Udata *iu = (u); \
+ io->value_ = iu->uv.user_; io->tt_ = iu->uv.ttuv_; \
+ checkliveness(G(L),io); }
+
/*
** Description of an upvalue for function prototypes
@@ -392,17 +404,7 @@ typedef struct Proto {
/*
** Lua Upvalues
*/
-typedef struct UpVal {
- CommonHeader;
- TValue *v; /* points to stack or to its own value */
- union {
- TValue value; /* the value (when closed) */
- struct { /* double linked list (when open) */
- struct UpVal *prev;
- struct UpVal *next;
- } l;
- } u;
-} UpVal;
+typedef struct UpVal UpVal;
/*
@@ -444,7 +446,7 @@ typedef union Closure {
typedef union TKey {
struct {
TValuefields;
- struct Node *next; /* for chaining */
+ int next; /* for chaining (offset for next node) */
} nk;
TValue tvk;
} TKey;
@@ -489,9 +491,12 @@ typedef struct Table {
LUAI_DDEC const TValue luaO_nilobject_;
+/* size of buffer for 'luaO_utf8esc' function */
+#define UTF8BUFFSZ 8
LUAI_FUNC int luaO_int2fb (unsigned int x);
LUAI_FUNC int luaO_fb2int (int x);
+LUAI_FUNC int luaO_utf8esc (char *buff, unsigned int x);
LUAI_FUNC int luaO_ceillog2 (unsigned int x);
LUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1,
const TValue *p2, TValue *res);
diff --git a/src/lopcodes.c b/src/lopcodes.c
index 0bd7a3e8..973e705d 100644
--- a/src/lopcodes.c
+++ b/src/lopcodes.c
@@ -1,5 +1,5 @@
/*
-** $Id: lopcodes.c,v 1.50 2013/04/26 13:07:53 roberto Exp $
+** $Id: lopcodes.c,v 1.53 2013/12/30 20:47:58 roberto Exp $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -31,11 +31,17 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
"ADD",
"SUB",
"MUL",
- "DIV",
- "IDIV",
"MOD",
"POW",
+ "DIV",
+ "IDIV",
+ "BAND",
+ "BOR",
+ "BXOR",
+ "SHL",
+ "SHR",
"UNM",
+ "BNOT",
"NOT",
"LEN",
"CONCAT",
@@ -80,11 +86,17 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */
,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */
,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */
- ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */
- ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_IDIV */
,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */
,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_IDIV */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BAND */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BOR */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BXOR */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHL */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHR */
,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */
+ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_BNOT */
,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */
,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */
,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */
diff --git a/src/lopcodes.h b/src/lopcodes.h
index 6c27b27a..3f5d0153 100644
--- a/src/lopcodes.h
+++ b/src/lopcodes.h
@@ -1,5 +1,5 @@
/*
-** $Id: lopcodes.h,v 1.143 2013/04/26 13:07:53 roberto Exp $
+** $Id: lopcodes.h,v 1.146 2013/12/30 20:47:58 roberto Exp $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -187,11 +187,17 @@ OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
OP_ADD,/* A B C R(A) := RK(B) + RK(C) */
OP_SUB,/* A B C R(A) := RK(B) - RK(C) */
OP_MUL,/* A B C R(A) := RK(B) * RK(C) */
-OP_DIV,/* A B C R(A) := RK(B) / RK(C) */
-OP_IDIV,/* A B C R(A) := RK(B) // RK(C) */
OP_MOD,/* A B C R(A) := RK(B) % RK(C) */
OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */
+OP_DIV,/* A B C R(A) := RK(B) / RK(C) */
+OP_IDIV,/* A B C R(A) := RK(B) // RK(C) */
+OP_BAND,/* A B C R(A) := RK(B) & RK(C) */
+OP_BOR,/* A B C R(A) := RK(B) | RK(C) */
+OP_BXOR,/* A B C R(A) := RK(B) ~ RK(C) */
+OP_SHL,/* A B C R(A) := RK(B) << RK(C) */
+OP_SHR,/* A B C R(A) := RK(B) >> RK(C) */
OP_UNM,/* A B R(A) := -R(B) */
+OP_BNOT,/* A B R(A) := ~R(B) */
OP_NOT,/* A B R(A) := not R(B) */
OP_LEN,/* A B R(A) := length of R(B) */
diff --git a/src/loslib.c b/src/loslib.c
index 6d59bc39..776dda57 100644
--- a/src/loslib.c
+++ b/src/loslib.c
@@ -1,5 +1,5 @@
/*
-** $Id: loslib.c,v 1.41 2013/05/14 15:57:11 roberto Exp $
+** $Id: loslib.c,v 1.45 2014/03/20 19:18:54 roberto Exp $
** Standard Operating System library
** See Copyright Notice in lua.h
*/
@@ -20,29 +20,44 @@
#include "lualib.h"
+#if !defined(LUA_STRFTIMEOPTIONS) /* { */
/*
** list of valid conversion specifiers for the 'strftime' function
*/
-#if !defined(LUA_STRFTIMEOPTIONS)
#if !defined(LUA_USE_POSIX)
#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" }
#else
#define LUA_STRFTIMEOPTIONS \
- { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "" \
- "", "E", "cCxXyY", \
+ { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \
+ "E", "cCxXyY", \
"O", "deHImMSuUVwWy" }
#endif
-#endif
+#endif /* } */
+
+
+
+#if !defined(l_time_t) /* { */
+/*
+** type to represent time_t in Lua
+*/
+#define l_timet lua_Integer
+#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t))
+#define l_checktime(L,a) ((time_t)luaL_checkinteger(L,a))
+#endif /* } */
+
+#if !defined(lua_tmpnam) /* { */
/*
** By default, Lua uses tmpnam except when POSIX is available, where it
** uses mkstemp.
*/
-#if defined(LUA_USE_MKSTEMP)
+
+#if defined(LUA_USE_POSIX) /* { */
+
#include <unistd.h>
#define LUA_TMPNAMBUFSIZE 32
#define lua_tmpnam(b,e) { \
@@ -51,29 +66,38 @@
if (e != -1) close(e); \
e = (e == -1); }
-#elif !defined(lua_tmpnam)
+#else /* }{ */
+/* ANSI definitions */
#define LUA_TMPNAMBUFSIZE L_tmpnam
#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); }
-#endif
+#endif /* } */
+
+#endif /* } */
+
+#if !defined(l_gmtime) /* { */
/*
** By default, Lua uses gmtime/localtime, except when POSIX is available,
** where it uses gmtime_r/localtime_r
*/
-#if defined(LUA_USE_GMTIME_R)
+
+#if defined(LUA_USE_POSIX) /* { */
#define l_gmtime(t,r) gmtime_r(t,r)
#define l_localtime(t,r) localtime_r(t,r)
-#elif !defined(l_gmtime)
+#else /* }{ */
+/* ANSI definitions */
#define l_gmtime(t,r) ((void)r, gmtime(t))
#define l_localtime(t,r) ((void)r, localtime(t))
-#endif
+#endif /* } */
+
+#endif /* } */
@@ -147,8 +171,7 @@ static void setboolfield (lua_State *L, const char *key, int value) {
static int getboolfield (lua_State *L, const char *key) {
int res;
- lua_getfield(L, -1, key);
- res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1);
+ res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1);
lua_pop(L, 1);
return res;
}
@@ -194,7 +217,7 @@ static const char *checkoption (lua_State *L, const char *conv, char *buff) {
static int os_date (lua_State *L) {
const char *s = luaL_optstring(L, 1, "%c");
- time_t t = luaL_opt(L, (time_t)luaL_checkinteger, 2, time(NULL));
+ time_t t = luaL_opt(L, l_checktime, 2, time(NULL));
struct tm tmr, *stm;
if (*s == '!') { /* UTC? */
stm = l_gmtime(&t, &tmr);
@@ -255,17 +278,18 @@ static int os_time (lua_State *L) {
ts.tm_isdst = getboolfield(L, "isdst");
t = mktime(&ts);
}
- if (t == (time_t)(-1))
+ if (t != (time_t)(l_timet)t)
+ luaL_error(L, "time result cannot be represented in this Lua instalation");
+ else if (t == (time_t)(-1))
lua_pushnil(L);
else
- lua_pushinteger(L, t);
+ l_pushtime(L, t);
return 1;
}
static int os_difftime (lua_State *L) {
- lua_pushnumber(L, difftime((time_t)(luaL_checkinteger(L, 1)),
- (time_t)(luaL_optinteger(L, 2, 0))));
+ lua_pushnumber(L, difftime((l_checktime(L, 1)), (l_checktime(L, 2))));
return 1;
}
diff --git a/src/lparser.c b/src/lparser.c
index e8a6b8ef..93491497 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.c,v 2.133 2013/04/26 13:07:53 roberto Exp $
+** $Id: lparser.c,v 2.138 2013/12/30 20:47:58 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -35,6 +35,10 @@
#define hasmultret(k) ((k) == VCALL || (k) == VVARARG)
+/* because all strings are unified by the scanner, the parser
+ can use pointer equality for string equality */
+#define eqstr(a,b) ((a) == (b))
+
/*
** nodes for block list (list of active blocks)
@@ -57,16 +61,6 @@ static void statement (LexState *ls);
static void expr (LexState *ls, expdesc *v);
-static void anchor_token (LexState *ls) {
- /* last token from outer function must be EOS */
- lua_assert(ls->fs != NULL || ls->t.token == TK_EOS);
- if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) {
- TString *ts = ls->t.seminfo.ts;
- luaX_newstring(ls, getstr(ts), ts->tsv.len);
- }
-}
-
-
/* semantic error */
static l_noret semerror (LexState *ls, const char *msg) {
ls->t.token = 0; /* remove 'near to' from final message */
@@ -222,7 +216,7 @@ static int searchupvalue (FuncState *fs, TString *name) {
int i;
Upvaldesc *up = fs->f->upvalues;
for (i = 0; i < fs->nups; i++) {
- if (luaS_eqstr(up[i].name, name)) return i;
+ if (eqstr(up[i].name, name)) return i;
}
return -1; /* not found */
}
@@ -246,7 +240,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
static int searchvar (FuncState *fs, TString *n) {
int i;
for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
- if (luaS_eqstr(n, getlocvar(fs, i)->varname))
+ if (eqstr(n, getlocvar(fs, i)->varname))
return i;
}
return -1; /* not found */
@@ -342,7 +336,7 @@ static void closegoto (LexState *ls, int g, Labeldesc *label) {
FuncState *fs = ls->fs;
Labellist *gl = &ls->dyd->gt;
Labeldesc *gt = &gl->arr[g];
- lua_assert(luaS_eqstr(gt->name, label->name));
+ lua_assert(eqstr(gt->name, label->name));
if (gt->nactvar < label->nactvar) {
TString *vname = getlocvar(fs, gt->nactvar)->varname;
const char *msg = luaO_pushfstring(ls->L,
@@ -369,7 +363,7 @@ static int findlabel (LexState *ls, int g) {
/* check labels in current block for a match */
for (i = bl->firstlabel; i < dyd->label.n; i++) {
Labeldesc *lb = &dyd->label.arr[i];
- if (luaS_eqstr(lb->name, gt->name)) { /* correct label? */
+ if (eqstr(lb->name, gt->name)) { /* correct label? */
if (gt->nactvar > lb->nactvar &&
(bl->upval || dyd->label.n > bl->firstlabel))
luaK_patchclose(ls->fs, gt->pc, lb->nactvar);
@@ -403,7 +397,7 @@ static void findgotos (LexState *ls, Labeldesc *lb) {
Labellist *gl = &ls->dyd->gt;
int i = ls->fs->bl->firstgoto;
while (i < gl->n) {
- if (luaS_eqstr(gl->arr[i].name, lb->name))
+ if (eqstr(gl->arr[i].name, lb->name))
closegoto(ls, i, lb);
else
i++;
@@ -525,7 +519,6 @@ static void codeclosure (LexState *ls, expdesc *v) {
static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
- lua_State *L = ls->L;
Proto *f;
fs->prev = ls->fs; /* linked list of funcstates */
fs->ls = ls;
@@ -544,10 +537,6 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
f = fs->f;
f->source = ls->source;
f->maxstacksize = 2; /* registers 0/1 are always valid */
- fs->h = luaH_new(L);
- /* anchor table of constants (to avoid being collected) */
- sethvalue2s(L, L->top, fs->h);
- incr_top(L);
enterblock(fs, bl, 0);
}
@@ -572,9 +561,6 @@ static void close_func (LexState *ls) {
f->sizeupvalues = fs->nups;
lua_assert(fs->bl == NULL);
ls->fs = fs->prev;
- /* last token read was anchored in defunct function; must re-anchor it */
- anchor_token(ls);
- L->top--; /* pop table of constants */
luaC_checkGC(L);
}
@@ -993,6 +979,7 @@ static UnOpr getunopr (int op) {
switch (op) {
case TK_NOT: return OPR_NOT;
case '-': return OPR_MINUS;
+ case '~': return OPR_BNOT;
case '#': return OPR_LEN;
default: return OPR_NOUNOPR;
}
@@ -1004,10 +991,15 @@ static BinOpr getbinopr (int op) {
case '+': return OPR_ADD;
case '-': return OPR_SUB;
case '*': return OPR_MUL;
- case '/': return OPR_DIV;
- case TK_IDIV: return OPR_IDIV;
case '%': return OPR_MOD;
case '^': return OPR_POW;
+ case '/': return OPR_DIV;
+ case TK_IDIV: return OPR_IDIV;
+ case '&': return OPR_BAND;
+ case '|': return OPR_BOR;
+ case '~': return OPR_BXOR;
+ case TK_SHL: return OPR_SHL;
+ case TK_SHR: return OPR_SHR;
case TK_CONCAT: return OPR_CONCAT;
case TK_NE: return OPR_NE;
case TK_EQ: return OPR_EQ;
@@ -1026,15 +1018,19 @@ static const struct {
lu_byte left; /* left priority for each binary operator */
lu_byte right; /* right priority */
} priority[] = { /* ORDER OPR */
- {6, 6}, {6, 6}, /* '+' '-' */
- {7, 7}, {7, 7}, {7, 7}, {7, 7}, /* '*' '/' '//' '%' */
- {10, 9}, {5, 4}, /* ^, .. (right associative) */
- {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */
- {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */
- {2, 2}, {1, 1} /* and, or */
+ {10, 10}, {10, 10}, /* '+' '-' */
+ {11, 11}, {11, 11}, /* '*' '%' */
+ {14, 13}, /* '^' (right associative) */
+ {11, 11}, {11, 11}, /* '/' '//' */
+ {6, 6}, {4, 4}, {5, 5}, /* '&' '|' '~' */
+ {7, 7}, {7, 7}, /* '<<' '>>' */
+ {9, 8}, /* '..' (right associative) */
+ {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */
+ {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */
+ {2, 2}, {1, 1} /* and, or */
};
-#define UNARY_PRIORITY 8 /* priority for unary operators */
+#define UNARY_PRIORITY 12 /* priority for unary operators */
/*
@@ -1202,7 +1198,7 @@ static void gotostat (LexState *ls, int pc) {
static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) {
int i;
for (i = fs->bl->firstlabel; i < ll->n; i++) {
- if (luaS_eqstr(label, ll->arr[i].name)) {
+ if (eqstr(label, ll->arr[i].name)) {
const char *msg = luaO_pushfstring(fs->ls->L,
"label " LUA_QS " already defined on line %d",
getstr(label), ll->arr[i].line);
@@ -1627,11 +1623,14 @@ Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
LexState lexstate;
FuncState funcstate;
Closure *cl = luaF_newLclosure(L, 1); /* create main closure */
- /* anchor closure (to avoid being collected) */
- setclLvalue(L, L->top, cl);
+ setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */
+ incr_top(L);
+ lexstate.h = luaH_new(L); /* create table for scanner */
+ sethvalue(L, L->top, lexstate.h); /* anchor it */
incr_top(L);
funcstate.f = cl->l.p = luaF_newproto(L);
funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
+ luaC_objbarrier(L, funcstate.f, funcstate.f->source);
lexstate.buff = buff;
lexstate.dyd = dyd;
dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;
@@ -1640,6 +1639,7 @@ Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
/* all scopes should be correctly finished */
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
- return cl; /* it's on the stack too */
+ L->top--; /* remove scanner's table */
+ return cl; /* closure is on the stack, too */
}
diff --git a/src/lparser.h b/src/lparser.h
index 147d3367..172d96d2 100644
--- a/src/lparser.h
+++ b/src/lparser.h
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.h,v 1.71 2013/04/16 18:46:28 roberto Exp $
+** $Id: lparser.h,v 1.72 2013/08/30 16:01:37 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -97,7 +97,6 @@ struct BlockCnt; /* defined in lparser.c */
/* state needed to generate code for a given function */
typedef struct FuncState {
Proto *f; /* current function header */
- Table *h; /* table to find (and reuse) elements in `k' */
struct FuncState *prev; /* enclosing function */
struct LexState *ls; /* lexical state */
struct BlockCnt *bl; /* chain of current blocks */
diff --git a/src/lstate.c b/src/lstate.c
index 207a106d..1628ad91 100644
--- a/src/lstate.c
+++ b/src/lstate.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.c,v 2.99 2012/10/02 17:40:53 roberto Exp $
+** $Id: lstate.c,v 2.121 2014/02/18 13:46:26 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -30,10 +30,6 @@
#define LUAI_GCPAUSE 200 /* 200% */
#endif
-#if !defined(LUAI_GCMAJOR)
-#define LUAI_GCMAJOR 200 /* 200% */
-#endif
-
#if !defined(LUAI_GCMUL)
#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */
#endif
@@ -119,6 +115,9 @@ CallInfo *luaE_extendCI (lua_State *L) {
}
+/*
+** free all CallInfo structures not in use by a thread
+*/
void luaE_freeCI (lua_State *L) {
CallInfo *ci = L->ci;
CallInfo *next = ci->next;
@@ -130,6 +129,22 @@ void luaE_freeCI (lua_State *L) {
}
+/*
+** free half of the CallInfo structures not in use by a thread
+*/
+void luaE_shrinkCI (lua_State *L) {
+ CallInfo *ci = L->ci;
+ while (ci->next != NULL) { /* while there is 'next' */
+ CallInfo *next2 = ci->next->next; /* next's next */
+ if (next2 == NULL) break;
+ luaM_free(L, ci->next); /* remove next */
+ ci->next = next2; /* remove 'next' from the list */
+ next2->previous = ci;
+ ci = next2;
+ }
+}
+
+
static void stack_init (lua_State *L1, lua_State *L) {
int i; CallInfo *ci;
/* initialize stack array */
@@ -163,22 +178,23 @@ static void freestack (lua_State *L) {
** Create registry table and its predefined values
*/
static void init_registry (lua_State *L, global_State *g) {
- TValue mt;
+ TValue temp;
/* create registry */
Table *registry = luaH_new(L);
sethvalue(L, &g->l_registry, registry);
luaH_resize(L, registry, LUA_RIDX_LAST, 0);
/* registry[LUA_RIDX_MAINTHREAD] = L */
- setthvalue(L, &mt, L);
- luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &mt);
+ setthvalue(L, &temp, L); /* temp = L */
+ luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp);
/* registry[LUA_RIDX_GLOBALS] = table of globals */
- sethvalue(L, &mt, luaH_new(L));
- luaH_setint(L, registry, LUA_RIDX_GLOBALS, &mt);
+ sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */
+ luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp);
}
/*
-** open parts of the state that may cause memory-allocation errors
+** open parts of the state that may cause memory-allocation errors.
+** ('g->version' != NULL flags that the state was completely build)
*/
static void f_luaopen (lua_State *L, void *ud) {
global_State *g = G(L);
@@ -190,20 +206,23 @@ static void f_luaopen (lua_State *L, void *ud) {
luaX_init(L);
/* pre-create memory-error message */
g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
- luaS_fix(g->memerrmsg); /* it should never be collected */
+ luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */
g->gcrunning = 1; /* allow gc */
+ g->version = lua_version(NULL);
+ luai_userstateopen(L);
}
/*
-** preinitialize a state with consistent values without allocating
+** preinitialize a thread with consistent values without allocating
** any memory (to avoid errors)
*/
-static void preinit_state (lua_State *L, global_State *g) {
+static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g;
L->stack = NULL;
L->ci = NULL;
L->stacksize = 0;
+ L->twups = L; /* thread has no upvalues */
L->errorJmp = NULL;
L->nCcalls = 0;
L->hook = NULL;
@@ -222,6 +241,8 @@ static void close_state (lua_State *L) {
global_State *g = G(L);
luaF_close(L, L->stack); /* close all upvalues for this thread */
luaC_freeallobjects(L); /* collect all objects */
+ if (g->version) /* closing a fully built state? */
+ luai_userstateclose(L);
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
luaZ_freebuffer(L, &g->buff);
freestack(L);
@@ -231,13 +252,20 @@ static void close_state (lua_State *L) {
LUA_API lua_State *lua_newthread (lua_State *L) {
+ global_State *g = G(L);
lua_State *L1;
lua_lock(L);
luaC_checkGC(L);
- L1 = &luaC_newobj(L, LUA_TTHREAD, sizeof(LX), NULL, offsetof(LX, l))->th;
+ /* create new thread */
+ L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l;
+ L1->marked = luaC_white(g);
+ L1->tt = LUA_TTHREAD;
+ /* link it on list 'allgc' */
+ L1->next = g->allgc;
+ g->allgc = obj2gco(L1);
setthvalue(L, L->top, L1);
api_incr_top(L);
- preinit_state(L1, G(L));
+ preinit_thread(L1, g);
L1->hookmask = L->hookmask;
L1->basehookcount = L->basehookcount;
L1->hook = L->hook;
@@ -269,36 +297,32 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g = &l->g;
L->next = NULL;
L->tt = LUA_TTHREAD;
- g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT);
+ g->currentwhite = bitmask(WHITE0BIT);
L->marked = luaC_white(g);
- g->gckind = KGC_NORMAL;
- preinit_state(L, g);
+ preinit_thread(L, g);
g->frealloc = f;
g->ud = ud;
g->mainthread = L;
g->seed = makeseed(L);
- g->uvhead.u.l.prev = &g->uvhead;
- g->uvhead.u.l.next = &g->uvhead;
g->gcrunning = 0; /* no GC while building state */
g->GCestimate = 0;
- g->strt.size = 0;
- g->strt.nuse = 0;
+ g->strt.size = g->strt.nuse = 0;
g->strt.hash = NULL;
setnilvalue(&g->l_registry);
luaZ_initbuffer(L, &g->buff);
g->panic = NULL;
- g->version = lua_version(NULL);
+ g->version = NULL;
g->gcstate = GCSpause;
- g->allgc = NULL;
- g->finobj = NULL;
- g->tobefnz = NULL;
- g->sweepgc = g->sweepfin = NULL;
+ g->gckind = KGC_NORMAL;
+ g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL;
+ g->sweepgc = NULL;
g->gray = g->grayagain = NULL;
g->weak = g->ephemeron = g->allweak = NULL;
+ g->twups = NULL;
g->totalbytes = sizeof(LG);
g->GCdebt = 0;
+ g->gcfinnum = 0;
g->gcpause = LUAI_GCPAUSE;
- g->gcmajorinc = LUAI_GCMAJOR;
g->gcstepmul = LUAI_GCMUL;
for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL;
if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {
@@ -306,8 +330,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
close_state(L);
L = NULL;
}
- else
- luai_userstateopen(L);
return L;
}
@@ -315,7 +337,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
LUA_API void lua_close (lua_State *L) {
L = G(L)->mainthread; /* only the main thread can be closed */
lua_lock(L);
- luai_userstateclose(L);
close_state(L);
}
diff --git a/src/lstate.h b/src/lstate.h
index c8a31f5c..7029adb3 100644
--- a/src/lstate.h
+++ b/src/lstate.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.h,v 2.82 2012/07/02 13:37:04 roberto Exp $
+** $Id: lstate.h,v 2.102 2014/02/18 13:46:26 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -16,25 +16,16 @@
/*
-** Some notes about garbage-collected objects: All objects in Lua must
-** be kept somehow accessible until being freed.
+** Some notes about garbage-collected objects: All objects in Lua must
+** be kept somehow accessible until being freed, so all objects always
+** belong to one (and only one) of these lists, using field 'next' of
+** the 'CommonHeader' for the link:
**
-** 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.
-**
-** Open upvalues are not subject to independent garbage collection. They
-** are collected together with their respective threads. Lua keeps a
-** double-linked list with all open upvalues (g->uvhead) so that it can
-** mark objects referred by them. (They are always gray, so they must
-** be remarked in the atomic step. Usually their contents would be marked
-** when traversing the respective threads, but the thread may already be
-** dead, while the upvalue is still accessible through closures.)
-**
-** Objects with finalizers are kept in the list g->finobj.
-**
-** The list g->tobefnz links all objects being finalized.
+** allgc: all objects not marked for finalization;
+** finobj: all objects marked for finalization;
+** tobefnz: all objects ready to be finalized;
+** fixedgc: all objects that are not to be collected (currently
+** only small strings, such as reserved words).
*/
@@ -53,12 +44,11 @@ struct lua_longjmp; /* defined in ldo.c */
/* kinds of Garbage Collection */
#define KGC_NORMAL 0
#define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */
-#define KGC_GEN 2 /* generational collection */
typedef struct stringtable {
- GCObject **hash;
- lu_int32 nuse; /* number of elements */
+ TString **hash;
+ int nuse; /* number of elements */
int size;
} stringtable;
@@ -123,21 +113,20 @@ typedef struct global_State {
lu_byte gcstate; /* state of garbage collector */
lu_byte gckind; /* kind of GC running */
lu_byte gcrunning; /* true if GC is running */
- int sweepstrgc; /* position of sweep in `strt' */
GCObject *allgc; /* list of all collectable objects */
+ GCObject **sweepgc; /* current position of sweep in list */
GCObject *finobj; /* list of collectable objects with finalizers */
- GCObject **sweepgc; /* current position of sweep in list 'allgc' */
- GCObject **sweepfin; /* current position of sweep in list 'finobj' */
GCObject *gray; /* list of gray objects */
GCObject *grayagain; /* list of objects to be traversed atomically */
GCObject *weak; /* list of tables with weak values */
GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
GCObject *allweak; /* list of all-weak tables */
GCObject *tobefnz; /* list of userdata to be GC */
- UpVal uvhead; /* head of double-linked list of all open upvalues */
+ GCObject *fixedgc; /* list of objects not to be collected */
+ struct lua_State *twups; /* list of threads with open upvalues */
Mbuffer buff; /* temporary buffer for string concatenation */
+ unsigned int gcfinnum; /* number of finalizers to call in each GC step */
int gcpause; /* size of pause between successive GCs */
- int gcmajorinc; /* pause between major collections (only in gen. mode) */
int gcstepmul; /* GC `granularity' */
lua_CFunction panic; /* to be called in unprotected errors */
struct lua_State *mainthread;
@@ -168,8 +157,9 @@ struct lua_State {
int basehookcount;
int hookcount;
lua_Hook hook;
- GCObject *openupval; /* list of open upvalues in this stack */
+ UpVal *openupval; /* list of open upvalues in this stack */
GCObject *gclist;
+ struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */
ptrdiff_t errfunc; /* current error handling function (stack index) */
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
@@ -189,7 +179,6 @@ union GCObject {
union Closure cl;
struct Table h;
struct Proto p;
- struct UpVal uv;
struct lua_State th; /* thread */
};
@@ -208,7 +197,6 @@ union GCObject {
check_exp(novariant((o)->gch.tt) == LUA_TFUNCTION, &((o)->cl))
#define gco2t(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h))
#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p))
-#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv))
#define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th))
/* macro to convert any Lua object into a GCObject */
@@ -222,6 +210,7 @@ LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
LUAI_FUNC void luaE_freeCI (lua_State *L);
+LUAI_FUNC void luaE_shrinkCI (lua_State *L);
#endif
diff --git a/src/lstring.c b/src/lstring.c
index d9781365..bbadb315 100644
--- a/src/lstring.c
+++ b/src/lstring.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstring.c,v 2.27 2013/06/19 14:27:00 roberto Exp $
+** $Id: lstring.c,v 2.38 2014/03/19 18:51:42 roberto Exp $
** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -12,12 +12,15 @@
#include "lua.h"
+#include "ldebug.h"
+#include "ldo.h"
#include "lmem.h"
#include "lobject.h"
#include "lstate.h"
#include "lstring.h"
+
/*
** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to
** compute its hash
@@ -39,15 +42,6 @@ int luaS_eqlngstr (TString *a, TString *b) {
}
-/*
-** equality for strings
-*/
-int luaS_eqstr (TString *a, TString *b) {
- return (a->tsv.tt == b->tsv.tt) &&
- (a->tsv.tt == LUA_TSHRSTR ? eqshrstr(a, b) : luaS_eqlngstr(a, b));
-}
-
-
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
unsigned int h = seed ^ cast(unsigned int, l);
size_t l1;
@@ -64,43 +58,41 @@ unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
void luaS_resize (lua_State *L, int newsize) {
int i;
stringtable *tb = &G(L)->strt;
- /* cannot resize while GC is traversing strings */
- luaC_runtilstate(L, ~bitmask(GCSsweepstring));
- if (newsize > tb->size) {
- luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *);
- for (i = tb->size; i < newsize; i++) tb->hash[i] = NULL;
+ if (newsize > tb->size) { /* grow table if needed */
+ luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *);
+ for (i = tb->size; i < newsize; i++)
+ tb->hash[i] = NULL;
}
- /* rehash */
- for (i=0; i<tb->size; i++) {
- GCObject *p = tb->hash[i];
+ for (i = 0; i < tb->size; i++) { /* rehash */
+ TString *p = tb->hash[i];
tb->hash[i] = NULL;
while (p) { /* for each node in the list */
- GCObject *next = gch(p)->next; /* save next */
- unsigned int h = lmod(gco2ts(p)->hash, newsize); /* new position */
- gch(p)->next = tb->hash[h]; /* chain it */
+ TString *hnext = p->tsv.hnext; /* save next */
+ unsigned int h = lmod(p->tsv.hash, newsize); /* new position */
+ p->tsv.hnext = tb->hash[h]; /* chain it */
tb->hash[h] = p;
- resetoldbit(p); /* see MOVE OLD rule */
- p = next;
+ p = hnext;
}
}
- if (newsize < tb->size) {
- /* shrinking slice must be empty */
+ if (newsize < tb->size) { /* shrink table if needed */
+ /* vanishing slice should be empty */
lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL);
- luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *);
+ luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *);
}
tb->size = newsize;
}
+
/*
** creates a new string object
*/
static TString *createstrobj (lua_State *L, const char *str, size_t l,
- int tag, unsigned int h, GCObject **list) {
+ int tag, unsigned int h) {
TString *ts;
size_t totalsize; /* total size of TString object */
totalsize = sizeof(TString) + ((l + 1) * sizeof(char));
- ts = &luaC_newobj(L, tag, totalsize, list, 0)->ts;
+ ts = &luaC_newobj(L, tag, totalsize)->ts;
ts->tsv.len = l;
ts->tsv.hash = h;
ts->tsv.extra = 0;
@@ -110,20 +102,13 @@ static TString *createstrobj (lua_State *L, const char *str, size_t l,
}
-/*
-** creates a new short string, inserting it into string table
-*/
-static TString *newshrstr (lua_State *L, const char *str, size_t l,
- unsigned int h) {
- GCObject **list; /* (pointer to) list where it will be inserted */
+LUAI_FUNC void luaS_remove (lua_State *L, TString *ts) {
stringtable *tb = &G(L)->strt;
- TString *s;
- if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
- luaS_resize(L, tb->size*2); /* too crowded */
- list = &tb->hash[lmod(h, tb->size)];
- s = createstrobj(L, str, l, LUA_TSHRSTR, h, list);
- tb->nuse++;
- return s;
+ TString **p = &tb->hash[lmod(ts->tsv.hash, tb->size)];
+ while (*p != ts) /* find previous element */
+ p = &(*p)->tsv.hnext;
+ *p = (*p)->tsv.hnext; /* remove element from its list */
+ tb->nuse--;
}
@@ -131,22 +116,28 @@ static TString *newshrstr (lua_State *L, const char *str, size_t l,
** checks whether short string exists and reuses it or creates a new one
*/
static TString *internshrstr (lua_State *L, const char *str, size_t l) {
- GCObject *o;
+ TString *ts;
global_State *g = G(L);
unsigned int h = luaS_hash(str, l, g->seed);
- for (o = g->strt.hash[lmod(h, g->strt.size)];
- o != NULL;
- o = gch(o)->next) {
- TString *ts = rawgco2ts(o);
- if (h == ts->tsv.hash &&
- l == ts->tsv.len &&
+ TString **list = &g->strt.hash[lmod(h, g->strt.size)];
+ for (ts = *list; ts != NULL; ts = ts->tsv.hnext) {
+ if (l == ts->tsv.len &&
(memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
- if (isdead(G(L), o)) /* string is dead (but was not collected yet)? */
- changewhite(o); /* resurrect it */
+ /* found! */
+ if (isdead(g, obj2gco(ts))) /* dead (but not collected yet)? */
+ changewhite(obj2gco(ts)); /* resurrect it */
return ts;
}
}
- return newshrstr(L, str, l, h); /* not found; create a new string */
+ if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) {
+ luaS_resize(L, g->strt.size * 2);
+ list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */
+ }
+ ts = createstrobj(L, str, l, LUA_TSHRSTR, h);
+ ts->tsv.hnext = *list;
+ *list = ts;
+ g->strt.nuse++;
+ return ts;
}
@@ -159,7 +150,7 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
else {
if (l + 1 > (MAX_SIZE - sizeof(TString))/sizeof(char))
luaM_toobig(L);
- return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed, NULL);
+ return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed);
}
}
@@ -172,14 +163,14 @@ TString *luaS_new (lua_State *L, const char *str) {
}
-Udata *luaS_newudata (lua_State *L, size_t s, Table *e) {
+Udata *luaS_newudata (lua_State *L, size_t s) {
Udata *u;
if (s > MAX_SIZE - sizeof(Udata))
luaM_toobig(L);
- u = &luaC_newobj(L, LUA_TUSERDATA, sizeof(Udata) + s, NULL, 0)->u;
+ u = &luaC_newobj(L, LUA_TUSERDATA, sizeof(Udata) + s)->u;
u->uv.len = s;
u->uv.metatable = NULL;
- u->uv.env = e;
+ setuservalue(L, u, luaO_nilobject);
return u;
}
diff --git a/src/lstring.h b/src/lstring.h
index d312ff3d..d5f5b249 100644
--- a/src/lstring.h
+++ b/src/lstring.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstring.h,v 1.49 2012/02/01 21:57:15 roberto Exp $
+** $Id: lstring.h,v 1.54 2014/03/19 18:51:42 roberto Exp $
** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -19,8 +19,6 @@
#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \
(sizeof(s)/sizeof(char))-1))
-#define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT)
-
/*
** test whether a string is a reserved word
@@ -36,9 +34,9 @@
LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
-LUAI_FUNC int luaS_eqstr (TString *a, TString *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 void luaS_remove (lua_State *L, TString *ts);
+LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s);
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);
diff --git a/src/lstrlib.c b/src/lstrlib.c
index 28acab83..d8106c0d 100644
--- a/src/lstrlib.c
+++ b/src/lstrlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstrlib.c,v 1.182 2013/06/20 15:06:51 roberto Exp $
+** $Id: lstrlib.c,v 1.189 2014/03/21 14:26:44 roberto Exp $
** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
@@ -116,7 +116,7 @@ static int str_rep (lua_State *L) {
lua_Integer n = luaL_checkinteger(L, 2);
const char *sep = luaL_optlstring(L, 3, "", &lsep);
if (n <= 0) lua_pushliteral(L, "");
- else if (l + lsep < l || l + lsep >= MAXSIZE / n) /* may overflow? */
+ else if (l + lsep < l || l + lsep > MAXSIZE / n) /* may overflow? */
return luaL_error(L, "resulting string too large");
else {
size_t totallen = n * l + (n - 1) * lsep;
@@ -124,8 +124,9 @@ static int str_rep (lua_State *L) {
char *p = luaL_buffinitsize(L, &b, totallen);
while (n-- > 1) { /* first n-1 copies (followed by separator) */
memcpy(p, s, l * sizeof(char)); p += l;
- if (lsep > 0) { /* avoid empty 'memcpy' (may be expensive) */
- memcpy(p, sep, lsep * sizeof(char)); p += lsep;
+ if (lsep > 0) { /* empty 'memcpy' is not that cheap */
+ memcpy(p, sep, lsep * sizeof(char));
+ p += lsep;
}
}
memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */
@@ -178,10 +179,11 @@ static int writer (lua_State *L, const void *b, size_t size, void *B) {
static int str_dump (lua_State *L) {
luaL_Buffer b;
+ int strip = lua_toboolean(L, 2);
luaL_checktype(L, 1, LUA_TFUNCTION);
lua_settop(L, 1);
luaL_buffinit(L,&b);
- if (lua_dump(L, writer, &b) != 0)
+ if (lua_dump(L, writer, &b, strip) != 0)
return luaL_error(L, "unable to dump given function");
luaL_pushresult(&b);
return 1;
@@ -938,6 +940,217 @@ static int str_format (lua_State *L) {
/* }====================================================== */
+/*
+** {======================================================
+** PACK/UNPACK
+** =======================================================
+*/
+
+/* maximum size for the binary representation of an integer */
+#define MAXINTSIZE 8
+
+
+/* number of bits in a character */
+#define NB CHAR_BIT
+
+/* mask for one character (NB ones) */
+#define MC (((lua_Integer)1 << NB) - 1)
+
+/* mask for one character without sign ((NB - 1) ones) */
+#define SM (((lua_Integer)1 << (NB - 1)) - 1)
+
+
+#define SZINT ((int)sizeof(lua_Integer))
+
+
+static union {
+ int dummy;
+ char little; /* true iff machine is little endian */
+} const nativeendian = {1};
+
+
+static int getendian (lua_State *L, int arg) {
+ const char *endian = luaL_optstring(L, arg,
+ (nativeendian.little ? "l" : "b"));
+ if (*endian == 'n') /* native? */
+ return nativeendian.little;
+ luaL_argcheck(L, *endian == 'l' || *endian == 'b', arg,
+ "endianess must be 'l'/'b'/'n'");
+ return (*endian == 'l');
+}
+
+
+static int getintsize (lua_State *L, int arg) {
+ int size = luaL_optint(L, arg, 0);
+ if (size == 0) size = SZINT;
+ luaL_argcheck(L, 1 <= size && size <= MAXINTSIZE, arg,
+ "integer size out of valid range");
+ return size;
+}
+
+
+static int packint (char *buff, lua_Integer n, int littleendian, int size) {
+ int i;
+ if (littleendian) {
+ for (i = 0; i < size - 1; i++) {
+ buff[i] = (n & MC);
+ n >>= NB;
+ }
+ }
+ else {
+ for (i = size - 1; i > 0; i--) {
+ buff[i] = (n & MC);
+ n >>= NB;
+ }
+ }
+ buff[i] = (n & MC); /* last byte */
+ /* test for overflow: OK if there are only zeros left in higher bytes,
+ or if there are only ones left and packed number is negative (signal
+ bit, the higher bit in last byte, is one) */
+ return ((n & ~MC) == 0 || (n | SM) == ~(lua_Integer)0);
+}
+
+
+static int packint_l (lua_State *L) {
+ char buff[MAXINTSIZE];
+ lua_Integer n = luaL_checkinteger(L, 1);
+ int size = getintsize(L, 2);
+ int endian = getendian(L, 3);
+ if (packint(buff, n, endian, size))
+ lua_pushlstring(L, buff, size);
+ else
+ luaL_error(L, "integer does not fit into given size (%d)", size);
+ return 1;
+}
+
+
+/* mask to check higher-order byte in a Lua integer */
+#define HIGHERBYTE (MC << (NB * (SZINT - 1)))
+
+/* mask to check higher-order byte + signal bit of next (lower) byte */
+#define HIGHERBYTE1 (HIGHERBYTE | (HIGHERBYTE >> 1))
+
+static int unpackint (const char *buff, lua_Integer *res,
+ int littleendian, int size) {
+ lua_Integer n = 0;
+ int i;
+ for (i = 0; i < size; i++) {
+ if (i >= SZINT) { /* will throw away a byte? */
+ /* check for overflow: it is OK to throw away leading zeros for a
+ positive number, leading ones for a negative number, and a
+ leading zero byte to allow unsigned integers with a 1 in
+ its "signal bit" */
+ if (!((n & HIGHERBYTE1) == 0 || /* zeros for positive number */
+ (n & HIGHERBYTE1) == HIGHERBYTE1 || /* ones for negative number */
+ ((n & HIGHERBYTE) == 0 && i == size - 1))) /* leading zero */
+ return 0; /* overflow */
+ }
+ n <<= NB;
+ n |= (lua_Integer)(unsigned char)buff[littleendian ? size - 1 - i : i];
+ }
+ if (size < SZINT) { /* need sign extension? */
+ lua_Integer mask = (~(lua_Integer)0) << (size*NB - 1);
+ if (n & mask) /* negative value? */
+ n |= mask; /* signal extension */
+ }
+ *res = n;
+ return 1;
+}
+
+
+static int unpackint_l (lua_State *L) {
+ lua_Integer res;
+ size_t len;
+ const char *s = luaL_checklstring(L, 1, &len);
+ lua_Integer pos = posrelat(luaL_optinteger(L, 2, 1), len);
+ int size = getintsize(L, 3);
+ int endian = getendian(L, 4);
+ luaL_argcheck(L, 1 <= pos && (size_t)pos + size - 1 <= len, 1,
+ "string too short");
+ if(unpackint(s + pos - 1, &res, endian, size))
+ lua_pushinteger(L, res);
+ else
+ luaL_error(L, "result does not fit into a Lua integer");
+ return 1;
+}
+
+
+static void correctendianess (lua_State *L, char *b, int size, int endianarg) {
+ int endian = getendian(L, endianarg);
+ if (endian != nativeendian.little) { /* not native endianess? */
+ int i = 0;
+ while (i < --size) {
+ char temp = b[i];
+ b[i++] = b[size];
+ b[size] = temp;
+ }
+ }
+}
+
+
+static int getfloatsize (lua_State *L, int arg) {
+ const char *size = luaL_optstring(L, arg, "n");
+ if (*size == 'n') return sizeof(lua_Number);
+ luaL_argcheck(L, *size == 'd' || *size == 'f', arg,
+ "size must be 'f'/'d'/'n'");
+ return (*size == 'd' ? sizeof(double) : sizeof(float));
+}
+
+
+static int packfloat_l (lua_State *L) {
+ float f; double d;
+ char *pn; /* pointer to number */
+ lua_Number n = luaL_checknumber(L, 1);
+ int size = getfloatsize(L, 2);
+ if (size == sizeof(lua_Number))
+ pn = (char*)&n;
+ else if (size == sizeof(float)) {
+ f = (float)n;
+ pn = (char*)&f;
+ }
+ else { /* native lua_Number may be neither float nor double */
+ lua_assert(size == sizeof(double));
+ d = (double)n;
+ pn = (char*)&d;
+ }
+ correctendianess(L, pn, size, 3);
+ lua_pushlstring(L, pn, size);
+ return 1;
+}
+
+
+static int unpackfloat_l (lua_State *L) {
+ lua_Number res;
+ size_t len;
+ const char *s = luaL_checklstring(L, 1, &len);
+ lua_Integer pos = posrelat(luaL_optinteger(L, 2, 1), len);
+ int size = getfloatsize(L, 3);
+ luaL_argcheck(L, 1 <= pos && (size_t)pos + size - 1 <= len, 1,
+ "string too short");
+ if (size == sizeof(lua_Number)) {
+ memcpy(&res, s + pos - 1, size);
+ correctendianess(L, (char*)&res, size, 4);
+ }
+ else if (size == sizeof(float)) {
+ float f;
+ memcpy(&f, s + pos - 1, size);
+ correctendianess(L, (char*)&f, size, 4);
+ res = (lua_Number)f;
+ }
+ else { /* native lua_Number may be neither float nor double */
+ double d;
+ lua_assert(size == sizeof(double));
+ memcpy(&d, s + pos - 1, size);
+ correctendianess(L, (char*)&d, size, 4);
+ res = (lua_Number)d;
+ }
+ lua_pushnumber(L, res);
+ return 1;
+}
+
+/* }====================================================== */
+
+
static const luaL_Reg strlib[] = {
{"byte", str_byte},
{"char", str_char},
@@ -953,6 +1166,10 @@ static const luaL_Reg strlib[] = {
{"reverse", str_reverse},
{"sub", str_sub},
{"upper", str_upper},
+ {"packfloat", packfloat_l},
+ {"packint", packint_l},
+ {"unpackfloat", unpackfloat_l},
+ {"unpackint", unpackint_l},
{NULL, NULL}
};
diff --git a/src/ltable.c b/src/ltable.c
index 4b39a8de..15432faa 100644
--- a/src/ltable.c
+++ b/src/ltable.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltable.c,v 2.78 2013/06/20 15:02:49 roberto Exp $
+** $Id: ltable.c,v 2.84 2014/01/27 13:34:32 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -79,7 +79,7 @@
static const Node dummynode_ = {
{NILCONSTANT}, /* value */
- {{NILCONSTANT, NULL}} /* key */
+ {{NILCONSTANT, 0}} /* key */
};
@@ -158,6 +158,7 @@ static int findindex (lua_State *L, Table *t, StkId key) {
if (0 < i && i <= t->sizearray) /* is `key' inside array part? */
return i-1; /* yes; that's the index (corrected to C) */
else {
+ int nx;
Node *n = mainposition(t, key);
for (;;) { /* check whether `key' is somewhere in the chain */
/* key may be dead already, but it is ok to use it in `next' */
@@ -168,9 +169,10 @@ static int findindex (lua_State *L, Table *t, StkId key) {
/* hash elements are numbered after array ones */
return i + t->sizearray;
}
- else n = gnext(n);
- if (n == NULL)
+ nx = gnext(n);
+ if (nx == 0)
luaG_runerror(L, "invalid key to " LUA_QL("next")); /* key not found */
+ else n += nx;
}
}
}
@@ -301,7 +303,7 @@ static void setnodevector (lua_State *L, Table *t, int size) {
t->node = luaM_newvector(L, size, Node);
for (i=0; i<size; i++) {
Node *n = gnode(t, i);
- gnext(n) = NULL;
+ gnext(n) = 0;
setnilvalue(gkey(n));
setnilvalue(gval(n));
}
@@ -376,7 +378,7 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) {
Table *luaH_new (lua_State *L) {
- Table *t = &luaC_newobj(L, LUA_TTABLE, sizeof(Table), NULL, 0)->h;
+ Table *t = &luaC_newobj(L, LUA_TTABLE, sizeof(Table))->h;
t->metatable = NULL;
t->flags = cast_byte(~0);
t->array = NULL;
@@ -419,7 +421,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
else if (ttisfloat(key)) {
lua_Number n = fltvalue(key);
lua_Integer k;
- if (luai_numisnan(L, n))
+ if (luai_numisnan(n))
luaG_runerror(L, "table index is NaN");
if (numisinteger(n, &k)) { /* index is int? */
setivalue(&aux, k);
@@ -429,31 +431,37 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
mp = mainposition(t, key);
if (!ttisnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */
Node *othern;
- Node *n = getfreepos(t); /* get a free place */
- if (n == NULL) { /* cannot find a free place? */
+ Node *f = getfreepos(t); /* get a free place */
+ if (f == NULL) { /* cannot find a free place? */
rehash(L, t, key); /* grow table */
/* whatever called 'newkey' take care of TM cache and GC barrier */
return luaH_set(L, t, key); /* insert key into grown table */
}
- lua_assert(!isdummy(n));
+ lua_assert(!isdummy(f));
othern = mainposition(t, gkey(mp));
if (othern != mp) { /* is colliding node out of its main position? */
/* yes; move colliding node into free position */
- while (gnext(othern) != mp) othern = gnext(othern); /* find previous */
- gnext(othern) = n; /* redo the chain with `n' in place of `mp' */
- *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */
- gnext(mp) = NULL; /* now `mp' is free */
+ while (othern + gnext(othern) != mp) /* find previous */
+ othern += gnext(othern);
+ gnext(othern) = f - othern; /* re-chain with 'f' in place of 'mp' */
+ *f = *mp; /* copy colliding node into free pos. (mp->next also goes) */
+ if (gnext(mp) != 0) {
+ gnext(f) += mp - f; /* correct 'next' */
+ gnext(mp) = 0; /* now 'mp' is free */
+ }
setnilvalue(gval(mp));
}
else { /* colliding node is in its own main position */
/* new node will go into free position */
- gnext(n) = gnext(mp); /* chain new position */
- gnext(mp) = n;
- mp = n;
+ if (gnext(mp) != 0)
+ gnext(f) = (mp + gnext(mp)) - f; /* chain new position */
+ else lua_assert(gnext(f) == 0);
+ gnext(mp) = f - mp;
+ mp = f;
}
}
setobj2t(L, gkey(mp), key);
- luaC_barrierback(L, obj2gco(t), key);
+ luaC_barrierback(L, t, key);
lua_assert(ttisnil(gval(mp)));
return gval(mp);
}
@@ -468,11 +476,15 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
return &t->array[key - 1];
else {
Node *n = hashint(t, key);
- do { /* check whether `key' is somewhere in the chain */
+ for (;;) { /* check whether `key' is somewhere in the chain */
if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key)
return gval(n); /* that's it */
- else n = gnext(n);
- } while (n);
+ else {
+ int nx = gnext(n);
+ if (nx == 0) break;
+ n += nx;
+ }
+ };
return luaO_nilobject;
}
}
@@ -484,11 +496,15 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
const TValue *luaH_getstr (Table *t, TString *key) {
Node *n = hashstr(t, key);
lua_assert(key->tsv.tt == LUA_TSHRSTR);
- do { /* check whether `key' is somewhere in the chain */
+ for (;;) { /* check whether `key' is somewhere in the chain */
if (ttisshrstring(gkey(n)) && eqshrstr(rawtsvalue(gkey(n)), key))
return gval(n); /* that's it */
- else n = gnext(n);
- } while (n);
+ else {
+ int nx = gnext(n);
+ if (nx == 0) break;
+ n += nx;
+ }
+ };
return luaO_nilobject;
}
@@ -509,11 +525,15 @@ const TValue *luaH_get (Table *t, const TValue *key) {
}
default: {
Node *n = mainposition(t, key);
- do { /* check whether `key' is somewhere in the chain */
+ for (;;) { /* check whether `key' is somewhere in the chain */
if (luaV_rawequalobj(gkey(n), key))
return gval(n); /* that's it */
- else n = gnext(n);
- } while (n);
+ else {
+ int nx = gnext(n);
+ if (nx == 0) break;
+ n += nx;
+ }
+ };
return luaO_nilobject;
}
}
diff --git a/src/ltable.h b/src/ltable.h
index 5a65b52e..12366d4b 100644
--- a/src/ltable.h
+++ b/src/ltable.h
@@ -1,5 +1,5 @@
/*
-** $Id: ltable.h,v 2.17 2013/04/26 15:39:25 roberto Exp $
+** $Id: ltable.h,v 2.18 2013/08/30 16:01:37 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -18,6 +18,11 @@
#define invalidateTMcache(t) ((t)->flags = 0)
+/* returns the key, given the value of a table entry */
+#define keyfromval(v) \
+ (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val))))
+
+
LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
TValue *value);
diff --git a/src/ltablib.c b/src/ltablib.c
index ad798b4e..a2801a29 100644
--- a/src/ltablib.c
+++ b/src/ltablib.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltablib.c,v 1.65 2013/03/07 18:17:24 roberto Exp $
+** $Id: ltablib.c,v 1.66 2014/03/21 13:52:33 roberto Exp $
** Library for Table Manipulation
** See Copyright Notice in lua.h
*/
@@ -140,7 +140,7 @@ static int unpack (lua_State *L) {
e = luaL_opt(L, luaL_checkint, 3, luaL_len(L, 1));
if (i > e) return 0; /* empty range */
n = e - i + 1; /* number of elements */
- if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */
+ if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arithmetic overflow */
return luaL_error(L, "too many results to unpack");
lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */
while (i++ < e) /* push arg[i + 1...e] */
diff --git a/src/ltm.c b/src/ltm.c
index 3d1126a1..84ae10d9 100644
--- a/src/ltm.c
+++ b/src/ltm.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.c,v 2.20 2013/05/06 17:19:11 roberto Exp $
+** $Id: ltm.c,v 2.25 2013/12/30 20:47:58 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -28,7 +28,7 @@ LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = {
"no value",
"nil", "boolean", udatatypename, "number",
"string", "table", "function", udatatypename, "thread",
- "proto", "upval" /* these last two cases are used for tests only */
+ "proto" /* this last case is used for tests only */
};
@@ -36,14 +36,16 @@ void luaT_init (lua_State *L) {
static const char *const luaT_eventname[] = { /* ORDER TM */
"__index", "__newindex",
"__gc", "__mode", "__len", "__eq",
- "__add", "__sub", "__mul", "__div", "__idiv", "__mod",
- "__pow", "__unm", "__lt", "__le",
+ "__add", "__sub", "__mul", "__mod", "__pow",
+ "__div", "__idiv",
+ "__band", "__bor", "__bxor", "__shl", "__shr",
+ "__unm", "__bnot", "__lt", "__le",
"__concat", "__call"
};
int i;
for (i=0; i<TM_N; i++) {
G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]);
- luaS_fix(G(L)->tmname[i]); /* never collect these names */
+ luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */
}
}
@@ -110,12 +112,17 @@ int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2,
void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
StkId res, TMS event) {
if (!luaT_callbinTM(L, p1, p2, res, event)) {
- if (event == TM_CONCAT)
- luaG_concaterror(L, p1, p2);
- else if (event == TM_IDIV && ttisnumber(p1) && ttisnumber(p2))
- luaG_tointerror(L, p1, p2);
- else
- luaG_aritherror(L, p1, p2);
+ switch (event) {
+ case TM_CONCAT:
+ luaG_concaterror(L, p1, p2);
+ case TM_IDIV: case TM_BAND: case TM_BOR: case TM_BXOR:
+ case TM_SHL: case TM_SHR: case TM_BNOT:
+ if (ttisnumber(p1) && ttisnumber(p2))
+ luaG_tointerror(L, p1, p2);
+ /* else go through */
+ default:
+ luaG_aritherror(L, p1, p2);
+ }
}
}
diff --git a/src/ltm.h b/src/ltm.h
index 206823ef..a84c798e 100644
--- a/src/ltm.h
+++ b/src/ltm.h
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.h,v 2.16 2013/04/29 16:56:50 roberto Exp $
+** $Id: ltm.h,v 2.19 2013/12/30 20:47:58 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -13,7 +13,7 @@
/*
* WARNING: if you change the order of this enumeration,
-* grep "ORDER TM"
+* grep "ORDER TM" and "ORDER OP"
*/
typedef enum {
TM_INDEX,
@@ -25,11 +25,17 @@ typedef enum {
TM_ADD,
TM_SUB,
TM_MUL,
- TM_DIV,
- TM_IDIV,
TM_MOD,
TM_POW,
+ TM_DIV,
+ TM_IDIV,
+ TM_BAND,
+ TM_BOR,
+ TM_BXOR,
+ TM_SHL,
+ TM_SHR,
TM_UNM,
+ TM_BNOT,
TM_LT,
TM_LE,
TM_CONCAT,
diff --git a/src/lua.c b/src/lua.c
index 6a007129..7a711113 100644
--- a/src/lua.c
+++ b/src/lua.c
@@ -1,5 +1,5 @@
/*
-** $Id: lua.c,v 1.206 2012/09/29 20:07:06 roberto Exp $
+** $Id: lua.c,v 1.210 2014/02/26 15:27:56 roberto Exp $
** Lua stand-alone interpreter
** See Copyright Notice in lua.h
*/
@@ -31,28 +31,38 @@
#define LUA_MAXINPUT 512
#endif
-#if !defined(LUA_INIT)
-#define LUA_INIT "LUA_INIT"
+#if !defined(LUA_INIT_VAR)
+#define LUA_INIT_VAR "LUA_INIT"
#endif
-#define LUA_INITVERSION \
- LUA_INIT "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
+#define LUA_INITVARVERSION \
+ LUA_INIT_VAR "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
/*
** lua_stdin_is_tty detects whether the standard input is a 'tty' (that
** is, whether we're running lua interactively).
*/
-#if defined(LUA_USE_ISATTY)
+#if !defined(lua_stdin_is_tty) /* { */
+
+#if defined(LUA_USE_POSIX) /* { */
+
#include <unistd.h>
#define lua_stdin_is_tty() isatty(0)
-#elif defined(LUA_WIN)
+
+#elif defined(LUA_WIN) /* }{ */
+
#include <io.h>
-#include <stdio.h>
#define lua_stdin_is_tty() _isatty(_fileno(stdin))
-#else
+
+#else /* }{ */
+
+/* ANSI definition */
#define lua_stdin_is_tty() 1 /* assume stdin is a tty */
-#endif
+
+#endif /* } */
+
+#endif /* } */
/*
@@ -61,9 +71,10 @@
** lua_saveline defines how to "save" a read line in a "history".
** lua_freeline defines how to free a line read by lua_readline.
*/
-#if defined(LUA_USE_READLINE)
+#if !defined(lua_readline) /* { */
+
+#if defined(LUA_USE_READLINE) /* { */
-#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL)
@@ -72,7 +83,7 @@
add_history(lua_tostring(L, idx)); /* add it to history */
#define lua_freeline(L,b) ((void)L, free(b))
-#elif !defined(lua_readline)
+#else /* }{ */
#define lua_readline(L,b,p) \
((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \
@@ -80,7 +91,9 @@
#define lua_saveline(L,idx) { (void)L; (void)idx; }
#define lua_freeline(L,b) { (void)L; (void)b; }
-#endif
+#endif /* } */
+
+#endif /* } */
@@ -257,20 +270,21 @@ static int incomplete (lua_State *L, int status) {
}
+/* prompt the user, read a line, and push it into the Lua stack */
static int pushline (lua_State *L, int firstline) {
char buffer[LUA_MAXINPUT];
char *b = buffer;
size_t l;
const char *prmt = get_prompt(L, firstline);
int readstatus = lua_readline(L, b, prmt);
- lua_pop(L, 1); /* remove result from 'get_prompt' */
if (readstatus == 0)
- return 0; /* no input */
+ return 0; /* no input (prompt will be popped by caller) */
+ lua_pop(L, 1); /* remove prompt */
l = strlen(b);
if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
b[l-1] = '\0'; /* remove it */
- if (firstline && b[0] == '=') /* first line starts with `=' ? */
- lua_pushfstring(L, "return %s", b+1); /* change it to `return' */
+ if (firstline && b[0] == '=') /* for compatibility with 5.2, ... */
+ lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */
else
lua_pushstring(L, b);
lua_freeline(L, b);
@@ -278,24 +292,48 @@ static int pushline (lua_State *L, int firstline) {
}
-static int loadline (lua_State *L) {
+/* try to compile line on the stack as 'return <line>'; on return, stack
+ has either compiled chunk or original line (if compilation failed) */
+static int addreturn (lua_State *L) {
int status;
- lua_settop(L, 0);
- if (!pushline(L, 1))
- return -1; /* no input */
+ size_t len; const char *line;
+ lua_pushliteral(L, "return ");
+ lua_pushvalue(L, -2); /* duplicate line */
+ lua_concat(L, 2); /* new line is "return ..." */
+ line = lua_tolstring(L, -1, &len);
+ if ((status = luaL_loadbuffer(L, line, len, "=stdin")) == LUA_OK)
+ lua_remove(L, -3); /* remove original line */
+ else
+ lua_pop(L, 2); /* remove result from 'luaL_loadbuffer' and new line */
+ return status;
+}
+
+
+/* read multiple lines until a complete line */
+static int multiline (lua_State *L) {
for (;;) { /* repeat until gets a complete line */
- size_t l;
- const char *line = lua_tolstring(L, 1, &l);
- status = luaL_loadbuffer(L, line, l, "=stdin");
- if (!incomplete(L, status)) break; /* cannot try to add lines? */
- if (!pushline(L, 0)) /* no more input? */
- return -1;
- lua_pushliteral(L, "\n"); /* add a new line... */
+ size_t len;
+ const char *line = lua_tolstring(L, 1, &len); /* get what it has */
+ int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */
+ if (!incomplete(L, status) || !pushline(L, 0))
+ return status; /* cannot/should not try to add continuation line */
+ lua_pushliteral(L, "\n"); /* add newline... */
lua_insert(L, -2); /* ...between the two lines */
lua_concat(L, 3); /* join them */
}
+}
+
+
+static int loadline (lua_State *L) {
+ int status;
+ lua_settop(L, 0);
+ if (!pushline(L, 1))
+ return -1; /* no input */
+ if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */
+ status = multiline(L); /* try as command, maybe with continuation lines */
lua_saveline(L, 1);
lua_remove(L, 1); /* remove line */
+ lua_assert(lua_gettop(L) == 1);
return status;
}
@@ -421,10 +459,10 @@ static int runargs (lua_State *L, char **argv, int n) {
static int handle_luainit (lua_State *L) {
- const char *name = "=" LUA_INITVERSION;
+ const char *name = "=" LUA_INITVARVERSION;
const char *init = getenv(name + 1);
if (init == NULL) {
- name = "=" LUA_INIT;
+ name = "=" LUA_INIT_VAR;
init = getenv(name + 1); /* try alternative name */
}
if (init == NULL) return LUA_OK;
diff --git a/src/lua.h b/src/lua.h
index 4fef6fee..5d1a1755 100644
--- a/src/lua.h
+++ b/src/lua.h
@@ -1,5 +1,5 @@
/*
-** $Id: lua.h,v 1.292 2013/07/05 14:29:51 roberto Exp $
+** $Id: lua.h,v 1.302 2014/03/20 19:42:35 roberto Exp $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
@@ -19,11 +19,11 @@
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "3"
#define LUA_VERSION_NUM 503
-#define LUA_VERSION_RELEASE "0 (work1)"
+#define LUA_VERSION_RELEASE "0 (work2)"
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
-#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2013 Lua.org, PUC-Rio"
+#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2014 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -182,14 +182,20 @@ LUA_API const void *(lua_topointer) (lua_State *L, int idx);
** Comparison and arithmetic functions
*/
-#define LUA_OPADD 0 /* ORDER TM */
+#define LUA_OPADD 0 /* ORDER TM, ORDER OP */
#define LUA_OPSUB 1
#define LUA_OPMUL 2
-#define LUA_OPDIV 3
-#define LUA_OPIDIV 4
-#define LUA_OPMOD 5
-#define LUA_OPPOW 6
-#define LUA_OPUNM 7
+#define LUA_OPMOD 3
+#define LUA_OPPOW 4
+#define LUA_OPDIV 5
+#define LUA_OPIDIV 6
+#define LUA_OPBAND 7
+#define LUA_OPBOR 8
+#define LUA_OPBXOR 9
+#define LUA_OPSHL 10
+#define LUA_OPSHR 11
+#define LUA_OPUNM 12
+#define LUA_OPBNOT 13
LUA_API void (lua_arith) (lua_State *L, int op);
@@ -222,12 +228,13 @@ LUA_API int (lua_pushthread) (lua_State *L);
/*
** get functions (Lua -> stack)
*/
-LUA_API void (lua_getglobal) (lua_State *L, const char *var);
-LUA_API void (lua_gettable) (lua_State *L, int idx);
-LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k);
-LUA_API void (lua_rawget) (lua_State *L, int idx);
-LUA_API void (lua_rawgeti) (lua_State *L, int idx, lua_Integer n);
-LUA_API void (lua_rawgetp) (lua_State *L, int idx, const void *p);
+LUA_API int (lua_getglobal) (lua_State *L, const char *var);
+LUA_API int (lua_gettable) (lua_State *L, int idx);
+LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k);
+LUA_API int (lua_rawget) (lua_State *L, int idx);
+LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n);
+LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p);
+
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);
@@ -264,7 +271,7 @@ LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
const char *chunkname,
const char *mode);
-LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data);
+LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip);
/*
@@ -288,10 +295,7 @@ LUA_API int (lua_status) (lua_State *L);
#define LUA_GCSTEP 5
#define LUA_GCSETPAUSE 6
#define LUA_GCSETSTEPMUL 7
-#define LUA_GCSETMAJORINC 8
#define LUA_GCISRUNNING 9
-#define LUA_GCGEN 10
-#define LUA_GCINC 11
LUA_API int (lua_gc) (lua_State *L, int what, int data);
@@ -394,7 +398,7 @@ LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n);
LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1,
int fidx2, int n2);
-LUA_API int (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count);
+LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count);
LUA_API lua_Hook (lua_gethook) (lua_State *L);
LUA_API int (lua_gethookmask) (lua_State *L);
LUA_API int (lua_gethookcount) (lua_State *L);
@@ -422,7 +426,7 @@ struct lua_Debug {
/******************************************************************************
-* Copyright (C) 1994-2013 Lua.org, PUC-Rio.
+* Copyright (C) 1994-2014 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
diff --git a/src/luac.c b/src/luac.c
index 43c3d0d6..7a7b230f 100644
--- a/src/luac.c
+++ b/src/luac.c
@@ -202,7 +202,7 @@ int main(int argc, char* argv[])
return EXIT_SUCCESS;
}
-#define nvalue(x) 0
+#define nvalue(x) ((lua_Number)0)
#define ttypenv(x) ttnov(x)
/*
** $Id: print.c,v 1.69 2013/07/04 01:03:46 lhf Exp $
diff --git a/src/luaconf.h b/src/luaconf.h
index 71d02561..3d6390a2 100644
--- a/src/luaconf.h
+++ b/src/luaconf.h
@@ -1,5 +1,5 @@
/*
-** $Id: luaconf.h,v 1.185 2013/06/25 19:04:40 roberto Exp $
+** $Id: luaconf.h,v 1.193 2014/03/21 14:27:16 roberto Exp $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
@@ -20,6 +20,24 @@
/*
+** ===================================================================
+@@ LUA_INT_INT / LUA_INT_LONG / LUA_INT_LONGLONG defines size for
+@* Lua integers;
+@@ LUA_REAL_FLOAT / LUA_REAL_DOUBLE / LUA_REAL_LONGDOUBLE defines size for
+@* Lua floats.
+**
+** These definitions set the numeric types for Lua. Lua should work
+** fine with 32-bit or 64-bit integers mixed with 32-bit or 64-bit
+** floats. The usual configurations are 64-bit integers and floats (the
+** default) and 32-bit integers and floats (Small Lua, for restricted
+** hardware).
+** =====================================================================
+*/
+#define LUA_INT_LONGLONG
+#define LUA_REAL_DOUBLE
+
+
+/*
@@ LUA_ANSI controls the use of non-ansi features.
** CHANGE it (define it) if you want Lua to avoid the use of any
** non-ansi feature or library.
@@ -41,24 +59,28 @@
#if defined(LUA_USE_LINUX)
+#define LUA_USE_C99
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
#define LUA_USE_READLINE /* needs some extra libraries */
-#define LUA_USE_STRTODHEX /* assume 'strtod' handles hex formats */
-#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */
-#define LUA_USE_LONGLONG /* assume support for long long */
#endif
#if defined(LUA_USE_MACOSX)
+#define LUA_USE_C99
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN /* does not need -ldl */
#define LUA_USE_READLINE /* needs an extra library: -lreadline */
-#define LUA_USE_STRTODHEX /* assume 'strtod' handles hex formats */
-#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */
-#define LUA_USE_LONGLONG /* assume support for long long */
#endif
+/*
+@@ LUA_USE_C99 includes all functionality from C 99.
+** CHANGE it (define it) if your system is compatible.
+*/
+#if defined(LUA_USE_C99)
+#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */
+#endif
+
/*
@@ LUA_USE_POSIX includes all functionality listed as X/Open System
@@ -66,11 +88,6 @@
** CHANGE it (define it) if your system is XSI compatible.
*/
#if defined(LUA_USE_POSIX)
-#define LUA_USE_MKSTEMP
-#define LUA_USE_ISATTY
-#define LUA_USE_POPEN
-#define LUA_USE_ULONGJMP
-#define LUA_USE_GMTIME_R
#endif
@@ -93,7 +110,8 @@
#define LUA_CDIR "!\\"
#define LUA_PATH_DEFAULT \
LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
- LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" ".\\?.lua"
+ LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \
+ ".\\?.lua;" ".\\?\\init.lua"
#define LUA_CPATH_DEFAULT \
LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll;" ".\\?.dll"
@@ -105,7 +123,8 @@
#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR
#define LUA_PATH_DEFAULT \
LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
- LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" "./?.lua"
+ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \
+ "./?.lua;" "./?/init.lua"
#define LUA_CPATH_DEFAULT \
LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so"
#endif /* } */
@@ -247,6 +266,11 @@
#if defined(LUA_COMPAT_ALL) /* { */
/*
+@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'.
+*/
+#define LUA_COMPAT_BITLIB
+
+/*
@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'.
** You can replace it with 'table.unpack'.
*/
@@ -350,7 +374,7 @@
/*
@@ LUAI_MAXSTACK limits the size of the Lua stack.
** CHANGE it if you need a different limit. This limit is arbitrary;
-** its only purpose is to stop Lua to consume unlimited stack
+** its only purpose is to stop Lua from consuming unlimited stack
** space (and to reserve some numbers for pseudo-indices).
*/
#if LUAI_BITSINT >= 32
@@ -372,27 +396,15 @@
#define LUAL_BUFFERSIZE BUFSIZ
-
-
/*
** {==================================================================
-** The following definitions set the numeric types for Lua.
-** Lua should work fine with 32-bit or 64-bit integers mixed with
-** 32-bit or 64-bit floats. The usual configurations are 64-bit
-** integers and floats (the default) and 32-bit integers and floats.
+** Configuration for Numbers.
+** Change these definitions if no predefined LUA_REAL_* / LUA_INT_*
+** satisfy your needs.
** ===================================================================
*/
/*
-@@ LUA_INTSIZE defines size for Lua integer: 1=int, 2=long, 3=long long
-@@ LUA_FLOATSIZE defines size for Lua float: 1=float, 2=double, 3=long double
-** Default is long long + double
-*/
-#define LUA_INTSIZE 3
-#define LUA_FLOATSIZE 2
-
-
-/*
@@ LUA_NUMBER is the floating-point type used by Lua.
**
@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
@@ -401,14 +413,14 @@
@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
@@ LUA_NUMBER_SCAN is the format for reading floats.
@@ LUA_NUMBER_FMT is the format for writing floats.
-@@ lua_number2str converts a floats to a string.
+@@ lua_number2str converts a float to a string.
**
@@ l_mathop allows the addition of an 'l' or 'f' to all math operations
**
@@ lua_str2number converts a decimal numeric string to a number.
*/
-#if LUA_FLOATSIZE == 1 /* { single float */
+#if defined(LUA_REAL_FLOAT) /* { single float */
#define LUA_NUMBER float
@@ -423,7 +435,7 @@
#define lua_str2number(s,p) strtof((s), (p))
-#elif LUA_FLOATSIZE == 3 /* }{ long double */
+#elif defined(LUA_REAL_LONGDOUBLE) /* }{ long double */
#define LUA_NUMBER long double
@@ -437,7 +449,7 @@
#define lua_str2number(s,p) strtold((s), (p))
-#else /* }{ default: double */
+#elif defined(LUA_REAL_DOUBLE) /* }{ double */
#define LUA_NUMBER double
@@ -451,7 +463,11 @@
#define lua_str2number(s,p) strtod((s), (p))
-#endif /* } */
+#else /* }{ */
+
+#error "numeric real type not defined"
+
+#endif /* } */
#if defined(LUA_ANSI)
@@ -481,8 +497,8 @@
/* the following operations need the math library */
#if defined(lobject_c) || defined(lvm_c)
#include <math.h>
-#define luai_nummod(L,a,b) ((a) - l_floor((a)/(b))*(b))
-#define luai_numpow(L,a,b) (l_mathop(pow)(a,b))
+#define luai_nummod(L,a,b) ((void)L, (a) - l_floor((a)/(b))*(b))
+#define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b))
#endif
/* these are quite standard operations */
@@ -493,12 +509,19 @@
#define luai_numdiv(L,a,b) ((a)/(b))
#define luai_numunm(L,a) (-(a))
#define luai_numeq(a,b) ((a)==(b))
-#define luai_numlt(L,a,b) ((a)<(b))
-#define luai_numle(L,a,b) ((a)<=(b))
-#define luai_numisnan(L,a) (!luai_numeq((a), (a)))
+#define luai_numlt(a,b) ((a)<(b))
+#define luai_numle(a,b) ((a)<=(b))
+#define luai_numisnan(a) (!luai_numeq((a), (a)))
#endif
+/*
+** The following macro checks whether an operation is not safe to be
+** performed by the constant folder. It should result in zero only if
+** the operation is safe.
+*/
+#define luai_numinvalidop(op,a,b) 0
+
/*
@@ LUA_INTEGER is the integer type used by Lua.
@@ -511,22 +534,31 @@
@@ lua_integer2str converts an integer to a string.
*/
-#if LUA_INTSIZE == 1 /* { int */
+#if defined(LUA_INT_INT) /* { int */
#define LUA_INTEGER int
#define LUA_INTEGER_FRMLEN ""
-#elif LUA_INTSIZE == 2 /* }{ long */
+#elif defined(LUA_INT_LONG) /* }{ long */
#define LUA_INTEGER long
#define LUA_INTEGER_FRMLEN "l"
-#else /* }{ default: long long */
+#elif defined(LUA_INT_LONGLONG) /* }{ long long */
+#if defined(_WIN32)
+#define LUA_INTEGER __int64
+#define LUA_INTEGER_FRMLEN "I64"
+#else
#define LUA_INTEGER long long
#define LUA_INTEGER_FRMLEN "ll"
+#endif
-#endif /* } */
+#else /* }{ */
+
+#error "numeric integer type not defined"
+
+#endif /* } */
#define LUA_INTEGER_SCAN "%" LUA_INTEGER_FRMLEN "d"
diff --git a/src/lualib.h b/src/lualib.h
index 9fd126bf..5165c0fb 100644
--- a/src/lualib.h
+++ b/src/lualib.h
@@ -1,5 +1,5 @@
/*
-** $Id: lualib.h,v 1.43 2011/12/08 12:11:37 roberto Exp $
+** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $
** Lua standard libraries
** See Copyright Notice in lua.h
*/
@@ -29,6 +29,9 @@ LUAMOD_API int (luaopen_os) (lua_State *L);
#define LUA_STRLIBNAME "string"
LUAMOD_API int (luaopen_string) (lua_State *L);
+#define LUA_UTF8LIBNAME "utf8"
+LUAMOD_API int (luaopen_utf8) (lua_State *L);
+
#define LUA_BITLIBNAME "bit32"
LUAMOD_API int (luaopen_bit32) (lua_State *L);
diff --git a/src/lundump.c b/src/lundump.c
index 38b04e42..72467e0f 100644
--- a/src/lundump.c
+++ b/src/lundump.c
@@ -1,5 +1,5 @@
/*
-** $Id: lundump.c,v 2.23 2013/04/26 18:48:35 roberto Exp $
+** $Id: lundump.c,v 2.34 2014/03/11 18:56:27 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -20,249 +20,247 @@
#include "lundump.h"
#include "lzio.h"
+
+#if !defined(luai_verifycode)
+#define luai_verifycode(L,b,f) /* empty */
+#endif
+
+
typedef struct {
- lua_State* L;
- ZIO* Z;
- Mbuffer* b;
- const char* name;
+ lua_State *L;
+ ZIO *Z;
+ Mbuffer *b;
+ const char *name;
} LoadState;
-static l_noret error(LoadState* S, const char* why)
-{
- luaO_pushfstring(S->L,"%s: %s precompiled chunk",S->name,why);
- luaD_throw(S->L,LUA_ERRSYNTAX);
+
+static l_noret error(LoadState *S, const char *why) {
+ luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why);
+ luaD_throw(S->L, LUA_ERRSYNTAX);
}
-#define LoadMem(S,b,n,size) LoadBlock(S,b,(n)*(size))
-#define LoadByte(S) (lu_byte)LoadChar(S)
-#define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x))
-#define LoadVector(S,b,n,size) LoadMem(S,b,n,size)
-#if !defined(luai_verifycode)
-#define luai_verifycode(L,b,f) /* empty */
-#endif
+/*
+** All high-level loads go through LoadVector; you can change it to
+** adapt to the endianess of the input
+*/
+#define LoadVector(S,b,n) LoadBlock(S,b,(n)*sizeof((b)[0]))
-static void LoadBlock(LoadState* S, void* b, size_t size)
-{
- if (luaZ_read(S->Z,b,size)!=0) error(S,"truncated");
+static void LoadBlock (LoadState *S, void *b, size_t size) {
+ if (luaZ_read(S->Z, b, size) != 0)
+ error(S, "truncated");
}
-static int LoadChar(LoadState* S)
-{
- char x;
- LoadVar(S,x);
- return x;
+
+#define LoadVar(S,x) LoadVector(S,&x,1)
+
+
+static lu_byte LoadByte (LoadState *S) {
+ lu_byte x;
+ LoadVar(S, x);
+ return x;
}
-static int LoadInt(LoadState* S)
-{
- int x;
- LoadVar(S,x);
- if (x<0) error(S,"corrupted");
- return x;
+
+static int LoadInt (LoadState *S) {
+ int x;
+ LoadVar(S, x);
+ return x;
}
-static lua_Number LoadNumber(LoadState* S)
-{
- lua_Number x;
- LoadVar(S,x);
- return x;
+
+static lua_Number LoadNumber (LoadState *S) {
+ lua_Number x;
+ LoadVar(S, x);
+ return x;
}
-static lua_Integer LoadInteger(LoadState* S)
-{
- lua_Integer x;
- LoadVar(S,x);
- return x;
+
+static lua_Integer LoadInteger (LoadState *S) {
+ lua_Integer x;
+ LoadVar(S, x);
+ return x;
}
-static TString* LoadString(LoadState* S)
-{
- size_t size;
- LoadVar(S,size);
- if (size==0)
- return NULL;
- else
- {
- char* s=luaZ_openspace(S->L,S->b,size);
- LoadBlock(S,s,size*sizeof(char));
- return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */
- }
+
+static TString *LoadString (LoadState *S) {
+ size_t size = LoadByte(S);
+ if (size == 0xFF)
+ LoadVar(S, size);
+ if (size == 0)
+ return NULL;
+ else {
+ char *s = luaZ_openspace(S->L, S->b, --size);
+ LoadVector(S, s, size);
+ return luaS_newlstr(S->L, s, size);
+ }
}
-static void LoadCode(LoadState* S, Proto* f)
-{
- int n=LoadInt(S);
- f->code=luaM_newvector(S->L,n,Instruction);
- f->sizecode=n;
- LoadVector(S,f->code,n,sizeof(Instruction));
+
+static void LoadCode (LoadState *S, Proto *f) {
+ int n = LoadInt(S);
+ f->code = luaM_newvector(S->L, n, Instruction);
+ f->sizecode = n;
+ LoadVector(S, f->code, n);
}
-static void LoadFunction(LoadState* S, Proto* f);
-
-static void LoadConstants(LoadState* S, Proto* f)
-{
- int i,n;
- n=LoadInt(S);
- f->k=luaM_newvector(S->L,n,TValue);
- f->sizek=n;
- for (i=0; i<n; i++) setnilvalue(&f->k[i]);
- for (i=0; i<n; i++)
- {
- TValue* o=&f->k[i];
- int t=LoadChar(S);
- switch (t)
- {
- case LUA_TNIL:
- setnilvalue(o);
- break;
- case LUA_TBOOLEAN:
- setbvalue(o,LoadChar(S));
- break;
- case LUA_TNUMFLT:
- setnvalue(o,LoadNumber(S));
- break;
- case LUA_TNUMINT:
- setivalue(o,LoadInteger(S));
- break;
- case LUA_TSHRSTR: case LUA_TLNGSTR:
- setsvalue2n(S->L,o,LoadString(S));
- break;
- default: lua_assert(0);
+
+static void LoadFunction(LoadState *S, Proto *f);
+
+
+static void LoadConstants (LoadState *S, Proto *f) {
+ int i, n;
+ n = LoadInt(S);
+ f->k = luaM_newvector(S->L, n, TValue);
+ f->sizek = n;
+ for (i = 0; i < n; i++)
+ setnilvalue(&f->k[i]);
+ for (i = 0; i < n; i++) {
+ TValue *o = &f->k[i];
+ int t = LoadByte(S);
+ switch (t) {
+ case LUA_TNIL:
+ setnilvalue(o);
+ break;
+ case LUA_TBOOLEAN:
+ setbvalue(o, LoadByte(S));
+ break;
+ case LUA_TNUMFLT:
+ setnvalue(o, LoadNumber(S));
+ break;
+ case LUA_TNUMINT:
+ setivalue(o, LoadInteger(S));
+ break;
+ case LUA_TSHRSTR:
+ case LUA_TLNGSTR:
+ setsvalue2n(S->L, o, LoadString(S));
+ break;
+ default:
+ lua_assert(0);
+ }
+ }
+ n = LoadInt(S);
+ f->p = luaM_newvector(S->L, n, Proto *);
+ f->sizep = n;
+ for (i = 0; i < n; i++)
+ f->p[i] = NULL;
+ for (i = 0; i < n; i++) {
+ f->p[i] = luaF_newproto(S->L);
+ LoadFunction(S, f->p[i]);
}
- }
- n=LoadInt(S);
- f->p=luaM_newvector(S->L,n,Proto*);
- f->sizep=n;
- for (i=0; i<n; i++) f->p[i]=NULL;
- for (i=0; i<n; i++)
- {
- f->p[i]=luaF_newproto(S->L);
- LoadFunction(S,f->p[i]);
- }
}
-static void LoadUpvalues(LoadState* S, Proto* f)
-{
- int i,n;
- n=LoadInt(S);
- f->upvalues=luaM_newvector(S->L,n,Upvaldesc);
- f->sizeupvalues=n;
- for (i=0; i<n; i++) f->upvalues[i].name=NULL;
- for (i=0; i<n; i++)
- {
- f->upvalues[i].instack=LoadByte(S);
- f->upvalues[i].idx=LoadByte(S);
- }
+
+static void LoadUpvalues (LoadState *S, Proto *f) {
+ int i, n;
+ n = LoadInt(S);
+ f->upvalues = luaM_newvector(S->L, n, Upvaldesc);
+ f->sizeupvalues = n;
+ for (i = 0; i < n; i++)
+ f->upvalues[i].name = NULL;
+ for (i = 0; i < n; i++) {
+ f->upvalues[i].instack = LoadByte(S);
+ f->upvalues[i].idx = LoadByte(S);
+ }
}
-static void LoadDebug(LoadState* S, Proto* f)
-{
- int i,n;
- f->source=LoadString(S);
- n=LoadInt(S);
- f->lineinfo=luaM_newvector(S->L,n,int);
- f->sizelineinfo=n;
- LoadVector(S,f->lineinfo,n,sizeof(int));
- n=LoadInt(S);
- f->locvars=luaM_newvector(S->L,n,LocVar);
- f->sizelocvars=n;
- for (i=0; i<n; i++) f->locvars[i].varname=NULL;
- for (i=0; i<n; i++)
- {
- f->locvars[i].varname=LoadString(S);
- f->locvars[i].startpc=LoadInt(S);
- f->locvars[i].endpc=LoadInt(S);
- }
- n=LoadInt(S);
- for (i=0; i<n; i++) f->upvalues[i].name=LoadString(S);
+
+static void LoadDebug (LoadState *S, Proto *f) {
+ int i, n;
+ f->source = LoadString(S);
+ n = LoadInt(S);
+ f->lineinfo = luaM_newvector(S->L, n, int);
+ f->sizelineinfo = n;
+ LoadVector(S, f->lineinfo, n);
+ n = LoadInt(S);
+ f->locvars = luaM_newvector(S->L, n, LocVar);
+ f->sizelocvars = n;
+ for (i = 0; i < n; i++)
+ f->locvars[i].varname = NULL;
+ for (i = 0; i < n; i++) {
+ f->locvars[i].varname = LoadString(S);
+ f->locvars[i].startpc = LoadInt(S);
+ f->locvars[i].endpc = LoadInt(S);
+ }
+ n = LoadInt(S);
+ for (i = 0; i < n; i++)
+ f->upvalues[i].name = LoadString(S);
}
-static void LoadFunction(LoadState* S, Proto* f)
-{
- f->linedefined=LoadInt(S);
- f->lastlinedefined=LoadInt(S);
- f->numparams=LoadByte(S);
- f->is_vararg=LoadByte(S);
- f->maxstacksize=LoadByte(S);
- LoadCode(S,f);
- LoadConstants(S,f);
- LoadUpvalues(S,f);
- LoadDebug(S,f);
+
+static void LoadFunction (LoadState *S, Proto *f) {
+ f->linedefined = LoadInt(S);
+ f->lastlinedefined = LoadInt(S);
+ f->numparams = LoadByte(S);
+ f->is_vararg = LoadByte(S);
+ f->maxstacksize = LoadByte(S);
+ LoadCode(S, f);
+ LoadConstants(S, f);
+ LoadUpvalues(S, f);
+ LoadDebug(S, f);
}
-/* the code below must be consistent with the code in luaU_header */
-#define N0 LUAC_HEADERSIZE
-#define N1 (sizeof(LUA_SIGNATURE)-sizeof(char))
-#define N2 N1+2
-#define N3 N2+6
-
-static void LoadHeader(LoadState* S)
-{
- lu_byte h[LUAC_HEADERSIZE];
- lu_byte s[LUAC_HEADERSIZE];
- luaU_header(h);
- memcpy(s,h,sizeof(char)); /* first char already read */
- LoadBlock(S,s+sizeof(char),LUAC_HEADERSIZE-sizeof(char));
- if (memcmp(h,s,N0)==0) return;
- if (memcmp(h,s,N1)!=0) error(S,"not a");
- if (memcmp(h,s,N2)!=0) error(S,"version mismatch in");
- if (memcmp(h,s,N3)!=0) error(S,"incompatible"); else error(S,"corrupted");
+
+static void checkliteral (LoadState *S, const char *s, const char *msg) {
+ char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
+ int len = strlen(s);
+ LoadVector(S, buff, len);
+ if (memcmp(s, buff, len) != 0)
+ error(S, msg);
}
-/*
-** load precompiled chunk
-*/
-Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name)
-{
- LoadState S;
- Closure* cl;
- if (*name=='@' || *name=='=')
- S.name=name+1;
- else if (*name==LUA_SIGNATURE[0])
- S.name="binary string";
- else
- S.name=name;
- S.L=L;
- S.Z=Z;
- S.b=buff;
- LoadHeader(&S);
- cl=luaF_newLclosure(L,1);
- setclLvalue(L,L->top,cl); incr_top(L);
- cl->l.p=luaF_newproto(L);
- LoadFunction(&S,cl->l.p);
- if (cl->l.p->sizeupvalues != 1)
- {
- Proto* p=cl->l.p;
- cl=luaF_newLclosure(L,cl->l.p->sizeupvalues);
- cl->l.p=p;
- setclLvalue(L,L->top-1,cl);
- }
- luai_verifycode(L,buff,cl->l.p);
- return cl;
+
+static void fchecksize (LoadState *S, size_t size, const char *tname) {
+ if (LoadByte(S) != size)
+ error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname));
+}
+
+
+#define checksize(S,t) fchecksize(S,sizeof(t),#t)
+
+static void checkHeader (LoadState *S) {
+ checkliteral(S, LUA_SIGNATURE + 1, "not a"); /* 1st char already checked */
+ if (LoadByte(S) != LUAC_VERSION)
+ error(S, "version mismatch in");
+ if (LoadByte(S) != LUAC_FORMAT)
+ error(S, "format mismatch in");
+ checkliteral(S, LUAC_DATA, "corrupted");
+ checksize(S, int);
+ checksize(S, size_t);
+ checksize(S, Instruction);
+ checksize(S, lua_Integer);
+ checksize(S, lua_Number);
+ if (LoadInteger(S) != LUAC_INT)
+ error(S, "endianess mismatch in");
+ if (LoadNumber(S) != LUAC_NUM)
+ error(S, "float format mismatch in");
}
-#define MYINT(s) (s[0]-'0')
-#define VERSION MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)
-#define FORMAT 0 /* this is the official format */
/*
-* make header for precompiled chunks
-* if you change the code below be sure to update LoadHeader and FORMAT above
-* and LUAC_HEADERSIZE in lundump.h
+** load precompiled chunk
*/
-void luaU_header (lu_byte* h)
-{
- int x=1;
- memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-sizeof(char));
- h+=sizeof(LUA_SIGNATURE)-sizeof(char);
- *h++=cast_byte(VERSION);
- *h++=cast_byte(FORMAT);
- *h++=cast_byte(*(char*)&x); /* endianness */
- *h++=cast_byte(sizeof(int));
- *h++=cast_byte(sizeof(size_t));
- *h++=cast_byte(sizeof(Instruction));
- *h++=cast_byte(sizeof(lua_Number));
- *h++=cast_byte(((lua_Number)0.5)==0); /* is lua_Number integral? */
- memcpy(h,LUAC_TAIL,sizeof(LUAC_TAIL)-sizeof(char));
+Closure *luaU_undump(lua_State *L, ZIO *Z, Mbuffer *buff,
+ const char *name) {
+ LoadState S;
+ Closure *cl;
+ if (*name == '@' || *name == '=')
+ S.name = name + 1;
+ else if (*name == LUA_SIGNATURE[0])
+ S.name = "binary string";
+ else
+ S.name = name;
+ S.L = L;
+ S.Z = Z;
+ S.b = buff;
+ checkHeader(&S);
+ cl = luaF_newLclosure(L, LoadByte(&S));
+ setclLvalue(L, L->top, cl);
+ incr_top(L);
+ cl->l.p = luaF_newproto(L);
+ LoadFunction(&S, cl->l.p);
+ lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues);
+ luai_verifycode(L, buff, cl->l.p);
+ return cl;
}
+
diff --git a/src/lundump.h b/src/lundump.h
index 2b8accec..8f64ca40 100644
--- a/src/lundump.h
+++ b/src/lundump.h
@@ -1,5 +1,5 @@
/*
-** $Id: lundump.h,v 1.39 2012/05/08 13:53:33 roberto Exp $
+** $Id: lundump.h,v 1.42 2014/03/11 14:22:54 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -7,22 +7,27 @@
#ifndef lundump_h
#define lundump_h
+#include "llimits.h"
#include "lobject.h"
#include "lzio.h"
-/* load one chunk; from lundump.c */
-LUAI_FUNC Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name);
-/* make header; from lundump.c */
-LUAI_FUNC void luaU_header (lu_byte* h);
+/* data to catch conversion errors */
+#define LUAC_DATA "\x19\x93\r\n\x1a\n"
-/* dump one chunk; from ldump.c */
-LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip);
+#define LUAC_INT cast_integer(0xABCD)
+#define LUAC_NUM cast_num(370.5)
-/* data to catch conversion errors */
-#define LUAC_TAIL "\x19\x93\r\n\x1a\n"
+#define MYINT(s) (s[0]-'0')
+#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR))
+#define LUAC_FORMAT 0 /* this is the official format */
-/* size in bytes of header of binary files */
-#define LUAC_HEADERSIZE (sizeof(LUA_SIGNATURE)-sizeof(char)+2+6+sizeof(LUAC_TAIL)-sizeof(char))
+/* load one chunk; from lundump.c */
+LUAI_FUNC Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff,
+ const char* name);
+
+/* dump one chunk; from ldump.c */
+LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
+ void* data, int strip);
#endif
diff --git a/src/lutf8lib.c b/src/lutf8lib.c
new file mode 100644
index 00000000..d78a6752
--- /dev/null
+++ b/src/lutf8lib.c
@@ -0,0 +1,240 @@
+/*
+** $Id: lutf8lib.c,v 1.4 2014/03/20 19:36:02 roberto Exp $
+** Standard library for UTF-8 manipulation
+** See Copyright Notice in lua.h
+*/
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define lutf8lib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+#define MAXUNICODE 0x10FFFF
+
+#define iscont(p) ((*(p) & 0xC0) == 0x80)
+
+
+/* from strlib */
+/* translate a relative string position: negative means back from end */
+static lua_Integer u_posrelat (lua_Integer pos, size_t len) {
+ if (pos >= 0) return pos;
+ else if (0u - (size_t)pos > len) return 0;
+ else return (lua_Integer)len + pos + 1;
+}
+
+
+/*
+** Decode an UTF-8 sequence, returning NULL if byte sequence is invalid.
+*/
+static const char *utf8_decode (const char *o, int *val) {
+ static unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF};
+ const unsigned char *s = (const unsigned char *)o;
+ unsigned int c = s[0];
+ unsigned int res = 0; /* final result */
+ if (c < 0x80) /* ascii? */
+ res = c;
+ else {
+ int count = 0; /* to count number of continuation bytes */
+ while (c & 0x40) { /* still have continuation bytes? */
+ int cc = s[++count]; /* read next byte */
+ if ((cc & 0xC0) != 0x80) /* not a continuation byte? */
+ return NULL; /* invalid byte sequence */
+ res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
+ c <<= 1; /* to test next bit */
+ }
+ res |= ((c & 0x7F) << (count * 5)); /* add first byte */
+ if (count > 3 || res > MAXUNICODE || res <= limits[count])
+ return NULL; /* invalid byte sequence */
+ s += count; /* skip continuation bytes read */
+ }
+ if (val) *val = res;
+ return (const char *)s + 1; /* +1 to include first byte */
+}
+
+
+/*
+** utf8len(s, [i]) --> number of codepoints in 's' after 'i';
+** nil if 's' not well formed
+*/
+static int utflen (lua_State *L) {
+ int n = 0;
+ const char *ends;
+ size_t len;
+ const char *s = luaL_checklstring(L, 1, &len);
+ lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), 1);
+ luaL_argcheck(L, 1 <= posi && posi <= (lua_Integer)len, 1,
+ "initial position out of string");
+ ends = s + len;
+ s += posi - 1;
+ while (s < ends && (s = utf8_decode(s, NULL)) != NULL)
+ n++;
+ if (s == ends)
+ lua_pushinteger(L, n);
+ else
+ lua_pushnil(L);
+ return 1;
+}
+
+
+/*
+** codepoint(s, [i, [j]]) -> returns codepoints for all characters
+** between i and j
+*/
+static int codepoint (lua_State *L) {
+ size_t len;
+ const char *s = luaL_checklstring(L, 1, &len);
+ lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len);
+ lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len);
+ int n;
+ const char *se;
+ luaL_argcheck(L, posi >= 1, 2, "out of range");
+ luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range");
+ if (posi > pose) return 0; /* empty interval; return no values */
+ n = (int)(pose - posi + 1);
+ if (posi + n <= pose) /* (lua_Integer -> int) overflow? */
+ return luaL_error(L, "string slice too long");
+ luaL_checkstack(L, n, "string slice too long");
+ n = 0;
+ se = s + pose;
+ for (s += posi - 1; s < se;) {
+ int code;
+ s = utf8_decode(s, &code);
+ if (s == NULL)
+ return luaL_error(L, "invalid UTF-8 code");
+ lua_pushinteger(L, code);
+ n++;
+ }
+ return n;
+}
+
+
+static void pushutfchar (lua_State *L, int arg) {
+ int code = luaL_checkint(L, arg);
+ luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range");
+ lua_pushfstring(L, "%U", code);
+}
+
+
+/*
+** utfchar(n1, n2, ...) -> char(n1)..char(n2)...
+*/
+static int utfchar (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ if (n == 1) /* optimize common case of single char */
+ pushutfchar(L, 1);
+ else {
+ int i;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ for (i = 1; i <= n; i++) {
+ pushutfchar(L, i);
+ luaL_addvalue(&b);
+ }
+ luaL_pushresult(&b);
+ }
+ return 1;
+}
+
+
+/*
+** offset(s, n, [i]) -> index where n-th character *after*
+** position 'i' starts; 0 means character at 'i'.
+*/
+static int byteoffset (lua_State *L) {
+ size_t len;
+ const char *s = luaL_checklstring(L, 1, &len);
+ int n = luaL_checkint(L, 2);
+ lua_Integer posi = u_posrelat(luaL_optinteger(L, 3, 1), len) - 1;
+ luaL_argcheck(L, 0 <= posi && posi <= (lua_Integer)len, 3,
+ "position out of range");
+ if (n == 0) {
+ /* find beginning of current byte sequence */
+ while (posi > 0 && iscont(s + posi)) posi--;
+ }
+ else if (n < 0) {
+ while (n < 0 && posi > 0) { /* move back */
+ do { /* find beginning of previous character */
+ posi--;
+ } while (posi > 0 && iscont(s + posi));
+ n++;
+ }
+ }
+ else {
+ n--; /* do not move for 1st character */
+ while (n > 0 && posi < (lua_Integer)len) {
+ do { /* find beginning of next character */
+ posi++;
+ } while (iscont(s + posi)); /* ('\0' is not continuation) */
+ n--;
+ }
+ }
+ if (n == 0)
+ lua_pushinteger(L, posi + 1);
+ else
+ lua_pushnil(L); /* no such position */
+ return 1;
+}
+
+
+static int iter_aux (lua_State *L) {
+ size_t len;
+ const char *s = luaL_checklstring(L, 1, &len);
+ int n = lua_tointeger(L, 2) - 1;
+ if (n < 0) /* first iteration? */
+ n = 0; /* start from here */
+ else if (n < (lua_Integer)len) {
+ n++; /* skip current byte */
+ while (iscont(s + n)) n++; /* and its continuations */
+ }
+ if (n >= (lua_Integer)len)
+ return 0; /* no more codepoints */
+ else {
+ int code;
+ const char *next = utf8_decode(s + n, &code);
+ if (next == NULL || iscont(next))
+ return luaL_error(L, "invalid UTF-8 code");
+ lua_pushinteger(L, n + 1);
+ lua_pushinteger(L, code);
+ return 2;
+ }
+}
+
+
+static int iter_codes (lua_State *L) {
+ luaL_checkstring(L, 1);
+ lua_pushcfunction(L, iter_aux);
+ lua_pushvalue(L, 1);
+ lua_pushinteger(L, 0);
+ return 3;
+}
+
+
+/* pattern to match a single UTF-8 character */
+#define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*"
+
+
+static struct luaL_Reg funcs[] = {
+ {"offset", byteoffset},
+ {"codepoint", codepoint},
+ {"char", utfchar},
+ {"len", utflen},
+ {"codes", iter_codes},
+ {NULL, NULL}
+};
+
+
+int luaopen_utf8 (lua_State *L) {
+ luaL_newlib(L, funcs);
+ lua_pushliteral(L, UTF8PATT);
+ lua_setfield(L, -2, "charpatt");
+ return 1;
+}
+
diff --git a/src/lvm.c b/src/lvm.c
index 0a41482c..a99e26b6 100644
--- a/src/lvm.c
+++ b/src/lvm.c
@@ -1,10 +1,11 @@
/*
-** $Id: lvm.c,v 2.175 2013/06/20 15:02:49 roberto Exp $
+** $Id: lvm.c,v 2.190 2014/03/15 12:29:48 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -29,7 +30,7 @@
/* limit for table tag-method chains (to avoid loops) */
-#define MAXTAGLOOP 100
+#define MAXTAGLOOP 2000
/* maximum length of the conversion of a number to a string */
@@ -52,17 +53,9 @@ int luaV_tostring (lua_State *L, StkId obj) {
return 0;
else {
char buff[MAXNUMBER2STR];
- size_t len;
- if (ttisinteger(obj))
- len = lua_integer2str(buff, ivalue(obj));
- else {
- len = lua_number2str(buff, fltvalue(obj));
- if (strspn(buff, "-0123456789") == len) { /* look like an integer? */
- buff[len++] = '.'; /* add a '.0' */
- buff[len++] = '0';
- buff[len] = '\0';
- }
- }
+ size_t len = (ttisinteger(obj))
+ ? lua_integer2str(buff, ivalue(obj))
+ : lua_number2str(buff, fltvalue(obj));
setsvalue2s(L, obj, luaS_newlstr(L, buff, len));
return 1;
}
@@ -73,7 +66,7 @@ int luaV_tostring (lua_State *L, StkId obj) {
** Check whether a float number is within the range of a lua_Integer.
** (The comparisons are tricky because of rounding, which can or
** not occur depending on the relative sizes of floats and integers.)
-** This function is called only when 'n' has an integer value.
+** This function should be called only when 'n' has an integral value.
*/
int luaV_numtointeger (lua_Number n, lua_Integer *p) {
if (cast_num(MIN_INTEGER) <= n && n < (MAX_INTEGER + cast_num(1))) {
@@ -121,7 +114,7 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
}
t = tm; /* else repeat with 'tm' */
}
- luaG_runerror(L, "loop in gettable");
+ luaG_runerror(L, "gettable chain too long; possible loop");
}
@@ -145,7 +138,7 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
/* no metamethod and (now) there is an entry with given key */
setobj2t(L, oldval, val); /* assign new value to that entry */
invalidateTMcache(h);
- luaC_barrierback(L, obj2gco(h), val);
+ luaC_barrierback(L, h, val);
return;
}
/* else will try the metamethod */
@@ -160,7 +153,7 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
}
t = tm; /* else repeat with 'tm' */
}
- luaG_runerror(L, "loop in settable");
+ luaG_runerror(L, "settable chain too long; possible loop");
}
@@ -192,7 +185,7 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
if (ttisinteger(l) && ttisinteger(r))
return (ivalue(l) < ivalue(r));
else if (tonumber(l, &nl) && tonumber(r, &nr))
- return luai_numlt(L, nl, nr);
+ return luai_numlt(nl, nr);
else if (ttisstring(l) && ttisstring(r))
return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0;
else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0)
@@ -207,7 +200,7 @@ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
if (ttisinteger(l) && ttisinteger(r))
return (ivalue(l) <= ivalue(r));
else if (tonumber(l, &nl) && tonumber(r, &nr))
- return luai_numle(L, nl, nr);
+ return luai_numle(nl, nr);
else if (ttisstring(l) && ttisstring(r))
return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0;
else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* first try `le' */
@@ -229,7 +222,7 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
else { /* two numbers with different variants */
lua_Number n1, n2;
lua_assert(ttisnumber(t1) && ttisnumber(t2));
- (void)tonumber(t1, &n1); (void)tonumber(t2, &n2);
+ cast_void(tonumber(t1, &n1)); cast_void(tonumber(t2, &n2));
return luai_numeq(n1, n2);
}
}
@@ -272,7 +265,7 @@ void luaV_concat (lua_State *L, int total) {
if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1))
luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT);
else if (tsvalue(top-1)->len == 0) /* second operand is empty? */
- (void)tostring(L, top - 2); /* result is first operand */
+ cast_void(tostring(L, top - 2)); /* result is first operand */
else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) {
setobjs2s(L, top - 2, top - 1); /* result is second op. */
}
@@ -333,8 +326,7 @@ lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y) {
if (cast_unsigned(y) + 1 <= 1U) { /* special cases: -1 or 0 */
if (y == 0)
luaG_runerror(L, "attempt to divide by zero");
- else /* -1 */
- return -x; /* avoid overflow with 0x80000... */
+ return intop(-, 0, x); /* y==-1; avoid overflow with 0x80000...//-1 */
}
else {
lua_Integer d = x / y; /* perform division */
@@ -350,8 +342,7 @@ lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y) {
if (cast_unsigned(y) + 1 <= 1U) { /* special cases: -1 or 0 */
if (y == 0)
luaG_runerror(L, "attempt to perform 'n%%0'");
- else /* -1 */
- return 0; /* avoid overflow with 0x80000... */
+ return 0; /* y==-1; avoid overflow with 0x80000...%-1 */
}
else {
lua_Integer r = x % y;
@@ -363,16 +354,36 @@ lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y) {
}
-lua_Integer luaV_pow (lua_Integer x, lua_Integer y) {
- lua_Integer r = 1;
- lua_assert(y >= 0);
- if (y == 0) return r;
- for (; y > 1; y >>= 1) {
- if (y & 1) r = intop(*, r, x);
- x = intop(*, x, x);
+lua_Integer luaV_pow (lua_State *L, lua_Integer x, lua_Integer y) {
+ if (y <= 0) { /* special cases: 0 or negative exponent */
+ if (y < 0)
+ luaG_runerror(L, "integer exponentiation with negative exponent");
+ return 1; /* x^0 == 1 */
+ }
+ else {
+ lua_Integer r = 1;
+ for (; y > 1; y >>= 1) {
+ if (y & 1) r = intop(*, r, x);
+ x = intop(*, x, x);
+ }
+ r = intop(*, r, x);
+ return r;
+ }
+}
+
+
+/* number of bits in an integer */
+#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT)
+
+LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
+ if (y < 0) { /* shift right? */
+ if (y <= -NBITS) return 0;
+ else return cast_integer(cast_unsigned(x) >> (-y));
+ }
+ else { /* shift left */
+ if (y >= NBITS) return 0;
+ else return x << y;
}
- r = intop(*, r, x);
- return r;
}
@@ -399,9 +410,9 @@ static Closure *getcached (Proto *p, UpVal **encup, StkId base) {
/*
** create a new Lua closure, push it in the stack, and initialize
-** its upvalues. Note that the call to 'luaC_barrierproto' must come
-** before the assignment to 'p->cache', as the function needs the
-** original value of that field.
+** its upvalues. Note that the closure is not cached if prototype is
+** already black (which means that 'cache' was already cleared by the
+** GC).
*/
static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
StkId ra) {
@@ -416,9 +427,11 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
ncl->l.upvals[i] = luaF_findupval(L, base + uv[i].idx);
else /* get upvalue from enclosing function */
ncl->l.upvals[i] = encup[uv[i].idx];
+ ncl->l.upvals[i]->refcount++;
+ /* new closure is white, so we do not need a barrier here */
}
- luaC_barrierproto(L, p, ncl);
- p->cache = ncl; /* save it on cache for reuse */
+ if (!isblack(obj2gco(p))) /* cache will not break GC invariant? */
+ p->cache = ncl; /* save it on cache for reuse */
}
@@ -432,7 +445,9 @@ void luaV_finishOp (lua_State *L) {
OpCode op = GET_OPCODE(inst);
switch (op) { /* finish its execution */
case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_IDIV:
- case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN:
+ case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR:
+ case OP_MOD: case OP_POW:
+ case OP_UNM: case OP_BNOT: case OP_LEN:
case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: {
setobjs2s(L, base + GETARG_A(inst), --L->top);
break;
@@ -590,7 +605,7 @@ void luaV_execute (lua_State *L) {
vmcase(OP_SETUPVAL,
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra);
- luaC_barrier(L, uv, ra);
+ luaC_upvalbarrier(L, uv);
)
vmcase(OP_SETTABLE,
Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
@@ -666,6 +681,51 @@ void luaV_execute (lua_State *L) {
}
else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); }
)
+ vmcase(OP_BAND,
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Integer ib; lua_Integer ic;
+ if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
+ setivalue(ra, intop(&, ib, ic));
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); }
+ )
+ vmcase(OP_BOR,
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Integer ib; lua_Integer ic;
+ if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
+ setivalue(ra, intop(|, ib, ic));
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); }
+ )
+ vmcase(OP_BXOR,
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Integer ib; lua_Integer ic;
+ if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
+ setivalue(ra, intop(^, ib, ic));
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); }
+ )
+ vmcase(OP_SHL,
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Integer ib; lua_Integer ic;
+ if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
+ setivalue(ra, luaV_shiftl(ib, ic));
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL)); }
+ )
+ vmcase(OP_SHR,
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Integer ib; lua_Integer ic;
+ if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
+ setivalue(ra, luaV_shiftl(ib, -ic));
+ }
+ else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR)); }
+ )
vmcase(OP_MOD,
TValue *rb = RKB(i);
TValue *rc = RKC(i);
@@ -683,11 +743,9 @@ void luaV_execute (lua_State *L) {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
lua_Number nb; lua_Number nc;
- lua_Integer ic;
- if (ttisinteger(rb) && ttisinteger(rc) &&
- (ic = ivalue(rc)) >= 0) {
- lua_Integer ib = ivalue(rb);
- setivalue(ra, luaV_pow(ib, ic));
+ if (ttisinteger(rb) && ttisinteger(rc)) {
+ lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
+ setivalue(ra, luaV_pow(L, ib, ic));
}
else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
setnvalue(ra, luai_numpow(L, nb, nc));
@@ -699,7 +757,7 @@ void luaV_execute (lua_State *L) {
lua_Number nb;
if (ttisinteger(rb)) {
lua_Integer ib = ivalue(rb);
- setivalue(ra, -ib);
+ setivalue(ra, intop(-, 0, ib));
}
else if (tonumber(rb, &nb)) {
setnvalue(ra, luai_numunm(L, nb));
@@ -708,6 +766,16 @@ void luaV_execute (lua_State *L) {
Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM));
}
)
+ vmcase(OP_BNOT,
+ TValue *rb = RB(i);
+ lua_Integer ib;
+ if (tointeger(rb, &ib)) {
+ setivalue(ra, intop(^, cast_integer(-1), ib));
+ }
+ else {
+ Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT));
+ }
+ )
vmcase(OP_NOT,
TValue *rb = RB(i);
int res = l_isfalse(rb); /* next assignment may change this value */
@@ -831,7 +899,7 @@ void luaV_execute (lua_State *L) {
}
)
vmcase(OP_FORLOOP,
- if (ttisinteger(ra)) { /* integer count? */
+ if (ttisinteger(ra)) { /* integer loop? */
lua_Integer step = ivalue(ra + 2);
lua_Integer idx = ivalue(ra) + step; /* increment index */
lua_Integer limit = ivalue(ra + 1);
@@ -841,12 +909,12 @@ void luaV_execute (lua_State *L) {
setivalue(ra + 3, idx); /* ...and external index */
}
}
- else { /* floating count */
+ else { /* floating loop */
lua_Number step = fltvalue(ra + 2);
lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */
lua_Number limit = fltvalue(ra + 1);
- if (luai_numlt(L, 0, step) ? luai_numle(L, idx, limit)
- : luai_numle(L, limit, idx)) {
+ if (luai_numlt(0, step) ? luai_numle(idx, limit)
+ : luai_numle(limit, idx)) {
ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
setnvalue(ra, idx); /* update internal index... */
setnvalue(ra + 3, idx); /* ...and external index */
@@ -857,10 +925,11 @@ void luaV_execute (lua_State *L) {
TValue *init = ra;
TValue *plimit = ra + 1;
TValue *pstep = ra + 2;
- if (ttisinteger(ra) && ttisinteger(ra + 1) && ttisinteger(ra + 2)) {
- setivalue(ra, ivalue(ra) - ivalue(pstep));
+ if (ttisinteger(init) && ttisinteger(plimit) && ttisinteger(pstep)) {
+ /* all values are integer */
+ setivalue(init, ivalue(init) - ivalue(pstep));
}
- else { /* try with floats */
+ else { /* try making all values floats */
lua_Number ninit; lua_Number nlimit; lua_Number nstep;
if (!tonumber(plimit, &nlimit))
luaG_runerror(L, LUA_QL("for") " limit must be a number");
@@ -870,7 +939,7 @@ void luaV_execute (lua_State *L) {
setnvalue(pstep, nstep);
if (!tonumber(init, &ninit))
luaG_runerror(L, LUA_QL("for") " initial value must be a number");
- setnvalue(ra, luai_numsub(L, ninit, nstep));
+ setnvalue(init, luai_numsub(L, ninit, nstep));
}
ci->u.l.savedpc += GETARG_sBx(i);
)
@@ -912,7 +981,7 @@ void luaV_execute (lua_State *L) {
for (; n > 0; n--) {
TValue *val = ra+n;
luaH_setint(L, h, last--, val);
- luaC_barrierback(L, obj2gco(h), val);
+ luaC_barrierback(L, h, val);
}
L->top = ci->top; /* correct top (in case of previous open call) */
)
diff --git a/src/lvm.h b/src/lvm.h
index 4f2651d3..20e24b32 100644
--- a/src/lvm.h
+++ b/src/lvm.h
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.h,v 2.23 2013/05/02 12:31:26 roberto Exp $
+** $Id: lvm.h,v 2.25 2013/12/30 20:47:58 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -43,7 +43,8 @@ LUAI_FUNC void luaV_execute (lua_State *L);
LUAI_FUNC void luaV_concat (lua_State *L, int total);
LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y);
LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y);
-LUAI_FUNC lua_Integer luaV_pow (lua_Integer x, lua_Integer y);
+LUAI_FUNC lua_Integer luaV_pow (lua_State *L, lua_Integer x, lua_Integer y);
+LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y);
LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb);
#endif
diff --git a/src/lzio.h b/src/lzio.h
index aec0bc12..2ad163a6 100644
--- a/src/lzio.h
+++ b/src/lzio.h
@@ -1,5 +1,5 @@
/*
-** $Id: lzio.h,v 1.27 2013/06/07 14:51:10 roberto Exp $
+** $Id: lzio.h,v 1.28 2014/01/31 15:14:22 roberto Exp $
** Buffered streams
** See Copyright Notice in lua.h
*/
@@ -32,6 +32,7 @@ typedef struct Mbuffer {
#define luaZ_sizebuffer(buff) ((buff)->buffsize)
#define luaZ_bufflen(buff) ((buff)->n)
+#define luaZ_buffremove(buff,i) ((buff)->n -= (i))
#define luaZ_resetbuffer(buff) ((buff)->n = 0)