mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-04 23:50:27 +00:00
Import Lua 3.5.4
Downloaded from https://www.lua.org/ftp/lua-5.3.4.tar.gz
This commit is contained in:
parent
52bff0d770
commit
c07e635a74
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/lua/dist/; revision=326344 svn path=/vendor/lua/5.3.4/; revision=326352; tag=vendor/lua/5.3.4
2
Makefile
2
Makefile
|
@ -46,7 +46,7 @@ TO_MAN= lua.1 luac.1
|
||||||
|
|
||||||
# Lua version and release.
|
# Lua version and release.
|
||||||
V= 5.3
|
V= 5.3
|
||||||
R= $V.0
|
R= $V.4
|
||||||
|
|
||||||
# Targets start here.
|
# Targets start here.
|
||||||
all: $(PLAT)
|
all: $(PLAT)
|
||||||
|
|
2
README
2
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
|
For installation instructions, license details, and
|
||||||
further information about Lua, see doc/readme.html.
|
further information about Lua, see doc/readme.html.
|
||||||
|
|
|
@ -3,43 +3,42 @@
|
||||||
<HEAD>
|
<HEAD>
|
||||||
<TITLE>Lua 5.3 Reference Manual - contents</TITLE>
|
<TITLE>Lua 5.3 Reference Manual - contents</TITLE>
|
||||||
<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
|
<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">
|
<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>
|
</HEAD>
|
||||||
|
|
||||||
<BODY>
|
<BODY>
|
||||||
|
|
||||||
<HR>
|
|
||||||
<H1>
|
<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
|
Lua 5.3 Reference Manual
|
||||||
</H1>
|
</H1>
|
||||||
|
|
||||||
<P>
|
<P>
|
||||||
The reference manual is the official definition of the Lua language.
|
The reference manual is the official definition of the Lua language.
|
||||||
|
<BR>
|
||||||
For a complete introduction to Lua programming, see the book
|
For a complete introduction to Lua programming, see the book
|
||||||
<A HREF="http://www.lua.org/pil/">Programming in Lua</A>.
|
<A HREF="http://www.lua.org/pil/">Programming in Lua</A>.
|
||||||
|
|
||||||
<P>
|
<DIV CLASS="menubar">
|
||||||
<A HREF="manual.html">start</A>
|
<A HREF="manual.html">start</A>
|
||||||
·
|
·
|
||||||
<A HREF="#contents">contents</A>
|
<A HREF="#contents">contents</A>
|
||||||
·
|
·
|
||||||
<A HREF="#index">index</A>
|
<A HREF="#index">index</A>
|
||||||
<HR>
|
·
|
||||||
|
<A HREF="http://www.lua.org/manual/">other versions</A>
|
||||||
|
</DIV>
|
||||||
|
|
||||||
|
<P>
|
||||||
<SMALL>
|
<SMALL>
|
||||||
Copyright © 2015 Lua.org, PUC-Rio.
|
Copyright © 2015–2017 Lua.org, PUC-Rio.
|
||||||
Freely available under the terms of the
|
Freely available under the terms of the
|
||||||
<A HREF="http://www.lua.org/license.html">Lua license</A>.
|
<A HREF="http://www.lua.org/license.html">Lua license</A>.
|
||||||
</SMALL>
|
</SMALL>
|
||||||
|
|
||||||
<H2><A NAME="contents">Contents</A></H2>
|
<H2><A NAME="contents">Contents</A></H2>
|
||||||
<UL style="padding: 0">
|
<UL CLASS="contents menubar">
|
||||||
<LI><A HREF="manual.html">1 – Introduction</A>
|
<LI><A HREF="manual.html">1 – Introduction</A>
|
||||||
<P>
|
<P>
|
||||||
<LI><A HREF="manual.html#2">2 – Basic Concepts</A>
|
<LI><A HREF="manual.html#2">2 – Basic Concepts</A>
|
||||||
|
@ -136,15 +135,14 @@ Freely available under the terms of the
|
||||||
</UL>
|
</UL>
|
||||||
|
|
||||||
<H2><A NAME="index">Index</A></H2>
|
<H2><A NAME="index">Index</A></H2>
|
||||||
<TABLE WIDTH="100%">
|
<TABLE CLASS="menubar" WIDTH="100%">
|
||||||
<TR VALIGN="top">
|
<TR>
|
||||||
<TD>
|
<TD>
|
||||||
<H3><A NAME="functions">Lua functions</A></H3>
|
<H3><A NAME="functions">Lua functions</A></H3>
|
||||||
<P>
|
<P>
|
||||||
<A HREF="manual.html#6.1">basic</A><BR>
|
<A HREF="manual.html#6.1">basic</A><BR>
|
||||||
<A HREF="manual.html#pdf-_G">_G</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-_VERSION">_VERSION</A><BR>
|
||||||
|
|
||||||
<A HREF="manual.html#pdf-assert">assert</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-collectgarbage">collectgarbage</A><BR>
|
||||||
<A HREF="manual.html#pdf-dofile">dofile</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>
|
<A HREF="manual.html#pdf-utf8.offset">utf8.offset</A><BR>
|
||||||
|
|
||||||
<H3><A NAME="env">environment<BR>variables</A></H3>
|
<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">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_CPATH_5_3">LUA_CPATH_5_3</A><BR>
|
||||||
<A HREF="manual.html#pdf-LUA_INIT">LUA_INIT</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_newmetatable">luaL_newmetatable</A><BR>
|
||||||
<A HREF="manual.html#luaL_newstate">luaL_newstate</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_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_optinteger">luaL_optinteger</A><BR>
|
||||||
<A HREF="manual.html#luaL_optlstring">luaL_optlstring</A><BR>
|
<A HREF="manual.html#luaL_optlstring">luaL_optlstring</A><BR>
|
||||||
<A HREF="manual.html#luaL_optnumber">luaL_optnumber</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>
|
<A HREF="manual.html#pdf-luaopen_utf8">luaopen_utf8</A><BR>
|
||||||
|
|
||||||
<H3><A NAME="constants">constants</A></H3>
|
<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_ERRERR">LUA_ERRERR</A><BR>
|
||||||
<A HREF="manual.html#pdf-LUA_ERRFILE">LUA_ERRFILE</A><BR>
|
<A HREF="manual.html#pdf-LUA_ERRFILE">LUA_ERRFILE</A><BR>
|
||||||
<A HREF="manual.html#pdf-LUA_ERRGCMM">LUA_ERRGCMM</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>
|
</TR>
|
||||||
</TABLE>
|
</TABLE>
|
||||||
|
|
||||||
<HR>
|
<P CLASS="footer">
|
||||||
<SMALL CLASS="footer">
|
|
||||||
Last update:
|
Last update:
|
||||||
Tue Dec 9 21:26:07 BRST 2014
|
Thu Dec 22 18:29:39 BRST 2016
|
||||||
</SMALL>
|
</P>
|
||||||
<!--
|
<!--
|
||||||
Last change: updated for Lua 5.3.0 (final)
|
Last change: revised for Lua 5.3.4
|
||||||
-->
|
-->
|
||||||
|
|
||||||
</BODY>
|
</BODY>
|
||||||
|
|
21
doc/index.css
Normal file
21
doc/index.css
Normal file
|
@ -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% ;
|
||||||
|
}
|
BIN
doc/logo.gif
BIN
doc/logo.gif
Binary file not shown.
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 9.7 KiB |
|
@ -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
|
.SH NAME
|
||||||
lua \- Lua interpreter
|
lua \- Lua interpreter
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
|
141
doc/lua.css
141
doc/lua.css
|
@ -3,89 +3,96 @@ html {
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
border: solid #a0a0a0 1px ;
|
|
||||||
border-radius: 20px ;
|
|
||||||
padding: 26px ;
|
|
||||||
margin: 16px ;
|
|
||||||
color: #000000 ;
|
|
||||||
background-color: #FFFFFF ;
|
background-color: #FFFFFF ;
|
||||||
|
color: #000000 ;
|
||||||
font-family: Helvetica, Arial, sans-serif ;
|
font-family: Helvetica, Arial, sans-serif ;
|
||||||
text-align: justify ;
|
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 {
|
h1, h2, h3, h4 {
|
||||||
|
color: #000080 ;
|
||||||
font-family: Verdana, Geneva, sans-serif ;
|
font-family: Verdana, Geneva, sans-serif ;
|
||||||
font-weight: normal ;
|
font-weight: normal ;
|
||||||
font-style: normal ;
|
font-style: normal ;
|
||||||
|
text-align: left ;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h1 {
|
||||||
padding-top: 0.4em ;
|
font-size: 28pt ;
|
||||||
padding-bottom: 0.4em ;
|
|
||||||
padding-left: 0.8em ;
|
|
||||||
padding-right: 0.8em ;
|
|
||||||
background-color: #D0D0FF ;
|
|
||||||
border-radius: 8px ;
|
|
||||||
border: solid #a0a0a0 1px ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h1 img {
|
||||||
padding-left: 0.5em ;
|
vertical-align: text-bottom ;
|
||||||
border-left: solid #D0D0FF 1em ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
table h3 {
|
h2:before {
|
||||||
padding-left: 0px ;
|
content: "\2756" ;
|
||||||
border-left: none ;
|
padding-right: 0.5em ;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none ;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:link {
|
a:link {
|
||||||
color: #000080 ;
|
color: #000080 ;
|
||||||
background-color: inherit ;
|
|
||||||
text-decoration: none ;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:visited {
|
|
||||||
background-color: inherit ;
|
|
||||||
text-decoration: none ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a:link:hover, a:visited:hover {
|
a:link:hover, a:visited:hover {
|
||||||
color: #000080 ;
|
|
||||||
background-color: #D0D0FF ;
|
background-color: #D0D0FF ;
|
||||||
border-radius: 4px;
|
color: #000080 ;
|
||||||
|
border-radius: 4px ;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:link:active, a:visited:active {
|
a:link:active, a:visited:active {
|
||||||
color: #FF0000 ;
|
color: #FF0000 ;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 a img {
|
div.menubar {
|
||||||
vertical-align: text-bottom ;
|
padding-bottom: 0.5em ;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.menubar {
|
||||||
|
margin-left: 2.5em ;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menubar a:hover {
|
||||||
|
margin: -3px -3px -3px -3px ;
|
||||||
|
padding: 3px 3px 3px 3px ;
|
||||||
|
border-radius: 4px ;
|
||||||
|
}
|
||||||
|
|
||||||
|
:target {
|
||||||
|
background-color: #F0F0F0 ;
|
||||||
|
margin: -8px ;
|
||||||
|
padding: 8px ;
|
||||||
|
border-radius: 8px ;
|
||||||
|
outline: none ;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
border: 0 ;
|
|
||||||
height: 1px ;
|
|
||||||
color: #a0a0a0 ;
|
|
||||||
background-color: #a0a0a0 ;
|
|
||||||
display: none ;
|
display: none ;
|
||||||
}
|
}
|
||||||
|
|
||||||
table hr {
|
table hr {
|
||||||
|
background-color: #a0a0a0 ;
|
||||||
|
color: #a0a0a0 ;
|
||||||
|
border: 0 ;
|
||||||
|
height: 1px ;
|
||||||
display: block ;
|
display: block ;
|
||||||
}
|
}
|
||||||
|
|
||||||
:target {
|
|
||||||
background-color: #F8F8F8 ;
|
|
||||||
padding: 8px ;
|
|
||||||
border: solid #a0a0a0 2px ;
|
|
||||||
border-radius: 8px ;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
color: gray ;
|
color: gray ;
|
||||||
font-size: x-small ;
|
font-size: x-small ;
|
||||||
|
text-transform: lowercase ;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=text] {
|
input[type=text] {
|
||||||
|
@ -103,3 +110,55 @@ pre.session {
|
||||||
padding: 1em ;
|
padding: 1em ;
|
||||||
border-radius: 8px ;
|
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 ;
|
||||||
|
}
|
||||||
|
|
|
@ -8,20 +8,14 @@ pre, code {
|
||||||
}
|
}
|
||||||
|
|
||||||
span.apii {
|
span.apii {
|
||||||
|
color: gray ;
|
||||||
float: right ;
|
float: right ;
|
||||||
font-family: inherit ;
|
font-family: inherit ;
|
||||||
font-style: normal ;
|
font-style: normal ;
|
||||||
font-size: small ;
|
font-size: small ;
|
||||||
color: gray ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p+h1, ul+h1 {
|
h2:before {
|
||||||
font-style: normal ;
|
content: "" ;
|
||||||
padding-top: 0.4em ;
|
padding-right: 0em ;
|
||||||
padding-bottom: 0.4em ;
|
|
||||||
padding-left: 16px ;
|
|
||||||
margin-left: -16px ;
|
|
||||||
background-color: #D0D0FF ;
|
|
||||||
border-radius: 8px ;
|
|
||||||
border: solid #000080 1px ;
|
|
||||||
}
|
}
|
||||||
|
|
1162
doc/manual.html
1162
doc/manual.html
File diff suppressed because it is too large
Load diff
|
@ -7,9 +7,9 @@
|
||||||
<STYLE TYPE="text/css">
|
<STYLE TYPE="text/css">
|
||||||
blockquote, .display {
|
blockquote, .display {
|
||||||
border: solid #a0a0a0 2px ;
|
border: solid #a0a0a0 2px ;
|
||||||
|
border-radius: 8px ;
|
||||||
padding: 1em ;
|
padding: 1em ;
|
||||||
margin: 0px ;
|
margin: 0px ;
|
||||||
border-radius: 8px ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.display {
|
.display {
|
||||||
|
@ -28,13 +28,12 @@ tt, kbd, code {
|
||||||
|
|
||||||
<BODY>
|
<BODY>
|
||||||
|
|
||||||
<HR>
|
|
||||||
<H1>
|
<H1>
|
||||||
<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua" BORDER=0></A>
|
<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
|
||||||
Welcome to Lua 5.3.0
|
Welcome to Lua 5.3
|
||||||
</H1>
|
</H1>
|
||||||
|
|
||||||
<P>
|
<DIV CLASS="menubar">
|
||||||
<A HREF="#about">about</A>
|
<A HREF="#about">about</A>
|
||||||
·
|
·
|
||||||
<A HREF="#install">installation</A>
|
<A HREF="#install">installation</A>
|
||||||
|
@ -44,9 +43,9 @@ Welcome to Lua 5.3.0
|
||||||
<A HREF="#license">license</A>
|
<A HREF="#license">license</A>
|
||||||
·
|
·
|
||||||
<A HREF="contents.html">reference manual</A>
|
<A HREF="contents.html">reference manual</A>
|
||||||
|
</DIV>
|
||||||
|
|
||||||
<H2><A NAME="about">About Lua</A></H2>
|
<H2><A NAME="about">About Lua</A></H2>
|
||||||
|
|
||||||
<P>
|
<P>
|
||||||
Lua is a powerful, fast, lightweight, embeddable scripting language
|
Lua is a powerful, fast, lightweight, embeddable scripting language
|
||||||
developed by a
|
developed by a
|
||||||
|
@ -76,7 +75,6 @@ which may differ slightly from the
|
||||||
distributed in this package.
|
distributed in this package.
|
||||||
|
|
||||||
<H2><A NAME="install">Installing Lua</A></H2>
|
<H2><A NAME="install">Installing Lua</A></H2>
|
||||||
|
|
||||||
<P>
|
<P>
|
||||||
Lua is distributed in
|
Lua is distributed in
|
||||||
<A HREF="http://www.lua.org/ftp/">source</A>
|
<A HREF="http://www.lua.org/ftp/">source</A>
|
||||||
|
@ -102,7 +100,6 @@ Try also
|
||||||
a multi-platform distribution of Lua that includes batteries.
|
a multi-platform distribution of Lua that includes batteries.
|
||||||
|
|
||||||
<H3>Building Lua</H3>
|
<H3>Building Lua</H3>
|
||||||
|
|
||||||
<P>
|
<P>
|
||||||
In most Unix-like platforms, simply do "<KBD>make</KBD>" with a suitable target.
|
In most Unix-like platforms, simply do "<KBD>make</KBD>" with a suitable target.
|
||||||
Here are the details.
|
Here are the details.
|
||||||
|
@ -110,7 +107,7 @@ Here are the details.
|
||||||
<OL>
|
<OL>
|
||||||
<LI>
|
<LI>
|
||||||
Open a terminal window and move to
|
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.
|
The <TT>Makefile</TT> there controls both the build process and the installation process.
|
||||||
<P>
|
<P>
|
||||||
<LI>
|
<LI>
|
||||||
|
@ -140,7 +137,8 @@ and liblua.a (the library).
|
||||||
</OL>
|
</OL>
|
||||||
<P>
|
<P>
|
||||||
If you're running Linux and get compilation errors,
|
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,
|
If you get link errors after that,
|
||||||
then try "<KBD>make linux MYLIBS=-ltermcap</KBD>".
|
then try "<KBD>make linux MYLIBS=-ltermcap</KBD>".
|
||||||
|
|
||||||
|
@ -174,7 +172,7 @@ then try "<KBD>make linux MYLIBS=-ltermcap</KBD>".
|
||||||
<DT>
|
<DT>
|
||||||
include:
|
include:
|
||||||
<DD>
|
<DD>
|
||||||
lauxlib.h lua.h lua.hpp luaconf.h lualib.h
|
lua.h luaconf.h lualib.h lauxlib.h lua.hpp
|
||||||
<DT>
|
<DT>
|
||||||
lib:
|
lib:
|
||||||
<DD>
|
<DD>
|
||||||
|
@ -215,7 +213,6 @@ then try "<KBD>make linux MYLIBS=-ltermcap</KBD>".
|
||||||
Further customization is available to experts by editing the Lua sources.
|
Further customization is available to experts by editing the Lua sources.
|
||||||
|
|
||||||
<H3><A NAME="other">Building Lua on other systems</A></H3>
|
<H3><A NAME="other">Building Lua on other systems</A></H3>
|
||||||
|
|
||||||
<P>
|
<P>
|
||||||
If you're not using the usual Unix tools, then the instructions for
|
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
|
building Lua depend on the compiler you use. You'll need to create
|
||||||
|
@ -258,7 +255,6 @@ compiler:
|
||||||
some features before building Lua.
|
some features before building Lua.
|
||||||
|
|
||||||
<H2><A NAME="changes">Changes since Lua 5.2</A></H2>
|
<H2><A NAME="changes">Changes since Lua 5.2</A></H2>
|
||||||
|
|
||||||
<P>
|
<P>
|
||||||
Here are the main changes introduced in Lua 5.3.
|
Here are the main changes introduced in Lua 5.3.
|
||||||
The
|
The
|
||||||
|
@ -280,7 +276,7 @@ Here are the other changes introduced in Lua 5.3:
|
||||||
<H3>Language</H3>
|
<H3>Language</H3>
|
||||||
<UL>
|
<UL>
|
||||||
<LI> userdata can have any Lua value as uservalue
|
<LI> userdata can have any Lua value as uservalue
|
||||||
<LI> integer division
|
<LI> floor division
|
||||||
<LI> more flexible rules for some metamethods
|
<LI> more flexible rules for some metamethods
|
||||||
</UL>
|
</UL>
|
||||||
|
|
||||||
|
@ -315,11 +311,10 @@ Here are the other changes introduced in Lua 5.3:
|
||||||
</UL>
|
</UL>
|
||||||
|
|
||||||
<H2><A NAME="license">License</A></H2>
|
<H2><A NAME="license">License</A></H2>
|
||||||
<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 ;">
|
|
||||||
</A>
|
|
||||||
|
|
||||||
<P>
|
<P>
|
||||||
|
<A HREF="http://www.opensource.org/docs/definition.php">
|
||||||
|
<IMG SRC="osi-certified-72x60.png" ALIGN="right" ALT="[osi certified]" STYLE="padding-left: 30px ;">
|
||||||
|
</A>
|
||||||
Lua is free software distributed under the terms of the
|
Lua is free software distributed under the terms of the
|
||||||
<A HREF="http://www.opensource.org/licenses/mit-license.html">MIT license</A>
|
<A HREF="http://www.opensource.org/licenses/mit-license.html">MIT license</A>
|
||||||
reproduced below;
|
reproduced below;
|
||||||
|
@ -333,7 +328,7 @@ For details, see
|
||||||
<A HREF="http://www.lua.org/license.html">this</A>.
|
<A HREF="http://www.lua.org/license.html">this</A>.
|
||||||
|
|
||||||
<BLOCKQUOTE STYLE="padding-bottom: 0em">
|
<BLOCKQUOTE STYLE="padding-bottom: 0em">
|
||||||
Copyright © 1994–2015 Lua.org, PUC-Rio.
|
Copyright © 1994–2017 Lua.org, PUC-Rio.
|
||||||
|
|
||||||
<P>
|
<P>
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
@ -358,13 +353,12 @@ THE SOFTWARE.
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
<P>
|
<P>
|
||||||
|
|
||||||
<HR>
|
<P CLASS="footer">
|
||||||
<SMALL CLASS="footer">
|
|
||||||
Last update:
|
Last update:
|
||||||
Fri Dec 12 09:58:42 BRST 2014
|
Thu Dec 22 18:22:57 BRST 2016
|
||||||
</SMALL>
|
</P>
|
||||||
<!--
|
<!--
|
||||||
Last change: updated for Lua 5.3.0 (final)
|
Last change: revised for Lua 5.3.4
|
||||||
-->
|
-->
|
||||||
|
|
||||||
</BODY>
|
</BODY>
|
||||||
|
|
|
@ -155,9 +155,9 @@ 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
|
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
|
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 \
|
llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldebug.h \
|
||||||
lobject.h lstate.h ltm.h lzio.h lmem.h lgc.h llex.h lparser.h lstring.h \
|
lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lgc.h llex.h lparser.h \
|
||||||
ltable.h
|
lstring.h ltable.h
|
||||||
lmathlib.o: lmathlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.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 \
|
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
|
||||||
|
|
262
src/lapi.c
262
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
|
** Lua API
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -51,29 +51,29 @@ const char lua_ident[] =
|
||||||
/* test for valid but not pseudo index */
|
/* test for valid but not pseudo index */
|
||||||
#define isstackindex(i, o) (isvalid(o) && !ispseudo(i))
|
#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) \
|
#define api_checkstackindex(l, i, o) \
|
||||||
api_check(isstackindex(i, o), "index not in the stack")
|
api_check(l, isstackindex(i, o), "index not in the stack")
|
||||||
|
|
||||||
|
|
||||||
static TValue *index2addr (lua_State *L, int idx) {
|
static TValue *index2addr (lua_State *L, int idx) {
|
||||||
CallInfo *ci = L->ci;
|
CallInfo *ci = L->ci;
|
||||||
if (idx > 0) {
|
if (idx > 0) {
|
||||||
TValue *o = ci->func + idx;
|
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;
|
if (o >= L->top) return NONVALIDVALUE;
|
||||||
else return o;
|
else return o;
|
||||||
}
|
}
|
||||||
else if (!ispseudo(idx)) { /* negative index */
|
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;
|
return L->top + idx;
|
||||||
}
|
}
|
||||||
else if (idx == LUA_REGISTRYINDEX)
|
else if (idx == LUA_REGISTRYINDEX)
|
||||||
return &G(L)->l_registry;
|
return &G(L)->l_registry;
|
||||||
else { /* upvalues */
|
else { /* upvalues */
|
||||||
idx = LUA_REGISTRYINDEX - idx;
|
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? */
|
if (ttislcf(ci->func)) /* light C function? */
|
||||||
return NONVALIDVALUE; /* it has no upvalues */
|
return NONVALIDVALUE; /* it has no upvalues */
|
||||||
else {
|
else {
|
||||||
|
@ -98,7 +98,7 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
|
||||||
int res;
|
int res;
|
||||||
CallInfo *ci = L->ci;
|
CallInfo *ci = L->ci;
|
||||||
lua_lock(L);
|
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? */
|
if (L->stack_last - L->top > n) /* stack large enough? */
|
||||||
res = 1; /* yes; check is OK */
|
res = 1; /* yes; check is OK */
|
||||||
else { /* no; need to grow stack */
|
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;
|
if (from == to) return;
|
||||||
lua_lock(to);
|
lua_lock(to);
|
||||||
api_checknelems(from, n);
|
api_checknelems(from, n);
|
||||||
api_check(G(from) == G(to), "moving among independent states");
|
api_check(from, G(from) == G(to), "moving among independent states");
|
||||||
api_check(to->ci->top - to->top >= n, "not enough elements to move");
|
api_check(from, to->ci->top - to->top >= n, "stack overflow");
|
||||||
from->top -= n;
|
from->top -= n;
|
||||||
for (i = 0; i < n; i++) {
|
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);
|
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) {
|
LUA_API int lua_absindex (lua_State *L, int idx) {
|
||||||
return (idx > 0 || ispseudo(idx))
|
return (idx > 0 || ispseudo(idx))
|
||||||
? 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;
|
StkId func = L->ci->func;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
if (idx >= 0) {
|
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)
|
while (L->top < (func + 1) + idx)
|
||||||
setnilvalue(L->top++);
|
setnilvalue(L->top++);
|
||||||
L->top = (func + 1) + idx;
|
L->top = (func + 1) + idx;
|
||||||
}
|
}
|
||||||
else {
|
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) */
|
L->top += idx+1; /* 'subtract' index (index is negative) */
|
||||||
}
|
}
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
|
@ -208,8 +209,8 @@ LUA_API void lua_rotate (lua_State *L, int idx, int n) {
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
t = L->top - 1; /* end of stack segment being rotated */
|
t = L->top - 1; /* end of stack segment being rotated */
|
||||||
p = index2addr(L, idx); /* start of segment */
|
p = index2addr(L, idx); /* start of segment */
|
||||||
api_checkstackindex(idx, p);
|
api_checkstackindex(L, idx, p);
|
||||||
api_check((n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
|
api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
|
||||||
m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
|
m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
|
||||||
reverse(L, p, m); /* reverse the prefix with length 'n' */
|
reverse(L, p, m); /* reverse the prefix with length 'n' */
|
||||||
reverse(L, m + 1, t); /* reverse the suffix */
|
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);
|
lua_lock(L);
|
||||||
fr = index2addr(L, fromidx);
|
fr = index2addr(L, fromidx);
|
||||||
to = index2addr(L, toidx);
|
to = index2addr(L, toidx);
|
||||||
api_checkvalidindex(to);
|
api_checkvalidindex(L, to);
|
||||||
setobj(L, to, fr);
|
setobj(L, to, fr);
|
||||||
if (isupvalue(toidx)) /* function upvalue? */
|
if (isupvalue(toidx)) /* function upvalue? */
|
||||||
luaC_barrier(L, clCvalue(L->ci->func), fr);
|
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) {
|
LUA_API const char *lua_typename (lua_State *L, int t) {
|
||||||
UNUSED(L);
|
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);
|
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 */
|
else { /* for unary operations, add fake 2nd operand */
|
||||||
api_checknelems(L, 1);
|
api_checknelems(L, 1);
|
||||||
setobjs2s(L, L->top, L->top - 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 */
|
/* 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);
|
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_OPEQ: i = luaV_equalobj(L, o1, o2); break;
|
||||||
case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break;
|
case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break;
|
||||||
case LUA_OPLE: i = luaV_lessequal(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);
|
lua_unlock(L);
|
||||||
|
@ -377,20 +378,22 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
lua_lock(L); /* 'luaO_tostring' may create a new string */
|
lua_lock(L); /* 'luaO_tostring' may create a new string */
|
||||||
|
luaO_tostring(L, o);
|
||||||
luaC_checkGC(L);
|
luaC_checkGC(L);
|
||||||
o = index2addr(L, idx); /* previous call may reallocate the stack */
|
o = index2addr(L, idx); /* previous call may reallocate the stack */
|
||||||
luaO_tostring(L, o);
|
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
}
|
}
|
||||||
if (len != NULL) *len = tsvalue(o)->len;
|
if (len != NULL)
|
||||||
|
*len = vslen(o);
|
||||||
return svalue(o);
|
return svalue(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API size_t lua_rawlen (lua_State *L, int idx) {
|
LUA_API size_t lua_rawlen (lua_State *L, int idx) {
|
||||||
StkId o = index2addr(L, idx);
|
StkId o = index2addr(L, idx);
|
||||||
switch (ttnov(o)) {
|
switch (ttype(o)) {
|
||||||
case LUA_TSTRING: return tsvalue(o)->len;
|
case LUA_TSHRSTR: return tsvalue(o)->shrlen;
|
||||||
|
case LUA_TLNGSTR: return tsvalue(o)->u.lnglen;
|
||||||
case LUA_TUSERDATA: return uvalue(o)->len;
|
case LUA_TUSERDATA: return uvalue(o)->len;
|
||||||
case LUA_TTABLE: return luaH_getn(hvalue(o));
|
case LUA_TTABLE: return luaH_getn(hvalue(o));
|
||||||
default: return 0;
|
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_TCCL: return clCvalue(o);
|
||||||
case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o)));
|
case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o)));
|
||||||
case LUA_TTHREAD: return thvalue(o);
|
case LUA_TTHREAD: return thvalue(o);
|
||||||
case LUA_TUSERDATA:
|
case LUA_TUSERDATA: return getudatamem(uvalue(o));
|
||||||
case LUA_TLIGHTUSERDATA:
|
case LUA_TLIGHTUSERDATA: return pvalue(o);
|
||||||
return lua_touserdata(L, idx);
|
|
||||||
default: return NULL;
|
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) {
|
LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
|
||||||
TString *ts;
|
TString *ts;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
luaC_checkGC(L);
|
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
|
||||||
ts = luaS_newlstr(L, s, len);
|
|
||||||
setsvalue2s(L, L->top, ts);
|
setsvalue2s(L, L->top, ts);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
|
luaC_checkGC(L);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return getstr(ts);
|
return getstr(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
|
LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
|
||||||
if (s == NULL) {
|
lua_lock(L);
|
||||||
lua_pushnil(L);
|
if (s == NULL)
|
||||||
return NULL;
|
setnilvalue(L->top);
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
TString *ts;
|
TString *ts;
|
||||||
lua_lock(L);
|
|
||||||
luaC_checkGC(L);
|
|
||||||
ts = luaS_new(L, s);
|
ts = luaS_new(L, s);
|
||||||
setsvalue2s(L, L->top, ts);
|
setsvalue2s(L, L->top, ts);
|
||||||
api_incr_top(L);
|
s = getstr(ts); /* internal copy's address */
|
||||||
lua_unlock(L);
|
|
||||||
return getstr(ts);
|
|
||||||
}
|
}
|
||||||
|
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) {
|
va_list argp) {
|
||||||
const char *ret;
|
const char *ret;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
luaC_checkGC(L);
|
|
||||||
ret = luaO_pushvfstring(L, fmt, argp);
|
ret = luaO_pushvfstring(L, fmt, argp);
|
||||||
|
luaC_checkGC(L);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -514,10 +520,10 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
|
||||||
const char *ret;
|
const char *ret;
|
||||||
va_list argp;
|
va_list argp;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
luaC_checkGC(L);
|
|
||||||
va_start(argp, fmt);
|
va_start(argp, fmt);
|
||||||
ret = luaO_pushvfstring(L, fmt, argp);
|
ret = luaO_pushvfstring(L, fmt, argp);
|
||||||
va_end(argp);
|
va_end(argp);
|
||||||
|
luaC_checkGC(L);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -531,8 +537,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
|
||||||
else {
|
else {
|
||||||
CClosure *cl;
|
CClosure *cl;
|
||||||
api_checknelems(L, n);
|
api_checknelems(L, n);
|
||||||
api_check(n <= MAXUPVAL, "upvalue index too large");
|
api_check(L, n <= MAXUPVAL, "upvalue index too large");
|
||||||
luaC_checkGC(L);
|
|
||||||
cl = luaF_newCclosure(L, n);
|
cl = luaF_newCclosure(L, n);
|
||||||
cl->f = fn;
|
cl->f = fn;
|
||||||
L->top -= n;
|
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);
|
setclCvalue(L, L->top, cl);
|
||||||
}
|
}
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
|
luaC_checkGC(L);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,18 +584,30 @@ LUA_API int lua_pushthread (lua_State *L) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
LUA_API int lua_getglobal (lua_State *L, const char *name) {
|
static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
|
||||||
Table *reg = hvalue(&G(L)->l_registry);
|
const TValue *slot;
|
||||||
const TValue *gt; /* global table */
|
TString *str = luaS_new(L, k);
|
||||||
lua_lock(L);
|
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
|
||||||
gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
|
setobj2s(L, L->top, slot);
|
||||||
setsvalue2s(L, L->top++, luaS_new(L, name));
|
api_incr_top(L);
|
||||||
luaV_gettable(L, gt, L->top - 1, L->top - 1);
|
}
|
||||||
|
else {
|
||||||
|
setsvalue2s(L, L->top, str);
|
||||||
|
api_incr_top(L);
|
||||||
|
luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
|
||||||
|
}
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return ttnov(L->top - 1);
|
return ttnov(L->top - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUA_API int lua_getglobal (lua_State *L, const char *name) {
|
||||||
|
Table *reg = hvalue(&G(L)->l_registry);
|
||||||
|
lua_lock(L);
|
||||||
|
return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API int lua_gettable (lua_State *L, int idx) {
|
LUA_API int lua_gettable (lua_State *L, int idx) {
|
||||||
StkId t;
|
StkId t;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
|
@ -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) {
|
LUA_API int lua_getfield (lua_State *L, int idx, const char *k) {
|
||||||
StkId t;
|
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
t = index2addr(L, idx);
|
return auxgetstr(L, index2addr(L, idx), k);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
|
LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
|
||||||
StkId t;
|
StkId t;
|
||||||
|
const TValue *slot;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
t = index2addr(L, idx);
|
t = index2addr(L, idx);
|
||||||
|
if (luaV_fastget(L, t, n, slot, luaH_getint)) {
|
||||||
|
setobj2s(L, L->top, slot);
|
||||||
|
api_incr_top(L);
|
||||||
|
}
|
||||||
|
else {
|
||||||
setivalue(L->top, n);
|
setivalue(L->top, n);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
luaV_gettable(L, t, L->top - 1, L->top - 1);
|
luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
|
||||||
|
}
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return ttnov(L->top - 1);
|
return ttnov(L->top - 1);
|
||||||
}
|
}
|
||||||
|
@ -628,7 +647,7 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
|
||||||
StkId t;
|
StkId t;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
t = index2addr(L, idx);
|
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));
|
setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1));
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return ttnov(L->top - 1);
|
return ttnov(L->top - 1);
|
||||||
|
@ -639,7 +658,7 @@ LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) {
|
||||||
StkId t;
|
StkId t;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
t = index2addr(L, idx);
|
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));
|
setobj2s(L, L->top, luaH_getint(hvalue(t), n));
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
|
@ -652,7 +671,7 @@ LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
|
||||||
TValue k;
|
TValue k;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
t = index2addr(L, idx);
|
t = index2addr(L, idx);
|
||||||
api_check(ttistable(t), "table expected");
|
api_check(L, ttistable(t), "table expected");
|
||||||
setpvalue(&k, cast(void *, p));
|
setpvalue(&k, cast(void *, p));
|
||||||
setobj2s(L, L->top, luaH_get(hvalue(t), &k));
|
setobj2s(L, L->top, luaH_get(hvalue(t), &k));
|
||||||
api_incr_top(L);
|
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) {
|
LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
|
||||||
Table *t;
|
Table *t;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
luaC_checkGC(L);
|
|
||||||
t = luaH_new(L);
|
t = luaH_new(L);
|
||||||
sethvalue(L, L->top, t);
|
sethvalue(L, L->top, t);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
if (narray > 0 || nrec > 0)
|
if (narray > 0 || nrec > 0)
|
||||||
luaH_resize(L, t, narray, nrec);
|
luaH_resize(L, t, narray, nrec);
|
||||||
|
luaC_checkGC(L);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -705,7 +724,7 @@ LUA_API int lua_getuservalue (lua_State *L, int idx) {
|
||||||
StkId o;
|
StkId o;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
o = index2addr(L, idx);
|
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);
|
getuservalue(L, uvalue(o), L->top);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
|
@ -717,17 +736,29 @@ LUA_API int lua_getuservalue (lua_State *L, int idx) {
|
||||||
** set functions (stack -> Lua)
|
** 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) {
|
LUA_API void lua_setglobal (lua_State *L, const char *name) {
|
||||||
Table *reg = hvalue(&G(L)->l_registry);
|
Table *reg = hvalue(&G(L)->l_registry);
|
||||||
const TValue *gt; /* global table */
|
lua_lock(L); /* unlock done in 'auxsetstr' */
|
||||||
lua_lock(L);
|
auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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) {
|
LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
|
||||||
StkId t;
|
lua_lock(L); /* unlock done in 'auxsetstr' */
|
||||||
lua_lock(L);
|
auxsetstr(L, index2addr(L, idx), k);
|
||||||
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_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
|
LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
|
||||||
StkId t;
|
StkId t;
|
||||||
|
const TValue *slot;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
api_checknelems(L, 1);
|
api_checknelems(L, 1);
|
||||||
t = index2addr(L, idx);
|
t = index2addr(L, idx);
|
||||||
setivalue(L->top++, n);
|
if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1))
|
||||||
luaV_settable(L, t, L->top - 1, L->top - 2);
|
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 */
|
L->top -= 2; /* pop value and key */
|
||||||
|
}
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API void lua_rawset (lua_State *L, int idx) {
|
LUA_API void lua_rawset (lua_State *L, int idx) {
|
||||||
StkId o;
|
StkId o;
|
||||||
Table *t;
|
TValue *slot;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
api_checknelems(L, 2);
|
api_checknelems(L, 2);
|
||||||
o = index2addr(L, idx);
|
o = index2addr(L, idx);
|
||||||
api_check(ttistable(o), "table expected");
|
api_check(L, ttistable(o), "table expected");
|
||||||
t = hvalue(o);
|
slot = luaH_set(L, hvalue(o), L->top - 2);
|
||||||
setobj2t(L, luaH_set(L, t, L->top-2), L->top-1);
|
setobj2t(L, slot, L->top - 1);
|
||||||
invalidateTMcache(t);
|
invalidateTMcache(hvalue(o));
|
||||||
luaC_barrierback(L, t, L->top-1);
|
luaC_barrierback(L, hvalue(o), L->top-1);
|
||||||
L->top -= 2;
|
L->top -= 2;
|
||||||
lua_unlock(L);
|
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) {
|
LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
|
||||||
StkId o;
|
StkId o;
|
||||||
Table *t;
|
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
api_checknelems(L, 1);
|
api_checknelems(L, 1);
|
||||||
o = index2addr(L, idx);
|
o = index2addr(L, idx);
|
||||||
api_check(ttistable(o), "table expected");
|
api_check(L, ttistable(o), "table expected");
|
||||||
t = hvalue(o);
|
luaH_setint(L, hvalue(o), n, L->top - 1);
|
||||||
luaH_setint(L, t, n, L->top - 1);
|
luaC_barrierback(L, hvalue(o), L->top-1);
|
||||||
luaC_barrierback(L, t, L->top-1);
|
|
||||||
L->top--;
|
L->top--;
|
||||||
lua_unlock(L);
|
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) {
|
LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
|
||||||
StkId o;
|
StkId o;
|
||||||
Table *t;
|
TValue k, *slot;
|
||||||
TValue k;
|
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
api_checknelems(L, 1);
|
api_checknelems(L, 1);
|
||||||
o = index2addr(L, idx);
|
o = index2addr(L, idx);
|
||||||
api_check(ttistable(o), "table expected");
|
api_check(L, ttistable(o), "table expected");
|
||||||
t = hvalue(o);
|
|
||||||
setpvalue(&k, cast(void *, p));
|
setpvalue(&k, cast(void *, p));
|
||||||
setobj2t(L, luaH_set(L, t, &k), L->top - 1);
|
slot = luaH_set(L, hvalue(o), &k);
|
||||||
luaC_barrierback(L, t, L->top - 1);
|
setobj2t(L, slot, L->top - 1);
|
||||||
|
luaC_barrierback(L, hvalue(o), L->top - 1);
|
||||||
L->top--;
|
L->top--;
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
}
|
}
|
||||||
|
@ -823,7 +851,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
|
||||||
if (ttisnil(L->top - 1))
|
if (ttisnil(L->top - 1))
|
||||||
mt = NULL;
|
mt = NULL;
|
||||||
else {
|
else {
|
||||||
api_check(ttistable(L->top - 1), "table expected");
|
api_check(L, ttistable(L->top - 1), "table expected");
|
||||||
mt = hvalue(L->top - 1);
|
mt = hvalue(L->top - 1);
|
||||||
}
|
}
|
||||||
switch (ttnov(obj)) {
|
switch (ttnov(obj)) {
|
||||||
|
@ -859,7 +887,7 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) {
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
api_checknelems(L, 1);
|
api_checknelems(L, 1);
|
||||||
o = index2addr(L, idx);
|
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);
|
setuservalue(L, uvalue(o), L->top - 1);
|
||||||
luaC_barrier(L, gcvalue(o), L->top - 1);
|
luaC_barrier(L, gcvalue(o), L->top - 1);
|
||||||
L->top--;
|
L->top--;
|
||||||
|
@ -873,7 +901,7 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) {
|
||||||
|
|
||||||
|
|
||||||
#define checkresults(L,na,nr) \
|
#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")
|
"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) {
|
lua_KContext ctx, lua_KFunction k) {
|
||||||
StkId func;
|
StkId func;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
api_check(k == NULL || !isLua(L->ci),
|
api_check(L, k == NULL || !isLua(L->ci),
|
||||||
"cannot use continuations inside hooks");
|
"cannot use continuations inside hooks");
|
||||||
api_checknelems(L, nargs+1);
|
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);
|
checkresults(L, nargs, nresults);
|
||||||
func = L->top - (nargs+1);
|
func = L->top - (nargs+1);
|
||||||
if (k != NULL && L->nny == 0) { /* need to prepare continuation? */
|
if (k != NULL && L->nny == 0) { /* need to prepare continuation? */
|
||||||
L->ci->u.c.k = k; /* save continuation */
|
L->ci->u.c.k = k; /* save continuation */
|
||||||
L->ci->u.c.ctx = ctx; /* save context */
|
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 */
|
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);
|
adjustresults(L, nresults);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
}
|
}
|
||||||
|
@ -911,7 +939,7 @@ struct CallS { /* data to 'f_call' */
|
||||||
|
|
||||||
static void f_call (lua_State *L, void *ud) {
|
static void f_call (lua_State *L, void *ud) {
|
||||||
struct CallS *c = cast(struct CallS *, 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;
|
int status;
|
||||||
ptrdiff_t func;
|
ptrdiff_t func;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
api_check(k == NULL || !isLua(L->ci),
|
api_check(L, k == NULL || !isLua(L->ci),
|
||||||
"cannot use continuations inside hooks");
|
"cannot use continuations inside hooks");
|
||||||
api_checknelems(L, nargs+1);
|
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);
|
checkresults(L, nargs, nresults);
|
||||||
if (errfunc == 0)
|
if (errfunc == 0)
|
||||||
func = 0;
|
func = 0;
|
||||||
else {
|
else {
|
||||||
StkId o = index2addr(L, errfunc);
|
StkId o = index2addr(L, errfunc);
|
||||||
api_checkstackindex(errfunc, o);
|
api_checkstackindex(L, errfunc, o);
|
||||||
func = savestack(L, o);
|
func = savestack(L, o);
|
||||||
}
|
}
|
||||||
c.func = L->top - (nargs+1); /* function to be called */
|
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;
|
L->errfunc = func;
|
||||||
setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */
|
setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */
|
||||||
ci->callstatus |= CIST_YPCALL; /* function can do error recovery */
|
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;
|
ci->callstatus &= ~CIST_YPCALL;
|
||||||
L->errfunc = ci->u.c.old_errfunc;
|
L->errfunc = ci->u.c.old_errfunc;
|
||||||
status = LUA_OK; /* if it is here, there were no errors */
|
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: {
|
case LUA_GCSTEP: {
|
||||||
l_mem debt = 1; /* =1 to signal that it did an actual step */
|
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 */
|
g->gcrunning = 1; /* allow GC to run */
|
||||||
if (data == 0) {
|
if (data == 0) {
|
||||||
luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */
|
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;
|
int more;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
t = index2addr(L, idx);
|
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);
|
more = luaH_next(L, hvalue(t), L->top - 1);
|
||||||
if (more) {
|
if (more) {
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
|
@ -1112,7 +1140,6 @@ LUA_API void lua_concat (lua_State *L, int n) {
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
api_checknelems(L, n);
|
api_checknelems(L, n);
|
||||||
if (n >= 2) {
|
if (n >= 2) {
|
||||||
luaC_checkGC(L);
|
|
||||||
luaV_concat(L, n);
|
luaV_concat(L, n);
|
||||||
}
|
}
|
||||||
else if (n == 0) { /* push empty string */
|
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);
|
api_incr_top(L);
|
||||||
}
|
}
|
||||||
/* else n == 1; nothing to do */
|
/* else n == 1; nothing to do */
|
||||||
|
luaC_checkGC(L);
|
||||||
lua_unlock(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) {
|
LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
|
||||||
Udata *u;
|
Udata *u;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
luaC_checkGC(L);
|
|
||||||
u = luaS_newudata(L, size);
|
u = luaS_newudata(L, size);
|
||||||
setuvalue(L, L->top, u);
|
setuvalue(L, L->top, u);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
|
luaC_checkGC(L);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return getudatamem(u);
|
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) {
|
static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) {
|
||||||
LClosure *f;
|
LClosure *f;
|
||||||
StkId fi = index2addr(L, fidx);
|
StkId fi = index2addr(L, fidx);
|
||||||
api_check(ttisLclosure(fi), "Lua function expected");
|
api_check(L, ttisLclosure(fi), "Lua function expected");
|
||||||
f = clLvalue(fi);
|
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;
|
if (pf) *pf = f;
|
||||||
return &f->upvals[n - 1]; /* get its upvalue pointer */
|
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 */
|
case LUA_TCCL: { /* C closure */
|
||||||
CClosure *f = clCvalue(fi);
|
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];
|
return &f->upvalue[n - 1];
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
api_check(0, "closure expected");
|
api_check(L, 0, "closure expected");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
** Auxiliary functions from Lua API
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -11,13 +11,13 @@
|
||||||
#include "llimits.h"
|
#include "llimits.h"
|
||||||
#include "lstate.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");}
|
"stack overflow");}
|
||||||
|
|
||||||
#define adjustresults(L,nres) \
|
#define adjustresults(L,nres) \
|
||||||
{ if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
|
{ 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")
|
"not enough elements in the stack")
|
||||||
|
|
||||||
|
|
||||||
|
|
155
src/lauxlib.c
155
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
|
** Auxiliary functions for building Lua libraries
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -17,7 +17,8 @@
|
||||||
#include <string.h>
|
#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.
|
** 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 LEVELS1 10 /* size of the first part of the stack */
|
||||||
#define LEVELS2 10 /* size of the second 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
|
** Search for a name for a function in all loaded modules
|
||||||
** (registry._LOADED).
|
|
||||||
*/
|
*/
|
||||||
static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
|
static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
|
||||||
int top = lua_gettop(L);
|
int top = lua_gettop(L);
|
||||||
lua_getinfo(L, "f", ar); /* push function */
|
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)) {
|
if (findfield(L, top + 1, 2)) {
|
||||||
const char *name = lua_tostring(L, -1);
|
const char *name = lua_tostring(L, -1);
|
||||||
if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */
|
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;
|
lua_Debug ar;
|
||||||
int li = 1, le = 1;
|
int li = 1, le = 1;
|
||||||
/* find an upper bound */
|
/* find an upper bound */
|
||||||
|
@ -126,14 +126,16 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
|
||||||
const char *msg, int level) {
|
const char *msg, int level) {
|
||||||
lua_Debug ar;
|
lua_Debug ar;
|
||||||
int top = lua_gettop(L);
|
int top = lua_gettop(L);
|
||||||
int numlevels = countlevels(L1);
|
int last = lastlevel(L1);
|
||||||
int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0;
|
int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1;
|
||||||
if (msg) lua_pushfstring(L, "%s\n", msg);
|
if (msg)
|
||||||
|
lua_pushfstring(L, "%s\n", msg);
|
||||||
|
luaL_checkstack(L, 10, NULL);
|
||||||
lua_pushliteral(L, "stack traceback:");
|
lua_pushliteral(L, "stack traceback:");
|
||||||
while (lua_getstack(L1, level++, &ar)) {
|
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 '...' */
|
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 {
|
else {
|
||||||
lua_getinfo(L1, "Slnt", &ar);
|
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) {
|
LUALIB_API void luaL_where (lua_State *L, int level) {
|
||||||
lua_Debug ar;
|
lua_Debug ar;
|
||||||
if (lua_getstack(L, level, &ar)) { /* check function at level */
|
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;
|
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, ...) {
|
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
|
||||||
va_list argp;
|
va_list argp;
|
||||||
va_start(argp, fmt);
|
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) {
|
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 */
|
return 0; /* leave previous value on top, but return 0 */
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
lua_newtable(L); /* create metatable */
|
lua_createtable(L, 0, 2); /* create metatable */
|
||||||
lua_pushstring(L, tname);
|
lua_pushstring(L, tname);
|
||||||
lua_setfield(L, -2, "__name"); /* metatable.__name = tname */
|
lua_setfield(L, -2, "__name"); /* metatable.__name = tname */
|
||||||
lua_pushvalue(L, -1);
|
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) {
|
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
|
||||||
/* keep some extra space to run error routines, if needed */
|
if (!lua_checkstack(L, space)) {
|
||||||
const int extra = LUA_MINSTACK;
|
|
||||||
if (!lua_checkstack(L, space + extra)) {
|
|
||||||
if (msg)
|
if (msg)
|
||||||
luaL_error(L, "stack overflow (%s)", msg);
|
luaL_error(L, "stack overflow (%s)", msg);
|
||||||
else
|
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
|
** check whether buffer is using a userdata on the stack as a temporary
|
||||||
** buffer
|
** buffer
|
||||||
|
@ -455,11 +512,12 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
|
||||||
if (newsize < B->n || newsize - B->n < sz)
|
if (newsize < B->n || newsize - B->n < sz)
|
||||||
luaL_error(L, "buffer too large");
|
luaL_error(L, "buffer too large");
|
||||||
/* create larger buffer */
|
/* create larger buffer */
|
||||||
newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char));
|
|
||||||
/* move content to new buffer */
|
|
||||||
memcpy(newbuff, B->b, B->n * sizeof(char));
|
|
||||||
if (buffonstack(B))
|
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->b = newbuff;
|
||||||
B->size = newsize;
|
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) {
|
LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
|
||||||
|
if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */
|
||||||
char *b = luaL_prepbuffsize(B, l);
|
char *b = luaL_prepbuffsize(B, l);
|
||||||
memcpy(b, s, l * sizeof(char));
|
memcpy(b, s, l * sizeof(char));
|
||||||
luaL_addsize(B, l);
|
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) {
|
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
|
||||||
lua_State *L = B->L;
|
lua_State *L = B->L;
|
||||||
lua_pushlstring(L, B->b, B->n);
|
lua_pushlstring(L, B->b, B->n);
|
||||||
if (buffonstack(B))
|
if (buffonstack(B)) {
|
||||||
lua_remove(L, -2); /* remove old buffer */
|
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) {
|
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;
|
int c;
|
||||||
lf->n = 0;
|
lf->n = 0;
|
||||||
do {
|
do {
|
||||||
|
@ -630,7 +692,7 @@ static int skipcomment (LoadF *lf, int *cp) {
|
||||||
if (c == '#') { /* first line is a comment (Unix exec. file)? */
|
if (c == '#') { /* first line is a comment (Unix exec. file)? */
|
||||||
do { /* skip first line */
|
do { /* skip first line */
|
||||||
c = getc(lf->f);
|
c = getc(lf->f);
|
||||||
} while (c != EOF && c != '\n') ;
|
} while (c != EOF && c != '\n');
|
||||||
*cp = getc(lf->f); /* skip end-of-line, if present */
|
*cp = getc(lf->f); /* skip end-of-line, if present */
|
||||||
return 1; /* there was a comment */
|
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) {
|
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)) {
|
switch (lua_type(L, idx)) {
|
||||||
case LUA_TNUMBER: {
|
case LUA_TNUMBER: {
|
||||||
if (lua_isinteger(L, idx))
|
if (lua_isinteger(L, idx))
|
||||||
lua_pushfstring(L, "%I", lua_tointeger(L, idx));
|
lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx));
|
||||||
else
|
else
|
||||||
lua_pushfstring(L, "%f", lua_tonumber(L, idx));
|
lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LUA_TSTRING:
|
case LUA_TSTRING:
|
||||||
|
@ -764,12 +830,17 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
|
||||||
case LUA_TNIL:
|
case LUA_TNIL:
|
||||||
lua_pushliteral(L, "nil");
|
lua_pushliteral(L, "nil");
|
||||||
break;
|
break;
|
||||||
default:
|
default: {
|
||||||
lua_pushfstring(L, "%s: %p", luaL_typename(L, idx),
|
int tt = luaL_getmetafield(L, idx, "__name"); /* try name */
|
||||||
lua_topointer(L, idx));
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return lua_tolstring(L, -1, len);
|
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
|
** 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
|
** global variable with that name. In any case, leaves on the stack
|
||||||
** the module table.
|
** the module table.
|
||||||
*/
|
*/
|
||||||
LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
|
LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
|
||||||
int sizehint) {
|
int sizehint) {
|
||||||
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */
|
luaL_findtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE, 1);
|
||||||
if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no _LOADED[modname]? */
|
if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no LOADED[modname]? */
|
||||||
lua_pop(L, 1); /* remove previous result */
|
lua_pop(L, 1); /* remove previous result */
|
||||||
/* try global variable (and create one if it does not exist) */
|
/* try global variable (and create one if it does not exist) */
|
||||||
lua_pushglobaltable(L);
|
lua_pushglobaltable(L);
|
||||||
if (luaL_findtable(L, 0, modname, sizehint) != NULL)
|
if (luaL_findtable(L, 0, modname, sizehint) != NULL)
|
||||||
luaL_error(L, "name conflict for module '%s'", modname);
|
luaL_error(L, "name conflict for module '%s'", modname);
|
||||||
lua_pushvalue(L, -1);
|
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,
|
LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
|
||||||
lua_CFunction openf, int glb) {
|
lua_CFunction openf, int glb) {
|
||||||
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
|
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
|
||||||
lua_getfield(L, -1, modname); /* _LOADED[modname] */
|
lua_getfield(L, -1, modname); /* LOADED[modname] */
|
||||||
if (!lua_toboolean(L, -1)) { /* package not already loaded? */
|
if (!lua_toboolean(L, -1)) { /* package not already loaded? */
|
||||||
lua_pop(L, 1); /* remove field */
|
lua_pop(L, 1); /* remove field */
|
||||||
lua_pushcfunction(L, openf);
|
lua_pushcfunction(L, openf);
|
||||||
lua_pushstring(L, modname); /* argument to open function */
|
lua_pushstring(L, modname); /* argument to open function */
|
||||||
lua_call(L, 1, 1); /* call 'openf' to open module */
|
lua_call(L, 1, 1); /* call 'openf' to open module */
|
||||||
lua_pushvalue(L, -1); /* make copy of module (call result) */
|
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) {
|
if (glb) {
|
||||||
lua_pushvalue(L, -1); /* copy of module */
|
lua_pushvalue(L, -1); /* copy of module */
|
||||||
lua_setglobal(L, modname); /* _G[modname] = 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");
|
luaL_error(L, "multiple Lua VMs detected");
|
||||||
else if (*v != ver)
|
else if (*v != ver)
|
||||||
luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
|
luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
|
||||||
ver, *v);
|
(LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)*v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
** Auxiliary functions for building Lua libraries
|
||||||
** See Copyright Notice in lua.h
|
** 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)
|
#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 {
|
typedef struct luaL_Reg {
|
||||||
const char *name;
|
const char *name;
|
||||||
lua_CFunction func;
|
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_fileresult) (lua_State *L, int stat, const char *fname);
|
||||||
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
|
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
|
||||||
|
|
||||||
/* pre-defined references */
|
/* predefined references */
|
||||||
#define LUA_NOREF (-2)
|
#define LUA_NOREF (-2)
|
||||||
#define LUA_REFNIL (-1)
|
#define LUA_REFNIL (-1)
|
||||||
|
|
||||||
|
|
|
@ -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
|
** Basic library
|
||||||
** See Copyright Notice in lua.h
|
** 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;
|
return NULL;
|
||||||
do {
|
do {
|
||||||
int digit = (isdigit((unsigned char)*s)) ? *s - '0'
|
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 */
|
if (digit >= base) return NULL; /* invalid numeral */
|
||||||
n = n * base + digit;
|
n = n * base + digit;
|
||||||
s++;
|
s++;
|
||||||
|
@ -86,8 +86,8 @@ static int luaB_tonumber (lua_State *L) {
|
||||||
const char *s;
|
const char *s;
|
||||||
lua_Integer n = 0; /* to avoid warnings */
|
lua_Integer n = 0; /* to avoid warnings */
|
||||||
lua_Integer base = luaL_checkinteger(L, 2);
|
lua_Integer base = luaL_checkinteger(L, 2);
|
||||||
luaL_checktype(L, 1, LUA_TSTRING); /* before 'luaL_checklstring'! */
|
luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */
|
||||||
s = luaL_checklstring(L, 1, &l);
|
s = lua_tolstring(L, 1, &l);
|
||||||
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
|
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
|
||||||
if (b_str2int(s, (int)base, &n) == s + l) {
|
if (b_str2int(s, (int)base, &n) == s + l) {
|
||||||
lua_pushinteger(L, n);
|
lua_pushinteger(L, n);
|
||||||
|
@ -102,8 +102,8 @@ static int luaB_tonumber (lua_State *L) {
|
||||||
static int luaB_error (lua_State *L) {
|
static int luaB_error (lua_State *L) {
|
||||||
int level = (int)luaL_optinteger(L, 2, 1);
|
int level = (int)luaL_optinteger(L, 2, 1);
|
||||||
lua_settop(L, 1);
|
lua_settop(L, 1);
|
||||||
if (lua_isstring(L, 1) && level > 0) { /* add extra information? */
|
if (lua_type(L, 1) == LUA_TSTRING && level > 0) {
|
||||||
luaL_where(L, level);
|
luaL_where(L, level); /* add extra information */
|
||||||
lua_pushvalue(L, 1);
|
lua_pushvalue(L, 1);
|
||||||
lua_concat(L, 2);
|
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) {
|
static int luaB_type (lua_State *L) {
|
||||||
luaL_checkany(L, 1);
|
int t = lua_type(L, 1);
|
||||||
lua_pushvalue(L, lua_upvalueindex(lua_type(L, 1) + 1));
|
luaL_argcheck(L, t != LUA_TNONE, 1, "value expected");
|
||||||
|
lua_pushstring(L, lua_typename(L, t));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int pairsmeta (lua_State *L, const char *method, int iszero,
|
static int pairsmeta (lua_State *L, const char *method, int iszero,
|
||||||
lua_CFunction iter) {
|
lua_CFunction iter) {
|
||||||
|
luaL_checkany(L, 1);
|
||||||
if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */
|
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_pushcfunction(L, iter); /* will return generator, */
|
||||||
lua_pushvalue(L, 1); /* state, */
|
lua_pushvalue(L, 1); /* state, */
|
||||||
if (iszero) lua_pushinteger(L, 0); /* and initial value */
|
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
|
** Traversal function for 'ipairs'
|
||||||
*/
|
|
||||||
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
|
|
||||||
*/
|
*/
|
||||||
static int ipairsaux (lua_State *L) {
|
static int ipairsaux (lua_State *L) {
|
||||||
lua_Integer i = luaL_checkinteger(L, 2) + 1;
|
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
|
** 'ipairs' function. Returns 'ipairsaux', given "table", 0.
|
||||||
** traverse a table, depending on whether the table has metamethods
|
** (The given "table" may not be a table.)
|
||||||
** that can affect the traversal.
|
|
||||||
*/
|
*/
|
||||||
static int luaB_ipairs (lua_State *L) {
|
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)
|
#if defined(LUA_COMPAT_IPAIRS)
|
||||||
return pairsmeta(L, "__ipairs", 1, iter);
|
return pairsmeta(L, "__ipairs", 1, ipairsaux);
|
||||||
#else
|
#else
|
||||||
luaL_checkany(L, 1);
|
luaL_checkany(L, 1);
|
||||||
lua_pushcfunction(L, iter); /* iteration function */
|
lua_pushcfunction(L, ipairsaux); /* iteration function */
|
||||||
lua_pushvalue(L, 1); /* state */
|
lua_pushvalue(L, 1); /* state */
|
||||||
lua_pushinteger(L, 0); /* initial value */
|
lua_pushinteger(L, 0); /* initial value */
|
||||||
return 3;
|
return 3;
|
||||||
|
@ -490,9 +474,9 @@ static const luaL_Reg base_funcs[] = {
|
||||||
{"setmetatable", luaB_setmetatable},
|
{"setmetatable", luaB_setmetatable},
|
||||||
{"tonumber", luaB_tonumber},
|
{"tonumber", luaB_tonumber},
|
||||||
{"tostring", luaB_tostring},
|
{"tostring", luaB_tostring},
|
||||||
|
{"type", luaB_type},
|
||||||
{"xpcall", luaB_xpcall},
|
{"xpcall", luaB_xpcall},
|
||||||
/* placeholders */
|
/* placeholders */
|
||||||
{"type", NULL},
|
|
||||||
{"_G", NULL},
|
{"_G", NULL},
|
||||||
{"_VERSION", NULL},
|
{"_VERSION", NULL},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
|
@ -500,7 +484,6 @@ static const luaL_Reg base_funcs[] = {
|
||||||
|
|
||||||
|
|
||||||
LUAMOD_API int luaopen_base (lua_State *L) {
|
LUAMOD_API int luaopen_base (lua_State *L) {
|
||||||
int i;
|
|
||||||
/* open lib into global table */
|
/* open lib into global table */
|
||||||
lua_pushglobaltable(L);
|
lua_pushglobaltable(L);
|
||||||
luaL_setfuncs(L, base_funcs, 0);
|
luaL_setfuncs(L, base_funcs, 0);
|
||||||
|
@ -510,11 +493,6 @@ LUAMOD_API int luaopen_base (lua_State *L) {
|
||||||
/* set global _VERSION */
|
/* set global _VERSION */
|
||||||
lua_pushliteral(L, LUA_VERSION);
|
lua_pushliteral(L, LUA_VERSION);
|
||||||
lua_setfield(L, -2, "_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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
** Standard library for bitwise operations
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -19,6 +19,10 @@
|
||||||
#if defined(LUA_COMPAT_BITLIB) /* { */
|
#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 */
|
/* number of bits to consider in a number */
|
||||||
#if !defined(LUA_NBITS)
|
#if !defined(LUA_NBITS)
|
||||||
#define LUA_NBITS 32
|
#define LUA_NBITS 32
|
||||||
|
@ -46,14 +50,14 @@ static lua_Unsigned andaux (lua_State *L) {
|
||||||
int i, n = lua_gettop(L);
|
int i, n = lua_gettop(L);
|
||||||
lua_Unsigned r = ~(lua_Unsigned)0;
|
lua_Unsigned r = ~(lua_Unsigned)0;
|
||||||
for (i = 1; i <= n; i++)
|
for (i = 1; i <= n; i++)
|
||||||
r &= luaL_checkunsigned(L, i);
|
r &= checkunsigned(L, i);
|
||||||
return trim(r);
|
return trim(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int b_and (lua_State *L) {
|
static int b_and (lua_State *L) {
|
||||||
lua_Unsigned r = andaux(L);
|
lua_Unsigned r = andaux(L);
|
||||||
lua_pushunsigned(L, r);
|
pushunsigned(L, r);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,8 +73,8 @@ static int b_or (lua_State *L) {
|
||||||
int i, n = lua_gettop(L);
|
int i, n = lua_gettop(L);
|
||||||
lua_Unsigned r = 0;
|
lua_Unsigned r = 0;
|
||||||
for (i = 1; i <= n; i++)
|
for (i = 1; i <= n; i++)
|
||||||
r |= luaL_checkunsigned(L, i);
|
r |= checkunsigned(L, i);
|
||||||
lua_pushunsigned(L, trim(r));
|
pushunsigned(L, trim(r));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,15 +83,15 @@ static int b_xor (lua_State *L) {
|
||||||
int i, n = lua_gettop(L);
|
int i, n = lua_gettop(L);
|
||||||
lua_Unsigned r = 0;
|
lua_Unsigned r = 0;
|
||||||
for (i = 1; i <= n; i++)
|
for (i = 1; i <= n; i++)
|
||||||
r ^= luaL_checkunsigned(L, i);
|
r ^= checkunsigned(L, i);
|
||||||
lua_pushunsigned(L, trim(r));
|
pushunsigned(L, trim(r));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int b_not (lua_State *L) {
|
static int b_not (lua_State *L) {
|
||||||
lua_Unsigned r = ~luaL_checkunsigned(L, 1);
|
lua_Unsigned r = ~checkunsigned(L, 1);
|
||||||
lua_pushunsigned(L, trim(r));
|
pushunsigned(L, trim(r));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,23 +108,23 @@ static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) {
|
||||||
else r <<= i;
|
else r <<= i;
|
||||||
r = trim(r);
|
r = trim(r);
|
||||||
}
|
}
|
||||||
lua_pushunsigned(L, r);
|
pushunsigned(L, r);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int b_lshift (lua_State *L) {
|
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) {
|
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) {
|
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);
|
lua_Integer i = luaL_checkinteger(L, 2);
|
||||||
if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1))))
|
if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1))))
|
||||||
return b_shift(L, r, -i);
|
return b_shift(L, r, -i);
|
||||||
|
@ -128,19 +132,19 @@ static int b_arshift (lua_State *L) {
|
||||||
if (i >= LUA_NBITS) r = ALLONES;
|
if (i >= LUA_NBITS) r = ALLONES;
|
||||||
else
|
else
|
||||||
r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */
|
r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */
|
||||||
lua_pushunsigned(L, r);
|
pushunsigned(L, r);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int b_rot (lua_State *L, lua_Integer d) {
|
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 */
|
int i = d & (LUA_NBITS - 1); /* i = d % NBITS */
|
||||||
r = trim(r);
|
r = trim(r);
|
||||||
if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */
|
if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */
|
||||||
r = (r << i) | (r >> (LUA_NBITS - i));
|
r = (r << i) | (r >> (LUA_NBITS - i));
|
||||||
lua_pushunsigned(L, trim(r));
|
pushunsigned(L, trim(r));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,23 +179,22 @@ static int fieldargs (lua_State *L, int farg, int *width) {
|
||||||
|
|
||||||
static int b_extract (lua_State *L) {
|
static int b_extract (lua_State *L) {
|
||||||
int w;
|
int w;
|
||||||
lua_Unsigned r = trim(luaL_checkunsigned(L, 1));
|
lua_Unsigned r = trim(checkunsigned(L, 1));
|
||||||
int f = fieldargs(L, 2, &w);
|
int f = fieldargs(L, 2, &w);
|
||||||
r = (r >> f) & mask(w);
|
r = (r >> f) & mask(w);
|
||||||
lua_pushunsigned(L, r);
|
pushunsigned(L, r);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int b_replace (lua_State *L) {
|
static int b_replace (lua_State *L) {
|
||||||
int w;
|
int w;
|
||||||
lua_Unsigned r = trim(luaL_checkunsigned(L, 1));
|
lua_Unsigned r = trim(checkunsigned(L, 1));
|
||||||
lua_Unsigned v = luaL_checkunsigned(L, 2);
|
lua_Unsigned v = trim(checkunsigned(L, 2));
|
||||||
int f = fieldargs(L, 3, &w);
|
int f = fieldargs(L, 3, &w);
|
||||||
int m = mask(w);
|
lua_Unsigned m = mask(w);
|
||||||
v &= m; /* erase bits outside given width */
|
r = (r & ~(m << f)) | ((v & m) << f);
|
||||||
r = (r & ~(m << f)) | (v << f);
|
pushunsigned(L, r);
|
||||||
lua_pushunsigned(L, r);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
709
src/lcode.c
709
src/lcode.c
File diff suppressed because it is too large
Load diff
|
@ -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
|
** Code generator for Lua
|
||||||
** See Copyright Notice in lua.h
|
** 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;
|
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)
|
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
|
||||||
|
|
||||||
|
|
|
@ -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
|
** Coroutine Library
|
||||||
** See Copyright Notice in lua.h
|
** 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));
|
lua_State *co = lua_tothread(L, lua_upvalueindex(1));
|
||||||
int r = auxresume(L, co, lua_gettop(L));
|
int r = auxresume(L, co, lua_gettop(L));
|
||||||
if (r < 0) {
|
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 */
|
luaL_where(L, 1); /* add extra info */
|
||||||
lua_insert(L, -2);
|
lua_insert(L, -2);
|
||||||
lua_concat(L, 2);
|
lua_concat(L, 2);
|
||||||
|
|
21
src/ldblib.c
21
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
|
** Interface from Lua to its debug API
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -27,6 +27,17 @@
|
||||||
static const int HOOKKEY = 0;
|
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) {
|
static int db_getregistry (lua_State *L) {
|
||||||
lua_pushvalue(L, LUA_REGISTRYINDEX);
|
lua_pushvalue(L, LUA_REGISTRYINDEX);
|
||||||
return 1;
|
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.
|
** 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) {
|
static int db_getinfo (lua_State *L) {
|
||||||
lua_Debug ar;
|
lua_Debug ar;
|
||||||
int arg;
|
int arg;
|
||||||
lua_State *L1 = getthread(L, &arg);
|
lua_State *L1 = getthread(L, &arg);
|
||||||
const char *options = luaL_optstring(L, arg+2, "flnStu");
|
const char *options = luaL_optstring(L, arg+2, "flnStu");
|
||||||
|
checkstack(L, L1, 3);
|
||||||
if (lua_isfunction(L, arg + 1)) { /* info about a function? */
|
if (lua_isfunction(L, arg + 1)) { /* info about a function? */
|
||||||
options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */
|
options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */
|
||||||
lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */
|
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);
|
int level = (int)luaL_checkinteger(L, arg + 1);
|
||||||
if (!lua_getstack(L1, level, &ar)) /* out of range? */
|
if (!lua_getstack(L1, level, &ar)) /* out of range? */
|
||||||
return luaL_argerror(L, arg+1, "level out of range");
|
return luaL_argerror(L, arg+1, "level out of range");
|
||||||
|
checkstack(L, L1, 1);
|
||||||
name = lua_getlocal(L1, &ar, nvar);
|
name = lua_getlocal(L1, &ar, nvar);
|
||||||
if (name) {
|
if (name) {
|
||||||
lua_xmove(L1, L, 1); /* move local value */
|
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");
|
return luaL_argerror(L, arg+1, "level out of range");
|
||||||
luaL_checkany(L, arg+3);
|
luaL_checkany(L, arg+3);
|
||||||
lua_settop(L, arg+3);
|
lua_settop(L, arg+3);
|
||||||
|
checkstack(L, L1, 1);
|
||||||
lua_xmove(L, L1, 1);
|
lua_xmove(L, L1, 1);
|
||||||
name = lua_setlocal(L1, &ar, nvar);
|
name = lua_setlocal(L1, &ar, nvar);
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
|
@ -350,6 +367,7 @@ static int db_sethook (lua_State *L) {
|
||||||
lua_pushvalue(L, -1);
|
lua_pushvalue(L, -1);
|
||||||
lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */
|
lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */
|
||||||
}
|
}
|
||||||
|
checkstack(L, L1, 1);
|
||||||
lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */
|
lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */
|
||||||
lua_pushvalue(L, arg + 1); /* value (hook function) */
|
lua_pushvalue(L, arg + 1); /* value (hook function) */
|
||||||
lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */
|
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");
|
lua_pushliteral(L, "external hook");
|
||||||
else { /* hook table must exist */
|
else { /* hook table must exist */
|
||||||
lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
|
lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
|
||||||
|
checkstack(L, L1, 1);
|
||||||
lua_pushthread(L1); lua_xmove(L1, L, 1);
|
lua_pushthread(L1); lua_xmove(L1, L, 1);
|
||||||
lua_rawget(L, -2); /* 1st result = hooktable[L1] */
|
lua_rawget(L, -2); /* 1st result = hooktable[L1] */
|
||||||
lua_remove(L, -2); /* remove hook table */
|
lua_remove(L, -2); /* remove hook table */
|
||||||
|
|
123
src/ldebug.c
123
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
|
** Debug Interface
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -34,7 +34,12 @@
|
||||||
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL)
|
#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) {
|
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) {
|
LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
|
||||||
if (func == NULL || mask == 0) { /* turn off hooks? */
|
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) {
|
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
|
||||||
int nparams = clLvalue(ci->func)->p->numparams;
|
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 */
|
return NULL; /* no such vararg */
|
||||||
else {
|
else {
|
||||||
*pos = ci->func + nparams + n;
|
*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) {
|
LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
|
||||||
const char *name;
|
const char *name;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
|
swapextra(L);
|
||||||
if (ar == NULL) { /* information about non-active function? */
|
if (ar == NULL) { /* information about non-active function? */
|
||||||
if (!isLfunction(L->top - 1)) /* not a Lua function? */
|
if (!isLfunction(L->top - 1)) /* not a Lua function? */
|
||||||
name = NULL;
|
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);
|
name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0);
|
||||||
}
|
}
|
||||||
else { /* active function; get information through 'ar' */
|
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);
|
name = findlocal(L, ar->i_ci, n, &pos);
|
||||||
if (name) {
|
if (name) {
|
||||||
setobj2s(L, L->top, pos);
|
setobj2s(L, L->top, pos);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
swapextra(L);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
|
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
|
||||||
StkId pos = 0; /* to avoid warnings */
|
StkId pos = NULL; /* to avoid warnings */
|
||||||
const char *name = findlocal(L, ar->i_ci, n, &pos);
|
const char *name;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
|
swapextra(L);
|
||||||
|
name = findlocal(L, ar->i_ci, n, &pos);
|
||||||
if (name) {
|
if (name) {
|
||||||
setobjs2s(L, pos, L->top - 1);
|
setobjs2s(L, pos, L->top - 1);
|
||||||
L->top--; /* pop value */
|
L->top--; /* pop value */
|
||||||
}
|
}
|
||||||
|
swapextra(L);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return name;
|
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,
|
static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
||||||
Closure *f, CallInfo *ci) {
|
Closure *f, CallInfo *ci) {
|
||||||
int status = 1;
|
int status = 1;
|
||||||
|
@ -243,11 +289,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'n': {
|
case 'n': {
|
||||||
/* calling function is a known Lua function? */
|
ar->namewhat = getfuncname(L, ci, &ar->name);
|
||||||
if (ci && !(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
|
|
||||||
ar->namewhat = getfuncname(L, ci->previous, &ar->name);
|
|
||||||
else
|
|
||||||
ar->namewhat = NULL;
|
|
||||||
if (ar->namewhat == NULL) {
|
if (ar->namewhat == NULL) {
|
||||||
ar->namewhat = ""; /* not found */
|
ar->namewhat = ""; /* not found */
|
||||||
ar->name = NULL;
|
ar->name = NULL;
|
||||||
|
@ -270,10 +312,11 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
|
||||||
CallInfo *ci;
|
CallInfo *ci;
|
||||||
StkId func;
|
StkId func;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
|
swapextra(L);
|
||||||
if (*what == '>') {
|
if (*what == '>') {
|
||||||
ci = NULL;
|
ci = NULL;
|
||||||
func = L->top - 1;
|
func = L->top - 1;
|
||||||
api_check(ttisfunction(func), "function expected");
|
api_check(L, ttisfunction(func), "function expected");
|
||||||
what++; /* skip the '>' */
|
what++; /* skip the '>' */
|
||||||
L->top--; /* pop function */
|
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);
|
setobjs2s(L, L->top, func);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
}
|
}
|
||||||
|
swapextra(L); /* correct before option 'L', which can raise a mem. error */
|
||||||
if (strchr(what, 'L'))
|
if (strchr(what, 'L'))
|
||||||
collectvalidlines(L, cl);
|
collectvalidlines(L, cl);
|
||||||
lua_unlock(L);
|
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 */
|
Proto *p = ci_func(ci)->p; /* calling function */
|
||||||
int pc = currentpc(ci); /* calling instruction index */
|
int pc = currentpc(ci); /* calling instruction index */
|
||||||
Instruction i = p->code[pc]; /* calling instruction */
|
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)) {
|
switch (GET_OPCODE(i)) {
|
||||||
case OP_CALL:
|
case OP_CALL:
|
||||||
case OP_TAILCALL: /* get function name */
|
case OP_TAILCALL:
|
||||||
return getobjname(p, pc, GETARG_A(i), name);
|
return getobjname(p, pc, GETARG_A(i), name); /* get function name */
|
||||||
case OP_TFORCALL: { /* for iterator */
|
case OP_TFORCALL: { /* for iterator */
|
||||||
*name = "for iterator";
|
*name = "for iterator";
|
||||||
return "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:
|
case OP_SELF: case OP_GETTABUP: case OP_GETTABLE:
|
||||||
tm = TM_INDEX;
|
tm = TM_INDEX;
|
||||||
break;
|
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_EQ: tm = TM_EQ; break;
|
||||||
case OP_LT: tm = TM_LT; break;
|
case OP_LT: tm = TM_LT; break;
|
||||||
case OP_LE: tm = TM_LE; 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]);
|
*name = getstr(G(L)->tmname[tm]);
|
||||||
return "metamethod";
|
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) {
|
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));
|
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) {
|
l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
|
||||||
const char *t1 = objtypename(p1);
|
const char *t1 = luaT_objtypename(L, p1);
|
||||||
const char *t2 = objtypename(p2);
|
const char *t2 = luaT_objtypename(L, p2);
|
||||||
if (t1 == t2)
|
if (strcmp(t1, t2) == 0)
|
||||||
luaG_runerror(L, "attempt to compare two %s values", t1);
|
luaG_runerror(L, "attempt to compare two %s values", t1);
|
||||||
else
|
else
|
||||||
luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
|
luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void addinfo (lua_State *L, const char *msg) {
|
/* add src:line information to 'msg' */
|
||||||
CallInfo *ci = L->ci;
|
const char *luaG_addinfo (lua_State *L, const char *msg, TString *src,
|
||||||
if (isLua(ci)) { /* is Lua code? */
|
int line) {
|
||||||
char buff[LUA_IDSIZE]; /* add file:line information */
|
char buff[LUA_IDSIZE];
|
||||||
int line = currentline(ci);
|
|
||||||
TString *src = ci_func(ci)->p->source;
|
|
||||||
if (src)
|
if (src)
|
||||||
luaO_chunkid(buff, getstr(src), LUA_IDSIZE);
|
luaO_chunkid(buff, getstr(src), LUA_IDSIZE);
|
||||||
else { /* no source available; use "?" instead */
|
else { /* no source available; use "?" instead */
|
||||||
buff[0] = '?'; buff[1] = '\0';
|
buff[0] = '?'; buff[1] = '\0';
|
||||||
}
|
}
|
||||||
luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
|
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, L->top - 1); /* move argument */
|
||||||
setobjs2s(L, L->top - 1, errfunc); /* push function */
|
setobjs2s(L, L->top - 1, errfunc); /* push function */
|
||||||
L->top++; /* assume EXTRA_STACK */
|
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);
|
luaD_throw(L, LUA_ERRRUN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
|
l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
|
||||||
|
CallInfo *ci = L->ci;
|
||||||
|
const char *msg;
|
||||||
va_list argp;
|
va_list argp;
|
||||||
va_start(argp, fmt);
|
va_start(argp, fmt);
|
||||||
addinfo(L, luaO_pushvfstring(L, fmt, argp));
|
msg = luaO_pushvfstring(L, fmt, argp); /* format message */
|
||||||
va_end(argp);
|
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);
|
luaG_errormsg(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -612,9 +665,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
|
||||||
void luaG_traceexec (lua_State *L) {
|
void luaG_traceexec (lua_State *L) {
|
||||||
CallInfo *ci = L->ci;
|
CallInfo *ci = L->ci;
|
||||||
lu_byte mask = L->hookmask;
|
lu_byte mask = L->hookmask;
|
||||||
int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0);
|
int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT));
|
||||||
if (counthook)
|
if (counthook)
|
||||||
resethookcount(L); /* reset count */
|
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? */
|
if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */
|
||||||
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
|
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
|
||||||
return; /* do not call hook again (VM yielded, so it did not move) */
|
return; /* do not call hook again (VM yielded, so it did not move) */
|
||||||
|
|
|
@ -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
|
** Auxiliary functions from Debug Interface module
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -17,9 +17,6 @@
|
||||||
|
|
||||||
#define resethookcount(L) (L->hookcount = L->basehookcount)
|
#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,
|
LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,
|
||||||
const char *opname);
|
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,
|
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
|
||||||
const TValue *p2);
|
const TValue *p2);
|
||||||
LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
|
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 l_noret luaG_errormsg (lua_State *L);
|
||||||
LUAI_FUNC void luaG_traceexec (lua_State *L);
|
LUAI_FUNC void luaG_traceexec (lua_State *L);
|
||||||
|
|
||||||
|
|
353
src/ldo.c
353
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
|
** Stack and Call structure of Lua
|
||||||
** See Copyright Notice in lua.h
|
** 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) {
|
static void correctstack (lua_State *L, TValue *oldstack) {
|
||||||
CallInfo *ci;
|
CallInfo *ci;
|
||||||
UpVal *up;
|
UpVal *up;
|
||||||
|
@ -206,9 +211,9 @@ static int stackinuse (lua_State *L) {
|
||||||
CallInfo *ci;
|
CallInfo *ci;
|
||||||
StkId lim = L->top;
|
StkId lim = L->top;
|
||||||
for (ci = L->ci; ci != NULL; ci = ci->previous) {
|
for (ci = L->ci; ci != NULL; ci = ci->previous) {
|
||||||
lua_assert(ci->top <= L->stack_last);
|
|
||||||
if (lim < ci->top) lim = ci->top;
|
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 */
|
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) {
|
void luaD_shrinkstack (lua_State *L) {
|
||||||
int inuse = stackinuse(L);
|
int inuse = stackinuse(L);
|
||||||
int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
|
int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
|
||||||
if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK;
|
if (goodsize > LUAI_MAXSTACK)
|
||||||
if (L->stacksize > LUAI_MAXSTACK) /* was handling stack overflow? */
|
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) */
|
luaE_freeCI(L); /* free all CIs (list grew because of an error) */
|
||||||
else
|
else
|
||||||
luaE_shrinkCI(L); /* shrink list */
|
luaE_shrinkCI(L); /* shrink list */
|
||||||
if (inuse > LUAI_MAXSTACK || /* still handling stack overflow? */
|
/* if thread is currently not handling a stack overflow and its
|
||||||
goodsize >= L->stacksize) /* would grow instead of shrink? */
|
good size is smaller than current size, shrink its stack */
|
||||||
condmovestack(L); /* don't change stack (change only for debugging) */
|
if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) &&
|
||||||
else
|
goodsize < L->stacksize)
|
||||||
luaD_reallocstack(L, goodsize); /* shrink it */
|
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) {
|
void luaD_hook (lua_State *L, int event, int line) {
|
||||||
lua_Hook hook = L->hook;
|
lua_Hook hook = L->hook;
|
||||||
if (hook && L->allowhook) {
|
if (hook && L->allowhook) { /* make sure there is a hook */
|
||||||
CallInfo *ci = L->ci;
|
CallInfo *ci = L->ci;
|
||||||
ptrdiff_t top = savestack(L, L->top);
|
ptrdiff_t top = savestack(L, L->top);
|
||||||
ptrdiff_t ci_top = savestack(L, ci->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 i;
|
||||||
int nfixargs = p->numparams;
|
int nfixargs = p->numparams;
|
||||||
StkId base, fixed;
|
StkId base, fixed;
|
||||||
lua_assert(actual >= nfixargs);
|
|
||||||
/* move fixed parameters to final position */
|
/* move fixed parameters to final position */
|
||||||
luaD_checkstack(L, p->maxstacksize); /* check again for new 'base' */
|
|
||||||
fixed = L->top - actual; /* first fixed argument */
|
fixed = L->top - actual; /* first fixed argument */
|
||||||
base = L->top; /* final position of first 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);
|
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;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,85 +325,57 @@ static void tryfuncTM (lua_State *L, StkId func) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** returns true if function has been executed (C function)
|
** 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.
|
||||||
*/
|
*/
|
||||||
int luaD_precall (lua_State *L, StkId func, int nresults) {
|
static int moveresults (lua_State *L, const TValue *firstResult, StkId res,
|
||||||
lua_CFunction f;
|
int nres, int wanted) {
|
||||||
CallInfo *ci;
|
switch (wanted) { /* handle typical cases separately */
|
||||||
int n; /* number of arguments (Lua) or returns (C) */
|
case 0: break; /* nothing to move */
|
||||||
ptrdiff_t funcr = savestack(L, func);
|
case 1: { /* one result needed */
|
||||||
switch (ttype(func)) {
|
if (nres == 0) /* no results? */
|
||||||
case LUA_TLCF: /* light C function */
|
firstResult = luaO_nilobject; /* adjust with nil */
|
||||||
f = fvalue(func);
|
setobjs2s(L, res, firstResult); /* move it to proper place */
|
||||||
goto Cfunc;
|
break;
|
||||||
case LUA_TCCL: { /* C closure */
|
}
|
||||||
f = clCvalue(func)->f;
|
case LUA_MULTRET: {
|
||||||
Cfunc:
|
int i;
|
||||||
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
|
for (i = 0; i < nres; i++) /* move all results to correct place */
|
||||||
ci = next_ci(L); /* now 'enter' new function */
|
setobjs2s(L, res + i, firstResult + i);
|
||||||
ci->nresults = nresults;
|
L->top = res + nres;
|
||||||
ci->func = restorestack(L, funcr);
|
return 0; /* wanted == LUA_MULTRET */
|
||||||
ci->top = L->top + LUA_MINSTACK;
|
}
|
||||||
lua_assert(ci->top <= L->stack_last);
|
default: {
|
||||||
ci->callstatus = 0;
|
int i;
|
||||||
luaC_checkGC(L); /* stack grow uses memory */
|
if (wanted <= nres) { /* enough results? */
|
||||||
if (L->hookmask & LUA_MASKCALL)
|
for (i = 0; i < wanted; i++) /* move wanted results to correct place */
|
||||||
luaD_hook(L, LUA_HOOKCALL, -1);
|
setobjs2s(L, res + i, firstResult + i);
|
||||||
lua_unlock(L);
|
}
|
||||||
n = (*f)(L); /* do the actual call */
|
else { /* not enough results; use all of them plus nils */
|
||||||
lua_lock(L);
|
for (i = 0; i < nres; i++) /* move all results to correct place */
|
||||||
api_checknelems(L, n);
|
setobjs2s(L, res + i, firstResult + i);
|
||||||
luaD_poscall(L, L->top - n);
|
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;
|
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 {
|
|
||||||
base = adjust_varargs(L, p, n);
|
|
||||||
func = restorestack(L, funcr); /* previous call can change stack */
|
|
||||||
}
|
|
||||||
ci = next_ci(L); /* now 'enter' new function */
|
|
||||||
ci->nresults = nresults;
|
|
||||||
ci->func = func;
|
|
||||||
ci->u.l.base = base;
|
|
||||||
ci->top = base + p->maxstacksize;
|
|
||||||
lua_assert(ci->top <= L->stack_last);
|
|
||||||
ci->u.l.savedpc = p->code; /* starting point */
|
|
||||||
ci->callstatus = CIST_LUA;
|
|
||||||
L->top = ci->top;
|
|
||||||
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 */
|
|
||||||
tryfuncTM(L, func); /* try to get '__call' metamethod */
|
|
||||||
return luaD_precall(L, func, nresults); /* now it must be a function */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int luaD_poscall (lua_State *L, StkId firstResult) {
|
/*
|
||||||
|
** 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;
|
StkId res;
|
||||||
int wanted, i;
|
int wanted = ci->nresults;
|
||||||
CallInfo *ci = L->ci;
|
|
||||||
if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
|
if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
|
||||||
if (L->hookmask & LUA_MASKRET) {
|
if (L->hookmask & LUA_MASKRET) {
|
||||||
ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
|
ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
|
||||||
|
@ -392,15 +385,104 @@ int luaD_poscall (lua_State *L, StkId firstResult) {
|
||||||
L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
|
L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
|
||||||
}
|
}
|
||||||
res = ci->func; /* res == final position of 1st result */
|
res = ci->func; /* res == final position of 1st result */
|
||||||
wanted = ci->nresults;
|
L->ci = ci->previous; /* back to caller */
|
||||||
L->ci = ci = ci->previous; /* back to caller */
|
/* move results to proper place */
|
||||||
/* move results to correct place */
|
return moveresults(L, firstResult, res, nres, wanted);
|
||||||
for (i = wanted; i != 0 && firstResult < L->top; i--)
|
}
|
||||||
setobjs2s(L, res++, firstResult++);
|
|
||||||
while (i-- > 0)
|
|
||||||
setnilvalue(res++);
|
|
||||||
L->top = res;
|
#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
|
||||||
return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */
|
|
||||||
|
|
||||||
|
/* 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' */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 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;
|
||||||
|
switch (ttype(func)) {
|
||||||
|
case LUA_TCCL: /* C closure */
|
||||||
|
f = clCvalue(func)->f;
|
||||||
|
goto Cfunc;
|
||||||
|
case LUA_TLCF: /* light C function */
|
||||||
|
f = fvalue(func);
|
||||||
|
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 = func;
|
||||||
|
ci->top = L->top + LUA_MINSTACK;
|
||||||
|
lua_assert(ci->top <= L->stack_last);
|
||||||
|
ci->callstatus = 0;
|
||||||
|
if (L->hookmask & LUA_MASKCALL)
|
||||||
|
luaD_hook(L, LUA_HOOKCALL, -1);
|
||||||
|
lua_unlock(L);
|
||||||
|
n = (*f)(L); /* do the actual call */
|
||||||
|
lua_lock(L);
|
||||||
|
api_checknelems(L, n);
|
||||||
|
luaD_poscall(L, ci, L->top - n, n);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
case LUA_TLCL: { /* Lua function: prepare its call */
|
||||||
|
StkId base;
|
||||||
|
Proto *p = clLvalue(func)->p;
|
||||||
|
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);
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
if (L->hookmask & LUA_MASKCALL)
|
||||||
|
callhook(L, ci);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
default: { /* not a function */
|
||||||
|
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 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 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,21 +492,25 @@ int luaD_poscall (lua_State *L, StkId firstResult) {
|
||||||
** When returns, all the results are on the stack, starting at the original
|
** When returns, all the results are on the stack, starting at the original
|
||||||
** function position.
|
** function position.
|
||||||
*/
|
*/
|
||||||
void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) {
|
void luaD_call (lua_State *L, StkId func, int nResults) {
|
||||||
if (++L->nCcalls >= LUAI_MAXCCALLS) {
|
if (++L->nCcalls >= LUAI_MAXCCALLS)
|
||||||
if (L->nCcalls == LUAI_MAXCCALLS)
|
stackerror(L);
|
||||||
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++;
|
|
||||||
if (!luaD_precall(L, func, nResults)) /* is a Lua function? */
|
if (!luaD_precall(L, func, nResults)) /* is a Lua function? */
|
||||||
luaV_execute(L); /* call it */
|
luaV_execute(L); /* call it */
|
||||||
if (!allowyield) L->nny--;
|
|
||||||
L->nCcalls--;
|
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
|
** Completes the execution of an interrupted C function, calling its
|
||||||
** continuation function.
|
** continuation function.
|
||||||
|
@ -437,19 +523,17 @@ static void finishCcall (lua_State *L, int status) {
|
||||||
/* error status can only happen in a protected call */
|
/* error status can only happen in a protected call */
|
||||||
lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD);
|
lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD);
|
||||||
if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */
|
if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */
|
||||||
ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */
|
ci->callstatus &= ~CIST_YPCALL; /* continuation is also inside it */
|
||||||
L->errfunc = ci->u.c.old_errfunc;
|
L->errfunc = ci->u.c.old_errfunc; /* with the same error function */
|
||||||
}
|
}
|
||||||
/* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already
|
/* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already
|
||||||
handled */
|
handled */
|
||||||
adjustresults(L, ci->nresults);
|
adjustresults(L, ci->nresults);
|
||||||
/* call continuation function */
|
|
||||||
lua_unlock(L);
|
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);
|
lua_lock(L);
|
||||||
api_checknelems(L, n);
|
api_checknelems(L, n);
|
||||||
/* finish 'luaD_precall' */
|
luaD_poscall(L, ci, L->top - n, n); /* finish 'luaD_precall' */
|
||||||
luaD_poscall(L, L->top - n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
** Signal an error in the call to 'lua_resume', not in the execution
|
||||||
** coroutine itself. (Such errors should not be handled by any coroutine
|
** of the coroutine itself. (Such errors should not be handled by any
|
||||||
** error handler and should not kill the coroutine.)
|
** coroutine error handler and should not kill the coroutine.)
|
||||||
*/
|
*/
|
||||||
static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
|
static int resume_error (lua_State *L, const char *msg, int narg) {
|
||||||
L->top = firstArg; /* remove args from the stack */
|
L->top -= narg; /* remove args from the stack */
|
||||||
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
|
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
|
||||||
api_incr_top(L);
|
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.
|
** coroutine.
|
||||||
*/
|
*/
|
||||||
static void resume (lua_State *L, void *ud) {
|
static void resume (lua_State *L, void *ud) {
|
||||||
int nCcalls = L->nCcalls;
|
int n = *(cast(int*, ud)); /* number of arguments */
|
||||||
StkId firstArg = cast(StkId, ud);
|
StkId firstArg = L->top - n; /* first argument */
|
||||||
CallInfo *ci = L->ci;
|
CallInfo *ci = L->ci;
|
||||||
if (nCcalls >= LUAI_MAXCCALLS)
|
if (L->status == LUA_OK) { /* starting a coroutine? */
|
||||||
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 (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */
|
if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */
|
||||||
luaV_execute(L); /* call it */
|
luaV_execute(L); /* call it */
|
||||||
}
|
}
|
||||||
else if (L->status != LUA_YIELD)
|
|
||||||
resume_error(L, "cannot resume dead coroutine", firstArg);
|
|
||||||
else { /* resuming from previous yield */
|
else { /* resuming from previous yield */
|
||||||
|
lua_assert(L->status == LUA_YIELD);
|
||||||
L->status = LUA_OK; /* mark that it is running (again) */
|
L->status = LUA_OK; /* mark that it is running (again) */
|
||||||
ci->func = restorestack(L, ci->extra);
|
ci->func = restorestack(L, ci->extra);
|
||||||
if (isLua(ci)) /* yielded inside a hook? */
|
if (isLua(ci)) /* yielded inside a hook? */
|
||||||
luaV_execute(L); /* just continue running Lua code */
|
luaV_execute(L); /* just continue running Lua code */
|
||||||
else { /* 'common' yield */
|
else { /* 'common' yield */
|
||||||
if (ci->u.c.k != NULL) { /* does it have a continuation function? */
|
if (ci->u.c.k != NULL) { /* does it have a continuation function? */
|
||||||
int n;
|
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */
|
n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
api_checknelems(L, n);
|
api_checknelems(L, n);
|
||||||
firstArg = L->top - n; /* yield results come from continuation */
|
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 */
|
unroll(L, NULL); /* run continuation */
|
||||||
}
|
}
|
||||||
lua_assert(nCcalls == L->nCcalls);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
|
LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
|
||||||
int status;
|
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);
|
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;
|
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 */
|
L->nny = 0; /* allow yields */
|
||||||
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
|
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'? */
|
if (status == -1) /* error calling 'lua_resume'? */
|
||||||
status = LUA_ERRRUN;
|
status = LUA_ERRRUN;
|
||||||
else { /* continue running after recoverable errors */
|
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;
|
L->status = LUA_YIELD;
|
||||||
ci->extra = savestack(L, ci->func); /* save current 'func' */
|
ci->extra = savestack(L, ci->func); /* save current 'func' */
|
||||||
if (isLua(ci)) { /* inside a hook? */
|
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 {
|
else {
|
||||||
if ((ci->u.c.k = k) != NULL) /* is there a continuation? */
|
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 */
|
int c = zgetc(p->z); /* read first character */
|
||||||
if (c == LUA_SIGNATURE[0]) {
|
if (c == LUA_SIGNATURE[0]) {
|
||||||
checkmode(L, p->mode, "binary");
|
checkmode(L, p->mode, "binary");
|
||||||
cl = luaU_undump(L, p->z, &p->buff, p->name);
|
cl = luaU_undump(L, p->z, p->name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
checkmode(L, p->mode, "text");
|
checkmode(L, p->mode, "text");
|
||||||
|
|
26
src/ldo.h
26
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
|
** Stack and Call structure of Lua
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -13,11 +13,21 @@
|
||||||
#include "lzio.h"
|
#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 savestack(L,p) ((char *)(p) - (char *)L->stack)
|
||||||
#define restorestack(L,n) ((TValue *)((char *)L->stack + (n)))
|
#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);
|
const char *mode);
|
||||||
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line);
|
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 int luaD_precall (lua_State *L, StkId func, int nresults);
|
||||||
LUAI_FUNC void luaD_call (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_callnoyield (lua_State *L, StkId func, int nResults);
|
||||||
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
|
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
|
||||||
ptrdiff_t oldtop, ptrdiff_t ef);
|
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_reallocstack (lua_State *L, int newsize);
|
||||||
LUAI_FUNC void luaD_growstack (lua_State *L, int n);
|
LUAI_FUNC void luaD_growstack (lua_State *L, int n);
|
||||||
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
|
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 l_noret luaD_throw (lua_State *L, int errcode);
|
||||||
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
|
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
|
||||||
|
|
|
@ -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
|
** save precompiled Lua chunks
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -38,7 +38,7 @@ typedef struct {
|
||||||
|
|
||||||
|
|
||||||
static void DumpBlock (const void *b, size_t size, DumpState *D) {
|
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);
|
lua_unlock(D->L);
|
||||||
D->status = (*D->writer)(D->L, b, size, D->data);
|
D->status = (*D->writer)(D->L, b, size, D->data);
|
||||||
lua_lock(D->L);
|
lua_lock(D->L);
|
||||||
|
@ -74,14 +74,15 @@ static void DumpString (const TString *s, DumpState *D) {
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
DumpByte(0, D);
|
DumpByte(0, D);
|
||||||
else {
|
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)
|
if (size < 0xFF)
|
||||||
DumpByte(cast_int(size), D);
|
DumpByte(cast_int(size), D);
|
||||||
else {
|
else {
|
||||||
DumpByte(0xFF, D);
|
DumpByte(0xFF, D);
|
||||||
DumpVar(size, 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' */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
** Auxiliary functions to manipulate prototypes and closures
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -22,6 +22,13 @@
|
||||||
#define isintwups(L) (L->twups != L)
|
#define isintwups(L) (L->twups != L)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 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
|
** Upvalues for Lua closures
|
||||||
*/
|
*/
|
||||||
|
|
103
src/lgc.c
103
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
|
** Garbage Collector
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -83,8 +83,13 @@
|
||||||
#define markvalue(g,o) { checkconsistency(o); \
|
#define markvalue(g,o) { checkconsistency(o); \
|
||||||
if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }
|
if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }
|
||||||
|
|
||||||
#define markobject(g,t) \
|
#define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); }
|
||||||
{ if ((t) && 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);
|
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
|
** If key is not marked, mark its entry as dead. This allows key to be
|
||||||
** from the table)
|
** 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) {
|
static void removeentry (Node *n) {
|
||||||
lua_assert(ttisnil(gval(n)));
|
lua_assert(ttisnil(gval(n)));
|
||||||
|
@ -226,15 +236,19 @@ static void reallymarkobject (global_State *g, GCObject *o) {
|
||||||
reentry:
|
reentry:
|
||||||
white2gray(o);
|
white2gray(o);
|
||||||
switch (o->tt) {
|
switch (o->tt) {
|
||||||
case LUA_TSHRSTR:
|
case LUA_TSHRSTR: {
|
||||||
|
gray2black(o);
|
||||||
|
g->GCmemtrav += sizelstring(gco2ts(o)->shrlen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case LUA_TLNGSTR: {
|
case LUA_TLNGSTR: {
|
||||||
gray2black(o);
|
gray2black(o);
|
||||||
g->GCmemtrav += sizestring(gco2ts(o));
|
g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LUA_TUSERDATA: {
|
case LUA_TUSERDATA: {
|
||||||
TValue uvalue;
|
TValue uvalue;
|
||||||
markobject(g, gco2u(o)->metatable); /* mark its metatable */
|
markobjectN(g, gco2u(o)->metatable); /* mark its metatable */
|
||||||
gray2black(o);
|
gray2black(o);
|
||||||
g->GCmemtrav += sizeudata(gco2u(o));
|
g->GCmemtrav += sizeudata(gco2u(o));
|
||||||
getuservalue(g->mainthread, gco2u(o), &uvalue);
|
getuservalue(g->mainthread, gco2u(o), &uvalue);
|
||||||
|
@ -275,7 +289,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
|
||||||
static void markmt (global_State *g) {
|
static void markmt (global_State *g) {
|
||||||
int i;
|
int i;
|
||||||
for (i=0; i < LUA_NUMTAGS; 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) {
|
static lu_mem traversetable (global_State *g, Table *h) {
|
||||||
const char *weakkey, *weakvalue;
|
const char *weakkey, *weakvalue;
|
||||||
const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
|
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? */
|
if (mode && ttisstring(mode) && /* is there a weak mode? */
|
||||||
((weakkey = strchr(svalue(mode), 'k')),
|
((weakkey = strchr(svalue(mode), 'k')),
|
||||||
(weakvalue = strchr(svalue(mode), 'v')),
|
(weakvalue = strchr(svalue(mode), 'v')),
|
||||||
|
@ -453,23 +467,28 @@ static lu_mem traversetable (global_State *g, Table *h) {
|
||||||
else /* not weak */
|
else /* not weak */
|
||||||
traversestrongtable(g, h);
|
traversestrongtable(g, h);
|
||||||
return sizeof(Table) + sizeof(TValue) * h->sizearray +
|
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) {
|
static int traverseproto (global_State *g, Proto *f) {
|
||||||
int i;
|
int i;
|
||||||
if (f->cache && iswhite(f->cache))
|
if (f->cache && iswhite(f->cache))
|
||||||
f->cache = NULL; /* allow cache to be collected */
|
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 */
|
for (i = 0; i < f->sizek; i++) /* mark literals */
|
||||||
markvalue(g, &f->k[i]);
|
markvalue(g, &f->k[i]);
|
||||||
for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */
|
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 */
|
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 */
|
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 +
|
return sizeof(Proto) + sizeof(Instruction) * f->sizecode +
|
||||||
sizeof(Proto *) * f->sizep +
|
sizeof(Proto *) * f->sizep +
|
||||||
sizeof(TValue) * f->sizek +
|
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) {
|
static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
|
||||||
int i;
|
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 */
|
for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */
|
||||||
UpVal *uv = cl->upvals[i];
|
UpVal *uv = cl->upvals[i];
|
||||||
if (uv != NULL) {
|
if (uv != NULL) {
|
||||||
|
@ -528,7 +547,8 @@ static lu_mem traversethread (global_State *g, lua_State *th) {
|
||||||
}
|
}
|
||||||
else if (g->gckind != KGC_EMERGENCY)
|
else if (g->gckind != KGC_EMERGENCY)
|
||||||
luaD_shrinkstack(th); /* do not change stack in emergency cycle */
|
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_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;
|
||||||
case LUA_TSHRSTR:
|
case LUA_TSHRSTR:
|
||||||
luaS_remove(L, gco2ts(o)); /* remove it from hash table */
|
luaS_remove(L, gco2ts(o)); /* remove it from hash table */
|
||||||
/* go through */
|
luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen));
|
||||||
|
break;
|
||||||
case LUA_TLNGSTR: {
|
case LUA_TLNGSTR: {
|
||||||
luaM_freemem(L, o, sizestring(gco2ts(o)));
|
luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: lua_assert(0);
|
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)
|
** 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;
|
GCObject **old = p;
|
||||||
int i = 0;
|
|
||||||
do {
|
do {
|
||||||
i++;
|
|
||||||
p = sweeplist(L, p, 1);
|
p = sweeplist(L, p, 1);
|
||||||
} while (p == old);
|
} while (p == old);
|
||||||
if (n) *n += i;
|
|
||||||
return p;
|
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) {
|
static void checkSizes (lua_State *L, global_State *g) {
|
||||||
if (g->gckind != KGC_EMERGENCY) {
|
if (g->gckind != KGC_EMERGENCY) {
|
||||||
l_mem olddebt = g->GCdebt;
|
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? */
|
if (g->strt.nuse < g->strt.size / 4) /* string table too big? */
|
||||||
luaS_resize(L, g->strt.size / 2); /* shrink it a little */
|
luaS_resize(L, g->strt.size / 2); /* shrink it a little */
|
||||||
g->GCestimate += g->GCdebt - olddebt; /* update estimate */
|
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) {
|
static void dothecall (lua_State *L, void *ud) {
|
||||||
UNUSED(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, tm); /* push finalizer... */
|
||||||
setobj2s(L, L->top + 1, &v); /* ... and its argument */
|
setobj2s(L, L->top + 1, &v); /* ... and its argument */
|
||||||
L->top += 2; /* and (next line) call the finalizer */
|
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);
|
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 */
|
L->allowhook = oldah; /* restore hooks */
|
||||||
g->gcrunning = running; /* restore state */
|
g->gcrunning = running; /* restore state */
|
||||||
if (status != LUA_OK && propagateerrors) { /* error while running __gc? */
|
if (status != LUA_OK && propagateerrors) { /* error while running __gc? */
|
||||||
|
@ -836,10 +855,10 @@ static int runafewfinalizers (lua_State *L) {
|
||||||
/*
|
/*
|
||||||
** call all pending finalizers
|
** call all pending finalizers
|
||||||
*/
|
*/
|
||||||
static void callallpendingfinalizers (lua_State *L, int propagateerrors) {
|
static void callallpendingfinalizers (lua_State *L) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
while (g->tobefnz)
|
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)) {
|
if (issweepphase(g)) {
|
||||||
makewhite(g, o); /* "sweep" object 'o' */
|
makewhite(g, o); /* "sweep" object 'o' */
|
||||||
if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */
|
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' */
|
/* search for pointer pointing to 'o' */
|
||||||
for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ }
|
for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ }
|
||||||
|
@ -931,19 +950,16 @@ static void setpause (global_State *g) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Enter first sweep phase.
|
** Enter first sweep phase.
|
||||||
** The call to 'sweeptolive' makes pointer point to an object inside
|
** The call to 'sweeplist' tries to make pointer point to an object
|
||||||
** the list (instead of to the header), so that the real sweep do not
|
** inside the list (instead of to the header), so that the real sweep do
|
||||||
** need to skip objects created between "now" and the start of the real
|
** not need to skip objects created between "now" and the start of the
|
||||||
** sweep.
|
** real sweep.
|
||||||
** Returns how many objects it swept.
|
|
||||||
*/
|
*/
|
||||||
static int entersweep (lua_State *L) {
|
static void entersweep (lua_State *L) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
int n = 0;
|
|
||||||
g->gcstate = GCSswpallgc;
|
g->gcstate = GCSswpallgc;
|
||||||
lua_assert(g->sweepgc == NULL);
|
lua_assert(g->sweepgc == NULL);
|
||||||
g->sweepgc = sweeptolive(L, &g->allgc, &n);
|
g->sweepgc = sweeplist(L, &g->allgc, 1);
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -951,7 +967,7 @@ void luaC_freeallobjects (lua_State *L) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
separatetobefnz(g, 1); /* separate all objects with finalizers */
|
separatetobefnz(g, 1); /* separate all objects with finalizers */
|
||||||
lua_assert(g->finobj == NULL);
|
lua_assert(g->finobj == NULL);
|
||||||
callallpendingfinalizers(L, 0);
|
callallpendingfinalizers(L);
|
||||||
lua_assert(g->tobefnz == NULL);
|
lua_assert(g->tobefnz == NULL);
|
||||||
g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */
|
g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */
|
||||||
g->gckind = KGC_NORMAL;
|
g->gckind = KGC_NORMAL;
|
||||||
|
@ -1002,6 +1018,7 @@ static l_mem atomic (lua_State *L) {
|
||||||
/* clear values from resurrected weak tables */
|
/* clear values from resurrected weak tables */
|
||||||
clearvalues(g, g->weak, origweak);
|
clearvalues(g, g->weak, origweak);
|
||||||
clearvalues(g, g->allweak, origall);
|
clearvalues(g, g->allweak, origall);
|
||||||
|
luaS_clearcache(g);
|
||||||
g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
|
g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
|
||||||
work += g->GCmemtrav; /* complete counting */
|
work += g->GCmemtrav; /* complete counting */
|
||||||
return work; /* estimate of memory marked by 'atomic' */
|
return work; /* estimate of memory marked by 'atomic' */
|
||||||
|
@ -1043,12 +1060,11 @@ static lu_mem singlestep (lua_State *L) {
|
||||||
}
|
}
|
||||||
case GCSatomic: {
|
case GCSatomic: {
|
||||||
lu_mem work;
|
lu_mem work;
|
||||||
int sw;
|
|
||||||
propagateall(g); /* make sure gray list is empty */
|
propagateall(g); /* make sure gray list is empty */
|
||||||
work = atomic(L); /* work is what was traversed by 'atomic' */
|
work = atomic(L); /* work is what was traversed by 'atomic' */
|
||||||
sw = entersweep(L);
|
entersweep(L);
|
||||||
g->GCestimate = gettotalbytes(g); /* first estimate */;
|
g->GCestimate = gettotalbytes(g); /* first estimate */;
|
||||||
return work + sw * GCSWEEPCOST;
|
return work;
|
||||||
}
|
}
|
||||||
case GCSswpallgc: { /* sweep "regular" objects */
|
case GCSswpallgc: { /* sweep "regular" objects */
|
||||||
return sweepstep(L, g, GCSswpfinobj, &g->finobj);
|
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) {
|
static l_mem getdebt (global_State *g) {
|
||||||
l_mem debt = g->GCdebt;
|
l_mem debt = g->GCdebt;
|
||||||
int stepmul = g->gcstepmul;
|
int stepmul = g->gcstepmul;
|
||||||
|
if (debt <= 0) return 0; /* minimal debt */
|
||||||
|
else {
|
||||||
debt = (debt / STEPMULADJ) + 1;
|
debt = (debt / STEPMULADJ) + 1;
|
||||||
debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
|
debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
|
||||||
return debt;
|
return debt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
41
src/lgc.h
41
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
|
** Garbage Collector
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -101,26 +101,35 @@
|
||||||
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
|
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
|
||||||
|
|
||||||
|
|
||||||
#define luaC_condGC(L,c) \
|
/*
|
||||||
{if (G(L)->GCdebt > 0) {c;}; condchangemem(L);}
|
** Does one step of collection when debt becomes positive. 'pre'/'pos'
|
||||||
#define luaC_checkGC(L) luaC_condGC(L, luaC_step(L);)
|
** 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) { \
|
#define luaC_barrier(L,p,v) ( \
|
||||||
if (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) \
|
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
|
||||||
luaC_barrier_(L,obj2gco(p),gcvalue(v)); }
|
luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
|
||||||
|
|
||||||
#define luaC_barrierback(L,p,v) { \
|
#define luaC_barrierback(L,p,v) ( \
|
||||||
if (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) \
|
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
|
||||||
luaC_barrierback_(L,p); }
|
luaC_barrierback_(L,p) : cast_void(0))
|
||||||
|
|
||||||
#define luaC_objbarrier(L,p,o) { \
|
#define luaC_objbarrier(L,p,o) ( \
|
||||||
if (isblack(p) && iswhite(o)) \
|
(isblack(p) && iswhite(o)) ? \
|
||||||
luaC_barrier_(L,obj2gco(p),obj2gco(o)); }
|
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
|
||||||
|
|
||||||
#define luaC_upvalbarrier(L,uv) \
|
#define luaC_upvalbarrier(L,uv) ( \
|
||||||
{ if (iscollectable((uv)->v) && !upisopen(uv)) \
|
(iscollectable((uv)->v) && !upisopen(uv)) ? \
|
||||||
luaC_upvalbarrier_(L,uv); }
|
luaC_upvalbarrier_(L,uv) : cast_void(0))
|
||||||
|
|
||||||
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
|
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
|
||||||
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
|
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
|
||||||
|
|
|
@ -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
|
** Initialization of libraries for lua.c and other clients
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -18,10 +18,10 @@
|
||||||
** open the library, which is already linked to the application.
|
** open the library, which is already linked to the application.
|
||||||
** For that, do the following code:
|
** 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_pushcfunction(L, luaopen_modname);
|
||||||
** lua_setfield(L, -2, modname);
|
** lua_setfield(L, -2, modname);
|
||||||
** lua_pop(L, 1); // remove _PRELOAD table
|
** lua_pop(L, 1); // remove PRELOAD table
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
70
src/liolib.c
70
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
|
** Standard I/O (and system) library
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -23,18 +23,25 @@
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
|
||||||
|
|
||||||
#if !defined(l_checkmode)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Check whether 'mode' matches '[rwa]%+?b?'.
|
|
||||||
** Change this macro to accept other modes for 'fopen' besides
|
** Change this macro to accept other modes for 'fopen' besides
|
||||||
** the standard ones.
|
** the standard ones.
|
||||||
*/
|
*/
|
||||||
#define l_checkmode(mode) \
|
#if !defined(l_checkmode)
|
||||||
(*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \
|
|
||||||
(*mode != '+' || ++mode) && /* skip if char is '+' */ \
|
/* accepted extensions to 'mode' in 'fopen' */
|
||||||
(*mode != 'b' || ++mode) && /* skip if char is 'b' */ \
|
#if !defined(L_MODEEXT)
|
||||||
(*mode == '\0'))
|
#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
|
#endif
|
||||||
|
|
||||||
|
@ -176,7 +183,7 @@ static FILE *tofile (lua_State *L) {
|
||||||
/*
|
/*
|
||||||
** When creating file handles, always creates a 'closed' file handle
|
** When creating file handles, always creates a 'closed' file handle
|
||||||
** before opening the actual file; so, if there is a memory error, the
|
** 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) {
|
static LStream *newprefile (lua_State *L) {
|
||||||
LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream));
|
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);
|
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) {
|
static void aux_lines (lua_State *L, int toclose) {
|
||||||
int n = lua_gettop(L) - 1; /* number of arguments to read */
|
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_pushinteger(L, n); /* number of arguments to read */
|
||||||
lua_pushboolean(L, toclose); /* close/not close file when finished */
|
lua_pushboolean(L, toclose); /* close/not close file when finished */
|
||||||
lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */
|
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 */
|
/* maximum length of a numeral */
|
||||||
#define MAXRN 200
|
#if !defined (L_MAXLENNUM)
|
||||||
|
#define L_MAXLENNUM 200
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* auxiliary structure used by 'read_number' */
|
/* auxiliary structure used by 'read_number' */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FILE *f; /* file being read */
|
FILE *f; /* file being read */
|
||||||
int c; /* current character (look ahead) */
|
int c; /* current character (look ahead) */
|
||||||
int n; /* number of elements in buffer 'buff' */
|
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;
|
} RN;
|
||||||
|
|
||||||
|
|
||||||
|
@ -377,7 +394,7 @@ typedef struct {
|
||||||
** Add current char to buffer (if not out of space) and read next one
|
** Add current char to buffer (if not out of space) and read next one
|
||||||
*/
|
*/
|
||||||
static int nextc (RN *rn) {
|
static int nextc (RN *rn) {
|
||||||
if (rn->n >= MAXRN) { /* buffer overflow? */
|
if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */
|
||||||
rn->buff[0] = '\0'; /* invalidate result */
|
rn->buff[0] = '\0'; /* invalidate result */
|
||||||
return 0; /* fail */
|
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) {
|
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);
|
return nextc(rn);
|
||||||
else return 0;
|
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.
|
** 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
|
** 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;
|
RN rn;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int hex = 0;
|
int hex = 0;
|
||||||
char decp[2] = ".";
|
char decp[2];
|
||||||
rn.f = f; rn.n = 0;
|
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);
|
l_lockfile(rn.f);
|
||||||
do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */
|
do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */
|
||||||
test2(&rn, "-+"); /* optional signal */
|
test2(&rn, "-+"); /* optional signal */
|
||||||
if (test2(&rn, "0")) {
|
if (test2(&rn, "00")) {
|
||||||
if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */
|
if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */
|
||||||
else count = 1; /* count initial '0' as a valid digit */
|
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) {
|
static int test_eof (lua_State *L, FILE *f) {
|
||||||
int c = getc(f);
|
int c = getc(f);
|
||||||
ungetc(c, f); /* no-op when c == EOF */
|
ungetc(c, f); /* no-op when c == EOF */
|
||||||
lua_pushlstring(L, NULL, 0);
|
lua_pushliteral(L, "");
|
||||||
return (c != EOF);
|
return (c != EOF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,7 +479,7 @@ static int read_line (lua_State *L, FILE *f, int chop) {
|
||||||
int c = '\0';
|
int c = '\0';
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
while (c != EOF && c != '\n') { /* repeat until end of line */
|
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;
|
int i = 0;
|
||||||
l_lockfile(f); /* no memory errors can happen inside the lock */
|
l_lockfile(f); /* no memory errors can happen inside the lock */
|
||||||
while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n')
|
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_Buffer b;
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
do { /* read file in chunks of LUAL_BUFFERSIZE bytes */
|
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);
|
nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f);
|
||||||
luaL_addsize(&b, nr);
|
luaL_addsize(&b, nr);
|
||||||
} while (nr == LUAL_BUFFERSIZE);
|
} 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) {
|
if (lua_type(L, arg) == LUA_TNUMBER) {
|
||||||
/* optimization: could be done exactly as for strings */
|
/* optimization: could be done exactly as for strings */
|
||||||
int len = lua_isinteger(L, arg)
|
int len = lua_isinteger(L, arg)
|
||||||
? fprintf(f, LUA_INTEGER_FMT, lua_tointeger(L, arg))
|
? fprintf(f, LUA_INTEGER_FMT,
|
||||||
: fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg));
|
(LUAI_UACINT)lua_tointeger(L, arg))
|
||||||
|
: fprintf(f, LUA_NUMBER_FMT,
|
||||||
|
(LUAI_UACNUMBER)lua_tonumber(L, arg));
|
||||||
status = status && (len > 0);
|
status = status && (len > 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
63
src/llex.c
63
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
|
** Lexical Analyzer
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -16,6 +16,7 @@
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
#include "lctype.h"
|
#include "lctype.h"
|
||||||
|
#include "ldebug.h"
|
||||||
#include "ldo.h"
|
#include "ldo.h"
|
||||||
#include "lgc.h"
|
#include "lgc.h"
|
||||||
#include "llex.h"
|
#include "llex.h"
|
||||||
|
@ -68,7 +69,7 @@ static void save (LexState *ls, int c) {
|
||||||
|
|
||||||
void luaX_init (lua_State *L) {
|
void luaX_init (lua_State *L) {
|
||||||
int i;
|
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 */
|
luaC_fix(L, obj2gco(e)); /* never collect this name */
|
||||||
for (i=0; i<NUM_RESERVED; i++) {
|
for (i=0; i<NUM_RESERVED; i++) {
|
||||||
TString *ts = luaS_new(L, luaX_tokens[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) {
|
static l_noret lexerror (LexState *ls, const char *msg, int token) {
|
||||||
char buff[LUA_IDSIZE];
|
msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber);
|
||||||
luaO_chunkid(buff, getstr(ls->source), LUA_IDSIZE);
|
|
||||||
msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg);
|
|
||||||
if (token)
|
if (token)
|
||||||
luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token));
|
luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token));
|
||||||
luaD_throw(ls->L, LUA_ERRSYNTAX);
|
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,
|
void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
|
||||||
int firstchar) {
|
int firstchar) {
|
||||||
ls->t.token = 0;
|
ls->t.token = 0;
|
||||||
ls->decpoint = '.';
|
|
||||||
ls->L = L;
|
ls->L = L;
|
||||||
ls->current = firstchar;
|
ls->current = firstchar;
|
||||||
ls->lookahead.token = TK_EOS; /* no look-ahead token */
|
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->linenumber = 1;
|
||||||
ls->lastline = 1;
|
ls->lastline = 1;
|
||||||
ls->source = source;
|
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 */
|
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 */
|
/* LUA_NUMBER */
|
||||||
/*
|
/*
|
||||||
** this function is quite liberal in what it accepts, as 'luaO_str2num'
|
** 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;
|
else break;
|
||||||
}
|
}
|
||||||
save(ls, '\0');
|
save(ls, '\0');
|
||||||
buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
|
if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */
|
||||||
if (!buff2num(ls->buff, &obj)) /* format error? */
|
lexerror(ls, "malformed number", TK_FLT);
|
||||||
trydecpoint(ls, &obj); /* try to update decimal point separator */
|
|
||||||
if (ttisinteger(&obj)) {
|
if (ttisinteger(&obj)) {
|
||||||
seminfo->i = ivalue(&obj);
|
seminfo->i = ivalue(&obj);
|
||||||
return TK_INT;
|
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
|
** skip a sequence '[=*[' or ']=*]'; if sequence is well formed, return
|
||||||
** -1 if sequence is malformed
|
** its number of '='s; otherwise, return a negative number (-1 iff there
|
||||||
|
** are no '='s after initial bracket)
|
||||||
*/
|
*/
|
||||||
static int skip_sep (LexState *ls) {
|
static int skip_sep (LexState *ls) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -501,8 +463,9 @@ static int llex (LexState *ls, SemInfo *seminfo) {
|
||||||
read_long_string(ls, seminfo, sep);
|
read_long_string(ls, seminfo, sep);
|
||||||
return TK_STRING;
|
return TK_STRING;
|
||||||
}
|
}
|
||||||
else if (sep == -1) return '[';
|
else if (sep != -1) /* '[=...' missing second bracket */
|
||||||
else lexerror(ls, "invalid long string delimiter", TK_STRING);
|
lexerror(ls, "invalid long string delimiter", TK_STRING);
|
||||||
|
return '[';
|
||||||
}
|
}
|
||||||
case '=': {
|
case '=': {
|
||||||
next(ls);
|
next(ls);
|
||||||
|
|
|
@ -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
|
** Lexical Analyzer
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -69,7 +69,6 @@ typedef struct LexState {
|
||||||
struct Dyndata *dyd; /* dynamic structures used by the parser */
|
struct Dyndata *dyd; /* dynamic structures used by the parser */
|
||||||
TString *source; /* current source name */
|
TString *source; /* current source name */
|
||||||
TString *envn; /* environment variable name */
|
TString *envn; /* environment variable name */
|
||||||
char decpoint; /* locale decimal point */
|
|
||||||
} LexState;
|
} LexState;
|
||||||
|
|
||||||
|
|
||||||
|
|
131
src/llimits.h
131
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
|
** Limits, basic types, and some other 'installation-dependent' definitions
|
||||||
** See Copyright Notice in lua.h
|
** 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
|
** this is for hashing only; there is no problem if the integer
|
||||||
** cannot hold the whole pointer value
|
** 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)
|
#if defined(LUAI_USER_ALIGNMENT_T)
|
||||||
typedef LUAI_USER_ALIGNMENT_T L_Umaxalign;
|
typedef LUAI_USER_ALIGNMENT_T L_Umaxalign;
|
||||||
#else
|
#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
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,7 +84,7 @@ typedef LUAI_UACINT l_uacInt;
|
||||||
#if defined(lua_assert)
|
#if defined(lua_assert)
|
||||||
#define check_exp(c,e) (lua_assert(c), (e))
|
#define check_exp(c,e) (lua_assert(c), (e))
|
||||||
/* to avoid problems with conditions too long */
|
/* 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
|
#else
|
||||||
#define lua_assert(c) ((void)0)
|
#define lua_assert(c) ((void)0)
|
||||||
#define check_exp(c,e) (e)
|
#define check_exp(c,e) (e)
|
||||||
|
@ -88,22 +94,20 @@ typedef LUAI_UACINT l_uacInt;
|
||||||
/*
|
/*
|
||||||
** assertion for checking API calls
|
** assertion for checking API calls
|
||||||
*/
|
*/
|
||||||
#if defined(LUA_USE_APICHECK)
|
#if !defined(luai_apicheck)
|
||||||
#include <assert.h>
|
#define luai_apicheck(l,e) lua_assert(e)
|
||||||
#define luai_apicheck(e) assert(e)
|
|
||||||
#else
|
|
||||||
#define luai_apicheck(e) lua_assert(e)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define api_check(l,e,msg) luai_apicheck(l,(e) && msg)
|
||||||
#define api_check(e,msg) luai_apicheck((e) && msg)
|
|
||||||
|
|
||||||
|
|
||||||
|
/* macro to avoid warnings about unused variables */
|
||||||
#if !defined(UNUSED)
|
#if !defined(UNUSED)
|
||||||
#define UNUSED(x) ((void)(x)) /* to avoid warnings */
|
#define UNUSED(x) ((void)(x))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* type casts (a macro highlights casts in the code) */
|
||||||
#define cast(t, exp) ((t)(exp))
|
#define cast(t, exp) ((t)(exp))
|
||||||
|
|
||||||
#define cast_void(i) cast(void, (i))
|
#define cast_void(i) cast(void, (i))
|
||||||
|
@ -149,11 +153,6 @@ typedef LUAI_UACINT l_uacInt;
|
||||||
#define LUAI_MAXCCALLS 200
|
#define LUAI_MAXCCALLS 200
|
||||||
#endif
|
#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)
|
#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
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -181,11 +206,19 @@ typedef unsigned long Instruction;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** macros that are executed whenever program enters the Lua core
|
||||||
|
** ('lua_lock') and leaves the core ('lua_unlock')
|
||||||
|
*/
|
||||||
#if !defined(lua_lock)
|
#if !defined(lua_lock)
|
||||||
#define lua_lock(L) ((void) 0)
|
#define lua_lock(L) ((void) 0)
|
||||||
#define lua_unlock(L) ((void) 0)
|
#define lua_unlock(L) ((void) 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** macro executed during Lua functions at points where the
|
||||||
|
** function can yield.
|
||||||
|
*/
|
||||||
#if !defined(luai_threadyield)
|
#if !defined(luai_threadyield)
|
||||||
#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);}
|
#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);}
|
||||||
#endif
|
#endif
|
||||||
|
@ -222,21 +255,69 @@ 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
|
** macro to control inclusion of some hard tests on stack reallocation
|
||||||
*/
|
*/
|
||||||
#if !defined(HARDSTACKTESTS)
|
#if !defined(HARDSTACKTESTS)
|
||||||
#define condmovestack(L) ((void)0)
|
#define condmovestack(L,pre,pos) ((void)0)
|
||||||
#else
|
#else
|
||||||
/* realloc stack keeping its size */
|
/* 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
|
#endif
|
||||||
|
|
||||||
#if !defined(HARDMEMTESTS)
|
#if !defined(HARDMEMTESTS)
|
||||||
#define condchangemem(L) condmovestack(L)
|
#define condchangemem(L,pre,pos) ((void)0)
|
||||||
#else
|
#else
|
||||||
#define condchangemem(L) \
|
#define condchangemem(L,pre,pos) \
|
||||||
((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1)))
|
{ if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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
|
** Standard mathematical library
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
static int math_abs (lua_State *L) {
|
static int math_abs (lua_State *L) {
|
||||||
if (lua_isinteger(L, 1)) {
|
if (lua_isinteger(L, 1)) {
|
||||||
lua_Integer n = lua_tointeger(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);
|
lua_pushinteger(L, n);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -183,8 +183,14 @@ static int math_log (lua_State *L) {
|
||||||
res = l_mathop(log)(x);
|
res = l_mathop(log)(x);
|
||||||
else {
|
else {
|
||||||
lua_Number base = luaL_checknumber(L, 2);
|
lua_Number base = luaL_checknumber(L, 2);
|
||||||
if (base == 10.0) res = l_mathop(log10)(x);
|
#if !defined(LUA_USE_C89)
|
||||||
else res = l_mathop(log)(x)/l_mathop(log)(base);
|
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);
|
lua_pushnumber(L, res);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -270,7 +276,7 @@ static int math_random (lua_State *L) {
|
||||||
|
|
||||||
static int math_randomseed (lua_State *L) {
|
static int math_randomseed (lua_State *L) {
|
||||||
l_srand((unsigned int)(lua_Integer)luaL_checknumber(L, 1));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
** Interface to Memory Manager
|
||||||
** See Copyright Notice in lua.h
|
** 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
|
#endif
|
||||||
newblock = (*g->frealloc)(g->ud, block, osize, nsize);
|
newblock = (*g->frealloc)(g->ud, block, osize, nsize);
|
||||||
if (newblock == NULL && nsize > 0) {
|
if (newblock == NULL && nsize > 0) {
|
||||||
api_check( nsize > realosize,
|
lua_assert(nsize > realosize); /* cannot fail when shrinking a block */
|
||||||
"realloc cannot fail when shrinking a block");
|
if (g->version) { /* is state fully built? */
|
||||||
luaC_fullgc(L, 1); /* try to free some memory... */
|
luaC_fullgc(L, 1); /* try to free some memory... */
|
||||||
newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
|
newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
|
||||||
|
}
|
||||||
if (newblock == NULL)
|
if (newblock == NULL)
|
||||||
luaD_throw(L, LUA_ERRMEM);
|
luaD_throw(L, LUA_ERRMEM);
|
||||||
}
|
}
|
||||||
|
|
174
src/loadlib.c
174
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
|
** Dynamic library loader for Lua
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
**
|
**
|
||||||
|
@ -14,6 +14,7 @@
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.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
|
** LUA_IGMARK is a mark to ignore all before it when building the
|
||||||
** luaopen_ function name.
|
** 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)
|
#if !defined (LUA_IGMARK)
|
||||||
#define LUA_IGMARK "-"
|
#define LUA_IGMARK "-"
|
||||||
#endif
|
#endif
|
||||||
|
@ -93,6 +63,7 @@ static const int CLIBS = 0;
|
||||||
|
|
||||||
#define LIB_FAIL "open"
|
#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>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Macro to covert pointer to void* to pointer to function. This cast
|
** Macro to convert pointer-to-void* to pointer-to-function. This cast
|
||||||
** is undefined according to ISO C, but POSIX assumes that it must work.
|
** is undefined according to ISO C, but POSIX assumes that it works.
|
||||||
** (The '__extension__' in gnu compilers is only to avoid warnings.)
|
** (The '__extension__' in gnu compilers is only to avoid warnings.)
|
||||||
*/
|
*/
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
|
@ -178,7 +149,6 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#undef setprogdir
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** optional flags for LoadLibraryEx
|
** optional flags for LoadLibraryEx
|
||||||
|
@ -188,21 +158,30 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
|
||||||
#endif
|
#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) {
|
static void setprogdir (lua_State *L) {
|
||||||
char buff[MAX_PATH + 1];
|
char buff[MAX_PATH + 1];
|
||||||
char *lb;
|
char *lb;
|
||||||
DWORD nsize = sizeof(buff)/sizeof(char);
|
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)
|
if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL)
|
||||||
luaL_error(L, "unable to get ModuleFileName");
|
luaL_error(L, "unable to get ModuleFileName");
|
||||||
else {
|
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);
|
luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff);
|
||||||
lua_remove(L, -2); /* remove original string */
|
lua_remove(L, -2); /* remove original string */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void pusherror (lua_State *L) {
|
static void pusherror (lua_State *L) {
|
||||||
int error = GetLastError();
|
int error = GetLastError();
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
|
@ -271,6 +250,67 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** {==================================================================
|
||||||
|
** 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]
|
** return registry.CLIBS[path]
|
||||||
*/
|
*/
|
||||||
|
@ -519,7 +559,7 @@ static int searcher_Croot (lua_State *L) {
|
||||||
|
|
||||||
static int searcher_preload (lua_State *L) {
|
static int searcher_preload (lua_State *L) {
|
||||||
const char *name = luaL_checkstring(L, 1);
|
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? */
|
if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */
|
||||||
lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
|
lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -556,9 +596,9 @@ static void findloader (lua_State *L, const char *name) {
|
||||||
|
|
||||||
static int ll_require (lua_State *L) {
|
static int ll_require (lua_State *L) {
|
||||||
const char *name = luaL_checkstring(L, 1);
|
const char *name = luaL_checkstring(L, 1);
|
||||||
lua_settop(L, 1); /* _LOADED table will be at index 2 */
|
lua_settop(L, 1); /* LOADED table will be at index 2 */
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
|
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
|
||||||
lua_getfield(L, 2, name); /* _LOADED[name] */
|
lua_getfield(L, 2, name); /* LOADED[name] */
|
||||||
if (lua_toboolean(L, -1)) /* is it there? */
|
if (lua_toboolean(L, -1)) /* is it there? */
|
||||||
return 1; /* package is already loaded */
|
return 1; /* package is already loaded */
|
||||||
/* else must load package */
|
/* 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_insert(L, -2); /* name is 1st argument (before search data) */
|
||||||
lua_call(L, 2, 1); /* run loader to load module */
|
lua_call(L, 2, 1); /* run loader to load module */
|
||||||
if (!lua_isnil(L, -1)) /* non-nil return? */
|
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? */
|
if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */
|
||||||
lua_pushboolean(L, 1); /* use true as result */
|
lua_pushboolean(L, 1); /* use true as result */
|
||||||
lua_pushvalue(L, -1); /* extra copy to be returned */
|
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;
|
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[] = {
|
static const luaL_Reg pk_funcs[] = {
|
||||||
{"loadlib", ll_loadlib},
|
{"loadlib", ll_loadlib},
|
||||||
{"searchpath", ll_searchpath},
|
{"searchpath", ll_searchpath},
|
||||||
|
@ -731,7 +736,7 @@ static void createsearcherstable (lua_State *L) {
|
||||||
int i;
|
int i;
|
||||||
/* create 'searchers' table */
|
/* create 'searchers' table */
|
||||||
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
|
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++) {
|
for (i=0; searchers[i] != NULL; i++) {
|
||||||
lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */
|
lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */
|
||||||
lua_pushcclosure(L, searchers[i], 1);
|
lua_pushcclosure(L, searchers[i], 1);
|
||||||
|
@ -763,19 +768,18 @@ LUAMOD_API int luaopen_package (lua_State *L) {
|
||||||
createclibstable(L);
|
createclibstable(L);
|
||||||
luaL_newlib(L, pk_funcs); /* create 'package' table */
|
luaL_newlib(L, pk_funcs); /* create 'package' table */
|
||||||
createsearcherstable(L);
|
createsearcherstable(L);
|
||||||
/* set field 'path' */
|
/* set paths */
|
||||||
setpath(L, "path", LUA_PATHVARVERSION, LUA_PATH_VAR, LUA_PATH_DEFAULT);
|
setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT);
|
||||||
/* set field 'cpath' */
|
setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
|
||||||
setpath(L, "cpath", LUA_CPATHVARVERSION, LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
|
|
||||||
/* store config information */
|
/* store config information */
|
||||||
lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n"
|
lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n"
|
||||||
LUA_EXEC_DIR "\n" LUA_IGMARK "\n");
|
LUA_EXEC_DIR "\n" LUA_IGMARK "\n");
|
||||||
lua_setfield(L, -2, "config");
|
lua_setfield(L, -2, "config");
|
||||||
/* set field 'loaded' */
|
/* set field 'loaded' */
|
||||||
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
|
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
|
||||||
lua_setfield(L, -2, "loaded");
|
lua_setfield(L, -2, "loaded");
|
||||||
/* set field 'preload' */
|
/* set field 'preload' */
|
||||||
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
|
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
|
||||||
lua_setfield(L, -2, "preload");
|
lua_setfield(L, -2, "preload");
|
||||||
lua_pushglobaltable(L);
|
lua_pushglobaltable(L);
|
||||||
lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */
|
lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */
|
||||||
|
|
155
src/lobject.c
155
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
|
** Some generic functions over Lua objects
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -10,6 +10,8 @@
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <locale.h>
|
||||||
|
#include <math.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -39,8 +41,12 @@ LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT};
|
||||||
int luaO_int2fb (unsigned int x) {
|
int luaO_int2fb (unsigned int x) {
|
||||||
int e = 0; /* exponent */
|
int e = 0; /* exponent */
|
||||||
if (x < 8) return x;
|
if (x < 8) return x;
|
||||||
while (x >= 0x10) {
|
while (x >= (8 << 4)) { /* coarse steps */
|
||||||
x = (x+1) >> 1;
|
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++;
|
e++;
|
||||||
}
|
}
|
||||||
return ((e+1) << 3) | (cast_int(x) - 8);
|
return ((e+1) << 3) | (cast_int(x) - 8);
|
||||||
|
@ -49,14 +55,15 @@ int luaO_int2fb (unsigned int x) {
|
||||||
|
|
||||||
/* converts back */
|
/* converts back */
|
||||||
int luaO_fb2int (int x) {
|
int luaO_fb2int (int x) {
|
||||||
int e = (x >> 3) & 0x1f;
|
return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1);
|
||||||
if (e == 0) return x;
|
|
||||||
else return ((x & 7) + 8) << (e - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Computes ceil(log2(x))
|
||||||
|
*/
|
||||||
int luaO_ceillog2 (unsigned int 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,
|
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,
|
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,
|
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 */
|
/* could not perform raw operation; try metamethod */
|
||||||
lua_assert(L != NULL); /* should not fail when folding (compile time) */
|
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) {
|
int luaO_hexavalue (int c) {
|
||||||
if (lisdigit(c)) return c - '0';
|
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'
|
** 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
|
/* maximum number of significant digits to read (to avoid overflows
|
||||||
even with single floats) */
|
even with single floats) */
|
||||||
|
@ -185,21 +191,22 @@ static int isneg (const char **s) {
|
||||||
** C99 specification for 'strtod'
|
** C99 specification for 'strtod'
|
||||||
*/
|
*/
|
||||||
static lua_Number lua_strx2number (const char *s, char **endptr) {
|
static lua_Number lua_strx2number (const char *s, char **endptr) {
|
||||||
|
int dot = lua_getlocaledecpoint();
|
||||||
lua_Number r = 0.0; /* result (accumulator) */
|
lua_Number r = 0.0; /* result (accumulator) */
|
||||||
int sigdig = 0; /* number of significant digits */
|
int sigdig = 0; /* number of significant digits */
|
||||||
int nosigdig = 0; /* number of non-significant digits */
|
int nosigdig = 0; /* number of non-significant digits */
|
||||||
int e = 0; /* exponent correction */
|
int e = 0; /* exponent correction */
|
||||||
int neg; /* 1 if number is negative */
|
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 */
|
*endptr = cast(char *, s); /* nothing is valid yet */
|
||||||
while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */
|
while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */
|
||||||
neg = isneg(&s); /* check signal */
|
neg = isneg(&s); /* check signal */
|
||||||
if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */
|
if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */
|
||||||
return 0.0; /* invalid format (no '0x') */
|
return 0.0; /* invalid format (no '0x') */
|
||||||
for (s += 2; ; s++) { /* skip '0x' and read numeral */
|
for (s += 2; ; s++) { /* skip '0x' and read numeral */
|
||||||
if (*s == '.') {
|
if (*s == dot) {
|
||||||
if (dot) break; /* second dot? stop loop */
|
if (hasdot) break; /* second dot? stop loop */
|
||||||
else dot = 1;
|
else hasdot = 1;
|
||||||
}
|
}
|
||||||
else if (lisxdigit(cast_uchar(*s))) {
|
else if (lisxdigit(cast_uchar(*s))) {
|
||||||
if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */
|
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? */
|
else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */
|
||||||
r = (r * cast_num(16.0)) + luaO_hexavalue(*s);
|
r = (r * cast_num(16.0)) + luaO_hexavalue(*s);
|
||||||
else e++; /* too many digits; ignore, but still count for exponent */
|
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 */
|
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;
|
char *endptr;
|
||||||
if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */
|
*result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */
|
||||||
return NULL;
|
: lua_str2number(s, &endptr);
|
||||||
else if (strpbrk(s, "xX")) /* hex? */
|
if (endptr == s) return NULL; /* nothing recognized? */
|
||||||
*result = lua_strx2number(s, &endptr);
|
while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */
|
||||||
else
|
return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */
|
||||||
*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 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 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;
|
||||||
|
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) {
|
static const char *l_str2int (const char *s, lua_Integer *result) {
|
||||||
lua_Unsigned a = 0;
|
lua_Unsigned a = 0;
|
||||||
int empty = 1;
|
int empty = 1;
|
||||||
|
@ -266,7 +312,10 @@ static const char *l_str2int (const char *s, lua_Integer *result) {
|
||||||
}
|
}
|
||||||
else { /* decimal */
|
else { /* decimal */
|
||||||
for (; lisdigit(cast_uchar(*s)); s++) {
|
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;
|
empty = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -290,7 +339,7 @@ size_t luaO_str2num (const char *s, TValue *o) {
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return 0; /* conversion failed */
|
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;
|
size_t len;
|
||||||
lua_assert(ttisnumber(obj));
|
lua_assert(ttisnumber(obj));
|
||||||
if (ttisinteger(obj))
|
if (ttisinteger(obj))
|
||||||
len = lua_integer2str(buff, ivalue(obj));
|
len = lua_integer2str(buff, sizeof(buff), ivalue(obj));
|
||||||
else {
|
else {
|
||||||
len = lua_number2str(buff, fltvalue(obj));
|
len = lua_number2str(buff, sizeof(buff), fltvalue(obj));
|
||||||
#if !defined(LUA_COMPAT_FLOATSTRING)
|
#if !defined(LUA_COMPAT_FLOATSTRING)
|
||||||
if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */
|
if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */
|
||||||
buff[len++] = '.';
|
buff[len++] = lua_getlocaledecpoint();
|
||||||
buff[len++] = '0'; /* adds '.0' to result */
|
buff[len++] = '0'; /* adds '.0' to result */
|
||||||
}
|
}
|
||||||
#endif
|
#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) {
|
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) {
|
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const char *e = strchr(fmt, '%');
|
const char *e = strchr(fmt, '%');
|
||||||
if (e == NULL) break;
|
if (e == NULL) break;
|
||||||
luaD_checkstack(L, 2); /* fmt + item */
|
|
||||||
pushstr(L, fmt, e - fmt);
|
pushstr(L, fmt, e - fmt);
|
||||||
switch (*(e+1)) {
|
switch (*(e+1)) {
|
||||||
case 's': {
|
case 's': { /* zero-terminated string */
|
||||||
const char *s = va_arg(argp, char *);
|
const char *s = va_arg(argp, char *);
|
||||||
if (s == NULL) s = "(null)";
|
if (s == NULL) s = "(null)";
|
||||||
pushstr(L, s, strlen(s));
|
pushstr(L, s, strlen(s));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'c': {
|
case 'c': { /* an 'int' as a character */
|
||||||
char buff = cast(char, va_arg(argp, int));
|
char buff = cast(char, va_arg(argp, int));
|
||||||
if (lisprint(cast_uchar(buff)))
|
if (lisprint(cast_uchar(buff)))
|
||||||
pushstr(L, &buff, 1);
|
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));
|
luaO_pushfstring(L, "<\\%d>", cast_uchar(buff));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'd': {
|
case 'd': { /* an 'int' */
|
||||||
setivalue(L->top++, va_arg(argp, int));
|
setivalue(L->top, va_arg(argp, int));
|
||||||
|
goto top2str;
|
||||||
|
}
|
||||||
|
case 'I': { /* a 'lua_Integer' */
|
||||||
|
setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt)));
|
||||||
|
goto top2str;
|
||||||
|
}
|
||||||
|
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);
|
luaO_tostring(L, L->top - 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'I': {
|
case 'p': { /* a pointer */
|
||||||
setivalue(L->top++, cast(lua_Integer, va_arg(argp, l_uacInt)));
|
|
||||||
luaO_tostring(L, L->top - 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'f': {
|
|
||||||
setfltvalue(L->top++, cast_num(va_arg(argp, l_uacNumber)));
|
|
||||||
luaO_tostring(L, L->top - 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'p': {
|
|
||||||
char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */
|
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);
|
pushstr(L, buff, l);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'U': {
|
case 'U': { /* an 'int' as a UTF-8 sequence */
|
||||||
char buff[UTF8BUFFSZ];
|
char buff[UTF8BUFFSZ];
|
||||||
int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long)));
|
int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long)));
|
||||||
pushstr(L, buff + UTF8BUFFSZ - l, l);
|
pushstr(L, buff + UTF8BUFFSZ - l, l);
|
||||||
|
|
115
src/lobject.h
115
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
|
** Type definitions for Lua objects
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -19,8 +19,8 @@
|
||||||
/*
|
/*
|
||||||
** Extra tags for non-values
|
** Extra tags for non-values
|
||||||
*/
|
*/
|
||||||
#define LUA_TPROTO LUA_NUMTAGS
|
#define LUA_TPROTO LUA_NUMTAGS /* function prototypes */
|
||||||
#define LUA_TDEADKEY (LUA_NUMTAGS+1)
|
#define LUA_TDEADKEY (LUA_NUMTAGS+1) /* removed keys in tables */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** number of all possible tags (including LUA_TNONE but excluding DEADKEY)
|
** number of all possible tags (including LUA_TNONE but excluding DEADKEY)
|
||||||
|
@ -35,8 +35,6 @@
|
||||||
** bit 6: whether value is collectable
|
** bit 6: whether value is collectable
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define VARBITS (3 << 4)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** LUA_TFUNCTION variants:
|
** 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,
|
** Tagged Values. This is the basic representation of values in Lua,
|
||||||
** an actual value plus a tag with its type.
|
** 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_
|
#define TValuefields Value value_; int tt_
|
||||||
|
|
||||||
typedef struct lua_TValue TValue;
|
|
||||||
|
typedef struct lua_TValue {
|
||||||
|
TValuefields;
|
||||||
|
} TValue;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* macro defining a nil value */
|
/* macro defining a nil value */
|
||||||
|
@ -179,9 +187,9 @@ typedef struct lua_TValue TValue;
|
||||||
/* Macros for internal tests */
|
/* Macros for internal tests */
|
||||||
#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt)
|
#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt)
|
||||||
|
|
||||||
#define checkliveness(g,obj) \
|
#define checkliveness(L,obj) \
|
||||||
lua_longassert(!iscollectable(obj) || \
|
lua_longassert(!iscollectable(obj) || \
|
||||||
(righttt(obj) && !isdead(g,gcvalue(obj))))
|
(righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj)))))
|
||||||
|
|
||||||
|
|
||||||
/* Macros to set values */
|
/* Macros to set values */
|
||||||
|
@ -190,9 +198,15 @@ typedef struct lua_TValue TValue;
|
||||||
#define setfltvalue(obj,x) \
|
#define setfltvalue(obj,x) \
|
||||||
{ TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_TNUMFLT); }
|
{ 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) \
|
#define setivalue(obj,x) \
|
||||||
{ TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); }
|
{ 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 setnilvalue(obj) settt_(obj, LUA_TNIL)
|
||||||
|
|
||||||
#define setfvalue(obj,x) \
|
#define setfvalue(obj,x) \
|
||||||
|
@ -211,32 +225,32 @@ typedef struct lua_TValue TValue;
|
||||||
#define setsvalue(L,obj,x) \
|
#define setsvalue(L,obj,x) \
|
||||||
{ TValue *io = (obj); TString *x_ = (x); \
|
{ TValue *io = (obj); TString *x_ = (x); \
|
||||||
val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \
|
val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \
|
||||||
checkliveness(G(L),io); }
|
checkliveness(L,io); }
|
||||||
|
|
||||||
#define setuvalue(L,obj,x) \
|
#define setuvalue(L,obj,x) \
|
||||||
{ TValue *io = (obj); Udata *x_ = (x); \
|
{ TValue *io = (obj); Udata *x_ = (x); \
|
||||||
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \
|
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \
|
||||||
checkliveness(G(L),io); }
|
checkliveness(L,io); }
|
||||||
|
|
||||||
#define setthvalue(L,obj,x) \
|
#define setthvalue(L,obj,x) \
|
||||||
{ TValue *io = (obj); lua_State *x_ = (x); \
|
{ TValue *io = (obj); lua_State *x_ = (x); \
|
||||||
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \
|
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \
|
||||||
checkliveness(G(L),io); }
|
checkliveness(L,io); }
|
||||||
|
|
||||||
#define setclLvalue(L,obj,x) \
|
#define setclLvalue(L,obj,x) \
|
||||||
{ TValue *io = (obj); LClosure *x_ = (x); \
|
{ TValue *io = (obj); LClosure *x_ = (x); \
|
||||||
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \
|
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \
|
||||||
checkliveness(G(L),io); }
|
checkliveness(L,io); }
|
||||||
|
|
||||||
#define setclCvalue(L,obj,x) \
|
#define setclCvalue(L,obj,x) \
|
||||||
{ TValue *io = (obj); CClosure *x_ = (x); \
|
{ TValue *io = (obj); CClosure *x_ = (x); \
|
||||||
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \
|
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \
|
||||||
checkliveness(G(L),io); }
|
checkliveness(L,io); }
|
||||||
|
|
||||||
#define sethvalue(L,obj,x) \
|
#define sethvalue(L,obj,x) \
|
||||||
{ TValue *io = (obj); Table *x_ = (x); \
|
{ TValue *io = (obj); Table *x_ = (x); \
|
||||||
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \
|
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \
|
||||||
checkliveness(G(L),io); }
|
checkliveness(L,io); }
|
||||||
|
|
||||||
#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY)
|
#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY)
|
||||||
|
|
||||||
|
@ -244,7 +258,7 @@ typedef struct lua_TValue TValue;
|
||||||
|
|
||||||
#define setobj(L,obj1,obj2) \
|
#define setobj(L,obj1,obj2) \
|
||||||
{ TValue *io1=(obj1); *io1 = *(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
|
#define setptvalue2s setptvalue
|
||||||
/* from table to same table */
|
/* from table to same table */
|
||||||
#define setobjt2t setobj
|
#define setobjt2t setobj
|
||||||
/* to table */
|
|
||||||
#define setobj2t setobj
|
|
||||||
/* to new object */
|
/* to new object */
|
||||||
#define setobj2n setobj
|
#define setobj2n setobj
|
||||||
#define setsvalue2n setsvalue
|
#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 */
|
typedef TValue *StkId; /* index to stack elements */
|
||||||
|
|
||||||
|
|
||||||
|
@ -303,9 +303,12 @@ typedef TValue *StkId; /* index to stack elements */
|
||||||
typedef struct TString {
|
typedef struct TString {
|
||||||
CommonHeader;
|
CommonHeader;
|
||||||
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
|
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
|
||||||
|
lu_byte shrlen; /* length for short strings */
|
||||||
unsigned int hash;
|
unsigned int hash;
|
||||||
size_t len; /* number of characters in string */
|
union {
|
||||||
|
size_t lnglen; /* length for long strings */
|
||||||
struct TString *hnext; /* linked list for hash table */
|
struct TString *hnext; /* linked list for hash table */
|
||||||
|
} u;
|
||||||
} TString;
|
} TString;
|
||||||
|
|
||||||
|
|
||||||
|
@ -322,13 +325,19 @@ typedef union UTString {
|
||||||
** Get the actual string (array of bytes) from a 'TString'.
|
** Get the actual string (array of bytes) from a 'TString'.
|
||||||
** (Access to 'extra' ensures that value is really a 'TString'.)
|
** (Access to 'extra' ensures that value is really a 'TString'.)
|
||||||
*/
|
*/
|
||||||
#define getaddrstr(ts) (cast(char *, (ts)) + sizeof(UTString))
|
|
||||||
#define getstr(ts) \
|
#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 */
|
/* get the actual string (array of bytes) from a Lua value */
|
||||||
#define svalue(o) getstr(tsvalue(o))
|
#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
|
** Header for userdata; memory area follows the end of this structure
|
||||||
|
@ -361,14 +370,14 @@ typedef union UUdata {
|
||||||
|
|
||||||
#define setuservalue(L,u,o) \
|
#define setuservalue(L,u,o) \
|
||||||
{ const TValue *io=(o); Udata *iu = (u); \
|
{ const TValue *io=(o); Udata *iu = (u); \
|
||||||
iu->user_ = io->value_; iu->ttuv_ = io->tt_; \
|
iu->user_ = io->value_; iu->ttuv_ = rttype(io); \
|
||||||
checkliveness(G(L),io); }
|
checkliveness(L,io); }
|
||||||
|
|
||||||
|
|
||||||
#define getuservalue(L,u,o) \
|
#define getuservalue(L,u,o) \
|
||||||
{ TValue *io=(o); const Udata *iu = (u); \
|
{ TValue *io=(o); const Udata *iu = (u); \
|
||||||
io->value_ = iu->user_; io->tt_ = iu->ttuv_; \
|
io->value_ = iu->user_; settt_(io, iu->ttuv_); \
|
||||||
checkliveness(G(L),io); }
|
checkliveness(L,io); }
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -376,7 +385,7 @@ typedef union UUdata {
|
||||||
*/
|
*/
|
||||||
typedef struct Upvaldesc {
|
typedef struct Upvaldesc {
|
||||||
TString *name; /* upvalue name (for debug information) */
|
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) */
|
lu_byte idx; /* index of upvalue (in stack or in outer function's list) */
|
||||||
} Upvaldesc;
|
} Upvaldesc;
|
||||||
|
|
||||||
|
@ -399,22 +408,22 @@ typedef struct Proto {
|
||||||
CommonHeader;
|
CommonHeader;
|
||||||
lu_byte numparams; /* number of fixed parameters */
|
lu_byte numparams; /* number of fixed parameters */
|
||||||
lu_byte is_vararg;
|
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 sizeupvalues; /* size of 'upvalues' */
|
||||||
int sizek; /* size of 'k' */
|
int sizek; /* size of 'k' */
|
||||||
int sizecode;
|
int sizecode;
|
||||||
int sizelineinfo;
|
int sizelineinfo;
|
||||||
int sizep; /* size of 'p' */
|
int sizep; /* size of 'p' */
|
||||||
int sizelocvars;
|
int sizelocvars;
|
||||||
int linedefined;
|
int linedefined; /* debug information */
|
||||||
int lastlinedefined;
|
int lastlinedefined; /* debug information */
|
||||||
TValue *k; /* constants used by the function */
|
TValue *k; /* constants used by the function */
|
||||||
Instruction *code;
|
Instruction *code; /* opcodes */
|
||||||
struct Proto **p; /* functions defined inside the function */
|
struct Proto **p; /* functions defined inside the function */
|
||||||
int *lineinfo; /* map from opcodes to source lines (debug information) */
|
int *lineinfo; /* map from opcodes to source lines (debug information) */
|
||||||
LocVar *locvars; /* information about local variables (debug information) */
|
LocVar *locvars; /* information about local variables (debug information) */
|
||||||
Upvaldesc *upvalues; /* upvalue 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 */
|
TString *source; /* used for debug information */
|
||||||
GCObject *gclist;
|
GCObject *gclist;
|
||||||
} Proto;
|
} Proto;
|
||||||
|
@ -476,7 +485,7 @@ typedef union TKey {
|
||||||
#define setnodekey(L,key,obj) \
|
#define setnodekey(L,key,obj) \
|
||||||
{ TKey *k_=(key); const TValue *io_=(obj); \
|
{ TKey *k_=(key); const TValue *io_=(obj); \
|
||||||
k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \
|
k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \
|
||||||
(void)L; checkliveness(G(L),io_); }
|
(void)L; checkliveness(L,io_); }
|
||||||
|
|
||||||
|
|
||||||
typedef struct Node {
|
typedef struct Node {
|
||||||
|
|
|
@ -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
|
** Opcodes for Lua virtual machine
|
||||||
** See Copyright Notice in lua.h
|
** 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 */
|
/* gets the index of the constant */
|
||||||
#define INDEXK(r) ((int)(r) & ~BITRK)
|
#define INDEXK(r) ((int)(r) & ~BITRK)
|
||||||
|
|
||||||
|
#if !defined(MAXINDEXRK) /* (for debugging only) */
|
||||||
#define MAXINDEXRK (BITRK - 1)
|
#define MAXINDEXRK (BITRK - 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* code a constant index as a RK value */
|
/* code a constant index as a RK value */
|
||||||
#define RKASK(x) ((x) | BITRK)
|
#define RKASK(x) ((x) | BITRK)
|
||||||
|
|
233
src/loslib.c
233
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
|
** Standard Operating System library
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -22,23 +22,42 @@
|
||||||
#include "lualib.h"
|
#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) /* { */
|
||||||
|
|
||||||
#if defined(LUA_USE_C89)
|
/* options for ANSI C 89 (only 1-char options) */
|
||||||
#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" }
|
#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_WINDOWS)
|
||||||
|
#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
|
||||||
|
#elif defined(LUA_USE_C89)
|
||||||
|
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
|
||||||
#else /* C99 specification */
|
#else /* C99 specification */
|
||||||
#define LUA_STRFTIMEOPTIONS \
|
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
|
||||||
{ "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \
|
|
||||||
"E", "cCxXyY", \
|
|
||||||
"O", "deHImMSuUVwWy" }
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
|
/* }================================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** {==================================================================
|
||||||
|
** Configuration for time-related stuff
|
||||||
|
** ===================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
#if !defined(l_time_t) /* { */
|
#if !defined(l_time_t) /* { */
|
||||||
/*
|
/*
|
||||||
|
@ -46,20 +65,51 @@
|
||||||
*/
|
*/
|
||||||
#define l_timet lua_Integer
|
#define l_timet lua_Integer
|
||||||
#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t))
|
#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 /* } */
|
#endif /* } */
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(l_gmtime) /* { */
|
||||||
#if !defined(lua_tmpnam) /* { */
|
|
||||||
/*
|
/*
|
||||||
** By default, Lua uses tmpnam except when POSIX is available, where it
|
** By default, Lua uses gmtime/localtime, except when POSIX is available,
|
||||||
** uses mkstemp.
|
** where it uses gmtime_r/localtime_r
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(LUA_USE_POSIX) /* { */
|
#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 /* } */
|
||||||
|
|
||||||
|
/* }================================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** {==================================================================
|
||||||
|
** 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) /* { */
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define LUA_TMPNAMBUFSIZE 32
|
#define LUA_TMPNAMBUFSIZE 32
|
||||||
|
@ -83,31 +133,10 @@
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
|
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
|
/* }================================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined(l_gmtime) /* { */
|
|
||||||
/*
|
|
||||||
** By default, Lua uses gmtime/localtime, except when POSIX is available,
|
|
||||||
** where it uses gmtime_r/localtime_r
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(LUA_USE_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) {
|
static int os_execute (lua_State *L) {
|
||||||
const char *cmd = luaL_optstring(L, 1, NULL);
|
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);
|
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) {
|
static int getboolfield (lua_State *L, const char *key) {
|
||||||
int res;
|
int res;
|
||||||
res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1);
|
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) {
|
/* maximum value for date fields (to avoid arithmetic overflows with 'int') */
|
||||||
int res, isnum;
|
#if !defined(L_MAXDATEFIELD)
|
||||||
lua_getfield(L, -1, key);
|
#define L_MAXDATEFIELD (INT_MAX / 2)
|
||||||
res = (int)lua_tointegerx(L, -1, &isnum);
|
#endif
|
||||||
if (!isnum) {
|
|
||||||
if (d < 0)
|
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);
|
return luaL_error(L, "field '%s' missing in date table", key);
|
||||||
res = d;
|
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);
|
lua_pop(L, 1);
|
||||||
return res;
|
return (int)res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char *checkoption (lua_State *L, const char *conv, char *buff) {
|
static const char *checkoption (lua_State *L, const char *conv,
|
||||||
static const char *const options[] = LUA_STRFTIMEOPTIONS;
|
ptrdiff_t convlen, char *buff) {
|
||||||
unsigned int i;
|
const char *option = LUA_STRFTIMEOPTIONS;
|
||||||
for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2) {
|
int oplen = 1; /* length of options being checked */
|
||||||
if (*conv != '\0' && strchr(options[i], *conv) != NULL) {
|
for (; *option != '\0' && oplen <= convlen; option += oplen) {
|
||||||
buff[1] = *conv;
|
if (*option == '|') /* next block? */
|
||||||
if (*options[i + 1] == '\0') { /* one-char conversion specifier? */
|
oplen++; /* will check options with next length (+1) */
|
||||||
buff[2] = '\0'; /* end buffer */
|
else if (memcmp(conv, option, oplen) == 0) { /* match? */
|
||||||
return conv + 1;
|
memcpy(buff, conv, oplen); /* copy valid option to buffer */
|
||||||
}
|
buff[oplen] = '\0';
|
||||||
else if (*(conv + 1) != '\0' &&
|
return conv + oplen; /* return next item */
|
||||||
strchr(options[i + 1], *(conv + 1)) != NULL) {
|
|
||||||
buff[2] = *(conv + 1); /* valid two-char conversion specifier */
|
|
||||||
buff[3] = '\0'; /* end buffer */
|
|
||||||
return conv + 2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
luaL_argerror(L, 1,
|
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) {
|
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));
|
time_t t = luaL_opt(L, l_checktime, 2, time(NULL));
|
||||||
|
const char *se = s + slen; /* 's' end */
|
||||||
struct tm tmr, *stm;
|
struct tm tmr, *stm;
|
||||||
if (*s == '!') { /* UTC? */
|
if (*s == '!') { /* UTC? */
|
||||||
stm = l_gmtime(&t, &tmr);
|
stm = l_gmtime(&t, &tmr);
|
||||||
|
@ -234,33 +293,26 @@ static int os_date (lua_State *L) {
|
||||||
else
|
else
|
||||||
stm = l_localtime(&t, &tmr);
|
stm = l_localtime(&t, &tmr);
|
||||||
if (stm == NULL) /* invalid date? */
|
if (stm == NULL) /* invalid date? */
|
||||||
lua_pushnil(L);
|
luaL_error(L, "time result cannot be represented in this installation");
|
||||||
else if (strcmp(s, "*t") == 0) {
|
if (strcmp(s, "*t") == 0) {
|
||||||
lua_createtable(L, 0, 9); /* 9 = number of fields */
|
lua_createtable(L, 0, 9); /* 9 = number of fields */
|
||||||
setfield(L, "sec", stm->tm_sec);
|
setallfields(L, stm);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
char cc[4];
|
char cc[4]; /* buffer for individual conversion specifiers */
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
cc[0] = '%';
|
cc[0] = '%';
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
while (*s) {
|
while (s < se) {
|
||||||
if (*s != '%') /* no conversion specifier? */
|
if (*s != '%') /* not a conversion specifier? */
|
||||||
luaL_addchar(&b, *s++);
|
luaL_addchar(&b, *s++);
|
||||||
else {
|
else {
|
||||||
size_t reslen;
|
size_t reslen;
|
||||||
char buff[200]; /* should be big enough for any conversion result */
|
char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
|
||||||
s = checkoption(L, s + 1, cc);
|
s++; /* skip '%' */
|
||||||
reslen = strftime(buff, sizeof(buff), cc, stm);
|
s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */
|
||||||
luaL_addlstring(&b, buff, reslen);
|
reslen = strftime(buff, SIZETIMEFMT, cc, stm);
|
||||||
|
luaL_addsize(&b, reslen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
|
@ -277,28 +329,27 @@ static int os_time (lua_State *L) {
|
||||||
struct tm ts;
|
struct tm ts;
|
||||||
luaL_checktype(L, 1, LUA_TTABLE);
|
luaL_checktype(L, 1, LUA_TTABLE);
|
||||||
lua_settop(L, 1); /* make sure table is at the top */
|
lua_settop(L, 1); /* make sure table is at the top */
|
||||||
ts.tm_sec = getfield(L, "sec", 0);
|
ts.tm_sec = getfield(L, "sec", 0, 0);
|
||||||
ts.tm_min = getfield(L, "min", 0);
|
ts.tm_min = getfield(L, "min", 0, 0);
|
||||||
ts.tm_hour = getfield(L, "hour", 12);
|
ts.tm_hour = getfield(L, "hour", 12, 0);
|
||||||
ts.tm_mday = getfield(L, "day", -1);
|
ts.tm_mday = getfield(L, "day", -1, 0);
|
||||||
ts.tm_mon = getfield(L, "month", -1) - 1;
|
ts.tm_mon = getfield(L, "month", -1, 1);
|
||||||
ts.tm_year = getfield(L, "year", -1) - 1900;
|
ts.tm_year = getfield(L, "year", -1, 1900);
|
||||||
ts.tm_isdst = getboolfield(L, "isdst");
|
ts.tm_isdst = getboolfield(L, "isdst");
|
||||||
t = mktime(&ts);
|
t = mktime(&ts);
|
||||||
|
setallfields(L, &ts); /* update fields with normalized values */
|
||||||
}
|
}
|
||||||
if (t != (time_t)(l_timet)t)
|
if (t != (time_t)(l_timet)t || t == (time_t)(-1))
|
||||||
luaL_error(L, "time result cannot be represented in this Lua instalation");
|
luaL_error(L, "time result cannot be represented in this installation");
|
||||||
else if (t == (time_t)(-1))
|
|
||||||
lua_pushnil(L);
|
|
||||||
else
|
|
||||||
l_pushtime(L, t);
|
l_pushtime(L, t);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int os_difftime (lua_State *L) {
|
static int os_difftime (lua_State *L) {
|
||||||
double res = difftime((l_checktime(L, 1)), (l_checktime(L, 2)));
|
time_t t1 = l_checktime(L, 1);
|
||||||
lua_pushnumber(L, (lua_Number)res);
|
time_t t2 = l_checktime(L, 2);
|
||||||
|
lua_pushnumber(L, (lua_Number)difftime(t1, t2));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
** Lua Parser
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -164,7 +164,8 @@ static int registerlocalvar (LexState *ls, TString *varname) {
|
||||||
int oldsize = f->sizelocvars;
|
int oldsize = f->sizelocvars;
|
||||||
luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
|
luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
|
||||||
LocVar, SHRT_MAX, "local variables");
|
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;
|
f->locvars[fs->nlocvars].varname = varname;
|
||||||
luaC_objbarrier(ls->L, f, varname);
|
luaC_objbarrier(ls->L, f, varname);
|
||||||
return fs->nlocvars++;
|
return fs->nlocvars++;
|
||||||
|
@ -230,7 +231,8 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
|
||||||
checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
|
checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
|
||||||
luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
|
luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
|
||||||
Upvaldesc, MAXUPVAL, "upvalues");
|
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].instack = (v->k == VLOCAL);
|
||||||
f->upvalues[fs->nups].idx = cast_byte(v->u.info);
|
f->upvalues[fs->nups].idx = cast_byte(v->u.info);
|
||||||
f->upvalues[fs->nups].name = name;
|
f->upvalues[fs->nups].name = name;
|
||||||
|
@ -255,7 +257,8 @@ static int searchvar (FuncState *fs, TString *n) {
|
||||||
*/
|
*/
|
||||||
static void markupval (FuncState *fs, int level) {
|
static void markupval (FuncState *fs, int level) {
|
||||||
BlockCnt *bl = fs->bl;
|
BlockCnt *bl = fs->bl;
|
||||||
while (bl->nactvar > level) bl = bl->previous;
|
while (bl->nactvar > level)
|
||||||
|
bl = bl->previous;
|
||||||
bl->upval = 1;
|
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
|
Find variable with given name 'n'. If it is an upvalue, add this
|
||||||
upvalue into all intermediate functions.
|
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? */
|
if (fs == NULL) /* no more levels? */
|
||||||
return VVOID; /* default is global */
|
init_exp(var, VVOID, 0); /* default is global */
|
||||||
else {
|
else {
|
||||||
int v = searchvar(fs, n); /* look up locals at current level */
|
int v = searchvar(fs, n); /* look up locals at current level */
|
||||||
if (v >= 0) { /* found? */
|
if (v >= 0) { /* found? */
|
||||||
init_exp(var, VLOCAL, v); /* variable is local */
|
init_exp(var, VLOCAL, v); /* variable is local */
|
||||||
if (!base)
|
if (!base)
|
||||||
markupval(fs, v); /* local will be used as an upval */
|
markupval(fs, v); /* local will be used as an upval */
|
||||||
return VLOCAL;
|
|
||||||
}
|
}
|
||||||
else { /* not found as local at current level; try upvalues */
|
else { /* not found as local at current level; try upvalues */
|
||||||
int idx = searchupvalue(fs, n); /* try existing upvalues */
|
int idx = searchupvalue(fs, n); /* try existing upvalues */
|
||||||
if (idx < 0) { /* not found? */
|
if (idx < 0) { /* not found? */
|
||||||
if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */
|
singlevaraux(fs->prev, n, var, 0); /* try upper levels */
|
||||||
return VVOID; /* not found; is a global */
|
if (var->k == VVOID) /* not found? */
|
||||||
|
return; /* it is a global */
|
||||||
/* else was LOCAL or UPVAL */
|
/* else was LOCAL or UPVAL */
|
||||||
idx = newupvalue(fs, n, var); /* will be a new upvalue */
|
idx = newupvalue(fs, n, var); /* will be a new upvalue */
|
||||||
}
|
}
|
||||||
init_exp(var, VUPVAL, idx);
|
init_exp(var, VUPVAL, idx); /* new or old upvalue */
|
||||||
return VUPVAL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,10 +295,11 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
|
||||||
static void singlevar (LexState *ls, expdesc *var) {
|
static void singlevar (LexState *ls, expdesc *var) {
|
||||||
TString *varname = str_checkname(ls);
|
TString *varname = str_checkname(ls);
|
||||||
FuncState *fs = ls->fs;
|
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;
|
expdesc key;
|
||||||
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
|
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 */
|
codestring(ls, &key, varname); /* key is variable name */
|
||||||
luaK_indexed(fs, var, &key); /* env[varname] */
|
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);
|
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) {
|
if (fs->np >= f->sizep) {
|
||||||
int oldsize = f->sizep;
|
int oldsize = f->sizep;
|
||||||
luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions");
|
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);
|
f->p[fs->np++] = clp = luaF_newproto(L);
|
||||||
luaC_objbarrier(L, f, clp);
|
luaC_objbarrier(L, f, clp);
|
||||||
|
@ -760,7 +766,7 @@ static void parlist (LexState *ls) {
|
||||||
}
|
}
|
||||||
case TK_DOTS: { /* param -> '...' */
|
case TK_DOTS: { /* param -> '...' */
|
||||||
luaX_next(ls);
|
luaX_next(ls);
|
||||||
f->is_vararg = 1;
|
f->is_vararg = 1; /* declared vararg */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: luaX_syntaxerror(ls, "<name> or '...' expected");
|
default: luaX_syntaxerror(ls, "<name> or '...' expected");
|
||||||
|
@ -1155,11 +1161,8 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
|
||||||
int nexps;
|
int nexps;
|
||||||
checknext(ls, '=');
|
checknext(ls, '=');
|
||||||
nexps = explist(ls, &e);
|
nexps = explist(ls, &e);
|
||||||
if (nexps != nvars) {
|
if (nexps != nvars)
|
||||||
adjust_assign(ls, nvars, nexps, &e);
|
adjust_assign(ls, nvars, nexps, &e);
|
||||||
if (nexps > nvars)
|
|
||||||
ls->fs->freereg -= nexps - nvars; /* remove extra values */
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
luaK_setoneret(ls->fs, &e); /* close last expression */
|
luaK_setoneret(ls->fs, &e); /* close last expression */
|
||||||
luaK_storevar(ls->fs, &lh->v, &e);
|
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 */
|
checkrepeated(fs, ll, label); /* check for repeated labels */
|
||||||
checknext(ls, TK_DBCOLON); /* skip double colon */
|
checknext(ls, TK_DBCOLON); /* skip double colon */
|
||||||
/* create new entry for this label */
|
/* 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 */
|
skipnoopstat(ls); /* skip other no-op statements */
|
||||||
if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
|
if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
|
||||||
/* assume that locals are already out of scope */
|
/* assume that locals are already out of scope */
|
||||||
|
@ -1493,7 +1496,7 @@ static void exprstat (LexState *ls) {
|
||||||
}
|
}
|
||||||
else { /* stat -> func */
|
else { /* stat -> func */
|
||||||
check_condition(ls, v.v.k == VCALL, "syntax error");
|
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)) {
|
if (hasmultret(e.k)) {
|
||||||
luaK_setmultret(fs, &e);
|
luaK_setmultret(fs, &e);
|
||||||
if (e.k == VCALL && nret == 1) { /* tail call? */
|
if (e.k == VCALL && nret == 1) { /* tail call? */
|
||||||
SET_OPCODE(getcode(fs,&e), OP_TAILCALL);
|
SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL);
|
||||||
lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar);
|
lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar);
|
||||||
}
|
}
|
||||||
first = fs->nactvar;
|
first = fs->nactvar;
|
||||||
nret = LUA_MULTRET; /* return all values */
|
nret = LUA_MULTRET; /* return all values */
|
||||||
|
@ -1610,7 +1613,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
|
||||||
BlockCnt bl;
|
BlockCnt bl;
|
||||||
expdesc v;
|
expdesc v;
|
||||||
open_func(ls, fs, &bl);
|
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... */
|
init_exp(&v, VLOCAL, 0); /* create and... */
|
||||||
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
|
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
|
||||||
luaX_next(ls); /* read first token */
|
luaX_next(ls); /* read first token */
|
||||||
|
@ -1626,10 +1629,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
||||||
FuncState funcstate;
|
FuncState funcstate;
|
||||||
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
|
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
|
||||||
setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */
|
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 */
|
lexstate.h = luaH_new(L); /* create table for scanner */
|
||||||
sethvalue(L, L->top, lexstate.h); /* anchor it */
|
sethvalue(L, L->top, lexstate.h); /* anchor it */
|
||||||
incr_top(L);
|
luaD_inctop(L);
|
||||||
funcstate.f = cl->p = luaF_newproto(L);
|
funcstate.f = cl->p = luaF_newproto(L);
|
||||||
funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
|
funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
|
||||||
lua_assert(iswhite(funcstate.f)); /* do not need barrier here */
|
lua_assert(iswhite(funcstate.f)); /* do not need barrier here */
|
||||||
|
|
|
@ -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
|
** Lua Parser
|
||||||
** See Copyright Notice in lua.h
|
** 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 {
|
typedef enum {
|
||||||
VVOID, /* no value */
|
VVOID, /* when 'expdesc' describes the last expression a list,
|
||||||
VNIL,
|
this kind means an empty list (so, no expression) */
|
||||||
VTRUE,
|
VNIL, /* constant nil */
|
||||||
VFALSE,
|
VTRUE, /* constant true */
|
||||||
VK, /* info = index of constant in 'k' */
|
VFALSE, /* constant false */
|
||||||
VKFLT, /* nval = numerical float value */
|
VK, /* constant in 'k'; info = index of constant in 'k' */
|
||||||
VKINT, /* nval = numerical integer value */
|
VKFLT, /* floating constant; nval = numerical float value */
|
||||||
VNONRELOC, /* info = result register */
|
VKINT, /* integer constant; nval = numerical integer value */
|
||||||
VLOCAL, /* info = local register */
|
VNONRELOC, /* expression has its value in a fixed register;
|
||||||
VUPVAL, /* info = index of upvalue in 'upvalues' */
|
info = result register */
|
||||||
VINDEXED, /* t = table register/upvalue; idx = index R/K */
|
VLOCAL, /* local variable; info = local register */
|
||||||
VJMP, /* info = instruction pc */
|
VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
|
||||||
VRELOCABLE, /* info = instruction pc */
|
VINDEXED, /* indexed variable;
|
||||||
VCALL, /* info = instruction pc */
|
ind.vt = whether 't' is register or upvalue;
|
||||||
VVARARG /* info = instruction pc */
|
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;
|
} expkind;
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,14 +54,14 @@ typedef enum {
|
||||||
typedef struct expdesc {
|
typedef struct expdesc {
|
||||||
expkind k;
|
expkind k;
|
||||||
union {
|
union {
|
||||||
|
lua_Integer ival; /* for VKINT */
|
||||||
|
lua_Number nval; /* for VKFLT */
|
||||||
|
int info; /* for generic use */
|
||||||
struct { /* for indexed variables (VINDEXED) */
|
struct { /* for indexed variables (VINDEXED) */
|
||||||
short idx; /* index (R/K) */
|
short idx; /* index (R/K) */
|
||||||
lu_byte t; /* table (register or upvalue) */
|
lu_byte t; /* table (register or upvalue) */
|
||||||
lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
|
lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
|
||||||
} ind;
|
} ind;
|
||||||
int info; /* for generic use */
|
|
||||||
lua_Number nval; /* for VKFLT */
|
|
||||||
lua_Integer ival; /* for VKINT */
|
|
||||||
} u;
|
} u;
|
||||||
int t; /* patch list of 'exit when true' */
|
int t; /* patch list of 'exit when true' */
|
||||||
int f; /* patch list of 'exit when false' */
|
int f; /* patch list of 'exit when false' */
|
||||||
|
|
37
src/lstate.c
37
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
|
** Global State
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -37,9 +37,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define MEMERRMSG "not enough memory"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** a macro to help the creation of a unique random seed when a state is
|
** a macro to help the creation of a unique random seed when a state is
|
||||||
** created; the seed is used to randomize hashes.
|
** created; the seed is used to randomize hashes.
|
||||||
|
@ -79,7 +76,7 @@ typedef struct LG {
|
||||||
*/
|
*/
|
||||||
#define addbuff(b,p,e) \
|
#define addbuff(b,p,e) \
|
||||||
{ size_t t = cast(size_t, 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) {
|
static unsigned int makeseed (lua_State *L) {
|
||||||
char buff[4 * sizeof(size_t)];
|
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)
|
** 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) {
|
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;
|
g->GCdebt = debt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +111,7 @@ CallInfo *luaE_extendCI (lua_State *L) {
|
||||||
L->ci->next = ci;
|
L->ci->next = ci;
|
||||||
ci->previous = L->ci;
|
ci->previous = L->ci;
|
||||||
ci->next = NULL;
|
ci->next = NULL;
|
||||||
|
L->nci++;
|
||||||
return ci;
|
return ci;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +126,7 @@ void luaE_freeCI (lua_State *L) {
|
||||||
while ((ci = next) != NULL) {
|
while ((ci = next) != NULL) {
|
||||||
next = ci->next;
|
next = ci->next;
|
||||||
luaM_free(L, ci);
|
luaM_free(L, ci);
|
||||||
|
L->nci--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,13 +136,14 @@ void luaE_freeCI (lua_State *L) {
|
||||||
*/
|
*/
|
||||||
void luaE_shrinkCI (lua_State *L) {
|
void luaE_shrinkCI (lua_State *L) {
|
||||||
CallInfo *ci = L->ci;
|
CallInfo *ci = L->ci;
|
||||||
while (ci->next != NULL) { /* while there is 'next' */
|
CallInfo *next2; /* next's next */
|
||||||
CallInfo *next2 = ci->next->next; /* next's next */
|
/* while there are two nexts */
|
||||||
if (next2 == NULL) break;
|
while (ci->next != NULL && (next2 = ci->next->next) != NULL) {
|
||||||
luaM_free(L, ci->next); /* remove next */
|
luaM_free(L, ci->next); /* free next */
|
||||||
|
L->nci--;
|
||||||
ci->next = next2; /* remove 'next' from the list */
|
ci->next = next2; /* remove 'next' from the list */
|
||||||
next2->previous = ci;
|
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 */
|
return; /* stack not completely built yet */
|
||||||
L->ci = &L->base_ci; /* free the entire 'ci' list */
|
L->ci = &L->base_ci; /* free the entire 'ci' list */
|
||||||
luaE_freeCI(L);
|
luaE_freeCI(L);
|
||||||
|
lua_assert(L->nci == 0);
|
||||||
luaM_freearray(L, L->stack, L->stacksize); /* free stack array */
|
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);
|
UNUSED(ud);
|
||||||
stack_init(L, L); /* init stack */
|
stack_init(L, L); /* init stack */
|
||||||
init_registry(L, g);
|
init_registry(L, g);
|
||||||
luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
|
luaS_init(L);
|
||||||
luaT_init(L);
|
luaT_init(L);
|
||||||
luaX_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->gcrunning = 1; /* allow gc */
|
||||||
g->version = lua_version(NULL);
|
g->version = lua_version(NULL);
|
||||||
luai_userstateopen(L);
|
luai_userstateopen(L);
|
||||||
|
@ -220,6 +222,7 @@ static void preinit_thread (lua_State *L, global_State *g) {
|
||||||
G(L) = g;
|
G(L) = g;
|
||||||
L->stack = NULL;
|
L->stack = NULL;
|
||||||
L->ci = NULL;
|
L->ci = NULL;
|
||||||
|
L->nci = 0;
|
||||||
L->stacksize = 0;
|
L->stacksize = 0;
|
||||||
L->twups = L; /* thread has no upvalues */
|
L->twups = L; /* thread has no upvalues */
|
||||||
L->errorJmp = NULL;
|
L->errorJmp = NULL;
|
||||||
|
@ -243,7 +246,6 @@ static void close_state (lua_State *L) {
|
||||||
if (g->version) /* closing a fully built state? */
|
if (g->version) /* closing a fully built state? */
|
||||||
luai_userstateclose(L);
|
luai_userstateclose(L);
|
||||||
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
|
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
|
||||||
luaZ_freebuffer(L, &g->buff);
|
|
||||||
freestack(L);
|
freestack(L);
|
||||||
lua_assert(gettotalbytes(g) == sizeof(LG));
|
lua_assert(gettotalbytes(g) == sizeof(LG));
|
||||||
(*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */
|
(*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.size = g->strt.nuse = 0;
|
||||||
g->strt.hash = NULL;
|
g->strt.hash = NULL;
|
||||||
setnilvalue(&g->l_registry);
|
setnilvalue(&g->l_registry);
|
||||||
luaZ_initbuffer(L, &g->buff);
|
|
||||||
g->panic = NULL;
|
g->panic = NULL;
|
||||||
g->version = NULL;
|
g->version = NULL;
|
||||||
g->gcstate = GCSpause;
|
g->gcstate = GCSpause;
|
||||||
|
|
30
src/lstate.h
30
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
|
** Global State
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -33,6 +33,15 @@
|
||||||
struct lua_longjmp; /* defined in ldo.c */
|
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 */
|
/* extra stack space to handle TM calls and some other extras */
|
||||||
#define EXTRA_STACK 5
|
#define EXTRA_STACK 5
|
||||||
|
@ -79,7 +88,7 @@ typedef struct CallInfo {
|
||||||
} u;
|
} u;
|
||||||
ptrdiff_t extra;
|
ptrdiff_t extra;
|
||||||
short nresults; /* expected number of results from this function */
|
short nresults; /* expected number of results from this function */
|
||||||
lu_byte callstatus;
|
unsigned short callstatus;
|
||||||
} CallInfo;
|
} CallInfo;
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,11 +98,13 @@ typedef struct CallInfo {
|
||||||
#define CIST_OAH (1<<0) /* original value of 'allowhook' */
|
#define CIST_OAH (1<<0) /* original value of 'allowhook' */
|
||||||
#define CIST_LUA (1<<1) /* call is running a Lua function */
|
#define CIST_LUA (1<<1) /* call is running a Lua function */
|
||||||
#define CIST_HOOKED (1<<2) /* call is running a debug hook */
|
#define CIST_HOOKED (1<<2) /* call is running a debug hook */
|
||||||
#define CIST_REENTRY (1<<3) /* call is running on same invocation of
|
#define CIST_FRESH (1<<3) /* call is running on a fresh invocation
|
||||||
luaV_execute of previous call */
|
of luaV_execute */
|
||||||
#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
|
#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
|
||||||
#define CIST_TAIL (1<<5) /* call was tail called */
|
#define CIST_TAIL (1<<5) /* call was tail called */
|
||||||
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
|
#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)
|
#define isLua(ci) ((ci)->callstatus & CIST_LUA)
|
||||||
|
|
||||||
|
@ -108,7 +119,7 @@ typedef struct CallInfo {
|
||||||
typedef struct global_State {
|
typedef struct global_State {
|
||||||
lua_Alloc frealloc; /* function to reallocate memory */
|
lua_Alloc frealloc; /* function to reallocate memory */
|
||||||
void *ud; /* auxiliary data to 'frealloc' */
|
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 */
|
l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
|
||||||
lu_mem GCmemtrav; /* memory traversed by the GC */
|
lu_mem GCmemtrav; /* memory traversed by the GC */
|
||||||
lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
|
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 *tobefnz; /* list of userdata to be GC */
|
||||||
GCObject *fixedgc; /* list of objects not to be collected */
|
GCObject *fixedgc; /* list of objects not to be collected */
|
||||||
struct lua_State *twups; /* list of threads with open upvalues */
|
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 */
|
unsigned int gcfinnum; /* number of finalizers to call in each GC step */
|
||||||
int gcpause; /* size of pause between successive GCs */
|
int gcpause; /* size of pause between successive GCs */
|
||||||
int gcstepmul; /* GC 'granularity' */
|
int gcstepmul; /* GC 'granularity' */
|
||||||
|
@ -140,6 +150,7 @@ typedef struct global_State {
|
||||||
TString *memerrmsg; /* memory-error message */
|
TString *memerrmsg; /* memory-error message */
|
||||||
TString *tmname[TM_N]; /* array with tag-method names */
|
TString *tmname[TM_N]; /* array with tag-method names */
|
||||||
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
|
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
|
||||||
|
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
|
||||||
} global_State;
|
} global_State;
|
||||||
|
|
||||||
|
|
||||||
|
@ -148,6 +159,7 @@ typedef struct global_State {
|
||||||
*/
|
*/
|
||||||
struct lua_State {
|
struct lua_State {
|
||||||
CommonHeader;
|
CommonHeader;
|
||||||
|
unsigned short nci; /* number of items in 'ci' list */
|
||||||
lu_byte status;
|
lu_byte status;
|
||||||
StkId top; /* first free slot in the stack */
|
StkId top; /* first free slot in the stack */
|
||||||
global_State *l_G;
|
global_State *l_G;
|
||||||
|
@ -160,14 +172,14 @@ struct lua_State {
|
||||||
struct lua_State *twups; /* list of threads with open upvalues */
|
struct lua_State *twups; /* list of threads with open upvalues */
|
||||||
struct lua_longjmp *errorJmp; /* current error recover point */
|
struct lua_longjmp *errorJmp; /* current error recover point */
|
||||||
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
|
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) */
|
ptrdiff_t errfunc; /* current error handling function (stack index) */
|
||||||
int stacksize;
|
int stacksize;
|
||||||
int basehookcount;
|
int basehookcount;
|
||||||
int hookcount;
|
int hookcount;
|
||||||
unsigned short nny; /* number of non-yieldable calls in stack */
|
unsigned short nny; /* number of non-yieldable calls in stack */
|
||||||
unsigned short nCcalls; /* number of nested C calls */
|
unsigned short nCcalls; /* number of nested C calls */
|
||||||
lu_byte hookmask;
|
l_signalT hookmask;
|
||||||
lu_byte allowhook;
|
lu_byte allowhook;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -210,7 +222,7 @@ union GCUnion {
|
||||||
|
|
||||||
|
|
||||||
/* actual number of total bytes allocated */
|
/* 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_setdebt (global_State *g, l_mem debt);
|
||||||
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
|
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
|
||||||
|
|
112
src/lstring.c
112
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)
|
** String table (keeps all strings handled by Lua)
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -22,6 +22,8 @@
|
||||||
#include "lstring.h"
|
#include "lstring.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define MEMERRMSG "not enough memory"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to
|
** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to
|
||||||
|
@ -36,24 +38,33 @@
|
||||||
** equality for long strings
|
** equality for long strings
|
||||||
*/
|
*/
|
||||||
int luaS_eqlngstr (TString *a, TString *b) {
|
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);
|
lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR);
|
||||||
return (a == b) || /* same instance or... */
|
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 */
|
(memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
|
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
|
||||||
unsigned int h = seed ^ cast(unsigned int, l);
|
unsigned int h = seed ^ cast(unsigned int, l);
|
||||||
size_t l1;
|
|
||||||
size_t step = (l >> LUAI_HASHLIMIT) + 1;
|
size_t step = (l >> LUAI_HASHLIMIT) + 1;
|
||||||
for (l1 = l; l1 >= step; l1 -= step)
|
for (; l >= step; l -= step)
|
||||||
h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1]));
|
h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
|
||||||
return h;
|
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
|
** resizes the string table
|
||||||
*/
|
*/
|
||||||
|
@ -69,9 +80,9 @@ void luaS_resize (lua_State *L, int newsize) {
|
||||||
TString *p = tb->hash[i];
|
TString *p = tb->hash[i];
|
||||||
tb->hash[i] = NULL;
|
tb->hash[i] = NULL;
|
||||||
while (p) { /* for each node in the list */
|
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 */
|
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;
|
tb->hash[h] = p;
|
||||||
p = hnext;
|
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
|
** creates a new string object
|
||||||
*/
|
*/
|
||||||
static TString *createstrobj (lua_State *L, const char *str, size_t l,
|
static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {
|
||||||
int tag, unsigned int h) {
|
|
||||||
TString *ts;
|
TString *ts;
|
||||||
GCObject *o;
|
GCObject *o;
|
||||||
size_t totalsize; /* total size of TString object */
|
size_t totalsize; /* total size of TString object */
|
||||||
totalsize = sizelstring(l);
|
totalsize = sizelstring(l);
|
||||||
o = luaC_newobj(L, tag, totalsize);
|
o = luaC_newobj(L, tag, totalsize);
|
||||||
ts = gco2ts(o);
|
ts = gco2ts(o);
|
||||||
ts->len = l;
|
|
||||||
ts->hash = h;
|
ts->hash = h;
|
||||||
ts->extra = 0;
|
ts->extra = 0;
|
||||||
memcpy(getaddrstr(ts), str, l * sizeof(char));
|
getstr(ts)[l] = '\0'; /* ending 0 */
|
||||||
getaddrstr(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;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,8 +155,8 @@ void luaS_remove (lua_State *L, TString *ts) {
|
||||||
stringtable *tb = &G(L)->strt;
|
stringtable *tb = &G(L)->strt;
|
||||||
TString **p = &tb->hash[lmod(ts->hash, tb->size)];
|
TString **p = &tb->hash[lmod(ts->hash, tb->size)];
|
||||||
while (*p != ts) /* find previous element */
|
while (*p != ts) /* find previous element */
|
||||||
p = &(*p)->hnext;
|
p = &(*p)->u.hnext;
|
||||||
*p = (*p)->hnext; /* remove element from its list */
|
*p = (*p)->u.hnext; /* remove element from its list */
|
||||||
tb->nuse--;
|
tb->nuse--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,8 +169,9 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
unsigned int h = luaS_hash(str, l, g->seed);
|
unsigned int h = luaS_hash(str, l, g->seed);
|
||||||
TString **list = &g->strt.hash[lmod(h, g->strt.size)];
|
TString **list = &g->strt.hash[lmod(h, g->strt.size)];
|
||||||
for (ts = *list; ts != NULL; ts = ts->hnext) {
|
lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
|
||||||
if (l == ts->len &&
|
for (ts = *list; ts != NULL; ts = ts->u.hnext) {
|
||||||
|
if (l == ts->shrlen &&
|
||||||
(memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
|
(memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
|
||||||
/* found! */
|
/* found! */
|
||||||
if (isdead(g, ts)) /* dead (but not collected yet)? */
|
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);
|
luaS_resize(L, g->strt.size * 2);
|
||||||
list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */
|
list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */
|
||||||
}
|
}
|
||||||
ts = createstrobj(L, str, l, LUA_TSHRSTR, h);
|
ts = createstrobj(L, l, LUA_TSHRSTR, h);
|
||||||
ts->hnext = *list;
|
memcpy(getstr(ts), str, l * sizeof(char));
|
||||||
|
ts->shrlen = cast_byte(l);
|
||||||
|
ts->u.hnext = *list;
|
||||||
*list = ts;
|
*list = ts;
|
||||||
g->strt.nuse++;
|
g->strt.nuse++;
|
||||||
return ts;
|
return ts;
|
||||||
|
@ -152,18 +200,36 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
|
||||||
if (l <= LUAI_MAXSHORTLEN) /* short string? */
|
if (l <= LUAI_MAXSHORTLEN) /* short string? */
|
||||||
return internshrstr(L, str, l);
|
return internshrstr(L, str, l);
|
||||||
else {
|
else {
|
||||||
if (l + 1 > (MAX_SIZE - sizeof(TString))/sizeof(char))
|
TString *ts;
|
||||||
|
if (l >= (MAX_SIZE - sizeof(TString))/sizeof(char))
|
||||||
luaM_toobig(L);
|
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) {
|
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];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
** String table (keep all strings handled by Lua)
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
|
|
||||||
#define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char))
|
#define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char))
|
||||||
#define sizestring(s) sizelstring((s)->len)
|
|
||||||
|
|
||||||
#define sizeludata(l) (sizeof(union UUdata) + (l))
|
#define sizeludata(l) (sizeof(union UUdata) + (l))
|
||||||
#define sizeudata(u) sizeludata((u)->len)
|
#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_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 int luaS_eqlngstr (TString *a, TString *b);
|
||||||
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
|
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 void luaS_remove (lua_State *L, TString *ts);
|
||||||
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s);
|
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_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_new (lua_State *L, const char *str);
|
||||||
|
LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
350
src/lstrlib.c
350
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
|
** Standard library for string operations and pattern-matching
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -11,7 +11,9 @@
|
||||||
|
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <float.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <locale.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -25,7 +27,8 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** maximum number of captures that a pattern can do during
|
** 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)
|
#if !defined(LUA_MAXCAPTURES)
|
||||||
#define LUA_MAXCAPTURES 32
|
#define LUA_MAXCAPTURES 32
|
||||||
|
@ -40,8 +43,10 @@
|
||||||
** Some sizes are better limited to fit in 'int', but must also fit in
|
** 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'.)
|
** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.)
|
||||||
*/
|
*/
|
||||||
|
#define MAX_SIZET ((size_t)(~(size_t)0))
|
||||||
|
|
||||||
#define MAXSIZE \
|
#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 (start < 1) start = 1;
|
||||||
if (end > (lua_Integer)l) end = l;
|
if (end > (lua_Integer)l) end = l;
|
||||||
if (start <= end)
|
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, "");
|
else lua_pushliteral(L, "");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -149,9 +154,9 @@ static int str_byte (lua_State *L) {
|
||||||
if (posi < 1) posi = 1;
|
if (posi < 1) posi = 1;
|
||||||
if (pose > (lua_Integer)l) pose = l;
|
if (pose > (lua_Integer)l) pose = l;
|
||||||
if (posi > pose) return 0; /* empty interval; return no values */
|
if (posi > pose) return 0; /* empty interval; return no values */
|
||||||
n = (int)(pose - posi + 1);
|
if (pose - posi >= INT_MAX) /* arithmetic overflow? */
|
||||||
if (posi + n <= pose) /* arithmetic overflow? */
|
|
||||||
return luaL_error(L, "string slice too long");
|
return luaL_error(L, "string slice too long");
|
||||||
|
n = (int)(pose - posi) + 1;
|
||||||
luaL_checkstack(L, n, "string slice too long");
|
luaL_checkstack(L, n, "string slice too long");
|
||||||
for (i=0; i<n; i++)
|
for (i=0; i<n; i++)
|
||||||
lua_pushinteger(L, uchar(s[posi+i-1]));
|
lua_pushinteger(L, uchar(s[posi+i-1]));
|
||||||
|
@ -207,12 +212,12 @@ static int str_dump (lua_State *L) {
|
||||||
|
|
||||||
|
|
||||||
typedef struct MatchState {
|
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_init; /* init of source string */
|
||||||
const char *src_end; /* end ('\0') of source string */
|
const char *src_end; /* end ('\0') of source string */
|
||||||
const char *p_end; /* end ('\0') of pattern */
|
const char *p_end; /* end ('\0') of pattern */
|
||||||
lua_State *L;
|
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 {
|
struct {
|
||||||
const char *init;
|
const char *init;
|
||||||
ptrdiff_t len;
|
ptrdiff_t len;
|
||||||
|
@ -499,7 +504,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
|
||||||
}
|
}
|
||||||
case '+': /* 1 or more repetitions */
|
case '+': /* 1 or more repetitions */
|
||||||
s++; /* 1 match already done */
|
s++; /* 1 match already done */
|
||||||
/* go through */
|
/* FALLTHROUGH */
|
||||||
case '*': /* 0 or more repetitions */
|
case '*': /* 0 or more repetitions */
|
||||||
s = max_expand(ms, s, p, ep);
|
s = max_expand(ms, s, p, ep);
|
||||||
break;
|
break;
|
||||||
|
@ -554,7 +559,7 @@ static void push_onecapture (MatchState *ms, int i, const char *s,
|
||||||
ptrdiff_t l = ms->capture[i].len;
|
ptrdiff_t l = ms->capture[i].len;
|
||||||
if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
|
if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
|
||||||
if (l == CAP_POSITION)
|
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
|
else
|
||||||
lua_pushlstring(ms->L, ms->capture[i].init, l);
|
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) {
|
static int str_find_aux (lua_State *L, int find) {
|
||||||
size_t ls, lp;
|
size_t ls, lp;
|
||||||
const char *s = luaL_checklstring(L, 1, &ls);
|
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 */
|
/* do a plain search */
|
||||||
const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp);
|
const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp);
|
||||||
if (s2) {
|
if (s2) {
|
||||||
lua_pushinteger(L, s2 - s + 1);
|
lua_pushinteger(L, (s2 - s) + 1);
|
||||||
lua_pushinteger(L, s2 - s + lp);
|
lua_pushinteger(L, (s2 - s) + lp);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -610,18 +631,13 @@ static int str_find_aux (lua_State *L, int find) {
|
||||||
if (anchor) {
|
if (anchor) {
|
||||||
p++; lp--; /* skip anchor character */
|
p++; lp--; /* skip anchor character */
|
||||||
}
|
}
|
||||||
ms.L = L;
|
prepstate(&ms, L, s, ls, p, lp);
|
||||||
ms.matchdepth = MAXCCALLS;
|
|
||||||
ms.src_init = s;
|
|
||||||
ms.src_end = s + ls;
|
|
||||||
ms.p_end = p + lp;
|
|
||||||
do {
|
do {
|
||||||
const char *res;
|
const char *res;
|
||||||
ms.level = 0;
|
reprepstate(&ms);
|
||||||
lua_assert(ms.matchdepth == MAXCCALLS);
|
|
||||||
if ((res=match(&ms, s1, p)) != NULL) {
|
if ((res=match(&ms, s1, p)) != NULL) {
|
||||||
if (find) {
|
if (find) {
|
||||||
lua_pushinteger(L, s1 - s + 1); /* start */
|
lua_pushinteger(L, (s1 - s) + 1); /* start */
|
||||||
lua_pushinteger(L, res - s); /* end */
|
lua_pushinteger(L, res - s); /* end */
|
||||||
return push_captures(&ms, NULL, 0) + 2;
|
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) {
|
static int gmatch_aux (lua_State *L) {
|
||||||
MatchState ms;
|
GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3));
|
||||||
size_t ls, lp;
|
|
||||||
const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
|
|
||||||
const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp);
|
|
||||||
const char *src;
|
const char *src;
|
||||||
ms.L = L;
|
gm->ms.L = L;
|
||||||
ms.matchdepth = MAXCCALLS;
|
for (src = gm->src; src <= gm->ms.src_end; src++) {
|
||||||
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++) {
|
|
||||||
const char *e;
|
const char *e;
|
||||||
ms.level = 0;
|
reprepstate(&gm->ms);
|
||||||
lua_assert(ms.matchdepth == MAXCCALLS);
|
if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) {
|
||||||
if ((e = match(&ms, src, p)) != NULL) {
|
gm->src = gm->lastmatch = e;
|
||||||
lua_Integer newstart = e-s;
|
return push_captures(&gm->ms, src, e);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0; /* not found */
|
return 0; /* not found */
|
||||||
|
@ -675,10 +687,14 @@ static int gmatch_aux (lua_State *L) {
|
||||||
|
|
||||||
|
|
||||||
static int gmatch (lua_State *L) {
|
static int gmatch (lua_State *L) {
|
||||||
luaL_checkstring(L, 1);
|
size_t ls, lp;
|
||||||
luaL_checkstring(L, 2);
|
const char *s = luaL_checklstring(L, 1, &ls);
|
||||||
lua_settop(L, 2);
|
const char *p = luaL_checklstring(L, 2, &lp);
|
||||||
lua_pushinteger(L, 0);
|
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);
|
lua_pushcclosure(L, gmatch_aux, 3);
|
||||||
return 1;
|
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) {
|
static int str_gsub (lua_State *L) {
|
||||||
size_t srcl, lp;
|
size_t srcl, lp;
|
||||||
const char *src = luaL_checklstring(L, 1, &srcl);
|
const char *src = luaL_checklstring(L, 1, &srcl); /* subject */
|
||||||
const char *p = luaL_checklstring(L, 2, &lp);
|
const char *p = luaL_checklstring(L, 2, &lp); /* pattern */
|
||||||
int tr = lua_type(L, 3);
|
const char *lastmatch = NULL; /* end of last match */
|
||||||
lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1);
|
int tr = lua_type(L, 3); /* replacement type */
|
||||||
|
lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */
|
||||||
int anchor = (*p == '^');
|
int anchor = (*p == '^');
|
||||||
lua_Integer n = 0;
|
lua_Integer n = 0; /* replacement count */
|
||||||
MatchState ms;
|
MatchState ms;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
|
luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
|
||||||
|
@ -760,25 +777,18 @@ static int str_gsub (lua_State *L) {
|
||||||
if (anchor) {
|
if (anchor) {
|
||||||
p++; lp--; /* skip anchor character */
|
p++; lp--; /* skip anchor character */
|
||||||
}
|
}
|
||||||
ms.L = L;
|
prepstate(&ms, L, src, srcl, p, lp);
|
||||||
ms.matchdepth = MAXCCALLS;
|
|
||||||
ms.src_init = src;
|
|
||||||
ms.src_end = src+srcl;
|
|
||||||
ms.p_end = p + lp;
|
|
||||||
while (n < max_s) {
|
while (n < max_s) {
|
||||||
const char *e;
|
const char *e;
|
||||||
ms.level = 0;
|
reprepstate(&ms); /* (re)prepare state for new match */
|
||||||
lua_assert(ms.matchdepth == MAXCCALLS);
|
if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */
|
||||||
e = match(&ms, src, p);
|
|
||||||
if (e) {
|
|
||||||
n++;
|
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? */
|
else if (src < ms.src_end) /* otherwise, skip one character */
|
||||||
src = e; /* skip it */
|
|
||||||
else if (src < ms.src_end)
|
|
||||||
luaL_addchar(&b, *src++);
|
luaL_addchar(&b, *src++);
|
||||||
else break;
|
else break; /* end of subject */
|
||||||
if (anchor) break;
|
if (anchor) break;
|
||||||
}
|
}
|
||||||
luaL_addlstring(&b, src, ms.src_end-src);
|
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))) */
|
#if !defined(lua_number2strx) /* { */
|
||||||
#define MAX_ITEM 512
|
|
||||||
|
/*
|
||||||
|
** 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 */
|
/* valid flags in a format specification */
|
||||||
#define FLAGS "-+ #0"
|
#define FLAGS "-+ #0"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** maximum size of each format specification (such as "%-099.99d")
|
** 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) {
|
static void addquoted (luaL_Buffer *b, const char *s, size_t len) {
|
||||||
size_t l;
|
|
||||||
const char *s = luaL_checklstring(L, arg, &l);
|
|
||||||
luaL_addchar(b, '"');
|
luaL_addchar(b, '"');
|
||||||
while (l--) {
|
while (len--) {
|
||||||
if (*s == '"' || *s == '\\' || *s == '\n') {
|
if (*s == '"' || *s == '\\' || *s == '\n') {
|
||||||
luaL_addchar(b, '\\');
|
luaL_addchar(b, '\\');
|
||||||
luaL_addchar(b, *s);
|
luaL_addchar(b, *s);
|
||||||
}
|
}
|
||||||
else if (*s == '\0' || iscntrl(uchar(*s))) {
|
else if (iscntrl(uchar(*s))) {
|
||||||
char buff[10];
|
char buff[10];
|
||||||
if (!isdigit(uchar(*(s+1))))
|
if (!isdigit(uchar(*(s+1))))
|
||||||
sprintf(buff, "\\%d", (int)uchar(*s));
|
l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s));
|
||||||
else
|
else
|
||||||
sprintf(buff, "\\%03d", (int)uchar(*s));
|
l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s));
|
||||||
luaL_addstring(b, buff);
|
luaL_addstring(b, buff);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -834,6 +927,57 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
|
||||||
luaL_addchar(b, '"');
|
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) {
|
static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
|
||||||
const char *p = strfrmt;
|
const char *p = strfrmt;
|
||||||
while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */
|
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)))
|
if (isdigit(uchar(*p)))
|
||||||
luaL_error(L, "invalid format (width or precision too long)");
|
luaL_error(L, "invalid format (width or precision too long)");
|
||||||
*(form++) = '%';
|
*(form++) = '%';
|
||||||
memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char));
|
memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char));
|
||||||
form += p - strfrmt + 1;
|
form += (p - strfrmt) + 1;
|
||||||
*form = '\0';
|
*form = '\0';
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -891,49 +1035,56 @@ static int str_format (lua_State *L) {
|
||||||
strfrmt = scanformat(L, strfrmt, form);
|
strfrmt = scanformat(L, strfrmt, form);
|
||||||
switch (*strfrmt++) {
|
switch (*strfrmt++) {
|
||||||
case 'c': {
|
case 'c': {
|
||||||
nb = sprintf(buff, form, (int)luaL_checkinteger(L, arg));
|
nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'd': case 'i':
|
case 'd': case 'i':
|
||||||
case 'o': case 'u': case 'x': case 'X': {
|
case 'o': case 'u': case 'x': case 'X': {
|
||||||
lua_Integer n = luaL_checkinteger(L, arg);
|
lua_Integer n = luaL_checkinteger(L, arg);
|
||||||
addlenmod(form, LUA_INTEGER_FRMLEN);
|
addlenmod(form, LUA_INTEGER_FRMLEN);
|
||||||
nb = sprintf(buff, form, n);
|
nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#if defined(LUA_USE_AFORMAT)
|
|
||||||
case 'a': case 'A':
|
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 'e': case 'E': case 'f':
|
||||||
case 'g': case 'G': {
|
case 'g': case 'G': {
|
||||||
|
lua_Number n = luaL_checknumber(L, arg);
|
||||||
addlenmod(form, LUA_NUMBER_FRMLEN);
|
addlenmod(form, LUA_NUMBER_FRMLEN);
|
||||||
nb = sprintf(buff, form, luaL_checknumber(L, arg));
|
nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'q': {
|
case 'q': {
|
||||||
addquoted(L, &b, arg);
|
addliteral(L, &b, arg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 's': {
|
case 's': {
|
||||||
size_t l;
|
size_t l;
|
||||||
const char *s = luaL_tolstring(L, arg, &l);
|
const char *s = luaL_tolstring(L, arg, &l);
|
||||||
if (!strchr(form, '.') && l >= 100) {
|
if (form[2] == '\0') /* no modifiers? */
|
||||||
/* no precision and string is too long to be formatted;
|
luaL_addvalue(&b); /* keep entire string */
|
||||||
keep original string */
|
|
||||||
luaL_addvalue(&b);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
nb = sprintf(buff, form, s);
|
luaL_argcheck(L, l == strlen(s), arg, "string contains zeros");
|
||||||
lua_pop(L, 1); /* remove result from 'luaL_tolstring' */
|
if (!strchr(form, '.') && l >= 100) {
|
||||||
break;
|
/* 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' */
|
default: { /* also treat cases 'pnLlh' */
|
||||||
return luaL_error(L, "invalid option '%%%c' to 'format'",
|
return luaL_error(L, "invalid option '%%%c' to 'format'",
|
||||||
*(strfrmt - 1));
|
*(strfrmt - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lua_assert(nb < MAX_ITEM);
|
||||||
luaL_addsize(&b, nb);
|
luaL_addsize(&b, nb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -952,8 +1103,8 @@ static int str_format (lua_State *L) {
|
||||||
|
|
||||||
|
|
||||||
/* value used for padding */
|
/* value used for padding */
|
||||||
#if !defined(LUA_PACKPADBYTE)
|
#if !defined(LUAL_PACKPADBYTE)
|
||||||
#define LUA_PACKPADBYTE 0x00
|
#define LUAL_PACKPADBYTE 0x00
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* maximum size for the binary representation of an integer */
|
/* maximum size for the binary representation of an integer */
|
||||||
|
@ -1190,7 +1341,7 @@ static int str_pack (lua_State *L) {
|
||||||
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
|
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
|
||||||
totalsize += ntoalign + size;
|
totalsize += ntoalign + size;
|
||||||
while (ntoalign-- > 0)
|
while (ntoalign-- > 0)
|
||||||
luaL_addchar(&b, LUA_PACKPADBYTE); /* fill alignment */
|
luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */
|
||||||
arg++;
|
arg++;
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case Kint: { /* signed integers */
|
case Kint: { /* signed integers */
|
||||||
|
@ -1225,8 +1376,11 @@ static int str_pack (lua_State *L) {
|
||||||
case Kchar: { /* fixed-size string */
|
case Kchar: { /* fixed-size string */
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *s = luaL_checklstring(L, arg, &len);
|
const char *s = luaL_checklstring(L, arg, &len);
|
||||||
luaL_argcheck(L, len == (size_t)size, arg, "wrong length");
|
luaL_argcheck(L, len <= (size_t)size, arg,
|
||||||
luaL_addlstring(&b, s, size);
|
"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;
|
break;
|
||||||
}
|
}
|
||||||
case Kstring: { /* strings with length count */
|
case Kstring: { /* strings with length count */
|
||||||
|
@ -1249,7 +1403,7 @@ static int str_pack (lua_State *L) {
|
||||||
totalsize += len + 1;
|
totalsize += len + 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Kpadding: luaL_addchar(&b, LUA_PACKPADBYTE); /* go through */
|
case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */
|
||||||
case Kpaddalign: case Knop:
|
case Kpaddalign: case Knop:
|
||||||
arg--; /* undo increment */
|
arg--; /* undo increment */
|
||||||
break;
|
break;
|
||||||
|
@ -1276,7 +1430,7 @@ static int str_packsize (lua_State *L) {
|
||||||
case Kstring: /* strings with length count */
|
case Kstring: /* strings with length count */
|
||||||
case Kzstr: /* zero-terminated string */
|
case Kzstr: /* zero-terminated string */
|
||||||
luaL_argerror(L, 1, "variable-length format");
|
luaL_argerror(L, 1, "variable-length format");
|
||||||
break;
|
/* call never return, but to avoid warnings: *//* FALLTHROUGH */
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
223
src/ltable.c
223
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)
|
** Lua tables (hash)
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -14,8 +14,8 @@
|
||||||
** Implementation of tables (aka arrays, objects, or hash tables).
|
** Implementation of tables (aka arrays, objects, or hash tables).
|
||||||
** Tables keep its elements in two parts: an array part and a hash part.
|
** 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
|
** 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
|
** part. The actual size of the array is the largest 'n' such that
|
||||||
** least half the slots between 0 and n are in use.
|
** more than half the slots between 1 and n are in use.
|
||||||
** Hash uses a mix of chained scatter table with Brent's variation.
|
** 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
|
** 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
|
** 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.
|
** Hence even when the load factor reaches 100%, performance remains good.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <float.h>
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
@ -71,13 +69,11 @@
|
||||||
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
|
#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 dummynode (&dummynode_)
|
||||||
|
|
||||||
#define isdummy(n) ((n) == dummynode)
|
|
||||||
|
|
||||||
static const Node dummynode_ = {
|
static const Node dummynode_ = {
|
||||||
{NILCONSTANT}, /* value */
|
{NILCONSTANT}, /* value */
|
||||||
{{NILCONSTANT, 0}} /* key */
|
{{NILCONSTANT, 0}} /* key */
|
||||||
|
@ -85,31 +81,33 @@ static const Node dummynode_ = {
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Checks whether a float has a value representable as a lua_Integer
|
** Hash for floating-point numbers.
|
||||||
** (and does the conversion if so)
|
** 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 int numisinteger (lua_Number x, lua_Integer *p) {
|
#if !defined(l_hashfloat)
|
||||||
if ((x) == l_floor(x)) /* integral value? */
|
static int l_hashfloat (lua_Number n) {
|
||||||
return lua_numbertointeger(x, p); /* try as an integer */
|
|
||||||
else return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** hash for floating-point numbers
|
|
||||||
*/
|
|
||||||
static Node *hashfloat (const Table *t, lua_Number n) {
|
|
||||||
int i;
|
int i;
|
||||||
n = l_mathop(frexp)(n, &i) * cast_num(INT_MAX - DBL_MAX_EXP);
|
lua_Integer ni;
|
||||||
i += cast_int(n);
|
n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN);
|
||||||
if (i < 0) {
|
if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */
|
||||||
if (cast(unsigned int, i) == 0u - i) /* use unsigned to avoid overflows */
|
lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL));
|
||||||
i = 0; /* handle INT_MIN */
|
return 0;
|
||||||
i = -i; /* must be a positive value */
|
}
|
||||||
|
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:
|
case LUA_TNUMINT:
|
||||||
return hashint(t, ivalue(key));
|
return hashint(t, ivalue(key));
|
||||||
case LUA_TNUMFLT:
|
case LUA_TNUMFLT:
|
||||||
return hashfloat(t, fltvalue(key));
|
return hashmod(t, l_hashfloat(fltvalue(key)));
|
||||||
case LUA_TSHRSTR:
|
case LUA_TSHRSTR:
|
||||||
return hashstr(t, tsvalue(key));
|
return hashstr(t, tsvalue(key));
|
||||||
case LUA_TLNGSTR: {
|
case LUA_TLNGSTR:
|
||||||
TString *s = tsvalue(key);
|
return hashpow2(t, luaS_hashlongstr(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_TBOOLEAN:
|
case LUA_TBOOLEAN:
|
||||||
return hashboolean(t, bvalue(key));
|
return hashboolean(t, bvalue(key));
|
||||||
case LUA_TLIGHTUSERDATA:
|
case LUA_TLIGHTUSERDATA:
|
||||||
|
@ -139,6 +131,7 @@ static Node *mainposition (const Table *t, const TValue *key) {
|
||||||
case LUA_TLCF:
|
case LUA_TLCF:
|
||||||
return hashpointer(t, fvalue(key));
|
return hashpointer(t, fvalue(key));
|
||||||
default:
|
default:
|
||||||
|
lua_assert(!ttisdeadkey(key));
|
||||||
return hashpointer(t, gcvalue(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
|
** 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
|
** "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
|
** between 2^(i - 1) + 1 and 2^i. 'pna' enters with the total number of
|
||||||
** return the number of elements that will go to that part.
|
** 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;
|
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 a = 0; /* number of elements smaller than 2^i */
|
||||||
unsigned int na = 0; /* number of elements to go to array part */
|
unsigned int na = 0; /* number of elements to go to array part */
|
||||||
unsigned int n = 0; /* optimal size for array part */
|
unsigned int optimal = 0; /* optimal size for array part */
|
||||||
for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) {
|
/* 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) {
|
if (nums[i] > 0) {
|
||||||
a += nums[i];
|
a += nums[i];
|
||||||
if (a > twotoi/2) { /* more than half elements present? */
|
if (a > twotoi/2) { /* more than half elements present? */
|
||||||
n = twotoi; /* optimal size (till now) */
|
optimal = twotoi; /* optimal size (till now) */
|
||||||
na = a; /* all elements up to 'n' will go to array part */
|
na = a; /* all elements up to 'optimal' will go to array part */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (a == *narray) break; /* all elements already counted */
|
|
||||||
}
|
}
|
||||||
*narray = n;
|
lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal);
|
||||||
lua_assert(*narray/2 <= na && na <= *narray);
|
*pna = na;
|
||||||
return 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) {
|
static unsigned int numusearray (const Table *t, unsigned int *nums) {
|
||||||
int lg;
|
int lg;
|
||||||
unsigned int ttlg; /* 2^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,
|
static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) {
|
||||||
unsigned int *pnasize) {
|
|
||||||
int totaluse = 0; /* total number of elements */
|
int totaluse = 0; /* total number of elements */
|
||||||
int ause = 0; /* elements added to 'nums' (can go to array part) */
|
int ause = 0; /* elements added to 'nums' (can go to array part) */
|
||||||
int i = sizenode(t);
|
int i = sizenode(t);
|
||||||
|
@ -293,7 +291,7 @@ static int numusehash (const Table *t, unsigned int *nums,
|
||||||
totaluse++;
|
totaluse++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*pnasize += ause;
|
*pna += ause;
|
||||||
return totaluse;
|
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) {
|
static void setnodevector (lua_State *L, Table *t, unsigned int size) {
|
||||||
int lsize;
|
|
||||||
if (size == 0) { /* no elements to hash part? */
|
if (size == 0) { /* no elements to hash part? */
|
||||||
t->node = cast(Node *, dummynode); /* use common 'dummynode' */
|
t->node = cast(Node *, dummynode); /* use common 'dummynode' */
|
||||||
lsize = 0;
|
t->lsizenode = 0;
|
||||||
|
t->lastfree = NULL; /* signal that it is using dummy node */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int i;
|
int i;
|
||||||
lsize = luaO_ceillog2(size);
|
int lsize = luaO_ceillog2(size);
|
||||||
if (lsize > MAXHBITS)
|
if (lsize > MAXHBITS)
|
||||||
luaG_runerror(L, "table overflow");
|
luaG_runerror(L, "table overflow");
|
||||||
size = twoto(lsize);
|
size = twoto(lsize);
|
||||||
|
@ -326,9 +324,9 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
|
||||||
setnilvalue(wgkey(n));
|
setnilvalue(wgkey(n));
|
||||||
setnilvalue(gval(n));
|
setnilvalue(gval(n));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
t->lsizenode = cast_byte(lsize);
|
t->lsizenode = cast_byte(lsize);
|
||||||
t->lastfree = gnode(t, size); /* all positions are free */
|
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;
|
unsigned int i;
|
||||||
int j;
|
int j;
|
||||||
unsigned int oldasize = t->sizearray;
|
unsigned int oldasize = t->sizearray;
|
||||||
int oldhsize = t->lsizenode;
|
int oldhsize = allocsizenode(t);
|
||||||
Node *nold = t->node; /* save old hash ... */
|
Node *nold = t->node; /* save old hash ... */
|
||||||
if (nasize > oldasize) /* array part must grow? */
|
if (nasize > oldasize) /* array part must grow? */
|
||||||
setarrayvector(L, t, nasize);
|
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);
|
luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
|
||||||
}
|
}
|
||||||
/* re-insert elements from hash part */
|
/* 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;
|
Node *old = nold + j;
|
||||||
if (!ttisnil(gval(old))) {
|
if (!ttisnil(gval(old))) {
|
||||||
/* doesn't need barrier/invalidate cache, as entry was
|
/* 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));
|
setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isdummy(nold))
|
if (oldhsize > 0) /* not the dummy node? */
|
||||||
luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old array */
|
luaM_freearray(L, nold, cast(size_t, oldhsize)); /* free old hash */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) {
|
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);
|
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
|
** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i
|
||||||
*/
|
*/
|
||||||
static void rehash (lua_State *L, Table *t, const TValue *ek) {
|
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];
|
unsigned int nums[MAXABITS + 1];
|
||||||
int i;
|
int i;
|
||||||
int totaluse;
|
int totaluse;
|
||||||
for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */
|
for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */
|
||||||
nasize = numusearray(t, nums); /* count keys in array part */
|
na = numusearray(t, nums); /* count keys in array part */
|
||||||
totaluse = nasize; /* all those keys are integer keys */
|
totaluse = na; /* all those keys are integer keys */
|
||||||
totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */
|
totaluse += numusehash(t, nums, &na); /* count keys in hash part */
|
||||||
/* count extra key */
|
/* count extra key */
|
||||||
nasize += countint(ek, nums);
|
na += countint(ek, nums);
|
||||||
totaluse++;
|
totaluse++;
|
||||||
/* compute new size for array part */
|
/* compute new size for array part */
|
||||||
na = computesizes(nums, &nasize);
|
asize = computesizes(nums, &na);
|
||||||
/* resize the table to new computed sizes */
|
/* 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) {
|
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->node, cast(size_t, sizenode(t)));
|
||||||
luaM_freearray(L, t->array, t->sizearray);
|
luaM_freearray(L, t->array, t->sizearray);
|
||||||
luaM_free(L, t);
|
luaM_free(L, t);
|
||||||
|
@ -421,11 +420,13 @@ void luaH_free (lua_State *L, Table *t) {
|
||||||
|
|
||||||
|
|
||||||
static Node *getfreepos (Table *t) {
|
static Node *getfreepos (Table *t) {
|
||||||
|
if (!isdummy(t)) {
|
||||||
while (t->lastfree > t->node) {
|
while (t->lastfree > t->node) {
|
||||||
t->lastfree--;
|
t->lastfree--;
|
||||||
if (ttisnil(gkey(t->lastfree)))
|
if (ttisnil(gkey(t->lastfree)))
|
||||||
return t->lastfree;
|
return t->lastfree;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return NULL; /* could not find a free place */
|
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;
|
TValue aux;
|
||||||
if (ttisnil(key)) luaG_runerror(L, "table index is nil");
|
if (ttisnil(key)) luaG_runerror(L, "table index is nil");
|
||||||
else if (ttisfloat(key)) {
|
else if (ttisfloat(key)) {
|
||||||
lua_Number n = fltvalue(key);
|
|
||||||
lua_Integer k;
|
lua_Integer k;
|
||||||
if (luai_numisnan(n))
|
if (luaV_tointeger(key, &k, 0)) { /* does index fit in an integer? */
|
||||||
luaG_runerror(L, "table index is NaN");
|
|
||||||
if (numisinteger(n, &k)) { /* index is int? */
|
|
||||||
setivalue(&aux, k);
|
setivalue(&aux, k);
|
||||||
key = &aux; /* insert it as an integer */
|
key = &aux; /* insert it as an integer */
|
||||||
}
|
}
|
||||||
|
else if (luai_numisnan(fltvalue(key)))
|
||||||
|
luaG_runerror(L, "table index is NaN");
|
||||||
}
|
}
|
||||||
mp = mainposition(t, key);
|
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 *othern;
|
||||||
Node *f = getfreepos(t); /* get a free place */
|
Node *f = getfreepos(t); /* get a free place */
|
||||||
if (f == NULL) { /* cannot find a free place? */
|
if (f == NULL) { /* cannot find a free place? */
|
||||||
rehash(L, t, key); /* grow table */
|
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 */
|
return luaH_set(L, t, key); /* insert key into grown table */
|
||||||
}
|
}
|
||||||
lua_assert(!isdummy(f));
|
lua_assert(!isdummy(t));
|
||||||
othern = mainposition(t, gkey(mp));
|
othern = mainposition(t, gkey(mp));
|
||||||
if (othern != mp) { /* is colliding node out of its main position? */
|
if (othern != mp) { /* is colliding node out of its main position? */
|
||||||
/* yes; move colliding node into free 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) {
|
const TValue *luaH_getint (Table *t, lua_Integer key) {
|
||||||
/* (1 <= key && key <= t->sizearray) */
|
/* (1 <= key && key <= t->sizearray) */
|
||||||
if (l_castS2U(key - 1) < t->sizearray)
|
if (l_castS2U(key) - 1 < t->sizearray)
|
||||||
return &t->array[key - 1];
|
return &t->array[key - 1];
|
||||||
else {
|
else {
|
||||||
Node *n = hashint(t, key);
|
Node *n = hashint(t, key);
|
||||||
|
@ -508,7 +508,7 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
|
||||||
if (nx == 0) break;
|
if (nx == 0) break;
|
||||||
n += nx;
|
n += nx;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
return luaO_nilobject;
|
return luaO_nilobject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -517,7 +517,7 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
|
||||||
/*
|
/*
|
||||||
** search function for short strings
|
** 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);
|
Node *n = hashstr(t, key);
|
||||||
lua_assert(key->tt == LUA_TSHRSTR);
|
lua_assert(key->tt == LUA_TSHRSTR);
|
||||||
for (;;) { /* check whether 'key' is somewhere in the chain */
|
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 */
|
return gval(n); /* that's it */
|
||||||
else {
|
else {
|
||||||
int nx = gnext(n);
|
int nx = gnext(n);
|
||||||
if (nx == 0) break;
|
if (nx == 0)
|
||||||
|
return luaO_nilobject; /* not found */
|
||||||
n += nx;
|
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) {
|
const TValue *luaH_get (Table *t, const TValue *key) {
|
||||||
switch (ttype(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_TNUMINT: return luaH_getint(t, ivalue(key));
|
||||||
case LUA_TNIL: return luaO_nilobject;
|
case LUA_TNIL: return luaO_nilobject;
|
||||||
case LUA_TNUMFLT: {
|
case LUA_TNUMFLT: {
|
||||||
lua_Integer k;
|
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 */
|
return luaH_getint(t, k); /* use specialized version */
|
||||||
/* else go through */
|
/* else... */
|
||||||
}
|
} /* FALLTHROUGH */
|
||||||
default: {
|
default:
|
||||||
Node *n = mainposition(t, key);
|
return getgeneric(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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,7 +651,7 @@ int luaH_getn (Table *t) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
/* else must find a boundary in hash part */
|
/* 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... */
|
return j; /* that is easy... */
|
||||||
else return unbound_search(t, j);
|
else return unbound_search(t, j);
|
||||||
}
|
}
|
||||||
|
@ -645,6 +664,6 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
|
||||||
return mainposition(t, key);
|
return mainposition(t, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
int luaH_isdummy (Node *n) { return isdummy(n); }
|
int luaH_isdummy (const Table *t) { return isdummy(t); }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
17
src/ltable.h
17
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)
|
** Lua tables (hash)
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -18,11 +18,23 @@
|
||||||
/* '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))
|
#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 wgkey(n) (&(n)->i_key.nk)
|
||||||
|
|
||||||
#define invalidateTMcache(t) ((t)->flags = 0)
|
#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 */
|
/* returns the key, given the value of a table entry */
|
||||||
#define keyfromval(v) \
|
#define keyfromval(v) \
|
||||||
(gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val))))
|
(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 const TValue *luaH_getint (Table *t, lua_Integer key);
|
||||||
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
|
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
|
||||||
TValue *value);
|
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_getstr (Table *t, TString *key);
|
||||||
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *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);
|
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)
|
#if defined(LUA_DEBUG)
|
||||||
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
|
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
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
383
src/ltablib.c
383
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
|
** Library for Table Manipulation
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
@ -19,40 +20,42 @@
|
||||||
#include "lualib.h"
|
#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 {
|
#define TAB_R 1 /* read */
|
||||||
int (*geti) (lua_State *L, int idx, lua_Integer n);
|
#define TAB_W 2 /* write */
|
||||||
void (*seti) (lua_State *L, int idx, lua_Integer n);
|
#define TAB_L 4 /* length */
|
||||||
} TabA;
|
#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))
|
||||||
** Check that 'arg' has a table and set access functions in 'ta' to raw
|
|
||||||
** or non-raw according to the presence of corresponding metamethods.
|
|
||||||
*/
|
static int checkfield (lua_State *L, const char *key, int n) {
|
||||||
static void checktab (lua_State *L, int arg, TabA *ta) {
|
lua_pushstring(L, key);
|
||||||
ta->geti = NULL; ta->seti = NULL;
|
return (lua_rawget(L, -n) != LUA_TNIL);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define aux_getn(L,n,ta) (checktab(L, n, ta), luaL_len(L, n))
|
/*
|
||||||
|
** 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, 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 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(LUA_COMPAT_MAXN)
|
#if defined(LUA_COMPAT_MAXN)
|
||||||
|
@ -74,8 +77,7 @@ static int maxn (lua_State *L) {
|
||||||
|
|
||||||
|
|
||||||
static int tinsert (lua_State *L) {
|
static int tinsert (lua_State *L) {
|
||||||
TabA ta;
|
lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */
|
||||||
lua_Integer e = aux_getn(L, 1, &ta) + 1; /* first empty element */
|
|
||||||
lua_Integer pos; /* where to insert new element */
|
lua_Integer pos; /* where to insert new element */
|
||||||
switch (lua_gettop(L)) {
|
switch (lua_gettop(L)) {
|
||||||
case 2: { /* called with only 2 arguments */
|
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 */
|
pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */
|
||||||
luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds");
|
luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds");
|
||||||
for (i = e; i > pos; i--) { /* move up elements */
|
for (i = e; i > pos; i--) { /* move up elements */
|
||||||
(*ta.geti)(L, 1, i - 1);
|
lua_geti(L, 1, i - 1);
|
||||||
(*ta.seti)(L, 1, i); /* t[i] = t[i - 1] */
|
lua_seti(L, 1, i); /* t[i] = t[i - 1] */
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -96,65 +98,67 @@ static int tinsert (lua_State *L) {
|
||||||
return luaL_error(L, "wrong number of arguments to 'insert'");
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int tremove (lua_State *L) {
|
static int tremove (lua_State *L) {
|
||||||
TabA ta;
|
lua_Integer size = aux_getn(L, 1, TAB_RW);
|
||||||
lua_Integer size = aux_getn(L, 1, &ta);
|
|
||||||
lua_Integer pos = luaL_optinteger(L, 2, size);
|
lua_Integer pos = luaL_optinteger(L, 2, size);
|
||||||
if (pos != size) /* validate 'pos' if given */
|
if (pos != size) /* validate 'pos' if given */
|
||||||
luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds");
|
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++) {
|
for ( ; pos < size; pos++) {
|
||||||
(*ta.geti)(L, 1, pos + 1);
|
lua_geti(L, 1, pos + 1);
|
||||||
(*ta.seti)(L, 1, pos); /* t[pos] = t[pos + 1] */
|
lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */
|
||||||
}
|
}
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
(*ta.seti)(L, 1, pos); /* t[pos] = nil */
|
lua_seti(L, 1, pos); /* t[pos] = nil */
|
||||||
return 1;
|
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) {
|
static int tmove (lua_State *L) {
|
||||||
TabA ta;
|
|
||||||
lua_Integer f = luaL_checkinteger(L, 2);
|
lua_Integer f = luaL_checkinteger(L, 2);
|
||||||
lua_Integer e = luaL_checkinteger(L, 3);
|
lua_Integer e = luaL_checkinteger(L, 3);
|
||||||
lua_Integer t = luaL_checkinteger(L, 4);
|
lua_Integer t = luaL_checkinteger(L, 4);
|
||||||
int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */
|
int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */
|
||||||
/* the following restriction avoids several problems with overflows */
|
checktab(L, 1, TAB_R);
|
||||||
luaL_argcheck(L, f > 0, 2, "initial position must be positive");
|
checktab(L, tt, TAB_W);
|
||||||
if (e >= f) { /* otherwise, nothing to move */
|
if (e >= f) { /* otherwise, nothing to move */
|
||||||
lua_Integer n, i;
|
lua_Integer n, i;
|
||||||
ta.geti = (luaL_getmetafield(L, 1, "__index") == LUA_TNIL)
|
luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3,
|
||||||
? (luaL_checktype(L, 1, LUA_TTABLE), lua_rawgeti)
|
"too many elements to move");
|
||||||
: lua_geti;
|
|
||||||
ta.seti = (luaL_getmetafield(L, tt, "__newindex") == LUA_TNIL)
|
|
||||||
? (luaL_checktype(L, tt, LUA_TTABLE), lua_rawseti)
|
|
||||||
: lua_seti;
|
|
||||||
n = e - f + 1; /* number of elements to move */
|
n = e - f + 1; /* number of elements to move */
|
||||||
if (t > f) {
|
luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4,
|
||||||
for (i = n - 1; i >= 0; i--) {
|
"destination wrap around");
|
||||||
(*ta.geti)(L, 1, f + i);
|
if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) {
|
||||||
(*ta.seti)(L, tt, t + i);
|
for (i = 0; i < n; i++) {
|
||||||
|
lua_geti(L, 1, f + i);
|
||||||
|
lua_seti(L, tt, t + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (i = 0; i < n; i++) {
|
for (i = n - 1; i >= 0; i--) {
|
||||||
(*ta.geti)(L, 1, f + i);
|
lua_geti(L, 1, f + i);
|
||||||
(*ta.seti)(L, tt, t + i);
|
lua_seti(L, tt, t + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lua_pushvalue(L, tt); /* return "to table" */
|
lua_pushvalue(L, tt); /* return destination table */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void addfield (lua_State *L, luaL_Buffer *b, TabA *ta, lua_Integer i) {
|
static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
|
||||||
(*ta->geti)(L, 1, i);
|
lua_geti(L, 1, i);
|
||||||
if (!lua_isstring(L, -1))
|
if (!lua_isstring(L, -1))
|
||||||
luaL_error(L, "invalid value (%s) at index %d in table for 'concat'",
|
luaL_error(L, "invalid value (%s) at index %d in table for 'concat'",
|
||||||
luaL_typename(L, -1), i);
|
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) {
|
static int tconcat (lua_State *L) {
|
||||||
TabA ta;
|
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
|
lua_Integer last = aux_getn(L, 1, TAB_R);
|
||||||
size_t lsep;
|
size_t lsep;
|
||||||
lua_Integer i, last;
|
|
||||||
const char *sep = luaL_optlstring(L, 2, "", &lsep);
|
const char *sep = luaL_optlstring(L, 2, "", &lsep);
|
||||||
checktab(L, 1, &ta);
|
lua_Integer i = luaL_optinteger(L, 3, 1);
|
||||||
i = luaL_optinteger(L, 3, 1);
|
last = luaL_optinteger(L, 4, last);
|
||||||
last = luaL_opt(L, luaL_checkinteger, 4, luaL_len(L, 1));
|
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
for (; i < last; i++) {
|
for (; i < last; i++) {
|
||||||
addfield(L, &b, &ta, i);
|
addfield(L, &b, i);
|
||||||
luaL_addlstring(&b, sep, lsep);
|
luaL_addlstring(&b, sep, lsep);
|
||||||
}
|
}
|
||||||
if (i == last) /* add last value (if interval was not empty) */
|
if (i == last) /* add last value (if interval was not empty) */
|
||||||
addfield(L, &b, &ta, i);
|
addfield(L, &b, i);
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -195,7 +197,7 @@ static int pack (lua_State *L) {
|
||||||
lua_createtable(L, n, 1); /* create result table */
|
lua_createtable(L, n, 1); /* create result table */
|
||||||
lua_insert(L, 1); /* put it at index 1 */
|
lua_insert(L, 1); /* put it at index 1 */
|
||||||
for (i = n; i >= 1; i--) /* assign elements */
|
for (i = n; i >= 1; i--) /* assign elements */
|
||||||
lua_rawseti(L, 1, i);
|
lua_seti(L, 1, i);
|
||||||
lua_pushinteger(L, n);
|
lua_pushinteger(L, n);
|
||||||
lua_setfield(L, 1, "n"); /* t.n = number of elements */
|
lua_setfield(L, 1, "n"); /* t.n = number of elements */
|
||||||
return 1; /* return table */
|
return 1; /* return table */
|
||||||
|
@ -203,20 +205,17 @@ static int pack (lua_State *L) {
|
||||||
|
|
||||||
|
|
||||||
static int unpack (lua_State *L) {
|
static int unpack (lua_State *L) {
|
||||||
TabA ta;
|
|
||||||
lua_Integer i, e;
|
|
||||||
lua_Unsigned n;
|
lua_Unsigned n;
|
||||||
checktab(L, 1, &ta);
|
lua_Integer i = luaL_optinteger(L, 2, 1);
|
||||||
i = luaL_optinteger(L, 2, 1);
|
lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
|
||||||
e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
|
|
||||||
if (i > e) return 0; /* empty range */
|
if (i > e) return 0; /* empty range */
|
||||||
n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */
|
n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */
|
||||||
if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n)))
|
if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n)))
|
||||||
return luaL_error(L, "too many results to unpack");
|
return luaL_error(L, "too many results to unpack");
|
||||||
do { /* must have at least one element */
|
for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */
|
||||||
(*ta.geti)(L, 1, i); /* push arg[i..e] */
|
lua_geti(L, 1, i);
|
||||||
} while (i++ < e);
|
}
|
||||||
|
lua_geti(L, 1, e); /* push last element */
|
||||||
return (int)n;
|
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) {
|
/* type for array indices */
|
||||||
(*ta->seti)(L, 1, i);
|
typedef unsigned int IdxT;
|
||||||
(*ta->seti)(L, 1, j);
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 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) {
|
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;
|
int res;
|
||||||
lua_pushvalue(L, 2);
|
lua_pushvalue(L, 2); /* push function */
|
||||||
lua_pushvalue(L, a-1); /* -1 to compensate function */
|
lua_pushvalue(L, a-1); /* -1 to compensate function */
|
||||||
lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */
|
lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */
|
||||||
lua_call(L, 2, 1);
|
lua_call(L, 2, 1); /* call function */
|
||||||
res = lua_toboolean(L, -1);
|
res = lua_toboolean(L, -1); /* get result */
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1); /* pop result */
|
||||||
return res;
|
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;
|
** Does the partition: Pivot P is at the top of the stack.
|
||||||
/* sort elements a[l], a[(l+u)/2] and a[u] */
|
** precondition: a[lo] <= P == a[up-1] <= a[up],
|
||||||
(*ta->geti)(L, 1, l);
|
** so it only needs to do the partition from lo + 1 to up - 2.
|
||||||
(*ta->geti)(L, 1, u);
|
** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up]
|
||||||
if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */
|
** returns 'i'.
|
||||||
set2(L, ta, l, u); /* swap a[l] - a[u] */
|
*/
|
||||||
else
|
static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
|
||||||
lua_pop(L, 2);
|
IdxT i = lo; /* will be incremented before first use */
|
||||||
if (u-l == 1) break; /* only 2 elements */
|
IdxT j = up - 1; /* will be decremented before first use */
|
||||||
i = (l+u)/2;
|
/* loop invariant: a[lo .. i] <= P <= a[j .. up] */
|
||||||
(*ta->geti)(L, 1, i);
|
for (;;) {
|
||||||
(*ta->geti)(L, 1, l);
|
/* next loop: repeat ++i while a[i] < P */
|
||||||
if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */
|
while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) {
|
||||||
set2(L, ta, i, l);
|
if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */
|
||||||
else {
|
luaL_error(L, "invalid order function for sorting");
|
||||||
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);
|
|
||||||
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] */
|
lua_pop(L, 1); /* remove a[i] */
|
||||||
}
|
}
|
||||||
/* repeat --j until a[j] <= P */
|
/* after the loop, a[i] >= P and a[lo .. i - 1] < P */
|
||||||
while ((*ta->geti)(L, 1, --j), sort_comp(L, -3, -1)) {
|
/* next loop: repeat --j while P < a[j] */
|
||||||
if (j<=l) luaL_error(L, "invalid order function for sorting");
|
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] */
|
lua_pop(L, 1); /* remove a[j] */
|
||||||
}
|
}
|
||||||
if (j<i) {
|
/* after the loop, a[j] <= P and a[j + 1 .. up] >= P */
|
||||||
lua_pop(L, 3); /* pop pivot, a[i], a[j] */
|
if (j < i) { /* no elements out of place? */
|
||||||
break;
|
/* 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;
|
||||||
}
|
}
|
||||||
set2(L, ta, i, j);
|
/* otherwise, swap a[i] - a[j] to restore invariant and repeat */
|
||||||
|
set2(L, 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;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
j=i+1; i=u; u=j-2;
|
|
||||||
}
|
|
||||||
auxsort(L, ta, j, i); /* call recursively the smaller one */
|
|
||||||
} /* repeat the routine for the larger one */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 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); /* 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[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 (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 {
|
||||||
|
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) */
|
||||||
|
}
|
||||||
|
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) {
|
static int sort (lua_State *L) {
|
||||||
TabA ta;
|
lua_Integer n = aux_getn(L, 1, TAB_RW);
|
||||||
int n = (int)aux_getn(L, 1, &ta);
|
if (n > 1) { /* non-trivial interval? */
|
||||||
luaL_checkstack(L, 50, ""); /* assume array is smaller than 2^50 */
|
luaL_argcheck(L, n < INT_MAX, 1, "array too big");
|
||||||
if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
|
if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
|
||||||
luaL_checktype(L, 2, LUA_TFUNCTION);
|
luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */
|
||||||
lua_settop(L, 2); /* make sure there are two arguments */
|
lua_settop(L, 2); /* make sure there are two arguments */
|
||||||
auxsort(L, &ta, 1, n);
|
auxsort(L, 1, (IdxT)n, 0);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
38
src/ltm.c
38
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
|
** Tag methods
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -57,7 +57,7 @@ void luaT_init (lua_State *L) {
|
||||||
** tag methods
|
** tag methods
|
||||||
*/
|
*/
|
||||||
const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
|
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);
|
lua_assert(event <= TM_EQ);
|
||||||
if (ttisnil(tm)) { /* no tag method? */
|
if (ttisnil(tm)) { /* no tag method? */
|
||||||
events->flags |= cast_byte(1u<<event); /* cache this fact */
|
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:
|
default:
|
||||||
mt = G(L)->mt[ttnov(o)];
|
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,
|
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
|
||||||
const TValue *p2, TValue *p3, int hasres) {
|
const TValue *p2, TValue *p3, int hasres) {
|
||||||
ptrdiff_t result = savestack(L, p3);
|
ptrdiff_t result = savestack(L, p3);
|
||||||
setobj2s(L, L->top++, f); /* push function (assume EXTRA_STACK) */
|
StkId func = L->top;
|
||||||
setobj2s(L, L->top++, p1); /* 1st argument */
|
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
|
||||||
setobj2s(L, L->top++, p2); /* 2nd argument */
|
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 */
|
if (!hasres) /* no result? 'p3' is third argument */
|
||||||
setobj2s(L, L->top++, p3); /* 3rd argument */
|
setobj2s(L, L->top++, p3); /* 3rd argument */
|
||||||
/* metamethod may yield only when called from Lua code */
|
/* 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 */
|
if (hasres) { /* if has result, move it to its place */
|
||||||
p3 = restorestack(L, result);
|
p3 = restorestack(L, result);
|
||||||
setobjs2s(L, p3, --L->top);
|
setobjs2s(L, p3, --L->top);
|
||||||
|
@ -117,6 +138,7 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case TM_CONCAT:
|
case TM_CONCAT:
|
||||||
luaG_concaterror(L, p1, p2);
|
luaG_concaterror(L, p1, p2);
|
||||||
|
/* call never returns, but to avoid warnings: *//* FALLTHROUGH */
|
||||||
case TM_BAND: case TM_BOR: case TM_BXOR:
|
case TM_BAND: case TM_BOR: case TM_BXOR:
|
||||||
case TM_SHL: case TM_SHR: case TM_BNOT: {
|
case TM_SHL: case TM_SHR: case TM_BNOT: {
|
||||||
lua_Number dummy;
|
lua_Number dummy;
|
||||||
|
@ -124,8 +146,8 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
||||||
luaG_tointerror(L, p1, p2);
|
luaG_tointerror(L, p1, p2);
|
||||||
else
|
else
|
||||||
luaG_opinterror(L, p1, p2, "perform bitwise operation on");
|
luaG_opinterror(L, p1, p2, "perform bitwise operation on");
|
||||||
/* else go through */
|
|
||||||
}
|
}
|
||||||
|
/* calls never return, but to avoid warnings: *//* FALLTHROUGH */
|
||||||
default:
|
default:
|
||||||
luaG_opinterror(L, p1, p2, "perform arithmetic on");
|
luaG_opinterror(L, p1, p2, "perform arithmetic on");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
** Tag methods
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -51,11 +51,12 @@ typedef enum {
|
||||||
#define fasttm(l,et,e) gfasttm(G(l), et, e)
|
#define fasttm(l,et,e) gfasttm(G(l), et, e)
|
||||||
|
|
||||||
#define ttypename(x) luaT_typenames_[(x) + 1]
|
#define ttypename(x) luaT_typenames_[(x) + 1]
|
||||||
#define objtypename(x) ttypename(ttnov(x))
|
|
||||||
|
|
||||||
LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS];
|
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_gettm (Table *events, TMS event, TString *ename);
|
||||||
LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,
|
LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,
|
||||||
TMS event);
|
TMS event);
|
||||||
|
|
57
src/lua.c
57
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
|
** Lua stand-alone interpreter
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -20,6 +20,7 @@
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined(LUA_PROMPT)
|
#if !defined(LUA_PROMPT)
|
||||||
#define LUA_PROMPT "> "
|
#define LUA_PROMPT "> "
|
||||||
#define LUA_PROMPT2 ">> "
|
#define LUA_PROMPT2 ">> "
|
||||||
|
@ -37,8 +38,7 @@
|
||||||
#define LUA_INIT_VAR "LUA_INIT"
|
#define LUA_INIT_VAR "LUA_INIT"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LUA_INITVARVERSION \
|
#define LUA_INITVARVERSION LUA_INIT_VAR LUA_VERSUFFIX
|
||||||
LUA_INIT_VAR "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -55,6 +55,8 @@
|
||||||
#elif defined(LUA_USE_WINDOWS) /* }{ */
|
#elif defined(LUA_USE_WINDOWS) /* }{ */
|
||||||
|
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
#define lua_stdin_is_tty() _isatty(_fileno(stdin))
|
#define lua_stdin_is_tty() _isatty(_fileno(stdin))
|
||||||
|
|
||||||
#else /* }{ */
|
#else /* }{ */
|
||||||
|
@ -80,9 +82,7 @@
|
||||||
#include <readline/readline.h>
|
#include <readline/readline.h>
|
||||||
#include <readline/history.h>
|
#include <readline/history.h>
|
||||||
#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL)
|
#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL)
|
||||||
#define lua_saveline(L,idx) \
|
#define lua_saveline(L,line) ((void)L, add_history(line))
|
||||||
if (lua_rawlen(L,idx) > 0) /* non-empty line? */ \
|
|
||||||
add_history(lua_tostring(L, idx)); /* add it to history */
|
|
||||||
#define lua_freeline(L,b) ((void)L, free(b))
|
#define lua_freeline(L,b) ((void)L, free(b))
|
||||||
|
|
||||||
#else /* }{ */
|
#else /* }{ */
|
||||||
|
@ -90,7 +90,7 @@
|
||||||
#define lua_readline(L,b,p) \
|
#define lua_readline(L,b,p) \
|
||||||
((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \
|
((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \
|
||||||
fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */
|
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; }
|
#define lua_freeline(L,b) { (void)L; (void)b; }
|
||||||
|
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
|
@ -315,31 +315,31 @@ static int pushline (lua_State *L, int firstline) {
|
||||||
lua_pop(L, 1); /* remove prompt */
|
lua_pop(L, 1); /* remove prompt */
|
||||||
l = strlen(b);
|
l = strlen(b);
|
||||||
if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
|
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, ... */
|
if (firstline && b[0] == '=') /* for compatibility with 5.2, ... */
|
||||||
lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */
|
lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */
|
||||||
else
|
else
|
||||||
lua_pushstring(L, b);
|
lua_pushlstring(L, b, l);
|
||||||
lua_freeline(L, b);
|
lua_freeline(L, b);
|
||||||
return 1;
|
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).
|
** has either compiled chunk or original line (if compilation failed).
|
||||||
*/
|
*/
|
||||||
static int addreturn (lua_State *L) {
|
static int addreturn (lua_State *L) {
|
||||||
int status;
|
const char *line = lua_tostring(L, -1); /* original line */
|
||||||
size_t len; const char *line;
|
const char *retline = lua_pushfstring(L, "return %s;", line);
|
||||||
lua_pushliteral(L, "return ");
|
int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin");
|
||||||
lua_pushvalue(L, -2); /* duplicate line */
|
if (status == LUA_OK) {
|
||||||
lua_concat(L, 2); /* new line is "return ..." */
|
lua_remove(L, -2); /* remove modified line */
|
||||||
line = lua_tolstring(L, -1, &len);
|
if (line[0] != '\0') /* non empty? */
|
||||||
if ((status = luaL_loadbuffer(L, line, len, "=stdin")) == LUA_OK)
|
lua_saveline(L, line); /* keep history */
|
||||||
lua_remove(L, -3); /* remove original line */
|
}
|
||||||
else
|
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;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,8 +352,10 @@ static int multiline (lua_State *L) {
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *line = lua_tolstring(L, 1, &len); /* get what it has */
|
const char *line = lua_tolstring(L, 1, &len); /* get what it has */
|
||||||
int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */
|
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 */
|
return status; /* cannot or should not try to add continuation line */
|
||||||
|
}
|
||||||
lua_pushliteral(L, "\n"); /* add newline... */
|
lua_pushliteral(L, "\n"); /* add newline... */
|
||||||
lua_insert(L, -2); /* ...between the two lines */
|
lua_insert(L, -2); /* ...between the two lines */
|
||||||
lua_concat(L, 3); /* join them */
|
lua_concat(L, 3); /* join them */
|
||||||
|
@ -374,7 +376,6 @@ static int loadline (lua_State *L) {
|
||||||
return -1; /* no input */
|
return -1; /* no input */
|
||||||
if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */
|
if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */
|
||||||
status = multiline(L); /* try as command, maybe with continuation lines */
|
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_remove(L, 1); /* remove line from the stack */
|
||||||
lua_assert(lua_gettop(L) == 1);
|
lua_assert(lua_gettop(L) == 1);
|
||||||
return status;
|
return status;
|
||||||
|
@ -482,14 +483,14 @@ static int collectargs (char **argv, int *first) {
|
||||||
args |= has_E;
|
args |= has_E;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
args |= has_i; /* goes through (-i implies -v) */
|
args |= has_i; /* (-i implies -v) *//* FALLTHROUGH */
|
||||||
case 'v':
|
case 'v':
|
||||||
if (argv[i][2] != '\0') /* extra characters after 1st? */
|
if (argv[i][2] != '\0') /* extra characters after 1st? */
|
||||||
return has_error; /* invalid option */
|
return has_error; /* invalid option */
|
||||||
args |= has_v;
|
args |= has_v;
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
args |= has_e; /* go through */
|
args |= has_e; /* FALLTHROUGH */
|
||||||
case 'l': /* both options need an argument */
|
case 'l': /* both options need an argument */
|
||||||
if (argv[i][2] == '\0') { /* no concatenated argument? */
|
if (argv[i][2] == '\0') { /* no concatenated argument? */
|
||||||
i++; /* try next 'argv' */
|
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) {
|
static int runargs (lua_State *L, char **argv, int n) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 1; i < n; i++) {
|
for (i = 1; i < n; i++) {
|
||||||
int status;
|
|
||||||
int option = argv[i][1];
|
int option = argv[i][1];
|
||||||
lua_assert(argv[i][0] == '-'); /* already checked */
|
lua_assert(argv[i][0] == '-'); /* already checked */
|
||||||
if (option == 'e' || option == 'l') {
|
if (option == 'e' || option == 'l') {
|
||||||
|
int status;
|
||||||
const char *extra = argv[i] + 2; /* both options need an argument */
|
const char *extra = argv[i] + 2; /* both options need an argument */
|
||||||
if (*extra == '\0') extra = argv[++i];
|
if (*extra == '\0') extra = argv[++i];
|
||||||
lua_assert(extra != NULL);
|
lua_assert(extra != NULL);
|
||||||
if (option == 'e')
|
status = (option == 'e')
|
||||||
status = dostring(L, extra, "=(command line)");
|
? dostring(L, extra, "=(command line)")
|
||||||
else
|
: dolibrary(L, extra);
|
||||||
status = dolibrary(L, extra);
|
|
||||||
if (status != LUA_OK) return 0;
|
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) {
|
static int handle_luainit (lua_State *L) {
|
||||||
const char *name = "=" LUA_INITVARVERSION;
|
const char *name = "=" LUA_INITVARVERSION;
|
||||||
const char *init = getenv(name + 1);
|
const char *init = getenv(name + 1);
|
||||||
|
|
19
src/lua.h
19
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 - A Scripting Language
|
||||||
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
|
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
|
||||||
** See Copyright Notice at the end of this file
|
** See Copyright Notice at the end of this file
|
||||||
|
@ -19,11 +19,11 @@
|
||||||
#define LUA_VERSION_MAJOR "5"
|
#define LUA_VERSION_MAJOR "5"
|
||||||
#define LUA_VERSION_MINOR "3"
|
#define LUA_VERSION_MINOR "3"
|
||||||
#define LUA_VERSION_NUM 503
|
#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_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
|
||||||
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
|
#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"
|
#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))
|
#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_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
|
||||||
#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
|
#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
|
||||||
|
|
||||||
#define lua_pushliteral(L, s) \
|
#define lua_pushliteral(L, s) lua_pushstring(L, "" s)
|
||||||
lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)
|
|
||||||
|
|
||||||
#define lua_pushglobaltable(L) \
|
#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)
|
#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
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
|
|
|
@ -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)
|
** Lua compiler (saves bytecodes to files; also lists bytecodes)
|
||||||
** See Copyright Notice in lua.h
|
** 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
|
** print bytecodes
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -226,7 +226,7 @@ int main(int argc, char* argv[])
|
||||||
static void PrintString(const TString* ts)
|
static void PrintString(const TString* ts)
|
||||||
{
|
{
|
||||||
const char* s=getstr(ts);
|
const char* s=getstr(ts);
|
||||||
size_t i,n=ts->len;
|
size_t i,n=tsslen(ts);
|
||||||
printf("%c",'"');
|
printf("%c",'"');
|
||||||
for (i=0; i<n; i++)
|
for (i=0; i<n; i++)
|
||||||
{
|
{
|
||||||
|
|
318
src/luaconf.h
318
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
|
** Configuration file for Lua
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -96,10 +96,8 @@
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUA_INT_INT / LUA_INT_LONG / LUA_INT_LONGLONG defines the type for
|
@@ LUA_INT_TYPE defines the type for Lua integers.
|
||||||
** Lua integers.
|
@@ LUA_FLOAT_TYPE defines the type for Lua floats.
|
||||||
@@ LUA_REAL_FLOAT / LUA_REAL_DOUBLE / LUA_REAL_LONGDOUBLE defines
|
|
||||||
** the type for Lua floats.
|
|
||||||
** Lua should work fine with any mix of these options (if supported
|
** Lua should work fine with any mix of these options (if supported
|
||||||
** by your C compiler). The usual configurations are 64-bit integers
|
** by your C compiler). The usual configurations are 64-bit integers
|
||||||
** and 'double' (the default), 32-bit integers and 'float' (for
|
** 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').
|
** 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) /* { */
|
#if defined(LUA_32BITS) /* { */
|
||||||
/*
|
/*
|
||||||
** 32-bit integers and 'float'
|
** 32-bit integers and 'float'
|
||||||
*/
|
*/
|
||||||
#if LUAI_BITSINT >= 32 /* use 'int' if big enough */
|
#if LUAI_BITSINT >= 32 /* use 'int' if big enough */
|
||||||
#define LUA_INT_INT
|
#define LUA_INT_TYPE LUA_INT_INT
|
||||||
#else /* otherwise use 'long' */
|
#else /* otherwise use 'long' */
|
||||||
#define LUA_INT_LONG
|
#define LUA_INT_TYPE LUA_INT_LONG
|
||||||
#endif
|
#endif
|
||||||
#define LUA_REAL_FLOAT
|
#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT
|
||||||
|
|
||||||
#elif defined(LUA_C89_NUMBERS) /* }{ */
|
#elif defined(LUA_C89_NUMBERS) /* }{ */
|
||||||
/*
|
/*
|
||||||
** largest types available for C89 ('long' and 'double')
|
** largest types available for C89 ('long' and 'double')
|
||||||
*/
|
*/
|
||||||
#define LUA_INT_LONG
|
#define LUA_INT_TYPE LUA_INT_LONG
|
||||||
#define LUA_REAL_DOUBLE
|
#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
|
||||||
|
|
||||||
|
#endif /* } */
|
||||||
|
|
||||||
|
|
||||||
#else /* }{ */
|
|
||||||
/*
|
/*
|
||||||
** default configuration for 64-bit Lua ('long long' and 'double')
|
** default configuration for 64-bit Lua ('long long' and 'double')
|
||||||
*/
|
*/
|
||||||
#define LUA_INT_LONGLONG
|
#if !defined(LUA_INT_TYPE)
|
||||||
#define LUA_REAL_DOUBLE
|
#define LUA_INT_TYPE LUA_INT_LONGLONG
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* } */
|
#if !defined(LUA_FLOAT_TYPE)
|
||||||
|
#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
|
||||||
|
#endif
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
|
@ -145,6 +158,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_PATH_DEFAULT is the default path that Lua uses to look for
|
||||||
** Lua libraries.
|
** Lua libraries.
|
||||||
|
@ -300,20 +325,15 @@
|
||||||
*/
|
*/
|
||||||
#define LUA_COMPAT_APIINTCASTS
|
#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 /* } */
|
#endif /* } */
|
||||||
|
|
||||||
|
|
||||||
#if defined(LUA_COMPAT_5_1) /* { */
|
#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'.
|
@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'.
|
||||||
** You can replace it with 'table.unpack'.
|
** You can replace it with 'table.unpack'.
|
||||||
|
@ -373,6 +393,15 @@
|
||||||
|
|
||||||
#endif /* } */
|
#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,77 +409,32 @@
|
||||||
/*
|
/*
|
||||||
** {==================================================================
|
** {==================================================================
|
||||||
** Configuration for Numbers.
|
** 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.
|
** satisfy your needs.
|
||||||
** ===================================================================
|
** ===================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUA_NUMBER is the floating-point type used by Lua.
|
@@ LUA_NUMBER is the floating-point type used by Lua.
|
||||||
**
|
@@ LUAI_UACNUMBER is the result of a 'default argument promotion'
|
||||||
@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
|
|
||||||
@@ over a floating number.
|
@@ 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_FRMLEN is the length modifier for writing floats.
|
||||||
@@ LUA_NUMBER_FMT is the format for writing floats.
|
@@ LUA_NUMBER_FMT is the format for writing floats.
|
||||||
@@ lua_number2str converts a float to a string.
|
@@ lua_number2str converts a float to a string.
|
||||||
**
|
|
||||||
@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
|
@@ 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.
|
@@ lua_str2number converts a decimal numeric string to a number.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(LUA_REAL_FLOAT) /* { single float */
|
|
||||||
|
|
||||||
#define LUA_NUMBER float
|
|
||||||
|
|
||||||
#define LUAI_UACNUMBER double
|
|
||||||
|
|
||||||
#define LUA_NUMBER_FRMLEN ""
|
|
||||||
#define LUA_NUMBER_FMT "%.7g"
|
|
||||||
|
|
||||||
#define l_mathop(op) op##f
|
|
||||||
|
|
||||||
#define lua_str2number(s,p) strtof((s), (p))
|
|
||||||
|
|
||||||
|
|
||||||
#elif defined(LUA_REAL_LONGDOUBLE) /* }{ long double */
|
|
||||||
|
|
||||||
#define LUA_NUMBER long double
|
|
||||||
|
|
||||||
#define LUAI_UACNUMBER long double
|
|
||||||
|
|
||||||
#define LUA_NUMBER_FRMLEN "L"
|
|
||||||
#define LUA_NUMBER_FMT "%.19Lg"
|
|
||||||
|
|
||||||
#define l_mathop(op) op##l
|
|
||||||
|
|
||||||
#define lua_str2number(s,p) strtold((s), (p))
|
|
||||||
|
|
||||||
#elif defined(LUA_REAL_DOUBLE) /* }{ double */
|
|
||||||
|
|
||||||
#define LUA_NUMBER double
|
|
||||||
|
|
||||||
#define LUAI_UACNUMBER double
|
|
||||||
|
|
||||||
#define LUA_NUMBER_FRMLEN ""
|
|
||||||
#define LUA_NUMBER_FMT "%.14g"
|
|
||||||
|
|
||||||
#define l_mathop(op) op
|
|
||||||
|
|
||||||
#define lua_str2number(s,p) strtod((s), (p))
|
|
||||||
|
|
||||||
#else /* }{ */
|
|
||||||
|
|
||||||
#error "numeric real type not defined"
|
|
||||||
|
|
||||||
#endif /* } */
|
|
||||||
|
|
||||||
|
/* The following definitions are good for most cases here */
|
||||||
|
|
||||||
#define l_floor(x) (l_mathop(floor)(x))
|
#define l_floor(x) (l_mathop(floor)(x))
|
||||||
|
|
||||||
#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n))
|
#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
|
@@ lua_numbertointeger converts a float number to an integer, or
|
||||||
|
@ -466,45 +450,60 @@
|
||||||
(*(p) = (LUA_INTEGER)(n), 1))
|
(*(p) = (LUA_INTEGER)(n), 1))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/* now the variable definitions */
|
||||||
@@ 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 LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */
|
||||||
#if defined(lobject_c) || defined(lvm_c)
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
/* floor division (defined as 'floor(a/b)') */
|
#define LUA_NUMBER float
|
||||||
#define luai_numidiv(L,a,b) ((void)L, l_mathop(floor)(luai_numdiv(L,a,b)))
|
|
||||||
|
|
||||||
/*
|
#define l_mathlim(n) (FLT_##n)
|
||||||
** 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_UACNUMBER double
|
||||||
#define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b))
|
|
||||||
|
|
||||||
#endif
|
#define LUA_NUMBER_FRMLEN ""
|
||||||
|
#define LUA_NUMBER_FMT "%.7g"
|
||||||
|
|
||||||
|
#define l_mathop(op) op##f
|
||||||
|
|
||||||
|
#define lua_str2number(s,p) strtof((s), (p))
|
||||||
|
|
||||||
|
|
||||||
|
#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"
|
||||||
|
#define LUA_NUMBER_FMT "%.19Lg"
|
||||||
|
|
||||||
|
#define l_mathop(op) op##l
|
||||||
|
|
||||||
|
#define lua_str2number(s,p) strtold((s), (p))
|
||||||
|
|
||||||
|
#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 ""
|
||||||
|
#define LUA_NUMBER_FMT "%.14g"
|
||||||
|
|
||||||
|
#define l_mathop(op) op
|
||||||
|
|
||||||
|
#define lua_str2number(s,p) strtod((s), (p))
|
||||||
|
|
||||||
|
#else /* }{ */
|
||||||
|
|
||||||
|
#error "numeric float type not defined"
|
||||||
|
|
||||||
|
#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
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -512,7 +511,7 @@
|
||||||
**
|
**
|
||||||
@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
|
@@ 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.
|
@@ over a lUA_INTEGER.
|
||||||
@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
|
@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
|
||||||
@@ LUA_INTEGER_FMT is the format for writing integers.
|
@@ LUA_INTEGER_FMT is the format for writing integers.
|
||||||
|
@ -525,10 +524,12 @@
|
||||||
/* The following definitions are good for most cases here */
|
/* The following definitions are good for most cases here */
|
||||||
|
|
||||||
#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d"
|
#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 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
|
** use LUAI_UACINT here to avoid problems with promotions (which
|
||||||
** can turn a comparison between unsigneds into a signed comparison)
|
** can turn a comparison between unsigneds into a signed comparison)
|
||||||
|
@ -538,7 +539,7 @@
|
||||||
|
|
||||||
/* now the variable definitions */
|
/* 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 int
|
||||||
#define LUA_INTEGER_FRMLEN ""
|
#define LUA_INTEGER_FRMLEN ""
|
||||||
|
@ -546,7 +547,7 @@
|
||||||
#define LUA_MAXINTEGER INT_MAX
|
#define LUA_MAXINTEGER INT_MAX
|
||||||
#define LUA_MININTEGER INT_MIN
|
#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 long
|
||||||
#define LUA_INTEGER_FRMLEN "l"
|
#define LUA_INTEGER_FRMLEN "l"
|
||||||
|
@ -554,8 +555,9 @@
|
||||||
#define LUA_MAXINTEGER LONG_MAX
|
#define LUA_MAXINTEGER LONG_MAX
|
||||||
#define LUA_MININTEGER LONG_MIN
|
#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) /* { */
|
#if defined(LLONG_MAX) /* { */
|
||||||
/* use ISO C99 stuff */
|
/* use ISO C99 stuff */
|
||||||
|
|
||||||
|
@ -592,13 +594,24 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** {==================================================================
|
** {==================================================================
|
||||||
** 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.
|
@@ 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
|
** leave 'lua_strx2number' undefined and Lua will provide its own
|
||||||
** implementation.
|
** implementation.
|
||||||
*/
|
*/
|
||||||
|
@ -608,12 +621,14 @@
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUA_USE_AFORMAT allows '%a'/'%A' specifiers in 'string.format'
|
@@ lua_number2strx converts a float to an hexadecimal numeric string.
|
||||||
** Enable it if the C function 'printf' supports these specifiers.
|
** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
|
||||||
** (C99 demands it and Windows also supports it.)
|
** Otherwise, you can leave 'lua_number2strx' undefined and Lua will
|
||||||
|
** provide its own implementation.
|
||||||
*/
|
*/
|
||||||
#if !defined(LUA_USE_C89) || defined(LUA_USE_WINDOWS)
|
#if !defined(LUA_USE_C89)
|
||||||
#define LUA_USE_AFORMAT
|
#define lua_number2strx(L,b,sz,f,n) \
|
||||||
|
((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -642,12 +657,50 @@
|
||||||
#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
|
#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
|
||||||
__STDC_VERSION__ >= 199901L
|
__STDC_VERSION__ >= 199901L
|
||||||
#include <stdint.h>
|
#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
|
#undef LUA_KCONTEXT
|
||||||
#define LUA_KCONTEXT intptr_t
|
#define LUA_KCONTEXT intptr_t
|
||||||
#endif
|
#endif
|
||||||
#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
|
#define LUAI_MAXSTACK 15000
|
||||||
#endif
|
#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
|
@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
|
||||||
|
@ -691,20 +741,18 @@
|
||||||
#define LUA_IDSIZE 60
|
#define LUA_IDSIZE 60
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
@@ 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.
|
@@ 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'.)
|
||||||
*/
|
*/
|
||||||
|
#if LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE
|
||||||
|
#define LUAL_BUFFERSIZE 8192
|
||||||
|
#else
|
||||||
#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
|
#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
|
||||||
|
#endif
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
|
|
|
@ -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
|
** Lua standard libraries
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -11,6 +11,9 @@
|
||||||
#include "lua.h"
|
#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);
|
LUAMOD_API int (luaopen_base) (lua_State *L);
|
||||||
|
|
||||||
|
|
|
@ -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
|
** load precompiled Lua chunks
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -32,7 +32,6 @@
|
||||||
typedef struct {
|
typedef struct {
|
||||||
lua_State *L;
|
lua_State *L;
|
||||||
ZIO *Z;
|
ZIO *Z;
|
||||||
Mbuffer *b;
|
|
||||||
const char *name;
|
const char *name;
|
||||||
} LoadState;
|
} LoadState;
|
||||||
|
|
||||||
|
@ -92,10 +91,15 @@ static TString *LoadString (LoadState *S) {
|
||||||
LoadVar(S, size);
|
LoadVar(S, size);
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
else {
|
else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */
|
||||||
char *s = luaZ_openspace(S->L, S->b, --size);
|
char buff[LUAI_MAXSHORTLEN];
|
||||||
LoadVector(S, s, size);
|
LoadVector(S, buff, size);
|
||||||
return luaS_newlstr(S->L, s, 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
|
** load precompiled chunk
|
||||||
*/
|
*/
|
||||||
LClosure *luaU_undump(lua_State *L, ZIO *Z, Mbuffer *buff,
|
LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
|
||||||
const char *name) {
|
|
||||||
LoadState S;
|
LoadState S;
|
||||||
LClosure *cl;
|
LClosure *cl;
|
||||||
if (*name == '@' || *name == '=')
|
if (*name == '@' || *name == '=')
|
||||||
|
@ -263,11 +266,10 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, Mbuffer *buff,
|
||||||
S.name = name;
|
S.name = name;
|
||||||
S.L = L;
|
S.L = L;
|
||||||
S.Z = Z;
|
S.Z = Z;
|
||||||
S.b = buff;
|
|
||||||
checkHeader(&S);
|
checkHeader(&S);
|
||||||
cl = luaF_newLclosure(L, LoadByte(&S));
|
cl = luaF_newLclosure(L, LoadByte(&S));
|
||||||
setclLvalue(L, L->top, cl);
|
setclLvalue(L, L->top, cl);
|
||||||
incr_top(L);
|
luaD_inctop(L);
|
||||||
cl->p = luaF_newproto(L);
|
cl->p = luaF_newproto(L);
|
||||||
LoadFunction(&S, cl->p, NULL);
|
LoadFunction(&S, cl->p, NULL);
|
||||||
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
|
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
|
||||||
|
|
|
@ -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
|
** load precompiled Lua chunks
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -23,8 +23,7 @@
|
||||||
#define LUAC_FORMAT 0 /* this is the official format */
|
#define LUAC_FORMAT 0 /* this is the official format */
|
||||||
|
|
||||||
/* load one chunk; from lundump.c */
|
/* load one chunk; from lundump.c */
|
||||||
LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff,
|
LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name);
|
||||||
const char* name);
|
|
||||||
|
|
||||||
/* dump one chunk; from ldump.c */
|
/* dump one chunk; from ldump.c */
|
||||||
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
|
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
|
||||||
|
|
|
@ -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
|
** Standard library for UTF-8 manipulation
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.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.
|
** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid.
|
||||||
*/
|
*/
|
||||||
static const char *utf8_decode (const char *o, int *val) {
|
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;
|
const unsigned char *s = (const unsigned char *)o;
|
||||||
unsigned int c = s[0];
|
unsigned int c = s[0];
|
||||||
unsigned int res = 0; /* final result */
|
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, posi >= 1, 2, "out of range");
|
||||||
luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range");
|
luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range");
|
||||||
if (posi > pose) return 0; /* empty interval; return no values */
|
if (posi > pose) return 0; /* empty interval; return no values */
|
||||||
n = (int)(pose - posi + 1);
|
if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */
|
||||||
if (posi + n <= pose) /* (lua_Integer -> int) overflow? */
|
|
||||||
return luaL_error(L, "string slice too long");
|
return luaL_error(L, "string slice too long");
|
||||||
|
n = (int)(pose - posi) + 1;
|
||||||
luaL_checkstack(L, n, "string slice too long");
|
luaL_checkstack(L, n, "string slice too long");
|
||||||
n = 0;
|
n = 0;
|
||||||
se = s + pose;
|
se = s + pose;
|
||||||
|
@ -234,7 +235,7 @@ static int iter_codes (lua_State *L) {
|
||||||
#define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*"
|
#define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*"
|
||||||
|
|
||||||
|
|
||||||
static struct luaL_Reg funcs[] = {
|
static const luaL_Reg funcs[] = {
|
||||||
{"offset", byteoffset},
|
{"offset", byteoffset},
|
||||||
{"codepoint", codepoint},
|
{"codepoint", codepoint},
|
||||||
{"char", utfchar},
|
{"char", utfchar},
|
||||||
|
@ -248,7 +249,7 @@ static struct luaL_Reg funcs[] = {
|
||||||
|
|
||||||
LUAMOD_API int luaopen_utf8 (lua_State *L) {
|
LUAMOD_API int luaopen_utf8 (lua_State *L) {
|
||||||
luaL_newlib(L, funcs);
|
luaL_newlib(L, funcs);
|
||||||
lua_pushliteral(L, UTF8PATT);
|
lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1);
|
||||||
lua_setfield(L, -2, "charpattern");
|
lua_setfield(L, -2, "charpattern");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
500
src/lvm.c
500
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
|
** Lua virtual machine
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -9,8 +9,9 @@
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
#include <float.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -30,36 +31,38 @@
|
||||||
#include "lvm.h"
|
#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) */
|
/* limit for table tag-method chains (to avoid loops) */
|
||||||
#define MAXTAGLOOP 2000
|
#define MAXTAGLOOP 2000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Similar to 'tonumber', but does not attempt to convert strings and
|
** 'l_intfitsf' checks whether a given integer can be converted to a
|
||||||
** ensure correct precision (no extra bits). Used in comparisons.
|
** 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 !defined(l_intfitsf)
|
||||||
if (ttisfloat(obj)) *n = fltvalue(obj);
|
|
||||||
else if (ttisinteger(obj)) {
|
/* number of bits in the mantissa of a float */
|
||||||
volatile lua_Number x = cast_num(ivalue(obj)); /* avoid extra precision */
|
#define NBM (l_mathlim(MANT_DIG))
|
||||||
*n = x;
|
|
||||||
}
|
/*
|
||||||
else {
|
** Check whether some integers may not fit in a float, that is, whether
|
||||||
*n = 0; /* to avoid warnings */
|
** (maxinteger >> NBM) > 0 (that implies (1 << NBM) <= maxinteger).
|
||||||
return 0;
|
** (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
|
||||||
return 1;
|
** 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;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (cvt2num(obj) && /* string convertible to number? */
|
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 */
|
*n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +91,7 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) {
|
||||||
** mode == 1: takes the floor of the number
|
** mode == 1: takes the floor of the number
|
||||||
** mode == 2: takes the ceil 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;
|
TValue v;
|
||||||
again:
|
again:
|
||||||
if (ttisfloat(obj)) {
|
if (ttisfloat(obj)) {
|
||||||
|
@ -106,7 +109,7 @@ static int tointeger_aux (const TValue *obj, lua_Integer *p, int mode) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (cvt2num(obj) &&
|
else if (cvt2num(obj) &&
|
||||||
luaO_str2num(svalue(obj), &v) == tsvalue(obj)->len + 1) {
|
luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
|
||||||
obj = &v;
|
obj = &v;
|
||||||
goto again; /* convert result from 'luaO_str2num' to an integer */
|
goto again; /* convert result from 'luaO_str2num' to an integer */
|
||||||
}
|
}
|
||||||
|
@ -114,14 +117,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
|
** Try to convert a 'for' limit to an integer, preserving the
|
||||||
** semantics of the loop.
|
** semantics of the loop.
|
||||||
|
@ -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,
|
static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
|
||||||
int *stopnow) {
|
int *stopnow) {
|
||||||
*stopnow = 0; /* usually, let loops run */
|
*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 */
|
lua_Number n; /* try to convert to float */
|
||||||
if (!tonumber(obj, &n)) /* cannot convert to float? */
|
if (!tonumber(obj, &n)) /* cannot convert to float? */
|
||||||
return 0; /* not a number */
|
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;
|
*p = LUA_MAXINTEGER;
|
||||||
if (step < 0) *stopnow = 1;
|
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).
|
** Finish the table access 'val = t[key]'.
|
||||||
** Compute '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 */
|
int loop; /* counter to avoid infinite loops */
|
||||||
|
const TValue *tm; /* metamethod */
|
||||||
for (loop = 0; loop < MAXTAGLOOP; loop++) {
|
for (loop = 0; loop < MAXTAGLOOP; loop++) {
|
||||||
const TValue *tm;
|
if (slot == NULL) { /* 't' is not a table? */
|
||||||
if (ttistable(t)) { /* 't' is a table? */
|
lua_assert(!ttistable(t));
|
||||||
Table *h = hvalue(t);
|
tm = luaT_gettmbyobj(L, t, TM_INDEX);
|
||||||
const TValue *res = luaH_get(h, key); /* do a primitive get */
|
if (ttisnil(tm))
|
||||||
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 */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* else will try metamethod */
|
|
||||||
}
|
|
||||||
else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))
|
|
||||||
luaG_typeerror(L, t, "index"); /* no metamethod */
|
luaG_typeerror(L, t, "index"); /* no metamethod */
|
||||||
if (ttisfunction(tm)) { /* metamethod is a function */
|
/* else will try the metamethod */
|
||||||
luaT_callTM(L, tm, t, key, val, 1);
|
}
|
||||||
|
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;
|
return;
|
||||||
}
|
}
|
||||||
t = tm; /* else repeat access over 'tm' */
|
/* else will try the metamethod */
|
||||||
}
|
}
|
||||||
luaG_runerror(L, "gettable chain too long; possible loop");
|
if (ttisfunction(tm)) { /* is metamethod a function? */
|
||||||
|
luaT_callTM(L, tm, t, key, val, 1); /* call it */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
/* else repeat (tail call 'luaV_finishget') */
|
||||||
|
}
|
||||||
|
luaG_runerror(L, "'__index' chain too long; possible loop");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Main function for table assignment (invoking metamethods if needed).
|
** Finish a table assignment 't[key] = val'.
|
||||||
** Compute '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 */
|
int loop; /* counter to avoid infinite loops */
|
||||||
for (loop = 0; loop < MAXTAGLOOP; loop++) {
|
for (loop = 0; loop < MAXTAGLOOP; loop++) {
|
||||||
const TValue *tm;
|
const TValue *tm; /* '__newindex' metamethod */
|
||||||
if (ttistable(t)) { /* 't' is a table? */
|
if (slot != NULL) { /* is 't' a table? */
|
||||||
Table *h = hvalue(t);
|
Table *h = hvalue(t); /* save 't' table */
|
||||||
TValue *oldval = cast(TValue *, luaH_get(h, key));
|
lua_assert(ttisnil(slot)); /* old value must be nil */
|
||||||
/* if previous value is not nil, there must be a previous entry
|
tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
|
||||||
in the table; a metamethod has no relevance */
|
if (tm == NULL) { /* no metamethod? */
|
||||||
if (!ttisnil(oldval) ||
|
if (slot == luaO_nilobject) /* no previous entry? */
|
||||||
/* previous value is nil; must check the metamethod */
|
slot = luaH_newkey(L, h, key); /* create one */
|
||||||
((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)))) {
|
|
||||||
/* no metamethod and (now) there is an entry with given key */
|
/* 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);
|
invalidateTMcache(h);
|
||||||
luaC_barrierback(L, h, val);
|
luaC_barrierback(L, h, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* else will try the metamethod */
|
/* 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)))
|
if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
|
||||||
luaG_typeerror(L, t, "index");
|
luaG_typeerror(L, t, "index");
|
||||||
|
}
|
||||||
/* try the metamethod */
|
/* try the metamethod */
|
||||||
if (ttisfunction(tm)) {
|
if (ttisfunction(tm)) {
|
||||||
luaT_callTM(L, tm, t, key, val, 0);
|
luaT_callTM(L, tm, t, key, val, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
t = tm; /* else repeat assignment over 'tm' */
|
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) {
|
static int l_strcmp (const TString *ls, const TString *rs) {
|
||||||
const char *l = getstr(ls);
|
const char *l = getstr(ls);
|
||||||
size_t ll = ls->len;
|
size_t ll = tsslen(ls);
|
||||||
const char *r = getstr(rs);
|
const char *r = getstr(rs);
|
||||||
size_t lr = rs->len;
|
size_t lr = tsslen(rs);
|
||||||
for (;;) { /* for each segment */
|
for (;;) { /* for each segment */
|
||||||
int temp = strcoll(l, r);
|
int temp = strcoll(l, r);
|
||||||
if (temp != 0) /* not equal? */
|
if (temp != 0) /* not equal? */
|
||||||
|
@ -260,16 +268,103 @@ 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'.
|
** Main operation less than; return 'l < r'.
|
||||||
*/
|
*/
|
||||||
int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
|
int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
|
||||||
int res;
|
int res;
|
||||||
lua_Number nl, nr;
|
if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */
|
||||||
if (ttisinteger(l) && ttisinteger(r)) /* both operands are integers? */
|
return LTnum(l, r);
|
||||||
return (ivalue(l) < ivalue(r));
|
|
||||||
else if (tofloat(l, &nl) && tofloat(r, &nr)) /* both are numbers? */
|
|
||||||
return luai_numlt(nl, nr);
|
|
||||||
else if (ttisstring(l) && ttisstring(r)) /* both are strings? */
|
else if (ttisstring(l) && ttisstring(r)) /* both are strings? */
|
||||||
return l_strcmp(tsvalue(l), tsvalue(r)) < 0;
|
return l_strcmp(tsvalue(l), tsvalue(r)) < 0;
|
||||||
else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */
|
else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */
|
||||||
|
@ -279,22 +374,29 @@ 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 luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
|
||||||
int res;
|
int res;
|
||||||
lua_Number nl, nr;
|
if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */
|
||||||
if (ttisinteger(l) && ttisinteger(r)) /* both operands are integers? */
|
return LEnum(l, r);
|
||||||
return (ivalue(l) <= ivalue(r));
|
|
||||||
else if (tofloat(l, &nl) && tofloat(r, &nr)) /* both are numbers? */
|
|
||||||
return luai_numle(nl, nr);
|
|
||||||
else if (ttisstring(l) && ttisstring(r)) /* both are strings? */
|
else if (ttisstring(l) && ttisstring(r)) /* both are strings? */
|
||||||
return l_strcmp(tsvalue(l), tsvalue(r)) <= 0;
|
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;
|
return res;
|
||||||
else if ((res = luaT_callorderTM(L, r, l, TM_LT)) < 0) /* else try 'lt' */
|
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);
|
luaG_ordererror(L, l, r);
|
||||||
return !res;
|
return !res; /* result is negated */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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)
|
if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER)
|
||||||
return 0; /* only numbers can be equal with different variants */
|
return 0; /* only numbers can be equal with different variants */
|
||||||
else { /* two numbers with different variants */
|
else { /* two numbers with different variants */
|
||||||
lua_Number n1, n2; /* compare them as floats */
|
lua_Integer i1, i2; /* compare them as integers */
|
||||||
lua_assert(ttisnumber(t1) && ttisnumber(t2));
|
return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2);
|
||||||
cast_void(tofloat(t1, &n1)); cast_void(tofloat(t2, &n2));
|
|
||||||
return luai_numeq(n1, n2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* values have same type and same variant */
|
/* 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) \
|
#define tostring(L,o) \
|
||||||
(ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1)))
|
(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,
|
** Main operation for concatenation: concat 'total' values in the stack,
|
||||||
** from 'L->top - total' up to 'L->top - 1'.
|
** 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) */
|
int n = 2; /* number of elements handled in this pass (at least 2) */
|
||||||
if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1))
|
if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1))
|
||||||
luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT);
|
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 */
|
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. */
|
setobjs2s(L, top - 2, top - 1); /* result is second op. */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* at least two non-empty string values; get as many as possible */
|
/* at least two non-empty string values; get as many as possible */
|
||||||
size_t tl = tsvalue(top-1)->len;
|
size_t tl = vslen(top - 1);
|
||||||
char *buffer;
|
TString *ts;
|
||||||
int i;
|
/* collect total length and number of strings */
|
||||||
/* collect total length */
|
for (n = 1; n < total && tostring(L, top - n - 1); n++) {
|
||||||
for (i = 1; i < total && tostring(L, top-i-1); i++) {
|
size_t l = vslen(top - n - 1);
|
||||||
size_t l = tsvalue(top-i-1)->len;
|
|
||||||
if (l >= (MAX_SIZE/sizeof(char)) - tl)
|
if (l >= (MAX_SIZE/sizeof(char)) - tl)
|
||||||
luaG_runerror(L, "string length overflow");
|
luaG_runerror(L, "string length overflow");
|
||||||
tl += l;
|
tl += l;
|
||||||
}
|
}
|
||||||
buffer = luaZ_openspace(L, &G(L)->buff, tl);
|
if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
|
||||||
tl = 0;
|
char buff[LUAI_MAXSHORTLEN];
|
||||||
n = i;
|
copy2buff(top, n, buff); /* copy strings to buffer */
|
||||||
do { /* copy all strings to buffer */
|
ts = luaS_newlstr(L, buff, tl);
|
||||||
size_t l = tsvalue(top-i)->len;
|
}
|
||||||
memcpy(buffer+tl, svalue(top-i), l * sizeof(char));
|
else { /* long string; copy strings directly to final result */
|
||||||
tl += l;
|
ts = luaS_createlngstrobj(L, tl);
|
||||||
} while (--i > 0);
|
copy2buff(top, n, getstr(ts));
|
||||||
setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); /* create result */
|
}
|
||||||
|
setsvalue2s(L, top - n, ts); /* create result */
|
||||||
}
|
}
|
||||||
total -= n-1; /* got 'n' strings to create 1 new */
|
total -= n-1; /* got 'n' strings to create 1 new */
|
||||||
L->top -= n-1; /* popped 'n' strings and pushed one */
|
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) {
|
void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
|
||||||
const TValue *tm;
|
const TValue *tm;
|
||||||
switch (ttnov(rb)) {
|
switch (ttype(rb)) {
|
||||||
case LUA_TTABLE: {
|
case LUA_TTABLE: {
|
||||||
Table *h = hvalue(rb);
|
Table *h = hvalue(rb);
|
||||||
tm = fasttm(L, h->metatable, TM_LEN);
|
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 */
|
setivalue(ra, luaH_getn(h)); /* else primitive len */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case LUA_TSTRING: {
|
case LUA_TSHRSTR: {
|
||||||
setivalue(ra, tsvalue(rb)->len);
|
setivalue(ra, tsvalue(rb)->shrlen);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TLNGSTR: {
|
||||||
|
setivalue(ra, tsvalue(rb)->u.lnglen);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default: { /* try metamethod */
|
default: { /* try metamethod */
|
||||||
|
@ -553,11 +670,11 @@ void luaV_finishOp (lua_State *L) {
|
||||||
case OP_LE: case OP_LT: case OP_EQ: {
|
case OP_LE: case OP_LT: case OP_EQ: {
|
||||||
int res = !l_isfalse(L->top - 1);
|
int res = !l_isfalse(L->top - 1);
|
||||||
L->top--;
|
L->top--;
|
||||||
/* metamethod should not be called when operand is K */
|
if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
|
||||||
lua_assert(!ISK(GETARG_B(inst)));
|
lua_assert(op == OP_LE);
|
||||||
if (op == OP_LE && /* "<=" using "<" instead? */
|
ci->callstatus ^= CIST_LEQ; /* clear mark */
|
||||||
ttisnil(luaT_gettmbyobj(L, base + GETARG_B(inst), TM_LE)))
|
res = !res; /* negate result */
|
||||||
res = !res; /* invert result */
|
}
|
||||||
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP);
|
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP);
|
||||||
if (res != GETARG_A(inst)) /* condition failed? */
|
if (res != GETARG_A(inst)) /* condition failed? */
|
||||||
ci->u.l.savedpc++; /* skip jump instruction */
|
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'
|
** 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))
|
#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 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 RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i))
|
||||||
#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \
|
#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \
|
||||||
ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i))
|
ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i))
|
||||||
#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \
|
#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \
|
||||||
ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i))
|
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 */
|
/* execute a jump instruction */
|
||||||
#define dojump(ci,i,e) \
|
#define dojump(ci,i,e) \
|
||||||
{ int a = GETARG_A(i); \
|
{ 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; }
|
ci->u.l.savedpc += GETARG_sBx(i) + e; }
|
||||||
|
|
||||||
/* for test instructions, execute the jump instruction that follows it */
|
/* 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 Protect(x) { {x;}; base = ci->u.l.base; }
|
||||||
|
|
||||||
#define checkGC(L,c) \
|
#define checkGC(L,c) \
|
||||||
Protect( luaC_condGC(L,{L->top = (c); /* limit of live values */ \
|
{ luaC_condGC(L, L->top = (c), /* limit of live values */ \
|
||||||
luaC_step(L); \
|
Protect(L->top = ci->top)); /* restore top */ \
|
||||||
L->top = ci->top;}) /* restore top */ \
|
luai_threadyield(L); }
|
||||||
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 vmdispatch(o) switch(o)
|
||||||
#define vmcase(l) case l:
|
#define vmcase(l) case l:
|
||||||
#define vmbreak break
|
#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) {
|
void luaV_execute (lua_State *L) {
|
||||||
CallInfo *ci = L->ci;
|
CallInfo *ci = L->ci;
|
||||||
LClosure *cl;
|
LClosure *cl;
|
||||||
TValue *k;
|
TValue *k;
|
||||||
StkId base;
|
StkId base;
|
||||||
|
ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */
|
||||||
newframe: /* reentry point when frame changes (call/return) */
|
newframe: /* reentry point when frame changes (call/return) */
|
||||||
lua_assert(ci == L->ci);
|
lua_assert(ci == L->ci);
|
||||||
cl = clLvalue(ci->func);
|
cl = clLvalue(ci->func); /* local reference to function's closure */
|
||||||
k = cl->p->k;
|
k = cl->p->k; /* local reference to function's constant table */
|
||||||
base = ci->u.l.base;
|
base = ci->u.l.base; /* local copy of function's base */
|
||||||
/* main loop of interpreter */
|
/* main loop of interpreter */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
Instruction i = *(ci->u.l.savedpc++);
|
Instruction i;
|
||||||
StkId ra;
|
StkId ra;
|
||||||
if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
|
vmfetch();
|
||||||
(--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);
|
|
||||||
vmdispatch (GET_OPCODE(i)) {
|
vmdispatch (GET_OPCODE(i)) {
|
||||||
vmcase(OP_MOVE) {
|
vmcase(OP_MOVE) {
|
||||||
setobjs2s(L, ra, RB(i));
|
setobjs2s(L, ra, RB(i));
|
||||||
|
@ -704,17 +834,22 @@ void luaV_execute (lua_State *L) {
|
||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_GETTABUP) {
|
vmcase(OP_GETTABUP) {
|
||||||
int b = GETARG_B(i);
|
TValue *upval = cl->upvals[GETARG_B(i)]->v;
|
||||||
Protect(luaV_gettable(L, cl->upvals[b]->v, RKC(i), ra));
|
TValue *rc = RKC(i);
|
||||||
|
gettableProtected(L, upval, rc, ra);
|
||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_GETTABLE) {
|
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;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_SETTABUP) {
|
vmcase(OP_SETTABUP) {
|
||||||
int a = GETARG_A(i);
|
TValue *upval = cl->upvals[GETARG_A(i)]->v;
|
||||||
Protect(luaV_settable(L, cl->upvals[a]->v, RKB(i), RKC(i)));
|
TValue *rb = RKB(i);
|
||||||
|
TValue *rc = RKC(i);
|
||||||
|
settableProtected(L, upval, rb, rc);
|
||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_SETUPVAL) {
|
vmcase(OP_SETUPVAL) {
|
||||||
|
@ -724,7 +859,9 @@ void luaV_execute (lua_State *L) {
|
||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_SETTABLE) {
|
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;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_NEWTABLE) {
|
vmcase(OP_NEWTABLE) {
|
||||||
|
@ -738,9 +875,15 @@ void luaV_execute (lua_State *L) {
|
||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_SELF) {
|
vmcase(OP_SELF) {
|
||||||
|
const TValue *aux;
|
||||||
StkId rb = RB(i);
|
StkId rb = RB(i);
|
||||||
setobjs2s(L, ra+1, rb);
|
TValue *rc = RKC(i);
|
||||||
Protect(luaV_gettable(L, rb, RKC(i), ra));
|
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;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_ADD) {
|
vmcase(OP_ADD) {
|
||||||
|
@ -927,8 +1070,8 @@ void luaV_execute (lua_State *L) {
|
||||||
StkId rb;
|
StkId rb;
|
||||||
L->top = base + c + 1; /* mark the end of concat operands */
|
L->top = base + c + 1; /* mark the end of concat operands */
|
||||||
Protect(luaV_concat(L, c - b + 1));
|
Protect(luaV_concat(L, c - b + 1));
|
||||||
ra = RA(i); /* 'luav_concat' may invoke TMs and move the stack */
|
ra = RA(i); /* 'luaV_concat' may invoke TMs and move the stack */
|
||||||
rb = b + base;
|
rb = base + b;
|
||||||
setobjs2s(L, ra, rb);
|
setobjs2s(L, ra, rb);
|
||||||
checkGC(L, (ra >= rb ? ra + 1 : rb));
|
checkGC(L, (ra >= rb ? ra + 1 : rb));
|
||||||
L->top = ci->top; /* restore top */
|
L->top = ci->top; /* restore top */
|
||||||
|
@ -942,7 +1085,7 @@ void luaV_execute (lua_State *L) {
|
||||||
TValue *rb = RKB(i);
|
TValue *rb = RKB(i);
|
||||||
TValue *rc = RKC(i);
|
TValue *rc = RKC(i);
|
||||||
Protect(
|
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++;
|
ci->u.l.savedpc++;
|
||||||
else
|
else
|
||||||
donextjump(ci);
|
donextjump(ci);
|
||||||
|
@ -989,12 +1132,12 @@ void luaV_execute (lua_State *L) {
|
||||||
int nresults = GETARG_C(i) - 1;
|
int nresults = GETARG_C(i) - 1;
|
||||||
if (b != 0) L->top = ra+b; /* else previous instruction set top */
|
if (b != 0) L->top = ra+b; /* else previous instruction set top */
|
||||||
if (luaD_precall(L, ra, nresults)) { /* C function? */
|
if (luaD_precall(L, ra, nresults)) { /* C function? */
|
||||||
if (nresults >= 0) L->top = ci->top; /* adjust results */
|
if (nresults >= 0)
|
||||||
base = ci->u.l.base;
|
L->top = ci->top; /* adjust results */
|
||||||
|
Protect((void)0); /* update 'base' */
|
||||||
}
|
}
|
||||||
else { /* Lua function */
|
else { /* Lua function */
|
||||||
ci = L->ci;
|
ci = L->ci;
|
||||||
ci->callstatus |= CIST_REENTRY;
|
|
||||||
goto newframe; /* restart luaV_execute over new Lua function */
|
goto newframe; /* restart luaV_execute over new Lua function */
|
||||||
}
|
}
|
||||||
vmbreak;
|
vmbreak;
|
||||||
|
@ -1003,8 +1146,9 @@ void luaV_execute (lua_State *L) {
|
||||||
int b = GETARG_B(i);
|
int b = GETARG_B(i);
|
||||||
if (b != 0) L->top = ra+b; /* else previous instruction set top */
|
if (b != 0) L->top = ra+b; /* else previous instruction set top */
|
||||||
lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
|
lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
|
||||||
if (luaD_precall(L, ra, LUA_MULTRET)) /* C function? */
|
if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */
|
||||||
base = ci->u.l.base;
|
Protect((void)0); /* update 'base' */
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
/* tail call: put called frame (n) in place of caller one (o) */
|
/* tail call: put called frame (n) in place of caller one (o) */
|
||||||
CallInfo *nci = L->ci; /* called frame */
|
CallInfo *nci = L->ci; /* called frame */
|
||||||
|
@ -1031,10 +1175,9 @@ void luaV_execute (lua_State *L) {
|
||||||
}
|
}
|
||||||
vmcase(OP_RETURN) {
|
vmcase(OP_RETURN) {
|
||||||
int b = GETARG_B(i);
|
int b = GETARG_B(i);
|
||||||
if (b != 0) L->top = ra+b-1;
|
|
||||||
if (cl->p->sizep > 0) luaF_close(L, base);
|
if (cl->p->sizep > 0) luaF_close(L, base);
|
||||||
b = luaD_poscall(L, ra);
|
b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
|
||||||
if (!(ci->callstatus & CIST_REENTRY)) /* 'ci' still the called one */
|
if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */
|
||||||
return; /* external invocation: return */
|
return; /* external invocation: return */
|
||||||
else { /* invocation via reentry: continue execution */
|
else { /* invocation via reentry: continue execution */
|
||||||
ci = L->ci;
|
ci = L->ci;
|
||||||
|
@ -1047,11 +1190,11 @@ void luaV_execute (lua_State *L) {
|
||||||
vmcase(OP_FORLOOP) {
|
vmcase(OP_FORLOOP) {
|
||||||
if (ttisinteger(ra)) { /* integer loop? */
|
if (ttisinteger(ra)) { /* integer loop? */
|
||||||
lua_Integer step = ivalue(ra + 2);
|
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);
|
lua_Integer limit = ivalue(ra + 1);
|
||||||
if ((0 < step) ? (idx <= limit) : (limit <= idx)) {
|
if ((0 < step) ? (idx <= limit) : (limit <= idx)) {
|
||||||
ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
|
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 */
|
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)
|
if (luai_numlt(0, step) ? luai_numle(idx, limit)
|
||||||
: luai_numle(limit, idx)) {
|
: luai_numle(limit, idx)) {
|
||||||
ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
|
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 */
|
setfltvalue(ra + 3, idx); /* ...and external index */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1079,7 +1222,7 @@ void luaV_execute (lua_State *L) {
|
||||||
/* all values are integer */
|
/* all values are integer */
|
||||||
lua_Integer initv = (stopnow ? 0 : ivalue(init));
|
lua_Integer initv = (stopnow ? 0 : ivalue(init));
|
||||||
setivalue(plimit, ilimit);
|
setivalue(plimit, ilimit);
|
||||||
setivalue(init, initv - ivalue(pstep));
|
setivalue(init, intop(-, initv, ivalue(pstep)));
|
||||||
}
|
}
|
||||||
else { /* try making all values floats */
|
else { /* try making all values floats */
|
||||||
lua_Number ninit; lua_Number nlimit; lua_Number nstep;
|
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+1, ra+1);
|
||||||
setobjs2s(L, cb, ra);
|
setobjs2s(L, cb, ra);
|
||||||
L->top = cb + 3; /* func. + 2 args (state and index) */
|
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;
|
L->top = ci->top;
|
||||||
i = *(ci->u.l.savedpc++); /* go to next instruction */
|
i = *(ci->u.l.savedpc++); /* go to next instruction */
|
||||||
ra = RA(i);
|
ra = RA(i);
|
||||||
|
@ -1127,11 +1270,10 @@ void luaV_execute (lua_State *L) {
|
||||||
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG);
|
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG);
|
||||||
c = GETARG_Ax(*ci->u.l.savedpc++);
|
c = GETARG_Ax(*ci->u.l.savedpc++);
|
||||||
}
|
}
|
||||||
luai_runtimecheck(L, ttistable(ra));
|
|
||||||
h = hvalue(ra);
|
h = hvalue(ra);
|
||||||
last = ((c-1)*LFIELDS_PER_FLUSH) + n;
|
last = ((c-1)*LFIELDS_PER_FLUSH) + n;
|
||||||
if (last > h->sizearray) /* needs more space? */
|
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--) {
|
for (; n > 0; n--) {
|
||||||
TValue *val = ra+n;
|
TValue *val = ra+n;
|
||||||
luaH_setint(L, h, last--, val);
|
luaH_setint(L, h, last--, val);
|
||||||
|
@ -1151,23 +1293,21 @@ void luaV_execute (lua_State *L) {
|
||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_VARARG) {
|
vmcase(OP_VARARG) {
|
||||||
int b = GETARG_B(i) - 1;
|
int b = GETARG_B(i) - 1; /* required results */
|
||||||
int j;
|
int j;
|
||||||
int n = cast_int(base - ci->func) - cl->p->numparams - 1;
|
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? */
|
if (b < 0) { /* B == 0? */
|
||||||
b = n; /* get all var. arguments */
|
b = n; /* get all var. arguments */
|
||||||
Protect(luaD_checkstack(L, n));
|
Protect(luaD_checkstack(L, n));
|
||||||
ra = RA(i); /* previous call may change the stack */
|
ra = RA(i); /* previous call may change the stack */
|
||||||
L->top = ra + n;
|
L->top = ra + n;
|
||||||
}
|
}
|
||||||
for (j = 0; j < b; j++) {
|
for (j = 0; j < b && j < n; j++)
|
||||||
if (j < n) {
|
|
||||||
setobjs2s(L, ra + j, base - n + j);
|
setobjs2s(L, ra + j, base - n + j);
|
||||||
}
|
for (; j < b; j++) /* complete required results with nil */
|
||||||
else {
|
|
||||||
setnilvalue(ra + j);
|
setnilvalue(ra + j);
|
||||||
}
|
|
||||||
}
|
|
||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_EXTRAARG) {
|
vmcase(OP_EXTRAARG) {
|
||||||
|
|
69
src/lvm.h
69
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
|
** Lua virtual machine
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -27,26 +27,81 @@
|
||||||
#endif
|
#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) \
|
#define tonumber(o,n) \
|
||||||
(ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))
|
(ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))
|
||||||
|
|
||||||
#define tointeger(o,i) \
|
#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 intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))
|
||||||
|
|
||||||
#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2)
|
#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_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_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_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_tonumber_ (const TValue *obj, lua_Number *n);
|
||||||
LUAI_FUNC int luaV_tointeger_ (const TValue *obj, lua_Integer *p);
|
LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode);
|
||||||
LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key,
|
LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
|
||||||
StkId val);
|
StkId val, const TValue *slot);
|
||||||
LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key,
|
LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
|
||||||
StkId val);
|
StkId val, const TValue *slot);
|
||||||
LUAI_FUNC void luaV_finishOp (lua_State *L);
|
LUAI_FUNC void luaV_finishOp (lua_State *L);
|
||||||
LUAI_FUNC void luaV_execute (lua_State *L);
|
LUAI_FUNC void luaV_execute (lua_State *L);
|
||||||
LUAI_FUNC void luaV_concat (lua_State *L, int total);
|
LUAI_FUNC void luaV_concat (lua_State *L, int total);
|
||||||
|
|
12
src/lzio.c
12
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
|
** Buffered streams
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -66,13 +66,3 @@ size_t luaZ_read (ZIO *z, void *b, size_t n) {
|
||||||
return 0;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
** Buffered streams
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -44,7 +44,6 @@ typedef struct Mbuffer {
|
||||||
#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0)
|
#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,
|
LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader,
|
||||||
void *data);
|
void *data);
|
||||||
LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */
|
LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */
|
||||||
|
|
Loading…
Reference in a new issue