summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README2
-rw-r--r--doc/contents.html20
-rw-r--r--doc/lua.css21
-rw-r--r--doc/manual.html938
-rw-r--r--doc/readme.html25
-rw-r--r--src/Makefile4
-rw-r--r--src/lapi.c162
-rw-r--r--src/lauxlib.c90
-rw-r--r--src/lauxlib.h7
-rw-r--r--src/lbaselib.c184
-rw-r--r--src/lbitlib.c88
-rw-r--r--src/lcode.c80
-rw-r--r--src/lcode.h7
-rw-r--r--src/ldblib.c27
-rw-r--r--src/ldebug.c110
-rw-r--r--src/ldebug.h5
-rw-r--r--src/ldo.c130
-rw-r--r--src/ldump.c6
-rw-r--r--src/lgc.c137
-rw-r--r--src/lgc.h17
-rw-r--r--src/linit.c10
-rw-r--r--src/liolib.c91
-rw-r--r--src/llex.c30
-rw-r--r--src/llex.h14
-rw-r--r--src/llimits.h25
-rw-r--r--src/lmem.c14
-rw-r--r--src/loadlib.c73
-rw-r--r--src/lobject.c124
-rw-r--r--src/lobject.h328
-rw-r--r--src/lopcodes.c10
-rw-r--r--src/lopcodes.h13
-rw-r--r--src/loslib.c31
-rw-r--r--src/lparser.c465
-rw-r--r--src/lparser.h45
-rw-r--r--src/lstate.c20
-rw-r--r--src/lstate.h18
-rw-r--r--src/lstring.c7
-rw-r--r--src/lstrlib.c73
-rw-r--r--src/ltable.c18
-rw-r--r--src/ltablib.c8
-rw-r--r--src/ltm.c8
-rw-r--r--src/ltm.h4
-rw-r--r--src/lua.c21
-rw-r--r--src/lua.h8
-rw-r--r--src/luac.c29
-rw-r--r--src/luaconf.h63
-rw-r--r--src/lualib.h4
-rw-r--r--src/lundump.c53
-rw-r--r--src/lundump.h11
-rw-r--r--src/lvm.c150
-rw-r--r--src/lvm.h11
-rw-r--r--src/lzio.c30
-rw-r--r--src/lzio.h5
53 files changed, 2418 insertions, 1456 deletions
diff --git a/README b/README
index 480518cf..fc4cbeed 100644
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
-This is Lua 5.2 (alpha), released on 23 Nov 2010.
+This is Lua 5.2 (beta), released on 13 Jun 2011.
For installation instructions, license details, and
further information about Lua, see doc/readme.html.
diff --git a/doc/contents.html b/doc/contents.html
index bc77d74a..5e94ebd1 100644
--- a/doc/contents.html
+++ b/doc/contents.html
@@ -22,7 +22,7 @@ Lua 5.2 Reference Manual
<P>
<IMG SRC="alert.png" ALIGN="absbottom" ALT="[!]">
-<EM>This is an alpha version of Lua 5.2.
+<EM>This is a beta version of Lua 5.2.
Some details may change in the final version.</EM>
<P>
@@ -38,7 +38,7 @@ For a complete introduction to Lua programming, see the book
<A HREF="#index">index</A>
<HR>
<SMALL>
-Copyright &copy; 2010 Lua.org, PUC-Rio.
+Copyright &copy; 2011 Lua.org, PUC-Rio.
Freely available under the terms of the
<a href="http://www.lua.org/license.html#5">Lua license</a>.
</SMALL>
@@ -120,7 +120,7 @@ Freely available under the terms of the
</UL>
<LI><A HREF="manual.html#6.5">6.5 &ndash; Table Manipulation</A>
<LI><A HREF="manual.html#6.6">6.6 &ndash; Mathematical Functions</A>
-<LI><A HREF="manual.html#6.7">6.7 &ndash; Bitwise operations</A>
+<LI><A HREF="manual.html#6.7">6.7 &ndash; Bitwise Operations</A>
<LI><A HREF="manual.html#6.8">6.8 &ndash; Input and Output Facilities</A>
<LI><A HREF="manual.html#6.9">6.9 &ndash; Operating System Facilities</A>
<LI><A HREF="manual.html#6.10">6.10 &ndash; The Debug Library</A>
@@ -154,14 +154,13 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-ipairs">ipairs</A><BR>
<A HREF="manual.html#pdf-load">load</A><BR>
<A HREF="manual.html#pdf-loadfile">loadfile</A><BR>
-<A HREF="manual.html#pdf-loadin">loadin</A><BR>
-<A HREF="manual.html#pdf-loadstring">loadstring</A><BR>
<A HREF="manual.html#pdf-next">next</A><BR>
<A HREF="manual.html#pdf-pairs">pairs</A><BR>
<A HREF="manual.html#pdf-pcall">pcall</A><BR>
<A HREF="manual.html#pdf-print">print</A><BR>
<A HREF="manual.html#pdf-rawequal">rawequal</A><BR>
<A HREF="manual.html#pdf-rawget">rawget</A><BR>
+<A HREF="manual.html#pdf-rawlen">rawlen</A><BR>
<A HREF="manual.html#pdf-rawset">rawset</A><BR>
<A HREF="manual.html#pdf-require">require</A><BR>
<A HREF="manual.html#pdf-select">select</A><BR>
@@ -178,8 +177,10 @@ Freely available under the terms of the
<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>
@@ -475,15 +476,18 @@ Freely available under the terms of the
<A HREF="manual.html#luaL_dofile">luaL_dofile</A><BR>
<A HREF="manual.html#luaL_dostring">luaL_dostring</A><BR>
<A HREF="manual.html#luaL_error">luaL_error</A><BR>
-<A HREF="manual.html#luaL_findtable">luaL_findtable</A><BR>
+<A HREF="manual.html#luaL_execresult">luaL_execresult</A><BR>
+<A HREF="manual.html#luaL_fileresult">luaL_fileresult</A><BR>
<A HREF="manual.html#luaL_getmetafield">luaL_getmetafield</A><BR>
<A HREF="manual.html#luaL_getmetatable">luaL_getmetatable</A><BR>
+<A HREF="manual.html#luaL_getsubtable">luaL_getsubtable</A><BR>
<A HREF="manual.html#luaL_gsub">luaL_gsub</A><BR>
<A HREF="manual.html#luaL_len">luaL_len</A><BR>
<A HREF="manual.html#luaL_loadbuffer">luaL_loadbuffer</A><BR>
<A HREF="manual.html#luaL_loadfile">luaL_loadfile</A><BR>
<A HREF="manual.html#luaL_loadstring">luaL_loadstring</A><BR>
<A HREF="manual.html#luaL_newlib">luaL_newlib</A><BR>
+<A HREF="manual.html#luaL_newlibtable">luaL_newlibtable</A><BR>
<A HREF="manual.html#luaL_newmetatable">luaL_newmetatable</A><BR>
<A HREF="manual.html#luaL_newstate">luaL_newstate</A><BR>
<A HREF="manual.html#luaL_openlibs">luaL_openlibs</A><BR>
@@ -516,10 +520,10 @@ Freely available under the terms of the
<HR>
<SMALL>
Last update:
-Mon Nov 22 16:38:54 BRST 2010
+Mon Jun 13 15:09:33 BRT 2011
</SMALL>
<!--
-Last change: revised for Lua 5.2.0 (alpha)
+Last change: revised for Lua 5.2.0 (beta)
-->
</BODY>
diff --git a/doc/lua.css b/doc/lua.css
index b9d3cca9..d87665c9 100644
--- a/doc/lua.css
+++ b/doc/lua.css
@@ -8,6 +8,7 @@ body {
}
h1, h2, h3, h4 {
+ font-family: Verdana, sans-serif ;
font-weight: normal ;
font-style: italic ;
}
@@ -27,7 +28,7 @@ h3 {
table h3 {
padding-left: 0px ;
- border-left: none ;
+ border-left: none ;
}
a:link {
@@ -62,3 +63,21 @@ hr {
padding: 8px ;
border: solid #a0a0a0 2px ;
}
+
+.footer {
+ color: gray ;
+ font-size: small ;
+}
+
+input[type=text] {
+ border: solid #a0a0a0 2px ;
+ border-radius: 2em ;
+ -moz-border-radius: 2em ;
+ background-image: url('images/search.png') ;
+ background-repeat: no-repeat;
+ background-position: left center ;
+ background-position: 4px center ;
+ padding-left: 20px ;
+ height: 2em ;
+}
+
diff --git a/doc/manual.html b/doc/manual.html
index c1548212..fdd3669b 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -17,14 +17,14 @@ Lua 5.2 Reference Manual
</h1>
<IMG SRC="alert.png" ALIGN="absbottom" ALT="[!]">
-<EM>This is an alpha version of Lua 5.2.
+<EM>This is a beta version of Lua 5.2.
Some details may change in the final version.</EM>
<P>
by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
<p>
<small>
-Copyright &copy; 2010 Lua.org, PUC-Rio.
+Copyright &copy; 2011 Lua.org, PUC-Rio.
Freely available under the terms of the
<a href="http://www.lua.org/license.html#5">Lua license</a>.
</small>
@@ -38,7 +38,7 @@ Freely available under the terms of the
<!-- ====================================================================== -->
<p>
-<!-- $Id: manual.of,v 1.66 2010/11/22 18:07:40 roberto Exp $ -->
+<!-- $Id: manual.of,v 1.77 2011/06/13 16:27:54 roberto Exp $ -->
@@ -53,7 +53,7 @@ It also offers good support for object-oriented programming,
functional programming, and data-driven programming.
Lua is intended to be used as a powerful, light-weight
scripting language for any program that needs one.
-Lua is implemented as a library, written in <em>clean</em> C,
+Lua is implemented as a library, written in <em>clean C</em>,
the common subset of ANSI&nbsp;C and C++.
@@ -125,11 +125,14 @@ it usually represents the absence of a useful value.
Both <b>nil</b> and <b>false</b> make a condition false;
any other value makes it true.
<em>Number</em> represents real (double-precision floating-point) numbers.
+Operations on numbers follow the same rules of
+the underlying C&nbsp;implementation,
+which, in turn, usually follows the IEEE 754 standard.
(It is easy to build Lua interpreters that use other
internal representations for numbers,
such as single-precision floats or long integers;
see file <code>luaconf.h</code>.)
-<em>String</em> represents arrays of characters.
+<em>String</em> represents immutable sequences of bytes.
Lua is 8-bit clean:
strings can contain any 8-bit value,
@@ -167,11 +170,19 @@ even those that do not support threads.
<p>
The type <em>table</em> implements associative arrays,
that is, arrays that can be indexed not only with numbers,
-but with any value (except <b>nil</b>).
+but with any Lua value except <b>nil</b> and NaN
+(<em>Not a Number</em>, a special numeric value used to represent
+undefined or unrepresentable results, such as <code>0/0</code>).
Tables can be <em>heterogeneous</em>;
that is, they can contain values of all types (except <b>nil</b>).
+Any key with value <b>nil</b> is not considered part of the table.
+Conversely, any key that is not part of a table has
+an associated value <b>nil</b>.
+
+
+<p>
Tables are the sole data structuring mechanism in Lua;
-they can be used to represent ordinary arrays,
+they can be used to represent ordinary arrays, sequences,
symbol tables, sets, records, graphs, trees, etc.
To represent records, Lua uses the field name as an index.
The language supports this representation by
@@ -181,8 +192,14 @@ There are several convenient ways to create tables in Lua
<p>
+We use the term <em>sequence</em> to denote a table where all
+integer keys comprise the set <em>{1..n}</em> for some integer <em>n</em>,
+which is called the length of the sequence (see <a href="#3.4.6">&sect;3.4.6</a>).
+
+
+<p>
Like indices,
-the value of a table field can be of any type (except <b>nil</b>).
+the value of a table field can be of any type.
In particular,
because functions are first-class values,
table fields can contain functions.
@@ -190,6 +207,14 @@ Thus tables can also carry <em>methods</em> (see <a href="#3.4.10">&sect;3.4.10<
<p>
+The indexing of tables follows
+the definition of equality in the language.
+The expressions <code>a[i]</code> and <code>a[j]</code>
+denote the same table element
+if and only if <code>i == j</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.
@@ -210,7 +235,7 @@ of a given value.
<p>
As discussed in <a href="#3.2">&sect;3.2</a> and <a href="#3.3.3">&sect;3.3.3</a>,
-any reference to a global name <code>var</code> is syntactically translated
+any reference to a global name <code>var</code> is syntactically translated
to <code>_ENV.var</code>.
Moreover, every chunk is compiled in the scope of an external
variable called <code>_ENV</code> (see <a href="#3.3.2">&sect;3.3.2</a>),
@@ -241,13 +266,13 @@ In Lua, the variable <a href="#pdf-_G"><code>_G</code></a> is initialized with t
<p>
When Lua compiles a chunk,
-it initializes the value of its <code>_ENV</code> variable
+it initializes the value of its <code>_ENV</code> variable
with the global environment (see <a href="#pdf-load"><code>load</code></a>).
Therefore, by default,
global variables in Lua code refer to entries in the global environment.
Moreover, all standard libraries are loaded in the global environment,
and several functions there operate on that environment.
-You can use <a href="#pdf-loadin"><code>loadin</code></a> to load a chunk with a different environment.
+You can use <a href="#pdf-load"><code>load</code></a> to load a chunk with a different environment.
(In C, you have to load the chunk and then change the value
of its first upvalue.)
@@ -283,7 +308,32 @@ which can take appropriate measures
Lua code can explicitly generate an error by calling the
<a href="#pdf-error"><code>error</code></a> function.
If you need to catch errors in Lua,
-you can use the <a href="#pdf-pcall"><code>pcall</code></a> or the <a href="#pdf-xpcall"><code>xpcall</code></a> function.
+you can use <a href="#pdf-pcall"><code>pcall</code></a> or <a href="#pdf-xpcall"><code>xpcall</code></a>
+to call a given function in <em>protected mode</em>.
+
+
+<p>
+Whenever there is an error,
+an <em>error object</em> (also called an <em>error message</em>)
+is propagated with information about the error.
+Lua itself only generates errors where the error object is a string,
+but programs may generate errors with
+any value for the error object.
+
+
+<p>
+When you use <a href="#pdf-xpcall"><code>xpcall</code></a> or <a href="#lua_pcall"><code>lua_pcall</code></a>,
+you may give an <em>message handler</em>
+to be called in case of errors.
+This function is called with the original error message
+and returns a new error message.
+It is called before the error unwonds the stack,
+so that it can gather more information about the error,
+for instance by inspecting the stack and creating a stack traceback.
+This message handler is still protected by the protected call;
+so, an error inside the message handler
+will call the message handler again.
+If this loop goes on, Lua breaks it and returns an appropriate message.
@@ -307,7 +357,7 @@ Lua calls this function to perform the addition.
<p>
The keys in a metatable are derived from the <em>event</em> names;
the corresponding values are called <em>metamethods</em>.
-In the previous example, the event is <code>"add"</code>
+In the previous example, the event is <code>"add"</code>
and the metamethod is the function that performs the addition.
@@ -623,6 +673,11 @@ equivalent to <code>not (b &lt; a)</code>.
<li><b>"index":</b>
The indexing access <code>table[key]</code>.
+Note that the metamethod is tried only
+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.)
<pre>
@@ -630,6 +685,7 @@ The indexing access <code>table[key]</code>.
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
@@ -649,6 +705,8 @@ The indexing access <code>table[key]</code>.
<li><b>"newindex":</b>
The indexing assignment <code>table[key] = value</code>.
+Note that the metamethod is tried only
+when <code>key</code> is not present in <code>table</code>.
<pre>
@@ -656,6 +714,7 @@ The indexing assignment <code>table[key] = value</code>.
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
@@ -758,7 +817,7 @@ memory usage.
<p>
You can change these numbers by calling <a href="#lua_gc"><code>lua_gc</code></a> in C
or <a href="#pdf-collectgarbage"><code>collectgarbage</code></a> in Lua.
-With these functions you can also control
+With these functions you can also control
the collector directly (e.g., stop and restart it).
@@ -766,8 +825,9 @@ the collector directly (e.g., stop and restart it).
<h3>2.5.1 &ndash; <a name="2.5.1">Garbage-Collection Metamethods</a></h3>
<p>
-Using the C&nbsp;API,
-you can set garbage-collector metamethods for full userdata (see <a href="#2.4">&sect;2.4</a>).
+You can set garbage-collector metamethods for tables
+and, using the C&nbsp;API,
+for full userdata (see <a href="#2.4">&sect;2.4</a>).
These metamethods are also called <em>finalizers</em>.
Finalizers allow you to coordinate Lua's garbage collection
with external resource management
@@ -776,43 +836,43 @@ or freeing your own memory).
<p>
-For a userdata to be finalized when collected,
+For an object (table or userdata) to be finalized when collected,
you must <em>mark</em> it for finalization.
-You mark a userdata for finalization when you set its metatable
+You mark an object for finalization when you set its metatable
and the metatable has a field indexed by the string "<code>__gc</code>".
Note that if you set a metatable without a <code>__gc</code> field
and later create that field in the metatable,
-the userdata will not be marked for finalization.
+the object will not be marked for finalization.
However, after a userdata is marked,
you can freely change the <code>__gc</code> field of its metatable.
<p>
-When a marked userdata becomes garbage,
+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 userdata in that list:
+for each object in that list:
<pre>
- function gc_event (udata)
- local h = metatable(udata).__gc
+ function gc_event (obj)
+ local h = metatable(obj).__gc
if type(h) == "function" then
- h(udata)
+ h(obj)
end
end
</pre>
<p>
At the end of each garbage-collection cycle,
-the finalizers for userdata are called in
+the finalizers for objects are called in
the reverse order that they were marked for collection,
among those collected in that cycle;
that is, the first finalizer to be called is the one associated
-with the userdata marked last in the program.
-The userdata memory is freed only in the next garbage-collection cycle.
+with the object marked last in the program.
+The object memory is freed only in the next garbage-collection cycle.
@@ -873,15 +933,13 @@ Lua treats strings and light C functions as non-object values.
<p>
-Userdata marked for finalization have a special behavior in weak tables.
-When a marked userdata is a value in a weak table,
-it is removed from the table the first time it is collected,
-before running its finalizer.
+Objects marked for finalization have a special behavior in weak tables.
+When a marked object is a value in a weak table,
+it is removed from the table before running its finalizer.
However, when it is a key,
-it is removed from the table only when it is really freed,
-after running its finalizer.
-This behavior allows the finalizer to access values
-associated with the userdata through weak tables.
+it is removed from the table only after running its finalizer.
+This behavior allows the finalizer to access properties
+associated with the object through weak tables.
@@ -980,7 +1038,7 @@ consider the following code:
print("co-body", r, s)
return b, "end"
end)
-
+
print("main", coroutine.resume(co, 1, 10))
print("main", coroutine.resume(co, "r"))
print("main", coroutine.resume(co, "x", "y"))
@@ -1048,8 +1106,7 @@ except as delimiters between names and keywords.
in Lua can be any string of letters,
digits, and underscores,
not beginning with a digit.
-This coincides with the definition of names in most languages.
-Identifiers are used to name variables and table fields.
+Identifiers are used to name variables, table fields, and labels.
<p>
@@ -1058,10 +1115,10 @@ and cannot be used as names:
<pre>
- and break do else elseif
- end false for function if
- in local nil not or
- repeat return then true until while
+ and break do else elseif end
+ false for function goto if in
+ local nil not or repeat return
+ then true until while
</pre>
<p>
@@ -1102,7 +1159,7 @@ results in a newline in the string.
The escape sequence '<code>\*</code>' skips the following span
of white-space characters,
including line breaks;
-it is particularly useful to break and indent a long string
+it is particularly useful to break and indent a long string
into multiple lines without adding the newlines and spaces
into the string contents.
@@ -1140,9 +1197,18 @@ Any kind of end-of-line sequence
(carriage return, newline, carriage return followed by newline,
or newline followed by carriage return)
is converted to a simple newline.
-You should not use long strings for non-text data;
-Use instead a regular quoted literal with explicit escape sequences
-for control characters.
+
+
+<p>
+When parsing a from a string source,
+any byte in a literal string not
+explicitly affected by the previous rules represents itself.
+However, Lua opens files for parsing in text mode,
+and the system file functions may have problems with
+some control characters.
+So, it is safer to represent
+non-text data as a quoted literal with
+explicit escape sequences for non-text characters.
<p>
@@ -1166,14 +1232,19 @@ the five literal strings below denote the same string:
</pre>
<p>
-A <em>numerical constant</em> can be written with an optional decimal part
-and an optional decimal exponent.
-Lua also accepts integer hexadecimal constants,
-by prefixing them with <code>0x</code>.
+A <em>numerical constant</em> can be written with an optional fractional part
+and an optional decimal exponent,
+marked by a letter '<code>e</code>' or '<code>E</code>'.
+Lua also accepts hexadecimal constants,
+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>e</code>' or '<code>E</code>'.
Examples of valid numerical constants are
<pre>
- 3 3.0 3.1416 314.16e-2 0.31416E1 0xff 0x56
+ 3 3.0 3.1416 314.16e-2 0.31416E1
+ 0xff 0x0.1E 0xA23p-4 0X1.921FB54442D18P+1
</pre>
<p>
@@ -1194,7 +1265,6 @@ Long comments are frequently used to disable code temporarily.
<p>
Variables are places that store values.
-
There are three kinds of variables in Lua:
global variables, local variables, and table fields.
@@ -1293,7 +1363,7 @@ A block can be explicitly delimited to produce a single statement:
Explicit blocks are useful
to control the scope of variable declarations.
Explicit blocks are also sometimes used to
-add a <b>return</b> or <b>break</b> statement in the middle
+add a <b>return</b> statement in the middle
of another block (see <a href="#3.3.4">&sect;3.3.4</a>).
@@ -1312,7 +1382,7 @@ a chunk is simply a block:
</pre>
<p>
-Lua handles a chunk as the body of an anonymous function
+Lua handles a chunk as the body of an anonymous function
with a variable number of arguments
(see <a href="#3.4.10">&sect;3.4.10</a>).
As such, chunks can define local variables,
@@ -1452,38 +1522,60 @@ declared inside the loop block.
<p>
-The <b>return</b> statement is used to return values
-from a function or a chunk (which is just a function).
+The <b>goto</b> statement transfers the program control to a label.
+For syntactical reasons,
+labels in Lua are considered statements too:
+
-Functions can return more than one value,
-so the syntax for the <b>return</b> statement is
<pre>
- stat ::= <b>return</b> [explist] [&lsquo;<b>;</b>&rsquo;]
+ stat ::= <b>goto</b> Name
+ stat ::= label
+ label ::= &lsquo;<b>@</b>&rsquo; Name &lsquo;<b>:</b>&rsquo;
</pre>
<p>
-The <b>break</b> statement is used to terminate the execution of a
+A label is visible in the entire block where it is defined
+(including nested blocks, but not nested functions).
+A goto may jump to any visible label as long as it does not
+enter into the scope of a local variable.
+
+
+<p>
+Both labels and empty statements are called <em>void statements</em>,
+as they perform no actions.
+
+
+<p>
+The <b>break</b> statement terminates the execution of a
<b>while</b>, <b>repeat</b>, or <b>for</b> loop,
skipping to the next statement after the loop:
<pre>
- stat ::= <b>break</b> [&lsquo;<b>;</b>&rsquo;]
+ stat ::= <b>break</b>
</pre><p>
A <b>break</b> ends the innermost enclosing loop.
<p>
-The <b>return</b> and <b>break</b>
-statements can only be written as the <em>last</em> statement of a block.
-If it is really necessary to <b>return</b> or <b>break</b> in the
-middle of a block,
+The <b>return</b> statement is used to return values
+from a function or a chunk (which is a function in disguise).
+
+Functions can return more than one value,
+so the syntax for the <b>return</b> statement is
+
+<pre>
+ stat ::= <b>return</b> [explist] [&lsquo;<b>;</b>&rsquo;]
+</pre>
+
+<p>
+The <b>return</b> statement can only be written
+as the last statement of a block.
+If it is really necessary to <b>return</b> in the middle of a block,
then an explicit inner block can be used,
-as in the idioms
-<code>do return end</code> and <code>do break end</code>,
-because now <b>return</b> and <b>break</b> are the last statements in
-their (inner) blocks.
+as in the idiom <code>do return end</code>,
+because now <b>return</b> is the last statement in its (inner) block.
@@ -1582,8 +1674,8 @@ is equivalent to the code:
local <em>f</em>, <em>s</em>, <em>var</em> = <em>explist</em>
while true do
local <em>var_1</em>, &middot;&middot;&middot;, <em>var_n</em> = <em>f</em>(<em>s</em>, <em>var</em>)
+ if <em>var_1</em> == nil then break end
<em>var</em> = <em>var_1</em>
- if <em>var</em> == nil then break end
<em>block</em>
end
end
@@ -1649,7 +1741,6 @@ Otherwise, all variables are initialized with <b>nil</b>.
<p>
A chunk is also a block (see <a href="#3.3.2">&sect;3.3.2</a>),
and so local variables can be declared in a chunk outside any explicit block.
-The scope of such local variables extends until the end of the chunk.
<p>
@@ -1671,7 +1762,7 @@ The basic expressions in Lua are the following:
exp ::= <b>nil</b> | <b>false</b> | <b>true</b>
exp ::= Number
exp ::= String
- exp ::= function
+ exp ::= functiondef
exp ::= tableconstructor
exp ::= &lsquo;<b>...</b>&rsquo;
exp ::= exp binop exp
@@ -1776,7 +1867,9 @@ the quotient towards minus infinity.
Lua provides automatic conversion between
string and number values at run time.
Any arithmetic operation applied to a string tries to convert
-this string to a number, following the usual conversion rules.
+this string to a number, following the rules of the Lua lexer.
+(The string may have leading and trailing spaces,
+plus an optional sign.)
Conversely, whenever a number is used where a string is expected,
the number is converted to a string, in a reasonable format.
For complete control over how numbers are converted to strings,
@@ -1802,8 +1895,8 @@ If the types are different, then the result is <b>false</b>.
Otherwise, the values of the operands are compared.
Numbers and strings are compared in the usual way.
Tables, userdata, and threads
-are compared by <em>reference</em>:
-two objects are considered equal only if they are the <em>same</em> object.
+are compared by reference:
+two objects are considered equal only if they are the same object.
Every time you create a new object
(a table, userdata, or thread),
this new object is different from any previously existing object.
@@ -1813,13 +1906,13 @@ Closures with any detectable difference
<p>
-You can change the way that Lua compares tables and userdata
+You can change the way that Lua compares tables and userdata
by using the "eq" metamethod (see <a href="#2.4">&sect;2.4</a>).
<p>
The conversion rules of <a href="#3.4.2">&sect;3.4.2</a>
-<em>do not</em> apply to equality comparisons.
+do not apply to equality comparisons.
Thus, <code>"0"==0</code> evaluates to <b>false</b>,
and <code>t[0]</code> and <code>t["0"]</code> denote different
entries in a table.
@@ -1902,25 +1995,27 @@ character is one byte).
<p>
-The length of a table <code>t</code> can be any integer index <code>n</code>
-such that <code>t[n]</code> is not <b>nil</b> and <code>t[n+1]</code> is <b>nil</b>;
-moreover, if <code>t[1]</code> is <b>nil</b>, <code>n</code> can be zero.
-(All accesses are assumed to be raw for this description.)
-For a regular array, where all non-nil values
-have keys from 1 to a given <code>n</code>,
-its length is exactly that <code>n</code>,
-the index of its last value.
-If the array has "holes"
-(that is, <b>nil</b> values between other non-nil values),
-then <code>#t</code> can be any of the indices that
-directly precedes a <b>nil</b> value
-(that is, it may consider any such <b>nil</b> value as the end of
-the array).
+The length of a table <code>t</code> is only defined if the
+table is a <em>sequence</em>,
+that is,
+all its numeric keys comprise the set <em>{1..n}</em> for some integer <em>n</em>.
+In that case, <em>n</em> is its length.
+Note that a table like
+
+<pre>
+ {10, 20, nil, 40}
+</pre><p>
+is not a sequence, because it has the key <code>4</code>
+but does not have the key <code>3</code>.
+(So, there is no <em>n</em> such that the set <em>{1..n}</em> is equal
+to the set of numeric keys of that table.)
+Note, however, that non-numeric keys do not interfere
+with whether a table is a sequence.
<p>
A program can modify the behavior of the length operator for
-any value but strings through metamethods (see <a href="#2.4">&sect;2.4</a>).
+any value but strings through the <code>__len</code> metamethod (see <a href="#2.4">&sect;2.4</a>).
@@ -1999,9 +2094,6 @@ If the last field in the list has the form <code>exp</code>
and the expression is a function call or a vararg expression,
then all values returned by this expression enter the list consecutively
(see <a href="#3.4.9">&sect;3.4.9</a>).
-To avoid this,
-enclose the function call or the vararg expression
-in parentheses (see <a href="#3.4">&sect;3.4</a>).
<p>
@@ -2060,7 +2152,7 @@ that is, the argument list is a single literal string.
<p>
-A call of the form <code>return</code> <em>functioncall</em> is called
+A call of the form <code>return <em>functioncall</em></code> is called
a <em>tail call</em>.
Lua implements <em>proper tail calls</em>
(or <em>proper tail recursion</em>):
@@ -2093,7 +2185,7 @@ So, none of the following examples are tail calls:
The syntax for function definition is
<pre>
- function ::= <b>function</b> funcbody
+ functiondef ::= <b>function</b> funcbody
funcbody ::= &lsquo;<b>(</b>&rsquo; [parlist] &lsquo;<b>)</b>&rsquo; block <b>end</b>
</pre>
@@ -2135,7 +2227,7 @@ translates to
<pre>
local f; f = function () <em>body</em> end
</pre><p>
-<em>not</em> to
+not to
<pre>
local f = function () <em>body</em> end
@@ -2153,8 +2245,6 @@ Then, whenever Lua executes the function definition,
the function is <em>instantiated</em> (or <em>closed</em>).
This function instance (or <em>closure</em>)
is the final value of the expression.
-Different instances of the same function
-can refer to different external local variables.
<p>
@@ -2249,9 +2339,9 @@ is syntactic sugar for
<p>
Lua is a lexically scoped language.
-The scope of variables begins at the first statement <em>after</em>
-their declaration and lasts until the end of the innermost block that
-includes the declaration.
+The scope of a local variable begins at the first statement after
+its declaration and lasts until the last non-void statement
+of the innermost block that includes the declaration.
Consider the following example:
<pre>
@@ -2356,9 +2446,9 @@ For convenience,
most query operations in the API do not follow a strict stack discipline.
Instead, they can refer to any element in the stack
by using an <em>index</em>:
-A positive index represents an <em>absolute</em> stack position
+A positive index represents an absolute stack position
(starting at&nbsp;1);
-a negative index represents an <em>offset</em> relative to the top of the stack.
+a negative index represents an offset relative to the top of the stack.
More specifically, if the stack has <em>n</em> elements,
then index&nbsp;1 represents the first element
(that is, the element that was pushed onto the stack first)
@@ -2594,7 +2684,7 @@ because its frame in the C stack was destroyed by the yield.
Instead, Lua calls a <em>continuation function</em>,
which was given as an argument to the callee function.
As the name implies,
-the continuation function should continue the task
+the continuation function should continue the task
of the original function.
@@ -2684,8 +2774,7 @@ is being allocated;
<p>
When <code>ptr</code> is not <code>NULL</code>,
-<code>osize</code> is the previous size of the block
-pointed by <code>ptr</code>,
+<code>osize</code> is the size of the block pointed by <code>ptr</code>,
that is, the size given when it was allocated or reallocated.
@@ -2705,18 +2794,14 @@ Lua assumes the following behavior from the allocator function:
<p>
-When <code>nsize</code> is zero:
-if <code>ptr</code> is not <code>NULL</code>,
-the allocator should free the block pointed to by <code>ptr</code>.
-Anyway, the allocator must return <code>NULL</code>.
+When <code>nsize</code> is zero,
+the allocator should behave like <code>free</code>
+and return <code>NULL</code>.
<p>
-When <code>nsize</code> is not zero:
-if <code>ptr</code> is <code>NULL</code>,
-the allocator should behave like <code>malloc</code>;
-when <code>ptr</code> is not <code>NULL</code>,
-the allocator behaves like <code>realloc</code>.
+When <code>nsize</code> is not zero,
+the allocator should behave like <code>realloc</code>.
The allocator returns <code>NULL</code>
if and only if it cannot fill the request.
Lua assumes that the allocator never fails when
@@ -2751,12 +2836,14 @@ but it seems a safe assumption.
<hr><h3><a name="lua_arith"><code>lua_arith</code></a></h3><p>
-<span class="apii">[-2, +1, <em>e</em>]</span>
+<span class="apii">[-(2/1), +1, <em>e</em>]</span>
<pre>int lua_arith (lua_State *L, int op);</pre>
<p>
-Performs an arithmetic operation over the two values at the top
-of the stack (with the value at the top being the second operand),
+Performs an arithmetic operation over the two values
+(or one, in the case of negation)
+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.
The function follows the semantics of the corresponding Lua operator
(that is, it may call metamethods).
@@ -2824,7 +2911,7 @@ when the function is called.
The function results are pushed onto the stack when the function returns.
The number of results is adjusted to <code>nresults</code>,
unless <code>nresults</code> is <a name="pdf-LUA_MULTRET"><code>LUA_MULTRET</code></a>.
-In this case, <em>all</em> results from the function are pushed.
+In this case, all results from the function are pushed.
Lua takes care that the returned values fit into the stack space.
The function results are pushed onto the stack in direct order
(the first result is pushed first),
@@ -3028,10 +3115,13 @@ without shifting any element
<p>
Creates a new empty table and pushes it onto the stack.
-The new table has space pre-allocated
-for <code>narr</code> array elements and <code>nrec</code> non-array elements.
-This pre-allocation is useful when you know exactly how many elements
+Parameter <code>narr</code> is a hint for how many elements the table
+will have as a sequence;
+parameter <code>nrec</code> is a hint for how many other elements
the table will have.
+Lua may use these hints to preallocate memory for the new table.
+This pre-allocation is useful for performance when you know in advance
+how many elements the table will have.
Otherwise you can use the function <a href="#lua_newtable"><code>lua_newtable</code></a>.
@@ -3147,6 +3237,11 @@ returns a boolean that tells whether the collector is running
</ul>
+<p>
+For more details about some options,
+see <a href="#pdf-collectgarbage"><code>collectgarbage</code></a>.
+
+
@@ -3655,7 +3750,7 @@ A typical traversal looks like this:
While traversing a table,
do not call <a href="#lua_tolstring"><code>lua_tolstring</code></a> directly on a key,
unless you know that the key is actually a string.
-Recall that <a href="#lua_tolstring"><code>lua_tolstring</code></a> <em>changes</em>
+Recall that <a href="#lua_tolstring"><code>lua_tolstring</code></a> may change
the value at the given index;
this confuses the next call to <a href="#lua_next"><code>lua_next</code></a>.
@@ -3683,7 +3778,7 @@ Lua to operate with another type for numbers (e.g., float or long).
<hr><h3><a name="lua_pcall"><code>lua_pcall</code></a></h3><p>
<span class="apii">[-(nargs + 1), +(nresults|1), <em>-</em>]</span>
-<pre>int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);</pre>
+<pre>int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);</pre>
<p>
Calls a function in protected mode.
@@ -3704,19 +3799,20 @@ and its arguments from the stack.
<p>
-If <code>errfunc</code> is 0,
+If <code>msgh</code> is 0,
then the error message returned on the stack
is exactly the original error message.
-Otherwise, <code>errfunc</code> is the stack index of an
-<em>error handler function</em>.
+Otherwise, <code>msgh</code> is the stack index of a
+<em>message handler</em>.
(In the current implementation, this index cannot be a pseudo-index.)
In case of runtime errors,
this function will be called with the error message
-and its return value will be the message returned on the stack by <a href="#lua_pcall"><code>lua_pcall</code></a>.
+and its return value will be the message
+returned on the stack by <a href="#lua_pcall"><code>lua_pcall</code></a>.
<p>
-Typically, the error handler function is used to add more debug
+Typically, the message handler is used to add more debug
information to the error message, such as a stack traceback.
Such information cannot be gathered after the return of <a href="#lua_pcall"><code>lua_pcall</code></a>,
since by then the stack has unwound.
@@ -3737,11 +3833,11 @@ a runtime error.
<li><b><a name="pdf-LUA_ERRMEM"><code>LUA_ERRMEM</code></a>:</b>
memory allocation error.
-For such errors, Lua does not call the error handler function.
+For such errors, Lua does not call the message handler.
</li>
<li><b><a name="pdf-LUA_ERRERR"><code>LUA_ERRERR</code></a>:</b>
-error while running the error handler function.
+error while running the message handler.
</li>
<li><b><a name="pdf-LUA_ERRGCMM"><code>LUA_ERRGCMM</code></a>:</b>
@@ -3944,7 +4040,8 @@ onto the stack.
Lua makes (or reuses) an internal copy of the given string,
so the memory at <code>s</code> can be freed or reused immediately after
the function returns.
-The string can contain embedded zeros.
+The string can contain any binary data,
+including embedded zeros.
<p>
@@ -3986,8 +4083,6 @@ onto the stack.
Lua makes (or reuses) an internal copy of the given string,
so the memory at <code>s</code> can be freed or reused immediately after
the function returns.
-The string should not contain embedded zeros;
-it is assumed to end at the first zero.
<p>
@@ -4249,14 +4344,11 @@ with user data <code>ud</code>.
<hr><h3><a name="lua_setuservalue"><code>lua_setuservalue</code></a></h3><p>
<span class="apii">[-1, +0, <em>-</em>]</span>
-<pre>int lua_setuservalue (lua_State *L, int index);</pre>
+<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
the new value associated to the userdata at the given index.
-If the value at the given index is not a userdata,
-<code>lua_setuservalue</code> returns 0.
-Otherwise it returns 1.
@@ -4296,7 +4388,7 @@ It is defined as a macro.
<hr><h3><a name="lua_setmetatable"><code>lua_setmetatable</code></a></h3><p>
<span class="apii">[-1, +0, <em>-</em>]</span>
-<pre>int lua_setmetatable (lua_State *L, int index);</pre>
+<pre>void lua_setmetatable (lua_State *L, int index);</pre>
<p>
Pops a table from the stack and
@@ -4716,7 +4808,7 @@ calling the writer again.
<pre>void lua_xmove (lua_State *from, lua_State *to, int n);</pre>
<p>
-Exchange values between different threads of the <em>same</em> global state.
+Exchange values between different threads of the same global state.
<p>
@@ -5033,17 +5125,14 @@ In the first case,
the parameter <code>ar</code> must be a valid activation record that was
filled by a previous call to <a href="#lua_getstack"><code>lua_getstack</code></a> or
given as argument to a hook (see <a href="#lua_Hook"><code>lua_Hook</code></a>).
-The index <code>n</code> selects which local variable to inspect
-(1 is the first parameter or active local variable, and so on,
-until the last active local variable).
-<a href="#lua_getlocal"><code>lua_getlocal</code></a> pushes the variable's value onto the stack
-and returns its name.
+The index <code>n</code> selects which local variable to inspect;
+see <a href="#pdf-debug.getlocal"><code>debug.getlocal</code></a> for details about variable indices
+and names.
<p>
-Variable names starting with '<code>(</code>' (open parentheses)
-represent internal variables
-(loop control variables, temporaries, and C&nbsp;function locals).
+<a href="#lua_getlocal"><code>lua_getlocal</code></a> pushes the variable's value onto the stack
+and returns its name.
<p>
@@ -5176,7 +5265,8 @@ before the function gets its arguments.
<li><b>The return hook:</b> is called when the interpreter returns from a function.
The hook is called just before Lua leaves the function.
-You have no access to the values to be returned by the function.
+There is no standard way to access the values
+to be returned by the function.
</li>
<li><b>The line hook:</b> is called when the interpreter is about to
@@ -5285,7 +5375,7 @@ refer to the <code>n2</code>-th upvalue of the Lua closure at index <code>fidx2<
The <em>auxiliary library</em> provides several convenient functions
to interface C with Lua.
-While the basic API provides the primitive functions for all
+While the basic API provides the primitive functions for all
interactions between C and Lua,
the auxiliary library provides higher-level functions for some
common tasks.
@@ -5816,15 +5906,28 @@ as <code>return luaL_error(<em>args</em>)</code>.
-<hr><h3><a name="luaL_findtable"><code>luaL_findtable</code></a></h3><p>
-<span class="apii">[-0, +1, <em>m</em>]</span>
-<pre>void luaL_findtable (lua_State *L, int idx, const char *fname);</pre>
+<hr><h3><a name="luaL_execresult"><code>luaL_execresult</code></a></h3><p>
+<span class="apii">[-0, +(1/3), <em>m</em>]</span>
+<pre>int luaL_execresult (lua_State *L, int stat);</pre>
<p>
-Ensures that the value <code>t[fname]</code>,
-where <code>t</code> is the value at the valid index <code>idx</code>,
-is a table,
-and pushes that table onto the stack.
+This function produces the return values for
+process-related functions in the standard library
+(<a href="#pdf-os.execute"><code>os.execute</code></a> and <a href="#pdf-io.close"><code>io.close</code></a>).
+
+
+
+
+
+<hr><h3><a name="luaL_fileresult"><code>luaL_fileresult</code></a></h3><p>
+<span class="apii">[-0, +(1/3), <em>m</em>]</span>
+<pre>int luaL_fileresult (lua_State *L, int stat,
+ const char *fname)</pre>
+
+<p>
+This function produces the return values for
+file-related functions in the standard library
+(<a href="#pdf-io.open"><code>io.open</code></a>, <a href="#pdf-os.rename"><code>os.rename</code></a>, <a href="#pdf-file:seek"><code>file:seek</code></a>, etc.).
@@ -5857,6 +5960,22 @@ in the registry (see <a href="#luaL_newmetatable"><code>luaL_newmetatable</code>
+<hr><h3><a name="luaL_getsubtable"><code>luaL_getsubtable</code></a></h3><p>
+<span class="apii">[-0, +1, <em>m</em>]</span>
+<pre>int luaL_getsubtable (lua_State *L, int idx, const char *fname);</pre>
+
+<p>
+Ensures that the value <code>t[fname]</code>,
+where <code>t</code> is the value at the valid index <code>idx</code>,
+is a table,
+and pushes that table onto the stack.
+Returns true if it finds a previous table there
+and false if it creates a new table.
+
+
+
+
+
<hr><h3><a name="luaL_gsub"><code>luaL_gsub</code></a></h3><p>
<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>const char *luaL_gsub (lua_State *L,
@@ -5965,13 +6084,27 @@ it does not run it.
<pre>int luaL_newlib (lua_State *L, const luaL_Reg *l);</pre>
<p>
-Equivalent to <a href="#luaL_setfuncs"><code>luaL_setfuncs</code></a> with no upvalues,
-but first creates a new table wherein to register the functions
-in list <code>l</code>.
+Creates a new table and registers there
+the functions in list <code>l</code>.
+It is implemented as the following macro:
+
+<pre>
+ (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
+</pre>
+
+
+
+<hr><h3><a name="luaL_newlibtable"><code>luaL_newlibtable</code></a></h3><p>
+<span class="apii">[-0, +1, <em>m</em>]</span>
+<pre>int luaL_newlibtable (lua_State *L, const luaL_Reg *l);</pre>
<p>
-Leaves the new table on the stack.
+Creates a new table with a size optimized
+to store all entries in the array <code>l</code>
+(but does not actually store them).
+It is intended to be used in conjunction with <a href="#luaL_setfuncs"><code>luaL_setfuncs</code></a>
+(see <a href="#luaL_newlib"><code>luaL_newlib</code></a>).
<p>
@@ -6176,7 +6309,7 @@ Returns an address to a space of size <code>sz</code>
where you can copy a string to be added to buffer <code>B</code>
(see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>).
After copying the string into this space you must call
-<a href="#luaL_addsize"><code>luaL_addsize</code></a> with the size of the string to actually add
+<a href="#luaL_addsize"><code>luaL_addsize</code></a> with the size of the string to actually add
it to the buffer.
@@ -6284,8 +6417,6 @@ Leaves a copy of that result on the stack.
Registers all functions in the array <code>l</code>
(see <a href="#luaL_Reg"><code>luaL_Reg</code></a>) into the table on the top of the stack
(below optional upvalues, see next).
-The pointer <code>l</code> may be <code>NULL</code>,
-representing an empty list.
<p>
@@ -6495,7 +6626,7 @@ e.g., by using <a href="#lua_call"><code>lua_call</code></a>.
<p>
The basic library provides some core functions to Lua.
If you do not include this library in your application,
-you should check carefully whether you need to provide
+you should check carefully whether you need to provide
implementations for some of its facilities.
@@ -6526,11 +6657,13 @@ This is the default option.
</li>
<li><b>"stop":</b>
-stops the garbage collector.
+stops automatic invocation of the garbage collector.
+The collector will run only when explcitly invoked,
+until a call to restart it.
</li>
<li><b>"restart":</b>
-restarts the garbage collector.
+restarts automatic invocation the garbage collector.
</li>
<li><b>"count":</b>
@@ -6543,6 +6676,8 @@ so the following equality is always true:
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.)
</li>
<li><b>"step":</b>
@@ -6658,7 +6793,7 @@ up to the first integer key absent from the table.
<p>
-<hr><h3><a name="pdf-load"><code>load (ld [, source [, mode]])</code></a></h3>
+<hr><h3><a name="pdf-load"><code>load (ld [, source [, mode [, env]]])</code></a></h3>
<p>
@@ -6666,32 +6801,35 @@ Loads a chunk.
<p>
+If <code>ld</code> is a string, the chunk is this string.
If <code>ld</code> is a function,
-calls it repeatedly to get the chunk pieces.
+<code>load</code> calls it repeatedly to get the chunk pieces.
Each call to <code>ld</code> must return a string that concatenates
with previous results.
A return of an empty string, <b>nil</b>, or no value signals the end of the chunk.
<p>
-If <code>ld</code> is a string, the chunk is this string.
+If there are no errors,
+returns the compiled chunk as a function;
+otherwise, returns <b>nil</b> plus the error message.
<p>
-If there are no errors,
-returns the compiled chunk as a function;
-otherwise, returns <b>nil</b> plus the error message.
If the resulting function has upvalues,
-the first upvalue is set to the value of the global environment
+the first upvalue is set to the value of the
+global environment or to <code>env</code>,
+if that parameter is given.
(When loading main chunks,
-this upvalue will be the <code>_ENV</code> variable (see <a href="#2.2">&sect;2.2</a>).)
+the first upvalue will be the <code>_ENV</code> variable (see <a href="#2.2">&sect;2.2</a>).)
<p>
<code>source</code> is used as the source of the chunk for error messages
and debug information (see <a href="#4.9">&sect;4.9</a>).
When absent,
-it defaults to "<code>=(load)</code>".
+it defaults to <code>ld</code>, if <code>ld</code> is a string,
+or to "<code>=(load)</code>".
<p>
@@ -6705,21 +6843,6 @@ The default is "<code>bt</code>".
<p>
-<hr><h3><a name="pdf-loadin"><code>loadin (env, ...)</code></a></h3>
-
-
-<p>
-This function is similar to <a href="#pdf-load"><code>load</code></a>,
-but sets <code>env</code> as the value of the first upvalue
-of the created function in case of success.
-(When loading main chunks,
-this upvalue will be the <code>_ENV</code> variable (see <a href="#2.2">&sect;2.2</a>).)
-The parameters after <code>env</code> are similar to those of <a href="#pdf-load"><code>load</code></a>, too.
-
-
-
-
-<p>
<hr><h3><a name="pdf-loadfile"><code>loadfile ([filename])</code></a></h3>
@@ -6733,29 +6856,6 @@ if no file name is given.
<p>
-<hr><h3><a name="pdf-loadstring"><code>loadstring (string [, chunkname])</code></a></h3>
-
-
-<p>
-Similar to <a href="#pdf-load"><code>load</code></a>,
-but gets the chunk from the given string.
-
-
-<p>
-To load and run a given string, use the idiom
-
-<pre>
- assert(loadstring(s))()
-</pre>
-
-<p>
-When absent,
-<code>chunkname</code> defaults to the given string.
-
-
-
-
-<p>
<hr><h3><a name="pdf-next"><code>next (table [, index])</code></a></h3>
@@ -6784,7 +6884,7 @@ use a numerical <b>for</b>.)
<p>
-The behavior of <code>next</code> is <em>undefined</em> if,
+The behavior of <code>next</code> is undefined if,
during the traversal,
you assign any value to a non-existent field in the table.
You may however modify existing fields.
@@ -6873,6 +6973,16 @@ without invoking any metamethod.
<p>
+<hr><h3><a name="pdf-rawlen"><code>rawlen (v)</code></a></h3>
+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.
+
+
+
+
+<p>
<hr><h3><a name="pdf-rawset"><code>rawset (table, index, value)</code></a></h3>
Sets the real value of <code>table[index]</code> to <code>value</code>,
without invoking any metamethod.
@@ -6934,9 +7044,9 @@ The base may be any integer between 2 and 36, inclusive.
In bases above&nbsp;10, the letter '<code>A</code>' (in either upper or lower case)
represents&nbsp;10, '<code>B</code>' represents&nbsp;11, and so forth,
with '<code>Z</code>' representing 35.
-In base 10 (the default), the number can have a decimal part,
-as well as an optional exponent part (see <a href="#3.1">&sect;3.1</a>).
-In other bases, only unsigned integers are accepted.
+In base 10 (the default),
+the numeral is converted following the coercion rules (see <a href="#3.4.2">&sect;3.4.2</a>).
+In other bases, only integers are accepted.
@@ -6984,12 +7094,12 @@ The current contents of this variable is "<code>Lua 5.2</code>".
<p>
-<hr><h3><a name="pdf-xpcall"><code>xpcall (f, err [, arg1, &middot;&middot;&middot;])</code></a></h3>
+<hr><h3><a name="pdf-xpcall"><code>xpcall (f, msgh [, arg1, &middot;&middot;&middot;])</code></a></h3>
<p>
This function is similar to <a href="#pdf-pcall"><code>pcall</code></a>,
-except that it sets a new error handler <code>err</code>.
+except that it sets a new message handler <code>msgh</code>.
@@ -7130,8 +7240,8 @@ Otherwise, it tries to find a <em>loader</em> for the module.
<p>
To find a loader,
-<code>require</code> is guided by the <a href="#pdf-package.loaders"><code>package.loaders</code></a> array.
-By changing this array,
+<code>require</code> is guided by the <a href="#pdf-package.loaders"><code>package.loaders</code></a> sequence.
+By changing this sequence,
we can change how <code>require</code> looks for a module.
The following explanation is based on the default configuration
for <a href="#pdf-package.loaders"><code>package.loaders</code></a>.
@@ -7151,7 +7261,10 @@ it tries an <em>all-in-one</em> loader (see <a href="#pdf-package.loaders"><code
<p>
Once a loader is found,
-<code>require</code> calls the loader with a single argument, <code>modname</code>.
+<code>require</code> calls the loader with two arguments:
+<code>modname</code> and an extra value dependent on how it got the loader.
+(If the loader came from a file,
+this extra value is the file name.)
If the loader returns any non-nil value,
<code>require</code> assigns the returned value to <code>package.loaded[modname]</code>.
If the loader does not return a non-nil value and
@@ -7164,7 +7277,7 @@ final value of <code>package.loaded[modname]</code>.
<p>
If there is any error loading or running the module,
or if it cannot find any loader for the module,
-then <code>require</code> signals an error.
+then <code>require</code> signals an error.
@@ -7255,9 +7368,13 @@ When looking for a module,
with the module name (the argument given to <a href="#pdf-require"><code>require</code></a>) as its
sole parameter.
The function can return another function (the module <em>loader</em>)
+plus an extra value that will be passed to that loader,
or a string explaining why it did not find that module
(or <b>nil</b> if it has nothing to say).
-Lua initializes this table with four functions.
+
+
+<p>
+Lua initializes this table with four searcher functions.
<p>
@@ -7313,6 +7430,13 @@ into one single library,
with each submodule keeping its original open function.
+<p>
+All searchers except the first (preload) return as the extra value
+the file name where the module was found,
+as returned by <a href="#pdf-package.searchpath"><code>package.searchpath</code></a>.
+The first searcher returns no extra value.
+
+
<p>
@@ -7384,10 +7508,16 @@ A table to store loaders for specific modules
(see <a href="#pdf-require"><code>require</code></a>).
+<p>
+This variable is only a reference to the real table;
+assignments to this variable do not change the
+table used by <a href="#pdf-require"><code>require</code></a>.
+
+
<p>
-<hr><h3><a name="pdf-package.searchpath"><code>package.searchpath (name, path)</code></a></h3>
+<hr><h3><a name="pdf-package.searchpath"><code>package.searchpath (name, path [, sep])</code></a></h3>
<p>
@@ -7400,8 +7530,15 @@ A path is string containing a sequence of
For each template,
the function changes each interrogation
mark in the template by a copy of <code>name</code>
-wherein all dots were replaced by the system's directory separator,
+wherein all occurrences of <code>sep</code>
+(a dot, by default)
+were replaced by the system's directory separator,
and then tries to open the resulting file name.
+If <code>sep</code> is the empty string,
+the replacement is not done.
+
+
+<p>
For instance, if the path is the string
<pre>
@@ -7485,9 +7622,8 @@ Note that numerical codes are not necessarily portable across platforms.
<p>
Returns a string containing a binary representation of the given function,
-so that a later <a href="#pdf-loadstring"><code>loadstring</code></a> on this string returns
-a copy of the function.
-<code>function</code> must be a Lua function without upvalues.
+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).
@@ -7552,16 +7688,19 @@ will produce the string:
</pre>
<p>
-The options <code>c</code>, <code>d</code>, <code>E</code>, <code>e</code>, <code>f</code>,
-<code>g</code>, <code>G</code>, <code>i</code>, <code>o</code>, <code>u</code>, <code>X</code>, and <code>x</code> all
-expect a number as argument,
-whereas <code>q</code> and <code>s</code> expect a string.
-
-
-<p>
-This function does not accept string values
-containing embedded zeros,
-except as arguments to the <code>q</code> option.
+Options
+<code>A</code> and <code>a</code> (when available),
+<code>E</code>, <code>e</code>, <code>f</code>,
+<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>
+expect an integer as argument;
+the range of that integer may be limited by
+the underlying C&nbsp;implementation.
+Option <code>q</code> expects a string
+and <code>s</code> expects a string without embedded zeros.
+If the argument to option <code>s</code> is not a string,
+it is converted to one following the same rules of <a href="#pdf-tostring"><code>tostring</code></a>.
@@ -7577,6 +7716,8 @@ then the whole match is produced in each call.
<p>
As an example, the following loop
+will iterate over all the words from string <code>s</code>,
+printing one per line:
<pre>
s = "hello world from Lua"
@@ -7584,8 +7725,6 @@ As an example, the following loop
print(w)
end
</pre><p>
-will iterate over all the words from string <code>s</code>,
-printing one per line.
The next example collects all pairs <code>key=value</code> from the
given string into a table:
@@ -7667,7 +7806,7 @@ Here are some examples:
--&gt; x="home = /home/roberto, user = roberto"
x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
- return loadstring(s)()
+ return load(s)()
end)
--&gt; x="4+5 = 9"
@@ -7715,9 +7854,11 @@ its default value is&nbsp;1 and can be negative.
<p>
-<hr><h3><a name="pdf-string.rep"><code>string.rep (s, n)</code></a></h3>
+<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>.
+the string <code>s</code> separated by the string <code>sep</code>.
+The default value for <code>sep</code> is the empty string
+(that is, no separator).
@@ -7867,7 +8008,7 @@ These repetition items will always match the longest possible sequence;
a single character class followed by '<code>-</code>',
which also matches 0 or more repetitions of characters in the class.
Unlike '<code>*</code>',
-these repetition items will always match the <em>shortest</em> possible sequence;
+these repetition items will always match the shortest possible sequence;
</li>
<li>
@@ -7949,41 +8090,55 @@ string <code>"flaaap"</code>, there will be two captures: 3&nbsp;and&nbsp;5.
-<h2>6.5 &ndash; <a name="6.5">Table Manipulation</a></h2><p>
+<h2>6.5 &ndash; <a name="6.5">Table Manipulation</a></h2>
+
+<p>
This library provides generic functions for table manipulation.
It provides all its functions inside the table <a name="pdf-table"><code>table</code></a>.
<p>
-Most functions in the table library assume that the table
-represents an array or a list.
-For these functions, when we talk about the "length" of a table
-we mean the result of the length operator.
+Currently, all functions in the table library assume that the table
+represents a list.
+In particular, they all ignore non-numeric keys
+in tables given as arguments.
+All functions in the table library,
+except <a href="#pdf-table.pack"><code>table.pack</code></a>,
+may apply the length operator on the list.
+In that case, the list must be a proper sequence
+or have a <code>__len</code> metamethod (see <a href="#3.4.6">&sect;3.4.6</a>).
+
+
+<p>
+For performance reasons,
+all table accesses (get/set) performed by these functions are raw.
+
+
+<p>
+<hr><h3><a name="pdf-table.concat"><code>table.concat (list [, sep [, i [, j]]])</code></a></h3>
<p>
-<hr><h3><a name="pdf-table.concat"><code>table.concat (table [, sep [, i [, j]]])</code></a></h3>
-Given an array where all elements are strings or numbers,
-returns <code>table[i]..sep..table[i+1] &middot;&middot;&middot; sep..table[j]</code>.
+Given a list where all elements are strings or numbers,
+returns <code>list[i]..sep..list[i+1] &middot;&middot;&middot; sep..list[j]</code>.
The default value for <code>sep</code> is the empty string,
the default for <code>i</code> is 1,
-and the default for <code>j</code> is the length of the table.
+and the default for <code>j</code> is <code>#list</code>.
If <code>i</code> is greater than <code>j</code>, returns the empty string.
<p>
-<hr><h3><a name="pdf-table.insert"><code>table.insert (table, [pos,] value)</code></a></h3>
+<hr><h3><a name="pdf-table.insert"><code>table.insert (list, [pos,] value)</code></a></h3>
<p>
-Inserts element <code>value</code> at position <code>pos</code> in <code>table</code>,
+Inserts element <code>value</code> at position <code>pos</code> in <code>list</code>,
shifting up other elements to open space, if necessary.
-The default value for <code>pos</code> is <code>n+1</code>,
-where <code>n</code> is the length of the table (see <a href="#3.4.6">&sect;3.4.6</a>),
+The default value for <code>pos</code> is <code>#list+1</code>,
so that a call <code>table.insert(t,x)</code> inserts <code>x</code> at the end
-of table <code>t</code>.
+of list <code>t</code>.
@@ -7993,36 +8148,38 @@ of table <code>t</code>.
<p>
-Returns a new table with all parameters stored into
-keys 1, 2, etc.
+Returns a new table with all parameters stored into keys 1, 2, etc.
and with a field "<code>n</code>" with the total number of parameters.
+Note that the result may not be a sequence,
+if any parameter is <b>nil</b>.
<p>
-<hr><h3><a name="pdf-table.remove"><code>table.remove (table [, pos])</code></a></h3>
+<hr><h3><a name="pdf-table.remove"><code>table.remove (list [, pos])</code></a></h3>
<p>
-Removes from <code>table</code> the element at position <code>pos</code>,
+Removes from <code>list</code> the element at position <code>pos</code>,
shifting down other elements to close the space, if necessary.
Returns the value of the removed element.
-The default value for <code>pos</code> is <code>n</code>,
-where <code>n</code> is the length of the table,
+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 table <code>t</code>.
+of list <code>t</code>.
<p>
-<hr><h3><a name="pdf-table.sort"><code>table.sort (table [, comp])</code></a></h3>
-Sorts table elements in a given order, <em>in-place</em>,
-from <code>table[1]</code> to <code>table[n]</code>,
-where <code>n</code> is the length of the table.
+<hr><h3><a name="pdf-table.sort"><code>table.sort (list [, comp])</code></a></h3>
+
+
+<p>
+Sorts list elements in a given order, <em>in-place</em>,
+from <code>table[1]</code> to <code>table[#list]</code>.
If <code>comp</code> is given,
-then it must be a function that receives two table elements
+then it must be a function that receives two list elements
and returns true when the first element must come
before the second in the final order
(so that <code>not comp(a[i+1],a[i])</code> will be true after the sort).
@@ -8040,16 +8197,16 @@ may have their relative positions changed by the sort.
<p>
<hr><h3><a name="pdf-table.unpack"><code>table.unpack (list [, i [, j]])</code></a></h3>
+
+
+<p>
Returns the elements from the given table.
This function is equivalent to
<pre>
return list[i], list[i+1], &middot;&middot;&middot;, list[j]
</pre><p>
-except that the above code can be written only for a fixed number
-of elements.
-By default, <code>i</code> is&nbsp;1 and <code>j</code> is the length of the list,
-as defined by the length operator (see <a href="#3.4.6">&sect;3.4.6</a>).
+By default, <code>i</code> is&nbsp;1 and <code>j</code> is <code>#list</code>.
@@ -8386,7 +8543,7 @@ Returns the hyperbolic tangent of <code>x</code>.
-<h2>6.7 &ndash; <a name="6.7">Bitwise operations</a></h2>
+<h2>6.7 &ndash; <a name="6.7">Bitwise Operations</a></h2>
<p>
This library provides bitwise operations.
@@ -8468,7 +8625,7 @@ Returns the bitwise or of its operands.
<p>
-Returns a boolean signaling
+Returns a boolean signaling
whether the bitwise and of its operands is different from zero.
@@ -8485,6 +8642,32 @@ Returns the bitwise exclusive or 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>
+<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>
@@ -8723,6 +8906,11 @@ Similar to <a href="#pdf-io.input"><code>io.input</code></a>, but operates over
<p>
+This function is system dependent and is not available
+on all platforms.
+
+
+<p>
Starts program <code>prog</code> in a separated process and returns
a file handle that you can use to read data from this program
(if <code>mode</code> is <code>"r"</code>, the default)
@@ -8730,11 +8918,6 @@ or to write data to this program
(if <code>mode</code> is <code>"w"</code>).
-<p>
-This function is system dependent and is not available
-on all platforms.
-
-
<p>
@@ -8794,8 +8977,9 @@ but that takes an unpredictable amount of time to happen.
<p>
-If <code>file</code> was created with <a href="#pdf-io.popen"><code>io.popen</code></a>,
-a successful close returns the exit status of the process.
+When closing a file handle created with <a href="#pdf-io.popen"><code>io.popen</code></a>,
+<a href="#pdf-file:close"><code>file:close</code></a> returns the same values
+returned by <a href="#pdf-os.execute"><code>os.execute</code></a>.
@@ -9020,6 +9204,8 @@ then <code>date</code> returns a table with the following fields:
<code>wday</code> (weekday, Sunday is&nbsp;1),
<code>yday</code> (day of the year),
and <code>isdst</code> (daylight saving flag, a boolean).
+This last field may be absent
+if the information is not available.
<p>
@@ -9056,9 +9242,28 @@ this value is exactly <code>t2</code><em>-</em><code>t1</code>.
<p>
This function is equivalent to the C&nbsp;function <code>system</code>.
It passes <code>command</code> to be executed by an operating system shell.
-It returns a status code, which is system-dependent.
-If <code>command</code> is absent, then it returns nonzero if a shell is available
-and zero otherwise.
+It returns <b>true</b>
+if the command terminated successfully.
+Otherwise, it returns <b>nil</b> plus a string and a number,
+as follows:
+
+<ul>
+
+<li><b>"<code>exit</code>":</b>
+the command terminated normally;
+the following number is the exit status of the command.
+</li>
+
+<li><b>"<code>signal</code>":</b>
+the command was terminated by a signal;
+the following number is the signal that terminated the command.
+</li>
+
+</ul>
+
+<p>
+When called without a <code>command</code>,
+<code>os.execute</code> returns a boolean that is true if a shell is available.
@@ -9072,10 +9277,10 @@ Calls the C&nbsp;function <code>exit</code> to terminate the host program.
If <code>code</code> is <b>true</b>,
the returned status is <code>EXIT_SUCCESS</code>;
if <code>code</code> is <b>false</b>,
-the returned status is <code>EXIT_FAILURE</code>.
+the returned status is <code>EXIT_FAILURE</code>;
if <code>code</code> is a number,
the returned status is this number.
-The default value for <code>code</code> is the success code.
+The default value for <code>code</code> is <b>true</b>.
<p>
@@ -9101,8 +9306,8 @@ or <b>nil</b> if the variable is not defined.
<p>
-Deletes the file or directory with the given name.
-Directories must be empty to be removed.
+Deletes the file (or empty directory, on POSIX systems)
+with the given name.
If this function fails, it returns <b>nil</b>,
plus a string describing the error.
@@ -9165,7 +9370,8 @@ and may have fields <code>hour</code>, <code>min</code>, <code>sec</code>, and <
<p>
The returned value is a number, whose meaning depends on your system.
-In POSIX, Windows, and some other systems, this number counts the number
+In POSIX, Windows, and some other systems,
+this number counts the number
of seconds since some given start time (the "epoch").
In other systems, the meaning is not specified,
and the number returned by <code>time</code> can be used only as an argument to
@@ -9186,7 +9392,7 @@ and explicitly removed when no longer needed.
<p>
-On some systems (POSIX),
+On POSIX systems,
this function also creates a file with that name,
to avoid security risks.
(Someone else might create the file with wrong permissions
@@ -9327,10 +9533,16 @@ about the <a href="#pdf-print"><code>print</code></a> function.
<p>
This function returns the name and the value of the local variable
with index <code>local</code> of the function at level <code>f</code> of the stack.
-(The first parameter or local variable has index&nbsp;1, and so on,
-until the last active local variable.)
-The function returns <b>nil</b> if there is no local
-variable with the given index,
+This function accesses not only explicit local variables,
+but also parameters, temporaries, etc.
+
+
+<p>
+The first parameter or local variable has index&nbsp;1, and so on,
+until the last active variable.
+Negative indices refer to vararg parameters;
+-1 is the first vararg parameter.
+The function returns <b>nil</b> if there is no variable with the given index,
and raises an error when called with a level out of range.
(You can call <a href="#pdf-debug.getinfo"><code>debug.getinfo</code></a> to check whether the level is valid.)
@@ -9338,7 +9550,7 @@ and raises an error when called with a level out of range.
<p>
Variable names starting with '<code>(</code>' (open parentheses)
represent internal variables
-(loop control variables, temporaries, and C&nbsp;function locals).
+(loop control variables, temporaries, varargs, and C&nbsp;function locals).
<p>
@@ -9454,6 +9666,11 @@ and raises an error when called with a <code>level</code> out of range.
Otherwise, it returns the name of the local variable.
+<p>
+See <a href="#pdf-debug.getlocal"><code>debug.getlocal</code></a> for more information about
+variable indices and names.
+
+
<p>
@@ -9463,6 +9680,7 @@ Otherwise, it returns the name of the local variable.
<p>
Sets the metatable for the given <code>object</code> to the given <code>table</code>
(which can be <b>nil</b>).
+Returns <code>object</code>.
@@ -9482,14 +9700,14 @@ Otherwise, it returns the name of the upvalue.
<p>
-<hr><h3><a name="pdf-debug.traceback"><code>debug.traceback ([thread,] [message] [, level])</code></a></h3>
+<hr><h3><a name="pdf-debug.traceback"><code>debug.traceback ([thread,] [message [, level]])</code></a></h3>
<p>
-If <code>message</code> is present but is not a string,
+If <code>message</code> is present but is neither a string nor <b>nil</b>,
this function returns <code>message</code> without further processing.
Otherwise,
-returns a string with a traceback of the call stack.
+it returns a string with a traceback of the call stack.
An optional <code>message</code> string is appended
at the beginning of the traceback.
An optional <code>level</code> number tells at which level
@@ -9636,6 +9854,14 @@ the interpreter does not report the error.
<p>
+When finishing normally,
+the interpreter closes its main Lua state
+(see <a href="#lua_close"><code>lua_close</code></a>).
+The script can avoid this step by terminating
+through <a href="#pdf-os.exit"><code>os.exit</code></a>.
+
+
+<p>
If the global variable <a name="pdf-_PROMPT"><code>_PROMPT</code></a> contains a string,
then its value is used as the prompt.
Similarly, if the global variable <a name="pdf-_PROMPT2"><code>_PROMPT2</code></a> contains a string,
@@ -9671,12 +9897,12 @@ as in
(Of course,
the location of the Lua interpreter can be different in your machine.
If <code>lua</code> is in your <code>PATH</code>,
-then
+then
<pre>
#!/usr/bin/env lua
</pre><p>
-is a more portable solution.)
+is a more portable solution.)
@@ -9696,21 +9922,38 @@ all these compatibility options will be removed in the next version of Lua.
<ul>
<li>
-Lua identifiers cannot use locale-dependent letters.
+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>.
+
+
+<p>
+C functions do not have environments any more.
+Use an upvalue with a shared table if you need to keep
+shared state among several C functions.
+(You may use <a href="#luaL_setfuncs"><code>luaL_setfuncs</code></a> to open a C library
+with all functions sharing a common upvalue.)
+
+
+<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>
-Doing a step in the garbage collector does not restart the collector
-if it has been stopped.
+Lua identifiers cannot use locale-dependent letters.
</li>
<li>
-Weak tables with weak keys now perform like <em>ephemeron tables</em>.
+Doing a step or a full collection in the garbage collector
+does not restart the collector if it has been stopped.
</li>
<li>
-Threads do not have individual environments.
-All threads share a single fixed environment.
+Weak tables with weak keys now perform like <em>ephemeron tables</em>.
</li>
<li>
@@ -9720,6 +9963,13 @@ Instead, tail calls generate a special new event,
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>
@@ -9735,9 +9985,8 @@ and it is easy to set up a module with regular Lua code.
</li>
<li>
-Functions <code>setfenv</code> and <code>getfenv</code> are deprecated.
-To set the environment of a Lua function,
-use the variable <code>_ENV</code> or the new function <a href="#pdf-loadin"><code>loadin</code></a>.
+Functions <code>setfenv</code> and <code>getfenv</code> are deprecated,
+because of the changes in environments.
</li>
<li>
@@ -9746,11 +9995,23 @@ Use <a href="#pdf-math.log"><code>math.log</code></a> with 10 as its second argu
</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>
@@ -9763,7 +10024,7 @@ as now patterns may contain '<code>\0</code>' as a regular character.
<li>
Lua does not have bytecode verification anymore.
So, all functions that load code
-(<a href="#pdf-load"><code>load</code></a>, <a href="#pdf-loadfile"><code>loadfile</code></a>, <a href="#pdf-loadstring"><code>loadstring</code></a>)
+(<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 bugs in the verification algorithm.)
@@ -9789,19 +10050,8 @@ You must get the global environment from the registry
<li>
Pseudoindex <code>LUA_ENVIRONINDEX</code>
and functions <code>lua_getfenv</code>/<code>lua_setfenv</code>
-were removed.
-C functions do not have environments any more.
-Use an upvalue with a shared table if you need to keep
-shared state among several C functions.
-(You may use <a href="#luaL_setfuncs"><code>luaL_setfuncs</code></a> to open a C library
-with all functions sharing a common upvalue.)
-
-
-<p>
-To manipulate the "environment" of a userdata
-(which is not called "environment" anymore),
-use the new functions
-<a href="#lua_getuservalue"><code>lua_getuservalue</code></a> and <a href="#lua_setuservalue"><code>lua_setuservalue</code></a>.
+were removed,
+as C&nbsp;functions do not have environments any more.
</li>
<li>
@@ -9812,12 +10062,21 @@ create globals anymore.
</li>
<li>
-Finalizers ("<code>__gc</code>" metamethods) for userdata are called in the
+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,
not that they were created (see <a href="#2.5.1">&sect;2.5.1</a>).
(Most userdata are marked immediately after they are created.)
Moreover,
-if the metatable does not have a "<code>__gc</code>" field when set,
+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>
@@ -9860,11 +10119,14 @@ Here is the complete syntax of Lua in extended BNF.
chunk ::= block
- block ::= {stat} [laststat [&lsquo;<b>;</b>&rsquo;]]
+ block ::= {stat} [retstat]
stat ::= &lsquo;<b>;</b>&rsquo; |
varlist &lsquo;<b>=</b>&rsquo; explist |
functioncall |
+ label |
+ <b>break</b> |
+ <b>goto</b> Name |
<b>do</b> block <b>end</b> |
<b>while</b> exp <b>do</b> block <b>end</b> |
<b>repeat</b> block <b>until</b> exp |
@@ -9875,7 +10137,9 @@ Here is the complete syntax of Lua in extended BNF.
<b>local</b> <b>function</b> Name funcbody |
<b>local</b> namelist [&lsquo;<b>=</b>&rsquo; explist]
- laststat ::= <b>return</b> [explist] | <b>break</b>
+ retstat ::= <b>return</b> [explist] [&lsquo;<b>;</b>&rsquo;]
+
+ label ::= &lsquo;<b>@</b>&rsquo; Name &lsquo;<b>:</b>&rsquo;
funcname ::= Name {&lsquo;<b>.</b>&rsquo; Name} [&lsquo;<b>:</b>&rsquo; Name]
@@ -9885,7 +10149,7 @@ Here is the complete syntax of Lua in extended BNF.
namelist ::= Name {&lsquo;<b>,</b>&rsquo; Name}
- explist ::= {exp &lsquo;<b>,</b>&rsquo;} exp
+ explist ::= exp {&lsquo;<b>,</b>&rsquo; exp}
exp ::= <b>nil</b> | <b>false</b> | <b>true</b> | Number | String | &lsquo;<b>...</b>&rsquo; | function |
prefixexp | tableconstructor | exp binop exp | unop exp
@@ -9896,7 +10160,7 @@ Here is the complete syntax of Lua in extended BNF.
args ::= &lsquo;<b>(</b>&rsquo; [explist] &lsquo;<b>)</b>&rsquo; | tableconstructor | String
- function ::= <b>function</b> funcbody
+ functiondef ::= <b>function</b> funcbody
funcbody ::= &lsquo;<b>(</b>&rsquo; [parlist] &lsquo;<b>)</b>&rsquo; block <b>end</b>
@@ -9929,10 +10193,10 @@ Here is the complete syntax of Lua in extended BNF.
<HR>
<SMALL>
Last update:
-Mon Nov 22 16:36:19 BRST 2010
+Mon Jun 13 14:56:14 BRT 2011
</SMALL>
<!--
-Last change: revised for Lua 5.2.0 (alpha)
+Last change: revised for Lua 5.2.0 (beta)
-->
</body></html>
diff --git a/doc/readme.html b/doc/readme.html
index 411d7605..a437ea17 100644
--- a/doc/readme.html
+++ b/doc/readme.html
@@ -27,12 +27,12 @@ tt, kbd, code {
<HR>
<H1>
<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua" BORDER=0></A>
-Welcome to Lua 5.2 (alpha)
+Welcome to Lua 5.2 (beta)
</H1>
<P>
<IMG SRC="alert.png" ALIGN="absbottom" ALT="[!]">
-<EM>This is an alpha version of Lua 5.2.
+<EM>This is a beta version of Lua 5.2.
Some details may change in the final version.</EM>
<P>
@@ -278,11 +278,13 @@ lists the
<H3>Main changes</H3>
<UL>
<LI> yieldable pcall and metamethods
-<LI> new <CODE>_ENV</CODE> scheme
+<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
</UL>
Here are the other changes introduced in Lua 5.2:
@@ -291,29 +293,34 @@ Here are the other changes introduced in Lua 5.2:
<LI> no more fenv for threads or functions
<LI> tables honor the <CODE>__len</CODE> metamethod
<LI> hex and <CODE>\*</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
</UL>
<H3>Libraries</H3>
<UL>
-<LI> new metamethods <CODE>__pairs</CODE> and <CODE>__ipairs</CODE>
<LI> arguments for function called through <CODE>xpcall</CODE>
<LI> optional 'mode' argument to load (to control binary x text)
-<LI> new function <CODE>loadin</CODE>
+<LI> optional 'env' argument to load (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
</UL>
<H3>C API</H3>
@@ -321,7 +328,7 @@ Here are the other changes introduced in Lua 5.2:
<LI> main thread predefined in the registry
<LI> new constants <CODE>LUA_OK</CODE> and <CODE>LUA_ERRGCMM</CODE>
<LI> new <CODE>lua_compare</CODE>, <CODE>lua_arith</CODE>, and <CODE>lua_len</CODE>
-<LI> new <CODE>lua_version</CODE> and <CODE>luaL_version</CODE>
+<LI> new <CODE>lua_version</CODE> and <CODE>luaL_checkversion</CODE>
<LI> <CODE>lua_pushstring</CODE> and <CODE>pushlstring</CODE> return string
<LI> new <CODE>luaL_testudata</CODE> and <CODE>luaL_setmetatable</CODE>
<LI> new <CODE>luaL_tolstring</CODE>
@@ -364,7 +371,7 @@ For details, see
<A HREF="http://www.lua.org/license.html">this</A>.
<BLOCKQUOTE>
-Copyright &copy; 1994&ndash;2010 Lua.org, PUC-Rio.
+Copyright &copy; 1994&ndash;2011 Lua.org, PUC-Rio.
<P>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -391,10 +398,10 @@ THE SOFTWARE.
<HR>
<SMALL>
Last update:
-Sat Nov 20 19:23:14 BRST 2010
+Mon Jun 13 15:07:49 BRT 2011
</SMALL>
<!--
-Last change: revised for Lua 5.2.0 (alpha)
+Last change: revised for Lua 5.2.0 (beta)
-->
</BODY>
diff --git a/src/Makefile b/src/Makefile
index b8cee9c6..9d3d97c8 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -126,7 +126,7 @@ lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h
lbitlib.o: lbitlib.c lua.h luaconf.h lauxlib.h lualib.h
lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \
lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \
- lstring.h ltable.h
+ lstring.h ltable.h lvm.h
lcorolib.o: lcorolib.c lua.h luaconf.h lauxlib.h lualib.h
lctype.o: lctype.c lctype.h lua.h luaconf.h llimits.h
ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h
@@ -164,7 +164,7 @@ lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \
ltm.h lzio.h lstring.h lgc.h
lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h
ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
- ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h
+ ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h
ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \
lmem.h lstring.h lgc.h ltable.h
diff --git a/src/lapi.c b/src/lapi.c
index 074979c3..7761419e 100644
--- a/src/lapi.c
+++ b/src/lapi.c
@@ -1,5 +1,5 @@
/*
-** $Id: lapi.c,v 2.140 2010/11/03 15:16:17 roberto Exp $
+** $Id: lapi.c,v 2.149 2011/06/13 14:13:06 roberto Exp $
** Lua API
** See Copyright Notice in lua.h
*/
@@ -59,9 +59,9 @@ static TValue *index2addr (lua_State *L, int idx) {
if (ttislcf(ci->func)) /* light C function? */
return cast(TValue *, luaO_nilobject); /* it has no upvalues */
else {
- Closure *func = clvalue(ci->func);
- return (idx <= func->c.nupvalues)
- ? &func->c.upvalue[idx-1]
+ CClosure *func = clCvalue(ci->func);
+ return (idx <= func->nupvalues)
+ ? &func->upvalue[idx-1]
: cast(TValue *, luaO_nilobject);
}
}
@@ -195,10 +195,8 @@ static void moveto (lua_State *L, TValue *fr, int idx) {
TValue *to = index2addr(L, idx);
api_checkvalidindex(L, to);
setobj(L, to, fr);
- if (idx < LUA_REGISTRYINDEX) { /* function upvalue? */
- lua_assert(ttisclosure(L->ci->func));
- luaC_barrier(L, clvalue(L->ci->func), fr);
- }
+ if (idx < LUA_REGISTRYINDEX) /* function upvalue? */
+ luaC_barrier(L, clCvalue(L->ci->func), fr);
/* LUA_REGISTRYINDEX does not need gc barrier
(collector revisits it before finishing collection) */
}
@@ -251,7 +249,7 @@ LUA_API const char *lua_typename (lua_State *L, int t) {
LUA_API int lua_iscfunction (lua_State *L, int idx) {
StkId o = index2addr(L, idx);
- return (ttislcf(o) || (ttisclosure(o) && clvalue(o)->c.isC));
+ return (ttislcf(o) || (ttisCclosure(o)));
}
@@ -278,20 +276,28 @@ LUA_API int lua_rawequal (lua_State *L, int index1, int index2) {
StkId o1 = index2addr(L, index1);
StkId o2 = index2addr(L, index2);
return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0
- : luaO_rawequalObj(o1, o2);
+ : luaV_rawequalobj(o1, o2);
}
LUA_API void lua_arith (lua_State *L, int op) {
+ StkId o1; /* 1st operand */
+ StkId o2; /* 2nd operand */
lua_lock(L);
- api_checknelems(L, 2);
- if (ttisnumber(L->top - 2) && ttisnumber(L->top - 1)) {
- changenvalue(L->top - 2,
- luaO_arith(op, nvalue(L->top - 2), nvalue(L->top - 1)));
+ if (op != LUA_OPUNM) /* all other operations expect two operands */
+ api_checknelems(L, 2);
+ else { /* for unary minus, add fake 2nd operand */
+ api_checknelems(L, 1);
+ setobjs2s(L, L->top, L->top - 1);
+ L->top++;
+ }
+ o1 = L->top - 2;
+ o2 = L->top - 1;
+ if (ttisnumber(o1) && ttisnumber(o2)) {
+ changenvalue(o1, luaO_arith(op, nvalue(o1), nvalue(o2)));
}
else
- luaV_arith(L, L->top - 2, L->top - 2, L->top - 1,
- cast(TMS, op - LUA_OPADD + TM_ADD));
+ luaV_arith(L, o1, o1, o2, cast(TMS, op - LUA_OPADD + TM_ADD));
L->top--;
lua_unlock(L);
}
@@ -390,7 +396,7 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
LUA_API size_t lua_rawlen (lua_State *L, int idx) {
StkId o = index2addr(L, idx);
- switch (ttype(o)) {
+ switch (ttypenv(o)) {
case LUA_TSTRING: return tsvalue(o)->len;
case LUA_TUSERDATA: return uvalue(o)->len;
case LUA_TTABLE: return luaH_getn(hvalue(o));
@@ -402,15 +408,15 @@ LUA_API size_t lua_rawlen (lua_State *L, int idx) {
LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) {
StkId o = index2addr(L, idx);
if (ttislcf(o)) return fvalue(o);
- else if (ttisclosure(o) && clvalue(o)->c.isC)
- return clvalue(o)->c.f;
+ else if (ttisCclosure(o))
+ return clCvalue(o)->f;
else return NULL; /* not a C function */
}
LUA_API void *lua_touserdata (lua_State *L, int idx) {
StkId o = index2addr(L, idx);
- switch (ttype(o)) {
+ switch (ttypenv(o)) {
case LUA_TUSERDATA: return (rawuvalue(o) + 1);
case LUA_TLIGHTUSERDATA: return pvalue(o);
default: return NULL;
@@ -428,7 +434,8 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
StkId o = index2addr(L, idx);
switch (ttype(o)) {
case LUA_TTABLE: return hvalue(o);
- case LUA_TFUNCTION: return clvalue(o);
+ case LUA_TLCL: return clLvalue(o);
+ case LUA_TCCL: return clCvalue(o);
case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o)));
case LUA_TTHREAD: return thvalue(o);
case LUA_TUSERDATA:
@@ -456,6 +463,8 @@ LUA_API void lua_pushnil (lua_State *L) {
LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
lua_lock(L);
setnvalue(L->top, n);
+ luai_checknum(L, L->top,
+ luaG_runerror(L, "C API - attempt to push a signaling NaN"));
api_incr_top(L);
lua_unlock(L);
}
@@ -548,7 +557,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
L->top -= n;
while (n--)
setobj2n(L, &cl->c.upvalue[n], L->top + n);
- setclvalue(L, L->top, cl);
+ setclCvalue(L, L->top, cl);
}
api_incr_top(L);
lua_unlock(L);
@@ -648,7 +657,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
int res;
lua_lock(L);
obj = index2addr(L, objindex);
- switch (ttype(obj)) {
+ switch (ttypenv(obj)) {
case LUA_TTABLE:
mt = hvalue(obj)->metatable;
break;
@@ -755,18 +764,19 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
api_check(L, ttistable(L->top - 1), "table expected");
mt = hvalue(L->top - 1);
}
- switch (ttype(obj)) {
+ switch (ttypenv(obj)) {
case LUA_TTABLE: {
hvalue(obj)->metatable = mt;
if (mt)
luaC_objbarrierback(L, gcvalue(obj), mt);
+ luaC_checkfinalizer(L, gcvalue(obj), mt);
break;
}
case LUA_TUSERDATA: {
uvalue(obj)->metatable = mt;
if (mt) {
luaC_objbarrier(L, rawuvalue(obj), mt);
- luaC_checkfinalizer(L, rawuvalue(obj));
+ luaC_checkfinalizer(L, gcvalue(obj), mt);
}
break;
}
@@ -912,15 +922,14 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
luaZ_init(L, &z, reader, data);
status = luaD_protectedparser(L, &z, chunkname);
if (status == LUA_OK) { /* no errors? */
- Closure *f = clvalue(L->top - 1); /* get newly created function */
- lua_assert(!f->c.isC);
- if (f->l.nupvalues == 1) { /* does it have one upvalue? */
+ LClosure *f = clLvalue(L->top - 1); /* get newly created function */
+ if (f->nupvalues == 1) { /* does it have one upvalue? */
/* get global table from registry */
Table *reg = hvalue(&G(L)->l_registry);
const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
- setobj(L, f->l.upvals[0]->v, gt);
- luaC_barrier(L, f->l.upvals[0], gt);
+ setobj(L, f->upvals[0]->v, gt);
+ luaC_barrier(L, f->upvals[0], gt);
}
}
lua_unlock(L);
@@ -959,11 +968,12 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
g = G(L);
switch (what) {
case LUA_GCSTOP: {
- stopgc(g);
+ g->gcrunning = 0;
break;
}
case LUA_GCRESTART: {
- g->GCdebt = 0;
+ luaE_setdebt(g, 0);
+ g->gcrunning = 1;
break;
}
case LUA_GCCOLLECT: {
@@ -972,30 +982,27 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
}
case LUA_GCCOUNT: {
/* GC values are expressed in Kbytes: #bytes/2^10 */
- res = cast_int(g->totalbytes >> 10);
+ res = cast_int(gettotalbytes(g) >> 10);
break;
}
case LUA_GCCOUNTB: {
- res = cast_int(g->totalbytes & 0x3ff);
+ res = cast_int(gettotalbytes(g) & 0x3ff);
break;
}
case LUA_GCSTEP: {
- int stopped = gcstopped(g);
if (g->gckind == KGC_GEN) { /* generational mode? */
res = (g->lastmajormem == 0); /* 1 if will do major collection */
- luaC_step(L); /* do a single step */
+ luaC_forcestep(L); /* do a single step */
}
else {
while (data-- >= 0) {
- luaC_step(L);
+ luaC_forcestep(L);
if (g->gcstate == GCSpause) { /* end of cycle? */
res = 1; /* signal it */
break;
}
}
}
- if (stopped) /* collector was stopped? */
- stopgc(g); /* keep it that way */
break;
}
case LUA_GCSETPAUSE: {
@@ -1014,7 +1021,7 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
break;
}
case LUA_GCISRUNNING: {
- res = !gcstopped(g);
+ res = g->gcrunning;
break;
}
case LUA_GCGEN: { /* change collector to generational mode */
@@ -1124,25 +1131,27 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
static const char *aux_upvalue (StkId fi, int n, TValue **val,
GCObject **owner) {
- Closure *f;
- if (!ttisclosure(fi)) return NULL;
- f = clvalue(fi);
- if (f->c.isC) {
- if (!(1 <= n && n <= f->c.nupvalues)) return NULL;
- *val = &f->c.upvalue[n-1];
- if (owner) *owner = obj2gco(f);
- return "";
- }
- else {
- const char *name;
- Proto *p = f->l.p;
- if (!(1 <= n && n <= p->sizeupvalues)) return NULL;
- *val = f->l.upvals[n-1]->v;
- if (owner) *owner = obj2gco(f->l.upvals[n - 1]);
- name = getstr(p->upvalues[n-1].name);
- if (name == NULL) /* no debug information? */
- name = "";
- return name;
+ switch (ttype(fi)) {
+ case LUA_TCCL: { /* C closure */
+ CClosure *f = clCvalue(fi);
+ if (!(1 <= n && n <= f->nupvalues)) return NULL;
+ *val = &f->upvalue[n-1];
+ if (owner) *owner = obj2gco(f);
+ return "";
+ }
+ case LUA_TLCL: { /* Lua closure */
+ LClosure *f = clLvalue(fi);
+ const char *name;
+ 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]);
+ name = getstr(p->upvalues[n-1].name);
+ if (name == NULL) /* no debug information? */
+ name = "";
+ return name;
+ }
+ default: return NULL; /* not a closure */
}
}
@@ -1180,34 +1189,39 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
}
-static UpVal **getupvalref (lua_State *L, int fidx, int n, Closure **pf) {
- Closure *f;
+static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) {
+ LClosure *f;
StkId fi = index2addr(L, fidx);
- api_check(L, ttisclosure(fi), "Lua function expected");
- f = clvalue(fi);
- api_check(L, !f->c.isC, "Lua function expected");
- api_check(L, (1 <= n && n <= f->l.p->sizeupvalues), "invalid upvalue index");
+ api_check(L, ttisLclosure(fi), "Lua function expected");
+ f = clLvalue(fi);
+ api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index");
if (pf) *pf = f;
- return &f->l.upvals[n - 1]; /* get its upvalue pointer */
+ return &f->upvals[n - 1]; /* get its upvalue pointer */
}
LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) {
- Closure *f;
StkId fi = index2addr(L, fidx);
- api_check(L, ttisclosure(fi), "function expected");
- f = clvalue(fi);
- if (f->c.isC) {
- api_check(L, 1 <= n && n <= f->c.nupvalues, "invalid upvalue index");
- return &f->c.upvalue[n - 1];
+ switch (ttype(fi)) {
+ case LUA_TLCL: { /* lua closure */
+ return *getupvalref(L, fidx, n, NULL);
+ }
+ case LUA_TCCL: { /* C closure */
+ CClosure *f = clCvalue(fi);
+ api_check(L, 1 <= n && n <= f->nupvalues, "invalid upvalue index");
+ return &f->upvalue[n - 1];
+ }
+ default: {
+ api_check(L, 0, "closure expected");
+ return NULL;
+ }
}
- else return *getupvalref(L, fidx, n, NULL);
}
LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
int fidx2, int n2) {
- Closure *f1;
+ LClosure *f1;
UpVal **up1 = getupvalref(L, fidx1, n1, &f1);
UpVal **up2 = getupvalref(L, fidx2, n2, NULL);
*up1 = *up2;
diff --git a/src/lauxlib.c b/src/lauxlib.c
index cdd5a53f..fc080230 100644
--- a/src/lauxlib.c
+++ b/src/lauxlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lauxlib.c,v 1.227 2010/11/10 18:05:36 roberto Exp $
+** $Id: lauxlib.c,v 1.232 2011/05/03 16:01:57 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -203,6 +203,64 @@ LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
return lua_error(L);
}
+
+LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
+ int en = errno; /* calls to Lua API may change this value */
+ if (stat) {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+ else {
+ lua_pushnil(L);
+ if (fname)
+ lua_pushfstring(L, "%s: %s", fname, strerror(en));
+ else
+ lua_pushfstring(L, "%s", strerror(en));
+ lua_pushinteger(L, en);
+ return 3;
+ }
+}
+
+
+#if !defined(inspectstat) /* { */
+
+#if defined(LUA_USE_POSIX)
+
+#include <sys/wait.h>
+
+/*
+** use appropriate macros to interpret 'pclose' return status
+*/
+#define inspectstat(stat,what) \
+ if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \
+ else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; }
+
+#else
+
+#define inspectstat(stat,what) /* no op */
+
+#endif
+
+#endif /* } */
+
+
+LUALIB_API int luaL_execresult (lua_State *L, int stat) {
+ const char *what = "exit"; /* type of termination */
+ if (stat == -1) /* error? */
+ return luaL_fileresult(L, 0, NULL);
+ else {
+ inspectstat(stat, what); /* interpret result */
+ if (*what == 'e' && stat == 0) /* successful termination? */
+ return luaL_fileresult(L, 1, NULL);
+ else { /* return nil,what,code */
+ lua_pushnil(L);
+ lua_pushstring(L, what);
+ lua_pushinteger(L, stat);
+ return 3;
+ }
+ }
+}
+
/* }====================================================== */
@@ -384,8 +442,10 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
newsize = B->n + sz;
if (newsize < B->n || newsize - B->n < sz)
luaL_error(L, "buffer too large");
- newbuff = (char *)lua_newuserdata(L, newsize); /* create larger buffer */
- memcpy(newbuff, B->b, B->n); /* move content to new buffer */
+ /* create larger buffer */
+ newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char));
+ /* move content to new buffer */
+ memcpy(newbuff, B->b, B->n * sizeof(char));
if (buffonstack(B))
lua_remove(L, -2); /* remove old buffer */
B->b = newbuff;
@@ -397,7 +457,7 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
char *b = luaL_prepbuffsize(B, l);
- memcpy(b, s, l);
+ memcpy(b, s, l * sizeof(char));
luaL_addsize(B, l);
}
@@ -700,8 +760,8 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
*/
#if defined(LUA_COMPAT_MODULE)
-static const char *luaL_findtablex (lua_State *L, int idx,
- const char *fname, int szhint) {
+static const char *luaL_findtable (lua_State *L, int idx,
+ const char *fname, int szhint) {
const char *e;
if (idx) lua_pushvalue(L, idx);
do {
@@ -745,13 +805,13 @@ static int libsize (const luaL_Reg *l) {
*/
LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
int sizehint) {
- luaL_findtablex(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */
+ 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? */
lua_pop(L, 1); /* remove previous result */
/* try global variable (and create one if it does not exist) */
lua_pushglobaltable(L);
- if (luaL_findtablex(L, 0, modname, sizehint) != NULL)
+ if (luaL_findtable(L, 0, modname, sizehint) != NULL)
luaL_error(L, "name conflict for module " LUA_QS, modname);
lua_pushvalue(L, -1);
lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */
@@ -767,7 +827,10 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname,
luaL_pushmodule(L, libname, libsize(l)); /* get/create library table */
lua_insert(L, -(nup + 1)); /* move library table to below upvalues */
}
- luaL_setfuncs(L, l, nup);
+ if (l)
+ luaL_setfuncs(L, l, nup);
+ else
+ lua_pop(L, nup); /* remove upvalues */
}
#endif
@@ -780,7 +843,7 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname,
*/
LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
luaL_checkstack(L, nup, "too many upvalues");
- for (; l && l->name; l++) { /* fill the table with given functions */
+ for (; l->name != NULL; l++) { /* fill the table with given functions */
int i;
for (i = 0; i < nup; i++) /* copy upvalues to the top */
lua_pushvalue(L, -nup);
@@ -795,15 +858,16 @@ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
** ensure that stack[idx][fname] has a table and push that table
** into the stack
*/
-LUALIB_API void luaL_findtable (lua_State *L, int idx, const char *fname) {
+LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
lua_getfield(L, idx, fname);
- if (lua_istable(L, -1)) return; /* table already there */
+ if (lua_istable(L, -1)) return 1; /* table already there */
else {
idx = lua_absindex(L, idx);
lua_pop(L, 1); /* remove previous result */
lua_newtable(L);
lua_pushvalue(L, -1); /* copy to be left at top */
lua_setfield(L, idx, fname); /* assign new table to field */
+ return 0; /* false, because did not find table there */
}
}
@@ -819,7 +883,7 @@ LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
lua_pushcfunction(L, openf);
lua_pushstring(L, modname); /* argument to open function */
lua_call(L, 1, 1); /* open module */
- luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED");
+ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
lua_pushvalue(L, -2); /* make copy of module (call result) */
lua_setfield(L, -2, modname); /* _LOADED[modname] = module */
lua_pop(L, 1); /* remove _LOADED table */
diff --git a/src/lauxlib.h b/src/lauxlib.h
index 39506456..8b85ebe5 100644
--- a/src/lauxlib.h
+++ b/src/lauxlib.h
@@ -1,5 +1,5 @@
/*
-** $Id: lauxlib.h,v 1.113 2010/11/16 19:20:01 roberto Exp $
+** $Id: lauxlib.h,v 1.116 2011/04/08 19:17:36 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -62,6 +62,9 @@ LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
const char *const lst[]);
+LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
+LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
+
/* pre-defined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)
@@ -83,7 +86,7 @@ LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
-LUALIB_API void (luaL_findtable) (lua_State *L, int idx, const char *fname);
+LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname);
LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,
const char *msg, int level);
diff --git a/src/lbaselib.c b/src/lbaselib.c
index 1553c1d0..82c8c1fe 100644
--- a/src/lbaselib.c
+++ b/src/lbaselib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lbaselib.c,v 1.251 2010/10/28 15:36:30 roberto Exp $
+** $Id: lbaselib.c,v 1.261 2011/05/26 16:09:40 roberto Exp $
** Basic library
** See Copyright Notice in lua.h
*/
@@ -32,44 +32,54 @@ static int luaB_print (lua_State *L) {
lua_call(L, 1, 1);
s = lua_tolstring(L, -1, &l); /* get result */
if (s == NULL)
- return luaL_error(L, LUA_QL("tostring") " must return a string to "
- LUA_QL("print"));
+ return luaL_error(L,
+ LUA_QL("tostring") " must return a string to " LUA_QL("print"));
if (i>1) luai_writestring("\t", 1);
luai_writestring(s, l);
lua_pop(L, 1); /* pop result */
}
- luai_writestring("\n", 1);
+ luai_writeline();
return 0;
}
+#define SPACECHARS " \f\n\r\t\v"
+
static int luaB_tonumber (lua_State *L) {
int base = luaL_optint(L, 2, 10);
+ luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
if (base == 10) { /* standard conversion */
luaL_checkany(L, 1);
if (lua_isnumber(L, 1)) {
lua_pushnumber(L, lua_tonumber(L, 1));
return 1;
- }
+ } /* else not a number */
}
else {
- const char *s1 = luaL_checkstring(L, 1);
- char *s2;
- unsigned long n;
+ size_t l;
+ const char *s = luaL_checklstring(L, 1, &l);
+ const char *e = s + l; /* end point for 's' */
int neg = 0;
- luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
- while (isspace((unsigned char)(*s1))) s1++; /* skip initial spaces */
- if (*s1 == '-') { s1++; neg = 1; }
- n = strtoul(s1, &s2, base);
- if (s1 != s2) { /* at least one valid digit? */
- while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */
- if (*s2 == '\0') { /* no invalid trailing characters? */
- lua_pushnumber(L, (neg) ? -(lua_Number)n : (lua_Number)n);
+ s += strspn(s, SPACECHARS); /* skip initial spaces */
+ if (*s == '-') { s++; neg = 1; } /* handle signal */
+ else if (*s == '+') s++;
+ if (isalnum((unsigned char)*s)) {
+ lua_Number n = 0;
+ do {
+ int digit = (isdigit((unsigned char)*s)) ? *s - '0'
+ : toupper((unsigned char)*s) - 'A' + 10;
+ if (digit >= base) break; /* invalid numeral; force a fail */
+ n = n * (lua_Number)base + (lua_Number)digit;
+ s++;
+ } while (isalnum((unsigned char)*s));
+ s += strspn(s, SPACECHARS); /* skip trailing spaces */
+ if (s == e) { /* no invalid trailing characters? */
+ lua_pushnumber(L, (neg) ? -n : n);
return 1;
- }
- }
+ } /* else not a number */
+ } /* else not a number */
}
- lua_pushnil(L); /* else not a number */
+ lua_pushnil(L); /* not a number */
return 1;
}
@@ -110,12 +120,10 @@ static int luaB_setmetatable (lua_State *L) {
}
-static int luaB_getfenv (lua_State *L) {
- return luaL_error(L, "getfenv/setfenv deprecated");
+static int luaB_deprecated (lua_State *L) {
+ return luaL_error(L, "deprecated function");
}
-#define luaB_setfenv luaB_getfenv
-
static int luaB_rawequal (lua_State *L) {
luaL_checkany(L, 1);
@@ -125,6 +133,15 @@ static int luaB_rawequal (lua_State *L) {
}
+static int luaB_rawlen (lua_State *L) {
+ int t = lua_type(L, 1);
+ luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
+ "table or string expected");
+ lua_pushinteger(L, lua_rawlen(L, 1));
+ return 1;
+}
+
+
static int luaB_rawget (lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
luaL_checkany(L, 2);
@@ -251,6 +268,11 @@ static int luaB_loadfile (lua_State *L) {
** =======================================================
*/
+/*
+** check whether a chunk (prefix in 's') satisfies given 'mode'
+** ('t' for text, 'b' for binary). Returns error message (also
+** pushed on the stack) in case of errors.
+*/
static const char *checkrights (lua_State *L, const char *mode, const char *s) {
if (strchr(mode, 'b') == NULL && *s == LUA_SIGNATURE[0])
return lua_pushstring(L, "attempt to load a binary chunk");
@@ -261,10 +283,11 @@ static const char *checkrights (lua_State *L, const char *mode, const char *s) {
/*
-** reserves a slot, above all arguments, to hold a copy of the returned
-** string to avoid it being collected while parsed
+** reserved slot, above all arguments, to hold a copy of the returned
+** string to avoid it being collected while parsed. 'load' has four
+** optional arguments (chunk, source name, mode, and environment).
*/
-#define RESERVEDSLOT 4
+#define RESERVEDSLOT 5
/*
@@ -273,25 +296,20 @@ static const char *checkrights (lua_State *L, const char *mode, const char *s) {
** stack top. Instead, it keeps its resulting string in a
** reserved slot inside the stack.
*/
-typedef struct { /* reader state */
- int f; /* position of reader function on stack */
- const char *mode; /* allowed modes (binary/text) */
-} Readstat;
-
static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
const char *s;
- Readstat *stat = (Readstat *)ud;
+ const char **mode = (const char **)ud;
luaL_checkstack(L, 2, "too many nested functions");
- lua_pushvalue(L, stat->f); /* get function */
+ lua_pushvalue(L, 1); /* get function */
lua_call(L, 0, 1); /* call it */
if (lua_isnil(L, -1)) {
*size = 0;
return NULL;
}
else if ((s = lua_tostring(L, -1)) != NULL) {
- if (stat->mode != NULL) { /* first time? */
- s = checkrights(L, stat->mode, s); /* check mode */
- stat->mode = NULL; /* to avoid further checks */
+ if (*mode != NULL) { /* first time? */
+ s = checkrights(L, *mode, s); /* check mode */
+ *mode = NULL; /* to avoid further checks */
if (s) luaL_error(L, s);
}
lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */
@@ -304,52 +322,38 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
}
-static int luaB_load_aux (lua_State *L, int farg) {
+static int luaB_load (lua_State *L) {
int status;
- Readstat stat;
size_t l;
- const char *s = lua_tolstring(L, farg, &l);
- stat.mode = luaL_optstring(L, farg + 2, "bt");
+ int top = lua_gettop(L);
+ const char *s = lua_tolstring(L, 1, &l);
+ const char *mode = luaL_optstring(L, 3, "bt");
if (s != NULL) { /* loading a string? */
- const char *chunkname = luaL_optstring(L, farg + 1, s);
- status = (checkrights(L, stat.mode, s) != NULL)
+ const char *chunkname = luaL_optstring(L, 2, s);
+ status = (checkrights(L, mode, s) != NULL)
|| luaL_loadbuffer(L, s, l, chunkname);
}
else { /* loading from a reader function */
- const char *chunkname = luaL_optstring(L, farg + 1, "=(load)");
- luaL_checktype(L, farg, LUA_TFUNCTION);
- stat.f = farg;
+ const char *chunkname = luaL_optstring(L, 2, "=(load)");
+ luaL_checktype(L, 1, LUA_TFUNCTION);
lua_settop(L, RESERVEDSLOT); /* create reserved slot */
- status = lua_load(L, generic_reader, &stat, chunkname);
+ status = lua_load(L, generic_reader, &mode, chunkname);
+ }
+ if (status == LUA_OK && top >= 4) { /* is there an 'env' argument */
+ lua_pushvalue(L, 4); /* environment for loaded function */
+ lua_setupvalue(L, -2, 1); /* set it as 1st upvalue */
}
return load_aux(L, status);
}
-static int luaB_load (lua_State *L) {
- return luaB_load_aux(L, 1);
-}
-
-
-static int luaB_loadin (lua_State *L) {
- int n;
- luaL_checkany(L, 1);
- n = luaB_load_aux(L, 2);
- if (n == 1) { /* success? */
- lua_pushvalue(L, 1); /* environment for loaded function */
- if (lua_setupvalue(L, -2, 1) == NULL)
- luaL_error(L, "loaded chunk does not have an upvalue");
- }
- return n;
-}
+#if defined(LUA_COMPAT_LOADSTRING)
+#define luaB_loadstring luaB_load
+#else
+#define luaB_loadstring luaB_deprecated
+#endif
-static int luaB_loadstring (lua_State *L) {
- lua_settop(L, 2);
- lua_pushliteral(L, "tb");
- return luaB_load(L); /* dostring(s, n) == load(s, n, "tb") */
-
-}
/* }====================================================== */
@@ -391,7 +395,7 @@ static int luaB_select (lua_State *L) {
static int pcallcont (lua_State *L) {
- int errfunc; /* call has an error function in bottom of the stack */
+ int errfunc = 0; /* =0 to avoid warnings */
int status = lua_getctx(L, &errfunc);
lua_assert(status != LUA_OK);
lua_pushboolean(L, (status == LUA_YIELD)); /* first result (status) */
@@ -436,55 +440,27 @@ static int luaB_tostring (lua_State *L) {
}
-static int luaB_newproxy (lua_State *L) {
- lua_settop(L, 1);
- lua_newuserdata(L, 0); /* create proxy */
- if (lua_toboolean(L, 1) == 0)
- return 1; /* no metatable */
- else if (lua_isboolean(L, 1)) {
- lua_createtable(L, 0, 1); /* create a new metatable `m' ... */
- lua_pushboolean(L, 1);
- lua_setfield(L, -2, "__gc"); /* ... m.__gc = false (HACK!!)... */
- lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */
- lua_pushboolean(L, 1);
- lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */
- }
- else {
- int validproxy = 0; /* to check if weaktable[metatable(u)] == true */
- if (lua_getmetatable(L, 1)) {
- lua_rawget(L, lua_upvalueindex(1));
- validproxy = lua_toboolean(L, -1);
- lua_pop(L, 1); /* remove value */
- }
- luaL_argcheck(L, validproxy, 1, "boolean or proxy expected");
- lua_getmetatable(L, 1); /* metatable is valid; get it */
- }
- lua_setmetatable(L, 2);
- return 1;
-}
-
-
static const luaL_Reg base_funcs[] = {
{"assert", luaB_assert},
{"collectgarbage", luaB_collectgarbage},
{"dofile", luaB_dofile},
{"error", luaB_error},
- {"getfenv", luaB_getfenv},
+ {"getfenv", luaB_deprecated},
{"getmetatable", luaB_getmetatable},
{"ipairs", luaB_ipairs},
{"loadfile", luaB_loadfile},
{"load", luaB_load},
- {"loadin", luaB_loadin},
{"loadstring", luaB_loadstring},
{"next", luaB_next},
{"pairs", luaB_pairs},
{"pcall", luaB_pcall},
{"print", luaB_print},
{"rawequal", luaB_rawequal},
+ {"rawlen", luaB_rawlen},
{"rawget", luaB_rawget},
{"rawset", luaB_rawset},
{"select", luaB_select},
- {"setfenv", luaB_setfenv},
+ {"setfenv", luaB_deprecated},
{"setmetatable", luaB_setmetatable},
{"tonumber", luaB_tonumber},
{"tostring", luaB_tostring},
@@ -503,14 +479,6 @@ LUAMOD_API int luaopen_base (lua_State *L) {
luaL_setfuncs(L, base_funcs, 0);
lua_pushliteral(L, LUA_VERSION);
lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */
- /* `newproxy' needs a weaktable as upvalue */
- lua_createtable(L, 0, 1); /* new table `w' */
- lua_pushvalue(L, -1); /* `w' will be its own metatable */
- lua_setmetatable(L, -2);
- lua_pushliteral(L, "kv");
- lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */
- lua_pushcclosure(L, luaB_newproxy, 1);
- lua_setfield(L, -2, "newproxy"); /* set global `newproxy' */
return 1;
}
diff --git a/src/lbitlib.c b/src/lbitlib.c
index 35879000..dcc0ac16 100644
--- a/src/lbitlib.c
+++ b/src/lbitlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lbitlib.c,v 1.13 2010/11/22 18:06:33 roberto Exp $
+** $Id: lbitlib.c,v 1.15 2010/12/17 13:26:38 roberto Exp $
** Standard library for bitwise operations
** See Copyright Notice in lua.h
*/
@@ -14,25 +14,30 @@
/* number of bits to consider in a number */
-#define NBITS 32
+#if !defined(LUA_NBITS)
+#define LUA_NBITS 32
+#endif
-#define ALLONES (~(((~(lua_Unsigned)0) << (NBITS - 1)) << 1))
-/* mask to trim extra bits */
+#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1))
+
+/* macro to trim extra bits */
#define trim(x) ((x) & ALLONES)
-typedef lua_Unsigned b_uint;
+/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */
+#define mask(n) (~((ALLONES << 1) << ((n) - 1)))
+
+typedef lua_Unsigned b_uint;
-#define getuintarg(L,arg) luaL_checkunsigned(L,arg)
static b_uint andaux (lua_State *L) {
int i, n = lua_gettop(L);
b_uint r = ~(b_uint)0;
for (i = 1; i <= n; i++)
- r &= getuintarg(L, i);
+ r &= luaL_checkunsigned(L, i);
return trim(r);
}
@@ -55,7 +60,7 @@ static int b_or (lua_State *L) {
int i, n = lua_gettop(L);
b_uint r = 0;
for (i = 1; i <= n; i++)
- r |= getuintarg(L, i);
+ r |= luaL_checkunsigned(L, i);
lua_pushunsigned(L, trim(r));
return 1;
}
@@ -65,14 +70,14 @@ static int b_xor (lua_State *L) {
int i, n = lua_gettop(L);
b_uint r = 0;
for (i = 1; i <= n; i++)
- r ^= getuintarg(L, i);
+ r ^= luaL_checkunsigned(L, i);
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_not (lua_State *L) {
- b_uint r = ~getuintarg(L, 1);
+ b_uint r = ~luaL_checkunsigned(L, 1);
lua_pushunsigned(L, trim(r));
return 1;
}
@@ -82,11 +87,11 @@ static int b_shift (lua_State *L, b_uint r, int i) {
if (i < 0) { /* shift right? */
i = -i;
r = trim(r);
- if (i >= NBITS) r = 0;
+ if (i >= LUA_NBITS) r = 0;
else r >>= i;
}
else { /* shift left */
- if (i >= NBITS) r = 0;
+ if (i >= LUA_NBITS) r = 0;
else r <<= i;
r = trim(r);
}
@@ -96,22 +101,22 @@ static int b_shift (lua_State *L, b_uint r, int i) {
static int b_lshift (lua_State *L) {
- return b_shift(L, getuintarg(L, 1), luaL_checkint(L, 2));
+ return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkint(L, 2));
}
static int b_rshift (lua_State *L) {
- return b_shift(L, getuintarg(L, 1), -luaL_checkint(L, 2));
+ return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkint(L, 2));
}
static int b_arshift (lua_State *L) {
- b_uint r = getuintarg(L, 1);
+ b_uint r = luaL_checkunsigned(L, 1);
int i = luaL_checkint(L, 2);
- if (i < 0 || !(r & ((b_uint)1 << (NBITS - 1))))
+ if (i < 0 || !(r & ((b_uint)1 << (LUA_NBITS - 1))))
return b_shift(L, r, -i);
else { /* arithmetic shift for 'negative' number */
- if (i >= NBITS) r = ALLONES;
+ if (i >= LUA_NBITS) r = ALLONES;
else
r = trim((r >> i) | ~(~(b_uint)0 >> i)); /* add signal bit */
lua_pushunsigned(L, r);
@@ -121,10 +126,10 @@ static int b_arshift (lua_State *L) {
static int b_rot (lua_State *L, int i) {
- b_uint r = getuintarg(L, 1);
- i &= (NBITS - 1); /* i = i % NBITS */
+ b_uint r = luaL_checkunsigned(L, 1);
+ i &= (LUA_NBITS - 1); /* i = i % NBITS */
r = trim(r);
- r = (r << i) | (r >> (NBITS - i));
+ r = (r << i) | (r >> (LUA_NBITS - i));
lua_pushunsigned(L, trim(r));
return 1;
}
@@ -140,17 +145,58 @@ static int b_rrot (lua_State *L) {
}
+/*
+** get field and width arguments for field-manipulation functions,
+** checking whether they are valid
+*/
+static int fieldargs (lua_State *L, int farg, int *width) {
+ int f = luaL_checkint(L, farg);
+ int w = luaL_optint(L, farg + 1, 1);
+ luaL_argcheck(L, 0 <= f, farg, "field cannot be netative");
+ luaL_argcheck(L, 0 < w, farg + 1, "width must be positive");
+ if (f + w > LUA_NBITS)
+ luaL_error(L, "trying to access non-existent bits");
+ *width = w;
+ return f;
+}
+
+
+static int b_extract (lua_State *L) {
+ int w;
+ b_uint r = luaL_checkunsigned(L, 1);
+ int f = fieldargs(L, 2, &w);
+ r = (r >> f) & mask(w);
+ lua_pushunsigned(L, r);
+ return 1;
+}
+
+
+static int b_replace (lua_State *L) {
+ int w;
+ b_uint r = luaL_checkunsigned(L, 1);
+ b_uint v = luaL_checkunsigned(L, 2);
+ int f = fieldargs(L, 3, &w);
+ int m = mask(w);
+ v &= m; /* erase bits outside given width */
+ r = (r & ~(m << f)) | (v << f);
+ lua_pushunsigned(L, r);
+ return 1;
+}
+
+
static const luaL_Reg bitlib[] = {
{"arshift", b_arshift},
{"band", b_and},
{"bnot", b_not},
{"bor", b_or},
{"bxor", b_xor},
+ {"btest", b_test},
+ {"extract", b_extract},
{"lrotate", b_lrot},
{"lshift", b_lshift},
+ {"replace", b_replace},
{"rrotate", b_rrot},
{"rshift", b_rshift},
- {"btest", b_test},
{NULL, NULL}
};
diff --git a/src/lcode.c b/src/lcode.c
index ea3217fa..00966a12 100644
--- a/src/lcode.c
+++ b/src/lcode.c
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.c,v 2.49 2010/07/07 16:27:29 roberto Exp $
+** $Id: lcode.c,v 2.56 2011/05/31 18:27:56 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -23,6 +23,7 @@
#include "lparser.h"
#include "lstring.h"
#include "ltable.h"
+#include "lvm.h"
#define hasjumps(e) ((e)->t != (e)->f)
@@ -35,19 +36,23 @@ static int isnumeral(expdesc *e) {
void luaK_nil (FuncState *fs, int from, int n) {
Instruction *previous;
+ int l = from + n - 1; /* last register to set nil */
if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
previous = &fs->f->code[fs->pc-1];
if (GET_OPCODE(*previous) == OP_LOADNIL) {
int pfrom = GETARG_A(*previous);
- int pto = GETARG_B(*previous);
- if (pfrom <= from && from <= pto+1) { /* can connect both? */
- if (from+n-1 > pto)
- SETARG_B(*previous, from+n-1);
+ int pl = pfrom + GETARG_B(*previous);
+ if ((pfrom <= from && from <= pl + 1) ||
+ (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
+ if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */
+ if (pl > l) l = pl; /* l = max(l, pl) */
+ SETARG_A(*previous, from);
+ SETARG_B(*previous, l - from);
return;
}
- }
+ } /* else go through */
}
- luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */
+ luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */
}
@@ -171,6 +176,19 @@ void luaK_patchlist (FuncState *fs, int list, int target) {
}
+LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level) {
+ level++; /* argument is +1 to reserve 0 as non-op */
+ while (list != NO_JUMP) {
+ int next = getjump(fs, list);
+ lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&
+ (GETARG_A(fs->f->code[list]) == 0 ||
+ GETARG_A(fs->f->code[list]) >= level));
+ SETARG_A(fs->f->code[list], level);
+ list = next;
+ }
+}
+
+
void luaK_patchtohere (FuncState *fs, int list) {
luaK_getlabel(fs);
luaK_concat(fs, &fs->jpc, list);
@@ -229,11 +247,11 @@ static int codeextraarg (FuncState *fs, int a) {
}
-int luaK_codeABxX (FuncState *fs, OpCode o, int reg, int k) {
- if (k < MAXARG_Bx)
- return luaK_codeABx(fs, o, reg, k + 1);
+int luaK_codek (FuncState *fs, int reg, int k) {
+ if (k <= MAXARG_Bx)
+ return luaK_codeABx(fs, OP_LOADK, reg, k);
else {
- int p = luaK_codeABx(fs, o, reg, 0);
+ int p = luaK_codeABx(fs, OP_LOADKX, reg, 0);
codeextraarg(fs, k);
return p;
}
@@ -278,7 +296,7 @@ static int addk (FuncState *fs, TValue *key, TValue *v) {
if (ttisnumber(idx)) {
lua_Number n = nvalue(idx);
lua_number2int(k, n);
- if (luaO_rawequalObj(&f->k[k], v))
+ 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 */
@@ -564,15 +582,15 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
- int func;
+ int ereg;
luaK_exp2anyreg(fs, e);
+ ereg = e->u.info; /* register where 'e' was placed */
freeexp(fs, e);
- func = fs->freereg;
- luaK_codeABC(fs, OP_SELF, func, e->u.info, luaK_exp2RK(fs, key));
- freeexp(fs, key);
- luaK_reserveregs(fs, 2);
- e->u.info = func;
+ e->u.info = fs->freereg; /* base register for op_self */
e->k = VNONRELOC;
+ luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */
+ luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key));
+ freeexp(fs, key);
}
@@ -603,21 +621,14 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
int pc; /* pc of last jump */
luaK_dischargevars(fs, e);
switch (e->k) {
- case VK: case VKNUM: case VTRUE: {
- pc = NO_JUMP; /* always true; do nothing */
- break;
- }
case VJMP: {
invertjump(fs, e);
pc = e->u.info;
break;
}
- case VFALSE: {
- if (!hasjumps(e)) {
- pc = luaK_jump(fs); /* always jump */
- break;
- }
- /* else go through */
+ case VK: case VKNUM: case VTRUE: {
+ pc = NO_JUMP; /* always true; do nothing */
+ break;
}
default: {
pc = jumponcond(fs, e, 0);
@@ -634,20 +645,13 @@ static void luaK_goiffalse (FuncState *fs, expdesc *e) {
int pc; /* pc of last jump */
luaK_dischargevars(fs, e);
switch (e->k) {
- case VNIL: case VFALSE: {
- pc = NO_JUMP; /* always false; do nothing */
- break;
- }
case VJMP: {
pc = e->u.info;
break;
}
- case VTRUE: {
- if (!hasjumps(e)) {
- pc = luaK_jump(fs); /* always jump */
- break;
- }
- /* else go through */
+ case VNIL: case VFALSE: {
+ pc = NO_JUMP; /* always false; do nothing */
+ break;
}
default: {
pc = jumponcond(fs, e, 1);
diff --git a/src/lcode.h b/src/lcode.h
index 86d21389..26a5daaf 100644
--- a/src/lcode.h
+++ b/src/lcode.h
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.h,v 1.55 2010/07/02 20:42:40 roberto Exp $
+** $Id: lcode.h,v 1.57 2011/04/07 18:14:12 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -44,11 +44,9 @@ typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t)
-#define luaK_codek(fs,reg,k) luaK_codeABxX(fs, OP_LOADK, reg, k)
-
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
-LUAI_FUNC int luaK_codeABxX (FuncState *fs, OpCode o, int reg, int k);
+LUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k);
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
@@ -71,6 +69,7 @@ LUAI_FUNC int luaK_jump (FuncState *fs);
LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret);
LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);
LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
+LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level);
LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);
LUAI_FUNC int luaK_getlabel (FuncState *fs);
LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line);
diff --git a/src/ldblib.c b/src/ldblib.c
index d631dcba..78f6cc06 100644
--- a/src/ldblib.c
+++ b/src/ldblib.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldblib.c,v 1.126 2010/11/16 18:01:28 roberto Exp $
+** $Id: ldblib.c,v 1.130 2011/04/08 19:17:36 roberto Exp $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
@@ -18,6 +18,9 @@
#include "lualib.h"
+#define HOOKKEY "_HKEY"
+
+
static int db_getregistry (lua_State *L) {
lua_pushvalue(L, LUA_REGISTRYINDEX);
@@ -39,8 +42,8 @@ static int db_setmetatable (lua_State *L) {
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
"nil or table expected");
lua_settop(L, 2);
- lua_pushboolean(L, lua_setmetatable(L, 1));
- return 1;
+ lua_setmetatable(L, 1);
+ return 1; /* return 1st argument */
}
@@ -250,14 +253,13 @@ static int db_upvaluejoin (lua_State *L) {
}
-static const char KEY_HOOK = 'h';
+#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY);
static void hookf (lua_State *L, lua_Debug *ar) {
static const char *const hooknames[] =
{"call", "return", "line", "count", "tail call"};
- lua_pushlightuserdata(L, (void *)&KEY_HOOK);
- lua_rawget(L, LUA_REGISTRYINDEX);
+ gethooktable(L);
lua_pushlightuserdata(L, L);
lua_rawget(L, -2);
if (lua_isfunction(L, -1)) {
@@ -291,19 +293,6 @@ static char *unmakemask (int mask, char *smask) {
}
-static void gethooktable (lua_State *L) {
- lua_pushlightuserdata(L, (void *)&KEY_HOOK);
- lua_rawget(L, LUA_REGISTRYINDEX);
- if (!lua_istable(L, -1)) {
- lua_pop(L, 1);
- lua_createtable(L, 0, 1);
- lua_pushlightuserdata(L, (void *)&KEY_HOOK);
- lua_pushvalue(L, -2);
- lua_rawset(L, LUA_REGISTRYINDEX);
- }
-}
-
-
static int db_sethook (lua_State *L) {
int arg, mask, count;
lua_Hook func;
diff --git a/src/ldebug.c b/src/ldebug.c
index a112f4da..a2565cf5 100644
--- a/src/ldebug.c
+++ b/src/ldebug.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldebug.c,v 2.74 2010/10/11 20:24:42 roberto Exp $
+** $Id: ldebug.c,v 2.82 2011/06/02 19:31:40 roberto Exp $
** Debug Interface
** See Copyright Notice in lua.h
*/
@@ -35,12 +35,12 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
static int currentpc (CallInfo *ci) {
lua_assert(isLua(ci));
- return pcRel(ci->u.l.savedpc, ci_func(ci)->l.p);
+ return pcRel(ci->u.l.savedpc, ci_func(ci)->p);
}
static int currentline (CallInfo *ci) {
- return getfuncline(ci_func(ci)->l.p, currentpc(ci));
+ return getfuncline(ci_func(ci)->p, currentpc(ci));
}
@@ -94,13 +94,28 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
}
+static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
+ int nparams = clLvalue(ci->func)->p->numparams;
+ if (n >= ci->u.l.base - ci->func - nparams)
+ return NULL; /* no such vararg */
+ else {
+ *pos = ci->func + nparams + n;
+ return "(*vararg)"; /* generic name for any vararg */
+ }
+}
+
+
static const char *findlocal (lua_State *L, CallInfo *ci, int n,
StkId *pos) {
const char *name = NULL;
StkId base;
if (isLua(ci)) {
- base = ci->u.l.base;
- name = luaF_getlocalname(ci_func(ci)->l.p, n, currentpc(ci));
+ if (n < 0) /* access to vararg values? */
+ return findvararg(ci, -n, pos);
+ else {
+ base = ci->u.l.base;
+ name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
+ }
}
else
base = ci->func + 1;
@@ -108,10 +123,8 @@ static const char *findlocal (lua_State *L, CallInfo *ci, int n,
StkId limit = (ci == L->ci) ? L->top : ci->next->func;
if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */
name = "(*temporary)"; /* generic name for any valid slot */
- else {
- *pos = base; /* to avoid warnings */
+ else
return NULL; /* no name */
- }
}
*pos = base + (n - 1);
return name;
@@ -125,10 +138,10 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
if (!isLfunction(L->top - 1)) /* not a Lua function? */
name = NULL;
else /* consider live variables at function start (parameters) */
- name = luaF_getlocalname(clvalue(L->top - 1)->l.p, n, 0);
+ name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0);
}
else { /* active function; get information through 'ar' */
- StkId pos;
+ StkId pos = 0; /* to avoid warnings */
name = findlocal(L, ar->i_ci, n, &pos);
if (name) {
setobj2s(L, L->top, pos);
@@ -141,11 +154,11 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
- StkId pos;
+ StkId pos = 0; /* to avoid warnings */
const char *name = findlocal(L, ar->i_ci, n, &pos);
lua_lock(L);
if (name)
- setobjs2s(L, pos, L->top - 1);
+ setobjs2s(L, pos, L->top - 1);
L->top--; /* pop value */
lua_unlock(L);
return name;
@@ -243,7 +256,7 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
if (*what == '>') {
ci = NULL;
func = L->top - 1;
- luai_apicheck(L, ttisfunction(func));
+ api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */
L->top--; /* pop function */
}
@@ -271,21 +284,38 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
** =======================================================
*/
+static const char *getobjname (lua_State *L, CallInfo *ci, int reg,
+ const char **name);
-static void kname (Proto *p, int c, int reg, const char *what,
- const char **name) {
- if (c == reg && what && *what == 'c')
- return; /* index is a constant; name already correct */
- else if (ISK(c) && ttisstring(&p->k[INDEXK(c)]))
- *name = svalue(&p->k[INDEXK(c)]);
- else
- *name = "?";
+
+/*
+** find a "name" for the RK value 'c'
+*/
+static void kname (lua_State *L, CallInfo *ci, int c, int oreg,
+ const char *what, const char **name) {
+ if (ISK(c)) { /* is 'c' a constant? */
+ TValue *kvalue = &ci_func(ci)->p->k[INDEXK(c)];
+ if (ttisstring(kvalue)) { /* literal constant? */
+ *name = svalue(kvalue); /* it is its own name */
+ return;
+ }
+ /* else no reasonable name found */
+ }
+ else { /* 'c' is a register */
+ if (c != oreg) /* not the original register? */
+ what = getobjname(L, ci, c, name); /* search for 'c' */
+ if (what && *what == 'c') { /* found a constant name? */
+ return; /* 'name' already filled */
+ }
+ /* else no reasonable name found */
+ }
+ *name = "?"; /* no reasonable name found */
}
static const char *getobjname (lua_State *L, CallInfo *ci, int reg,
const char **name) {
- Proto *p = ci_func(ci)->l.p;
+ Proto *p = ci_func(ci)->p;
const char *what = NULL;
int lastpc = currentpc(ci);
int pc;
@@ -312,10 +342,10 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg,
if (reg == a) {
int k = GETARG_C(i); /* key index */
int t = GETARG_B(i);
- const char *vn = (op == OP_GETTABLE) /* name of indexed variable */
+ const char *vn = (op == OP_GETTABLE) /* name of indexed variable */
? luaF_getlocalname(p, t + 1, pc)
: getstr(p->upvalues[t].name);
- kname(p, k, a, what, name);
+ kname(L, ci, k, a, what, name);
what = (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field";
}
break;
@@ -329,10 +359,11 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg,
}
break;
}
- case OP_LOADK: {
+ case OP_LOADK:
+ case OP_LOADKX: {
if (reg == a) {
- int b = GETARG_Bx(i);
- b = (b > 0) ? b - 1 : GETARG_Ax(p->code[pc + 1]);
+ int b = (op == OP_LOADK) ? GETARG_Bx(i)
+ : GETARG_Ax(p->code[pc + 1]);
if (ttisstring(&p->k[b])) {
what = "constant";
*name = svalue(&p->k[b]);
@@ -341,15 +372,15 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg,
break;
}
case OP_LOADNIL: {
- int b = GETARG_B(i); /* move from 'b' to 'a' */
- if (a <= reg && reg <= b) /* set registers from 'a' to 'b' */
+ int b = GETARG_B(i);
+ if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */
what = NULL;
break;
}
case OP_SELF: {
if (reg == a) {
int k = GETARG_C(i); /* key index */
- kname(p, k, a, what, name);
+ kname(L, ci, k, a, what, name);
what = "method";
}
break;
@@ -371,6 +402,10 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg,
pc += b; /* do the jump */
break;
}
+ case OP_TEST: {
+ if (reg == a) what = NULL; /* jumped code can change 'a' */
+ break;
+ }
default:
if (testAMode(op) && reg == a) what = NULL;
break;
@@ -386,9 +421,9 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
if ((ci->callstatus & CIST_TAIL) || !isLua(ci->previous))
return NULL; /* calling function is not Lua (or is unknown) */
ci = ci->previous; /* calling function */
- i = ci_func(ci)->l.p->code[currentpc(ci)];
+ i = ci_func(ci)->p->code[currentpc(ci)];
if (GET_OPCODE(i) == OP_EXTRAARG) /* extra argument? */
- i = ci_func(ci)->l.p->code[currentpc(ci) - 1]; /* get 'real' instruction */
+ i = ci_func(ci)->p->code[currentpc(ci) - 1]; /* get 'real' instruction */
switch (GET_OPCODE(i)) {
case OP_CALL:
case OP_TAILCALL:
@@ -425,7 +460,10 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
-/* only ANSI way to check whether a pointer points to an array */
+/*
+** only ANSI way to check whether a pointer points to an array
+** (used only for error messages, so efficiency is not a big concern)
+*/
static int isinstack (CallInfo *ci, const TValue *o) {
StkId p;
for (p = ci->u.l.base; p < ci->top; p++)
@@ -436,7 +474,7 @@ static int isinstack (CallInfo *ci, const TValue *o) {
static const char *getupvalname (CallInfo *ci, const TValue *o,
const char **name) {
- LClosure *c = &ci_func(ci)->l;
+ LClosure *c = ci_func(ci);
int i;
for (i = 0; i < c->nupvalues; i++) {
if (c->upvals[i]->v == o) {
@@ -455,7 +493,7 @@ void luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
const char *kind = NULL;
if (isLua(ci)) {
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
- if (!kind && isinstack(ci, o)) /* no? try a register */
+ if (!kind && isinstack(ci, o)) /* no? try a register */
kind = getobjname(L, ci, cast_int(o - ci->u.l.base), &name);
}
if (kind)
@@ -497,7 +535,7 @@ static void addinfo (lua_State *L, const char *msg) {
if (isLua(ci)) { /* is Lua code? */
char buff[LUA_IDSIZE]; /* add file:line information */
int line = currentline(ci);
- TString *src = ci_func(ci)->l.p->source;
+ TString *src = ci_func(ci)->p->source;
if (src)
luaO_chunkid(buff, getstr(src), LUA_IDSIZE);
else { /* no source available; use "?" instead */
diff --git a/src/ldebug.h b/src/ldebug.h
index 545fa345..6590c56b 100644
--- a/src/ldebug.h
+++ b/src/ldebug.h
@@ -1,5 +1,5 @@
/*
-** $Id: ldebug.h,v 2.5 2009/06/10 16:57:53 roberto Exp $
+** $Id: ldebug.h,v 2.6 2011/06/02 19:31:40 roberto Exp $
** Auxiliary functions from Debug Interface module
** See Copyright Notice in lua.h
*/
@@ -17,6 +17,9 @@
#define resethookcount(L) (L->hookcount = L->basehookcount)
+/* Active Lua function (given call info) */
+#define ci_func(ci) (clLvalue((ci)->func))
+
LUAI_FUNC void luaG_typeerror (lua_State *L, const TValue *o,
const char *opname);
diff --git a/src/ldo.c b/src/ldo.c
index f4f91006..c3d86aff 100644
--- a/src/ldo.c
+++ b/src/ldo.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.c,v 2.90 2010/10/25 19:01:37 roberto Exp $
+** $Id: ldo.c,v 2.95 2011/06/02 19:31:40 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -293,65 +293,59 @@ static StkId tryfuncTM (lua_State *L, StkId func) {
** returns true if function has been executed (C function)
*/
int luaD_precall (lua_State *L, StkId func, int nresults) {
- Closure *cl;
lua_CFunction f;
- ptrdiff_t funcr;
- if (!ttisfunction(func)) /* `func' is not a function? */
- func = tryfuncTM(L, func); /* check the `function' tag method */
- funcr = savestack(L, func);
- if (ttislcf(func)) { /* light C function? */
- f = fvalue(func); /* get it */
- goto isCfunc; /* go to call it */
- }
- cl = clvalue(func);
- if (cl->c.isC) { /* C closure? */
- CallInfo *ci;
- int n;
- f = cl->c.f;
- isCfunc: /* call C function 'f' */
- luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
- ci = next_ci(L); /* now 'enter' new function */
- ci->nresults = nresults;
- ci->func = restorestack(L, funcr);
- ci->top = L->top + LUA_MINSTACK;
- lua_assert(ci->top <= L->stack_last);
- ci->callstatus = 0;
- if (L->hookmask & LUA_MASKCALL)
- luaD_hook(L, LUA_HOOKCALL, -1);
- lua_unlock(L);
- n = (*f)(L); /* do the actual call */
- lua_lock(L);
- api_checknelems(L, n);
- luaD_poscall(L, L->top - n);
- return 1;
- }
- else { /* Lua function: prepare its call */
- CallInfo *ci;
- int nparams, nargs;
- StkId base;
- Proto *p = cl->l.p;
- luaD_checkstack(L, p->maxstacksize);
- func = restorestack(L, funcr);
- nargs = cast_int(L->top - func) - 1; /* number of real arguments */
- nparams = p->numparams; /* number of expected parameters */
- for (; nargs < nparams; nargs++)
- setnilvalue(L->top++); /* complete missing arguments */
- if (!p->is_vararg) /* no varargs? */
- base = func + 1;
- else /* vararg function */
- base = adjust_varargs(L, p, nargs);
- ci = next_ci(L); /* now 'enter' new function */
- ci->nresults = nresults;
- ci->func = func;
- ci->u.l.base = base;
- ci->top = base + p->maxstacksize;
- lua_assert(ci->top <= L->stack_last);
- ci->u.l.savedpc = p->code; /* starting point */
- ci->callstatus = CIST_LUA;
- L->top = ci->top;
- if (L->hookmask & LUA_MASKCALL)
- callhook(L, ci);
- return 0;
+ CallInfo *ci;
+ int n; /* number of arguments (Lua) or returns (C) */
+ ptrdiff_t funcr = savestack(L, func);
+ switch (ttype(func)) {
+ case LUA_TLCF: /* light C function */
+ f = fvalue(func);
+ goto Cfunc;
+ case LUA_TCCL: { /* C closure */
+ f = clCvalue(func)->f;
+ Cfunc:
+ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
+ ci = next_ci(L); /* now 'enter' new function */
+ ci->nresults = nresults;
+ ci->func = restorestack(L, funcr);
+ ci->top = L->top + LUA_MINSTACK;
+ lua_assert(ci->top <= L->stack_last);
+ ci->callstatus = 0;
+ if (L->hookmask & LUA_MASKCALL)
+ luaD_hook(L, LUA_HOOKCALL, -1);
+ lua_unlock(L);
+ n = (*f)(L); /* do the actual call */
+ lua_lock(L);
+ api_checknelems(L, n);
+ luaD_poscall(L, L->top - n);
+ return 1;
+ }
+ case LUA_TLCL: { /* Lua function: prepare its call */
+ StkId base;
+ Proto *p = clLvalue(func)->p;
+ luaD_checkstack(L, p->maxstacksize);
+ func = restorestack(L, funcr);
+ n = cast_int(L->top - func) - 1; /* number of real arguments */
+ for (; n < p->numparams; n++)
+ setnilvalue(L->top++); /* complete missing arguments */
+ base = (!p->is_vararg) ? func + 1 : adjust_varargs(L, p, n);
+ ci = next_ci(L); /* now 'enter' new function */
+ ci->nresults = nresults;
+ ci->func = func;
+ ci->u.l.base = base;
+ ci->top = base + p->maxstacksize;
+ lua_assert(ci->top <= L->stack_last);
+ ci->u.l.savedpc = p->code; /* starting point */
+ ci->callstatus = CIST_LUA;
+ L->top = ci->top;
+ if (L->hookmask & LUA_MASKCALL)
+ callhook(L, ci);
+ return 0;
+ }
+ default: { /* not a function */
+ func = tryfuncTM(L, func); /* retry with 'function' tag method */
+ return luaD_precall(L, func, nresults);
+ }
}
}
@@ -615,8 +609,8 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u,
*/
struct SParser { /* data to `f_parser' */
ZIO *z;
- Mbuffer buff; /* buffer to be used by the scanner */
- Varlist varl; /* list of local variables (to be used by the parser) */
+ Mbuffer buff; /* dynamic structure used by the scanner */
+ Dyndata dyd; /* dynamic structures used by the parser */
const char *name;
};
@@ -625,14 +619,14 @@ static void f_parser (lua_State *L, void *ud) {
Proto *tf;
Closure *cl;
struct SParser *p = cast(struct SParser *, ud);
- int c = luaZ_lookahead(p->z);
+ int c = zgetc(p->z); /* read first character */
tf = (c == LUA_SIGNATURE[0])
? luaU_undump(L, p->z, &p->buff, p->name)
- : luaY_parser(L, p->z, &p->buff, &p->varl, p->name);
+ : luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
setptvalue2s(L, L->top, tf);
incr_top(L);
cl = luaF_newLclosure(L, tf);
- setclvalue(L, L->top - 1, cl);
+ setclLvalue(L, L->top - 1, cl);
for (i = 0; i < tf->sizeupvalues; i++) /* initialize upvalues */
cl->l.upvals[i] = luaF_newupval(L);
}
@@ -643,11 +637,15 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) {
int status;
L->nny++; /* cannot yield during parsing */
p.z = z; p.name = name;
- p.varl.actvar = NULL; p.varl.nactvar = p.varl.actvarsize = 0;
+ p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0;
+ p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
+ p.dyd.label.arr = NULL; p.dyd.label.size = 0;
luaZ_initbuffer(L, &p.buff);
status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
luaZ_freebuffer(L, &p.buff);
- luaM_freearray(L, p.varl.actvar, p.varl.actvarsize);
+ luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
+ luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);
+ luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size);
L->nny--;
return status;
}
diff --git a/src/ldump.c b/src/ldump.c
index 54a7bb48..77b578d7 100644
--- a/src/ldump.c
+++ b/src/ldump.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldump.c,v 1.17 2010/10/13 21:04:52 lhf Exp $
+** $Id: ldump.c,v 1.18 2011/05/06 13:35:17 lhf Exp $
** save precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -69,7 +69,7 @@ static void DumpString(const TString* s, DumpState* D)
{
size_t size=s->tsv.len+1; /* include trailing '\0' */
DumpVar(size,D);
- DumpBlock(getstr(s),size,D);
+ DumpBlock(getstr(s),size*sizeof(char),D);
}
}
@@ -150,7 +150,7 @@ static void DumpFunction(const Proto* f, DumpState* D)
static void DumpHeader(DumpState* D)
{
- char h[LUAC_HEADERSIZE];
+ lu_byte h[LUAC_HEADERSIZE];
luaU_header(h);
DumpBlock(h,LUAC_HEADERSIZE,D);
}
diff --git a/src/lgc.c b/src/lgc.c
index 2286f54e..598cc71c 100644
--- a/src/lgc.c
+++ b/src/lgc.c
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.c,v 2.103 2010/10/25 19:01:37 roberto Exp $
+** $Id: lgc.c,v 2.109 2011/05/05 19:42:25 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -51,7 +51,7 @@
** standard negative debt for GC; a reasonable "time" to wait before
** starting a new cycle
*/
-#define stddebt(g) (-cast(l_mem, g->totalbytes/100) * g->gcpause)
+#define stddebt(g) (-cast(l_mem, gettotalbytes(g)/100) * g->gcpause)
/*
@@ -68,11 +68,15 @@
#define stringmark(s) ((void)((s) && resetbits((s)->tsv.marked, WHITEBITS)))
-#define isfinalized(u) testbit((u)->marked, FINALIZEDBIT)
+#define isfinalized(x) testbit(gch(x)->marked, FINALIZEDBIT)
#define checkdeadkey(n) lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n)))
+#define checkconsistency(obj) \
+ lua_longassert(!iscollectable(obj) || righttt(obj))
+
+
#define markvalue(g,o) { checkconsistency(o); \
if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }
@@ -114,12 +118,11 @@ static void removeentry (Node *n) {
*/
static int iscleared (const TValue *o, int iskey) {
if (!iscollectable(o)) return 0;
- if (ttisstring(o)) {
+ else if (ttisstring(o)) {
stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */
return 0;
}
- return iswhite(gcvalue(o)) ||
- (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o))));
+ else return iswhite(gcvalue(o)) || (!iskey && isfinalized(gcvalue(o)));
}
@@ -319,8 +322,7 @@ static void remarkupvals (global_State *g) {
** mark root set and reset all gray lists, to start a new
** incremental (or full) collection
*/
-static void markroot (lua_State *L) {
- global_State *g = G(L);
+static void markroot (global_State *g) {
g->gray = g->grayagain = NULL;
g->weak = g->allweak = g->ephemeron = NULL;
markobject(g, g->mainthread);
@@ -635,6 +637,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
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 */
+ l_mem debt = g->GCdebt; /* current debt */
if (isgenerational(g)) { /* generational mode? */
toclear = ~0; /* clear nothing */
toset = bitmask(OLDBIT); /* set the old bit of all surviving objects */
@@ -657,13 +660,15 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */
if (testbits(marked, tostop)) {
static GCObject *nullp = NULL;
- return &nullp; /* stop sweeping this list */
+ p = &nullp; /* stop sweeping this list */
+ break;
}
/* update marks */
gch(curr)->marked = cast_byte((marked & toclear) | toset);
p = &gch(curr)->next; /* go to next element */
}
}
+ luaE_setdebt(g, debt); /* sweeping should not change debt */
return p;
}
@@ -687,19 +692,17 @@ static void checkSizes (lua_State *L) {
}
-static Udata *udata2finalize (global_State *g) {
+static GCObject *udata2finalize (global_State *g) {
GCObject *o = g->tobefnz; /* get first element */
- Udata *u = rawgco2u(o);
- lua_assert(isfinalized(&u->uv));
- lua_assert(!isold(o));
- g->tobefnz = u->uv.next; /* remove it from 'tobefnz' list */
- u->uv.next = g->allgc; /* return it to 'allgc' list */
+ lua_assert(isfinalized(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(u->uv.marked, SEPARATED); /* mark that it is not in 'tobefnz' */
- resetoldbit(o); /* see MOVE OLD rule */
+ resetbit(gch(o)->marked, SEPARATED); /* mark that it is not in 'tobefnz' */
+ lua_assert(!isold(o)); /* see MOVE OLD rule */
if (!keepinvariant(g)) /* not keeping invariant? */
makewhite(g, o); /* "sweep" object */
- return u;
+ return o;
}
@@ -711,20 +714,22 @@ static void dothecall (lua_State *L, void *ud) {
static void GCTM (lua_State *L, int propagateerrors) {
global_State *g = G(L);
- Udata *udata = udata2finalize(g);
- const TValue *tm = gfasttm(g, udata->uv.metatable, TM_GC);
+ const TValue *tm;
+ TValue v;
+ setgcovalue(L, &v, udata2finalize(g));
+ tm = luaT_gettmbyobj(L, &v, TM_GC);
if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */
int status;
lu_byte oldah = L->allowhook;
- lu_mem oldd = g->GCdebt;
+ int running = g->gcrunning;
L->allowhook = 0; /* stop debug hooks during GC tag method */
- stopgc(g); /* avoid GC steps */
+ g->gcrunning = 0; /* avoid GC steps */
setobj2s(L, L->top, tm); /* push finalizer... */
- setuvalue(L, L->top+1, udata); /* ... and its argument */
+ setobj2s(L, L->top + 1, &v); /* ... and its argument */
L->top += 2; /* and (next line) call the finalizer */
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
L->allowhook = oldah; /* restore hooks */
- g->GCdebt = oldd; /* restore threshold */
+ g->gcrunning = running; /* restore state */
if (status != LUA_OK && propagateerrors) { /* error while running __gc? */
if (status == LUA_ERRRUN) { /* is there an error msg.? */
luaO_pushfstring(L, "error in __gc tag method (%s)",
@@ -738,25 +743,25 @@ static void GCTM (lua_State *L, int propagateerrors) {
/*
-** move all unreachable udata that need finalization from list 'udgc' to
-** list 'tobefnz'
+** move all unreachable objects that need finalization from list 'finobj'
+** to list 'tobefnz'
*/
void luaC_separateudata (lua_State *L, int all) {
global_State *g = G(L);
- GCObject **p = &g->udgc;
+ GCObject **p = &g->finobj;
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;
while ((curr = *p) != NULL) { /* traverse all finalizable objects */
- lua_assert(gch(curr)->tt == LUA_TUSERDATA && !isfinalized(gco2u(curr)));
+ lua_assert(!isfinalized(curr));
lua_assert(testbit(gch(curr)->marked, SEPARATED));
if (!(all || iswhite(curr))) /* not being collected? */
p = &gch(curr)->next; /* don't bother with it */
else {
l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */
- *p = gch(curr)->next; /* remove 'curr' from 'udgc' list */
+ *p = gch(curr)->next; /* remove 'curr' from 'finobj' list */
gch(curr)->next = *lastnext; /* link at the end of 'tobefnz' list */
*lastnext = curr;
lastnext = &gch(curr)->next;
@@ -766,23 +771,23 @@ void luaC_separateudata (lua_State *L, int all) {
/*
-** if userdata 'u' has a finalizer, remove it from 'allgc' list (must
-** search the list to find it) and link it in 'udgc' list.
+** if object 'o' has a finalizer, remove it from 'allgc' list (must
+** search the list to find it) and link it in 'finobj' list.
*/
-void luaC_checkfinalizer (lua_State *L, Udata *u) {
+void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
global_State *g = G(L);
- if (testbit(u->uv.marked, SEPARATED) || /* udata is already separated... */
- isfinalized(&u->uv) || /* ... or is finalized... */
- gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalizer? */
+ 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? */
return; /* nothing to be done */
- else { /* move 'u' to 'udgc' list */
+ else { /* move 'o' to 'finobj' list */
GCObject **p;
- for (p = &g->allgc; *p != obj2gco(u); p = &gch(*p)->next) ;
- *p = u->uv.next; /* remove 'u' from root list */
- u->uv.next = g->udgc; /* link it in list 'udgc' */
- g->udgc = obj2gco(u);
- l_setbit(u->uv.marked, SEPARATED); /* mark it as such */
- resetoldbit(obj2gco(u)); /* see MOVE OLD rule */
+ for (p = &g->allgc; *p != o; p = &gch(*p)->next) ;
+ *p = gch(o)->next; /* remove 'o' from root list */
+ gch(o)->next = g->finobj; /* link it in list 'finobj' */
+ g->finobj = o;
+ l_setbit(gch(o)->marked, SEPARATED); /* mark it as such */
+ resetoldbit(o); /* see MOVE OLD rule */
}
}
@@ -808,7 +813,7 @@ void luaC_changemode (lua_State *L, int mode) {
if (mode == KGC_GEN) { /* change to generational mode */
/* make sure gray lists are consistent */
luaC_runtilstate(L, bitmask(GCSpropagate));
- g->lastmajormem = g->totalbytes;
+ g->lastmajormem = gettotalbytes(g);
g->gckind = KGC_GEN;
}
else { /* change to incremental mode */
@@ -823,10 +828,14 @@ void luaC_changemode (lua_State *L, int mode) {
/*
-** call all pending finalizers */
+** call all pending finalizers
+*/
static void callallpendingfinalizers (lua_State *L, int propagateerrors) {
global_State *g = G(L);
- while (g->tobefnz) GCTM(L, propagateerrors);
+ while (g->tobefnz) {
+ resetoldbit(g->tobefnz);
+ GCTM(L, propagateerrors);
+ }
}
@@ -837,8 +846,8 @@ void luaC_freeallobjects (lua_State *L) {
/* following "white" makes all objects look dead */
g->currentwhite = WHITEBITS;
g->gckind = KGC_NORMAL;
- sweepwholelist(L, &g->udgc);
- lua_assert(g->udgc == NULL);
+ sweepwholelist(L, &g->finobj);
+ lua_assert(g->finobj == NULL);
sweepwholelist(L, &g->allgc);
lua_assert(g->allgc == NULL);
for (i = 0; i < g->strt.size; i++) /* free all string lists */
@@ -883,7 +892,7 @@ static l_mem singlestep (lua_State *L) {
switch (g->gcstate) {
case GCSpause: {
if (!isgenerational(g))
- markroot(L); /* start a new collection */
+ markroot(g); /* start a new collection */
/* in any case, root must be marked */
lua_assert(!iswhite(obj2gco(g->mainthread))
&& !iswhite(gcvalue(&g->l_registry)));
@@ -905,7 +914,7 @@ static l_mem singlestep (lua_State *L) {
return GCSWEEPCOST;
}
else { /* no more strings to sweep */
- g->sweepgc = &g->udgc; /* prepare to sweep userdata */
+ g->sweepgc = &g->finobj; /* prepare to sweep finalizable objects */
g->gcstate = GCSsweepudata;
return 0;
}
@@ -955,15 +964,15 @@ static void generationalcollection (lua_State *L) {
global_State *g = G(L);
if (g->lastmajormem == 0) { /* signal for another major collection? */
luaC_fullgc(L, 0); /* perform a full regular collection */
- g->lastmajormem = g->totalbytes; /* update control */
+ g->lastmajormem = gettotalbytes(g); /* update control */
}
else {
luaC_runtilstate(L, ~bitmask(GCSpause)); /* run complete cycle */
luaC_runtilstate(L, bitmask(GCSpause));
- if (g->totalbytes > g->lastmajormem/100 * g->gcmajorinc)
+ if (gettotalbytes(g) > g->lastmajormem/100 * g->gcmajorinc)
g->lastmajormem = 0; /* signal for a major collection */
}
- g->GCdebt = stddebt(g);
+ luaE_setdebt(g, stddebt(g));
}
@@ -974,22 +983,34 @@ static void step (lua_State *L) {
lim -= singlestep(L);
} while (lim > 0 && g->gcstate != GCSpause);
if (g->gcstate != GCSpause)
- g->GCdebt -= GCSTEPSIZE;
+ luaE_setdebt(g, g->GCdebt - GCSTEPSIZE);
else
- g->GCdebt = stddebt(g);
+ luaE_setdebt(g, stddebt(g));
}
-void luaC_step (lua_State *L) {
+/*
+** performs a basic GC step even if the collector is stopped
+*/
+void luaC_forcestep (lua_State *L) {
+ global_State *g = G(L);
int i;
- if (isgenerational(G(L))) generationalcollection(L);
+ if (isgenerational(g)) generationalcollection(L);
else step(L);
- for (i = 0; i < GCFINALIZENUM && G(L)->tobefnz; i++)
+ for (i = 0; i < GCFINALIZENUM && g->tobefnz; i++)
GCTM(L, 1); /* Call a few pending finalizers */
}
/*
+** performs a basic GC step only if collector is running
+*/
+void luaC_step (lua_State *L) {
+ if (G(L)->gcrunning) luaC_forcestep(L);
+}
+
+
+/*
** performs a full GC cycle; if "isemergency", does not call
** finalizers (which could change stack positions)
*/
@@ -1016,7 +1037,7 @@ void luaC_fullgc (lua_State *L, int isemergency) {
luaC_runtilstate(L, bitmask(GCSpropagate));
}
g->gckind = origkind;
- g->GCdebt = stddebt(g);
+ luaE_setdebt(g, stddebt(g));
if (!isemergency) /* do not run finalizers during emergency GC */
callallpendingfinalizers(L, 1);
}
diff --git a/src/lgc.h b/src/lgc.h
index 9c5b05e2..0fae4dd2 100644
--- a/src/lgc.h
+++ b/src/lgc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.h,v 2.44 2010/06/30 14:11:17 roberto Exp $
+** $Id: lgc.h,v 2.50 2011/01/26 16:30:02 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -52,10 +52,6 @@
#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic)
-#define gcstopped(g) ((g)->GCdebt == MIN_LMEM)
-#define stopgc(g) ((g)->GCdebt = MIN_LMEM)
-
-
/*
** some useful bit tricks
*/
@@ -76,8 +72,8 @@
#define WHITE0BIT 0 /* object is white (type 0) */
#define WHITE1BIT 1 /* object is white (type 1) */
#define BLACKBIT 2 /* object is black */
-#define FINALIZEDBIT 3 /* for userdata: has been finalized */
-#define SEPARATED 4 /* " ": it's in 'udgc' list or in 'tobefnz' */
+#define 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) */
/* bit 7 is currently used by tests (luaL_checkmemory) */
@@ -108,7 +104,9 @@
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
-#define luaC_checkGC(L) {condchangemem(L); if (G(L)->GCdebt > 0) luaC_step(L);}
+#define luaC_condGC(L,c) \
+ {if (G(L)->GCdebt > 0) {c;}; condchangemem(L);}
+#define luaC_checkGC(L) luaC_condGC(L, luaC_step(L);)
#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \
@@ -130,6 +128,7 @@
LUAI_FUNC void luaC_separateudata (lua_State *L, int all);
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L);
+LUAI_FUNC void luaC_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,
@@ -137,7 +136,7 @@ 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_checkfinalizer (lua_State *L, Udata *u);
+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);
diff --git a/src/linit.c b/src/linit.c
index fa944671..8d3aa657 100644
--- a/src/linit.c
+++ b/src/linit.c
@@ -1,16 +1,16 @@
/*
-** $Id: linit.c,v 1.30 2010/11/12 15:48:30 roberto Exp $
-** Initialization of libraries for lua.c and other clients
+** $Id: linit.c,v 1.32 2011/04/08 19:17:36 roberto Exp $
+** Initialization of libraries for lua.c and other clients
** See Copyright Notice in lua.h
*/
-/*
+/*
** If you embed Lua in your program and need to open the standard
** libraries, call luaL_openlibs in your program. If you need a
** different set of libraries, copy this file to your project and edit
** it to suit your needs.
-*/
+*/
#define linit_c
@@ -57,7 +57,7 @@ LUALIB_API void luaL_openlibs (lua_State *L) {
lua_pop(L, 1); /* remove lib */
}
/* add open functions from 'preloadedlibs' into 'package.preload' table */
- luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
+ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
for (lib = preloadedlibs; lib->func; lib++) {
lua_pushcfunction(L, lib->func);
lua_setfield(L, -2, lib->name);
diff --git a/src/liolib.c b/src/liolib.c
index 658601ad..ab1f1311 100644
--- a/src/liolib.c
+++ b/src/liolib.c
@@ -1,5 +1,5 @@
/*
-** $Id: liolib.c,v 2.95 2010/11/10 18:05:36 roberto Exp $
+** $Id: liolib.c,v 2.99 2011/03/03 16:34:46 roberto Exp $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
@@ -26,28 +26,29 @@
** lua_popen spawns a new process connected to the current one through
** the file streams.
*/
-#if !defined(lua_popen)
+#if !defined(lua_popen) /* { */
-#if defined(LUA_USE_POPEN)
+#if defined(LUA_USE_POPEN) /* { */
-#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m))
-#define lua_pclose(L,file) ((void)L, pclose(file))
+#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m))
+#define lua_pclose(L,file) ((void)L, pclose(file))
-#elif defined(LUA_WIN)
+#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 lua_popen(L,c,m) ((void)L, _popen(c,m))
+#define lua_pclose(L,file) ((void)L, _pclose(file))
-#else
-#define lua_popen(L,c,m) ((void)((void)c, m), \
- luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0)
-#define lua_pclose(L,file) ((void)((void)L, file), -1)
+#else /* }{ */
-#endif
+#define lua_popen(L,c,m) ((void)((void)c, m), \
+ luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0)
+#define lua_pclose(L,file) ((void)((void)L, file), -1)
-#endif
+#endif /* } */
+
+#endif /* } */
#define IO_INPUT 1
@@ -57,24 +58,6 @@
static const char *const fnames[] = {"input", "output"};
-static int pushresult (lua_State *L, int i, const char *filename) {
- int en = errno; /* calls to Lua API may change this value */
- if (i) {
- lua_pushboolean(L, 1);
- return 1;
- }
- else {
- lua_pushnil(L);
- if (filename)
- lua_pushfstring(L, "%s: %s", filename, strerror(en));
- else
- lua_pushfstring(L, "%s", strerror(en));
- lua_pushinteger(L, en);
- return 3;
- }
-}
-
-
static void fileerror (lua_State *L, int arg, const char *filename) {
lua_pushfstring(L, "%s: %s", filename, strerror(errno));
luaL_argerror(L, arg, lua_tostring(L, -1));
@@ -143,13 +126,8 @@ static int io_noclose (lua_State *L) {
static int io_pclose (lua_State *L) {
FILE **p = tofilep(L);
int stat = lua_pclose(L, *p);
- *p = NULL;
- if (stat == -1) /* error? */
- return pushresult(L, 0, NULL);
- else {
- lua_pushinteger(L, stat);
- return 1; /* return status */
- }
+ *p = NULL; /* mark stream as closed (for GC) */
+ return luaL_execresult(L, stat);
}
@@ -159,8 +137,8 @@ static int io_pclose (lua_State *L) {
static int io_fclose (lua_State *L) {
FILE **p = tofilep(L);
int ok = (fclose(*p) == 0);
- *p = NULL;
- return pushresult(L, ok, NULL);
+ *p = NULL; /* mark stream as closed (for GC) */
+ return luaL_fileresult(L, ok, NULL);
}
@@ -181,8 +159,7 @@ static int io_close (lua_State *L) {
static int io_gc (lua_State *L) {
FILE *f = *tofilep(L);
- /* ignore closed files */
- if (f != NULL)
+ if (f != NULL) /* ignore closed files */
aux_close(L);
return 0;
}
@@ -205,14 +182,14 @@ static int io_open (lua_State *L) {
int i = 0;
/* check whether 'mode' matches '[rwa]%+?b?' */
if (!(mode[i] != '\0' && strchr("rwa", mode[i++]) != NULL &&
- (mode[i] != '+' || ++i) && /* skip if char is '+' */
- (mode[i] != 'b' || ++i) && /* skip if char is 'b' */
+ (mode[i] != '+' || ++i) && /* skip if char is '+' */
+ (mode[i] != 'b' || ++i) && /* skip if char is 'b' */
(mode[i] == '\0')))
luaL_error(L, "invalid mode " LUA_QL("%s")
" (should match " LUA_QL("[rwa]%%+?b?") ")", mode);
pf = newfile(L);
*pf = fopen(filename, mode);
- return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
+ return (*pf == NULL) ? luaL_fileresult(L, 0, filename) : 1;
}
@@ -225,14 +202,14 @@ static int io_popen (lua_State *L) {
const char *mode = luaL_optstring(L, 2, "r");
FILE **pf = newfile(L);
*pf = lua_popen(L, filename, mode);
- return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
+ return (*pf == NULL) ? luaL_fileresult(L, 0, filename) : 1;
}
static int io_tmpfile (lua_State *L) {
FILE **pf = newfile(L);
*pf = tmpfile();
- return (*pf == NULL) ? pushresult(L, 0, NULL) : 1;
+ return (*pf == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
}
@@ -305,7 +282,7 @@ static int io_lines (lua_State *L) {
if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */
if (lua_isnil(L, 1)) { /* no file name? */
lua_rawgeti(L, lua_upvalueindex(1), IO_INPUT); /* get default input */
- lua_replace(L, 1); /* put it at index 1 */
+ lua_replace(L, 1); /* put it at index 1 */
tofile(L); /* check that it's a valid file handle */
toclose = 0; /* do not close it after iteration */
}
@@ -315,7 +292,7 @@ static int io_lines (lua_State *L) {
*pf = fopen(filename, "r");
if (*pf == NULL)
fileerror(L, 1, filename);
- lua_replace(L, 1); /* put file at index 1 */
+ lua_replace(L, 1); /* put file at index 1 */
toclose = 1; /* close it after iteration */
}
aux_lines(L, toclose);
@@ -443,7 +420,7 @@ static int g_read (lua_State *L, FILE *f, int first) {
}
}
if (ferror(f))
- return pushresult(L, 0, NULL);
+ return luaL_fileresult(L, 0, NULL);
if (!success) {
lua_pop(L, 1); /* remove last result */
lua_pushnil(L); /* push nil instead */
@@ -507,7 +484,7 @@ static int g_write (lua_State *L, FILE *f, int arg) {
}
}
if (status) return 1; /* file handle already on stack top */
- else return pushresult(L, status, NULL);
+ else return luaL_fileresult(L, status, NULL);
}
@@ -517,7 +494,7 @@ static int io_write (lua_State *L) {
static int f_write (lua_State *L) {
- FILE * f = tofile(L);
+ FILE * f = tofile(L);
lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */
return g_write(L, f, 2);
}
@@ -531,7 +508,7 @@ static int f_seek (lua_State *L) {
long offset = luaL_optlong(L, 3, 0);
op = fseek(f, offset, mode[op]);
if (op)
- return pushresult(L, 0, NULL); /* error */
+ return luaL_fileresult(L, 0, NULL); /* error */
else {
lua_pushinteger(L, ftell(f));
return 1;
@@ -546,18 +523,18 @@ static int f_setvbuf (lua_State *L) {
int op = luaL_checkoption(L, 2, NULL, modenames);
lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
int res = setvbuf(f, NULL, mode[op], sz);
- return pushresult(L, res == 0, NULL);
+ return luaL_fileresult(L, res == 0, NULL);
}
static int io_flush (lua_State *L) {
- return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
+ return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
}
static int f_flush (lua_State *L) {
- return pushresult(L, fflush(tofile(L)) == 0, NULL);
+ return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL);
}
diff --git a/src/llex.c b/src/llex.c
index 9980af71..7d034b0a 100644
--- a/src/llex.c
+++ b/src/llex.c
@@ -1,5 +1,5 @@
/*
-** $Id: llex.c,v 2.41 2010/11/18 18:38:44 roberto Exp $
+** $Id: llex.c,v 2.47 2011/05/03 15:51:16 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -35,7 +35,7 @@
/* ORDER RESERVED */
static const char *const luaX_tokens [] = {
"and", "break", "do", "else", "elseif",
- "end", "false", "for", "function", "if",
+ "end", "false", "for", "function", "goto", "if",
"in", "local", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while",
"..", "...", "==", ">=", "<=", "~=", "<eof>",
@@ -67,7 +67,6 @@ void luaX_init (lua_State *L) {
for (i=0; i<NUM_RESERVED; i++) {
TString *ts = luaS_new(L, luaX_tokens[i]);
luaS_fix(ts); /* reserved words are never collected */
- lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN);
ts->tsv.reserved = cast_byte(i+1); /* reserved word */
}
}
@@ -127,7 +126,7 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t 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_setstr(L, ls->fs->h, ts);
+ o = luaH_setstr(L, ls->fs->h, ts);
if (ttisnil(o)) {
setbvalue(o, 1); /* t[string] = true */
luaC_checkGC(L);
@@ -152,9 +151,11 @@ static void inclinenumber (LexState *ls) {
}
-void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) {
+void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
+ int firstchar) {
ls->decpoint = '.';
ls->L = L;
+ ls->current = firstchar;
ls->lookahead.token = TK_EOS; /* no look-ahead token */
ls->z = z;
ls->fs = NULL;
@@ -164,7 +165,6 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) {
ls->envn = luaS_new(L, LUA_ENV); /* create env name */
luaS_fix(ls->envn); /* never collect this name */
luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
- next(ls); /* read first char */
}
@@ -185,7 +185,7 @@ static int check_next (LexState *ls, const char *set) {
}
-/*
+/*
** change all characters 'from' in buffer to 'to'
*/
static void buffreplace (LexState *ls, char from, char to) {
@@ -200,6 +200,9 @@ static void buffreplace (LexState *ls, char from, char to) {
#define getlocaledecpoint() (localeconv()->decimal_point[0])
#endif
+
+#define buff2d(b,e) luaO_str2d(luaZ_buffer(b), luaZ_bufflen(b) - 1, e)
+
/*
** in case of format error, try to change decimal point separator to
** the one defined in the current locale and check again
@@ -208,7 +211,7 @@ static void trydecpoint (LexState *ls, SemInfo *seminfo) {
char old = ls->decpoint;
ls->decpoint = getlocaledecpoint();
buffreplace(ls, old, ls->decpoint); /* try new decimal separator */
- if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) {
+ if (!buff2d(ls->buff, &seminfo->r)) {
/* format error with correct decimal point: no more options */
buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */
lexerror(ls, "malformed number", TK_NUMBER);
@@ -226,7 +229,7 @@ static void read_numeral (LexState *ls, SemInfo *seminfo) {
} while (lislalnum(ls->current) || ls->current == '.');
save(ls, '\0');
buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
- if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) /* format error? */
+ if (!buff2d(ls->buff, &seminfo->r)) /* format error? */
trydecpoint(ls, seminfo); /* try to update decimal point separator */
}
@@ -283,13 +286,6 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
}
-static int hexavalue (int c) {
- if (lisdigit(c)) return c - '0';
- else if (lisupper(c)) return c - 'A' + 10;
- else return c - 'a' + 10;
-}
-
-
static int readhexaesc (LexState *ls) {
int c1, c2 = EOZ;
if (!lisxdigit(c1 = next(ls)) || !lisxdigit(c2 = next(ls))) {
@@ -299,7 +295,7 @@ static int readhexaesc (LexState *ls) {
if (c2 != EOZ) save(ls, c2);
lexerror(ls, "hexadecimal digit expected", TK_STRING);
}
- return (hexavalue(c1) << 4) + hexavalue(c2);
+ return (luaO_hexavalue(c1) << 4) + luaO_hexavalue(c2);
}
diff --git a/src/llex.h b/src/llex.h
index 1a811dce..5edbbc1d 100644
--- a/src/llex.h
+++ b/src/llex.h
@@ -1,5 +1,5 @@
/*
-** $Id: llex.h,v 1.65 2010/04/05 16:35:37 roberto Exp $
+** $Id: llex.h,v 1.70 2011/05/03 15:51:16 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -13,8 +13,6 @@
#define FIRST_RESERVED 257
-/* maximum length of a reserved word */
-#define TOKEN_LEN (sizeof("function")/sizeof(char))
/*
@@ -25,7 +23,7 @@ enum RESERVED {
/* terminal symbols denoted by reserved words */
TK_AND = FIRST_RESERVED, TK_BREAK,
TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
- TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
+ TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
/* other terminal symbols */
TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_EOS,
@@ -48,17 +46,19 @@ typedef struct Token {
} Token;
+/* state of the lexer plus state of the parser when shared by all
+ functions */
typedef struct LexState {
int current; /* current character (charint) */
int linenumber; /* input line counter */
int lastline; /* line of last token `consumed' */
Token t; /* current token */
Token lookahead; /* look ahead token */
- struct FuncState *fs; /* `FuncState' is private to the parser */
+ struct FuncState *fs; /* current function (parser) */
struct lua_State *L;
ZIO *z; /* input stream */
Mbuffer *buff; /* buffer for tokens */
- struct Varlist *varl; /* list of all active local variables */
+ struct Dyndata *dyd; /* dynamic structures used by the parser */
TString *source; /* current source name */
TString *envn; /* environment variable name */
char decpoint; /* locale decimal point */
@@ -67,7 +67,7 @@ typedef struct LexState {
LUAI_FUNC void luaX_init (lua_State *L);
LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z,
- TString *source);
+ TString *source, int firstchar);
LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l);
LUAI_FUNC void luaX_next (LexState *ls);
LUAI_FUNC int luaX_lookahead (LexState *ls);
diff --git a/src/llimits.h b/src/llimits.h
index f8ede143..b5714413 100644
--- a/src/llimits.h
+++ b/src/llimits.h
@@ -1,5 +1,5 @@
/*
-** $Id: llimits.h,v 1.84 2010/11/08 16:33:20 roberto Exp $
+** $Id: llimits.h,v 1.89 2011/05/05 19:43:14 roberto Exp $
** Limits, basic types, and some other `installation-dependent' definitions
** See Copyright Notice in lua.h
*/
@@ -59,9 +59,12 @@ typedef LUAI_UACNUMBER l_uacNumber;
/* internal assertions for in-house debugging */
#if defined(lua_assert)
#define check_exp(c,e) (lua_assert(c), (e))
+/* to avoid problems with conditions too long */
+#define lua_longassert(c) { if (!(c)) lua_assert(0); }
#else
#define lua_assert(c) /* empty */
#define check_exp(c,e) (e)
+#define lua_longassert(c) /* empty */
#endif
/*
@@ -87,6 +90,7 @@ typedef LUAI_UACNUMBER l_uacNumber;
#define cast_byte(i) cast(lu_byte, (i))
#define cast_num(i) cast(lua_Number, (i))
#define cast_int(i) cast(int, (i))
+#define cast_uchar(i) cast(unsigned char, (i))
/*
@@ -173,6 +177,9 @@ typedef lu_int32 Instruction;
** lua_number2integer is a macro to convert lua_Number to lua_Integer.
** lua_number2unsigned is a macro to convert a lua_Number to a lua_Unsigned.
** lua_unsigned2number is a macro to convert a lua_Unsigned to a lua_Number.
+** luai_hashnum is a macro to hash a lua_Number value into an integer.
+** The hash must be deterministic and give reasonable values for
+** both small and large values (outside the range of integers).
*/
#if defined(MS_ASMTRICK) /* { */
@@ -203,6 +210,10 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; };
volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \
(i) = (t)u.l_p[LUA_IEEEENDIAN]; }
+#define luai_hashnum(i,n) \
+ { volatile union luai_Cast u; u.l_d = (n) + 1.0; /* avoid -0 */ \
+ (i) = u.l_p[0] + u.l_p[1]; } /* add double bits for his hash */
+
#define lua_number2int(i,n) lua_number2int32(i, n, int)
#define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer)
#define lua_number2unsigned(i,n) lua_number2int32(i, n, lua_Unsigned)
@@ -241,14 +252,8 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; };
#endif
-/*
-** luai_hashnum is a macro do hash a lua_Number value into an integer.
-** The hash must be deterministic and give reasonable values for
-** both small and large values (outside the range of integers).
-** It is used only in ltable.c.
-*/
-#if !defined(luai_hashnum) /* { */
+#if (defined(ltable_c) || defined(luaall_c)) && !defined(luai_hashnum)
#include <float.h>
#include <math.h>
@@ -257,7 +262,7 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; };
n = frexp(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \
lua_number2int(i, n); i += e; }
-#endif /* } */
+#endif
@@ -275,7 +280,7 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; };
#define condchangemem(L) condmovestack(L)
#else
#define condchangemem(L) \
- ((void)(gcstopped(G(L)) || (luaC_fullgc(L, 0), 1)))
+ ((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1)))
#endif
#endif
diff --git a/src/lmem.c b/src/lmem.c
index 0f3178a2..c3775dfb 100644
--- a/src/lmem.c
+++ b/src/lmem.c
@@ -1,5 +1,5 @@
/*
-** $Id: lmem.c,v 1.79 2010/05/05 18:49:56 roberto Exp $
+** $Id: lmem.c,v 1.81 2010/12/20 19:40:07 roberto Exp $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
@@ -79,14 +79,14 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
size_t realosize = (block) ? osize : 0;
lua_assert((realosize == 0) == (block == NULL));
#if defined(HARDMEMTESTS)
- if (nsize > realosize && !gcstopped(g))
+ if (nsize > realosize && g->gcrunning)
luaC_fullgc(L, 1); /* force a GC whenever possible */
#endif
newblock = (*g->frealloc)(g->ud, block, osize, nsize);
if (newblock == NULL && nsize > 0) {
api_check(L, nsize > realosize,
"realloc cannot fail when shrinking a block");
- if (!gcstopped(g)) {
+ if (g->gcrunning) {
luaC_fullgc(L, 1); /* try to free some memory... */
newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
}
@@ -94,9 +94,7 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
luaD_throw(L, LUA_ERRMEM);
}
lua_assert((nsize == 0) == (newblock == NULL));
- g->totalbytes = (g->totalbytes - realosize) + nsize;
- if (!gcstopped(g))
- g->GCdebt += nsize; /* give some credit to garbage collector */
+ g->GCdebt = (g->GCdebt + nsize) - realosize;
#if defined(TRACEMEM)
{ /* auxiliary patch to monitor garbage collection.
** To plot, gnuplot with following command:
@@ -108,9 +106,7 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
if ((total % 200) == 0) {
if (f == NULL) f = fopen(TRACEMEM, "w");
fprintf(f, "%lu %u %d %d\n", total,
- g->totalbytes,
- gcstopped(g) ? 0 : g->GCdebt,
- g->gcstate * 1000);
+ g->totalbytes, g->GCdebt, g->gcstate * 1000);
}
}
#endif
diff --git a/src/loadlib.c b/src/loadlib.c
index 3e5eaecf..ce3c2e6e 100644
--- a/src/loadlib.c
+++ b/src/loadlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: loadlib.c,v 1.94 2010/11/10 20:00:04 roberto Exp $
+** $Id: loadlib.c,v 1.98 2011/04/08 19:17:36 roberto Exp $
** Dynamic library loader for Lua
** See Copyright Notice in lua.h
**
@@ -164,7 +164,7 @@ static void pusherror (lua_State *L) {
int error = GetLastError();
char buffer[128];
if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, error, 0, buffer, sizeof(buffer), NULL))
+ NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL))
lua_pushstring(L, buffer);
else
lua_pushfstring(L, "system error %d\n", error);
@@ -321,8 +321,10 @@ static const char *pushnexttemplate (lua_State *L, const char *path) {
static const char *searchpath (lua_State *L, const char *name,
- const char *path) {
- name = luaL_gsub(L, name, ".", LUA_DIRSEP);
+ const char *path,
+ const char *sep) {
+ if (*sep != '\0') /* non-empty separator? */
+ name = luaL_gsub(L, name, sep, LUA_DIRSEP); /* replace it by proper one */
lua_pushliteral(L, ""); /* error accumulator */
while ((path = pushnexttemplate(L, path)) != NULL) {
const char *filename = luaL_gsub(L, lua_tostring(L, -1),
@@ -339,7 +341,9 @@ static const char *searchpath (lua_State *L, const char *name,
static int ll_searchpath (lua_State *L) {
- const char *f = searchpath(L, luaL_checkstring(L, 1), luaL_checkstring(L, 2));
+ const char *f = searchpath(L, luaL_checkstring(L, 1),
+ luaL_checkstring(L, 2),
+ luaL_optstring(L, 3, "."));
if (f != NULL) return 1;
else { /* error message is on top of the stack */
lua_pushnil(L);
@@ -356,13 +360,19 @@ static const char *findfile (lua_State *L, const char *name,
path = lua_tostring(L, -1);
if (path == NULL)
luaL_error(L, LUA_QL("package.%s") " must be a string", pname);
- return searchpath(L, name, path);
+ return searchpath(L, name, path, ".");
}
-static void loaderror (lua_State *L, const char *filename) {
- luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s",
- lua_tostring(L, 1), filename, lua_tostring(L, -1));
+static int checkload (lua_State *L, int stat, const char *filename) {
+ if (stat) { /* module loaded successfully? */
+ lua_pushstring(L, filename); /* will be 2nd argument to module */
+ return 2; /* return open function and file name */
+ }
+ else
+ return luaL_error(L, "error loading module " LUA_QS
+ " from file " LUA_QS ":\n\t%s",
+ lua_tostring(L, 1), filename, lua_tostring(L, -1));
}
@@ -370,10 +380,8 @@ static int loader_Lua (lua_State *L) {
const char *filename;
const char *name = luaL_checkstring(L, 1);
filename = findfile(L, name, "path");
- if (filename == NULL) return 1; /* library not found in this path */
- if (luaL_loadfile(L, filename) != LUA_OK)
- loaderror(L, filename);
- return 1; /* library loaded successfully */
+ if (filename == NULL) return 1; /* module not found in this path */
+ return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename);
}
@@ -398,10 +406,8 @@ static int loadfunc (lua_State *L, const char *filename, const char *modname) {
static int loader_C (lua_State *L) {
const char *name = luaL_checkstring(L, 1);
const char *filename = findfile(L, name, "cpath");
- if (filename == NULL) return 1; /* library not found in this path */
- if (loadfunc(L, filename, name) != 0)
- loaderror(L, filename);
- return 1; /* library loaded successfully */
+ if (filename == NULL) return 1; /* module not found in this path */
+ return checkload(L, (loadfunc(L, filename, name) == 0), filename);
}
@@ -415,12 +421,16 @@ static int loader_Croot (lua_State *L) {
filename = findfile(L, lua_tostring(L, -1), "cpath");
if (filename == NULL) return 1; /* root not found */
if ((stat = loadfunc(L, filename, name)) != 0) {
- if (stat != ERRFUNC) loaderror(L, filename); /* real error */
- lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS,
- name, filename);
- return 1; /* function not found */
+ if (stat != ERRFUNC)
+ return checkload(L, 0, filename); /* real error */
+ else { /* open function not found */
+ lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS,
+ name, filename);
+ return 1;
+ }
}
- return 1;
+ lua_pushstring(L, filename); /* will be 2nd argument to module */
+ return 2;
}
@@ -453,16 +463,19 @@ static int ll_require (lua_State *L) {
luaL_error(L, "module " LUA_QS " not found:%s",
name, lua_tostring(L, -2));
lua_pushstring(L, name);
- lua_call(L, 1, 1); /* call it */
- if (lua_isfunction(L, -1)) /* did it find module? */
+ lua_call(L, 1, 2); /* call it */
+ if (lua_isfunction(L, -2)) /* did it find module? */
break; /* module loaded successfully */
- else if (lua_isstring(L, -1)) /* loader returned error message? */
- lua_concat(L, 2); /* accumulate it */
+ else if (lua_isstring(L, -2)) { /* loader returned error message? */
+ lua_pop(L, 1); /* remove extra return */
+ lua_concat(L, 2); /* accumulate error message */
+ }
else
- lua_pop(L, 1);
+ lua_pop(L, 2); /* remove both returns */
}
lua_pushstring(L, name); /* pass name as argument to module */
- lua_call(L, 1, 1); /* run loaded module */
+ lua_insert(L, -2); /* name is 1st argument (before search data) */
+ lua_call(L, 2, 1); /* run loaded module */
if (!lua_isnil(L, -1)) /* non-nil return? */
lua_setfield(L, 2, name); /* _LOADED[name] = returned value */
lua_getfield(L, 2, name);
@@ -639,10 +652,10 @@ LUAMOD_API int luaopen_package (lua_State *L) {
LUA_EXEC_DIR "\n" LUA_IGMARK "\n");
lua_setfield(L, -2, "config");
/* set field `loaded' */
- luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED");
+ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
lua_setfield(L, -2, "loaded");
/* set field `preload' */
- luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
+ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
lua_setfield(L, -2, "preload");
lua_pushglobaltable(L);
lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */
diff --git a/src/lobject.c b/src/lobject.c
index f5fc09d7..dcc487ca 100644
--- a/src/lobject.c
+++ b/src/lobject.c
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.c,v 2.43 2010/10/29 15:54:55 roberto Exp $
+** $Id: lobject.c,v 2.49 2011/05/31 18:24:36 roberto Exp $
** Some generic functions over Lua objects
** See Copyright Notice in lua.h
*/
@@ -70,28 +70,6 @@ int luaO_ceillog2 (unsigned int x) {
}
-int luaO_rawequalObj (const TValue *t1, const TValue *t2) {
- if (ttype(t1) != ttype(t2)) return 0;
- else switch (ttype(t1)) {
- case LUA_TNIL:
- return 1;
- case LUA_TNUMBER:
- return luai_numeq(nvalue(t1), nvalue(t2));
- case LUA_TBOOLEAN:
- return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */
- case LUA_TLIGHTUSERDATA:
- return pvalue(t1) == pvalue(t2);
- case LUA_TSTRING:
- return rawtsvalue(t1) == rawtsvalue(t2);
- case LUA_TLCF:
- return fvalue(t1) == fvalue(t2);
- default:
- lua_assert(iscollectable(t1));
- return gcvalue(t1) == gcvalue(t2);
- }
-}
-
-
lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) {
switch (op) {
case LUA_OPADD: return luai_numadd(NULL, v1, v2);
@@ -106,19 +84,87 @@ lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) {
}
-static int checkend (const char *s, const char *endptr) {
- if (endptr == s) return 0; /* no characters converted */
- while (lisspace(cast(unsigned char, *endptr))) endptr++;
- return (*endptr == '\0'); /* OK if no trailing characters */
+int luaO_hexavalue (int c) {
+ if (lisdigit(c)) return c - '0';
+ else if (lisupper(c)) return c - 'A' + 10;
+ else return c - 'a' + 10;
+}
+
+
+#if !defined(lua_strx2number)
+
+#include <math.h>
+
+
+static int isneg (const char **s) {
+ if (**s == '-') { (*s)++; return 1; }
+ else if (**s == '+') (*s)++;
+ return 0;
}
-int luaO_str2d (const char *s, lua_Number *result) {
+static lua_Number readhexa (const char **s, lua_Number r, int *count) {
+ while (lisxdigit(cast_uchar(**s))) { /* read integer part */
+ r = (r * 16.0) + (double)luaO_hexavalue(*(*s)++);
+ (*count)++;
+ }
+ return r;
+}
+
+
+/*
+** convert an hexadecimal numeric string to a number, following
+** C99 specification for 'strtod'
+*/
+static lua_Number lua_strx2number (const char *s, char **endptr) {
+ lua_Number r = 0.0;
+ int e = 0, i = 0;
+ int neg = 0; /* 1 if number is negative */
+ *endptr = cast(char *, s); /* nothing is valid yet */
+ while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */
+ neg = isneg(&s); /* check signal */
+ if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */
+ return 0.0; /* invalid format (no '0x') */
+ s += 2; /* skip '0x' */
+ r = readhexa(&s, r, &i); /* read integer part */
+ if (*s == '.') {
+ s++; /* skip dot */
+ r = readhexa(&s, r, &e); /* read fractional part */
+ }
+ if (i == 0 && e == 0)
+ return 0.0; /* invalid format (no digit) */
+ e *= -4; /* each fractional digit divides value by 2^-4 */
+ *endptr = cast(char *, s); /* valid up to here */
+ if (*s == 'p' || *s == 'P') { /* exponent part? */
+ int exp1 = 0;
+ int neg1;
+ s++; /* skip 'p' */
+ neg1 = isneg(&s); /* signal */
+ if (!lisdigit(cast_uchar(*s)))
+ goto ret; /* must have at least one digit */
+ while (lisdigit(cast_uchar(*s))) /* read exponent */
+ exp1 = exp1 * 10 + *(s++) - '0';
+ if (neg1) exp1 = -exp1;
+ e += exp1;
+ }
+ *endptr = cast(char *, s); /* valid up to here */
+ ret:
+ if (neg) r = -r;
+ return ldexp(r, e);
+}
+
+#endif
+
+
+int luaO_str2d (const char *s, size_t len, lua_Number *result) {
char *endptr;
- *result = lua_str2number(s, &endptr);
- if (checkend(s, endptr)) return 1; /* conversion OK? */
- *result = cast_num(strtoul(s, &endptr, 0)); /* try hexadecimal */
- return checkend(s, endptr);
+ if (strpbrk(s, "xX")) /* hexa? */
+ *result = lua_strx2number(s, &endptr);
+ else
+ *result = lua_str2number(s, &endptr);
+ if (endptr == s) return 0; /* nothing recognized */
+ while (lisspace(cast_uchar(*endptr))) endptr++;
+ return (endptr == s + len); /* OK if no trailing characters */
}
@@ -196,19 +242,20 @@ const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) {
}
+/* number of chars of a literal string without the ending \0 */
+#define LL(x) (sizeof(x)/sizeof(char) - 1)
-#define LL(x) (sizeof(x) - 1)
#define RETS "..."
#define PRE "[string \""
#define POS "\"]"
-#define addstr(a,b,l) ( memcpy(a,b,l), a += (l) )
+#define addstr(a,b,l) ( memcpy(a,b,(l) * sizeof(char)), a += (l) )
void luaO_chunkid (char *out, const char *source, size_t bufflen) {
size_t l = strlen(source);
if (*source == '=') { /* 'literal' source */
if (l <= bufflen) /* small enough? */
- memcpy(out, source + 1, l);
+ memcpy(out, source + 1, l * sizeof(char));
else { /* truncate it */
addstr(out, source + 1, bufflen - 1);
*out = '\0';
@@ -216,11 +263,11 @@ void luaO_chunkid (char *out, const char *source, size_t bufflen) {
}
else if (*source == '@') { /* file name */
if (l <= bufflen) /* small enough? */
- memcpy(out, source + 1, l);
+ memcpy(out, source + 1, l * sizeof(char));
else { /* add '...' before rest of name */
addstr(out, RETS, LL(RETS));
bufflen -= LL(RETS);
- memcpy(out, source + 1 + l - bufflen, bufflen);
+ memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char));
}
}
else { /* string; format as [string "source"] */
@@ -236,6 +283,7 @@ void luaO_chunkid (char *out, const char *source, size_t bufflen) {
addstr(out, source, l);
addstr(out, RETS, LL(RETS));
}
- memcpy(out, POS, LL(POS) + 1);
+ memcpy(out, POS, (LL(POS) + 1) * sizeof(char));
}
}
+
diff --git a/src/lobject.h b/src/lobject.h
index 5b856f3c..7f7a6830 100644
--- a/src/lobject.h
+++ b/src/lobject.h
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.h,v 2.42 2010/07/26 15:53:23 roberto Exp $
+** $Id: lobject.h,v 2.60 2011/06/13 14:13:06 roberto Exp $
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
@@ -23,12 +23,38 @@
#define LUA_TUPVAL (LUA_NUMTAGS+1)
#define LUA_TDEADKEY (LUA_NUMTAGS+2)
+/*
+** number of all possible tags (including LUA_TNONE but excluding DEADKEY)
+*/
+#define LUA_TOTALTAGS (LUA_TUPVAL+2)
+
+
+/*
+** tags for Tagged Values have the following use of bits:
+** bits 0-3: actual tag (a LUA_T* value)
+** bits 4-5: variant bits
+** bit 6: whether value is collectable
+*/
/*
-** Variant tag for light C functions (negative to be considered
-** non collectable by 'iscollectable')
+** LUA_TFUNCTION variants:
+** 0 - Lua function
+** 1 - light C function
+** 2 - regular C function (closure)
*/
-#define LUA_TLCF (~0x0F | LUA_TFUNCTION)
+
+/* Variant tags for functions */
+#define LUA_TLCL (LUA_TFUNCTION | (0 << 4)) /* Lua closure */
+#define LUA_TLCF (LUA_TFUNCTION | (1 << 4)) /* light C function */
+#define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) /* C closure */
+
+
+/* Bit mark for collectable types */
+#define BIT_ISCOLLECTABLE (1 << 6)
+
+/* mark a tag as collectable */
+#define ctb(t) ((t) | BIT_ISCOLLECTABLE)
+
/*
** Union of all collectable objects
@@ -55,13 +81,10 @@ typedef struct GCheader {
/*
** Union of all Lua values
*/
-typedef union {
- GCObject *gc; /* collectable objects */
- void *p; /* light userdata */
- lua_Number n; /* numbers */
- int b; /* booleans */
- lua_CFunction f; /* light C functions */
-} Value;
+typedef union Value Value;
+
+
+#define numfield lua_Number n; /* numbers */
@@ -72,125 +95,143 @@ typedef union {
#define TValuefields Value value_; int tt_
-typedef struct lua_TValue {
- TValuefields;
-} TValue;
+typedef struct lua_TValue TValue;
/* macro defining a nil value */
-#define NILCONSTANT {NULL}, LUA_TNIL
+#define NILCONSTANT {NULL}, LUA_TNIL
-/*
-** type tag of a TValue
-*/
-#define ttype(o) ((o)->tt_)
+#define val_(o) ((o)->value_)
+#define num_(o) (val_(o).n)
-/*
-** type tag of a TValue with no variants
-*/
-#define ttypenv(o) (ttype(o) & 0x0F)
+/* raw type tag of a TValue */
+#define rttype(o) ((o)->tt_)
+
+/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */
+#define ttype(o) (rttype(o) & 0x3F)
+
+
+/* type tag of a TValue with no variants (bits 0-3) */
+#define ttypenv(o) (rttype(o) & 0x0F)
/* Macros to test type */
-#define ttisnil(o) (ttype(o) == LUA_TNIL)
-#define ttisnumber(o) (ttype(o) == LUA_TNUMBER)
-#define ttisstring(o) (ttype(o) == LUA_TSTRING)
-#define ttistable(o) (ttype(o) == LUA_TTABLE)
-#define ttisfunction(o) (ttypenv(o) == LUA_TFUNCTION)
-#define ttisclosure(o) (ttype(o) == LUA_TFUNCTION)
-#define ttislcf(o) (ttype(o) == LUA_TLCF)
-#define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN)
-#define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA)
-#define ttisthread(o) (ttype(o) == LUA_TTHREAD)
-#define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA)
-#define ttisdeadkey(o) (ttype(o) == LUA_TDEADKEY)
+#define checktag(o,t) (rttype(o) == (t))
+#define ttisnumber(o) checktag((o), LUA_TNUMBER)
+#define ttisnil(o) checktag((o), LUA_TNIL)
+#define ttisboolean(o) checktag((o), LUA_TBOOLEAN)
+#define ttislightuserdata(o) checktag((o), LUA_TLIGHTUSERDATA)
+#define ttisstring(o) checktag((o), ctb(LUA_TSTRING))
+#define ttistable(o) checktag((o), ctb(LUA_TTABLE))
+#define ttisfunction(o) (ttypenv(o) == LUA_TFUNCTION)
+#define ttisclosure(o) ((rttype(o) & 0x1F) == LUA_TFUNCTION)
+#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 ttisthread(o) checktag((o), ctb(LUA_TTHREAD))
+#define ttisdeadkey(o) checktag((o), ctb(LUA_TDEADKEY))
+
+#define ttisequal(o1,o2) (rttype(o1) == rttype(o2))
/* Macros to access values */
-#define gcvalue(o) check_exp(iscollectable(o), (o)->value_.gc)
-#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value_.p)
-#define nvalue(o) check_exp(ttisnumber(o), (o)->value_.n)
-#define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value_.gc->ts)
+#define nvalue(o) check_exp(ttisnumber(o), num_(o))
+#define gcvalue(o) check_exp(iscollectable(o), val_(o).gc)
+#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), &(o)->value_.gc->u)
+#define rawuvalue(o) check_exp(ttisuserdata(o), &val_(o).gc->u)
#define uvalue(o) (&rawuvalue(o)->uv)
-#define clvalue(o) check_exp(ttisclosure(o), &(o)->value_.gc->cl)
-#define fvalue(o) check_exp(ttislcf(o), (o)->value_.f)
-#define hvalue(o) check_exp(ttistable(o), &(o)->value_.gc->h)
-#define bvalue(o) check_exp(ttisboolean(o), (o)->value_.b)
-#define thvalue(o) check_exp(ttisthread(o), &(o)->value_.gc->th)
+#define clvalue(o) check_exp(ttisclosure(o), &val_(o).gc->cl)
+#define clLvalue(o) check_exp(ttisLclosure(o), &val_(o).gc->cl.l)
+#define clCvalue(o) check_exp(ttisCclosure(o), &val_(o).gc->cl.c)
+#define fvalue(o) check_exp(ttislcf(o), val_(o).f)
+#define hvalue(o) check_exp(ttistable(o), &val_(o).gc->h)
+#define bvalue(o) check_exp(ttisboolean(o), val_(o).b)
+#define thvalue(o) check_exp(ttisthread(o), &val_(o).gc->th)
#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
-#define iscollectable(o) (ttype(o) >= LUA_TSTRING)
+#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE)
/* Macros for internal tests */
-#define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt)
-
-#define checkconsistency(obj) lua_assert(!iscollectable(obj) || righttt(obj))
+#define righttt(obj) (ttypenv(obj) == gcvalue(obj)->gch.tt)
#define checkliveness(g,obj) \
- lua_assert(!iscollectable(obj) || (righttt(obj) && !isdead(g,gcvalue(obj))))
+ lua_longassert(!iscollectable(obj) || \
+ (righttt(obj) && !isdead(g,gcvalue(obj))))
/* Macros to set values */
-#define setnilvalue(obj) ((obj)->tt_=LUA_TNIL)
+#define settt_(o,t) ((o)->tt_=(t))
#define setnvalue(obj,x) \
- { TValue *i_o=(obj); i_o->value_.n=(x); i_o->tt_=LUA_TNUMBER; }
+ { TValue *io=(obj); num_(io)=(x); settt_(io, LUA_TNUMBER); }
-#define setfvalue(obj,x) \
- { TValue *i_o=(obj); i_o->value_.f=(x); i_o->tt_=LUA_TLCF; }
+#define changenvalue(o,x) check_exp(ttisnumber(o), num_(o)=(x))
-#define changenvalue(o,x) check_exp((o)->tt_==LUA_TNUMBER, (o)->value_.n=(x))
+#define setnilvalue(obj) settt_(obj, LUA_TNIL)
+
+#define setfvalue(obj,x) \
+ { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_TLCF); }
#define setpvalue(obj,x) \
- { TValue *i_o=(obj); i_o->value_.p=(x); i_o->tt_=LUA_TLIGHTUSERDATA; }
+ { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); }
#define setbvalue(obj,x) \
- { TValue *i_o=(obj); i_o->value_.b=(x); i_o->tt_=LUA_TBOOLEAN; }
+ { TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); }
+
+#define setgcovalue(L,obj,x) \
+ { TValue *io=(obj); GCObject *i_g=(x); \
+ val_(io).gc=i_g; settt_(io, ctb(gch(i_g)->tt)); }
#define setsvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TSTRING; \
- checkliveness(G(L),i_o); }
+ { TValue *io=(obj); \
+ val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TSTRING)); \
+ checkliveness(G(L),io); }
#define setuvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TUSERDATA; \
- checkliveness(G(L),i_o); }
+ { TValue *io=(obj); \
+ val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TUSERDATA)); \
+ checkliveness(G(L),io); }
#define setthvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TTHREAD; \
- checkliveness(G(L),i_o); }
+ { TValue *io=(obj); \
+ val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTHREAD)); \
+ checkliveness(G(L),io); }
+
+#define setclLvalue(L,obj,x) \
+ { TValue *io=(obj); \
+ val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TLCL)); \
+ checkliveness(G(L),io); }
-#define setclvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TFUNCTION; \
- checkliveness(G(L),i_o); }
+#define setclCvalue(L,obj,x) \
+ { TValue *io=(obj); \
+ val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TCCL)); \
+ checkliveness(G(L),io); }
#define sethvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TTABLE; \
- checkliveness(G(L),i_o); }
+ { TValue *io=(obj); \
+ val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTABLE)); \
+ checkliveness(G(L),io); }
#define setptvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TPROTO; \
- checkliveness(G(L),i_o); }
+ { TValue *io=(obj); \
+ val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TPROTO)); \
+ checkliveness(G(L),io); }
-#define setdeadvalue(obj) ((obj)->tt_=LUA_TDEADKEY)
+#define setdeadvalue(obj) settt_(obj, ctb(LUA_TDEADKEY))
#define setobj(L,obj1,obj2) \
- { const TValue *o2=(obj2); TValue *o1=(obj1); \
- o1->value_ = o2->value_; o1->tt_=o2->tt_; \
- checkliveness(G(L),o1); }
+ { const TValue *io2=(obj2); TValue *io1=(obj1); \
+ io1->value_ = io2->value_; io1->tt_ = io2->tt_; \
+ checkliveness(G(L),io1); }
/*
@@ -214,9 +255,121 @@ typedef struct lua_TValue {
+
+/*
+** {======================================================
+** NaN Trick
+** =======================================================
+*/
+
+#if defined(LUA_NANTRICKLE) || defined(LUA_NANTRICKBE)
+
+/*
+** numbers are represented in the 'd_' field. All other values have the
+** value (NNMARK | tag) in 'tt_'. A number with such pattern would be
+** a "signaled NaN", which is never generated by regular operations by
+** the CPU (nor by 'strtod')
+*/
+#if !defined(NNMARK)
+#define NNMARK 0x7FF7A500
+#endif
+
+#undef TValuefields
+#if defined(LUA_NANTRICKLE)
+/* little endian */
+#define TValuefields \
+ union { struct { Value v_; int tt_; } i; double d_; } u
+#else
+/* big endian */
+#define TValuefields \
+ union { struct { int tt_; Value v_; } i; double d_; } u
+#endif
+
+#undef numfield
+#define numfield /* no such field; numbers are the entire struct */
+
+/* basic check to distinguish numbers from non-numbers */
+#undef ttisnumber
+#define ttisnumber(o) (((o)->u.i.tt_ & 0x7fffff00) != NNMARK)
+
+#define tag2tt(t) (NNMARK | (t))
+
+#undef NILCONSTANT
+#define NILCONSTANT {{{NULL}, tag2tt(LUA_TNIL)}}
+
+#undef val_
+#define val_(o) ((o)->u.i.v_)
+#undef num_
+#define num_(o) ((o)->u.d_)
+
+#undef rttype
+#define rttype(o) (ttisnumber(o) ? LUA_TNUMBER : (o)->u.i.tt_ & 0xff)
+
+#undef settt_
+#define settt_(o,t) ((o)->u.i.tt_=tag2tt(t))
+
+#undef setnvalue
+#define setnvalue(obj,x) \
+ { TValue *io_=(obj); num_(io_)=(x); lua_assert(ttisnumber(io_)); }
+
+#undef setobj
+#define setobj(L,obj1,obj2) \
+ { const TValue *o2_=(obj2); TValue *o1_=(obj1); \
+ o1_->u = o2_->u; \
+ checkliveness(G(L),o1_); }
+
+
+/*
+** these redefinitions are not mandatory, but these forms are more efficient
+*/
+
+#undef checktag
+#define checktag(o,t) ((o)->u.i.tt_ == tag2tt(t))
+
+#undef ttisequal
+#define ttisequal(o1,o2) \
+ (ttisnumber(o1) ? ttisnumber(o2) : ((o1)->u.i.tt_ == (o2)->u.i.tt_))
+
+
+
+#define luai_checknum(L,o,c) { if (!ttisnumber(o)) c; }
+
+
+#else
+
+#define luai_checknum(L,o,c) { /* empty */ }
+
+#endif
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** types and prototypes
+** =======================================================
+*/
+
+
+union Value {
+ GCObject *gc; /* collectable objects */
+ void *p; /* light userdata */
+ int b; /* booleans */
+ lua_CFunction f; /* light C functions */
+ numfield /* numbers */
+};
+
+
+struct lua_TValue {
+ TValuefields;
+};
+
+
typedef TValue *StkId; /* index to stack elements */
+
+
/*
** Header for string value; string bytes follow the end of this structure
*/
@@ -226,7 +379,7 @@ typedef union TString {
CommonHeader;
lu_byte reserved;
unsigned int hash;
- size_t len;
+ size_t len; /* number of characters in string */
} tsv;
} TString;
@@ -247,7 +400,7 @@ typedef union Udata {
CommonHeader;
struct Table *metatable;
struct Table *env;
- size_t len;
+ size_t len; /* number of bytes */
} uv;
} Udata;
@@ -346,9 +499,9 @@ typedef union Closure {
} Closure;
-#define isLfunction(o) (ttisclosure(o) && !clvalue(o)->c.isC)
+#define isLfunction(o) ttisLclosure(o)
-#define getproto(o) (clvalue(o)->l.p)
+#define getproto(o) (clLvalue(o)->p)
/*
@@ -403,12 +556,13 @@ typedef struct Table {
LUAI_DDEC const TValue luaO_nilobject_;
+
LUAI_FUNC int luaO_int2fb (unsigned int x);
LUAI_FUNC int luaO_fb2int (int x);
-LUAI_FUNC int luaO_ceillog2 (lu_int32 x);
+LUAI_FUNC int luaO_ceillog2 (unsigned int x);
LUAI_FUNC lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2);
-LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2);
-LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result);
+LUAI_FUNC int luaO_str2d (const char *s, size_t len, lua_Number *result);
+LUAI_FUNC int luaO_hexavalue (int c);
LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
va_list argp);
LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...);
diff --git a/src/lopcodes.c b/src/lopcodes.c
index af267224..2e346766 100644
--- a/src/lopcodes.c
+++ b/src/lopcodes.c
@@ -1,5 +1,5 @@
/*
-** $Id: lopcodes.c,v 1.44 2010/10/13 16:45:54 roberto Exp $
+** $Id: lopcodes.c,v 1.48 2011/04/19 16:22:13 roberto Exp $
** See Copyright Notice in lua.h
*/
@@ -16,6 +16,7 @@
LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
"MOVE",
"LOADK",
+ "LOADKX",
"LOADBOOL",
"LOADNIL",
"GETUPVAL",
@@ -50,7 +51,6 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
"TFORCALL",
"TFORLOOP",
"SETLIST",
- "CLOSE",
"CLOSURE",
"VARARG",
"EXTRAARG",
@@ -64,8 +64,9 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
/* T A B C mode opcode */
opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */
,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */
+ ,opmode(0, 1, OpArgN, OpArgN, iABx) /* OP_LOADKX */
,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */
- ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LOADNIL */
+ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_LOADNIL */
,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */
,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */
,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */
@@ -88,7 +89,7 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */
,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */
,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */
- ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TEST */
+ ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TEST */
,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */
,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */
,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */
@@ -98,7 +99,6 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
,opmode(0, 0, OpArgN, OpArgU, iABC) /* OP_TFORCALL */
,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_TFORLOOP */
,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */
- ,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */
,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */
,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */
,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */
diff --git a/src/lopcodes.h b/src/lopcodes.h
index af1dc9cd..01c69bdb 100644
--- a/src/lopcodes.h
+++ b/src/lopcodes.h
@@ -1,5 +1,5 @@
/*
-** $Id: lopcodes.h,v 1.137 2010/10/25 12:24:55 roberto Exp $
+** $Id: lopcodes.h,v 1.141 2011/04/19 16:22:13 roberto Exp $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -167,9 +167,10 @@ typedef enum {
name args description
------------------------------------------------------------------------*/
OP_MOVE,/* A B R(A) := R(B) */
-OP_LOADK,/* A Bx R(A) := Kst(Bx - 1) */
+OP_LOADK,/* A Bx R(A) := Kst(Bx) */
+OP_LOADKX,/* A R(A) := Kst(extra arg) */
OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */
-OP_LOADNIL,/* A B R(A) := ... := R(B) := nil */
+OP_LOADNIL,/* A B R(A), R(A+1), ..., R(A+B) := nil */
OP_GETUPVAL,/* A B R(A) := UpValue[B] */
OP_GETTABUP,/* A B C R(A) := UpValue[B][RK(C)] */
@@ -195,8 +196,7 @@ OP_LEN,/* A B R(A) := length of R(B) */
OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */
-OP_JMP,/* sBx pc+=sBx */
-
+OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A) + 1 */
OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
@@ -217,7 +217,6 @@ OP_TFORLOOP,/* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/
OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
-OP_CLOSE,/* A close all variables in the stack up to (>=) R(A)*/
OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx]) */
OP_VARARG,/* A B R(A), R(A+1), ..., R(A+B-2) = vararg */
@@ -244,7 +243,7 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
(*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next
'instruction' is EXTRAARG(real C).
- (*) In OP_LOADK, if (Bx == 0) then next 'instruction' is EXTRAARG(real Bx).
+ (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG.
(*) For comparisons, A specifies what condition the test should accept
(true or false).
diff --git a/src/loslib.c b/src/loslib.c
index 0278eb51..2ce9902f 100644
--- a/src/loslib.c
+++ b/src/loslib.c
@@ -1,5 +1,5 @@
/*
-** $Id: loslib.c,v 1.32 2010/10/05 12:18:03 roberto Exp $
+** $Id: loslib.c,v 1.34 2011/03/03 16:34:46 roberto Exp $
** Standard Operating System library
** See Copyright Notice in lua.h
*/
@@ -59,37 +59,28 @@
-static int os_pushresult (lua_State *L, int i, const char *filename) {
- int en = errno; /* calls to Lua API may change this value */
- if (i) {
- lua_pushboolean(L, 1);
- return 1;
- }
+static int os_execute (lua_State *L) {
+ const char *cmd = luaL_optstring(L, 1, NULL);
+ int stat = system(cmd);
+ if (cmd != NULL)
+ return luaL_execresult(L, stat);
else {
- lua_pushnil(L);
- lua_pushfstring(L, "%s: %s", filename, strerror(en));
- lua_pushinteger(L, en);
- return 3;
+ lua_pushboolean(L, stat); /* true if there is a shell */
+ return 1;
}
}
-static int os_execute (lua_State *L) {
- lua_pushinteger(L, system(luaL_optstring(L, 1, NULL)));
- return 1;
-}
-
-
static int os_remove (lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
- return os_pushresult(L, remove(filename) == 0, filename);
+ return luaL_fileresult(L, remove(filename) == 0, filename);
}
static int os_rename (lua_State *L) {
const char *fromname = luaL_checkstring(L, 1);
const char *toname = luaL_checkstring(L, 2);
- return os_pushresult(L, rename(fromname, toname) == 0, fromname);
+ return luaL_fileresult(L, rename(fromname, toname) == 0, fromname);
}
@@ -182,7 +173,7 @@ static const char *checkoption (lua_State *L, const char *conv, char *buff) {
return conv; /* to avoid warnings */
}
-
+
static int os_date (lua_State *L) {
const char *s = luaL_optstring(L, 1, "%c");
time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL));
diff --git a/src/lparser.c b/src/lparser.c
index 3524b9b2..225e022e 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.c,v 2.92 2010/09/07 19:21:39 roberto Exp $
+** $Id: lparser.c,v 2.109 2011/05/02 17:33:01 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -41,10 +41,11 @@
*/
typedef struct BlockCnt {
struct BlockCnt *previous; /* chain */
- int breaklist; /* list of jumps out of this loop */
- lu_byte nactvar; /* # active locals outside the breakable structure */
+ int firstlabel; /* index of first label in this block */
+ int firstgoto; /* index of first pending goto in this block */
+ lu_byte nactvar; /* # active locals outside the block */
lu_byte upval; /* true if some variable in the block is an upvalue */
- lu_byte isbreakable; /* true if `block' is a loop */
+ lu_byte isloop; /* true if `block' is a loop */
} BlockCnt;
@@ -52,7 +53,7 @@ typedef struct BlockCnt {
/*
** prototypes for recursive non-terminal functions
*/
-static void chunk (LexState *ls);
+static void statement (LexState *ls);
static void expr (LexState *ls, expdesc *v);
@@ -66,6 +67,13 @@ static void anchor_token (LexState *ls) {
}
+/* semantic error */
+static void semerror (LexState *ls, const char *msg) {
+ ls->t.token = 0; /* remove 'near to' from final message */
+ luaX_syntaxerror(ls, msg);
+}
+
+
static void error_expected (LexState *ls, int token) {
luaX_syntaxerror(ls,
luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token)));
@@ -103,6 +111,7 @@ static void check (LexState *ls, int c) {
error_expected(ls, c);
}
+
static void checknext (LexState *ls, int c) {
check(ls, c);
luaX_next(ls);
@@ -167,13 +176,13 @@ static int registerlocalvar (LexState *ls, TString *varname) {
static void new_localvar (LexState *ls, TString *name) {
FuncState *fs = ls->fs;
- Varlist *vl = ls->varl;
+ Dyndata *dyd = ls->dyd;
int reg = registerlocalvar(ls, name);
- checklimit(fs, vl->nactvar + 1 - fs->firstlocal,
+ checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
MAXVARS, "local variables");
- luaM_growvector(ls->L, vl->actvar, vl->nactvar + 1,
- vl->actvarsize, vardesc, MAX_INT, "local variables");
- vl->actvar[vl->nactvar++].idx = cast(unsigned short, reg);
+ luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1,
+ dyd->actvar.size, Vardesc, MAX_INT, "local variables");
+ dyd->actvar.arr[dyd->actvar.n++].idx = cast(unsigned short, reg);
}
@@ -186,7 +195,7 @@ static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) {
static LocVar *getlocvar (FuncState *fs, int i) {
- int idx = fs->ls->varl->actvar[fs->firstlocal + i].idx;
+ int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx;
lua_assert(idx < fs->nlocvars);
return &fs->f->locvars[idx];
}
@@ -202,7 +211,7 @@ static void adjustlocalvars (LexState *ls, int nvars) {
static void removevars (FuncState *fs, int tolevel) {
- fs->ls->varl->nactvar -= (fs->nactvar - tolevel);
+ fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel);
while (fs->nactvar > tolevel)
getlocvar(fs, --fs->nactvar)->endpc = fs->pc;
}
@@ -245,12 +254,12 @@ static int searchvar (FuncState *fs, TString *n) {
/*
Mark block where variable at given level was defined
- (to emit OP_CLOSE later).
+ (to emit close instructions later).
*/
static void markupval (FuncState *fs, int level) {
BlockCnt *bl = fs->bl;
- while (bl && bl->nactvar > level) bl = bl->previous;
- if (bl) bl->upval = 1;
+ while (bl->nactvar > level) bl = bl->previous;
+ bl->upval = 1;
}
@@ -327,10 +336,107 @@ static void enterlevel (LexState *ls) {
#define leavelevel(ls) (G((ls)->L)->nCcalls--)
-static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) {
- bl->breaklist = NO_JUMP;
- bl->isbreakable = isbreakable;
+static void closegoto (LexState *ls, int g, Labeldesc *label) {
+ int i;
+ FuncState *fs = ls->fs;
+ Labellist *gl = &ls->dyd->gt;
+ Labeldesc *gt = &gl->arr[g];
+ lua_assert(eqstr(gt->name, label->name));
+ if (gt->nactvar < label->nactvar) {
+ const char *msg = luaO_pushfstring(ls->L,
+ "<goto %s> at line %d jumps into the scope of local " LUA_QS,
+ getstr(gt->name), gt->line, getstr(getlocvar(fs, gt->nactvar)->varname));
+ semerror(ls, msg);
+ }
+ luaK_patchlist(fs, gt->pc, label->pc);
+ /* remove goto from pending list */
+ for (i = g; i < gl->n - 1; i++)
+ gl->arr[i] = gl->arr[i + 1];
+ gl->n--;
+}
+
+
+/*
+** try to close a goto with existing labels; this solves backward jumps
+*/
+static int findlabel (LexState *ls, int g) {
+ int i;
+ BlockCnt *bl = ls->fs->bl;
+ Dyndata *dyd = ls->dyd;
+ Labeldesc *gt = &dyd->gt.arr[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 (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);
+ closegoto(ls, g, lb); /* close it */
+ return 1;
+ }
+ }
+ return 0; /* label not found; cannot close goto */
+}
+
+
+static int newlabelentry (LexState *ls, Labellist *l, TString *name,
+ int line, int pc) {
+ int n = l->n;
+ luaM_growvector(ls->L, l->arr, n, l->size, Labeldesc, MAX_INT, "labels");
+ l->arr[n].name = name;
+ l->arr[n].line = line;
+ l->arr[n].nactvar = ls->fs->nactvar;
+ l->arr[n].pc = pc;
+ l->n++;
+ return n;
+}
+
+
+/*
+** check whether new label 'lb' matches any pending gotos in current
+** block; solves forward jumps
+*/
+static void findgotos (LexState *ls, Labeldesc *lb) {
+ Labellist *gl = &ls->dyd->gt;
+ int i = ls->fs->bl->firstgoto;
+ while (i < gl->n) {
+ if (eqstr(gl->arr[i].name, lb->name))
+ closegoto(ls, i, lb);
+ else
+ i++;
+ }
+}
+
+
+/*
+** "export" pending gotos to outer level, to check them against
+** outer labels; if the block being exited has upvalues, and
+** the goto exists the scope of any variable (which can be the
+** upvalue), close those variables being exited.
+*/
+static void movegotosout (FuncState *fs, BlockCnt *bl) {
+ int i = bl->firstgoto;
+ Labellist *gl = &fs->ls->dyd->gt;
+ /* correct pending gotos to current block and try to close it
+ with visible labels */
+ while (i < gl->n) {
+ Labeldesc *gt = &gl->arr[i];
+ if (gt->nactvar > bl->nactvar) {
+ if (bl->upval)
+ luaK_patchclose(fs, gt->pc, bl->nactvar);
+ gt->nactvar = bl->nactvar;
+ }
+ if (!findlabel(fs->ls, i))
+ i++; /* move to next one */
+ }
+}
+
+
+static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {
+ bl->isloop = isloop;
bl->nactvar = fs->nactvar;
+ bl->firstlabel = fs->ls->dyd->label.n;
+ bl->firstgoto = fs->ls->dyd->gt.n;
bl->upval = 0;
bl->previous = fs->bl;
fs->bl = bl;
@@ -338,17 +444,48 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) {
}
+/*
+** create a label named "break" to resolve break statements
+*/
+static void breaklabel (LexState *ls) {
+ TString *n = luaS_new(ls->L, "break");
+ int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc);
+ findgotos(ls, &ls->dyd->label.arr[l]);
+}
+
+/*
+** generates an error for an undefined 'goto'; choose appropriate
+** message when label name is a reserved word (which can only be 'break')
+*/
+static void undefgoto (LexState *ls, Labeldesc *gt) {
+ const char *msg = (gt->name->tsv.reserved > 0)
+ ? "<%s> at line %d not inside a loop"
+ : "label " LUA_QS " (<goto> at line %d) undefined";
+ msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);
+ semerror(ls, msg);
+}
+
+
static void leaveblock (FuncState *fs) {
BlockCnt *bl = fs->bl;
+ LexState *ls = fs->ls;
+ if (bl->previous && bl->upval) {
+ /* create a 'jump to here' to close upvalues */
+ int j = luaK_jump(fs);
+ luaK_patchclose(fs, j, bl->nactvar);
+ luaK_patchtohere(fs, j);
+ }
+ if (bl->isloop)
+ breaklabel(ls); /* close pending breaks */
fs->bl = bl->previous;
removevars(fs, bl->nactvar);
- if (bl->upval)
- luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
- /* a block either controls scope or breaks (never both) */
- lua_assert(!bl->isbreakable || !bl->upval);
lua_assert(bl->nactvar == fs->nactvar);
fs->freereg = fs->nactvar; /* free registers */
- luaK_patchtohere(fs, bl->breaklist);
+ ls->dyd->label.n = bl->firstlabel; /* remove local labels */
+ if (bl->previous) /* inner block? */
+ movegotosout(fs, bl); /* update pending gotos to outer block */
+ else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */
+ undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */
}
@@ -368,10 +505,11 @@ static void codeclosure (LexState *ls, Proto *clp, expdesc *v) {
f->p[fs->np++] = clp;
luaC_objbarrier(ls->L, f, clp);
init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1));
+ luaK_exp2nextreg(fs, v); /* fix it at stack top (for GC) */
}
-static void open_func (LexState *ls, FuncState *fs) {
+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 */
@@ -387,7 +525,7 @@ static void open_func (LexState *ls, FuncState *fs) {
fs->nups = 0;
fs->nlocvars = 0;
fs->nactvar = 0;
- fs->firstlocal = ls->varl->nactvar;
+ fs->firstlocal = ls->dyd->actvar.n;
fs->bl = NULL;
f = luaF_newproto(L);
fs->f = f;
@@ -400,6 +538,7 @@ static void open_func (LexState *ls, FuncState *fs) {
/* anchor table of constants (to avoid being collected) */
sethvalue2s(L, L->top, fs->h);
incr_top(L);
+ enterblock(fs, bl, 0);
}
@@ -408,7 +547,7 @@ static void close_func (LexState *ls) {
FuncState *fs = ls->fs;
Proto *f = fs->f;
luaK_ret(fs, 0, 0); /* final return */
- removevars(fs, 0);
+ leaveblock(fs);
luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
f->sizecode = fs->pc;
luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
@@ -435,42 +574,49 @@ static void close_func (LexState *ls) {
** opens the main function, which is a regular vararg function with an
** upvalue named LUA_ENV
*/
-static void open_mainfunc (LexState *ls, FuncState *fs) {
+static void open_mainfunc (LexState *ls, FuncState *fs, BlockCnt *bl) {
expdesc v;
- open_func(ls, fs);
+ open_func(ls, fs, bl);
fs->f->is_vararg = 1; /* main function is always vararg */
init_exp(&v, VLOCAL, 0);
newupvalue(fs, ls->envn, &v); /* create environment upvalue */
}
-Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Varlist *varl,
- const char *name) {
- LexState lexstate;
- FuncState funcstate;
- TString *tname = luaS_new(L, name);
- setsvalue2s(L, L->top, tname); /* push name to protect it */
- incr_top(L);
- lexstate.buff = buff;
- lexstate.varl = varl;
- luaX_setinput(L, &lexstate, z, tname);
- open_mainfunc(&lexstate, &funcstate);
- luaX_next(&lexstate); /* read first token */
- chunk(&lexstate); /* read main chunk */
- check(&lexstate, TK_EOS);
- close_func(&lexstate);
- L->top--; /* pop name */
- lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
- return funcstate.f;
-}
-
-
/*============================================================*/
/* GRAMMAR RULES */
/*============================================================*/
+/*
+** check whether current token is in the follow set of a block.
+** 'until' closes syntactical blocks, but do not close scope,
+** so it handled in separate.
+*/
+static int block_follow (LexState *ls, int withuntil) {
+ switch (ls->t.token) {
+ case TK_ELSE: case TK_ELSEIF:
+ case TK_END: case TK_EOS:
+ return 1;
+ case TK_UNTIL: return withuntil;
+ default: return 0;
+ }
+}
+
+
+static void statlist (LexState *ls) {
+ /* statlist -> { stat [`;'] } */
+ while (!block_follow(ls, 1)) {
+ if (ls->t.token == TK_RETURN) {
+ statement(ls);
+ return; /* 'return' must be last statement */
+ }
+ statement(ls);
+ }
+}
+
+
static void fieldsel (LexState *ls, expdesc *v) {
/* fieldsel -> ['.' | ':'] NAME */
FuncState *fs = ls->fs;
@@ -586,7 +732,7 @@ static void field (LexState *ls, struct ConsControl *cc) {
static void constructor (LexState *ls, expdesc *t) {
- /* constructor -> '{' [ field { sep field } [sep] ] '}'
+ /* constructor -> '{' [ field { sep field } [sep] ] '}'
sep -> ',' | ';' */
FuncState *fs = ls->fs;
int line = ls->linenumber;
@@ -596,7 +742,7 @@ static void constructor (LexState *ls, expdesc *t) {
cc.t = t;
init_exp(t, VRELOCABLE, pc);
init_exp(&cc.v, VVOID, 0); /* no value (yet) */
- luaK_exp2nextreg(ls->fs, t); /* fix it at stack top (for gc) */
+ luaK_exp2nextreg(ls->fs, t); /* fix it at stack top */
checknext(ls, '{');
do {
lua_assert(cc.v.k == VVOID || cc.tostore > 0);
@@ -643,19 +789,20 @@ static void parlist (LexState *ls) {
}
-static void body (LexState *ls, expdesc *e, int needself, int line) {
- /* body -> `(' parlist `)' chunk END */
+static void body (LexState *ls, expdesc *e, int ismethod, int line) {
+ /* body -> `(' parlist `)' block END */
FuncState new_fs;
- open_func(ls, &new_fs);
+ BlockCnt bl;
+ open_func(ls, &new_fs, &bl);
new_fs.f->linedefined = line;
checknext(ls, '(');
- if (needself) {
- new_localvarliteral(ls, "self");
+ if (ismethod) {
+ new_localvarliteral(ls, "self"); /* create 'self' parameter */
adjustlocalvars(ls, 1);
}
parlist(ls);
checknext(ls, ')');
- chunk(ls);
+ statlist(ls);
new_fs.f->lastlinedefined = ls->linenumber;
check_match(ls, TK_END, TK_FUNCTION, line);
codeclosure(ls, new_fs.f, e);
@@ -663,8 +810,8 @@ static void body (LexState *ls, expdesc *e, int needself, int line) {
}
-static int explist1 (LexState *ls, expdesc *v) {
- /* explist1 -> expr { `,' expr } */
+static int explist (LexState *ls, expdesc *v) {
+ /* explist -> expr { `,' expr } */
int n = 1; /* at least one expression */
expr(ls, v);
while (testnext(ls, ',')) {
@@ -681,12 +828,12 @@ static void funcargs (LexState *ls, expdesc *f, int line) {
expdesc args;
int base, nparams;
switch (ls->t.token) {
- case '(': { /* funcargs -> `(' [ explist1 ] `)' */
+ case '(': { /* funcargs -> `(' [ explist ] `)' */
luaX_next(ls);
if (ls->t.token == ')') /* arg list is empty? */
args.k = VVOID;
else {
- explist1(ls, &args);
+ explist(ls, &args);
luaK_setmultret(fs, &args);
}
check_match(ls, ')', '(', line);
@@ -937,23 +1084,12 @@ static void expr (LexState *ls, expdesc *v) {
*/
-static int block_follow (int token) {
- switch (token) {
- case TK_ELSE: case TK_ELSEIF: case TK_END:
- case TK_UNTIL: case TK_EOS:
- return 1;
- default: return 0;
- }
-}
-
-
static void block (LexState *ls) {
- /* block -> chunk */
+ /* block -> statlist */
FuncState *fs = ls->fs;
BlockCnt bl;
enterblock(fs, &bl, 0);
- chunk(ls);
- lua_assert(bl.breaklist == NO_JUMP);
+ statlist(ls);
leaveblock(fs);
}
@@ -1012,10 +1148,10 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
"variable names");
assignment(ls, &nv, nvars+1);
}
- else { /* assignment -> `=' explist1 */
+ else { /* assignment -> `=' explist */
int nexps;
checknext(ls, '=');
- nexps = explist1(ls, &e);
+ nexps = explist(ls, &e);
if (nexps != nvars) {
adjust_assign(ls, nvars, nexps, &e);
if (nexps > nvars)
@@ -1042,19 +1178,38 @@ static int cond (LexState *ls) {
}
-static void breakstat (LexState *ls) {
+static void gotostat (LexState *ls, TString *label, int line) {
+ /* create new entry for this goto */
+ int g = newlabelentry(ls, &ls->dyd->gt, label, line, luaK_jump(ls->fs));
+ findlabel(ls, g);
+}
+
+
+static void labelstat (LexState *ls, TString *label, int line) {
+ /* label -> '@' NAME ':' */
FuncState *fs = ls->fs;
- BlockCnt *bl = fs->bl;
- int upval = 0;
- while (bl && !bl->isbreakable) {
- upval |= bl->upval;
- bl = bl->previous;
+ Labellist *ll = &ls->dyd->label;
+ int l, i; /* index of new label being created */
+ /* check for repeated labels on the same block */
+ for (i = ls->fs->bl->firstlabel; i < ll->n; i++) {
+ if (eqstr(label, ll->arr[i].name)) {
+ const char *msg = luaO_pushfstring(ls->L,
+ "label " LUA_QS " already defined on line %d",
+ getstr(label), ll->arr[i].line);
+ semerror(ls, msg);
+ }
}
- if (!bl)
- luaX_syntaxerror(ls, "no loop to break");
- if (upval)
- luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
- luaK_concat(fs, &bl->breaklist, luaK_jump(fs));
+ checknext(ls, ':'); /* skip colon */
+ /* create new entry for this label */
+ l = newlabelentry(ls, ll, label, line, fs->pc);
+ /* skip other no-op statements */
+ while (ls->t.token == ';' || ls->t.token == '@')
+ statement(ls);
+ if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
+ /* assume that locals are already out of scope */
+ ll->arr[l].nactvar = fs->bl->nactvar;
+ }
+ findgotos(ls, &ll->arr[l]);
}
@@ -1086,19 +1241,13 @@ static void repeatstat (LexState *ls, int line) {
enterblock(fs, &bl1, 1); /* loop block */
enterblock(fs, &bl2, 0); /* scope block */
luaX_next(ls); /* skip REPEAT */
- chunk(ls);
+ statlist(ls);
check_match(ls, TK_UNTIL, TK_REPEAT, line);
condexit = cond(ls); /* read condition (inside scope block) */
- if (!bl2.upval) { /* no upvalues? */
- leaveblock(fs); /* finish scope */
- luaK_patchlist(fs, condexit, repeat_init); /* close the loop */
- }
- else { /* complete semantics when there are upvalues */
- breakstat(ls); /* if condition then break */
- luaK_patchtohere(ls->fs, condexit); /* else... */
- leaveblock(fs); /* finish scope... */
- luaK_jumpto(fs, repeat_init); /* and repeat */
- }
+ if (bl2.upval) /* upvalues? */
+ luaK_patchclose(fs, condexit, bl2.nactvar);
+ leaveblock(fs); /* finish scope */
+ luaK_patchlist(fs, condexit, repeat_init); /* close the loop */
leaveblock(fs); /* finish loop */
}
@@ -1163,7 +1312,7 @@ static void fornum (LexState *ls, TString *varname, int line) {
static void forlist (LexState *ls, TString *indexname) {
- /* forlist -> NAME {,NAME} IN explist1 forbody */
+ /* forlist -> NAME {,NAME} IN explist forbody */
FuncState *fs = ls->fs;
expdesc e;
int nvars = 4; /* gen, state, control, plus at least one declared var */
@@ -1181,7 +1330,7 @@ static void forlist (LexState *ls, TString *indexname) {
}
checknext(ls, TK_IN);
line = ls->linenumber;
- adjust_assign(ls, 3, explist1(ls, &e), &e);
+ adjust_assign(ls, 3, explist(ls, &e), &e);
luaK_checkstack(fs, 3); /* extra space to call generator */
forbody(ls, base, line, nvars - 3, 0);
}
@@ -1241,19 +1390,20 @@ static void ifstat (LexState *ls, int line) {
static void localfunc (LexState *ls) {
- expdesc v, b;
+ expdesc b;
FuncState *fs = ls->fs;
- new_localvar(ls, str_checkname(ls));
- init_exp(&v, VLOCAL, fs->freereg);
- luaK_reserveregs(fs, 1);
- adjustlocalvars(ls, 1);
- body(ls, &b, 0, ls->linenumber);
- luaK_storevar(fs, &v, &b);
+ int varidx = fs->nactvar; /* index of new local variable */
+ new_localvar(ls, str_checkname(ls)); /* new local variable */
+ adjustlocalvars(ls, 1); /* enter its scope */
+ body(ls, &b, 0, ls->linenumber); /* function created in next register */
+ lua_assert(b.k == VNONRELOC && b.u.ind.idx == varidx);
+ /* debug information will only see the variable after this point! */
+ getlocvar(fs, varidx)->startpc = fs->pc;
}
static void localstat (LexState *ls) {
- /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
+ /* stat -> LOCAL NAME {`,' NAME} [`=' explist] */
int nvars = 0;
int nexps;
expdesc e;
@@ -1262,7 +1412,7 @@ static void localstat (LexState *ls) {
nvars++;
} while (testnext(ls, ','));
if (testnext(ls, '='))
- nexps = explist1(ls, &e);
+ nexps = explist(ls, &e);
else {
e.k = VVOID;
nexps = 0;
@@ -1274,25 +1424,25 @@ static void localstat (LexState *ls) {
static int funcname (LexState *ls, expdesc *v) {
/* funcname -> NAME {fieldsel} [`:' NAME] */
- int needself = 0;
+ int ismethod = 0;
singlevar(ls, v);
while (ls->t.token == '.')
fieldsel(ls, v);
if (ls->t.token == ':') {
- needself = 1;
+ ismethod = 1;
fieldsel(ls, v);
}
- return needself;
+ return ismethod;
}
static void funcstat (LexState *ls, int line) {
/* funcstat -> FUNCTION funcname body */
- int needself;
+ int ismethod;
expdesc v, b;
luaX_next(ls); /* skip FUNCTION */
- needself = funcname(ls, &v);
- body(ls, &b, needself, line);
+ ismethod = funcname(ls, &v);
+ body(ls, &b, ismethod, line);
luaK_storevar(ls->fs, &v, &b);
luaK_fixline(ls->fs, line); /* definition `happens' in the first line */
}
@@ -1313,14 +1463,14 @@ static void exprstat (LexState *ls) {
static void retstat (LexState *ls) {
- /* stat -> RETURN explist */
+ /* stat -> RETURN [explist] [';'] */
FuncState *fs = ls->fs;
expdesc e;
int first, nret; /* registers with returned values */
- if (block_follow(ls->t.token) || ls->t.token == ';')
+ if (block_follow(ls, 1) || ls->t.token == ';')
first = nret = 0; /* return no values */
else {
- nret = explist1(ls, &e); /* optional return values */
+ nret = explist(ls, &e); /* optional return values */
if (hasmultret(e.k)) {
luaK_setmultret(fs, &e);
if (e.k == VCALL && nret == 1) { /* tail call? */
@@ -1341,41 +1491,43 @@ static void retstat (LexState *ls) {
}
}
luaK_ret(fs, first, nret);
+ testnext(ls, ';'); /* skip optional semicolon */
}
-static int statement (LexState *ls) {
+static void statement (LexState *ls) {
int line = ls->linenumber; /* may be needed for error messages */
+ enterlevel(ls);
switch (ls->t.token) {
case ';': { /* stat -> ';' (empty statement) */
luaX_next(ls); /* skip ';' */
- return 0;
+ break;
}
case TK_IF: { /* stat -> ifstat */
ifstat(ls, line);
- return 0;
+ break;
}
case TK_WHILE: { /* stat -> whilestat */
whilestat(ls, line);
- return 0;
+ break;
}
case TK_DO: { /* stat -> DO block END */
luaX_next(ls); /* skip DO */
block(ls);
check_match(ls, TK_END, TK_DO, line);
- return 0;
+ break;
}
case TK_FOR: { /* stat -> forstat */
forstat(ls, line);
- return 0;
+ break;
}
case TK_REPEAT: { /* stat -> repeatstat */
repeatstat(ls, line);
- return 0;
+ break;
}
case TK_FUNCTION: { /* stat -> funcstat */
funcstat(ls, line);
- return 0;
+ break;
}
case TK_LOCAL: { /* stat -> localstat */
luaX_next(ls); /* skip LOCAL */
@@ -1383,39 +1535,62 @@ static int statement (LexState *ls) {
localfunc(ls);
else
localstat(ls);
- return 0;
+ break;
+ }
+ case '@': { /* stat -> label */
+ luaX_next(ls); /* skip '@' */
+ labelstat(ls, str_checkname(ls), line);
+ break;
}
case TK_RETURN: { /* stat -> retstat */
luaX_next(ls); /* skip RETURN */
retstat(ls);
- return 1; /* must be last statement */
+ break;
}
case TK_BREAK: { /* stat -> breakstat */
luaX_next(ls); /* skip BREAK */
- breakstat(ls);
- return 1; /* must be last statement */
+ /* code it as "goto 'break'" */
+ gotostat(ls, luaS_new(ls->L, "break"), line);
+ break;
+ }
+ case TK_GOTO: { /* stat -> 'goto' NAME */
+ luaX_next(ls); /* skip GOTO */
+ gotostat(ls, str_checkname(ls), line);
+ break;
}
default: { /* stat -> func | assignment */
exprstat(ls);
- return 0;
+ break;
}
}
+ lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
+ ls->fs->freereg >= ls->fs->nactvar);
+ ls->fs->freereg = ls->fs->nactvar; /* free registers */
+ leavelevel(ls);
}
+/* }====================================================================== */
-static void chunk (LexState *ls) {
- /* chunk -> { stat [`;'] } */
- int islast = 0;
- enterlevel(ls);
- while (!islast && !block_follow(ls->t.token)) {
- islast = statement(ls);
- if (islast)
- testnext(ls, ';');
- lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
- ls->fs->freereg >= ls->fs->nactvar);
- ls->fs->freereg = ls->fs->nactvar; /* free registers */
- }
- leavelevel(ls);
+
+Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
+ Dyndata *dyd, const char *name, int firstchar) {
+ LexState lexstate;
+ FuncState funcstate;
+ BlockCnt bl;
+ TString *tname = luaS_new(L, name);
+ setsvalue2s(L, L->top, tname); /* push name to protect it */
+ incr_top(L);
+ lexstate.buff = buff;
+ lexstate.dyd = dyd;
+ dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;
+ luaX_setinput(L, &lexstate, z, tname, firstchar);
+ open_mainfunc(&lexstate, &funcstate, &bl);
+ luaX_next(&lexstate); /* read first token */
+ statlist(&lexstate); /* main body */
+ check(&lexstate, TK_EOS);
+ close_func(&lexstate);
+ L->top--; /* pop name */
+ lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
+ return funcstate.f;
}
-/* }====================================================================== */
diff --git a/src/lparser.h b/src/lparser.h
index 6055a85b..4e7e06fc 100644
--- a/src/lparser.h
+++ b/src/lparser.h
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.h,v 1.65 2010/07/07 16:27:29 roberto Exp $
+** $Id: lparser.h,v 1.68 2011/02/23 13:13:10 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -53,19 +53,42 @@ typedef struct expdesc {
} expdesc;
-typedef struct vardesc {
- unsigned short idx;
-} vardesc;
+/* description of active local variable */
+typedef struct Vardesc {
+ unsigned short idx; /* variable index in stack */
+} Vardesc;
-/* list of all active local variables */
-typedef struct Varlist {
- vardesc *actvar;
- int nactvar;
- int actvarsize;
-} Varlist;
+/* description of pending goto statements and label statements */
+typedef struct Labeldesc {
+ TString *name; /* label identifier */
+ int pc; /* position in code */
+ int line; /* line where it appeared */
+ lu_byte nactvar; /* local level where it appears in current block */
+} Labeldesc;
+/* list of labels or gotos */
+typedef struct Labellist {
+ Labeldesc *arr; /* array */
+ int n; /* number of entries in use */
+ int size; /* array size */
+} Labellist;
+
+
+/* dynamic structures used by the parser */
+typedef struct Dyndata {
+ struct { /* list of active local variables */
+ Vardesc *arr;
+ int n;
+ int size;
+ } actvar;
+ Labellist gt; /* list of pending gotos */
+ Labellist label; /* list of active labels */
+} Dyndata;
+
+
+/* control of blocks */
struct BlockCnt; /* defined in lparser.c */
@@ -91,7 +114,7 @@ typedef struct FuncState {
LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
- Varlist *varl, const char *name);
+ Dyndata *dyd, const char *name, int firstchar);
#endif
diff --git a/src/lstate.c b/src/lstate.c
index 39a0ef4d..45dac3c5 100644
--- a/src/lstate.c
+++ b/src/lstate.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.c,v 2.86 2010/09/03 14:14:01 roberto Exp $
+** $Id: lstate.c,v 2.89 2010/12/20 19:40:07 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -65,11 +65,14 @@ typedef struct LG {
#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l)))
-
/*
-** maximum number of nested calls made by error-handling function
+** set GCdebt to a new value keeping the value (totalbytes + GCdebt)
+** invariant
*/
-#define LUAI_EXTRACALLS 10
+void luaE_setdebt (global_State *g, l_mem debt) {
+ g->totalbytes -= (debt - g->GCdebt);
+ g->GCdebt = debt;
+}
CallInfo *luaE_extendCI (lua_State *L) {
@@ -154,7 +157,7 @@ static void f_luaopen (lua_State *L, void *ud) {
/* pre-create memory-error message */
g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
luaS_fix(g->memerrmsg); /* it should never be collected */
- g->GCdebt = 0;
+ g->gcrunning = 1; /* allow gc */
}
@@ -187,7 +190,7 @@ static void close_state (lua_State *L) {
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
luaZ_freebuffer(L, &g->buff);
freestack(L);
- lua_assert(g->totalbytes == sizeof(LG));
+ lua_assert(gettotalbytes(g) == sizeof(LG));
(*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0);
}
@@ -241,7 +244,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->mainthread = L;
g->uvhead.u.l.prev = &g->uvhead;
g->uvhead.u.l.next = &g->uvhead;
- stopgc(g); /* no GC while building state */
+ g->gcrunning = 0; /* no GC while building state */
g->lastmajormem = 0;
g->strt.size = 0;
g->strt.nuse = 0;
@@ -252,11 +255,12 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->version = lua_version(NULL);
g->gcstate = GCSpause;
g->allgc = NULL;
- g->udgc = NULL;
+ g->finobj = NULL;
g->tobefnz = NULL;
g->gray = g->grayagain = NULL;
g->weak = g->ephemeron = g->allweak = NULL;
g->totalbytes = sizeof(LG);
+ g->GCdebt = 0;
g->gcpause = LUAI_GCPAUSE;
g->gcmajorinc = LUAI_GCMAJOR;
g->gcstepmul = LUAI_GCMUL;
diff --git a/src/lstate.h b/src/lstate.h
index bc64a4ae..9d21e7e8 100644
--- a/src/lstate.h
+++ b/src/lstate.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.h,v 2.68 2010/10/29 17:52:46 roberto Exp $
+** $Id: lstate.h,v 2.72 2011/06/02 19:31:40 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -32,9 +32,9 @@
** when traversing the respective threads, but the thread may already be
** dead, while the upvalue is still accessible through closures.)
**
-** Userdata with finalizers are kept in the list g->udgc.
+** Objects with finalizers are kept in the list g->finobj.
**
-** The list g->tobefnz links all userdata being finalized.
+** The list g->tobefnz links all objects being finalized.
*/
@@ -104,7 +104,6 @@ typedef struct CallInfo {
#define CIST_TAIL (1<<6) /* call was tail called */
-#define ci_func(ci) (clvalue((ci)->func))
#define isLua(ci) ((ci)->callstatus & CIST_LUA)
@@ -114,8 +113,8 @@ typedef struct CallInfo {
typedef struct global_State {
lua_Alloc frealloc; /* function to reallocate memory */
void *ud; /* auxiliary data to `frealloc' */
- lu_mem totalbytes; /* number of bytes currently allocated */
- l_mem GCdebt; /* when positive, run a GC step */
+ lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */
+ l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
lu_mem lastmajormem; /* memory in use after last major collection */
stringtable strt; /* hash table for strings */
TValue l_registry;
@@ -123,9 +122,10 @@ typedef struct global_State {
lu_byte currentwhite;
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 *udgc; /* list of collectable userdata with finalizers */
+ GCObject *finobj; /* list of collectable objects with finalizers */
GCObject **sweepgc; /* current position of sweep */
GCObject *gray; /* list of gray objects */
GCObject *grayagain; /* list of objects to be traversed atomically */
@@ -209,6 +209,10 @@ union GCObject {
#define obj2gco(v) (cast(GCObject *, (v)))
+/* actual number of total bytes allocated */
+#define gettotalbytes(g) ((g)->totalbytes + (g)->GCdebt)
+
+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);
diff --git a/src/lstring.c b/src/lstring.c
index 145621b6..adec415e 100644
--- a/src/lstring.c
+++ b/src/lstring.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstring.c,v 2.18 2010/05/10 18:23:45 roberto Exp $
+** $Id: lstring.c,v 2.19 2011/05/03 16:01:57 roberto Exp $
** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -84,8 +84,9 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
o != NULL;
o = gch(o)->next) {
TString *ts = rawgco2ts(o);
- if (h == ts->tsv.hash && ts->tsv.len == l &&
- (memcmp(str, getstr(ts), l) == 0)) {
+ if (h == ts->tsv.hash &&
+ ts->tsv.len == l &&
+ (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 */
return ts;
diff --git a/src/lstrlib.c b/src/lstrlib.c
index 2491bbb4..369054fd 100644
--- a/src/lstrlib.c
+++ b/src/lstrlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstrlib.c,v 1.159 2010/11/19 16:25:51 roberto Exp $
+** $Id: lstrlib.c,v 1.168 2011/06/09 18:22:47 roberto Exp $
** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
@@ -45,7 +45,7 @@ static int str_len (lua_State *L) {
/* translate a relative string position: negative means back from end */
static size_t posrelat (ptrdiff_t pos, size_t len) {
if (pos >= 0) return (size_t)pos;
- else if (pos == -pos || (size_t)-pos > len) return 0;
+ else if (-(size_t)pos > len) return 0;
else return len - ((size_t)-pos) + 1;
}
@@ -101,15 +101,29 @@ static int str_upper (lua_State *L) {
return 1;
}
+
+/* reasonable limit to avoid arithmetic overflow */
+#define MAXSIZE ((~(size_t)0) >> 1)
+
static int str_rep (lua_State *L) {
- size_t l;
- luaL_Buffer b;
+ size_t l, lsep;
const char *s = luaL_checklstring(L, 1, &l);
int n = luaL_checkint(L, 2);
- luaL_buffinit(L, &b);
- while (n-- > 0)
- luaL_addlstring(&b, s, l);
- luaL_pushresult(&b);
+ 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? */
+ return luaL_error(L, "resulting string too large");
+ else {
+ size_t totallen = n * l + (n - 1) * lsep;
+ luaL_Buffer b;
+ 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;
+ memcpy(p, sep, lsep * sizeof(char)); p += lsep;
+ }
+ memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */
+ luaL_pushresultsize(&b, totallen);
+ }
return 1;
}
@@ -125,7 +139,7 @@ static int str_byte (lua_State *L) {
if (posi > pose) return 0; /* empty interval; return no values */
n = (int)(pose - posi + 1);
if (posi + n <= pose) /* overflow? */
- luaL_error(L, "string slice too long");
+ return luaL_error(L, "string slice too long");
luaL_checkstack(L, n, "string slice too long");
for (i=0; i<n; i++)
lua_pushinteger(L, uchar(s[posi+i-1]));
@@ -161,7 +175,7 @@ static int str_dump (lua_State *L) {
lua_settop(L, 1);
luaL_buffinit(L,&b);
if (lua_dump(L, writer, &b) != 0)
- luaL_error(L, "unable to dump given function");
+ return luaL_error(L, "unable to dump given function");
luaL_pushresult(&b);
return 1;
}
@@ -510,7 +524,7 @@ static int nospecials (const char *p, size_t l) {
size_t upto = 0;
do {
if (strpbrk(p + upto, SPECIALS))
- return 0; /* pattern has a special character */
+ return 0; /* pattern has a special character */
upto += strlen(p + upto) + 1; /* may have more after \0 */
} while (upto <= l);
return 1; /* no special chars found */
@@ -729,7 +743,7 @@ static int str_gsub (lua_State *L) {
** the previous length
*/
#if !defined(LUA_INTFRMLEN) /* { */
-#if defined(LUA_USELONGLONG)
+#if defined(LUA_USE_LONGLONG)
#define LUA_INTFRMLEN "ll"
#define LUA_INTFRM_T long long
@@ -794,7 +808,7 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
const char *p = strfrmt;
while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */
- if ((size_t)(p - strfrmt) >= sizeof(FLAGS))
+ if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char))
luaL_error(L, "invalid format (repeated flags)");
if (isdigit(uchar(*p))) p++; /* skip width */
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
@@ -806,7 +820,7 @@ static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
if (isdigit(uchar(*p)))
luaL_error(L, "invalid format (width or precision too long)");
*(form++) = '%';
- memcpy(form, strfrmt, p - strfrmt + 1);
+ memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char));
form += p - strfrmt + 1;
*form = '\0';
return p;
@@ -861,6 +875,9 @@ static int str_format (lua_State *L) {
break;
}
case 'e': case 'E': case 'f':
+#if defined(LUA_USE_AFORMAT)
+ case 'a': case 'A':
+#endif
case 'g': case 'G': {
addlenmod(form, LUA_FLTFRMLEN);
nb = sprintf(buff, form, (LUA_FLTFRM_T)luaL_checknumber(L, arg));
@@ -872,16 +889,16 @@ static int str_format (lua_State *L) {
}
case 's': {
size_t l;
- const char *s = luaL_checklstring(L, arg, &l);
+ const char *s = luaL_tolstring(L, arg, &l);
if (!strchr(form, '.') && l >= 100) {
/* no precision and string is too long to be formatted;
keep original string */
- lua_pushvalue(L, arg);
luaL_addvalue(&b);
break;
}
else {
nb = sprintf(buff, form, s);
+ lua_pop(L, 1); /* remove result from 'luaL_tolstring' */
break;
}
}
@@ -900,6 +917,15 @@ static int str_format (lua_State *L) {
/* }====================================================== */
+static int noindex (lua_State *L) {
+ const char *f = lua_tostring(L, 2);
+ if (f)
+ return luaL_error(L, "no field '%s' in strings", f);
+ else
+ return luaL_error(L, "no such field in strings");
+}
+
+
static const luaL_Reg strlib[] = {
{"byte", str_byte},
{"char", str_char},
@@ -915,19 +941,22 @@ static const luaL_Reg strlib[] = {
{"reverse", str_reverse},
{"sub", str_sub},
{"upper", str_upper},
+ {"__index", noindex},
{NULL, NULL}
};
static void createmetatable (lua_State *L) {
- lua_createtable(L, 0, 1); /* create metatable for strings */
+ /* setmetatable("", {__index = string}) */
lua_pushliteral(L, ""); /* dummy string */
- lua_pushvalue(L, -2);
- lua_setmetatable(L, -2); /* set string metatable */
+ lua_createtable(L, 0, 1); /* create metatable for strings */
+ lua_pushvalue(L, -3); /* set the string library... */
+ lua_setfield(L, -2, "__index"); /* ...as the __index metamethod */
+ lua_setmetatable(L, -2); /* set metatable for strings */
lua_pop(L, 1); /* pop dummy string */
- lua_pushvalue(L, -2); /* string library... */
- lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */
- lua_pop(L, 1); /* pop metatable */
+ /* setmetatable(string, string) */
+ lua_pushvalue(L, -1); /* push string library */
+ lua_setmetatable(L, -2); /* set it as its own metatable */
}
diff --git a/src/ltable.c b/src/ltable.c
index 7ff0f897..155c2716 100644
--- a/src/ltable.c
+++ b/src/ltable.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltable.c,v 2.53 2010/11/11 15:38:43 roberto Exp $
+** $Id: ltable.c,v 2.59 2011/06/09 18:23:27 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -33,6 +33,7 @@
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
+#include "lvm.h"
/*
@@ -87,8 +88,9 @@ static Node *hashnum (const Table *t, lua_Number n) {
int i;
luai_hashnum(i, n);
if (i < 0) {
- i = -i; /* must be a positive value */
- if (i < 0) i = 0; /* handle INT_MIN */
+ if ((unsigned int)i == -(unsigned int)i)
+ i = 0; /* handle INT_MIN */
+ i = -i; /* must be a positive value */
}
return hashmod(t, i);
}
@@ -148,8 +150,8 @@ static int findindex (lua_State *L, Table *t, StkId key) {
Node *n = mainposition(t, key);
do { /* check whether `key' is somewhere in the chain */
/* key may be dead already, but it is ok to use it in `next' */
- if (luaO_rawequalObj(gkey(n), key) ||
- (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) &&
+ if (luaV_rawequalobj(gkey(n), key) ||
+ (ttisdeadkey(gkey(n)) && iscollectable(key) &&
gcvalue(gkey(n)) == gcvalue(key))) {
i = cast_int(n - gnode(t, 0)); /* key index in hash table */
/* hash elements are numbered after array ones */
@@ -336,7 +338,7 @@ void luaH_resizearray (lua_State *L, Table *t, int nasize) {
static void rehash (lua_State *L, Table *t, const TValue *ek) {
int nasize, na;
- int nums[MAXBITS+1]; /* nums[i] = number of keys between 2^(i-1) and 2^i */
+ int nums[MAXBITS+1]; /* nums[i] = number of keys with 2^(i-1) < k <= 2^i */
int i;
int totaluse;
for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */
@@ -467,7 +469,7 @@ const TValue *luaH_getstr (Table *t, TString *key) {
** main search function
*/
const TValue *luaH_get (Table *t, const TValue *key) {
- switch (ttype(key)) {
+ switch (ttypenv(key)) {
case LUA_TNIL: return luaO_nilobject;
case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key));
case LUA_TNUMBER: {
@@ -481,7 +483,7 @@ const TValue *luaH_get (Table *t, const TValue *key) {
default: {
Node *n = mainposition(t, key);
do { /* check whether `key' is somewhere in the chain */
- if (luaO_rawequalObj(gkey(n), key))
+ if (luaV_rawequalobj(gkey(n), key))
return gval(n); /* that's it */
else n = gnext(n);
} while (n);
diff --git a/src/ltablib.c b/src/ltablib.c
index faabfe53..0d69fc90 100644
--- a/src/ltablib.c
+++ b/src/ltablib.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltablib.c,v 1.58 2010/11/23 17:21:14 roberto Exp $
+** $Id: ltablib.c,v 1.59 2010/12/17 12:15:34 roberto Exp $
** Library for Table Manipulation
** See Copyright Notice in lua.h
*/
@@ -17,7 +17,7 @@
#define aux_getn(L,n) \
- (luaL_checktype(L, n, LUA_TTABLE), (int)lua_rawlen(L, n))
+ (luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n))
static int deprecatedfunc (lua_State *L) {
@@ -104,7 +104,7 @@ static int tconcat (lua_State *L) {
const char *sep = luaL_optlstring(L, 2, "", &lsep);
luaL_checktype(L, 1, LUA_TTABLE);
i = luaL_optint(L, 3, 1);
- last = luaL_opt(L, luaL_checkint, 4, (int)lua_rawlen(L, 1));
+ last = luaL_opt(L, luaL_checkint, 4, luaL_len(L, 1));
luaL_buffinit(L, &b);
for (; i < last; i++) {
addfield(L, &b, i);
@@ -143,7 +143,7 @@ static int unpack (lua_State *L) {
int i, e, n;
luaL_checktype(L, 1, LUA_TTABLE);
i = luaL_optint(L, 2, 1);
- e = luaL_opt(L, luaL_checkint, 3, (int)lua_rawlen(L, 1));
+ 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 */
diff --git a/src/ltm.c b/src/ltm.c
index faa8f57d..e70006dd 100644
--- a/src/ltm.c
+++ b/src/ltm.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.c,v 2.12 2010/04/13 20:48:12 roberto Exp $
+** $Id: ltm.c,v 2.14 2011/06/02 19:31:40 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -21,11 +21,11 @@
static const char udatatypename[] = "userdata";
-LUAI_DDEF const char *const luaT_typenames_[] = {
+LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = {
"no value",
"nil", "boolean", udatatypename, "number",
"string", "table", "function", udatatypename, "thread",
- "proto", "upval"
+ "proto", "upval" /* these last two cases are used for tests only */
};
@@ -62,7 +62,7 @@ const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
Table *mt;
- switch (ttype(o)) {
+ switch (ttypenv(o)) {
case LUA_TTABLE:
mt = hvalue(o)->metatable;
break;
diff --git a/src/ltm.h b/src/ltm.h
index 05abc40b..89bdc19a 100644
--- a/src/ltm.h
+++ b/src/ltm.h
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.h,v 2.10 2010/04/13 20:48:12 roberto Exp $
+** $Id: ltm.h,v 2.11 2011/02/28 17:32:10 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -46,7 +46,7 @@ typedef enum {
#define ttypename(x) luaT_typenames_[(x) + 1]
#define objtypename(x) ttypename(ttypenv(x))
-LUAI_DDEC const char *const luaT_typenames_[];
+LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS];
LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename);
diff --git a/src/lua.c b/src/lua.c
index fe2f0698..4d098b97 100644
--- a/src/lua.c
+++ b/src/lua.c
@@ -1,5 +1,5 @@
/*
-** $Id: lua.c,v 1.194 2010/10/25 19:01:37 roberto Exp $
+** $Id: lua.c,v 1.199 2011/05/26 16:09:40 roberto Exp $
** Lua stand-alone interpreter
** See Copyright Notice in lua.h
*/
@@ -106,13 +106,11 @@ static void laction (int i) {
static void print_usage (const char *badoption) {
- if (badoption[1] == 'e' || badoption[1] == 'l') {
- luai_writestringerror("%s: ", progname);
+ luai_writestringerror("%s: ", progname);
+ if (badoption[1] == 'e' || badoption[1] == 'l')
luai_writestringerror("'%s' needs argument\n", badoption);
- } else {
- luai_writestringerror("%s: ", progname);
+ else
luai_writestringerror("unrecognized option '%s'\n", badoption);
- }
luai_writestringerror(
"usage: %s [options] [script [args]]\n"
"Available options are:\n"
@@ -185,7 +183,8 @@ static int docall (lua_State *L, int narg, int nres) {
static void print_version (void) {
- printf("%s\n", LUA_COPYRIGHT);
+ luai_writestring(LUA_COPYRIGHT, sizeof(LUA_COPYRIGHT));
+ luai_writeline();
}
@@ -247,14 +246,14 @@ static const char *get_prompt (lua_State *L, int firstline) {
}
/* mark in error messages for incomplete statements */
-#define mark "<eof>"
-#define marklen (sizeof(mark) - 1)
+#define EOFMARK "<eof>"
+#define marklen (sizeof(EOFMARK)/sizeof(char) - 1)
static int incomplete (lua_State *L, int status) {
if (status == LUA_ERRSYNTAX) {
size_t lmsg;
const char *msg = lua_tolstring(L, -1, &lmsg);
- if (lmsg >= marklen && strcmp(msg + lmsg - marklen, mark) == 0) {
+ if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) {
lua_pop(L, 1);
return 1;
}
@@ -322,7 +321,7 @@ static void dotty (lua_State *L) {
}
}
lua_settop(L, 0); /* clear stack */
- luai_writestring("\n", 1);
+ luai_writeline();
progname = oldprogname;
}
diff --git a/src/lua.h b/src/lua.h
index 0e1f97a4..05d0d565 100644
--- a/src/lua.h
+++ b/src/lua.h
@@ -1,5 +1,5 @@
/*
-** $Id: lua.h,v 1.276 2010/10/26 19:32:19 roberto Exp $
+** $Id: lua.h,v 1.277 2011/04/18 14:15:48 roberto Exp $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
@@ -18,12 +18,12 @@
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "2"
-#define LUA_VERSION_RELEASE "0" " (alpha)"
+#define LUA_VERSION_RELEASE "0" " (beta)"
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_VERSION_NUM 502
-#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2010 Lua.org, PUC-Rio"
+#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2011 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -415,7 +415,7 @@ struct lua_Debug {
/******************************************************************************
-* Copyright (C) 1994-2010 Lua.org, PUC-Rio. All rights reserved.
+* Copyright (C) 1994-2011 Lua.org, PUC-Rio. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
diff --git a/src/luac.c b/src/luac.c
index 19ef916d..1b28c799 100644
--- a/src/luac.c
+++ b/src/luac.c
@@ -1,5 +1,5 @@
/*
-** $Id: luac.c,v 1.65 2010/10/26 09:07:52 lhf Exp $
+** $Id: luac.c,v 1.66 2011/05/10 01:08:57 lhf Exp $
** Lua compiler (saves bytecodes to files; also list bytecodes)
** See Copyright Notice in lua.h
*/
@@ -143,9 +143,12 @@ static const Proto* combine(lua_State* L, int n)
int i=n;
if (lua_load(L,reader,&i,"=(" PROGNAME ")")!=LUA_OK) fatal(lua_tostring(L,-1));
f=toproto(L,-1);
- for (i=0; i<n; i++) f->p[i]=toproto(L,i-n-1);
+ for (i=0; i<n; i++)
+ {
+ f->p[i]=toproto(L,i-n-1);
+ if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
+ }
f->sizelineinfo=0;
- f->sizeupvalues=0;
return f;
}
}
@@ -200,7 +203,7 @@ int main(int argc, char* argv[])
}
/*
-** $Id: print.c,v 1.66 2010/10/26 09:07:52 lhf Exp $
+** $Id: print.c,v 1.67 2011/05/06 13:37:15 lhf Exp $
** print bytecodes
** See Copyright Notice in lua.h
*/
@@ -270,6 +273,7 @@ static void PrintConstant(const Proto* f, int i)
}
#define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-")
+#define MYK(x) (-1-(x))
static void PrintCode(const Proto* f)
{
@@ -293,23 +297,25 @@ static void PrintCode(const Proto* f)
{
case iABC:
printf("%d",a);
- if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (-1-INDEXK(b)) : b);
- if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c);
+ if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (MYK(INDEXK(b))) : b);
+ if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (MYK(INDEXK(c))) : c);
break;
case iABx:
- if (getBMode(o)==OpArgK) printf("%d %d",a,-bx); else printf("%d %d",a,bx);
+ printf("%d",a);
+ if (getBMode(o)==OpArgK) printf(" %d",MYK(bx));
+ if (getBMode(o)==OpArgU) printf(" %d",bx);
break;
case iAsBx:
- if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx);
+ printf("%d %d",a,sbx);
break;
case iAx:
- printf("%d",-1-ax);
+ printf("%d",MYK(ax));
break;
}
switch (o)
{
case OP_LOADK:
- if (bx>0) { printf("\t; "); PrintConstant(f,bx-1); }
+ printf("\t; "); PrintConstant(f,bx);
break;
case OP_GETUPVAL:
case OP_SETUPVAL:
@@ -355,8 +361,7 @@ static void PrintCode(const Proto* f)
printf("\t; %p",VOID(f->p[bx]));
break;
case OP_SETLIST:
- if (c==0) printf("\t; %d",(int)code[++pc]);
- else printf("\t; %d",c);
+ if (c==0) printf("\t; %d",(int)code[++pc]); else printf("\t; %d",c);
break;
case OP_EXTRAARG:
printf("\t; "); PrintConstant(f,ax);
diff --git a/src/luaconf.h b/src/luaconf.h
index 1222dc9c..72a1689a 100644
--- a/src/luaconf.h
+++ b/src/luaconf.h
@@ -1,5 +1,5 @@
/*
-** $Id: luaconf.h,v 1.151 2010/11/12 15:48:30 roberto Exp $
+** $Id: luaconf.h,v 1.159 2011/06/13 14:13:06 roberto Exp $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
@@ -35,6 +35,7 @@
#if defined(LUA_WIN)
#define LUA_DL_DLL
+#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */
#endif
@@ -43,12 +44,18 @@
#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 hexa 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_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 hexa formats */
+#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */
+#define LUA_USE_LONGLONG /* assume support for long long */
#endif
@@ -202,10 +209,11 @@
/*
-@@ luai_writestring defines how 'print' prints its results.
+@@ luai_writestring/luai_writeline define how 'print' prints its results.
*/
#include <stdio.h>
#define luai_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
+#define luai_writeline() (luai_writestring("\n", 1), fflush(stdout))
/*
@@ luai_writestringerror defines how to print error messages.
@@ -254,6 +262,12 @@
#define LUA_COMPAT_LOG10
/*
+@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base
+** library. You can rewrite 'loadstring(s)' as 'load(s)'.
+*/
+#define LUA_COMPAT_LOADSTRING
+
+/*
@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library.
*/
#define LUA_COMPAT_MAXN
@@ -371,14 +385,27 @@
@@ LUA_NUMBER_FMT is the format for writing numbers.
@@ lua_number2str converts a number to a string.
@@ LUAI_MAXNUMBER2STR is maximum size of previous conversion.
-@@ lua_str2number converts a string to a number.
*/
#define LUA_NUMBER_SCAN "%lf"
#define LUA_NUMBER_FMT "%.14g"
#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n))
#define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */
+
+
+/*
+@@ lua_str2number converts a decimal numeric string to a number.
+@@ lua_strx2number converts an hexadecimal numeric string to a number.
+** In C99, 'strtod' do 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.
+*/
#define lua_str2number(s,p) strtod((s), (p))
+#if defined(LUA_USE_STRTODHEX)
+#define lua_strx2number(s,p) strtod((s), (p))
+#endif
+
/*
@@ The luai_num* macros define the primitive operations over numbers.
@@ -438,11 +465,11 @@
/*
@@ LUA_IEEEENDIAN is the endianness of doubles in your machine
-@@ (0 for little endian, 1 for big endian); if not defined, Lua will
-@@ check it dynamically.
+** (0 for little endian, 1 for big endian); if not defined, Lua will
+** check it dynamically.
*/
/* check for known architectures */
-#if defined(__i386__) || defined(__i386) || defined(i386) || \
+#if defined(__i386__) || defined(__i386) || defined(__X86__) || \
defined (__x86_64)
#define LUA_IEEEENDIAN 0
#elif defined(__POWERPC__) || defined(__ppc__)
@@ -458,6 +485,30 @@
/* }================================================================== */
+/*
+@@ LUA_NANTRICKLE/LUA_NANTRICKBE controls the use of a trick to pack all
+** types into a single double value, using NaN values to represent
+** non-number values. The trick only works on 32-bit machines (ints and
+** pointers are 32-bit values) with numbers represented as IEEE 754-2008
+** doubles with conventional endianess (12345678 or 87654321), in CPUs
+** that do not produce signaling NaN values (all NaNs are quiet).
+*/
+#if defined(LUA_CORE) /* { */
+
+#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */
+
+/* little-endian architectures that satisfy those conditions */
+#if defined(__i386__) || defined(__i386) || defined(__X86__)
+
+#define LUA_NANTRICKLE
+
+#endif
+
+#endif /* } */
+
+#endif /* } */
+
+
/* =================================================================== */
diff --git a/src/lualib.h b/src/lualib.h
index 233a331e..8132da6c 100644
--- a/src/lualib.h
+++ b/src/lualib.h
@@ -1,5 +1,5 @@
/*
-** $Id: lualib.h,v 1.41 2010/10/25 14:32:36 roberto Exp $
+** $Id: lualib.h,v 1.42 2011/05/25 14:12:28 roberto Exp $
** Lua standard libraries
** See Copyright Notice in lua.h
*/
@@ -50,7 +50,7 @@ LUALIB_API void (luaL_openlibs) (lua_State *L);
-#ifndef lua_assert
+#if !defined(lua_assert)
#define lua_assert(x) ((void)0)
#endif
diff --git a/src/lundump.c b/src/lundump.c
index c875d767..ba1a3dc3 100644
--- a/src/lundump.c
+++ b/src/lundump.c
@@ -1,5 +1,5 @@
/*
-** $Id: lundump.c,v 1.68 2010/10/26 00:23:46 lhf Exp $
+** $Id: lundump.c,v 1.69 2011/05/06 13:35:17 lhf Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -38,6 +38,10 @@ static void error(LoadState* S, const char* why)
#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) (f)
+#endif
+
static void LoadBlock(LoadState* S, void* b, size_t size)
{
if (luaZ_read(S->Z,b,size)!=0) error(S,"corrupted");
@@ -54,6 +58,7 @@ static int LoadInt(LoadState* S)
{
int x;
LoadVar(S,x);
+ if (x<0) error(S,"corrupted");
return x;
}
@@ -73,7 +78,7 @@ static TString* LoadString(LoadState* S)
else
{
char* s=luaZ_openspace(S->L,S->b,size);
- LoadBlock(S,s,size);
+ LoadBlock(S,s,size*sizeof(char));
return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */
}
}
@@ -177,16 +182,17 @@ static Proto* LoadFunction(LoadState* S)
/* the code below must be consistent with the code in luaU_header */
#define N0 LUAC_HEADERSIZE
-#define N1 (sizeof(LUA_SIGNATURE)-1)
+#define N1 (sizeof(LUA_SIGNATURE)-sizeof(char))
#define N2 N1+2
#define N3 N2+6
static void LoadHeader(LoadState* S)
{
- char h[LUAC_HEADERSIZE];
- char s[LUAC_HEADERSIZE];
+ lu_byte h[LUAC_HEADERSIZE];
+ lu_byte s[LUAC_HEADERSIZE];
luaU_header(h);
- LoadBlock(S,s,LUAC_HEADERSIZE);
+ 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");
@@ -209,29 +215,30 @@ Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name)
S.Z=Z;
S.b=buff;
LoadHeader(&S);
- return LoadFunction(&S);
+ return luai_verifycode(L,buff,LoadFunction(&S));
}
-/* data to catch conversion errors */
-#define TAIL "\x19\x93\r\n\x1a\n"
+#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 make any changes in the code below or in LUA_SIGNATURE in lua.h,
-* be sure to update LoadHeader above and LUAC_HEADERSIZE in lundump.h
+* if you change the code below be sure to update LoadHeader and FORMAT above
+* and LUAC_HEADERSIZE in lundump.h
*/
-void luaU_header (char* h)
+void luaU_header (lu_byte* h)
{
int x=1;
- memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1);
- h+=sizeof(LUA_SIGNATURE)-1;
- *h++=(char)0x52; /* Lua 5.2 */
- *h++=(char)0; /* the official format */
- *h++=(char)*(char*)&x; /* endianness */
- *h++=(char)sizeof(int);
- *h++=(char)sizeof(size_t);
- *h++=(char)sizeof(Instruction);
- *h++=(char)sizeof(lua_Number);
- *h++=(char)(((lua_Number)0.5)==0); /* is lua_Number integral? */
- memcpy(h,TAIL,sizeof(TAIL)-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));
}
diff --git a/src/lundump.h b/src/lundump.h
index e55918cf..b63993ff 100644
--- a/src/lundump.h
+++ b/src/lundump.h
@@ -1,5 +1,5 @@
/*
-** $Id: lundump.h,v 1.43 2010/10/26 00:23:46 lhf Exp $
+** $Id: lundump.h,v 1.44 2011/05/06 13:35:17 lhf Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -14,12 +14,15 @@
LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name);
/* make header; from lundump.c */
-LUAI_FUNC void luaU_header (char* h);
+LUAI_FUNC void luaU_header (lu_byte* h);
/* dump one chunk; from ldump.c */
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip);
-/* size of header of binary files */
-#define LUAC_HEADERSIZE 18
+/* data to catch conversion errors */
+#define LUAC_TAIL "\x19\x93\r\n\x1a\n"
+
+/* size in bytes of header of binary files */
+#define LUAC_HEADERSIZE (sizeof(LUA_SIGNATURE)-sizeof(char)+2+6+sizeof(LUAC_TAIL)-sizeof(char))
#endif
diff --git a/src/lvm.c b/src/lvm.c
index 42c6c81f..e4f90af4 100644
--- a/src/lvm.c
+++ b/src/lvm.c
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.c,v 2.125 2010/10/29 17:52:46 roberto Exp $
+** $Id: lvm.c,v 2.141 2011/06/09 18:24:22 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -35,7 +35,7 @@
const TValue *luaV_tonumber (const TValue *obj, TValue *n) {
lua_Number num;
if (ttisnumber(obj)) return obj;
- if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) {
+ if (ttisstring(obj) && luaO_str2d(svalue(obj), tsvalue(obj)->len, &num)) {
setnvalue(n, num);
return n;
}
@@ -65,7 +65,7 @@ static void traceexec (lua_State *L) {
luaD_hook(L, LUA_HOOKCOUNT, -1);
}
if (mask & LUA_MASKLINE) {
- Proto *p = ci_func(ci)->l.p;
+ Proto *p = ci_func(ci)->p;
int npc = pcRel(ci->u.l.savedpc, p);
int newline = getfuncline(p, npc);
if (npc == 0 || /* call linehook when enter a new function, */
@@ -161,7 +161,6 @@ static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2,
if (ttisnil(tm))
tm = luaT_gettmbyobj(L, p2, event); /* try second operand */
if (ttisnil(tm)) return 0;
- if (event == TM_UNM) p2 = luaO_nilobject;
callTM(L, tm, p1, p2, res, 1);
return 1;
}
@@ -175,7 +174,7 @@ static const TValue *get_equalTM (lua_State *L, Table *mt1, Table *mt2,
if (mt1 == mt2) return tm1; /* same metatables => same metamethods */
tm2 = fasttm(L, mt2, event);
if (tm2 == NULL) return NULL; /* no metamethod */
- if (luaO_rawequalObj(tm1, tm2)) /* same metamethods? */
+ if (luaV_rawequalobj(tm1, tm2)) /* same metamethods? */
return tm1;
return NULL;
}
@@ -238,9 +237,12 @@ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
}
-int luaV_equalval_ (lua_State *L, const TValue *t1, const TValue *t2) {
+/*
+** equality of Lua values. L == NULL means raw equality (no metamethods)
+*/
+int luaV_equalobj_ (lua_State *L, const TValue *t1, const TValue *t2) {
const TValue *tm;
- lua_assert(ttype(t1) == ttype(t2));
+ lua_assert(ttisequal(t1, t2));
switch (ttype(t1)) {
case LUA_TNIL: return 1;
case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2));
@@ -250,15 +252,19 @@ int luaV_equalval_ (lua_State *L, const TValue *t1, const TValue *t2) {
case LUA_TSTRING: return eqstr(rawtsvalue(t1), rawtsvalue(t2));
case LUA_TUSERDATA: {
if (uvalue(t1) == uvalue(t2)) return 1;
+ else if (L == NULL) return 0;
tm = get_equalTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ);
break; /* will try TM */
}
case LUA_TTABLE: {
if (hvalue(t1) == hvalue(t2)) return 1;
+ else if (L == NULL) return 0;
tm = get_equalTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ);
break; /* will try TM */
}
- default: return gcvalue(t1) == gcvalue(t2);
+ default:
+ lua_assert(iscollectable(t1));
+ return gcvalue(t1) == gcvalue(t2);
}
if (tm == NULL) return 0; /* no TM? */
callTM(L, tm, t1, t2, L->top, 1); /* call TM */
@@ -286,18 +292,20 @@ void luaV_concat (lua_State *L, int total) {
char *buffer;
int i;
/* collect total length */
- for (n = 1; n < total && tostring(L, top-n-1); n++) {
- size_t l = tsvalue(top-n-1)->len;
- if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
+ for (i = 1; i < total && tostring(L, top-i-1); i++) {
+ size_t l = tsvalue(top-i-1)->len;
+ if (l >= (MAX_SIZET/sizeof(char)) - tl)
+ luaG_runerror(L, "string length overflow");
tl += l;
}
buffer = luaZ_openspace(L, &G(L)->buff, tl);
tl = 0;
- for (i=n; i>0; i--) { /* concat all strings */
+ n = i;
+ do { /* concat all strings */
size_t l = tsvalue(top-i)->len;
- memcpy(buffer+tl, svalue(top-i), l);
+ memcpy(buffer+tl, svalue(top-i), l * sizeof(char));
tl += l;
- }
+ } while (--i > 0);
setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
}
total -= n-1; /* got 'n' strings to create 1 new */
@@ -308,7 +316,7 @@ void luaV_concat (lua_State *L, int total) {
void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
const TValue *tm;
- switch (ttype(rb)) {
+ switch (ttypenv(rb)) {
case LUA_TTABLE: {
Table *h = hvalue(rb);
tm = fasttm(L, h->metatable, TM_LEN);
@@ -327,7 +335,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
break;
}
}
- callTM(L, tm, rb, luaO_nilobject, ra, 1);
+ callTM(L, tm, rb, rb, ra, 1);
}
@@ -378,7 +386,7 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
Upvaldesc *uv = p->upvalues;
int i;
Closure *ncl = luaF_newLclosure(L, p);
- setclvalue(L, ra, ncl); /* anchor new closure in stack */
+ setclLvalue(L, ra, ncl); /* anchor new closure in stack */
for (i = 0; i < nup; i++) { /* fill in its upvalues */
if (uv[i].instack) /* upvalue refers to local variable? */
ncl->l.upvals[i] = luaF_findupval(L, base + uv[i].idx);
@@ -454,6 +462,11 @@ void luaV_finishOp (lua_State *L) {
** some macros for common tasks in `luaV_execute'
*/
+#if !defined luai_runtimecheck
+#define luai_runtimecheck(L, c) /* void */
+#endif
+
+
#define RA(i) (base+GETARG_A(i))
/* to be used after possible stack reallocation */
#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i))
@@ -466,12 +479,19 @@ void luaV_finishOp (lua_State *L) {
(k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++)))
-#define dojump(i) (ci->u.l.savedpc += (i))
+/* execute a jump instruction */
+#define dojump(ci,i,e) \
+ { int a = GETARG_A(i); \
+ if (a > 0) luaF_close(L, ci->u.l.base + a - 1); \
+ ci->u.l.savedpc += GETARG_sBx(i) + e; }
+
+/* for test instructions, execute the jump instruction that follows it */
+#define donextjump(ci) { i = *ci->u.l.savedpc; dojump(ci, i, 1); }
#define Protect(x) { {x;}; base = ci->u.l.base; }
-#define checkGC(L) Protect(luaC_checkGC(L); luai_threadyield(L);)
+#define checkGC(L,c) Protect(luaC_condGC(L, c); luai_threadyield(L);)
#define arith_op(op,tm) { \
@@ -493,9 +513,8 @@ void luaV_execute (lua_State *L) {
TValue *k;
StkId base;
newframe: /* reentry point when frame changes (call/return) */
- lua_assert(isLua(ci));
lua_assert(ci == L->ci);
- cl = &clvalue(ci->func)->l;
+ cl = clLvalue(ci->func);
k = cl->p->k;
base = ci->u.l.base;
/* main loop of interpreter */
@@ -515,7 +534,13 @@ void luaV_execute (lua_State *L) {
setobjs2s(L, ra, RB(i));
)
vmcase(OP_LOADK,
- TValue *rb = KBx(i);
+ TValue *rb = k + GETARG_Bx(i);
+ setobj2s(L, ra, rb);
+ )
+ vmcase(OP_LOADKX,
+ TValue *rb;
+ lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG);
+ rb = k + GETARG_Ax(*ci->u.l.savedpc++);
setobj2s(L, ra, rb);
)
vmcase(OP_LOADBOOL,
@@ -523,10 +548,10 @@ void luaV_execute (lua_State *L) {
if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */
)
vmcase(OP_LOADNIL,
- TValue *rb = RB(i);
+ int b = GETARG_B(i);
do {
- setnilvalue(rb--);
- } while (rb >= ra);
+ setnilvalue(ra++);
+ } while (b--);
)
vmcase(OP_GETUPVAL,
int b = GETARG_B(i);
@@ -558,7 +583,11 @@ void luaV_execute (lua_State *L) {
sethvalue(L, ra, t);
if (b != 0 || c != 0)
luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c));
- checkGC(L);
+ checkGC(L,
+ L->top = ra + 1; /* limit of live values */
+ luaC_step(L);
+ L->top = ci->top; /* restore top */
+ )
)
vmcase(OP_SELF,
StkId rb = RB(i);
@@ -594,7 +623,8 @@ void luaV_execute (lua_State *L) {
}
)
vmcase(OP_NOT,
- int res = l_isfalse(RB(i)); /* next assignment may change this value */
+ TValue *rb = RB(i);
+ int res = l_isfalse(rb); /* next assignment may change this value */
setbvalue(ra, res);
)
vmcase(OP_LEN,
@@ -603,49 +633,61 @@ void luaV_execute (lua_State *L) {
vmcase(OP_CONCAT,
int b = GETARG_B(i);
int c = GETARG_C(i);
+ StkId rb;
L->top = base + c + 1; /* mark the end of concat operands */
- Protect(luaV_concat(L, c-b+1); checkGC(L);)
+ Protect(luaV_concat(L, c - b + 1));
+ ra = RA(i); /* 'luav_concat' may invoke TMs and move the stack */
+ rb = b + base;
+ setobjs2s(L, ra, rb);
+ checkGC(L,
+ L->top = (ra >= rb ? ra + 1 : rb); /* limit of live values */
+ luaC_step(L);
+ )
L->top = ci->top; /* restore top */
- setobjs2s(L, RA(i), base+b);
)
vmcase(OP_JMP,
- dojump(GETARG_sBx(i));
+ dojump(ci, i, 0);
)
vmcase(OP_EQ,
TValue *rb = RKB(i);
TValue *rc = RKC(i);
Protect(
- if (equalobj(L, rb, rc) == GETARG_A(i))
- dojump(GETARG_sBx(*ci->u.l.savedpc));
+ if (equalobj(L, rb, rc) != GETARG_A(i))
+ ci->u.l.savedpc++;
+ else
+ donextjump(ci);
)
- ci->u.l.savedpc++;
)
vmcase(OP_LT,
Protect(
- if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i))
- dojump(GETARG_sBx(*ci->u.l.savedpc));
+ if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i))
+ ci->u.l.savedpc++;
+ else
+ donextjump(ci);
)
- ci->u.l.savedpc++;
)
vmcase(OP_LE,
Protect(
- if (luaV_lessequal(L, RKB(i), RKC(i)) == GETARG_A(i))
- dojump(GETARG_sBx(*ci->u.l.savedpc));
+ if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i))
+ ci->u.l.savedpc++;
+ else
+ donextjump(ci);
)
- ci->u.l.savedpc++;
)
vmcase(OP_TEST,
- if (GETARG_C(i) ? !l_isfalse(ra) : l_isfalse(ra))
- dojump(GETARG_sBx(*ci->u.l.savedpc));
- ci->u.l.savedpc++;
+ if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra))
+ ci->u.l.savedpc++;
+ else
+ donextjump(ci);
)
vmcase(OP_TESTSET,
TValue *rb = RB(i);
- if (GETARG_C(i) ? !l_isfalse(rb) : l_isfalse(rb)) {
+ if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb))
+ ci->u.l.savedpc++;
+ else {
setobjs2s(L, ra, rb);
- dojump(GETARG_sBx(*ci->u.l.savedpc));
+ donextjump(ci);
}
- ci->u.l.savedpc++;
)
vmcase(OP_CALL,
int b = GETARG_B(i);
@@ -711,7 +753,7 @@ void luaV_execute (lua_State *L) {
lua_Number limit = nvalue(ra+1);
if (luai_numlt(L, 0, step) ? luai_numle(L, idx, limit)
: luai_numle(L, limit, idx)) {
- dojump(GETARG_sBx(i)); /* jump back */
+ ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
setnvalue(ra, idx); /* update internal index... */
setnvalue(ra+3, idx); /* ...and external index */
}
@@ -727,7 +769,7 @@ void luaV_execute (lua_State *L) {
else if (!tonumber(pstep, ra+2))
luaG_runerror(L, LUA_QL("for") " step must be a number");
setnvalue(ra, luai_numsub(L, nvalue(ra), nvalue(pstep)));
- dojump(GETARG_sBx(i));
+ ci->u.l.savedpc += GETARG_sBx(i);
)
vmcase(OP_TFORCALL,
StkId cb = ra + 3; /* call base */
@@ -746,7 +788,7 @@ void luaV_execute (lua_State *L) {
l_tforloop:
if (!ttisnil(ra + 1)) { /* continue loop? */
setobjs2s(L, ra, ra + 1); /* save control variable */
- dojump(GETARG_sBx(i)); /* jump back */
+ ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
}
)
vmcase(OP_SETLIST,
@@ -759,6 +801,7 @@ void luaV_execute (lua_State *L) {
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG);
c = GETARG_Ax(*ci->u.l.savedpc++);
}
+ luai_runtimecheck(L, ttistable(ra));
h = hvalue(ra);
last = ((c-1)*LFIELDS_PER_FLUSH) + n;
if (last > h->sizearray) /* needs more space? */
@@ -770,17 +813,18 @@ void luaV_execute (lua_State *L) {
}
L->top = ci->top; /* correct top (in case of previous open call) */
)
- vmcase(OP_CLOSE,
- luaF_close(L, ra);
- )
vmcase(OP_CLOSURE,
Proto *p = cl->p->p[GETARG_Bx(i)];
Closure *ncl = getcached(p, cl->upvals, base); /* cached closure */
if (ncl == NULL) /* no match? */
pushclosure(L, p, cl->upvals, base, ra); /* create a new one */
else
- setclvalue(L, ra, ncl); /* push cashed closure */
- checkGC(L);
+ setclLvalue(L, ra, ncl); /* push cashed closure */
+ checkGC(L,
+ L->top = ra + 1; /* limit of live values */
+ luaC_step(L);
+ L->top = ci->top; /* restore top */
+ )
)
vmcase(OP_VARARG,
int b = GETARG_B(i) - 1;
diff --git a/src/lvm.h b/src/lvm.h
index 8e91da59..ec358224 100644
--- a/src/lvm.h
+++ b/src/lvm.h
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.h,v 2.14 2009/12/17 16:20:01 roberto Exp $
+** $Id: lvm.h,v 2.17 2011/05/31 18:27:56 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -17,12 +17,15 @@
#define tonumber(o,n) (ttisnumber(o) || (((o) = luaV_tonumber(o,n)) != NULL))
-#define equalobj(L,o1,o2) \
- (ttype(o1) == ttype(o2) && luaV_equalval_(L, o1, o2))
+#define equalobj(L,o1,o2) (ttisequal(o1, o2) && luaV_equalobj_(L, o1, o2))
+
+#define luaV_rawequalobj(t1,t2) \
+ (ttisequal(t1,t2) && luaV_equalobj_(NULL,t1,t2))
/* not to called directly */
-LUAI_FUNC int luaV_equalval_ (lua_State *L, const TValue *t1, const TValue *t2);
+LUAI_FUNC int luaV_equalobj_ (lua_State *L, const TValue *t1, const TValue *t2);
+
LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
diff --git a/src/lzio.c b/src/lzio.c
index 5121ada8..7d2677bd 100644
--- a/src/lzio.c
+++ b/src/lzio.c
@@ -1,5 +1,5 @@
/*
-** $Id: lzio.c,v 1.31 2005/06/03 20:15:29 roberto Exp $
+** $Id: lzio.c,v 1.33 2011/02/23 13:13:10 roberto Exp $
** a generic input stream interface
** See Copyright Notice in lua.h
*/
@@ -25,26 +25,14 @@ int luaZ_fill (ZIO *z) {
lua_unlock(L);
buff = z->reader(L, z->data, &size);
lua_lock(L);
- if (buff == NULL || size == 0) return EOZ;
- z->n = size - 1;
+ if (buff == NULL || size == 0)
+ return EOZ;
+ z->n = size - 1; /* discount char being returned */
z->p = buff;
return char2int(*(z->p++));
}
-int luaZ_lookahead (ZIO *z) {
- if (z->n == 0) {
- if (luaZ_fill(z) == EOZ)
- return EOZ;
- else {
- z->n++; /* luaZ_fill removed first byte; put back it */
- z->p--;
- }
- }
- return char2int(*z->p);
-}
-
-
void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) {
z->L = L;
z->reader = reader;
@@ -58,8 +46,14 @@ void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) {
size_t luaZ_read (ZIO *z, void *b, size_t n) {
while (n) {
size_t m;
- if (luaZ_lookahead(z) == EOZ)
- return n; /* return number of missing bytes */
+ if (z->n == 0) { /* no bytes in buffer? */
+ if (luaZ_fill(z) == EOZ) /* try to read more */
+ return n; /* no more input; return number of missing bytes */
+ else {
+ z->n++; /* luaZ_fill consumed first byte; put it back */
+ z->p--;
+ }
+ }
m = (n <= z->n) ? n : z->n; /* min. between n and z->n */
memcpy(b, z->p, m);
z->n -= m;
diff --git a/src/lzio.h b/src/lzio.h
index 53eb91ef..4174986d 100644
--- a/src/lzio.h
+++ b/src/lzio.h
@@ -1,5 +1,5 @@
/*
-** $Id: lzio.h,v 1.22 2009/05/18 17:26:25 roberto Exp $
+** $Id: lzio.h,v 1.24 2011/02/23 13:13:10 roberto Exp $
** Buffered streams
** See Copyright Notice in lua.h
*/
@@ -50,7 +50,6 @@ LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n);
LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader,
void *data);
LUAI_FUNC size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */
-LUAI_FUNC int luaZ_lookahead (ZIO *z);
@@ -59,7 +58,7 @@ LUAI_FUNC int luaZ_lookahead (ZIO *z);
struct Zio {
size_t n; /* bytes still unread */
const char *p; /* current position in buffer */
- lua_Reader reader;
+ lua_Reader reader; /* reader function */
void* data; /* additional data */
lua_State *L; /* Lua state (for reader) */
};