diff options
author | Lua Team <team@lua.org> | 2014-03-21 12:00:00 +0000 |
---|---|---|
committer | repogen <> | 2014-03-21 12:00:00 +0000 |
commit | 05a6ab2dd30e7707c7d5424b905eb93a1dd5c5b2 (patch) | |
tree | f24db6e4692bebf7031418ff9c3b51b345016023 | |
parent | 87cc247b6b22184fba47184c218a642ea7a49e96 (diff) | |
download | lua-github-5.3.0-work2.tar.gz |
Lua 5.3.0-work25.3.0-work2
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | doc/alert.png | bin | 0 -> 1411 bytes | |||
-rw-r--r-- | doc/contents.html | 71 | ||||
-rw-r--r-- | doc/lua.css | 31 | ||||
-rw-r--r-- | doc/manual.css | 9 | ||||
-rw-r--r-- | doc/manual.html | 1625 | ||||
-rw-r--r-- | doc/readme.html | 93 | ||||
-rw-r--r-- | src/.fix | 2 | ||||
-rw-r--r-- | src/Makefile | 9 | ||||
-rw-r--r-- | src/lapi.c | 136 | ||||
-rw-r--r-- | src/lauxlib.c | 130 | ||||
-rw-r--r-- | src/lauxlib.h | 30 | ||||
-rw-r--r-- | src/lbaselib.c | 16 | ||||
-rw-r--r-- | src/lbitlib.c | 59 | ||||
-rw-r--r-- | src/lcode.c | 101 | ||||
-rw-r--r-- | src/lcode.h | 10 | ||||
-rw-r--r-- | src/ldblib.c | 10 | ||||
-rw-r--r-- | src/ldebug.c | 33 | ||||
-rw-r--r-- | src/ldebug.h | 4 | ||||
-rw-r--r-- | src/ldo.c | 43 | ||||
-rw-r--r-- | src/ldump.c | 287 | ||||
-rw-r--r-- | src/lfunc.c | 93 | ||||
-rw-r--r-- | src/lfunc.h | 27 | ||||
-rw-r--r-- | src/lgc.c | 623 | ||||
-rw-r--r-- | src/lgc.h | 79 | ||||
-rw-r--r-- | src/linit.c | 3 | ||||
-rw-r--r-- | src/liolib.c | 119 | ||||
-rw-r--r-- | src/llex.c | 122 | ||||
-rw-r--r-- | src/llex.h | 4 | ||||
-rw-r--r-- | src/llimits.h | 11 | ||||
-rw-r--r-- | src/lmathlib.c | 15 | ||||
-rw-r--r-- | src/loadlib.c | 34 | ||||
-rw-r--r-- | src/lobject.c | 126 | ||||
-rw-r--r-- | src/lobject.h | 45 | ||||
-rw-r--r-- | src/lopcodes.c | 22 | ||||
-rw-r--r-- | src/lopcodes.h | 12 | ||||
-rw-r--r-- | src/loslib.c | 60 | ||||
-rw-r--r-- | src/lparser.c | 74 | ||||
-rw-r--r-- | src/lparser.h | 3 | ||||
-rw-r--r-- | src/lstate.c | 85 | ||||
-rw-r--r-- | src/lstate.h | 49 | ||||
-rw-r--r-- | src/lstring.c | 101 | ||||
-rw-r--r-- | src/lstring.h | 8 | ||||
-rw-r--r-- | src/lstrlib.c | 227 | ||||
-rw-r--r-- | src/ltable.c | 74 | ||||
-rw-r--r-- | src/ltable.h | 7 | ||||
-rw-r--r-- | src/ltablib.c | 4 | ||||
-rw-r--r-- | src/ltm.c | 29 | ||||
-rw-r--r-- | src/ltm.h | 14 | ||||
-rw-r--r-- | src/lua.c | 100 | ||||
-rw-r--r-- | src/lua.h | 46 | ||||
-rw-r--r-- | src/luac.c | 2 | ||||
-rw-r--r-- | src/luaconf.h | 120 | ||||
-rw-r--r-- | src/lualib.h | 5 | ||||
-rw-r--r-- | src/lundump.c | 416 | ||||
-rw-r--r-- | src/lundump.h | 27 | ||||
-rw-r--r-- | src/lutf8lib.c | 240 | ||||
-rw-r--r-- | src/lvm.c | 181 | ||||
-rw-r--r-- | src/lvm.h | 5 | ||||
-rw-r--r-- | src/lzio.h | 3 |
60 files changed, 3262 insertions, 2654 deletions
@@ -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 Binary files differnew file mode 100644 index 00000000..49380746 --- /dev/null +++ b/doc/alert.png diff --git a/doc/contents.html b/doc/contents.html index 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 © 2011–2013 Lua.org, PUC-Rio. +Copyright © 2011–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 – Expressions</A> <UL> <LI><A HREF="manual.html#3.4.1">3.4.1 – Arithmetic Operators</A> -<LI><A HREF="manual.html#3.4.2">3.4.2 – Coercions and Conversions</A> -<LI><A HREF="manual.html#3.4.3">3.4.3 – Relational Operators</A> -<LI><A HREF="manual.html#3.4.4">3.4.4 – Logical Operators</A> -<LI><A HREF="manual.html#3.4.5">3.4.5 – Concatenation</A> -<LI><A HREF="manual.html#3.4.6">3.4.6 – The Length Operator</A> -<LI><A HREF="manual.html#3.4.7">3.4.7 – Precedence</A> -<LI><A HREF="manual.html#3.4.8">3.4.8 – Table Constructors</A> -<LI><A HREF="manual.html#3.4.9">3.4.9 – Function Calls</A> -<LI><A HREF="manual.html#3.4.10">3.4.10 – Function Definitions</A> +<LI><A HREF="manual.html#3.4.2">3.4.2 – Bitwise Operators</A> +<LI><A HREF="manual.html#3.4.3">3.4.3 – Coercions and Conversions</A> +<LI><A HREF="manual.html#3.4.4">3.4.4 – Relational Operators</A> +<LI><A HREF="manual.html#3.4.5">3.4.5 – Logical Operators</A> +<LI><A HREF="manual.html#3.4.6">3.4.6 – Concatenation</A> +<LI><A HREF="manual.html#3.4.7">3.4.7 – The Length Operator</A> +<LI><A HREF="manual.html#3.4.8">3.4.8 – Precedence</A> +<LI><A HREF="manual.html#3.4.9">3.4.9 – Table Constructors</A> +<LI><A HREF="manual.html#3.4.10">3.4.10 – Function Calls</A> +<LI><A HREF="manual.html#3.4.11">3.4.11 – Function Definitions</A> </UL> <LI><A HREF="manual.html#3.5">3.5 – 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 – Patterns</A> </UL> -<LI><A HREF="manual.html#6.5">6.5 – Table Manipulation</A> -<LI><A HREF="manual.html#6.6">6.6 – Mathematical Functions</A> -<LI><A HREF="manual.html#6.7">6.7 – Bitwise Operations</A> +<LI><A HREF="manual.html#6.5">6.5 – UTF-8 Support</A> +<LI><A HREF="manual.html#6.6">6.6 – Table Manipulation</A> +<LI><A HREF="manual.html#6.7">6.7 – Mathematical Functions</A> <LI><A HREF="manual.html#6.8">6.8 – Input and Output Facilities</A> <LI><A HREF="manual.html#6.9">6.9 – Operating System Facilities</A> <LI><A HREF="manual.html#6.10">6.10 – The Debug Library</A> @@ -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 © 2011–2013 Lua.org, PUC-Rio. +Copyright © 2011–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">§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">§3.4.9</a>). +(see <a href="#3.4.10">§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">§3.4.8</a>). +(see <a href="#3.4.9">§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">§3.4.6</a>). +which is called the length of the sequence (see <a href="#3.4.7">§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">§3.4.10</a>). +Thus tables can also carry <em>methods</em> (see <a href="#3.4.11">§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">§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(···) - 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 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(···) - 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">§3.4.3</a>). </li> -<li><b>"concat": </b> -the <code>..</code> (concatenation) operation. +<li><b>"band": </b> +the <code>&</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(···) - 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(···) - end - end - end -</pre><p> -See <a href="#3.4.6">§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><<</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>>></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><</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 < op2 -- numeric comparison - elseif type(op1) == "string" and type(op2) == "string" then - return op1 < op2 -- lexicographic comparison - else - local h = getbinhandler(op1, op2, "__lt") - if h then - return not not h(op1, op2) - else - error(···) - 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">§3.4.7</a>). +Otherwise, Lua raises an error. </li> -<li><b>"le": </b> -the <code><=</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 <= op2 -- numeric comparison - elseif type(op1) == "string" and type(op2) == "string" then - return op1 <= 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(···) - end - end - end - end -</pre><p> -Note that, in the absence of a "le" metamethod, -Lua tries the "lt", assuming that <code>a <= b</code> is -equivalent to <code>not (b < a)</code>. +<li><b>"lt": </b> +the <code><</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><=</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 <= b</code> is equivalent to <code>not (b < 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(···) - 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(···) - 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(···) - 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 – <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">§3.4.10</a>). +(see <a href="#3.4.11">§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> > 0 and <em>var</em> <= <em>limit</em>) or (<em>step</em> <= 0 and <em>var</em> >= <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 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">§3.4.9</a>. +Function calls are explained in <a href="#3.4.10">§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">§3.1</a>; variables are explained in <a href="#3.2">§3.2</a>; -function definitions are explained in <a href="#3.4.10">§3.4.10</a>; -function calls are explained in <a href="#3.4.9">§3.4.9</a>; -table constructors are explained in <a href="#3.4.8">§3.4.8</a>. +function definitions are explained in <a href="#3.4.11">§3.4.11</a>; +function calls are explained in <a href="#3.4.10">§3.4.10</a>; +table constructors are explained in <a href="#3.4.9">§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">§3.4.10</a>. +they are explained in <a href="#3.4.11">§3.4.11</a>. <p> Binary operators comprise arithmetic operators (see <a href="#3.4.1">§3.4.1</a>), -relational operators (see <a href="#3.4.3">§3.4.3</a>), logical operators (see <a href="#3.4.4">§3.4.4</a>), -and the concatenation operator (see <a href="#3.4.5">§3.4.5</a>). +bitwise operators (see <a href="#3.4.2">§3.4.2</a>), +relational operators (see <a href="#3.4.4">§3.4.4</a>), logical operators (see <a href="#3.4.5">§3.4.5</a>), +and the concatenation operator (see <a href="#3.4.6">§3.4.6</a>). Unary operators comprise the unary minus (see <a href="#3.4.1">§3.4.1</a>), -the unary <b>not</b> (see <a href="#3.4.4">§3.4.4</a>), -and the unary <em>length operator</em> (see <a href="#3.4.6">§3.4.6</a>). +the unary bitwise not (see <a href="#3.4.2">§3.4.2</a>), +the unary logic <b>not</b> (see <a href="#3.4.5">§3.4.5</a>), +and the unary <em>length operator</em> (see <a href="#3.4.7">§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">§3.4.2</a>), -then they are converted to floating-point numbers, +numbers (see <a href="#3.4.3">§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">§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">§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 – <a name="3.4.2">Coercions and Conversions</a></h3> +<h3>3.4.2 – <a name="3.4.2">Bitwise Operators</a></h3><p> +Lua supports the following bitwise operators: +the binary <code>&</code> (bitwise and), +<code>|</code> (bitwise or), <code>~</code> (bitwise exclusive or), +<code>>></code> (right shift), <code><<</code> (left shift), +and unary <code>~</code> (bitwise not). + + +<p> +All bitwise operations convert its operands to integers +(see <a href="#3.4.3">§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 – <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 – <a name="3.4.3">Relational Operators</a></h3><p> +<h3>3.4.4 – <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 >= b</code> is translated to <code>b <= a</code>. -<h3>3.4.4 – <a name="3.4.4">Logical Operators</a></h3><p> +<h3>3.4.5 – <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">§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 – <a name="3.4.5">Concatenation</a></h3><p> +<h3>3.4.6 – <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">§3.4.2</a>. +strings according to the rules described in <a href="#3.4.3">§3.4.3</a>. Otherwise, the <code>__concat</code> metamethod is called (see <a href="#2.4">§2.4</a>). -<h3>3.4.6 – <a name="3.4.6">The Length Operator</a></h3> +<h3>3.4.7 – <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 – <a name="3.4.7">Precedence</a></h3><p> +<h3>3.4.8 – <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 – <a name="3.4.8">Table Constructors</a></h3><p> +<h3>3.4.9 – <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">§3.4.9</a>). +(see <a href="#3.4.10">§3.4.10</a>). <p> @@ -2279,7 +2206,7 @@ as a convenience for machine-generated code. -<h3>3.4.9 – <a name="3.4.9">Function Calls</a></h3><p> +<h3>3.4.10 – <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 – <a name="3.4.10">Function Definitions</a></h3> +<h3>3.4.11 – <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>&</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><<</code>)</li> +<li><b><a name="pdf-LUA_OPSHR"><code>LUA_OPSHR</code></a>: </b> performs right shift (<code>>></code>)</li> </ul> @@ -3283,7 +3217,7 @@ If <code>n</code> is 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">§3.4.5</a>). +(see <a href="#3.4.6">§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">§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">§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">§2.5</a>). -The function returns the previous value of the step multiplier. +the collector (see <a href="#2.5">§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">§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">§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 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">§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">§3.4.6</a>). +it is equivalent to the '<code>#</code>' operator in Lua (see <a href="#3.4.7">§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 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, –]</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, –]</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, –]</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 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">§3.4.2</a>); +or a number or string convertible to an integer (see <a href="#3.4.3">§3.4.3</a>); otherwise, <code>lua_tointegerx</code> returns 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 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">§3.4.2</a>); +(see <a href="#3.4.3">§3.4.3</a>); otherwise, <a href="#lua_tonumberx"><code>lua_tonumberx</code></a> returns 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">§3.4.2</a>); +(see <a href="#3.4.3">§3.4.3</a>); otherwise, <code>lua_tounsignedx</code> returns 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, –]</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 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">§3.4.6</a>). +it is equivalent to the '<code>#</code>' operator in Lua (see <a href="#3.4.7">§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 – <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">§6.4</a>);</li> -<li>table manipulation (<a href="#6.5">§6.5</a>);</li> +<li>basic UTF-8 support (<a href="#6.5">§6.5</a>);</li> -<li>mathematical functions (<a href="#6.6">§6.6</a>) (sin, log, etc.);</li> +<li>table manipulation (<a href="#6.6">§6.6</a>);</li> -<li>bitwise operations (<a href="#6.7">§6.7</a>);</li> +<li>mathematical functions (<a href="#6.7">§6.7</a>) (sin, log, etc.);</li> <li>input and output (<a href="#6.8">§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">§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 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) --> 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) - --> x="lua-5.2.tar.gz" + --> x="lua-5.3.tar.gz" </pre> @@ -8219,6 +8196,45 @@ its default value is 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 and 5. -<h2>6.5 – <a name="6.5">Table Manipulation</a></h2> +<h2>6.5 – <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 (···)</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">§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 – <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">§3.4.6</a>). +or have a <code>__len</code> metamethod (see <a href="#3.4.7">§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 1 and <code>j</code> is <code>#list</code>. -<h2>6.6 – <a name="6.6">Mathematical Functions</a></h2> +<h2>6.7 – <a name="6.7">Mathematical Functions</a></h2> <p> This library is an interface to the standard C 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 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 – <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 (···)</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 (···)</code></a></h3> - - -<p> -Returns the bitwise <em>or</em> of its operands. - - - - -<p> -<hr><h3><a name="pdf-bit32.btest"><code>bit32.btest (···)</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 (···)</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(···)</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 function <code>gmtime</code> and C 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 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 5.1 to Lua 5.2. +from Lua 5.2 to Lua 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 5.1 -have been removed in Lua 5.2. - - - -<h2>8.1 – <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 – <a name="8.2">Changes in the Libraries</a></h2> +<h2>8.1 – <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 5.2 and Lua 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 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 5.2.) </li> </ul> @@ -10492,76 +10348,39 @@ change between versions. -<h2>8.3 – <a name="8.3">Changes in the API</a></h2> +<h2>8.2 – <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">§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 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">§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 – <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> · <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 © 1994–2013 Lua.org, PUC-Rio. +Copyright © 1994–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> @@ -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 \ @@ -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) @@ -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); @@ -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); @@ -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; } } @@ -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); @@ -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] */ @@ -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); + } } } @@ -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, @@ -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; @@ -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 @@ -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; +} + @@ -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) */ ) @@ -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 @@ -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) |