aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--README2
-rw-r--r--doc/contents.html40
-rw-r--r--doc/index.css21
-rw-r--r--doc/logo.gifbin4232 -> 9893 bytes
-rw-r--r--doc/lua.13
-rw-r--r--doc/lua.css137
-rw-r--r--doc/manual.css14
-rw-r--r--doc/manual.html1180
-rw-r--r--doc/readme.html40
-rw-r--r--src/Makefile60
-rw-r--r--src/lapi.c266
-rw-r--r--src/lapi.h6
-rw-r--r--src/lauxlib.c161
-rw-r--r--src/lauxlib.h14
-rw-r--r--src/lbaselib.c54
-rw-r--r--src/lbitlib.c51
-rw-r--r--src/lcode.c709
-rw-r--r--src/lcode.h5
-rw-r--r--src/lcorolib.c4
-rw-r--r--src/ldblib.c21
-rw-r--r--src/ldebug.c131
-rw-r--r--src/ldebug.h7
-rw-r--r--src/ldo.c287
-rw-r--r--src/ldo.h26
-rw-r--r--src/ldump.c9
-rw-r--r--src/lfunc.h9
-rw-r--r--src/lgc.c111
-rw-r--r--src/lgc.h41
-rw-r--r--src/linit.c6
-rw-r--r--src/liolib.c70
-rw-r--r--src/llex.c63
-rw-r--r--src/llex.h3
-rw-r--r--src/llimits.h131
-rw-r--r--src/lmathlib.c22
-rw-r--r--src/lmem.c11
-rw-r--r--src/loadlib.c176
-rw-r--r--src/lobject.c149
-rw-r--r--src/lobject.h117
-rw-r--r--src/lopcodes.h4
-rw-r--r--src/loslib.c233
-rw-r--r--src/lparser.c55
-rw-r--r--src/lparser.h53
-rw-r--r--src/lstate.c37
-rw-r--r--src/lstate.h34
-rw-r--r--src/lstring.c112
-rw-r--r--src/lstring.h7
-rw-r--r--src/lstrlib.c352
-rw-r--r--src/ltable.c233
-rw-r--r--src/ltable.h19
-rw-r--r--src/ltablib.c381
-rw-r--r--src/ltm.c40
-rw-r--r--src/ltm.h5
-rw-r--r--src/lua.c59
-rw-r--r--src/lua.h19
-rw-r--r--src/luac.c6
-rw-r--r--src/luaconf.h292
-rw-r--r--src/lualib.h5
-rw-r--r--src/lundump.c22
-rw-r--r--src/lundump.h5
-rw-r--r--src/lutf8lib.c15
-rw-r--r--src/lvm.c510
-rw-r--r--src/lvm.h69
-rw-r--r--src/lzio.c12
-rw-r--r--src/lzio.h3
65 files changed, 4185 insertions, 2556 deletions
diff --git a/Makefile b/Makefile
index 7fa91c858bb1..119110d2f010 100644
--- a/Makefile
+++ b/Makefile
@@ -46,7 +46,7 @@ TO_MAN= lua.1 luac.1
# Lua version and release.
V= 5.3
-R= $V.0
+R= $V.4
# Targets start here.
all: $(PLAT)
diff --git a/README b/README
index 32fb68e77e31..0b31908a06cb 100644
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
-This is Lua 5.3.0, released on 06 Jan 2015.
+This is Lua 5.3.4, released on 12 Jan 2017.
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 e59e4215eee3..445556f96415 100644
--- a/doc/contents.html
+++ b/doc/contents.html
@@ -3,43 +3,42 @@
<HEAD>
<TITLE>Lua 5.3 Reference Manual - contents</TITLE>
<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
+<LINK REL="stylesheet" TYPE="text/css" HREF="index.css">
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1">
-<STYLE TYPE="text/css">
-ul {
- list-style-type: none ;
- list-style-position: outside ;
-}
-</STYLE>
</HEAD>
<BODY>
-<HR>
<H1>
-<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="" BORDER=0></A>
+<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
Lua 5.3 Reference Manual
</H1>
<P>
The reference manual is the official definition of the Lua language.
+<BR>
For a complete introduction to Lua programming, see the book
<A HREF="http://www.lua.org/pil/">Programming in Lua</A>.
-<P>
+<DIV CLASS="menubar">
<A HREF="manual.html">start</A>
&middot;
<A HREF="#contents">contents</A>
&middot;
<A HREF="#index">index</A>
-<HR>
+&middot;
+<A HREF="http://www.lua.org/manual/">other versions</A>
+</DIV>
+
+<P>
<SMALL>
-Copyright &copy; 2015 Lua.org, PUC-Rio.
+Copyright &copy; 2015&ndash;2017 Lua.org, PUC-Rio.
Freely available under the terms of the
<A HREF="http://www.lua.org/license.html">Lua license</A>.
</SMALL>
<H2><A NAME="contents">Contents</A></H2>
-<UL style="padding: 0">
+<UL CLASS="contents menubar">
<LI><A HREF="manual.html">1 &ndash; Introduction</A>
<P>
<LI><A HREF="manual.html#2">2 &ndash; Basic Concepts</A>
@@ -136,15 +135,14 @@ Freely available under the terms of the
</UL>
<H2><A NAME="index">Index</A></H2>
-<TABLE WIDTH="100%">
-<TR VALIGN="top">
+<TABLE CLASS="menubar" WIDTH="100%">
+<TR>
<TD>
<H3><A NAME="functions">Lua functions</A></H3>
<P>
<A HREF="manual.html#6.1">basic</A><BR>
<A HREF="manual.html#pdf-_G">_G</A><BR>
<A HREF="manual.html#pdf-_VERSION">_VERSION</A><BR>
-
<A HREF="manual.html#pdf-assert">assert</A><BR>
<A HREF="manual.html#pdf-collectgarbage">collectgarbage</A><BR>
<A HREF="manual.html#pdf-dofile">dofile</A><BR>
@@ -321,6 +319,7 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-utf8.offset">utf8.offset</A><BR>
<H3><A NAME="env">environment<BR>variables</A></H3>
+<P>
<A HREF="manual.html#pdf-LUA_CPATH">LUA_CPATH</A><BR>
<A HREF="manual.html#pdf-LUA_CPATH_5_3">LUA_CPATH_5_3</A><BR>
<A HREF="manual.html#pdf-LUA_INIT">LUA_INIT</A><BR>
@@ -513,6 +512,7 @@ Freely available under the terms of the
<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>
+<A HREF="manual.html#luaL_opt">luaL_opt</A><BR>
<A HREF="manual.html#luaL_optinteger">luaL_optinteger</A><BR>
<A HREF="manual.html#luaL_optlstring">luaL_optlstring</A><BR>
<A HREF="manual.html#luaL_optnumber">luaL_optnumber</A><BR>
@@ -546,6 +546,7 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-luaopen_utf8">luaopen_utf8</A><BR>
<H3><A NAME="constants">constants</A></H3>
+<P>
<A HREF="manual.html#pdf-LUA_ERRERR">LUA_ERRERR</A><BR>
<A HREF="manual.html#pdf-LUA_ERRFILE">LUA_ERRFILE</A><BR>
<A HREF="manual.html#pdf-LUA_ERRGCMM">LUA_ERRGCMM</A><BR>
@@ -606,13 +607,12 @@ Freely available under the terms of the
</TR>
</TABLE>
-<HR>
-<SMALL CLASS="footer">
+<P CLASS="footer">
Last update:
-Tue Dec 9 21:26:07 BRST 2014
-</SMALL>
+Thu Dec 22 18:29:39 BRST 2016
+</P>
<!--
-Last change: updated for Lua 5.3.0 (final)
+Last change: revised for Lua 5.3.4
-->
</BODY>
diff --git a/doc/index.css b/doc/index.css
new file mode 100644
index 000000000000..c96183573199
--- /dev/null
+++ b/doc/index.css
@@ -0,0 +1,21 @@
+ul {
+ list-style-type: none ;
+}
+
+ul.contents {
+ padding: 0 ;
+}
+
+table {
+ border: none ;
+ border-spacing: 0 ;
+ border-collapse: collapse ;
+}
+
+td {
+ vertical-align: top ;
+ padding: 0 ;
+ text-align: left ;
+ line-height: 1.25 ;
+ width: 15% ;
+}
diff --git a/doc/logo.gif b/doc/logo.gif
index 2f5e4ac2e742..5c77eacc3b8f 100644
--- a/doc/logo.gif
+++ b/doc/logo.gif
Binary files differ
diff --git a/doc/lua.1 b/doc/lua.1
index 411531b9ed6e..d728d0b80c17 100644
--- a/doc/lua.1
+++ b/doc/lua.1
@@ -1,4 +1,5 @@
-.TH LUA 1 "$Date: 2014/12/10 15:55:45 $"
+.\" $Id: lua.man,v 1.14 2016/10/17 15:43:50 lhf Exp $
+.TH LUA 1 "$Date: 2016/10/17 15:43:50 $"
.SH NAME
lua \- Lua interpreter
.SH SYNOPSIS
diff --git a/doc/lua.css b/doc/lua.css
index 3199a2b6e8fc..5bedf7eb898e 100644
--- a/doc/lua.css
+++ b/doc/lua.css
@@ -3,89 +3,96 @@ html {
}
body {
- border: solid #a0a0a0 1px ;
- border-radius: 20px ;
- padding: 26px ;
- margin: 16px ;
- color: #000000 ;
background-color: #FFFFFF ;
+ color: #000000 ;
font-family: Helvetica, Arial, sans-serif ;
text-align: justify ;
+ line-height: 1.25 ;
+ margin: 16px auto ;
+ padding: 32px ;
+ border: solid #a0a0a0 1px ;
+ border-radius: 20px ;
+ max-width: 70em ;
+ width: 90% ;
}
h1, h2, h3, h4 {
+ color: #000080 ;
font-family: Verdana, Geneva, sans-serif ;
font-weight: normal ;
font-style: normal ;
+ text-align: left ;
}
-h2 {
- padding-top: 0.4em ;
- padding-bottom: 0.4em ;
- padding-left: 0.8em ;
- padding-right: 0.8em ;
- background-color: #D0D0FF ;
- border-radius: 8px ;
- border: solid #a0a0a0 1px ;
+h1 {
+ font-size: 28pt ;
}
-h3 {
- padding-left: 0.5em ;
- border-left: solid #D0D0FF 1em ;
+h1 img {
+ vertical-align: text-bottom ;
}
-table h3 {
- padding-left: 0px ;
- border-left: none ;
+h2:before {
+ content: "\2756" ;
+ padding-right: 0.5em ;
}
-a:link {
- color: #000080 ;
- background-color: inherit ;
+a {
text-decoration: none ;
}
-a:visited {
- background-color: inherit ;
- text-decoration: none ;
+a:link {
+ color: #000080 ;
}
a:link:hover, a:visited:hover {
- color: #000080 ;
background-color: #D0D0FF ;
- border-radius: 4px;
+ color: #000080 ;
+ border-radius: 4px ;
}
a:link:active, a:visited:active {
color: #FF0000 ;
}
-h1 a img {
- vertical-align: text-bottom ;
+div.menubar {
+ padding-bottom: 0.5em ;
}
-hr {
- border: 0 ;
- height: 1px ;
- color: #a0a0a0 ;
- background-color: #a0a0a0 ;
- display: none ;
+p.menubar {
+ margin-left: 2.5em ;
}
-table hr {
- display: block ;
+.menubar a:hover {
+ margin: -3px -3px -3px -3px ;
+ padding: 3px 3px 3px 3px ;
+ border-radius: 4px ;
}
:target {
- background-color: #F8F8F8 ;
+ background-color: #F0F0F0 ;
+ margin: -8px ;
padding: 8px ;
- border: solid #a0a0a0 2px ;
border-radius: 8px ;
+ outline: none ;
+}
+
+hr {
+ display: none ;
+}
+
+table hr {
+ background-color: #a0a0a0 ;
+ color: #a0a0a0 ;
+ border: 0 ;
+ height: 1px ;
+ display: block ;
}
.footer {
color: gray ;
font-size: x-small ;
+ text-transform: lowercase ;
}
input[type=text] {
@@ -103,3 +110,55 @@ pre.session {
padding: 1em ;
border-radius: 8px ;
}
+
+td.gutter {
+ width: 4% ;
+}
+
+table.columns {
+ border: none ;
+ border-spacing: 0 ;
+ border-collapse: collapse ;
+}
+
+table.columns td {
+ vertical-align: top ;
+ padding: 0 ;
+ padding-bottom: 1em ;
+ text-align: justify ;
+ line-height: 1.25 ;
+}
+
+p.logos a:link:hover, p.logos a:visited:hover {
+ background-color: inherit ;
+}
+
+table.book {
+ border: none ;
+ border-spacing: 0 ;
+ border-collapse: collapse ;
+}
+
+table.book td {
+ padding: 0 ;
+ vertical-align: top ;
+}
+
+table.book td.cover {
+ padding-right: 1em ;
+}
+
+table.book img {
+ border: solid #000080 1px ;
+}
+
+table.book span {
+ font-size: small ;
+ text-align: left ;
+ display: block ;
+ margin-top: 0.25em ;
+}
+
+img {
+ background-color: white ;
+}
diff --git a/doc/manual.css b/doc/manual.css
index ca613cd9fb11..aa0e677dd52a 100644
--- a/doc/manual.css
+++ b/doc/manual.css
@@ -8,20 +8,14 @@ pre, code {
}
span.apii {
+ color: gray ;
float: right ;
font-family: inherit ;
font-style: normal ;
font-size: small ;
- color: gray ;
}
-p+h1, ul+h1 {
- font-style: normal ;
- padding-top: 0.4em ;
- padding-bottom: 0.4em ;
- padding-left: 16px ;
- margin-left: -16px ;
- background-color: #D0D0FF ;
- border-radius: 8px ;
- border: solid #000080 1px ;
+h2:before {
+ content: "" ;
+ padding-right: 0em ;
}
diff --git a/doc/manual.html b/doc/manual.html
index 5ed8f0692217..3126b5d6afb3 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -1,39 +1,41 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
-
-<head>
-<title>Lua 5.3 Reference Manual</title>
-<link rel="stylesheet" type="text/css" href="lua.css">
-<link rel="stylesheet" type="text/css" href="manual.css">
+<HTML>
+<HEAD>
+<TITLE>Lua 5.3 Reference Manual</TITLE>
+<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
+<LINK REL="stylesheet" TYPE="text/css" HREF="manual.css">
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1">
-</head>
+</HEAD>
-<body>
+<BODY>
-<hr>
-<h1>
-<a href="http://www.lua.org/"><img src="logo.gif" alt="" border="0"></a>
+<H1>
+<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
Lua 5.3 Reference Manual
-</h1>
+</H1>
+<P>
by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
-<p>
-<small>
-Copyright &copy; 2015 Lua.org, PUC-Rio.
+
+<P>
+<SMALL>
+Copyright &copy; 2015&ndash;2017 Lua.org, PUC-Rio.
Freely available under the terms of the
<a href="http://www.lua.org/license.html">Lua license</a>.
-</small>
-<hr>
-<p>
+</SMALL>
-<a href="contents.html#contents">contents</A>
+<DIV CLASS="menubar">
+<A HREF="contents.html#contents">contents</A>
&middot;
-<a href="contents.html#index">index</A>
+<A HREF="contents.html#index">index</A>
+&middot;
+<A HREF="http://www.lua.org/manual/">other versions</A>
+</DIV>
<!-- ====================================================================== -->
<p>
-<!-- $Id: manual.of,v 1.146 2015/01/06 11:23:01 roberto Exp $ -->
+<!-- $Id: manual.of,v 1.167 2017/01/09 15:18:11 roberto Exp $ -->
@@ -41,30 +43,47 @@ Freely available under the terms of the
<h1>1 &ndash; <a name="1">Introduction</a></h1>
<p>
-Lua is an extension programming language designed to support
-general procedural programming with data description
-facilities.
-Lua also offers good support for object-oriented programming,
-functional programming, and data-driven programming.
-Lua is intended to be used as a powerful, lightweight,
-embeddable scripting language for any program that needs one.
+Lua is a powerful, efficient, lightweight, embeddable scripting language.
+It supports procedural programming,
+object-oriented programming, functional programming,
+data-driven programming, and data description.
+
+
+<p>
+Lua combines simple procedural syntax with powerful data description
+constructs based on associative arrays and extensible semantics.
+Lua is dynamically typed,
+runs by interpreting bytecode with a register-based
+virtual machine,
+and has automatic memory management with
+incremental garbage collection,
+making it ideal for configuration, scripting,
+and rapid prototyping.
+
+
+<p>
Lua is implemented as a library, written in <em>clean C</em>,
the common subset of Standard&nbsp;C and C++.
+The Lua distribution includes a host program called <code>lua</code>,
+which uses the Lua library to offer a complete,
+standalone Lua interpreter,
+for interactive or batch use.
+Lua is intended to be used both as a powerful, lightweight,
+embeddable scripting language for any program that needs one,
+and as a powerful but lightweight and efficient stand-alone language.
<p>
As an extension language, Lua has no notion of a "main" program:
-it only works <em>embedded</em> in a host client,
+it works <em>embedded</em> in a host client,
called the <em>embedding program</em> or simply the <em>host</em>.
+(Frequently, this host is the stand-alone <code>lua</code> program.)
The host program can invoke functions to execute a piece of Lua code,
can write and read Lua variables,
and can register C&nbsp;functions to be called by Lua code.
Through the use of C&nbsp;functions, Lua can be augmented to cope with
a wide range of different domains,
thus creating customized programming languages sharing a syntactical framework.
-The Lua distribution includes a sample host program called <code>lua</code>,
-which uses the Lua library to offer a complete, standalone Lua interpreter,
-for interactive or batch use.
<p>
@@ -113,15 +132,15 @@ There are eight basic types in Lua:
<em>nil</em>, <em>boolean</em>, <em>number</em>,
<em>string</em>, <em>function</em>, <em>userdata</em>,
<em>thread</em>, and <em>table</em>.
-<em>Nil</em> is the type of the value <b>nil</b>,
+The type <em>nil</em> has one single value, <b>nil</b>,
whose main property is to be different from any other value;
it usually represents the absence of a useful value.
-<em>Boolean</em> is the type of the values <b>false</b> and <b>true</b>.
+The type <em>boolean</em> has two values, <b>false</b> and <b>true</b>.
Both <b>nil</b> and <b>false</b> make a condition false;
any other value makes it true.
-<em>Number</em> represents both
+The type <em>number</em> represents both
integer numbers and real (floating-point) numbers.
-<em>String</em> represents immutable sequences of bytes.
+The type <em>string</em> represents immutable sequences of bytes.
Lua is 8-bit clean:
strings can contain any 8-bit value,
@@ -132,6 +151,7 @@ it makes no assumptions about the contents of a string.
<p>
The type <em>number</em> uses two internal representations,
+or two subtypes,
one called <em>integer</em> and the other called <em>float</em>.
Lua has explicit rules about when each representation is used,
but it also converts between them automatically as needed (see <a href="#3.4.3">&sect;3.4.3</a>).
@@ -142,7 +162,7 @@ or to assume complete control over the representation of each number.
Standard Lua uses 64-bit integers and double-precision (64-bit) floats,
but you can also compile Lua so that it
uses 32-bit integers and/or single-precision (32-bit) floats.
-The option with 32 bits for both integers and floats
+The option with 32 bits for both integers and floats
is particularly attractive
for small machines and embedded systems.
(See macro <code>LUA_32BITS</code> in file <code>luaconf.h</code>.)
@@ -185,8 +205,8 @@ even those that do not support threads natively.
The type <em>table</em> implements associative arrays,
that is, arrays that can be indexed not only with numbers,
but with any Lua value except <b>nil</b> and NaN.
-(<em>Not a Number</em> is a special numeric value used to represent
-undefined or unrepresentable results, such as <code>0/0</code>.)
+(<em>Not a Number</em> is a special value used to represent
+undefined or unrepresentable numerical 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.
@@ -196,7 +216,7 @@ an associated value <b>nil</b>.
<p>
Tables are the sole data-structuring mechanism in Lua;
-they can be used to represent ordinary arrays, sequences,
+they can be used to represent ordinary arrays, lists,
symbol tables, sets, records, graphs, trees, etc.
To represent records, Lua uses the field name as an index.
The language supports this representation by
@@ -206,13 +226,6 @@ There are several convenient ways to create tables in Lua
<p>
-We use the term <em>sequence</em> to denote a table where
-the set of all positive numeric keys is equal to {1..<em>n</em>}
-for some non-negative integer <em>n</em>,
-which is called the length of the sequence (see <a href="#3.4.7">&sect;3.4.7</a>).
-
-
-<p>
Like indices,
the values of table fields can be of any type.
In particular,
@@ -348,8 +361,8 @@ It is up to the Lua program or its host to handle such error objects.
When you use <a href="#pdf-xpcall"><code>xpcall</code></a> or <a href="#lua_pcall"><code>lua_pcall</code></a>,
you may give a <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.
+This function is called with the original error object
+and returns a new error object.
It is called before the error unwinds the stack,
so that it can gather more information about the error,
for instance by inspecting the stack and creating a stack traceback.
@@ -358,6 +371,9 @@ so, an error inside the message handler
will call the message handler again.
If this loop goes on for too long,
Lua breaks it and returns an appropriate message.
+(The message handler is called only for regular runtime errors.
+It is not called for memory-allocation errors
+nor for errors while running finalizers.)
@@ -379,23 +395,30 @@ Lua calls this function to perform the addition.
<p>
-The keys in a metatable are derived from the <em>event</em> names;
+The key for each event in a metatable is a string
+with the event name prefixed by two underscores;
the corresponding values are called <em>metamethods</em>.
-In the previous example, the event is <code>"add"</code>
+In the previous example, the key is "<code>__add</code>"
and the metamethod is the function that performs the addition.
<p>
You can query the metatable of any value
using the <a href="#pdf-getmetatable"><code>getmetatable</code></a> function.
+Lua queries metamethods in metatables using a raw access (see <a href="#pdf-rawget"><code>rawget</code></a>).
+So, to retrieve the metamethod for event <code>ev</code> in object <code>o</code>,
+Lua does the equivalent to the following code:
+<pre>
+ rawget(getmetatable(<em>o</em>) or {}, "__<em>ev</em>")
+</pre>
<p>
You can replace the metatable of tables
using the <a href="#pdf-setmetatable"><code>setmetatable</code></a> function.
-You cannot change the metatable of other types from Lua
+You cannot change the metatable of other types from Lua code
(except by using the debug library (<a href="#6.10">&sect;6.10</a>));
-you must use the C&nbsp;API for that.
+you should use the C&nbsp;API for that.
<p>
@@ -417,23 +440,7 @@ when a userdata or a table is garbage collected (<a href="#2.5">&sect;2.5</a>).
<p>
-A detailed list of events controlled by metatables is given next.
-Each operation is identified by its corresponding event name.
-The key for each event is a string with its name prefixed by
-two underscores, '<code>__</code>';
-for instance, the key for operation "add" is the
-string "<code>__add</code>".
-Note that queries for metamethods are always raw;
-the access to a metamethod does not invoke other metamethods.
-You can emulate how Lua queries a metamethod for an object <code>obj</code>
-with the following code:
-
-<pre>
- rawget(getmetatable(obj) or {}, "__" .. event_name)
-</pre>
-
-<p>
-For the unary operators (negation, length, and bitwise not),
+For the unary operators (negation, length, and bitwise NOT),
the metamethod is computed and called with a dummy second operand,
equal to the first one.
This extra operand is only to simplify Lua's internals
@@ -442,17 +449,21 @@ and may be removed in future versions.
(For most uses this extra operand is irrelevant.)
+<p>
+A detailed list of events controlled by metatables is given next.
+Each operation is identified by its corresponding key.
+
-<ul>
-<li><b>"add": </b>
-the <code>+</code> operation.
+<ul>
+<li><b><code>__add</code>: </b>
+the addition (<code>+</code>) operation.
If any operand for an addition is not a number
(nor a string coercible to a number),
Lua will try to call a metamethod.
First, Lua will check the first operand (even if it is valid).
-If that operand does not define a metamethod for the "<code>__add</code>" event,
+If that operand does not define a metamethod for <code>__add</code>,
then Lua will check the second operand.
If Lua can find a metamethod,
it calls the metamethod with the two operands as arguments,
@@ -463,99 +474,84 @@ Otherwise,
it raises an error.
</li>
-<li><b>"sub": </b>
-the <code>-</code> operation.
-
-Behavior similar to the "add" operation.
+<li><b><code>__sub</code>: </b>
+the subtraction (<code>-</code>) operation.
+Behavior similar to the addition operation.
</li>
-<li><b>"mul": </b>
-the <code>*</code> operation.
-
-Behavior similar to the "add" operation.
+<li><b><code>__mul</code>: </b>
+the multiplication (<code>*</code>) operation.
+Behavior similar to the addition operation.
</li>
-<li><b>"div": </b>
-the <code>/</code> operation.
-
-Behavior similar to the "add" operation.
+<li><b><code>__div</code>: </b>
+the division (<code>/</code>) operation.
+Behavior similar to the addition operation.
</li>
-<li><b>"mod": </b>
-the <code>%</code> operation.
-
-Behavior similar to the "add" operation.
+<li><b><code>__mod</code>: </b>
+the modulo (<code>%</code>) operation.
+Behavior similar to the addition operation.
</li>
-<li><b>"pow": </b>
-the <code>^</code> (exponentiation) operation.
-
-Behavior similar to the "add" operation.
+<li><b><code>__pow</code>: </b>
+the exponentiation (<code>^</code>) operation.
+Behavior similar to the addition operation.
</li>
-<li><b>"unm": </b>
-the <code>-</code> (unary minus) operation.
-
-Behavior similar to the "add" operation.
+<li><b><code>__unm</code>: </b>
+the negation (unary <code>-</code>) operation.
+Behavior similar to the addition operation.
</li>
-<li><b>"idiv": </b>
-the <code>//</code> (floor division) operation.
-
-Behavior similar to the "add" operation.
+<li><b><code>__idiv</code>: </b>
+the floor division (<code>//</code>) operation.
+Behavior similar to the addition operation.
</li>
-<li><b>"band": </b>
-the <code>&amp;</code> (bitwise and) operation.
-
-Behavior similar to the "add" operation,
+<li><b><code>__band</code>: </b>
+the bitwise AND (<code>&amp;</code>) operation.
+Behavior similar to the addition operation,
except that Lua will try a metamethod
-if any operator is neither an integer
+if any operand is neither an integer
nor a value coercible to an integer (see <a href="#3.4.3">&sect;3.4.3</a>).
</li>
-<li><b>"bor": </b>
-the <code>|</code> (bitwise or) operation.
-
-Behavior similar to the "band" operation.
+<li><b><code>__bor</code>: </b>
+the bitwise OR (<code>|</code>) operation.
+Behavior similar to the bitwise AND operation.
</li>
-<li><b>"bxor": </b>
-the <code>~</code> (bitwise exclusive or) operation.
-
-Behavior similar to the "band" operation.
+<li><b><code>__bxor</code>: </b>
+the bitwise exclusive OR (binary <code>~</code>) operation.
+Behavior similar to the bitwise AND operation.
</li>
-<li><b>"bnot": </b>
-the <code>~</code> (bitwise unary not) operation.
-
-Behavior similar to the "band" operation.
+<li><b><code>__bnot</code>: </b>
+the bitwise NOT (unary <code>~</code>) operation.
+Behavior similar to the bitwise AND operation.
</li>
-<li><b>"shl": </b>
-the <code>&lt;&lt;</code> (bitwise left shift) operation.
-
-Behavior similar to the "band" operation.
+<li><b><code>__shl</code>: </b>
+the bitwise left shift (<code>&lt;&lt;</code>) operation.
+Behavior similar to the bitwise AND operation.
</li>
-<li><b>"shr": </b>
-the <code>&gt;&gt;</code> (bitwise right shift) operation.
-
-Behavior similar to the "band" operation.
+<li><b><code>__shr</code>: </b>
+the bitwise right shift (<code>&gt;&gt;</code>) operation.
+Behavior similar to the bitwise AND operation.
</li>
-<li><b>"concat": </b>
-the <code>..</code> (concatenation) operation.
-
-Behavior similar to the "add" operation,
+<li><b><code>__concat</code>: </b>
+the concatenation (<code>..</code>) operation.
+Behavior similar to the addition operation,
except that Lua will try a metamethod
-if any operator is neither a string nor a number
+if any operand is neither a string nor a number
(which is always coercible to a string).
</li>
-<li><b>"len": </b>
-the <code>#</code> (length) operation.
-
+<li><b><code>__len</code>: </b>
+the length (<code>#</code>) operation.
If the object is not a string,
Lua will try its metamethod.
If there is a metamethod,
@@ -568,42 +564,40 @@ then Lua uses the table length operation (see <a href="#3.4.7">&sect;3.4.7</a>).
Otherwise, Lua raises an error.
</li>
-<li><b>"eq": </b>
-the <code>==</code> (equal) operation.
-
-Behavior similar to the "add" operation,
+<li><b><code>__eq</code>: </b>
+the equal (<code>==</code>) operation.
+Behavior similar to the addition operation,
except that Lua will try a metamethod only when the values
being compared are either both tables or both full userdata
and they are not primitively equal.
The result of the call is always converted to a boolean.
</li>
-<li><b>"lt": </b>
-the <code>&lt;</code> (less than) operation.
-
-Behavior similar to the "add" operation,
+<li><b><code>__lt</code>: </b>
+the less than (<code>&lt;</code>) operation.
+Behavior similar to the addition operation,
except that Lua will try a metamethod only when the values
being compared are neither both numbers nor both strings.
The result of the call is always converted to a boolean.
</li>
-<li><b>"le": </b>
-the <code>&lt;=</code> (less equal) operation.
-
+<li><b><code>__le</code>: </b>
+the less equal (<code>&lt;=</code>) operation.
Unlike other operations,
-The less-equal operation can use two different events.
-First, Lua looks for the "<code>__le</code>" metamethod in both operands,
-like in the "lt" operation.
+the less-equal operation can use two different events.
+First, Lua looks for the <code>__le</code> metamethod in both operands,
+like in the less than operation.
If it cannot find such a metamethod,
-then it will try the "<code>__lt</code>" event,
+then it will try the <code>__lt</code> metamethod,
assuming that <code>a &lt;= b</code> is equivalent to <code>not (b &lt; a)</code>.
As with the other comparison operators,
the result is always a boolean.
+(This use of the <code>__lt</code> event can be removed in future versions;
+it is also slower than a real <code>__le</code> metamethod.)
</li>
-<li><b>"index": </b>
+<li><b><code>__index</code>: </b>
The indexing access <code>table[key]</code>.
-
This event happens when <code>table</code> is not a table or
when <code>key</code> is not present in <code>table</code>.
The metamethod is looked up in <code>table</code>.
@@ -613,16 +607,18 @@ The metamethod is looked up in <code>table</code>.
Despite the name,
the metamethod for this event can be either a function or a table.
If it is a function,
-it is called with <code>table</code> and <code>key</code> as arguments.
+it is called with <code>table</code> and <code>key</code> as arguments,
+and the result of the call
+(adjusted to one value)
+is the result of the operation.
If it is a table,
the final result is the result of indexing this table with <code>key</code>.
(This indexing is regular, not raw,
and therefore can trigger another metamethod.)
</li>
-<li><b>"newindex": </b>
+<li><b><code>__newindex</code>: </b>
The indexing assignment <code>table[key] = value</code>.
-
Like the index event,
this event happens when <code>table</code> is not a table or
when <code>key</code> is not present in <code>table</code>.
@@ -641,26 +637,44 @@ and therefore can trigger another metamethod.)
<p>
-Whenever there is a "newindex" metamethod,
+Whenever there is a <code>__newindex</code> metamethod,
Lua does not perform the primitive assignment.
(If necessary,
the metamethod itself can call <a href="#pdf-rawset"><code>rawset</code></a>
to do the assignment.)
</li>
-<li><b>"call": </b>
+<li><b><code>__call</code>: </b>
The call operation <code>func(args)</code>.
-
This event happens when Lua tries to call a non-function value
(that is, <code>func</code> is not a function).
The metamethod is looked up in <code>func</code>.
If present,
the metamethod is called with <code>func</code> as its first argument,
followed by the arguments of the original call (<code>args</code>).
+All results of the call
+are the result of the operation.
+(This is the only metamethod that allows multiple results.)
</li>
</ul>
+<p>
+It is a good practice to add all needed metamethods to a table
+before setting it as a metatable of some object.
+In particular, the <code>__gc</code> metamethod works only when this order
+is followed (see <a href="#2.5.1">&sect;2.5.1</a>).
+
+
+<p>
+Because metatables are regular tables,
+they can contain arbitrary fields,
+not only the event names defined above.
+Some functions in the standard library
+(e.g., <a href="#pdf-tostring"><code>tostring</code></a>)
+use other fields in metatables for their own purposes.
+
+
@@ -752,8 +766,6 @@ 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 object will not be marked for finalization.
-However, after an object has been marked,
-you can freely change the <code>__gc</code> field of its metatable.
<p>
@@ -794,7 +806,7 @@ Moreover, if the finalizer marks a finalizing object for finalization again,
its finalizer will be called again in the next cycle where the
object is unreachable.
In any case,
-the object memory is freed only in the GC cycle where
+the object memory is freed only in a GC cycle where
the object is unreachable and not marked for finalization.
@@ -822,8 +834,8 @@ then the garbage collector will collect that object.
<p>
A weak table can have weak keys, weak values, or both.
-A table with weak keys allows the collection of its keys,
-but prevents the collection of its values.
+A table with weak values allows the collection of its values,
+but prevents the collection of its keys.
A table with both weak keys and weak values allows the collection of
both keys and values.
In any case, if either the key or the value is collected,
@@ -857,7 +869,7 @@ before the change takes effect.
<p>
Only objects that have an explicit construction
are removed from weak tables.
-Values, such as numbers and light C functions,
+Values, such as numbers and light C&nbsp;functions,
are not subject to garbage collection,
and therefore are not removed from weak tables
(unless their associated values are collected).
@@ -913,10 +925,10 @@ You execute a coroutine by calling <a href="#pdf-coroutine.resume"><code>corouti
When you first call <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>,
passing as its first argument
a thread returned by <a href="#pdf-coroutine.create"><code>coroutine.create</code></a>,
-the coroutine starts its execution,
-at the first line of its main function.
+the coroutine starts its execution by
+calling its main function.
Extra arguments passed to <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> are passed
-as arguments to the coroutine's main function.
+as arguments to that function.
After the coroutine starts running,
it runs until it terminates or <em>yields</em>.
@@ -930,7 +942,7 @@ In case of normal termination,
<a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> returns <b>true</b>,
plus any values returned by the coroutine main function.
In case of errors, <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> returns <b>false</b>
-plus an error message.
+plus an error object.
<p>
@@ -1046,7 +1058,8 @@ except as delimiters between names and keywords.
(also called <em>identifiers</em>)
in Lua can be any string of letters,
digits, and underscores,
-not beginning with a digit.
+not beginning with a digit and
+not being a reserved word.
Identifiers are used to name variables, table fields, and labels.
@@ -1067,7 +1080,7 @@ Lua is a case-sensitive language:
<code>and</code> is a reserved word, but <code>And</code> and <code>AND</code>
are two different, valid names.
As a convention,
-programs should avoid creating
+programs should avoid creating
names that start with an underscore followed by
one or more uppercase letters (such as <a href="#pdf-_VERSION"><code>_VERSION</code></a>).
@@ -1084,7 +1097,7 @@ The following strings denote other tokens:
</pre>
<p>
-<em>Literal strings</em>
+A <em>short literal string</em>
can be delimited by matching single or double quotes,
and can contain the following C-like escape sequences:
'<code>\a</code>' (bell),
@@ -1097,7 +1110,7 @@ and can contain the following C-like escape sequences:
'<code>\\</code>' (backslash),
'<code>\"</code>' (quotation mark [double quote]),
and '<code>\'</code>' (apostrophe [single quote]).
-A backslash followed by a real newline
+A backslash followed by a line break
results in a newline in the string.
The escape sequence '<code>\z</code>' skips the following span
of white-space characters,
@@ -1105,13 +1118,13 @@ including line breaks;
it is particularly useful to break and indent a long literal string
into multiple lines without adding the newlines and spaces
into the string contents.
+A short literal string cannot contain unescaped line breaks
+nor escapes not forming a valid escape sequence.
<p>
-Strings in Lua can contain any 8-bit value, including embedded zeros,
-which can be specified as '<code>\0</code>'.
-More generally,
-we can specify any byte in a literal string by its numerical value.
+We can specify any byte in a short literal string by its numeric value
+(including embedded zeros).
This can be done
with the escape sequence <code>\x<em>XX</em></code>,
where <em>XX</em> is a sequence of exactly two hexadecimal digits,
@@ -1155,17 +1168,6 @@ is converted to a simple newline.
<p>
-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>
For convenience,
when the opening long bracket is immediately followed by a newline,
the newline is not included in the string.
@@ -1186,7 +1188,18 @@ the five literal strings below denote the same string:
</pre>
<p>
-A <em>numerical constant</em> (or <em>numeral</em>)
+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 the non-text characters.
+
+
+<p>
+A <em>numeric constant</em> (or <em>numeral</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>'.
@@ -1195,9 +1208,11 @@ which start with <code>0x</code> or <code>0X</code>.
Hexadecimal constants also accept an optional fractional part
plus an optional binary exponent,
marked by a letter '<code>p</code>' or '<code>P</code>'.
-A numeric constant with a fractional dot or an exponent
+A numeric constant with a radix point or an exponent
denotes a float;
-otherwise it denotes an integer.
+otherwise,
+if its value fits in an integer,
+it denotes an integer.
Examples of valid integer constants are
<pre>
@@ -1581,11 +1596,11 @@ because now <b>return</b> is the last statement in its (inner) block.
<p>
The <b>for</b> statement has two forms:
-one numeric and one generic.
+one numerical and one generic.
<p>
-The numeric <b>for</b> loop repeats a block of code while a
+The numerical <b>for</b> loop repeats a block of code while a
control variable runs through an arithmetic progression.
It has the following syntax:
@@ -1788,7 +1803,7 @@ bitwise operators (see <a href="#3.4.2">&sect;3.4.2</a>),
relational operators (see <a href="#3.4.4">&sect;3.4.4</a>), logical operators (see <a href="#3.4.5">&sect;3.4.5</a>),
and the concatenation operator (see <a href="#3.4.6">&sect;3.4.6</a>).
Unary operators comprise the unary minus (see <a href="#3.4.1">&sect;3.4.1</a>),
-the unary bitwise not (see <a href="#3.4.2">&sect;3.4.2</a>),
+the unary bitwise NOT (see <a href="#3.4.2">&sect;3.4.2</a>),
the unary logical <b>not</b> (see <a href="#3.4.5">&sect;3.4.5</a>),
and the unary <em>length operator</em> (see <a href="#3.4.7">&sect;3.4.7</a>).
@@ -1878,14 +1893,14 @@ so that it works for non-integer exponents too.
<p>
-Floor division (<code>//</code>) is a division
-that rounds the quotient towards minus infinite,
+Floor division (<code>//</code>) is a division
+that rounds the quotient towards minus infinity,
that is, the floor of the division of its operands.
<p>
Modulo is defined as the remainder of a division
-that rounds the quotient towards minus infinite (floor division).
+that rounds the quotient towards minus infinity (floor division).
<p>
@@ -1902,12 +1917,12 @@ that is equal modulo <em>2<sup>64</sup></em> to the mathematical result.)
Lua supports the following bitwise operators:
<ul>
-<li><b><code>&amp;</code>: </b>bitwise and</li>
-<li><b><code>&#124;</code>: </b>bitwise or</li>
-<li><b><code>~</code>: </b>bitwise exclusive or</li>
+<li><b><code>&amp;</code>: </b>bitwise AND</li>
+<li><b><code>&#124;</code>: </b>bitwise OR</li>
+<li><b><code>~</code>: </b>bitwise exclusive OR</li>
<li><b><code>&gt;&gt;</code>: </b>right shift</li>
<li><b><code>&lt;&lt;</code>: </b>left shift</li>
-<li><b><code>~</code>: </b>unary bitwise not</li>
+<li><b><code>~</code>: </b>unary bitwise NOT</li>
</ul>
<p>
@@ -1940,7 +1955,7 @@ this is called the <em>usual rule</em>.
The C API also converts both integers to floats and
floats to integers, as needed.
Moreover, string concatenation accepts numbers as arguments,
-besides strings.
+besides strings.
<p>
@@ -1972,8 +1987,16 @@ The conversion from strings to numbers goes as follows:
First, the string is converted to an integer or a float,
following its syntax and the rules of the Lua lexer.
(The string may have also leading and trailing spaces and a sign.)
-Then, the resulting number is converted to the required type
-(float or integer) according to the previous rules.
+Then, the resulting number (float or integer)
+is converted to the type (float or integer) required by the context
+(e.g., the operation that forced the conversion).
+
+
+<p>
+All conversions from strings to numbers
+accept both a dot and the current locale mark
+as the radix character.
+(The Lua lexer, however, accepts only a dot.)
<p>
@@ -2006,11 +2029,7 @@ Equality (<code>==</code>) first compares the type of its operands.
If the types are different, then the result is <b>false</b>.
Otherwise, the values of the operands are compared.
Strings are compared in the obvious way.
-Numbers follow the usual rule for binary operations:
-if both operands are integers,
-they are compared as integers;
-otherwise, they are converted to floats
-and compared as such.
+Numbers are equal if they denote the same mathematical value.
<p>
@@ -2045,8 +2064,8 @@ The operator <code>~=</code> is exactly the negation of equality (<code>==</code
<p>
The order operators work as follows.
If both arguments are numbers,
-then they are compared following
-the usual rule for binary operations.
+then they are compared according to their mathematical values
+(regardless of their subtypes).
Otherwise, if both arguments are strings,
then their values are compared according to the current locale.
Otherwise, Lua tries to call the "lt" or the "le"
@@ -2055,6 +2074,12 @@ A comparison <code>a &gt; b</code> is translated to <code>b &lt; a</code>
and <code>a &gt;= b</code> is translated to <code>b &lt;= a</code>.
+<p>
+Following the IEEE 754 standard,
+NaN is considered neither smaller than,
+nor equal to, nor greater than any value (including itself).
+
+
@@ -2111,37 +2136,66 @@ Otherwise, the <code>__concat</code> metamethod is called (see <a href="#2.4">&s
<p>
The length operator is denoted by the unary prefix operator <code>#</code>.
-The length of a string is its number of bytes
-(that is, the usual meaning of string length when each
-character is one byte).
<p>
-A program can modify the behavior of the length operator for
-any value but strings through the <code>__len</code> metamethod (see <a href="#2.4">&sect;2.4</a>).
+The length of a string is its number of bytes
+(that is, the usual meaning of string length when each
+character is one byte).
<p>
-Unless a <code>__len</code> metamethod is given,
-the length of a table <code>t</code> is only defined if the
-table is a <em>sequence</em>,
-that is,
-the set of its positive numeric keys is equal to <em>{1..n}</em>
-for some non-negative integer <em>n</em>.
-In that case, <em>n</em> is its length.
-Note that a table like
+The length operator applied on a table
+returns a border in that table.
+A <em>border</em> in a table <code>t</code> is any natural number
+that satisfies the following condition:
<pre>
- {10, 20, nil, 40}
+ (border == 0 or t[border] ~= nil) and t[border + 1] == nil
</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 positive numeric keys of that table.)
-Note, however, that non-numeric keys do not interfere
+In words,
+a border is any (natural) index in a table
+where a non-nil value is followed by a nil value
+(or zero, when index 1 is nil).
+
+
+<p>
+A table with exactly one border is called a <em>sequence</em>.
+For instance, the table <code>{10, 20, 30, 40, 50}</code> is a sequence,
+as it has only one border (5).
+The table <code>{10, 20, 30, nil, 50}</code> has two borders (3 and 5),
+and therefore it is not a sequence.
+The table <code>{nil, 20, 30, nil, nil, 60, nil}</code>
+has three borders (0, 3, and 6),
+so it is not a sequence, too.
+The table <code>{}</code> is a sequence with border 0.
+Note that non-natural keys do not interfere
with whether a table is a sequence.
+<p>
+When <code>t</code> is a sequence,
+<code>#t</code> returns its only border,
+which corresponds to the intuitive notion of the length of the sequence.
+When <code>t</code> is not a sequence,
+<code>#t</code> can return any of its borders.
+(The exact one depends on details of
+the internal representation of the table,
+which in turn can depend on how the table was populated and
+the memory addresses of its non-numeric keys.)
+
+
+<p>
+The computation of the length of a table
+has a guaranteed worst time of <em>O(log n)</em>,
+where <em>n</em> is the largest natural key in the table.
+
+
+<p>
+A program can modify the behavior of the length operator for
+any value but strings through the <code>__len</code> metamethod (see <a href="#2.4">&sect;2.4</a>).
+
+
@@ -2556,6 +2610,28 @@ However, you can change this behavior by compiling Lua
with the macro <a name="pdf-LUA_USE_APICHECK"><code>LUA_USE_APICHECK</code></a> defined.
+<p>
+The Lua library is fully reentrant:
+it has no global variables.
+It keeps all information it needs in a dynamic structure,
+called the <em>Lua state</em>.
+
+
+<p>
+Each Lua state has one or more threads,
+which correspond to independent, cooperative lines of execution.
+The type <a href="#lua_State"><code>lua_State</code></a> (despite its name) refers to a thread.
+(Indirectly, through the thread, it also refers to the
+Lua state associated to the thread.)
+
+
+<p>
+A pointer to a thread must be passed as the first argument to
+every function in the library, except to <a href="#lua_newstate"><code>lua_newstate</code></a>,
+which creates a Lua state from scratch and returns a pointer
+to the <em>main thread</em> in the new state.
+
+
<h2>4.1 &ndash; <a name="4.1">The Stack</a></h2>
@@ -2563,6 +2639,8 @@ with the macro <a name="pdf-LUA_USE_APICHECK"><code>LUA_USE_APICHECK</code></a>
Lua uses a <em>virtual stack</em> to pass values to and from C.
Each element in this stack represents a Lua value
(<b>nil</b>, number, string, etc.).
+Functions in the API can access this stack through the
+Lua state parameter that they receive.
<p>
@@ -2570,7 +2648,8 @@ Whenever Lua calls C, the called function gets a new stack,
which is independent of previous stacks and of stacks of
C&nbsp;functions that are still active.
This stack initially contains any arguments to the C&nbsp;function
-and it is where the C&nbsp;function pushes its results
+and it is where the C&nbsp;function can store temporary
+Lua values and must push its results
to be returned to the caller (see <a href="#lua_CFunction"><code>lua_CFunction</code></a>).
@@ -2636,29 +2715,22 @@ works only with <em>valid indices</em> or <em>acceptable indices</em>.
<p>
A <em>valid index</em> is an index that refers to a
-real position within the stack, that is,
-its position lies between&nbsp;1 and the stack top
-(<code>1 &le; abs(index) &le; top</code>).
-
-Usually, functions that can modify the value at an index
-require valid indices.
-
-
-<p>
-Unless otherwise noted,
-any function that accepts valid indices also accepts <em>pseudo-indices</em>,
-which represent some Lua values that are accessible to C&nbsp;code
-but which are not in the stack.
-Pseudo-indices are used to access the registry
+position that stores a modifiable Lua value.
+It comprises stack indices between&nbsp;1 and the stack top
+(<code>1 &le; abs(index) &le; top</code>)
+
+plus <em>pseudo-indices</em>,
+which represent some positions that are accessible to C&nbsp;code
+but that are not in the stack.
+Pseudo-indices are used to access the registry (see <a href="#4.5">&sect;4.5</a>)
and the upvalues of a C&nbsp;function (see <a href="#4.4">&sect;4.4</a>).
<p>
-Functions that do not need a specific stack position,
-but only a value in the stack (e.g., query functions),
+Functions that do not need a specific mutable position,
+but only a value (e.g., query functions),
can be called with acceptable indices.
An <em>acceptable index</em> can be any valid index,
-including the pseudo-indices,
but it also can be any positive index after the stack top
within the space allocated for the stack,
that is, indices up to the stack size.
@@ -2701,11 +2773,13 @@ Whenever a C&nbsp;function is called,
its upvalues are located at specific pseudo-indices.
These pseudo-indices are produced by the macro
<a href="#lua_upvalueindex"><code>lua_upvalueindex</code></a>.
-The first value associated with a function is at position
+The first upvalue associated with a function is at index
<code>lua_upvalueindex(1)</code>, and so on.
Any access to <code>lua_upvalueindex(<em>n</em>)</code>,
where <em>n</em> is greater than the number of upvalues of the
-current function (but not greater than 256),
+current function
+(but not greater than 256,
+which is one plus the maximum number of upvalues in a closure),
produces an acceptable but invalid index.
@@ -2719,8 +2793,7 @@ Lua provides a <em>registry</em>,
a predefined table that can be used by any C&nbsp;code to
store whatever Lua values it needs to store.
The registry table is always located at pseudo-index
-<a name="pdf-LUA_REGISTRYINDEX"><code>LUA_REGISTRYINDEX</code></a>,
-which is a valid index.
+<a name="pdf-LUA_REGISTRYINDEX"><code>LUA_REGISTRYINDEX</code></a>.
Any C&nbsp;library can store data into this table,
but it must take care to choose keys
that are different from those used
@@ -2768,8 +2841,7 @@ Internally, Lua uses the C <code>longjmp</code> facility to handle errors.
(Lua will use exceptions if you compile it as C++;
search for <code>LUAI_THROW</code> in the source code for details.)
When Lua faces any error
-(such as a memory allocation error, type errors, syntax errors,
-and runtime errors)
+(such as a memory allocation error or a type error)
it <em>raises</em> an error;
that is, it does a long jump.
A <em>protected environment</em> uses <code>setjmp</code>
@@ -2778,6 +2850,17 @@ any error jumps to the most recent active recovery point.
<p>
+Inside a C&nbsp;function you can raise an error by calling <a href="#lua_error"><code>lua_error</code></a>.
+
+
+<p>
+Most functions in the API can raise an error,
+for instance due to a memory allocation error.
+The documentation for each function indicates whether
+it can raise errors.
+
+
+<p>
If an error happens outside any protected environment,
Lua calls a <em>panic function</em> (see <a href="#lua_atpanic"><code>lua_atpanic</code></a>)
and then calls <code>abort</code>,
@@ -2788,24 +2871,30 @@ never returning
<p>
+The panic function,
+as its name implies,
+is a mechanism of last resort.
+Programs should avoid it.
+As a general rule,
+when a C&nbsp;function is called by Lua with a Lua state,
+it can do whatever it wants on that Lua state,
+as it should be already protected.
+However,
+when C code operates on other Lua states
+(e.g., a Lua parameter to the function,
+a Lua state stored in the registry, or
+the result of <a href="#lua_newthread"><code>lua_newthread</code></a>),
+it should use them only in API calls that cannot raise errors.
+
+
+<p>
The panic function runs as if it were a message handler (see <a href="#2.3">&sect;2.3</a>);
-in particular, the error message is at the top of the stack.
+in particular, the error object is at the top of the stack.
However, there is no guarantee about stack space.
To push anything on the stack,
the panic function must first check the available space (see <a href="#4.2">&sect;4.2</a>).
-<p>
-Most functions in the API can raise an error,
-for instance due to a memory allocation error.
-The documentation for each function indicates whether
-it can raise errors.
-
-
-<p>
-Inside a C&nbsp;function you can raise an error by calling <a href="#lua_error"><code>lua_error</code></a>.
-
-
@@ -2813,7 +2902,7 @@ Inside a C&nbsp;function you can raise an error by calling <a href="#lua_error">
<p>
Internally, Lua uses the C <code>longjmp</code> facility to yield a coroutine.
-Therefore, if a C function <code>foo</code> calls an API function
+Therefore, if a C&nbsp;function <code>foo</code> calls an API function
and this API function yields
(directly or indirectly by calling another function that yields),
Lua cannot return to <code>foo</code> any more,
@@ -2831,7 +2920,7 @@ All those functions receive a <em>continuation function</em>
<p>
We need to set some terminology to explain continuations.
-We have a C function called from Lua which we will call
+We have a C&nbsp;function called from Lua which we will call
the <em>original function</em>.
This original function then calls one of those three functions in the C API,
which we will call the <em>callee function</em>,
@@ -2971,7 +3060,11 @@ by looking only at its arguments
The third field, <code>x</code>,
tells whether the function may raise errors:
'<code>-</code>' means the function never raises any error;
-'<code>e</code>' means the function may raise errors;
+'<code>m</code>' means the function may raise out-of-memory errors
+and errors running a <code>__gc</code> metamethod;
+'<code>e</code>' means the function may raise any errors
+(it can run arbitrary Lua code,
+either directly or through metamethods);
'<code>v</code>' means the function may raise an error on purpose.
@@ -2981,7 +3074,8 @@ tells whether the function may raise errors:
<pre>int lua_absindex (lua_State *L, int idx);</pre>
<p>
-Converts the acceptable index <code>idx</code> into an absolute index
+Converts the acceptable index <code>idx</code>
+into an equivalent absolute index
(that is, one that does not depend on the stack top).
@@ -3097,10 +3191,10 @@ The value of <code>op</code> must be one of the following constants:
<li><b><a name="pdf-LUA_OPMOD"><code>LUA_OPMOD</code></a>: </b> performs modulo (<code>%</code>)</li>
<li><b><a name="pdf-LUA_OPPOW"><code>LUA_OPPOW</code></a>: </b> performs exponentiation (<code>^</code>)</li>
<li><b><a name="pdf-LUA_OPUNM"><code>LUA_OPUNM</code></a>: </b> performs mathematical negation (unary <code>-</code>)</li>
-<li><b><a name="pdf-LUA_OPBNOT"><code>LUA_OPBNOT</code></a>: </b> performs bitwise negation (<code>~</code>)</li>
-<li><b><a name="pdf-LUA_OPBAND"><code>LUA_OPBAND</code></a>: </b> performs bitwise and (<code>&amp;</code>)</li>
-<li><b><a name="pdf-LUA_OPBOR"><code>LUA_OPBOR</code></a>: </b> performs bitwise or (<code>|</code>)</li>
-<li><b><a name="pdf-LUA_OPBXOR"><code>LUA_OPBXOR</code></a>: </b> performs bitwise exclusive or (<code>~</code>)</li>
+<li><b><a name="pdf-LUA_OPBNOT"><code>LUA_OPBNOT</code></a>: </b> performs bitwise NOT (<code>~</code>)</li>
+<li><b><a name="pdf-LUA_OPBAND"><code>LUA_OPBAND</code></a>: </b> performs bitwise AND (<code>&amp;</code>)</li>
+<li><b><a name="pdf-LUA_OPBOR"><code>LUA_OPBOR</code></a>: </b> performs bitwise OR (<code>|</code>)</li>
+<li><b><a name="pdf-LUA_OPBXOR"><code>LUA_OPBXOR</code></a>: </b> performs bitwise exclusive OR (<code>~</code>)</li>
<li><b><a name="pdf-LUA_OPSHL"><code>LUA_OPSHL</code></a>: </b> performs left shift (<code>&lt;&lt;</code>)</li>
<li><b><a name="pdf-LUA_OPSHR"><code>LUA_OPSHR</code></a>: </b> performs right shift (<code>&gt;&gt;</code>)</li>
@@ -3141,8 +3235,9 @@ 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, all results from the function are pushed.
-Lua takes care that the returned values fit into the stack space.
+In this case, all results from the function are pushed;
+Lua takes care that the returned values fit into the stack space,
+but it does not ensure any extra space in the stack.
The function results are pushed onto the stack in direct order
(the first result is pushed first),
so that after the call the last result is on the top of the stack.
@@ -3224,7 +3319,7 @@ many results.
<p>
As an example, the following function receives a variable number
-of numerical arguments and returns their average and their sum:
+of numeric arguments and returns their average and their sum:
<pre>
static int foo (lua_State *L) {
@@ -3252,14 +3347,15 @@ of numerical arguments and returns their average and their sum:
<pre>int lua_checkstack (lua_State *L, int n);</pre>
<p>
-Ensures that the stack has space for at least <code>n</code> extra slots.
+Ensures that the stack has space for at least <code>n</code> extra slots
+(that is, that you can safely push up to <code>n</code> values into it).
It returns false if it cannot fulfill the request,
either because it would cause the stack
to be larger than a fixed maximum size
(typically at least several thousand elements) or
because it cannot allocate memory for the extra space.
This function never shrinks the stack;
-if the stack is already larger than the new size,
+if the stack already has space for the extra slots,
it is left unchanged.
@@ -3344,7 +3440,7 @@ Values at other positions are not affected.
<hr><h3><a name="lua_createtable"><code>lua_createtable</code></a></h3><p>
-<span class="apii">[-0, +1, <em>e</em>]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>void lua_createtable (lua_State *L, int narr, int nrec);</pre>
<p>
@@ -3354,7 +3450,7 @@ 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
+This preallocation 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>.
@@ -3363,7 +3459,7 @@ Otherwise you can use the function <a href="#lua_newtable"><code>lua_newtable</c
<hr><h3><a name="lua_dump"><code>lua_dump</code></a></h3><p>
-<span class="apii">[-0, +0, <em>e</em>]</span>
+<span class="apii">[-0, +0, &ndash;]</span>
<pre>int lua_dump (lua_State *L,
lua_Writer writer,
void *data,
@@ -3383,8 +3479,9 @@ to write them.
<p>
If <code>strip</code> is true,
-the binary representation is created without debug information
-about the function.
+the binary representation may not include all debug information
+about the function,
+to save space.
<p>
@@ -3416,7 +3513,7 @@ and therefore never returns
<hr><h3><a name="lua_gc"><code>lua_gc</code></a></h3><p>
-<span class="apii">[-0, +0, <em>e</em>]</span>
+<span class="apii">[-0, +0, <em>m</em>]</span>
<pre>int lua_gc (lua_State *L, int what, int data);</pre>
<p>
@@ -3624,7 +3721,7 @@ in particular, 0&nbsp;means an empty stack.
<pre>int lua_getuservalue (lua_State *L, int index);</pre>
<p>
-Pushes onto the stack the Lua value associated with the userdata
+Pushes onto the stack the Lua value associated with the full userdata
at the given index.
@@ -3661,7 +3758,7 @@ By default this type is <code>long long</code>,
(usually a 64-bit two-complement integer),
but that can be changed to <code>long</code> or <code>int</code>
(usually a 32-bit two-complement integer).
-(See <code>LUA_INT</code> in <code>luaconf.h</code>.)
+(See <code>LUA_INT_TYPE</code> in <code>luaconf.h</code>.)
<p>
@@ -3850,7 +3947,7 @@ and 0&nbsp;otherwise.
<p>
The type for continuation-function contexts.
-It must be a numerical type.
+It must be a numeric type.
This type is defined as <code>intptr_t</code>
when <code>intptr_t</code> is available,
so that it can store pointers too.
@@ -3911,7 +4008,7 @@ The return values of <code>lua_load</code> are:
syntax error during precompilation;</li>
<li><b><a href="#pdf-LUA_ERRMEM"><code>LUA_ERRMEM</code></a>: </b>
-memory allocation error;</li>
+memory allocation (out-of-memory) error;</li>
<li><b><a href="#pdf-LUA_ERRGCMM"><code>LUA_ERRGCMM</code></a>: </b>
error while running a <code>__gc</code> metamethod.
@@ -3967,7 +4064,8 @@ Creates a new thread running in a new, independent state.
Returns <code>NULL</code> if it cannot create the thread or the state
(due to lack of memory).
The argument <code>f</code> is the allocator function;
-Lua does all memory allocation for this state through this function.
+Lua does all memory allocation for this state
+through this function (see <a href="#lua_Alloc"><code>lua_Alloc</code></a>).
The second argument, <code>ud</code>, is an opaque pointer that Lua
passes to the allocator in every call.
@@ -3976,7 +4074,7 @@ passes to the allocator in every call.
<hr><h3><a name="lua_newtable"><code>lua_newtable</code></a></h3><p>
-<span class="apii">[-0, +1, <em>e</em>]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>void lua_newtable (lua_State *L);</pre>
<p>
@@ -3988,7 +4086,7 @@ It is equivalent to <code>lua_createtable(L, 0, 0)</code>.
<hr><h3><a name="lua_newthread"><code>lua_newthread</code></a></h3><p>
-<span class="apii">[-0, +1, <em>e</em>]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>lua_State *lua_newthread (lua_State *L);</pre>
<p>
@@ -4009,7 +4107,7 @@ like any Lua object.
<hr><h3><a name="lua_newuserdata"><code>lua_newuserdata</code></a></h3><p>
-<span class="apii">[-0, +1, <em>e</em>]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>void *lua_newuserdata (lua_State *L, size_t size);</pre>
<p>
@@ -4068,7 +4166,7 @@ the table during its traversal.
<hr><h3><a name="lua_Number"><code>lua_Number</code></a></h3>
-<pre>typedef double lua_Number;</pre>
+<pre>typedef ... lua_Number;</pre>
<p>
The type of floats in Lua.
@@ -4076,8 +4174,8 @@ The type of floats in Lua.
<p>
By default this type is double,
-but that can be changed to a single float.
-(See <code>LUA_REAL</code> in <code>luaconf.h</code>.)
+but that can be changed to a single float or a long double.
+(See <code>LUA_FLOAT_TYPE</code> in <code>luaconf.h</code>.)
@@ -4120,7 +4218,7 @@ If there are no errors during the call,
<a href="#lua_pcall"><code>lua_pcall</code></a> behaves exactly like <a href="#lua_call"><code>lua_call</code></a>.
However, if there is any error,
<a href="#lua_pcall"><code>lua_pcall</code></a> catches it,
-pushes a single value on the stack (the error message),
+pushes a single value on the stack (the error object),
and returns an error code.
Like <a href="#lua_call"><code>lua_call</code></a>,
<a href="#lua_pcall"><code>lua_pcall</code></a> always removes the function
@@ -4129,20 +4227,20 @@ and its arguments from the stack.
<p>
If <code>msgh</code> is 0,
-then the error message returned on the stack
-is exactly the original error message.
+then the error object returned on the stack
+is exactly the original error object.
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.)
+(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
+this function will be called with the error object
+and its return value will be the object
returned on the stack by <a href="#lua_pcall"><code>lua_pcall</code></a>.
<p>
Typically, the message handler is used to add more debug
-information to the error message, such as a stack traceback.
+information to the error object, 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.
@@ -4171,7 +4269,9 @@ error while running the message handler.
<li><b><a name="pdf-LUA_ERRGCMM"><code>LUA_ERRGCMM</code></a>: </b>
error while running a <code>__gc</code> metamethod.
-(This error typically has no relation with the function being called.)
+For such errors, Lua does not call the message handler
+(as this kind of error typically has no relation
+with the function being called).
</li>
</ul>
@@ -4219,7 +4319,7 @@ Pushes a boolean value with value <code>b</code> onto the stack.
<hr><h3><a name="lua_pushcclosure"><code>lua_pushcclosure</code></a></h3><p>
-<span class="apii">[-n, +1, <em>e</em>]</span>
+<span class="apii">[-n, +1, <em>m</em>]</span>
<pre>void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);</pre>
<p>
@@ -4247,7 +4347,7 @@ The maximum value for <code>n</code> is 255.
<p>
When <code>n</code> is zero,
-this function creates a <em>light C function</em>,
+this function creates a <em>light C&nbsp;function</em>,
which is just a pointer to the C&nbsp;function.
In that case, it never raises a memory error.
@@ -4261,26 +4361,17 @@ In that case, it never raises a memory error.
<p>
Pushes a C&nbsp;function onto the stack.
-This function receives a pointer to a C function
+This function receives a pointer to a C&nbsp;function
and pushes onto the stack a Lua value of type <code>function</code> that,
when called, invokes the corresponding C&nbsp;function.
<p>
-Any function to be registered in Lua must
+Any function to be callable by Lua must
follow the correct protocol to receive its parameters
and return its results (see <a href="#lua_CFunction"><code>lua_CFunction</code></a>).
-<p>
-<code>lua_pushcfunction</code> is defined as a macro:
-
-<pre>
- #define lua_pushcfunction(L,f) lua_pushcclosure(L,f,0)
-</pre><p>
-Note that <code>f</code> is used twice.
-
-
@@ -4309,7 +4400,7 @@ The conversion specifiers can only be
'<code>%%</code>' (inserts the character '<code>%</code>'),
'<code>%s</code>' (inserts a zero-terminated string, with no size restrictions),
'<code>%f</code>' (inserts a <a href="#lua_Number"><code>lua_Number</code></a>),
-'<code>%L</code>' (inserts a <a href="#lua_Integer"><code>lua_Integer</code></a>),
+'<code>%I</code>' (inserts a <a href="#lua_Integer"><code>lua_Integer</code></a>),
'<code>%p</code>' (inserts a pointer as a hexadecimal numeral),
'<code>%d</code>' (inserts an <code>int</code>),
'<code>%c</code>' (inserts an <code>int</code> as a one-byte character), and
@@ -4318,6 +4409,12 @@ The conversion specifiers can only be
</ul>
+<p>
+Unlike other push functions,
+this function checks for the stack space it needs,
+including the slot for its result.
+
+
@@ -4365,20 +4462,19 @@ light userdata with the same C&nbsp;address.
<hr><h3><a name="lua_pushliteral"><code>lua_pushliteral</code></a></h3><p>
-<span class="apii">[-0, +1, <em>e</em>]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>const char *lua_pushliteral (lua_State *L, const char *s);</pre>
<p>
-This macro is equivalent to <a href="#lua_pushlstring"><code>lua_pushlstring</code></a>,
-but can be used only when <code>s</code> is a literal string.
-It automatically provides the string length.
+This macro is equivalent to <a href="#lua_pushstring"><code>lua_pushstring</code></a>,
+but should be used only when <code>s</code> is a literal string.
<hr><h3><a name="lua_pushlstring"><code>lua_pushlstring</code></a></h3><p>
-<span class="apii">[-0, +1, <em>e</em>]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>const char *lua_pushlstring (lua_State *L, const char *s, size_t len);</pre>
<p>
@@ -4421,7 +4517,7 @@ Pushes a float with value <code>n</code> onto the stack.
<hr><h3><a name="lua_pushstring"><code>lua_pushstring</code></a></h3><p>
-<span class="apii">[-0, +1, <em>e</em>]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>const char *lua_pushstring (lua_State *L, const char *s);</pre>
<p>
@@ -4468,7 +4564,7 @@ onto the stack.
<hr><h3><a name="lua_pushvfstring"><code>lua_pushvfstring</code></a></h3><p>
-<span class="apii">[-0, +1, <em>e</em>]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>const char *lua_pushvfstring (lua_State *L,
const char *fmt,
va_list argp);</pre>
@@ -4488,7 +4584,7 @@ instead of a variable number of arguments.
<p>
Returns 1 if the two values in indices <code>index1</code> and
<code>index2</code> are primitively equal
-(that is, without calling metamethods).
+(that is, without calling the <code>__eq</code> metamethod).
Otherwise returns&nbsp;0.
Also returns&nbsp;0 if any of the indices are not valid.
@@ -4515,8 +4611,8 @@ Similar to <a href="#lua_gettable"><code>lua_gettable</code></a>, but does a raw
<p>
Pushes onto the stack the value <code>t[n]</code>,
where <code>t</code> is the table at the given index.
-The access is raw;
-that is, it does not invoke metamethods.
+The access is raw,
+that is, it does not invoke the <code>__index</code> metamethod.
<p>
@@ -4535,7 +4631,7 @@ Pushes onto the stack the value <code>t[k]</code>,
where <code>t</code> is the table at the given index and
<code>k</code> is the pointer <code>p</code> represented as a light userdata.
The access is raw;
-that is, it does not invoke metamethods.
+that is, it does not invoke the <code>__index</code> metamethod.
<p>
@@ -4563,7 +4659,7 @@ for other values, it is&nbsp;0.
<hr><h3><a name="lua_rawset"><code>lua_rawset</code></a></h3><p>
-<span class="apii">[-2, +0, <em>e</em>]</span>
+<span class="apii">[-2, +0, <em>m</em>]</span>
<pre>void lua_rawset (lua_State *L, int index);</pre>
<p>
@@ -4575,7 +4671,7 @@ Similar to <a href="#lua_settable"><code>lua_settable</code></a>, but does a raw
<hr><h3><a name="lua_rawseti"><code>lua_rawseti</code></a></h3><p>
-<span class="apii">[-1, +0, <em>e</em>]</span>
+<span class="apii">[-1, +0, <em>m</em>]</span>
<pre>void lua_rawseti (lua_State *L, int index, lua_Integer i);</pre>
<p>
@@ -4586,28 +4682,28 @@ and <code>v</code> is the value at the top of the stack.
<p>
This function pops the value from the stack.
-The assignment is raw;
-that is, it does not invoke metamethods.
+The assignment is raw,
+that is, it does not invoke the <code>__newindex</code> metamethod.
<hr><h3><a name="lua_rawsetp"><code>lua_rawsetp</code></a></h3><p>
-<span class="apii">[-1, +0, <em>e</em>]</span>
+<span class="apii">[-1, +0, <em>m</em>]</span>
<pre>void lua_rawsetp (lua_State *L, int index, const void *p);</pre>
<p>
-Does the equivalent of <code>t[k] = v</code>,
+Does the equivalent of <code>t[p] = v</code>,
where <code>t</code> is the table at the given index,
-<code>k</code> is the pointer <code>p</code> represented as a light userdata,
+<code>p</code> is encoded as a light userdata,
and <code>v</code> is the value at the top of the stack.
<p>
This function pops the value from the stack.
-The assignment is raw;
-that is, it does not invoke metamethods.
+The assignment is raw,
+that is, it does not invoke <code>__newindex</code> metamethod.
@@ -4640,7 +4736,7 @@ The reader function may return pieces of any size greater than zero.
<pre>void lua_register (lua_State *L, const char *name, lua_CFunction f);</pre>
<p>
-Sets the C function <code>f</code> as the new value of global <code>name</code>.
+Sets the C&nbsp;function <code>f</code> as the new value of global <code>name</code>.
It is defined as a macro:
<pre>
@@ -4672,7 +4768,7 @@ because a pseudo-index is not an actual stack position.
<p>
Moves the top element into the given valid index
without shifting any element
-(therefore replacing the value at the given index),
+(therefore replacing the value at that given index),
and then pops the top element.
@@ -4684,7 +4780,7 @@ and then pops the top element.
<pre>int lua_resume (lua_State *L, lua_State *from, int nargs);</pre>
<p>
-Starts and resumes a coroutine in a given thread.
+Starts and resumes a coroutine in the given thread <code>L</code>.
<p>
@@ -4706,7 +4802,7 @@ or an error code in case of errors (see <a href="#lua_pcall"><code>lua_pcall</co
In case of errors,
the stack is not unwound,
so you can use the debug API over it.
-The error message is on the top of the stack.
+The error object is on the top of the stack.
<p>
@@ -4731,12 +4827,16 @@ this parameter can be <code>NULL</code>.
<pre>void lua_rotate (lua_State *L, int idx, int n);</pre>
<p>
-Rotates the stack elements from <code>idx</code> to the top <code>n</code> positions
-in the direction of the top, for a positive <code>n</code>,
+Rotates the stack elements between the valid index <code>idx</code>
+and the top of the stack.
+The elements are rotated <code>n</code> positions in the direction of the top,
+for a positive <code>n</code>,
or <code>-n</code> positions in the direction of the bottom,
for a negative <code>n</code>.
The absolute value of <code>n</code> must not be greater than the size
of the slice being rotated.
+This function cannot be called with a pseudo-index,
+because a pseudo-index is not an actual stack position.
@@ -4857,7 +4957,7 @@ If <code>index</code> is&nbsp;0, then all stack elements are removed.
<p>
Pops a value from the stack and sets it as
-the new value associated to the userdata at the given index.
+the new value associated to the full userdata at the given index.
@@ -4993,13 +5093,13 @@ indicates whether the operation succeeded.
<hr><h3><a name="lua_tolstring"><code>lua_tolstring</code></a></h3><p>
-<span class="apii">[-0, +0, <em>e</em>]</span>
+<span class="apii">[-0, +0, <em>m</em>]</span>
<pre>const char *lua_tolstring (lua_State *L, int index, size_t *len);</pre>
<p>
Converts the Lua value at the given index to a C&nbsp;string.
If <code>len</code> is not <code>NULL</code>,
-it also sets <code>*len</code> with the string length.
+it sets <code>*len</code> with the string length.
The Lua value must be a string or a number;
otherwise, the function returns <code>NULL</code>.
If the value is a number,
@@ -5010,7 +5110,7 @@ when <code>lua_tolstring</code> is applied to keys during a table traversal.)
<p>
-<code>lua_tolstring</code> returns a fully aligned pointer
+<code>lua_tolstring</code> returns a pointer
to a string inside the Lua state.
This string always has a zero ('<code>\0</code>')
after its last character (as in&nbsp;C),
@@ -5072,14 +5172,14 @@ There is no way to convert the pointer back to its original value.
<p>
-Typically this function is used only for debug information.
+Typically this function is used only for hashing and debug information.
<hr><h3><a name="lua_tostring"><code>lua_tostring</code></a></h3><p>
-<span class="apii">[-0, +0, <em>e</em>]</span>
+<span class="apii">[-0, +0, <em>m</em>]</span>
<pre>const char *lua_tostring (lua_State *L, int index);</pre>
<p>
@@ -5127,7 +5227,7 @@ Returns the type of the value in the given valid index,
or <code>LUA_TNONE</code> for a non-valid (but acceptable) index.
The types returned by <a href="#lua_type"><code>lua_type</code></a> are coded by the following constants
defined in <code>lua.h</code>:
-<a name="pdf-LUA_TNIL"><code>LUA_TNIL</code></a>,
+<a name="pdf-LUA_TNIL"><code>LUA_TNIL</code></a> (0),
<a name="pdf-LUA_TNUMBER"><code>LUA_TNUMBER</code></a>,
<a name="pdf-LUA_TBOOLEAN"><code>LUA_TBOOLEAN</code></a>,
<a name="pdf-LUA_TSTRING"><code>LUA_TSTRING</code></a>,
@@ -5177,11 +5277,13 @@ the running function (see <a href="#4.4">&sect;4.4</a>).
<hr><h3><a name="lua_version"><code>lua_version</code></a></h3><p>
-<span class="apii">[-0, +0, <em>v</em>]</span>
+<span class="apii">[-0, +0, &ndash;]</span>
<pre>const lua_Number *lua_version (lua_State *L);</pre>
<p>
-Returns the address of the version number stored in the Lua core.
+Returns the address of the version number
+(a C static variable)
+stored in the Lua core.
When called with a valid <a href="#lua_State"><code>lua_State</code></a>,
returns the address of the version used to create that state.
When called with <code>NULL</code>,
@@ -5269,7 +5371,7 @@ that will be passed as results to <a href="#lua_resume"><code>lua_resume</code><
<p>
When the coroutine is resumed again,
Lua calls the given continuation function <code>k</code> to continue
-the execution of the C function that yielded (see <a href="#4.7">&sect;4.7</a>).
+the execution of the C&nbsp;function that yielded (see <a href="#4.7">&sect;4.7</a>).
This continuation function receives the same stack
from the previous function,
with the <code>n</code> results removed and
@@ -5285,9 +5387,9 @@ when the coroutine eventually resumes,
it continues executing the continuation function.
However, there is one special case,
which is when this function is called
-from inside a line hook (see <a href="#4.9">&sect;4.9</a>).
+from inside a line or a count hook (see <a href="#4.9">&sect;4.9</a>).
In that case, <code>lua_yieldk</code> should be called with no continuation
-(probably in the form of <a href="#lua_yield"><code>lua_yield</code></a>),
+(probably in the form of <a href="#lua_yield"><code>lua_yield</code></a>) and no results,
and the hook should return immediately after the call.
Lua will yield and,
when the coroutine resumes again,
@@ -5618,24 +5720,26 @@ it returns 0.
<pre>const char *lua_getupvalue (lua_State *L, int funcindex, int n);</pre>
<p>
-Gets information about a closure's upvalue.
-(For Lua functions,
-upvalues are the external local variables that the function uses,
-and that are consequently included in its closure.)
-<a href="#lua_getupvalue"><code>lua_getupvalue</code></a> gets the index <code>n</code> of an upvalue,
-pushes the upvalue's value onto the stack,
+Gets information about the <code>n</code>-th upvalue
+of the closure at index <code>funcindex</code>.
+It pushes the upvalue's value onto the stack
and returns its name.
-<code>funcindex</code> points to the closure in the stack.
-(Upvalues have no particular order,
-as they are active through the whole function.
-So, they are numbered in an arbitrary order.)
+Returns <code>NULL</code> (and pushes nothing)
+when the index <code>n</code> is greater than the number of upvalues.
<p>
-Returns <code>NULL</code> (and pushes nothing)
-when the index is greater than the number of upvalues.
For C&nbsp;functions, this function uses the empty string <code>""</code>
as a name for all upvalues.
+(For Lua functions,
+upvalues are the external local variables that the function uses,
+and that are consequently included in its closure.)
+
+
+<p>
+Upvalues have no particular order,
+as they are active through the whole function.
+They are numbered in an arbitrary order.
@@ -5680,10 +5784,10 @@ that is, they cannot call <a href="#lua_yieldk"><code>lua_yieldk</code></a>,
<p>
Hook functions can yield under the following conditions:
-Only count and line events can yield
-and they cannot yield any value;
-to yield a hook function must finish its execution
-calling <a href="#lua_yield"><code>lua_yield</code></a> with <code>nresults</code> equal to zero.
+Only count and line events can yield;
+to yield, a hook function must finish its execution
+calling <a href="#lua_yield"><code>lua_yield</code></a> with <code>nresults</code> equal to zero
+(that is, with no values).
@@ -5700,7 +5804,7 @@ Sets the debugging hook function.
<p>
Argument <code>f</code> is the hook function.
<code>mask</code> specifies on which events the hook will be called:
-it is formed by a bitwise or of the constants
+it is formed by a bitwise OR of the constants
<a name="pdf-LUA_MASKCALL"><code>LUA_MASKCALL</code></a>,
<a name="pdf-LUA_MASKRET"><code>LUA_MASKRET</code></a>,
<a name="pdf-LUA_MASKLINE"><code>LUA_MASKLINE</code></a>,
@@ -5748,9 +5852,7 @@ A hook is disabled by setting <code>mask</code> to zero.
<p>
Sets the value of a local variable of a given activation record.
-Parameters <code>ar</code> and <code>n</code> are as in <a href="#lua_getlocal"><code>lua_getlocal</code></a>
-(see <a href="#lua_getlocal"><code>lua_getlocal</code></a>).
-<a href="#lua_setlocal"><code>lua_setlocal</code></a> assigns the value at the top of the stack
+It assigns the value at the top of the stack
to the variable and returns its name.
It also pops the value from the stack.
@@ -5761,6 +5863,10 @@ when the index is greater than
the number of active local variables.
+<p>
+Parameters <code>ar</code> and <code>n</code> are as in function <a href="#lua_getlocal"><code>lua_getlocal</code></a>.
+
+
@@ -5773,13 +5879,15 @@ Sets the value of a closure's upvalue.
It assigns the value at the top of the stack
to the upvalue and returns its name.
It also pops the value from the stack.
-Parameters <code>funcindex</code> and <code>n</code> are as in the <a href="#lua_getupvalue"><code>lua_getupvalue</code></a>
-(see <a href="#lua_getupvalue"><code>lua_getupvalue</code></a>).
<p>
Returns <code>NULL</code> (and pops nothing)
-when the index is greater than the number of upvalues.
+when the index <code>n</code> is greater than the number of upvalues.
+
+
+<p>
+Parameters <code>funcindex</code> and <code>n</code> are as in function <a href="#lua_getupvalue"><code>lua_getupvalue</code></a>.
@@ -5792,9 +5900,6 @@ when the index is greater than the number of upvalues.
<p>
Returns a unique identifier for the upvalue numbered <code>n</code>
from the closure at index <code>funcindex</code>.
-Parameters <code>funcindex</code> and <code>n</code> are as in the <a href="#lua_getupvalue"><code>lua_getupvalue</code></a>
-(see <a href="#lua_getupvalue"><code>lua_getupvalue</code></a>)
-(but <code>n</code> cannot be greater than the number of upvalues).
<p>
@@ -5805,6 +5910,11 @@ Lua closures that share an upvalue
will return identical ids for those upvalue indices.
+<p>
+Parameters <code>funcindex</code> and <code>n</code> are as in function <a href="#lua_getupvalue"><code>lua_getupvalue</code></a>,
+but <code>n</code> cannot be greater than the number of upvalues.
+
+
@@ -5880,7 +5990,7 @@ in alphabetical order.
<hr><h3><a name="luaL_addchar"><code>luaL_addchar</code></a></h3><p>
-<span class="apii">[-?, +?, <em>e</em>]</span>
+<span class="apii">[-?, +?, <em>m</em>]</span>
<pre>void luaL_addchar (luaL_Buffer *B, char c);</pre>
<p>
@@ -5892,7 +6002,7 @@ Adds the byte <code>c</code> to the buffer <code>B</code>
<hr><h3><a name="luaL_addlstring"><code>luaL_addlstring</code></a></h3><p>
-<span class="apii">[-?, +?, <em>e</em>]</span>
+<span class="apii">[-?, +?, <em>m</em>]</span>
<pre>void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);</pre>
<p>
@@ -5906,7 +6016,7 @@ The string can contain embedded zeros.
<hr><h3><a name="luaL_addsize"><code>luaL_addsize</code></a></h3><p>
-<span class="apii">[-?, +?, <em>e</em>]</span>
+<span class="apii">[-?, +?, &ndash;]</span>
<pre>void luaL_addsize (luaL_Buffer *B, size_t n);</pre>
<p>
@@ -5919,7 +6029,7 @@ buffer area (see <a href="#luaL_prepbuffer"><code>luaL_prepbuffer</code></a>).
<hr><h3><a name="luaL_addstring"><code>luaL_addstring</code></a></h3><p>
-<span class="apii">[-?, +?, <em>e</em>]</span>
+<span class="apii">[-?, +?, <em>m</em>]</span>
<pre>void luaL_addstring (luaL_Buffer *B, const char *s);</pre>
<p>
@@ -5932,7 +6042,7 @@ to the buffer <code>B</code>
<hr><h3><a name="luaL_addvalue"><code>luaL_addvalue</code></a></h3><p>
-<span class="apii">[-1, +?, <em>e</em>]</span>
+<span class="apii">[-1, +?, <em>m</em>]</span>
<pre>void luaL_addvalue (luaL_Buffer *B);</pre>
<p>
@@ -5972,7 +6082,7 @@ If it is not, raises an error with a standard message (see <a href="#luaL_argerr
<p>
Raises an error reporting a problem with argument <code>arg</code>
-of the C function that called it,
+of the C&nbsp;function that called it,
using a standard message
that includes <code>extramsg</code> as a comment:
@@ -6070,7 +6180,7 @@ the buffer must be declared as a variable
<hr><h3><a name="luaL_buffinitsize"><code>luaL_buffinitsize</code></a></h3><p>
-<span class="apii">[-?, +?, <em>e</em>]</span>
+<span class="apii">[-?, +?, <em>m</em>]</span>
<pre>char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz);</pre>
<p>
@@ -6246,7 +6356,7 @@ returns the userdata address (see <a href="#lua_touserdata"><code>lua_touserdata
<hr><h3><a name="luaL_checkversion"><code>luaL_checkversion</code></a></h3><p>
-<span class="apii">[-0, +0, &ndash;]</span>
+<span class="apii">[-0, +0, <em>v</em>]</span>
<pre>void luaL_checkversion (lua_State *L);</pre>
<p>
@@ -6321,7 +6431,7 @@ as <code>return luaL_error(<em>args</em>)</code>.
<hr><h3><a name="luaL_execresult"><code>luaL_execresult</code></a></h3><p>
-<span class="apii">[-0, +3, <em>e</em>]</span>
+<span class="apii">[-0, +3, <em>m</em>]</span>
<pre>int luaL_execresult (lua_State *L, int stat);</pre>
<p>
@@ -6334,7 +6444,7 @@ process-related functions in the standard library
<hr><h3><a name="luaL_fileresult"><code>luaL_fileresult</code></a></h3><p>
-<span class="apii">[-0, +(1|3), <em>e</em>]</span>
+<span class="apii">[-0, +(1|3), <em>m</em>]</span>
<pre>int luaL_fileresult (lua_State *L, int stat, const char *fname);</pre>
<p>
@@ -6347,7 +6457,7 @@ file-related functions in the standard library
<hr><h3><a name="luaL_getmetafield"><code>luaL_getmetafield</code></a></h3><p>
-<span class="apii">[-0, +(0|1), <em>e</em>]</span>
+<span class="apii">[-0, +(0|1), <em>m</em>]</span>
<pre>int luaL_getmetafield (lua_State *L, int obj, const char *e);</pre>
<p>
@@ -6362,14 +6472,14 @@ pushes nothing and returns <code>LUA_TNIL</code>.
<hr><h3><a name="luaL_getmetatable"><code>luaL_getmetatable</code></a></h3><p>
-<span class="apii">[-0, +1, &ndash;]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>int luaL_getmetatable (lua_State *L, const char *tname);</pre>
<p>
Pushes onto the stack the metatable associated with name <code>tname</code>
-in the registry (see <a href="#luaL_newmetatable"><code>luaL_newmetatable</code></a>).
-If there is no metatable associated with <code>tname</code>,
-returns false and pushes <b>nil</b>.
+in the registry (see <a href="#luaL_newmetatable"><code>luaL_newmetatable</code></a>)
+(<b>nil</b> if there is no metatable associated with that name).
+Returns the type of the pushed value.
@@ -6392,7 +6502,7 @@ 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>e</em>]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>const char *luaL_gsub (lua_State *L,
const char *s,
const char *p,
@@ -6462,7 +6572,7 @@ The string <code>mode</code> works as in function <a href="#lua_load"><code>lua_
<hr><h3><a name="luaL_loadfile"><code>luaL_loadfile</code></a></h3><p>
-<span class="apii">[-0, +1, <em>e</em>]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>int luaL_loadfile (lua_State *L, const char *filename);</pre>
<p>
@@ -6473,7 +6583,7 @@ Equivalent to <a href="#luaL_loadfilex"><code>luaL_loadfilex</code></a> with <co
<hr><h3><a name="luaL_loadfilex"><code>luaL_loadfilex</code></a></h3><p>
-<span class="apii">[-0, +1, <em>e</em>]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>int luaL_loadfilex (lua_State *L, const char *filename,
const char *mode);</pre>
@@ -6493,7 +6603,8 @@ The string <code>mode</code> works as in function <a href="#lua_load"><code>lua_
<p>
This function returns the same results as <a href="#lua_load"><code>lua_load</code></a>,
but it has an extra error code <a name="pdf-LUA_ERRFILE"><code>LUA_ERRFILE</code></a>
-if it cannot open/read the file or the file has a wrong mode.
+for file-related errors
+(e.g., it cannot open or read the file).
<p>
@@ -6527,7 +6638,7 @@ it does not run it.
<hr><h3><a name="luaL_newlib"><code>luaL_newlib</code></a></h3><p>
-<span class="apii">[-0, +1, <em>e</em>]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>void luaL_newlib (lua_State *L, const luaL_Reg l[]);</pre>
<p>
@@ -6549,7 +6660,7 @@ not a pointer to it.
<hr><h3><a name="luaL_newlibtable"><code>luaL_newlibtable</code></a></h3><p>
-<span class="apii">[-0, +1, <em>e</em>]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);</pre>
<p>
@@ -6570,7 +6681,7 @@ not a pointer to it.
<hr><h3><a name="luaL_newmetatable"><code>luaL_newmetatable</code></a></h3><p>
-<span class="apii">[-0, +1, <em>e</em>]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>int luaL_newmetatable (lua_State *L, const char *tname);</pre>
<p>
@@ -6624,6 +6735,27 @@ Opens all standard Lua libraries into the given state.
+<hr><h3><a name="luaL_opt"><code>luaL_opt</code></a></h3><p>
+<span class="apii">[-0, +0, <em>e</em>]</span>
+<pre>T luaL_opt (L, func, arg, dflt);</pre>
+
+<p>
+This macro is defined as follows:
+
+<pre>
+ (lua_isnoneornil(L,(arg)) ? (dflt) : func(L,(arg)))
+</pre><p>
+In words, if the argument <code>arg</code> is nil or absent,
+the macro results in the default <code>dflt</code>.
+Otherwise, it results in the result of calling <code>func</code>
+with the state <code>L</code> and the argument index <code>arg</code> as
+parameters.
+Note that it evaluates the expression <code>dflt</code> only if needed.
+
+
+
+
+
<hr><h3><a name="luaL_optinteger"><code>luaL_optinteger</code></a></h3><p>
<span class="apii">[-0, +0, <em>v</em>]</span>
<pre>lua_Integer luaL_optinteger (lua_State *L,
@@ -6660,6 +6792,14 @@ Otherwise, raises an error.
<p>
If <code>l</code> is not <code>NULL</code>,
fills the position <code>*l</code> with the result's length.
+If the result is <code>NULL</code>
+(only possible when returning <code>d</code> and <code>d == NULL</code>),
+its length is considered zero.
+
+
+<p>
+This function uses <a href="#lua_tolstring"><code>lua_tolstring</code></a> to get its result,
+so all conversions and caveats of that function apply here.
@@ -6698,7 +6838,7 @@ Otherwise, raises an error.
<hr><h3><a name="luaL_prepbuffer"><code>luaL_prepbuffer</code></a></h3><p>
-<span class="apii">[-?, +?, <em>e</em>]</span>
+<span class="apii">[-?, +?, <em>m</em>]</span>
<pre>char *luaL_prepbuffer (luaL_Buffer *B);</pre>
<p>
@@ -6710,7 +6850,7 @@ with the predefined size <a name="pdf-LUAL_BUFFERSIZE"><code>LUAL_BUFFERSIZE</co
<hr><h3><a name="luaL_prepbuffsize"><code>luaL_prepbuffsize</code></a></h3><p>
-<span class="apii">[-?, +?, <em>e</em>]</span>
+<span class="apii">[-?, +?, <em>m</em>]</span>
<pre>char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz);</pre>
<p>
@@ -6726,7 +6866,7 @@ it to the buffer.
<hr><h3><a name="luaL_pushresult"><code>luaL_pushresult</code></a></h3><p>
-<span class="apii">[-?, +1, <em>e</em>]</span>
+<span class="apii">[-?, +1, <em>m</em>]</span>
<pre>void luaL_pushresult (luaL_Buffer *B);</pre>
<p>
@@ -6738,7 +6878,7 @@ the top of the stack.
<hr><h3><a name="luaL_pushresultsize"><code>luaL_pushresultsize</code></a></h3><p>
-<span class="apii">[-?, +1, <em>e</em>]</span>
+<span class="apii">[-?, +1, <em>m</em>]</span>
<pre>void luaL_pushresultsize (luaL_Buffer *B, size_t sz);</pre>
<p>
@@ -6749,7 +6889,7 @@ Equivalent to the sequence <a href="#luaL_addsize"><code>luaL_addsize</code></a>
<hr><h3><a name="luaL_ref"><code>luaL_ref</code></a></h3><p>
-<span class="apii">[-1, +0, <em>e</em>]</span>
+<span class="apii">[-1, +0, <em>m</em>]</span>
<pre>int luaL_ref (lua_State *L, int t);</pre>
<p>
@@ -6820,7 +6960,7 @@ Leaves a copy of the module on the stack.
<hr><h3><a name="luaL_setfuncs"><code>luaL_setfuncs</code></a></h3><p>
-<span class="apii">[-nup, +0, <em>e</em>]</span>
+<span class="apii">[-nup, +0, <em>m</em>]</span>
<pre>void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);</pre>
<p>
@@ -6884,7 +7024,7 @@ this function receives the file handle as its sole argument and
must return either <b>true</b> (in case of success)
or <b>nil</b> plus an error message (in case of error).
Once Lua calls this field,
-the field value is changed to <code>NULL</code>
+it changes the field value to <code>NULL</code>
to signal that the handle is closed.
@@ -6892,7 +7032,7 @@ to signal that the handle is closed.
<hr><h3><a name="luaL_testudata"><code>luaL_testudata</code></a></h3><p>
-<span class="apii">[-0, +0, <em>e</em>]</span>
+<span class="apii">[-0, +0, <em>m</em>]</span>
<pre>void *luaL_testudata (lua_State *L, int arg, const char *tname);</pre>
<p>
@@ -6918,7 +7058,7 @@ the function also sets <code>*len</code> with the string length.
<p>
-If the value has a metatable with a <code>"__tostring"</code> field,
+If the value has a metatable with a <code>__tostring</code> field,
then <code>luaL_tolstring</code> calls the corresponding metamethod
with the value as argument,
and uses the result of the call as its result.
@@ -6928,7 +7068,7 @@ and uses the result of the call as its result.
<hr><h3><a name="luaL_traceback"><code>luaL_traceback</code></a></h3><p>
-<span class="apii">[-0, +1, <em>e</em>]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
int level);</pre>
@@ -6975,7 +7115,7 @@ If <code>ref</code> is <a href="#pdf-LUA_NOREF"><code>LUA_NOREF</code></a> or <a
<hr><h3><a name="luaL_where"><code>luaL_where</code></a></h3><p>
-<span class="apii">[-0, +1, <em>e</em>]</span>
+<span class="apii">[-0, +1, <em>m</em>]</span>
<pre>void luaL_where (lua_State *L, int lvl);</pre>
<p>
@@ -7207,7 +7347,7 @@ nor vice versa.
<p>
If <code>object</code> does not have a metatable, returns <b>nil</b>.
Otherwise,
-if the object's metatable has a <code>"__metatable"</code> field,
+if the object's metatable has a <code>__metatable</code> field,
returns the associated value.
Otherwise, returns the metatable of the given object.
@@ -7333,7 +7473,7 @@ you can use <code>next(t)</code> to check whether a table is empty.
<p>
The order in which the indices are enumerated is not specified,
<em>even for numeric indices</em>.
-(To traverse a table in numeric order,
+(To traverse a table in numerical order,
use a numerical <b>for</b>.)
@@ -7411,7 +7551,7 @@ use <a href="#pdf-string.format"><code>string.format</code></a> and <a href="#pd
<p>
<hr><h3><a name="pdf-rawequal"><code>rawequal (v1, v2)</code></a></h3>
Checks whether <code>v1</code> is equal to <code>v2</code>,
-without invoking any metamethod.
+without invoking the <code>__eq</code> metamethod.
Returns a boolean.
@@ -7420,7 +7560,7 @@ Returns a boolean.
<p>
<hr><h3><a name="pdf-rawget"><code>rawget (table, index)</code></a></h3>
Gets the real value of <code>table[index]</code>,
-without invoking any metamethod.
+without invoking the <code>__index</code> metamethod.
<code>table</code> must be a table;
<code>index</code> may be any value.
@@ -7431,7 +7571,7 @@ without invoking any metamethod.
<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.
+without invoking the <code>__len</code> metamethod.
Returns an integer.
@@ -7440,7 +7580,7 @@ Returns an integer.
<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.
+without invoking the <code>__newindex</code> metamethod.
<code>table</code> must be a table,
<code>index</code> any value different from <b>nil</b> and NaN,
and <code>value</code> any Lua value.
@@ -7472,10 +7612,11 @@ and <code>select</code> returns the total number of extra arguments it received.
<p>
Sets the metatable for the given table.
-(You cannot change the metatable of other types from Lua, only from&nbsp;C.)
+(To change the metatable of other types from Lua code,
+you must use the debug library (<a href="#6.10">&sect;6.10</a>).)
If <code>metatable</code> is <b>nil</b>,
removes the metatable of the given table.
-If the original metatable has a <code>"__metatable"</code> field,
+If the original metatable has a <code>__metatable</code> field,
raises an error.
@@ -7522,14 +7663,12 @@ the function returns <b>nil</b>.
<hr><h3><a name="pdf-tostring"><code>tostring (v)</code></a></h3>
Receives a value of any type and
converts it to a string in a human-readable format.
-Floats always produce strings with some
-floating-point indication (either a decimal dot or an exponent).
(For complete control of how numbers are converted,
use <a href="#pdf-string.format"><code>string.format</code></a>.)
<p>
-If the metatable of <code>v</code> has a <code>"__tostring"</code> field,
+If the metatable of <code>v</code> has a <code>__tostring</code> field,
then <code>tostring</code> calls the corresponding value
with <code>v</code> as argument,
and uses the result of the call as its result.
@@ -7555,8 +7694,11 @@ and "<code>userdata</code>".
<p>
<hr><h3><a name="pdf-_VERSION"><code>_VERSION</code></a></h3>
+
+
+<p>
A global variable (not a function) that
-holds a string containing the current interpreter version.
+holds a string containing the running Lua version.
The current value of this variable is "<code>Lua 5.3</code>".
@@ -7579,8 +7721,8 @@ except that it sets a new message handler <code>msgh</code>.
<h2>6.2 &ndash; <a name="6.2">Coroutine Manipulation</a></h2>
<p>
-The operations related to coroutines comprise a sub-library of
-the basic library and come inside the table <a name="pdf-coroutine"><code>coroutine</code></a>.
+This library comprises the operations to manipulate coroutines,
+which come inside the table <a name="pdf-coroutine"><code>coroutine</code></a>.
See <a href="#2.6">&sect;2.6</a> for a general description of coroutines.
@@ -7590,7 +7732,7 @@ See <a href="#2.6">&sect;2.6</a> for a general description of coroutines.
<p>
Creates a new coroutine, with body <code>f</code>.
-<code>f</code> must be a Lua function.
+<code>f</code> must be a function.
Returns this new coroutine,
an object with type <code>"thread"</code>.
@@ -7607,7 +7749,7 @@ Returns true when the running coroutine can yield.
<p>
A running coroutine is yieldable if it is not the main thread and
-it is not inside a non-yieldable C function.
+it is not inside a non-yieldable C&nbsp;function.
@@ -7674,7 +7816,7 @@ or if it has stopped with an error.
<p>
Creates a new coroutine, with body <code>f</code>.
-<code>f</code> must be a Lua function.
+<code>f</code> must be a function.
Returns a function that resumes the coroutine each time it is called.
Any arguments passed to the function behave as the
extra arguments to <code>resume</code>.
@@ -7809,8 +7951,8 @@ The path used by <a href="#pdf-require"><code>require</code></a> to search for a
<p>
Lua initializes the C&nbsp;path <a href="#pdf-package.cpath"><code>package.cpath</code></a> in the same way
it initializes the Lua path <a href="#pdf-package.path"><code>package.path</code></a>,
-using the environment variable <a name="pdf-LUA_CPATH_5_3"><code>LUA_CPATH_5_3</code></a>
-or the environment variable <a name="pdf-LUA_CPATH"><code>LUA_CPATH</code></a>
+using the environment variable <a name="pdf-LUA_CPATH_5_3"><code>LUA_CPATH_5_3</code></a>,
+or the environment variable <a name="pdf-LUA_CPATH"><code>LUA_CPATH</code></a>,
or a default path defined in <code>luaconf.h</code>.
@@ -8073,7 +8215,7 @@ The string library assumes one-byte character encodings.
<p>
<hr><h3><a name="pdf-string.byte"><code>string.byte (s [, i [, j]])</code></a></h3>
-Returns the internal numerical codes of the characters <code>s[i]</code>,
+Returns the internal numeric codes of the characters <code>s[i]</code>,
<code>s[i+1]</code>, ..., <code>s[j]</code>.
The default value for <code>i</code> is&nbsp;1;
the default value for <code>j</code> is&nbsp;<code>i</code>.
@@ -8082,7 +8224,7 @@ following the same rules of function <a href="#pdf-string.sub"><code>string.sub<
<p>
-Numerical codes are not necessarily portable across platforms.
+Numeric codes are not necessarily portable across platforms.
@@ -8091,12 +8233,12 @@ Numerical codes are not necessarily portable across platforms.
<hr><h3><a name="pdf-string.char"><code>string.char (&middot;&middot;&middot;)</code></a></h3>
Receives zero or more integers.
Returns a string with length equal to the number of arguments,
-in which each character has the internal numerical code equal
+in which each character has the internal numeric code equal
to its corresponding argument.
<p>
-Numerical codes are not necessarily portable across platforms.
+Numeric codes are not necessarily portable across platforms.
@@ -8112,9 +8254,9 @@ of the given function,
so that a later <a href="#pdf-load"><code>load</code></a> on this string returns
a copy of the function (but with new upvalues).
If <code>strip</code> is a true value,
-the binary representation is created without debug information
-about the function
-(local variable names, lines, etc.).
+the binary representation may not include all debug information
+about the function,
+to save space.
<p>
@@ -8138,7 +8280,7 @@ Looks for the first match of
If it finds a match, then <code>find</code> returns the indices of&nbsp;<code>s</code>
where this occurrence starts and ends;
otherwise, it returns <b>nil</b>.
-A third, optional numerical argument <code>init</code> specifies
+A third, optional numeric argument <code>init</code> specifies
where to start the search;
its default value is&nbsp;1 and can be negative.
A value of <b>true</b> as a fourth, optional argument <code>plain</code>
@@ -8169,6 +8311,9 @@ The only differences are that the options/modifiers
<code>*</code>, <code>h</code>, <code>L</code>, <code>l</code>, <code>n</code>,
and <code>p</code> are not supported
and that there is an extra option, <code>q</code>.
+
+
+<p>
The <code>q</code> option formats a string between double quotes,
using escape sequences when necessary to ensure that
it can safely be read back by the Lua interpreter.
@@ -8186,16 +8331,22 @@ may produce the string:
<p>
Options
-<code>A</code> and <code>a</code> (when available),
-<code>E</code>, <code>e</code>, <code>f</code>,
+<code>A</code>, <code>a</code>, <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.
-Option <code>q</code> expects a string;
-option <code>s</code> expects a string without embedded zeros.
-If the argument to option <code>s</code> is not a string,
+When Lua is compiled with a C89 compiler,
+options <code>A</code> and <code>a</code> (hexadecimal floats)
+do not support any modifier (flags, width, length).
+
+
+<p>
+Option <code>s</code> expects a string;
+if its argument is not a string,
it is converted to one following the same rules of <a href="#pdf-tostring"><code>tostring</code></a>.
+If the option has any modifier (flags, width, length),
+the string argument should not contain embedded zeros.
@@ -8344,7 +8495,7 @@ the captures from the pattern;
otherwise it returns <b>nil</b>.
If <code>pattern</code> specifies no captures,
then the whole match is returned.
-A third, optional numerical argument <code>init</code> specifies
+A third, optional numeric argument <code>init</code> specifies
where to start the search;
its default value is&nbsp;1 and can be negative.
@@ -8358,7 +8509,7 @@ its default value is&nbsp;1 and can be negative.
<p>
Returns a binary string containing the values <code>v1</code>, <code>v2</code>, etc.
packed (that is, serialized in binary form)
-according to the format string <code>fmt</code> (see <a href="#6.4.2">&sect;6.4.2</a>).
+according to the format string <code>fmt</code> (see <a href="#6.4.2">&sect;6.4.2</a>).
@@ -8385,6 +8536,11 @@ The default value for <code>sep</code> is the empty string
Returns the empty string if <code>n</code> is not positive.
+<p>
+(Note that it is very easy to exhaust the memory of your machine
+with a single call to this function.)
+
+
<p>
@@ -8404,7 +8560,8 @@ If <code>j</code> is absent, then it is assumed to be equal to -1
In particular,
the call <code>string.sub(s,1,j)</code> returns a prefix of <code>s</code>
with length <code>j</code>,
-and <code>string.sub(s, -i)</code> returns a suffix of <code>s</code>
+and <code>string.sub(s, -i)</code> (for a positive <code>i</code>)
+returns a suffix of <code>s</code>
with length <code>i</code>.
@@ -8499,7 +8656,7 @@ represents the character <em>x</em> itself.
represents the character <em>x</em>.
This is the standard way to escape the magic characters.
Any non-alphanumeric character
-(including all punctuations, even the non-magical)
+(including all punctuation characters, even the non-magical)
can be preceded by a '<code>%</code>'
when used to represent itself in a pattern.
</li>
@@ -8521,6 +8678,14 @@ the lowercase letters plus the '<code>-</code>' character.
<p>
+You can put a closing square bracket in a set
+by positioning it as the first character in the set.
+You can put an hyphen in a set
+by positioning it as the first or the last character in the set.
+(You can also use an escape for both cases.)
+
+
+<p>
The interaction between ranges and classes is not defined.
Therefore, patterns like <code>[%a-z]</code> or <code>[a-%%]</code>
have no meaning.
@@ -8813,7 +8978,7 @@ Returns the number of UTF-8 characters in string <code>s</code>
that start between positions <code>i</code> and <code>j</code> (both inclusive).
The default for <code>i</code> is 1 and for <code>j</code> is -1.
If it finds any invalid byte sequence,
-returns a false value plus the position of the first invalid byte.
+returns a false value plus the position of the first invalid byte.
@@ -8857,8 +9022,7 @@ It provides all its functions inside the table <a name="pdf-table"><code>table</
<p>
Remember that, whenever an operation needs the length of a table,
-the table must be a proper sequence
-or have a <code>__len</code> metamethod (see <a href="#3.4.7">&sect;3.4.7</a>).
+all caveats about the length operator apply (see <a href="#3.4.7">&sect;3.4.7</a>).
All functions ignore non-numeric keys
in the tables given as arguments.
@@ -8898,13 +9062,17 @@ of list <code>t</code>.
<p>
-Moves elements from table <code>a1</code> to table <code>a2</code>.
-This function performs the equivalent to the following
+Moves elements from table <code>a1</code> to table <code>a2</code>,
+performing the equivalent to the following
multiple assignment:
<code>a2[t],&middot;&middot;&middot; = a1[f],&middot;&middot;&middot;,a1[e]</code>.
The default for <code>a2</code> is <code>a1</code>.
The destination range can overlap with the source range.
-Index <code>f</code> must be positive.
+The number of elements to be moved must fit in a Lua integer.
+
+
+<p>
+Returns the destination table <code>a2</code>.
@@ -8956,14 +9124,22 @@ If <code>comp</code> is given,
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(list[i+1],list[i])</code> will be true after the sort).
+(so that, after the sort,
+<code>i &lt; j</code> implies <code>not comp(list[j],list[i])</code>).
If <code>comp</code> is not given,
then the standard Lua operator <code>&lt;</code> is used instead.
<p>
-The sort algorithm is not stable;
-that is, elements considered equal by the given order
+Note that the <code>comp</code> function must define
+a strict partial order over the elements in the list;
+that is, it must be asymmetric and transitive.
+Otherwise, no valid sort may be possible.
+
+
+<p>
+The sort algorithm is not stable:
+elements considered equal by the given order
may have their relative positions changed by the sort.
@@ -9120,7 +9296,7 @@ that rounds the quotient towards zero. (integer/float)
<p>
The float value <code>HUGE_VAL</code>,
-a value larger than any other numerical value.
+a value larger than any other numeric value.
@@ -9215,14 +9391,13 @@ in the range <em>[0,1)</em>.
When called with two integers <code>m</code> and <code>n</code>,
<code>math.random</code> returns a pseudo-random integer
with uniform distribution in the range <em>[m, n]</em>.
-(The value <em>m-n</em> cannot be negative and must fit in a Lua integer.)
+(The value <em>n-m</em> cannot be negative and must fit in a Lua integer.)
The call <code>math.random(n)</code> is equivalent to <code>math.random(1,n)</code>.
<p>
This function is an interface to the underling
pseudo-random generator function provided by C.
-No guarantees can be given for its statistical properties.
@@ -9300,7 +9475,7 @@ or <b>nil</b> if <code>x</code> is not a number.
<p>
Returns a boolean,
-true if integer <code>m</code> is below integer <code>n</code> when
+true if and only if integer <code>m</code> is below integer <code>n</code> when
they are compared as unsigned integers.
@@ -9390,7 +9565,7 @@ instead of returning an error code.
<p>
-<hr><h3><a name="pdf-io.lines"><code>io.lines ([filename &middot;&middot;&middot;])</code></a></h3>
+<hr><h3><a name="pdf-io.lines"><code>io.lines ([filename, &middot;&middot;&middot;])</code></a></h3>
<p>
@@ -9422,8 +9597,8 @@ instead of returning an error code.
<p>
This function opens a file,
in the mode specified in the string <code>mode</code>.
-It returns a new file handle,
-or, in case of errors, <b>nil</b> plus an error message.
+In case of success,
+it returns a new file handle.
<p>
@@ -9488,7 +9663,8 @@ Equivalent to <code>io.input():read(&middot;&middot;&middot;)</code>.
<p>
-Returns a handle for a temporary file.
+In case of success,
+returns a handle for a temporary file.
This file is opened in update mode
and it is automatically removed when the program ends.
@@ -9602,16 +9778,12 @@ reads a numeral and returns it as a float or an integer,
following the lexical conventions of Lua.
(The numeral may have leading spaces and a sign.)
This format always reads the longest input sequence that
-is a valid prefix for a number;
-if that prefix does not form a valid number
+is a valid prefix for a numeral;
+if that prefix does not form a valid numeral
(e.g., an empty string, "<code>0x</code>", or "<code>3.4e-</code>"),
it is discarded and the function returns <b>nil</b>.
</li>
-<li><b>"<code>i</code>": </b>
-reads an integral number and returns it as an integer.
-</li>
-
<li><b>"<code>a</code>": </b>
reads the whole file, starting at the current position.
On end of file, it returns the empty string.
@@ -9768,10 +9940,10 @@ then the date is formatted in Coordinated Universal Time.
After this optional character,
if <code>format</code> is the string "<code>*t</code>",
then <code>date</code> returns a table with the following fields:
-<code>year</code> (four digits), <code>month</code> (1&ndash;12), <code>day</code> (1&ndash;31),
+<code>year</code>, <code>month</code> (1&ndash;12), <code>day</code> (1&ndash;31),
<code>hour</code> (0&ndash;23), <code>min</code> (0&ndash;59), <code>sec</code> (0&ndash;61),
-<code>wday</code> (weekday, Sunday is&nbsp;1),
-<code>yday</code> (day of the year),
+<code>wday</code> (weekday, 1&ndash;7, Sunday is&nbsp;1),
+<code>yday</code> (day of the year, 1&ndash;366),
and <code>isdst</code> (daylight saving flag, a boolean).
This last field may be absent
if the information is not available.
@@ -9786,8 +9958,8 @@ formatted according to the same rules as the ISO&nbsp;C function <code>strftime<
<p>
When called without arguments,
<code>date</code> returns a reasonable date and time representation that depends on
-the host system and on the current locale
-(that is, <code>os.date()</code> is equivalent to <code>os.date("%c")</code>).
+the host system and on the current locale.
+(More specifically, <code>os.date()</code> is equivalent to <code>os.date("%c")</code>.)
<p>
@@ -9889,6 +10061,7 @@ 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 and the error code.
+Otherwise, it returns true.
@@ -9898,9 +10071,10 @@ plus a string describing the error and the error code.
<p>
-Renames file or directory named <code>oldname</code> to <code>newname</code>.
+Renames the file or directory named <code>oldname</code> to <code>newname</code>.
If this function fails, it returns <b>nil</b>,
plus a string describing the error and the error code.
+Otherwise, it returns true.
@@ -9946,17 +10120,26 @@ because of its reliance on C&nbsp;function <code>setlocale</code>.
<p>
Returns the current time when called without arguments,
-or a time representing the date and time specified by the given table.
+or a time representing the local date and time specified by the given table.
This table must have fields <code>year</code>, <code>month</code>, and <code>day</code>,
and may have fields
<code>hour</code> (default is 12),
<code>min</code> (default is 0),
<code>sec</code> (default is 0),
and <code>isdst</code> (default is <b>nil</b>).
+Other fields are ignored.
For a description of these fields, see the <a href="#pdf-os.date"><code>os.date</code></a> function.
<p>
+The values in these fields do not need to be inside their valid ranges.
+For instance, if <code>sec</code> is -10,
+it means -10 seconds from the time specified by the other fields;
+if <code>hour</code> is 1000,
+it means +1000 hours from the time specified by the other fields.
+
+
+<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
@@ -10093,7 +10276,7 @@ valid lines.
<p>
For instance, the expression <code>debug.getinfo(1,"n").name</code> returns
-a table with a name for the current function,
+a name for the current function,
if a reasonable name can be found,
and the expression <code>debug.getinfo(print)</code>
returns a table with all available information
@@ -10184,7 +10367,7 @@ represent variables with no known names
<p>
Returns the Lua value associated to <code>u</code>.
-If <code>u</code> is not a userdata,
+If <code>u</code> is not a full userdata,
returns <b>nil</b>.
@@ -10383,7 +10566,7 @@ and as <code>lua -</code> otherwise.
<p>
-When called without option <code>-E</code>,
+When called without option <code>-E</code>,
the interpreter checks for an environment variable <a name="pdf-LUA_INIT_5_3"><code>LUA_INIT_5_3</code></a>
(or <a name="pdf-LUA_INIT"><code>LUA_INIT</code></a> if the versioned name is not defined)
before running any argument.
@@ -10465,9 +10648,17 @@ by issuing a different prompt.
<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,
+its value is used as the secondary prompt
+(issued during incomplete statements).
+
+
+<p>
In case of unprotected errors in the script,
the interpreter reports the error to the standard error stream.
-If the error object is not a string but
+If the error object is not a string but
has a metamethod <code>__tostring</code>,
the interpreter calls this metamethod to produce the final message.
Otherwise, the interpreter converts the error object to a string
@@ -10599,7 +10790,8 @@ The <code>bit32</code> library has been deprecated.
It is easy to require a compatible external library or,
better yet, to replace its functions with appropriate bitwise operations.
(Keep in mind that <code>bit32</code> operates on 32-bit integers,
-while the bitwise operators in standard Lua operate on 64-bit integers.)
+while the bitwise operators in Lua&nbsp;5.3 operate on Lua integers,
+which by default have 64&nbsp;bits.)
</li>
<li>
@@ -10614,7 +10806,7 @@ its <code>__ipairs</code> metamethod has been deprecated.
<li>
Option names in <a href="#pdf-io.read"><code>io.read</code></a> do not have a starting '<code>*</code>' anymore.
-For compatibility, Lua will continue to ignore this character.
+For compatibility, Lua will continue to accept (and ignore) this character.
</li>
<li>
@@ -10641,6 +10833,12 @@ if it cannot find an open function according to the new style.
but it did not document the change.)
</li>
+<li>
+The call <code>collectgarbage("count")</code> now returns only one result.
+(You can compute that second result from the fractional part
+of the first result.)
+</li>
+
</ul>
@@ -10775,14 +10973,12 @@ and LiteralString, see <a href="#3.1">&sect;3.1</a>.)
-
-<HR>
-<SMALL CLASS="footer">
+<P CLASS="footer">
Last update:
-Tue Jan 6 10:10:50 BRST 2015
-</SMALL>
+Mon Jan 9 13:30:53 BRST 2017
+</P>
<!--
-Last change: revised for Lua 5.3.0 (final)
+Last change: revised for Lua 5.3.4
-->
</body></html>
diff --git a/doc/readme.html b/doc/readme.html
index 016575570133..96a9386e2af0 100644
--- a/doc/readme.html
+++ b/doc/readme.html
@@ -7,9 +7,9 @@
<STYLE TYPE="text/css">
blockquote, .display {
border: solid #a0a0a0 2px ;
+ border-radius: 8px ;
padding: 1em ;
margin: 0px ;
- border-radius: 8px ;
}
.display {
@@ -28,13 +28,12 @@ tt, kbd, code {
<BODY>
-<HR>
<H1>
-<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua" BORDER=0></A>
-Welcome to Lua 5.3.0
+<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
+Welcome to Lua 5.3
</H1>
-<P>
+<DIV CLASS="menubar">
<A HREF="#about">about</A>
&middot;
<A HREF="#install">installation</A>
@@ -44,9 +43,9 @@ Welcome to Lua 5.3.0
<A HREF="#license">license</A>
&middot;
<A HREF="contents.html">reference manual</A>
+</DIV>
<H2><A NAME="about">About Lua</A></H2>
-
<P>
Lua is a powerful, fast, lightweight, embeddable scripting language
developed by a
@@ -76,7 +75,6 @@ which may differ slightly from the
distributed in this package.
<H2><A NAME="install">Installing Lua</A></H2>
-
<P>
Lua is distributed in
<A HREF="http://www.lua.org/ftp/">source</A>
@@ -102,7 +100,6 @@ Try also
a multi-platform distribution of Lua that includes batteries.
<H3>Building Lua</H3>
-
<P>
In most Unix-like platforms, simply do "<KBD>make</KBD>" with a suitable target.
Here are the details.
@@ -110,7 +107,7 @@ Here are the details.
<OL>
<LI>
Open a terminal window and move to
-the top-level directory, which is named <TT>lua-5.3.0</TT>.
+the top-level directory, which is named <TT>lua-5.3.x</TT>.
The <TT>Makefile</TT> there controls both the build process and the installation process.
<P>
<LI>
@@ -140,7 +137,8 @@ and liblua.a (the library).
</OL>
<P>
If you're running Linux and get compilation errors,
-make sure you have installed the <TT>readline</TT> development package.
+make sure you have installed the <TT>readline</TT> development package
+(which is probably named <TT>libreadline-dev</TT> or <TT>readline-devel</TT>).
If you get link errors after that,
then try "<KBD>make linux MYLIBS=-ltermcap</KBD>".
@@ -174,7 +172,7 @@ then try "<KBD>make linux MYLIBS=-ltermcap</KBD>".
<DT>
include:
<DD>
- lauxlib.h lua.h lua.hpp luaconf.h lualib.h
+ lua.h luaconf.h lualib.h lauxlib.h lua.hpp
<DT>
lib:
<DD>
@@ -215,7 +213,6 @@ then try "<KBD>make linux MYLIBS=-ltermcap</KBD>".
Further customization is available to experts by editing the Lua sources.
<H3><A NAME="other">Building Lua on other systems</A></H3>
-
<P>
If you're not using the usual Unix tools, then the instructions for
building Lua depend on the compiler you use. You'll need to create
@@ -258,7 +255,6 @@ compiler:
some features before building Lua.
<H2><A NAME="changes">Changes since Lua 5.2</A></H2>
-
<P>
Here are the main changes introduced in Lua 5.3.
The
@@ -280,7 +276,7 @@ Here are the other changes introduced in Lua 5.3:
<H3>Language</H3>
<UL>
<LI> userdata can have any Lua value as uservalue
-<LI> integer division
+<LI> floor division
<LI> more flexible rules for some metamethods
</UL>
@@ -315,11 +311,10 @@ Here are the other changes introduced in Lua 5.3:
</UL>
<H2><A NAME="license">License</A></H2>
+<P>
<A HREF="http://www.opensource.org/docs/definition.php">
-<IMG SRC="osi-certified-72x60.png" ALIGN="right" BORDER="0" ALT="[osi certified]" STYLE="padding-left: 30px ;">
+<IMG SRC="osi-certified-72x60.png" ALIGN="right" ALT="[osi certified]" STYLE="padding-left: 30px ;">
</A>
-
-<P>
Lua is free software distributed under the terms of the
<A HREF="http://www.opensource.org/licenses/mit-license.html">MIT license</A>
reproduced below;
@@ -333,7 +328,7 @@ For details, see
<A HREF="http://www.lua.org/license.html">this</A>.
<BLOCKQUOTE STYLE="padding-bottom: 0em">
-Copyright &copy; 1994&ndash;2015 Lua.org, PUC-Rio.
+Copyright &copy; 1994&ndash;2017 Lua.org, PUC-Rio.
<P>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -358,13 +353,12 @@ THE SOFTWARE.
</BLOCKQUOTE>
<P>
-<HR>
-<SMALL CLASS="footer">
+<P CLASS="footer">
Last update:
-Fri Dec 12 09:58:42 BRST 2014
-</SMALL>
+Thu Dec 22 18:22:57 BRST 2016
+</P>
<!--
-Last change: updated for Lua 5.3.0 (final)
+Last change: revised for Lua 5.3.4
-->
</BODY>
diff --git a/src/Makefile b/src/Makefile
index 2e7a4120cef2..d71c75c87322 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -130,68 +130,68 @@ solaris:
# DO NOT DELETE
lapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
- lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h \
- ltable.h lundump.h lvm.h
+ lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h \
+ ltable.h lundump.h lvm.h
lauxlib.o: lauxlib.c lprefix.h lua.h luaconf.h lauxlib.h
lbaselib.o: lbaselib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lbitlib.o: lbitlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lcode.o: lcode.c lprefix.h 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 lvm.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 lvm.h
lcorolib.o: lcorolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lctype.o: lctype.c lprefix.h lctype.h lua.h luaconf.h llimits.h
ldblib.o: ldblib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
ldebug.o: ldebug.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
- lobject.h ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h \
- ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h
+ lobject.h ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h \
+ ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h
ldo.o: ldo.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
- lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \
- lparser.h lstring.h ltable.h lundump.h lvm.h
+ lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \
+ lparser.h lstring.h ltable.h lundump.h lvm.h
ldump.o: ldump.c lprefix.h lua.h luaconf.h lobject.h llimits.h lstate.h \
- ltm.h lzio.h lmem.h lundump.h
+ ltm.h lzio.h lmem.h lundump.h
lfunc.o: lfunc.c lprefix.h lua.h luaconf.h lfunc.h lobject.h llimits.h \
- lgc.h lstate.h ltm.h lzio.h lmem.h
+ lgc.h lstate.h ltm.h lzio.h lmem.h
lgc.o: lgc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
- llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
+ llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
linit.o: linit.c lprefix.h lua.h luaconf.h lualib.h lauxlib.h
liolib.o: liolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
-llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldo.h \
- lobject.h lstate.h ltm.h lzio.h lmem.h lgc.h llex.h lparser.h lstring.h \
- ltable.h
+llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldebug.h \
+ lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lgc.h llex.h lparser.h \
+ lstring.h ltable.h
lmathlib.o: lmathlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lmem.o: lmem.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
- llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h
+ llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h
loadlib.o: loadlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lobject.o: lobject.c lprefix.h lua.h luaconf.h lctype.h llimits.h \
- ldebug.h lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h \
- lvm.h
+ ldebug.h lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h \
+ lvm.h
lopcodes.o: lopcodes.c lprefix.h lopcodes.h llimits.h lua.h luaconf.h
loslib.o: loslib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lparser.o: lparser.c lprefix.h 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 lfunc.h lstring.h lgc.h ltable.h
+ llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
+ ldo.h lfunc.h lstring.h lgc.h ltable.h
lstate.o: lstate.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
- lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h \
- lstring.h ltable.h
+ lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h \
+ lstring.h ltable.h
lstring.o: lstring.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
- lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h
+ lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h
lstrlib.o: lstrlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
ltable.o: ltable.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
- llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
+ llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
ltablib.o: ltablib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
ltm.o: ltm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
- llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h ltable.h lvm.h
+ llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h ltable.h lvm.h
lua.o: lua.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
luac.o: luac.c lprefix.h lua.h luaconf.h lauxlib.h lobject.h llimits.h \
- lstate.h ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h
+ lstate.h ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h
lundump.o: lundump.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
- lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h \
- lundump.h
+ lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h \
+ lundump.h
lutf8lib.o: lutf8lib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lvm.o: lvm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
- llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h \
- ltable.h lvm.h
+ llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h \
+ ltable.h lvm.h
lzio.o: lzio.c lprefix.h lua.h luaconf.h llimits.h lmem.h lstate.h \
- lobject.h ltm.h lzio.h
+ lobject.h ltm.h lzio.h
# (end of Makefile)
diff --git a/src/lapi.c b/src/lapi.c
index fbfafa304ff8..c9455a5d8cd5 100644
--- a/src/lapi.c
+++ b/src/lapi.c
@@ -1,5 +1,5 @@
/*
-** $Id: lapi.c,v 2.244 2014/12/26 14:43:45 roberto Exp $
+** $Id: lapi.c,v 2.259 2016/02/29 14:27:14 roberto Exp $
** Lua API
** See Copyright Notice in lua.h
*/
@@ -51,29 +51,29 @@ const char lua_ident[] =
/* test for valid but not pseudo index */
#define isstackindex(i, o) (isvalid(o) && !ispseudo(i))
-#define api_checkvalidindex(o) api_check(isvalid(o), "invalid index")
+#define api_checkvalidindex(l,o) api_check(l, isvalid(o), "invalid index")
-#define api_checkstackindex(i, o) \
- api_check(isstackindex(i, o), "index not in the stack")
+#define api_checkstackindex(l, i, o) \
+ api_check(l, isstackindex(i, o), "index not in the stack")
static TValue *index2addr (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
TValue *o = ci->func + idx;
- api_check(idx <= ci->top - (ci->func + 1), "unacceptable index");
+ api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index");
if (o >= L->top) return NONVALIDVALUE;
else return o;
}
else if (!ispseudo(idx)) { /* negative index */
- api_check(idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
+ api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
return L->top + idx;
}
else if (idx == LUA_REGISTRYINDEX)
return &G(L)->l_registry;
else { /* upvalues */
idx = LUA_REGISTRYINDEX - idx;
- api_check(idx <= MAXUPVAL + 1, "upvalue index too large");
+ api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
if (ttislcf(ci->func)) /* light C function? */
return NONVALIDVALUE; /* it has no upvalues */
else {
@@ -98,7 +98,7 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
int res;
CallInfo *ci = L->ci;
lua_lock(L);
- api_check(n >= 0, "negative 'n'");
+ api_check(L, n >= 0, "negative 'n'");
if (L->stack_last - L->top > n) /* stack large enough? */
res = 1; /* yes; check is OK */
else { /* no; need to grow stack */
@@ -120,11 +120,12 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
if (from == to) return;
lua_lock(to);
api_checknelems(from, n);
- api_check(G(from) == G(to), "moving among independent states");
- api_check(to->ci->top - to->top >= n, "not enough elements to move");
+ api_check(from, G(from) == G(to), "moving among independent states");
+ api_check(from, to->ci->top - to->top >= n, "stack overflow");
from->top -= n;
for (i = 0; i < n; i++) {
- setobj2s(to, to->top++, from->top + i);
+ setobj2s(to, to->top, from->top + i);
+ to->top++; /* stack already checked by previous 'api_check' */
}
lua_unlock(to);
}
@@ -159,7 +160,7 @@ LUA_API const lua_Number *lua_version (lua_State *L) {
LUA_API int lua_absindex (lua_State *L, int idx) {
return (idx > 0 || ispseudo(idx))
? idx
- : cast_int(L->top - L->ci->func + idx);
+ : cast_int(L->top - L->ci->func) + idx;
}
@@ -172,13 +173,13 @@ LUA_API void lua_settop (lua_State *L, int idx) {
StkId func = L->ci->func;
lua_lock(L);
if (idx >= 0) {
- api_check(idx <= L->stack_last - (func + 1), "new top too large");
+ api_check(L, idx <= L->stack_last - (func + 1), "new top too large");
while (L->top < (func + 1) + idx)
setnilvalue(L->top++);
L->top = (func + 1) + idx;
}
else {
- api_check(-(idx+1) <= (L->top - (func + 1)), "invalid new top");
+ api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
L->top += idx+1; /* 'subtract' index (index is negative) */
}
lua_unlock(L);
@@ -208,8 +209,8 @@ LUA_API void lua_rotate (lua_State *L, int idx, int n) {
lua_lock(L);
t = L->top - 1; /* end of stack segment being rotated */
p = index2addr(L, idx); /* start of segment */
- api_checkstackindex(idx, p);
- api_check((n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
+ api_checkstackindex(L, idx, p);
+ api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
reverse(L, p, m); /* reverse the prefix with length 'n' */
reverse(L, m + 1, t); /* reverse the suffix */
@@ -223,7 +224,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
lua_lock(L);
fr = index2addr(L, fromidx);
to = index2addr(L, toidx);
- api_checkvalidindex(to);
+ api_checkvalidindex(L, to);
setobj(L, to, fr);
if (isupvalue(toidx)) /* function upvalue? */
luaC_barrier(L, clCvalue(L->ci->func), fr);
@@ -255,7 +256,7 @@ LUA_API int lua_type (lua_State *L, int idx) {
LUA_API const char *lua_typename (lua_State *L, int t) {
UNUSED(L);
- api_check(LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag");
+ api_check(L, LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag");
return ttypename(t);
}
@@ -305,7 +306,7 @@ LUA_API void lua_arith (lua_State *L, int op) {
else { /* for unary operations, add fake 2nd operand */
api_checknelems(L, 1);
setobjs2s(L, L->top, L->top - 1);
- L->top++;
+ api_incr_top(L);
}
/* first operand at top - 2, second at top - 1; result go to top - 2 */
luaO_arith(L, op, L->top - 2, L->top - 1, L->top - 2);
@@ -325,7 +326,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
case LUA_OPEQ: i = luaV_equalobj(L, o1, o2); break;
case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break;
case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break;
- default: api_check(0, "invalid option");
+ default: api_check(L, 0, "invalid option");
}
}
lua_unlock(L);
@@ -377,20 +378,22 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
return NULL;
}
lua_lock(L); /* 'luaO_tostring' may create a new string */
+ luaO_tostring(L, o);
luaC_checkGC(L);
o = index2addr(L, idx); /* previous call may reallocate the stack */
- luaO_tostring(L, o);
lua_unlock(L);
}
- if (len != NULL) *len = tsvalue(o)->len;
+ if (len != NULL)
+ *len = vslen(o);
return svalue(o);
}
LUA_API size_t lua_rawlen (lua_State *L, int idx) {
StkId o = index2addr(L, idx);
- switch (ttnov(o)) {
- case LUA_TSTRING: return tsvalue(o)->len;
+ switch (ttype(o)) {
+ case LUA_TSHRSTR: return tsvalue(o)->shrlen;
+ case LUA_TLNGSTR: return tsvalue(o)->u.lnglen;
case LUA_TUSERDATA: return uvalue(o)->len;
case LUA_TTABLE: return luaH_getn(hvalue(o));
default: return 0;
@@ -431,9 +434,8 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
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:
- case LUA_TLIGHTUSERDATA:
- return lua_touserdata(L, idx);
+ case LUA_TUSERDATA: return getudatamem(uvalue(o));
+ case LUA_TLIGHTUSERDATA: return pvalue(o);
default: return NULL;
}
}
@@ -469,33 +471,37 @@ LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
}
+/*
+** Pushes on the stack a string with given length. Avoid using 's' when
+** 'len' == 0 (as 's' can be NULL in that case), due to later use of
+** 'memcmp' and 'memcpy'.
+*/
LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts;
lua_lock(L);
- luaC_checkGC(L);
- ts = luaS_newlstr(L, s, len);
+ ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
setsvalue2s(L, L->top, ts);
api_incr_top(L);
+ luaC_checkGC(L);
lua_unlock(L);
return getstr(ts);
}
LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
- if (s == NULL) {
- lua_pushnil(L);
- return NULL;
- }
+ lua_lock(L);
+ if (s == NULL)
+ setnilvalue(L->top);
else {
TString *ts;
- lua_lock(L);
- luaC_checkGC(L);
ts = luaS_new(L, s);
setsvalue2s(L, L->top, ts);
- api_incr_top(L);
- lua_unlock(L);
- return getstr(ts);
+ s = getstr(ts); /* internal copy's address */
}
+ api_incr_top(L);
+ luaC_checkGC(L);
+ lua_unlock(L);
+ return s;
}
@@ -503,8 +509,8 @@ LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt,
va_list argp) {
const char *ret;
lua_lock(L);
- luaC_checkGC(L);
ret = luaO_pushvfstring(L, fmt, argp);
+ luaC_checkGC(L);
lua_unlock(L);
return ret;
}
@@ -514,10 +520,10 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
const char *ret;
va_list argp;
lua_lock(L);
- luaC_checkGC(L);
va_start(argp, fmt);
ret = luaO_pushvfstring(L, fmt, argp);
va_end(argp);
+ luaC_checkGC(L);
lua_unlock(L);
return ret;
}
@@ -531,8 +537,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
else {
CClosure *cl;
api_checknelems(L, n);
- api_check(n <= MAXUPVAL, "upvalue index too large");
- luaC_checkGC(L);
+ api_check(L, n <= MAXUPVAL, "upvalue index too large");
cl = luaF_newCclosure(L, n);
cl->f = fn;
L->top -= n;
@@ -543,6 +548,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
setclCvalue(L, L->top, cl);
}
api_incr_top(L);
+ luaC_checkGC(L);
lua_unlock(L);
}
@@ -578,15 +584,27 @@ LUA_API int lua_pushthread (lua_State *L) {
*/
+static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
+ const TValue *slot;
+ TString *str = luaS_new(L, k);
+ if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
+ setobj2s(L, L->top, slot);
+ api_incr_top(L);
+ }
+ else {
+ setsvalue2s(L, L->top, str);
+ api_incr_top(L);
+ luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
+ }
+ lua_unlock(L);
+ return ttnov(L->top - 1);
+}
+
+
LUA_API int lua_getglobal (lua_State *L, const char *name) {
Table *reg = hvalue(&G(L)->l_registry);
- const TValue *gt; /* global table */
lua_lock(L);
- gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
- setsvalue2s(L, L->top++, luaS_new(L, name));
- luaV_gettable(L, gt, L->top - 1, L->top - 1);
- lua_unlock(L);
- return ttnov(L->top - 1);
+ return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);
}
@@ -601,24 +619,25 @@ LUA_API int lua_gettable (lua_State *L, int idx) {
LUA_API int lua_getfield (lua_State *L, int idx, const char *k) {
- StkId t;
lua_lock(L);
- t = index2addr(L, idx);
- setsvalue2s(L, L->top, luaS_new(L, k));
- api_incr_top(L);
- luaV_gettable(L, t, L->top - 1, L->top - 1);
- lua_unlock(L);
- return ttnov(L->top - 1);
+ return auxgetstr(L, index2addr(L, idx), k);
}
LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
StkId t;
+ const TValue *slot;
lua_lock(L);
t = index2addr(L, idx);
- setivalue(L->top, n);
- api_incr_top(L);
- luaV_gettable(L, t, L->top - 1, L->top - 1);
+ if (luaV_fastget(L, t, n, slot, luaH_getint)) {
+ setobj2s(L, L->top, slot);
+ api_incr_top(L);
+ }
+ else {
+ setivalue(L->top, n);
+ api_incr_top(L);
+ luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
+ }
lua_unlock(L);
return ttnov(L->top - 1);
}
@@ -628,7 +647,7 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
StkId t;
lua_lock(L);
t = index2addr(L, idx);
- api_check(ttistable(t), "table expected");
+ api_check(L, ttistable(t), "table expected");
setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1));
lua_unlock(L);
return ttnov(L->top - 1);
@@ -639,7 +658,7 @@ LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) {
StkId t;
lua_lock(L);
t = index2addr(L, idx);
- api_check(ttistable(t), "table expected");
+ api_check(L, ttistable(t), "table expected");
setobj2s(L, L->top, luaH_getint(hvalue(t), n));
api_incr_top(L);
lua_unlock(L);
@@ -652,7 +671,7 @@ LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
TValue k;
lua_lock(L);
t = index2addr(L, idx);
- api_check(ttistable(t), "table expected");
+ api_check(L, ttistable(t), "table expected");
setpvalue(&k, cast(void *, p));
setobj2s(L, L->top, luaH_get(hvalue(t), &k));
api_incr_top(L);
@@ -664,12 +683,12 @@ LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t;
lua_lock(L);
- luaC_checkGC(L);
t = luaH_new(L);
sethvalue(L, L->top, t);
api_incr_top(L);
if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec);
+ luaC_checkGC(L);
lua_unlock(L);
}
@@ -705,7 +724,7 @@ LUA_API int lua_getuservalue (lua_State *L, int idx) {
StkId o;
lua_lock(L);
o = index2addr(L, idx);
- api_check(ttisfulluserdata(o), "full userdata expected");
+ api_check(L, ttisfulluserdata(o), "full userdata expected");
getuservalue(L, uvalue(o), L->top);
api_incr_top(L);
lua_unlock(L);
@@ -717,17 +736,29 @@ LUA_API int lua_getuservalue (lua_State *L, int idx) {
** set functions (stack -> Lua)
*/
+/*
+** t[k] = value at the top of the stack (where 'k' is a string)
+*/
+static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
+ const TValue *slot;
+ TString *str = luaS_new(L, k);
+ api_checknelems(L, 1);
+ if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1))
+ L->top--; /* pop value */
+ else {
+ setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
+ api_incr_top(L);
+ luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
+ L->top -= 2; /* pop value and key */
+ }
+ lua_unlock(L); /* lock done by caller */
+}
+
LUA_API void lua_setglobal (lua_State *L, const char *name) {
Table *reg = hvalue(&G(L)->l_registry);
- const TValue *gt; /* global table */
- lua_lock(L);
- api_checknelems(L, 1);
- gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
- setsvalue2s(L, L->top++, luaS_new(L, name));
- luaV_settable(L, gt, L->top - 1, L->top - 2);
- L->top -= 2; /* pop value and key */
- lua_unlock(L);
+ lua_lock(L); /* unlock done in 'auxsetstr' */
+ auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);
}
@@ -743,40 +774,40 @@ LUA_API void lua_settable (lua_State *L, int idx) {
LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
- StkId t;
- lua_lock(L);
- api_checknelems(L, 1);
- t = index2addr(L, idx);
- setsvalue2s(L, L->top++, luaS_new(L, k));
- luaV_settable(L, t, L->top - 1, L->top - 2);
- L->top -= 2; /* pop value and key */
- lua_unlock(L);
+ lua_lock(L); /* unlock done in 'auxsetstr' */
+ auxsetstr(L, index2addr(L, idx), k);
}
LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
StkId t;
+ const TValue *slot;
lua_lock(L);
api_checknelems(L, 1);
t = index2addr(L, idx);
- setivalue(L->top++, n);
- luaV_settable(L, t, L->top - 1, L->top - 2);
- L->top -= 2; /* pop value and key */
+ if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1))
+ L->top--; /* pop value */
+ else {
+ setivalue(L->top, n);
+ api_incr_top(L);
+ luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
+ L->top -= 2; /* pop value and key */
+ }
lua_unlock(L);
}
LUA_API void lua_rawset (lua_State *L, int idx) {
StkId o;
- Table *t;
+ TValue *slot;
lua_lock(L);
api_checknelems(L, 2);
o = index2addr(L, idx);
- api_check(ttistable(o), "table expected");
- t = hvalue(o);
- setobj2t(L, luaH_set(L, t, L->top-2), L->top-1);
- invalidateTMcache(t);
- luaC_barrierback(L, t, L->top-1);
+ api_check(L, ttistable(o), "table expected");
+ slot = luaH_set(L, hvalue(o), L->top - 2);
+ setobj2t(L, slot, L->top - 1);
+ invalidateTMcache(hvalue(o));
+ luaC_barrierback(L, hvalue(o), L->top-1);
L->top -= 2;
lua_unlock(L);
}
@@ -784,14 +815,12 @@ LUA_API void lua_rawset (lua_State *L, int idx) {
LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
StkId o;
- Table *t;
lua_lock(L);
api_checknelems(L, 1);
o = index2addr(L, idx);
- api_check(ttistable(o), "table expected");
- t = hvalue(o);
- luaH_setint(L, t, n, L->top - 1);
- luaC_barrierback(L, t, L->top-1);
+ api_check(L, ttistable(o), "table expected");
+ luaH_setint(L, hvalue(o), n, L->top - 1);
+ luaC_barrierback(L, hvalue(o), L->top-1);
L->top--;
lua_unlock(L);
}
@@ -799,16 +828,15 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
StkId o;
- Table *t;
- TValue k;
+ TValue k, *slot;
lua_lock(L);
api_checknelems(L, 1);
o = index2addr(L, idx);
- api_check(ttistable(o), "table expected");
- t = hvalue(o);
+ api_check(L, ttistable(o), "table expected");
setpvalue(&k, cast(void *, p));
- setobj2t(L, luaH_set(L, t, &k), L->top - 1);
- luaC_barrierback(L, t, L->top - 1);
+ slot = luaH_set(L, hvalue(o), &k);
+ setobj2t(L, slot, L->top - 1);
+ luaC_barrierback(L, hvalue(o), L->top - 1);
L->top--;
lua_unlock(L);
}
@@ -823,7 +851,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
if (ttisnil(L->top - 1))
mt = NULL;
else {
- api_check(ttistable(L->top - 1), "table expected");
+ api_check(L, ttistable(L->top - 1), "table expected");
mt = hvalue(L->top - 1);
}
switch (ttnov(obj)) {
@@ -859,7 +887,7 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 1);
o = index2addr(L, idx);
- api_check(ttisfulluserdata(o), "full userdata expected");
+ api_check(L, ttisfulluserdata(o), "full userdata expected");
setuservalue(L, uvalue(o), L->top - 1);
luaC_barrier(L, gcvalue(o), L->top - 1);
L->top--;
@@ -873,7 +901,7 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) {
#define checkresults(L,na,nr) \
- api_check((nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
+ api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
"results from function overflow current stack size")
@@ -881,19 +909,19 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
lua_KContext ctx, lua_KFunction k) {
StkId func;
lua_lock(L);
- api_check(k == NULL || !isLua(L->ci),
+ api_check(L, k == NULL || !isLua(L->ci),
"cannot use continuations inside hooks");
api_checknelems(L, nargs+1);
- api_check(L->status == LUA_OK, "cannot do calls on non-normal thread");
+ api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults);
func = L->top - (nargs+1);
if (k != NULL && L->nny == 0) { /* need to prepare continuation? */
L->ci->u.c.k = k; /* save continuation */
L->ci->u.c.ctx = ctx; /* save context */
- luaD_call(L, func, nresults, 1); /* do the call */
+ luaD_call(L, func, nresults); /* do the call */
}
else /* no continuation or no yieldable */
- luaD_call(L, func, nresults, 0); /* just do the call */
+ luaD_callnoyield(L, func, nresults); /* just do the call */
adjustresults(L, nresults);
lua_unlock(L);
}
@@ -911,7 +939,7 @@ struct CallS { /* data to 'f_call' */
static void f_call (lua_State *L, void *ud) {
struct CallS *c = cast(struct CallS *, ud);
- luaD_call(L, c->func, c->nresults, 0);
+ luaD_callnoyield(L, c->func, c->nresults);
}
@@ -922,16 +950,16 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
int status;
ptrdiff_t func;
lua_lock(L);
- api_check(k == NULL || !isLua(L->ci),
+ api_check(L, k == NULL || !isLua(L->ci),
"cannot use continuations inside hooks");
api_checknelems(L, nargs+1);
- api_check(L->status == LUA_OK, "cannot do calls on non-normal thread");
+ api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults);
if (errfunc == 0)
func = 0;
else {
StkId o = index2addr(L, errfunc);
- api_checkstackindex(errfunc, o);
+ api_checkstackindex(L, errfunc, o);
func = savestack(L, o);
}
c.func = L->top - (nargs+1); /* function to be called */
@@ -949,7 +977,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
L->errfunc = func;
setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */
ci->callstatus |= CIST_YPCALL; /* function can do error recovery */
- luaD_call(L, c.func, nresults, 1); /* do the call */
+ luaD_call(L, c.func, nresults); /* do the call */
ci->callstatus &= ~CIST_YPCALL;
L->errfunc = ci->u.c.old_errfunc;
status = LUA_OK; /* if it is here, there were no errors */
@@ -1038,7 +1066,7 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
}
case LUA_GCSTEP: {
l_mem debt = 1; /* =1 to signal that it did an actual step */
- int oldrunning = g->gcrunning;
+ lu_byte oldrunning = g->gcrunning;
g->gcrunning = 1; /* allow GC to run */
if (data == 0) {
luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */
@@ -1096,7 +1124,7 @@ LUA_API int lua_next (lua_State *L, int idx) {
int more;
lua_lock(L);
t = index2addr(L, idx);
- api_check(ttistable(t), "table expected");
+ api_check(L, ttistable(t), "table expected");
more = luaH_next(L, hvalue(t), L->top - 1);
if (more) {
api_incr_top(L);
@@ -1112,7 +1140,6 @@ LUA_API void lua_concat (lua_State *L, int n) {
lua_lock(L);
api_checknelems(L, n);
if (n >= 2) {
- luaC_checkGC(L);
luaV_concat(L, n);
}
else if (n == 0) { /* push empty string */
@@ -1120,6 +1147,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
api_incr_top(L);
}
/* else n == 1; nothing to do */
+ luaC_checkGC(L);
lua_unlock(L);
}
@@ -1155,10 +1183,10 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) {
LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
Udata *u;
lua_lock(L);
- luaC_checkGC(L);
u = luaS_newudata(L, size);
setuvalue(L, L->top, u);
api_incr_top(L);
+ luaC_checkGC(L);
lua_unlock(L);
return getudatamem(u);
}
@@ -1228,9 +1256,9 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) {
LClosure *f;
StkId fi = index2addr(L, fidx);
- api_check(ttisLclosure(fi), "Lua function expected");
+ api_check(L, ttisLclosure(fi), "Lua function expected");
f = clLvalue(fi);
- api_check((1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index");
+ api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index");
if (pf) *pf = f;
return &f->upvals[n - 1]; /* get its upvalue pointer */
}
@@ -1244,11 +1272,11 @@ LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) {
}
case LUA_TCCL: { /* C closure */
CClosure *f = clCvalue(fi);
- api_check(1 <= n && n <= f->nupvalues, "invalid upvalue index");
+ api_check(L, 1 <= n && n <= f->nupvalues, "invalid upvalue index");
return &f->upvalue[n - 1];
}
default: {
- api_check(0, "closure expected");
+ api_check(L, 0, "closure expected");
return NULL;
}
}
diff --git a/src/lapi.h b/src/lapi.h
index 092f5e974cb1..6d36dee3fb78 100644
--- a/src/lapi.h
+++ b/src/lapi.h
@@ -1,5 +1,5 @@
/*
-** $Id: lapi.h,v 2.8 2014/07/15 21:26:50 roberto Exp $
+** $Id: lapi.h,v 2.9 2015/03/06 19:49:50 roberto Exp $
** Auxiliary functions from Lua API
** See Copyright Notice in lua.h
*/
@@ -11,13 +11,13 @@
#include "llimits.h"
#include "lstate.h"
-#define api_incr_top(L) {L->top++; api_check(L->top <= L->ci->top, \
+#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
"stack overflow");}
#define adjustresults(L,nres) \
{ if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
-#define api_checknelems(L,n) api_check((n) < (L->top - L->ci->func), \
+#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
"not enough elements in the stack")
diff --git a/src/lauxlib.c b/src/lauxlib.c
index 1c41d6a8eaf4..f7a383663e19 100644
--- a/src/lauxlib.c
+++ b/src/lauxlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lauxlib.c,v 1.279 2014/12/14 18:32:26 roberto Exp $
+** $Id: lauxlib.c,v 1.289 2016/12/20 18:37:00 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -17,7 +17,8 @@
#include <string.h>
-/* This file uses only the official API of Lua.
+/*
+** This file uses only the official API of Lua.
** Any function declared here could be written as an application function.
*/
@@ -33,8 +34,8 @@
*/
-#define LEVELS1 12 /* size of the first part of the stack */
-#define LEVELS2 10 /* size of the second part of the stack */
+#define LEVELS1 10 /* size of the first part of the stack */
+#define LEVELS2 11 /* size of the second part of the stack */
@@ -68,12 +69,11 @@ static int findfield (lua_State *L, int objidx, int level) {
/*
** Search for a name for a function in all loaded modules
-** (registry._LOADED).
*/
static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
int top = lua_gettop(L);
lua_getinfo(L, "f", ar); /* push function */
- lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
+ lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
if (findfield(L, top + 1, 2)) {
const char *name = lua_tostring(L, -1);
if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */
@@ -107,7 +107,7 @@ static void pushfuncname (lua_State *L, lua_Debug *ar) {
}
-static int countlevels (lua_State *L) {
+static int lastlevel (lua_State *L) {
lua_Debug ar;
int li = 1, le = 1;
/* find an upper bound */
@@ -126,14 +126,16 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
const char *msg, int level) {
lua_Debug ar;
int top = lua_gettop(L);
- int numlevels = countlevels(L1);
- int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0;
- if (msg) lua_pushfstring(L, "%s\n", msg);
+ int last = lastlevel(L1);
+ int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1;
+ if (msg)
+ lua_pushfstring(L, "%s\n", msg);
+ luaL_checkstack(L, 10, NULL);
lua_pushliteral(L, "stack traceback:");
while (lua_getstack(L1, level++, &ar)) {
- if (level == mark) { /* too many levels? */
+ if (n1-- == 0) { /* too many levels? */
lua_pushliteral(L, "\n\t..."); /* add a '...' */
- level = numlevels - LEVELS2; /* and skip to last ones */
+ level = last - LEVELS2 + 1; /* and skip to last ones */
}
else {
lua_getinfo(L1, "Slnt", &ar);
@@ -196,6 +198,10 @@ static void tag_error (lua_State *L, int arg, int tag) {
}
+/*
+** The use of 'lua_pushfstring' ensures this function does not
+** need reserved stack space when called.
+*/
LUALIB_API void luaL_where (lua_State *L, int level) {
lua_Debug ar;
if (lua_getstack(L, level, &ar)) { /* check function at level */
@@ -205,10 +211,15 @@ LUALIB_API void luaL_where (lua_State *L, int level) {
return;
}
}
- lua_pushliteral(L, ""); /* else, no information available... */
+ lua_pushfstring(L, ""); /* else, no information available... */
}
+/*
+** Again, the use of 'lua_pushvfstring' ensures this function does
+** not need reserved stack space when called. (At worst, it generates
+** an error with "stack overflow" instead of the given message.)
+*/
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
@@ -286,10 +297,10 @@ LUALIB_API int luaL_execresult (lua_State *L, int stat) {
*/
LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
- if (luaL_getmetatable(L, tname)) /* name already in use? */
+ if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */
return 0; /* leave previous value on top, but return 0 */
lua_pop(L, 1);
- lua_newtable(L); /* create metatable */
+ lua_createtable(L, 0, 2); /* create metatable */
lua_pushstring(L, tname);
lua_setfield(L, -2, "__name"); /* metatable.__name = tname */
lua_pushvalue(L, -1);
@@ -347,10 +358,15 @@ LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def,
}
+/*
+** Ensures the stack has at least 'space' extra slots, raising an error
+** if it cannot fulfill the request. (The error handling needs a few
+** extra slots to format the error message. In case of an error without
+** this extra space, Lua will generate the same 'stack overflow' error,
+** but without 'msg'.)
+*/
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
- /* keep some extra space to run error routines, if needed */
- const int extra = LUA_MINSTACK;
- if (!lua_checkstack(L, space + extra)) {
+ if (!lua_checkstack(L, space)) {
if (msg)
luaL_error(L, "stack overflow (%s)", msg);
else
@@ -435,6 +451,47 @@ LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg,
** =======================================================
*/
+/* userdata to box arbitrary data */
+typedef struct UBox {
+ void *box;
+ size_t bsize;
+} UBox;
+
+
+static void *resizebox (lua_State *L, int idx, size_t newsize) {
+ void *ud;
+ lua_Alloc allocf = lua_getallocf(L, &ud);
+ UBox *box = (UBox *)lua_touserdata(L, idx);
+ void *temp = allocf(ud, box->box, box->bsize, newsize);
+ if (temp == NULL && newsize > 0) { /* allocation error? */
+ resizebox(L, idx, 0); /* free buffer */
+ luaL_error(L, "not enough memory for buffer allocation");
+ }
+ box->box = temp;
+ box->bsize = newsize;
+ return temp;
+}
+
+
+static int boxgc (lua_State *L) {
+ resizebox(L, 1, 0);
+ return 0;
+}
+
+
+static void *newbox (lua_State *L, size_t newsize) {
+ UBox *box = (UBox *)lua_newuserdata(L, sizeof(UBox));
+ box->box = NULL;
+ box->bsize = 0;
+ if (luaL_newmetatable(L, "LUABOX")) { /* creating metatable? */
+ lua_pushcfunction(L, boxgc);
+ lua_setfield(L, -2, "__gc"); /* metatable.__gc = boxgc */
+ }
+ lua_setmetatable(L, -2);
+ return resizebox(L, -1, newsize);
+}
+
+
/*
** check whether buffer is using a userdata on the stack as a temporary
** buffer
@@ -455,11 +512,12 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
if (newsize < B->n || newsize - B->n < sz)
luaL_error(L, "buffer too large");
/* 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 */
+ newbuff = (char *)resizebox(L, -1, newsize);
+ else { /* no buffer yet */
+ newbuff = (char *)newbox(L, newsize);
+ memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */
+ }
B->b = newbuff;
B->size = newsize;
}
@@ -468,9 +526,11 @@ 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 * sizeof(char));
- luaL_addsize(B, l);
+ if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */
+ char *b = luaL_prepbuffsize(B, l);
+ memcpy(b, s, l * sizeof(char));
+ luaL_addsize(B, l);
+ }
}
@@ -482,8 +542,10 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
lua_State *L = B->L;
lua_pushlstring(L, B->b, B->n);
- if (buffonstack(B))
- lua_remove(L, -2); /* remove old buffer */
+ if (buffonstack(B)) {
+ resizebox(L, -2, 0); /* delete old buffer */
+ lua_remove(L, -2); /* remove its header from the stack */
+ }
}
@@ -605,7 +667,7 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
static int skipBOM (LoadF *lf) {
- const char *p = "\xEF\xBB\xBF"; /* Utf8 BOM mark */
+ const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
int c;
lf->n = 0;
do {
@@ -630,7 +692,7 @@ static int skipcomment (LoadF *lf, int *cp) {
if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */
c = getc(lf->f);
- } while (c != EOF && c != '\n') ;
+ } while (c != EOF && c != '\n');
*cp = getc(lf->f); /* skip end-of-line, if present */
return 1; /* there was a comment */
}
@@ -746,13 +808,17 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
- if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */
+ if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */
+ if (!lua_isstring(L, -1))
+ luaL_error(L, "'__tostring' must return a string");
+ }
+ else {
switch (lua_type(L, idx)) {
case LUA_TNUMBER: {
if (lua_isinteger(L, idx))
- lua_pushfstring(L, "%I", lua_tointeger(L, idx));
+ lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx));
else
- lua_pushfstring(L, "%f", lua_tonumber(L, idx));
+ lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx));
break;
}
case LUA_TSTRING:
@@ -764,10 +830,15 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
case LUA_TNIL:
lua_pushliteral(L, "nil");
break;
- default:
- lua_pushfstring(L, "%s: %p", luaL_typename(L, idx),
- lua_topointer(L, idx));
+ default: {
+ int tt = luaL_getmetafield(L, idx, "__name"); /* try name */
+ const char *kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) :
+ luaL_typename(L, idx);
+ lua_pushfstring(L, "%s: %p", kind, lua_topointer(L, idx));
+ if (tt != LUA_TNIL)
+ lua_remove(L, -2); /* remove '__name' */
break;
+ }
}
}
return lua_tolstring(L, -1, len);
@@ -819,23 +890,23 @@ static int libsize (const luaL_Reg *l) {
/*
** Find or create a module table with a given name. The function
-** first looks at the _LOADED table and, if that fails, try a
+** first looks at the LOADED table and, if that fails, try a
** global variable with that name. In any case, leaves on the stack
** the module table.
*/
LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
int sizehint) {
- luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */
- if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no _LOADED[modname]? */
+ luaL_findtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE, 1);
+ if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no LOADED[modname]? */
lua_pop(L, 1); /* remove previous result */
/* try global variable (and create one if it does not exist) */
lua_pushglobaltable(L);
if (luaL_findtable(L, 0, modname, sizehint) != NULL)
luaL_error(L, "name conflict for module '%s'", modname);
lua_pushvalue(L, -1);
- lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */
+ lua_setfield(L, -3, modname); /* LOADED[modname] = new table */
}
- lua_remove(L, -2); /* remove _LOADED table */
+ lua_remove(L, -2); /* remove LOADED table */
}
@@ -899,17 +970,17 @@ LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
*/
LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
lua_CFunction openf, int glb) {
- luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
- lua_getfield(L, -1, modname); /* _LOADED[modname] */
+ luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
+ lua_getfield(L, -1, modname); /* LOADED[modname] */
if (!lua_toboolean(L, -1)) { /* package not already loaded? */
lua_pop(L, 1); /* remove field */
lua_pushcfunction(L, openf);
lua_pushstring(L, modname); /* argument to open function */
lua_call(L, 1, 1); /* call 'openf' to open module */
lua_pushvalue(L, -1); /* make copy of module (call result) */
- lua_setfield(L, -3, modname); /* _LOADED[modname] = module */
+ lua_setfield(L, -3, modname); /* LOADED[modname] = module */
}
- lua_remove(L, -2); /* remove _LOADED table */
+ lua_remove(L, -2); /* remove LOADED table */
if (glb) {
lua_pushvalue(L, -1); /* copy of module */
lua_setglobal(L, modname); /* _G[modname] = module */
@@ -967,6 +1038,6 @@ LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) {
luaL_error(L, "multiple Lua VMs detected");
else if (*v != ver)
luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
- ver, *v);
+ (LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)*v);
}
diff --git a/src/lauxlib.h b/src/lauxlib.h
index 0bac2467ec61..9a2e66aa0670 100644
--- a/src/lauxlib.h
+++ b/src/lauxlib.h
@@ -1,5 +1,5 @@
/*
-** $Id: lauxlib.h,v 1.128 2014/10/29 16:11:17 roberto Exp $
+** $Id: lauxlib.h,v 1.131 2016/12/06 14:54:31 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -16,10 +16,18 @@
-/* extra error code for 'luaL_load' */
+/* extra error code for 'luaL_loadfilex' */
#define LUA_ERRFILE (LUA_ERRERR+1)
+/* key, in the registry, for table of loaded modules */
+#define LUA_LOADED_TABLE "_LOADED"
+
+
+/* key, in the registry, for table of preloaded loaders */
+#define LUA_PRELOAD_TABLE "_PRELOAD"
+
+
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
@@ -65,7 +73,7 @@ LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
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 */
+/* predefined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)
diff --git a/src/lbaselib.c b/src/lbaselib.c
index a2403952f028..08523e6e7540 100644
--- a/src/lbaselib.c
+++ b/src/lbaselib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lbaselib.c,v 1.309 2014/12/10 12:26:42 roberto Exp $
+** $Id: lbaselib.c,v 1.314 2016/09/05 19:06:34 roberto Exp $
** Basic library
** See Copyright Notice in lua.h
*/
@@ -55,7 +55,7 @@ static const char *b_str2int (const char *s, int base, lua_Integer *pn) {
return NULL;
do {
int digit = (isdigit((unsigned char)*s)) ? *s - '0'
- : toupper((unsigned char)*s) - 'A' + 10;
+ : (toupper((unsigned char)*s) - 'A') + 10;
if (digit >= base) return NULL; /* invalid numeral */
n = n * base + digit;
s++;
@@ -86,8 +86,8 @@ static int luaB_tonumber (lua_State *L) {
const char *s;
lua_Integer n = 0; /* to avoid warnings */
lua_Integer base = luaL_checkinteger(L, 2);
- luaL_checktype(L, 1, LUA_TSTRING); /* before 'luaL_checklstring'! */
- s = luaL_checklstring(L, 1, &l);
+ luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */
+ s = lua_tolstring(L, 1, &l);
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
if (b_str2int(s, (int)base, &n) == s + l) {
lua_pushinteger(L, n);
@@ -102,8 +102,8 @@ static int luaB_tonumber (lua_State *L) {
static int luaB_error (lua_State *L) {
int level = (int)luaL_optinteger(L, 2, 1);
lua_settop(L, 1);
- if (lua_isstring(L, 1) && level > 0) { /* add extra information? */
- luaL_where(L, level);
+ if (lua_type(L, 1) == LUA_TSTRING && level > 0) {
+ luaL_where(L, level); /* add extra information */
lua_pushvalue(L, 1);
lua_concat(L, 2);
}
@@ -198,20 +198,18 @@ static int luaB_collectgarbage (lua_State *L) {
}
-/*
-** This function has all type names as upvalues, to maximize performance.
-*/
static int luaB_type (lua_State *L) {
- luaL_checkany(L, 1);
- lua_pushvalue(L, lua_upvalueindex(lua_type(L, 1) + 1));
+ int t = lua_type(L, 1);
+ luaL_argcheck(L, t != LUA_TNONE, 1, "value expected");
+ lua_pushstring(L, lua_typename(L, t));
return 1;
}
static int pairsmeta (lua_State *L, const char *method, int iszero,
lua_CFunction iter) {
+ luaL_checkany(L, 1);
if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */
- luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */
lua_pushcfunction(L, iter); /* will return generator, */
lua_pushvalue(L, 1); /* state, */
if (iszero) lua_pushinteger(L, 0); /* and initial value */
@@ -243,18 +241,7 @@ static int luaB_pairs (lua_State *L) {
/*
-** Traversal function for 'ipairs' for raw tables
-*/
-static int ipairsaux_raw (lua_State *L) {
- lua_Integer i = luaL_checkinteger(L, 2) + 1;
- luaL_checktype(L, 1, LUA_TTABLE);
- lua_pushinteger(L, i);
- return (lua_rawgeti(L, 1, i) == LUA_TNIL) ? 1 : 2;
-}
-
-
-/*
-** Traversal function for 'ipairs' for tables with metamethods
+** Traversal function for 'ipairs'
*/
static int ipairsaux (lua_State *L) {
lua_Integer i = luaL_checkinteger(L, 2) + 1;
@@ -264,18 +251,15 @@ static int ipairsaux (lua_State *L) {
/*
-** This function will use either 'ipairsaux' or 'ipairsaux_raw' to
-** traverse a table, depending on whether the table has metamethods
-** that can affect the traversal.
+** 'ipairs' function. Returns 'ipairsaux', given "table", 0.
+** (The given "table" may not be a table.)
*/
static int luaB_ipairs (lua_State *L) {
- lua_CFunction iter = (luaL_getmetafield(L, 1, "__index") != LUA_TNIL)
- ? ipairsaux : ipairsaux_raw;
#if defined(LUA_COMPAT_IPAIRS)
- return pairsmeta(L, "__ipairs", 1, iter);
+ return pairsmeta(L, "__ipairs", 1, ipairsaux);
#else
luaL_checkany(L, 1);
- lua_pushcfunction(L, iter); /* iteration function */
+ lua_pushcfunction(L, ipairsaux); /* iteration function */
lua_pushvalue(L, 1); /* state */
lua_pushinteger(L, 0); /* initial value */
return 3;
@@ -490,9 +474,9 @@ static const luaL_Reg base_funcs[] = {
{"setmetatable", luaB_setmetatable},
{"tonumber", luaB_tonumber},
{"tostring", luaB_tostring},
+ {"type", luaB_type},
{"xpcall", luaB_xpcall},
/* placeholders */
- {"type", NULL},
{"_G", NULL},
{"_VERSION", NULL},
{NULL, NULL}
@@ -500,7 +484,6 @@ static const luaL_Reg base_funcs[] = {
LUAMOD_API int luaopen_base (lua_State *L) {
- int i;
/* open lib into global table */
lua_pushglobaltable(L);
luaL_setfuncs(L, base_funcs, 0);
@@ -510,11 +493,6 @@ LUAMOD_API int luaopen_base (lua_State *L) {
/* set global _VERSION */
lua_pushliteral(L, LUA_VERSION);
lua_setfield(L, -2, "_VERSION");
- /* set function 'type' with proper upvalues */
- for (i = 0; i < LUA_NUMTAGS; i++) /* push all type names as upvalues */
- lua_pushstring(L, lua_typename(L, i));
- lua_pushcclosure(L, luaB_type, LUA_NUMTAGS);
- lua_setfield(L, -2, "type");
return 1;
}
diff --git a/src/lbitlib.c b/src/lbitlib.c
index 15d5f0cdfc40..1cb1d5b93238 100644
--- a/src/lbitlib.c
+++ b/src/lbitlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lbitlib.c,v 1.28 2014/11/02 19:19:04 roberto Exp $
+** $Id: lbitlib.c,v 1.30 2015/11/11 19:08:09 roberto Exp $
** Standard library for bitwise operations
** See Copyright Notice in lua.h
*/
@@ -19,6 +19,10 @@
#if defined(LUA_COMPAT_BITLIB) /* { */
+#define pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n))
+#define checkunsigned(L,i) ((lua_Unsigned)luaL_checkinteger(L,i))
+
+
/* number of bits to consider in a number */
#if !defined(LUA_NBITS)
#define LUA_NBITS 32
@@ -46,14 +50,14 @@ static lua_Unsigned andaux (lua_State *L) {
int i, n = lua_gettop(L);
lua_Unsigned r = ~(lua_Unsigned)0;
for (i = 1; i <= n; i++)
- r &= luaL_checkunsigned(L, i);
+ r &= checkunsigned(L, i);
return trim(r);
}
static int b_and (lua_State *L) {
lua_Unsigned r = andaux(L);
- lua_pushunsigned(L, r);
+ pushunsigned(L, r);
return 1;
}
@@ -69,8 +73,8 @@ static int b_or (lua_State *L) {
int i, n = lua_gettop(L);
lua_Unsigned r = 0;
for (i = 1; i <= n; i++)
- r |= luaL_checkunsigned(L, i);
- lua_pushunsigned(L, trim(r));
+ r |= checkunsigned(L, i);
+ pushunsigned(L, trim(r));
return 1;
}
@@ -79,15 +83,15 @@ static int b_xor (lua_State *L) {
int i, n = lua_gettop(L);
lua_Unsigned r = 0;
for (i = 1; i <= n; i++)
- r ^= luaL_checkunsigned(L, i);
- lua_pushunsigned(L, trim(r));
+ r ^= checkunsigned(L, i);
+ pushunsigned(L, trim(r));
return 1;
}
static int b_not (lua_State *L) {
- lua_Unsigned r = ~luaL_checkunsigned(L, 1);
- lua_pushunsigned(L, trim(r));
+ lua_Unsigned r = ~checkunsigned(L, 1);
+ pushunsigned(L, trim(r));
return 1;
}
@@ -104,23 +108,23 @@ static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) {
else r <<= i;
r = trim(r);
}
- lua_pushunsigned(L, r);
+ pushunsigned(L, r);
return 1;
}
static int b_lshift (lua_State *L) {
- return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkinteger(L, 2));
+ return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2));
}
static int b_rshift (lua_State *L) {
- return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkinteger(L, 2));
+ return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2));
}
static int b_arshift (lua_State *L) {
- lua_Unsigned r = luaL_checkunsigned(L, 1);
+ lua_Unsigned r = checkunsigned(L, 1);
lua_Integer i = luaL_checkinteger(L, 2);
if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1))))
return b_shift(L, r, -i);
@@ -128,19 +132,19 @@ static int b_arshift (lua_State *L) {
if (i >= LUA_NBITS) r = ALLONES;
else
r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */
- lua_pushunsigned(L, r);
+ pushunsigned(L, r);
return 1;
}
}
static int b_rot (lua_State *L, lua_Integer d) {
- lua_Unsigned r = luaL_checkunsigned(L, 1);
+ lua_Unsigned r = checkunsigned(L, 1);
int i = d & (LUA_NBITS - 1); /* i = d % NBITS */
r = trim(r);
if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */
r = (r << i) | (r >> (LUA_NBITS - i));
- lua_pushunsigned(L, trim(r));
+ pushunsigned(L, trim(r));
return 1;
}
@@ -175,23 +179,22 @@ static int fieldargs (lua_State *L, int farg, int *width) {
static int b_extract (lua_State *L) {
int w;
- lua_Unsigned r = trim(luaL_checkunsigned(L, 1));
+ lua_Unsigned r = trim(checkunsigned(L, 1));
int f = fieldargs(L, 2, &w);
r = (r >> f) & mask(w);
- lua_pushunsigned(L, r);
+ pushunsigned(L, r);
return 1;
}
static int b_replace (lua_State *L) {
int w;
- lua_Unsigned r = trim(luaL_checkunsigned(L, 1));
- lua_Unsigned v = luaL_checkunsigned(L, 2);
+ lua_Unsigned r = trim(checkunsigned(L, 1));
+ lua_Unsigned v = trim(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);
+ lua_Unsigned m = mask(w);
+ r = (r & ~(m << f)) | ((v & m) << f);
+ pushunsigned(L, r);
return 1;
}
diff --git a/src/lcode.c b/src/lcode.c
index 5e34624bf462..0bb414262e3c 100644
--- a/src/lcode.c
+++ b/src/lcode.c
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.c,v 2.99 2014/12/29 16:49:25 roberto Exp $
+** $Id: lcode.c,v 2.112 2016/12/22 13:08:50 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -29,15 +29,19 @@
#include "lvm.h"
-/* Maximum number of registers in a Lua function */
-#define MAXREGS 250
+/* Maximum number of registers in a Lua function (must fit in 8 bits) */
+#define MAXREGS 255
#define hasjumps(e) ((e)->t != (e)->f)
-static int tonumeral(expdesc *e, TValue *v) {
- if (e->t != NO_JUMP || e->f != NO_JUMP)
+/*
+** If expression is a numeric constant, fills 'v' with its value
+** and returns 1. Otherwise, returns 0.
+*/
+static int tonumeral(const expdesc *e, TValue *v) {
+ if (hasjumps(e))
return 0; /* not a numeral */
switch (e->k) {
case VKINT:
@@ -51,13 +55,19 @@ static int tonumeral(expdesc *e, TValue *v) {
}
+/*
+** Create a OP_LOADNIL instruction, but try to optimize: if the previous
+** instruction is also OP_LOADNIL and ranges are compatible, adjust
+** range of previous instruction instead of emitting a new one. (For
+** instance, 'local a; local b' will generate a single opcode.)
+*/
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);
+ if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */
+ int pfrom = GETARG_A(*previous); /* get previous range */
int pl = pfrom + GETARG_B(*previous);
if ((pfrom <= from && from <= pl + 1) ||
(from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
@@ -73,37 +83,84 @@ void luaK_nil (FuncState *fs, int from, int n) {
}
+/*
+** Gets the destination address of a jump instruction. Used to traverse
+** a list of jumps.
+*/
+static int getjump (FuncState *fs, int pc) {
+ int offset = GETARG_sBx(fs->f->code[pc]);
+ if (offset == NO_JUMP) /* point to itself represents end of list */
+ return NO_JUMP; /* end of list */
+ else
+ return (pc+1)+offset; /* turn offset into absolute position */
+}
+
+
+/*
+** Fix jump instruction at position 'pc' to jump to 'dest'.
+** (Jump addresses are relative in Lua)
+*/
+static void fixjump (FuncState *fs, int pc, int dest) {
+ Instruction *jmp = &fs->f->code[pc];
+ int offset = dest - (pc + 1);
+ lua_assert(dest != NO_JUMP);
+ if (abs(offset) > MAXARG_sBx)
+ luaX_syntaxerror(fs->ls, "control structure too long");
+ SETARG_sBx(*jmp, offset);
+}
+
+
+/*
+** Concatenate jump-list 'l2' into jump-list 'l1'
+*/
+void luaK_concat (FuncState *fs, int *l1, int l2) {
+ if (l2 == NO_JUMP) return; /* nothing to concatenate? */
+ else if (*l1 == NO_JUMP) /* no original list? */
+ *l1 = l2; /* 'l1' points to 'l2' */
+ else {
+ int list = *l1;
+ int next;
+ while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */
+ list = next;
+ fixjump(fs, list, l2); /* last element links to 'l2' */
+ }
+}
+
+
+/*
+** Create a jump instruction and return its position, so its destination
+** can be fixed later (with 'fixjump'). If there are jumps to
+** this position (kept in 'jpc'), link them all together so that
+** 'patchlistaux' will fix all them directly to the final destination.
+*/
int luaK_jump (FuncState *fs) {
int jpc = fs->jpc; /* save list of jumps to here */
int j;
- fs->jpc = NO_JUMP;
+ fs->jpc = NO_JUMP; /* no more jumps to here */
j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
luaK_concat(fs, &j, jpc); /* keep them on hold */
return j;
}
+/*
+** Code a 'return' instruction
+*/
void luaK_ret (FuncState *fs, int first, int nret) {
luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
}
+/*
+** Code a "conditional jump", that is, a test or comparison opcode
+** followed by a jump. Return jump position.
+*/
static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
luaK_codeABC(fs, op, A, B, C);
return luaK_jump(fs);
}
-static void fixjump (FuncState *fs, int pc, int dest) {
- Instruction *jmp = &fs->f->code[pc];
- int offset = dest-(pc+1);
- lua_assert(dest != NO_JUMP);
- if (abs(offset) > MAXARG_sBx)
- luaX_syntaxerror(fs->ls, "control structure too long");
- SETARG_sBx(*jmp, offset);
-}
-
-
/*
** returns current 'pc' and marks it as a jump target (to avoid wrong
** optimizations with consecutive instructions not in the same basic block).
@@ -114,15 +171,11 @@ int luaK_getlabel (FuncState *fs) {
}
-static int getjump (FuncState *fs, int pc) {
- int offset = GETARG_sBx(fs->f->code[pc]);
- if (offset == NO_JUMP) /* point to itself represents end of list */
- return NO_JUMP; /* end of list */
- else
- return (pc+1)+offset; /* turn offset into absolute position */
-}
-
-
+/*
+** Returns the position of the instruction "controlling" a given
+** jump (that is, its condition), or the jump itself if it is
+** unconditional.
+*/
static Instruction *getjumpcontrol (FuncState *fs, int pc) {
Instruction *pi = &fs->f->code[pc];
if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
@@ -133,37 +186,41 @@ static Instruction *getjumpcontrol (FuncState *fs, int pc) {
/*
-** check whether list has any jump that do not produce a value
-** (or produce an inverted value)
+** Patch destination register for a TESTSET instruction.
+** If instruction in position 'node' is not a TESTSET, return 0 ("fails").
+** Otherwise, if 'reg' is not 'NO_REG', set it as the destination
+** register. Otherwise, change instruction to a simple 'TEST' (produces
+** no register value)
*/
-static int need_value (FuncState *fs, int list) {
- for (; list != NO_JUMP; list = getjump(fs, list)) {
- Instruction i = *getjumpcontrol(fs, list);
- if (GET_OPCODE(i) != OP_TESTSET) return 1;
- }
- return 0; /* not found */
-}
-
-
static int patchtestreg (FuncState *fs, int node, int reg) {
Instruction *i = getjumpcontrol(fs, node);
if (GET_OPCODE(*i) != OP_TESTSET)
return 0; /* cannot patch other instructions */
if (reg != NO_REG && reg != GETARG_B(*i))
SETARG_A(*i, reg);
- else /* no register to put value or register already has the value */
+ else {
+ /* no register to put value or register already has the value;
+ change instruction to simple test */
*i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
-
+ }
return 1;
}
+/*
+** Traverse a list of tests ensuring no one produces a value
+*/
static void removevalues (FuncState *fs, int list) {
for (; list != NO_JUMP; list = getjump(fs, list))
patchtestreg(fs, list, NO_REG);
}
+/*
+** Traverse a list of tests, patching their destination address and
+** registers: tests producing values jump to 'vtarget' (and put their
+** values in 'reg'), other tests jump to 'dtarget'.
+*/
static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
int dtarget) {
while (list != NO_JUMP) {
@@ -177,15 +234,35 @@ static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
}
+/*
+** Ensure all pending jumps to current position are fixed (jumping
+** to current position with no values) and reset list of pending
+** jumps
+*/
static void dischargejpc (FuncState *fs) {
patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
fs->jpc = NO_JUMP;
}
+/*
+** Add elements in 'list' to list of pending jumps to "here"
+** (current position)
+*/
+void luaK_patchtohere (FuncState *fs, int list) {
+ luaK_getlabel(fs); /* mark "here" as a jump target */
+ luaK_concat(fs, &fs->jpc, list);
+}
+
+
+/*
+** Path all jumps in 'list' to jump to 'target'.
+** (The assert means that we cannot fix a jump to a forward address
+** because we only know addresses once code is generated.)
+*/
void luaK_patchlist (FuncState *fs, int list, int target) {
- if (target == fs->pc)
- luaK_patchtohere(fs, list);
+ if (target == fs->pc) /* 'target' is current position? */
+ luaK_patchtohere(fs, list); /* add list to pending jumps */
else {
lua_assert(target < fs->pc);
patchlistaux(fs, list, target, NO_REG, target);
@@ -193,39 +270,26 @@ void luaK_patchlist (FuncState *fs, int list, int target) {
}
+/*
+** Path all jumps in 'list' to close upvalues up to given 'level'
+** (The assertion checks that jumps either were closing nothing
+** or were closing higher levels, from inner blocks.)
+*/
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);
+ for (; list != NO_JUMP; list = 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);
-}
-
-
-void luaK_concat (FuncState *fs, int *l1, int l2) {
- if (l2 == NO_JUMP) return;
- else if (*l1 == NO_JUMP)
- *l1 = l2;
- else {
- int list = *l1;
- int next;
- while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */
- list = next;
- fixjump(fs, list, l2);
}
}
+/*
+** Emit instruction 'i', checking for array sizes and saving also its
+** line information. Return 'i' position.
+*/
static int luaK_code (FuncState *fs, Instruction i) {
Proto *f = fs->f;
dischargejpc(fs); /* 'pc' will change */
@@ -241,6 +305,10 @@ static int luaK_code (FuncState *fs, Instruction i) {
}
+/*
+** Format and emit an 'iABC' instruction. (Assertions check consistency
+** of parameters versus opcode.)
+*/
int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
lua_assert(getOpMode(o) == iABC);
lua_assert(getBMode(o) != OpArgN || b == 0);
@@ -250,6 +318,9 @@ int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
}
+/*
+** Format and emit an 'iABx' instruction.
+*/
int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
lua_assert(getCMode(o) == OpArgN);
@@ -258,12 +329,20 @@ int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
}
+/*
+** Emit an "extra argument" instruction (format 'iAx')
+*/
static int codeextraarg (FuncState *fs, int a) {
lua_assert(a <= MAXARG_Ax);
return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a));
}
+/*
+** Emit a "load constant" instruction, using either 'OP_LOADK'
+** (if constant index 'k' fits in 18 bits) or an 'OP_LOADKX'
+** instruction with "extra argument".
+*/
int luaK_codek (FuncState *fs, int reg, int k) {
if (k <= MAXARG_Bx)
return luaK_codeABx(fs, OP_LOADK, reg, k);
@@ -275,22 +354,35 @@ int luaK_codek (FuncState *fs, int reg, int k) {
}
+/*
+** Check register-stack level, keeping track of its maximum size
+** in field 'maxstacksize'
+*/
void luaK_checkstack (FuncState *fs, int n) {
int newstack = fs->freereg + n;
if (newstack > fs->f->maxstacksize) {
if (newstack >= MAXREGS)
- luaX_syntaxerror(fs->ls, "function or expression too complex");
+ luaX_syntaxerror(fs->ls,
+ "function or expression needs too many registers");
fs->f->maxstacksize = cast_byte(newstack);
}
}
+/*
+** Reserve 'n' registers in register stack
+*/
void luaK_reserveregs (FuncState *fs, int n) {
luaK_checkstack(fs, n);
fs->freereg += n;
}
+/*
+** Free register 'reg', if it is neither a constant index nor
+** a local variable.
+)
+*/
static void freereg (FuncState *fs, int reg) {
if (!ISK(reg) && reg >= fs->nactvar) {
fs->freereg--;
@@ -299,6 +391,9 @@ static void freereg (FuncState *fs, int reg) {
}
+/*
+** Free register used by expression 'e' (if any)
+*/
static void freeexp (FuncState *fs, expdesc *e) {
if (e->k == VNONRELOC)
freereg(fs, e->u.info);
@@ -306,8 +401,29 @@ static void freeexp (FuncState *fs, expdesc *e) {
/*
+** Free registers used by expressions 'e1' and 'e2' (if any) in proper
+** order.
+*/
+static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) {
+ int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1;
+ int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1;
+ if (r1 > r2) {
+ freereg(fs, r1);
+ freereg(fs, r2);
+ }
+ else {
+ freereg(fs, r2);
+ freereg(fs, r1);
+ }
+}
+
+
+/*
+** Add constant 'v' to prototype's list of constants (field 'k').
** Use scanner's table to cache position of constants in constant list
-** and try to reuse constants
+** and try to reuse constants. Because some values should not be used
+** as keys (nil cannot be a key, integer keys can collapse with float
+** keys), the caller must provide a useful 'key' for indexing the cache.
*/
static int addk (FuncState *fs, TValue *key, TValue *v) {
lua_State *L = fs->ls->L;
@@ -336,17 +452,21 @@ static int addk (FuncState *fs, TValue *key, TValue *v) {
}
+/*
+** Add a string to list of constants and return its index.
+*/
int luaK_stringK (FuncState *fs, TString *s) {
TValue o;
setsvalue(fs->ls->L, &o, s);
- return addk(fs, &o, &o);
+ return addk(fs, &o, &o); /* use string itself as key */
}
/*
-** Integers use userdata as keys to avoid collision with floats with same
-** value; conversion to 'void*' used only for hashing, no "precision"
-** problems
+** Add an integer to list of constants and return its index.
+** Integers use userdata as keys to avoid collision with floats with
+** same value; conversion to 'void*' is used only for hashing, so there
+** are no "precision" problems.
*/
int luaK_intK (FuncState *fs, lua_Integer n) {
TValue k, o;
@@ -355,21 +475,29 @@ int luaK_intK (FuncState *fs, lua_Integer n) {
return addk(fs, &k, &o);
}
-
+/*
+** Add a float to list of constants and return its index.
+*/
static int luaK_numberK (FuncState *fs, lua_Number r) {
TValue o;
setfltvalue(&o, r);
- return addk(fs, &o, &o);
+ return addk(fs, &o, &o); /* use number itself as key */
}
+/*
+** Add a boolean to list of constants and return its index.
+*/
static int boolK (FuncState *fs, int b) {
TValue o;
setbvalue(&o, b);
- return addk(fs, &o, &o);
+ return addk(fs, &o, &o); /* use boolean itself as key */
}
+/*
+** Add nil to list of constants and return its index.
+*/
static int nilK (FuncState *fs) {
TValue k, v;
setnilvalue(&v);
@@ -379,54 +507,79 @@ static int nilK (FuncState *fs) {
}
+/*
+** Fix an expression to return the number of results 'nresults'.
+** Either 'e' is a multi-ret expression (function call or vararg)
+** or 'nresults' is LUA_MULTRET (as any expression can satisfy that).
+*/
void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
if (e->k == VCALL) { /* expression is an open function call? */
- SETARG_C(getcode(fs, e), nresults+1);
+ SETARG_C(getinstruction(fs, e), nresults + 1);
}
else if (e->k == VVARARG) {
- SETARG_B(getcode(fs, e), nresults+1);
- SETARG_A(getcode(fs, e), fs->freereg);
+ Instruction *pc = &getinstruction(fs, e);
+ SETARG_B(*pc, nresults + 1);
+ SETARG_A(*pc, fs->freereg);
luaK_reserveregs(fs, 1);
}
+ else lua_assert(nresults == LUA_MULTRET);
}
+/*
+** Fix an expression to return one result.
+** If expression is not a multi-ret expression (function call or
+** vararg), it already returns one result, so nothing needs to be done.
+** Function calls become VNONRELOC expressions (as its result comes
+** fixed in the base register of the call), while vararg expressions
+** become VRELOCABLE (as OP_VARARG puts its results where it wants).
+** (Calls are created returning one result, so that does not need
+** to be fixed.)
+*/
void luaK_setoneret (FuncState *fs, expdesc *e) {
if (e->k == VCALL) { /* expression is an open function call? */
- e->k = VNONRELOC;
- e->u.info = GETARG_A(getcode(fs, e));
+ /* already returns 1 value */
+ lua_assert(GETARG_C(getinstruction(fs, e)) == 2);
+ e->k = VNONRELOC; /* result has fixed position */
+ e->u.info = GETARG_A(getinstruction(fs, e));
}
else if (e->k == VVARARG) {
- SETARG_B(getcode(fs, e), 2);
+ SETARG_B(getinstruction(fs, e), 2);
e->k = VRELOCABLE; /* can relocate its simple result */
}
}
+/*
+** Ensure that expression 'e' is not a variable.
+*/
void luaK_dischargevars (FuncState *fs, expdesc *e) {
switch (e->k) {
- case VLOCAL: {
- e->k = VNONRELOC;
+ case VLOCAL: { /* already in a register */
+ e->k = VNONRELOC; /* becomes a non-relocatable value */
break;
}
- case VUPVAL: {
+ case VUPVAL: { /* move value to some (pending) register */
e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
e->k = VRELOCABLE;
break;
}
case VINDEXED: {
- OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */
+ OpCode op;
freereg(fs, e->u.ind.idx);
- if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */
+ if (e->u.ind.vt == VLOCAL) { /* is 't' in a register? */
freereg(fs, e->u.ind.t);
op = OP_GETTABLE;
}
+ else {
+ lua_assert(e->u.ind.vt == VUPVAL);
+ op = OP_GETTABUP; /* 't' is in an upvalue */
+ }
e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
e->k = VRELOCABLE;
break;
}
- case VVARARG:
- case VCALL: {
+ case VVARARG: case VCALL: {
luaK_setoneret(fs, e);
break;
}
@@ -435,12 +588,10 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
}
-static int code_label (FuncState *fs, int A, int b, int jump) {
- luaK_getlabel(fs); /* those instructions may be jump targets */
- return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
-}
-
-
+/*
+** Ensures expression value is in register 'reg' (and therefore
+** 'e' will become a non-relocatable expression).
+*/
static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
luaK_dischargevars(fs, e);
switch (e->k) {
@@ -465,8 +616,8 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
break;
}
case VRELOCABLE: {
- Instruction *pc = &getcode(fs, e);
- SETARG_A(*pc, reg);
+ Instruction *pc = &getinstruction(fs, e);
+ SETARG_A(*pc, reg); /* instruction will put result in 'reg' */
break;
}
case VNONRELOC: {
@@ -475,7 +626,7 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
break;
}
default: {
- lua_assert(e->k == VVOID || e->k == VJMP);
+ lua_assert(e->k == VJMP);
return; /* nothing to do... */
}
}
@@ -484,17 +635,46 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
}
+/*
+** Ensures expression value is in any register.
+*/
static void discharge2anyreg (FuncState *fs, expdesc *e) {
- if (e->k != VNONRELOC) {
- luaK_reserveregs(fs, 1);
- discharge2reg(fs, e, fs->freereg-1);
+ if (e->k != VNONRELOC) { /* no fixed register yet? */
+ luaK_reserveregs(fs, 1); /* get a register */
+ discharge2reg(fs, e, fs->freereg-1); /* put value there */
}
}
+static int code_loadbool (FuncState *fs, int A, int b, int jump) {
+ luaK_getlabel(fs); /* those instructions may be jump targets */
+ return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
+}
+
+
+/*
+** check whether list has any jump that do not produce a value
+** or produce an inverted value
+*/
+static int need_value (FuncState *fs, int list) {
+ for (; list != NO_JUMP; list = getjump(fs, list)) {
+ Instruction i = *getjumpcontrol(fs, list);
+ if (GET_OPCODE(i) != OP_TESTSET) return 1;
+ }
+ return 0; /* not found */
+}
+
+
+/*
+** Ensures final expression result (including results from its jump
+** lists) is in register 'reg'.
+** If expression has jumps, need to patch these jumps either to
+** its final position or to "load" instructions (for those tests
+** that do not produce values).
+*/
static void exp2reg (FuncState *fs, expdesc *e, int reg) {
discharge2reg(fs, e, reg);
- if (e->k == VJMP)
+ if (e->k == VJMP) /* expression itself is a test? */
luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */
if (hasjumps(e)) {
int final; /* position after whole expression */
@@ -502,8 +682,8 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) {
int p_t = NO_JUMP; /* position of an eventual LOAD true */
if (need_value(fs, e->t) || need_value(fs, e->f)) {
int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
- p_f = code_label(fs, reg, 0, 1);
- p_t = code_label(fs, reg, 1, 0);
+ p_f = code_loadbool(fs, reg, 0, 1);
+ p_t = code_loadbool(fs, reg, 1, 0);
luaK_patchtohere(fs, fj);
}
final = luaK_getlabel(fs);
@@ -516,6 +696,10 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) {
}
+/*
+** Ensures final expression result (including results from its jump
+** lists) is in next available register.
+*/
void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e);
freeexp(fs, e);
@@ -524,26 +708,39 @@ void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
}
+/*
+** Ensures final expression result (including results from its jump
+** lists) is in some (any) register and return that register.
+*/
int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e);
- if (e->k == VNONRELOC) {
- if (!hasjumps(e)) return e->u.info; /* exp is already in a register */
+ if (e->k == VNONRELOC) { /* expression already has a register? */
+ if (!hasjumps(e)) /* no jumps? */
+ return e->u.info; /* result is already in a register */
if (e->u.info >= fs->nactvar) { /* reg. is not a local? */
- exp2reg(fs, e, e->u.info); /* put value on it */
+ exp2reg(fs, e, e->u.info); /* put final result in it */
return e->u.info;
}
}
- luaK_exp2nextreg(fs, e); /* default */
+ luaK_exp2nextreg(fs, e); /* otherwise, use next available register */
return e->u.info;
}
+/*
+** Ensures final expression result is either in a register or in an
+** upvalue.
+*/
void luaK_exp2anyregup (FuncState *fs, expdesc *e) {
if (e->k != VUPVAL || hasjumps(e))
luaK_exp2anyreg(fs, e);
}
+/*
+** Ensures final expression result is either in a register or it is
+** a constant.
+*/
void luaK_exp2val (FuncState *fs, expdesc *e) {
if (hasjumps(e))
luaK_exp2anyreg(fs, e);
@@ -552,35 +749,26 @@ void luaK_exp2val (FuncState *fs, expdesc *e) {
}
+/*
+** Ensures final expression result is in a valid R/K index
+** (that is, it is either in a register or in 'k' with an index
+** in the range of R/K indices).
+** Returns R/K index.
+*/
int luaK_exp2RK (FuncState *fs, expdesc *e) {
luaK_exp2val(fs, e);
- switch (e->k) {
- case VTRUE:
- case VFALSE:
- case VNIL: {
- if (fs->nk <= MAXINDEXRK) { /* constant fits in RK operand? */
- e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE));
- e->k = VK;
- return RKASK(e->u.info);
- }
- else break;
- }
- case VKINT: {
- e->u.info = luaK_intK(fs, e->u.ival);
- e->k = VK;
- goto vk;
- }
- case VKFLT: {
- e->u.info = luaK_numberK(fs, e->u.nval);
- e->k = VK;
- /* go through */
- }
- case VK: {
+ switch (e->k) { /* move constants to 'k' */
+ case VTRUE: e->u.info = boolK(fs, 1); goto vk;
+ case VFALSE: e->u.info = boolK(fs, 0); goto vk;
+ case VNIL: e->u.info = nilK(fs); goto vk;
+ case VKINT: e->u.info = luaK_intK(fs, e->u.ival); goto vk;
+ case VKFLT: e->u.info = luaK_numberK(fs, e->u.nval); goto vk;
+ case VK:
vk:
+ e->k = VK;
if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */
return RKASK(e->u.info);
else break;
- }
default: break;
}
/* not a constant in the right range: put it in a register */
@@ -588,11 +776,14 @@ int luaK_exp2RK (FuncState *fs, expdesc *e) {
}
+/*
+** Generate code to store result of expression 'ex' into variable 'var'.
+*/
void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
switch (var->k) {
case VLOCAL: {
freeexp(fs, ex);
- exp2reg(fs, ex, var->u.info);
+ exp2reg(fs, ex, var->u.info); /* compute 'ex' into proper place */
return;
}
case VUPVAL: {
@@ -606,29 +797,32 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
break;
}
- default: {
- lua_assert(0); /* invalid var kind to store */
- break;
- }
+ default: lua_assert(0); /* invalid var kind to store */
}
freeexp(fs, ex);
}
+/*
+** Emit SELF instruction (convert expression 'e' into 'e:key(e,').
+*/
void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
int ereg;
luaK_exp2anyreg(fs, e);
ereg = e->u.info; /* register where 'e' was placed */
freeexp(fs, e);
e->u.info = fs->freereg; /* base register for op_self */
- e->k = VNONRELOC;
+ e->k = VNONRELOC; /* self expression has a fixed register */
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);
}
-static void invertjump (FuncState *fs, expdesc *e) {
+/*
+** Negate condition 'e' (where 'e' is a comparison).
+*/
+static void negatecondition (FuncState *fs, expdesc *e) {
Instruction *pc = getjumpcontrol(fs, e->u.info);
lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
GET_OPCODE(*pc) != OP_TEST);
@@ -636,9 +830,15 @@ static void invertjump (FuncState *fs, expdesc *e) {
}
+/*
+** Emit instruction to jump if 'e' is 'cond' (that is, if 'cond'
+** is true, code will jump if 'e' is true.) Return jump position.
+** Optimize when 'e' is 'not' something, inverting the condition
+** and removing the 'not'.
+*/
static int jumponcond (FuncState *fs, expdesc *e, int cond) {
if (e->k == VRELOCABLE) {
- Instruction ie = getcode(fs, e);
+ Instruction ie = getinstruction(fs, e);
if (GET_OPCODE(ie) == OP_NOT) {
fs->pc--; /* remove previous OP_NOT */
return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
@@ -651,13 +851,16 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) {
}
+/*
+** Emit code to go through if 'e' is true, jump otherwise.
+*/
void luaK_goiftrue (FuncState *fs, expdesc *e) {
- int pc; /* pc of last jump */
+ int pc; /* pc of new jump */
luaK_dischargevars(fs, e);
switch (e->k) {
- case VJMP: {
- invertjump(fs, e);
- pc = e->u.info;
+ case VJMP: { /* condition? */
+ negatecondition(fs, e); /* jump when it is false */
+ pc = e->u.info; /* save jump position */
break;
}
case VK: case VKFLT: case VKINT: case VTRUE: {
@@ -665,22 +868,25 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
break;
}
default: {
- pc = jumponcond(fs, e, 0);
+ pc = jumponcond(fs, e, 0); /* jump when false */
break;
}
}
- luaK_concat(fs, &e->f, pc); /* insert last jump in 'f' list */
- luaK_patchtohere(fs, e->t);
+ luaK_concat(fs, &e->f, pc); /* insert new jump in false list */
+ luaK_patchtohere(fs, e->t); /* true list jumps to here (to go through) */
e->t = NO_JUMP;
}
+/*
+** Emit code to go through if 'e' is false, jump otherwise.
+*/
void luaK_goiffalse (FuncState *fs, expdesc *e) {
- int pc; /* pc of last jump */
+ int pc; /* pc of new jump */
luaK_dischargevars(fs, e);
switch (e->k) {
case VJMP: {
- pc = e->u.info;
+ pc = e->u.info; /* already jump if true */
break;
}
case VNIL: case VFALSE: {
@@ -688,29 +894,32 @@ void luaK_goiffalse (FuncState *fs, expdesc *e) {
break;
}
default: {
- pc = jumponcond(fs, e, 1);
+ pc = jumponcond(fs, e, 1); /* jump if true */
break;
}
}
- luaK_concat(fs, &e->t, pc); /* insert last jump in 't' list */
- luaK_patchtohere(fs, e->f);
+ luaK_concat(fs, &e->t, pc); /* insert new jump in 't' list */
+ luaK_patchtohere(fs, e->f); /* false list jumps to here (to go through) */
e->f = NO_JUMP;
}
+/*
+** Code 'not e', doing constant folding.
+*/
static void codenot (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e);
switch (e->k) {
case VNIL: case VFALSE: {
- e->k = VTRUE;
+ e->k = VTRUE; /* true == not nil == not false */
break;
}
case VK: case VKFLT: case VKINT: case VTRUE: {
- e->k = VFALSE;
+ e->k = VFALSE; /* false == not "x" == not 0.5 == not 1 == not true */
break;
}
case VJMP: {
- invertjump(fs, e);
+ negatecondition(fs, e);
break;
}
case VRELOCABLE:
@@ -721,30 +930,32 @@ static void codenot (FuncState *fs, expdesc *e) {
e->k = VRELOCABLE;
break;
}
- default: {
- lua_assert(0); /* cannot happen */
- break;
- }
+ default: lua_assert(0); /* cannot happen */
}
/* interchange true and false lists */
{ int temp = e->f; e->f = e->t; e->t = temp; }
- removevalues(fs, e->f);
+ removevalues(fs, e->f); /* values are useless when negated */
removevalues(fs, e->t);
}
+/*
+** Create expression 't[k]'. 't' must have its final result already in a
+** register or upvalue.
+*/
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
- lua_assert(!hasjumps(t));
- t->u.ind.t = t->u.info;
- t->u.ind.idx = luaK_exp2RK(fs, k);
- t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL
- : check_exp(vkisinreg(t->k), VLOCAL);
+ lua_assert(!hasjumps(t) && (vkisinreg(t->k) || t->k == VUPVAL));
+ t->u.ind.t = t->u.info; /* register or upvalue index */
+ t->u.ind.idx = luaK_exp2RK(fs, k); /* R/K index for key */
+ t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : VLOCAL;
t->k = VINDEXED;
}
/*
-** return false if folding can raise an error
+** Return false if folding can raise an error.
+** Bitwise operations need operands convertible to integers; division
+** operations cannot have 0 as divisor.
*/
static int validop (int op, TValue *v1, TValue *v2) {
switch (op) {
@@ -761,9 +972,11 @@ static int validop (int op, TValue *v1, TValue *v2) {
/*
-** Try to "constant-fold" an operation; return 1 iff successful
+** Try to "constant-fold" an operation; return 1 iff successful.
+** (In this case, 'e1' has the final result.)
*/
-static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) {
+static int constfolding (FuncState *fs, int op, expdesc *e1,
+ const expdesc *e2) {
TValue v1, v2, res;
if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2))
return 0; /* non-numeric operands or not safe to fold */
@@ -772,7 +985,7 @@ static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) {
e1->k = VKINT;
e1->u.ival = ivalue(&res);
}
- else { /* folds neither NaN nor 0.0 (to avoid collapsing with -0.0) */
+ else { /* folds neither NaN nor 0.0 (to avoid problems with -0.0) */
lua_Number n = fltvalue(&res);
if (luai_numisnan(n) || n == 0)
return 0;
@@ -784,81 +997,100 @@ static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) {
/*
-** Code for binary and unary expressions that "produce values"
-** (arithmetic operations, bitwise operations, concat, length). First
-** try to do constant folding (only for numeric [arithmetic and
-** bitwise] operations, which is what 'lua_arith' accepts).
+** Emit code for unary expressions that "produce values"
+** (everything but 'not').
+** Expression to produce final result will be encoded in 'e'.
+*/
+static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) {
+ int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */
+ freeexp(fs, e);
+ e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */
+ e->k = VRELOCABLE; /* all those operations are relocatable */
+ luaK_fixline(fs, line);
+}
+
+
+/*
+** Emit code for binary expressions that "produce values"
+** (everything but logical operators 'and'/'or' and comparison
+** operators).
** Expression to produce final result will be encoded in 'e1'.
+** Because 'luaK_exp2RK' can free registers, its calls must be
+** in "stack order" (that is, first on 'e2', which may have more
+** recent registers to be released).
*/
-static void codeexpval (FuncState *fs, OpCode op,
- expdesc *e1, expdesc *e2, int line) {
- lua_assert(op >= OP_ADD);
- if (op <= OP_BNOT && constfolding(fs, op - OP_ADD + LUA_OPADD, e1, e2))
- return; /* result has been folded */
- else {
- int o1, o2;
- /* move operands to registers (if needed) */
- if (op == OP_UNM || op == OP_BNOT || op == OP_LEN) { /* unary op? */
- o2 = 0; /* no second expression */
- o1 = luaK_exp2anyreg(fs, e1); /* cannot operate on constants */
- }
- else { /* regular case (binary operators) */
- o2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */
- o1 = luaK_exp2RK(fs, e1);
- }
- if (o1 > o2) { /* free registers in proper order */
- freeexp(fs, e1);
- freeexp(fs, e2);
- }
- else {
- freeexp(fs, e2);
- freeexp(fs, e1);
- }
- e1->u.info = luaK_codeABC(fs, op, 0, o1, o2); /* generate opcode */
- e1->k = VRELOCABLE; /* all those operations are relocable */
- luaK_fixline(fs, line);
- }
+static void codebinexpval (FuncState *fs, OpCode op,
+ expdesc *e1, expdesc *e2, int line) {
+ int rk2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */
+ int rk1 = luaK_exp2RK(fs, e1);
+ freeexps(fs, e1, e2);
+ e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */
+ e1->k = VRELOCABLE; /* all those operations are relocatable */
+ luaK_fixline(fs, line);
}
-static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
- expdesc *e2) {
- int o1 = luaK_exp2RK(fs, e1);
- int o2 = luaK_exp2RK(fs, e2);
- freeexp(fs, e2);
- freeexp(fs, e1);
- if (cond == 0 && op != OP_EQ) {
- int temp; /* exchange args to replace by '<' or '<=' */
- temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */
- cond = 1;
+/*
+** Emit code for comparisons.
+** 'e1' was already put in R/K form by 'luaK_infix'.
+*/
+static void codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
+ int rk1 = (e1->k == VK) ? RKASK(e1->u.info)
+ : check_exp(e1->k == VNONRELOC, e1->u.info);
+ int rk2 = luaK_exp2RK(fs, e2);
+ freeexps(fs, e1, e2);
+ switch (opr) {
+ case OPR_NE: { /* '(a ~= b)' ==> 'not (a == b)' */
+ e1->u.info = condjump(fs, OP_EQ, 0, rk1, rk2);
+ break;
+ }
+ case OPR_GT: case OPR_GE: {
+ /* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */
+ OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
+ e1->u.info = condjump(fs, op, 1, rk2, rk1); /* invert operands */
+ break;
+ }
+ default: { /* '==', '<', '<=' use their own opcodes */
+ OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
+ e1->u.info = condjump(fs, op, 1, rk1, rk2);
+ break;
+ }
}
- e1->u.info = condjump(fs, op, cond, o1, o2);
e1->k = VJMP;
}
+/*
+** Aplly prefix operation 'op' to expression 'e'.
+*/
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
- expdesc e2;
- e2.t = e2.f = NO_JUMP; e2.k = VKINT; e2.u.ival = 0;
+ static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
switch (op) {
- case OPR_MINUS: case OPR_BNOT: case OPR_LEN: {
- codeexpval(fs, cast(OpCode, (op - OPR_MINUS) + OP_UNM), e, &e2, line);
+ case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */
+ if (constfolding(fs, op + LUA_OPUNM, e, &ef))
+ break;
+ /* FALLTHROUGH */
+ case OPR_LEN:
+ codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line);
break;
- }
case OPR_NOT: codenot(fs, e); break;
default: lua_assert(0);
}
}
+/*
+** Process 1st operand 'v' of binary operation 'op' before reading
+** 2nd operand.
+*/
void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
switch (op) {
case OPR_AND: {
- luaK_goiftrue(fs, v);
+ luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */
break;
}
case OPR_OR: {
- luaK_goiffalse(fs, v);
+ luaK_goiffalse(fs, v); /* go ahead only if 'v' is false */
break;
}
case OPR_CONCAT: {
@@ -870,7 +1102,9 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
case OPR_MOD: case OPR_POW:
case OPR_BAND: case OPR_BOR: case OPR_BXOR:
case OPR_SHL: case OPR_SHR: {
- if (!tonumeral(v, NULL)) luaK_exp2RK(fs, v);
+ if (!tonumeral(v, NULL))
+ luaK_exp2RK(fs, v);
+ /* else keep numeral, which may be folded with 2nd operand */
break;
}
default: {
@@ -881,18 +1115,24 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
}
+/*
+** Finalize code for binary operation, after reading 2nd operand.
+** For '(a .. b .. c)' (which is '(a .. (b .. c))', because
+** concatenation is right associative), merge second CONCAT into first
+** one.
+*/
void luaK_posfix (FuncState *fs, BinOpr op,
expdesc *e1, expdesc *e2, int line) {
switch (op) {
case OPR_AND: {
- lua_assert(e1->t == NO_JUMP); /* list must be closed */
+ lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */
luaK_dischargevars(fs, e2);
luaK_concat(fs, &e2->f, e1->f);
*e1 = *e2;
break;
}
case OPR_OR: {
- lua_assert(e1->f == NO_JUMP); /* list must be closed */
+ lua_assert(e1->f == NO_JUMP); /* list closed by 'luK_infix' */
luaK_dischargevars(fs, e2);
luaK_concat(fs, &e2->t, e1->t);
*e1 = *e2;
@@ -900,15 +1140,16 @@ void luaK_posfix (FuncState *fs, BinOpr op,
}
case OPR_CONCAT: {
luaK_exp2val(fs, e2);
- if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
- lua_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1);
+ if (e2->k == VRELOCABLE &&
+ GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) {
+ lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2))-1);
freeexp(fs, e1);
- SETARG_B(getcode(fs, e2), e1->u.info);
+ SETARG_B(getinstruction(fs, e2), e1->u.info);
e1->k = VRELOCABLE; e1->u.info = e2->u.info;
}
else {
luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
- codeexpval(fs, OP_CONCAT, e1, e2, line);
+ codebinexpval(fs, OP_CONCAT, e1, e2, line);
}
break;
}
@@ -916,15 +1157,13 @@ void luaK_posfix (FuncState *fs, BinOpr op,
case OPR_IDIV: case OPR_MOD: case OPR_POW:
case OPR_BAND: case OPR_BOR: case OPR_BXOR:
case OPR_SHL: case OPR_SHR: {
- codeexpval(fs, cast(OpCode, (op - OPR_ADD) + OP_ADD), e1, e2, line);
- break;
- }
- case OPR_EQ: case OPR_LT: case OPR_LE: {
- codecomp(fs, cast(OpCode, op - OPR_EQ + OP_EQ), 1, e1, e2);
+ if (!constfolding(fs, op + LUA_OPADD, e1, e2))
+ codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line);
break;
}
+ case OPR_EQ: case OPR_LT: case OPR_LE:
case OPR_NE: case OPR_GT: case OPR_GE: {
- codecomp(fs, cast(OpCode, op - OPR_NE + OP_EQ), 0, e1, e2);
+ codecomp(fs, op, e1, e2);
break;
}
default: lua_assert(0);
@@ -932,15 +1171,25 @@ void luaK_posfix (FuncState *fs, BinOpr op,
}
+/*
+** Change line information associated with current position.
+*/
void luaK_fixline (FuncState *fs, int line) {
fs->f->lineinfo[fs->pc - 1] = line;
}
+/*
+** Emit a SETLIST instruction.
+** 'base' is register that keeps table;
+** 'nelems' is #table plus those to be stored now;
+** 'tostore' is number of values (in registers 'base + 1',...) to add to
+** table (or LUA_MULTRET to add up to stack top).
+*/
void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1;
int b = (tostore == LUA_MULTRET) ? 0 : tostore;
- lua_assert(tostore != 0);
+ lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH);
if (c <= MAXARG_C)
luaK_codeABC(fs, OP_SETLIST, base, b, c);
else if (c <= MAXARG_Ax) {
diff --git a/src/lcode.h b/src/lcode.h
index 43ab86db77b0..cd306d573aef 100644
--- a/src/lcode.h
+++ b/src/lcode.h
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.h,v 1.63 2013/12/30 20:47:58 roberto Exp $
+** $Id: lcode.h,v 1.64 2016/01/05 16:22:37 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -40,7 +40,8 @@ typedef enum BinOpr {
typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
-#define getcode(fs,e) ((fs)->f->code[(e)->u.info])
+/* get (pointer to) instruction of given 'expdesc' */
+#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info])
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
diff --git a/src/lcorolib.c b/src/lcorolib.c
index 0c0b7fa6b31c..2303429e7bb3 100644
--- a/src/lcorolib.c
+++ b/src/lcorolib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lcorolib.c,v 1.9 2014/11/02 19:19:04 roberto Exp $
+** $Id: lcorolib.c,v 1.10 2016/04/11 19:19:55 roberto Exp $
** Coroutine Library
** See Copyright Notice in lua.h
*/
@@ -75,7 +75,7 @@ static int luaB_auxwrap (lua_State *L) {
lua_State *co = lua_tothread(L, lua_upvalueindex(1));
int r = auxresume(L, co, lua_gettop(L));
if (r < 0) {
- if (lua_isstring(L, -1)) { /* error object is a string? */
+ if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */
luaL_where(L, 1); /* add extra info */
lua_insert(L, -2);
lua_concat(L, 2);
diff --git a/src/ldblib.c b/src/ldblib.c
index 24a11b53ee32..786f6cd95d7e 100644
--- a/src/ldblib.c
+++ b/src/ldblib.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldblib.c,v 1.148 2015/01/02 12:52:22 roberto Exp $
+** $Id: ldblib.c,v 1.151 2015/11/23 11:29:43 roberto Exp $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
@@ -27,6 +27,17 @@
static const int HOOKKEY = 0;
+/*
+** If L1 != L, L1 can be in any state, and therefore there are no
+** guarantees about its stack space; any push in L1 must be
+** checked.
+*/
+static void checkstack (lua_State *L, lua_State *L1, int n) {
+ if (L != L1 && !lua_checkstack(L1, n))
+ luaL_error(L, "stack overflow");
+}
+
+
static int db_getregistry (lua_State *L) {
lua_pushvalue(L, LUA_REGISTRYINDEX);
return 1;
@@ -127,12 +138,16 @@ static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
/*
** Calls 'lua_getinfo' and collects all results in a new table.
+** L1 needs stack space for an optional input (function) plus
+** two optional outputs (function and line table) from function
+** 'lua_getinfo'.
*/
static int db_getinfo (lua_State *L) {
lua_Debug ar;
int arg;
lua_State *L1 = getthread(L, &arg);
const char *options = luaL_optstring(L, arg+2, "flnStu");
+ checkstack(L, L1, 3);
if (lua_isfunction(L, arg + 1)) { /* info about a function? */
options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */
lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */
@@ -190,6 +205,7 @@ static int db_getlocal (lua_State *L) {
int level = (int)luaL_checkinteger(L, arg + 1);
if (!lua_getstack(L1, level, &ar)) /* out of range? */
return luaL_argerror(L, arg+1, "level out of range");
+ checkstack(L, L1, 1);
name = lua_getlocal(L1, &ar, nvar);
if (name) {
lua_xmove(L1, L, 1); /* move local value */
@@ -216,6 +232,7 @@ static int db_setlocal (lua_State *L) {
return luaL_argerror(L, arg+1, "level out of range");
luaL_checkany(L, arg+3);
lua_settop(L, arg+3);
+ checkstack(L, L1, 1);
lua_xmove(L, L1, 1);
name = lua_setlocal(L1, &ar, nvar);
if (name == NULL)
@@ -350,6 +367,7 @@ static int db_sethook (lua_State *L) {
lua_pushvalue(L, -1);
lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */
}
+ checkstack(L, L1, 1);
lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */
lua_pushvalue(L, arg + 1); /* value (hook function) */
lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */
@@ -370,6 +388,7 @@ static int db_gethook (lua_State *L) {
lua_pushliteral(L, "external hook");
else { /* hook table must exist */
lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
+ checkstack(L, L1, 1);
lua_pushthread(L1); lua_xmove(L1, L, 1);
lua_rawget(L, -2); /* 1st result = hooktable[L1] */
lua_remove(L, -2); /* remove hook table */
diff --git a/src/ldebug.c b/src/ldebug.c
index 6986bf0f6098..239affb76c52 100644
--- a/src/ldebug.c
+++ b/src/ldebug.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldebug.c,v 2.110 2015/01/02 12:52:22 roberto Exp $
+** $Id: ldebug.c,v 2.121 2016/10/19 12:32:10 roberto Exp $
** Debug Interface
** See Copyright Notice in lua.h
*/
@@ -34,7 +34,12 @@
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL)
-static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
+/* Active Lua function (given call info) */
+#define ci_func(ci) (clLvalue((ci)->func))
+
+
+static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
+ const char **name);
static int currentpc (CallInfo *ci) {
@@ -49,7 +54,29 @@ static int currentline (CallInfo *ci) {
/*
-** this function can be called asynchronous (e.g. during a signal)
+** If function yielded, its 'func' can be in the 'extra' field. The
+** next function restores 'func' to its correct value for debugging
+** purposes. (It exchanges 'func' and 'extra'; so, when called again,
+** after debugging, it also "re-restores" ** 'func' to its altered value.
+*/
+static void swapextra (lua_State *L) {
+ if (L->status == LUA_YIELD) {
+ CallInfo *ci = L->ci; /* get function that yielded */
+ StkId temp = ci->func; /* exchange its 'func' and 'extra' values */
+ ci->func = restorestack(L, ci->extra);
+ ci->extra = savestack(L, temp);
+ }
+}
+
+
+/*
+** This function can be called asynchronously (e.g. during a signal).
+** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by
+** 'resethookcount') are for debug only, and it is no problem if they
+** get arbitrary values (causes at most one wrong hook call). 'hookmask'
+** is an atomic value. We assume that pointers are atomic too (e.g., gcc
+** ensures that for all platforms where it runs). Moreover, 'hook' is
+** always checked before being called (see 'luaD_hook').
*/
LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
if (func == NULL || mask == 0) { /* turn off hooks? */
@@ -106,7 +133,7 @@ static const char *upvalname (Proto *p, int uv) {
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)
+ if (n >= cast_int(ci->u.l.base - ci->func) - nparams)
return NULL; /* no such vararg */
else {
*pos = ci->func + nparams + n;
@@ -144,6 +171,7 @@ static const char *findlocal (lua_State *L, CallInfo *ci, int n,
LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
const char *name;
lua_lock(L);
+ swapextra(L);
if (ar == NULL) { /* information about non-active function? */
if (!isLfunction(L->top - 1)) /* not a Lua function? */
name = NULL;
@@ -151,26 +179,30 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0);
}
else { /* active function; get information through 'ar' */
- StkId pos = 0; /* to avoid warnings */
+ StkId pos = NULL; /* to avoid warnings */
name = findlocal(L, ar->i_ci, n, &pos);
if (name) {
setobj2s(L, L->top, pos);
api_incr_top(L);
}
}
+ swapextra(L);
lua_unlock(L);
return name;
}
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
- StkId pos = 0; /* to avoid warnings */
- const char *name = findlocal(L, ar->i_ci, n, &pos);
+ StkId pos = NULL; /* to avoid warnings */
+ const char *name;
lua_lock(L);
+ swapextra(L);
+ name = findlocal(L, ar->i_ci, n, &pos);
if (name) {
setobjs2s(L, pos, L->top - 1);
L->top--; /* pop value */
}
+ swapextra(L);
lua_unlock(L);
return name;
}
@@ -213,6 +245,20 @@ static void collectvalidlines (lua_State *L, Closure *f) {
}
+static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
+ if (ci == NULL) /* no 'ci'? */
+ return NULL; /* no info */
+ else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */
+ *name = "__gc";
+ return "metamethod"; /* report it as such */
+ }
+ /* calling function is a known Lua function? */
+ else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
+ return funcnamefromcode(L, ci->previous, name);
+ else return NULL; /* no way to find a name */
+}
+
+
static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
Closure *f, CallInfo *ci) {
int status = 1;
@@ -243,11 +289,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
break;
}
case 'n': {
- /* calling function is a known Lua function? */
- if (ci && !(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
- ar->namewhat = getfuncname(L, ci->previous, &ar->name);
- else
- ar->namewhat = NULL;
+ ar->namewhat = getfuncname(L, ci, &ar->name);
if (ar->namewhat == NULL) {
ar->namewhat = ""; /* not found */
ar->name = NULL;
@@ -270,10 +312,11 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
CallInfo *ci;
StkId func;
lua_lock(L);
+ swapextra(L);
if (*what == '>') {
ci = NULL;
func = L->top - 1;
- api_check(ttisfunction(func), "function expected");
+ api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */
L->top--; /* pop function */
}
@@ -288,6 +331,7 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
setobjs2s(L, L->top, func);
api_incr_top(L);
}
+ swapextra(L); /* correct before option 'L', which can raise a mem. error */
if (strchr(what, 'L'))
collectvalidlines(L, cl);
lua_unlock(L);
@@ -438,8 +482,15 @@ static const char *getobjname (Proto *p, int lastpc, int reg,
}
-static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
- TMS tm = (TMS)0; /* to avoid warnings */
+/*
+** Try to find a name for a function based on the code that called it.
+** (Only works when function was called by a Lua function.)
+** Returns what the name is (e.g., "for iterator", "method",
+** "metamethod") and sets '*name' to point to the name.
+*/
+static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
+ const char **name) {
+ TMS tm = (TMS)0; /* (initial value avoids warnings) */
Proto *p = ci_func(ci)->p; /* calling function */
int pc = currentpc(ci); /* calling instruction index */
Instruction i = p->code[pc]; /* calling instruction */
@@ -449,13 +500,13 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
}
switch (GET_OPCODE(i)) {
case OP_CALL:
- case OP_TAILCALL: /* get function name */
- return getobjname(p, pc, GETARG_A(i), name);
+ case OP_TAILCALL:
+ return getobjname(p, pc, GETARG_A(i), name); /* get function name */
case OP_TFORCALL: { /* for iterator */
*name = "for iterator";
return "for iterator";
}
- /* all other instructions can call only through metamethods */
+ /* other instructions can do calls through metamethods */
case OP_SELF: case OP_GETTABUP: case OP_GETTABLE:
tm = TM_INDEX;
break;
@@ -476,7 +527,8 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
case OP_EQ: tm = TM_EQ; break;
case OP_LT: tm = TM_LT; break;
case OP_LE: tm = TM_LE; break;
- default: lua_assert(0); /* other instructions cannot call a function */
+ default:
+ return NULL; /* cannot find a reasonable name */
}
*name = getstr(G(L)->tmname[tm]);
return "metamethod";
@@ -531,7 +583,7 @@ static const char *varinfo (lua_State *L, const TValue *o) {
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
- const char *t = objtypename(o);
+ const char *t = luaT_objtypename(L, o);
luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o));
}
@@ -563,28 +615,25 @@ l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
- const char *t1 = objtypename(p1);
- const char *t2 = objtypename(p2);
- if (t1 == t2)
+ const char *t1 = luaT_objtypename(L, p1);
+ const char *t2 = luaT_objtypename(L, p2);
+ if (strcmp(t1, t2) == 0)
luaG_runerror(L, "attempt to compare two %s values", t1);
else
luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
}
-static void addinfo (lua_State *L, const char *msg) {
- CallInfo *ci = L->ci;
- if (isLua(ci)) { /* is Lua code? */
- char buff[LUA_IDSIZE]; /* add file:line information */
- int line = currentline(ci);
- TString *src = ci_func(ci)->p->source;
- if (src)
- luaO_chunkid(buff, getstr(src), LUA_IDSIZE);
- else { /* no source available; use "?" instead */
- buff[0] = '?'; buff[1] = '\0';
- }
- luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
+/* add src:line information to 'msg' */
+const char *luaG_addinfo (lua_State *L, const char *msg, TString *src,
+ int line) {
+ char buff[LUA_IDSIZE];
+ if (src)
+ luaO_chunkid(buff, getstr(src), LUA_IDSIZE);
+ else { /* no source available; use "?" instead */
+ buff[0] = '?'; buff[1] = '\0';
}
+ return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
}
@@ -594,17 +643,21 @@ l_noret luaG_errormsg (lua_State *L) {
setobjs2s(L, L->top, L->top - 1); /* move argument */
setobjs2s(L, L->top - 1, errfunc); /* push function */
L->top++; /* assume EXTRA_STACK */
- luaD_call(L, L->top - 2, 1, 0); /* call it */
+ luaD_callnoyield(L, L->top - 2, 1); /* call it */
}
luaD_throw(L, LUA_ERRRUN);
}
l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
+ CallInfo *ci = L->ci;
+ const char *msg;
va_list argp;
va_start(argp, fmt);
- addinfo(L, luaO_pushvfstring(L, fmt, argp));
+ msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp);
+ if (isLua(ci)) /* if Lua function, add source:line information */
+ luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci));
luaG_errormsg(L);
}
@@ -612,9 +665,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
void luaG_traceexec (lua_State *L) {
CallInfo *ci = L->ci;
lu_byte mask = L->hookmask;
- int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0);
+ int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT));
if (counthook)
resethookcount(L); /* reset count */
+ else if (!(mask & LUA_MASKLINE))
+ return; /* no line hook and count != 0; nothing to be done */
if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
return; /* do not call hook again (VM yielded, so it did not move) */
diff --git a/src/ldebug.h b/src/ldebug.h
index 0d8966ca9a61..0e31546b1b4b 100644
--- a/src/ldebug.h
+++ b/src/ldebug.h
@@ -1,5 +1,5 @@
/*
-** $Id: ldebug.h,v 2.12 2014/11/10 14:46:05 roberto Exp $
+** $Id: ldebug.h,v 2.14 2015/05/22 17:45:56 roberto Exp $
** Auxiliary functions from Debug Interface module
** See Copyright Notice in lua.h
*/
@@ -17,9 +17,6 @@
#define resethookcount(L) (L->hookcount = L->basehookcount)
-/* Active Lua function (given call info) */
-#define ci_func(ci) (clLvalue((ci)->func))
-
LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,
const char *opname);
@@ -33,6 +30,8 @@ LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1,
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
const TValue *p2);
LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
+LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
+ TString *src, int line);
LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
LUAI_FUNC void luaG_traceexec (lua_State *L);
diff --git a/src/ldo.c b/src/ldo.c
index 6159e51da2d4..90b695fb04c7 100644
--- a/src/ldo.c
+++ b/src/ldo.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.c,v 2.135 2014/11/11 17:13:39 roberto Exp $
+** $Id: ldo.c,v 2.157 2016/12/13 15:52:21 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -150,6 +150,11 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
/* }====================================================== */
+/*
+** {==================================================================
+** Stack reallocation
+** ===================================================================
+*/
static void correctstack (lua_State *L, TValue *oldstack) {
CallInfo *ci;
UpVal *up;
@@ -206,9 +211,9 @@ static int stackinuse (lua_State *L) {
CallInfo *ci;
StkId lim = L->top;
for (ci = L->ci; ci != NULL; ci = ci->previous) {
- lua_assert(ci->top <= L->stack_last);
if (lim < ci->top) lim = ci->top;
}
+ lua_assert(lim <= L->stack_last);
return cast_int(lim - L->stack) + 1; /* part of stack in use */
}
@@ -216,22 +221,38 @@ static int stackinuse (lua_State *L) {
void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L);
int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
- if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK;
- if (L->stacksize > LUAI_MAXSTACK) /* was handling stack overflow? */
+ if (goodsize > LUAI_MAXSTACK)
+ goodsize = LUAI_MAXSTACK; /* respect stack limit */
+ if (L->stacksize > LUAI_MAXSTACK) /* had been handling stack overflow? */
luaE_freeCI(L); /* free all CIs (list grew because of an error) */
else
luaE_shrinkCI(L); /* shrink list */
- if (inuse > LUAI_MAXSTACK || /* still handling stack overflow? */
- goodsize >= L->stacksize) /* would grow instead of shrink? */
- condmovestack(L); /* don't change stack (change only for debugging) */
- else
- luaD_reallocstack(L, goodsize); /* shrink it */
+ /* if thread is currently not handling a stack overflow and its
+ good size is smaller than current size, shrink its stack */
+ if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) &&
+ goodsize < L->stacksize)
+ luaD_reallocstack(L, goodsize);
+ else /* don't change stack */
+ condmovestack(L,{},{}); /* (change only for debugging) */
+}
+
+
+void luaD_inctop (lua_State *L) {
+ luaD_checkstack(L, 1);
+ L->top++;
}
+/* }================================================================== */
+
+/*
+** Call a hook for the given event. Make sure there is a hook to be
+** called. (Both 'L->hook' and 'L->hookmask', which triggers this
+** function, can be changed asynchronously by signals.)
+*/
void luaD_hook (lua_State *L, int event, int line) {
lua_Hook hook = L->hook;
- if (hook && L->allowhook) {
+ if (hook && L->allowhook) { /* make sure there is a hook */
CallInfo *ci = L->ci;
ptrdiff_t top = savestack(L, L->top);
ptrdiff_t ci_top = savestack(L, ci->top);
@@ -273,15 +294,15 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
int i;
int nfixargs = p->numparams;
StkId base, fixed;
- lua_assert(actual >= nfixargs);
/* move fixed parameters to final position */
- luaD_checkstack(L, p->maxstacksize); /* check again for new 'base' */
fixed = L->top - actual; /* first fixed argument */
base = L->top; /* final position of first argument */
- for (i=0; i<nfixargs; i++) {
+ for (i = 0; i < nfixargs && i < actual; i++) {
setobjs2s(L, L->top++, fixed + i);
- setnilvalue(fixed + i);
+ setnilvalue(fixed + i); /* erase original copy (for GC) */
}
+ for (; i < nfixargs; i++)
+ setnilvalue(L->top++); /* complete missing arguments */
return base;
}
@@ -304,74 +325,145 @@ static void tryfuncTM (lua_State *L, StkId func) {
}
+/*
+** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'.
+** Handle most typical cases (zero results for commands, one result for
+** expressions, multiple results for tail calls/single parameters)
+** separated.
+*/
+static int moveresults (lua_State *L, const TValue *firstResult, StkId res,
+ int nres, int wanted) {
+ switch (wanted) { /* handle typical cases separately */
+ case 0: break; /* nothing to move */
+ case 1: { /* one result needed */
+ if (nres == 0) /* no results? */
+ firstResult = luaO_nilobject; /* adjust with nil */
+ setobjs2s(L, res, firstResult); /* move it to proper place */
+ break;
+ }
+ case LUA_MULTRET: {
+ int i;
+ for (i = 0; i < nres; i++) /* move all results to correct place */
+ setobjs2s(L, res + i, firstResult + i);
+ L->top = res + nres;
+ return 0; /* wanted == LUA_MULTRET */
+ }
+ default: {
+ int i;
+ if (wanted <= nres) { /* enough results? */
+ for (i = 0; i < wanted; i++) /* move wanted results to correct place */
+ setobjs2s(L, res + i, firstResult + i);
+ }
+ else { /* not enough results; use all of them plus nils */
+ for (i = 0; i < nres; i++) /* move all results to correct place */
+ setobjs2s(L, res + i, firstResult + i);
+ for (; i < wanted; i++) /* complete wanted number of results */
+ setnilvalue(res + i);
+ }
+ break;
+ }
+ }
+ L->top = res + wanted; /* top points after the last result */
+ return 1;
+}
+
+
+/*
+** Finishes a function call: calls hook if necessary, removes CallInfo,
+** moves current number of results to proper place; returns 0 iff call
+** wanted multiple (variable number of) results.
+*/
+int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) {
+ StkId res;
+ int wanted = ci->nresults;
+ if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
+ if (L->hookmask & LUA_MASKRET) {
+ ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
+ luaD_hook(L, LUA_HOOKRET, -1);
+ firstResult = restorestack(L, fr);
+ }
+ L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
+ }
+ res = ci->func; /* res == final position of 1st result */
+ L->ci = ci->previous; /* back to caller */
+ /* move results to proper place */
+ return moveresults(L, firstResult, res, nres, wanted);
+}
+
+
#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
+/* macro to check stack size, preserving 'p' */
+#define checkstackp(L,n,p) \
+ luaD_checkstackaux(L, n, \
+ ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
+ luaC_checkGC(L), /* stack grow uses memory */ \
+ p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
+
+
/*
-** returns true if function has been executed (C function)
+** Prepares a function call: checks the stack, creates a new CallInfo
+** entry, fills in the relevant information, calls hook if needed.
+** If function is a C function, does the call, too. (Otherwise, leave
+** the execution ('luaV_execute') to the caller, to allow stackless
+** calls.) Returns true iff function has been executed (C function).
*/
int luaD_precall (lua_State *L, StkId func, int nresults) {
lua_CFunction f;
CallInfo *ci;
- int n; /* number of arguments (Lua) or returns (C) */
- ptrdiff_t funcr = savestack(L, func);
switch (ttype(func)) {
+ case LUA_TCCL: /* C closure */
+ f = clCvalue(func)->f;
+ goto Cfunc;
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 */
+ Cfunc: {
+ int n; /* number of returns */
+ checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
- ci->func = restorestack(L, funcr);
+ ci->func = func;
ci->top = L->top + LUA_MINSTACK;
lua_assert(ci->top <= L->stack_last);
ci->callstatus = 0;
- luaC_checkGC(L); /* stack grow uses memory */
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);
+ luaD_poscall(L, ci, L->top - n, n);
return 1;
}
case LUA_TLCL: { /* Lua function: prepare its call */
StkId base;
Proto *p = clLvalue(func)->p;
- n = cast_int(L->top - func) - 1; /* number of real arguments */
- luaD_checkstack(L, p->maxstacksize);
- for (; n < p->numparams; n++)
- setnilvalue(L->top++); /* complete missing arguments */
- if (!p->is_vararg) {
- func = restorestack(L, funcr);
- base = func + 1;
- }
- else {
+ int n = cast_int(L->top - func) - 1; /* number of real arguments */
+ int fsize = p->maxstacksize; /* frame size */
+ checkstackp(L, fsize, func);
+ if (p->is_vararg)
base = adjust_varargs(L, p, n);
- func = restorestack(L, funcr); /* previous call can change stack */
+ else { /* non vararg function */
+ for (; n < p->numparams; n++)
+ setnilvalue(L->top++); /* complete missing arguments */
+ base = func + 1;
}
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
ci->func = func;
ci->u.l.base = base;
- ci->top = base + p->maxstacksize;
+ L->top = ci->top = base + fsize;
lua_assert(ci->top <= L->stack_last);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus = CIST_LUA;
- L->top = ci->top;
- luaC_checkGC(L); /* stack grow uses memory */
if (L->hookmask & LUA_MASKCALL)
callhook(L, ci);
return 0;
}
default: { /* not a function */
- luaD_checkstack(L, 1); /* ensure space for metamethod */
- func = restorestack(L, funcr); /* previous call may change stack */
+ checkstackp(L, 1, func); /* ensure space for metamethod */
tryfuncTM(L, func); /* try to get '__call' metamethod */
return luaD_precall(L, func, nresults); /* now it must be a function */
}
@@ -379,28 +471,18 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
}
-int luaD_poscall (lua_State *L, StkId firstResult) {
- StkId res;
- int wanted, i;
- CallInfo *ci = L->ci;
- if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
- if (L->hookmask & LUA_MASKRET) {
- ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
- luaD_hook(L, LUA_HOOKRET, -1);
- firstResult = restorestack(L, fr);
- }
- L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
- }
- res = ci->func; /* res == final position of 1st result */
- wanted = ci->nresults;
- L->ci = ci = ci->previous; /* back to caller */
- /* move results to correct place */
- for (i = wanted; i != 0 && firstResult < L->top; i--)
- setobjs2s(L, res++, firstResult++);
- while (i-- > 0)
- setnilvalue(res++);
- L->top = res;
- return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */
+/*
+** Check appropriate error for stack overflow ("regular" overflow or
+** overflow while handling stack overflow). If 'nCalls' is larger than
+** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but
+** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to
+** allow overflow handling to work)
+*/
+static void stackerror (lua_State *L) {
+ if (L->nCcalls == LUAI_MAXCCALLS)
+ luaG_runerror(L, "C stack overflow");
+ else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
+ luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
}
@@ -410,22 +492,26 @@ int luaD_poscall (lua_State *L, StkId firstResult) {
** When returns, all the results are on the stack, starting at the original
** function position.
*/
-void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) {
- if (++L->nCcalls >= LUAI_MAXCCALLS) {
- if (L->nCcalls == LUAI_MAXCCALLS)
- luaG_runerror(L, "C stack overflow");
- else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
- luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
- }
- if (!allowyield) L->nny++;
+void luaD_call (lua_State *L, StkId func, int nResults) {
+ if (++L->nCcalls >= LUAI_MAXCCALLS)
+ stackerror(L);
if (!luaD_precall(L, func, nResults)) /* is a Lua function? */
luaV_execute(L); /* call it */
- if (!allowyield) L->nny--;
L->nCcalls--;
}
/*
+** Similar to 'luaD_call', but does not allow yields during the call
+*/
+void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
+ L->nny++;
+ luaD_call(L, func, nResults);
+ L->nny--;
+}
+
+
+/*
** Completes the execution of an interrupted C function, calling its
** continuation function.
*/
@@ -437,19 +523,17 @@ static void finishCcall (lua_State *L, int status) {
/* error status can only happen in a protected call */
lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD);
if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */
- ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */
- L->errfunc = ci->u.c.old_errfunc;
+ ci->callstatus &= ~CIST_YPCALL; /* continuation is also inside it */
+ L->errfunc = ci->u.c.old_errfunc; /* with the same error function */
}
/* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already
handled */
adjustresults(L, ci->nresults);
- /* call continuation function */
lua_unlock(L);
- n = (*ci->u.c.k)(L, status, ci->u.c.ctx);
+ n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */
lua_lock(L);
api_checknelems(L, n);
- /* finish 'luaD_precall' */
- luaD_poscall(L, L->top - n);
+ luaD_poscall(L, ci, L->top - n, n); /* finish 'luaD_precall' */
}
@@ -512,15 +596,16 @@ static int recover (lua_State *L, int status) {
/*
-** signal an error in the call to 'resume', not in the execution of the
-** coroutine itself. (Such errors should not be handled by any coroutine
-** error handler and should not kill the coroutine.)
+** Signal an error in the call to 'lua_resume', not in the execution
+** of the coroutine itself. (Such errors should not be handled by any
+** coroutine error handler and should not kill the coroutine.)
*/
-static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
- L->top = firstArg; /* remove args from the stack */
+static int resume_error (lua_State *L, const char *msg, int narg) {
+ L->top -= narg; /* remove args from the stack */
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
api_incr_top(L);
- luaD_throw(L, -1); /* jump back to 'lua_resume' */
+ lua_unlock(L);
+ return LUA_ERRRUN;
}
@@ -532,51 +617,51 @@ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
** coroutine.
*/
static void resume (lua_State *L, void *ud) {
- int nCcalls = L->nCcalls;
- StkId firstArg = cast(StkId, ud);
+ int n = *(cast(int*, ud)); /* number of arguments */
+ StkId firstArg = L->top - n; /* first argument */
CallInfo *ci = L->ci;
- if (nCcalls >= LUAI_MAXCCALLS)
- resume_error(L, "C stack overflow", firstArg);
- if (L->status == LUA_OK) { /* may be starting a coroutine */
- if (ci != &L->base_ci) /* not in base level? */
- resume_error(L, "cannot resume non-suspended coroutine", firstArg);
- /* coroutine is in base level; start running it */
+ if (L->status == LUA_OK) { /* starting a coroutine? */
if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */
luaV_execute(L); /* call it */
}
- else if (L->status != LUA_YIELD)
- resume_error(L, "cannot resume dead coroutine", firstArg);
else { /* resuming from previous yield */
+ lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */
ci->func = restorestack(L, ci->extra);
if (isLua(ci)) /* yielded inside a hook? */
luaV_execute(L); /* just continue running Lua code */
else { /* 'common' yield */
if (ci->u.c.k != NULL) { /* does it have a continuation function? */
- int n;
lua_unlock(L);
n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */
lua_lock(L);
api_checknelems(L, n);
firstArg = L->top - n; /* yield results come from continuation */
}
- luaD_poscall(L, firstArg); /* finish 'luaD_precall' */
+ luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */
}
unroll(L, NULL); /* run continuation */
}
- lua_assert(nCcalls == L->nCcalls);
}
LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
int status;
- int oldnny = L->nny; /* save "number of non-yieldable" calls */
+ unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */
lua_lock(L);
- luai_userstateresume(L, nargs);
+ if (L->status == LUA_OK) { /* may be starting a coroutine */
+ if (L->ci != &L->base_ci) /* not in base level? */
+ return resume_error(L, "cannot resume non-suspended coroutine", nargs);
+ }
+ else if (L->status != LUA_YIELD)
+ return resume_error(L, "cannot resume dead coroutine", nargs);
L->nCcalls = (from) ? from->nCcalls + 1 : 1;
+ if (L->nCcalls >= LUAI_MAXCCALLS)
+ return resume_error(L, "C stack overflow", nargs);
+ luai_userstateresume(L, nargs);
L->nny = 0; /* allow yields */
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
- status = luaD_rawrunprotected(L, resume, L->top - nargs);
+ status = luaD_rawrunprotected(L, resume, &nargs);
if (status == -1) /* error calling 'lua_resume'? */
status = LUA_ERRRUN;
else { /* continue running after recoverable errors */
@@ -619,7 +704,7 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,
L->status = LUA_YIELD;
ci->extra = savestack(L, ci->func); /* save current 'func' */
if (isLua(ci)) { /* inside a hook? */
- api_check(k == NULL, "hooks cannot continue after yielding");
+ api_check(L, k == NULL, "hooks cannot continue after yielding");
}
else {
if ((ci->u.c.k = k) != NULL) /* is there a continuation? */
@@ -684,7 +769,7 @@ static void f_parser (lua_State *L, void *ud) {
int c = zgetc(p->z); /* read first character */
if (c == LUA_SIGNATURE[0]) {
checkmode(L, p->mode, "binary");
- cl = luaU_undump(L, p->z, &p->buff, p->name);
+ cl = luaU_undump(L, p->z, p->name);
}
else {
checkmode(L, p->mode, "text");
diff --git a/src/ldo.h b/src/ldo.h
index 05745c8ad8d5..4f5d51c3c704 100644
--- a/src/ldo.h
+++ b/src/ldo.h
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.h,v 2.21 2014/10/25 11:50:46 roberto Exp $
+** $Id: ldo.h,v 2.29 2015/12/21 13:02:14 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -13,11 +13,21 @@
#include "lzio.h"
-#define luaD_checkstack(L,n) if (L->stack_last - L->top <= (n)) \
- luaD_growstack(L, n); else condmovestack(L);
+/*
+** Macro to check stack size and grow stack if needed. Parameters
+** 'pre'/'pos' allow the macro to preserve a pointer into the
+** stack across reallocations, doing the work only when needed.
+** 'condmovestack' is used in heavy tests to force a stack reallocation
+** at every check.
+*/
+#define luaD_checkstackaux(L,n,pre,pos) \
+ if (L->stack_last - L->top <= (n)) \
+ { pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); }
+
+/* In general, 'pre'/'pos' are empty (nothing to save) */
+#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0)
-#define incr_top(L) {L->top++; luaD_checkstack(L,0);}
#define savestack(L,p) ((char *)(p) - (char *)L->stack)
#define restorestack(L,n) ((TValue *)((char *)L->stack + (n)))
@@ -30,14 +40,16 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
const char *mode);
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line);
LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults);
-LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults,
- int allowyield);
+LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
+LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t oldtop, ptrdiff_t ef);
-LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult);
+LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult,
+ int nres);
LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
LUAI_FUNC void luaD_growstack (lua_State *L, int n);
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
+LUAI_FUNC void luaD_inctop (lua_State *L);
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
diff --git a/src/ldump.c b/src/ldump.c
index b6c7114f5d9f..016e300822f2 100644
--- a/src/ldump.c
+++ b/src/ldump.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldump.c,v 2.34 2014/11/02 19:19:04 roberto Exp $
+** $Id: ldump.c,v 2.37 2015/10/08 15:53:49 roberto Exp $
** save precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -38,7 +38,7 @@ typedef struct {
static void DumpBlock (const void *b, size_t size, DumpState *D) {
- if (D->status == 0) {
+ if (D->status == 0 && size > 0) {
lua_unlock(D->L);
D->status = (*D->writer)(D->L, b, size, D->data);
lua_lock(D->L);
@@ -74,14 +74,15 @@ static void DumpString (const TString *s, DumpState *D) {
if (s == NULL)
DumpByte(0, D);
else {
- size_t size = s->len + 1; /* include trailing '\0' */
+ size_t size = tsslen(s) + 1; /* include trailing '\0' */
+ const char *str = getstr(s);
if (size < 0xFF)
DumpByte(cast_int(size), D);
else {
DumpByte(0xFF, D);
DumpVar(size, D);
}
- DumpVector(getstr(s), size - 1, D); /* no need to save '\0' */
+ DumpVector(str, size - 1, D); /* no need to save '\0' */
}
}
diff --git a/src/lfunc.h b/src/lfunc.h
index 256d3cf90bd2..2eeb0d5a4898 100644
--- a/src/lfunc.h
+++ b/src/lfunc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lfunc.h,v 2.14 2014/06/19 18:27:20 roberto Exp $
+** $Id: lfunc.h,v 2.15 2015/01/13 15:49:11 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@@ -23,6 +23,13 @@
/*
+** maximum number of upvalues in a closure (both C and Lua). (Value
+** must fit in a VM register.)
+*/
+#define MAXUPVAL 255
+
+
+/*
** Upvalues for Lua closures
*/
struct UpVal {
diff --git a/src/lgc.c b/src/lgc.c
index 8b95fb67da03..ba2c19e14e94 100644
--- a/src/lgc.c
+++ b/src/lgc.c
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.c,v 2.201 2014/12/20 13:58:15 roberto Exp $
+** $Id: lgc.c,v 2.215 2016/12/22 13:08:50 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -83,8 +83,13 @@
#define markvalue(g,o) { checkconsistency(o); \
if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }
-#define markobject(g,t) \
- { if ((t) && iswhite(t)) reallymarkobject(g, obj2gco(t)); }
+#define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); }
+
+/*
+** mark an object that can be NULL (either because it is really optional,
+** or it was stripped as debug info, or inside an uncompleted structure)
+*/
+#define markobjectN(g,t) { if (t) markobject(g,t); }
static void reallymarkobject (global_State *g, GCObject *o);
@@ -109,8 +114,13 @@ static void reallymarkobject (global_State *g, GCObject *o);
/*
-** if key is not marked, mark its entry as dead (therefore removing it
-** from the table)
+** If key is not marked, mark its entry as dead. This allows key to be
+** collected, but keeps its entry in the table. A dead node is needed
+** when Lua looks up for a key (it may be part of a chain) and when
+** traversing a weak table (key might be removed from the table during
+** traversal). Other places never manipulate dead keys, because its
+** associated nil value is enough to signal that the entry is logically
+** empty.
*/
static void removeentry (Node *n) {
lua_assert(ttisnil(gval(n)));
@@ -226,15 +236,19 @@ static void reallymarkobject (global_State *g, GCObject *o) {
reentry:
white2gray(o);
switch (o->tt) {
- case LUA_TSHRSTR:
+ case LUA_TSHRSTR: {
+ gray2black(o);
+ g->GCmemtrav += sizelstring(gco2ts(o)->shrlen);
+ break;
+ }
case LUA_TLNGSTR: {
gray2black(o);
- g->GCmemtrav += sizestring(gco2ts(o));
+ g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen);
break;
}
case LUA_TUSERDATA: {
TValue uvalue;
- markobject(g, gco2u(o)->metatable); /* mark its metatable */
+ markobjectN(g, gco2u(o)->metatable); /* mark its metatable */
gray2black(o);
g->GCmemtrav += sizeudata(gco2u(o));
getuservalue(g->mainthread, gco2u(o), &uvalue);
@@ -275,7 +289,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
static void markmt (global_State *g) {
int i;
for (i=0; i < LUA_NUMTAGS; i++)
- markobject(g, g->mt[i]);
+ markobjectN(g, g->mt[i]);
}
@@ -437,7 +451,7 @@ static void traversestrongtable (global_State *g, Table *h) {
static lu_mem traversetable (global_State *g, Table *h) {
const char *weakkey, *weakvalue;
const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
- markobject(g, h->metatable);
+ markobjectN(g, h->metatable);
if (mode && ttisstring(mode) && /* is there a weak mode? */
((weakkey = strchr(svalue(mode), 'k')),
(weakvalue = strchr(svalue(mode), 'v')),
@@ -453,23 +467,28 @@ static lu_mem traversetable (global_State *g, Table *h) {
else /* not weak */
traversestrongtable(g, h);
return sizeof(Table) + sizeof(TValue) * h->sizearray +
- sizeof(Node) * cast(size_t, sizenode(h));
+ sizeof(Node) * cast(size_t, allocsizenode(h));
}
+/*
+** Traverse a prototype. (While a prototype is being build, its
+** arrays can be larger than needed; the extra slots are filled with
+** NULL, so the use of 'markobjectN')
+*/
static int traverseproto (global_State *g, Proto *f) {
int i;
if (f->cache && iswhite(f->cache))
f->cache = NULL; /* allow cache to be collected */
- markobject(g, f->source);
+ markobjectN(g, f->source);
for (i = 0; i < f->sizek; i++) /* mark literals */
markvalue(g, &f->k[i]);
for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */
- markobject(g, f->upvalues[i].name);
+ markobjectN(g, f->upvalues[i].name);
for (i = 0; i < f->sizep; i++) /* mark nested protos */
- markobject(g, f->p[i]);
+ markobjectN(g, f->p[i]);
for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
- markobject(g, f->locvars[i].varname);
+ markobjectN(g, f->locvars[i].varname);
return sizeof(Proto) + sizeof(Instruction) * f->sizecode +
sizeof(Proto *) * f->sizep +
sizeof(TValue) * f->sizek +
@@ -494,7 +513,7 @@ static lu_mem traverseCclosure (global_State *g, CClosure *cl) {
*/
static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
int i;
- markobject(g, cl->p); /* mark its prototype */
+ markobjectN(g, cl->p); /* mark its prototype */
for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */
UpVal *uv = cl->upvals[i];
if (uv != NULL) {
@@ -520,7 +539,7 @@ static lu_mem traversethread (global_State *g, lua_State *th) {
StkId lim = th->stack + th->stacksize; /* real end of stack */
for (; o < lim; o++) /* clear not-marked stack slice */
setnilvalue(o);
- /* 'remarkupvals' may have removed thread from 'twups' list */
+ /* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) {
th->twups = g->twups; /* link it back to the list */
g->twups = th;
@@ -528,7 +547,8 @@ static lu_mem traversethread (global_State *g, lua_State *th) {
}
else if (g->gckind != KGC_EMERGENCY)
luaD_shrinkstack(th); /* do not change stack in emergency cycle */
- return (sizeof(lua_State) + sizeof(TValue) * th->stacksize);
+ return (sizeof(lua_State) + sizeof(TValue) * th->stacksize +
+ sizeof(CallInfo) * th->nci);
}
@@ -689,9 +709,10 @@ static void freeobj (lua_State *L, GCObject *o) {
case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;
case LUA_TSHRSTR:
luaS_remove(L, gco2ts(o)); /* remove it from hash table */
- /* go through */
+ luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen));
+ break;
case LUA_TLNGSTR: {
- luaM_freemem(L, o, sizestring(gco2ts(o)));
+ luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen));
break;
}
default: lua_assert(0);
@@ -733,14 +754,11 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
/*
** sweep a list until a live object (or end of list)
*/
-static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) {
+static GCObject **sweeptolive (lua_State *L, GCObject **p) {
GCObject **old = p;
- int i = 0;
do {
- i++;
p = sweeplist(L, p, 1);
} while (p == old);
- if (n) *n += i;
return p;
}
@@ -754,12 +772,11 @@ static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) {
*/
/*
-** If possible, free concatenation buffer and shrink string table
+** If possible, shrink string table
*/
static void checkSizes (lua_State *L, global_State *g) {
if (g->gckind != KGC_EMERGENCY) {
l_mem olddebt = g->GCdebt;
- luaZ_freebuffer(L, &g->buff); /* free concatenation buffer */
if (g->strt.nuse < g->strt.size / 4) /* string table too big? */
luaS_resize(L, g->strt.size / 2); /* shrink it a little */
g->GCestimate += g->GCdebt - olddebt; /* update estimate */
@@ -782,7 +799,7 @@ static GCObject *udata2finalize (global_State *g) {
static void dothecall (lua_State *L, void *ud) {
UNUSED(ud);
- luaD_call(L, L->top - 2, 0, 0);
+ luaD_callnoyield(L, L->top - 2, 0);
}
@@ -801,7 +818,9 @@ static void GCTM (lua_State *L, int propagateerrors) {
setobj2s(L, L->top, tm); /* push finalizer... */
setobj2s(L, L->top + 1, &v); /* ... and its argument */
L->top += 2; /* and (next line) call the finalizer */
+ L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
+ L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */
g->gcrunning = running; /* restore state */
if (status != LUA_OK && propagateerrors) { /* error while running __gc? */
@@ -836,10 +855,10 @@ static int runafewfinalizers (lua_State *L) {
/*
** call all pending finalizers
*/
-static void callallpendingfinalizers (lua_State *L, int propagateerrors) {
+static void callallpendingfinalizers (lua_State *L) {
global_State *g = G(L);
while (g->tobefnz)
- GCTM(L, propagateerrors);
+ GCTM(L, 0);
}
@@ -889,7 +908,7 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
if (issweepphase(g)) {
makewhite(g, o); /* "sweep" object 'o' */
if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */
- g->sweepgc = sweeptolive(L, g->sweepgc, NULL); /* change 'sweepgc' */
+ g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */
}
/* search for pointer pointing to 'o' */
for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ }
@@ -931,19 +950,16 @@ static void setpause (global_State *g) {
/*
** Enter first sweep phase.
-** The call to 'sweeptolive' makes pointer point to an object inside
-** the list (instead of to the header), so that the real sweep do not
-** need to skip objects created between "now" and the start of the real
-** sweep.
-** Returns how many objects it swept.
+** The call to 'sweeplist' tries to make pointer point to an object
+** inside the list (instead of to the header), so that the real sweep do
+** not need to skip objects created between "now" and the start of the
+** real sweep.
*/
-static int entersweep (lua_State *L) {
+static void entersweep (lua_State *L) {
global_State *g = G(L);
- int n = 0;
g->gcstate = GCSswpallgc;
lua_assert(g->sweepgc == NULL);
- g->sweepgc = sweeptolive(L, &g->allgc, &n);
- return n;
+ g->sweepgc = sweeplist(L, &g->allgc, 1);
}
@@ -951,7 +967,7 @@ void luaC_freeallobjects (lua_State *L) {
global_State *g = G(L);
separatetobefnz(g, 1); /* separate all objects with finalizers */
lua_assert(g->finobj == NULL);
- callallpendingfinalizers(L, 0);
+ callallpendingfinalizers(L);
lua_assert(g->tobefnz == NULL);
g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */
g->gckind = KGC_NORMAL;
@@ -1002,6 +1018,7 @@ static l_mem atomic (lua_State *L) {
/* clear values from resurrected weak tables */
clearvalues(g, g->weak, origweak);
clearvalues(g, g->allweak, origall);
+ luaS_clearcache(g);
g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
work += g->GCmemtrav; /* complete counting */
return work; /* estimate of memory marked by 'atomic' */
@@ -1043,12 +1060,11 @@ static lu_mem singlestep (lua_State *L) {
}
case GCSatomic: {
lu_mem work;
- int sw;
propagateall(g); /* make sure gray list is empty */
work = atomic(L); /* work is what was traversed by 'atomic' */
- sw = entersweep(L);
+ entersweep(L);
g->GCestimate = gettotalbytes(g); /* first estimate */;
- return work + sw * GCSWEEPCOST;
+ return work;
}
case GCSswpallgc: { /* sweep "regular" objects */
return sweepstep(L, g, GCSswpfinobj, &g->finobj);
@@ -1098,9 +1114,12 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
static l_mem getdebt (global_State *g) {
l_mem debt = g->GCdebt;
int stepmul = g->gcstepmul;
- debt = (debt / STEPMULADJ) + 1;
- debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
- return debt;
+ if (debt <= 0) return 0; /* minimal debt */
+ else {
+ debt = (debt / STEPMULADJ) + 1;
+ debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
+ return debt;
+ }
}
/*
diff --git a/src/lgc.h b/src/lgc.h
index 0eedf84204a3..aed3e18a5f04 100644
--- a/src/lgc.h
+++ b/src/lgc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.h,v 2.86 2014/10/25 11:50:46 roberto Exp $
+** $Id: lgc.h,v 2.91 2015/12/21 13:02:14 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -101,26 +101,35 @@
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
-#define luaC_condGC(L,c) \
- {if (G(L)->GCdebt > 0) {c;}; condchangemem(L);}
-#define luaC_checkGC(L) luaC_condGC(L, luaC_step(L);)
+/*
+** Does one step of collection when debt becomes positive. 'pre'/'pos'
+** allows some adjustments to be done only when needed. macro
+** 'condchangemem' is used only for heavy tests (forcing a full
+** GC cycle on every opportunity)
+*/
+#define luaC_condGC(L,pre,pos) \
+ { if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \
+ condchangemem(L,pre,pos); }
+
+/* more often than not, 'pre'/'pos' are empty */
+#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
-#define luaC_barrier(L,p,v) { \
- if (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) \
- luaC_barrier_(L,obj2gco(p),gcvalue(v)); }
+#define luaC_barrier(L,p,v) ( \
+ (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
+ luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
-#define luaC_barrierback(L,p,v) { \
- if (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) \
- luaC_barrierback_(L,p); }
+#define luaC_barrierback(L,p,v) ( \
+ (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
+ luaC_barrierback_(L,p) : cast_void(0))
-#define luaC_objbarrier(L,p,o) { \
- if (isblack(p) && iswhite(o)) \
- luaC_barrier_(L,obj2gco(p),obj2gco(o)); }
+#define luaC_objbarrier(L,p,o) ( \
+ (isblack(p) && iswhite(o)) ? \
+ luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
-#define luaC_upvalbarrier(L,uv) \
- { if (iscollectable((uv)->v) && !upisopen(uv)) \
- luaC_upvalbarrier_(L,uv); }
+#define luaC_upvalbarrier(L,uv) ( \
+ (iscollectable((uv)->v) && !upisopen(uv)) ? \
+ luaC_upvalbarrier_(L,uv) : cast_void(0))
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
diff --git a/src/linit.c b/src/linit.c
index 8ce94ccb3554..afcaf98b24bd 100644
--- a/src/linit.c
+++ b/src/linit.c
@@ -1,5 +1,5 @@
/*
-** $Id: linit.c,v 1.38 2015/01/05 13:48:33 roberto Exp $
+** $Id: linit.c,v 1.39 2016/12/04 20:17:24 roberto Exp $
** Initialization of libraries for lua.c and other clients
** See Copyright Notice in lua.h
*/
@@ -18,10 +18,10 @@
** open the library, which is already linked to the application.
** For that, do the following code:
**
-** luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
+** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
** lua_pushcfunction(L, luaopen_modname);
** lua_setfield(L, -2, modname);
-** lua_pop(L, 1); // remove _PRELOAD table
+** lua_pop(L, 1); // remove PRELOAD table
*/
#include "lprefix.h"
diff --git a/src/liolib.c b/src/liolib.c
index 4dea39684a3b..156840358d0e 100644
--- a/src/liolib.c
+++ b/src/liolib.c
@@ -1,5 +1,5 @@
/*
-** $Id: liolib.c,v 2.142 2015/01/02 12:50:28 roberto Exp $
+** $Id: liolib.c,v 2.151 2016/12/20 18:37:00 roberto Exp $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
@@ -23,18 +23,25 @@
#include "lualib.h"
-#if !defined(l_checkmode)
+
/*
-** Check whether 'mode' matches '[rwa]%+?b?'.
** Change this macro to accept other modes for 'fopen' besides
** the standard ones.
*/
-#define l_checkmode(mode) \
- (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \
- (*mode != '+' || ++mode) && /* skip if char is '+' */ \
- (*mode != 'b' || ++mode) && /* skip if char is 'b' */ \
- (*mode == '\0'))
+#if !defined(l_checkmode)
+
+/* accepted extensions to 'mode' in 'fopen' */
+#if !defined(L_MODEEXT)
+#define L_MODEEXT "b"
+#endif
+
+/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */
+static int l_checkmode (const char *mode) {
+ return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL &&
+ (*mode != '+' || (++mode, 1)) && /* skip if char is '+' */
+ (strspn(mode, L_MODEEXT) == strlen(mode))); /* check extensions */
+}
#endif
@@ -176,7 +183,7 @@ static FILE *tofile (lua_State *L) {
/*
** When creating file handles, always creates a 'closed' file handle
** before opening the actual file; so, if there is a memory error, the
-** file is not left opened.
+** handle is in a consistent state.
*/
static LStream *newprefile (lua_State *L) {
LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream));
@@ -318,8 +325,15 @@ static int io_output (lua_State *L) {
static int io_readline (lua_State *L);
+/*
+** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit
+** in the limit for upvalues of a closure)
+*/
+#define MAXARGLINE 250
+
static void aux_lines (lua_State *L, int toclose) {
int n = lua_gettop(L) - 1; /* number of arguments to read */
+ luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments");
lua_pushinteger(L, n); /* number of arguments to read */
lua_pushboolean(L, toclose); /* close/not close file when finished */
lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */
@@ -362,14 +376,17 @@ static int io_lines (lua_State *L) {
/* maximum length of a numeral */
-#define MAXRN 200
+#if !defined (L_MAXLENNUM)
+#define L_MAXLENNUM 200
+#endif
+
/* auxiliary structure used by 'read_number' */
typedef struct {
FILE *f; /* file being read */
int c; /* current character (look ahead) */
int n; /* number of elements in buffer 'buff' */
- char buff[MAXRN + 1]; /* +1 for ending '\0' */
+ char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */
} RN;
@@ -377,7 +394,7 @@ typedef struct {
** Add current char to buffer (if not out of space) and read next one
*/
static int nextc (RN *rn) {
- if (rn->n >= MAXRN) { /* buffer overflow? */
+ if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */
rn->buff[0] = '\0'; /* invalidate result */
return 0; /* fail */
}
@@ -390,10 +407,10 @@ static int nextc (RN *rn) {
/*
-** Accept current char if it is in 'set' (of size 1 or 2)
+** Accept current char if it is in 'set' (of size 2)
*/
static int test2 (RN *rn, const char *set) {
- if (rn->c == set[0] || (rn->c == set[1] && rn->c != '\0'))
+ if (rn->c == set[0] || rn->c == set[1])
return nextc(rn);
else return 0;
}
@@ -410,12 +427,6 @@ static int readdigits (RN *rn, int hex) {
}
-/* access to locale "radix character" (decimal point) */
-#if !defined(l_getlocaledecpoint)
-#define l_getlocaledecpoint() (localeconv()->decimal_point[0])
-#endif
-
-
/*
** Read a number: first reads a valid prefix of a numeral into a buffer.
** Then it calls 'lua_stringtonumber' to check whether the format is
@@ -425,13 +436,14 @@ static int read_number (lua_State *L, FILE *f) {
RN rn;
int count = 0;
int hex = 0;
- char decp[2] = ".";
+ char decp[2];
rn.f = f; rn.n = 0;
- decp[0] = l_getlocaledecpoint(); /* get decimal point from locale */
+ decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */
+ decp[1] = '.'; /* always accept a dot */
l_lockfile(rn.f);
do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */
test2(&rn, "-+"); /* optional signal */
- if (test2(&rn, "0")) {
+ if (test2(&rn, "00")) {
if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */
else count = 1; /* count initial '0' as a valid digit */
}
@@ -457,7 +469,7 @@ static int read_number (lua_State *L, FILE *f) {
static int test_eof (lua_State *L, FILE *f) {
int c = getc(f);
ungetc(c, f); /* no-op when c == EOF */
- lua_pushlstring(L, NULL, 0);
+ lua_pushliteral(L, "");
return (c != EOF);
}
@@ -467,7 +479,7 @@ static int read_line (lua_State *L, FILE *f, int chop) {
int c = '\0';
luaL_buffinit(L, &b);
while (c != EOF && c != '\n') { /* repeat until end of line */
- char *buff = luaL_prepbuffer(&b); /* pre-allocate buffer */
+ char *buff = luaL_prepbuffer(&b); /* preallocate buffer */
int i = 0;
l_lockfile(f); /* no memory errors can happen inside the lock */
while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n')
@@ -488,7 +500,7 @@ static void read_all (lua_State *L, FILE *f) {
luaL_Buffer b;
luaL_buffinit(L, &b);
do { /* read file in chunks of LUAL_BUFFERSIZE bytes */
- char *p = luaL_prepbuffsize(&b, LUAL_BUFFERSIZE);
+ char *p = luaL_prepbuffer(&b);
nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f);
luaL_addsize(&b, nr);
} while (nr == LUAL_BUFFERSIZE);
@@ -607,8 +619,10 @@ static int g_write (lua_State *L, FILE *f, int arg) {
if (lua_type(L, arg) == LUA_TNUMBER) {
/* optimization: could be done exactly as for strings */
int len = lua_isinteger(L, arg)
- ? fprintf(f, LUA_INTEGER_FMT, lua_tointeger(L, arg))
- : fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg));
+ ? fprintf(f, LUA_INTEGER_FMT,
+ (LUAI_UACINT)lua_tointeger(L, arg))
+ : fprintf(f, LUA_NUMBER_FMT,
+ (LUAI_UACNUMBER)lua_tonumber(L, arg));
status = status && (len > 0);
}
else {
diff --git a/src/llex.c b/src/llex.c
index 6e4a457ad635..70328273f7a9 100644
--- a/src/llex.c
+++ b/src/llex.c
@@ -1,5 +1,5 @@
/*
-** $Id: llex.c,v 2.89 2014/11/14 16:06:09 roberto Exp $
+** $Id: llex.c,v 2.96 2016/05/02 14:02:12 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -16,6 +16,7 @@
#include "lua.h"
#include "lctype.h"
+#include "ldebug.h"
#include "ldo.h"
#include "lgc.h"
#include "llex.h"
@@ -68,7 +69,7 @@ static void save (LexState *ls, int c) {
void luaX_init (lua_State *L) {
int i;
- TString *e = luaS_new(L, LUA_ENV); /* create env name */
+ TString *e = luaS_newliteral(L, LUA_ENV); /* create env name */
luaC_fix(L, obj2gco(e)); /* never collect this name */
for (i=0; i<NUM_RESERVED; i++) {
TString *ts = luaS_new(L, luaX_tokens[i]);
@@ -106,9 +107,7 @@ static const char *txtToken (LexState *ls, int token) {
static l_noret lexerror (LexState *ls, const char *msg, int token) {
- char buff[LUA_IDSIZE];
- luaO_chunkid(buff, getstr(ls->source), LUA_IDSIZE);
- msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg);
+ msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber);
if (token)
luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token));
luaD_throw(ls->L, LUA_ERRSYNTAX);
@@ -163,7 +162,6 @@ static void inclinenumber (LexState *ls) {
void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
int firstchar) {
ls->t.token = 0;
- ls->decpoint = '.';
ls->L = L;
ls->current = firstchar;
ls->lookahead.token = TK_EOS; /* no look-ahead token */
@@ -172,7 +170,7 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
ls->linenumber = 1;
ls->lastline = 1;
ls->source = source;
- ls->envn = luaS_new(L, LUA_ENV); /* get env name */
+ ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */
luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
}
@@ -208,42 +206,6 @@ static int check_next2 (LexState *ls, const char *set) {
}
-/*
-** change all characters 'from' in buffer to 'to'
-*/
-static void buffreplace (LexState *ls, char from, char to) {
- if (from != to) {
- size_t n = luaZ_bufflen(ls->buff);
- char *p = luaZ_buffer(ls->buff);
- while (n--)
- if (p[n] == from) p[n] = to;
- }
-}
-
-
-#if !defined(l_getlocaledecpoint)
-#define l_getlocaledecpoint() (localeconv()->decimal_point[0])
-#endif
-
-
-#define buff2num(b,o) (luaO_str2num(luaZ_buffer(b), o) != 0)
-
-/*
-** in case of format error, try to change decimal point separator to
-** the one defined in the current locale and check again
-*/
-static void trydecpoint (LexState *ls, TValue *o) {
- char old = ls->decpoint;
- ls->decpoint = l_getlocaledecpoint();
- buffreplace(ls, old, ls->decpoint); /* try new decimal separator */
- if (!buff2num(ls->buff, o)) {
- /* format error with correct decimal point: no more options */
- buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */
- lexerror(ls, "malformed number", TK_FLT);
- }
-}
-
-
/* LUA_NUMBER */
/*
** this function is quite liberal in what it accepts, as 'luaO_str2num'
@@ -267,9 +229,8 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) {
else break;
}
save(ls, '\0');
- buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
- if (!buff2num(ls->buff, &obj)) /* format error? */
- trydecpoint(ls, &obj); /* try to update decimal point separator */
+ if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */
+ lexerror(ls, "malformed number", TK_FLT);
if (ttisinteger(&obj)) {
seminfo->i = ivalue(&obj);
return TK_INT;
@@ -283,8 +244,9 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) {
/*
-** skip a sequence '[=*[' or ']=*]' and return its number of '='s or
-** -1 if sequence is malformed
+** skip a sequence '[=*[' or ']=*]'; if sequence is well formed, return
+** its number of '='s; otherwise, return a negative number (-1 iff there
+** are no '='s after initial bracket)
*/
static int skip_sep (LexState *ls) {
int count = 0;
@@ -501,8 +463,9 @@ static int llex (LexState *ls, SemInfo *seminfo) {
read_long_string(ls, seminfo, sep);
return TK_STRING;
}
- else if (sep == -1) return '[';
- else lexerror(ls, "invalid long string delimiter", TK_STRING);
+ else if (sep != -1) /* '[=...' missing second bracket */
+ lexerror(ls, "invalid long string delimiter", TK_STRING);
+ return '[';
}
case '=': {
next(ls);
diff --git a/src/llex.h b/src/llex.h
index afb40b56228f..2363d87e40ea 100644
--- a/src/llex.h
+++ b/src/llex.h
@@ -1,5 +1,5 @@
/*
-** $Id: llex.h,v 1.78 2014/10/29 15:38:24 roberto Exp $
+** $Id: llex.h,v 1.79 2016/05/02 14:02:12 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -69,7 +69,6 @@ typedef struct LexState {
struct Dyndata *dyd; /* dynamic structures used by the parser */
TString *source; /* current source name */
TString *envn; /* environment variable name */
- char decpoint; /* locale decimal point */
} LexState;
diff --git a/src/llimits.h b/src/llimits.h
index 8f71a6ffb951..f21377fef981 100644
--- a/src/llimits.h
+++ b/src/llimits.h
@@ -1,5 +1,5 @@
/*
-** $Id: llimits.h,v 1.125 2014/12/19 13:30:23 roberto Exp $
+** $Id: llimits.h,v 1.141 2015/11/19 19:16:22 roberto Exp $
** Limits, basic types, and some other 'installation-dependent' definitions
** See Copyright Notice in lua.h
*/
@@ -52,11 +52,11 @@ typedef unsigned char lu_byte;
/*
-** conversion of pointer to integer:
+** conversion of pointer to unsigned integer:
** this is for hashing only; there is no problem if the integer
** cannot hold the whole pointer value
*/
-#define point2int(p) ((unsigned int)((size_t)(p) & UINT_MAX))
+#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX))
@@ -64,7 +64,13 @@ typedef unsigned char lu_byte;
#if defined(LUAI_USER_ALIGNMENT_T)
typedef LUAI_USER_ALIGNMENT_T L_Umaxalign;
#else
-typedef union { double u; void *s; lua_Integer i; long l; } L_Umaxalign;
+typedef union {
+ lua_Number n;
+ double u;
+ void *s;
+ lua_Integer i;
+ long l;
+} L_Umaxalign;
#endif
@@ -78,7 +84,7 @@ typedef LUAI_UACINT l_uacInt;
#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); }
+#define lua_longassert(c) ((c) ? (void)0 : lua_assert(0))
#else
#define lua_assert(c) ((void)0)
#define check_exp(c,e) (e)
@@ -88,22 +94,20 @@ typedef LUAI_UACINT l_uacInt;
/*
** assertion for checking API calls
*/
-#if defined(LUA_USE_APICHECK)
-#include <assert.h>
-#define luai_apicheck(e) assert(e)
-#else
-#define luai_apicheck(e) lua_assert(e)
+#if !defined(luai_apicheck)
+#define luai_apicheck(l,e) lua_assert(e)
#endif
-
-#define api_check(e,msg) luai_apicheck((e) && msg)
+#define api_check(l,e,msg) luai_apicheck(l,(e) && msg)
+/* macro to avoid warnings about unused variables */
#if !defined(UNUSED)
-#define UNUSED(x) ((void)(x)) /* to avoid warnings */
+#define UNUSED(x) ((void)(x))
#endif
+/* type casts (a macro highlights casts in the code) */
#define cast(t, exp) ((t)(exp))
#define cast_void(i) cast(void, (i))
@@ -149,11 +153,6 @@ typedef LUAI_UACINT l_uacInt;
#define LUAI_MAXCCALLS 200
#endif
-/*
-** maximum number of upvalues in a closure (both C and Lua). (Value
-** must fit in an unsigned char.)
-*/
-#define MAXUPVAL UCHAR_MAX
/*
@@ -168,10 +167,36 @@ typedef unsigned long Instruction;
+/*
+** Maximum length for short strings, that is, strings that are
+** internalized. (Cannot be smaller than reserved words or tags for
+** metamethods, as these strings must be internalized;
+** #("function") = 8, #("__newindex") = 10.)
+*/
+#if !defined(LUAI_MAXSHORTLEN)
+#define LUAI_MAXSHORTLEN 40
+#endif
+
-/* minimum size for the string table (must be power of 2) */
+/*
+** Initial size for the string table (must be power of 2).
+** The Lua core alone registers ~50 strings (reserved words +
+** metaevent keys + a few others). Libraries would typically add
+** a few dozens more.
+*/
#if !defined(MINSTRTABSIZE)
-#define MINSTRTABSIZE 64 /* minimum size for "predefined" strings */
+#define MINSTRTABSIZE 128
+#endif
+
+
+/*
+** Size of cache for strings in the API. 'N' is the number of
+** sets (better be a prime) and "M" is the size of each set (M == 1
+** makes a direct cache.)
+*/
+#if !defined(STRCACHE_N)
+#define STRCACHE_N 53
+#define STRCACHE_M 2
#endif
@@ -181,11 +206,19 @@ typedef unsigned long Instruction;
#endif
+/*
+** macros that are executed whenever program enters the Lua core
+** ('lua_lock') and leaves the core ('lua_unlock')
+*/
#if !defined(lua_lock)
#define lua_lock(L) ((void) 0)
#define lua_unlock(L) ((void) 0)
#endif
+/*
+** macro executed during Lua functions at points where the
+** function can yield.
+*/
#if !defined(luai_threadyield)
#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);}
#endif
@@ -223,20 +256,68 @@ typedef unsigned long Instruction;
/*
+** The luai_num* macros define the primitive operations over numbers.
+*/
+
+/* floor division (defined as 'floor(a/b)') */
+#if !defined(luai_numidiv)
+#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b)))
+#endif
+
+/* float division */
+#if !defined(luai_numdiv)
+#define luai_numdiv(L,a,b) ((a)/(b))
+#endif
+
+/*
+** modulo: defined as 'a - floor(a/b)*b'; this definition gives NaN when
+** 'b' is huge, but the result should be 'a'. 'fmod' gives the result of
+** 'a - trunc(a/b)*b', and therefore must be corrected when 'trunc(a/b)
+** ~= floor(a/b)'. That happens when the division has a non-integer
+** negative result, which is equivalent to the test below.
+*/
+#if !defined(luai_nummod)
+#define luai_nummod(L,a,b,m) \
+ { (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); }
+#endif
+
+/* exponentiation */
+#if !defined(luai_numpow)
+#define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b))
+#endif
+
+/* the others are quite standard operations */
+#if !defined(luai_numadd)
+#define luai_numadd(L,a,b) ((a)+(b))
+#define luai_numsub(L,a,b) ((a)-(b))
+#define luai_nummul(L,a,b) ((a)*(b))
+#define luai_numunm(L,a) (-(a))
+#define luai_numeq(a,b) ((a)==(b))
+#define luai_numlt(a,b) ((a)<(b))
+#define luai_numle(a,b) ((a)<=(b))
+#define luai_numisnan(a) (!luai_numeq((a), (a)))
+#endif
+
+
+
+
+
+/*
** macro to control inclusion of some hard tests on stack reallocation
*/
#if !defined(HARDSTACKTESTS)
-#define condmovestack(L) ((void)0)
+#define condmovestack(L,pre,pos) ((void)0)
#else
/* realloc stack keeping its size */
-#define condmovestack(L) luaD_reallocstack((L), (L)->stacksize)
+#define condmovestack(L,pre,pos) \
+ { int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_); pos; }
#endif
#if !defined(HARDMEMTESTS)
-#define condchangemem(L) condmovestack(L)
+#define condchangemem(L,pre,pos) ((void)0)
#else
-#define condchangemem(L) \
- ((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1)))
+#define condchangemem(L,pre,pos) \
+ { if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } }
#endif
#endif
diff --git a/src/lmathlib.c b/src/lmathlib.c
index 002c508bc465..b7f8baee076c 100644
--- a/src/lmathlib.c
+++ b/src/lmathlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lmathlib.c,v 1.114 2014/12/27 20:32:26 roberto Exp $
+** $Id: lmathlib.c,v 1.119 2016/12/22 13:08:50 roberto Exp $
** Standard mathematical library
** See Copyright Notice in lua.h
*/
@@ -39,7 +39,7 @@
static int math_abs (lua_State *L) {
if (lua_isinteger(L, 1)) {
lua_Integer n = lua_tointeger(L, 1);
- if (n < 0) n = (lua_Integer)(0u - n);
+ if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n);
lua_pushinteger(L, n);
}
else
@@ -183,8 +183,14 @@ static int math_log (lua_State *L) {
res = l_mathop(log)(x);
else {
lua_Number base = luaL_checknumber(L, 2);
- if (base == 10.0) res = l_mathop(log10)(x);
- else res = l_mathop(log)(x)/l_mathop(log)(base);
+#if !defined(LUA_USE_C89)
+ if (base == l_mathop(2.0))
+ res = l_mathop(log2)(x); else
+#endif
+ if (base == l_mathop(10.0))
+ res = l_mathop(log10)(x);
+ else
+ res = l_mathop(log)(x)/l_mathop(log)(base);
}
lua_pushnumber(L, res);
return 1;
@@ -259,7 +265,7 @@ static int math_random (lua_State *L) {
default: return luaL_error(L, "wrong number of arguments");
}
/* random integer in the interval [low, up] */
- luaL_argcheck(L, low <= up, 1, "interval is empty");
+ luaL_argcheck(L, low <= up, 1, "interval is empty");
luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1,
"interval too large");
r *= (double)(up - low) + 1.0;
@@ -270,7 +276,7 @@ static int math_random (lua_State *L) {
static int math_randomseed (lua_State *L) {
l_srand((unsigned int)(lua_Integer)luaL_checknumber(L, 1));
- (void)rand(); /* discard first value to avoid undesirable correlations */
+ (void)l_rand(); /* discard first value to avoid undesirable correlations */
return 0;
}
@@ -278,9 +284,9 @@ static int math_randomseed (lua_State *L) {
static int math_type (lua_State *L) {
if (lua_type(L, 1) == LUA_TNUMBER) {
if (lua_isinteger(L, 1))
- lua_pushliteral(L, "integer");
+ lua_pushliteral(L, "integer");
else
- lua_pushliteral(L, "float");
+ lua_pushliteral(L, "float");
}
else {
luaL_checkany(L, 1);
diff --git a/src/lmem.c b/src/lmem.c
index 4feaf036c726..0a0476cc7739 100644
--- a/src/lmem.c
+++ b/src/lmem.c
@@ -1,5 +1,5 @@
/*
-** $Id: lmem.c,v 1.89 2014/11/02 19:33:33 roberto Exp $
+** $Id: lmem.c,v 1.91 2015/03/06 19:45:54 roberto Exp $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
@@ -85,10 +85,11 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
#endif
newblock = (*g->frealloc)(g->ud, block, osize, nsize);
if (newblock == NULL && nsize > 0) {
- api_check( nsize > realosize,
- "realloc cannot fail when shrinking a block");
- luaC_fullgc(L, 1); /* try to free some memory... */
- newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
+ lua_assert(nsize > realosize); /* cannot fail when shrinking a block */
+ if (g->version) { /* is state fully built? */
+ luaC_fullgc(L, 1); /* try to free some memory... */
+ newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
+ }
if (newblock == NULL)
luaD_throw(L, LUA_ERRMEM);
}
diff --git a/src/loadlib.c b/src/loadlib.c
index 7f8d99029866..4791e748b160 100644
--- a/src/loadlib.c
+++ b/src/loadlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: loadlib.c,v 1.124 2015/01/05 13:51:39 roberto Exp $
+** $Id: loadlib.c,v 1.130 2017/01/12 17:14:26 roberto Exp $
** Dynamic library loader for Lua
** See Copyright Notice in lua.h
**
@@ -14,6 +14,7 @@
#include "lprefix.h"
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -24,40 +25,9 @@
/*
-** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment
-** variables that Lua check to set its paths.
-*/
-#if !defined(LUA_PATH_VAR)
-#define LUA_PATH_VAR "LUA_PATH"
-#endif
-
-#if !defined(LUA_CPATH_VAR)
-#define LUA_CPATH_VAR "LUA_CPATH"
-#endif
-
-#define LUA_PATHSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
-
-#define LUA_PATHVARVERSION LUA_PATH_VAR LUA_PATHSUFFIX
-#define LUA_CPATHVARVERSION LUA_CPATH_VAR LUA_PATHSUFFIX
-
-/*
-** LUA_PATH_SEP is the character that separates templates in a path.
-** LUA_PATH_MARK is the string that marks the substitution points in a
-** template.
-** LUA_EXEC_DIR in a Windows path is replaced by the executable's
-** directory.
** LUA_IGMARK is a mark to ignore all before it when building the
** luaopen_ function name.
*/
-#if !defined (LUA_PATH_SEP)
-#define LUA_PATH_SEP ";"
-#endif
-#if !defined (LUA_PATH_MARK)
-#define LUA_PATH_MARK "?"
-#endif
-#if !defined (LUA_EXEC_DIR)
-#define LUA_EXEC_DIR "!"
-#endif
#if !defined (LUA_IGMARK)
#define LUA_IGMARK "-"
#endif
@@ -93,7 +63,8 @@ static const int CLIBS = 0;
#define LIB_FAIL "open"
-#define setprogdir(L) ((void)0)
+
+#define setprogdir(L) ((void)0)
/*
@@ -136,8 +107,8 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym);
#include <dlfcn.h>
/*
-** Macro to covert pointer to void* to pointer to function. This cast
-** is undefined according to ISO C, but POSIX assumes that it must work.
+** Macro to convert pointer-to-void* to pointer-to-function. This cast
+** is undefined according to ISO C, but POSIX assumes that it works.
** (The '__extension__' in gnu compilers is only to avoid warnings.)
*/
#if defined(__GNUC__)
@@ -178,7 +149,6 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
#include <windows.h>
-#undef setprogdir
/*
** optional flags for LoadLibraryEx
@@ -188,21 +158,30 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
#endif
+#undef setprogdir
+
+
+/*
+** Replace in the path (on the top of the stack) any occurrence
+** of LUA_EXEC_DIR with the executable's path.
+*/
static void setprogdir (lua_State *L) {
char buff[MAX_PATH + 1];
char *lb;
DWORD nsize = sizeof(buff)/sizeof(char);
- DWORD n = GetModuleFileNameA(NULL, buff, nsize);
+ DWORD n = GetModuleFileNameA(NULL, buff, nsize); /* get exec. name */
if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL)
luaL_error(L, "unable to get ModuleFileName");
else {
- *lb = '\0';
+ *lb = '\0'; /* cut name on the last '\\' to get the path */
luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff);
lua_remove(L, -2); /* remove original string */
}
}
+
+
static void pusherror (lua_State *L) {
int error = GetLastError();
char buffer[128];
@@ -272,6 +251,67 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
/*
+** {==================================================================
+** Set Paths
+** ===================================================================
+*/
+
+/*
+** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment
+** variables that Lua check to set its paths.
+*/
+#if !defined(LUA_PATH_VAR)
+#define LUA_PATH_VAR "LUA_PATH"
+#endif
+
+#if !defined(LUA_CPATH_VAR)
+#define LUA_CPATH_VAR "LUA_CPATH"
+#endif
+
+
+#define AUXMARK "\1" /* auxiliary mark */
+
+
+/*
+** return registry.LUA_NOENV as a boolean
+*/
+static int noenv (lua_State *L) {
+ int b;
+ lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
+ b = lua_toboolean(L, -1);
+ lua_pop(L, 1); /* remove value */
+ return b;
+}
+
+
+/*
+** Set a path
+*/
+static void setpath (lua_State *L, const char *fieldname,
+ const char *envname,
+ const char *dft) {
+ const char *nver = lua_pushfstring(L, "%s%s", envname, LUA_VERSUFFIX);
+ const char *path = getenv(nver); /* use versioned name */
+ if (path == NULL) /* no environment variable? */
+ path = getenv(envname); /* try unversioned name */
+ if (path == NULL || noenv(L)) /* no environment variable? */
+ lua_pushstring(L, dft); /* use default */
+ else {
+ /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
+ path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP,
+ LUA_PATH_SEP AUXMARK LUA_PATH_SEP);
+ luaL_gsub(L, path, AUXMARK, dft);
+ lua_remove(L, -2); /* remove result from 1st 'gsub' */
+ }
+ setprogdir(L);
+ lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */
+ lua_pop(L, 1); /* pop versioned variable name */
+}
+
+/* }================================================================== */
+
+
+/*
** return registry.CLIBS[path]
*/
static void *checkclib (lua_State *L, const char *path) {
@@ -519,7 +559,7 @@ static int searcher_Croot (lua_State *L) {
static int searcher_preload (lua_State *L) {
const char *name = luaL_checkstring(L, 1);
- lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD");
+ lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */
lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
return 1;
@@ -556,9 +596,9 @@ static void findloader (lua_State *L, const char *name) {
static int ll_require (lua_State *L) {
const char *name = luaL_checkstring(L, 1);
- lua_settop(L, 1); /* _LOADED table will be at index 2 */
- lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
- lua_getfield(L, 2, name); /* _LOADED[name] */
+ lua_settop(L, 1); /* LOADED table will be at index 2 */
+ lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
+ lua_getfield(L, 2, name); /* LOADED[name] */
if (lua_toboolean(L, -1)) /* is it there? */
return 1; /* package is already loaded */
/* else must load package */
@@ -568,11 +608,11 @@ static int ll_require (lua_State *L) {
lua_insert(L, -2); /* name is 1st argument (before search data) */
lua_call(L, 2, 1); /* run loader to load module */
if (!lua_isnil(L, -1)) /* non-nil return? */
- lua_setfield(L, 2, name); /* _LOADED[name] = returned value */
+ lua_setfield(L, 2, name); /* LOADED[name] = returned value */
if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */
lua_pushboolean(L, 1); /* use true as result */
lua_pushvalue(L, -1); /* extra copy to be returned */
- lua_setfield(L, 2, name); /* _LOADED[name] = true */
+ lua_setfield(L, 2, name); /* LOADED[name] = true */
}
return 1;
}
@@ -665,41 +705,6 @@ static int ll_seeall (lua_State *L) {
-/* auxiliary mark (for internal use) */
-#define AUXMARK "\1"
-
-
-/*
-** return registry.LUA_NOENV as a boolean
-*/
-static int noenv (lua_State *L) {
- int b;
- lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
- b = lua_toboolean(L, -1);
- lua_pop(L, 1); /* remove value */
- return b;
-}
-
-
-static void setpath (lua_State *L, const char *fieldname, const char *envname1,
- const char *envname2, const char *def) {
- const char *path = getenv(envname1);
- if (path == NULL) /* no environment variable? */
- path = getenv(envname2); /* try alternative name */
- if (path == NULL || noenv(L)) /* no environment variable? */
- lua_pushstring(L, def); /* use default */
- else {
- /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
- path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP,
- LUA_PATH_SEP AUXMARK LUA_PATH_SEP);
- luaL_gsub(L, path, AUXMARK, def);
- lua_remove(L, -2);
- }
- setprogdir(L);
- lua_setfield(L, -2, fieldname);
-}
-
-
static const luaL_Reg pk_funcs[] = {
{"loadlib", ll_loadlib},
{"searchpath", ll_searchpath},
@@ -731,7 +736,7 @@ static void createsearcherstable (lua_State *L) {
int i;
/* create 'searchers' table */
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
- /* fill it with pre-defined searchers */
+ /* fill it with predefined searchers */
for (i=0; searchers[i] != NULL; i++) {
lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */
lua_pushcclosure(L, searchers[i], 1);
@@ -763,19 +768,18 @@ LUAMOD_API int luaopen_package (lua_State *L) {
createclibstable(L);
luaL_newlib(L, pk_funcs); /* create 'package' table */
createsearcherstable(L);
- /* set field 'path' */
- setpath(L, "path", LUA_PATHVARVERSION, LUA_PATH_VAR, LUA_PATH_DEFAULT);
- /* set field 'cpath' */
- setpath(L, "cpath", LUA_CPATHVARVERSION, LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
+ /* set paths */
+ setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT);
+ setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
/* store config information */
lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n"
LUA_EXEC_DIR "\n" LUA_IGMARK "\n");
lua_setfield(L, -2, "config");
/* set field 'loaded' */
- luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
+ luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
lua_setfield(L, -2, "loaded");
/* set field 'preload' */
- luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
+ luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
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 6a24aff95d9a..2da76899a27e 100644
--- a/src/lobject.c
+++ b/src/lobject.c
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.c,v 2.101 2014/12/26 14:43:45 roberto Exp $
+** $Id: lobject.c,v 2.113 2016/12/22 13:08:50 roberto Exp $
** Some generic functions over Lua objects
** See Copyright Notice in lua.h
*/
@@ -10,6 +10,8 @@
#include "lprefix.h"
+#include <locale.h>
+#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -39,8 +41,12 @@ LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT};
int luaO_int2fb (unsigned int x) {
int e = 0; /* exponent */
if (x < 8) return x;
- while (x >= 0x10) {
- x = (x+1) >> 1;
+ while (x >= (8 << 4)) { /* coarse steps */
+ x = (x + 0xf) >> 4; /* x = ceil(x / 16) */
+ e += 4;
+ }
+ while (x >= (8 << 1)) { /* fine steps */
+ x = (x + 1) >> 1; /* x = ceil(x / 2) */
e++;
}
return ((e+1) << 3) | (cast_int(x) - 8);
@@ -49,14 +55,15 @@ int luaO_int2fb (unsigned int x) {
/* converts back */
int luaO_fb2int (int x) {
- int e = (x >> 3) & 0x1f;
- if (e == 0) return x;
- else return ((x & 7) + 8) << (e - 1);
+ return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1);
}
+/*
+** Computes ceil(log2(x))
+*/
int luaO_ceillog2 (unsigned int x) {
- static const lu_byte log_2[256] = {
+ static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
@@ -149,13 +156,13 @@ void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2,
}
/* could not perform raw operation; try metamethod */
lua_assert(L != NULL); /* should not fail when folding (compile time) */
- luaT_trybinTM(L, p1, p2, res, cast(TMS, op - LUA_OPADD + TM_ADD));
+ luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD));
}
int luaO_hexavalue (int c) {
if (lisdigit(c)) return c - '0';
- else return ltolower(c) - 'a' + 10;
+ else return (ltolower(c) - 'a') + 10;
}
@@ -172,9 +179,8 @@ static int isneg (const char **s) {
** Lua's implementation for 'lua_strx2number'
** ===================================================================
*/
-#if !defined(lua_strx2number)
-#include <math.h>
+#if !defined(lua_strx2number)
/* maximum number of significant digits to read (to avoid overflows
even with single floats) */
@@ -185,21 +191,22 @@ static int isneg (const char **s) {
** C99 specification for 'strtod'
*/
static lua_Number lua_strx2number (const char *s, char **endptr) {
+ int dot = lua_getlocaledecpoint();
lua_Number r = 0.0; /* result (accumulator) */
int sigdig = 0; /* number of significant digits */
int nosigdig = 0; /* number of non-significant digits */
int e = 0; /* exponent correction */
int neg; /* 1 if number is negative */
- int dot = 0; /* true after seen a dot */
+ int hasdot = 0; /* true after seen a dot */
*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') */
for (s += 2; ; s++) { /* skip '0x' and read numeral */
- if (*s == '.') {
- if (dot) break; /* second dot? stop loop */
- else dot = 1;
+ if (*s == dot) {
+ if (hasdot) break; /* second dot? stop loop */
+ else hasdot = 1;
}
else if (lisxdigit(cast_uchar(*s))) {
if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */
@@ -207,7 +214,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */
r = (r * cast_num(16.0)) + luaO_hexavalue(*s);
else e++; /* too many digits; ignore, but still count for exponent */
- if (dot) e--; /* decimal digit? correct exponent */
+ if (hasdot) e--; /* decimal digit? correct exponent */
}
else break; /* neither a dot nor a digit */
}
@@ -236,20 +243,59 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
/* }====================================================== */
-static const char *l_str2d (const char *s, lua_Number *result) {
+/* maximum length of a numeral */
+#if !defined (L_MAXLENNUM)
+#define L_MAXLENNUM 200
+#endif
+
+static const char *l_str2dloc (const char *s, lua_Number *result, int mode) {
char *endptr;
- if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */
+ *result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */
+ : lua_str2number(s, &endptr);
+ if (endptr == s) return NULL; /* nothing recognized? */
+ while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */
+ return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */
+}
+
+
+/*
+** Convert string 's' to a Lua number (put in 'result'). Return NULL
+** on fail or the address of the ending '\0' on success.
+** 'pmode' points to (and 'mode' contains) special things in the string:
+** - 'x'/'X' means an hexadecimal numeral
+** - 'n'/'N' means 'inf' or 'nan' (which should be rejected)
+** - '.' just optimizes the search for the common case (nothing special)
+** This function accepts both the current locale or a dot as the radix
+** mark. If the convertion fails, it may mean number has a dot but
+** locale accepts something else. In that case, the code copies 's'
+** to a buffer (because 's' is read-only), changes the dot to the
+** current locale radix mark, and tries to convert again.
+*/
+static const char *l_str2d (const char *s, lua_Number *result) {
+ const char *endptr;
+ const char *pmode = strpbrk(s, ".xXnN");
+ int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0;
+ if (mode == 'n') /* reject 'inf' and 'nan' */
return NULL;
- else if (strpbrk(s, "xX")) /* hex? */
- *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 == '\0' ? endptr : NULL); /* OK if no trailing characters */
+ endptr = l_str2dloc(s, result, mode); /* try to convert */
+ if (endptr == NULL) { /* failed? may be a different locale */
+ char buff[L_MAXLENNUM + 1];
+ const char *pdot = strchr(s, '.');
+ if (strlen(s) > L_MAXLENNUM || pdot == NULL)
+ return NULL; /* string too long or no dot; fail */
+ strcpy(buff, s); /* copy string to buffer */
+ buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */
+ endptr = l_str2dloc(buff, result, mode); /* try again */
+ if (endptr != NULL)
+ endptr = s + (endptr - buff); /* make relative to 's' */
+ }
+ return endptr;
}
+#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10)
+#define MAXLASTD cast_int(LUA_MAXINTEGER % 10)
+
static const char *l_str2int (const char *s, lua_Integer *result) {
lua_Unsigned a = 0;
int empty = 1;
@@ -266,7 +312,10 @@ static const char *l_str2int (const char *s, lua_Integer *result) {
}
else { /* decimal */
for (; lisdigit(cast_uchar(*s)); s++) {
- a = a * 10 + *s - '0';
+ int d = *s - '0';
+ if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */
+ return NULL; /* do not accept it (as integer) */
+ a = a * 10 + d;
empty = 0;
}
}
@@ -290,7 +339,7 @@ size_t luaO_str2num (const char *s, TValue *o) {
}
else
return 0; /* conversion failed */
- return (e - s + 1); /* success; return string size */
+ return (e - s) + 1; /* success; return string size */
}
@@ -324,12 +373,12 @@ void luaO_tostring (lua_State *L, StkId obj) {
size_t len;
lua_assert(ttisnumber(obj));
if (ttisinteger(obj))
- len = lua_integer2str(buff, ivalue(obj));
+ len = lua_integer2str(buff, sizeof(buff), ivalue(obj));
else {
- len = lua_number2str(buff, fltvalue(obj));
+ len = lua_number2str(buff, sizeof(buff), fltvalue(obj));
#if !defined(LUA_COMPAT_FLOATSTRING)
if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */
- buff[len++] = '.';
+ buff[len++] = lua_getlocaledecpoint();
buff[len++] = '0'; /* adds '.0' to result */
}
#endif
@@ -339,27 +388,29 @@ void luaO_tostring (lua_State *L, StkId obj) {
static void pushstr (lua_State *L, const char *str, size_t l) {
- setsvalue2s(L, L->top++, luaS_newlstr(L, str, l));
+ setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
+ luaD_inctop(L);
}
-/* this function handles only '%d', '%c', '%f', '%p', and '%s'
- conventional formats, plus Lua-specific '%I' and '%U' */
+/*
+** this function handles only '%d', '%c', '%f', '%p', and '%s'
+ conventional formats, plus Lua-specific '%I' and '%U'
+*/
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
int n = 0;
for (;;) {
const char *e = strchr(fmt, '%');
if (e == NULL) break;
- luaD_checkstack(L, 2); /* fmt + item */
pushstr(L, fmt, e - fmt);
switch (*(e+1)) {
- case 's': {
+ case 's': { /* zero-terminated string */
const char *s = va_arg(argp, char *);
if (s == NULL) s = "(null)";
pushstr(L, s, strlen(s));
break;
}
- case 'c': {
+ case 'c': { /* an 'int' as a character */
char buff = cast(char, va_arg(argp, int));
if (lisprint(cast_uchar(buff)))
pushstr(L, &buff, 1);
@@ -367,28 +418,28 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
luaO_pushfstring(L, "<\\%d>", cast_uchar(buff));
break;
}
- case 'd': {
- setivalue(L->top++, va_arg(argp, int));
- luaO_tostring(L, L->top - 1);
- break;
+ case 'd': { /* an 'int' */
+ setivalue(L->top, va_arg(argp, int));
+ goto top2str;
}
- case 'I': {
- setivalue(L->top++, cast(lua_Integer, va_arg(argp, l_uacInt)));
- luaO_tostring(L, L->top - 1);
- break;
+ case 'I': { /* a 'lua_Integer' */
+ setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt)));
+ goto top2str;
}
- case 'f': {
- setfltvalue(L->top++, cast_num(va_arg(argp, l_uacNumber)));
+ case 'f': { /* a 'lua_Number' */
+ setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber)));
+ top2str: /* convert the top element to a string */
+ luaD_inctop(L);
luaO_tostring(L, L->top - 1);
break;
}
- case 'p': {
+ case 'p': { /* a pointer */
char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */
- int l = sprintf(buff, "%p", va_arg(argp, void *));
+ int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *));
pushstr(L, buff, l);
break;
}
- case 'U': {
+ case 'U': { /* an 'int' as a UTF-8 sequence */
char buff[UTF8BUFFSZ];
int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long)));
pushstr(L, buff + UTF8BUFFSZ - l, l);
diff --git a/src/lobject.h b/src/lobject.h
index d7d0ebf31b05..3c042289492b 100644
--- a/src/lobject.h
+++ b/src/lobject.h
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.h,v 2.106 2015/01/05 13:52:37 roberto Exp $
+** $Id: lobject.h,v 2.117 2016/08/01 19:51:24 roberto Exp $
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
@@ -19,8 +19,8 @@
/*
** Extra tags for non-values
*/
-#define LUA_TPROTO LUA_NUMTAGS
-#define LUA_TDEADKEY (LUA_NUMTAGS+1)
+#define LUA_TPROTO LUA_NUMTAGS /* function prototypes */
+#define LUA_TDEADKEY (LUA_NUMTAGS+1) /* removed keys in tables */
/*
** number of all possible tags (including LUA_TNONE but excluding DEADKEY)
@@ -35,8 +35,6 @@
** bit 6: whether value is collectable
*/
-#define VARBITS (3 << 4)
-
/*
** LUA_TFUNCTION variants:
@@ -90,22 +88,32 @@ struct GCObject {
-/*
-** Union of all Lua values
-*/
-typedef union Value Value;
-
-
-
/*
** Tagged Values. This is the basic representation of values in Lua,
** an actual value plus a tag with its type.
*/
+/*
+** Union of all Lua values
+*/
+typedef union Value {
+ GCObject *gc; /* collectable objects */
+ void *p; /* light userdata */
+ int b; /* booleans */
+ lua_CFunction f; /* light C functions */
+ lua_Integer i; /* integer numbers */
+ lua_Number n; /* float numbers */
+} Value;
+
+
#define TValuefields Value value_; int tt_
-typedef struct lua_TValue TValue;
+
+typedef struct lua_TValue {
+ TValuefields;
+} TValue;
+
/* macro defining a nil value */
@@ -179,9 +187,9 @@ typedef struct lua_TValue TValue;
/* Macros for internal tests */
#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt)
-#define checkliveness(g,obj) \
+#define checkliveness(L,obj) \
lua_longassert(!iscollectable(obj) || \
- (righttt(obj) && !isdead(g,gcvalue(obj))))
+ (righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj)))))
/* Macros to set values */
@@ -190,9 +198,15 @@ typedef struct lua_TValue TValue;
#define setfltvalue(obj,x) \
{ TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_TNUMFLT); }
+#define chgfltvalue(obj,x) \
+ { TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); }
+
#define setivalue(obj,x) \
{ TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); }
+#define chgivalue(obj,x) \
+ { TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); }
+
#define setnilvalue(obj) settt_(obj, LUA_TNIL)
#define setfvalue(obj,x) \
@@ -211,32 +225,32 @@ typedef struct lua_TValue TValue;
#define setsvalue(L,obj,x) \
{ TValue *io = (obj); TString *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \
- checkliveness(G(L),io); }
+ checkliveness(L,io); }
#define setuvalue(L,obj,x) \
{ TValue *io = (obj); Udata *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \
- checkliveness(G(L),io); }
+ checkliveness(L,io); }
#define setthvalue(L,obj,x) \
{ TValue *io = (obj); lua_State *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \
- checkliveness(G(L),io); }
+ checkliveness(L,io); }
#define setclLvalue(L,obj,x) \
{ TValue *io = (obj); LClosure *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \
- checkliveness(G(L),io); }
+ checkliveness(L,io); }
#define setclCvalue(L,obj,x) \
{ TValue *io = (obj); CClosure *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \
- checkliveness(G(L),io); }
+ checkliveness(L,io); }
#define sethvalue(L,obj,x) \
{ TValue *io = (obj); Table *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \
- checkliveness(G(L),io); }
+ checkliveness(L,io); }
#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY)
@@ -244,7 +258,7 @@ typedef struct lua_TValue TValue;
#define setobj(L,obj1,obj2) \
{ TValue *io1=(obj1); *io1 = *(obj2); \
- (void)L; checkliveness(G(L),io1); }
+ (void)L; checkliveness(L,io1); }
/*
@@ -260,12 +274,13 @@ typedef struct lua_TValue TValue;
#define setptvalue2s setptvalue
/* from table to same table */
#define setobjt2t setobj
-/* to table */
-#define setobj2t setobj
/* to new object */
#define setobj2n setobj
#define setsvalue2n setsvalue
+/* to table (define it as an expression to be used in macros) */
+#define setobj2t(L,o1,o2) ((void)L, *(o1)=*(o2), checkliveness(L,(o1)))
+
@@ -276,21 +291,6 @@ typedef struct lua_TValue TValue;
*/
-union Value {
- GCObject *gc; /* collectable objects */
- void *p; /* light userdata */
- int b; /* booleans */
- lua_CFunction f; /* light C functions */
- lua_Integer i; /* integer numbers */
- lua_Number n; /* float numbers */
-};
-
-
-struct lua_TValue {
- TValuefields;
-};
-
-
typedef TValue *StkId; /* index to stack elements */
@@ -303,9 +303,12 @@ typedef TValue *StkId; /* index to stack elements */
typedef struct TString {
CommonHeader;
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
+ lu_byte shrlen; /* length for short strings */
unsigned int hash;
- size_t len; /* number of characters in string */
- struct TString *hnext; /* linked list for hash table */
+ union {
+ size_t lnglen; /* length for long strings */
+ struct TString *hnext; /* linked list for hash table */
+ } u;
} TString;
@@ -322,13 +325,19 @@ typedef union UTString {
** Get the actual string (array of bytes) from a 'TString'.
** (Access to 'extra' ensures that value is really a 'TString'.)
*/
-#define getaddrstr(ts) (cast(char *, (ts)) + sizeof(UTString))
#define getstr(ts) \
- check_exp(sizeof((ts)->extra), cast(const char*, getaddrstr(ts)))
+ check_exp(sizeof((ts)->extra), cast(char *, (ts)) + sizeof(UTString))
+
/* get the actual string (array of bytes) from a Lua value */
#define svalue(o) getstr(tsvalue(o))
+/* get string length from 'TString *s' */
+#define tsslen(s) ((s)->tt == LUA_TSHRSTR ? (s)->shrlen : (s)->u.lnglen)
+
+/* get string length from 'TValue *o' */
+#define vslen(o) tsslen(tsvalue(o))
+
/*
** Header for userdata; memory area follows the end of this structure
@@ -361,14 +370,14 @@ typedef union UUdata {
#define setuservalue(L,u,o) \
{ const TValue *io=(o); Udata *iu = (u); \
- iu->user_ = io->value_; iu->ttuv_ = io->tt_; \
- checkliveness(G(L),io); }
+ iu->user_ = io->value_; iu->ttuv_ = rttype(io); \
+ checkliveness(L,io); }
#define getuservalue(L,u,o) \
{ TValue *io=(o); const Udata *iu = (u); \
- io->value_ = iu->user_; io->tt_ = iu->ttuv_; \
- checkliveness(G(L),io); }
+ io->value_ = iu->user_; settt_(io, iu->ttuv_); \
+ checkliveness(L,io); }
/*
@@ -376,7 +385,7 @@ typedef union UUdata {
*/
typedef struct Upvaldesc {
TString *name; /* upvalue name (for debug information) */
- lu_byte instack; /* whether it is in stack */
+ lu_byte instack; /* whether it is in stack (register) */
lu_byte idx; /* index of upvalue (in stack or in outer function's list) */
} Upvaldesc;
@@ -399,22 +408,22 @@ typedef struct Proto {
CommonHeader;
lu_byte numparams; /* number of fixed parameters */
lu_byte is_vararg;
- lu_byte maxstacksize; /* maximum stack used by this function */
+ lu_byte maxstacksize; /* number of registers needed by this function */
int sizeupvalues; /* size of 'upvalues' */
int sizek; /* size of 'k' */
int sizecode;
int sizelineinfo;
int sizep; /* size of 'p' */
int sizelocvars;
- int linedefined;
- int lastlinedefined;
+ int linedefined; /* debug information */
+ int lastlinedefined; /* debug information */
TValue *k; /* constants used by the function */
- Instruction *code;
+ Instruction *code; /* opcodes */
struct Proto **p; /* functions defined inside the function */
int *lineinfo; /* map from opcodes to source lines (debug information) */
LocVar *locvars; /* information about local variables (debug information) */
Upvaldesc *upvalues; /* upvalue information */
- struct LClosure *cache; /* last created closure with this prototype */
+ struct LClosure *cache; /* last-created closure with this prototype */
TString *source; /* used for debug information */
GCObject *gclist;
} Proto;
@@ -476,7 +485,7 @@ typedef union TKey {
#define setnodekey(L,key,obj) \
{ TKey *k_=(key); const TValue *io_=(obj); \
k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \
- (void)L; checkliveness(G(L),io_); }
+ (void)L; checkliveness(L,io_); }
typedef struct Node {
diff --git a/src/lopcodes.h b/src/lopcodes.h
index 864b8e4bb5d4..bbc4b61968aa 100644
--- a/src/lopcodes.h
+++ b/src/lopcodes.h
@@ -1,5 +1,5 @@
/*
-** $Id: lopcodes.h,v 1.148 2014/10/25 11:50:46 roberto Exp $
+** $Id: lopcodes.h,v 1.149 2016/07/19 17:12:21 roberto Exp $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -139,7 +139,9 @@ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */
/* gets the index of the constant */
#define INDEXK(r) ((int)(r) & ~BITRK)
+#if !defined(MAXINDEXRK) /* (for debugging only) */
#define MAXINDEXRK (BITRK - 1)
+#endif
/* code a constant index as a RK value */
#define RKASK(x) ((x) | BITRK)
diff --git a/src/loslib.c b/src/loslib.c
index 20359b24747c..5a94eb9068d5 100644
--- a/src/loslib.c
+++ b/src/loslib.c
@@ -1,5 +1,5 @@
/*
-** $Id: loslib.c,v 1.54 2014/12/26 14:46:07 roberto Exp $
+** $Id: loslib.c,v 1.65 2016/07/18 17:58:58 roberto Exp $
** Standard Operating System library
** See Copyright Notice in lua.h
*/
@@ -22,23 +22,42 @@
#include "lualib.h"
-#if !defined(LUA_STRFTIMEOPTIONS) /* { */
/*
-** list of valid conversion specifiers for the 'strftime' function
+** {==================================================================
+** List of valid conversion specifiers for the 'strftime' function;
+** options are grouped by length; group of length 2 start with '||'.
+** ===================================================================
*/
+#if !defined(LUA_STRFTIMEOPTIONS) /* { */
+
+/* options for ANSI C 89 (only 1-char options) */
+#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
+
+/* options for ISO C 99 and POSIX */
+#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
+ "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
+
+/* options for Windows */
+#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
+ "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
-#if defined(LUA_USE_C89)
-#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" }
+#if defined(LUA_USE_WINDOWS)
+#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
+#elif defined(LUA_USE_C89)
+#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
#else /* C99 specification */
-#define LUA_STRFTIMEOPTIONS \
- { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \
- "E", "cCxXyY", \
- "O", "deHImMSuUVwWy" }
+#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
#endif
#endif /* } */
+/* }================================================================== */
+/*
+** {==================================================================
+** Configuration for time-related stuff
+** ===================================================================
+*/
#if !defined(l_time_t) /* { */
/*
@@ -46,17 +65,48 @@
*/
#define l_timet lua_Integer
#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t))
-#define l_checktime(L,a) ((time_t)luaL_checkinteger(L,a))
+
+static time_t l_checktime (lua_State *L, int arg) {
+ lua_Integer t = luaL_checkinteger(L, arg);
+ luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds");
+ return (time_t)t;
+}
#endif /* } */
+#if !defined(l_gmtime) /* { */
+/*
+** By default, Lua uses gmtime/localtime, except when POSIX is available,
+** where it uses gmtime_r/localtime_r
+*/
+
+#if defined(LUA_USE_POSIX) /* { */
+
+#define l_gmtime(t,r) gmtime_r(t,r)
+#define l_localtime(t,r) localtime_r(t,r)
+
+#else /* }{ */
+
+/* ISO C definitions */
+#define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t))
+#define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t))
+
+#endif /* } */
+
+#endif /* } */
+
+/* }================================================================== */
+
-#if !defined(lua_tmpnam) /* { */
/*
-** By default, Lua uses tmpnam except when POSIX is available, where it
-** uses mkstemp.
+** {==================================================================
+** Configuration for 'tmpnam':
+** By default, Lua uses tmpnam except when POSIX is available, where
+** it uses mkstemp.
+** ===================================================================
*/
+#if !defined(lua_tmpnam) /* { */
#if defined(LUA_USE_POSIX) /* { */
@@ -83,31 +133,10 @@
#endif /* } */
#endif /* } */
+/* }================================================================== */
-#if !defined(l_gmtime) /* { */
-/*
-** By default, Lua uses gmtime/localtime, except when POSIX is available,
-** where it uses gmtime_r/localtime_r
-*/
-
-#if defined(LUA_USE_POSIX) /* { */
-
-#define l_gmtime(t,r) gmtime_r(t,r)
-#define l_localtime(t,r) localtime_r(t,r)
-
-#else /* }{ */
-
-/* ISO C definitions */
-#define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t))
-#define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t))
-
-#endif /* } */
-
-#endif /* } */
-
-
static int os_execute (lua_State *L) {
const char *cmd = luaL_optstring(L, 1, NULL);
@@ -177,6 +206,23 @@ static void setboolfield (lua_State *L, const char *key, int value) {
lua_setfield(L, -2, key);
}
+
+/*
+** Set all fields from structure 'tm' in the table on top of the stack
+*/
+static void setallfields (lua_State *L, struct tm *stm) {
+ setfield(L, "sec", stm->tm_sec);
+ setfield(L, "min", stm->tm_min);
+ setfield(L, "hour", stm->tm_hour);
+ setfield(L, "day", stm->tm_mday);
+ setfield(L, "month", stm->tm_mon + 1);
+ setfield(L, "year", stm->tm_year + 1900);
+ setfield(L, "wday", stm->tm_wday + 1);
+ setfield(L, "yday", stm->tm_yday + 1);
+ setboolfield(L, "isdst", stm->tm_isdst);
+}
+
+
static int getboolfield (lua_State *L, const char *key) {
int res;
res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1);
@@ -185,36 +231,43 @@ static int getboolfield (lua_State *L, const char *key) {
}
-static int getfield (lua_State *L, const char *key, int d) {
- int res, isnum;
- lua_getfield(L, -1, key);
- res = (int)lua_tointegerx(L, -1, &isnum);
- if (!isnum) {
- if (d < 0)
+/* maximum value for date fields (to avoid arithmetic overflows with 'int') */
+#if !defined(L_MAXDATEFIELD)
+#define L_MAXDATEFIELD (INT_MAX / 2)
+#endif
+
+static int getfield (lua_State *L, const char *key, int d, int delta) {
+ int isnum;
+ int t = lua_getfield(L, -1, key); /* get field and its type */
+ lua_Integer res = lua_tointegerx(L, -1, &isnum);
+ if (!isnum) { /* field is not an integer? */
+ if (t != LUA_TNIL) /* some other value? */
+ return luaL_error(L, "field '%s' is not an integer", key);
+ else if (d < 0) /* absent field; no default? */
return luaL_error(L, "field '%s' missing in date table", key);
res = d;
}
+ else {
+ if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD))
+ return luaL_error(L, "field '%s' is out-of-bound", key);
+ res -= delta;
+ }
lua_pop(L, 1);
- return res;
+ return (int)res;
}
-static const char *checkoption (lua_State *L, const char *conv, char *buff) {
- static const char *const options[] = LUA_STRFTIMEOPTIONS;
- unsigned int i;
- for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2) {
- if (*conv != '\0' && strchr(options[i], *conv) != NULL) {
- buff[1] = *conv;
- if (*options[i + 1] == '\0') { /* one-char conversion specifier? */
- buff[2] = '\0'; /* end buffer */
- return conv + 1;
- }
- else if (*(conv + 1) != '\0' &&
- strchr(options[i + 1], *(conv + 1)) != NULL) {
- buff[2] = *(conv + 1); /* valid two-char conversion specifier */
- buff[3] = '\0'; /* end buffer */
- return conv + 2;
- }
+static const char *checkoption (lua_State *L, const char *conv,
+ ptrdiff_t convlen, char *buff) {
+ const char *option = LUA_STRFTIMEOPTIONS;
+ int oplen = 1; /* length of options being checked */
+ for (; *option != '\0' && oplen <= convlen; option += oplen) {
+ if (*option == '|') /* next block? */
+ oplen++; /* will check options with next length (+1) */
+ else if (memcmp(conv, option, oplen) == 0) { /* match? */
+ memcpy(buff, conv, oplen); /* copy valid option to buffer */
+ buff[oplen] = '\0';
+ return conv + oplen; /* return next item */
}
}
luaL_argerror(L, 1,
@@ -223,9 +276,15 @@ static const char *checkoption (lua_State *L, const char *conv, char *buff) {
}
+/* maximum size for an individual 'strftime' item */
+#define SIZETIMEFMT 250
+
+
static int os_date (lua_State *L) {
- const char *s = luaL_optstring(L, 1, "%c");
+ size_t slen;
+ const char *s = luaL_optlstring(L, 1, "%c", &slen);
time_t t = luaL_opt(L, l_checktime, 2, time(NULL));
+ const char *se = s + slen; /* 's' end */
struct tm tmr, *stm;
if (*s == '!') { /* UTC? */
stm = l_gmtime(&t, &tmr);
@@ -234,33 +293,26 @@ static int os_date (lua_State *L) {
else
stm = l_localtime(&t, &tmr);
if (stm == NULL) /* invalid date? */
- lua_pushnil(L);
- else if (strcmp(s, "*t") == 0) {
+ luaL_error(L, "time result cannot be represented in this installation");
+ if (strcmp(s, "*t") == 0) {
lua_createtable(L, 0, 9); /* 9 = number of fields */
- setfield(L, "sec", stm->tm_sec);
- setfield(L, "min", stm->tm_min);
- setfield(L, "hour", stm->tm_hour);
- setfield(L, "day", stm->tm_mday);
- setfield(L, "month", stm->tm_mon+1);
- setfield(L, "year", stm->tm_year+1900);
- setfield(L, "wday", stm->tm_wday+1);
- setfield(L, "yday", stm->tm_yday+1);
- setboolfield(L, "isdst", stm->tm_isdst);
+ setallfields(L, stm);
}
else {
- char cc[4];
+ char cc[4]; /* buffer for individual conversion specifiers */
luaL_Buffer b;
cc[0] = '%';
luaL_buffinit(L, &b);
- while (*s) {
- if (*s != '%') /* no conversion specifier? */
+ while (s < se) {
+ if (*s != '%') /* not a conversion specifier? */
luaL_addchar(&b, *s++);
else {
size_t reslen;
- char buff[200]; /* should be big enough for any conversion result */
- s = checkoption(L, s + 1, cc);
- reslen = strftime(buff, sizeof(buff), cc, stm);
- luaL_addlstring(&b, buff, reslen);
+ char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
+ s++; /* skip '%' */
+ s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */
+ reslen = strftime(buff, SIZETIMEFMT, cc, stm);
+ luaL_addsize(&b, reslen);
}
}
luaL_pushresult(&b);
@@ -277,28 +329,27 @@ static int os_time (lua_State *L) {
struct tm ts;
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 1); /* make sure table is at the top */
- ts.tm_sec = getfield(L, "sec", 0);
- ts.tm_min = getfield(L, "min", 0);
- ts.tm_hour = getfield(L, "hour", 12);
- ts.tm_mday = getfield(L, "day", -1);
- ts.tm_mon = getfield(L, "month", -1) - 1;
- ts.tm_year = getfield(L, "year", -1) - 1900;
+ ts.tm_sec = getfield(L, "sec", 0, 0);
+ ts.tm_min = getfield(L, "min", 0, 0);
+ ts.tm_hour = getfield(L, "hour", 12, 0);
+ ts.tm_mday = getfield(L, "day", -1, 0);
+ ts.tm_mon = getfield(L, "month", -1, 1);
+ ts.tm_year = getfield(L, "year", -1, 1900);
ts.tm_isdst = getboolfield(L, "isdst");
t = mktime(&ts);
+ setallfields(L, &ts); /* update fields with normalized values */
}
- if (t != (time_t)(l_timet)t)
- luaL_error(L, "time result cannot be represented in this Lua instalation");
- else if (t == (time_t)(-1))
- lua_pushnil(L);
- else
- l_pushtime(L, t);
+ if (t != (time_t)(l_timet)t || t == (time_t)(-1))
+ luaL_error(L, "time result cannot be represented in this installation");
+ l_pushtime(L, t);
return 1;
}
static int os_difftime (lua_State *L) {
- double res = difftime((l_checktime(L, 1)), (l_checktime(L, 2)));
- lua_pushnumber(L, (lua_Number)res);
+ time_t t1 = l_checktime(L, 1);
+ time_t t2 = l_checktime(L, 2);
+ lua_pushnumber(L, (lua_Number)difftime(t1, t2));
return 1;
}
diff --git a/src/lparser.c b/src/lparser.c
index 9a54dfc98d70..cd4512d4d417 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.c,v 2.147 2014/12/27 20:31:43 roberto Exp $
+** $Id: lparser.c,v 2.155 2016/08/01 19:51:24 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -164,7 +164,8 @@ static int registerlocalvar (LexState *ls, TString *varname) {
int oldsize = f->sizelocvars;
luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
LocVar, SHRT_MAX, "local variables");
- while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;
+ while (oldsize < f->sizelocvars)
+ f->locvars[oldsize++].varname = NULL;
f->locvars[fs->nlocvars].varname = varname;
luaC_objbarrier(ls->L, f, varname);
return fs->nlocvars++;
@@ -230,7 +231,8 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
Upvaldesc, MAXUPVAL, "upvalues");
- while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL;
+ while (oldsize < f->sizeupvalues)
+ f->upvalues[oldsize++].name = NULL;
f->upvalues[fs->nups].instack = (v->k == VLOCAL);
f->upvalues[fs->nups].idx = cast_byte(v->u.info);
f->upvalues[fs->nups].name = name;
@@ -255,7 +257,8 @@ static int searchvar (FuncState *fs, TString *n) {
*/
static void markupval (FuncState *fs, int level) {
BlockCnt *bl = fs->bl;
- while (bl->nactvar > level) bl = bl->previous;
+ while (bl->nactvar > level)
+ bl = bl->previous;
bl->upval = 1;
}
@@ -264,27 +267,26 @@ static void markupval (FuncState *fs, int level) {
Find variable with given name 'n'. If it is an upvalue, add this
upvalue into all intermediate functions.
*/
-static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
+static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
if (fs == NULL) /* no more levels? */
- return VVOID; /* default is global */
+ init_exp(var, VVOID, 0); /* default is global */
else {
int v = searchvar(fs, n); /* look up locals at current level */
if (v >= 0) { /* found? */
init_exp(var, VLOCAL, v); /* variable is local */
if (!base)
markupval(fs, v); /* local will be used as an upval */
- return VLOCAL;
}
else { /* not found as local at current level; try upvalues */
int idx = searchupvalue(fs, n); /* try existing upvalues */
if (idx < 0) { /* not found? */
- if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */
- return VVOID; /* not found; is a global */
+ singlevaraux(fs->prev, n, var, 0); /* try upper levels */
+ if (var->k == VVOID) /* not found? */
+ return; /* it is a global */
/* else was LOCAL or UPVAL */
idx = newupvalue(fs, n, var); /* will be a new upvalue */
}
- init_exp(var, VUPVAL, idx);
- return VUPVAL;
+ init_exp(var, VUPVAL, idx); /* new or old upvalue */
}
}
}
@@ -293,10 +295,11 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
static void singlevar (LexState *ls, expdesc *var) {
TString *varname = str_checkname(ls);
FuncState *fs = ls->fs;
- if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */
+ singlevaraux(fs, varname, var, 1);
+ if (var->k == VVOID) { /* global name? */
expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
- lua_assert(var->k == VLOCAL || var->k == VUPVAL);
+ lua_assert(var->k != VVOID); /* this one must exist */
codestring(ls, &key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */
}
@@ -320,6 +323,8 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
luaK_nil(fs, reg, extra);
}
}
+ if (nexps > nvars)
+ ls->fs->freereg -= nexps - nvars; /* remove extra values */
}
@@ -499,7 +504,8 @@ static Proto *addprototype (LexState *ls) {
if (fs->np >= f->sizep) {
int oldsize = f->sizep;
luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions");
- while (oldsize < f->sizep) f->p[oldsize++] = NULL;
+ while (oldsize < f->sizep)
+ f->p[oldsize++] = NULL;
}
f->p[fs->np++] = clp = luaF_newproto(L);
luaC_objbarrier(L, f, clp);
@@ -760,7 +766,7 @@ static void parlist (LexState *ls) {
}
case TK_DOTS: { /* param -> '...' */
luaX_next(ls);
- f->is_vararg = 1;
+ f->is_vararg = 1; /* declared vararg */
break;
}
default: luaX_syntaxerror(ls, "<name> or '...' expected");
@@ -1155,11 +1161,8 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
int nexps;
checknext(ls, '=');
nexps = explist(ls, &e);
- if (nexps != nvars) {
+ if (nexps != nvars)
adjust_assign(ls, nvars, nexps, &e);
- if (nexps > nvars)
- ls->fs->freereg -= nexps - nvars; /* remove extra values */
- }
else {
luaK_setoneret(ls->fs, &e); /* close last expression */
luaK_storevar(ls->fs, &lh->v, &e);
@@ -1225,7 +1228,7 @@ static void labelstat (LexState *ls, TString *label, int line) {
checkrepeated(fs, ll, label); /* check for repeated labels */
checknext(ls, TK_DBCOLON); /* skip double colon */
/* create new entry for this label */
- l = newlabelentry(ls, ll, label, line, fs->pc);
+ l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs));
skipnoopstat(ls); /* skip other no-op statements */
if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
/* assume that locals are already out of scope */
@@ -1493,7 +1496,7 @@ static void exprstat (LexState *ls) {
}
else { /* stat -> func */
check_condition(ls, v.v.k == VCALL, "syntax error");
- SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */
+ SETARG_C(getinstruction(fs, &v.v), 1); /* call statement uses no results */
}
}
@@ -1510,8 +1513,8 @@ static void retstat (LexState *ls) {
if (hasmultret(e.k)) {
luaK_setmultret(fs, &e);
if (e.k == VCALL && nret == 1) { /* tail call? */
- SET_OPCODE(getcode(fs,&e), OP_TAILCALL);
- lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar);
+ SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL);
+ lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar);
}
first = fs->nactvar;
nret = LUA_MULTRET; /* return all values */
@@ -1610,7 +1613,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
BlockCnt bl;
expdesc v;
open_func(ls, fs, &bl);
- fs->f->is_vararg = 1; /* main function is always vararg */
+ fs->f->is_vararg = 1; /* main function is always declared vararg */
init_exp(&v, VLOCAL, 0); /* create and... */
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
luaX_next(ls); /* read first token */
@@ -1626,10 +1629,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
FuncState funcstate;
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */
- incr_top(L);
+ luaD_inctop(L);
lexstate.h = luaH_new(L); /* create table for scanner */
sethvalue(L, L->top, lexstate.h); /* anchor it */
- incr_top(L);
+ luaD_inctop(L);
funcstate.f = cl->p = luaF_newproto(L);
funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
lua_assert(iswhite(funcstate.f)); /* do not need barrier here */
diff --git a/src/lparser.h b/src/lparser.h
index 62c50cac7cc8..02e9b03aebcb 100644
--- a/src/lparser.h
+++ b/src/lparser.h
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.h,v 1.74 2014/10/25 11:50:46 roberto Exp $
+** $Id: lparser.h,v 1.76 2015/12/30 18:16:13 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -13,25 +13,38 @@
/*
-** Expression descriptor
+** Expression and variable descriptor.
+** Code generation for variables and expressions can be delayed to allow
+** optimizations; An 'expdesc' structure describes a potentially-delayed
+** variable/expression. It has a description of its "main" value plus a
+** list of conditional jumps that can also produce its value (generated
+** by short-circuit operators 'and'/'or').
*/
+/* kinds of variables/expressions */
typedef enum {
- VVOID, /* no value */
- VNIL,
- VTRUE,
- VFALSE,
- VK, /* info = index of constant in 'k' */
- VKFLT, /* nval = numerical float value */
- VKINT, /* nval = numerical integer value */
- VNONRELOC, /* info = result register */
- VLOCAL, /* info = local register */
- VUPVAL, /* info = index of upvalue in 'upvalues' */
- VINDEXED, /* t = table register/upvalue; idx = index R/K */
- VJMP, /* info = instruction pc */
- VRELOCABLE, /* info = instruction pc */
- VCALL, /* info = instruction pc */
- VVARARG /* info = instruction pc */
+ VVOID, /* when 'expdesc' describes the last expression a list,
+ this kind means an empty list (so, no expression) */
+ VNIL, /* constant nil */
+ VTRUE, /* constant true */
+ VFALSE, /* constant false */
+ VK, /* constant in 'k'; info = index of constant in 'k' */
+ VKFLT, /* floating constant; nval = numerical float value */
+ VKINT, /* integer constant; nval = numerical integer value */
+ VNONRELOC, /* expression has its value in a fixed register;
+ info = result register */
+ VLOCAL, /* local variable; info = local register */
+ VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
+ VINDEXED, /* indexed variable;
+ ind.vt = whether 't' is register or upvalue;
+ ind.t = table register or upvalue;
+ ind.idx = key's R/K index */
+ VJMP, /* expression is a test/comparison;
+ info = pc of corresponding jump instruction */
+ VRELOCABLE, /* expression can put result in any register;
+ info = instruction pc */
+ VCALL, /* expression is a function call; info = instruction pc */
+ VVARARG /* vararg expression; info = instruction pc */
} expkind;
@@ -41,14 +54,14 @@ typedef enum {
typedef struct expdesc {
expkind k;
union {
+ lua_Integer ival; /* for VKINT */
+ lua_Number nval; /* for VKFLT */
+ int info; /* for generic use */
struct { /* for indexed variables (VINDEXED) */
short idx; /* index (R/K) */
lu_byte t; /* table (register or upvalue) */
lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
} ind;
- int info; /* for generic use */
- lua_Number nval; /* for VKFLT */
- lua_Integer ival; /* for VKINT */
} u;
int t; /* patch list of 'exit when true' */
int f; /* patch list of 'exit when false' */
diff --git a/src/lstate.c b/src/lstate.c
index ff6b02d36ae0..9194ac3419e1 100644
--- a/src/lstate.c
+++ b/src/lstate.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.c,v 2.127 2014/11/02 19:33:33 roberto Exp $
+** $Id: lstate.c,v 2.133 2015/11/13 12:16:51 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -37,9 +37,6 @@
#endif
-#define MEMERRMSG "not enough memory"
-
-
/*
** a macro to help the creation of a unique random seed when a state is
** created; the seed is used to randomize hashes.
@@ -79,7 +76,7 @@ typedef struct LG {
*/
#define addbuff(b,p,e) \
{ size_t t = cast(size_t, e); \
- memcpy(buff + p, &t, sizeof(t)); p += sizeof(t); }
+ memcpy(b + p, &t, sizeof(t)); p += sizeof(t); }
static unsigned int makeseed (lua_State *L) {
char buff[4 * sizeof(size_t)];
@@ -96,10 +93,14 @@ static unsigned int makeseed (lua_State *L) {
/*
** set GCdebt to a new value keeping the value (totalbytes + GCdebt)
-** invariant
+** invariant (and avoiding underflows in 'totalbytes')
*/
void luaE_setdebt (global_State *g, l_mem debt) {
- g->totalbytes -= (debt - g->GCdebt);
+ l_mem tb = gettotalbytes(g);
+ lua_assert(tb > 0);
+ if (debt < tb - MAX_LMEM)
+ debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */
+ g->totalbytes = tb - debt;
g->GCdebt = debt;
}
@@ -110,6 +111,7 @@ CallInfo *luaE_extendCI (lua_State *L) {
L->ci->next = ci;
ci->previous = L->ci;
ci->next = NULL;
+ L->nci++;
return ci;
}
@@ -124,6 +126,7 @@ void luaE_freeCI (lua_State *L) {
while ((ci = next) != NULL) {
next = ci->next;
luaM_free(L, ci);
+ L->nci--;
}
}
@@ -133,13 +136,14 @@ void luaE_freeCI (lua_State *L) {
*/
void luaE_shrinkCI (lua_State *L) {
CallInfo *ci = L->ci;
- while (ci->next != NULL) { /* while there is 'next' */
- CallInfo *next2 = ci->next->next; /* next's next */
- if (next2 == NULL) break;
- luaM_free(L, ci->next); /* remove next */
+ CallInfo *next2; /* next's next */
+ /* while there are two nexts */
+ while (ci->next != NULL && (next2 = ci->next->next) != NULL) {
+ luaM_free(L, ci->next); /* free next */
+ L->nci--;
ci->next = next2; /* remove 'next' from the list */
next2->previous = ci;
- ci = next2;
+ ci = next2; /* keep next's next */
}
}
@@ -169,6 +173,7 @@ static void freestack (lua_State *L) {
return; /* stack not completely built yet */
L->ci = &L->base_ci; /* free the entire 'ci' list */
luaE_freeCI(L);
+ lua_assert(L->nci == 0);
luaM_freearray(L, L->stack, L->stacksize); /* free stack array */
}
@@ -200,12 +205,9 @@ static void f_luaopen (lua_State *L, void *ud) {
UNUSED(ud);
stack_init(L, L); /* init stack */
init_registry(L, g);
- luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
+ luaS_init(L);
luaT_init(L);
luaX_init(L);
- /* pre-create memory-error message */
- g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
- luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */
g->gcrunning = 1; /* allow gc */
g->version = lua_version(NULL);
luai_userstateopen(L);
@@ -220,6 +222,7 @@ static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g;
L->stack = NULL;
L->ci = NULL;
+ L->nci = 0;
L->stacksize = 0;
L->twups = L; /* thread has no upvalues */
L->errorJmp = NULL;
@@ -243,7 +246,6 @@ static void close_state (lua_State *L) {
if (g->version) /* closing a fully built state? */
luai_userstateclose(L);
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
- luaZ_freebuffer(L, &g->buff);
freestack(L);
lua_assert(gettotalbytes(g) == sizeof(LG));
(*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */
@@ -312,7 +314,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->strt.size = g->strt.nuse = 0;
g->strt.hash = NULL;
setnilvalue(&g->l_registry);
- luaZ_initbuffer(L, &g->buff);
g->panic = NULL;
g->version = NULL;
g->gcstate = GCSpause;
diff --git a/src/lstate.h b/src/lstate.h
index 81e12c40db0a..a469466c4475 100644
--- a/src/lstate.h
+++ b/src/lstate.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.h,v 2.119 2014/10/30 18:53:28 roberto Exp $
+** $Id: lstate.h,v 2.133 2016/12/22 13:08:50 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -23,7 +23,7 @@
**
** 'allgc': all objects not marked for finalization;
** 'finobj': all objects marked for finalization;
-** 'tobefnz': all objects ready to be finalized;
+** 'tobefnz': all objects ready to be finalized;
** 'fixedgc': all objects that are not to be collected (currently
** only small strings, such as reserved words).
@@ -33,6 +33,15 @@
struct lua_longjmp; /* defined in ldo.c */
+/*
+** Atomic type (relative to signals) to better ensure that 'lua_sethook'
+** is thread safe
+*/
+#if !defined(l_signalT)
+#include <signal.h>
+#define l_signalT sig_atomic_t
+#endif
+
/* extra stack space to handle TM calls and some other extras */
#define EXTRA_STACK 5
@@ -57,7 +66,7 @@ typedef struct stringtable {
** Information about a call.
** When a thread yields, 'func' is adjusted to pretend that the
** top function has only the yielded values in its stack; in that
-** case, the actual 'func' value is saved in field 'extra'.
+** case, the actual 'func' value is saved in field 'extra'.
** When a function calls another with a continuation, 'extra' keeps
** the function index so that, in case of errors, the continuation
** function can be called with the correct top.
@@ -79,7 +88,7 @@ typedef struct CallInfo {
} u;
ptrdiff_t extra;
short nresults; /* expected number of results from this function */
- lu_byte callstatus;
+ unsigned short callstatus;
} CallInfo;
@@ -89,11 +98,13 @@ typedef struct CallInfo {
#define CIST_OAH (1<<0) /* original value of 'allowhook' */
#define CIST_LUA (1<<1) /* call is running a Lua function */
#define CIST_HOOKED (1<<2) /* call is running a debug hook */
-#define CIST_REENTRY (1<<3) /* call is running on same invocation of
- luaV_execute of previous call */
+#define CIST_FRESH (1<<3) /* call is running on a fresh invocation
+ of luaV_execute */
#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
#define CIST_TAIL (1<<5) /* call was tail called */
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
+#define CIST_LEQ (1<<7) /* using __lt for __le */
+#define CIST_FIN (1<<8) /* call is running a finalizer */
#define isLua(ci) ((ci)->callstatus & CIST_LUA)
@@ -108,7 +119,7 @@ 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 - GCdebt */
+ l_mem totalbytes; /* number of bytes currently allocated - GCdebt */
l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
lu_mem GCmemtrav; /* memory traversed by the GC */
lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
@@ -130,7 +141,6 @@ typedef struct global_State {
GCObject *tobefnz; /* list of userdata to be GC */
GCObject *fixedgc; /* list of objects not to be collected */
struct lua_State *twups; /* list of threads with open upvalues */
- Mbuffer buff; /* temporary buffer for string concatenation */
unsigned int gcfinnum; /* number of finalizers to call in each GC step */
int gcpause; /* size of pause between successive GCs */
int gcstepmul; /* GC 'granularity' */
@@ -140,6 +150,7 @@ typedef struct global_State {
TString *memerrmsg; /* memory-error message */
TString *tmname[TM_N]; /* array with tag-method names */
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
+ TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
} global_State;
@@ -148,6 +159,7 @@ typedef struct global_State {
*/
struct lua_State {
CommonHeader;
+ unsigned short nci; /* number of items in 'ci' list */
lu_byte status;
StkId top; /* first free slot in the stack */
global_State *l_G;
@@ -160,14 +172,14 @@ struct lua_State {
struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
- lua_Hook hook;
+ volatile lua_Hook hook;
ptrdiff_t errfunc; /* current error handling function (stack index) */
int stacksize;
int basehookcount;
int hookcount;
unsigned short nny; /* number of non-yieldable calls in stack */
unsigned short nCcalls; /* number of nested C calls */
- lu_byte hookmask;
+ l_signalT hookmask;
lu_byte allowhook;
};
@@ -210,7 +222,7 @@ union GCUnion {
/* actual number of total bytes allocated */
-#define gettotalbytes(g) ((g)->totalbytes + (g)->GCdebt)
+#define gettotalbytes(g) cast(lu_mem, (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);
diff --git a/src/lstring.c b/src/lstring.c
index 2947113c3c9d..9351766fd63b 100644
--- a/src/lstring.c
+++ b/src/lstring.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstring.c,v 2.45 2014/11/02 19:19:04 roberto Exp $
+** $Id: lstring.c,v 2.56 2015/11/23 11:32:51 roberto Exp $
** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -22,6 +22,8 @@
#include "lstring.h"
+#define MEMERRMSG "not enough memory"
+
/*
** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to
@@ -36,24 +38,33 @@
** equality for long strings
*/
int luaS_eqlngstr (TString *a, TString *b) {
- size_t len = a->len;
+ size_t len = a->u.lnglen;
lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR);
return (a == b) || /* same instance or... */
- ((len == b->len) && /* equal length and ... */
+ ((len == b->u.lnglen) && /* equal length and ... */
(memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */
}
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
unsigned int h = seed ^ cast(unsigned int, l);
- size_t l1;
size_t step = (l >> LUAI_HASHLIMIT) + 1;
- for (l1 = l; l1 >= step; l1 -= step)
- h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1]));
+ for (; l >= step; l -= step)
+ h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
return h;
}
+unsigned int luaS_hashlongstr (TString *ts) {
+ lua_assert(ts->tt == LUA_TLNGSTR);
+ if (ts->extra == 0) { /* no hash? */
+ ts->hash = luaS_hash(getstr(ts), ts->u.lnglen, ts->hash);
+ ts->extra = 1; /* now it has its hash */
+ }
+ return ts->hash;
+}
+
+
/*
** resizes the string table
*/
@@ -69,9 +80,9 @@ void luaS_resize (lua_State *L, int newsize) {
TString *p = tb->hash[i];
tb->hash[i] = NULL;
while (p) { /* for each node in the list */
- TString *hnext = p->hnext; /* save next */
+ TString *hnext = p->u.hnext; /* save next */
unsigned int h = lmod(p->hash, newsize); /* new position */
- p->hnext = tb->hash[h]; /* chain it */
+ p->u.hnext = tb->hash[h]; /* chain it */
tb->hash[h] = p;
p = hnext;
}
@@ -85,23 +96,57 @@ void luaS_resize (lua_State *L, int newsize) {
}
+/*
+** Clear API string cache. (Entries cannot be empty, so fill them with
+** a non-collectable string.)
+*/
+void luaS_clearcache (global_State *g) {
+ int i, j;
+ for (i = 0; i < STRCACHE_N; i++)
+ for (j = 0; j < STRCACHE_M; j++) {
+ if (iswhite(g->strcache[i][j])) /* will entry be collected? */
+ g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */
+ }
+}
+
+
+/*
+** Initialize the string table and the string cache
+*/
+void luaS_init (lua_State *L) {
+ global_State *g = G(L);
+ int i, j;
+ luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
+ /* pre-create memory-error message */
+ g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
+ luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */
+ for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */
+ for (j = 0; j < STRCACHE_M; j++)
+ g->strcache[i][j] = g->memerrmsg;
+}
+
+
/*
** creates a new string object
*/
-static TString *createstrobj (lua_State *L, const char *str, size_t l,
- int tag, unsigned int h) {
+static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {
TString *ts;
GCObject *o;
size_t totalsize; /* total size of TString object */
totalsize = sizelstring(l);
o = luaC_newobj(L, tag, totalsize);
ts = gco2ts(o);
- ts->len = l;
ts->hash = h;
ts->extra = 0;
- memcpy(getaddrstr(ts), str, l * sizeof(char));
- getaddrstr(ts)[l] = '\0'; /* ending 0 */
+ getstr(ts)[l] = '\0'; /* ending 0 */
+ return ts;
+}
+
+
+TString *luaS_createlngstrobj (lua_State *L, size_t l) {
+ TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed);
+ ts->u.lnglen = l;
return ts;
}
@@ -110,8 +155,8 @@ void luaS_remove (lua_State *L, TString *ts) {
stringtable *tb = &G(L)->strt;
TString **p = &tb->hash[lmod(ts->hash, tb->size)];
while (*p != ts) /* find previous element */
- p = &(*p)->hnext;
- *p = (*p)->hnext; /* remove element from its list */
+ p = &(*p)->u.hnext;
+ *p = (*p)->u.hnext; /* remove element from its list */
tb->nuse--;
}
@@ -124,8 +169,9 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
global_State *g = G(L);
unsigned int h = luaS_hash(str, l, g->seed);
TString **list = &g->strt.hash[lmod(h, g->strt.size)];
- for (ts = *list; ts != NULL; ts = ts->hnext) {
- if (l == ts->len &&
+ lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
+ for (ts = *list; ts != NULL; ts = ts->u.hnext) {
+ if (l == ts->shrlen &&
(memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
/* found! */
if (isdead(g, ts)) /* dead (but not collected yet)? */
@@ -137,8 +183,10 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
luaS_resize(L, g->strt.size * 2);
list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */
}
- ts = createstrobj(L, str, l, LUA_TSHRSTR, h);
- ts->hnext = *list;
+ ts = createstrobj(L, l, LUA_TSHRSTR, h);
+ memcpy(getstr(ts), str, l * sizeof(char));
+ ts->shrlen = cast_byte(l);
+ ts->u.hnext = *list;
*list = ts;
g->strt.nuse++;
return ts;
@@ -152,18 +200,36 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
if (l <= LUAI_MAXSHORTLEN) /* short string? */
return internshrstr(L, str, l);
else {
- if (l + 1 > (MAX_SIZE - sizeof(TString))/sizeof(char))
+ TString *ts;
+ if (l >= (MAX_SIZE - sizeof(TString))/sizeof(char))
luaM_toobig(L);
- return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed);
+ ts = luaS_createlngstrobj(L, l);
+ memcpy(getstr(ts), str, l * sizeof(char));
+ return ts;
}
}
/*
-** new zero-terminated string
+** Create or reuse a zero-terminated string, first checking in the
+** cache (using the string address as a key). The cache can contain
+** only zero-terminated strings, so it is safe to use 'strcmp' to
+** check hits.
*/
TString *luaS_new (lua_State *L, const char *str) {
- return luaS_newlstr(L, str, strlen(str));
+ unsigned int i = point2uint(str) % STRCACHE_N; /* hash */
+ int j;
+ TString **p = G(L)->strcache[i];
+ for (j = 0; j < STRCACHE_M; j++) {
+ if (strcmp(str, getstr(p[j])) == 0) /* hit? */
+ return p[j]; /* that is it */
+ }
+ /* normal route */
+ for (j = STRCACHE_M - 1; j > 0; j--)
+ p[j] = p[j - 1]; /* move out last element */
+ /* new element is first in the list */
+ p[0] = luaS_newlstr(L, str, strlen(str));
+ return p[0];
}
diff --git a/src/lstring.h b/src/lstring.h
index d3f04caf7289..27efd2077269 100644
--- a/src/lstring.h
+++ b/src/lstring.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstring.h,v 1.56 2014/07/18 14:46:47 roberto Exp $
+** $Id: lstring.h,v 1.61 2015/11/03 15:36:01 roberto Exp $
** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -13,7 +13,6 @@
#define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char))
-#define sizestring(s) sizelstring((s)->len)
#define sizeludata(l) (sizeof(union UUdata) + (l))
#define sizeudata(u) sizeludata((u)->len)
@@ -35,12 +34,16 @@
LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
+LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts);
LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
+LUAI_FUNC void luaS_clearcache (global_State *g);
+LUAI_FUNC void luaS_init (lua_State *L);
LUAI_FUNC void luaS_remove (lua_State *L, TString *ts);
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s);
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
LUAI_FUNC TString *luaS_new (lua_State *L, const char *str);
+LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);
#endif
diff --git a/src/lstrlib.c b/src/lstrlib.c
index a650b768d574..c7aa755fabd2 100644
--- a/src/lstrlib.c
+++ b/src/lstrlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstrlib.c,v 1.221 2014/12/11 14:03:07 roberto Exp $
+** $Id: lstrlib.c,v 1.254 2016/12/22 13:08:50 roberto Exp $
** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
@@ -11,7 +11,9 @@
#include <ctype.h>
+#include <float.h>
#include <limits.h>
+#include <locale.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -25,7 +27,8 @@
/*
** maximum number of captures that a pattern can do during
-** pattern-matching. This limit is arbitrary.
+** pattern-matching. This limit is arbitrary, but must fit in
+** an unsigned char.
*/
#if !defined(LUA_MAXCAPTURES)
#define LUA_MAXCAPTURES 32
@@ -40,8 +43,10 @@
** Some sizes are better limited to fit in 'int', but must also fit in
** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.)
*/
+#define MAX_SIZET ((size_t)(~(size_t)0))
+
#define MAXSIZE \
- (sizeof(size_t) < sizeof(int) ? (~(size_t)0) : (size_t)(INT_MAX))
+ (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX))
@@ -70,7 +75,7 @@ static int str_sub (lua_State *L) {
if (start < 1) start = 1;
if (end > (lua_Integer)l) end = l;
if (start <= end)
- lua_pushlstring(L, s + start - 1, (size_t)(end - start + 1));
+ lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1);
else lua_pushliteral(L, "");
return 1;
}
@@ -149,9 +154,9 @@ static int str_byte (lua_State *L) {
if (posi < 1) posi = 1;
if (pose > (lua_Integer)l) pose = l;
if (posi > pose) return 0; /* empty interval; return no values */
- n = (int)(pose - posi + 1);
- if (posi + n <= pose) /* arithmetic overflow? */
+ if (pose - posi >= INT_MAX) /* arithmetic overflow? */
return luaL_error(L, "string slice too long");
+ n = (int)(pose - posi) + 1;
luaL_checkstack(L, n, "string slice too long");
for (i=0; i<n; i++)
lua_pushinteger(L, uchar(s[posi+i-1]));
@@ -207,12 +212,12 @@ static int str_dump (lua_State *L) {
typedef struct MatchState {
- int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
const char *src_init; /* init of source string */
const char *src_end; /* end ('\0') of source string */
const char *p_end; /* end ('\0') of pattern */
lua_State *L;
- int level; /* total number of captures (finished or unfinished) */
+ int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
+ unsigned char level; /* total number of captures (finished or unfinished) */
struct {
const char *init;
ptrdiff_t len;
@@ -499,7 +504,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
}
case '+': /* 1 or more repetitions */
s++; /* 1 match already done */
- /* go through */
+ /* FALLTHROUGH */
case '*': /* 0 or more repetitions */
s = max_expand(ms, s, p, ep);
break;
@@ -554,7 +559,7 @@ static void push_onecapture (MatchState *ms, int i, const char *s,
ptrdiff_t l = ms->capture[i].len;
if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
if (l == CAP_POSITION)
- lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
+ lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1);
else
lua_pushlstring(ms->L, ms->capture[i].init, l);
}
@@ -583,6 +588,22 @@ static int nospecials (const char *p, size_t l) {
}
+static void prepstate (MatchState *ms, lua_State *L,
+ const char *s, size_t ls, const char *p, size_t lp) {
+ ms->L = L;
+ ms->matchdepth = MAXCCALLS;
+ ms->src_init = s;
+ ms->src_end = s + ls;
+ ms->p_end = p + lp;
+}
+
+
+static void reprepstate (MatchState *ms) {
+ ms->level = 0;
+ lua_assert(ms->matchdepth == MAXCCALLS);
+}
+
+
static int str_find_aux (lua_State *L, int find) {
size_t ls, lp;
const char *s = luaL_checklstring(L, 1, &ls);
@@ -598,8 +619,8 @@ static int str_find_aux (lua_State *L, int find) {
/* do a plain search */
const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp);
if (s2) {
- lua_pushinteger(L, s2 - s + 1);
- lua_pushinteger(L, s2 - s + lp);
+ lua_pushinteger(L, (s2 - s) + 1);
+ lua_pushinteger(L, (s2 - s) + lp);
return 2;
}
}
@@ -610,18 +631,13 @@ static int str_find_aux (lua_State *L, int find) {
if (anchor) {
p++; lp--; /* skip anchor character */
}
- ms.L = L;
- ms.matchdepth = MAXCCALLS;
- ms.src_init = s;
- ms.src_end = s + ls;
- ms.p_end = p + lp;
+ prepstate(&ms, L, s, ls, p, lp);
do {
const char *res;
- ms.level = 0;
- lua_assert(ms.matchdepth == MAXCCALLS);
+ reprepstate(&ms);
if ((res=match(&ms, s1, p)) != NULL) {
if (find) {
- lua_pushinteger(L, s1 - s + 1); /* start */
+ lua_pushinteger(L, (s1 - s) + 1); /* start */
lua_pushinteger(L, res - s); /* end */
return push_captures(&ms, NULL, 0) + 2;
}
@@ -645,29 +661,25 @@ static int str_match (lua_State *L) {
}
+/* state for 'gmatch' */
+typedef struct GMatchState {
+ const char *src; /* current position */
+ const char *p; /* pattern */
+ const char *lastmatch; /* end of last match */
+ MatchState ms; /* match state */
+} GMatchState;
+
+
static int gmatch_aux (lua_State *L) {
- MatchState ms;
- size_t ls, lp;
- const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
- const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp);
+ GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3));
const char *src;
- ms.L = L;
- ms.matchdepth = MAXCCALLS;
- ms.src_init = s;
- ms.src_end = s+ls;
- ms.p_end = p + lp;
- for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3));
- src <= ms.src_end;
- src++) {
+ gm->ms.L = L;
+ for (src = gm->src; src <= gm->ms.src_end; src++) {
const char *e;
- ms.level = 0;
- lua_assert(ms.matchdepth == MAXCCALLS);
- if ((e = match(&ms, src, p)) != NULL) {
- lua_Integer newstart = e-s;
- if (e == src) newstart++; /* empty match? go at least one position */
- lua_pushinteger(L, newstart);
- lua_replace(L, lua_upvalueindex(3));
- return push_captures(&ms, src, e);
+ reprepstate(&gm->ms);
+ if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) {
+ gm->src = gm->lastmatch = e;
+ return push_captures(&gm->ms, src, e);
}
}
return 0; /* not found */
@@ -675,10 +687,14 @@ static int gmatch_aux (lua_State *L) {
static int gmatch (lua_State *L) {
- luaL_checkstring(L, 1);
- luaL_checkstring(L, 2);
- lua_settop(L, 2);
- lua_pushinteger(L, 0);
+ size_t ls, lp;
+ const char *s = luaL_checklstring(L, 1, &ls);
+ const char *p = luaL_checklstring(L, 2, &lp);
+ GMatchState *gm;
+ lua_settop(L, 2); /* keep them on closure to avoid being collected */
+ gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState));
+ prepstate(&gm->ms, L, s, ls, p, lp);
+ gm->src = s; gm->p = p; gm->lastmatch = NULL;
lua_pushcclosure(L, gmatch_aux, 3);
return 1;
}
@@ -745,12 +761,13 @@ static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
static int str_gsub (lua_State *L) {
size_t srcl, lp;
- const char *src = luaL_checklstring(L, 1, &srcl);
- const char *p = luaL_checklstring(L, 2, &lp);
- int tr = lua_type(L, 3);
- lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1);
+ const char *src = luaL_checklstring(L, 1, &srcl); /* subject */
+ const char *p = luaL_checklstring(L, 2, &lp); /* pattern */
+ const char *lastmatch = NULL; /* end of last match */
+ int tr = lua_type(L, 3); /* replacement type */
+ lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */
int anchor = (*p == '^');
- lua_Integer n = 0;
+ lua_Integer n = 0; /* replacement count */
MatchState ms;
luaL_Buffer b;
luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
@@ -760,25 +777,18 @@ static int str_gsub (lua_State *L) {
if (anchor) {
p++; lp--; /* skip anchor character */
}
- ms.L = L;
- ms.matchdepth = MAXCCALLS;
- ms.src_init = src;
- ms.src_end = src+srcl;
- ms.p_end = p + lp;
+ prepstate(&ms, L, src, srcl, p, lp);
while (n < max_s) {
const char *e;
- ms.level = 0;
- lua_assert(ms.matchdepth == MAXCCALLS);
- e = match(&ms, src, p);
- if (e) {
+ reprepstate(&ms); /* (re)prepare state for new match */
+ if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */
n++;
- add_value(&ms, &b, src, e, tr);
+ add_value(&ms, &b, src, e, tr); /* add replacement to buffer */
+ src = lastmatch = e;
}
- if (e && e>src) /* non empty match? */
- src = e; /* skip it */
- else if (src < ms.src_end)
+ else if (src < ms.src_end) /* otherwise, skip one character */
luaL_addchar(&b, *src++);
- else break;
+ else break; /* end of subject */
if (anchor) break;
}
luaL_addlstring(&b, src, ms.src_end-src);
@@ -797,34 +807,117 @@ static int str_gsub (lua_State *L) {
** =======================================================
*/
-/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
-#define MAX_ITEM 512
+#if !defined(lua_number2strx) /* { */
+
+/*
+** Hexadecimal floating-point formatter
+*/
+
+#include <math.h>
+
+#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char))
+
+
+/*
+** Number of bits that goes into the first digit. It can be any value
+** between 1 and 4; the following definition tries to align the number
+** to nibble boundaries by making what is left after that first digit a
+** multiple of 4.
+*/
+#define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1)
+
+
+/*
+** Add integer part of 'x' to buffer and return new 'x'
+*/
+static lua_Number adddigit (char *buff, int n, lua_Number x) {
+ lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */
+ int d = (int)dd;
+ buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */
+ return x - dd; /* return what is left */
+}
+
+
+static int num2straux (char *buff, int sz, lua_Number x) {
+ /* if 'inf' or 'NaN', format it like '%g' */
+ if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL)
+ return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x);
+ else if (x == 0) { /* can be -0... */
+ /* create "0" or "-0" followed by exponent */
+ return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x);
+ }
+ else {
+ int e;
+ lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */
+ int n = 0; /* character count */
+ if (m < 0) { /* is number negative? */
+ buff[n++] = '-'; /* add signal */
+ m = -m; /* make it positive */
+ }
+ buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */
+ m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */
+ e -= L_NBFD; /* this digit goes before the radix point */
+ if (m > 0) { /* more digits? */
+ buff[n++] = lua_getlocaledecpoint(); /* add radix point */
+ do { /* add as many digits as needed */
+ m = adddigit(buff, n++, m * 16);
+ } while (m > 0);
+ }
+ n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */
+ lua_assert(n < sz);
+ return n;
+ }
+}
+
+
+static int lua_number2strx (lua_State *L, char *buff, int sz,
+ const char *fmt, lua_Number x) {
+ int n = num2straux(buff, sz, x);
+ if (fmt[SIZELENMOD] == 'A') {
+ int i;
+ for (i = 0; i < n; i++)
+ buff[i] = toupper(uchar(buff[i]));
+ }
+ else if (fmt[SIZELENMOD] != 'a')
+ luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
+ return n;
+}
+
+#endif /* } */
+
+
+/*
+** Maximum size of each formatted item. This maximum size is produced
+** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.',
+** and '\0') + number of decimal digits to represent maxfloat (which
+** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra
+** expenses", such as locale-dependent stuff)
+*/
+#define MAX_ITEM (120 + l_mathlim(MAX_10_EXP))
+
/* valid flags in a format specification */
#define FLAGS "-+ #0"
/*
** maximum size of each format specification (such as "%-099.99d")
-** (+2 for length modifiers; +10 accounts for %99.99x plus margin of error)
*/
-#define MAX_FORMAT (sizeof(FLAGS) + 2 + 10)
+#define MAX_FORMAT 32
-static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
- size_t l;
- const char *s = luaL_checklstring(L, arg, &l);
+static void addquoted (luaL_Buffer *b, const char *s, size_t len) {
luaL_addchar(b, '"');
- while (l--) {
+ while (len--) {
if (*s == '"' || *s == '\\' || *s == '\n') {
luaL_addchar(b, '\\');
luaL_addchar(b, *s);
}
- else if (*s == '\0' || iscntrl(uchar(*s))) {
+ else if (iscntrl(uchar(*s))) {
char buff[10];
if (!isdigit(uchar(*(s+1))))
- sprintf(buff, "\\%d", (int)uchar(*s));
+ l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s));
else
- sprintf(buff, "\\%03d", (int)uchar(*s));
+ l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s));
luaL_addstring(b, buff);
}
else
@@ -834,6 +927,57 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
luaL_addchar(b, '"');
}
+
+/*
+** Ensures the 'buff' string uses a dot as the radix character.
+*/
+static void checkdp (char *buff, int nb) {
+ if (memchr(buff, '.', nb) == NULL) { /* no dot? */
+ char point = lua_getlocaledecpoint(); /* try locale point */
+ char *ppoint = (char *)memchr(buff, point, nb);
+ if (ppoint) *ppoint = '.'; /* change it to a dot */
+ }
+}
+
+
+static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
+ switch (lua_type(L, arg)) {
+ case LUA_TSTRING: {
+ size_t len;
+ const char *s = lua_tolstring(L, arg, &len);
+ addquoted(b, s, len);
+ break;
+ }
+ case LUA_TNUMBER: {
+ char *buff = luaL_prepbuffsize(b, MAX_ITEM);
+ int nb;
+ if (!lua_isinteger(L, arg)) { /* float? */
+ lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */
+ nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n);
+ checkdp(buff, nb); /* ensure it uses a dot */
+ }
+ else { /* integers */
+ lua_Integer n = lua_tointeger(L, arg);
+ const char *format = (n == LUA_MININTEGER) /* corner case? */
+ ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */
+ : LUA_INTEGER_FMT; /* else use default format */
+ nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n);
+ }
+ luaL_addsize(b, nb);
+ break;
+ }
+ case LUA_TNIL: case LUA_TBOOLEAN: {
+ luaL_tolstring(L, arg, NULL);
+ luaL_addvalue(b);
+ break;
+ }
+ default: {
+ luaL_argerror(L, arg, "value has no literal form");
+ }
+ }
+}
+
+
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 */
@@ -849,8 +993,8 @@ 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) * sizeof(char));
- form += p - strfrmt + 1;
+ memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char));
+ form += (p - strfrmt) + 1;
*form = '\0';
return p;
}
@@ -891,49 +1035,56 @@ static int str_format (lua_State *L) {
strfrmt = scanformat(L, strfrmt, form);
switch (*strfrmt++) {
case 'c': {
- nb = sprintf(buff, form, (int)luaL_checkinteger(L, arg));
+ nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg));
break;
}
case 'd': case 'i':
case 'o': case 'u': case 'x': case 'X': {
lua_Integer n = luaL_checkinteger(L, arg);
addlenmod(form, LUA_INTEGER_FRMLEN);
- nb = sprintf(buff, form, n);
+ nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n);
break;
}
-#if defined(LUA_USE_AFORMAT)
case 'a': case 'A':
-#endif
+ addlenmod(form, LUA_NUMBER_FRMLEN);
+ nb = lua_number2strx(L, buff, MAX_ITEM, form,
+ luaL_checknumber(L, arg));
+ break;
case 'e': case 'E': case 'f':
case 'g': case 'G': {
+ lua_Number n = luaL_checknumber(L, arg);
addlenmod(form, LUA_NUMBER_FRMLEN);
- nb = sprintf(buff, form, luaL_checknumber(L, arg));
+ nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n);
break;
}
case 'q': {
- addquoted(L, &b, arg);
+ addliteral(L, &b, arg);
break;
}
case 's': {
size_t 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 */
- luaL_addvalue(&b);
- break;
- }
+ if (form[2] == '\0') /* no modifiers? */
+ luaL_addvalue(&b); /* keep entire string */
else {
- nb = sprintf(buff, form, s);
- lua_pop(L, 1); /* remove result from 'luaL_tolstring' */
- break;
+ luaL_argcheck(L, l == strlen(s), arg, "string contains zeros");
+ if (!strchr(form, '.') && l >= 100) {
+ /* no precision and string is too long to be formatted */
+ luaL_addvalue(&b); /* keep entire string */
+ }
+ else { /* format the string into 'buff' */
+ nb = l_sprintf(buff, MAX_ITEM, form, s);
+ lua_pop(L, 1); /* remove result from 'luaL_tolstring' */
+ }
}
+ break;
}
default: { /* also treat cases 'pnLlh' */
return luaL_error(L, "invalid option '%%%c' to 'format'",
*(strfrmt - 1));
}
}
+ lua_assert(nb < MAX_ITEM);
luaL_addsize(&b, nb);
}
}
@@ -952,8 +1103,8 @@ static int str_format (lua_State *L) {
/* value used for padding */
-#if !defined(LUA_PACKPADBYTE)
-#define LUA_PACKPADBYTE 0x00
+#if !defined(LUAL_PACKPADBYTE)
+#define LUAL_PACKPADBYTE 0x00
#endif
/* maximum size for the binary representation of an integer */
@@ -1110,7 +1261,7 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
** 'psize' is filled with option's size, 'notoalign' with its
** alignment requirements.
** Local variable 'size' gets the size to be aligned. (Kpadal option
-** always gets its full alignment, other options are limited by
+** always gets its full alignment, other options are limited by
** the maximum alignment ('maxalign'). Kchar option needs no alignment
** despite its size.
*/
@@ -1190,7 +1341,7 @@ static int str_pack (lua_State *L) {
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
totalsize += ntoalign + size;
while (ntoalign-- > 0)
- luaL_addchar(&b, LUA_PACKPADBYTE); /* fill alignment */
+ luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */
arg++;
switch (opt) {
case Kint: { /* signed integers */
@@ -1225,8 +1376,11 @@ static int str_pack (lua_State *L) {
case Kchar: { /* fixed-size string */
size_t len;
const char *s = luaL_checklstring(L, arg, &len);
- luaL_argcheck(L, len == (size_t)size, arg, "wrong length");
- luaL_addlstring(&b, s, size);
+ luaL_argcheck(L, len <= (size_t)size, arg,
+ "string longer than given size");
+ luaL_addlstring(&b, s, len); /* add string */
+ while (len++ < (size_t)size) /* pad extra space */
+ luaL_addchar(&b, LUAL_PACKPADBYTE);
break;
}
case Kstring: { /* strings with length count */
@@ -1249,7 +1403,7 @@ static int str_pack (lua_State *L) {
totalsize += len + 1;
break;
}
- case Kpadding: luaL_addchar(&b, LUA_PACKPADBYTE); /* go through */
+ case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */
case Kpaddalign: case Knop:
arg--; /* undo increment */
break;
@@ -1276,7 +1430,7 @@ static int str_packsize (lua_State *L) {
case Kstring: /* strings with length count */
case Kzstr: /* zero-terminated string */
luaL_argerror(L, 1, "variable-length format");
- break;
+ /* call never return, but to avoid warnings: *//* FALLTHROUGH */
default: break;
}
}
diff --git a/src/ltable.c b/src/ltable.c
index 38be00513dc8..d080189f28d0 100644
--- a/src/ltable.c
+++ b/src/ltable.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltable.c,v 2.100 2015/01/05 13:52:37 roberto Exp $
+** $Id: ltable.c,v 2.118 2016/11/07 12:38:35 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -14,8 +14,8 @@
** Implementation of tables (aka arrays, objects, or hash tables).
** Tables keep its elements in two parts: an array part and a hash part.
** Non-negative integer keys are all candidates to be kept in the array
-** part. The actual size of the array is the largest 'n' such that at
-** least half the slots between 0 and n are in use.
+** part. The actual size of the array is the largest 'n' such that
+** more than half the slots between 1 and n are in use.
** Hash uses a mix of chained scatter table with Brent's variation.
** A main invariant of these tables is that, if an element is not
** in its main position (i.e. the 'original' position that its hash gives
@@ -23,9 +23,7 @@
** Hence even when the load factor reaches 100%, performance remains good.
*/
-#include <float.h>
#include <math.h>
-#include <string.h>
#include <limits.h>
#include "lua.h"
@@ -71,13 +69,11 @@
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
-#define hashpointer(t,p) hashmod(t, point2int(p))
+#define hashpointer(t,p) hashmod(t, point2uint(p))
#define dummynode (&dummynode_)
-#define isdummy(n) ((n) == dummynode)
-
static const Node dummynode_ = {
{NILCONSTANT}, /* value */
{{NILCONSTANT, 0}} /* key */
@@ -85,31 +81,33 @@ static const Node dummynode_ = {
/*
-** Checks whether a float has a value representable as a lua_Integer
-** (and does the conversion if so)
-*/
-static int numisinteger (lua_Number x, lua_Integer *p) {
- if ((x) == l_floor(x)) /* integral value? */
- return lua_numbertointeger(x, p); /* try as an integer */
- else return 0;
-}
-
-
-/*
-** hash for floating-point numbers
+** Hash for floating-point numbers.
+** The main computation should be just
+** n = frexp(n, &i); return (n * INT_MAX) + i
+** but there are some numerical subtleties.
+** In a two-complement representation, INT_MAX does not has an exact
+** representation as a float, but INT_MIN does; because the absolute
+** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the
+** absolute value of the product 'frexp * -INT_MIN' is smaller or equal
+** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when
+** adding 'i'; the use of '~u' (instead of '-u') avoids problems with
+** INT_MIN.
*/
-static Node *hashfloat (const Table *t, lua_Number n) {
+#if !defined(l_hashfloat)
+static int l_hashfloat (lua_Number n) {
int i;
- n = l_mathop(frexp)(n, &i) * cast_num(INT_MAX - DBL_MAX_EXP);
- i += cast_int(n);
- if (i < 0) {
- if (cast(unsigned int, i) == 0u - i) /* use unsigned to avoid overflows */
- i = 0; /* handle INT_MIN */
- i = -i; /* must be a positive value */
+ lua_Integer ni;
+ n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN);
+ if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */
+ lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL));
+ return 0;
+ }
+ else { /* normal case */
+ unsigned int u = cast(unsigned int, i) + cast(unsigned int, ni);
+ return cast_int(u <= cast(unsigned int, INT_MAX) ? u : ~u);
}
- return hashmod(t, i);
}
-
+#endif
/*
@@ -121,17 +119,11 @@ static Node *mainposition (const Table *t, const TValue *key) {
case LUA_TNUMINT:
return hashint(t, ivalue(key));
case LUA_TNUMFLT:
- return hashfloat(t, fltvalue(key));
+ return hashmod(t, l_hashfloat(fltvalue(key)));
case LUA_TSHRSTR:
return hashstr(t, tsvalue(key));
- case LUA_TLNGSTR: {
- TString *s = tsvalue(key);
- if (s->extra == 0) { /* no hash? */
- s->hash = luaS_hash(getstr(s), s->len, s->hash);
- s->extra = 1; /* now it has its hash */
- }
- return hashstr(t, tsvalue(key));
- }
+ case LUA_TLNGSTR:
+ return hashpow2(t, luaS_hashlongstr(tsvalue(key)));
case LUA_TBOOLEAN:
return hashboolean(t, bvalue(key));
case LUA_TLIGHTUSERDATA:
@@ -139,6 +131,7 @@ static Node *mainposition (const Table *t, const TValue *key) {
case LUA_TLCF:
return hashpointer(t, fvalue(key));
default:
+ lua_assert(!ttisdeadkey(key));
return hashpointer(t, gcvalue(key));
}
}
@@ -219,28 +212,29 @@ int luaH_next (lua_State *L, Table *t, StkId key) {
/*
** Compute the optimal size for the array part of table 't'. 'nums' is a
** "count array" where 'nums[i]' is the number of integers in the table
-** between 2^(i - 1) + 1 and 2^i. Put in '*narray' the optimal size, and
-** return the number of elements that will go to that part.
+** between 2^(i - 1) + 1 and 2^i. 'pna' enters with the total number of
+** integer keys in the table and leaves with the number of keys that
+** will go to the array part; return the optimal size.
*/
-static unsigned int computesizes (unsigned int nums[], unsigned int *narray) {
+static unsigned int computesizes (unsigned int nums[], unsigned int *pna) {
int i;
- unsigned int twotoi; /* 2^i */
+ unsigned int twotoi; /* 2^i (candidate for optimal size) */
unsigned int a = 0; /* number of elements smaller than 2^i */
unsigned int na = 0; /* number of elements to go to array part */
- unsigned int n = 0; /* optimal size for array part */
- for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) {
+ unsigned int optimal = 0; /* optimal size for array part */
+ /* loop while keys can fill more than half of total size */
+ for (i = 0, twotoi = 1; *pna > twotoi / 2; i++, twotoi *= 2) {
if (nums[i] > 0) {
a += nums[i];
if (a > twotoi/2) { /* more than half elements present? */
- n = twotoi; /* optimal size (till now) */
- na = a; /* all elements up to 'n' will go to array part */
+ optimal = twotoi; /* optimal size (till now) */
+ na = a; /* all elements up to 'optimal' will go to array part */
}
}
- if (a == *narray) break; /* all elements already counted */
}
- *narray = n;
- lua_assert(*narray/2 <= na && na <= *narray);
- return na;
+ lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal);
+ *pna = na;
+ return optimal;
}
@@ -255,6 +249,11 @@ static int countint (const TValue *key, unsigned int *nums) {
}
+/*
+** Count keys in array part of table 't': Fill 'nums[i]' with
+** number of keys that will go into corresponding slice and return
+** total number of non-nil keys.
+*/
static unsigned int numusearray (const Table *t, unsigned int *nums) {
int lg;
unsigned int ttlg; /* 2^lg */
@@ -281,8 +280,7 @@ static unsigned int numusearray (const Table *t, unsigned int *nums) {
}
-static int numusehash (const Table *t, unsigned int *nums,
- unsigned int *pnasize) {
+static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) {
int totaluse = 0; /* total number of elements */
int ause = 0; /* elements added to 'nums' (can go to array part) */
int i = sizenode(t);
@@ -293,7 +291,7 @@ static int numusehash (const Table *t, unsigned int *nums,
totaluse++;
}
}
- *pnasize += ause;
+ *pna += ause;
return totaluse;
}
@@ -308,14 +306,14 @@ static void setarrayvector (lua_State *L, Table *t, unsigned int size) {
static void setnodevector (lua_State *L, Table *t, unsigned int size) {
- int lsize;
if (size == 0) { /* no elements to hash part? */
t->node = cast(Node *, dummynode); /* use common 'dummynode' */
- lsize = 0;
+ t->lsizenode = 0;
+ t->lastfree = NULL; /* signal that it is using dummy node */
}
else {
int i;
- lsize = luaO_ceillog2(size);
+ int lsize = luaO_ceillog2(size);
if (lsize > MAXHBITS)
luaG_runerror(L, "table overflow");
size = twoto(lsize);
@@ -326,9 +324,9 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
setnilvalue(wgkey(n));
setnilvalue(gval(n));
}
+ t->lsizenode = cast_byte(lsize);
+ t->lastfree = gnode(t, size); /* all positions are free */
}
- t->lsizenode = cast_byte(lsize);
- t->lastfree = gnode(t, size); /* all positions are free */
}
@@ -337,7 +335,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
unsigned int i;
int j;
unsigned int oldasize = t->sizearray;
- int oldhsize = t->lsizenode;
+ int oldhsize = allocsizenode(t);
Node *nold = t->node; /* save old hash ... */
if (nasize > oldasize) /* array part must grow? */
setarrayvector(L, t, nasize);
@@ -354,7 +352,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
}
/* re-insert elements from hash part */
- for (j = twoto(oldhsize) - 1; j >= 0; j--) {
+ for (j = oldhsize - 1; j >= 0; j--) {
Node *old = nold + j;
if (!ttisnil(gval(old))) {
/* doesn't need barrier/invalidate cache, as entry was
@@ -362,13 +360,13 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old));
}
}
- if (!isdummy(nold))
- luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old array */
+ if (oldhsize > 0) /* not the dummy node? */
+ luaM_freearray(L, nold, cast(size_t, oldhsize)); /* free old hash */
}
void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) {
- int nsize = isdummy(t->node) ? 0 : sizenode(t);
+ int nsize = allocsizenode(t);
luaH_resize(L, t, nasize, nsize);
}
@@ -376,21 +374,22 @@ void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) {
** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i
*/
static void rehash (lua_State *L, Table *t, const TValue *ek) {
- unsigned int nasize, na;
+ unsigned int asize; /* optimal size for array part */
+ unsigned int na; /* number of keys in the array part */
unsigned int nums[MAXABITS + 1];
int i;
int totaluse;
for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */
- nasize = numusearray(t, nums); /* count keys in array part */
- totaluse = nasize; /* all those keys are integer keys */
- totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */
+ na = numusearray(t, nums); /* count keys in array part */
+ totaluse = na; /* all those keys are integer keys */
+ totaluse += numusehash(t, nums, &na); /* count keys in hash part */
/* count extra key */
- nasize += countint(ek, nums);
+ na += countint(ek, nums);
totaluse++;
/* compute new size for array part */
- na = computesizes(nums, &nasize);
+ asize = computesizes(nums, &na);
/* resize the table to new computed sizes */
- luaH_resize(L, t, nasize, totaluse - na);
+ luaH_resize(L, t, asize, totaluse - na);
}
@@ -413,7 +412,7 @@ Table *luaH_new (lua_State *L) {
void luaH_free (lua_State *L, Table *t) {
- if (!isdummy(t->node))
+ if (!isdummy(t))
luaM_freearray(L, t->node, cast(size_t, sizenode(t)));
luaM_freearray(L, t->array, t->sizearray);
luaM_free(L, t);
@@ -421,10 +420,12 @@ void luaH_free (lua_State *L, Table *t) {
static Node *getfreepos (Table *t) {
- while (t->lastfree > t->node) {
- t->lastfree--;
- if (ttisnil(gkey(t->lastfree)))
- return t->lastfree;
+ if (!isdummy(t)) {
+ while (t->lastfree > t->node) {
+ t->lastfree--;
+ if (ttisnil(gkey(t->lastfree)))
+ return t->lastfree;
+ }
}
return NULL; /* could not find a free place */
}
@@ -443,25 +444,24 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
TValue aux;
if (ttisnil(key)) luaG_runerror(L, "table index is nil");
else if (ttisfloat(key)) {
- lua_Number n = fltvalue(key);
lua_Integer k;
- if (luai_numisnan(n))
- luaG_runerror(L, "table index is NaN");
- if (numisinteger(n, &k)) { /* index is int? */
+ if (luaV_tointeger(key, &k, 0)) { /* does index fit in an integer? */
setivalue(&aux, k);
key = &aux; /* insert it as an integer */
}
+ else if (luai_numisnan(fltvalue(key)))
+ luaG_runerror(L, "table index is NaN");
}
mp = mainposition(t, key);
- if (!ttisnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */
+ if (!ttisnil(gval(mp)) || isdummy(t)) { /* main position is taken? */
Node *othern;
Node *f = getfreepos(t); /* get a free place */
if (f == NULL) { /* cannot find a free place? */
rehash(L, t, key); /* grow table */
- /* whatever called 'newkey' takes care of TM cache and GC barrier */
+ /* whatever called 'newkey' takes care of TM cache */
return luaH_set(L, t, key); /* insert key into grown table */
}
- lua_assert(!isdummy(f));
+ lua_assert(!isdummy(t));
othern = mainposition(t, gkey(mp));
if (othern != mp) { /* is colliding node out of its main position? */
/* yes; move colliding node into free position */
@@ -496,7 +496,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
*/
const TValue *luaH_getint (Table *t, lua_Integer key) {
/* (1 <= key && key <= t->sizearray) */
- if (l_castS2U(key - 1) < t->sizearray)
+ if (l_castS2U(key) - 1 < t->sizearray)
return &t->array[key - 1];
else {
Node *n = hashint(t, key);
@@ -508,7 +508,7 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
if (nx == 0) break;
n += nx;
}
- };
+ }
return luaO_nilobject;
}
}
@@ -517,7 +517,7 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
/*
** search function for short strings
*/
-const TValue *luaH_getstr (Table *t, TString *key) {
+const TValue *luaH_getshortstr (Table *t, TString *key) {
Node *n = hashstr(t, key);
lua_assert(key->tt == LUA_TSHRSTR);
for (;;) { /* check whether 'key' is somewhere in the chain */
@@ -526,11 +526,41 @@ const TValue *luaH_getstr (Table *t, TString *key) {
return gval(n); /* that's it */
else {
int nx = gnext(n);
- if (nx == 0) break;
+ if (nx == 0)
+ return luaO_nilobject; /* not found */
n += nx;
}
- };
- return luaO_nilobject;
+ }
+}
+
+
+/*
+** "Generic" get version. (Not that generic: not valid for integers,
+** which may be in array part, nor for floats with integral values.)
+*/
+static const TValue *getgeneric (Table *t, const TValue *key) {
+ Node *n = mainposition(t, key);
+ for (;;) { /* check whether 'key' is somewhere in the chain */
+ if (luaV_rawequalobj(gkey(n), key))
+ return gval(n); /* that's it */
+ else {
+ int nx = gnext(n);
+ if (nx == 0)
+ return luaO_nilobject; /* not found */
+ n += nx;
+ }
+ }
+}
+
+
+const TValue *luaH_getstr (Table *t, TString *key) {
+ if (key->tt == LUA_TSHRSTR)
+ return luaH_getshortstr(t, key);
+ else { /* for long strings, use generic case */
+ TValue ko;
+ setsvalue(cast(lua_State *, NULL), &ko, key);
+ return getgeneric(t, &ko);
+ }
}
@@ -539,28 +569,17 @@ const TValue *luaH_getstr (Table *t, TString *key) {
*/
const TValue *luaH_get (Table *t, const TValue *key) {
switch (ttype(key)) {
- case LUA_TSHRSTR: return luaH_getstr(t, tsvalue(key));
+ case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key));
case LUA_TNUMINT: return luaH_getint(t, ivalue(key));
case LUA_TNIL: return luaO_nilobject;
case LUA_TNUMFLT: {
lua_Integer k;
- if (numisinteger(fltvalue(key), &k)) /* index is int? */
+ if (luaV_tointeger(key, &k, 0)) /* index is int? */
return luaH_getint(t, k); /* use specialized version */
- /* else go through */
- }
- default: {
- Node *n = mainposition(t, key);
- for (;;) { /* check whether 'key' is somewhere in the chain */
- if (luaV_rawequalobj(gkey(n), key))
- return gval(n); /* that's it */
- else {
- int nx = gnext(n);
- if (nx == 0) break;
- n += nx;
- }
- };
- return luaO_nilobject;
- }
+ /* else... */
+ } /* FALLTHROUGH */
+ default:
+ return getgeneric(t, key);
}
}
@@ -632,7 +651,7 @@ int luaH_getn (Table *t) {
return i;
}
/* else must find a boundary in hash part */
- else if (isdummy(t->node)) /* hash part is empty? */
+ else if (isdummy(t)) /* hash part is empty? */
return j; /* that is easy... */
else return unbound_search(t, j);
}
@@ -645,6 +664,6 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
return mainposition(t, key);
}
-int luaH_isdummy (Node *n) { return isdummy(n); }
+int luaH_isdummy (const Table *t) { return isdummy(t); }
#endif
diff --git a/src/ltable.h b/src/ltable.h
index 53d25511ad49..6da9024fe1fc 100644
--- a/src/ltable.h
+++ b/src/ltable.h
@@ -1,5 +1,5 @@
/*
-** $Id: ltable.h,v 2.20 2014/09/04 18:15:29 roberto Exp $
+** $Id: ltable.h,v 2.23 2016/12/22 13:08:50 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -15,14 +15,26 @@
#define gnext(n) ((n)->i_key.nk.next)
-/* 'const' to avoid wrong writings that can mess up field 'next' */
+/* 'const' to avoid wrong writings that can mess up field 'next' */
#define gkey(n) cast(const TValue*, (&(n)->i_key.tvk))
+/*
+** writable version of 'gkey'; allows updates to individual fields,
+** but not to the whole (which has incompatible type)
+*/
#define wgkey(n) (&(n)->i_key.nk)
#define invalidateTMcache(t) ((t)->flags = 0)
+/* true when 't' is using 'dummynode' as its hash part */
+#define isdummy(t) ((t)->lastfree == NULL)
+
+
+/* allocated size for hash nodes */
+#define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t))
+
+
/* returns the key, given the value of a table entry */
#define keyfromval(v) \
(gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val))))
@@ -31,6 +43,7 @@
LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
TValue *value);
+LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key);
@@ -46,7 +59,7 @@ LUAI_FUNC int luaH_getn (Table *t);
#if defined(LUA_DEBUG)
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
-LUAI_FUNC int luaH_isdummy (Node *n);
+LUAI_FUNC int luaH_isdummy (const Table *t);
#endif
diff --git a/src/ltablib.c b/src/ltablib.c
index 8f78afb7f25e..98b2f8713794 100644
--- a/src/ltablib.c
+++ b/src/ltablib.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltablib.c,v 1.79 2014/11/02 19:19:04 roberto Exp $
+** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $
** Library for Table Manipulation
** See Copyright Notice in lua.h
*/
@@ -12,6 +12,7 @@
#include <limits.h>
#include <stddef.h>
+#include <string.h>
#include "lua.h"
@@ -19,42 +20,44 @@
#include "lualib.h"
-
/*
-** Structure with table-access functions
+** Operations that an object must define to mimic a table
+** (some functions only need some of them)
*/
-typedef struct {
- int (*geti) (lua_State *L, int idx, lua_Integer n);
- void (*seti) (lua_State *L, int idx, lua_Integer n);
-} TabA;
+#define TAB_R 1 /* read */
+#define TAB_W 2 /* write */
+#define TAB_L 4 /* length */
+#define TAB_RW (TAB_R | TAB_W) /* read/write */
+
+
+#define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n))
+
+
+static int checkfield (lua_State *L, const char *key, int n) {
+ lua_pushstring(L, key);
+ return (lua_rawget(L, -n) != LUA_TNIL);
+}
/*
-** Check that 'arg' has a table and set access functions in 'ta' to raw
-** or non-raw according to the presence of corresponding metamethods.
+** Check that 'arg' either is a table or can behave like one (that is,
+** has a metatable with the required metamethods)
*/
-static void checktab (lua_State *L, int arg, TabA *ta) {
- ta->geti = NULL; ta->seti = NULL;
- if (lua_getmetatable(L, arg)) {
- lua_pushliteral(L, "__index"); /* 'index' metamethod */
- if (lua_rawget(L, -2) != LUA_TNIL)
- ta->geti = lua_geti;
- lua_pushliteral(L, "__newindex"); /* 'newindex' metamethod */
- if (lua_rawget(L, -3) != LUA_TNIL)
- ta->seti = lua_seti;
- lua_pop(L, 3); /* pop metatable plus both metamethods */
- }
- if (ta->geti == NULL || ta->seti == NULL) {
- luaL_checktype(L, arg, LUA_TTABLE); /* must be table for raw methods */
- if (ta->geti == NULL) ta->geti = lua_rawgeti;
- if (ta->seti == NULL) ta->seti = lua_rawseti;
+static void checktab (lua_State *L, int arg, int what) {
+ if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */
+ int n = 1; /* number of elements to pop */
+ if (lua_getmetatable(L, arg) && /* must have metatable */
+ (!(what & TAB_R) || checkfield(L, "__index", ++n)) &&
+ (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) &&
+ (!(what & TAB_L) || checkfield(L, "__len", ++n))) {
+ lua_pop(L, n); /* pop metatable and tested metamethods */
+ }
+ else
+ luaL_checktype(L, arg, LUA_TTABLE); /* force an error */
}
}
-#define aux_getn(L,n,ta) (checktab(L, n, ta), luaL_len(L, n))
-
-
#if defined(LUA_COMPAT_MAXN)
static int maxn (lua_State *L) {
lua_Number max = 0;
@@ -74,8 +77,7 @@ static int maxn (lua_State *L) {
static int tinsert (lua_State *L) {
- TabA ta;
- lua_Integer e = aux_getn(L, 1, &ta) + 1; /* first empty element */
+ lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */
lua_Integer pos; /* where to insert new element */
switch (lua_gettop(L)) {
case 2: { /* called with only 2 arguments */
@@ -87,8 +89,8 @@ static int tinsert (lua_State *L) {
pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */
luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds");
for (i = e; i > pos; i--) { /* move up elements */
- (*ta.geti)(L, 1, i - 1);
- (*ta.seti)(L, 1, i); /* t[i] = t[i - 1] */
+ lua_geti(L, 1, i - 1);
+ lua_seti(L, 1, i); /* t[i] = t[i - 1] */
}
break;
}
@@ -96,65 +98,67 @@ static int tinsert (lua_State *L) {
return luaL_error(L, "wrong number of arguments to 'insert'");
}
}
- (*ta.seti)(L, 1, pos); /* t[pos] = v */
+ lua_seti(L, 1, pos); /* t[pos] = v */
return 0;
}
static int tremove (lua_State *L) {
- TabA ta;
- lua_Integer size = aux_getn(L, 1, &ta);
+ lua_Integer size = aux_getn(L, 1, TAB_RW);
lua_Integer pos = luaL_optinteger(L, 2, size);
if (pos != size) /* validate 'pos' if given */
luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds");
- (*ta.geti)(L, 1, pos); /* result = t[pos] */
+ lua_geti(L, 1, pos); /* result = t[pos] */
for ( ; pos < size; pos++) {
- (*ta.geti)(L, 1, pos + 1);
- (*ta.seti)(L, 1, pos); /* t[pos] = t[pos + 1] */
+ lua_geti(L, 1, pos + 1);
+ lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */
}
lua_pushnil(L);
- (*ta.seti)(L, 1, pos); /* t[pos] = nil */
+ lua_seti(L, 1, pos); /* t[pos] = nil */
return 1;
}
+/*
+** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever
+** possible, copy in increasing order, which is better for rehashing.
+** "possible" means destination after original range, or smaller
+** than origin, or copying to another table.
+*/
static int tmove (lua_State *L) {
- TabA ta;
lua_Integer f = luaL_checkinteger(L, 2);
lua_Integer e = luaL_checkinteger(L, 3);
lua_Integer t = luaL_checkinteger(L, 4);
int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */
- /* the following restriction avoids several problems with overflows */
- luaL_argcheck(L, f > 0, 2, "initial position must be positive");
+ checktab(L, 1, TAB_R);
+ checktab(L, tt, TAB_W);
if (e >= f) { /* otherwise, nothing to move */
lua_Integer n, i;
- ta.geti = (luaL_getmetafield(L, 1, "__index") == LUA_TNIL)
- ? (luaL_checktype(L, 1, LUA_TTABLE), lua_rawgeti)
- : lua_geti;
- ta.seti = (luaL_getmetafield(L, tt, "__newindex") == LUA_TNIL)
- ? (luaL_checktype(L, tt, LUA_TTABLE), lua_rawseti)
- : lua_seti;
+ luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3,
+ "too many elements to move");
n = e - f + 1; /* number of elements to move */
- if (t > f) {
- for (i = n - 1; i >= 0; i--) {
- (*ta.geti)(L, 1, f + i);
- (*ta.seti)(L, tt, t + i);
+ luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4,
+ "destination wrap around");
+ if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) {
+ for (i = 0; i < n; i++) {
+ lua_geti(L, 1, f + i);
+ lua_seti(L, tt, t + i);
}
}
else {
- for (i = 0; i < n; i++) {
- (*ta.geti)(L, 1, f + i);
- (*ta.seti)(L, tt, t + i);
+ for (i = n - 1; i >= 0; i--) {
+ lua_geti(L, 1, f + i);
+ lua_seti(L, tt, t + i);
}
}
}
- lua_pushvalue(L, tt); /* return "to table" */
+ lua_pushvalue(L, tt); /* return destination table */
return 1;
}
-static void addfield (lua_State *L, luaL_Buffer *b, TabA *ta, lua_Integer i) {
- (*ta->geti)(L, 1, i);
+static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
+ lua_geti(L, 1, i);
if (!lua_isstring(L, -1))
luaL_error(L, "invalid value (%s) at index %d in table for 'concat'",
luaL_typename(L, -1), i);
@@ -163,21 +167,19 @@ static void addfield (lua_State *L, luaL_Buffer *b, TabA *ta, lua_Integer i) {
static int tconcat (lua_State *L) {
- TabA ta;
luaL_Buffer b;
+ lua_Integer last = aux_getn(L, 1, TAB_R);
size_t lsep;
- lua_Integer i, last;
const char *sep = luaL_optlstring(L, 2, "", &lsep);
- checktab(L, 1, &ta);
- i = luaL_optinteger(L, 3, 1);
- last = luaL_opt(L, luaL_checkinteger, 4, luaL_len(L, 1));
+ lua_Integer i = luaL_optinteger(L, 3, 1);
+ last = luaL_optinteger(L, 4, last);
luaL_buffinit(L, &b);
for (; i < last; i++) {
- addfield(L, &b, &ta, i);
+ addfield(L, &b, i);
luaL_addlstring(&b, sep, lsep);
}
if (i == last) /* add last value (if interval was not empty) */
- addfield(L, &b, &ta, i);
+ addfield(L, &b, i);
luaL_pushresult(&b);
return 1;
}
@@ -195,7 +197,7 @@ static int pack (lua_State *L) {
lua_createtable(L, n, 1); /* create result table */
lua_insert(L, 1); /* put it at index 1 */
for (i = n; i >= 1; i--) /* assign elements */
- lua_rawseti(L, 1, i);
+ lua_seti(L, 1, i);
lua_pushinteger(L, n);
lua_setfield(L, 1, "n"); /* t.n = number of elements */
return 1; /* return table */
@@ -203,20 +205,17 @@ static int pack (lua_State *L) {
static int unpack (lua_State *L) {
- TabA ta;
- lua_Integer i, e;
lua_Unsigned n;
- checktab(L, 1, &ta);
- i = luaL_optinteger(L, 2, 1);
- e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
+ lua_Integer i = luaL_optinteger(L, 2, 1);
+ lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
if (i > e) return 0; /* empty range */
n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */
if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n)))
return luaL_error(L, "too many results to unpack");
- do { /* must have at least one element */
- (*ta.geti)(L, 1, i); /* push arg[i..e] */
- } while (i++ < e);
-
+ for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */
+ lua_geti(L, 1, i);
+ }
+ lua_geti(L, 1, e); /* push last element */
return (int)n;
}
@@ -233,97 +232,191 @@ static int unpack (lua_State *L) {
*/
-static void set2 (lua_State *L, TabA *ta, int i, int j) {
- (*ta->seti)(L, 1, i);
- (*ta->seti)(L, 1, j);
+/* type for array indices */
+typedef unsigned int IdxT;
+
+
+/*
+** Produce a "random" 'unsigned int' to randomize pivot choice. This
+** macro is used only when 'sort' detects a big imbalance in the result
+** of a partition. (If you don't want/need this "randomness", ~0 is a
+** good choice.)
+*/
+#if !defined(l_randomizePivot) /* { */
+
+#include <time.h>
+
+/* size of 'e' measured in number of 'unsigned int's */
+#define sof(e) (sizeof(e) / sizeof(unsigned int))
+
+/*
+** Use 'time' and 'clock' as sources of "randomness". Because we don't
+** know the types 'clock_t' and 'time_t', we cannot cast them to
+** anything without risking overflows. A safe way to use their values
+** is to copy them to an array of a known type and use the array values.
+*/
+static unsigned int l_randomizePivot (void) {
+ clock_t c = clock();
+ time_t t = time(NULL);
+ unsigned int buff[sof(c) + sof(t)];
+ unsigned int i, rnd = 0;
+ memcpy(buff, &c, sof(c) * sizeof(unsigned int));
+ memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int));
+ for (i = 0; i < sof(buff); i++)
+ rnd += buff[i];
+ return rnd;
+}
+
+#endif /* } */
+
+
+/* arrays larger than 'RANLIMIT' may use randomized pivots */
+#define RANLIMIT 100u
+
+
+static void set2 (lua_State *L, IdxT i, IdxT j) {
+ lua_seti(L, 1, i);
+ lua_seti(L, 1, j);
}
+
+/*
+** Return true iff value at stack index 'a' is less than the value at
+** index 'b' (according to the order of the sort).
+*/
static int sort_comp (lua_State *L, int a, int b) {
- if (!lua_isnil(L, 2)) { /* function? */
+ if (lua_isnil(L, 2)) /* no function? */
+ return lua_compare(L, a, b, LUA_OPLT); /* a < b */
+ else { /* function */
int res;
- lua_pushvalue(L, 2);
+ lua_pushvalue(L, 2); /* push function */
lua_pushvalue(L, a-1); /* -1 to compensate function */
lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */
- lua_call(L, 2, 1);
- res = lua_toboolean(L, -1);
- lua_pop(L, 1);
+ lua_call(L, 2, 1); /* call function */
+ res = lua_toboolean(L, -1); /* get result */
+ lua_pop(L, 1); /* pop result */
return res;
}
- else /* a < b? */
- return lua_compare(L, a, b, LUA_OPLT);
}
-static void auxsort (lua_State *L, TabA *ta, int l, int u) {
- while (l < u) { /* for tail recursion */
- int i, j;
- /* sort elements a[l], a[(l+u)/2] and a[u] */
- (*ta->geti)(L, 1, l);
- (*ta->geti)(L, 1, u);
- if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */
- set2(L, ta, l, u); /* swap a[l] - a[u] */
+
+/*
+** Does the partition: Pivot P is at the top of the stack.
+** precondition: a[lo] <= P == a[up-1] <= a[up],
+** so it only needs to do the partition from lo + 1 to up - 2.
+** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up]
+** returns 'i'.
+*/
+static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
+ IdxT i = lo; /* will be incremented before first use */
+ IdxT j = up - 1; /* will be decremented before first use */
+ /* loop invariant: a[lo .. i] <= P <= a[j .. up] */
+ for (;;) {
+ /* next loop: repeat ++i while a[i] < P */
+ while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) {
+ if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */
+ luaL_error(L, "invalid order function for sorting");
+ lua_pop(L, 1); /* remove a[i] */
+ }
+ /* after the loop, a[i] >= P and a[lo .. i - 1] < P */
+ /* next loop: repeat --j while P < a[j] */
+ while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) {
+ if (j < i) /* j < i but a[j] > P ?? */
+ luaL_error(L, "invalid order function for sorting");
+ lua_pop(L, 1); /* remove a[j] */
+ }
+ /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */
+ if (j < i) { /* no elements out of place? */
+ /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */
+ lua_pop(L, 1); /* pop a[j] */
+ /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */
+ set2(L, up - 1, i);
+ return i;
+ }
+ /* otherwise, swap a[i] - a[j] to restore invariant and repeat */
+ set2(L, i, j);
+ }
+}
+
+
+/*
+** Choose an element in the middle (2nd-3th quarters) of [lo,up]
+** "randomized" by 'rnd'
+*/
+static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {
+ IdxT r4 = (up - lo) / 4; /* range/4 */
+ IdxT p = rnd % (r4 * 2) + (lo + r4);
+ lua_assert(lo + r4 <= p && p <= up - r4);
+ return p;
+}
+
+
+/*
+** QuickSort algorithm (recursive function)
+*/
+static void auxsort (lua_State *L, IdxT lo, IdxT up,
+ unsigned int rnd) {
+ while (lo < up) { /* loop for tail recursion */
+ IdxT p; /* Pivot index */
+ IdxT n; /* to be used later */
+ /* sort elements 'lo', 'p', and 'up' */
+ lua_geti(L, 1, lo);
+ lua_geti(L, 1, up);
+ if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */
+ set2(L, lo, up); /* swap a[lo] - a[up] */
else
- lua_pop(L, 2);
- if (u-l == 1) break; /* only 2 elements */
- i = (l+u)/2;
- (*ta->geti)(L, 1, i);
- (*ta->geti)(L, 1, l);
- if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */
- set2(L, ta, i, l);
+ lua_pop(L, 2); /* remove both values */
+ if (up - lo == 1) /* only 2 elements? */
+ return; /* already sorted */
+ if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */
+ p = (lo + up)/2; /* middle element is a good pivot */
+ else /* for larger intervals, it is worth a random pivot */
+ p = choosePivot(lo, up, rnd);
+ lua_geti(L, 1, p);
+ lua_geti(L, 1, lo);
+ if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */
+ set2(L, p, lo); /* swap a[p] - a[lo] */
else {
- lua_pop(L, 1); /* remove a[l] */
- (*ta->geti)(L, 1, u);
- if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */
- set2(L, ta, i, u);
+ lua_pop(L, 1); /* remove a[lo] */
+ lua_geti(L, 1, up);
+ if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */
+ set2(L, p, up); /* swap a[up] - a[p] */
else
lua_pop(L, 2);
}
- if (u-l == 2) break; /* only 3 elements */
- (*ta->geti)(L, 1, i); /* Pivot */
- lua_pushvalue(L, -1);
- (*ta->geti)(L, 1, u-1);
- set2(L, ta, i, u-1);
- /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
- i = l; j = u-1;
- for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */
- /* repeat ++i until a[i] >= P */
- while ((*ta->geti)(L, 1, ++i), sort_comp(L, -1, -2)) {
- if (i>=u) luaL_error(L, "invalid order function for sorting");
- lua_pop(L, 1); /* remove a[i] */
- }
- /* repeat --j until a[j] <= P */
- while ((*ta->geti)(L, 1, --j), sort_comp(L, -3, -1)) {
- if (j<=l) luaL_error(L, "invalid order function for sorting");
- lua_pop(L, 1); /* remove a[j] */
- }
- if (j<i) {
- lua_pop(L, 3); /* pop pivot, a[i], a[j] */
- break;
- }
- set2(L, ta, i, j);
- }
- (*ta->geti)(L, 1, u-1);
- (*ta->geti)(L, 1, i);
- set2(L, ta, u-1, i); /* swap pivot (a[u-1]) with a[i] */
- /* a[l..i-1] <= a[i] == P <= a[i+1..u] */
- /* adjust so that smaller half is in [j..i] and larger one in [l..u] */
- if (i-l < u-i) {
- j=l; i=i-1; l=i+2;
+ if (up - lo == 2) /* only 3 elements? */
+ return; /* already sorted */
+ lua_geti(L, 1, p); /* get middle element (Pivot) */
+ lua_pushvalue(L, -1); /* push Pivot */
+ lua_geti(L, 1, up - 1); /* push a[up - 1] */
+ set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */
+ p = partition(L, lo, up);
+ /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */
+ if (p - lo < up - p) { /* lower interval is smaller? */
+ auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */
+ n = p - lo; /* size of smaller interval */
+ lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */
}
else {
- j=i+1; i=u; u=j-2;
+ auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */
+ n = up - p; /* size of smaller interval */
+ up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */
}
- auxsort(L, ta, j, i); /* call recursively the smaller one */
- } /* repeat the routine for the larger one */
+ if ((up - lo) / 128 > n) /* partition too imbalanced? */
+ rnd = l_randomizePivot(); /* try a new randomization */
+ } /* tail call auxsort(L, lo, up, rnd) */
}
+
static int sort (lua_State *L) {
- TabA ta;
- int n = (int)aux_getn(L, 1, &ta);
- luaL_checkstack(L, 50, ""); /* assume array is smaller than 2^50 */
- if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
- luaL_checktype(L, 2, LUA_TFUNCTION);
- lua_settop(L, 2); /* make sure there are two arguments */
- auxsort(L, &ta, 1, n);
+ lua_Integer n = aux_getn(L, 1, TAB_RW);
+ if (n > 1) { /* non-trivial interval? */
+ luaL_argcheck(L, n < INT_MAX, 1, "array too big");
+ if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
+ luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */
+ lua_settop(L, 2); /* make sure there are two arguments */
+ auxsort(L, 1, (IdxT)n, 0);
+ }
return 0;
}
diff --git a/src/ltm.c b/src/ltm.c
index 25b46b17f90d..14e525788842 100644
--- a/src/ltm.c
+++ b/src/ltm.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.c,v 2.33 2014/11/21 12:15:57 roberto Exp $
+** $Id: ltm.c,v 2.38 2016/12/22 13:08:50 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -15,7 +15,7 @@
#include "lua.h"
#include "ldebug.h"
-#include "ldo.h"
+#include "ldo.h"
#include "lobject.h"
#include "lstate.h"
#include "lstring.h"
@@ -57,7 +57,7 @@ void luaT_init (lua_State *L) {
** tag methods
*/
const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
- const TValue *tm = luaH_getstr(events, ename);
+ const TValue *tm = luaH_getshortstr(events, ename);
lua_assert(event <= TM_EQ);
if (ttisnil(tm)) { /* no tag method? */
events->flags |= cast_byte(1u<<event); /* cache this fact */
@@ -79,20 +79,41 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
default:
mt = G(L)->mt[ttnov(o)];
}
- return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject);
+ return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject);
+}
+
+
+/*
+** Return the name of the type of an object. For tables and userdata
+** with metatable, use their '__name' metafield, if present.
+*/
+const char *luaT_objtypename (lua_State *L, const TValue *o) {
+ Table *mt;
+ if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) ||
+ (ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) {
+ const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name"));
+ if (ttisstring(name)) /* is '__name' a string? */
+ return getstr(tsvalue(name)); /* use it as type name */
+ }
+ return ttypename(ttnov(o)); /* else use standard type name */
}
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, TValue *p3, int hasres) {
ptrdiff_t result = savestack(L, p3);
- setobj2s(L, L->top++, f); /* push function (assume EXTRA_STACK) */
- setobj2s(L, L->top++, p1); /* 1st argument */
- setobj2s(L, L->top++, p2); /* 2nd argument */
+ StkId func = L->top;
+ setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
+ setobj2s(L, func + 1, p1); /* 1st argument */
+ setobj2s(L, func + 2, p2); /* 2nd argument */
+ L->top += 3;
if (!hasres) /* no result? 'p3' is third argument */
setobj2s(L, L->top++, p3); /* 3rd argument */
/* metamethod may yield only when called from Lua code */
- luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci));
+ if (isLua(L->ci))
+ luaD_call(L, func, hasres);
+ else
+ luaD_callnoyield(L, func, hasres);
if (hasres) { /* if has result, move it to its place */
p3 = restorestack(L, result);
setobjs2s(L, p3, --L->top);
@@ -117,6 +138,7 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
switch (event) {
case TM_CONCAT:
luaG_concaterror(L, p1, p2);
+ /* call never returns, but to avoid warnings: *//* FALLTHROUGH */
case TM_BAND: case TM_BOR: case TM_BXOR:
case TM_SHL: case TM_SHR: case TM_BNOT: {
lua_Number dummy;
@@ -124,8 +146,8 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
luaG_tointerror(L, p1, p2);
else
luaG_opinterror(L, p1, p2, "perform bitwise operation on");
- /* else go through */
}
+ /* calls never return, but to avoid warnings: *//* FALLTHROUGH */
default:
luaG_opinterror(L, p1, p2, "perform arithmetic on");
}
diff --git a/src/ltm.h b/src/ltm.h
index 180179ce038e..63db7269bbfc 100644
--- a/src/ltm.h
+++ b/src/ltm.h
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.h,v 2.21 2014/10/25 11:50:46 roberto Exp $
+** $Id: ltm.h,v 2.22 2016/02/26 19:20:15 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -51,11 +51,12 @@ typedef enum {
#define fasttm(l,et,e) gfasttm(G(l), et, e)
#define ttypename(x) luaT_typenames_[(x) + 1]
-#define objtypename(x) ttypename(ttnov(x))
LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS];
+LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o);
+
LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename);
LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,
TMS event);
diff --git a/src/lua.c b/src/lua.c
index 34a3900a7949..3f082da6be61 100644
--- a/src/lua.c
+++ b/src/lua.c
@@ -1,5 +1,5 @@
/*
-** $Id: lua.c,v 1.222 2014/11/11 19:41:27 roberto Exp $
+** $Id: lua.c,v 1.230 2017/01/12 17:14:26 roberto Exp $
** Lua stand-alone interpreter
** See Copyright Notice in lua.h
*/
@@ -20,6 +20,7 @@
#include "lualib.h"
+
#if !defined(LUA_PROMPT)
#define LUA_PROMPT "> "
#define LUA_PROMPT2 ">> "
@@ -37,8 +38,7 @@
#define LUA_INIT_VAR "LUA_INIT"
#endif
-#define LUA_INITVARVERSION \
- LUA_INIT_VAR "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
+#define LUA_INITVARVERSION LUA_INIT_VAR LUA_VERSUFFIX
/*
@@ -55,6 +55,8 @@
#elif defined(LUA_USE_WINDOWS) /* }{ */
#include <io.h>
+#include <windows.h>
+
#define lua_stdin_is_tty() _isatty(_fileno(stdin))
#else /* }{ */
@@ -80,9 +82,7 @@
#include <readline/readline.h>
#include <readline/history.h>
#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL)
-#define lua_saveline(L,idx) \
- if (lua_rawlen(L,idx) > 0) /* non-empty line? */ \
- add_history(lua_tostring(L, idx)); /* add it to history */
+#define lua_saveline(L,line) ((void)L, add_history(line))
#define lua_freeline(L,b) ((void)L, free(b))
#else /* }{ */
@@ -90,7 +90,7 @@
#define lua_readline(L,b,p) \
((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \
fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */
-#define lua_saveline(L,idx) { (void)L; (void)idx; }
+#define lua_saveline(L,line) { (void)L; (void)line; }
#define lua_freeline(L,b) { (void)L; (void)b; }
#endif /* } */
@@ -315,31 +315,31 @@ static int pushline (lua_State *L, int firstline) {
lua_pop(L, 1); /* remove prompt */
l = strlen(b);
if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
- b[l-1] = '\0'; /* remove it */
+ b[--l] = '\0'; /* remove it */
if (firstline && b[0] == '=') /* for compatibility with 5.2, ... */
lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */
else
- lua_pushstring(L, b);
+ lua_pushlstring(L, b, l);
lua_freeline(L, b);
return 1;
}
/*
-** Try to compile line on the stack as 'return <line>'; on return, stack
+** Try to compile line on the stack as 'return <line>;'; on return, stack
** has either compiled chunk or original line (if compilation failed).
*/
static int addreturn (lua_State *L) {
- int status;
- size_t len; const char *line;
- lua_pushliteral(L, "return ");
- lua_pushvalue(L, -2); /* duplicate line */
- lua_concat(L, 2); /* new line is "return ..." */
- line = lua_tolstring(L, -1, &len);
- if ((status = luaL_loadbuffer(L, line, len, "=stdin")) == LUA_OK)
- lua_remove(L, -3); /* remove original line */
+ const char *line = lua_tostring(L, -1); /* original line */
+ const char *retline = lua_pushfstring(L, "return %s;", line);
+ int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin");
+ if (status == LUA_OK) {
+ lua_remove(L, -2); /* remove modified line */
+ if (line[0] != '\0') /* non empty? */
+ lua_saveline(L, line); /* keep history */
+ }
else
- lua_pop(L, 2); /* remove result from 'luaL_loadbuffer' and new line */
+ lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */
return status;
}
@@ -352,8 +352,10 @@ static int multiline (lua_State *L) {
size_t len;
const char *line = lua_tolstring(L, 1, &len); /* get what it has */
int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */
- if (!incomplete(L, status) || !pushline(L, 0))
+ if (!incomplete(L, status) || !pushline(L, 0)) {
+ lua_saveline(L, line); /* keep history */
return status; /* cannot or should not try to add continuation line */
+ }
lua_pushliteral(L, "\n"); /* add newline... */
lua_insert(L, -2); /* ...between the two lines */
lua_concat(L, 3); /* join them */
@@ -374,7 +376,6 @@ static int loadline (lua_State *L) {
return -1; /* no input */
if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */
status = multiline(L); /* try as command, maybe with continuation lines */
- lua_saveline(L, 1); /* keep history */
lua_remove(L, 1); /* remove line from the stack */
lua_assert(lua_gettop(L) == 1);
return status;
@@ -458,7 +459,7 @@ static int handle_script (lua_State *L, char **argv) {
/*
** Traverses all arguments from 'argv', returning a mask with those
** needed before running any Lua code (or an error code if it finds
-** any invalid argument). 'first' returns the first not-handled argument
+** any invalid argument). 'first' returns the first not-handled argument
** (either the script name or a bad argument in case of error).
*/
static int collectargs (char **argv, int *first) {
@@ -482,14 +483,14 @@ static int collectargs (char **argv, int *first) {
args |= has_E;
break;
case 'i':
- args |= has_i; /* goes through (-i implies -v) */
+ args |= has_i; /* (-i implies -v) *//* FALLTHROUGH */
case 'v':
if (argv[i][2] != '\0') /* extra characters after 1st? */
return has_error; /* invalid option */
args |= has_v;
break;
case 'e':
- args |= has_e; /* go through */
+ args |= has_e; /* FALLTHROUGH */
case 'l': /* both options need an argument */
if (argv[i][2] == '\0') { /* no concatenated argument? */
i++; /* try next 'argv' */
@@ -513,17 +514,16 @@ static int collectargs (char **argv, int *first) {
static int runargs (lua_State *L, char **argv, int n) {
int i;
for (i = 1; i < n; i++) {
- int status;
int option = argv[i][1];
lua_assert(argv[i][0] == '-'); /* already checked */
if (option == 'e' || option == 'l') {
+ int status;
const char *extra = argv[i] + 2; /* both options need an argument */
if (*extra == '\0') extra = argv[++i];
lua_assert(extra != NULL);
- if (option == 'e')
- status = dostring(L, extra, "=(command line)");
- else
- status = dolibrary(L, extra);
+ status = (option == 'e')
+ ? dostring(L, extra, "=(command line)")
+ : dolibrary(L, extra);
if (status != LUA_OK) return 0;
}
}
@@ -531,6 +531,7 @@ static int runargs (lua_State *L, char **argv, int n) {
}
+
static int handle_luainit (lua_State *L) {
const char *name = "=" LUA_INITVARVERSION;
const char *init = getenv(name + 1);
diff --git a/src/lua.h b/src/lua.h
index 09a4ccaf89f2..26c0e2d698c4 100644
--- a/src/lua.h
+++ b/src/lua.h
@@ -1,5 +1,5 @@
/*
-** $Id: lua.h,v 1.325 2014/12/26 17:24:27 roberto Exp $
+** $Id: lua.h,v 1.332 2016/12/22 15:51:20 roberto Exp $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
@@ -19,11 +19,11 @@
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "3"
#define LUA_VERSION_NUM 503
-#define LUA_VERSION_RELEASE "0"
+#define LUA_VERSION_RELEASE "4"
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
-#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2015 Lua.org, PUC-Rio"
+#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2017 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -35,9 +35,11 @@
/*
-** pseudo-indices
+** Pseudo-indices
+** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
+** space after that to help overflow detection)
*/
-#define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX
+#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000)
#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
@@ -356,11 +358,10 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
-#define lua_pushliteral(L, s) \
- lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)
+#define lua_pushliteral(L, s) lua_pushstring(L, "" s)
#define lua_pushglobaltable(L) \
- lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)
+ ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
@@ -459,7 +460,7 @@ struct lua_Debug {
/******************************************************************************
-* Copyright (C) 1994-2015 Lua.org, PUC-Rio.
+* Copyright (C) 1994-2017 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
diff --git a/src/luac.c b/src/luac.c
index c565f46aa50a..c0c91d017ae3 100644
--- a/src/luac.c
+++ b/src/luac.c
@@ -1,5 +1,5 @@
/*
-** $Id: luac.c,v 1.72 2015/01/06 03:09:13 lhf Exp $
+** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $
** Lua compiler (saves bytecodes to files; also lists bytecodes)
** See Copyright Notice in lua.h
*/
@@ -206,7 +206,7 @@ int main(int argc, char* argv[])
}
/*
-** $Id: print.c,v 1.76 2015/01/05 16:12:50 lhf Exp $
+** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $
** print bytecodes
** See Copyright Notice in lua.h
*/
@@ -226,7 +226,7 @@ int main(int argc, char* argv[])
static void PrintString(const TString* ts)
{
const char* s=getstr(ts);
- size_t i,n=ts->len;
+ size_t i,n=tsslen(ts);
printf("%c",'"');
for (i=0; i<n; i++)
{
diff --git a/src/luaconf.h b/src/luaconf.h
index fd28d21aec96..f37bea0964bd 100644
--- a/src/luaconf.h
+++ b/src/luaconf.h
@@ -1,5 +1,5 @@
/*
-** $Id: luaconf.h,v 1.238 2014/12/29 13:27:55 roberto Exp $
+** $Id: luaconf.h,v 1.259 2016/12/22 13:08:50 roberto Exp $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
@@ -96,10 +96,8 @@
/*
-@@ LUA_INT_INT / LUA_INT_LONG / LUA_INT_LONGLONG defines the type for
-** Lua integers.
-@@ LUA_REAL_FLOAT / LUA_REAL_DOUBLE / LUA_REAL_LONGDOUBLE defines
-** the type for Lua floats.
+@@ LUA_INT_TYPE defines the type for Lua integers.
+@@ LUA_FLOAT_TYPE defines the type for Lua floats.
** Lua should work fine with any mix of these options (if supported
** by your C compiler). The usual configurations are 64-bit integers
** and 'double' (the default), 32-bit integers and 'float' (for
@@ -107,32 +105,47 @@
** compliant with C99, which may not have support for 'long long').
*/
+/* predefined options for LUA_INT_TYPE */
+#define LUA_INT_INT 1
+#define LUA_INT_LONG 2
+#define LUA_INT_LONGLONG 3
+
+/* predefined options for LUA_FLOAT_TYPE */
+#define LUA_FLOAT_FLOAT 1
+#define LUA_FLOAT_DOUBLE 2
+#define LUA_FLOAT_LONGDOUBLE 3
+
#if defined(LUA_32BITS) /* { */
/*
** 32-bit integers and 'float'
*/
#if LUAI_BITSINT >= 32 /* use 'int' if big enough */
-#define LUA_INT_INT
+#define LUA_INT_TYPE LUA_INT_INT
#else /* otherwise use 'long' */
-#define LUA_INT_LONG
+#define LUA_INT_TYPE LUA_INT_LONG
#endif
-#define LUA_REAL_FLOAT
+#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT
#elif defined(LUA_C89_NUMBERS) /* }{ */
/*
** largest types available for C89 ('long' and 'double')
*/
-#define LUA_INT_LONG
-#define LUA_REAL_DOUBLE
+#define LUA_INT_TYPE LUA_INT_LONG
+#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
+
+#endif /* } */
+
-#else /* }{ */
/*
** default configuration for 64-bit Lua ('long long' and 'double')
*/
-#define LUA_INT_LONGLONG
-#define LUA_REAL_DOUBLE
+#if !defined(LUA_INT_TYPE)
+#define LUA_INT_TYPE LUA_INT_LONGLONG
+#endif
-#endif /* } */
+#if !defined(LUA_FLOAT_TYPE)
+#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
+#endif
/* }================================================================== */
@@ -146,6 +159,18 @@
*/
/*
+** LUA_PATH_SEP is the character that separates templates in a path.
+** LUA_PATH_MARK is the string that marks the substitution points in a
+** template.
+** LUA_EXEC_DIR in a Windows path is replaced by the executable's
+** directory.
+*/
+#define LUA_PATH_SEP ";"
+#define LUA_PATH_MARK "?"
+#define LUA_EXEC_DIR "!"
+
+
+/*
@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
** Lua libraries.
@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for
@@ -155,7 +180,7 @@
** non-conventional directories.
*/
#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
-#if defined(_WIN32) /* { */
+#if defined(_WIN32) /* { */
/*
** In Windows, any exclamation mark ('!') in the path is replaced by the
** path of the directory of the executable file of the current process.
@@ -300,20 +325,15 @@
*/
#define LUA_COMPAT_APIINTCASTS
-
-/*
-@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a
-@@ a float mark ('.0').
-** This macro is not on by default even in compatibility mode,
-** because this is not really an incompatibility.
-*/
-/* #define LUA_COMPAT_FLOATSTRING */
-
#endif /* } */
#if defined(LUA_COMPAT_5_1) /* { */
+/* Incompatibilities from 5.2 -> 5.3 */
+#define LUA_COMPAT_MATHLIB
+#define LUA_COMPAT_APIINTCASTS
+
/*
@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'.
** You can replace it with 'table.unpack'.
@@ -373,6 +393,15 @@
#endif /* } */
+
+/*
+@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a
+@@ a float mark ('.0').
+** This macro is not on by default even in compatibility mode,
+** because this is not really an incompatibility.
+*/
+/* #define LUA_COMPAT_FLOATSTRING */
+
/* }================================================================== */
@@ -380,30 +409,55 @@
/*
** {==================================================================
** Configuration for Numbers.
-** Change these definitions if no predefined LUA_REAL_* / LUA_INT_*
+** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*
** satisfy your needs.
** ===================================================================
*/
/*
@@ LUA_NUMBER is the floating-point type used by Lua.
-**
-@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
+@@ LUAI_UACNUMBER is the result of a 'default argument promotion'
@@ over a floating number.
-**
+@@ l_mathlim(x) corrects limit name 'x' to the proper float type
+** by prefixing it with one of FLT/DBL/LDBL.
@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
@@ LUA_NUMBER_FMT is the format for writing floats.
@@ lua_number2str converts a float to a string.
-**
@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
-**
+@@ l_floor takes the floor of a float.
@@ lua_str2number converts a decimal numeric string to a number.
*/
-#if defined(LUA_REAL_FLOAT) /* { single float */
+
+/* The following definitions are good for most cases here */
+
+#define l_floor(x) (l_mathop(floor)(x))
+
+#define lua_number2str(s,sz,n) \
+ l_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n))
+
+/*
+@@ lua_numbertointeger converts a float number to an integer, or
+** returns 0 if float is not within the range of a lua_Integer.
+** (The range comparisons are tricky because of rounding. The tests
+** here assume a two-complement representation, where MININTEGER always
+** has an exact representation as a float; MAXINTEGER may not have one,
+** and therefore its conversion to float may have an ill-defined value.)
+*/
+#define lua_numbertointeger(n,p) \
+ ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
+ (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
+ (*(p) = (LUA_INTEGER)(n), 1))
+
+
+/* now the variable definitions */
+
+#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */
#define LUA_NUMBER float
+#define l_mathlim(n) (FLT_##n)
+
#define LUAI_UACNUMBER double
#define LUA_NUMBER_FRMLEN ""
@@ -414,10 +468,12 @@
#define lua_str2number(s,p) strtof((s), (p))
-#elif defined(LUA_REAL_LONGDOUBLE) /* }{ long double */
+#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */
#define LUA_NUMBER long double
+#define l_mathlim(n) (LDBL_##n)
+
#define LUAI_UACNUMBER long double
#define LUA_NUMBER_FRMLEN "L"
@@ -427,10 +483,12 @@
#define lua_str2number(s,p) strtold((s), (p))
-#elif defined(LUA_REAL_DOUBLE) /* }{ double */
+#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */
#define LUA_NUMBER double
+#define l_mathlim(n) (DBL_##n)
+
#define LUAI_UACNUMBER double
#define LUA_NUMBER_FRMLEN ""
@@ -440,79 +498,20 @@
#define lua_str2number(s,p) strtod((s), (p))
-#else /* }{ */
+#else /* }{ */
-#error "numeric real type not defined"
+#error "numeric float type not defined"
#endif /* } */
-#define l_floor(x) (l_mathop(floor)(x))
-
-#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n))
-
-
-/*
-@@ lua_numbertointeger converts a float number to an integer, or
-** returns 0 if float is not within the range of a lua_Integer.
-** (The range comparisons are tricky because of rounding. The tests
-** here assume a two-complement representation, where MININTEGER always
-** has an exact representation as a float; MAXINTEGER may not have one,
-** and therefore its conversion to float may have an ill-defined value.)
-*/
-#define lua_numbertointeger(n,p) \
- ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
- (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
- (*(p) = (LUA_INTEGER)(n), 1))
-
-
-/*
-@@ The luai_num* macros define the primitive operations over numbers.
-** They should work for any size of floating numbers.
-*/
-
-/* the following operations need the math library */
-#if defined(lobject_c) || defined(lvm_c)
-#include <math.h>
-
-/* floor division (defined as 'floor(a/b)') */
-#define luai_numidiv(L,a,b) ((void)L, l_mathop(floor)(luai_numdiv(L,a,b)))
-
-/*
-** module: defined as 'a - floor(a/b)*b'; the previous definition gives
-** NaN when 'b' is huge, but the result should be 'a'. 'fmod' gives the
-** result of 'a - trunc(a/b)*b', and therefore must be corrected when
-** 'trunc(a/b) ~= floor(a/b)'. That happens when the division has a
-** non-integer negative result, which is equivalent to the test below
-*/
-#define luai_nummod(L,a,b,m) \
- { (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); }
-
-/* exponentiation */
-#define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b))
-
-#endif
-
-/* these are quite standard operations */
-#if defined(LUA_CORE)
-#define luai_numadd(L,a,b) ((a)+(b))
-#define luai_numsub(L,a,b) ((a)-(b))
-#define luai_nummul(L,a,b) ((a)*(b))
-#define luai_numdiv(L,a,b) ((a)/(b))
-#define luai_numunm(L,a) (-(a))
-#define luai_numeq(a,b) ((a)==(b))
-#define luai_numlt(a,b) ((a)<(b))
-#define luai_numle(a,b) ((a)<=(b))
-#define luai_numisnan(a) (!luai_numeq((a), (a)))
-#endif
-
/*
@@ LUA_INTEGER is the integer type used by Lua.
**
@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
**
-@@ LUAI_UACINT is the result of an 'usual argument conversion'
+@@ LUAI_UACINT is the result of a 'default argument promotion'
@@ over a lUA_INTEGER.
@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
@@ LUA_INTEGER_FMT is the format for writing integers.
@@ -525,10 +524,12 @@
/* The following definitions are good for most cases here */
#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d"
-#define lua_integer2str(s,n) sprintf((s), LUA_INTEGER_FMT, (n))
#define LUAI_UACINT LUA_INTEGER
+#define lua_integer2str(s,sz,n) \
+ l_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n))
+
/*
** use LUAI_UACINT here to avoid problems with promotions (which
** can turn a comparison between unsigneds into a signed comparison)
@@ -538,7 +539,7 @@
/* now the variable definitions */
-#if defined(LUA_INT_INT) /* { int */
+#if LUA_INT_TYPE == LUA_INT_INT /* { int */
#define LUA_INTEGER int
#define LUA_INTEGER_FRMLEN ""
@@ -546,7 +547,7 @@
#define LUA_MAXINTEGER INT_MAX
#define LUA_MININTEGER INT_MIN
-#elif defined(LUA_INT_LONG) /* }{ long */
+#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */
#define LUA_INTEGER long
#define LUA_INTEGER_FRMLEN "l"
@@ -554,8 +555,9 @@
#define LUA_MAXINTEGER LONG_MAX
#define LUA_MININTEGER LONG_MIN
-#elif defined(LUA_INT_LONGLONG) /* }{ long long */
+#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */
+/* use presence of macro LLONG_MAX as proxy for C99 compliance */
#if defined(LLONG_MAX) /* { */
/* use ISO C99 stuff */
@@ -592,28 +594,41 @@
/*
** {==================================================================
-** Dependencies with C99
+** Dependencies with C99 and other C details
** ===================================================================
*/
/*
+@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89.
+** (All uses in Lua have only one format item.)
+*/
+#if !defined(LUA_USE_C89)
+#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i)
+#else
+#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i))
+#endif
+
+
+/*
@@ lua_strx2number converts an hexadecimal numeric string to a number.
-** In C99, 'strtod' does both conversions. Otherwise, you can
+** In C99, 'strtod' does that conversion. Otherwise, you can
** leave 'lua_strx2number' undefined and Lua will provide its own
** implementation.
*/
#if !defined(LUA_USE_C89)
-#define lua_strx2number(s,p) lua_str2number(s,p)
+#define lua_strx2number(s,p) lua_str2number(s,p)
#endif
/*
-@@ LUA_USE_AFORMAT allows '%a'/'%A' specifiers in 'string.format'
-** Enable it if the C function 'printf' supports these specifiers.
-** (C99 demands it and Windows also supports it.)
+@@ lua_number2strx converts a float to an hexadecimal numeric string.
+** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
+** Otherwise, you can leave 'lua_number2strx' undefined and Lua will
+** provide its own implementation.
*/
-#if !defined(LUA_USE_C89) || defined(LUA_USE_WINDOWS)
-#define LUA_USE_AFORMAT
+#if !defined(LUA_USE_C89)
+#define lua_number2strx(L,b,sz,f,n) \
+ ((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n)))
#endif
@@ -642,12 +657,50 @@
#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
__STDC_VERSION__ >= 199901L
#include <stdint.h>
-#if defined (INTPTR_MAX) /* even in C99 this type is optional */
+#if defined(INTPTR_MAX) /* even in C99 this type is optional */
#undef LUA_KCONTEXT
#define LUA_KCONTEXT intptr_t
#endif
#endif
+
+/*
+@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point).
+** Change that if you do not want to use C locales. (Code using this
+** macro must include header 'locale.h'.)
+*/
+#if !defined(lua_getlocaledecpoint)
+#define lua_getlocaledecpoint() (localeconv()->decimal_point[0])
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Language Variations
+** =====================================================================
+*/
+
+/*
+@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some
+** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from
+** numbers to strings. Define LUA_NOCVTS2N to turn off automatic
+** coercion from strings to numbers.
+*/
+/* #define LUA_NOCVTN2S */
+/* #define LUA_NOCVTS2N */
+
+
+/*
+@@ LUA_USE_APICHECK turns on several consistency checks on the C API.
+** Define it as a help when debugging C code.
+*/
+#if defined(LUA_USE_APICHECK)
+#include <assert.h>
+#define luai_apicheck(l,e) assert(e)
+#endif
+
/* }================================================================== */
@@ -671,9 +724,6 @@
#define LUAI_MAXSTACK 15000
#endif
-/* reserve some space for error handling */
-#define LUAI_FIRSTPSEUDOIDX (-LUAI_MAXSTACK - 1000)
-
/*
@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
@@ -692,19 +742,17 @@
/*
-@@ LUAI_MAXSHORTLEN is the maximum length for short strings, that is,
-** strings that are internalized. (Cannot be smaller than reserved words
-** or tags for metamethods, as these strings must be internalized;
-** #("function") = 8, #("__newindex") = 10.)
-*/
-#define LUAI_MAXSHORTLEN 40
-
-
-/*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
-** CHANGE it if it uses too much C-stack space.
+** CHANGE it if it uses too much C-stack space. (For long double,
+** 'string.format("%.99f", -1e4932)' needs 5034 bytes, so a
+** smaller buffer would force a memory allocation for each call to
+** 'string.format'.)
*/
-#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
+#if LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE
+#define LUAL_BUFFERSIZE 8192
+#else
+#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
+#endif
/* }================================================================== */
diff --git a/src/lualib.h b/src/lualib.h
index 5165c0fb3f0f..6c0bc4cb084e 100644
--- a/src/lualib.h
+++ b/src/lualib.h
@@ -1,5 +1,5 @@
/*
-** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $
+** $Id: lualib.h,v 1.45 2017/01/12 17:14:26 roberto Exp $
** Lua standard libraries
** See Copyright Notice in lua.h
*/
@@ -11,6 +11,9 @@
#include "lua.h"
+/* version suffix for environment variable names */
+#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
+
LUAMOD_API int (luaopen_base) (lua_State *L);
diff --git a/src/lundump.c b/src/lundump.c
index 510f32582748..4080af9c0d94 100644
--- a/src/lundump.c
+++ b/src/lundump.c
@@ -1,5 +1,5 @@
/*
-** $Id: lundump.c,v 2.41 2014/11/02 19:19:04 roberto Exp $
+** $Id: lundump.c,v 2.44 2015/11/02 16:09:30 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -32,7 +32,6 @@
typedef struct {
lua_State *L;
ZIO *Z;
- Mbuffer *b;
const char *name;
} LoadState;
@@ -92,10 +91,15 @@ static TString *LoadString (LoadState *S) {
LoadVar(S, size);
if (size == 0)
return NULL;
- else {
- char *s = luaZ_openspace(S->L, S->b, --size);
- LoadVector(S, s, size);
- return luaS_newlstr(S->L, s, size);
+ else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */
+ char buff[LUAI_MAXSHORTLEN];
+ LoadVector(S, buff, size);
+ return luaS_newlstr(S->L, buff, size);
+ }
+ else { /* long string */
+ TString *ts = luaS_createlngstrobj(S->L, size);
+ LoadVector(S, getstr(ts), size); /* load directly in final place */
+ return ts;
}
}
@@ -251,8 +255,7 @@ static void checkHeader (LoadState *S) {
/*
** load precompiled chunk
*/
-LClosure *luaU_undump(lua_State *L, ZIO *Z, Mbuffer *buff,
- const char *name) {
+LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
LoadState S;
LClosure *cl;
if (*name == '@' || *name == '=')
@@ -263,11 +266,10 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, Mbuffer *buff,
S.name = name;
S.L = L;
S.Z = Z;
- S.b = buff;
checkHeader(&S);
cl = luaF_newLclosure(L, LoadByte(&S));
setclLvalue(L, L->top, cl);
- incr_top(L);
+ luaD_inctop(L);
cl->p = luaF_newproto(L);
LoadFunction(&S, cl->p, NULL);
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
diff --git a/src/lundump.h b/src/lundump.h
index ef43d5126476..aa5cc82f1b58 100644
--- a/src/lundump.h
+++ b/src/lundump.h
@@ -1,5 +1,5 @@
/*
-** $Id: lundump.h,v 1.44 2014/06/19 18:27:20 roberto Exp $
+** $Id: lundump.h,v 1.45 2015/09/08 15:41:05 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -23,8 +23,7 @@
#define LUAC_FORMAT 0 /* this is the official format */
/* load one chunk; from lundump.c */
-LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff,
- const char* name);
+LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name);
/* dump one chunk; from ldump.c */
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
diff --git a/src/lutf8lib.c b/src/lutf8lib.c
index be4f087f7606..de9e3dcdd648 100644
--- a/src/lutf8lib.c
+++ b/src/lutf8lib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lutf8lib.c,v 1.13 2014/11/02 19:19:04 roberto Exp $
+** $Id: lutf8lib.c,v 1.16 2016/12/22 13:08:50 roberto Exp $
** Standard library for UTF-8 manipulation
** See Copyright Notice in lua.h
*/
@@ -11,6 +11,7 @@
#include <assert.h>
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
@@ -37,7 +38,7 @@ static lua_Integer u_posrelat (lua_Integer pos, size_t len) {
** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid.
*/
static const char *utf8_decode (const char *o, int *val) {
- static unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF};
+ static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF};
const unsigned char *s = (const unsigned char *)o;
unsigned int c = s[0];
unsigned int res = 0; /* final result */
@@ -106,9 +107,9 @@ static int codepoint (lua_State *L) {
luaL_argcheck(L, posi >= 1, 2, "out of range");
luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range");
if (posi > pose) return 0; /* empty interval; return no values */
- n = (int)(pose - posi + 1);
- if (posi + n <= pose) /* (lua_Integer -> int) overflow? */
+ if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */
return luaL_error(L, "string slice too long");
+ n = (int)(pose - posi) + 1;
luaL_checkstack(L, n, "string slice too long");
n = 0;
se = s + pose;
@@ -193,7 +194,7 @@ static int byteoffset (lua_State *L) {
lua_pushinteger(L, posi + 1);
else /* no such character */
lua_pushnil(L);
- return 1;
+ return 1;
}
@@ -234,7 +235,7 @@ static int iter_codes (lua_State *L) {
#define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*"
-static struct luaL_Reg funcs[] = {
+static const luaL_Reg funcs[] = {
{"offset", byteoffset},
{"codepoint", codepoint},
{"char", utfchar},
@@ -248,7 +249,7 @@ static struct luaL_Reg funcs[] = {
LUAMOD_API int luaopen_utf8 (lua_State *L) {
luaL_newlib(L, funcs);
- lua_pushliteral(L, UTF8PATT);
+ lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1);
lua_setfield(L, -2, "charpattern");
return 1;
}
diff --git a/src/lvm.c b/src/lvm.c
index 2ac1b02df48f..84ade6b2fa6c 100644
--- a/src/lvm.c
+++ b/src/lvm.c
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.c,v 2.232 2014/12/27 20:30:38 roberto Exp $
+** $Id: lvm.c,v 2.268 2016/02/05 19:59:14 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -9,8 +9,9 @@
#include "lprefix.h"
-
+#include <float.h>
#include <limits.h>
+#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -30,36 +31,38 @@
#include "lvm.h"
-/*
-** You can define LUA_FLOORN2I if you want to convert floats to integers
-** by flooring them (instead of raising an error if they are not
-** integral values)
-*/
-#if !defined(LUA_FLOORN2I)
-#define LUA_FLOORN2I 0
-#endif
-
-
/* limit for table tag-method chains (to avoid loops) */
#define MAXTAGLOOP 2000
+
/*
-** Similar to 'tonumber', but does not attempt to convert strings and
-** ensure correct precision (no extra bits). Used in comparisons.
+** 'l_intfitsf' checks whether a given integer can be converted to a
+** float without rounding. Used in comparisons. Left undefined if
+** all integers fit in a float precisely.
*/
-static int tofloat (const TValue *obj, lua_Number *n) {
- if (ttisfloat(obj)) *n = fltvalue(obj);
- else if (ttisinteger(obj)) {
- volatile lua_Number x = cast_num(ivalue(obj)); /* avoid extra precision */
- *n = x;
- }
- else {
- *n = 0; /* to avoid warnings */
- return 0;
- }
- return 1;
-}
+#if !defined(l_intfitsf)
+
+/* number of bits in the mantissa of a float */
+#define NBM (l_mathlim(MANT_DIG))
+
+/*
+** Check whether some integers may not fit in a float, that is, whether
+** (maxinteger >> NBM) > 0 (that implies (1 << NBM) <= maxinteger).
+** (The shifts are done in parts to avoid shifting by more than the size
+** of an integer. In a worst case, NBM == 113 for long double and
+** sizeof(integer) == 32.)
+*/
+#if ((((LUA_MAXINTEGER >> (NBM / 4)) >> (NBM / 4)) >> (NBM / 4)) \
+ >> (NBM - (3 * (NBM / 4)))) > 0
+
+#define l_intfitsf(i) \
+ (-((lua_Integer)1 << NBM) <= (i) && (i) <= ((lua_Integer)1 << NBM))
+
+#endif
+
+#endif
+
/*
@@ -73,7 +76,7 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) {
return 1;
}
else if (cvt2num(obj) && /* string convertible to number? */
- luaO_str2num(svalue(obj), &v) == tsvalue(obj)->len + 1) {
+ luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
*n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */
return 1;
}
@@ -88,7 +91,7 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) {
** mode == 1: takes the floor of the number
** mode == 2: takes the ceil of the number
*/
-static int tointeger_aux (const TValue *obj, lua_Integer *p, int mode) {
+int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
TValue v;
again:
if (ttisfloat(obj)) {
@@ -106,7 +109,7 @@ static int tointeger_aux (const TValue *obj, lua_Integer *p, int mode) {
return 1;
}
else if (cvt2num(obj) &&
- luaO_str2num(svalue(obj), &v) == tsvalue(obj)->len + 1) {
+ luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
obj = &v;
goto again; /* convert result from 'luaO_str2num' to an integer */
}
@@ -115,14 +118,6 @@ static int tointeger_aux (const TValue *obj, lua_Integer *p, int mode) {
/*
-** try to convert a value to an integer
-*/
-int luaV_tointeger_ (const TValue *obj, lua_Integer *p) {
- return tointeger_aux(obj, p, LUA_FLOORN2I);
-}
-
-
-/*
** Try to convert a 'for' limit to an integer, preserving the
** semantics of the loop.
** (The following explanation assumes a non-negative step; it is valid
@@ -140,11 +135,11 @@ int luaV_tointeger_ (const TValue *obj, lua_Integer *p) {
static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
int *stopnow) {
*stopnow = 0; /* usually, let loops run */
- if (!tointeger_aux(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */
+ if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */
lua_Number n; /* try to convert to float */
if (!tonumber(obj, &n)) /* cannot convert to float? */
return 0; /* not a number */
- if (n > 0) { /* if true, float is larger than max integer */
+ if (luai_numlt(0, n)) { /* if true, float is larger than max integer */
*p = LUA_MAXINTEGER;
if (step < 0) *stopnow = 1;
}
@@ -158,75 +153,88 @@ static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
/*
-** Main function for table access (invoking metamethods if needed).
-** Compute 'val = t[key]'
+** Finish the table access 'val = t[key]'.
+** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to
+** t[k] entry (which must be nil).
*/
-void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
+void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
+ const TValue *slot) {
int loop; /* counter to avoid infinite loops */
+ const TValue *tm; /* metamethod */
for (loop = 0; loop < MAXTAGLOOP; loop++) {
- const TValue *tm;
- if (ttistable(t)) { /* 't' is a table? */
- Table *h = hvalue(t);
- const TValue *res = luaH_get(h, key); /* do a primitive get */
- if (!ttisnil(res) || /* result is not nil? */
- (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */
- setobj2s(L, val, res); /* result is the raw get */
+ if (slot == NULL) { /* 't' is not a table? */
+ lua_assert(!ttistable(t));
+ tm = luaT_gettmbyobj(L, t, TM_INDEX);
+ if (ttisnil(tm))
+ luaG_typeerror(L, t, "index"); /* no metamethod */
+ /* else will try the metamethod */
+ }
+ else { /* 't' is a table */
+ lua_assert(ttisnil(slot));
+ tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */
+ if (tm == NULL) { /* no metamethod? */
+ setnilvalue(val); /* result is nil */
return;
}
- /* else will try metamethod */
+ /* else will try the metamethod */
+ }
+ if (ttisfunction(tm)) { /* is metamethod a function? */
+ luaT_callTM(L, tm, t, key, val, 1); /* call it */
+ return;
}
- else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))
- luaG_typeerror(L, t, "index"); /* no metamethod */
- if (ttisfunction(tm)) { /* metamethod is a function */
- luaT_callTM(L, tm, t, key, val, 1);
+ t = tm; /* else try to access 'tm[key]' */
+ if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */
+ setobj2s(L, val, slot); /* done */
return;
}
- t = tm; /* else repeat access over 'tm' */
+ /* else repeat (tail call 'luaV_finishget') */
}
- luaG_runerror(L, "gettable chain too long; possible loop");
+ luaG_runerror(L, "'__index' chain too long; possible loop");
}
/*
-** Main function for table assignment (invoking metamethods if needed).
-** Compute 't[key] = val'
+** Finish a table assignment 't[key] = val'.
+** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points
+** to the entry 't[key]', or to 'luaO_nilobject' if there is no such
+** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset'
+** would have done the job.)
*/
-void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
+void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
+ StkId val, const TValue *slot) {
int loop; /* counter to avoid infinite loops */
for (loop = 0; loop < MAXTAGLOOP; loop++) {
- const TValue *tm;
- if (ttistable(t)) { /* 't' is a table? */
- Table *h = hvalue(t);
- TValue *oldval = cast(TValue *, luaH_get(h, key));
- /* if previous value is not nil, there must be a previous entry
- in the table; a metamethod has no relevance */
- if (!ttisnil(oldval) ||
- /* previous value is nil; must check the metamethod */
- ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL &&
- /* no metamethod; is there a previous entry in the table? */
- (oldval != luaO_nilobject ||
- /* no previous entry; must create one. (The next test is
- always true; we only need the assignment.) */
- (oldval = luaH_newkey(L, h, key), 1)))) {
+ const TValue *tm; /* '__newindex' metamethod */
+ if (slot != NULL) { /* is 't' a table? */
+ Table *h = hvalue(t); /* save 't' table */
+ lua_assert(ttisnil(slot)); /* old value must be nil */
+ tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
+ if (tm == NULL) { /* no metamethod? */
+ if (slot == luaO_nilobject) /* no previous entry? */
+ slot = luaH_newkey(L, h, key); /* create one */
/* no metamethod and (now) there is an entry with given key */
- setobj2t(L, oldval, val); /* assign new value to that entry */
+ setobj2t(L, cast(TValue *, slot), val); /* set its new value */
invalidateTMcache(h);
luaC_barrierback(L, h, val);
return;
}
/* else will try the metamethod */
}
- else /* not a table; check metamethod */
+ else { /* not a table; check metamethod */
if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
luaG_typeerror(L, t, "index");
+ }
/* try the metamethod */
if (ttisfunction(tm)) {
luaT_callTM(L, tm, t, key, val, 0);
return;
}
t = tm; /* else repeat assignment over 'tm' */
+ if (luaV_fastset(L, t, key, slot, luaH_get, val))
+ return; /* done */
+ /* else loop */
}
- luaG_runerror(L, "settable chain too long; possible loop");
+ luaG_runerror(L, "'__newindex' chain too long; possible loop");
}
@@ -239,9 +247,9 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
*/
static int l_strcmp (const TString *ls, const TString *rs) {
const char *l = getstr(ls);
- size_t ll = ls->len;
+ size_t ll = tsslen(ls);
const char *r = getstr(rs);
- size_t lr = rs->len;
+ size_t lr = tsslen(rs);
for (;;) { /* for each segment */
int temp = strcoll(l, r);
if (temp != 0) /* not equal? */
@@ -261,15 +269,102 @@ static int l_strcmp (const TString *ls, const TString *rs) {
/*
+** Check whether integer 'i' is less than float 'f'. If 'i' has an
+** exact representation as a float ('l_intfitsf'), compare numbers as
+** floats. Otherwise, if 'f' is outside the range for integers, result
+** is trivial. Otherwise, compare them as integers. (When 'i' has no
+** float representation, either 'f' is "far away" from 'i' or 'f' has
+** no precision left for a fractional part; either way, how 'f' is
+** truncated is irrelevant.) When 'f' is NaN, comparisons must result
+** in false.
+*/
+static int LTintfloat (lua_Integer i, lua_Number f) {
+#if defined(l_intfitsf)
+ if (!l_intfitsf(i)) {
+ if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */
+ return 1; /* f >= maxint + 1 > i */
+ else if (f > cast_num(LUA_MININTEGER)) /* minint < f <= maxint ? */
+ return (i < cast(lua_Integer, f)); /* compare them as integers */
+ else /* f <= minint <= i (or 'f' is NaN) --> not(i < f) */
+ return 0;
+ }
+#endif
+ return luai_numlt(cast_num(i), f); /* compare them as floats */
+}
+
+
+/*
+** Check whether integer 'i' is less than or equal to float 'f'.
+** See comments on previous function.
+*/
+static int LEintfloat (lua_Integer i, lua_Number f) {
+#if defined(l_intfitsf)
+ if (!l_intfitsf(i)) {
+ if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */
+ return 1; /* f >= maxint + 1 > i */
+ else if (f >= cast_num(LUA_MININTEGER)) /* minint <= f <= maxint ? */
+ return (i <= cast(lua_Integer, f)); /* compare them as integers */
+ else /* f < minint <= i (or 'f' is NaN) --> not(i <= f) */
+ return 0;
+ }
+#endif
+ return luai_numle(cast_num(i), f); /* compare them as floats */
+}
+
+
+/*
+** Return 'l < r', for numbers.
+*/
+static int LTnum (const TValue *l, const TValue *r) {
+ if (ttisinteger(l)) {
+ lua_Integer li = ivalue(l);
+ if (ttisinteger(r))
+ return li < ivalue(r); /* both are integers */
+ else /* 'l' is int and 'r' is float */
+ return LTintfloat(li, fltvalue(r)); /* l < r ? */
+ }
+ else {
+ lua_Number lf = fltvalue(l); /* 'l' must be float */
+ if (ttisfloat(r))
+ return luai_numlt(lf, fltvalue(r)); /* both are float */
+ else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */
+ return 0; /* NaN < i is always false */
+ else /* without NaN, (l < r) <--> not(r <= l) */
+ return !LEintfloat(ivalue(r), lf); /* not (r <= l) ? */
+ }
+}
+
+
+/*
+** Return 'l <= r', for numbers.
+*/
+static int LEnum (const TValue *l, const TValue *r) {
+ if (ttisinteger(l)) {
+ lua_Integer li = ivalue(l);
+ if (ttisinteger(r))
+ return li <= ivalue(r); /* both are integers */
+ else /* 'l' is int and 'r' is float */
+ return LEintfloat(li, fltvalue(r)); /* l <= r ? */
+ }
+ else {
+ lua_Number lf = fltvalue(l); /* 'l' must be float */
+ if (ttisfloat(r))
+ return luai_numle(lf, fltvalue(r)); /* both are float */
+ else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */
+ return 0; /* NaN <= i is always false */
+ else /* without NaN, (l <= r) <--> not(r < l) */
+ return !LTintfloat(ivalue(r), lf); /* not (r < l) ? */
+ }
+}
+
+
+/*
** Main operation less than; return 'l < r'.
*/
int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
int res;
- lua_Number nl, nr;
- if (ttisinteger(l) && ttisinteger(r)) /* both operands are integers? */
- return (ivalue(l) < ivalue(r));
- else if (tofloat(l, &nl) && tofloat(r, &nr)) /* both are numbers? */
- return luai_numlt(nl, nr);
+ if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */
+ return LTnum(l, r);
else if (ttisstring(l) && ttisstring(r)) /* both are strings? */
return l_strcmp(tsvalue(l), tsvalue(r)) < 0;
else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */
@@ -279,27 +374,34 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
/*
-** Main operation less than or equal to; return 'l <= r'.
+** Main operation less than or equal to; return 'l <= r'. If it needs
+** a metamethod and there is no '__le', try '__lt', based on
+** l <= r iff !(r < l) (assuming a total order). If the metamethod
+** yields during this substitution, the continuation has to know
+** about it (to negate the result of r<l); bit CIST_LEQ in the call
+** status keeps that information.
*/
int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
int res;
- lua_Number nl, nr;
- if (ttisinteger(l) && ttisinteger(r)) /* both operands are integers? */
- return (ivalue(l) <= ivalue(r));
- else if (tofloat(l, &nl) && tofloat(r, &nr)) /* both are numbers? */
- return luai_numle(nl, nr);
+ if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */
+ return LEnum(l, r);
else if (ttisstring(l) && ttisstring(r)) /* both are strings? */
return l_strcmp(tsvalue(l), tsvalue(r)) <= 0;
- else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* first try 'le' */
+ else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* try 'le' */
return res;
- else if ((res = luaT_callorderTM(L, r, l, TM_LT)) < 0) /* else try 'lt' */
- luaG_ordererror(L, l, r);
- return !res;
+ else { /* try 'lt': */
+ L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
+ res = luaT_callorderTM(L, r, l, TM_LT);
+ L->ci->callstatus ^= CIST_LEQ; /* clear mark */
+ if (res < 0)
+ luaG_ordererror(L, l, r);
+ return !res; /* result is negated */
+ }
}
/*
-** Main operation for equality of Lua values; return 't1 == t2'.
+** Main operation for equality of Lua values; return 't1 == t2'.
** L == NULL means raw equality (no metamethods)
*/
int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
@@ -308,10 +410,8 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER)
return 0; /* only numbers can be equal with different variants */
else { /* two numbers with different variants */
- lua_Number n1, n2; /* compare them as floats */
- lua_assert(ttisnumber(t1) && ttisnumber(t2));
- cast_void(tofloat(t1, &n1)); cast_void(tofloat(t2, &n2));
- return luai_numeq(n1, n2);
+ lua_Integer i1, i2; /* compare them as integers */
+ return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2);
}
}
/* values have same type and same variant */
@@ -354,6 +454,19 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
#define tostring(L,o) \
(ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1)))
+#define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0)
+
+/* copy strings in stack from top - n up to top - 1 to buffer */
+static void copy2buff (StkId top, int n, char *buff) {
+ size_t tl = 0; /* size already copied */
+ do {
+ size_t l = vslen(top - n); /* length of string being copied */
+ memcpy(buff + tl, svalue(top - n), l * sizeof(char));
+ tl += l;
+ } while (--n > 0);
+}
+
+
/*
** Main operation for concatenation: concat 'total' values in the stack,
** from 'L->top - total' up to 'L->top - 1'.
@@ -365,32 +478,32 @@ void luaV_concat (lua_State *L, int total) {
int n = 2; /* number of elements handled in this pass (at least 2) */
if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1))
luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT);
- else if (tsvalue(top-1)->len == 0) /* second operand is empty? */
+ else if (isemptystr(top - 1)) /* second operand is empty? */
cast_void(tostring(L, top - 2)); /* result is first operand */
- else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) {
+ else if (isemptystr(top - 2)) { /* first operand is an empty string? */
setobjs2s(L, top - 2, top - 1); /* result is second op. */
}
else {
/* at least two non-empty string values; get as many as possible */
- size_t tl = tsvalue(top-1)->len;
- char *buffer;
- int i;
- /* collect total length */
- for (i = 1; i < total && tostring(L, top-i-1); i++) {
- size_t l = tsvalue(top-i-1)->len;
+ size_t tl = vslen(top - 1);
+ TString *ts;
+ /* collect total length and number of strings */
+ for (n = 1; n < total && tostring(L, top - n - 1); n++) {
+ size_t l = vslen(top - n - 1);
if (l >= (MAX_SIZE/sizeof(char)) - tl)
luaG_runerror(L, "string length overflow");
tl += l;
}
- buffer = luaZ_openspace(L, &G(L)->buff, tl);
- tl = 0;
- n = i;
- do { /* copy all strings to buffer */
- size_t l = tsvalue(top-i)->len;
- memcpy(buffer+tl, svalue(top-i), l * sizeof(char));
- tl += l;
- } while (--i > 0);
- setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); /* create result */
+ if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
+ char buff[LUAI_MAXSHORTLEN];
+ copy2buff(top, n, buff); /* copy strings to buffer */
+ ts = luaS_newlstr(L, buff, tl);
+ }
+ else { /* long string; copy strings directly to final result */
+ ts = luaS_createlngstrobj(L, tl);
+ copy2buff(top, n, getstr(ts));
+ }
+ setsvalue2s(L, top - n, ts); /* create result */
}
total -= n-1; /* got 'n' strings to create 1 new */
L->top -= n-1; /* popped 'n' strings and pushed one */
@@ -403,7 +516,7 @@ void luaV_concat (lua_State *L, int total) {
*/
void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
const TValue *tm;
- switch (ttnov(rb)) {
+ switch (ttype(rb)) {
case LUA_TTABLE: {
Table *h = hvalue(rb);
tm = fasttm(L, h->metatable, TM_LEN);
@@ -411,8 +524,12 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
setivalue(ra, luaH_getn(h)); /* else primitive len */
return;
}
- case LUA_TSTRING: {
- setivalue(ra, tsvalue(rb)->len);
+ case LUA_TSHRSTR: {
+ setivalue(ra, tsvalue(rb)->shrlen);
+ return;
+ }
+ case LUA_TLNGSTR: {
+ setivalue(ra, tsvalue(rb)->u.lnglen);
return;
}
default: { /* try metamethod */
@@ -448,7 +565,7 @@ lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) {
/*
-** Integer modulus; return 'm % n'. (Assume that C '%' with
+** Integer modulus; return 'm % n'. (Assume that C '%' with
** negative operands follows C99 behavior. See previous comment
** about luaV_div.)
*/
@@ -553,11 +670,11 @@ void luaV_finishOp (lua_State *L) {
case OP_LE: case OP_LT: case OP_EQ: {
int res = !l_isfalse(L->top - 1);
L->top--;
- /* metamethod should not be called when operand is K */
- lua_assert(!ISK(GETARG_B(inst)));
- if (op == OP_LE && /* "<=" using "<" instead? */
- ttisnil(luaT_gettmbyobj(L, base + GETARG_B(inst), TM_LE)))
- res = !res; /* invert result */
+ if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
+ lua_assert(op == OP_LE);
+ ci->callstatus ^= CIST_LEQ; /* clear mark */
+ res = !res; /* negate result */
+ }
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP);
if (res != GETARG_A(inst)) /* condition failed? */
ci->u.l.savedpc++; /* skip jump instruction */
@@ -607,27 +724,20 @@ 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))
#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i))
#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \
ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i))
#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \
ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i))
-#define KBx(i) \
- (k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++)))
/* 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); \
+ 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 */
@@ -637,38 +747,58 @@ void luaV_finishOp (lua_State *L) {
#define Protect(x) { {x;}; base = ci->u.l.base; }
#define checkGC(L,c) \
- Protect( luaC_condGC(L,{L->top = (c); /* limit of live values */ \
- luaC_step(L); \
- L->top = ci->top;}) /* restore top */ \
- luai_threadyield(L); )
-
+ { luaC_condGC(L, L->top = (c), /* limit of live values */ \
+ Protect(L->top = ci->top)); /* restore top */ \
+ luai_threadyield(L); }
+
+
+/* fetch an instruction and prepare its execution */
+#define vmfetch() { \
+ i = *(ci->u.l.savedpc++); \
+ if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \
+ Protect(luaG_traceexec(L)); \
+ ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
+ lua_assert(base == ci->u.l.base); \
+ lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \
+}
#define vmdispatch(o) switch(o)
#define vmcase(l) case l:
#define vmbreak break
+
+/*
+** copy of 'luaV_gettable', but protecting the call to potential
+** metamethod (which can reallocate the stack)
+*/
+#define gettableProtected(L,t,k,v) { const TValue *slot; \
+ if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
+ else Protect(luaV_finishget(L,t,k,v,slot)); }
+
+
+/* same for 'luaV_settable' */
+#define settableProtected(L,t,k,v) { const TValue *slot; \
+ if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
+ Protect(luaV_finishset(L,t,k,v,slot)); }
+
+
+
void luaV_execute (lua_State *L) {
CallInfo *ci = L->ci;
LClosure *cl;
TValue *k;
StkId base;
+ ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */
newframe: /* reentry point when frame changes (call/return) */
lua_assert(ci == L->ci);
- cl = clLvalue(ci->func);
- k = cl->p->k;
- base = ci->u.l.base;
+ cl = clLvalue(ci->func); /* local reference to function's closure */
+ k = cl->p->k; /* local reference to function's constant table */
+ base = ci->u.l.base; /* local copy of function's base */
/* main loop of interpreter */
for (;;) {
- Instruction i = *(ci->u.l.savedpc++);
+ Instruction i;
StkId ra;
- if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
- (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
- Protect(luaG_traceexec(L));
- }
- /* WARNING: several calls may realloc the stack and invalidate 'ra' */
- ra = RA(i);
- lua_assert(base == ci->u.l.base);
- lua_assert(base <= L->top && L->top < L->stack + L->stacksize);
+ vmfetch();
vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) {
setobjs2s(L, ra, RB(i));
@@ -704,17 +834,22 @@ void luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_GETTABUP) {
- int b = GETARG_B(i);
- Protect(luaV_gettable(L, cl->upvals[b]->v, RKC(i), ra));
+ TValue *upval = cl->upvals[GETARG_B(i)]->v;
+ TValue *rc = RKC(i);
+ gettableProtected(L, upval, rc, ra);
vmbreak;
}
vmcase(OP_GETTABLE) {
- Protect(luaV_gettable(L, RB(i), RKC(i), ra));
+ StkId rb = RB(i);
+ TValue *rc = RKC(i);
+ gettableProtected(L, rb, rc, ra);
vmbreak;
}
vmcase(OP_SETTABUP) {
- int a = GETARG_A(i);
- Protect(luaV_settable(L, cl->upvals[a]->v, RKB(i), RKC(i)));
+ TValue *upval = cl->upvals[GETARG_A(i)]->v;
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ settableProtected(L, upval, rb, rc);
vmbreak;
}
vmcase(OP_SETUPVAL) {
@@ -724,7 +859,9 @@ void luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_SETTABLE) {
- Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ settableProtected(L, ra, rb, rc);
vmbreak;
}
vmcase(OP_NEWTABLE) {
@@ -738,12 +875,18 @@ void luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_SELF) {
+ const TValue *aux;
StkId rb = RB(i);
- setobjs2s(L, ra+1, rb);
- Protect(luaV_gettable(L, rb, RKC(i), ra));
+ TValue *rc = RKC(i);
+ TString *key = tsvalue(rc); /* key must be a string */
+ setobjs2s(L, ra + 1, rb);
+ if (luaV_fastget(L, rb, key, aux, luaH_getstr)) {
+ setobj2s(L, ra, aux);
+ }
+ else Protect(luaV_finishget(L, rb, rc, ra, aux));
vmbreak;
}
- vmcase(OP_ADD) {
+ vmcase(OP_ADD) {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
lua_Number nb; lua_Number nc;
@@ -927,8 +1070,8 @@ void luaV_execute (lua_State *L) {
StkId rb;
L->top = base + c + 1; /* mark the end of concat operands */
Protect(luaV_concat(L, c - b + 1));
- ra = RA(i); /* 'luav_concat' may invoke TMs and move the stack */
- rb = b + base;
+ ra = RA(i); /* 'luaV_concat' may invoke TMs and move the stack */
+ rb = base + b;
setobjs2s(L, ra, rb);
checkGC(L, (ra >= rb ? ra + 1 : rb));
L->top = ci->top; /* restore top */
@@ -942,7 +1085,7 @@ void luaV_execute (lua_State *L) {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
Protect(
- if (cast_int(luaV_equalobj(L, rb, rc)) != GETARG_A(i))
+ if (luaV_equalobj(L, rb, rc) != GETARG_A(i))
ci->u.l.savedpc++;
else
donextjump(ci);
@@ -989,12 +1132,12 @@ void luaV_execute (lua_State *L) {
int nresults = GETARG_C(i) - 1;
if (b != 0) L->top = ra+b; /* else previous instruction set top */
if (luaD_precall(L, ra, nresults)) { /* C function? */
- if (nresults >= 0) L->top = ci->top; /* adjust results */
- base = ci->u.l.base;
+ if (nresults >= 0)
+ L->top = ci->top; /* adjust results */
+ Protect((void)0); /* update 'base' */
}
else { /* Lua function */
ci = L->ci;
- ci->callstatus |= CIST_REENTRY;
goto newframe; /* restart luaV_execute over new Lua function */
}
vmbreak;
@@ -1003,8 +1146,9 @@ void luaV_execute (lua_State *L) {
int b = GETARG_B(i);
if (b != 0) L->top = ra+b; /* else previous instruction set top */
lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
- if (luaD_precall(L, ra, LUA_MULTRET)) /* C function? */
- base = ci->u.l.base;
+ if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */
+ Protect((void)0); /* update 'base' */
+ }
else {
/* tail call: put called frame (n) in place of caller one (o) */
CallInfo *nci = L->ci; /* called frame */
@@ -1031,10 +1175,9 @@ void luaV_execute (lua_State *L) {
}
vmcase(OP_RETURN) {
int b = GETARG_B(i);
- if (b != 0) L->top = ra+b-1;
if (cl->p->sizep > 0) luaF_close(L, base);
- b = luaD_poscall(L, ra);
- if (!(ci->callstatus & CIST_REENTRY)) /* 'ci' still the called one */
+ b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
+ if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */
return; /* external invocation: return */
else { /* invocation via reentry: continue execution */
ci = L->ci;
@@ -1047,11 +1190,11 @@ void luaV_execute (lua_State *L) {
vmcase(OP_FORLOOP) {
if (ttisinteger(ra)) { /* integer loop? */
lua_Integer step = ivalue(ra + 2);
- lua_Integer idx = ivalue(ra) + step; /* increment index */
+ lua_Integer idx = intop(+, ivalue(ra), step); /* increment index */
lua_Integer limit = ivalue(ra + 1);
if ((0 < step) ? (idx <= limit) : (limit <= idx)) {
ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
- setivalue(ra, idx); /* update internal index... */
+ chgivalue(ra, idx); /* update internal index... */
setivalue(ra + 3, idx); /* ...and external index */
}
}
@@ -1062,7 +1205,7 @@ void luaV_execute (lua_State *L) {
if (luai_numlt(0, step) ? luai_numle(idx, limit)
: luai_numle(limit, idx)) {
ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
- setfltvalue(ra, idx); /* update internal index... */
+ chgfltvalue(ra, idx); /* update internal index... */
setfltvalue(ra + 3, idx); /* ...and external index */
}
}
@@ -1079,7 +1222,7 @@ void luaV_execute (lua_State *L) {
/* all values are integer */
lua_Integer initv = (stopnow ? 0 : ivalue(init));
setivalue(plimit, ilimit);
- setivalue(init, initv - ivalue(pstep));
+ setivalue(init, intop(-, initv, ivalue(pstep)));
}
else { /* try making all values floats */
lua_Number ninit; lua_Number nlimit; lua_Number nstep;
@@ -1102,7 +1245,7 @@ void luaV_execute (lua_State *L) {
setobjs2s(L, cb+1, ra+1);
setobjs2s(L, cb, ra);
L->top = cb + 3; /* func. + 2 args (state and index) */
- Protect(luaD_call(L, cb, GETARG_C(i), 1));
+ Protect(luaD_call(L, cb, GETARG_C(i)));
L->top = ci->top;
i = *(ci->u.l.savedpc++); /* go to next instruction */
ra = RA(i);
@@ -1127,11 +1270,10 @@ 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? */
- luaH_resizearray(L, h, last); /* pre-allocate it at once */
+ luaH_resizearray(L, h, last); /* preallocate it at once */
for (; n > 0; n--) {
TValue *val = ra+n;
luaH_setint(L, h, last--, val);
@@ -1151,23 +1293,21 @@ void luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_VARARG) {
- int b = GETARG_B(i) - 1;
+ int b = GETARG_B(i) - 1; /* required results */
int j;
int n = cast_int(base - ci->func) - cl->p->numparams - 1;
+ if (n < 0) /* less arguments than parameters? */
+ n = 0; /* no vararg arguments */
if (b < 0) { /* B == 0? */
b = n; /* get all var. arguments */
Protect(luaD_checkstack(L, n));
ra = RA(i); /* previous call may change the stack */
L->top = ra + n;
}
- for (j = 0; j < b; j++) {
- if (j < n) {
- setobjs2s(L, ra + j, base - n + j);
- }
- else {
- setnilvalue(ra + j);
- }
- }
+ for (j = 0; j < b && j < n; j++)
+ setobjs2s(L, ra + j, base - n + j);
+ for (; j < b; j++) /* complete required results with nil */
+ setnilvalue(ra + j);
vmbreak;
}
vmcase(OP_EXTRAARG) {
diff --git a/src/lvm.h b/src/lvm.h
index 5c5e18c3ac7c..422f87194918 100644
--- a/src/lvm.h
+++ b/src/lvm.h
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.h,v 2.34 2014/08/01 17:24:02 roberto Exp $
+** $Id: lvm.h,v 2.41 2016/12/22 13:08:50 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -27,26 +27,81 @@
#endif
+/*
+** You can define LUA_FLOORN2I if you want to convert floats to integers
+** by flooring them (instead of raising an error if they are not
+** integral values)
+*/
+#if !defined(LUA_FLOORN2I)
+#define LUA_FLOORN2I 0
+#endif
+
+
#define tonumber(o,n) \
(ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))
#define tointeger(o,i) \
- (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger_(o,i))
+ (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))
#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))
#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2)
+/*
+** fast track for 'gettable': if 't' is a table and 't[k]' is not nil,
+** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise,
+** return 0 (meaning it will have to check metamethod) with 'slot'
+** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise).
+** 'f' is the raw get function to use.
+*/
+#define luaV_fastget(L,t,k,slot,f) \
+ (!ttistable(t) \
+ ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
+ : (slot = f(hvalue(t), k), /* else, do raw access */ \
+ !ttisnil(slot))) /* result not nil? */
+
+/*
+** standard implementation for 'gettable'
+*/
+#define luaV_gettable(L,t,k,v) { const TValue *slot; \
+ if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
+ else luaV_finishget(L,t,k,v,slot); }
+
+
+/*
+** Fast track for set table. If 't' is a table and 't[k]' is not nil,
+** call GC barrier, do a raw 't[k]=v', and return true; otherwise,
+** return false with 'slot' equal to NULL (if 't' is not a table) or
+** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro
+** returns true, there is no need to 'invalidateTMcache', because the
+** call is not creating a new entry.
+*/
+#define luaV_fastset(L,t,k,slot,f,v) \
+ (!ttistable(t) \
+ ? (slot = NULL, 0) \
+ : (slot = f(hvalue(t), k), \
+ ttisnil(slot) ? 0 \
+ : (luaC_barrierback(L, hvalue(t), v), \
+ setobj2t(L, cast(TValue *,slot), v), \
+ 1)))
+
+
+#define luaV_settable(L,t,k,v) { const TValue *slot; \
+ if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
+ luaV_finishset(L,t,k,v,slot); }
+
+
+
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);
LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);
-LUAI_FUNC int luaV_tointeger_ (const TValue *obj, lua_Integer *p);
-LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key,
- StkId val);
-LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key,
- StkId val);
+LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode);
+LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
+ StkId val, const TValue *slot);
+LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
+ StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishOp (lua_State *L);
LUAI_FUNC void luaV_execute (lua_State *L);
LUAI_FUNC void luaV_concat (lua_State *L, int total);
diff --git a/src/lzio.c b/src/lzio.c
index 46493920f414..c9e1f491f34d 100644
--- a/src/lzio.c
+++ b/src/lzio.c
@@ -1,5 +1,5 @@
/*
-** $Id: lzio.c,v 1.36 2014/11/02 19:19:04 roberto Exp $
+** $Id: lzio.c,v 1.37 2015/09/08 15:41:05 roberto Exp $
** Buffered streams
** See Copyright Notice in lua.h
*/
@@ -66,13 +66,3 @@ size_t luaZ_read (ZIO *z, void *b, size_t n) {
return 0;
}
-/* ------------------------------------------------------------------------ */
-char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) {
- if (n > buff->buffsize) {
- if (n < LUA_MINBUFFER) n = LUA_MINBUFFER;
- luaZ_resizebuffer(L, buff, n);
- }
- return buff->buffer;
-}
-
-
diff --git a/src/lzio.h b/src/lzio.h
index b2e56bcd6e39..e7b6f34b1e3c 100644
--- a/src/lzio.h
+++ b/src/lzio.h
@@ -1,5 +1,5 @@
/*
-** $Id: lzio.h,v 1.30 2014/12/19 17:26:14 roberto Exp $
+** $Id: lzio.h,v 1.31 2015/09/08 15:41:05 roberto Exp $
** Buffered streams
** See Copyright Notice in lua.h
*/
@@ -44,7 +44,6 @@ typedef struct Mbuffer {
#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0)
-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 */