diff options
Diffstat (limited to 'src/libs/3rdparty')
86 files changed, 74754 insertions, 119 deletions
diff --git a/src/libs/3rdparty/CMakeLists.txt b/src/libs/3rdparty/CMakeLists.txt index 8445a0d01b..364c9a425e 100644 --- a/src/libs/3rdparty/CMakeLists.txt +++ b/src/libs/3rdparty/CMakeLists.txt @@ -4,6 +4,8 @@ add_subdirectory(libvterm) add_subdirectory(libptyqt) add_subdirectory(qrcodegen) add_subdirectory(qtkeychain) +add_subdirectory(lua) +add_subdirectory(sol2) if(WIN32) add_subdirectory(winpty) diff --git a/src/libs/3rdparty/googletest b/src/libs/3rdparty/googletest -Subproject b796f7d44681514f58a683a3a71ff17c94edb0c +Subproject f8d7d77c06936315286eb55f8de22cd23c18857 diff --git a/src/libs/3rdparty/lua/CMakeLists.txt b/src/libs/3rdparty/lua/CMakeLists.txt new file mode 100644 index 0000000000..4501f540c8 --- /dev/null +++ b/src/libs/3rdparty/lua/CMakeLists.txt @@ -0,0 +1,75 @@ + +add_qtc_library(lua546 + PROPERTIES QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON + PUBLIC_INCLUDES src + STATIC + SOURCES + src/lapi.c + src/lapi.h + src/lauxlib.c + src/lauxlib.h + src/lbaselib.c + src/lcode.c + src/lcode.h + src/lcorolib.c + src/lctype.c + src/lctype.h + src/ldblib.c + src/ldebug.c + src/ldebug.h + src/ldo.c + src/ldo.h + src/ldump.c + src/lfunc.c + src/lfunc.h + src/lgc.c + src/lgc.h + src/linit.c + src/liolib.c + src/llex.c + src/llex.h + src/lmathlib.c + src/lmem.c + src/lmem.h + src/loadlib.c + src/lobject.c + src/lobject.h + src/lopcodes.c + src/lopcodes.h + src/loslib.c + src/lparser.c + src/lparser.h + src/lstate.c + src/lstate.h + src/lstring.c + src/lstring.h + src/lstrlib.c + src/ltable.c + src/ltable.h + src/ltablib.c + src/ltm.c + src/ltm.h + src/lua.c + src/lua.h + src/luaconf.h + src/lundump.c + src/lundump.h + src/lutf8lib.c + src/lvm.c + src/lvm.h + src/lzio.c + src/lzio.h +) + +extend_qtc_library(lua546 + CONDITION LINUX + PUBLIC_DEFINES LUA_USE_LINUX +) +extend_qtc_library(lua546 + CONDITION WIN32 + PUBLIC_DEFINES LUA_USE_WINDOWS +) +extend_qtc_library(lua546 + CONDITION APPLE + PUBLIC_DEFINES LUA_USE_MACOSX +) diff --git a/src/libs/3rdparty/lua/LICENSE b/src/libs/3rdparty/lua/LICENSE new file mode 100644 index 0000000000..441cc1981c --- /dev/null +++ b/src/libs/3rdparty/lua/LICENSE @@ -0,0 +1,16 @@ +Copyright © 1994–2023 Lua.org, PUC-Rio. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file diff --git a/src/libs/3rdparty/lua/README b/src/libs/3rdparty/lua/README new file mode 100644 index 0000000000..1ae97165ba --- /dev/null +++ b/src/libs/3rdparty/lua/README @@ -0,0 +1,6 @@ + +This is Lua 5.4.6, released on 02 May 2023. + +For installation instructions, license details, and +further information about Lua, see doc/readme.html. + diff --git a/src/libs/3rdparty/lua/doc/contents.html b/src/libs/3rdparty/lua/doc/contents.html new file mode 100644 index 0000000000..1231e6d248 --- /dev/null +++ b/src/libs/3rdparty/lua/doc/contents.html @@ -0,0 +1,678 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<HTML> +<HEAD> +<TITLE>Lua 5.4 Reference Manual - contents</TITLE> +<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css"> +<LINK REL="stylesheet" TYPE="text/css" HREF="index.css"> +<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1"> +</HEAD> + +<BODY> + +<H1> +<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> +Lua 5.4 Reference Manual +</H1> + +<P> +The reference manual is the official definition of the Lua language. +<BR> +For a complete introduction to Lua programming, see the book +<A HREF="http://www.lua.org/pil/">Programming in Lua</A>. + +<DIV CLASS="menubar"> +<A HREF="manual.html">start</A> +· +<A HREF="#contents">contents</A> +· +<A HREF="#index">index</A> +· +<A HREF="http://www.lua.org/manual/">other versions</A> +</DIV> + +<P> +<SMALL> +Copyright © 2020–2023 Lua.org, PUC-Rio. +Freely available under the terms of the +<A HREF="http://www.lua.org/license.html">Lua license</A>. +</SMALL> + +<H2><A NAME="contents">Contents</A></H2> +<UL CLASS="contents menubar"> +<LI><A HREF="manual.html">1 – Introduction</A> +<P> +<LI><A HREF="manual.html#2">2 – Basic Concepts</A> +<UL> +<LI><A HREF="manual.html#2.1">2.1 – Values and Types</A> +<LI><A HREF="manual.html#2.2">2.2 – Environments and the Global Environment</A> +<LI><A HREF="manual.html#2.3">2.3 – Error Handling</A> +<LI><A HREF="manual.html#2.4">2.4 – Metatables and Metamethods</A> +<LI><A HREF="manual.html#2.5">2.5 – Garbage Collection</A> +<UL> +<LI><A HREF="manual.html#2.5.1">2.5.1 – Incremental Garbage Collection</A> +<LI><A HREF="manual.html#2.5.2">2.5.2 – Generational Garbage Collection</A> +<LI><A HREF="manual.html#2.5.3">2.5.3 – Garbage-Collection Metamethods</A> +<LI><A HREF="manual.html#2.5.4">2.5.4 – Weak Tables</A> +</UL> +<LI><A HREF="manual.html#2.6">2.6 – Coroutines</A> +</UL> +<P> +<LI><A HREF="manual.html#3">3 – The Language</A> +<UL> +<LI><A HREF="manual.html#3.1">3.1 – Lexical Conventions</A> +<LI><A HREF="manual.html#3.2">3.2 – Variables</A> +<LI><A HREF="manual.html#3.3">3.3 – Statements</A> +<UL> +<LI><A HREF="manual.html#3.3.1">3.3.1 – Blocks</A> +<LI><A HREF="manual.html#3.3.2">3.3.2 – Chunks</A> +<LI><A HREF="manual.html#3.3.3">3.3.3 – Assignment</A> +<LI><A HREF="manual.html#3.3.4">3.3.4 – Control Structures</A> +<LI><A HREF="manual.html#3.3.5">3.3.5 – For Statement</A> +<LI><A HREF="manual.html#3.3.6">3.3.6 – Function Calls as Statements</A> +<LI><A HREF="manual.html#3.3.7">3.3.7 – Local Declarations</A> +<LI><A HREF="manual.html#3.3.8">3.3.8 – To-be-closed Variables</A> +</UL> +<LI><A HREF="manual.html#3.4">3.4 – Expressions</A> +<UL> +<LI><A HREF="manual.html#3.4.1">3.4.1 – Arithmetic Operators</A> +<LI><A HREF="manual.html#3.4.2">3.4.2 – Bitwise Operators</A> +<LI><A HREF="manual.html#3.4.3">3.4.3 – Coercions and Conversions</A> +<LI><A HREF="manual.html#3.4.4">3.4.4 – Relational Operators</A> +<LI><A HREF="manual.html#3.4.5">3.4.5 – Logical Operators</A> +<LI><A HREF="manual.html#3.4.6">3.4.6 – Concatenation</A> +<LI><A HREF="manual.html#3.4.7">3.4.7 – The Length Operator</A> +<LI><A HREF="manual.html#3.4.8">3.4.8 – Precedence</A> +<LI><A HREF="manual.html#3.4.9">3.4.9 – Table Constructors</A> +<LI><A HREF="manual.html#3.4.10">3.4.10 – Function Calls</A> +<LI><A HREF="manual.html#3.4.11">3.4.11 – Function Definitions</A> +<LI><A HREF="manual.html#3.4.12">3.4.12 – Lists of expressions, multiple results, and adjustment<A> + +</UL> +<LI><A HREF="manual.html#3.5">3.5 – Visibility Rules</A> +</UL> +<P> +<LI><A HREF="manual.html#4">4 – The Application Program Interface</A> +<UL> +<LI><A HREF="manual.html#4.1">4.1 – The Stack</A> +<UL> +<LI><A HREF="manual.html#4.1.1">4.1.1 – Stack Size</A> +<LI><A HREF="manual.html#4.1.2">4.1.2 – Valid and Acceptable Indices</A> +<LI><A HREF="manual.html#4.1.3">4.1.3 – Pointers to strings</A> +</UL> +<LI><A HREF="manual.html#4.2">4.2 – C Closures</A> +<LI><A HREF="manual.html#4.3">4.3 – Registry</A> +<LI><A HREF="manual.html#4.4">4.4 – Error Handling in C</A> +<UL> +<LI><A HREF="manual.html#4.4.1">4.4.1 – Status Codes</A> +</UL> +<LI><A HREF="manual.html#4.5">4.5 – Handling Yields in C</A> +<LI><A HREF="manual.html#4.6">4.6 – Functions and Types</A> +<LI><A HREF="manual.html#4.7">4.7 – The Debug Interface</A> +</UL> +<P> +<LI><A HREF="manual.html#5">5 – The Auxiliary Library</A> +<UL> +<LI><A HREF="manual.html#5.1">5.1 – Functions and Types</A> +</UL> +<P> +<LI><A HREF="manual.html#6">6 – The Standard Libraries</A> +<UL> +<LI><A HREF="manual.html#6.1">6.1 – Basic Functions</A> +<LI><A HREF="manual.html#6.2">6.2 – Coroutine Manipulation</A> +<LI><A HREF="manual.html#6.3">6.3 – Modules</A> +<LI><A HREF="manual.html#6.4">6.4 – String Manipulation</A> +<UL> +<LI><A HREF="manual.html#6.4.1">6.4.1 – Patterns</A> +<LI><A HREF="manual.html#6.4.2">6.4.2 – Format Strings for Pack and Unpack</A> +</UL> +<LI><A HREF="manual.html#6.5">6.5 – UTF-8 Support</A> +<LI><A HREF="manual.html#6.6">6.6 – Table Manipulation</A> +<LI><A HREF="manual.html#6.7">6.7 – Mathematical Functions</A> +<LI><A HREF="manual.html#6.8">6.8 – Input and Output Facilities</A> +<LI><A HREF="manual.html#6.9">6.9 – Operating System Facilities</A> +<LI><A HREF="manual.html#6.10">6.10 – The Debug Library</A> +</UL> +<P> +<LI><A HREF="manual.html#7">7 – Lua Standalone</A> +<P> +<LI><A HREF="manual.html#8">8 – Incompatibilities with the Previous Version</A> +<UL> +<LI><A HREF="manual.html#8.1">8.1 – Incompatibilities in the Language</A> +<LI><A HREF="manual.html#8.2">8.2 – Incompatibilities in the Libraries</A> +<LI><A HREF="manual.html#8.3">8.3 – Incompatibilities in the API</A> +</UL> +<P> +<LI><A HREF="manual.html#9">9 – The Complete Syntax of Lua</A> +</UL> + +<H2><A NAME="index">Index</A></H2> +<TABLE CLASS="menubar" WIDTH="100%"> +<TR> +<TD> +<H3><A NAME="functions">Lua functions</A></H3> +<P> +<A HREF="manual.html#6.1">basic</A><BR> +<A HREF="manual.html#pdf-_G">_G</A><BR> +<A HREF="manual.html#pdf-_VERSION">_VERSION</A><BR> +<A HREF="manual.html#pdf-assert">assert</A><BR> +<A HREF="manual.html#pdf-collectgarbage">collectgarbage</A><BR> +<A HREF="manual.html#pdf-dofile">dofile</A><BR> +<A HREF="manual.html#pdf-error">error</A><BR> +<A HREF="manual.html#pdf-getmetatable">getmetatable</A><BR> +<A HREF="manual.html#pdf-ipairs">ipairs</A><BR> +<A HREF="manual.html#pdf-load">load</A><BR> +<A HREF="manual.html#pdf-loadfile">loadfile</A><BR> +<A HREF="manual.html#pdf-next">next</A><BR> +<A HREF="manual.html#pdf-pairs">pairs</A><BR> +<A HREF="manual.html#pdf-pcall">pcall</A><BR> +<A HREF="manual.html#pdf-print">print</A><BR> +<A HREF="manual.html#pdf-rawequal">rawequal</A><BR> +<A HREF="manual.html#pdf-rawget">rawget</A><BR> +<A HREF="manual.html#pdf-rawlen">rawlen</A><BR> +<A HREF="manual.html#pdf-rawset">rawset</A><BR> +<A HREF="manual.html#pdf-require">require</A><BR> +<A HREF="manual.html#pdf-select">select</A><BR> +<A HREF="manual.html#pdf-setmetatable">setmetatable</A><BR> +<A HREF="manual.html#pdf-tonumber">tonumber</A><BR> +<A HREF="manual.html#pdf-tostring">tostring</A><BR> +<A HREF="manual.html#pdf-type">type</A><BR> +<A HREF="manual.html#pdf-warn">warn</A><BR> +<A HREF="manual.html#pdf-xpcall">xpcall</A><BR> + +<P> +<A HREF="manual.html#6.2">coroutine</A><BR> +<A HREF="manual.html#pdf-coroutine.close">coroutine.close</A><BR> +<A HREF="manual.html#pdf-coroutine.create">coroutine.create</A><BR> +<A HREF="manual.html#pdf-coroutine.isyieldable">coroutine.isyieldable</A><BR> +<A HREF="manual.html#pdf-coroutine.resume">coroutine.resume</A><BR> +<A HREF="manual.html#pdf-coroutine.running">coroutine.running</A><BR> +<A HREF="manual.html#pdf-coroutine.status">coroutine.status</A><BR> +<A HREF="manual.html#pdf-coroutine.wrap">coroutine.wrap</A><BR> +<A HREF="manual.html#pdf-coroutine.yield">coroutine.yield</A><BR> + +<P> +<A HREF="manual.html#6.10">debug</A><BR> +<A HREF="manual.html#pdf-debug.debug">debug.debug</A><BR> +<A HREF="manual.html#pdf-debug.gethook">debug.gethook</A><BR> +<A HREF="manual.html#pdf-debug.getinfo">debug.getinfo</A><BR> +<A HREF="manual.html#pdf-debug.getlocal">debug.getlocal</A><BR> +<A HREF="manual.html#pdf-debug.getmetatable">debug.getmetatable</A><BR> +<A HREF="manual.html#pdf-debug.getregistry">debug.getregistry</A><BR> +<A HREF="manual.html#pdf-debug.getupvalue">debug.getupvalue</A><BR> +<A HREF="manual.html#pdf-debug.getuservalue">debug.getuservalue</A><BR> +<A HREF="manual.html#pdf-debug.sethook">debug.sethook</A><BR> +<A HREF="manual.html#pdf-debug.setlocal">debug.setlocal</A><BR> +<A HREF="manual.html#pdf-debug.setmetatable">debug.setmetatable</A><BR> +<A HREF="manual.html#pdf-debug.setupvalue">debug.setupvalue</A><BR> +<A HREF="manual.html#pdf-debug.setuservalue">debug.setuservalue</A><BR> +<A HREF="manual.html#pdf-debug.traceback">debug.traceback</A><BR> +<A HREF="manual.html#pdf-debug.upvalueid">debug.upvalueid</A><BR> +<A HREF="manual.html#pdf-debug.upvaluejoin">debug.upvaluejoin</A><BR> + +<P> +<A HREF="manual.html#6.8">io</A><BR> +<A HREF="manual.html#pdf-io.close">io.close</A><BR> +<A HREF="manual.html#pdf-io.flush">io.flush</A><BR> +<A HREF="manual.html#pdf-io.input">io.input</A><BR> +<A HREF="manual.html#pdf-io.lines">io.lines</A><BR> +<A HREF="manual.html#pdf-io.open">io.open</A><BR> +<A HREF="manual.html#pdf-io.output">io.output</A><BR> +<A HREF="manual.html#pdf-io.popen">io.popen</A><BR> +<A HREF="manual.html#pdf-io.read">io.read</A><BR> +<A HREF="manual.html#pdf-io.stderr">io.stderr</A><BR> +<A HREF="manual.html#pdf-io.stdin">io.stdin</A><BR> +<A HREF="manual.html#pdf-io.stdout">io.stdout</A><BR> +<A HREF="manual.html#pdf-io.tmpfile">io.tmpfile</A><BR> +<A HREF="manual.html#pdf-io.type">io.type</A><BR> +<A HREF="manual.html#pdf-io.write">io.write</A><BR> + +<A HREF="manual.html#pdf-file:close">file:close</A><BR> +<A HREF="manual.html#pdf-file:flush">file:flush</A><BR> +<A HREF="manual.html#pdf-file:lines">file:lines</A><BR> +<A HREF="manual.html#pdf-file:read">file:read</A><BR> +<A HREF="manual.html#pdf-file:seek">file:seek</A><BR> +<A HREF="manual.html#pdf-file:setvbuf">file:setvbuf</A><BR> +<A HREF="manual.html#pdf-file:write">file:write</A><BR> + +</TD> +<TD> +<H3> </H3> +<P> +<A HREF="manual.html#6.7">math</A><BR> +<A HREF="manual.html#pdf-math.abs">math.abs</A><BR> +<A HREF="manual.html#pdf-math.acos">math.acos</A><BR> +<A HREF="manual.html#pdf-math.asin">math.asin</A><BR> +<A HREF="manual.html#pdf-math.atan">math.atan</A><BR> +<A HREF="manual.html#pdf-math.ceil">math.ceil</A><BR> +<A HREF="manual.html#pdf-math.cos">math.cos</A><BR> +<A HREF="manual.html#pdf-math.deg">math.deg</A><BR> +<A HREF="manual.html#pdf-math.exp">math.exp</A><BR> +<A HREF="manual.html#pdf-math.floor">math.floor</A><BR> +<A HREF="manual.html#pdf-math.fmod">math.fmod</A><BR> +<A HREF="manual.html#pdf-math.huge">math.huge</A><BR> +<A HREF="manual.html#pdf-math.log">math.log</A><BR> +<A HREF="manual.html#pdf-math.max">math.max</A><BR> +<A HREF="manual.html#pdf-math.maxinteger">math.maxinteger</A><BR> +<A HREF="manual.html#pdf-math.min">math.min</A><BR> +<A HREF="manual.html#pdf-math.mininteger">math.mininteger</A><BR> +<A HREF="manual.html#pdf-math.modf">math.modf</A><BR> +<A HREF="manual.html#pdf-math.pi">math.pi</A><BR> +<A HREF="manual.html#pdf-math.rad">math.rad</A><BR> +<A HREF="manual.html#pdf-math.random">math.random</A><BR> +<A HREF="manual.html#pdf-math.randomseed">math.randomseed</A><BR> +<A HREF="manual.html#pdf-math.sin">math.sin</A><BR> +<A HREF="manual.html#pdf-math.sqrt">math.sqrt</A><BR> +<A HREF="manual.html#pdf-math.tan">math.tan</A><BR> +<A HREF="manual.html#pdf-math.tointeger">math.tointeger</A><BR> +<A HREF="manual.html#pdf-math.type">math.type</A><BR> +<A HREF="manual.html#pdf-math.ult">math.ult</A><BR> + +<P> +<A HREF="manual.html#6.9">os</A><BR> +<A HREF="manual.html#pdf-os.clock">os.clock</A><BR> +<A HREF="manual.html#pdf-os.date">os.date</A><BR> +<A HREF="manual.html#pdf-os.difftime">os.difftime</A><BR> +<A HREF="manual.html#pdf-os.execute">os.execute</A><BR> +<A HREF="manual.html#pdf-os.exit">os.exit</A><BR> +<A HREF="manual.html#pdf-os.getenv">os.getenv</A><BR> +<A HREF="manual.html#pdf-os.remove">os.remove</A><BR> +<A HREF="manual.html#pdf-os.rename">os.rename</A><BR> +<A HREF="manual.html#pdf-os.setlocale">os.setlocale</A><BR> +<A HREF="manual.html#pdf-os.time">os.time</A><BR> +<A HREF="manual.html#pdf-os.tmpname">os.tmpname</A><BR> + +<P> +<A HREF="manual.html#6.3">package</A><BR> +<A HREF="manual.html#pdf-package.config">package.config</A><BR> +<A HREF="manual.html#pdf-package.cpath">package.cpath</A><BR> +<A HREF="manual.html#pdf-package.loaded">package.loaded</A><BR> +<A HREF="manual.html#pdf-package.loadlib">package.loadlib</A><BR> +<A HREF="manual.html#pdf-package.path">package.path</A><BR> +<A HREF="manual.html#pdf-package.preload">package.preload</A><BR> +<A HREF="manual.html#pdf-package.searchers">package.searchers</A><BR> +<A HREF="manual.html#pdf-package.searchpath">package.searchpath</A><BR> + +<P> +<A HREF="manual.html#6.4">string</A><BR> +<A HREF="manual.html#pdf-string.byte">string.byte</A><BR> +<A HREF="manual.html#pdf-string.char">string.char</A><BR> +<A HREF="manual.html#pdf-string.dump">string.dump</A><BR> +<A HREF="manual.html#pdf-string.find">string.find</A><BR> +<A HREF="manual.html#pdf-string.format">string.format</A><BR> +<A HREF="manual.html#pdf-string.gmatch">string.gmatch</A><BR> +<A HREF="manual.html#pdf-string.gsub">string.gsub</A><BR> +<A HREF="manual.html#pdf-string.len">string.len</A><BR> +<A HREF="manual.html#pdf-string.lower">string.lower</A><BR> +<A HREF="manual.html#pdf-string.match">string.match</A><BR> +<A HREF="manual.html#pdf-string.pack">string.pack</A><BR> +<A HREF="manual.html#pdf-string.packsize">string.packsize</A><BR> +<A HREF="manual.html#pdf-string.rep">string.rep</A><BR> +<A HREF="manual.html#pdf-string.reverse">string.reverse</A><BR> +<A HREF="manual.html#pdf-string.sub">string.sub</A><BR> +<A HREF="manual.html#pdf-string.unpack">string.unpack</A><BR> +<A HREF="manual.html#pdf-string.upper">string.upper</A><BR> + +<P> +<A HREF="manual.html#6.6">table</A><BR> +<A HREF="manual.html#pdf-table.concat">table.concat</A><BR> +<A HREF="manual.html#pdf-table.insert">table.insert</A><BR> +<A HREF="manual.html#pdf-table.move">table.move</A><BR> +<A HREF="manual.html#pdf-table.pack">table.pack</A><BR> +<A HREF="manual.html#pdf-table.remove">table.remove</A><BR> +<A HREF="manual.html#pdf-table.sort">table.sort</A><BR> +<A HREF="manual.html#pdf-table.unpack">table.unpack</A><BR> + +<P> +<A HREF="manual.html#6.5">utf8</A><BR> +<A HREF="manual.html#pdf-utf8.char">utf8.char</A><BR> +<A HREF="manual.html#pdf-utf8.charpattern">utf8.charpattern</A><BR> +<A HREF="manual.html#pdf-utf8.codepoint">utf8.codepoint</A><BR> +<A HREF="manual.html#pdf-utf8.codes">utf8.codes</A><BR> +<A HREF="manual.html#pdf-utf8.len">utf8.len</A><BR> +<A HREF="manual.html#pdf-utf8.offset">utf8.offset</A><BR> + +<H3><A NAME="metamethods">metamethods</A></H3> +<P> +<A HREF="manual.html#2.4">__add</A><BR> +<A HREF="manual.html#2.4">__band</A><BR> +<A HREF="manual.html#2.4">__bnot</A><BR> +<A HREF="manual.html#2.4">__bor</A><BR> +<A HREF="manual.html#2.4">__bxor</A><BR> +<A HREF="manual.html#2.4">__call</A><BR> +<A HREF="manual.html#3.3.8">__close</A><BR> +<A HREF="manual.html#2.4">__concat</A><BR> +<A HREF="manual.html#2.4">__div</A><BR> +<A HREF="manual.html#2.4">__eq</A><BR> +<A HREF="manual.html#2.5.3">__gc</A><BR> +<A HREF="manual.html#2.4">__idiv</A><BR> +<A HREF="manual.html#2.4">__index</A><BR> +<A HREF="manual.html#2.4">__le</A><BR> +<A HREF="manual.html#2.4">__len</A><BR> +<A HREF="manual.html#2.4">__lt</A><BR> +<A HREF="manual.html#pdf-getmetatable">__metatable</A><BR> +<A HREF="manual.html#2.4">__mod</A><BR> +<A HREF="manual.html#2.5.4">__mode</A><BR> +<A HREF="manual.html#2.4">__mul</A><BR> +<A HREF="manual.html#luaL_newmetatable">__name</A><BR> +<A HREF="manual.html#2.4">__newindex</A><BR> +<A HREF="manual.html#pdf-pairs">__pairs</A><BR> +<A HREF="manual.html#2.4">__pow</A><BR> +<A HREF="manual.html#2.4">__shl</A><BR> +<A HREF="manual.html#2.4">__shr</A><BR> +<A HREF="manual.html#2.4">__sub</A><BR> +<A HREF="manual.html#pdf-tostring">__tostring</A><BR> +<A HREF="manual.html#2.4">__unm</A><BR> + +<H3><A NAME="env">environment<BR>variables</A></H3> +<P> +<A HREF="manual.html#pdf-LUA_CPATH">LUA_CPATH</A><BR> +<A HREF="manual.html#pdf-LUA_CPATH_5_4">LUA_CPATH_5_4</A><BR> +<A HREF="manual.html#pdf-LUA_INIT">LUA_INIT</A><BR> +<A HREF="manual.html#pdf-LUA_INIT_5_4">LUA_INIT_5_4</A><BR> +<A HREF="manual.html#pdf-LUA_PATH">LUA_PATH</A><BR> +<A HREF="manual.html#pdf-LUA_PATH_5_4">LUA_PATH_5_4</A><BR> + +</TD> +<TD> +<H3><A NAME="api">C API</A></H3> +<P> +<A HREF="manual.html#lua_Alloc">lua_Alloc</A><BR> +<A HREF="manual.html#lua_CFunction">lua_CFunction</A><BR> +<A HREF="manual.html#lua_Debug">lua_Debug</A><BR> +<A HREF="manual.html#lua_Hook">lua_Hook</A><BR> +<A HREF="manual.html#lua_Integer">lua_Integer</A><BR> +<A HREF="manual.html#lua_KContext">lua_KContext</A><BR> +<A HREF="manual.html#lua_KFunction">lua_KFunction</A><BR> +<A HREF="manual.html#lua_Number">lua_Number</A><BR> +<A HREF="manual.html#lua_Reader">lua_Reader</A><BR> +<A HREF="manual.html#lua_State">lua_State</A><BR> +<A HREF="manual.html#lua_Unsigned">lua_Unsigned</A><BR> +<A HREF="manual.html#lua_WarnFunction">lua_WarnFunction</A><BR> +<A HREF="manual.html#lua_Writer">lua_Writer</A><BR> + +<P> +<A HREF="manual.html#lua_absindex">lua_absindex</A><BR> +<A HREF="manual.html#lua_arith">lua_arith</A><BR> +<A HREF="manual.html#lua_atpanic">lua_atpanic</A><BR> +<A HREF="manual.html#lua_call">lua_call</A><BR> +<A HREF="manual.html#lua_callk">lua_callk</A><BR> +<A HREF="manual.html#lua_checkstack">lua_checkstack</A><BR> +<A HREF="manual.html#lua_close">lua_close</A><BR> +<A HREF="manual.html#lua_closeslot">lua_closeslot</A><BR> +<A HREF="manual.html#lua_compare">lua_compare</A><BR> +<A HREF="manual.html#lua_concat">lua_concat</A><BR> +<A HREF="manual.html#lua_copy">lua_copy</A><BR> +<A HREF="manual.html#lua_createtable">lua_createtable</A><BR> +<A HREF="manual.html#lua_dump">lua_dump</A><BR> +<A HREF="manual.html#lua_error">lua_error</A><BR> +<A HREF="manual.html#lua_gc">lua_gc</A><BR> +<A HREF="manual.html#lua_getallocf">lua_getallocf</A><BR> +<A HREF="manual.html#lua_getextraspace">lua_getextraspace</A><BR> +<A HREF="manual.html#lua_getfield">lua_getfield</A><BR> +<A HREF="manual.html#lua_getglobal">lua_getglobal</A><BR> +<A HREF="manual.html#lua_gethook">lua_gethook</A><BR> +<A HREF="manual.html#lua_gethookcount">lua_gethookcount</A><BR> +<A HREF="manual.html#lua_gethookmask">lua_gethookmask</A><BR> +<A HREF="manual.html#lua_geti">lua_geti</A><BR> +<A HREF="manual.html#lua_getinfo">lua_getinfo</A><BR> +<A HREF="manual.html#lua_getiuservalue">lua_getiuservalue</A><BR> +<A HREF="manual.html#lua_getlocal">lua_getlocal</A><BR> +<A HREF="manual.html#lua_getmetatable">lua_getmetatable</A><BR> +<A HREF="manual.html#lua_getstack">lua_getstack</A><BR> +<A HREF="manual.html#lua_gettable">lua_gettable</A><BR> +<A HREF="manual.html#lua_gettop">lua_gettop</A><BR> +<A HREF="manual.html#lua_getupvalue">lua_getupvalue</A><BR> +<A HREF="manual.html#lua_insert">lua_insert</A><BR> +<A HREF="manual.html#lua_isboolean">lua_isboolean</A><BR> +<A HREF="manual.html#lua_iscfunction">lua_iscfunction</A><BR> +<A HREF="manual.html#lua_isfunction">lua_isfunction</A><BR> +<A HREF="manual.html#lua_isinteger">lua_isinteger</A><BR> +<A HREF="manual.html#lua_islightuserdata">lua_islightuserdata</A><BR> +<A HREF="manual.html#lua_isnil">lua_isnil</A><BR> +<A HREF="manual.html#lua_isnone">lua_isnone</A><BR> +<A HREF="manual.html#lua_isnoneornil">lua_isnoneornil</A><BR> +<A HREF="manual.html#lua_isnumber">lua_isnumber</A><BR> +<A HREF="manual.html#lua_isstring">lua_isstring</A><BR> +<A HREF="manual.html#lua_istable">lua_istable</A><BR> +<A HREF="manual.html#lua_isthread">lua_isthread</A><BR> +<A HREF="manual.html#lua_isuserdata">lua_isuserdata</A><BR> +<A HREF="manual.html#lua_isyieldable">lua_isyieldable</A><BR> +<A HREF="manual.html#lua_len">lua_len</A><BR> +<A HREF="manual.html#lua_load">lua_load</A><BR> +<A HREF="manual.html#lua_newstate">lua_newstate</A><BR> +<A HREF="manual.html#lua_newtable">lua_newtable</A><BR> +<A HREF="manual.html#lua_newthread">lua_newthread</A><BR> +<A HREF="manual.html#lua_newuserdatauv">lua_newuserdatauv</A><BR> +<A HREF="manual.html#lua_next">lua_next</A><BR> +<A HREF="manual.html#lua_numbertointeger">lua_numbertointeger</A><BR> +<A HREF="manual.html#lua_pcall">lua_pcall</A><BR> +<A HREF="manual.html#lua_pcallk">lua_pcallk</A><BR> +<A HREF="manual.html#lua_pop">lua_pop</A><BR> +<A HREF="manual.html#lua_pushboolean">lua_pushboolean</A><BR> +<A HREF="manual.html#lua_pushcclosure">lua_pushcclosure</A><BR> +<A HREF="manual.html#lua_pushcfunction">lua_pushcfunction</A><BR> +<A HREF="manual.html#lua_pushfstring">lua_pushfstring</A><BR> +<A HREF="manual.html#lua_pushglobaltable">lua_pushglobaltable</A><BR> +<A HREF="manual.html#lua_pushinteger">lua_pushinteger</A><BR> +<A HREF="manual.html#lua_pushlightuserdata">lua_pushlightuserdata</A><BR> +<A HREF="manual.html#lua_pushliteral">lua_pushliteral</A><BR> +<A HREF="manual.html#lua_pushlstring">lua_pushlstring</A><BR> +<A HREF="manual.html#lua_pushnil">lua_pushnil</A><BR> +<A HREF="manual.html#lua_pushnumber">lua_pushnumber</A><BR> +<A HREF="manual.html#lua_pushstring">lua_pushstring</A><BR> +<A HREF="manual.html#lua_pushthread">lua_pushthread</A><BR> +<A HREF="manual.html#lua_pushvalue">lua_pushvalue</A><BR> +<A HREF="manual.html#lua_pushvfstring">lua_pushvfstring</A><BR> +<A HREF="manual.html#lua_rawequal">lua_rawequal</A><BR> +<A HREF="manual.html#lua_rawget">lua_rawget</A><BR> +<A HREF="manual.html#lua_rawgeti">lua_rawgeti</A><BR> +<A HREF="manual.html#lua_rawgetp">lua_rawgetp</A><BR> +<A HREF="manual.html#lua_rawlen">lua_rawlen</A><BR> +<A HREF="manual.html#lua_rawset">lua_rawset</A><BR> +<A HREF="manual.html#lua_rawseti">lua_rawseti</A><BR> +<A HREF="manual.html#lua_rawsetp">lua_rawsetp</A><BR> +<A HREF="manual.html#lua_register">lua_register</A><BR> +<A HREF="manual.html#lua_remove">lua_remove</A><BR> +<A HREF="manual.html#lua_replace">lua_replace</A><BR> +<A HREF="manual.html#lua_resetthread">lua_resetthread</A><BR> +<A HREF="manual.html#lua_resume">lua_resume</A><BR> +<A HREF="manual.html#lua_rotate">lua_rotate</A><BR> +<A HREF="manual.html#lua_setallocf">lua_setallocf</A><BR> +<A HREF="manual.html#lua_setfield">lua_setfield</A><BR> +<A HREF="manual.html#lua_setglobal">lua_setglobal</A><BR> +<A HREF="manual.html#lua_sethook">lua_sethook</A><BR> +<A HREF="manual.html#lua_seti">lua_seti</A><BR> +<A HREF="manual.html#lua_setiuservalue">lua_setiuservalue</A><BR> +<A HREF="manual.html#lua_setlocal">lua_setlocal</A><BR> +<A HREF="manual.html#lua_setmetatable">lua_setmetatable</A><BR> +<A HREF="manual.html#lua_settable">lua_settable</A><BR> +<A HREF="manual.html#lua_settop">lua_settop</A><BR> +<A HREF="manual.html#lua_setupvalue">lua_setupvalue</A><BR> +<A HREF="manual.html#lua_setwarnf">lua_setwarnf</A><BR> +<A HREF="manual.html#lua_status">lua_status</A><BR> +<A HREF="manual.html#lua_stringtonumber">lua_stringtonumber</A><BR> +<A HREF="manual.html#lua_toboolean">lua_toboolean</A><BR> +<A HREF="manual.html#lua_tocfunction">lua_tocfunction</A><BR> +<A HREF="manual.html#lua_toclose">lua_toclose</A><BR> +<A HREF="manual.html#lua_tointeger">lua_tointeger</A><BR> +<A HREF="manual.html#lua_tointegerx">lua_tointegerx</A><BR> +<A HREF="manual.html#lua_tolstring">lua_tolstring</A><BR> +<A HREF="manual.html#lua_tonumber">lua_tonumber</A><BR> +<A HREF="manual.html#lua_tonumberx">lua_tonumberx</A><BR> +<A HREF="manual.html#lua_topointer">lua_topointer</A><BR> +<A HREF="manual.html#lua_tostring">lua_tostring</A><BR> +<A HREF="manual.html#lua_tothread">lua_tothread</A><BR> +<A HREF="manual.html#lua_touserdata">lua_touserdata</A><BR> +<A HREF="manual.html#lua_type">lua_type</A><BR> +<A HREF="manual.html#lua_typename">lua_typename</A><BR> +<A HREF="manual.html#lua_upvalueid">lua_upvalueid</A><BR> +<A HREF="manual.html#lua_upvalueindex">lua_upvalueindex</A><BR> +<A HREF="manual.html#lua_upvaluejoin">lua_upvaluejoin</A><BR> +<A HREF="manual.html#lua_version">lua_version</A><BR> +<A HREF="manual.html#lua_warning">lua_warning</A><BR> +<A HREF="manual.html#lua_xmove">lua_xmove</A><BR> +<A HREF="manual.html#lua_yield">lua_yield</A><BR> +<A HREF="manual.html#lua_yieldk">lua_yieldk</A><BR> + +</TD> +<TD> +<H3><A NAME="auxlib">auxiliary library</A></H3> +<P> +<A HREF="manual.html#luaL_Buffer">luaL_Buffer</A><BR> +<A HREF="manual.html#luaL_Reg">luaL_Reg</A><BR> +<A HREF="manual.html#luaL_Stream">luaL_Stream</A><BR> + +<P> +<A HREF="manual.html#luaL_addchar">luaL_addchar</A><BR> +<A HREF="manual.html#luaL_addgsub">luaL_addgsub</A><BR> +<A HREF="manual.html#luaL_addlstring">luaL_addlstring</A><BR> +<A HREF="manual.html#luaL_addsize">luaL_addsize</A><BR> +<A HREF="manual.html#luaL_addstring">luaL_addstring</A><BR> +<A HREF="manual.html#luaL_addvalue">luaL_addvalue</A><BR> +<A HREF="manual.html#luaL_argcheck">luaL_argcheck</A><BR> +<A HREF="manual.html#luaL_argerror">luaL_argerror</A><BR> +<A HREF="manual.html#luaL_argexpected">luaL_argexpected</A><BR> +<A HREF="manual.html#luaL_buffaddr">luaL_buffaddr</A><BR> +<A HREF="manual.html#luaL_buffinit">luaL_buffinit</A><BR> +<A HREF="manual.html#luaL_buffinitsize">luaL_buffinitsize</A><BR> +<A HREF="manual.html#luaL_bufflen">luaL_bufflen</A><BR> +<A HREF="manual.html#luaL_buffsub">luaL_buffsub</A><BR> +<A HREF="manual.html#luaL_callmeta">luaL_callmeta</A><BR> +<A HREF="manual.html#luaL_checkany">luaL_checkany</A><BR> +<A HREF="manual.html#luaL_checkinteger">luaL_checkinteger</A><BR> +<A HREF="manual.html#luaL_checklstring">luaL_checklstring</A><BR> +<A HREF="manual.html#luaL_checknumber">luaL_checknumber</A><BR> +<A HREF="manual.html#luaL_checkoption">luaL_checkoption</A><BR> +<A HREF="manual.html#luaL_checkstack">luaL_checkstack</A><BR> +<A HREF="manual.html#luaL_checkstring">luaL_checkstring</A><BR> +<A HREF="manual.html#luaL_checktype">luaL_checktype</A><BR> +<A HREF="manual.html#luaL_checkudata">luaL_checkudata</A><BR> +<A HREF="manual.html#luaL_checkversion">luaL_checkversion</A><BR> +<A HREF="manual.html#luaL_dofile">luaL_dofile</A><BR> +<A HREF="manual.html#luaL_dostring">luaL_dostring</A><BR> +<A HREF="manual.html#luaL_error">luaL_error</A><BR> +<A HREF="manual.html#luaL_execresult">luaL_execresult</A><BR> +<A HREF="manual.html#luaL_fileresult">luaL_fileresult</A><BR> +<A HREF="manual.html#luaL_getmetafield">luaL_getmetafield</A><BR> +<A HREF="manual.html#luaL_getmetatable">luaL_getmetatable</A><BR> +<A HREF="manual.html#luaL_getsubtable">luaL_getsubtable</A><BR> +<A HREF="manual.html#luaL_gsub">luaL_gsub</A><BR> +<A HREF="manual.html#luaL_len">luaL_len</A><BR> +<A HREF="manual.html#luaL_loadbuffer">luaL_loadbuffer</A><BR> +<A HREF="manual.html#luaL_loadbufferx">luaL_loadbufferx</A><BR> +<A HREF="manual.html#luaL_loadfile">luaL_loadfile</A><BR> +<A HREF="manual.html#luaL_loadfilex">luaL_loadfilex</A><BR> +<A HREF="manual.html#luaL_loadstring">luaL_loadstring</A><BR> +<A HREF="manual.html#luaL_newlib">luaL_newlib</A><BR> +<A HREF="manual.html#luaL_newlibtable">luaL_newlibtable</A><BR> +<A HREF="manual.html#luaL_newmetatable">luaL_newmetatable</A><BR> +<A HREF="manual.html#luaL_newstate">luaL_newstate</A><BR> +<A HREF="manual.html#luaL_openlibs">luaL_openlibs</A><BR> +<A HREF="manual.html#luaL_opt">luaL_opt</A><BR> +<A HREF="manual.html#luaL_optinteger">luaL_optinteger</A><BR> +<A HREF="manual.html#luaL_optlstring">luaL_optlstring</A><BR> +<A HREF="manual.html#luaL_optnumber">luaL_optnumber</A><BR> +<A HREF="manual.html#luaL_optstring">luaL_optstring</A><BR> +<A HREF="manual.html#luaL_prepbuffer">luaL_prepbuffer</A><BR> +<A HREF="manual.html#luaL_prepbuffsize">luaL_prepbuffsize</A><BR> +<A HREF="manual.html#luaL_pushfail">luaL_pushfail</A><BR> +<A HREF="manual.html#luaL_pushresult">luaL_pushresult</A><BR> +<A HREF="manual.html#luaL_pushresultsize">luaL_pushresultsize</A><BR> +<A HREF="manual.html#luaL_ref">luaL_ref</A><BR> +<A HREF="manual.html#luaL_requiref">luaL_requiref</A><BR> +<A HREF="manual.html#luaL_setfuncs">luaL_setfuncs</A><BR> +<A HREF="manual.html#luaL_setmetatable">luaL_setmetatable</A><BR> +<A HREF="manual.html#luaL_testudata">luaL_testudata</A><BR> +<A HREF="manual.html#luaL_tolstring">luaL_tolstring</A><BR> +<A HREF="manual.html#luaL_traceback">luaL_traceback</A><BR> +<A HREF="manual.html#luaL_typeerror">luaL_typeerror</A><BR> +<A HREF="manual.html#luaL_typename">luaL_typename</A><BR> +<A HREF="manual.html#luaL_unref">luaL_unref</A><BR> +<A HREF="manual.html#luaL_where">luaL_where</A><BR> + +<H3><A NAME="library">standard library</A></H3> +<P> +<A HREF="manual.html#pdf-luaopen_base">luaopen_base</A><BR> +<A HREF="manual.html#pdf-luaopen_coroutine">luaopen_coroutine</A><BR> +<A HREF="manual.html#pdf-luaopen_debug">luaopen_debug</A><BR> +<A HREF="manual.html#pdf-luaopen_io">luaopen_io</A><BR> +<A HREF="manual.html#pdf-luaopen_math">luaopen_math</A><BR> +<A HREF="manual.html#pdf-luaopen_os">luaopen_os</A><BR> +<A HREF="manual.html#pdf-luaopen_package">luaopen_package</A><BR> +<A HREF="manual.html#pdf-luaopen_string">luaopen_string</A><BR> +<A HREF="manual.html#pdf-luaopen_table">luaopen_table</A><BR> +<A HREF="manual.html#pdf-luaopen_utf8">luaopen_utf8</A><BR> + +<H3><A NAME="constants">constants</A></H3> +<P> +<A HREF="manual.html#pdf-LUA_ERRERR">LUA_ERRERR</A><BR> +<A HREF="manual.html#pdf-LUA_ERRFILE">LUA_ERRFILE</A><BR> +<A HREF="manual.html#pdf-LUA_ERRMEM">LUA_ERRMEM</A><BR> +<A HREF="manual.html#pdf-LUA_ERRRUN">LUA_ERRRUN</A><BR> +<A HREF="manual.html#pdf-LUA_ERRSYNTAX">LUA_ERRSYNTAX</A><BR> +<A HREF="manual.html#pdf-LUA_HOOKCALL">LUA_HOOKCALL</A><BR> +<A HREF="manual.html#pdf-LUA_HOOKCOUNT">LUA_HOOKCOUNT</A><BR> +<A HREF="manual.html#pdf-LUA_HOOKLINE">LUA_HOOKLINE</A><BR> +<A HREF="manual.html#pdf-LUA_HOOKRET">LUA_HOOKRET</A><BR> +<A HREF="manual.html#pdf-LUA_HOOKTAILCALL">LUA_HOOKTAILCALL</A><BR> +<A HREF="manual.html#pdf-LUA_LOADED_TABLE">LUA_LOADED_TABLE</A><BR> +<A HREF="manual.html#pdf-LUA_MASKCALL">LUA_MASKCALL</A><BR> +<A HREF="manual.html#pdf-LUA_MASKCOUNT">LUA_MASKCOUNT</A><BR> +<A HREF="manual.html#pdf-LUA_MASKLINE">LUA_MASKLINE</A><BR> +<A HREF="manual.html#pdf-LUA_MASKRET">LUA_MASKRET</A><BR> +<A HREF="manual.html#pdf-LUA_MAXINTEGER">LUA_MAXINTEGER</A><BR> +<A HREF="manual.html#pdf-LUA_MININTEGER">LUA_MININTEGER</A><BR> +<A HREF="manual.html#pdf-LUA_MINSTACK">LUA_MINSTACK</A><BR> +<A HREF="manual.html#pdf-LUA_MULTRET">LUA_MULTRET</A><BR> +<A HREF="manual.html#pdf-LUA_NOREF">LUA_NOREF</A><BR> +<A HREF="manual.html#pdf-LUA_OK">LUA_OK</A><BR> +<A HREF="manual.html#pdf-LUA_OPADD">LUA_OPADD</A><BR> +<A HREF="manual.html#pdf-LUA_OPBAND">LUA_OPBAND</A><BR> +<A HREF="manual.html#pdf-LUA_OPBNOT">LUA_OPBNOT</A><BR> +<A HREF="manual.html#pdf-LUA_OPBOR">LUA_OPBOR</A><BR> +<A HREF="manual.html#pdf-LUA_OPBXOR">LUA_OPBXOR</A><BR> +<A HREF="manual.html#pdf-LUA_OPDIV">LUA_OPDIV</A><BR> +<A HREF="manual.html#pdf-LUA_OPEQ">LUA_OPEQ</A><BR> +<A HREF="manual.html#pdf-LUA_OPIDIV">LUA_OPIDIV</A><BR> +<A HREF="manual.html#pdf-LUA_OPLE">LUA_OPLE</A><BR> +<A HREF="manual.html#pdf-LUA_OPLT">LUA_OPLT</A><BR> +<A HREF="manual.html#pdf-LUA_OPMOD">LUA_OPMOD</A><BR> +<A HREF="manual.html#pdf-LUA_OPMUL">LUA_OPMUL</A><BR> +<A HREF="manual.html#pdf-LUA_OPPOW">LUA_OPPOW</A><BR> +<A HREF="manual.html#pdf-LUA_OPSHL">LUA_OPSHL</A><BR> +<A HREF="manual.html#pdf-LUA_OPSHR">LUA_OPSHR</A><BR> +<A HREF="manual.html#pdf-LUA_OPSUB">LUA_OPSUB</A><BR> +<A HREF="manual.html#pdf-LUA_OPUNM">LUA_OPUNM</A><BR> +<A HREF="manual.html#pdf-LUA_PRELOAD_TABLE">LUA_PRELOAD_TABLE</A><BR> +<A HREF="manual.html#pdf-LUA_REFNIL">LUA_REFNIL</A><BR> +<A HREF="manual.html#pdf-LUA_REGISTRYINDEX">LUA_REGISTRYINDEX</A><BR> +<A HREF="manual.html#pdf-LUA_RIDX_GLOBALS">LUA_RIDX_GLOBALS</A><BR> +<A HREF="manual.html#pdf-LUA_RIDX_MAINTHREAD">LUA_RIDX_MAINTHREAD</A><BR> +<A HREF="manual.html#pdf-LUA_TBOOLEAN">LUA_TBOOLEAN</A><BR> +<A HREF="manual.html#pdf-LUA_TFUNCTION">LUA_TFUNCTION</A><BR> +<A HREF="manual.html#pdf-LUA_TLIGHTUSERDATA">LUA_TLIGHTUSERDATA</A><BR> +<A HREF="manual.html#pdf-LUA_TNIL">LUA_TNIL</A><BR> +<A HREF="manual.html#pdf-LUA_TNONE">LUA_TNONE</A><BR> +<A HREF="manual.html#pdf-LUA_TNUMBER">LUA_TNUMBER</A><BR> +<A HREF="manual.html#pdf-LUA_TSTRING">LUA_TSTRING</A><BR> +<A HREF="manual.html#pdf-LUA_TTABLE">LUA_TTABLE</A><BR> +<A HREF="manual.html#pdf-LUA_TTHREAD">LUA_TTHREAD</A><BR> +<A HREF="manual.html#pdf-LUA_TUSERDATA">LUA_TUSERDATA</A><BR> +<A HREF="manual.html#pdf-LUA_USE_APICHECK">LUA_USE_APICHECK</A><BR> +<A HREF="manual.html#pdf-LUA_YIELD">LUA_YIELD</A><BR> +<A HREF="manual.html#pdf-LUAL_BUFFERSIZE">LUAL_BUFFERSIZE</A><BR> + +</TD> +</TR> +</TABLE> + +<P CLASS="footer"> +Last update: +Sat Apr 1 17:57:05 UTC 2023 +</P> +<!-- +Last change: revised for Lua 5.4.5 +--> + +</BODY> +</HTML> diff --git a/src/libs/3rdparty/lua/doc/index.css b/src/libs/3rdparty/lua/doc/index.css new file mode 100644 index 0000000000..c961835731 --- /dev/null +++ b/src/libs/3rdparty/lua/doc/index.css @@ -0,0 +1,21 @@ +ul { + list-style-type: none ; +} + +ul.contents { + padding: 0 ; +} + +table { + border: none ; + border-spacing: 0 ; + border-collapse: collapse ; +} + +td { + vertical-align: top ; + padding: 0 ; + text-align: left ; + line-height: 1.25 ; + width: 15% ; +} diff --git a/src/libs/3rdparty/lua/doc/logo.gif b/src/libs/3rdparty/lua/doc/logo.gif Binary files differnew file mode 100644 index 0000000000..5c77eacc3b --- /dev/null +++ b/src/libs/3rdparty/lua/doc/logo.gif diff --git a/src/libs/3rdparty/lua/doc/lua.1 b/src/libs/3rdparty/lua/doc/lua.1 new file mode 100644 index 0000000000..3f472fd81f --- /dev/null +++ b/src/libs/3rdparty/lua/doc/lua.1 @@ -0,0 +1,155 @@ +.\" $Id: lua.man,v 1.14 2022/09/23 09:06:36 lhf Exp $ +.TH LUA 1 "$Date: 2022/09/23 09:06:36 $" +.SH NAME +lua \- Lua interpreter +.SH SYNOPSIS +.B lua +[ +.I options +] +[ +.I script +[ +.I args +] +] +.SH DESCRIPTION +.B lua +is the standalone Lua interpreter. +It loads and executes Lua programs, +either in textual source form or +in precompiled binary form. +(Precompiled binaries are output by +.BR luac , +the Lua compiler.) +.B lua +can be used as a batch interpreter and also interactively. +.LP +After handling the +.IR options , +the Lua program in file +.I script +is loaded and executed. +The +.I args +are available to +.I script +as strings in a global table named +.B arg +and also as arguments to its main function. +When called without arguments, +.B lua +behaves as +.B "lua \-v \-i" +if the standard input is a terminal, +and as +.B "lua \-" +otherwise. +.LP +In interactive mode, +.B lua +prompts the user, +reads lines from the standard input, +and executes them as they are read. +If the line contains an expression, +then the line is evaluated and the result is printed. +If a line does not contain a complete statement, +then a secondary prompt is displayed and +lines are read until a complete statement is formed or +a syntax error is found. +.LP +Before handling command line options and scripts, +.B lua +checks the contents of the environment variables +.B LUA_INIT_5_4 +and +.BR LUA_INIT , +in that order. +If the contents are of the form +.RI '@ filename ', +then +.I filename +is executed. +Otherwise, the contents are assumed to be a Lua statement and is executed. +When +.B LUA_INIT_5_4 +is defined, +.B LUA_INIT +is ignored. +.SH OPTIONS +.TP +.BI \-e " stat" +execute statement +.IR stat . +.TP +.B \-i +enter interactive mode after executing +.IR script . +.TP +.BI \-l " mod" +require library +.I mod +into global +.IR mod . +.TP +.BI \-l " g=mod" +require library +.I mod +into global +.IR g . +.TP +.B \-v +show version information. +.TP +.B \-E +ignore environment variables. +.TP +.B \-W +turn warnings on. +.TP +.B \-\- +stop handling options. +.TP +.B \- +stop handling options and execute the standard input as a file. +.SH ENVIRONMENT VARIABLES +The following environment variables affect the execution of +.BR lua . +When defined, +the version-specific variants take priority +and the version-neutral variants are ignored. +.TP +.B LUA_INIT, LUA_INIT_5_4 +Code to be executed before command line options and scripts. +.TP +.B LUA_PATH, LUA_PATH_5_4 +Initial value of package.cpath, +the path used by require to search for Lua loaders. +.TP +.B LUA_CPATH, LUA_CPATH_5_4 +Initial value of package.cpath, +the path used by require to search for C loaders. +.SH EXIT STATUS +If a script calls os.exit, +then +.B lua +exits with the given exit status. +Otherwise, +.B lua +exits +with EXIT_SUCCESS (0 on POSIX systems) if there were no errors +and +with EXIT_FAILURE (1 on POSIX systems) if there were errors. +Errors raised in interactive mode do not cause exits. +.SH DIAGNOSTICS +Error messages should be self explanatory. +.SH "SEE ALSO" +.BR luac (1) +.br +The documentation at lua.org, +especially section 7 of the reference manual. +.SH AUTHORS +R. Ierusalimschy, +L. H. de Figueiredo, +W. Celes +.\" EOF diff --git a/src/libs/3rdparty/lua/doc/lua.css b/src/libs/3rdparty/lua/doc/lua.css new file mode 100644 index 0000000000..cbd0799d15 --- /dev/null +++ b/src/libs/3rdparty/lua/doc/lua.css @@ -0,0 +1,161 @@ +html { + background-color: #F8F8F8 ; +} + +body { + background-color: #FFFFFF ; + color: #000000 ; + font-family: Helvetica, Arial, sans-serif ; + text-align: justify ; + line-height: 1.25 ; + margin: 16px auto ; + padding: 32px ; + border: solid #ccc 1px ; + border-radius: 20px ; + max-width: 70em ; + width: 90% ; +} + +h1, h2, h3, h4 { + color: #000080 ; + font-family: Verdana, Geneva, sans-serif ; + font-weight: normal ; + font-style: normal ; + text-align: left ; +} + +h1 { + font-size: 28pt ; +} + +h1 img { + vertical-align: text-bottom ; +} + +h2:before { + content: "\2756" ; + padding-right: 0.5em ; +} + +a { + text-decoration: none ; +} + +a:link { + color: #000080 ; +} + +a:link:hover, a:visited:hover { + background-color: #D0D0FF ; + color: #000080 ; + border-radius: 4px ; +} + +a:link:active, a:visited:active { + color: #FF0000 ; +} + +div.menubar { + 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 { + display: none ; +} + +table hr { + background-color: #a0a0a0 ; + color: #a0a0a0 ; + border: 0 ; + height: 1px ; + display: block ; +} + +.footer { + color: gray ; + font-size: x-small ; + text-transform: lowercase ; +} + +input[type=text] { + border: solid #a0a0a0 2px ; + border-radius: 2em ; + background-image: url('images/search.png') ; + background-repeat: no-repeat ; + background-position: 4px center ; + padding-left: 20px ; + height: 2em ; +} + +pre.session { + background-color: #F8F8F8 ; + padding: 1em ; + border-radius: 8px ; +} + +table { + border: none ; + border-spacing: 0 ; + border-collapse: collapse ; +} + +td { + padding: 0 ; + margin: 0 ; +} + +td.gutter { + width: 4% ; +} + +table.columns td { + vertical-align: top ; + padding-bottom: 1em ; + text-align: justify ; + line-height: 1.25 ; +} + +table.book td { + 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 ; +} + +p.logos a:link:hover, p.logos a:visited:hover { + background-color: inherit ; +} + +img { + background-color: white ; +} diff --git a/src/libs/3rdparty/lua/doc/luac.1 b/src/libs/3rdparty/lua/doc/luac.1 new file mode 100644 index 0000000000..33a4ed00ac --- /dev/null +++ b/src/libs/3rdparty/lua/doc/luac.1 @@ -0,0 +1,118 @@ +.\" $Id: luac.man,v 1.29 2011/11/16 13:53:40 lhf Exp $ +.TH LUAC 1 "$Date: 2011/11/16 13:53:40 $" +.SH NAME +luac \- Lua compiler +.SH SYNOPSIS +.B luac +[ +.I options +] [ +.I filenames +] +.SH DESCRIPTION +.B luac +is the Lua compiler. +It translates programs written in the Lua programming language +into binary files containing precompiled chunks +that can be later loaded and executed. +.LP +The main advantages of precompiling chunks are: +faster loading, +protecting source code from accidental user changes, +and +off-line syntax checking. +Precompiling does not imply faster execution +because in Lua chunks are always compiled into bytecodes before being executed. +.B luac +simply allows those bytecodes to be saved in a file for later execution. +Precompiled chunks are not necessarily smaller than the corresponding source. +The main goal in precompiling is faster loading. +.LP +In the command line, +you can mix +text files containing Lua source and +binary files containing precompiled chunks. +.B luac +produces a single output file containing the combined bytecodes +for all files given. +Executing the combined file is equivalent to executing the given files. +By default, +the output file is named +.BR luac.out , +but you can change this with the +.B \-o +option. +.LP +Precompiled chunks are +.I not +portable across different architectures. +Moreover, +the internal format of precompiled chunks +is likely to change when a new version of Lua is released. +Make sure you save the source files of all Lua programs that you precompile. +.LP +.SH OPTIONS +.TP +.B \-l +produce a listing of the compiled bytecode for Lua's virtual machine. +Listing bytecodes is useful to learn about Lua's virtual machine. +If no files are given, then +.B luac +loads +.B luac.out +and lists its contents. +Use +.B \-l \-l +for a full listing. +.TP +.BI \-o " file" +output to +.IR file , +instead of the default +.BR luac.out . +(You can use +.B "'\-'" +for standard output, +but not on platforms that open standard output in text mode.) +The output file may be one of the given files because +all files are loaded before the output file is written. +Be careful not to overwrite precious files. +.TP +.B \-p +load files but do not generate any output file. +Used mainly for syntax checking and for testing precompiled chunks: +corrupted files will probably generate errors when loaded. +If no files are given, then +.B luac +loads +.B luac.out +and tests its contents. +No messages are displayed if the file loads without errors. +.TP +.B \-s +strip debug information before writing the output file. +This saves some space in very large chunks, +but if errors occur when running a stripped chunk, +then the error messages may not contain the full information they usually do. +In particular, +line numbers and names of local variables are lost. +.TP +.B \-v +show version information. +.TP +.B \-\- +stop handling options. +.TP +.B \- +stop handling options and process standard input. +.SH "SEE ALSO" +.BR lua (1) +.br +The documentation at lua.org. +.SH DIAGNOSTICS +Error messages should be self explanatory. +.SH AUTHORS +R. Ierusalimschy, +L. H. de Figueiredo, +W. Celes +.\" EOF diff --git a/src/libs/3rdparty/lua/doc/manual.css b/src/libs/3rdparty/lua/doc/manual.css new file mode 100644 index 0000000000..aa0e677dd5 --- /dev/null +++ b/src/libs/3rdparty/lua/doc/manual.css @@ -0,0 +1,21 @@ +h3 code { + font-family: inherit ; + font-size: inherit ; +} + +pre, code { + font-size: 12pt ; +} + +span.apii { + color: gray ; + float: right ; + font-family: inherit ; + font-style: normal ; + font-size: small ; +} + +h2:before { + content: "" ; + padding-right: 0em ; +} diff --git a/src/libs/3rdparty/lua/doc/manual.html b/src/libs/3rdparty/lua/doc/manual.html new file mode 100644 index 0000000000..0af688b343 --- /dev/null +++ b/src/libs/3rdparty/lua/doc/manual.html @@ -0,0 +1,12046 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<HTML> +<HEAD> +<TITLE>Lua 5.4 Reference Manual</TITLE> +<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css"> +<LINK REL="stylesheet" TYPE="text/css" HREF="manual.css"> +<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1"> +</HEAD> + +<BODY> + +<H1> +<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> +Lua 5.4 Reference Manual +</H1> + +<P> +by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes + +<P> +<SMALL> +Copyright © 2020–2023 Lua.org, PUC-Rio. +Freely available under the terms of the +<a href="http://www.lua.org/license.html">Lua license</a>. +</SMALL> + +<DIV CLASS="menubar"> +<A HREF="contents.html#contents">contents</A> +· +<A HREF="contents.html#index">index</A> +· +<A HREF="http://www.lua.org/manual/">other versions</A> +</DIV> + +<!-- ====================================================================== --> +<p> + +<!-- $Id: manual.of $ --> + + + + +<h1>1 – <a name="1">Introduction</a></h1> + +<p> +Lua is a powerful, efficient, lightweight, embeddable scripting language. +It supports procedural programming, +object-oriented programming, functional programming, +data-driven programming, and data description. + + +<p> +Lua combines simple procedural syntax with powerful data description +constructs based on associative arrays and extensible semantics. +Lua is dynamically typed, +runs by interpreting bytecode with a register-based +virtual machine, +and has automatic memory management with +a generational garbage collection, +making it ideal for configuration, scripting, +and rapid prototyping. + + +<p> +Lua is implemented as a library, written in <em>clean C</em>, +the common subset of standard C and C++. +The Lua distribution includes a host program called <code>lua</code>, +which uses the Lua library to offer a complete, +standalone Lua interpreter, +for interactive or batch use. +Lua is intended to be used both as a powerful, lightweight, +embeddable scripting language for any program that needs one, +and as a powerful but lightweight and efficient stand-alone language. + + +<p> +As an extension language, Lua has no notion of a "main" program: +it works <em>embedded</em> in a host client, +called the <em>embedding program</em> or simply the <em>host</em>. +(Frequently, this host is the stand-alone <code>lua</code> program.) +The host program can invoke functions to execute a piece of Lua code, +can write and read Lua variables, +and can register C functions to be called by Lua code. +Through the use of C functions, Lua can be augmented to cope with +a wide range of different domains, +thus creating customized programming languages sharing a syntactical framework. + + +<p> +Lua is free software, +and is provided as usual with no guarantees, +as stated in its license. +The implementation described in this manual is available +at Lua's official web site, <code>www.lua.org</code>. + + +<p> +Like any other reference manual, +this document is dry in places. +For a discussion of the decisions behind the design of Lua, +see the technical papers available at Lua's web site. +For a detailed introduction to programming in Lua, +see Roberto's book, <em>Programming in Lua</em>. + + + +<h1>2 – <a name="2">Basic Concepts</a></h1> + + + +<p> +This section describes the basic concepts of the language. + + + + + +<h2>2.1 – <a name="2.1">Values and Types</a></h2> + +<p> +Lua is a dynamically typed language. +This means that +variables do not have types; only values do. +There are no type definitions in the language. +All values carry their own type. + + +<p> +All values in Lua are first-class values. +This means that all values can be stored in variables, +passed as arguments to other functions, and returned as results. + + +<p> +There are eight basic types in Lua: +<em>nil</em>, <em>boolean</em>, <em>number</em>, +<em>string</em>, <em>function</em>, <em>userdata</em>, +<em>thread</em>, and <em>table</em>. +The type <em>nil</em> has one single value, <b>nil</b>, +whose main property is to be different from any other value; +it often represents the absence of a useful value. +The type <em>boolean</em> has two values, <b>false</b> and <b>true</b>. +Both <b>nil</b> and <b>false</b> make a condition false; +they are collectively called <em>false values</em>. +Any other value makes a condition true. +Despite its name, +<b>false</b> is frequently used as an alternative to <b>nil</b>, +with the key difference that <b>false</b> behaves +like a regular value in a table, +while a <b>nil</b> in a table represents an absent key. + + +<p> +The type <em>number</em> represents both +integer numbers and real (floating-point) numbers, +using two subtypes: <em>integer</em> and <em>float</em>. +Standard Lua uses 64-bit integers and double-precision (64-bit) floats, +but you can also compile Lua so that it +uses 32-bit integers and/or single-precision (32-bit) floats. +The option with 32 bits for both integers and floats +is particularly attractive +for small machines and embedded systems. +(See macro <code>LUA_32BITS</code> in file <code>luaconf.h</code>.) + + +<p> +Unless stated otherwise, +any overflow when manipulating integer values <em>wrap around</em>, +according to the usual rules of two-complement arithmetic. +(In other words, +the actual result is the unique representable integer +that is equal modulo <em>2<sup>n</sup></em> to the mathematical result, +where <em>n</em> is the number of bits of the integer type.) + + +<p> +Lua has explicit rules about when each subtype is used, +but it also converts between them automatically as needed (see <a href="#3.4.3">§3.4.3</a>). +Therefore, +the programmer may choose to mostly ignore the difference +between integers and floats +or to assume complete control over the representation of each number. + + +<p> +The type <em>string</em> represents immutable sequences of bytes. + +Lua is 8-bit clean: +strings can contain any 8-bit value, +including embedded zeros ('<code>\0</code>'). +Lua is also encoding-agnostic; +it makes no assumptions about the contents of a string. +The length of any string in Lua must fit in a Lua integer. + + +<p> +Lua can call (and manipulate) functions written in Lua and +functions written in C (see <a href="#3.4.10">§3.4.10</a>). +Both are represented by the type <em>function</em>. + + +<p> +The type <em>userdata</em> is provided to allow arbitrary C data to +be stored in Lua variables. +A userdata value represents a block of raw memory. +There are two kinds of userdata: +<em>full userdata</em>, +which is an object with a block of memory managed by Lua, +and <em>light userdata</em>, +which is simply a C pointer value. +Userdata has no predefined operations in Lua, +except assignment and identity test. +By using <em>metatables</em>, +the programmer can define operations for full userdata values +(see <a href="#2.4">§2.4</a>). +Userdata values cannot be created or modified in Lua, +only through the C API. +This guarantees the integrity of data owned by +the host program and C libraries. + + +<p> +The type <em>thread</em> represents independent threads of execution +and it is used to implement coroutines (see <a href="#2.6">§2.6</a>). +Lua threads are not related to operating-system threads. +Lua supports coroutines on all systems, +even those that do not support threads natively. + + +<p> +The type <em>table</em> implements associative arrays, +that is, arrays that can have as indices not only numbers, +but any Lua value except <b>nil</b> and NaN. +(<em>Not a Number</em> is a special floating-point value +used by the IEEE 754 standard to represent +undefined numerical results, such as <code>0/0</code>.) +Tables can be <em>heterogeneous</em>; +that is, they can contain values of all types (except <b>nil</b>). +Any key associated to the value <b>nil</b> is not considered part of the table. +Conversely, any key that is not part of a table has +an associated value <b>nil</b>. + + +<p> +Tables are the sole data-structuring mechanism in Lua; +they can be used to represent ordinary arrays, lists, +symbol tables, sets, records, graphs, trees, etc. +To represent records, Lua uses the field name as an index. +The language supports this representation by +providing <code>a.name</code> as syntactic sugar for <code>a["name"]</code>. +There are several convenient ways to create tables in Lua +(see <a href="#3.4.9">§3.4.9</a>). + + +<p> +Like indices, +the values of table fields can be of any type. +In particular, +because functions are first-class values, +table fields can contain functions. +Thus tables can also carry <em>methods</em> (see <a href="#3.4.11">§3.4.11</a>). + + +<p> +The indexing of tables follows +the definition of raw equality in the language. +The expressions <code>a[i]</code> and <code>a[j]</code> +denote the same table element +if and only if <code>i</code> and <code>j</code> are raw equal +(that is, equal without metamethods). +In particular, floats with integral values +are equal to their respective integers +(e.g., <code>1.0 == 1</code>). +To avoid ambiguities, +any float used as a key that is equal to an integer +is converted to that integer. +For instance, if you write <code>a[2.0] = true</code>, +the actual key inserted into the table will be the integer <code>2</code>. + + +<p> +Tables, functions, threads, and (full) userdata values are <em>objects</em>: +variables do not actually <em>contain</em> these values, +only <em>references</em> to them. +Assignment, parameter passing, and function returns +always manipulate references to such values; +these operations do not imply any kind of copy. + + +<p> +The library function <a href="#pdf-type"><code>type</code></a> returns a string describing the type +of a given value (see <a href="#pdf-type"><code>type</code></a>). + + + + + +<h2>2.2 – <a name="2.2">Environments and the Global Environment</a></h2> + +<p> +As we will discuss further in <a href="#3.2">§3.2</a> and <a href="#3.3.3">§3.3.3</a>, +any reference to a free name +(that is, a name not bound to any declaration) <code>var</code> +is syntactically translated to <code>_ENV.var</code>. +Moreover, every chunk is compiled in the scope of +an external local variable named <code>_ENV</code> (see <a href="#3.3.2">§3.3.2</a>), +so <code>_ENV</code> itself is never a free name in a chunk. + + +<p> +Despite the existence of this external <code>_ENV</code> variable and +the translation of free names, +<code>_ENV</code> is a completely regular name. +In particular, +you can define new variables and parameters with that name. +Each reference to a free name uses the <code>_ENV</code> that is +visible at that point in the program, +following the usual visibility rules of Lua (see <a href="#3.5">§3.5</a>). + + +<p> +Any table used as the value of <code>_ENV</code> is called an <em>environment</em>. + + +<p> +Lua keeps a distinguished environment called the <em>global environment</em>. +This value is kept at a special index in the C registry (see <a href="#4.3">§4.3</a>). +In Lua, the global variable <a href="#pdf-_G"><code>_G</code></a> is initialized with this same value. +(<a href="#pdf-_G"><code>_G</code></a> is never used internally, +so changing its value will affect only your own code.) + + +<p> +When Lua loads a chunk, +the default value for its <code>_ENV</code> variable +is the global environment (see <a href="#pdf-load"><code>load</code></a>). +Therefore, by default, +free names in Lua code refer to entries in the global environment +and, therefore, they are also called <em>global variables</em>. +Moreover, all standard libraries are loaded in the global environment +and some functions there operate on that environment. +You can use <a href="#pdf-load"><code>load</code></a> (or <a href="#pdf-loadfile"><code>loadfile</code></a>) +to load a chunk with a different environment. +(In C, you have to load the chunk and then change the value +of its first upvalue; see <a href="#lua_setupvalue"><code>lua_setupvalue</code></a>.) + + + + + +<h2>2.3 – <a name="2.3">Error Handling</a></h2> + +<p> +Several operations in Lua can <em>raise</em> an error. +An error interrupts the normal flow of the program, +which can continue by <em>catching</em> the error. + + +<p> +Lua code can explicitly raise an error by calling the +<a href="#pdf-error"><code>error</code></a> function. +(This function never returns.) + + +<p> +To catch errors in Lua, +you can do a <em>protected call</em>, +using <a href="#pdf-pcall"><code>pcall</code></a> (or <a href="#pdf-xpcall"><code>xpcall</code></a>). +The function <a href="#pdf-pcall"><code>pcall</code></a> calls a given function in <em>protected mode</em>. +Any error while running the function stops its execution, +and control returns immediately to <code>pcall</code>, +which returns a status code. + + +<p> +Because Lua is an embedded extension language, +Lua code starts running by a call +from C code in the host program. +(When you use Lua standalone, +the <code>lua</code> application is the host program.) +Usually, this call is protected; +so, when an otherwise unprotected error occurs during +the compilation or execution of a Lua chunk, +control returns to the host, +which can take appropriate measures, +such as printing an error message. + + +<p> +Whenever there is an error, +an <em>error object</em> +is propagated with information about the error. +Lua itself only generates errors whose error object is a string, +but programs may generate errors with +any value as the error object. +It is up to the Lua program or its host to handle such error objects. +For historical reasons, +an error object is often called an <em>error message</em>, +even though it does not have to be a string. + + +<p> +When you use <a href="#pdf-xpcall"><code>xpcall</code></a> (or <a href="#lua_pcall"><code>lua_pcall</code></a>, in C) +you may give a <em>message handler</em> +to be called in case of errors. +This function is called with the original error object +and returns a new error object. +It is called before the error unwinds the stack, +so that it can gather more information about the error, +for instance by inspecting the stack and creating a stack traceback. +This message handler is still protected by the protected call; +so, an error inside the message handler +will call the message handler again. +If this loop goes on for too long, +Lua breaks it and returns an appropriate message. +The message handler is called only for regular runtime errors. +It is not called for memory-allocation errors +nor for errors while running finalizers or other message handlers. + + +<p> +Lua also offers a system of <em>warnings</em> (see <a href="#pdf-warn"><code>warn</code></a>). +Unlike errors, warnings do not interfere +in any way with program execution. +They typically only generate a message to the user, +although this behavior can be adapted from C (see <a href="#lua_setwarnf"><code>lua_setwarnf</code></a>). + + + + + +<h2>2.4 – <a name="2.4">Metatables and Metamethods</a></h2> + +<p> +Every value in Lua can have a <em>metatable</em>. +This <em>metatable</em> is an ordinary Lua table +that defines the behavior of the original value +under certain events. +You can change several aspects of the behavior +of a value by setting specific fields in its metatable. +For instance, when a non-numeric value is the operand of an addition, +Lua checks for a function in the field <code>__add</code> of the value's metatable. +If it finds one, +Lua calls this function to perform the addition. + + +<p> +The key for each event in a metatable is a string +with the event name prefixed by two underscores; +the corresponding value is called a <em>metavalue</em>. +For most events, the metavalue must be a function, +which is then called a <em>metamethod</em>. +In the previous example, the key is the string "<code>__add</code>" +and the metamethod is the function that performs the addition. +Unless stated otherwise, +a metamethod may in fact be any callable value, +which is either a function or a value with a <code>__call</code> metamethod. + + +<p> +You can query the metatable of any value +using the <a href="#pdf-getmetatable"><code>getmetatable</code></a> function. +Lua queries metamethods in metatables using a raw access (see <a href="#pdf-rawget"><code>rawget</code></a>). + + +<p> +You can replace the metatable of tables +using the <a href="#pdf-setmetatable"><code>setmetatable</code></a> function. +You cannot change the metatable of other types from Lua code, +except by using the debug library (<a href="#6.10">§6.10</a>). + + +<p> +Tables and full userdata have individual metatables, +although multiple tables and userdata can share their metatables. +Values of all other types share one single metatable per type; +that is, there is one single metatable for all numbers, +one for all strings, etc. +By default, a value has no metatable, +but the string library sets a metatable for the string type (see <a href="#6.4">§6.4</a>). + + +<p> +A detailed list of operations controlled by metatables is given next. +Each event is identified by its corresponding key. +By convention, all metatable keys used by Lua are composed by +two underscores followed by lowercase Latin letters. + + + +<ul> + +<li><b><code>__add</code>: </b> +the addition (<code>+</code>) operation. +If any operand for an addition is not a number, +Lua will try to call a metamethod. +It starts by checking the first operand (even if it is a number); +if that operand does not define a metamethod for <code>__add</code>, +then Lua will check the second operand. +If Lua can find a metamethod, +it calls the metamethod with the two operands as arguments, +and the result of the call +(adjusted to one value) +is the result of the operation. +Otherwise, if no metamethod is found, +Lua raises an error. +</li> + +<li><b><code>__sub</code>: </b> +the subtraction (<code>-</code>) operation. +Behavior similar to the addition operation. +</li> + +<li><b><code>__mul</code>: </b> +the multiplication (<code>*</code>) operation. +Behavior similar to the addition operation. +</li> + +<li><b><code>__div</code>: </b> +the division (<code>/</code>) operation. +Behavior similar to the addition operation. +</li> + +<li><b><code>__mod</code>: </b> +the modulo (<code>%</code>) operation. +Behavior similar to the addition operation. +</li> + +<li><b><code>__pow</code>: </b> +the exponentiation (<code>^</code>) operation. +Behavior similar to the addition operation. +</li> + +<li><b><code>__unm</code>: </b> +the negation (unary <code>-</code>) operation. +Behavior similar to the addition operation. +</li> + +<li><b><code>__idiv</code>: </b> +the floor division (<code>//</code>) operation. +Behavior similar to the addition operation. +</li> + +<li><b><code>__band</code>: </b> +the bitwise AND (<code>&</code>) operation. +Behavior similar to the addition operation, +except that Lua will try a metamethod +if any operand is neither an integer +nor a float coercible to an integer (see <a href="#3.4.3">§3.4.3</a>). +</li> + +<li><b><code>__bor</code>: </b> +the bitwise OR (<code>|</code>) operation. +Behavior similar to the bitwise AND operation. +</li> + +<li><b><code>__bxor</code>: </b> +the bitwise exclusive OR (binary <code>~</code>) operation. +Behavior similar to the bitwise AND operation. +</li> + +<li><b><code>__bnot</code>: </b> +the bitwise NOT (unary <code>~</code>) operation. +Behavior similar to the bitwise AND operation. +</li> + +<li><b><code>__shl</code>: </b> +the bitwise left shift (<code><<</code>) operation. +Behavior similar to the bitwise AND operation. +</li> + +<li><b><code>__shr</code>: </b> +the bitwise right shift (<code>>></code>) operation. +Behavior similar to the bitwise AND operation. +</li> + +<li><b><code>__concat</code>: </b> +the concatenation (<code>..</code>) operation. +Behavior similar to the addition operation, +except that Lua will try a metamethod +if any operand is neither a string nor a number +(which is always coercible to a string). +</li> + +<li><b><code>__len</code>: </b> +the length (<code>#</code>) operation. +If the object is not a string, +Lua will try its metamethod. +If there is a metamethod, +Lua calls it with the object as argument, +and the result of the call +(always adjusted to one value) +is the result of the operation. +If there is no metamethod but the object is a table, +then Lua uses the table length operation (see <a href="#3.4.7">§3.4.7</a>). +Otherwise, Lua raises an error. +</li> + +<li><b><code>__eq</code>: </b> +the equal (<code>==</code>) operation. +Behavior similar to the addition operation, +except that Lua will try a metamethod only when the values +being compared are either both tables or both full userdata +and they are not primitively equal. +The result of the call is always converted to a boolean. +</li> + +<li><b><code>__lt</code>: </b> +the less than (<code><</code>) operation. +Behavior similar to the addition operation, +except that Lua will try a metamethod only when the values +being compared are neither both numbers nor both strings. +Moreover, the result of the call is always converted to a boolean. +</li> + +<li><b><code>__le</code>: </b> +the less equal (<code><=</code>) operation. +Behavior similar to the less than operation. +</li> + +<li><b><code>__index</code>: </b> +The indexing access operation <code>table[key]</code>. +This event happens when <code>table</code> is not a table or +when <code>key</code> is not present in <code>table</code>. +The metavalue is looked up in the metatable of <code>table</code>. + + +<p> +The metavalue for this event can be either a function, a table, +or any value with an <code>__index</code> metavalue. +If it is a function, +it is called with <code>table</code> and <code>key</code> as arguments, +and the result of the call +(adjusted to one value) +is the result of the operation. +Otherwise, +the final result is the result of indexing this metavalue with <code>key</code>. +This indexing is regular, not raw, +and therefore can trigger another <code>__index</code> metavalue. +</li> + +<li><b><code>__newindex</code>: </b> +The indexing assignment <code>table[key] = value</code>. +Like the index event, +this event happens when <code>table</code> is not a table or +when <code>key</code> is not present in <code>table</code>. +The metavalue is looked up in the metatable of <code>table</code>. + + +<p> +Like with indexing, +the metavalue for this event can be either a function, a table, +or any value with an <code>__newindex</code> metavalue. +If it is a function, +it is called with <code>table</code>, <code>key</code>, and <code>value</code> as arguments. +Otherwise, +Lua repeats the indexing assignment over this metavalue +with the same key and value. +This assignment is regular, not raw, +and therefore can trigger another <code>__newindex</code> metavalue. + + +<p> +Whenever a <code>__newindex</code> metavalue is invoked, +Lua does not perform the primitive assignment. +If needed, +the metamethod itself can call <a href="#pdf-rawset"><code>rawset</code></a> +to do the assignment. +</li> + +<li><b><code>__call</code>: </b> +The call operation <code>func(args)</code>. +This event happens when Lua tries to call a non-function value +(that is, <code>func</code> is not a function). +The metamethod is looked up in <code>func</code>. +If present, +the metamethod is called with <code>func</code> as its first argument, +followed by the arguments of the original call (<code>args</code>). +All results of the call +are the results of the operation. +This is the only metamethod that allows multiple results. +</li> + +</ul> + +<p> +In addition to the previous list, +the interpreter also respects the following keys in metatables: +<code>__gc</code> (see <a href="#2.5.3">§2.5.3</a>), +<code>__close</code> (see <a href="#3.3.8">§3.3.8</a>), +<code>__mode</code> (see <a href="#2.5.4">§2.5.4</a>), +and <code>__name</code>. +(The entry <code>__name</code>, +when it contains a string, +may be used by <a href="#pdf-tostring"><code>tostring</code></a> and in error messages.) + + +<p> +For the unary operators (negation, length, and bitwise NOT), +the metamethod is computed and called with a dummy second operand, +equal to the first one. +This extra operand is only to simplify Lua's internals +(by making these operators behave like a binary operation) +and may be removed in future versions. +For most uses this extra operand is irrelevant. + + +<p> +Because metatables are regular tables, +they can contain arbitrary fields, +not only the event names defined above. +Some functions in the standard library +(e.g., <a href="#pdf-tostring"><code>tostring</code></a>) +use other fields in metatables for their own purposes. + + +<p> +It is a good practice to add all needed metamethods to a table +before setting it as a metatable of some object. +In particular, the <code>__gc</code> metamethod works only when this order +is followed (see <a href="#2.5.3">§2.5.3</a>). +It is also a good practice to set the metatable of an object +right after its creation. + + + + + +<h2>2.5 – <a name="2.5">Garbage Collection</a></h2> + + + +<p> +Lua performs automatic memory management. +This means that +you do not have to worry about allocating memory for new objects +or freeing it when the objects are no longer needed. +Lua manages memory automatically by running +a <em>garbage collector</em> to collect all <em>dead</em> objects. +All memory used by Lua is subject to automatic management: +strings, tables, userdata, functions, threads, internal structures, etc. + + +<p> +An object is considered <em>dead</em> +as soon as the collector can be sure the object +will not be accessed again in the normal execution of the program. +("Normal execution" here excludes finalizers, +which can resurrect dead objects (see <a href="#2.5.3">§2.5.3</a>), +and excludes also operations using the debug library.) +Note that the time when the collector can be sure that an object +is dead may not coincide with the programmer's expectations. +The only guarantees are that Lua will not collect an object +that may still be accessed in the normal execution of the program, +and it will eventually collect an object +that is inaccessible from Lua. +(Here, +<em>inaccessible from Lua</em> means that neither a variable nor +another live object refer to the object.) +Because Lua has no knowledge about C code, +it never collects objects accessible through the registry (see <a href="#4.3">§4.3</a>), +which includes the global environment (see <a href="#2.2">§2.2</a>). + + +<p> +The garbage collector (GC) in Lua can work in two modes: +incremental and generational. + + +<p> +The default GC mode with the default parameters +are adequate for most uses. +However, programs that waste a large proportion of their time +allocating and freeing memory can benefit from other settings. +Keep in mind that the GC behavior is non-portable +both across platforms and across different Lua releases; +therefore, optimal settings are also non-portable. + + +<p> +You can change the GC mode and parameters by calling +<a href="#lua_gc"><code>lua_gc</code></a> in C +or <a href="#pdf-collectgarbage"><code>collectgarbage</code></a> in Lua. +You can also use these functions to control +the collector directly (e.g., to stop and restart it). + + + + + +<h3>2.5.1 – <a name="2.5.1">Incremental Garbage Collection</a></h3> + +<p> +In incremental mode, +each GC cycle performs a mark-and-sweep collection in small steps +interleaved with the program's execution. +In this mode, +the collector uses three numbers to control its garbage-collection cycles: +the <em>garbage-collector pause</em>, +the <em>garbage-collector step multiplier</em>, +and the <em>garbage-collector step size</em>. + + +<p> +The garbage-collector pause +controls how long the collector waits before starting a new cycle. +The collector starts a new cycle when the use of memory +hits <em>n%</em> of the use after the previous collection. +Larger values make the collector less aggressive. +Values equal to or less than 100 mean the collector will not wait to +start a new cycle. +A value of 200 means that the collector waits for the total memory in use +to double before starting a new cycle. +The default value is 200; the maximum value is 1000. + + +<p> +The garbage-collector step multiplier +controls the speed of the collector relative to +memory allocation, +that is, +how many elements it marks or sweeps for each +kilobyte of memory allocated. +Larger values make the collector more aggressive but also increase +the size of each incremental step. +You should not use values less than 100, +because they make the collector too slow and +can result in the collector never finishing a cycle. +The default value is 100; the maximum value is 1000. + + +<p> +The garbage-collector step size controls the +size of each incremental step, +specifically how many bytes the interpreter allocates +before performing a step. +This parameter is logarithmic: +A value of <em>n</em> means the interpreter will allocate <em>2<sup>n</sup></em> +bytes between steps and perform equivalent work during the step. +A large value (e.g., 60) makes the collector a stop-the-world +(non-incremental) collector. +The default value is 13, +which means steps of approximately 8 Kbytes. + + + + + +<h3>2.5.2 – <a name="2.5.2">Generational Garbage Collection</a></h3> + +<p> +In generational mode, +the collector does frequent <em>minor</em> collections, +which traverses only objects recently created. +If after a minor collection the use of memory is still above a limit, +the collector does a stop-the-world <em>major</em> collection, +which traverses all objects. +The generational mode uses two parameters: +the <em>minor multiplier</em> and the <em>the major multiplier</em>. + + +<p> +The minor multiplier controls the frequency of minor collections. +For a minor multiplier <em>x</em>, +a new minor collection will be done when memory +grows <em>x%</em> larger than the memory in use after the previous major +collection. +For instance, for a multiplier of 20, +the collector will do a minor collection when the use of memory +gets 20% larger than the use after the previous major collection. +The default value is 20; the maximum value is 200. + + +<p> +The major multiplier controls the frequency of major collections. +For a major multiplier <em>x</em>, +a new major collection will be done when memory +grows <em>x%</em> larger than the memory in use after the previous major +collection. +For instance, for a multiplier of 100, +the collector will do a major collection when the use of memory +gets larger than twice the use after the previous collection. +The default value is 100; the maximum value is 1000. + + + + + +<h3>2.5.3 – <a name="2.5.3">Garbage-Collection Metamethods</a></h3> + +<p> +You can set garbage-collector metamethods for tables +and, using the C API, +for full userdata (see <a href="#2.4">§2.4</a>). +These metamethods, called <em>finalizers</em>, +are called when the garbage collector detects that the +corresponding table or userdata is dead. +Finalizers allow you to coordinate Lua's garbage collection +with external resource management such as closing files, +network or database connections, +or freeing your own memory. + + +<p> +For an object (table or userdata) to be finalized when collected, +you must <em>mark</em> it for finalization. + +You mark an object for finalization when you set its metatable +and the metatable has a <code>__gc</code> metamethod. +Note that if you set a metatable without a <code>__gc</code> field +and later create that field in the metatable, +the object will not be marked for finalization. + + +<p> +When a marked object becomes dead, +it is not collected immediately by the garbage collector. +Instead, Lua puts it in a list. +After the collection, +Lua goes through that list. +For each object in the list, +it checks the object's <code>__gc</code> metamethod: +If it is present, +Lua calls it with the object as its single argument. + + +<p> +At the end of each garbage-collection cycle, +the finalizers are called in +the reverse order that the objects were marked for finalization, +among those collected in that cycle; +that is, the first finalizer to be called is the one associated +with the object marked last in the program. +The execution of each finalizer may occur at any point during +the execution of the regular code. + + +<p> +Because the object being collected must still be used by the finalizer, +that object (and other objects accessible only through it) +must be <em>resurrected</em> by Lua. +Usually, this resurrection is transient, +and the object memory is freed in the next garbage-collection cycle. +However, if the finalizer stores the object in some global place +(e.g., a global variable), +then the resurrection is permanent. +Moreover, if the finalizer marks a finalizing object for finalization again, +its finalizer will be called again in the next cycle where the +object is dead. +In any case, +the object memory is freed only in a GC cycle where +the object is dead and not marked for finalization. + + +<p> +When you close a state (see <a href="#lua_close"><code>lua_close</code></a>), +Lua calls the finalizers of all objects marked for finalization, +following the reverse order that they were marked. +If any finalizer marks objects for collection during that phase, +these marks have no effect. + + +<p> +Finalizers cannot yield nor run the garbage collector. +Because they can run in unpredictable times, +it is good practice to restrict each finalizer +to the minimum necessary to properly release +its associated resource. + + +<p> +Any error while running a finalizer generates a warning; +the error is not propagated. + + + + + +<h3>2.5.4 – <a name="2.5.4">Weak Tables</a></h3> + +<p> +A <em>weak table</em> is a table whose elements are +<em>weak references</em>. +A weak reference is ignored by the garbage collector. +In other words, +if the only references to an object are weak references, +then the garbage collector will collect that object. + + +<p> +A weak table can have weak keys, weak values, or both. +A table with weak values allows the collection of its values, +but prevents the collection of its keys. +A table with both weak keys and weak values allows the collection of +both keys and values. +In any case, if either the key or the value is collected, +the whole pair is removed from the table. +The weakness of a table is controlled by the +<code>__mode</code> field of its metatable. +This metavalue, if present, must be one of the following strings: +"<code>k</code>", for a table with weak keys; +"<code>v</code>", for a table with weak values; +or "<code>kv</code>", for a table with both weak keys and values. + + +<p> +A table with weak keys and strong values +is also called an <em>ephemeron table</em>. +In an ephemeron table, +a value is considered reachable only if its key is reachable. +In particular, +if the only reference to a key comes through its value, +the pair is removed. + + +<p> +Any change in the weakness of a table may take effect only +at the next collect cycle. +In particular, if you change the weakness to a stronger mode, +Lua may still collect some items from that table +before the change takes effect. + + +<p> +Only objects that have an explicit construction +are removed from weak tables. +Values, such as numbers and light C functions, +are not subject to garbage collection, +and therefore are not removed from weak tables +(unless their associated values are collected). +Although strings are subject to garbage collection, +they do not have an explicit construction and +their equality is by value; +they behave more like values than like objects. +Therefore, they are not removed from weak tables. + + +<p> +Resurrected objects +(that is, objects being finalized +and objects accessible only through objects being finalized) +have a special behavior in weak tables. +They are removed from weak values before running their finalizers, +but are removed from weak keys only in the next collection +after running their finalizers, when such objects are actually freed. +This behavior allows the finalizer to access properties +associated with the object through weak tables. + + +<p> +If a weak table is among the resurrected objects in a collection cycle, +it may not be properly cleared until the next cycle. + + + + + + + +<h2>2.6 – <a name="2.6">Coroutines</a></h2> + +<p> +Lua supports coroutines, +also called <em>collaborative multithreading</em>. +A coroutine in Lua represents an independent thread of execution. +Unlike threads in multithread systems, however, +a coroutine only suspends its execution by explicitly calling +a yield function. + + +<p> +You create a coroutine by calling <a href="#pdf-coroutine.create"><code>coroutine.create</code></a>. +Its sole argument is a function +that is the main function of the coroutine. +The <code>create</code> function only creates a new coroutine and +returns a handle to it (an object of type <em>thread</em>); +it does not start the coroutine. + + +<p> +You execute a coroutine by calling <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>. +When you first call <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>, +passing as its first argument +a thread returned by <a href="#pdf-coroutine.create"><code>coroutine.create</code></a>, +the coroutine starts its execution by +calling its main function. +Extra arguments passed to <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> are passed +as arguments to that function. +After the coroutine starts running, +it runs until it terminates or <em>yields</em>. + + +<p> +A coroutine can terminate its execution in two ways: +normally, when its main function returns +(explicitly or implicitly, after the last instruction); +and abnormally, if there is an unprotected error. +In case of normal termination, +<a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> returns <b>true</b>, +plus any values returned by the coroutine main function. +In case of errors, <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> returns <b>false</b> +plus the error object. +In this case, the coroutine does not unwind its stack, +so that it is possible to inspect it after the error +with the debug API. + + +<p> +A coroutine yields by calling <a href="#pdf-coroutine.yield"><code>coroutine.yield</code></a>. +When a coroutine yields, +the corresponding <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> returns immediately, +even if the yield happens inside nested function calls +(that is, not in the main function, +but in a function directly or indirectly called by the main function). +In the case of a yield, <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> also returns <b>true</b>, +plus any values passed to <a href="#pdf-coroutine.yield"><code>coroutine.yield</code></a>. +The next time you resume the same coroutine, +it continues its execution from the point where it yielded, +with the call to <a href="#pdf-coroutine.yield"><code>coroutine.yield</code></a> returning any extra +arguments passed to <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>. + + +<p> +Like <a href="#pdf-coroutine.create"><code>coroutine.create</code></a>, +the <a href="#pdf-coroutine.wrap"><code>coroutine.wrap</code></a> function also creates a coroutine, +but instead of returning the coroutine itself, +it returns a function that, when called, resumes the coroutine. +Any arguments passed to this function +go as extra arguments to <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>. +<a href="#pdf-coroutine.wrap"><code>coroutine.wrap</code></a> returns all the values returned by <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>, +except the first one (the boolean error code). +Unlike <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a>, +the function created by <a href="#pdf-coroutine.wrap"><code>coroutine.wrap</code></a> +propagates any error to the caller. +In this case, +the function also closes the coroutine (see <a href="#pdf-coroutine.close"><code>coroutine.close</code></a>). + + +<p> +As an example of how coroutines work, +consider the following code: + +<pre> + function foo (a) + print("foo", a) + return coroutine.yield(2*a) + end + + co = coroutine.create(function (a,b) + print("co-body", a, b) + local r = foo(a+1) + print("co-body", r) + local r, s = coroutine.yield(a+b, a-b) + print("co-body", r, s) + return b, "end" + end) + + print("main", coroutine.resume(co, 1, 10)) + print("main", coroutine.resume(co, "r")) + print("main", coroutine.resume(co, "x", "y")) + print("main", coroutine.resume(co, "x", "y")) +</pre><p> +When you run it, it produces the following output: + +<pre> + co-body 1 10 + foo 2 + main true 4 + co-body r + main true 11 -9 + co-body x y + main true 10 end + main false cannot resume dead coroutine +</pre> + +<p> +You can also create and manipulate coroutines through the C API: +see functions <a href="#lua_newthread"><code>lua_newthread</code></a>, <a href="#lua_resume"><code>lua_resume</code></a>, +and <a href="#lua_yield"><code>lua_yield</code></a>. + + + + + +<h1>3 – <a name="3">The Language</a></h1> + + + +<p> +This section describes the lexis, the syntax, and the semantics of Lua. +In other words, +this section describes +which tokens are valid, +how they can be combined, +and what their combinations mean. + + +<p> +Language constructs will be explained using the usual extended BNF notation, +in which +{<em>a</em>} means 0 or more <em>a</em>'s, and +[<em>a</em>] means an optional <em>a</em>. +Non-terminals are shown like non-terminal, +keywords are shown like <b>kword</b>, +and other terminal symbols are shown like ‘<b>=</b>’. +The complete syntax of Lua can be found in <a href="#9">§9</a> +at the end of this manual. + + + + + +<h2>3.1 – <a name="3.1">Lexical Conventions</a></h2> + +<p> +Lua is a free-form language. +It ignores spaces and comments between lexical elements (tokens), +except as delimiters between two tokens. +In source code, +Lua recognizes as spaces the standard ASCII whitespace +characters space, form feed, newline, +carriage return, horizontal tab, and vertical tab. + + +<p> +<em>Names</em> +(also called <em>identifiers</em>) +in Lua can be any string of Latin letters, +Arabic-Indic digits, and underscores, +not beginning with a digit and +not being a reserved word. +Identifiers are used to name variables, table fields, and labels. + + +<p> +The following <em>keywords</em> are reserved +and cannot be used as names: + + +<pre> + and break do else elseif end + false for function goto if in + local nil not or repeat return + then true until while +</pre> + +<p> +Lua is a case-sensitive language: +<code>and</code> is a reserved word, but <code>And</code> and <code>AND</code> +are two different, valid names. +As a convention, +programs should avoid creating +names that start with an underscore followed by +one or more uppercase letters (such as <a href="#pdf-_VERSION"><code>_VERSION</code></a>). + + +<p> +The following strings denote other tokens: + +<pre> + + - * / % ^ # + & ~ | << >> // + == ~= <= >= < > = + ( ) { } [ ] :: + ; : , . .. ... +</pre> + +<p> +A <em>short literal string</em> +can be delimited by matching single or double quotes, +and can contain the following C-like escape sequences: +'<code>\a</code>' (bell), +'<code>\b</code>' (backspace), +'<code>\f</code>' (form feed), +'<code>\n</code>' (newline), +'<code>\r</code>' (carriage return), +'<code>\t</code>' (horizontal tab), +'<code>\v</code>' (vertical tab), +'<code>\\</code>' (backslash), +'<code>\"</code>' (quotation mark [double quote]), +and '<code>\'</code>' (apostrophe [single quote]). +A backslash followed by a line break +results in a newline in the string. +The escape sequence '<code>\z</code>' skips the following span +of whitespace characters, +including line breaks; +it is particularly useful to break and indent a long literal string +into multiple lines without adding the newlines and spaces +into the string contents. +A short literal string cannot contain unescaped line breaks +nor escapes not forming a valid escape sequence. + + +<p> +We can specify any byte in a short literal string, +including embedded zeros, +by its numeric value. +This can be done +with the escape sequence <code>\x<em>XX</em></code>, +where <em>XX</em> is a sequence of exactly two hexadecimal digits, +or with the escape sequence <code>\<em>ddd</em></code>, +where <em>ddd</em> is a sequence of up to three decimal digits. +(Note that if a decimal escape sequence is to be followed by a digit, +it must be expressed using exactly three digits.) + + +<p> +The UTF-8 encoding of a Unicode character +can be inserted in a literal string with +the escape sequence <code>\u{<em>XXX</em>}</code> +(with mandatory enclosing braces), +where <em>XXX</em> is a sequence of one or more hexadecimal digits +representing the character code point. +This code point can be any value less than <em>2<sup>31</sup></em>. +(Lua uses the original UTF-8 specification here, +which is not restricted to valid Unicode code points.) + + +<p> +Literal strings can also be defined using a long format +enclosed by <em>long brackets</em>. +We define an <em>opening long bracket of level <em>n</em></em> as an opening +square bracket followed by <em>n</em> equal signs followed by another +opening square bracket. +So, an opening long bracket of level 0 is written as <code>[[</code>, +an opening long bracket of level 1 is written as <code>[=[</code>, +and so on. +A <em>closing long bracket</em> is defined similarly; +for instance, +a closing long bracket of level 4 is written as <code>]====]</code>. +A <em>long literal</em> starts with an opening long bracket of any level and +ends at the first closing long bracket of the same level. +It can contain any text except a closing bracket of the same level. +Literals in this bracketed form can run for several lines, +do not interpret any escape sequences, +and ignore long brackets of any other level. +Any kind of end-of-line sequence +(carriage return, newline, carriage return followed by newline, +or newline followed by carriage return) +is converted to a simple newline. +When the opening long bracket is immediately followed by a newline, +the newline is not included in the string. + + +<p> +As an example, in a system using ASCII +(in which '<code>a</code>' is coded as 97, +newline is coded as 10, and '<code>1</code>' is coded as 49), +the five literal strings below denote the same string: + +<pre> + a = 'alo\n123"' + a = "alo\n123\"" + a = '\97lo\10\04923"' + a = [[alo + 123"]] + a = [==[ + alo + 123"]==] +</pre> + +<p> +Any byte in a literal string not +explicitly affected by the previous rules represents itself. +However, Lua opens files for parsing in text mode, +and the system's file functions may have problems with +some control characters. +So, it is safer to represent +binary data as a quoted literal with +explicit escape sequences for the non-text characters. + + +<p> +A <em>numeric constant</em> (or <em>numeral</em>) +can be written with an optional fractional part +and an optional decimal exponent, +marked by a letter '<code>e</code>' or '<code>E</code>'. +Lua also accepts hexadecimal constants, +which start with <code>0x</code> or <code>0X</code>. +Hexadecimal constants also accept an optional fractional part +plus an optional binary exponent, +marked by a letter '<code>p</code>' or '<code>P</code>' and written in decimal. +(For instance, <code>0x1.fp10</code> denotes 1984, +which is <em>0x1f / 16</em> multiplied by <em>2<sup>10</sup></em>.) + + +<p> +A numeric constant with a radix point or an exponent +denotes a float; +otherwise, +if its value fits in an integer or it is a hexadecimal constant, +it denotes an integer; +otherwise (that is, a decimal integer numeral that overflows), +it denotes a float. +Hexadecimal numerals with neither a radix point nor an exponent +always denote an integer value; +if the value overflows, it <em>wraps around</em> +to fit into a valid integer. + + +<p> +Examples of valid integer constants are + +<pre> + 3 345 0xff 0xBEBADA +</pre><p> +Examples of valid float constants are + +<pre> + 3.0 3.1416 314.16e-2 0.31416E1 34e1 + 0x0.1E 0xA23p-4 0X1.921FB54442D18P+1 +</pre> + +<p> +A <em>comment</em> starts with a double hyphen (<code>--</code>) +anywhere outside a string. +If the text immediately after <code>--</code> is not an opening long bracket, +the comment is a <em>short comment</em>, +which runs until the end of the line. +Otherwise, it is a <em>long comment</em>, +which runs until the corresponding closing long bracket. + + + + + +<h2>3.2 – <a name="3.2">Variables</a></h2> + +<p> +Variables are places that store values. +There are three kinds of variables in Lua: +global variables, local variables, and table fields. + + +<p> +A single name can denote a global variable or a local variable +(or a function's formal parameter, +which is a particular kind of local variable): + +<pre> + var ::= Name +</pre><p> +Name denotes identifiers (see <a href="#3.1">§3.1</a>). + + +<p> +Any variable name is assumed to be global unless explicitly declared +as a local (see <a href="#3.3.7">§3.3.7</a>). +Local variables are <em>lexically scoped</em>: +local variables can be freely accessed by functions +defined inside their scope (see <a href="#3.5">§3.5</a>). + + +<p> +Before the first assignment to a variable, its value is <b>nil</b>. + + +<p> +Square brackets are used to index a table: + +<pre> + var ::= prefixexp ‘<b>[</b>’ exp ‘<b>]</b>’ +</pre><p> +The meaning of accesses to table fields can be changed via metatables +(see <a href="#2.4">§2.4</a>). + + +<p> +The syntax <code>var.Name</code> is just syntactic sugar for +<code>var["Name"]</code>: + +<pre> + var ::= prefixexp ‘<b>.</b>’ Name +</pre> + +<p> +An access to a global variable <code>x</code> +is equivalent to <code>_ENV.x</code>. +Due to the way that chunks are compiled, +the variable <code>_ENV</code> itself is never global (see <a href="#2.2">§2.2</a>). + + + + + +<h2>3.3 – <a name="3.3">Statements</a></h2> + + + +<p> +Lua supports an almost conventional set of statements, +similar to those in other conventional languages. +This set includes +blocks, assignments, control structures, function calls, +and variable declarations. + + + + + +<h3>3.3.1 – <a name="3.3.1">Blocks</a></h3> + +<p> +A block is a list of statements, +which are executed sequentially: + +<pre> + block ::= {stat} +</pre><p> +Lua has <em>empty statements</em> +that allow you to separate statements with semicolons, +start a block with a semicolon +or write two semicolons in sequence: + +<pre> + stat ::= ‘<b>;</b>’ +</pre> + +<p> +Both function calls and assignments +can start with an open parenthesis. +This possibility leads to an ambiguity in Lua's grammar. +Consider the following fragment: + +<pre> + a = b + c + (print or io.write)('done') +</pre><p> +The grammar could see this fragment in two ways: + +<pre> + a = b + c(print or io.write)('done') + + a = b + c; (print or io.write)('done') +</pre><p> +The current parser always sees such constructions +in the first way, +interpreting the open parenthesis +as the start of the arguments to a call. +To avoid this ambiguity, +it is a good practice to always precede with a semicolon +statements that start with a parenthesis: + +<pre> + ;(print or io.write)('done') +</pre> + +<p> +A block can be explicitly delimited to produce a single statement: + +<pre> + stat ::= <b>do</b> block <b>end</b> +</pre><p> +Explicit blocks are useful +to control the scope of variable declarations. +Explicit blocks are also sometimes used to +add a <b>return</b> statement in the middle +of another block (see <a href="#3.3.4">§3.3.4</a>). + + + + + +<h3>3.3.2 – <a name="3.3.2">Chunks</a></h3> + +<p> +The unit of compilation of Lua is called a <em>chunk</em>. +Syntactically, +a chunk is simply a block: + +<pre> + chunk ::= block +</pre> + +<p> +Lua handles a chunk as the body of an anonymous function +with a variable number of arguments +(see <a href="#3.4.11">§3.4.11</a>). +As such, chunks can define local variables, +receive arguments, and return values. +Moreover, such anonymous function is compiled as in the +scope of an external local variable called <code>_ENV</code> (see <a href="#2.2">§2.2</a>). +The resulting function always has <code>_ENV</code> as its only external variable, +even if it does not use that variable. + + +<p> +A chunk can be stored in a file or in a string inside the host program. +To execute a chunk, +Lua first <em>loads</em> it, +precompiling the chunk's code into instructions for a virtual machine, +and then Lua executes the compiled code +with an interpreter for the virtual machine. + + +<p> +Chunks can also be precompiled into binary form; +see the program <code>luac</code> and the function <a href="#pdf-string.dump"><code>string.dump</code></a> for details. +Programs in source and compiled forms are interchangeable; +Lua automatically detects the file type and acts accordingly (see <a href="#pdf-load"><code>load</code></a>). + + + + + +<h3>3.3.3 – <a name="3.3.3">Assignment</a></h3> + +<p> +Lua allows multiple assignments. +Therefore, the syntax for assignment +defines a list of variables on the left side +and a list of expressions on the right side. +The elements in both lists are separated by commas: + +<pre> + stat ::= varlist ‘<b>=</b>’ explist + varlist ::= var {‘<b>,</b>’ var} + explist ::= exp {‘<b>,</b>’ exp} +</pre><p> +Expressions are discussed in <a href="#3.4">§3.4</a>. + + +<p> +Before the assignment, +the list of values is <em>adjusted</em> to the length of +the list of variables (see <a href="#3.4.12">§3.4.12</a>). + + +<p> +If a variable is both assigned and read +inside a multiple assignment, +Lua ensures that all reads get the value of the variable +before the assignment. +Thus the code + +<pre> + i = 3 + i, a[i] = i+1, 20 +</pre><p> +sets <code>a[3]</code> to 20, without affecting <code>a[4]</code> +because the <code>i</code> in <code>a[i]</code> is evaluated (to 3) +before it is assigned 4. +Similarly, the line + +<pre> + x, y = y, x +</pre><p> +exchanges the values of <code>x</code> and <code>y</code>, +and + +<pre> + x, y, z = y, z, x +</pre><p> +cyclically permutes the values of <code>x</code>, <code>y</code>, and <code>z</code>. + + +<p> +Note that this guarantee covers only accesses +syntactically inside the assignment statement. +If a function or a metamethod called during the assignment +changes the value of a variable, +Lua gives no guarantees about the order of that access. + + +<p> +An assignment to a global name <code>x = val</code> +is equivalent to the assignment +<code>_ENV.x = val</code> (see <a href="#2.2">§2.2</a>). + + +<p> +The meaning of assignments to table fields and +global variables (which are actually table fields, too) +can be changed via metatables (see <a href="#2.4">§2.4</a>). + + + + + +<h3>3.3.4 – <a name="3.3.4">Control Structures</a></h3><p> +The control structures +<b>if</b>, <b>while</b>, and <b>repeat</b> have the usual meaning and +familiar syntax: + + + + +<pre> + stat ::= <b>while</b> exp <b>do</b> block <b>end</b> + stat ::= <b>repeat</b> block <b>until</b> exp + stat ::= <b>if</b> exp <b>then</b> block {<b>elseif</b> exp <b>then</b> block} [<b>else</b> block] <b>end</b> +</pre><p> +Lua also has a <b>for</b> statement, in two flavors (see <a href="#3.3.5">§3.3.5</a>). + + +<p> +The condition expression of a +control structure can return any value. +Both <b>false</b> and <b>nil</b> test false. +All values different from <b>nil</b> and <b>false</b> test true. +In particular, the number 0 and the empty string also test true. + + +<p> +In the <b>repeat</b>–<b>until</b> loop, +the inner block does not end at the <b>until</b> keyword, +but only after the condition. +So, the condition can refer to local variables +declared inside the loop block. + + +<p> +The <b>goto</b> statement transfers the program control to a label. +For syntactical reasons, +labels in Lua are considered statements too: + + + +<pre> + stat ::= <b>goto</b> Name + stat ::= label + label ::= ‘<b>::</b>’ Name ‘<b>::</b>’ +</pre> + +<p> +A label is visible in the entire block where it is defined, +except inside nested functions. +A goto may jump to any visible label as long as it does not +enter into the scope of a local variable. +A label should not be declared +where a label with the same name is visible, +even if this other label has been declared in an enclosing block. + + +<p> +The <b>break</b> statement terminates the execution of a +<b>while</b>, <b>repeat</b>, or <b>for</b> loop, +skipping to the next statement after the loop: + + +<pre> + stat ::= <b>break</b> +</pre><p> +A <b>break</b> ends the innermost enclosing loop. + + +<p> +The <b>return</b> statement is used to return values +from a function or a chunk +(which is handled as an anonymous function). + +Functions can return more than one value, +so the syntax for the <b>return</b> statement is + +<pre> + stat ::= <b>return</b> [explist] [‘<b>;</b>’] +</pre> + +<p> +The <b>return</b> statement can only be written +as the last statement of a block. +If it is necessary to <b>return</b> in the middle of a block, +then an explicit inner block can be used, +as in the idiom <code>do return end</code>, +because now <b>return</b> is the last statement in its (inner) block. + + + + + +<h3>3.3.5 – <a name="3.3.5">For Statement</a></h3> + +<p> + +The <b>for</b> statement has two forms: +one numerical and one generic. + + + +<h4>The numerical <b>for</b> loop</h4> + +<p> +The numerical <b>for</b> loop repeats a block of code while a +control variable goes through an arithmetic progression. +It has the following syntax: + +<pre> + stat ::= <b>for</b> Name ‘<b>=</b>’ exp ‘<b>,</b>’ exp [‘<b>,</b>’ exp] <b>do</b> block <b>end</b> +</pre><p> +The given identifier (Name) defines the control variable, +which is a new variable local to the loop body (<em>block</em>). + + +<p> +The loop starts by evaluating once the three control expressions. +Their values are called respectively +the <em>initial value</em>, the <em>limit</em>, and the <em>step</em>. +If the step is absent, it defaults to 1. + + +<p> +If both the initial value and the step are integers, +the loop is done with integers; +note that the limit may not be an integer. +Otherwise, the three values are converted to +floats and the loop is done with floats. +Beware of floating-point accuracy in this case. + + +<p> +After that initialization, +the loop body is repeated with the value of the control variable +going through an arithmetic progression, +starting at the initial value, +with a common difference given by the step. +A negative step makes a decreasing sequence; +a step equal to zero raises an error. +The loop continues while the value is less than +or equal to the limit +(greater than or equal to for a negative step). +If the initial value is already greater than the limit +(or less than, if the step is negative), +the body is not executed. + + +<p> +For integer loops, +the control variable never wraps around; +instead, the loop ends in case of an overflow. + + +<p> +You should not change the value of the control variable +during the loop. +If you need its value after the loop, +assign it to another variable before exiting the loop. + + + + + +<h4>The generic <b>for</b> loop</h4> + +<p> +The generic <b>for</b> statement works over functions, +called <em>iterators</em>. +On each iteration, the iterator function is called to produce a new value, +stopping when this new value is <b>nil</b>. +The generic <b>for</b> loop has the following syntax: + +<pre> + stat ::= <b>for</b> namelist <b>in</b> explist <b>do</b> block <b>end</b> + namelist ::= Name {‘<b>,</b>’ Name} +</pre><p> +A <b>for</b> statement like + +<pre> + for <em>var_1</em>, ···, <em>var_n</em> in <em>explist</em> do <em>body</em> end +</pre><p> +works as follows. + + +<p> +The names <em>var_i</em> declare loop variables local to the loop body. +The first of these variables is the <em>control variable</em>. + + +<p> +The loop starts by evaluating <em>explist</em> +to produce four values: +an <em>iterator function</em>, +a <em>state</em>, +an initial value for the control variable, +and a <em>closing value</em>. + + +<p> +Then, at each iteration, +Lua calls the iterator function with two arguments: +the state and the control variable. +The results from this call are then assigned to the loop variables, +following the rules of multiple assignments (see <a href="#3.3.3">§3.3.3</a>). +If the control variable becomes <b>nil</b>, +the loop terminates. +Otherwise, the body is executed and the loop goes +to the next iteration. + + +<p> +The closing value behaves like a +to-be-closed variable (see <a href="#3.3.8">§3.3.8</a>), +which can be used to release resources when the loop ends. +Otherwise, it does not interfere with the loop. + + +<p> +You should not change the value of the control variable +during the loop. + + + + + + + +<h3>3.3.6 – <a name="3.3.6">Function Calls as Statements</a></h3><p> +To allow possible side-effects, +function calls can be executed as statements: + +<pre> + stat ::= functioncall +</pre><p> +In this case, all returned values are thrown away. +Function calls are explained in <a href="#3.4.10">§3.4.10</a>. + + + + + +<h3>3.3.7 – <a name="3.3.7">Local Declarations</a></h3><p> +Local variables can be declared anywhere inside a block. +The declaration can include an initialization: + +<pre> + stat ::= <b>local</b> attnamelist [‘<b>=</b>’ explist] + attnamelist ::= Name attrib {‘<b>,</b>’ Name attrib} +</pre><p> +If present, an initial assignment has the same semantics +of a multiple assignment (see <a href="#3.3.3">§3.3.3</a>). +Otherwise, all variables are initialized with <b>nil</b>. + + +<p> +Each variable name may be postfixed by an attribute +(a name between angle brackets): + +<pre> + attrib ::= [‘<b><</b>’ Name ‘<b>></b>’] +</pre><p> +There are two possible attributes: +<code>const</code>, which declares a constant variable, +that is, a variable that cannot be assigned to +after its initialization; +and <code>close</code>, which declares a to-be-closed variable (see <a href="#3.3.8">§3.3.8</a>). +A list of variables can contain at most one to-be-closed variable. + + +<p> +A chunk is also a block (see <a href="#3.3.2">§3.3.2</a>), +and so local variables can be declared in a chunk outside any explicit block. + + +<p> +The visibility rules for local variables are explained in <a href="#3.5">§3.5</a>. + + + + + +<h3>3.3.8 – <a name="3.3.8">To-be-closed Variables</a></h3> + +<p> +A to-be-closed variable behaves like a constant local variable, +except that its value is <em>closed</em> whenever the variable +goes out of scope, including normal block termination, +exiting its block by <b>break</b>/<b>goto</b>/<b>return</b>, +or exiting by an error. + + +<p> +Here, to <em>close</em> a value means +to call its <code>__close</code> metamethod. +When calling the metamethod, +the value itself is passed as the first argument +and the error object that caused the exit (if any) +is passed as a second argument; +if there was no error, the second argument is <b>nil</b>. + + +<p> +The value assigned to a to-be-closed variable +must have a <code>__close</code> metamethod +or be a false value. +(<b>nil</b> and <b>false</b> are ignored as to-be-closed values.) + + +<p> +If several to-be-closed variables go out of scope at the same event, +they are closed in the reverse order that they were declared. + + +<p> +If there is any error while running a closing method, +that error is handled like an error in the regular code +where the variable was defined. +After an error, +the other pending closing methods will still be called. + + +<p> +If a coroutine yields and is never resumed again, +some variables may never go out of scope, +and therefore they will never be closed. +(These variables are the ones created inside the coroutine +and in scope at the point where the coroutine yielded.) +Similarly, if a coroutine ends with an error, +it does not unwind its stack, +so it does not close any variable. +In both cases, +you can either use finalizers +or call <a href="#pdf-coroutine.close"><code>coroutine.close</code></a> to close the variables. +However, if the coroutine was created +through <a href="#pdf-coroutine.wrap"><code>coroutine.wrap</code></a>, +then its corresponding function will close the coroutine +in case of errors. + + + + + + + +<h2>3.4 – <a name="3.4">Expressions</a></h2> + + + +<p> +The basic expressions in Lua are the following: + +<pre> + exp ::= prefixexp + exp ::= <b>nil</b> | <b>false</b> | <b>true</b> + exp ::= Numeral + exp ::= LiteralString + exp ::= functiondef + exp ::= tableconstructor + exp ::= ‘<b>...</b>’ + exp ::= exp binop exp + exp ::= unop exp + prefixexp ::= var | functioncall | ‘<b>(</b>’ exp ‘<b>)</b>’ +</pre> + +<p> +Numerals and literal strings are explained in <a href="#3.1">§3.1</a>; +variables are explained in <a href="#3.2">§3.2</a>; +function definitions are explained in <a href="#3.4.11">§3.4.11</a>; +function calls are explained in <a href="#3.4.10">§3.4.10</a>; +table constructors are explained in <a href="#3.4.9">§3.4.9</a>. +Vararg expressions, +denoted by three dots ('<code>...</code>'), can only be used when +directly inside a variadic function; +they are explained in <a href="#3.4.11">§3.4.11</a>. + + +<p> +Binary operators comprise arithmetic operators (see <a href="#3.4.1">§3.4.1</a>), +bitwise operators (see <a href="#3.4.2">§3.4.2</a>), +relational operators (see <a href="#3.4.4">§3.4.4</a>), logical operators (see <a href="#3.4.5">§3.4.5</a>), +and the concatenation operator (see <a href="#3.4.6">§3.4.6</a>). +Unary operators comprise the unary minus (see <a href="#3.4.1">§3.4.1</a>), +the unary bitwise NOT (see <a href="#3.4.2">§3.4.2</a>), +the unary logical <b>not</b> (see <a href="#3.4.5">§3.4.5</a>), +and the unary <em>length operator</em> (see <a href="#3.4.7">§3.4.7</a>). + + + + + +<h3>3.4.1 – <a name="3.4.1">Arithmetic Operators</a></h3><p> +Lua supports the following arithmetic operators: + +<ul> +<li><b><code>+</code>: </b>addition</li> +<li><b><code>-</code>: </b>subtraction</li> +<li><b><code>*</code>: </b>multiplication</li> +<li><b><code>/</code>: </b>float division</li> +<li><b><code>//</code>: </b>floor division</li> +<li><b><code>%</code>: </b>modulo</li> +<li><b><code>^</code>: </b>exponentiation</li> +<li><b><code>-</code>: </b>unary minus</li> +</ul> + +<p> +With the exception of exponentiation and float division, +the arithmetic operators work as follows: +If both operands are integers, +the operation is performed over integers and the result is an integer. +Otherwise, if both operands are numbers, +then they are converted to floats, +the operation is performed following the machine's rules +for floating-point arithmetic +(usually the IEEE 754 standard), +and the result is a float. +(The string library coerces strings to numbers in +arithmetic operations; see <a href="#3.4.3">§3.4.3</a> for details.) + + +<p> +Exponentiation and float division (<code>/</code>) +always convert their operands to floats +and the result is always a float. +Exponentiation uses the ISO C function <code>pow</code>, +so that it works for non-integer exponents too. + + +<p> +Floor division (<code>//</code>) is a division +that rounds the quotient towards minus infinity, +resulting in the floor of the division of its operands. + + +<p> +Modulo is defined as the remainder of a division +that rounds the quotient towards minus infinity (floor division). + + +<p> +In case of overflows in integer arithmetic, +all operations <em>wrap around</em>. + + + +<h3>3.4.2 – <a name="3.4.2">Bitwise Operators</a></h3><p> +Lua supports the following bitwise operators: + +<ul> +<li><b><code>&</code>: </b>bitwise AND</li> +<li><b><code>|</code>: </b>bitwise OR</li> +<li><b><code>~</code>: </b>bitwise exclusive OR</li> +<li><b><code>>></code>: </b>right shift</li> +<li><b><code><<</code>: </b>left shift</li> +<li><b><code>~</code>: </b>unary bitwise NOT</li> +</ul> + +<p> +All bitwise operations convert its operands to integers +(see <a href="#3.4.3">§3.4.3</a>), +operate on all bits of those integers, +and result in an integer. + + +<p> +Both right and left shifts fill the vacant bits with zeros. +Negative displacements shift to the other direction; +displacements with absolute values equal to or higher than +the number of bits in an integer +result in zero (as all bits are shifted out). + + + + + +<h3>3.4.3 – <a name="3.4.3">Coercions and Conversions</a></h3><p> +Lua provides some automatic conversions between some +types and representations at run time. +Bitwise operators always convert float operands to integers. +Exponentiation and float division +always convert integer operands to floats. +All other arithmetic operations applied to mixed numbers +(integers and floats) convert the integer operand to a float. +The C API also converts both integers to floats and +floats to integers, as needed. +Moreover, string concatenation accepts numbers as arguments, +besides strings. + + +<p> +In a conversion from integer to float, +if the integer value has an exact representation as a float, +that is the result. +Otherwise, +the conversion gets the nearest higher or +the nearest lower representable value. +This kind of conversion never fails. + + +<p> +The conversion from float to integer +checks whether the float has an exact representation as an integer +(that is, the float has an integral value and +it is in the range of integer representation). +If it does, that representation is the result. +Otherwise, the conversion fails. + + +<p> +Several places in Lua coerce strings to numbers when necessary. +In particular, +the string library sets metamethods that try to coerce +strings to numbers in all arithmetic operations. +If the conversion fails, +the library calls the metamethod of the other operand +(if present) or it raises an error. +Note that bitwise operators do not do this coercion. + + +<p> +It is always a good practice not to rely on the +implicit coercions from strings to numbers, +as they are not always applied; +in particular, <code>"1"==1</code> is false and <code>"1"<1</code> raises an error +(see <a href="#3.4.4">§3.4.4</a>). +These coercions exist mainly for compatibility and may be removed +in future versions of the language. + + +<p> +A string is converted to an integer or a float +following its syntax and the rules of the Lua lexer. +The string may have also leading and trailing whitespaces and a sign. +All conversions from strings to numbers +accept both a dot and the current locale mark +as the radix character. +(The Lua lexer, however, accepts only a dot.) +If the string is not a valid numeral, +the conversion fails. +If necessary, the result of this first step is then converted +to a specific number subtype following the previous rules +for conversions between floats and integers. + + +<p> +The conversion from numbers to strings uses a +non-specified human-readable format. +To convert numbers to strings in any specific way, +use the function <a href="#pdf-string.format"><code>string.format</code></a>. + + + + + +<h3>3.4.4 – <a name="3.4.4">Relational Operators</a></h3><p> +Lua supports the following relational operators: + +<ul> +<li><b><code>==</code>: </b>equality</li> +<li><b><code>~=</code>: </b>inequality</li> +<li><b><code><</code>: </b>less than</li> +<li><b><code>></code>: </b>greater than</li> +<li><b><code><=</code>: </b>less or equal</li> +<li><b><code>>=</code>: </b>greater or equal</li> +</ul><p> +These operators always result in <b>false</b> or <b>true</b>. + + +<p> +Equality (<code>==</code>) first compares the type of its operands. +If the types are different, then the result is <b>false</b>. +Otherwise, the values of the operands are compared. +Strings are equal if they have the same byte content. +Numbers are equal if they denote the same mathematical value. + + +<p> +Tables, userdata, and threads +are compared by reference: +two objects are considered equal only if they are the same object. +Every time you create a new object +(a table, a userdata, or a thread), +this new object is different from any previously existing object. +A function is always equal to itself. +Functions with any detectable difference +(different behavior, different definition) are always different. +Functions created at different times but with no detectable differences +may be classified as equal or not +(depending on internal caching details). + + +<p> +You can change the way that Lua compares tables and userdata +by using the <code>__eq</code> metamethod (see <a href="#2.4">§2.4</a>). + + +<p> +Equality comparisons do not convert strings to numbers +or vice versa. +Thus, <code>"0"==0</code> evaluates to <b>false</b>, +and <code>t[0]</code> and <code>t["0"]</code> denote different +entries in a table. + + +<p> +The operator <code>~=</code> is exactly the negation of equality (<code>==</code>). + + +<p> +The order operators work as follows. +If both arguments are numbers, +then they are compared according to their mathematical values, +regardless of their subtypes. +Otherwise, if both arguments are strings, +then their values are compared according to the current locale. +Otherwise, Lua tries to call the <code>__lt</code> or the <code>__le</code> +metamethod (see <a href="#2.4">§2.4</a>). +A comparison <code>a > b</code> is translated to <code>b < a</code> +and <code>a >= b</code> is translated to <code>b <= a</code>. + + +<p> +Following the IEEE 754 standard, +the special value NaN is considered neither less than, +nor equal to, nor greater than any value, including itself. + + + + + +<h3>3.4.5 – <a name="3.4.5">Logical Operators</a></h3><p> +The logical operators in Lua are +<b>and</b>, <b>or</b>, and <b>not</b>. +Like the control structures (see <a href="#3.3.4">§3.3.4</a>), +all logical operators consider both <b>false</b> and <b>nil</b> as false +and anything else as true. + + +<p> +The negation operator <b>not</b> always returns <b>false</b> or <b>true</b>. +The conjunction operator <b>and</b> returns its first argument +if this value is <b>false</b> or <b>nil</b>; +otherwise, <b>and</b> returns its second argument. +The disjunction operator <b>or</b> returns its first argument +if this value is different from <b>nil</b> and <b>false</b>; +otherwise, <b>or</b> returns its second argument. +Both <b>and</b> and <b>or</b> use short-circuit evaluation; +that is, +the second operand is evaluated only if necessary. +Here are some examples: + +<pre> + 10 or 20 --> 10 + 10 or error() --> 10 + nil or "a" --> "a" + nil and 10 --> nil + false and error() --> false + false and nil --> false + false or nil --> nil + 10 and 20 --> 20 +</pre> + + + + +<h3>3.4.6 – <a name="3.4.6">Concatenation</a></h3><p> +The string concatenation operator in Lua is +denoted by two dots ('<code>..</code>'). +If both operands are strings or numbers, +then the numbers are converted to strings +in a non-specified format (see <a href="#3.4.3">§3.4.3</a>). +Otherwise, the <code>__concat</code> metamethod is called (see <a href="#2.4">§2.4</a>). + + + + + +<h3>3.4.7 – <a name="3.4.7">The Length Operator</a></h3> + +<p> +The length operator is denoted by the unary prefix operator <code>#</code>. + + +<p> +The length of a string is its number of bytes. +(That is the usual meaning of string length when each +character is one byte.) + + +<p> +The length operator applied on a table +returns a border in that table. +A <em>border</em> in a table <code>t</code> is any non-negative integer +that satisfies the following condition: + +<pre> + (border == 0 or t[border] ~= nil) and + (t[border + 1] == nil or border == math.maxinteger) +</pre><p> +In words, +a border is any positive integer index present in the table +that is followed by an absent index, +plus two limit cases: +zero, when index 1 is absent; +and the maximum value for an integer, when that index is present. +Note that keys that are not positive integers +do not interfere with borders. + + +<p> +A table with exactly one border is called a <em>sequence</em>. +For instance, the table <code>{10, 20, 30, 40, 50}</code> is a sequence, +as it has only one border (5). +The table <code>{10, 20, 30, nil, 50}</code> has two borders (3 and 5), +and therefore it is not a sequence. +(The <b>nil</b> at index 4 is called a <em>hole</em>.) +The table <code>{nil, 20, 30, nil, nil, 60, nil}</code> +has three borders (0, 3, and 6), +so it is not a sequence, too. +The table <code>{}</code> is a sequence with border 0. + + +<p> +When <code>t</code> is a sequence, +<code>#t</code> returns its only border, +which corresponds to the intuitive notion of the length of the sequence. +When <code>t</code> is not a sequence, +<code>#t</code> can return any of its borders. +(The exact one depends on details of +the internal representation of the table, +which in turn can depend on how the table was populated and +the memory addresses of its non-numeric keys.) + + +<p> +The computation of the length of a table +has a guaranteed worst time of <em>O(log n)</em>, +where <em>n</em> is the largest integer key in the table. + + +<p> +A program can modify the behavior of the length operator for +any value but strings through the <code>__len</code> metamethod (see <a href="#2.4">§2.4</a>). + + + + + +<h3>3.4.8 – <a name="3.4.8">Precedence</a></h3><p> +Operator precedence in Lua follows the table below, +from lower to higher priority: + +<pre> + or + and + < > <= >= ~= == + | + ~ + & + << >> + .. + + - + * / // % + unary operators (not # - ~) + ^ +</pre><p> +As usual, +you can use parentheses to change the precedences of an expression. +The concatenation ('<code>..</code>') and exponentiation ('<code>^</code>') +operators are right associative. +All other binary operators are left associative. + + + + + +<h3>3.4.9 – <a name="3.4.9">Table Constructors</a></h3><p> +Table constructors are expressions that create tables. +Every time a constructor is evaluated, a new table is created. +A constructor can be used to create an empty table +or to create a table and initialize some of its fields. +The general syntax for constructors is + +<pre> + tableconstructor ::= ‘<b>{</b>’ [fieldlist] ‘<b>}</b>’ + fieldlist ::= field {fieldsep field} [fieldsep] + field ::= ‘<b>[</b>’ exp ‘<b>]</b>’ ‘<b>=</b>’ exp | Name ‘<b>=</b>’ exp | exp + fieldsep ::= ‘<b>,</b>’ | ‘<b>;</b>’ +</pre> + +<p> +Each field of the form <code>[exp1] = exp2</code> adds to the new table an entry +with key <code>exp1</code> and value <code>exp2</code>. +A field of the form <code>name = exp</code> is equivalent to +<code>["name"] = exp</code>. +Fields of the form <code>exp</code> are equivalent to +<code>[i] = exp</code>, where <code>i</code> are consecutive integers +starting with 1; +fields in the other formats do not affect this counting. +For example, + +<pre> + a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 } +</pre><p> +is equivalent to + +<pre> + do + local t = {} + t[f(1)] = g + t[1] = "x" -- 1st exp + t[2] = "y" -- 2nd exp + t.x = 1 -- t["x"] = 1 + t[3] = f(x) -- 3rd exp + t[30] = 23 + t[4] = 45 -- 4th exp + a = t + end +</pre> + +<p> +The order of the assignments in a constructor is undefined. +(This order would be relevant only when there are repeated keys.) + + +<p> +If the last field in the list has the form <code>exp</code> +and the expression is a multires expression, +then all values returned by this expression enter the list consecutively +(see <a href="#3.4.12">§3.4.12</a>). + + +<p> +The field list can have an optional trailing separator, +as a convenience for machine-generated code. + + + + + +<h3>3.4.10 – <a name="3.4.10">Function Calls</a></h3><p> +A function call in Lua has the following syntax: + +<pre> + functioncall ::= prefixexp args +</pre><p> +In a function call, +first prefixexp and args are evaluated. +If the value of prefixexp has type <em>function</em>, +then this function is called +with the given arguments. +Otherwise, if present, +the prefixexp <code>__call</code> metamethod is called: +its first argument is the value of prefixexp, +followed by the original call arguments +(see <a href="#2.4">§2.4</a>). + + +<p> +The form + +<pre> + functioncall ::= prefixexp ‘<b>:</b>’ Name args +</pre><p> +can be used to emulate methods. +A call <code>v:name(<em>args</em>)</code> +is syntactic sugar for <code>v.name(v,<em>args</em>)</code>, +except that <code>v</code> is evaluated only once. + + +<p> +Arguments have the following syntax: + +<pre> + args ::= ‘<b>(</b>’ [explist] ‘<b>)</b>’ + args ::= tableconstructor + args ::= LiteralString +</pre><p> +All argument expressions are evaluated before the call. +A call of the form <code>f{<em>fields</em>}</code> is +syntactic sugar for <code>f({<em>fields</em>})</code>; +that is, the argument list is a single new table. +A call of the form <code>f'<em>string</em>'</code> +(or <code>f"<em>string</em>"</code> or <code>f[[<em>string</em>]]</code>) +is syntactic sugar for <code>f('<em>string</em>')</code>; +that is, the argument list is a single literal string. + + +<p> +A call of the form <code>return <em>functioncall</em></code> not in the +scope of a to-be-closed variable is called a <em>tail call</em>. +Lua implements <em>proper tail calls</em> +(or <em>proper tail recursion</em>): +In a tail call, +the called function reuses the stack entry of the calling function. +Therefore, there is no limit on the number of nested tail calls that +a program can execute. +However, a tail call erases any debug information about the +calling function. +Note that a tail call only happens with a particular syntax, +where the <b>return</b> has one single function call as argument, +and it is outside the scope of any to-be-closed variable. +This syntax makes the calling function return exactly +the returns of the called function, +without any intervening action. +So, none of the following examples are tail calls: + +<pre> + return (f(x)) -- results adjusted to 1 + return 2 * f(x) -- result multiplied by 2 + return x, f(x) -- additional results + f(x); return -- results discarded + return x or f(x) -- results adjusted to 1 +</pre> + + + + +<h3>3.4.11 – <a name="3.4.11">Function Definitions</a></h3> + +<p> +The syntax for function definition is + +<pre> + functiondef ::= <b>function</b> funcbody + funcbody ::= ‘<b>(</b>’ [parlist] ‘<b>)</b>’ block <b>end</b> +</pre> + +<p> +The following syntactic sugar simplifies function definitions: + +<pre> + stat ::= <b>function</b> funcname funcbody + stat ::= <b>local</b> <b>function</b> Name funcbody + funcname ::= Name {‘<b>.</b>’ Name} [‘<b>:</b>’ Name] +</pre><p> +The statement + +<pre> + function f () <em>body</em> end +</pre><p> +translates to + +<pre> + f = function () <em>body</em> end +</pre><p> +The statement + +<pre> + function t.a.b.c.f () <em>body</em> end +</pre><p> +translates to + +<pre> + t.a.b.c.f = function () <em>body</em> end +</pre><p> +The statement + +<pre> + local function f () <em>body</em> end +</pre><p> +translates to + +<pre> + local f; f = function () <em>body</em> end +</pre><p> +not to + +<pre> + local f = function () <em>body</em> end +</pre><p> +(This only makes a difference when the body of the function +contains references to <code>f</code>.) + + +<p> +A function definition is an executable expression, +whose value has type <em>function</em>. +When Lua precompiles a chunk, +all its function bodies are precompiled too, +but they are not created yet. +Then, whenever Lua executes the function definition, +the function is <em>instantiated</em> (or <em>closed</em>). +This function instance, or <em>closure</em>, +is the final value of the expression. + + +<p> +Parameters act as local variables that are +initialized with the argument values: + +<pre> + parlist ::= namelist [‘<b>,</b>’ ‘<b>...</b>’] | ‘<b>...</b>’ +</pre><p> +When a Lua function is called, +it adjusts its list of arguments to +the length of its list of parameters (see <a href="#3.4.12">§3.4.12</a>), +unless the function is a <em>variadic function</em>, +which is indicated by three dots ('<code>...</code>') +at the end of its parameter list. +A variadic function does not adjust its argument list; +instead, it collects all extra arguments and supplies them +to the function through a <em>vararg expression</em>, +which is also written as three dots. +The value of this expression is a list of all actual extra arguments, +similar to a function with multiple results (see <a href="#3.4.12">§3.4.12</a>). + + +<p> +As an example, consider the following definitions: + +<pre> + function f(a, b) end + function g(a, b, ...) end + function r() return 1,2,3 end +</pre><p> +Then, we have the following mapping from arguments to parameters and +to the vararg expression: + +<pre> + CALL PARAMETERS + + f(3) a=3, b=nil + f(3, 4) a=3, b=4 + f(3, 4, 5) a=3, b=4 + f(r(), 10) a=1, b=10 + f(r()) a=1, b=2 + + g(3) a=3, b=nil, ... --> (nothing) + g(3, 4) a=3, b=4, ... --> (nothing) + g(3, 4, 5, 8) a=3, b=4, ... --> 5 8 + g(5, r()) a=5, b=1, ... --> 2 3 +</pre> + +<p> +Results are returned using the <b>return</b> statement (see <a href="#3.3.4">§3.3.4</a>). +If control reaches the end of a function +without encountering a <b>return</b> statement, +then the function returns with no results. + + +<p> + +There is a system-dependent limit on the number of values +that a function may return. +This limit is guaranteed to be greater than 1000. + + +<p> +The <em>colon</em> syntax +is used to emulate <em>methods</em>, +adding an implicit extra parameter <code>self</code> to the function. +Thus, the statement + +<pre> + function t.a.b.c:f (<em>params</em>) <em>body</em> end +</pre><p> +is syntactic sugar for + +<pre> + t.a.b.c.f = function (self, <em>params</em>) <em>body</em> end +</pre> + + + + +<h3>3.4.12 – <a name="3.4.12">Lists of expressions, multiple results, +and adjustment</a></h3> + +<p> +Both function calls and vararg expressions can result in multiple values. +These expressions are called <em>multires expressions</em>. + + +<p> +When a multires expression is used as the last element +of a list of expressions, +all results from the expression are added to the +list of values produced by the list of expressions. +Note that a single expression +in a place that expects a list of expressions +is the last expression in that (singleton) list. + + +<p> +These are the places where Lua expects a list of expressions: + +<ul> + +<li>A <b>return</b> statement, +for instance <code>return e1, e2, e3</code> (see <a href="#3.3.4">§3.3.4</a>).</li> + +<li>A table constructor, +for instance <code>{e1, e2, e3}</code> (see <a href="#3.4.9">§3.4.9</a>).</li> + +<li>The arguments of a function call, +for instance <code>foo(e1, e2, e3)</code> (see <a href="#3.4.10">§3.4.10</a>).</li> + +<li>A multiple assignment, +for instance <code>a , b, c = e1, e2, e3</code> (see <a href="#3.3.3">§3.3.3</a>).</li> + +<li>A local declaration, +for instance <code>local a , b, c = e1, e2, e3</code> (see <a href="#3.3.7">§3.3.7</a>).</li> + +<li>The initial values in a generic <b>for</b> loop, +for instance <code>for k in e1, e2, e3 do ... end</code> (see <a href="#3.3.5">§3.3.5</a>).</li> + +</ul><p> +In the last four cases, +the list of values from the list of expressions +must be <em>adjusted</em> to a specific length: +the number of parameters in a call to a non-variadic function +(see <a href="#3.4.11">§3.4.11</a>), +the number of variables in a multiple assignment or +a local declaration, +and exactly four values for a generic <b>for</b> loop. +The <em>adjustment</em> follows these rules: +If there are more values than needed, +the extra values are thrown away; +if there are fewer values than needed, +the list is extended with <b>nil</b>'s. +When the list of expressions ends with a multires expression, +all results from that expression enter the list of values +before the adjustment. + + +<p> +When a multires expression is used +in a list of expressions without being the last element, +or in a place where the syntax expects a single expression, +Lua adjusts the result list of that expression to one element. +As a particular case, +the syntax expects a single expression inside a parenthesized expression; +therefore, adding parentheses around a multires expression +forces it to produce exactly one result. + + +<p> +We seldom need to use a vararg expression in a place +where the syntax expects a single expression. +(Usually it is simpler to add a regular parameter before +the variadic part and use that parameter.) +When there is such a need, +we recommend assigning the vararg expression +to a single variable and using that variable +in its place. + + +<p> +Here are some examples of uses of mutlres expressions. +In all cases, when the construction needs +"the n-th result" and there is no such result, +it uses a <b>nil</b>. + +<pre> + print(x, f()) -- prints x and all results from f(). + print(x, (f())) -- prints x and the first result from f(). + print(f(), x) -- prints the first result from f() and x. + print(1 + f()) -- prints 1 added to the first result from f(). + local x = ... -- x gets the first vararg argument. + x,y = ... -- x gets the first vararg argument, + -- y gets the second vararg argument. + x,y,z = w, f() -- x gets w, y gets the first result from f(), + -- z gets the second result from f(). + x,y,z = f() -- x gets the first result from f(), + -- y gets the second result from f(), + -- z gets the third result from f(). + x,y,z = f(), g() -- x gets the first result from f(), + -- y gets the first result from g(), + -- z gets the second result from g(). + x,y,z = (f()) -- x gets the first result from f(), y and z get nil. + return f() -- returns all results from f(). + return x, ... -- returns x and all received vararg arguments. + return x,y,f() -- returns x, y, and all results from f(). + {f()} -- creates a list with all results from f(). + {...} -- creates a list with all vararg arguments. + {f(), 5} -- creates a list with the first result from f() and 5. +</pre> + + + + + + +<h2>3.5 – <a name="3.5">Visibility Rules</a></h2> + +<p> + +Lua is a lexically scoped language. +The scope of a local variable begins at the first statement after +its declaration and lasts until the last non-void statement +of the innermost block that includes the declaration. +(<em>Void statements</em> are labels and empty statements.) +Consider the following example: + +<pre> + x = 10 -- global variable + do -- new block + local x = x -- new 'x', with value 10 + print(x) --> 10 + x = x+1 + do -- another block + local x = x+1 -- another 'x' + print(x) --> 12 + end + print(x) --> 11 + end + print(x) --> 10 (the global one) +</pre> + +<p> +Notice that, in a declaration like <code>local x = x</code>, +the new <code>x</code> being declared is not in scope yet, +and so the second <code>x</code> refers to the outside variable. + + +<p> +Because of the lexical scoping rules, +local variables can be freely accessed by functions +defined inside their scope. +A local variable used by an inner function is called an <em>upvalue</em> +(or <em>external local variable</em>, or simply <em>external variable</em>) +inside the inner function. + + +<p> +Notice that each execution of a <b>local</b> statement +defines new local variables. +Consider the following example: + +<pre> + a = {} + local x = 20 + for i = 1, 10 do + local y = 0 + a[i] = function () y = y + 1; return x + y end + end +</pre><p> +The loop creates ten closures +(that is, ten instances of the anonymous function). +Each of these closures uses a different <code>y</code> variable, +while all of them share the same <code>x</code>. + + + + + +<h1>4 – <a name="4">The Application Program Interface</a></h1> + + + +<p> + +This section describes the C API for Lua, that is, +the set of C functions available to the host program to communicate +with Lua. +All API functions and related types and constants +are declared in the header file <a name="pdf-lua.h"><code>lua.h</code></a>. + + +<p> +Even when we use the term "function", +any facility in the API may be provided as a macro instead. +Except where stated otherwise, +all such macros use each of their arguments exactly once +(except for the first argument, which is always a Lua state), +and so do not generate any hidden side-effects. + + +<p> +As in most C libraries, +the Lua API functions do not check their arguments +for validity or consistency. +However, you can change this behavior by compiling Lua +with the macro <a name="pdf-LUA_USE_APICHECK"><code>LUA_USE_APICHECK</code></a> defined. + + +<p> +The Lua library is fully reentrant: +it has no global variables. +It keeps all information it needs in a dynamic structure, +called the <em>Lua state</em>. + + +<p> +Each Lua state has one or more threads, +which correspond to independent, cooperative lines of execution. +The type <a href="#lua_State"><code>lua_State</code></a> (despite its name) refers to a thread. +(Indirectly, through the thread, it also refers to the +Lua state associated to the thread.) + + +<p> +A pointer to a thread must be passed as the first argument to +every function in the library, except to <a href="#lua_newstate"><code>lua_newstate</code></a>, +which creates a Lua state from scratch and returns a pointer +to the <em>main thread</em> in the new state. + + + + + +<h2>4.1 – <a name="4.1">The Stack</a></h2> + + + +<p> +Lua uses a <em>virtual stack</em> to pass values to and from C. +Each element in this stack represents a Lua value +(<b>nil</b>, number, string, etc.). +Functions in the API can access this stack through the +Lua state parameter that they receive. + + +<p> +Whenever Lua calls C, the called function gets a new stack, +which is independent of previous stacks and of stacks of +C functions that are still active. +This stack initially contains any arguments to the C function +and it is where the C function can store temporary +Lua values and must push its results +to be returned to the caller (see <a href="#lua_CFunction"><code>lua_CFunction</code></a>). + + +<p> +For convenience, +most query operations in the API do not follow a strict stack discipline. +Instead, they can refer to any element in the stack +by using an <em>index</em>: +A positive index represents an absolute stack position, +starting at 1 as the bottom of the stack; +a negative index represents an offset relative to the top of the stack. +More specifically, if the stack has <em>n</em> elements, +then index 1 represents the first element +(that is, the element that was pushed onto the stack first) +and +index <em>n</em> represents the last element; +index -1 also represents the last element +(that is, the element at the top) +and index <em>-n</em> represents the first element. + + + + + +<h3>4.1.1 – <a name="4.1.1">Stack Size</a></h3> + +<p> +When you interact with the Lua API, +you are responsible for ensuring consistency. +In particular, +<em>you are responsible for controlling stack overflow</em>. +When you call any API function, +you must ensure the stack has enough room to accommodate the results. + + +<p> +There is one exception to the above rule: +When you call a Lua function +without a fixed number of results (see <a href="#lua_call"><code>lua_call</code></a>), +Lua ensures that the stack has enough space for all results. +However, it does not ensure any extra space. +So, before pushing anything on the stack after such a call +you should use <a href="#lua_checkstack"><code>lua_checkstack</code></a>. + + +<p> +Whenever Lua calls C, +it ensures that the stack has space for +at least <a name="pdf-LUA_MINSTACK"><code>LUA_MINSTACK</code></a> extra elements; +that is, you can safely push up to <code>LUA_MINSTACK</code> values into it. +<code>LUA_MINSTACK</code> is defined as 20, +so that usually you do not have to worry about stack space +unless your code has loops pushing elements onto the stack. +Whenever necessary, +you can use the function <a href="#lua_checkstack"><code>lua_checkstack</code></a> +to ensure that the stack has enough space for pushing new elements. + + + + + +<h3>4.1.2 – <a name="4.1.2">Valid and Acceptable Indices</a></h3> + +<p> +Any function in the API that receives stack indices +works only with <em>valid indices</em> or <em>acceptable indices</em>. + + +<p> +A <em>valid index</em> is an index that refers to a +position that stores a modifiable Lua value. +It comprises stack indices between 1 and the stack top +(<code>1 ≤ abs(index) ≤ top</code>) + +plus <em>pseudo-indices</em>, +which represent some positions that are accessible to C code +but that are not in the stack. +Pseudo-indices are used to access the registry (see <a href="#4.3">§4.3</a>) +and the upvalues of a C function (see <a href="#4.2">§4.2</a>). + + +<p> +Functions that do not need a specific mutable position, +but only a value (e.g., query functions), +can be called with acceptable indices. +An <em>acceptable index</em> can be any valid index, +but it also can be any positive index after the stack top +within the space allocated for the stack, +that is, indices up to the stack size. +(Note that 0 is never an acceptable index.) +Indices to upvalues (see <a href="#4.2">§4.2</a>) greater than the real number +of upvalues in the current C function are also acceptable (but invalid). +Except when noted otherwise, +functions in the API work with acceptable indices. + + +<p> +Acceptable indices serve to avoid extra tests +against the stack top when querying the stack. +For instance, a C function can query its third argument +without the need to check whether there is a third argument, +that is, without the need to check whether 3 is a valid index. + + +<p> +For functions that can be called with acceptable indices, +any non-valid index is treated as if it +contains a value of a virtual type <a name="pdf-LUA_TNONE"><code>LUA_TNONE</code></a>, +which behaves like a nil value. + + + + + +<h3>4.1.3 – <a name="4.1.3">Pointers to strings</a></h3> + +<p> +Several functions in the API return pointers (<code>const char*</code>) +to Lua strings in the stack. +(See <a href="#lua_pushfstring"><code>lua_pushfstring</code></a>, <a href="#lua_pushlstring"><code>lua_pushlstring</code></a>, +<a href="#lua_pushstring"><code>lua_pushstring</code></a>, and <a href="#lua_tolstring"><code>lua_tolstring</code></a>. +See also <a href="#luaL_checklstring"><code>luaL_checklstring</code></a>, <a href="#luaL_checkstring"><code>luaL_checkstring</code></a>, +and <a href="#luaL_tolstring"><code>luaL_tolstring</code></a> in the auxiliary library.) + + +<p> +In general, +Lua's garbage collection can free or move internal memory +and then invalidate pointers to internal strings. +To allow a safe use of these pointers, +the API guarantees that any pointer to a string in a stack index +is valid while the string value at that index is not removed from the stack. +(It can be moved to another index, though.) +When the index is a pseudo-index (referring to an upvalue), +the pointer is valid while the corresponding call is active and +the corresponding upvalue is not modified. + + +<p> +Some functions in the debug interface +also return pointers to strings, +namely <a href="#lua_getlocal"><code>lua_getlocal</code></a>, <a href="#lua_getupvalue"><code>lua_getupvalue</code></a>, +<a href="#lua_setlocal"><code>lua_setlocal</code></a>, and <a href="#lua_setupvalue"><code>lua_setupvalue</code></a>. +For these functions, the pointer is guaranteed to +be valid while the caller function is active and +the given closure (if one was given) is in the stack. + + +<p> +Except for these guarantees, +the garbage collector is free to invalidate +any pointer to internal strings. + + + + + + + +<h2>4.2 – <a name="4.2">C Closures</a></h2> + +<p> +When a C function is created, +it is possible to associate some values with it, +thus creating a <em>C closure</em> +(see <a href="#lua_pushcclosure"><code>lua_pushcclosure</code></a>); +these values are called <em>upvalues</em> and are +accessible to the function whenever it is called. + + +<p> +Whenever a C function is called, +its upvalues are located at specific pseudo-indices. +These pseudo-indices are produced by the macro +<a href="#lua_upvalueindex"><code>lua_upvalueindex</code></a>. +The first upvalue associated with a function is at index +<code>lua_upvalueindex(1)</code>, and so on. +Any access to <code>lua_upvalueindex(<em>n</em>)</code>, +where <em>n</em> is greater than the number of upvalues of the +current function +(but not greater than 256, +which is one plus the maximum number of upvalues in a closure), +produces an acceptable but invalid index. + + +<p> +A C closure can also change the values +of its corresponding upvalues. + + + + + +<h2>4.3 – <a name="4.3">Registry</a></h2> + +<p> +Lua provides a <em>registry</em>, +a predefined table that can be used by any C code to +store whatever Lua values it needs to store. +The registry table is always accessible at pseudo-index +<a name="pdf-LUA_REGISTRYINDEX"><code>LUA_REGISTRYINDEX</code></a>. +Any C library can store data into this table, +but it must take care to choose keys +that are different from those used +by other libraries, to avoid collisions. +Typically, you should use as key a string containing your library name, +or a light userdata with the address of a C object in your code, +or any Lua object created by your code. +As with variable names, +string keys starting with an underscore followed by +uppercase letters are reserved for Lua. + + +<p> +The integer keys in the registry are used +by the reference mechanism (see <a href="#luaL_ref"><code>luaL_ref</code></a>) +and by some predefined values. +Therefore, integer keys in the registry +must not be used for other purposes. + + +<p> +When you create a new Lua state, +its registry comes with some predefined values. +These predefined values are indexed with integer keys +defined as constants in <code>lua.h</code>. +The following constants are defined: + +<ul> +<li><b><a name="pdf-LUA_RIDX_MAINTHREAD"><code>LUA_RIDX_MAINTHREAD</code></a>: </b> At this index the registry has +the main thread of the state. +(The main thread is the one created together with the state.) +</li> + +<li><b><a name="pdf-LUA_RIDX_GLOBALS"><code>LUA_RIDX_GLOBALS</code></a>: </b> At this index the registry has +the global environment. +</li> +</ul> + + + + +<h2>4.4 – <a name="4.4">Error Handling in C</a></h2> + + + +<p> +Internally, Lua uses the C <code>longjmp</code> facility to handle errors. +(Lua will use exceptions if you compile it as C++; +search for <code>LUAI_THROW</code> in the source code for details.) +When Lua faces any error, +such as a memory allocation error or a type error, +it <em>raises</em> an error; +that is, it does a long jump. +A <em>protected environment</em> uses <code>setjmp</code> +to set a recovery point; +any error jumps to the most recent active recovery point. + + +<p> +Inside a C function you can raise an error explicitly +by calling <a href="#lua_error"><code>lua_error</code></a>. + + +<p> +Most functions in the API can raise an error, +for instance due to a memory allocation error. +The documentation for each function indicates whether +it can raise errors. + + +<p> +If an error happens outside any protected environment, +Lua calls a <em>panic function</em> (see <a href="#lua_atpanic"><code>lua_atpanic</code></a>) +and then calls <code>abort</code>, +thus exiting the host application. +Your panic function can avoid this exit by +never returning +(e.g., doing a long jump to your own recovery point outside Lua). + + +<p> +The panic function, +as its name implies, +is a mechanism of last resort. +Programs should avoid it. +As a general rule, +when a C function is called by Lua with a Lua state, +it can do whatever it wants on that Lua state, +as it should be already protected. +However, +when C code operates on other Lua states +(e.g., a Lua-state argument to the function, +a Lua state stored in the registry, or +the result of <a href="#lua_newthread"><code>lua_newthread</code></a>), +it should use them only in API calls that cannot raise errors. + + +<p> +The panic function runs as if it were a message handler (see <a href="#2.3">§2.3</a>); +in particular, the error object is on the top of the stack. +However, there is no guarantee about stack space. +To push anything on the stack, +the panic function must first check the available space (see <a href="#4.1.1">§4.1.1</a>). + + + + + +<h3>4.4.1 – <a name="4.4.1">Status Codes</a></h3> + +<p> +Several functions that report errors in the API use the following +status codes to indicate different kinds of errors or other conditions: + +<ul> + +<li><b><a name="pdf-LUA_OK"><code>LUA_OK</code></a> (0): </b> no errors.</li> + +<li><b><a name="pdf-LUA_ERRRUN"><code>LUA_ERRRUN</code></a>: </b> a runtime error.</li> + +<li><b><a name="pdf-LUA_ERRMEM"><code>LUA_ERRMEM</code></a>: </b> +memory allocation error. +For such errors, Lua does not call the message handler. +</li> + +<li><b><a name="pdf-LUA_ERRERR"><code>LUA_ERRERR</code></a>: </b> error while running the message handler.</li> + +<li><b><a name="pdf-LUA_ERRSYNTAX"><code>LUA_ERRSYNTAX</code></a>: </b> syntax error during precompilation.</li> + +<li><b><a name="pdf-LUA_YIELD"><code>LUA_YIELD</code></a>: </b> the thread (coroutine) yields.</li> + +<li><b><a name="pdf-LUA_ERRFILE"><code>LUA_ERRFILE</code></a>: </b> a file-related error; +e.g., it cannot open or read the file.</li> + +</ul><p> +These constants are defined in the header file <code>lua.h</code>. + + + + + + + +<h2>4.5 – <a name="4.5">Handling Yields in C</a></h2> + +<p> +Internally, Lua uses the C <code>longjmp</code> facility to yield a coroutine. +Therefore, if a C function <code>foo</code> calls an API function +and this API function yields +(directly or indirectly by calling another function that yields), +Lua cannot return to <code>foo</code> any more, +because the <code>longjmp</code> removes its frame from the C stack. + + +<p> +To avoid this kind of problem, +Lua raises an error whenever it tries to yield across an API call, +except for three functions: +<a href="#lua_yieldk"><code>lua_yieldk</code></a>, <a href="#lua_callk"><code>lua_callk</code></a>, and <a href="#lua_pcallk"><code>lua_pcallk</code></a>. +All those functions receive a <em>continuation function</em> +(as a parameter named <code>k</code>) to continue execution after a yield. + + +<p> +We need to set some terminology to explain continuations. +We have a C function called from Lua which we will call +the <em>original function</em>. +This original function then calls one of those three functions in the C API, +which we will call the <em>callee function</em>, +that then yields the current thread. +This can happen when the callee function is <a href="#lua_yieldk"><code>lua_yieldk</code></a>, +or when the callee function is either <a href="#lua_callk"><code>lua_callk</code></a> or <a href="#lua_pcallk"><code>lua_pcallk</code></a> +and the function called by them yields. + + +<p> +Suppose the running thread yields while executing the callee function. +After the thread resumes, +it eventually will finish running the callee function. +However, +the callee function cannot return to the original function, +because its frame in the C stack was destroyed by the yield. +Instead, Lua calls a <em>continuation function</em>, +which was given as an argument to the callee function. +As the name implies, +the continuation function should continue the task +of the original function. + + +<p> +As an illustration, consider the following function: + +<pre> + int original_function (lua_State *L) { + ... /* code 1 */ + status = lua_pcall(L, n, m, h); /* calls Lua */ + ... /* code 2 */ + } +</pre><p> +Now we want to allow +the Lua code being run by <a href="#lua_pcall"><code>lua_pcall</code></a> to yield. +First, we can rewrite our function like here: + +<pre> + int k (lua_State *L, int status, lua_KContext ctx) { + ... /* code 2 */ + } + + int original_function (lua_State *L) { + ... /* code 1 */ + return k(L, lua_pcall(L, n, m, h), ctx); + } +</pre><p> +In the above code, +the new function <code>k</code> is a +<em>continuation function</em> (with type <a href="#lua_KFunction"><code>lua_KFunction</code></a>), +which should do all the work that the original function +was doing after calling <a href="#lua_pcall"><code>lua_pcall</code></a>. +Now, we must inform Lua that it must call <code>k</code> if the Lua code +being executed by <a href="#lua_pcall"><code>lua_pcall</code></a> gets interrupted in some way +(errors or yielding), +so we rewrite the code as here, +replacing <a href="#lua_pcall"><code>lua_pcall</code></a> by <a href="#lua_pcallk"><code>lua_pcallk</code></a>: + +<pre> + int original_function (lua_State *L) { + ... /* code 1 */ + return k(L, lua_pcallk(L, n, m, h, ctx2, k), ctx1); + } +</pre><p> +Note the external, explicit call to the continuation: +Lua will call the continuation only if needed, that is, +in case of errors or resuming after a yield. +If the called function returns normally without ever yielding, +<a href="#lua_pcallk"><code>lua_pcallk</code></a> (and <a href="#lua_callk"><code>lua_callk</code></a>) will also return normally. +(Of course, instead of calling the continuation in that case, +you can do the equivalent work directly inside the original function.) + + +<p> +Besides the Lua state, +the continuation function has two other parameters: +the final status of the call and the context value (<code>ctx</code>) that +was passed originally to <a href="#lua_pcallk"><code>lua_pcallk</code></a>. +Lua does not use this context value; +it only passes this value from the original function to the +continuation function. +For <a href="#lua_pcallk"><code>lua_pcallk</code></a>, +the status is the same value that would be returned by <a href="#lua_pcallk"><code>lua_pcallk</code></a>, +except that it is <a href="#pdf-LUA_YIELD"><code>LUA_YIELD</code></a> when being executed after a yield +(instead of <a href="#pdf-LUA_OK"><code>LUA_OK</code></a>). +For <a href="#lua_yieldk"><code>lua_yieldk</code></a> and <a href="#lua_callk"><code>lua_callk</code></a>, +the status is always <a href="#pdf-LUA_YIELD"><code>LUA_YIELD</code></a> when Lua calls the continuation. +(For these two functions, +Lua will not call the continuation in case of errors, +because they do not handle errors.) +Similarly, when using <a href="#lua_callk"><code>lua_callk</code></a>, +you should call the continuation function +with <a href="#pdf-LUA_OK"><code>LUA_OK</code></a> as the status. +(For <a href="#lua_yieldk"><code>lua_yieldk</code></a>, there is not much point in calling +directly the continuation function, +because <a href="#lua_yieldk"><code>lua_yieldk</code></a> usually does not return.) + + +<p> +Lua treats the continuation function as if it were the original function. +The continuation function receives the same Lua stack +from the original function, +in the same state it would be if the callee function had returned. +(For instance, +after a <a href="#lua_callk"><code>lua_callk</code></a> the function and its arguments are +removed from the stack and replaced by the results from the call.) +It also has the same upvalues. +Whatever it returns is handled by Lua as if it were the return +of the original function. + + + + + +<h2>4.6 – <a name="4.6">Functions and Types</a></h2> + +<p> +Here we list all functions and types from the C API in +alphabetical order. +Each function has an indicator like this: +<span class="apii">[-o, +p, <em>x</em>]</span> + + +<p> +The first field, <code>o</code>, +is how many elements the function pops from the stack. +The second field, <code>p</code>, +is how many elements the function pushes onto the stack. +(Any function always pushes its results after popping its arguments.) +A field in the form <code>x|y</code> means the function can push (or pop) +<code>x</code> or <code>y</code> elements, +depending on the situation; +an interrogation mark '<code>?</code>' means that +we cannot know how many elements the function pops/pushes +by looking only at its arguments. +(For instance, they may depend on what is in the stack.) +The third field, <code>x</code>, +tells whether the function may raise errors: +'<code>-</code>' means the function never raises any error; +'<code>m</code>' means the function may raise only out-of-memory errors; +'<code>v</code>' means the function may raise the errors explained in the text; +'<code>e</code>' means the function can run arbitrary Lua code, +either directly or through metamethods, +and therefore may raise any errors. + + + +<hr><h3><a name="lua_absindex"><code>lua_absindex</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_absindex (lua_State *L, int idx);</pre> + +<p> +Converts the acceptable index <code>idx</code> +into an equivalent absolute index +(that is, one that does not depend on the stack size). + + + + + +<hr><h3><a name="lua_Alloc"><code>lua_Alloc</code></a></h3> +<pre>typedef void * (*lua_Alloc) (void *ud, + void *ptr, + size_t osize, + size_t nsize);</pre> + +<p> +The type of the memory-allocation function used by Lua states. +The allocator function must provide a +functionality similar to <code>realloc</code>, +but not exactly the same. +Its arguments are +<code>ud</code>, an opaque pointer passed to <a href="#lua_newstate"><code>lua_newstate</code></a>; +<code>ptr</code>, a pointer to the block being allocated/reallocated/freed; +<code>osize</code>, the original size of the block or some code about what +is being allocated; +and <code>nsize</code>, the new size of the block. + + +<p> +When <code>ptr</code> is not <code>NULL</code>, +<code>osize</code> is the size of the block pointed by <code>ptr</code>, +that is, the size given when it was allocated or reallocated. + + +<p> +When <code>ptr</code> is <code>NULL</code>, +<code>osize</code> encodes the kind of object that Lua is allocating. +<code>osize</code> is any of +<a href="#pdf-LUA_TSTRING"><code>LUA_TSTRING</code></a>, <a href="#pdf-LUA_TTABLE"><code>LUA_TTABLE</code></a>, <a href="#pdf-LUA_TFUNCTION"><code>LUA_TFUNCTION</code></a>, +<a href="#pdf-LUA_TUSERDATA"><code>LUA_TUSERDATA</code></a>, or <a href="#pdf-LUA_TTHREAD"><code>LUA_TTHREAD</code></a> when (and only when) +Lua is creating a new object of that type. +When <code>osize</code> is some other value, +Lua is allocating memory for something else. + + +<p> +Lua assumes the following behavior from the allocator function: + + +<p> +When <code>nsize</code> is zero, +the allocator must behave like <code>free</code> +and then return <code>NULL</code>. + + +<p> +When <code>nsize</code> is not zero, +the allocator must behave like <code>realloc</code>. +In particular, the allocator returns <code>NULL</code> +if and only if it cannot fulfill the request. + + +<p> +Here is a simple implementation for the allocator function. +It is used in the auxiliary library by <a href="#luaL_newstate"><code>luaL_newstate</code></a>. + +<pre> + static void *l_alloc (void *ud, void *ptr, size_t osize, + size_t nsize) { + (void)ud; (void)osize; /* not used */ + if (nsize == 0) { + free(ptr); + return NULL; + } + else + return realloc(ptr, nsize); + } +</pre><p> +Note that ISO C ensures +that <code>free(NULL)</code> has no effect and that +<code>realloc(NULL,size)</code> is equivalent to <code>malloc(size)</code>. + + + + + +<hr><h3><a name="lua_arith"><code>lua_arith</code></a></h3><p> +<span class="apii">[-(2|1), +1, <em>e</em>]</span> +<pre>void lua_arith (lua_State *L, int op);</pre> + +<p> +Performs an arithmetic or bitwise operation over the two values +(or one, in the case of negations) +at the top of the stack, +with the value on the top being the second operand, +pops these values, and pushes the result of the operation. +The function follows the semantics of the corresponding Lua operator +(that is, it may call metamethods). + + +<p> +The value of <code>op</code> must be one of the following constants: + +<ul> + +<li><b><a name="pdf-LUA_OPADD"><code>LUA_OPADD</code></a>: </b> performs addition (<code>+</code>)</li> +<li><b><a name="pdf-LUA_OPSUB"><code>LUA_OPSUB</code></a>: </b> performs subtraction (<code>-</code>)</li> +<li><b><a name="pdf-LUA_OPMUL"><code>LUA_OPMUL</code></a>: </b> performs multiplication (<code>*</code>)</li> +<li><b><a name="pdf-LUA_OPDIV"><code>LUA_OPDIV</code></a>: </b> performs float division (<code>/</code>)</li> +<li><b><a name="pdf-LUA_OPIDIV"><code>LUA_OPIDIV</code></a>: </b> performs floor division (<code>//</code>)</li> +<li><b><a name="pdf-LUA_OPMOD"><code>LUA_OPMOD</code></a>: </b> performs modulo (<code>%</code>)</li> +<li><b><a name="pdf-LUA_OPPOW"><code>LUA_OPPOW</code></a>: </b> performs exponentiation (<code>^</code>)</li> +<li><b><a name="pdf-LUA_OPUNM"><code>LUA_OPUNM</code></a>: </b> performs mathematical negation (unary <code>-</code>)</li> +<li><b><a name="pdf-LUA_OPBNOT"><code>LUA_OPBNOT</code></a>: </b> performs bitwise NOT (<code>~</code>)</li> +<li><b><a name="pdf-LUA_OPBAND"><code>LUA_OPBAND</code></a>: </b> performs bitwise AND (<code>&</code>)</li> +<li><b><a name="pdf-LUA_OPBOR"><code>LUA_OPBOR</code></a>: </b> performs bitwise OR (<code>|</code>)</li> +<li><b><a name="pdf-LUA_OPBXOR"><code>LUA_OPBXOR</code></a>: </b> performs bitwise exclusive OR (<code>~</code>)</li> +<li><b><a name="pdf-LUA_OPSHL"><code>LUA_OPSHL</code></a>: </b> performs left shift (<code><<</code>)</li> +<li><b><a name="pdf-LUA_OPSHR"><code>LUA_OPSHR</code></a>: </b> performs right shift (<code>>></code>)</li> + +</ul> + + + + +<hr><h3><a name="lua_atpanic"><code>lua_atpanic</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);</pre> + +<p> +Sets a new panic function and returns the old one (see <a href="#4.4">§4.4</a>). + + + + + +<hr><h3><a name="lua_call"><code>lua_call</code></a></h3><p> +<span class="apii">[-(nargs+1), +nresults, <em>e</em>]</span> +<pre>void lua_call (lua_State *L, int nargs, int nresults);</pre> + +<p> +Calls a function. +Like regular Lua calls, +<code>lua_call</code> respects the <code>__call</code> metamethod. +So, here the word "function" +means any callable value. + + +<p> +To do a call you must use the following protocol: +first, the function to be called is pushed onto the stack; +then, the arguments to the call are pushed +in direct order; +that is, the first argument is pushed first. +Finally you call <a href="#lua_call"><code>lua_call</code></a>; +<code>nargs</code> is the number of arguments that you pushed onto the stack. +When the function returns, +all arguments and the function value are popped +and the call results are pushed onto the stack. +The number of results is adjusted to <code>nresults</code>, +unless <code>nresults</code> is <a name="pdf-LUA_MULTRET"><code>LUA_MULTRET</code></a>. +In this case, all results from the function are pushed; +Lua takes care that the returned values fit into the stack space, +but it does not ensure any extra space in the stack. +The function results are pushed onto the stack in direct order +(the first result is pushed first), +so that after the call the last result is on the top of the stack. + + +<p> +Any error while calling and running the function is propagated upwards +(with a <code>longjmp</code>). + + +<p> +The following example shows how the host program can do the +equivalent to this Lua code: + +<pre> + a = f("how", t.x, 14) +</pre><p> +Here it is in C: + +<pre> + lua_getglobal(L, "f"); /* function to be called */ + lua_pushliteral(L, "how"); /* 1st argument */ + lua_getglobal(L, "t"); /* table to be indexed */ + lua_getfield(L, -1, "x"); /* push result of t.x (2nd arg) */ + lua_remove(L, -2); /* remove 't' from the stack */ + lua_pushinteger(L, 14); /* 3rd argument */ + lua_call(L, 3, 1); /* call 'f' with 3 arguments and 1 result */ + lua_setglobal(L, "a"); /* set global 'a' */ +</pre><p> +Note that the code above is <em>balanced</em>: +at its end, the stack is back to its original configuration. +This is considered good programming practice. + + + + + +<hr><h3><a name="lua_callk"><code>lua_callk</code></a></h3><p> +<span class="apii">[-(nargs + 1), +nresults, <em>e</em>]</span> +<pre>void lua_callk (lua_State *L, + int nargs, + int nresults, + lua_KContext ctx, + lua_KFunction k);</pre> + +<p> +This function behaves exactly like <a href="#lua_call"><code>lua_call</code></a>, +but allows the called function to yield (see <a href="#4.5">§4.5</a>). + + + + + +<hr><h3><a name="lua_CFunction"><code>lua_CFunction</code></a></h3> +<pre>typedef int (*lua_CFunction) (lua_State *L);</pre> + +<p> +Type for C functions. + + +<p> +In order to communicate properly with Lua, +a C function must use the following protocol, +which defines the way parameters and results are passed: +a C function receives its arguments from Lua in its stack +in direct order (the first argument is pushed first). +So, when the function starts, +<code>lua_gettop(L)</code> returns the number of arguments received by the function. +The first argument (if any) is at index 1 +and its last argument is at index <code>lua_gettop(L)</code>. +To return values to Lua, a C function just pushes them onto the stack, +in direct order (the first result is pushed first), +and returns in C the number of results. +Any other value in the stack below the results will be properly +discarded by Lua. +Like a Lua function, a C function called by Lua can also return +many results. + + +<p> +As an example, the following function receives a variable number +of numeric arguments and returns their average and their sum: + +<pre> + static int foo (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + lua_Number sum = 0.0; + int i; + for (i = 1; i <= n; i++) { + if (!lua_isnumber(L, i)) { + lua_pushliteral(L, "incorrect argument"); + lua_error(L); + } + sum += lua_tonumber(L, i); + } + lua_pushnumber(L, sum/n); /* first result */ + lua_pushnumber(L, sum); /* second result */ + return 2; /* number of results */ + } +</pre> + + + + +<hr><h3><a name="lua_checkstack"><code>lua_checkstack</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_checkstack (lua_State *L, int n);</pre> + +<p> +Ensures that the stack has space for at least <code>n</code> extra elements, +that is, that you can safely push up to <code>n</code> values into it. +It returns false if it cannot fulfill the request, +either because it would cause the stack +to be greater than a fixed maximum size +(typically at least several thousand elements) or +because it cannot allocate memory for the extra space. +This function never shrinks the stack; +if the stack already has space for the extra elements, +it is left unchanged. + + + + + +<hr><h3><a name="lua_close"><code>lua_close</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>void lua_close (lua_State *L);</pre> + +<p> +Close all active to-be-closed variables in the main thread, +release all objects in the given Lua state +(calling the corresponding garbage-collection metamethods, if any), +and frees all dynamic memory used by this state. + + +<p> +On several platforms, you may not need to call this function, +because all resources are naturally released when the host program ends. +On the other hand, long-running programs that create multiple states, +such as daemons or web servers, +will probably need to close states as soon as they are not needed. + + + + + +<hr><h3><a name="lua_closeslot"><code>lua_closeslot</code></a></h3><p> +<span class="apii">[-0, +0, <em>e</em>]</span> +<pre>void lua_closeslot (lua_State *L, int index);</pre> + +<p> +Close the to-be-closed slot at the given index and set its value to <b>nil</b>. +The index must be the last index previously marked to be closed +(see <a href="#lua_toclose"><code>lua_toclose</code></a>) that is still active (that is, not closed yet). + + +<p> +A <code>__close</code> metamethod cannot yield +when called through this function. + + +<p> +(This function was introduced in release 5.4.3.) + + + + + +<hr><h3><a name="lua_closethread"><code>lua_closethread</code></a></h3><p> +<span class="apii">[-0, +?, –]</span> +<pre>int lua_closethread (lua_State *L, lua_State *from);</pre> + +<p> +Resets a thread, cleaning its call stack and closing all pending +to-be-closed variables. +Returns a status code: +<a href="#pdf-LUA_OK"><code>LUA_OK</code></a> for no errors in the thread +(either the original error that stopped the thread or +errors in closing methods), +or an error status otherwise. +In case of error, +leaves the error object on the top of the stack. + + +<p> +The parameter <code>from</code> represents the coroutine that is resetting <code>L</code>. +If there is no such coroutine, +this parameter can be <code>NULL</code>. + + +<p> +(This function was introduced in release 5.4.6.) + + + + + +<hr><h3><a name="lua_compare"><code>lua_compare</code></a></h3><p> +<span class="apii">[-0, +0, <em>e</em>]</span> +<pre>int lua_compare (lua_State *L, int index1, int index2, int op);</pre> + +<p> +Compares two Lua values. +Returns 1 if the value at index <code>index1</code> satisfies <code>op</code> +when compared with the value at index <code>index2</code>, +following the semantics of the corresponding Lua operator +(that is, it may call metamethods). +Otherwise returns 0. +Also returns 0 if any of the indices is not valid. + + +<p> +The value of <code>op</code> must be one of the following constants: + +<ul> + +<li><b><a name="pdf-LUA_OPEQ"><code>LUA_OPEQ</code></a>: </b> compares for equality (<code>==</code>)</li> +<li><b><a name="pdf-LUA_OPLT"><code>LUA_OPLT</code></a>: </b> compares for less than (<code><</code>)</li> +<li><b><a name="pdf-LUA_OPLE"><code>LUA_OPLE</code></a>: </b> compares for less or equal (<code><=</code>)</li> + +</ul> + + + + +<hr><h3><a name="lua_concat"><code>lua_concat</code></a></h3><p> +<span class="apii">[-n, +1, <em>e</em>]</span> +<pre>void lua_concat (lua_State *L, int n);</pre> + +<p> +Concatenates the <code>n</code> values at the top of the stack, +pops them, and leaves the result on the top. +If <code>n</code> is 1, the result is the single value on the stack +(that is, the function does nothing); +if <code>n</code> is 0, the result is the empty string. +Concatenation is performed following the usual semantics of Lua +(see <a href="#3.4.6">§3.4.6</a>). + + + + + +<hr><h3><a name="lua_copy"><code>lua_copy</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>void lua_copy (lua_State *L, int fromidx, int toidx);</pre> + +<p> +Copies the element at index <code>fromidx</code> +into the valid index <code>toidx</code>, +replacing the value at that position. +Values at other positions are not affected. + + + + + +<hr><h3><a name="lua_createtable"><code>lua_createtable</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>void lua_createtable (lua_State *L, int narr, int nrec);</pre> + +<p> +Creates a new empty table and pushes it onto the stack. +Parameter <code>narr</code> is a hint for how many elements the table +will have as a sequence; +parameter <code>nrec</code> is a hint for how many other elements +the table will have. +Lua may use these hints to preallocate memory for the new table. +This preallocation may help performance when you know in advance +how many elements the table will have. +Otherwise you can use the function <a href="#lua_newtable"><code>lua_newtable</code></a>. + + + + + +<hr><h3><a name="lua_dump"><code>lua_dump</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_dump (lua_State *L, + lua_Writer writer, + void *data, + int strip);</pre> + +<p> +Dumps a function as a binary chunk. +Receives a Lua function on the top of the stack +and produces a binary chunk that, +if loaded again, +results in a function equivalent to the one dumped. +As it produces parts of the chunk, +<a href="#lua_dump"><code>lua_dump</code></a> calls function <code>writer</code> (see <a href="#lua_Writer"><code>lua_Writer</code></a>) +with the given <code>data</code> +to write them. + + +<p> +If <code>strip</code> is true, +the binary representation may not include all debug information +about the function, +to save space. + + +<p> +The value returned is the error code returned by the last +call to the writer; +0 means no errors. + + +<p> +This function does not pop the Lua function from the stack. + + + + + +<hr><h3><a name="lua_error"><code>lua_error</code></a></h3><p> +<span class="apii">[-1, +0, <em>v</em>]</span> +<pre>int lua_error (lua_State *L);</pre> + +<p> +Raises a Lua error, +using the value on the top of the stack as the error object. +This function does a long jump, +and therefore never returns +(see <a href="#luaL_error"><code>luaL_error</code></a>). + + + + + +<hr><h3><a name="lua_gc"><code>lua_gc</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_gc (lua_State *L, int what, ...);</pre> + +<p> +Controls the garbage collector. + + +<p> +This function performs several tasks, +according to the value of the parameter <code>what</code>. +For options that need extra arguments, +they are listed after the option. + +<ul> + +<li><b><code>LUA_GCCOLLECT</code>: </b> +Performs a full garbage-collection cycle. +</li> + +<li><b><code>LUA_GCSTOP</code>: </b> +Stops the garbage collector. +</li> + +<li><b><code>LUA_GCRESTART</code>: </b> +Restarts the garbage collector. +</li> + +<li><b><code>LUA_GCCOUNT</code>: </b> +Returns the current amount of memory (in Kbytes) in use by Lua. +</li> + +<li><b><code>LUA_GCCOUNTB</code>: </b> +Returns the remainder of dividing the current amount of bytes of +memory in use by Lua by 1024. +</li> + +<li><b><code>LUA_GCSTEP</code> <code>(int stepsize)</code>: </b> +Performs an incremental step of garbage collection, +corresponding to the allocation of <code>stepsize</code> Kbytes. +</li> + +<li><b><code>LUA_GCISRUNNING</code>: </b> +Returns a boolean that tells whether the collector is running +(i.e., not stopped). +</li> + +<li><b><code>LUA_GCINC</code> (int pause, int stepmul, stepsize): </b> +Changes the collector to incremental mode +with the given parameters (see <a href="#2.5.1">§2.5.1</a>). +Returns the previous mode (<code>LUA_GCGEN</code> or <code>LUA_GCINC</code>). +</li> + +<li><b><code>LUA_GCGEN</code> (int minormul, int majormul): </b> +Changes the collector to generational mode +with the given parameters (see <a href="#2.5.2">§2.5.2</a>). +Returns the previous mode (<code>LUA_GCGEN</code> or <code>LUA_GCINC</code>). +</li> + +</ul><p> +For more details about these options, +see <a href="#pdf-collectgarbage"><code>collectgarbage</code></a>. + + +<p> +This function should not be called by a finalizer. + + + + + +<hr><h3><a name="lua_getallocf"><code>lua_getallocf</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>lua_Alloc lua_getallocf (lua_State *L, void **ud);</pre> + +<p> +Returns the memory-allocation function of a given state. +If <code>ud</code> is not <code>NULL</code>, Lua stores in <code>*ud</code> the +opaque pointer given when the memory-allocator function was set. + + + + + +<hr><h3><a name="lua_getfield"><code>lua_getfield</code></a></h3><p> +<span class="apii">[-0, +1, <em>e</em>]</span> +<pre>int lua_getfield (lua_State *L, int index, const char *k);</pre> + +<p> +Pushes onto the stack the value <code>t[k]</code>, +where <code>t</code> is the value at the given index. +As in Lua, this function may trigger a metamethod +for the "index" event (see <a href="#2.4">§2.4</a>). + + +<p> +Returns the type of the pushed value. + + + + + +<hr><h3><a name="lua_getextraspace"><code>lua_getextraspace</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>void *lua_getextraspace (lua_State *L);</pre> + +<p> +Returns a pointer to a raw memory area associated with the +given Lua state. +The application can use this area for any purpose; +Lua does not use it for anything. + + +<p> +Each new thread has this area initialized with a copy +of the area of the main thread. + + +<p> +By default, this area has the size of a pointer to void, +but you can recompile Lua with a different size for this area. +(See <code>LUA_EXTRASPACE</code> in <code>luaconf.h</code>.) + + + + + +<hr><h3><a name="lua_getglobal"><code>lua_getglobal</code></a></h3><p> +<span class="apii">[-0, +1, <em>e</em>]</span> +<pre>int lua_getglobal (lua_State *L, const char *name);</pre> + +<p> +Pushes onto the stack the value of the global <code>name</code>. +Returns the type of that value. + + + + + +<hr><h3><a name="lua_geti"><code>lua_geti</code></a></h3><p> +<span class="apii">[-0, +1, <em>e</em>]</span> +<pre>int lua_geti (lua_State *L, int index, lua_Integer i);</pre> + +<p> +Pushes onto the stack the value <code>t[i]</code>, +where <code>t</code> is the value at the given index. +As in Lua, this function may trigger a metamethod +for the "index" event (see <a href="#2.4">§2.4</a>). + + +<p> +Returns the type of the pushed value. + + + + + +<hr><h3><a name="lua_getmetatable"><code>lua_getmetatable</code></a></h3><p> +<span class="apii">[-0, +(0|1), –]</span> +<pre>int lua_getmetatable (lua_State *L, int index);</pre> + +<p> +If the value at the given index has a metatable, +the function pushes that metatable onto the stack and returns 1. +Otherwise, +the function returns 0 and pushes nothing on the stack. + + + + + +<hr><h3><a name="lua_gettable"><code>lua_gettable</code></a></h3><p> +<span class="apii">[-1, +1, <em>e</em>]</span> +<pre>int lua_gettable (lua_State *L, int index);</pre> + +<p> +Pushes onto the stack the value <code>t[k]</code>, +where <code>t</code> is the value at the given index +and <code>k</code> is the value on the top of the stack. + + +<p> +This function pops the key from the stack, +pushing the resulting value in its place. +As in Lua, this function may trigger a metamethod +for the "index" event (see <a href="#2.4">§2.4</a>). + + +<p> +Returns the type of the pushed value. + + + + + +<hr><h3><a name="lua_gettop"><code>lua_gettop</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_gettop (lua_State *L);</pre> + +<p> +Returns the index of the top element in the stack. +Because indices start at 1, +this result is equal to the number of elements in the stack; +in particular, 0 means an empty stack. + + + + + +<hr><h3><a name="lua_getiuservalue"><code>lua_getiuservalue</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>int lua_getiuservalue (lua_State *L, int index, int n);</pre> + +<p> +Pushes onto the stack the <code>n</code>-th user value associated with the +full userdata at the given index and +returns the type of the pushed value. + + +<p> +If the userdata does not have that value, +pushes <b>nil</b> and returns <a href="#pdf-LUA_TNONE"><code>LUA_TNONE</code></a>. + + + + + +<hr><h3><a name="lua_insert"><code>lua_insert</code></a></h3><p> +<span class="apii">[-1, +1, –]</span> +<pre>void lua_insert (lua_State *L, int index);</pre> + +<p> +Moves the top element into the given valid index, +shifting up the elements above this index to open space. +This function cannot be called with a pseudo-index, +because a pseudo-index is not an actual stack position. + + + + + +<hr><h3><a name="lua_Integer"><code>lua_Integer</code></a></h3> +<pre>typedef ... lua_Integer;</pre> + +<p> +The type of integers in Lua. + + +<p> +By default this type is <code>long long</code>, +(usually a 64-bit two-complement integer), +but that can be changed to <code>long</code> or <code>int</code> +(usually a 32-bit two-complement integer). +(See <code>LUA_INT_TYPE</code> in <code>luaconf.h</code>.) + + +<p> +Lua also defines the constants +<a name="pdf-LUA_MININTEGER"><code>LUA_MININTEGER</code></a> and <a name="pdf-LUA_MAXINTEGER"><code>LUA_MAXINTEGER</code></a>, +with the minimum and the maximum values that fit in this type. + + + + + +<hr><h3><a name="lua_isboolean"><code>lua_isboolean</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_isboolean (lua_State *L, int index);</pre> + +<p> +Returns 1 if the value at the given index is a boolean, +and 0 otherwise. + + + + + +<hr><h3><a name="lua_iscfunction"><code>lua_iscfunction</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_iscfunction (lua_State *L, int index);</pre> + +<p> +Returns 1 if the value at the given index is a C function, +and 0 otherwise. + + + + + +<hr><h3><a name="lua_isfunction"><code>lua_isfunction</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_isfunction (lua_State *L, int index);</pre> + +<p> +Returns 1 if the value at the given index is a function +(either C or Lua), and 0 otherwise. + + + + + +<hr><h3><a name="lua_isinteger"><code>lua_isinteger</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_isinteger (lua_State *L, int index);</pre> + +<p> +Returns 1 if the value at the given index is an integer +(that is, the value is a number and is represented as an integer), +and 0 otherwise. + + + + + +<hr><h3><a name="lua_islightuserdata"><code>lua_islightuserdata</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_islightuserdata (lua_State *L, int index);</pre> + +<p> +Returns 1 if the value at the given index is a light userdata, +and 0 otherwise. + + + + + +<hr><h3><a name="lua_isnil"><code>lua_isnil</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_isnil (lua_State *L, int index);</pre> + +<p> +Returns 1 if the value at the given index is <b>nil</b>, +and 0 otherwise. + + + + + +<hr><h3><a name="lua_isnone"><code>lua_isnone</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_isnone (lua_State *L, int index);</pre> + +<p> +Returns 1 if the given index is not valid, +and 0 otherwise. + + + + + +<hr><h3><a name="lua_isnoneornil"><code>lua_isnoneornil</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_isnoneornil (lua_State *L, int index);</pre> + +<p> +Returns 1 if the given index is not valid +or if the value at this index is <b>nil</b>, +and 0 otherwise. + + + + + +<hr><h3><a name="lua_isnumber"><code>lua_isnumber</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_isnumber (lua_State *L, int index);</pre> + +<p> +Returns 1 if the value at the given index is a number +or a string convertible to a number, +and 0 otherwise. + + + + + +<hr><h3><a name="lua_isstring"><code>lua_isstring</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_isstring (lua_State *L, int index);</pre> + +<p> +Returns 1 if the value at the given index is a string +or a number (which is always convertible to a string), +and 0 otherwise. + + + + + +<hr><h3><a name="lua_istable"><code>lua_istable</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_istable (lua_State *L, int index);</pre> + +<p> +Returns 1 if the value at the given index is a table, +and 0 otherwise. + + + + + +<hr><h3><a name="lua_isthread"><code>lua_isthread</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_isthread (lua_State *L, int index);</pre> + +<p> +Returns 1 if the value at the given index is a thread, +and 0 otherwise. + + + + + +<hr><h3><a name="lua_isuserdata"><code>lua_isuserdata</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_isuserdata (lua_State *L, int index);</pre> + +<p> +Returns 1 if the value at the given index is a userdata +(either full or light), and 0 otherwise. + + + + + +<hr><h3><a name="lua_isyieldable"><code>lua_isyieldable</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_isyieldable (lua_State *L);</pre> + +<p> +Returns 1 if the given coroutine can yield, +and 0 otherwise. + + + + + +<hr><h3><a name="lua_KContext"><code>lua_KContext</code></a></h3> +<pre>typedef ... lua_KContext;</pre> + +<p> +The type for continuation-function contexts. +It must be a numeric type. +This type is defined as <code>intptr_t</code> +when <code>intptr_t</code> is available, +so that it can store pointers too. +Otherwise, it is defined as <code>ptrdiff_t</code>. + + + + + +<hr><h3><a name="lua_KFunction"><code>lua_KFunction</code></a></h3> +<pre>typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);</pre> + +<p> +Type for continuation functions (see <a href="#4.5">§4.5</a>). + + + + + +<hr><h3><a name="lua_len"><code>lua_len</code></a></h3><p> +<span class="apii">[-0, +1, <em>e</em>]</span> +<pre>void lua_len (lua_State *L, int index);</pre> + +<p> +Returns the length of the value at the given index. +It is equivalent to the '<code>#</code>' operator in Lua (see <a href="#3.4.7">§3.4.7</a>) and +may trigger a metamethod for the "length" event (see <a href="#2.4">§2.4</a>). +The result is pushed on the stack. + + + + + +<hr><h3><a name="lua_load"><code>lua_load</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>int lua_load (lua_State *L, + lua_Reader reader, + void *data, + const char *chunkname, + const char *mode);</pre> + +<p> +Loads a Lua chunk without running it. +If there are no errors, +<code>lua_load</code> pushes the compiled chunk as a Lua +function on top of the stack. +Otherwise, it pushes an error message. + + +<p> +The <code>lua_load</code> function uses a user-supplied <code>reader</code> function +to read the chunk (see <a href="#lua_Reader"><code>lua_Reader</code></a>). +The <code>data</code> argument is an opaque value passed to the reader function. + + +<p> +The <code>chunkname</code> argument gives a name to the chunk, +which is used for error messages and in debug information (see <a href="#4.7">§4.7</a>). + + +<p> +<code>lua_load</code> automatically detects whether the chunk is text or binary +and loads it accordingly (see program <code>luac</code>). +The string <code>mode</code> works as in function <a href="#pdf-load"><code>load</code></a>, +with the addition that +a <code>NULL</code> value is equivalent to the string "<code>bt</code>". + + +<p> +<code>lua_load</code> uses the stack internally, +so the reader function must always leave the stack +unmodified when returning. + + +<p> +<code>lua_load</code> can return +<a href="#pdf-LUA_OK"><code>LUA_OK</code></a>, <a href="#pdf-LUA_ERRSYNTAX"><code>LUA_ERRSYNTAX</code></a>, or <a href="#pdf-LUA_ERRMEM"><code>LUA_ERRMEM</code></a>. +The function may also return other values corresponding to +errors raised by the read function (see <a href="#4.4.1">§4.4.1</a>). + + +<p> +If the resulting function has upvalues, +its first upvalue is set to the value of the global environment +stored at index <code>LUA_RIDX_GLOBALS</code> in the registry (see <a href="#4.3">§4.3</a>). +When loading main chunks, +this upvalue will be the <code>_ENV</code> variable (see <a href="#2.2">§2.2</a>). +Other upvalues are initialized with <b>nil</b>. + + + + + +<hr><h3><a name="lua_newstate"><code>lua_newstate</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>lua_State *lua_newstate (lua_Alloc f, void *ud);</pre> + +<p> +Creates a new independent state and returns its main thread. +Returns <code>NULL</code> if it cannot create the state +(due to lack of memory). +The argument <code>f</code> is the allocator function; +Lua will do all memory allocation for this state +through this function (see <a href="#lua_Alloc"><code>lua_Alloc</code></a>). +The second argument, <code>ud</code>, is an opaque pointer that Lua +passes to the allocator in every call. + + + + + +<hr><h3><a name="lua_newtable"><code>lua_newtable</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>void lua_newtable (lua_State *L);</pre> + +<p> +Creates a new empty table and pushes it onto the stack. +It is equivalent to <code>lua_createtable(L, 0, 0)</code>. + + + + + +<hr><h3><a name="lua_newthread"><code>lua_newthread</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>lua_State *lua_newthread (lua_State *L);</pre> + +<p> +Creates a new thread, pushes it on the stack, +and returns a pointer to a <a href="#lua_State"><code>lua_State</code></a> that represents this new thread. +The new thread returned by this function shares with the original thread +its global environment, +but has an independent execution stack. + + +<p> +Threads are subject to garbage collection, +like any Lua object. + + + + + +<hr><h3><a name="lua_newuserdatauv"><code>lua_newuserdatauv</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue);</pre> + +<p> +This function creates and pushes on the stack a new full userdata, +with <code>nuvalue</code> associated Lua values, called <code>user values</code>, +plus an associated block of raw memory with <code>size</code> bytes. +(The user values can be set and read with the functions +<a href="#lua_setiuservalue"><code>lua_setiuservalue</code></a> and <a href="#lua_getiuservalue"><code>lua_getiuservalue</code></a>.) + + +<p> +The function returns the address of the block of memory. +Lua ensures that this address is valid as long as +the corresponding userdata is alive (see <a href="#2.5">§2.5</a>). +Moreover, if the userdata is marked for finalization (see <a href="#2.5.3">§2.5.3</a>), +its address is valid at least until the call to its finalizer. + + + + + +<hr><h3><a name="lua_next"><code>lua_next</code></a></h3><p> +<span class="apii">[-1, +(2|0), <em>v</em>]</span> +<pre>int lua_next (lua_State *L, int index);</pre> + +<p> +Pops a key from the stack, +and pushes a key–value pair from the table at the given index, +the "next" pair after the given key. +If there are no more elements in the table, +then <a href="#lua_next"><code>lua_next</code></a> returns 0 and pushes nothing. + + +<p> +A typical table traversal looks like this: + +<pre> + /* table is in the stack at index 't' */ + lua_pushnil(L); /* first key */ + while (lua_next(L, t) != 0) { + /* uses 'key' (at index -2) and 'value' (at index -1) */ + printf("%s - %s\n", + lua_typename(L, lua_type(L, -2)), + lua_typename(L, lua_type(L, -1))); + /* removes 'value'; keeps 'key' for next iteration */ + lua_pop(L, 1); + } +</pre> + +<p> +While traversing a table, +avoid calling <a href="#lua_tolstring"><code>lua_tolstring</code></a> directly on a key, +unless you know that the key is actually a string. +Recall that <a href="#lua_tolstring"><code>lua_tolstring</code></a> may change +the value at the given index; +this confuses the next call to <a href="#lua_next"><code>lua_next</code></a>. + + +<p> +This function may raise an error if the given key +is neither <b>nil</b> nor present in the table. +See function <a href="#pdf-next"><code>next</code></a> for the caveats of modifying +the table during its traversal. + + + + + +<hr><h3><a name="lua_Number"><code>lua_Number</code></a></h3> +<pre>typedef ... lua_Number;</pre> + +<p> +The type of floats in Lua. + + +<p> +By default this type is double, +but that can be changed to a single float or a long double. +(See <code>LUA_FLOAT_TYPE</code> in <code>luaconf.h</code>.) + + + + + +<hr><h3><a name="lua_numbertointeger"><code>lua_numbertointeger</code></a></h3> +<pre>int lua_numbertointeger (lua_Number n, lua_Integer *p);</pre> + +<p> +Tries to convert a Lua float to a Lua integer; +the float <code>n</code> must have an integral value. +If that value is within the range of Lua integers, +it is converted to an integer and assigned to <code>*p</code>. +The macro results in a boolean indicating whether the +conversion was successful. +(Note that this range test can be tricky to do +correctly without this macro, due to rounding.) + + +<p> +This macro may evaluate its arguments more than once. + + + + + +<hr><h3><a name="lua_pcall"><code>lua_pcall</code></a></h3><p> +<span class="apii">[-(nargs + 1), +(nresults|1), –]</span> +<pre>int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);</pre> + +<p> +Calls a function (or a callable object) in protected mode. + + +<p> +Both <code>nargs</code> and <code>nresults</code> have the same meaning as +in <a href="#lua_call"><code>lua_call</code></a>. +If there are no errors during the call, +<a href="#lua_pcall"><code>lua_pcall</code></a> behaves exactly like <a href="#lua_call"><code>lua_call</code></a>. +However, if there is any error, +<a href="#lua_pcall"><code>lua_pcall</code></a> catches it, +pushes a single value on the stack (the error object), +and returns an error code. +Like <a href="#lua_call"><code>lua_call</code></a>, +<a href="#lua_pcall"><code>lua_pcall</code></a> always removes the function +and its arguments from the stack. + + +<p> +If <code>msgh</code> is 0, +then the error object returned on the stack +is exactly the original error object. +Otherwise, <code>msgh</code> is the stack index of a +<em>message handler</em>. +(This index cannot be a pseudo-index.) +In case of runtime errors, +this handler will be called with the error object +and its return value will be the object +returned on the stack by <a href="#lua_pcall"><code>lua_pcall</code></a>. + + +<p> +Typically, the message handler is used to add more debug +information to the error object, such as a stack traceback. +Such information cannot be gathered after the return of <a href="#lua_pcall"><code>lua_pcall</code></a>, +since by then the stack has unwound. + + +<p> +The <a href="#lua_pcall"><code>lua_pcall</code></a> function returns one of the following status codes: +<a href="#pdf-LUA_OK"><code>LUA_OK</code></a>, <a href="#pdf-LUA_ERRRUN"><code>LUA_ERRRUN</code></a>, <a href="#pdf-LUA_ERRMEM"><code>LUA_ERRMEM</code></a>, or <a href="#pdf-LUA_ERRERR"><code>LUA_ERRERR</code></a>. + + + + + +<hr><h3><a name="lua_pcallk"><code>lua_pcallk</code></a></h3><p> +<span class="apii">[-(nargs + 1), +(nresults|1), –]</span> +<pre>int lua_pcallk (lua_State *L, + int nargs, + int nresults, + int msgh, + lua_KContext ctx, + lua_KFunction k);</pre> + +<p> +This function behaves exactly like <a href="#lua_pcall"><code>lua_pcall</code></a>, +except that it allows the called function to yield (see <a href="#4.5">§4.5</a>). + + + + + +<hr><h3><a name="lua_pop"><code>lua_pop</code></a></h3><p> +<span class="apii">[-n, +0, <em>e</em>]</span> +<pre>void lua_pop (lua_State *L, int n);</pre> + +<p> +Pops <code>n</code> elements from the stack. +It is implemented as a macro over <a href="#lua_settop"><code>lua_settop</code></a>. + + + + + +<hr><h3><a name="lua_pushboolean"><code>lua_pushboolean</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>void lua_pushboolean (lua_State *L, int b);</pre> + +<p> +Pushes a boolean value with value <code>b</code> onto the stack. + + + + + +<hr><h3><a name="lua_pushcclosure"><code>lua_pushcclosure</code></a></h3><p> +<span class="apii">[-n, +1, <em>m</em>]</span> +<pre>void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);</pre> + +<p> +Pushes a new C closure onto the stack. +This function receives a pointer to a C function +and pushes onto the stack a Lua value of type <code>function</code> that, +when called, invokes the corresponding C function. +The parameter <code>n</code> tells how many upvalues this function will have +(see <a href="#4.2">§4.2</a>). + + +<p> +Any function to be callable by Lua must +follow the correct protocol to receive its parameters +and return its results (see <a href="#lua_CFunction"><code>lua_CFunction</code></a>). + + +<p> +When a C function is created, +it is possible to associate some values with it, +the so called upvalues; +these upvalues are then accessible to the function whenever it is called. +This association is called a C closure (see <a href="#4.2">§4.2</a>). +To create a C closure, +first the initial values for its upvalues must be pushed onto the stack. +(When there are multiple upvalues, the first value is pushed first.) +Then <a href="#lua_pushcclosure"><code>lua_pushcclosure</code></a> +is called to create and push the C function onto the stack, +with the argument <code>n</code> telling how many values will be +associated with the function. +<a href="#lua_pushcclosure"><code>lua_pushcclosure</code></a> also pops these values from the stack. + + +<p> +The maximum value for <code>n</code> is 255. + + +<p> +When <code>n</code> is zero, +this function creates a <em>light C function</em>, +which is just a pointer to the C function. +In that case, it never raises a memory error. + + + + + +<hr><h3><a name="lua_pushcfunction"><code>lua_pushcfunction</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>void lua_pushcfunction (lua_State *L, lua_CFunction f);</pre> + +<p> +Pushes a C function onto the stack. +This function is equivalent to <a href="#lua_pushcclosure"><code>lua_pushcclosure</code></a> with no upvalues. + + + + + +<hr><h3><a name="lua_pushfstring"><code>lua_pushfstring</code></a></h3><p> +<span class="apii">[-0, +1, <em>v</em>]</span> +<pre>const char *lua_pushfstring (lua_State *L, const char *fmt, ...);</pre> + +<p> +Pushes onto the stack a formatted string +and returns a pointer to this string (see <a href="#4.1.3">§4.1.3</a>). +It is similar to the ISO C function <code>sprintf</code>, +but has two important differences. +First, +you do not have to allocate space for the result; +the result is a Lua string and Lua takes care of memory allocation +(and deallocation, through garbage collection). +Second, +the conversion specifiers are quite restricted. +There are no flags, widths, or precisions. +The conversion specifiers can only be +'<code>%%</code>' (inserts the character '<code>%</code>'), +'<code>%s</code>' (inserts a zero-terminated string, with no size restrictions), +'<code>%f</code>' (inserts a <a href="#lua_Number"><code>lua_Number</code></a>), +'<code>%I</code>' (inserts a <a href="#lua_Integer"><code>lua_Integer</code></a>), +'<code>%p</code>' (inserts a pointer), +'<code>%d</code>' (inserts an <code>int</code>), +'<code>%c</code>' (inserts an <code>int</code> as a one-byte character), and +'<code>%U</code>' (inserts a <code>long int</code> as a UTF-8 byte sequence). + + +<p> +This function may raise errors due to memory overflow +or an invalid conversion specifier. + + + + + +<hr><h3><a name="lua_pushglobaltable"><code>lua_pushglobaltable</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>void lua_pushglobaltable (lua_State *L);</pre> + +<p> +Pushes the global environment onto the stack. + + + + + +<hr><h3><a name="lua_pushinteger"><code>lua_pushinteger</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>void lua_pushinteger (lua_State *L, lua_Integer n);</pre> + +<p> +Pushes an integer with value <code>n</code> onto the stack. + + + + + +<hr><h3><a name="lua_pushlightuserdata"><code>lua_pushlightuserdata</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>void lua_pushlightuserdata (lua_State *L, void *p);</pre> + +<p> +Pushes a light userdata onto the stack. + + +<p> +Userdata represent C values in Lua. +A <em>light userdata</em> represents a pointer, a <code>void*</code>. +It is a value (like a number): +you do not create it, it has no individual metatable, +and it is not collected (as it was never created). +A light userdata is equal to "any" +light userdata with the same C address. + + + + + +<hr><h3><a name="lua_pushliteral"><code>lua_pushliteral</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>const char *lua_pushliteral (lua_State *L, const char *s);</pre> + +<p> +This macro is equivalent to <a href="#lua_pushstring"><code>lua_pushstring</code></a>, +but should be used only when <code>s</code> is a literal string. +(Lua may optimize this case.) + + + + + +<hr><h3><a name="lua_pushlstring"><code>lua_pushlstring</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>const char *lua_pushlstring (lua_State *L, const char *s, size_t len);</pre> + +<p> +Pushes the string pointed to by <code>s</code> with size <code>len</code> +onto the stack. +Lua will make or reuse an internal copy of the given string, +so the memory at <code>s</code> can be freed or reused immediately after +the function returns. +The string can contain any binary data, +including embedded zeros. + + +<p> +Returns a pointer to the internal copy of the string (see <a href="#4.1.3">§4.1.3</a>). + + + + + +<hr><h3><a name="lua_pushnil"><code>lua_pushnil</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>void lua_pushnil (lua_State *L);</pre> + +<p> +Pushes a nil value onto the stack. + + + + + +<hr><h3><a name="lua_pushnumber"><code>lua_pushnumber</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>void lua_pushnumber (lua_State *L, lua_Number n);</pre> + +<p> +Pushes a float with value <code>n</code> onto the stack. + + + + + +<hr><h3><a name="lua_pushstring"><code>lua_pushstring</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>const char *lua_pushstring (lua_State *L, const char *s);</pre> + +<p> +Pushes the zero-terminated string pointed to by <code>s</code> +onto the stack. +Lua will make or reuse an internal copy of the given string, +so the memory at <code>s</code> can be freed or reused immediately after +the function returns. + + +<p> +Returns a pointer to the internal copy of the string (see <a href="#4.1.3">§4.1.3</a>). + + +<p> +If <code>s</code> is <code>NULL</code>, pushes <b>nil</b> and returns <code>NULL</code>. + + + + + +<hr><h3><a name="lua_pushthread"><code>lua_pushthread</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>int lua_pushthread (lua_State *L);</pre> + +<p> +Pushes the thread represented by <code>L</code> onto the stack. +Returns 1 if this thread is the main thread of its state. + + + + + +<hr><h3><a name="lua_pushvalue"><code>lua_pushvalue</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>void lua_pushvalue (lua_State *L, int index);</pre> + +<p> +Pushes a copy of the element at the given index +onto the stack. + + + + + +<hr><h3><a name="lua_pushvfstring"><code>lua_pushvfstring</code></a></h3><p> +<span class="apii">[-0, +1, <em>v</em>]</span> +<pre>const char *lua_pushvfstring (lua_State *L, + const char *fmt, + va_list argp);</pre> + +<p> +Equivalent to <a href="#lua_pushfstring"><code>lua_pushfstring</code></a>, except that it receives a <code>va_list</code> +instead of a variable number of arguments. + + + + + +<hr><h3><a name="lua_rawequal"><code>lua_rawequal</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_rawequal (lua_State *L, int index1, int index2);</pre> + +<p> +Returns 1 if the two values in indices <code>index1</code> and +<code>index2</code> are primitively equal +(that is, equal without calling the <code>__eq</code> metamethod). +Otherwise returns 0. +Also returns 0 if any of the indices are not valid. + + + + + +<hr><h3><a name="lua_rawget"><code>lua_rawget</code></a></h3><p> +<span class="apii">[-1, +1, –]</span> +<pre>int lua_rawget (lua_State *L, int index);</pre> + +<p> +Similar to <a href="#lua_gettable"><code>lua_gettable</code></a>, but does a raw access +(i.e., without metamethods). +The value at <code>index</code> must be a table. + + + + + +<hr><h3><a name="lua_rawgeti"><code>lua_rawgeti</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>int lua_rawgeti (lua_State *L, int index, lua_Integer n);</pre> + +<p> +Pushes onto the stack the value <code>t[n]</code>, +where <code>t</code> is the table at the given index. +The access is raw, +that is, it does not use the <code>__index</code> metavalue. + + +<p> +Returns the type of the pushed value. + + + + + +<hr><h3><a name="lua_rawgetp"><code>lua_rawgetp</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>int lua_rawgetp (lua_State *L, int index, const void *p);</pre> + +<p> +Pushes onto the stack the value <code>t[k]</code>, +where <code>t</code> is the table at the given index and +<code>k</code> is the pointer <code>p</code> represented as a light userdata. +The access is raw; +that is, it does not use the <code>__index</code> metavalue. + + +<p> +Returns the type of the pushed value. + + + + + +<hr><h3><a name="lua_rawlen"><code>lua_rawlen</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>lua_Unsigned lua_rawlen (lua_State *L, int index);</pre> + +<p> +Returns the raw "length" of the value at the given index: +for strings, this is the string length; +for tables, this is the result of the length operator ('<code>#</code>') +with no metamethods; +for userdata, this is the size of the block of memory allocated +for the userdata. +For other values, this call returns 0. + + + + + +<hr><h3><a name="lua_rawset"><code>lua_rawset</code></a></h3><p> +<span class="apii">[-2, +0, <em>m</em>]</span> +<pre>void lua_rawset (lua_State *L, int index);</pre> + +<p> +Similar to <a href="#lua_settable"><code>lua_settable</code></a>, but does a raw assignment +(i.e., without metamethods). +The value at <code>index</code> must be a table. + + + + + +<hr><h3><a name="lua_rawseti"><code>lua_rawseti</code></a></h3><p> +<span class="apii">[-1, +0, <em>m</em>]</span> +<pre>void lua_rawseti (lua_State *L, int index, lua_Integer i);</pre> + +<p> +Does the equivalent of <code>t[i] = v</code>, +where <code>t</code> is the table at the given index +and <code>v</code> is the value on the top of the stack. + + +<p> +This function pops the value from the stack. +The assignment is raw, +that is, it does not use the <code>__newindex</code> metavalue. + + + + + +<hr><h3><a name="lua_rawsetp"><code>lua_rawsetp</code></a></h3><p> +<span class="apii">[-1, +0, <em>m</em>]</span> +<pre>void lua_rawsetp (lua_State *L, int index, const void *p);</pre> + +<p> +Does the equivalent of <code>t[p] = v</code>, +where <code>t</code> is the table at the given index, +<code>p</code> is encoded as a light userdata, +and <code>v</code> is the value on the top of the stack. + + +<p> +This function pops the value from the stack. +The assignment is raw, +that is, it does not use the <code>__newindex</code> metavalue. + + + + + +<hr><h3><a name="lua_Reader"><code>lua_Reader</code></a></h3> +<pre>typedef const char * (*lua_Reader) (lua_State *L, + void *data, + size_t *size);</pre> + +<p> +The reader function used by <a href="#lua_load"><code>lua_load</code></a>. +Every time <a href="#lua_load"><code>lua_load</code></a> needs another piece of the chunk, +it calls the reader, +passing along its <code>data</code> parameter. +The reader must return a pointer to a block of memory +with a new piece of the chunk +and set <code>size</code> to the block size. +The block must exist until the reader function is called again. +To signal the end of the chunk, +the reader must return <code>NULL</code> or set <code>size</code> to zero. +The reader function may return pieces of any size greater than zero. + + + + + +<hr><h3><a name="lua_register"><code>lua_register</code></a></h3><p> +<span class="apii">[-0, +0, <em>e</em>]</span> +<pre>void lua_register (lua_State *L, const char *name, lua_CFunction f);</pre> + +<p> +Sets the C function <code>f</code> as the new value of global <code>name</code>. +It is defined as a macro: + +<pre> + #define lua_register(L,n,f) \ + (lua_pushcfunction(L, f), lua_setglobal(L, n)) +</pre> + + + + +<hr><h3><a name="lua_remove"><code>lua_remove</code></a></h3><p> +<span class="apii">[-1, +0, –]</span> +<pre>void lua_remove (lua_State *L, int index);</pre> + +<p> +Removes the element at the given valid index, +shifting down the elements above this index to fill the gap. +This function cannot be called with a pseudo-index, +because a pseudo-index is not an actual stack position. + + + + + +<hr><h3><a name="lua_replace"><code>lua_replace</code></a></h3><p> +<span class="apii">[-1, +0, –]</span> +<pre>void lua_replace (lua_State *L, int index);</pre> + +<p> +Moves the top element into the given valid index +without shifting any element +(therefore replacing the value at that given index), +and then pops the top element. + + + + + +<hr><h3><a name="lua_resetthread"><code>lua_resetthread</code></a></h3><p> +<span class="apii">[-0, +?, –]</span> +<pre>int lua_resetthread (lua_State *L);</pre> + +<p> +This function is deprecated; +it is equivalent to <a href="#lua_closethread"><code>lua_closethread</code></a> with +<code>from</code> being <code>NULL</code>. + + + + + +<hr><h3><a name="lua_resume"><code>lua_resume</code></a></h3><p> +<span class="apii">[-?, +?, –]</span> +<pre>int lua_resume (lua_State *L, lua_State *from, int nargs, + int *nresults);</pre> + +<p> +Starts and resumes a coroutine in the given thread <code>L</code>. + + +<p> +To start a coroutine, +you push the main function plus any arguments +onto the empty stack of the thread. +then you call <a href="#lua_resume"><code>lua_resume</code></a>, +with <code>nargs</code> being the number of arguments. +This call returns when the coroutine suspends or finishes its execution. +When it returns, +<code>*nresults</code> is updated and +the top of the stack contains +the <code>*nresults</code> values passed to <a href="#lua_yield"><code>lua_yield</code></a> +or returned by the body function. +<a href="#lua_resume"><code>lua_resume</code></a> returns +<a href="#pdf-LUA_YIELD"><code>LUA_YIELD</code></a> if the coroutine yields, +<a href="#pdf-LUA_OK"><code>LUA_OK</code></a> if the coroutine finishes its execution +without errors, +or an error code in case of errors (see <a href="#4.4.1">§4.4.1</a>). +In case of errors, +the error object is on the top of the stack. + + +<p> +To resume a coroutine, +you remove the <code>*nresults</code> yielded values from its stack, +push the values to be passed as results from <code>yield</code>, +and then call <a href="#lua_resume"><code>lua_resume</code></a>. + + +<p> +The parameter <code>from</code> represents the coroutine that is resuming <code>L</code>. +If there is no such coroutine, +this parameter can be <code>NULL</code>. + + + + + +<hr><h3><a name="lua_rotate"><code>lua_rotate</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>void lua_rotate (lua_State *L, int idx, int n);</pre> + +<p> +Rotates the stack elements between the valid index <code>idx</code> +and the top of the stack. +The elements are rotated <code>n</code> positions in the direction of the top, +for a positive <code>n</code>, +or <code>-n</code> positions in the direction of the bottom, +for a negative <code>n</code>. +The absolute value of <code>n</code> must not be greater than the size +of the slice being rotated. +This function cannot be called with a pseudo-index, +because a pseudo-index is not an actual stack position. + + + + + +<hr><h3><a name="lua_setallocf"><code>lua_setallocf</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);</pre> + +<p> +Changes the allocator function of a given state to <code>f</code> +with user data <code>ud</code>. + + + + + +<hr><h3><a name="lua_setfield"><code>lua_setfield</code></a></h3><p> +<span class="apii">[-1, +0, <em>e</em>]</span> +<pre>void lua_setfield (lua_State *L, int index, const char *k);</pre> + +<p> +Does the equivalent to <code>t[k] = v</code>, +where <code>t</code> is the value at the given index +and <code>v</code> is the value on the top of the stack. + + +<p> +This function pops the value from the stack. +As in Lua, this function may trigger a metamethod +for the "newindex" event (see <a href="#2.4">§2.4</a>). + + + + + +<hr><h3><a name="lua_setglobal"><code>lua_setglobal</code></a></h3><p> +<span class="apii">[-1, +0, <em>e</em>]</span> +<pre>void lua_setglobal (lua_State *L, const char *name);</pre> + +<p> +Pops a value from the stack and +sets it as the new value of global <code>name</code>. + + + + + +<hr><h3><a name="lua_seti"><code>lua_seti</code></a></h3><p> +<span class="apii">[-1, +0, <em>e</em>]</span> +<pre>void lua_seti (lua_State *L, int index, lua_Integer n);</pre> + +<p> +Does the equivalent to <code>t[n] = v</code>, +where <code>t</code> is the value at the given index +and <code>v</code> is the value on the top of the stack. + + +<p> +This function pops the value from the stack. +As in Lua, this function may trigger a metamethod +for the "newindex" event (see <a href="#2.4">§2.4</a>). + + + + + +<hr><h3><a name="lua_setiuservalue"><code>lua_setiuservalue</code></a></h3><p> +<span class="apii">[-1, +0, –]</span> +<pre>int lua_setiuservalue (lua_State *L, int index, int n);</pre> + +<p> +Pops a value from the stack and sets it as +the new <code>n</code>-th user value associated to the +full userdata at the given index. +Returns 0 if the userdata does not have that value. + + + + + +<hr><h3><a name="lua_setmetatable"><code>lua_setmetatable</code></a></h3><p> +<span class="apii">[-1, +0, –]</span> +<pre>int lua_setmetatable (lua_State *L, int index);</pre> + +<p> +Pops a table or <b>nil</b> from the stack and +sets that value as the new metatable for the value at the given index. +(<b>nil</b> means no metatable.) + + +<p> +(For historical reasons, this function returns an <code>int</code>, +which now is always 1.) + + + + + +<hr><h3><a name="lua_settable"><code>lua_settable</code></a></h3><p> +<span class="apii">[-2, +0, <em>e</em>]</span> +<pre>void lua_settable (lua_State *L, int index);</pre> + +<p> +Does the equivalent to <code>t[k] = v</code>, +where <code>t</code> is the value at the given index, +<code>v</code> is the value on the top of the stack, +and <code>k</code> is the value just below the top. + + +<p> +This function pops both the key and the value from the stack. +As in Lua, this function may trigger a metamethod +for the "newindex" event (see <a href="#2.4">§2.4</a>). + + + + + +<hr><h3><a name="lua_settop"><code>lua_settop</code></a></h3><p> +<span class="apii">[-?, +?, <em>e</em>]</span> +<pre>void lua_settop (lua_State *L, int index);</pre> + +<p> +Accepts any index, or 0, +and sets the stack top to this index. +If the new top is greater than the old one, +then the new elements are filled with <b>nil</b>. +If <code>index</code> is 0, then all stack elements are removed. + + +<p> +This function can run arbitrary code when removing an index +marked as to-be-closed from the stack. + + + + + +<hr><h3><a name="lua_setwarnf"><code>lua_setwarnf</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>void lua_setwarnf (lua_State *L, lua_WarnFunction f, void *ud);</pre> + +<p> +Sets the warning function to be used by Lua to emit warnings +(see <a href="#lua_WarnFunction"><code>lua_WarnFunction</code></a>). +The <code>ud</code> parameter sets the value <code>ud</code> passed to +the warning function. + + + + + +<hr><h3><a name="lua_State"><code>lua_State</code></a></h3> +<pre>typedef struct lua_State lua_State;</pre> + +<p> +An opaque structure that points to a thread and indirectly +(through the thread) to the whole state of a Lua interpreter. +The Lua library is fully reentrant: +it has no global variables. +All information about a state is accessible through this structure. + + +<p> +A pointer to this structure must be passed as the first argument to +every function in the library, except to <a href="#lua_newstate"><code>lua_newstate</code></a>, +which creates a Lua state from scratch. + + + + + +<hr><h3><a name="lua_status"><code>lua_status</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_status (lua_State *L);</pre> + +<p> +Returns the status of the thread <code>L</code>. + + +<p> +The status can be <a href="#pdf-LUA_OK"><code>LUA_OK</code></a> for a normal thread, +an error code if the thread finished the execution +of a <a href="#lua_resume"><code>lua_resume</code></a> with an error, +or <a href="#pdf-LUA_YIELD"><code>LUA_YIELD</code></a> if the thread is suspended. + + +<p> +You can call functions only in threads with status <a href="#pdf-LUA_OK"><code>LUA_OK</code></a>. +You can resume threads with status <a href="#pdf-LUA_OK"><code>LUA_OK</code></a> +(to start a new coroutine) or <a href="#pdf-LUA_YIELD"><code>LUA_YIELD</code></a> +(to resume a coroutine). + + + + + +<hr><h3><a name="lua_stringtonumber"><code>lua_stringtonumber</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>size_t lua_stringtonumber (lua_State *L, const char *s);</pre> + +<p> +Converts the zero-terminated string <code>s</code> to a number, +pushes that number into the stack, +and returns the total size of the string, +that is, its length plus one. +The conversion can result in an integer or a float, +according to the lexical conventions of Lua (see <a href="#3.1">§3.1</a>). +The string may have leading and trailing whitespaces and a sign. +If the string is not a valid numeral, +returns 0 and pushes nothing. +(Note that the result can be used as a boolean, +true if the conversion succeeds.) + + + + + +<hr><h3><a name="lua_toboolean"><code>lua_toboolean</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_toboolean (lua_State *L, int index);</pre> + +<p> +Converts the Lua value at the given index to a C boolean +value (0 or 1). +Like all tests in Lua, +<a href="#lua_toboolean"><code>lua_toboolean</code></a> returns true for any Lua value +different from <b>false</b> and <b>nil</b>; +otherwise it returns false. +(If you want to accept only actual boolean values, +use <a href="#lua_isboolean"><code>lua_isboolean</code></a> to test the value's type.) + + + + + +<hr><h3><a name="lua_tocfunction"><code>lua_tocfunction</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>lua_CFunction lua_tocfunction (lua_State *L, int index);</pre> + +<p> +Converts a value at the given index to a C function. +That value must be a C function; +otherwise, returns <code>NULL</code>. + + + + + +<hr><h3><a name="lua_toclose"><code>lua_toclose</code></a></h3><p> +<span class="apii">[-0, +0, <em>m</em>]</span> +<pre>void lua_toclose (lua_State *L, int index);</pre> + +<p> +Marks the given index in the stack as a +to-be-closed slot (see <a href="#3.3.8">§3.3.8</a>). +Like a to-be-closed variable in Lua, +the value at that slot in the stack will be closed +when it goes out of scope. +Here, in the context of a C function, +to go out of scope means that the running function returns to Lua, +or there is an error, +or the slot is removed from the stack through +<a href="#lua_settop"><code>lua_settop</code></a> or <a href="#lua_pop"><code>lua_pop</code></a>, +or there is a call to <a href="#lua_closeslot"><code>lua_closeslot</code></a>. +A slot marked as to-be-closed should not be removed from the stack +by any other function in the API except <a href="#lua_settop"><code>lua_settop</code></a> or <a href="#lua_pop"><code>lua_pop</code></a>, +unless previously deactivated by <a href="#lua_closeslot"><code>lua_closeslot</code></a>. + + +<p> +This function should not be called for an index +that is equal to or below an active to-be-closed slot. + + +<p> +Note that, both in case of errors and of a regular return, +by the time the <code>__close</code> metamethod runs, +the C stack was already unwound, +so that any automatic C variable declared in the calling function +(e.g., a buffer) will be out of scope. + + + + + +<hr><h3><a name="lua_tointeger"><code>lua_tointeger</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>lua_Integer lua_tointeger (lua_State *L, int index);</pre> + +<p> +Equivalent to <a href="#lua_tointegerx"><code>lua_tointegerx</code></a> with <code>isnum</code> equal to <code>NULL</code>. + + + + + +<hr><h3><a name="lua_tointegerx"><code>lua_tointegerx</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>lua_Integer lua_tointegerx (lua_State *L, int index, int *isnum);</pre> + +<p> +Converts the Lua value at the given index +to the signed integral type <a href="#lua_Integer"><code>lua_Integer</code></a>. +The Lua value must be an integer, +or a number or string convertible to an integer (see <a href="#3.4.3">§3.4.3</a>); +otherwise, <code>lua_tointegerx</code> returns 0. + + +<p> +If <code>isnum</code> is not <code>NULL</code>, +its referent is assigned a boolean value that +indicates whether the operation succeeded. + + + + + +<hr><h3><a name="lua_tolstring"><code>lua_tolstring</code></a></h3><p> +<span class="apii">[-0, +0, <em>m</em>]</span> +<pre>const char *lua_tolstring (lua_State *L, int index, size_t *len);</pre> + +<p> +Converts the Lua value at the given index to a C string. +If <code>len</code> is not <code>NULL</code>, +it sets <code>*len</code> with the string length. +The Lua value must be a string or a number; +otherwise, the function returns <code>NULL</code>. +If the value is a number, +then <code>lua_tolstring</code> also +<em>changes the actual value in the stack to a string</em>. +(This change confuses <a href="#lua_next"><code>lua_next</code></a> +when <code>lua_tolstring</code> is applied to keys during a table traversal.) + + +<p> +<code>lua_tolstring</code> returns a pointer +to a string inside the Lua state (see <a href="#4.1.3">§4.1.3</a>). +This string always has a zero ('<code>\0</code>') +after its last character (as in C), +but can contain other zeros in its body. + + + + + +<hr><h3><a name="lua_tonumber"><code>lua_tonumber</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>lua_Number lua_tonumber (lua_State *L, int index);</pre> + +<p> +Equivalent to <a href="#lua_tonumberx"><code>lua_tonumberx</code></a> with <code>isnum</code> equal to <code>NULL</code>. + + + + + +<hr><h3><a name="lua_tonumberx"><code>lua_tonumberx</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>lua_Number lua_tonumberx (lua_State *L, int index, int *isnum);</pre> + +<p> +Converts the Lua value at the given index +to the C type <a href="#lua_Number"><code>lua_Number</code></a> (see <a href="#lua_Number"><code>lua_Number</code></a>). +The Lua value must be a number or a string convertible to a number +(see <a href="#3.4.3">§3.4.3</a>); +otherwise, <a href="#lua_tonumberx"><code>lua_tonumberx</code></a> returns 0. + + +<p> +If <code>isnum</code> is not <code>NULL</code>, +its referent is assigned a boolean value that +indicates whether the operation succeeded. + + + + + +<hr><h3><a name="lua_topointer"><code>lua_topointer</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>const void *lua_topointer (lua_State *L, int index);</pre> + +<p> +Converts the value at the given index to a generic +C pointer (<code>void*</code>). +The value can be a userdata, a table, a thread, a string, or a function; +otherwise, <code>lua_topointer</code> returns <code>NULL</code>. +Different objects will give different pointers. +There is no way to convert the pointer back to its original value. + + +<p> +Typically this function is used only for hashing and debug information. + + + + + +<hr><h3><a name="lua_tostring"><code>lua_tostring</code></a></h3><p> +<span class="apii">[-0, +0, <em>m</em>]</span> +<pre>const char *lua_tostring (lua_State *L, int index);</pre> + +<p> +Equivalent to <a href="#lua_tolstring"><code>lua_tolstring</code></a> with <code>len</code> equal to <code>NULL</code>. + + + + + +<hr><h3><a name="lua_tothread"><code>lua_tothread</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>lua_State *lua_tothread (lua_State *L, int index);</pre> + +<p> +Converts the value at the given index to a Lua thread +(represented as <code>lua_State*</code>). +This value must be a thread; +otherwise, the function returns <code>NULL</code>. + + + + + +<hr><h3><a name="lua_touserdata"><code>lua_touserdata</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>void *lua_touserdata (lua_State *L, int index);</pre> + +<p> +If the value at the given index is a full userdata, +returns its memory-block address. +If the value is a light userdata, +returns its value (a pointer). +Otherwise, returns <code>NULL</code>. + + + + + +<hr><h3><a name="lua_type"><code>lua_type</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_type (lua_State *L, int index);</pre> + +<p> +Returns the type of the value in the given valid index, +or <code>LUA_TNONE</code> for a non-valid but acceptable index. +The types returned by <a href="#lua_type"><code>lua_type</code></a> are coded by the following constants +defined in <code>lua.h</code>: +<a name="pdf-LUA_TNIL"><code>LUA_TNIL</code></a>, +<a name="pdf-LUA_TNUMBER"><code>LUA_TNUMBER</code></a>, +<a name="pdf-LUA_TBOOLEAN"><code>LUA_TBOOLEAN</code></a>, +<a name="pdf-LUA_TSTRING"><code>LUA_TSTRING</code></a>, +<a name="pdf-LUA_TTABLE"><code>LUA_TTABLE</code></a>, +<a name="pdf-LUA_TFUNCTION"><code>LUA_TFUNCTION</code></a>, +<a name="pdf-LUA_TUSERDATA"><code>LUA_TUSERDATA</code></a>, +<a name="pdf-LUA_TTHREAD"><code>LUA_TTHREAD</code></a>, +and +<a name="pdf-LUA_TLIGHTUSERDATA"><code>LUA_TLIGHTUSERDATA</code></a>. + + + + + +<hr><h3><a name="lua_typename"><code>lua_typename</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>const char *lua_typename (lua_State *L, int tp);</pre> + +<p> +Returns the name of the type encoded by the value <code>tp</code>, +which must be one the values returned by <a href="#lua_type"><code>lua_type</code></a>. + + + + + +<hr><h3><a name="lua_Unsigned"><code>lua_Unsigned</code></a></h3> +<pre>typedef ... lua_Unsigned;</pre> + +<p> +The unsigned version of <a href="#lua_Integer"><code>lua_Integer</code></a>. + + + + + +<hr><h3><a name="lua_upvalueindex"><code>lua_upvalueindex</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_upvalueindex (int i);</pre> + +<p> +Returns the pseudo-index that represents the <code>i</code>-th upvalue of +the running function (see <a href="#4.2">§4.2</a>). +<code>i</code> must be in the range <em>[1,256]</em>. + + + + + +<hr><h3><a name="lua_version"><code>lua_version</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>lua_Number lua_version (lua_State *L);</pre> + +<p> +Returns the version number of this core. + + + + + +<hr><h3><a name="lua_WarnFunction"><code>lua_WarnFunction</code></a></h3> +<pre>typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);</pre> + +<p> +The type of warning functions, called by Lua to emit warnings. +The first parameter is an opaque pointer +set by <a href="#lua_setwarnf"><code>lua_setwarnf</code></a>. +The second parameter is the warning message. +The third parameter is a boolean that +indicates whether the message is +to be continued by the message in the next call. + + +<p> +See <a href="#pdf-warn"><code>warn</code></a> for more details about warnings. + + + + + +<hr><h3><a name="lua_warning"><code>lua_warning</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>void lua_warning (lua_State *L, const char *msg, int tocont);</pre> + +<p> +Emits a warning with the given message. +A message in a call with <code>tocont</code> true should be +continued in another call to this function. + + +<p> +See <a href="#pdf-warn"><code>warn</code></a> for more details about warnings. + + + + + +<hr><h3><a name="lua_Writer"><code>lua_Writer</code></a></h3> +<pre>typedef int (*lua_Writer) (lua_State *L, + const void* p, + size_t sz, + void* ud);</pre> + +<p> +The type of the writer function used by <a href="#lua_dump"><code>lua_dump</code></a>. +Every time <a href="#lua_dump"><code>lua_dump</code></a> produces another piece of chunk, +it calls the writer, +passing along the buffer to be written (<code>p</code>), +its size (<code>sz</code>), +and the <code>ud</code> parameter supplied to <a href="#lua_dump"><code>lua_dump</code></a>. + + +<p> +The writer returns an error code: +0 means no errors; +any other value means an error and stops <a href="#lua_dump"><code>lua_dump</code></a> from +calling the writer again. + + + + + +<hr><h3><a name="lua_xmove"><code>lua_xmove</code></a></h3><p> +<span class="apii">[-?, +?, –]</span> +<pre>void lua_xmove (lua_State *from, lua_State *to, int n);</pre> + +<p> +Exchange values between different threads of the same state. + + +<p> +This function pops <code>n</code> values from the stack <code>from</code>, +and pushes them onto the stack <code>to</code>. + + + + + +<hr><h3><a name="lua_yield"><code>lua_yield</code></a></h3><p> +<span class="apii">[-?, +?, <em>v</em>]</span> +<pre>int lua_yield (lua_State *L, int nresults);</pre> + +<p> +This function is equivalent to <a href="#lua_yieldk"><code>lua_yieldk</code></a>, +but it has no continuation (see <a href="#4.5">§4.5</a>). +Therefore, when the thread resumes, +it continues the function that called +the function calling <code>lua_yield</code>. +To avoid surprises, +this function should be called only in a tail call. + + + + + +<hr><h3><a name="lua_yieldk"><code>lua_yieldk</code></a></h3><p> +<span class="apii">[-?, +?, <em>v</em>]</span> +<pre>int lua_yieldk (lua_State *L, + int nresults, + lua_KContext ctx, + lua_KFunction k);</pre> + +<p> +Yields a coroutine (thread). + + +<p> +When a C function calls <a href="#lua_yieldk"><code>lua_yieldk</code></a>, +the running coroutine suspends its execution, +and the call to <a href="#lua_resume"><code>lua_resume</code></a> that started this coroutine returns. +The parameter <code>nresults</code> is the number of values from the stack +that will be passed as results to <a href="#lua_resume"><code>lua_resume</code></a>. + + +<p> +When the coroutine is resumed again, +Lua calls the given continuation function <code>k</code> to continue +the execution of the C function that yielded (see <a href="#4.5">§4.5</a>). +This continuation function receives the same stack +from the previous function, +with the <code>n</code> results removed and +replaced by the arguments passed to <a href="#lua_resume"><code>lua_resume</code></a>. +Moreover, +the continuation function receives the value <code>ctx</code> +that was passed to <a href="#lua_yieldk"><code>lua_yieldk</code></a>. + + +<p> +Usually, this function does not return; +when the coroutine eventually resumes, +it continues executing the continuation function. +However, there is one special case, +which is when this function is called +from inside a line or a count hook (see <a href="#4.7">§4.7</a>). +In that case, <code>lua_yieldk</code> should be called with no continuation +(probably in the form of <a href="#lua_yield"><code>lua_yield</code></a>) and no results, +and the hook should return immediately after the call. +Lua will yield and, +when the coroutine resumes again, +it will continue the normal execution +of the (Lua) function that triggered the hook. + + +<p> +This function can raise an error if it is called from a thread +with a pending C call with no continuation function +(what is called a <em>C-call boundary</em>), +or it is called from a thread that is not running inside a resume +(typically the main thread). + + + + + + + +<h2>4.7 – <a name="4.7">The Debug Interface</a></h2> + +<p> +Lua has no built-in debugging facilities. +Instead, it offers a special interface +by means of functions and <em>hooks</em>. +This interface allows the construction of different +kinds of debuggers, profilers, and other tools +that need "inside information" from the interpreter. + + + +<hr><h3><a name="lua_Debug"><code>lua_Debug</code></a></h3> +<pre>typedef struct lua_Debug { + int event; + const char *name; /* (n) */ + const char *namewhat; /* (n) */ + const char *what; /* (S) */ + const char *source; /* (S) */ + size_t srclen; /* (S) */ + int currentline; /* (l) */ + int linedefined; /* (S) */ + int lastlinedefined; /* (S) */ + unsigned char nups; /* (u) number of upvalues */ + unsigned char nparams; /* (u) number of parameters */ + char isvararg; /* (u) */ + char istailcall; /* (t) */ + unsigned short ftransfer; /* (r) index of first value transferred */ + unsigned short ntransfer; /* (r) number of transferred values */ + char short_src[LUA_IDSIZE]; /* (S) */ + /* private part */ + <em>other fields</em> +} lua_Debug;</pre> + +<p> +A structure used to carry different pieces of +information about a function or an activation record. +<a href="#lua_getstack"><code>lua_getstack</code></a> fills only the private part +of this structure, for later use. +To fill the other fields of <a href="#lua_Debug"><code>lua_Debug</code></a> with useful information, +you must call <a href="#lua_getinfo"><code>lua_getinfo</code></a> with an appropriate parameter. +(Specifically, to get a field, +you must add the letter between parentheses in the field's comment +to the parameter <code>what</code> of <a href="#lua_getinfo"><code>lua_getinfo</code></a>.) + + +<p> +The fields of <a href="#lua_Debug"><code>lua_Debug</code></a> have the following meaning: + +<ul> + +<li><b><code>source</code>: </b> +the source of the chunk that created the function. +If <code>source</code> starts with a '<code>@</code>', +it means that the function was defined in a file where +the file name follows the '<code>@</code>'. +If <code>source</code> starts with a '<code>=</code>', +the remainder of its contents describes the source in a user-dependent manner. +Otherwise, +the function was defined in a string where +<code>source</code> is that string. +</li> + +<li><b><code>srclen</code>: </b> +The length of the string <code>source</code>. +</li> + +<li><b><code>short_src</code>: </b> +a "printable" version of <code>source</code>, to be used in error messages. +</li> + +<li><b><code>linedefined</code>: </b> +the line number where the definition of the function starts. +</li> + +<li><b><code>lastlinedefined</code>: </b> +the line number where the definition of the function ends. +</li> + +<li><b><code>what</code>: </b> +the string <code>"Lua"</code> if the function is a Lua function, +<code>"C"</code> if it is a C function, +<code>"main"</code> if it is the main part of a chunk. +</li> + +<li><b><code>currentline</code>: </b> +the current line where the given function is executing. +When no line information is available, +<code>currentline</code> is set to -1. +</li> + +<li><b><code>name</code>: </b> +a reasonable name for the given function. +Because functions in Lua are first-class values, +they do not have a fixed name: +some functions can be the value of multiple global variables, +while others can be stored only in a table field. +The <code>lua_getinfo</code> function checks how the function was +called to find a suitable name. +If it cannot find a name, +then <code>name</code> is set to <code>NULL</code>. +</li> + +<li><b><code>namewhat</code>: </b> +explains the <code>name</code> field. +The value of <code>namewhat</code> can be +<code>"global"</code>, <code>"local"</code>, <code>"method"</code>, +<code>"field"</code>, <code>"upvalue"</code>, or <code>""</code> (the empty string), +according to how the function was called. +(Lua uses the empty string when no other option seems to apply.) +</li> + +<li><b><code>istailcall</code>: </b> +true if this function invocation was called by a tail call. +In this case, the caller of this level is not in the stack. +</li> + +<li><b><code>nups</code>: </b> +the number of upvalues of the function. +</li> + +<li><b><code>nparams</code>: </b> +the number of parameters of the function +(always 0 for C functions). +</li> + +<li><b><code>isvararg</code>: </b> +true if the function is a variadic function +(always true for C functions). +</li> + +<li><b><code>ftransfer</code>: </b> +the index in the stack of the first value being "transferred", +that is, parameters in a call or return values in a return. +(The other values are in consecutive indices.) +Using this index, you can access and modify these values +through <a href="#lua_getlocal"><code>lua_getlocal</code></a> and <a href="#lua_setlocal"><code>lua_setlocal</code></a>. +This field is only meaningful during a +call hook, denoting the first parameter, +or a return hook, denoting the first value being returned. +(For call hooks, this value is always 1.) +</li> + +<li><b><code>ntransfer</code>: </b> +The number of values being transferred (see previous item). +(For calls of Lua functions, +this value is always equal to <code>nparams</code>.) +</li> + +</ul> + + + + +<hr><h3><a name="lua_gethook"><code>lua_gethook</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>lua_Hook lua_gethook (lua_State *L);</pre> + +<p> +Returns the current hook function. + + + + + +<hr><h3><a name="lua_gethookcount"><code>lua_gethookcount</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_gethookcount (lua_State *L);</pre> + +<p> +Returns the current hook count. + + + + + +<hr><h3><a name="lua_gethookmask"><code>lua_gethookmask</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_gethookmask (lua_State *L);</pre> + +<p> +Returns the current hook mask. + + + + + +<hr><h3><a name="lua_getinfo"><code>lua_getinfo</code></a></h3><p> +<span class="apii">[-(0|1), +(0|1|2), <em>m</em>]</span> +<pre>int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);</pre> + +<p> +Gets information about a specific function or function invocation. + + +<p> +To get information about a function invocation, +the parameter <code>ar</code> must be a valid activation record that was +filled by a previous call to <a href="#lua_getstack"><code>lua_getstack</code></a> or +given as argument to a hook (see <a href="#lua_Hook"><code>lua_Hook</code></a>). + + +<p> +To get information about a function, you push it onto the stack +and start the <code>what</code> string with the character '<code>></code>'. +(In that case, +<code>lua_getinfo</code> pops the function from the top of the stack.) +For instance, to know in which line a function <code>f</code> was defined, +you can write the following code: + +<pre> + lua_Debug ar; + lua_getglobal(L, "f"); /* get global 'f' */ + lua_getinfo(L, ">S", &ar); + printf("%d\n", ar.linedefined); +</pre> + +<p> +Each character in the string <code>what</code> +selects some fields of the structure <code>ar</code> to be filled or +a value to be pushed on the stack. +(These characters are also documented in the declaration of +the structure <a href="#lua_Debug"><code>lua_Debug</code></a>, +between parentheses in the comments following each field.) + +<ul> + +<li><b>'<code>f</code>': </b> +pushes onto the stack the function that is +running at the given level; +</li> + +<li><b>'<code>l</code>': </b> fills in the field <code>currentline</code>; +</li> + +<li><b>'<code>n</code>': </b> fills in the fields <code>name</code> and <code>namewhat</code>; +</li> + +<li><b>'<code>r</code>': </b> fills in the fields <code>ftransfer</code> and <code>ntransfer</code>; +</li> + +<li><b>'<code>S</code>': </b> +fills in the fields <code>source</code>, <code>short_src</code>, +<code>linedefined</code>, <code>lastlinedefined</code>, and <code>what</code>; +</li> + +<li><b>'<code>t</code>': </b> fills in the field <code>istailcall</code>; +</li> + +<li><b>'<code>u</code>': </b> fills in the fields +<code>nups</code>, <code>nparams</code>, and <code>isvararg</code>; +</li> + +<li><b>'<code>L</code>': </b> +pushes onto the stack a table whose indices are +the lines on the function with some associated code, +that is, the lines where you can put a break point. +(Lines with no code include empty lines and comments.) +If this option is given together with option '<code>f</code>', +its table is pushed after the function. +This is the only option that can raise a memory error. +</li> + +</ul> + +<p> +This function returns 0 to signal an invalid option in <code>what</code>; +even then the valid options are handled correctly. + + + + + +<hr><h3><a name="lua_getlocal"><code>lua_getlocal</code></a></h3><p> +<span class="apii">[-0, +(0|1), –]</span> +<pre>const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);</pre> + +<p> +Gets information about a local variable or a temporary value +of a given activation record or a given function. + + +<p> +In the first case, +the parameter <code>ar</code> must be a valid activation record that was +filled by a previous call to <a href="#lua_getstack"><code>lua_getstack</code></a> or +given as argument to a hook (see <a href="#lua_Hook"><code>lua_Hook</code></a>). +The index <code>n</code> selects which local variable to inspect; +see <a href="#pdf-debug.getlocal"><code>debug.getlocal</code></a> for details about variable indices +and names. + + +<p> +<a href="#lua_getlocal"><code>lua_getlocal</code></a> pushes the variable's value onto the stack +and returns its name. + + +<p> +In the second case, <code>ar</code> must be <code>NULL</code> and the function +to be inspected must be on the top of the stack. +In this case, only parameters of Lua functions are visible +(as there is no information about what variables are active) +and no values are pushed onto the stack. + + +<p> +Returns <code>NULL</code> (and pushes nothing) +when the index is greater than +the number of active local variables. + + + + + +<hr><h3><a name="lua_getstack"><code>lua_getstack</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>int lua_getstack (lua_State *L, int level, lua_Debug *ar);</pre> + +<p> +Gets information about the interpreter runtime stack. + + +<p> +This function fills parts of a <a href="#lua_Debug"><code>lua_Debug</code></a> structure with +an identification of the <em>activation record</em> +of the function executing at a given level. +Level 0 is the current running function, +whereas level <em>n+1</em> is the function that has called level <em>n</em> +(except for tail calls, which do not count in the stack). +When called with a level greater than the stack depth, +<a href="#lua_getstack"><code>lua_getstack</code></a> returns 0; +otherwise it returns 1. + + + + + +<hr><h3><a name="lua_getupvalue"><code>lua_getupvalue</code></a></h3><p> +<span class="apii">[-0, +(0|1), –]</span> +<pre>const char *lua_getupvalue (lua_State *L, int funcindex, int n);</pre> + +<p> +Gets information about the <code>n</code>-th upvalue +of the closure at index <code>funcindex</code>. +It pushes the upvalue's value onto the stack +and returns its name. +Returns <code>NULL</code> (and pushes nothing) +when the index <code>n</code> is greater than the number of upvalues. + + +<p> +See <a href="#pdf-debug.getupvalue"><code>debug.getupvalue</code></a> for more information about upvalues. + + + + + +<hr><h3><a name="lua_Hook"><code>lua_Hook</code></a></h3> +<pre>typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);</pre> + +<p> +Type for debugging hook functions. + + +<p> +Whenever a hook is called, its <code>ar</code> argument has its field +<code>event</code> set to the specific event that triggered the hook. +Lua identifies these events with the following constants: +<a name="pdf-LUA_HOOKCALL"><code>LUA_HOOKCALL</code></a>, <a name="pdf-LUA_HOOKRET"><code>LUA_HOOKRET</code></a>, +<a name="pdf-LUA_HOOKTAILCALL"><code>LUA_HOOKTAILCALL</code></a>, <a name="pdf-LUA_HOOKLINE"><code>LUA_HOOKLINE</code></a>, +and <a name="pdf-LUA_HOOKCOUNT"><code>LUA_HOOKCOUNT</code></a>. +Moreover, for line events, the field <code>currentline</code> is also set. +To get the value of any other field in <code>ar</code>, +the hook must call <a href="#lua_getinfo"><code>lua_getinfo</code></a>. + + +<p> +For call events, <code>event</code> can be <code>LUA_HOOKCALL</code>, +the normal value, or <code>LUA_HOOKTAILCALL</code>, for a tail call; +in this case, there will be no corresponding return event. + + +<p> +While Lua is running a hook, it disables other calls to hooks. +Therefore, if a hook calls back Lua to execute a function or a chunk, +this execution occurs without any calls to hooks. + + +<p> +Hook functions cannot have continuations, +that is, they cannot call <a href="#lua_yieldk"><code>lua_yieldk</code></a>, +<a href="#lua_pcallk"><code>lua_pcallk</code></a>, or <a href="#lua_callk"><code>lua_callk</code></a> with a non-null <code>k</code>. + + +<p> +Hook functions can yield under the following conditions: +Only count and line events can yield; +to yield, a hook function must finish its execution +calling <a href="#lua_yield"><code>lua_yield</code></a> with <code>nresults</code> equal to zero +(that is, with no values). + + + + + +<hr><h3><a name="lua_sethook"><code>lua_sethook</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);</pre> + +<p> +Sets the debugging hook function. + + +<p> +Argument <code>f</code> is the hook function. +<code>mask</code> specifies on which events the hook will be called: +it is formed by a bitwise OR of the constants +<a name="pdf-LUA_MASKCALL"><code>LUA_MASKCALL</code></a>, +<a name="pdf-LUA_MASKRET"><code>LUA_MASKRET</code></a>, +<a name="pdf-LUA_MASKLINE"><code>LUA_MASKLINE</code></a>, +and <a name="pdf-LUA_MASKCOUNT"><code>LUA_MASKCOUNT</code></a>. +The <code>count</code> argument is only meaningful when the mask +includes <code>LUA_MASKCOUNT</code>. +For each event, the hook is called as explained below: + +<ul> + +<li><b>The call hook: </b> is called when the interpreter calls a function. +The hook is called just after Lua enters the new function. +</li> + +<li><b>The return hook: </b> is called when the interpreter returns from a function. +The hook is called just before Lua leaves the function. +</li> + +<li><b>The line hook: </b> is called when the interpreter is about to +start the execution of a new line of code, +or when it jumps back in the code (even to the same line). +This event only happens while Lua is executing a Lua function. +</li> + +<li><b>The count hook: </b> is called after the interpreter executes every +<code>count</code> instructions. +This event only happens while Lua is executing a Lua function. +</li> + +</ul> + +<p> +Hooks are disabled by setting <code>mask</code> to zero. + + + + + +<hr><h3><a name="lua_setlocal"><code>lua_setlocal</code></a></h3><p> +<span class="apii">[-(0|1), +0, –]</span> +<pre>const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);</pre> + +<p> +Sets the value of a local variable of a given activation record. +It assigns the value on the top of the stack +to the variable and returns its name. +It also pops the value from the stack. + + +<p> +Returns <code>NULL</code> (and pops nothing) +when the index is greater than +the number of active local variables. + + +<p> +Parameters <code>ar</code> and <code>n</code> are as in the function <a href="#lua_getlocal"><code>lua_getlocal</code></a>. + + + + + +<hr><h3><a name="lua_setupvalue"><code>lua_setupvalue</code></a></h3><p> +<span class="apii">[-(0|1), +0, –]</span> +<pre>const char *lua_setupvalue (lua_State *L, int funcindex, int n);</pre> + +<p> +Sets the value of a closure's upvalue. +It assigns the value on the top of the stack +to the upvalue and returns its name. +It also pops the value from the stack. + + +<p> +Returns <code>NULL</code> (and pops nothing) +when the index <code>n</code> is greater than the number of upvalues. + + +<p> +Parameters <code>funcindex</code> and <code>n</code> are as in +the function <a href="#lua_getupvalue"><code>lua_getupvalue</code></a>. + + + + + +<hr><h3><a name="lua_upvalueid"><code>lua_upvalueid</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>void *lua_upvalueid (lua_State *L, int funcindex, int n);</pre> + +<p> +Returns a unique identifier for the upvalue numbered <code>n</code> +from the closure at index <code>funcindex</code>. + + +<p> +These unique identifiers allow a program to check whether different +closures share upvalues. +Lua closures that share an upvalue +(that is, that access a same external local variable) +will return identical ids for those upvalue indices. + + +<p> +Parameters <code>funcindex</code> and <code>n</code> are as in +the function <a href="#lua_getupvalue"><code>lua_getupvalue</code></a>, +but <code>n</code> cannot be greater than the number of upvalues. + + + + + +<hr><h3><a name="lua_upvaluejoin"><code>lua_upvaluejoin</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>void lua_upvaluejoin (lua_State *L, int funcindex1, int n1, + int funcindex2, int n2);</pre> + +<p> +Make the <code>n1</code>-th upvalue of the Lua closure at index <code>funcindex1</code> +refer to the <code>n2</code>-th upvalue of the Lua closure at index <code>funcindex2</code>. + + + + + + + +<h1>5 – <a name="5">The Auxiliary Library</a></h1> + + + +<p> + +The <em>auxiliary library</em> provides several convenient functions +to interface C with Lua. +While the basic API provides the primitive functions for all +interactions between C and Lua, +the auxiliary library provides higher-level functions for some +common tasks. + + +<p> +All functions and types from the auxiliary library +are defined in header file <code>lauxlib.h</code> and +have a prefix <code>luaL_</code>. + + +<p> +All functions in the auxiliary library are built on +top of the basic API, +and so they provide nothing that cannot be done with that API. +Nevertheless, the use of the auxiliary library ensures +more consistency to your code. + + +<p> +Several functions in the auxiliary library use internally some +extra stack slots. +When a function in the auxiliary library uses less than five slots, +it does not check the stack size; +it simply assumes that there are enough slots. + + +<p> +Several functions in the auxiliary library are used to +check C function arguments. +Because the error message is formatted for arguments +(e.g., "<code>bad argument #1</code>"), +you should not use these functions for other stack values. + + +<p> +Functions called <code>luaL_check*</code> +always raise an error if the check is not satisfied. + + + + + +<h2>5.1 – <a name="5.1">Functions and Types</a></h2> + +<p> +Here we list all functions and types from the auxiliary library +in alphabetical order. + + + +<hr><h3><a name="luaL_addchar"><code>luaL_addchar</code></a></h3><p> +<span class="apii">[-?, +?, <em>m</em>]</span> +<pre>void luaL_addchar (luaL_Buffer *B, char c);</pre> + +<p> +Adds the byte <code>c</code> to the buffer <code>B</code> +(see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>). + + + + + +<hr><h3><a name="luaL_addgsub"><code>luaL_addgsub</code></a></h3><p> +<span class="apii">[-?, +?, <em>m</em>]</span> +<pre>const void luaL_addgsub (luaL_Buffer *B, const char *s, + const char *p, const char *r);</pre> + +<p> +Adds a copy of the string <code>s</code> to the buffer <code>B</code> (see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>), +replacing any occurrence of the string <code>p</code> +with the string <code>r</code>. + + + + + +<hr><h3><a name="luaL_addlstring"><code>luaL_addlstring</code></a></h3><p> +<span class="apii">[-?, +?, <em>m</em>]</span> +<pre>void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);</pre> + +<p> +Adds the string pointed to by <code>s</code> with length <code>l</code> to +the buffer <code>B</code> +(see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>). +The string can contain embedded zeros. + + + + + +<hr><h3><a name="luaL_addsize"><code>luaL_addsize</code></a></h3><p> +<span class="apii">[-?, +?, –]</span> +<pre>void luaL_addsize (luaL_Buffer *B, size_t n);</pre> + +<p> +Adds to the buffer <code>B</code> +a string of length <code>n</code> previously copied to the +buffer area (see <a href="#luaL_prepbuffer"><code>luaL_prepbuffer</code></a>). + + + + + +<hr><h3><a name="luaL_addstring"><code>luaL_addstring</code></a></h3><p> +<span class="apii">[-?, +?, <em>m</em>]</span> +<pre>void luaL_addstring (luaL_Buffer *B, const char *s);</pre> + +<p> +Adds the zero-terminated string pointed to by <code>s</code> +to the buffer <code>B</code> +(see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>). + + + + + +<hr><h3><a name="luaL_addvalue"><code>luaL_addvalue</code></a></h3><p> +<span class="apii">[-?, +?, <em>m</em>]</span> +<pre>void luaL_addvalue (luaL_Buffer *B);</pre> + +<p> +Adds the value on the top of the stack +to the buffer <code>B</code> +(see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>). +Pops the value. + + +<p> +This is the only function on string buffers that can (and must) +be called with an extra element on the stack, +which is the value to be added to the buffer. + + + + + +<hr><h3><a name="luaL_argcheck"><code>luaL_argcheck</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>void luaL_argcheck (lua_State *L, + int cond, + int arg, + const char *extramsg);</pre> + +<p> +Checks whether <code>cond</code> is true. +If it is not, raises an error with a standard message (see <a href="#luaL_argerror"><code>luaL_argerror</code></a>). + + + + + +<hr><h3><a name="luaL_argerror"><code>luaL_argerror</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>int luaL_argerror (lua_State *L, int arg, const char *extramsg);</pre> + +<p> +Raises an error reporting a problem with argument <code>arg</code> +of the C function that called it, +using a standard message +that includes <code>extramsg</code> as a comment: + +<pre> + bad argument #<em>arg</em> to '<em>funcname</em>' (<em>extramsg</em>) +</pre><p> +This function never returns. + + + + + +<hr><h3><a name="luaL_argexpected"><code>luaL_argexpected</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>void luaL_argexpected (lua_State *L, + int cond, + int arg, + const char *tname);</pre> + +<p> +Checks whether <code>cond</code> is true. +If it is not, raises an error about the type of the argument <code>arg</code> +with a standard message (see <a href="#luaL_typeerror"><code>luaL_typeerror</code></a>). + + + + + +<hr><h3><a name="luaL_Buffer"><code>luaL_Buffer</code></a></h3> +<pre>typedef struct luaL_Buffer luaL_Buffer;</pre> + +<p> +Type for a <em>string buffer</em>. + + +<p> +A string buffer allows C code to build Lua strings piecemeal. +Its pattern of use is as follows: + +<ul> + +<li>First declare a variable <code>b</code> of type <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>.</li> + +<li>Then initialize it with a call <code>luaL_buffinit(L, &b)</code>.</li> + +<li> +Then add string pieces to the buffer calling any of +the <code>luaL_add*</code> functions. +</li> + +<li> +Finish by calling <code>luaL_pushresult(&b)</code>. +This call leaves the final string on the top of the stack. +</li> + +</ul> + +<p> +If you know beforehand the maximum size of the resulting string, +you can use the buffer like this: + +<ul> + +<li>First declare a variable <code>b</code> of type <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>.</li> + +<li>Then initialize it and preallocate a space of +size <code>sz</code> with a call <code>luaL_buffinitsize(L, &b, sz)</code>.</li> + +<li>Then produce the string into that space.</li> + +<li> +Finish by calling <code>luaL_pushresultsize(&b, sz)</code>, +where <code>sz</code> is the total size of the resulting string +copied into that space (which may be less than or +equal to the preallocated size). +</li> + +</ul> + +<p> +During its normal operation, +a string buffer uses a variable number of stack slots. +So, while using a buffer, you cannot assume that you know where +the top of the stack is. +You can use the stack between successive calls to buffer operations +as long as that use is balanced; +that is, +when you call a buffer operation, +the stack is at the same level +it was immediately after the previous buffer operation. +(The only exception to this rule is <a href="#luaL_addvalue"><code>luaL_addvalue</code></a>.) +After calling <a href="#luaL_pushresult"><code>luaL_pushresult</code></a>, +the stack is back to its level when the buffer was initialized, +plus the final string on its top. + + + + + +<hr><h3><a name="luaL_buffaddr"><code>luaL_buffaddr</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>char *luaL_buffaddr (luaL_Buffer *B);</pre> + +<p> +Returns the address of the current content of buffer <code>B</code> +(see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>). +Note that any addition to the buffer may invalidate this address. + + + + + +<hr><h3><a name="luaL_buffinit"><code>luaL_buffinit</code></a></h3><p> +<span class="apii">[-0, +?, –]</span> +<pre>void luaL_buffinit (lua_State *L, luaL_Buffer *B);</pre> + +<p> +Initializes a buffer <code>B</code> +(see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>). +This function does not allocate any space; +the buffer must be declared as a variable. + + + + + +<hr><h3><a name="luaL_bufflen"><code>luaL_bufflen</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>size_t luaL_bufflen (luaL_Buffer *B);</pre> + +<p> +Returns the length of the current content of buffer <code>B</code> +(see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>). + + + + + +<hr><h3><a name="luaL_buffinitsize"><code>luaL_buffinitsize</code></a></h3><p> +<span class="apii">[-?, +?, <em>m</em>]</span> +<pre>char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz);</pre> + +<p> +Equivalent to the sequence +<a href="#luaL_buffinit"><code>luaL_buffinit</code></a>, <a href="#luaL_prepbuffsize"><code>luaL_prepbuffsize</code></a>. + + + + + +<hr><h3><a name="luaL_buffsub"><code>luaL_buffsub</code></a></h3><p> +<span class="apii">[-?, +?, –]</span> +<pre>void luaL_buffsub (luaL_Buffer *B, int n);</pre> + +<p> +Removes <code>n</code> bytes from the buffer <code>B</code> +(see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>). +The buffer must have at least that many bytes. + + + + + +<hr><h3><a name="luaL_callmeta"><code>luaL_callmeta</code></a></h3><p> +<span class="apii">[-0, +(0|1), <em>e</em>]</span> +<pre>int luaL_callmeta (lua_State *L, int obj, const char *e);</pre> + +<p> +Calls a metamethod. + + +<p> +If the object at index <code>obj</code> has a metatable and this +metatable has a field <code>e</code>, +this function calls this field passing the object as its only argument. +In this case this function returns true and pushes onto the +stack the value returned by the call. +If there is no metatable or no metamethod, +this function returns false without pushing any value on the stack. + + + + + +<hr><h3><a name="luaL_checkany"><code>luaL_checkany</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>void luaL_checkany (lua_State *L, int arg);</pre> + +<p> +Checks whether the function has an argument +of any type (including <b>nil</b>) at position <code>arg</code>. + + + + + +<hr><h3><a name="luaL_checkinteger"><code>luaL_checkinteger</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>lua_Integer luaL_checkinteger (lua_State *L, int arg);</pre> + +<p> +Checks whether the function argument <code>arg</code> is an integer +(or can be converted to an integer) +and returns this integer. + + + + + +<hr><h3><a name="luaL_checklstring"><code>luaL_checklstring</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>const char *luaL_checklstring (lua_State *L, int arg, size_t *l);</pre> + +<p> +Checks whether the function argument <code>arg</code> is a string +and returns this string; +if <code>l</code> is not <code>NULL</code> fills its referent +with the string's length. + + +<p> +This function uses <a href="#lua_tolstring"><code>lua_tolstring</code></a> to get its result, +so all conversions and caveats of that function apply here. + + + + + +<hr><h3><a name="luaL_checknumber"><code>luaL_checknumber</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>lua_Number luaL_checknumber (lua_State *L, int arg);</pre> + +<p> +Checks whether the function argument <code>arg</code> is a number +and returns this number converted to a <code>lua_Number</code>. + + + + + +<hr><h3><a name="luaL_checkoption"><code>luaL_checkoption</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>int luaL_checkoption (lua_State *L, + int arg, + const char *def, + const char *const lst[]);</pre> + +<p> +Checks whether the function argument <code>arg</code> is a string and +searches for this string in the array <code>lst</code> +(which must be NULL-terminated). +Returns the index in the array where the string was found. +Raises an error if the argument is not a string or +if the string cannot be found. + + +<p> +If <code>def</code> is not <code>NULL</code>, +the function uses <code>def</code> as a default value when +there is no argument <code>arg</code> or when this argument is <b>nil</b>. + + +<p> +This is a useful function for mapping strings to C enums. +(The usual convention in Lua libraries is +to use strings instead of numbers to select options.) + + + + + +<hr><h3><a name="luaL_checkstack"><code>luaL_checkstack</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>void luaL_checkstack (lua_State *L, int sz, const char *msg);</pre> + +<p> +Grows the stack size to <code>top + sz</code> elements, +raising an error if the stack cannot grow to that size. +<code>msg</code> is an additional text to go into the error message +(or <code>NULL</code> for no additional text). + + + + + +<hr><h3><a name="luaL_checkstring"><code>luaL_checkstring</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>const char *luaL_checkstring (lua_State *L, int arg);</pre> + +<p> +Checks whether the function argument <code>arg</code> is a string +and returns this string. + + +<p> +This function uses <a href="#lua_tolstring"><code>lua_tolstring</code></a> to get its result, +so all conversions and caveats of that function apply here. + + + + + +<hr><h3><a name="luaL_checktype"><code>luaL_checktype</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>void luaL_checktype (lua_State *L, int arg, int t);</pre> + +<p> +Checks whether the function argument <code>arg</code> has type <code>t</code>. +See <a href="#lua_type"><code>lua_type</code></a> for the encoding of types for <code>t</code>. + + + + + +<hr><h3><a name="luaL_checkudata"><code>luaL_checkudata</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>void *luaL_checkudata (lua_State *L, int arg, const char *tname);</pre> + +<p> +Checks whether the function argument <code>arg</code> is a userdata +of the type <code>tname</code> (see <a href="#luaL_newmetatable"><code>luaL_newmetatable</code></a>) and +returns the userdata's memory-block address (see <a href="#lua_touserdata"><code>lua_touserdata</code></a>). + + + + + +<hr><h3><a name="luaL_checkversion"><code>luaL_checkversion</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>void luaL_checkversion (lua_State *L);</pre> + +<p> +Checks whether the code making the call and the Lua library being called +are using the same version of Lua and the same numeric types. + + + + + +<hr><h3><a name="luaL_dofile"><code>luaL_dofile</code></a></h3><p> +<span class="apii">[-0, +?, <em>m</em>]</span> +<pre>int luaL_dofile (lua_State *L, const char *filename);</pre> + +<p> +Loads and runs the given file. +It is defined as the following macro: + +<pre> + (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0)) +</pre><p> +It returns 0 (<a href="#pdf-LUA_OK"><code>LUA_OK</code></a>) if there are no errors, +or 1 in case of errors. + + + + + +<hr><h3><a name="luaL_dostring"><code>luaL_dostring</code></a></h3><p> +<span class="apii">[-0, +?, –]</span> +<pre>int luaL_dostring (lua_State *L, const char *str);</pre> + +<p> +Loads and runs the given string. +It is defined as the following macro: + +<pre> + (luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0)) +</pre><p> +It returns 0 (<a href="#pdf-LUA_OK"><code>LUA_OK</code></a>) if there are no errors, +or 1 in case of errors. + + + + + +<hr><h3><a name="luaL_error"><code>luaL_error</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>int luaL_error (lua_State *L, const char *fmt, ...);</pre> + +<p> +Raises an error. +The error message format is given by <code>fmt</code> +plus any extra arguments, +following the same rules of <a href="#lua_pushfstring"><code>lua_pushfstring</code></a>. +It also adds at the beginning of the message the file name and +the line number where the error occurred, +if this information is available. + + +<p> +This function never returns, +but it is an idiom to use it in C functions +as <code>return luaL_error(<em>args</em>)</code>. + + + + + +<hr><h3><a name="luaL_execresult"><code>luaL_execresult</code></a></h3><p> +<span class="apii">[-0, +3, <em>m</em>]</span> +<pre>int luaL_execresult (lua_State *L, int stat);</pre> + +<p> +This function produces the return values for +process-related functions in the standard library +(<a href="#pdf-os.execute"><code>os.execute</code></a> and <a href="#pdf-io.close"><code>io.close</code></a>). + + + + + +<hr><h3><a name="luaL_fileresult"><code>luaL_fileresult</code></a></h3><p> +<span class="apii">[-0, +(1|3), <em>m</em>]</span> +<pre>int luaL_fileresult (lua_State *L, int stat, const char *fname);</pre> + +<p> +This function produces the return values for +file-related functions in the standard library +(<a href="#pdf-io.open"><code>io.open</code></a>, <a href="#pdf-os.rename"><code>os.rename</code></a>, <a href="#pdf-file:seek"><code>file:seek</code></a>, etc.). + + + + + +<hr><h3><a name="luaL_getmetafield"><code>luaL_getmetafield</code></a></h3><p> +<span class="apii">[-0, +(0|1), <em>m</em>]</span> +<pre>int luaL_getmetafield (lua_State *L, int obj, const char *e);</pre> + +<p> +Pushes onto the stack the field <code>e</code> from the metatable +of the object at index <code>obj</code> and returns the type of the pushed value. +If the object does not have a metatable, +or if the metatable does not have this field, +pushes nothing and returns <code>LUA_TNIL</code>. + + + + + +<hr><h3><a name="luaL_getmetatable"><code>luaL_getmetatable</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>int luaL_getmetatable (lua_State *L, const char *tname);</pre> + +<p> +Pushes onto the stack the metatable associated with the name <code>tname</code> +in the registry (see <a href="#luaL_newmetatable"><code>luaL_newmetatable</code></a>), +or <b>nil</b> if there is no metatable associated with that name. +Returns the type of the pushed value. + + + + + +<hr><h3><a name="luaL_getsubtable"><code>luaL_getsubtable</code></a></h3><p> +<span class="apii">[-0, +1, <em>e</em>]</span> +<pre>int luaL_getsubtable (lua_State *L, int idx, const char *fname);</pre> + +<p> +Ensures that the value <code>t[fname]</code>, +where <code>t</code> is the value at index <code>idx</code>, +is a table, +and pushes that table onto the stack. +Returns true if it finds a previous table there +and false if it creates a new table. + + + + + +<hr><h3><a name="luaL_gsub"><code>luaL_gsub</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>const char *luaL_gsub (lua_State *L, + const char *s, + const char *p, + const char *r);</pre> + +<p> +Creates a copy of string <code>s</code>, +replacing any occurrence of the string <code>p</code> +with the string <code>r</code>. +Pushes the resulting string on the stack and returns it. + + + + + +<hr><h3><a name="luaL_len"><code>luaL_len</code></a></h3><p> +<span class="apii">[-0, +0, <em>e</em>]</span> +<pre>lua_Integer luaL_len (lua_State *L, int index);</pre> + +<p> +Returns the "length" of the value at the given index +as a number; +it is equivalent to the '<code>#</code>' operator in Lua (see <a href="#3.4.7">§3.4.7</a>). +Raises an error if the result of the operation is not an integer. +(This case can only happen through metamethods.) + + + + + +<hr><h3><a name="luaL_loadbuffer"><code>luaL_loadbuffer</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>int luaL_loadbuffer (lua_State *L, + const char *buff, + size_t sz, + const char *name);</pre> + +<p> +Equivalent to <a href="#luaL_loadbufferx"><code>luaL_loadbufferx</code></a> with <code>mode</code> equal to <code>NULL</code>. + + + + + +<hr><h3><a name="luaL_loadbufferx"><code>luaL_loadbufferx</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>int luaL_loadbufferx (lua_State *L, + const char *buff, + size_t sz, + const char *name, + const char *mode);</pre> + +<p> +Loads a buffer as a Lua chunk. +This function uses <a href="#lua_load"><code>lua_load</code></a> to load the chunk in the +buffer pointed to by <code>buff</code> with size <code>sz</code>. + + +<p> +This function returns the same results as <a href="#lua_load"><code>lua_load</code></a>. +<code>name</code> is the chunk name, +used for debug information and error messages. +The string <code>mode</code> works as in the function <a href="#lua_load"><code>lua_load</code></a>. + + + + + +<hr><h3><a name="luaL_loadfile"><code>luaL_loadfile</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>int luaL_loadfile (lua_State *L, const char *filename);</pre> + +<p> +Equivalent to <a href="#luaL_loadfilex"><code>luaL_loadfilex</code></a> with <code>mode</code> equal to <code>NULL</code>. + + + + + +<hr><h3><a name="luaL_loadfilex"><code>luaL_loadfilex</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>int luaL_loadfilex (lua_State *L, const char *filename, + const char *mode);</pre> + +<p> +Loads a file as a Lua chunk. +This function uses <a href="#lua_load"><code>lua_load</code></a> to load the chunk in the file +named <code>filename</code>. +If <code>filename</code> is <code>NULL</code>, +then it loads from the standard input. +The first line in the file is ignored if it starts with a <code>#</code>. + + +<p> +The string <code>mode</code> works as in the function <a href="#lua_load"><code>lua_load</code></a>. + + +<p> +This function returns the same results as <a href="#lua_load"><code>lua_load</code></a> +or <a href="#pdf-LUA_ERRFILE"><code>LUA_ERRFILE</code></a> for file-related errors. + + +<p> +As <a href="#lua_load"><code>lua_load</code></a>, this function only loads the chunk; +it does not run it. + + + + + +<hr><h3><a name="luaL_loadstring"><code>luaL_loadstring</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>int luaL_loadstring (lua_State *L, const char *s);</pre> + +<p> +Loads a string as a Lua chunk. +This function uses <a href="#lua_load"><code>lua_load</code></a> to load the chunk in +the zero-terminated string <code>s</code>. + + +<p> +This function returns the same results as <a href="#lua_load"><code>lua_load</code></a>. + + +<p> +Also as <a href="#lua_load"><code>lua_load</code></a>, this function only loads the chunk; +it does not run it. + + + + + +<hr><h3><a name="luaL_newlib"><code>luaL_newlib</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>void luaL_newlib (lua_State *L, const luaL_Reg l[]);</pre> + +<p> +Creates a new table and registers there +the functions in the list <code>l</code>. + + +<p> +It is implemented as the following macro: + +<pre> + (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) +</pre><p> +The array <code>l</code> must be the actual array, +not a pointer to it. + + + + + +<hr><h3><a name="luaL_newlibtable"><code>luaL_newlibtable</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);</pre> + +<p> +Creates a new table with a size optimized +to store all entries in the array <code>l</code> +(but does not actually store them). +It is intended to be used in conjunction with <a href="#luaL_setfuncs"><code>luaL_setfuncs</code></a> +(see <a href="#luaL_newlib"><code>luaL_newlib</code></a>). + + +<p> +It is implemented as a macro. +The array <code>l</code> must be the actual array, +not a pointer to it. + + + + + +<hr><h3><a name="luaL_newmetatable"><code>luaL_newmetatable</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>int luaL_newmetatable (lua_State *L, const char *tname);</pre> + +<p> +If the registry already has the key <code>tname</code>, +returns 0. +Otherwise, +creates a new table to be used as a metatable for userdata, +adds to this new table the pair <code>__name = tname</code>, +adds to the registry the pair <code>[tname] = new table</code>, +and returns 1. + + +<p> +In both cases, +the function pushes onto the stack the final value associated +with <code>tname</code> in the registry. + + + + + +<hr><h3><a name="luaL_newstate"><code>luaL_newstate</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>lua_State *luaL_newstate (void);</pre> + +<p> +Creates a new Lua state. +It calls <a href="#lua_newstate"><code>lua_newstate</code></a> with an +allocator based on the ISO C allocation functions +and then sets a warning function and a panic function (see <a href="#4.4">§4.4</a>) +that print messages to the standard error output. + + +<p> +Returns the new state, +or <code>NULL</code> if there is a memory allocation error. + + + + + +<hr><h3><a name="luaL_openlibs"><code>luaL_openlibs</code></a></h3><p> +<span class="apii">[-0, +0, <em>e</em>]</span> +<pre>void luaL_openlibs (lua_State *L);</pre> + +<p> +Opens all standard Lua libraries into the given state. + + + + + +<hr><h3><a name="luaL_opt"><code>luaL_opt</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>T luaL_opt (L, func, arg, dflt);</pre> + +<p> +This macro is defined as follows: + +<pre> + (lua_isnoneornil(L,(arg)) ? (dflt) : func(L,(arg))) +</pre><p> +In words, if the argument <code>arg</code> is nil or absent, +the macro results in the default <code>dflt</code>. +Otherwise, it results in the result of calling <code>func</code> +with the state <code>L</code> and the argument index <code>arg</code> as +arguments. +Note that it evaluates the expression <code>dflt</code> only if needed. + + + + + +<hr><h3><a name="luaL_optinteger"><code>luaL_optinteger</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>lua_Integer luaL_optinteger (lua_State *L, + int arg, + lua_Integer d);</pre> + +<p> +If the function argument <code>arg</code> is an integer +(or it is convertible to an integer), +returns this integer. +If this argument is absent or is <b>nil</b>, +returns <code>d</code>. +Otherwise, raises an error. + + + + + +<hr><h3><a name="luaL_optlstring"><code>luaL_optlstring</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>const char *luaL_optlstring (lua_State *L, + int arg, + const char *d, + size_t *l);</pre> + +<p> +If the function argument <code>arg</code> is a string, +returns this string. +If this argument is absent or is <b>nil</b>, +returns <code>d</code>. +Otherwise, raises an error. + + +<p> +If <code>l</code> is not <code>NULL</code>, +fills its referent with the result's length. +If the result is <code>NULL</code> +(only possible when returning <code>d</code> and <code>d == NULL</code>), +its length is considered zero. + + +<p> +This function uses <a href="#lua_tolstring"><code>lua_tolstring</code></a> to get its result, +so all conversions and caveats of that function apply here. + + + + + +<hr><h3><a name="luaL_optnumber"><code>luaL_optnumber</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number d);</pre> + +<p> +If the function argument <code>arg</code> is a number, +returns this number as a <code>lua_Number</code>. +If this argument is absent or is <b>nil</b>, +returns <code>d</code>. +Otherwise, raises an error. + + + + + +<hr><h3><a name="luaL_optstring"><code>luaL_optstring</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>const char *luaL_optstring (lua_State *L, + int arg, + const char *d);</pre> + +<p> +If the function argument <code>arg</code> is a string, +returns this string. +If this argument is absent or is <b>nil</b>, +returns <code>d</code>. +Otherwise, raises an error. + + + + + +<hr><h3><a name="luaL_prepbuffer"><code>luaL_prepbuffer</code></a></h3><p> +<span class="apii">[-?, +?, <em>m</em>]</span> +<pre>char *luaL_prepbuffer (luaL_Buffer *B);</pre> + +<p> +Equivalent to <a href="#luaL_prepbuffsize"><code>luaL_prepbuffsize</code></a> +with the predefined size <a name="pdf-LUAL_BUFFERSIZE"><code>LUAL_BUFFERSIZE</code></a>. + + + + + +<hr><h3><a name="luaL_prepbuffsize"><code>luaL_prepbuffsize</code></a></h3><p> +<span class="apii">[-?, +?, <em>m</em>]</span> +<pre>char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz);</pre> + +<p> +Returns an address to a space of size <code>sz</code> +where you can copy a string to be added to buffer <code>B</code> +(see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>). +After copying the string into this space you must call +<a href="#luaL_addsize"><code>luaL_addsize</code></a> with the size of the string to actually add +it to the buffer. + + + + + +<hr><h3><a name="luaL_pushfail"><code>luaL_pushfail</code></a></h3><p> +<span class="apii">[-0, +1, –]</span> +<pre>void luaL_pushfail (lua_State *L);</pre> + +<p> +Pushes the <b>fail</b> value onto the stack (see <a href="#6">§6</a>). + + + + + +<hr><h3><a name="luaL_pushresult"><code>luaL_pushresult</code></a></h3><p> +<span class="apii">[-?, +1, <em>m</em>]</span> +<pre>void luaL_pushresult (luaL_Buffer *B);</pre> + +<p> +Finishes the use of buffer <code>B</code> leaving the final string on +the top of the stack. + + + + + +<hr><h3><a name="luaL_pushresultsize"><code>luaL_pushresultsize</code></a></h3><p> +<span class="apii">[-?, +1, <em>m</em>]</span> +<pre>void luaL_pushresultsize (luaL_Buffer *B, size_t sz);</pre> + +<p> +Equivalent to the sequence <a href="#luaL_addsize"><code>luaL_addsize</code></a>, <a href="#luaL_pushresult"><code>luaL_pushresult</code></a>. + + + + + +<hr><h3><a name="luaL_ref"><code>luaL_ref</code></a></h3><p> +<span class="apii">[-1, +0, <em>m</em>]</span> +<pre>int luaL_ref (lua_State *L, int t);</pre> + +<p> +Creates and returns a <em>reference</em>, +in the table at index <code>t</code>, +for the object on the top of the stack (and pops the object). + + +<p> +A reference is a unique integer key. +As long as you do not manually add integer keys into the table <code>t</code>, +<a href="#luaL_ref"><code>luaL_ref</code></a> ensures the uniqueness of the key it returns. +You can retrieve an object referred by the reference <code>r</code> +by calling <code>lua_rawgeti(L, t, r)</code>. +The function <a href="#luaL_unref"><code>luaL_unref</code></a> frees a reference. + + +<p> +If the object on the top of the stack is <b>nil</b>, +<a href="#luaL_ref"><code>luaL_ref</code></a> returns the constant <a name="pdf-LUA_REFNIL"><code>LUA_REFNIL</code></a>. +The constant <a name="pdf-LUA_NOREF"><code>LUA_NOREF</code></a> is guaranteed to be different +from any reference returned by <a href="#luaL_ref"><code>luaL_ref</code></a>. + + + + + +<hr><h3><a name="luaL_Reg"><code>luaL_Reg</code></a></h3> +<pre>typedef struct luaL_Reg { + const char *name; + lua_CFunction func; +} luaL_Reg;</pre> + +<p> +Type for arrays of functions to be registered by +<a href="#luaL_setfuncs"><code>luaL_setfuncs</code></a>. +<code>name</code> is the function name and <code>func</code> is a pointer to +the function. +Any array of <a href="#luaL_Reg"><code>luaL_Reg</code></a> must end with a sentinel entry +in which both <code>name</code> and <code>func</code> are <code>NULL</code>. + + + + + +<hr><h3><a name="luaL_requiref"><code>luaL_requiref</code></a></h3><p> +<span class="apii">[-0, +1, <em>e</em>]</span> +<pre>void luaL_requiref (lua_State *L, const char *modname, + lua_CFunction openf, int glb);</pre> + +<p> +If <code>package.loaded[modname]</code> is not true, +calls the function <code>openf</code> with the string <code>modname</code> as an argument +and sets the call result to <code>package.loaded[modname]</code>, +as if that function has been called through <a href="#pdf-require"><code>require</code></a>. + + +<p> +If <code>glb</code> is true, +also stores the module into the global <code>modname</code>. + + +<p> +Leaves a copy of the module on the stack. + + + + + +<hr><h3><a name="luaL_setfuncs"><code>luaL_setfuncs</code></a></h3><p> +<span class="apii">[-nup, +0, <em>m</em>]</span> +<pre>void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);</pre> + +<p> +Registers all functions in the array <code>l</code> +(see <a href="#luaL_Reg"><code>luaL_Reg</code></a>) into the table on the top of the stack +(below optional upvalues, see next). + + +<p> +When <code>nup</code> is not zero, +all functions are created with <code>nup</code> upvalues, +initialized with copies of the <code>nup</code> values +previously pushed on the stack +on top of the library table. +These values are popped from the stack after the registration. + + +<p> +A function with a <code>NULL</code> value represents a placeholder, +which is filled with <b>false</b>. + + + + + +<hr><h3><a name="luaL_setmetatable"><code>luaL_setmetatable</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>void luaL_setmetatable (lua_State *L, const char *tname);</pre> + +<p> +Sets the metatable of the object on the top of the stack +as the metatable associated with name <code>tname</code> +in the registry (see <a href="#luaL_newmetatable"><code>luaL_newmetatable</code></a>). + + + + + +<hr><h3><a name="luaL_Stream"><code>luaL_Stream</code></a></h3> +<pre>typedef struct luaL_Stream { + FILE *f; + lua_CFunction closef; +} luaL_Stream;</pre> + +<p> +The standard representation for file handles +used by the standard I/O library. + + +<p> +A file handle is implemented as a full userdata, +with a metatable called <code>LUA_FILEHANDLE</code> +(where <code>LUA_FILEHANDLE</code> is a macro with the actual metatable's name). +The metatable is created by the I/O library +(see <a href="#luaL_newmetatable"><code>luaL_newmetatable</code></a>). + + +<p> +This userdata must start with the structure <code>luaL_Stream</code>; +it can contain other data after this initial structure. +The field <code>f</code> points to the corresponding C stream +(or it can be <code>NULL</code> to indicate an incompletely created handle). +The field <code>closef</code> points to a Lua function +that will be called to close the stream +when the handle is closed or collected; +this function receives the file handle as its sole argument and +must return either a true value, in case of success, +or a false value plus an error message, in case of error. +Once Lua calls this field, +it changes the field value to <code>NULL</code> +to signal that the handle is closed. + + + + + +<hr><h3><a name="luaL_testudata"><code>luaL_testudata</code></a></h3><p> +<span class="apii">[-0, +0, <em>m</em>]</span> +<pre>void *luaL_testudata (lua_State *L, int arg, const char *tname);</pre> + +<p> +This function works like <a href="#luaL_checkudata"><code>luaL_checkudata</code></a>, +except that, when the test fails, +it returns <code>NULL</code> instead of raising an error. + + + + + +<hr><h3><a name="luaL_tolstring"><code>luaL_tolstring</code></a></h3><p> +<span class="apii">[-0, +1, <em>e</em>]</span> +<pre>const char *luaL_tolstring (lua_State *L, int idx, size_t *len);</pre> + +<p> +Converts any Lua value at the given index to a C string +in a reasonable format. +The resulting string is pushed onto the stack and also +returned by the function (see <a href="#4.1.3">§4.1.3</a>). +If <code>len</code> is not <code>NULL</code>, +the function also sets <code>*len</code> with the string length. + + +<p> +If the value has a metatable with a <code>__tostring</code> field, +then <code>luaL_tolstring</code> calls the corresponding metamethod +with the value as argument, +and uses the result of the call as its result. + + + + + +<hr><h3><a name="luaL_traceback"><code>luaL_traceback</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, + int level);</pre> + +<p> +Creates and pushes a traceback of the stack <code>L1</code>. +If <code>msg</code> is not <code>NULL</code>, it is appended +at the beginning of the traceback. +The <code>level</code> parameter tells at which level +to start the traceback. + + + + + +<hr><h3><a name="luaL_typeerror"><code>luaL_typeerror</code></a></h3><p> +<span class="apii">[-0, +0, <em>v</em>]</span> +<pre>int luaL_typeerror (lua_State *L, int arg, const char *tname);</pre> + +<p> +Raises a type error for the argument <code>arg</code> +of the C function that called it, +using a standard message; +<code>tname</code> is a "name" for the expected type. +This function never returns. + + + + + +<hr><h3><a name="luaL_typename"><code>luaL_typename</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>const char *luaL_typename (lua_State *L, int index);</pre> + +<p> +Returns the name of the type of the value at the given index. + + + + + +<hr><h3><a name="luaL_unref"><code>luaL_unref</code></a></h3><p> +<span class="apii">[-0, +0, –]</span> +<pre>void luaL_unref (lua_State *L, int t, int ref);</pre> + +<p> +Releases the reference <code>ref</code> from the table at index <code>t</code> +(see <a href="#luaL_ref"><code>luaL_ref</code></a>). +The entry is removed from the table, +so that the referred object can be collected. +The reference <code>ref</code> is also freed to be used again. + + +<p> +If <code>ref</code> is <a href="#pdf-LUA_NOREF"><code>LUA_NOREF</code></a> or <a href="#pdf-LUA_REFNIL"><code>LUA_REFNIL</code></a>, +<a href="#luaL_unref"><code>luaL_unref</code></a> does nothing. + + + + + +<hr><h3><a name="luaL_where"><code>luaL_where</code></a></h3><p> +<span class="apii">[-0, +1, <em>m</em>]</span> +<pre>void luaL_where (lua_State *L, int lvl);</pre> + +<p> +Pushes onto the stack a string identifying the current position +of the control at level <code>lvl</code> in the call stack. +Typically this string has the following format: + +<pre> + <em>chunkname</em>:<em>currentline</em>: +</pre><p> +Level 0 is the running function, +level 1 is the function that called the running function, +etc. + + +<p> +This function is used to build a prefix for error messages. + + + + + + + +<h1>6 – <a name="6">The Standard Libraries</a></h1> + + + +<p> +The standard Lua libraries provide useful functions +that are implemented in C through the C API. +Some of these functions provide essential services to the language +(e.g., <a href="#pdf-type"><code>type</code></a> and <a href="#pdf-getmetatable"><code>getmetatable</code></a>); +others provide access to outside services (e.g., I/O); +and others could be implemented in Lua itself, +but that for different reasons +deserve an implementation in C (e.g., <a href="#pdf-table.sort"><code>table.sort</code></a>). + + +<p> +All libraries are implemented through the official C API +and are provided as separate C modules. +Unless otherwise noted, +these library functions do not adjust its number of arguments +to its expected parameters. +For instance, a function documented as <code>foo(arg)</code> +should not be called without an argument. + + +<p> +The notation <b>fail</b> means a false value representing +some kind of failure. +(Currently, <b>fail</b> is equal to <b>nil</b>, +but that may change in future versions. +The recommendation is to always test the success of these functions +with <code>(not status)</code>, instead of <code>(status == nil)</code>.) + + +<p> +Currently, Lua has the following standard libraries: + +<ul> + +<li>basic library (<a href="#6.1">§6.1</a>);</li> + +<li>coroutine library (<a href="#6.2">§6.2</a>);</li> + +<li>package library (<a href="#6.3">§6.3</a>);</li> + +<li>string manipulation (<a href="#6.4">§6.4</a>);</li> + +<li>basic UTF-8 support (<a href="#6.5">§6.5</a>);</li> + +<li>table manipulation (<a href="#6.6">§6.6</a>);</li> + +<li>mathematical functions (<a href="#6.7">§6.7</a>) (sin, log, etc.);</li> + +<li>input and output (<a href="#6.8">§6.8</a>);</li> + +<li>operating system facilities (<a href="#6.9">§6.9</a>);</li> + +<li>debug facilities (<a href="#6.10">§6.10</a>).</li> + +</ul><p> +Except for the basic and the package libraries, +each library provides all its functions as fields of a global table +or as methods of its objects. + + +<p> +To have access to these libraries, +the C host program should call the <a href="#luaL_openlibs"><code>luaL_openlibs</code></a> function, +which opens all standard libraries. +Alternatively, +the host program can open them individually by using +<a href="#luaL_requiref"><code>luaL_requiref</code></a> to call +<a name="pdf-luaopen_base"><code>luaopen_base</code></a> (for the basic library), +<a name="pdf-luaopen_package"><code>luaopen_package</code></a> (for the package library), +<a name="pdf-luaopen_coroutine"><code>luaopen_coroutine</code></a> (for the coroutine library), +<a name="pdf-luaopen_string"><code>luaopen_string</code></a> (for the string library), +<a name="pdf-luaopen_utf8"><code>luaopen_utf8</code></a> (for the UTF-8 library), +<a name="pdf-luaopen_table"><code>luaopen_table</code></a> (for the table library), +<a name="pdf-luaopen_math"><code>luaopen_math</code></a> (for the mathematical library), +<a name="pdf-luaopen_io"><code>luaopen_io</code></a> (for the I/O library), +<a name="pdf-luaopen_os"><code>luaopen_os</code></a> (for the operating system library), +and <a name="pdf-luaopen_debug"><code>luaopen_debug</code></a> (for the debug library). +These functions are declared in <a name="pdf-lualib.h"><code>lualib.h</code></a>. + + + + + +<h2>6.1 – <a name="6.1">Basic Functions</a></h2> + +<p> +The basic library provides core functions to Lua. +If you do not include this library in your application, +you should check carefully whether you need to provide +implementations for some of its facilities. + + +<p> +<hr><h3><a name="pdf-assert"><code>assert (v [, message])</code></a></h3> + + +<p> +Raises an error if +the value of its argument <code>v</code> is false (i.e., <b>nil</b> or <b>false</b>); +otherwise, returns all its arguments. +In case of error, +<code>message</code> is the error object; +when absent, it defaults to "<code>assertion failed!</code>" + + + + +<p> +<hr><h3><a name="pdf-collectgarbage"><code>collectgarbage ([opt [, arg]])</code></a></h3> + + +<p> +This function is a generic interface to the garbage collector. +It performs different functions according to its first argument, <code>opt</code>: + +<ul> + +<li><b>"<code>collect</code>": </b> +Performs a full garbage-collection cycle. +This is the default option. +</li> + +<li><b>"<code>stop</code>": </b> +Stops automatic execution of the garbage collector. +The collector will run only when explicitly invoked, +until a call to restart it. +</li> + +<li><b>"<code>restart</code>": </b> +Restarts automatic execution of the garbage collector. +</li> + +<li><b>"<code>count</code>": </b> +Returns the total memory in use by Lua in Kbytes. +The value has a fractional part, +so that it multiplied by 1024 +gives the exact number of bytes in use by Lua. +</li> + +<li><b>"<code>step</code>": </b> +Performs a garbage-collection step. +The step "size" is controlled by <code>arg</code>. +With a zero value, +the collector will perform one basic (indivisible) step. +For non-zero values, +the collector will perform as if that amount of memory +(in Kbytes) had been allocated by Lua. +Returns <b>true</b> if the step finished a collection cycle. +</li> + +<li><b>"<code>isrunning</code>": </b> +Returns a boolean that tells whether the collector is running +(i.e., not stopped). +</li> + +<li><b>"<code>incremental</code>": </b> +Change the collector mode to incremental. +This option can be followed by three numbers: +the garbage-collector pause, +the step multiplier, +and the step size (see <a href="#2.5.1">§2.5.1</a>). +A zero means to not change that value. +</li> + +<li><b>"<code>generational</code>": </b> +Change the collector mode to generational. +This option can be followed by two numbers: +the garbage-collector minor multiplier +and the major multiplier (see <a href="#2.5.2">§2.5.2</a>). +A zero means to not change that value. +</li> + +</ul><p> +See <a href="#2.5">§2.5</a> for more details about garbage collection +and some of these options. + + +<p> +This function should not be called by a finalizer. + + + + +<p> +<hr><h3><a name="pdf-dofile"><code>dofile ([filename])</code></a></h3> +Opens the named file and executes its content as a Lua chunk. +When called without arguments, +<code>dofile</code> executes the content of the standard input (<code>stdin</code>). +Returns all values returned by the chunk. +In case of errors, <code>dofile</code> propagates the error +to its caller. +(That is, <code>dofile</code> does not run in protected mode.) + + + + +<p> +<hr><h3><a name="pdf-error"><code>error (message [, level])</code></a></h3> +Raises an error (see <a href="#2.3">§2.3</a>) with <code>message</code> as the error object. +This function never returns. + + +<p> +Usually, <code>error</code> adds some information about the error position +at the beginning of the message, if the message is a string. +The <code>level</code> argument specifies how to get the error position. +With level 1 (the default), the error position is where the +<code>error</code> function was called. +Level 2 points the error to where the function +that called <code>error</code> was called; and so on. +Passing a level 0 avoids the addition of error position information +to the message. + + + + +<p> +<hr><h3><a name="pdf-_G"><code>_G</code></a></h3> +A global variable (not a function) that +holds the global environment (see <a href="#2.2">§2.2</a>). +Lua itself does not use this variable; +changing its value does not affect any environment, +nor vice versa. + + + + +<p> +<hr><h3><a name="pdf-getmetatable"><code>getmetatable (object)</code></a></h3> + + +<p> +If <code>object</code> does not have a metatable, returns <b>nil</b>. +Otherwise, +if the object's metatable has a <code>__metatable</code> field, +returns the associated value. +Otherwise, returns the metatable of the given object. + + + + +<p> +<hr><h3><a name="pdf-ipairs"><code>ipairs (t)</code></a></h3> + + +<p> +Returns three values (an iterator function, the table <code>t</code>, and 0) +so that the construction + +<pre> + for i,v in ipairs(t) do <em>body</em> end +</pre><p> +will iterate over the key–value pairs +(<code>1,t[1]</code>), (<code>2,t[2]</code>), ..., +up to the first absent index. + + + + +<p> +<hr><h3><a name="pdf-load"><code>load (chunk [, chunkname [, mode [, env]]])</code></a></h3> + + +<p> +Loads a chunk. + + +<p> +If <code>chunk</code> is a string, the chunk is this string. +If <code>chunk</code> is a function, +<code>load</code> calls it repeatedly to get the chunk pieces. +Each call to <code>chunk</code> must return a string that concatenates +with previous results. +A return of an empty string, <b>nil</b>, or no value signals the end of the chunk. + + +<p> +If there are no syntactic errors, +<code>load</code> returns the compiled chunk as a function; +otherwise, it returns <b>fail</b> plus the error message. + + +<p> +When you load a main chunk, +the resulting function will always have exactly one upvalue, +the <code>_ENV</code> variable (see <a href="#2.2">§2.2</a>). +However, +when you load a binary chunk created from a function (see <a href="#pdf-string.dump"><code>string.dump</code></a>), +the resulting function can have an arbitrary number of upvalues, +and there is no guarantee that its first upvalue will be +the <code>_ENV</code> variable. +(A non-main function may not even have an <code>_ENV</code> upvalue.) + + +<p> +Regardless, if the resulting function has any upvalues, +its first upvalue is set to the value of <code>env</code>, +if that parameter is given, +or to the value of the global environment. +Other upvalues are initialized with <b>nil</b>. +All upvalues are fresh, that is, +they are not shared with any other function. + + +<p> +<code>chunkname</code> is used as the name of the chunk for error messages +and debug information (see <a href="#4.7">§4.7</a>). +When absent, +it defaults to <code>chunk</code>, if <code>chunk</code> is a string, +or to "<code>=(load)</code>" otherwise. + + +<p> +The string <code>mode</code> controls whether the chunk can be text or binary +(that is, a precompiled chunk). +It may be the string "<code>b</code>" (only binary chunks), +"<code>t</code>" (only text chunks), +or "<code>bt</code>" (both binary and text). +The default is "<code>bt</code>". + + +<p> +It is safe to load malformed binary chunks; +<code>load</code> signals an appropriate error. +However, +Lua does not check the consistency of the code inside binary chunks; +running maliciously crafted bytecode can crash the interpreter. + + + + +<p> +<hr><h3><a name="pdf-loadfile"><code>loadfile ([filename [, mode [, env]]])</code></a></h3> + + +<p> +Similar to <a href="#pdf-load"><code>load</code></a>, +but gets the chunk from file <code>filename</code> +or from the standard input, +if no file name is given. + + + + +<p> +<hr><h3><a name="pdf-next"><code>next (table [, index])</code></a></h3> + + +<p> +Allows a program to traverse all fields of a table. +Its first argument is a table and its second argument +is an index in this table. +A call to <code>next</code> returns the next index of the table +and its associated value. +When called with <b>nil</b> as its second argument, +<code>next</code> returns an initial index +and its associated value. +When called with the last index, +or with <b>nil</b> in an empty table, +<code>next</code> returns <b>nil</b>. +If the second argument is absent, then it is interpreted as <b>nil</b>. +In particular, +you can use <code>next(t)</code> to check whether a table is empty. + + +<p> +The order in which the indices are enumerated is not specified, +<em>even for numeric indices</em>. +(To traverse a table in numerical order, +use a numerical <b>for</b>.) + + +<p> +You should not assign any value to a non-existent field in a table +during its traversal. +You may however modify existing fields. +In particular, you may set existing fields to nil. + + + + +<p> +<hr><h3><a name="pdf-pairs"><code>pairs (t)</code></a></h3> + + +<p> +If <code>t</code> has a metamethod <code>__pairs</code>, +calls it with <code>t</code> as argument and returns the first three +results from the call. + + +<p> +Otherwise, +returns three values: the <a href="#pdf-next"><code>next</code></a> function, the table <code>t</code>, and <b>nil</b>, +so that the construction + +<pre> + for k,v in pairs(t) do <em>body</em> end +</pre><p> +will iterate over all key–value pairs of table <code>t</code>. + + +<p> +See function <a href="#pdf-next"><code>next</code></a> for the caveats of modifying +the table during its traversal. + + + + +<p> +<hr><h3><a name="pdf-pcall"><code>pcall (f [, arg1, ···])</code></a></h3> + + +<p> +Calls the function <code>f</code> with +the given arguments in <em>protected mode</em>. +This means that any error inside <code>f</code> is not propagated; +instead, <code>pcall</code> catches the error +and returns a status code. +Its first result is the status code (a boolean), +which is <b>true</b> if the call succeeds without errors. +In such case, <code>pcall</code> also returns all results from the call, +after this first result. +In case of any error, <code>pcall</code> returns <b>false</b> plus the error object. +Note that errors caught by <code>pcall</code> do not call a message handler. + + + + +<p> +<hr><h3><a name="pdf-print"><code>print (···)</code></a></h3> +Receives any number of arguments +and prints their values to <code>stdout</code>, +converting each argument to a string +following the same rules of <a href="#pdf-tostring"><code>tostring</code></a>. + + +<p> +The function <code>print</code> is not intended for formatted output, +but only as a quick way to show a value, +for instance for debugging. +For complete control over the output, +use <a href="#pdf-string.format"><code>string.format</code></a> and <a href="#pdf-io.write"><code>io.write</code></a>. + + + + +<p> +<hr><h3><a name="pdf-rawequal"><code>rawequal (v1, v2)</code></a></h3> +Checks whether <code>v1</code> is equal to <code>v2</code>, +without invoking the <code>__eq</code> metamethod. +Returns a boolean. + + + + +<p> +<hr><h3><a name="pdf-rawget"><code>rawget (table, index)</code></a></h3> +Gets the real value of <code>table[index]</code>, +without using the <code>__index</code> metavalue. +<code>table</code> must be a table; +<code>index</code> may be any value. + + + + +<p> +<hr><h3><a name="pdf-rawlen"><code>rawlen (v)</code></a></h3> +Returns the length of the object <code>v</code>, +which must be a table or a string, +without invoking the <code>__len</code> metamethod. +Returns an integer. + + + + +<p> +<hr><h3><a name="pdf-rawset"><code>rawset (table, index, value)</code></a></h3> +Sets the real value of <code>table[index]</code> to <code>value</code>, +without using the <code>__newindex</code> metavalue. +<code>table</code> must be a table, +<code>index</code> any value different from <b>nil</b> and NaN, +and <code>value</code> any Lua value. + + +<p> +This function returns <code>table</code>. + + + + +<p> +<hr><h3><a name="pdf-select"><code>select (index, ···)</code></a></h3> + + +<p> +If <code>index</code> is a number, +returns all arguments after argument number <code>index</code>; +a negative number indexes from the end (-1 is the last argument). +Otherwise, <code>index</code> must be the string <code>"#"</code>, +and <code>select</code> returns the total number of extra arguments it received. + + + + +<p> +<hr><h3><a name="pdf-setmetatable"><code>setmetatable (table, metatable)</code></a></h3> + + +<p> +Sets the metatable for the given table. +If <code>metatable</code> is <b>nil</b>, +removes the metatable of the given table. +If the original metatable has a <code>__metatable</code> field, +raises an error. + + +<p> +This function returns <code>table</code>. + + +<p> +To change the metatable of other types from Lua code, +you must use the debug library (<a href="#6.10">§6.10</a>). + + + + +<p> +<hr><h3><a name="pdf-tonumber"><code>tonumber (e [, base])</code></a></h3> + + +<p> +When called with no <code>base</code>, +<code>tonumber</code> tries to convert its argument to a number. +If the argument is already a number or +a string convertible to a number, +then <code>tonumber</code> returns this number; +otherwise, it returns <b>fail</b>. + + +<p> +The conversion of strings can result in integers or floats, +according to the lexical conventions of Lua (see <a href="#3.1">§3.1</a>). +The string may have leading and trailing spaces and a sign. + + +<p> +When called with <code>base</code>, +then <code>e</code> must be a string to be interpreted as +an integer numeral in that base. +The base may be any integer between 2 and 36, inclusive. +In bases above 10, the letter '<code>A</code>' (in either upper or lower case) +represents 10, '<code>B</code>' represents 11, and so forth, +with '<code>Z</code>' representing 35. +If the string <code>e</code> is not a valid numeral in the given base, +the function returns <b>fail</b>. + + + + +<p> +<hr><h3><a name="pdf-tostring"><code>tostring (v)</code></a></h3> + + +<p> +Receives a value of any type and +converts it to a string in a human-readable format. + + +<p> +If the metatable of <code>v</code> has a <code>__tostring</code> field, +then <code>tostring</code> calls the corresponding value +with <code>v</code> as argument, +and uses the result of the call as its result. +Otherwise, if the metatable of <code>v</code> has a <code>__name</code> field +with a string value, +<code>tostring</code> may use that string in its final result. + + +<p> +For complete control of how numbers are converted, +use <a href="#pdf-string.format"><code>string.format</code></a>. + + + + +<p> +<hr><h3><a name="pdf-type"><code>type (v)</code></a></h3> + + +<p> +Returns the type of its only argument, coded as a string. +The possible results of this function are +"<code>nil</code>" (a string, not the value <b>nil</b>), +"<code>number</code>", +"<code>string</code>", +"<code>boolean</code>", +"<code>table</code>", +"<code>function</code>", +"<code>thread</code>", +and "<code>userdata</code>". + + + + +<p> +<hr><h3><a name="pdf-_VERSION"><code>_VERSION</code></a></h3> + + +<p> +A global variable (not a function) that +holds a string containing the running Lua version. +The current value of this variable is "<code>Lua 5.4</code>". + + + + +<p> +<hr><h3><a name="pdf-warn"><code>warn (msg1, ···)</code></a></h3> + + +<p> +Emits a warning with a message composed by the concatenation +of all its arguments (which should be strings). + + +<p> +By convention, +a one-piece message starting with '<code>@</code>' +is intended to be a <em>control message</em>, +which is a message to the warning system itself. +In particular, the standard warning function in Lua +recognizes the control messages "<code>@off</code>", +to stop the emission of warnings, +and "<code>@on</code>", to (re)start the emission; +it ignores unknown control messages. + + + + +<p> +<hr><h3><a name="pdf-xpcall"><code>xpcall (f, msgh [, arg1, ···])</code></a></h3> + + +<p> +This function is similar to <a href="#pdf-pcall"><code>pcall</code></a>, +except that it sets a new message handler <code>msgh</code>. + + + + + + + +<h2>6.2 – <a name="6.2">Coroutine Manipulation</a></h2> + +<p> +This library comprises the operations to manipulate coroutines, +which come inside the table <a name="pdf-coroutine"><code>coroutine</code></a>. +See <a href="#2.6">§2.6</a> for a general description of coroutines. + + +<p> +<hr><h3><a name="pdf-coroutine.close"><code>coroutine.close (co)</code></a></h3> + + +<p> +Closes coroutine <code>co</code>, +that is, +closes all its pending to-be-closed variables +and puts the coroutine in a dead state. +The given coroutine must be dead or suspended. +In case of error +(either the original error that stopped the coroutine or +errors in closing methods), +returns <b>false</b> plus the error object; +otherwise returns <b>true</b>. + + + + +<p> +<hr><h3><a name="pdf-coroutine.create"><code>coroutine.create (f)</code></a></h3> + + +<p> +Creates a new coroutine, with body <code>f</code>. +<code>f</code> must be a function. +Returns this new coroutine, +an object with type <code>"thread"</code>. + + + + +<p> +<hr><h3><a name="pdf-coroutine.isyieldable"><code>coroutine.isyieldable ([co])</code></a></h3> + + +<p> +Returns <b>true</b> when the coroutine <code>co</code> can yield. +The default for <code>co</code> is the running coroutine. + + +<p> +A coroutine is yieldable if it is not the main thread and +it is not inside a non-yieldable C function. + + + + +<p> +<hr><h3><a name="pdf-coroutine.resume"><code>coroutine.resume (co [, val1, ···])</code></a></h3> + + +<p> +Starts or continues the execution of coroutine <code>co</code>. +The first time you resume a coroutine, +it starts running its body. +The values <code>val1</code>, ... are passed +as the arguments to the body function. +If the coroutine has yielded, +<code>resume</code> restarts it; +the values <code>val1</code>, ... are passed +as the results from the yield. + + +<p> +If the coroutine runs without any errors, +<code>resume</code> returns <b>true</b> plus any values passed to <code>yield</code> +(when the coroutine yields) or any values returned by the body function +(when the coroutine terminates). +If there is any error, +<code>resume</code> returns <b>false</b> plus the error message. + + + + +<p> +<hr><h3><a name="pdf-coroutine.running"><code>coroutine.running ()</code></a></h3> + + +<p> +Returns the running coroutine plus a boolean, +<b>true</b> when the running coroutine is the main one. + + + + +<p> +<hr><h3><a name="pdf-coroutine.status"><code>coroutine.status (co)</code></a></h3> + + +<p> +Returns the status of the coroutine <code>co</code>, as a string: +<code>"running"</code>, +if the coroutine is running +(that is, it is the one that called <code>status</code>); +<code>"suspended"</code>, if the coroutine is suspended in a call to <code>yield</code>, +or if it has not started running yet; +<code>"normal"</code> if the coroutine is active but not running +(that is, it has resumed another coroutine); +and <code>"dead"</code> if the coroutine has finished its body function, +or if it has stopped with an error. + + + + +<p> +<hr><h3><a name="pdf-coroutine.wrap"><code>coroutine.wrap (f)</code></a></h3> + + +<p> +Creates a new coroutine, with body <code>f</code>; +<code>f</code> must be a function. +Returns a function that resumes the coroutine each time it is called. +Any arguments passed to this function behave as the +extra arguments to <code>resume</code>. +The function returns the same values returned by <code>resume</code>, +except the first boolean. +In case of error, +the function closes the coroutine and propagates the error. + + + + +<p> +<hr><h3><a name="pdf-coroutine.yield"><code>coroutine.yield (···)</code></a></h3> + + +<p> +Suspends the execution of the calling coroutine. +Any arguments to <code>yield</code> are passed as extra results to <code>resume</code>. + + + + + + + +<h2>6.3 – <a name="6.3">Modules</a></h2> + +<p> +The package library provides basic +facilities for loading modules in Lua. +It exports one function directly in the global environment: +<a href="#pdf-require"><code>require</code></a>. +Everything else is exported in the table <a name="pdf-package"><code>package</code></a>. + + +<p> +<hr><h3><a name="pdf-require"><code>require (modname)</code></a></h3> + + +<p> +Loads the given module. +The function starts by looking into the <a href="#pdf-package.loaded"><code>package.loaded</code></a> table +to determine whether <code>modname</code> is already loaded. +If it is, then <code>require</code> returns the value stored +at <code>package.loaded[modname]</code>. +(The absence of a second result in this case +signals that this call did not have to load the module.) +Otherwise, it tries to find a <em>loader</em> for the module. + + +<p> +To find a loader, +<code>require</code> is guided by the table <a href="#pdf-package.searchers"><code>package.searchers</code></a>. +Each item in this table is a search function, +that searches for the module in a particular way. +By changing this table, +we can change how <code>require</code> looks for a module. +The following explanation is based on the default configuration +for <a href="#pdf-package.searchers"><code>package.searchers</code></a>. + + +<p> +First <code>require</code> queries <code>package.preload[modname]</code>. +If it has a value, +this value (which must be a function) is the loader. +Otherwise <code>require</code> searches for a Lua loader using the +path stored in <a href="#pdf-package.path"><code>package.path</code></a>. +If that also fails, it searches for a C loader using the +path stored in <a href="#pdf-package.cpath"><code>package.cpath</code></a>. +If that also fails, +it tries an <em>all-in-one</em> loader (see <a href="#pdf-package.searchers"><code>package.searchers</code></a>). + + +<p> +Once a loader is found, +<code>require</code> calls the loader with two arguments: +<code>modname</code> and an extra value, +a <em>loader data</em>, +also returned by the searcher. +The loader data can be any value useful to the module; +for the default searchers, +it indicates where the loader was found. +(For instance, if the loader came from a file, +this extra value is the file path.) +If the loader returns any non-nil value, +<code>require</code> assigns the returned value to <code>package.loaded[modname]</code>. +If the loader does not return a non-nil value and +has not assigned any value to <code>package.loaded[modname]</code>, +then <code>require</code> assigns <b>true</b> to this entry. +In any case, <code>require</code> returns the +final value of <code>package.loaded[modname]</code>. +Besides that value, <code>require</code> also returns as a second result +the loader data returned by the searcher, +which indicates how <code>require</code> found the module. + + +<p> +If there is any error loading or running the module, +or if it cannot find any loader for the module, +then <code>require</code> raises an error. + + + + +<p> +<hr><h3><a name="pdf-package.config"><code>package.config</code></a></h3> + + +<p> +A string describing some compile-time configurations for packages. +This string is a sequence of lines: + +<ul> + +<li>The first line is the directory separator string. +Default is '<code>\</code>' for Windows and '<code>/</code>' for all other systems.</li> + +<li>The second line is the character that separates templates in a path. +Default is '<code>;</code>'.</li> + +<li>The third line is the string that marks the +substitution points in a template. +Default is '<code>?</code>'.</li> + +<li>The fourth line is a string that, in a path in Windows, +is replaced by the executable's directory. +Default is '<code>!</code>'.</li> + +<li>The fifth line is a mark to ignore all text after it +when building the <code>luaopen_</code> function name. +Default is '<code>-</code>'.</li> + +</ul> + + + +<p> +<hr><h3><a name="pdf-package.cpath"><code>package.cpath</code></a></h3> + + +<p> +A string with the path used by <a href="#pdf-require"><code>require</code></a> +to search for a C loader. + + +<p> +Lua initializes the C path <a href="#pdf-package.cpath"><code>package.cpath</code></a> in the same way +it initializes the Lua path <a href="#pdf-package.path"><code>package.path</code></a>, +using the environment variable <a name="pdf-LUA_CPATH_5_4"><code>LUA_CPATH_5_4</code></a>, +or the environment variable <a name="pdf-LUA_CPATH"><code>LUA_CPATH</code></a>, +or a default path defined in <code>luaconf.h</code>. + + + + +<p> +<hr><h3><a name="pdf-package.loaded"><code>package.loaded</code></a></h3> + + +<p> +A table used by <a href="#pdf-require"><code>require</code></a> to control which +modules are already loaded. +When you require a module <code>modname</code> and +<code>package.loaded[modname]</code> is not false, +<a href="#pdf-require"><code>require</code></a> simply returns the value stored there. + + +<p> +This variable is only a reference to the real table; +assignments to this variable do not change the +table used by <a href="#pdf-require"><code>require</code></a>. +The real table is stored in the C registry (see <a href="#4.3">§4.3</a>), +indexed by the key <a name="pdf-LUA_LOADED_TABLE"><code>LUA_LOADED_TABLE</code></a>, a string. + + + + +<p> +<hr><h3><a name="pdf-package.loadlib"><code>package.loadlib (libname, funcname)</code></a></h3> + + +<p> +Dynamically links the host program with the C library <code>libname</code>. + + +<p> +If <code>funcname</code> is "<code>*</code>", +then it only links with the library, +making the symbols exported by the library +available to other dynamically linked libraries. +Otherwise, +it looks for a function <code>funcname</code> inside the library +and returns this function as a C function. +So, <code>funcname</code> must follow the <a href="#lua_CFunction"><code>lua_CFunction</code></a> prototype +(see <a href="#lua_CFunction"><code>lua_CFunction</code></a>). + + +<p> +This is a low-level function. +It completely bypasses the package and module system. +Unlike <a href="#pdf-require"><code>require</code></a>, +it does not perform any path searching and +does not automatically adds extensions. +<code>libname</code> must be the complete file name of the C library, +including if necessary a path and an extension. +<code>funcname</code> must be the exact name exported by the C library +(which may depend on the C compiler and linker used). + + +<p> +This functionality is not supported by ISO C. +As such, it is only available on some platforms +(Windows, Linux, Mac OS X, Solaris, BSD, +plus other Unix systems that support the <code>dlfcn</code> standard). + + +<p> +This function is inherently insecure, +as it allows Lua to call any function in any readable dynamic +library in the system. +(Lua calls any function assuming the function +has a proper prototype and respects a proper protocol +(see <a href="#lua_CFunction"><code>lua_CFunction</code></a>). +Therefore, +calling an arbitrary function in an arbitrary dynamic library +more often than not results in an access violation.) + + + + +<p> +<hr><h3><a name="pdf-package.path"><code>package.path</code></a></h3> + + +<p> +A string with the path used by <a href="#pdf-require"><code>require</code></a> +to search for a Lua loader. + + +<p> +At start-up, Lua initializes this variable with +the value of the environment variable <a name="pdf-LUA_PATH_5_4"><code>LUA_PATH_5_4</code></a> or +the environment variable <a name="pdf-LUA_PATH"><code>LUA_PATH</code></a> or +with a default path defined in <code>luaconf.h</code>, +if those environment variables are not defined. +A "<code>;;</code>" in the value of the environment variable +is replaced by the default path. + + + + +<p> +<hr><h3><a name="pdf-package.preload"><code>package.preload</code></a></h3> + + +<p> +A table to store loaders for specific modules +(see <a href="#pdf-require"><code>require</code></a>). + + +<p> +This variable is only a reference to the real table; +assignments to this variable do not change the +table used by <a href="#pdf-require"><code>require</code></a>. +The real table is stored in the C registry (see <a href="#4.3">§4.3</a>), +indexed by the key <a name="pdf-LUA_PRELOAD_TABLE"><code>LUA_PRELOAD_TABLE</code></a>, a string. + + + + +<p> +<hr><h3><a name="pdf-package.searchers"><code>package.searchers</code></a></h3> + + +<p> +A table used by <a href="#pdf-require"><code>require</code></a> to control how to find modules. + + +<p> +Each entry in this table is a <em>searcher function</em>. +When looking for a module, +<a href="#pdf-require"><code>require</code></a> calls each of these searchers in ascending order, +with the module name (the argument given to <a href="#pdf-require"><code>require</code></a>) as its +sole argument. +If the searcher finds the module, +it returns another function, the module <em>loader</em>, +plus an extra value, a <em>loader data</em>, +that will be passed to that loader and +returned as a second result by <a href="#pdf-require"><code>require</code></a>. +If it cannot find the module, +it returns a string explaining why +(or <b>nil</b> if it has nothing to say). + + +<p> +Lua initializes this table with four searcher functions. + + +<p> +The first searcher simply looks for a loader in the +<a href="#pdf-package.preload"><code>package.preload</code></a> table. + + +<p> +The second searcher looks for a loader as a Lua library, +using the path stored at <a href="#pdf-package.path"><code>package.path</code></a>. +The search is done as described in function <a href="#pdf-package.searchpath"><code>package.searchpath</code></a>. + + +<p> +The third searcher looks for a loader as a C library, +using the path given by the variable <a href="#pdf-package.cpath"><code>package.cpath</code></a>. +Again, +the search is done as described in function <a href="#pdf-package.searchpath"><code>package.searchpath</code></a>. +For instance, +if the C path is the string + +<pre> + "./?.so;./?.dll;/usr/local/?/init.so" +</pre><p> +the searcher for module <code>foo</code> +will try to open the files <code>./foo.so</code>, <code>./foo.dll</code>, +and <code>/usr/local/foo/init.so</code>, in that order. +Once it finds a C library, +this searcher first uses a dynamic link facility to link the +application with the library. +Then it tries to find a C function inside the library to +be used as the loader. +The name of this C function is the string "<code>luaopen_</code>" +concatenated with a copy of the module name where each dot +is replaced by an underscore. +Moreover, if the module name has a hyphen, +its suffix after (and including) the first hyphen is removed. +For instance, if the module name is <code>a.b.c-v2.1</code>, +the function name will be <code>luaopen_a_b_c</code>. + + +<p> +The fourth searcher tries an <em>all-in-one loader</em>. +It searches the C path for a library for +the root name of the given module. +For instance, when requiring <code>a.b.c</code>, +it will search for a C library for <code>a</code>. +If found, it looks into it for an open function for +the submodule; +in our example, that would be <code>luaopen_a_b_c</code>. +With this facility, a package can pack several C submodules +into one single library, +with each submodule keeping its original open function. + + +<p> +All searchers except the first one (preload) return as the extra value +the file path where the module was found, +as returned by <a href="#pdf-package.searchpath"><code>package.searchpath</code></a>. +The first searcher always returns the string "<code>:preload:</code>". + + +<p> +Searchers should raise no errors and have no side effects in Lua. +(They may have side effects in C, +for instance by linking the application with a library.) + + + + +<p> +<hr><h3><a name="pdf-package.searchpath"><code>package.searchpath (name, path [, sep [, rep]])</code></a></h3> + + +<p> +Searches for the given <code>name</code> in the given <code>path</code>. + + +<p> +A path is a string containing a sequence of +<em>templates</em> separated by semicolons. +For each template, +the function replaces each interrogation mark (if any) +in the template with a copy of <code>name</code> +wherein all occurrences of <code>sep</code> +(a dot, by default) +were replaced by <code>rep</code> +(the system's directory separator, by default), +and then tries to open the resulting file name. + + +<p> +For instance, if the path is the string + +<pre> + "./?.lua;./?.lc;/usr/local/?/init.lua" +</pre><p> +the search for the name <code>foo.a</code> +will try to open the files +<code>./foo/a.lua</code>, <code>./foo/a.lc</code>, and +<code>/usr/local/foo/a/init.lua</code>, in that order. + + +<p> +Returns the resulting name of the first file that it can +open in read mode (after closing the file), +or <b>fail</b> plus an error message if none succeeds. +(This error message lists all file names it tried to open.) + + + + + + + +<h2>6.4 – <a name="6.4">String Manipulation</a></h2> + + + +<p> +This library provides generic functions for string manipulation, +such as finding and extracting substrings, and pattern matching. +When indexing a string in Lua, the first character is at position 1 +(not at 0, as in C). +Indices are allowed to be negative and are interpreted as indexing backwards, +from the end of the string. +Thus, the last character is at position -1, and so on. + + +<p> +The string library provides all its functions inside the table +<a name="pdf-string"><code>string</code></a>. +It also sets a metatable for strings +where the <code>__index</code> field points to the <code>string</code> table. +Therefore, you can use the string functions in object-oriented style. +For instance, <code>string.byte(s,i)</code> +can be written as <code>s:byte(i)</code>. + + +<p> +The string library assumes one-byte character encodings. + + +<p> +<hr><h3><a name="pdf-string.byte"><code>string.byte (s [, i [, j]])</code></a></h3> +Returns the internal numeric codes of the characters <code>s[i]</code>, +<code>s[i+1]</code>, ..., <code>s[j]</code>. +The default value for <code>i</code> is 1; +the default value for <code>j</code> is <code>i</code>. +These indices are corrected +following the same rules of function <a href="#pdf-string.sub"><code>string.sub</code></a>. + + +<p> +Numeric codes are not necessarily portable across platforms. + + + + +<p> +<hr><h3><a name="pdf-string.char"><code>string.char (···)</code></a></h3> +Receives zero or more integers. +Returns a string with length equal to the number of arguments, +in which each character has the internal numeric code equal +to its corresponding argument. + + +<p> +Numeric codes are not necessarily portable across platforms. + + + + +<p> +<hr><h3><a name="pdf-string.dump"><code>string.dump (function [, strip])</code></a></h3> + + +<p> +Returns a string containing a binary representation +(a <em>binary chunk</em>) +of the given function, +so that a later <a href="#pdf-load"><code>load</code></a> on this string returns +a copy of the function (but with new upvalues). +If <code>strip</code> is a true value, +the binary representation may not include all debug information +about the function, +to save space. + + +<p> +Functions with upvalues have only their number of upvalues saved. +When (re)loaded, +those upvalues receive fresh instances. +(See the <a href="#pdf-load"><code>load</code></a> function for details about +how these upvalues are initialized. +You can use the debug library to serialize +and reload the upvalues of a function +in a way adequate to your needs.) + + + + +<p> +<hr><h3><a name="pdf-string.find"><code>string.find (s, pattern [, init [, plain]])</code></a></h3> + + +<p> +Looks for the first match of +<code>pattern</code> (see <a href="#6.4.1">§6.4.1</a>) in the string <code>s</code>. +If it finds a match, then <code>find</code> returns the indices of <code>s</code> +where this occurrence starts and ends; +otherwise, it returns <b>fail</b>. +A third, optional numeric argument <code>init</code> specifies +where to start the search; +its default value is 1 and can be negative. +A <b>true</b> as a fourth, optional argument <code>plain</code> +turns off the pattern matching facilities, +so the function does a plain "find substring" operation, +with no characters in <code>pattern</code> being considered magic. + + +<p> +If the pattern has captures, +then in a successful match +the captured values are also returned, +after the two indices. + + + + +<p> +<hr><h3><a name="pdf-string.format"><code>string.format (formatstring, ···)</code></a></h3> + + +<p> +Returns a formatted version of its variable number of arguments +following the description given in its first argument, +which must be a string. +The format string follows the same rules as the ISO C function <code>sprintf</code>. +The only differences are that the conversion specifiers and modifiers +<code>F</code>, <code>n</code>, <code>*</code>, <code>h</code>, <code>L</code>, and <code>l</code> are not supported +and that there is an extra specifier, <code>q</code>. +Both width and precision, when present, +are limited to two digits. + + +<p> +The specifier <code>q</code> formats booleans, nil, numbers, and strings +in a way that the result is a valid constant in Lua source code. +Booleans and nil are written in the obvious way +(<code>true</code>, <code>false</code>, <code>nil</code>). +Floats are written in hexadecimal, +to preserve full precision. +A string is written between double quotes, +using escape sequences when necessary to ensure that +it can safely be read back by the Lua interpreter. +For instance, the call + +<pre> + string.format('%q', 'a string with "quotes" and \n new line') +</pre><p> +may produce the string: + +<pre> + "a string with \"quotes\" and \ + new line" +</pre><p> +This specifier does not support modifiers (flags, width, precision). + + +<p> +The conversion specifiers +<code>A</code>, <code>a</code>, <code>E</code>, <code>e</code>, <code>f</code>, +<code>G</code>, and <code>g</code> all expect a number as argument. +The specifiers <code>c</code>, <code>d</code>, +<code>i</code>, <code>o</code>, <code>u</code>, <code>X</code>, and <code>x</code> +expect an integer. +When Lua is compiled with a C89 compiler, +the specifiers <code>A</code> and <code>a</code> (hexadecimal floats) +do not support modifiers. + + +<p> +The specifier <code>s</code> expects a string; +if its argument is not a string, +it is converted to one following the same rules of <a href="#pdf-tostring"><code>tostring</code></a>. +If the specifier has any modifier, +the corresponding string argument should not contain embedded zeros. + + +<p> +The specifier <code>p</code> formats the pointer +returned by <a href="#lua_topointer"><code>lua_topointer</code></a>. +That gives a unique string identifier for tables, userdata, +threads, strings, and functions. +For other values (numbers, nil, booleans), +this specifier results in a string representing +the pointer <code>NULL</code>. + + + + +<p> +<hr><h3><a name="pdf-string.gmatch"><code>string.gmatch (s, pattern [, init])</code></a></h3> +Returns an iterator function that, +each time it is called, +returns the next captures from <code>pattern</code> (see <a href="#6.4.1">§6.4.1</a>) +over the string <code>s</code>. +If <code>pattern</code> specifies no captures, +then the whole match is produced in each call. +A third, optional numeric argument <code>init</code> specifies +where to start the search; +its default value is 1 and can be negative. + + +<p> +As an example, the following loop +will iterate over all the words from string <code>s</code>, +printing one per line: + +<pre> + s = "hello world from Lua" + for w in string.gmatch(s, "%a+") do + print(w) + end +</pre><p> +The next example collects all pairs <code>key=value</code> from the +given string into a table: + +<pre> + t = {} + s = "from=world, to=Lua" + for k, v in string.gmatch(s, "(%w+)=(%w+)") do + t[k] = v + end +</pre> + +<p> +For this function, a caret '<code>^</code>' at the start of a pattern does not +work as an anchor, as this would prevent the iteration. + + + + +<p> +<hr><h3><a name="pdf-string.gsub"><code>string.gsub (s, pattern, repl [, n])</code></a></h3> +Returns a copy of <code>s</code> +in which all (or the first <code>n</code>, if given) +occurrences of the <code>pattern</code> (see <a href="#6.4.1">§6.4.1</a>) have been +replaced by a replacement string specified by <code>repl</code>, +which can be a string, a table, or a function. +<code>gsub</code> also returns, as its second value, +the total number of matches that occurred. +The name <code>gsub</code> comes from <em>Global SUBstitution</em>. + + +<p> +If <code>repl</code> is a string, then its value is used for replacement. +The character <code>%</code> works as an escape character: +any sequence in <code>repl</code> of the form <code>%<em>d</em></code>, +with <em>d</em> between 1 and 9, +stands for the value of the <em>d</em>-th captured substring; +the sequence <code>%0</code> stands for the whole match; +the sequence <code>%%</code> stands for a single <code>%</code>. + + +<p> +If <code>repl</code> is a table, then the table is queried for every match, +using the first capture as the key. + + +<p> +If <code>repl</code> is a function, then this function is called every time a +match occurs, with all captured substrings passed as arguments, +in order. + + +<p> +In any case, +if the pattern specifies no captures, +then it behaves as if the whole pattern was inside a capture. + + +<p> +If the value returned by the table query or by the function call +is a string or a number, +then it is used as the replacement string; +otherwise, if it is <b>false</b> or <b>nil</b>, +then there is no replacement +(that is, the original match is kept in the string). + + +<p> +Here are some examples: + +<pre> + x = string.gsub("hello world", "(%w+)", "%1 %1") + --> x="hello hello world world" + + x = string.gsub("hello world", "%w+", "%0 %0", 1) + --> x="hello hello world" + + x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1") + --> x="world hello Lua from" + + x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv) + --> x="home = /home/roberto, user = roberto" + + x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s) + return load(s)() + end) + --> x="4+5 = 9" + + local t = {name="lua", version="5.4"} + x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t) + --> x="lua-5.4.tar.gz" +</pre> + + + +<p> +<hr><h3><a name="pdf-string.len"><code>string.len (s)</code></a></h3> + + +<p> +Receives a string and returns its length. +The empty string <code>""</code> has length 0. +Embedded zeros are counted, +so <code>"a\000bc\000"</code> has length 5. + + + + +<p> +<hr><h3><a name="pdf-string.lower"><code>string.lower (s)</code></a></h3> + + +<p> +Receives a string and returns a copy of this string with all +uppercase letters changed to lowercase. +All other characters are left unchanged. +The definition of what an uppercase letter is depends on the current locale. + + + + +<p> +<hr><h3><a name="pdf-string.match"><code>string.match (s, pattern [, init])</code></a></h3> + + +<p> +Looks for the first <em>match</em> of +the <code>pattern</code> (see <a href="#6.4.1">§6.4.1</a>) in the string <code>s</code>. +If it finds one, then <code>match</code> returns +the captures from the pattern; +otherwise it returns <b>fail</b>. +If <code>pattern</code> specifies no captures, +then the whole match is returned. +A third, optional numeric argument <code>init</code> specifies +where to start the search; +its default value is 1 and can be negative. + + + + +<p> +<hr><h3><a name="pdf-string.pack"><code>string.pack (fmt, v1, v2, ···)</code></a></h3> + + +<p> +Returns a binary string containing the values <code>v1</code>, <code>v2</code>, etc. +serialized in binary form (packed) +according to the format string <code>fmt</code> (see <a href="#6.4.2">§6.4.2</a>). + + + + +<p> +<hr><h3><a name="pdf-string.packsize"><code>string.packsize (fmt)</code></a></h3> + + +<p> +Returns the length of a string resulting from <a href="#pdf-string.pack"><code>string.pack</code></a> +with the given format. +The format string cannot have the variable-length options +'<code>s</code>' or '<code>z</code>' (see <a href="#6.4.2">§6.4.2</a>). + + + + +<p> +<hr><h3><a name="pdf-string.rep"><code>string.rep (s, n [, sep])</code></a></h3> + + +<p> +Returns a string that is the concatenation of <code>n</code> copies of +the string <code>s</code> separated by the string <code>sep</code>. +The default value for <code>sep</code> is the empty string +(that is, no separator). +Returns the empty string if <code>n</code> is not positive. + + +<p> +(Note that it is very easy to exhaust the memory of your machine +with a single call to this function.) + + + + +<p> +<hr><h3><a name="pdf-string.reverse"><code>string.reverse (s)</code></a></h3> + + +<p> +Returns a string that is the string <code>s</code> reversed. + + + + +<p> +<hr><h3><a name="pdf-string.sub"><code>string.sub (s, i [, j])</code></a></h3> + + +<p> +Returns the substring of <code>s</code> that +starts at <code>i</code> and continues until <code>j</code>; +<code>i</code> and <code>j</code> can be negative. +If <code>j</code> is absent, then it is assumed to be equal to -1 +(which is the same as the string length). +In particular, +the call <code>string.sub(s,1,j)</code> returns a prefix of <code>s</code> +with length <code>j</code>, +and <code>string.sub(s, -i)</code> (for a positive <code>i</code>) +returns a suffix of <code>s</code> +with length <code>i</code>. + + +<p> +If, after the translation of negative indices, +<code>i</code> is less than 1, +it is corrected to 1. +If <code>j</code> is greater than the string length, +it is corrected to that length. +If, after these corrections, +<code>i</code> is greater than <code>j</code>, +the function returns the empty string. + + + + +<p> +<hr><h3><a name="pdf-string.unpack"><code>string.unpack (fmt, s [, pos])</code></a></h3> + + +<p> +Returns the values packed in string <code>s</code> (see <a href="#pdf-string.pack"><code>string.pack</code></a>) +according to the format string <code>fmt</code> (see <a href="#6.4.2">§6.4.2</a>). +An optional <code>pos</code> marks where +to start reading in <code>s</code> (default is 1). +After the read values, +this function also returns the index of the first unread byte in <code>s</code>. + + + + +<p> +<hr><h3><a name="pdf-string.upper"><code>string.upper (s)</code></a></h3> + + +<p> +Receives a string and returns a copy of this string with all +lowercase letters changed to uppercase. +All other characters are left unchanged. +The definition of what a lowercase letter is depends on the current locale. + + + + + + + +<h3>6.4.1 – <a name="6.4.1">Patterns</a></h3> + + + +<p> +Patterns in Lua are described by regular strings, +which are interpreted as patterns by the pattern-matching functions +<a href="#pdf-string.find"><code>string.find</code></a>, +<a href="#pdf-string.gmatch"><code>string.gmatch</code></a>, +<a href="#pdf-string.gsub"><code>string.gsub</code></a>, +and <a href="#pdf-string.match"><code>string.match</code></a>. +This section describes the syntax and the meaning +(that is, what they match) of these strings. + + + + + +<h4>Character Class:</h4><p> +A <em>character class</em> is used to represent a set of characters. +The following combinations are allowed in describing a character class: + +<ul> + +<li><b><em>x</em>: </b> +(where <em>x</em> is not one of the <em>magic characters</em> +<code>^$()%.[]*+-?</code>) +represents the character <em>x</em> itself. +</li> + +<li><b><code>.</code>: </b> (a dot) represents all characters.</li> + +<li><b><code>%a</code>: </b> represents all letters.</li> + +<li><b><code>%c</code>: </b> represents all control characters.</li> + +<li><b><code>%d</code>: </b> represents all digits.</li> + +<li><b><code>%g</code>: </b> represents all printable characters except space.</li> + +<li><b><code>%l</code>: </b> represents all lowercase letters.</li> + +<li><b><code>%p</code>: </b> represents all punctuation characters.</li> + +<li><b><code>%s</code>: </b> represents all space characters.</li> + +<li><b><code>%u</code>: </b> represents all uppercase letters.</li> + +<li><b><code>%w</code>: </b> represents all alphanumeric characters.</li> + +<li><b><code>%x</code>: </b> represents all hexadecimal digits.</li> + +<li><b><code>%<em>x</em></code>: </b> (where <em>x</em> is any non-alphanumeric character) +represents the character <em>x</em>. +This is the standard way to escape the magic characters. +Any non-alphanumeric character +(including all punctuation characters, even the non-magical) +can be preceded by a '<code>%</code>' to represent itself in a pattern. +</li> + +<li><b><code>[<em>set</em>]</code>: </b> +represents the class which is the union of all +characters in <em>set</em>. +A range of characters can be specified by +separating the end characters of the range, +in ascending order, with a '<code>-</code>'. +All classes <code>%</code><em>x</em> described above can also be used as +components in <em>set</em>. +All other characters in <em>set</em> represent themselves. +For example, <code>[%w_]</code> (or <code>[_%w]</code>) +represents all alphanumeric characters plus the underscore, +<code>[0-7]</code> represents the octal digits, +and <code>[0-7%l%-]</code> represents the octal digits plus +the lowercase letters plus the '<code>-</code>' character. + + +<p> +You can put a closing square bracket in a set +by positioning it as the first character in the set. +You can put a hyphen in a set +by positioning it as the first or the last character in the set. +(You can also use an escape for both cases.) + + +<p> +The interaction between ranges and classes is not defined. +Therefore, patterns like <code>[%a-z]</code> or <code>[a-%%]</code> +have no meaning. +</li> + +<li><b><code>[^<em>set</em>]</code>: </b> +represents the complement of <em>set</em>, +where <em>set</em> is interpreted as above. +</li> + +</ul><p> +For all classes represented by single letters (<code>%a</code>, <code>%c</code>, etc.), +the corresponding uppercase letter represents the complement of the class. +For instance, <code>%S</code> represents all non-space characters. + + +<p> +The definitions of letter, space, and other character groups +depend on the current locale. +In particular, the class <code>[a-z]</code> may not be equivalent to <code>%l</code>. + + + + + +<h4>Pattern Item:</h4><p> +A <em>pattern item</em> can be + +<ul> + +<li> +a single character class, +which matches any single character in the class; +</li> + +<li> +a single character class followed by '<code>*</code>', +which matches sequences of zero or more characters in the class. +These repetition items will always match the longest possible sequence; +</li> + +<li> +a single character class followed by '<code>+</code>', +which matches sequences of one or more characters in the class. +These repetition items will always match the longest possible sequence; +</li> + +<li> +a single character class followed by '<code>-</code>', +which also matches sequences of zero or more characters in the class. +Unlike '<code>*</code>', +these repetition items will always match the shortest possible sequence; +</li> + +<li> +a single character class followed by '<code>?</code>', +which matches zero or one occurrence of a character in the class. +It always matches one occurrence if possible; +</li> + +<li> +<code>%<em>n</em></code>, for <em>n</em> between 1 and 9; +such item matches a substring equal to the <em>n</em>-th captured string +(see below); +</li> + +<li> +<code>%b<em>xy</em></code>, where <em>x</em> and <em>y</em> are two distinct characters; +such item matches strings that start with <em>x</em>, end with <em>y</em>, +and where the <em>x</em> and <em>y</em> are <em>balanced</em>. +This means that, if one reads the string from left to right, +counting <em>+1</em> for an <em>x</em> and <em>-1</em> for a <em>y</em>, +the ending <em>y</em> is the first <em>y</em> where the count reaches 0. +For instance, the item <code>%b()</code> matches expressions with +balanced parentheses. +</li> + +<li> +<code>%f[<em>set</em>]</code>, a <em>frontier pattern</em>; +such item matches an empty string at any position such that +the next character belongs to <em>set</em> +and the previous character does not belong to <em>set</em>. +The set <em>set</em> is interpreted as previously described. +The beginning and the end of the subject are handled as if +they were the character '<code>\0</code>'. +</li> + +</ul> + + + + +<h4>Pattern:</h4><p> +A <em>pattern</em> is a sequence of pattern items. +A caret '<code>^</code>' at the beginning of a pattern anchors the match at the +beginning of the subject string. +A '<code>$</code>' at the end of a pattern anchors the match at the +end of the subject string. +At other positions, +'<code>^</code>' and '<code>$</code>' have no special meaning and represent themselves. + + + + + +<h4>Captures:</h4><p> +A pattern can contain sub-patterns enclosed in parentheses; +they describe <em>captures</em>. +When a match succeeds, the substrings of the subject string +that match captures are stored (<em>captured</em>) for future use. +Captures are numbered according to their left parentheses. +For instance, in the pattern <code>"(a*(.)%w(%s*))"</code>, +the part of the string matching <code>"a*(.)%w(%s*)"</code> is +stored as the first capture, and therefore has number 1; +the character matching "<code>.</code>" is captured with number 2, +and the part matching "<code>%s*</code>" has number 3. + + +<p> +As a special case, the capture <code>()</code> captures +the current string position (a number). +For instance, if we apply the pattern <code>"()aa()"</code> on the +string <code>"flaaap"</code>, there will be two captures: 3 and 5. + + + + + +<h4>Multiple matches:</h4><p> +The function <a href="#pdf-string.gsub"><code>string.gsub</code></a> and the iterator <a href="#pdf-string.gmatch"><code>string.gmatch</code></a> +match multiple occurrences of the given pattern in the subject. +For these functions, +a new match is considered valid only +if it ends at least one byte after the end of the previous match. +In other words, the pattern machine never accepts the +empty string as a match immediately after another match. +As an example, +consider the results of the following code: + +<pre> + > string.gsub("abc", "()a*()", print); + --> 1 2 + --> 3 3 + --> 4 4 +</pre><p> +The second and third results come from Lua matching an empty +string after '<code>b</code>' and another one after '<code>c</code>'. +Lua does not match an empty string after '<code>a</code>', +because it would end at the same position of the previous match. + + + + + + + +<h3>6.4.2 – <a name="6.4.2">Format Strings for Pack and Unpack</a></h3> + +<p> +The first argument to <a href="#pdf-string.pack"><code>string.pack</code></a>, +<a href="#pdf-string.packsize"><code>string.packsize</code></a>, and <a href="#pdf-string.unpack"><code>string.unpack</code></a> +is a format string, +which describes the layout of the structure being created or read. + + +<p> +A format string is a sequence of conversion options. +The conversion options are as follows: + +<ul> +<li><b><code><</code>: </b>sets little endian</li> +<li><b><code>></code>: </b>sets big endian</li> +<li><b><code>=</code>: </b>sets native endian</li> +<li><b><code>![<em>n</em>]</code>: </b>sets maximum alignment to <code>n</code> +(default is native alignment)</li> +<li><b><code>b</code>: </b>a signed byte (<code>char</code>)</li> +<li><b><code>B</code>: </b>an unsigned byte (<code>char</code>)</li> +<li><b><code>h</code>: </b>a signed <code>short</code> (native size)</li> +<li><b><code>H</code>: </b>an unsigned <code>short</code> (native size)</li> +<li><b><code>l</code>: </b>a signed <code>long</code> (native size)</li> +<li><b><code>L</code>: </b>an unsigned <code>long</code> (native size)</li> +<li><b><code>j</code>: </b>a <code>lua_Integer</code></li> +<li><b><code>J</code>: </b>a <code>lua_Unsigned</code></li> +<li><b><code>T</code>: </b>a <code>size_t</code> (native size)</li> +<li><b><code>i[<em>n</em>]</code>: </b>a signed <code>int</code> with <code>n</code> bytes +(default is native size)</li> +<li><b><code>I[<em>n</em>]</code>: </b>an unsigned <code>int</code> with <code>n</code> bytes +(default is native size)</li> +<li><b><code>f</code>: </b>a <code>float</code> (native size)</li> +<li><b><code>d</code>: </b>a <code>double</code> (native size)</li> +<li><b><code>n</code>: </b>a <code>lua_Number</code></li> +<li><b><code>c<em>n</em></code>: </b>a fixed-sized string with <code>n</code> bytes</li> +<li><b><code>z</code>: </b>a zero-terminated string</li> +<li><b><code>s[<em>n</em>]</code>: </b>a string preceded by its length +coded as an unsigned integer with <code>n</code> bytes +(default is a <code>size_t</code>)</li> +<li><b><code>x</code>: </b>one byte of padding</li> +<li><b><code>X<em>op</em></code>: </b>an empty item that aligns +according to option <code>op</code> +(which is otherwise ignored)</li> +<li><b>'<code> </code>': </b>(space) ignored</li> +</ul><p> +(A "<code>[<em>n</em>]</code>" means an optional integral numeral.) +Except for padding, spaces, and configurations +(options "<code>xX <=>!</code>"), +each option corresponds to an argument in <a href="#pdf-string.pack"><code>string.pack</code></a> +or a result in <a href="#pdf-string.unpack"><code>string.unpack</code></a>. + + +<p> +For options "<code>!<em>n</em></code>", "<code>s<em>n</em></code>", "<code>i<em>n</em></code>", and "<code>I<em>n</em></code>", +<code>n</code> can be any integer between 1 and 16. +All integral options check overflows; +<a href="#pdf-string.pack"><code>string.pack</code></a> checks whether the given value fits in the given size; +<a href="#pdf-string.unpack"><code>string.unpack</code></a> checks whether the read value fits in a Lua integer. +For the unsigned options, +Lua integers are treated as unsigned values too. + + +<p> +Any format string starts as if prefixed by "<code>!1=</code>", +that is, +with maximum alignment of 1 (no alignment) +and native endianness. + + +<p> +Native endianness assumes that the whole system is +either big or little endian. +The packing functions will not emulate correctly the behavior +of mixed-endian formats. + + +<p> +Alignment works as follows: +For each option, +the format gets extra padding until the data starts +at an offset that is a multiple of the minimum between the +option size and the maximum alignment; +this minimum must be a power of 2. +Options "<code>c</code>" and "<code>z</code>" are not aligned; +option "<code>s</code>" follows the alignment of its starting integer. + + +<p> +All padding is filled with zeros by <a href="#pdf-string.pack"><code>string.pack</code></a> +and ignored by <a href="#pdf-string.unpack"><code>string.unpack</code></a>. + + + + + + + +<h2>6.5 – <a name="6.5">UTF-8 Support</a></h2> + +<p> +This library provides basic support for UTF-8 encoding. +It provides all its functions inside the table <a name="pdf-utf8"><code>utf8</code></a>. +This library does not provide any support for Unicode other +than the handling of the encoding. +Any operation that needs the meaning of a character, +such as character classification, is outside its scope. + + +<p> +Unless stated otherwise, +all functions that expect a byte position as a parameter +assume that the given position is either the start of a byte sequence +or one plus the length of the subject string. +As in the string library, +negative indices count from the end of the string. + + +<p> +Functions that create byte sequences +accept all values up to <code>0x7FFFFFFF</code>, +as defined in the original UTF-8 specification; +that implies byte sequences of up to six bytes. + + +<p> +Functions that interpret byte sequences only accept +valid sequences (well formed and not overlong). +By default, they only accept byte sequences +that result in valid Unicode code points, +rejecting values greater than <code>10FFFF</code> and surrogates. +A boolean argument <code>lax</code>, when available, +lifts these checks, +so that all values up to <code>0x7FFFFFFF</code> are accepted. +(Not well formed and overlong sequences are still rejected.) + + +<p> +<hr><h3><a name="pdf-utf8.char"><code>utf8.char (···)</code></a></h3> + + +<p> +Receives zero or more integers, +converts each one to its corresponding UTF-8 byte sequence +and returns a string with the concatenation of all these sequences. + + + + +<p> +<hr><h3><a name="pdf-utf8.charpattern"><code>utf8.charpattern</code></a></h3> + + +<p> +The pattern (a string, not a function) "<code>[\0-\x7F\xC2-\xFD][\x80-\xBF]*</code>" +(see <a href="#6.4.1">§6.4.1</a>), +which matches exactly one UTF-8 byte sequence, +assuming that the subject is a valid UTF-8 string. + + + + +<p> +<hr><h3><a name="pdf-utf8.codes"><code>utf8.codes (s [, lax])</code></a></h3> + + +<p> +Returns values so that the construction + +<pre> + for p, c in utf8.codes(s) do <em>body</em> end +</pre><p> +will iterate over all UTF-8 characters in string <code>s</code>, +with <code>p</code> being the position (in bytes) and <code>c</code> the code point +of each character. +It raises an error if it meets any invalid byte sequence. + + + + +<p> +<hr><h3><a name="pdf-utf8.codepoint"><code>utf8.codepoint (s [, i [, j [, lax]]])</code></a></h3> + + +<p> +Returns the code points (as integers) from all characters in <code>s</code> +that start between byte position <code>i</code> and <code>j</code> (both included). +The default for <code>i</code> is 1 and for <code>j</code> is <code>i</code>. +It raises an error if it meets any invalid byte sequence. + + + + +<p> +<hr><h3><a name="pdf-utf8.len"><code>utf8.len (s [, i [, j [, lax]]])</code></a></h3> + + +<p> +Returns the number of UTF-8 characters in string <code>s</code> +that start between positions <code>i</code> and <code>j</code> (both inclusive). +The default for <code>i</code> is 1 and for <code>j</code> is -1. +If it finds any invalid byte sequence, +returns <b>fail</b> plus the position of the first invalid byte. + + + + +<p> +<hr><h3><a name="pdf-utf8.offset"><code>utf8.offset (s, n [, i])</code></a></h3> + + +<p> +Returns the position (in bytes) where the encoding of the +<code>n</code>-th character of <code>s</code> +(counting from position <code>i</code>) starts. +A negative <code>n</code> gets characters before position <code>i</code>. +The default for <code>i</code> is 1 when <code>n</code> is non-negative +and <code>#s + 1</code> otherwise, +so that <code>utf8.offset(s, -n)</code> gets the offset of the +<code>n</code>-th character from the end of the string. +If the specified character is neither in the subject +nor right after its end, +the function returns <b>fail</b>. + + +<p> +As a special case, +when <code>n</code> is 0 the function returns the start of the encoding +of the character that contains the <code>i</code>-th byte of <code>s</code>. + + +<p> +This function assumes that <code>s</code> is a valid UTF-8 string. + + + + + + + +<h2>6.6 – <a name="6.6">Table Manipulation</a></h2> + +<p> +This library provides generic functions for table manipulation. +It provides all its functions inside the table <a name="pdf-table"><code>table</code></a>. + + +<p> +Remember that, whenever an operation needs the length of a table, +all caveats about the length operator apply (see <a href="#3.4.7">§3.4.7</a>). +All functions ignore non-numeric keys +in the tables given as arguments. + + +<p> +<hr><h3><a name="pdf-table.concat"><code>table.concat (list [, sep [, i [, j]]])</code></a></h3> + + +<p> +Given a list where all elements are strings or numbers, +returns the string <code>list[i]..sep..list[i+1] ··· sep..list[j]</code>. +The default value for <code>sep</code> is the empty string, +the default for <code>i</code> is 1, +and the default for <code>j</code> is <code>#list</code>. +If <code>i</code> is greater than <code>j</code>, returns the empty string. + + + + +<p> +<hr><h3><a name="pdf-table.insert"><code>table.insert (list, [pos,] value)</code></a></h3> + + +<p> +Inserts element <code>value</code> at position <code>pos</code> in <code>list</code>, +shifting up the elements +<code>list[pos], list[pos+1], ···, list[#list]</code>. +The default value for <code>pos</code> is <code>#list+1</code>, +so that a call <code>table.insert(t,x)</code> inserts <code>x</code> at the end +of the list <code>t</code>. + + + + +<p> +<hr><h3><a name="pdf-table.move"><code>table.move (a1, f, e, t [,a2])</code></a></h3> + + +<p> +Moves elements from the table <code>a1</code> to the table <code>a2</code>, +performing the equivalent to the following +multiple assignment: +<code>a2[t],··· = a1[f],···,a1[e]</code>. +The default for <code>a2</code> is <code>a1</code>. +The destination range can overlap with the source range. +The number of elements to be moved must fit in a Lua integer. + + +<p> +Returns the destination table <code>a2</code>. + + + + +<p> +<hr><h3><a name="pdf-table.pack"><code>table.pack (···)</code></a></h3> + + +<p> +Returns a new table with all arguments stored into keys 1, 2, etc. +and with a field "<code>n</code>" with the total number of arguments. +Note that the resulting table may not be a sequence, +if some arguments are <b>nil</b>. + + + + +<p> +<hr><h3><a name="pdf-table.remove"><code>table.remove (list [, pos])</code></a></h3> + + +<p> +Removes from <code>list</code> the element at position <code>pos</code>, +returning the value of the removed element. +When <code>pos</code> is an integer between 1 and <code>#list</code>, +it shifts down the elements +<code>list[pos+1], list[pos+2], ···, list[#list]</code> +and erases element <code>list[#list]</code>; +The index <code>pos</code> can also be 0 when <code>#list</code> is 0, +or <code>#list + 1</code>. + + +<p> +The default value for <code>pos</code> is <code>#list</code>, +so that a call <code>table.remove(l)</code> removes the last element +of the list <code>l</code>. + + + + +<p> +<hr><h3><a name="pdf-table.sort"><code>table.sort (list [, comp])</code></a></h3> + + +<p> +Sorts the list elements in a given order, <em>in-place</em>, +from <code>list[1]</code> to <code>list[#list]</code>. +If <code>comp</code> is given, +then it must be a function that receives two list elements +and returns true when the first element must come +before the second in the final order, +so that, after the sort, +<code>i <= j</code> implies <code>not comp(list[j],list[i])</code>. +If <code>comp</code> is not given, +then the standard Lua operator <code><</code> is used instead. + + +<p> +The <code>comp</code> function must define a consistent order; +more formally, the function must define a strict weak order. +(A weak order is similar to a total order, +but it can equate different elements for comparison purposes.) + + +<p> +The sort algorithm is not stable: +Different elements considered equal by the given order +may have their relative positions changed by the sort. + + + + +<p> +<hr><h3><a name="pdf-table.unpack"><code>table.unpack (list [, i [, j]])</code></a></h3> + + +<p> +Returns the elements from the given list. +This function is equivalent to + +<pre> + return list[i], list[i+1], ···, list[j] +</pre><p> +By default, <code>i</code> is 1 and <code>j</code> is <code>#list</code>. + + + + + + + +<h2>6.7 – <a name="6.7">Mathematical Functions</a></h2> + +<p> +This library provides basic mathematical functions. +It provides all its functions and constants inside the table <a name="pdf-math"><code>math</code></a>. +Functions with the annotation "<code>integer/float</code>" give +integer results for integer arguments +and float results for non-integer arguments. +The rounding functions +<a href="#pdf-math.ceil"><code>math.ceil</code></a>, <a href="#pdf-math.floor"><code>math.floor</code></a>, and <a href="#pdf-math.modf"><code>math.modf</code></a> +return an integer when the result fits in the range of an integer, +or a float otherwise. + + +<p> +<hr><h3><a name="pdf-math.abs"><code>math.abs (x)</code></a></h3> + + +<p> +Returns the maximum value between <code>x</code> and <code>-x</code>. (integer/float) + + + + +<p> +<hr><h3><a name="pdf-math.acos"><code>math.acos (x)</code></a></h3> + + +<p> +Returns the arc cosine of <code>x</code> (in radians). + + + + +<p> +<hr><h3><a name="pdf-math.asin"><code>math.asin (x)</code></a></h3> + + +<p> +Returns the arc sine of <code>x</code> (in radians). + + + + +<p> +<hr><h3><a name="pdf-math.atan"><code>math.atan (y [, x])</code></a></h3> + + +<p> + +Returns the arc tangent of <code>y/x</code> (in radians), +using the signs of both arguments to find the +quadrant of the result. +It also handles correctly the case of <code>x</code> being zero. + + +<p> +The default value for <code>x</code> is 1, +so that the call <code>math.atan(y)</code> +returns the arc tangent of <code>y</code>. + + + + +<p> +<hr><h3><a name="pdf-math.ceil"><code>math.ceil (x)</code></a></h3> + + +<p> +Returns the smallest integral value greater than or equal to <code>x</code>. + + + + +<p> +<hr><h3><a name="pdf-math.cos"><code>math.cos (x)</code></a></h3> + + +<p> +Returns the cosine of <code>x</code> (assumed to be in radians). + + + + +<p> +<hr><h3><a name="pdf-math.deg"><code>math.deg (x)</code></a></h3> + + +<p> +Converts the angle <code>x</code> from radians to degrees. + + + + +<p> +<hr><h3><a name="pdf-math.exp"><code>math.exp (x)</code></a></h3> + + +<p> +Returns the value <em>e<sup>x</sup></em> +(where <code>e</code> is the base of natural logarithms). + + + + +<p> +<hr><h3><a name="pdf-math.floor"><code>math.floor (x)</code></a></h3> + + +<p> +Returns the largest integral value less than or equal to <code>x</code>. + + + + +<p> +<hr><h3><a name="pdf-math.fmod"><code>math.fmod (x, y)</code></a></h3> + + +<p> +Returns the remainder of the division of <code>x</code> by <code>y</code> +that rounds the quotient towards zero. (integer/float) + + + + +<p> +<hr><h3><a name="pdf-math.huge"><code>math.huge</code></a></h3> + + +<p> +The float value <code>HUGE_VAL</code>, +a value greater than any other numeric value. + + + + +<p> +<hr><h3><a name="pdf-math.log"><code>math.log (x [, base])</code></a></h3> + + +<p> +Returns the logarithm of <code>x</code> in the given base. +The default for <code>base</code> is <em>e</em> +(so that the function returns the natural logarithm of <code>x</code>). + + + + +<p> +<hr><h3><a name="pdf-math.max"><code>math.max (x, ···)</code></a></h3> + + +<p> +Returns the argument with the maximum value, +according to the Lua operator <code><</code>. + + + + +<p> +<hr><h3><a name="pdf-math.maxinteger"><code>math.maxinteger</code></a></h3> +An integer with the maximum value for an integer. + + + + +<p> +<hr><h3><a name="pdf-math.min"><code>math.min (x, ···)</code></a></h3> + + +<p> +Returns the argument with the minimum value, +according to the Lua operator <code><</code>. + + + + +<p> +<hr><h3><a name="pdf-math.mininteger"><code>math.mininteger</code></a></h3> +An integer with the minimum value for an integer. + + + + +<p> +<hr><h3><a name="pdf-math.modf"><code>math.modf (x)</code></a></h3> + + +<p> +Returns the integral part of <code>x</code> and the fractional part of <code>x</code>. +Its second result is always a float. + + + + +<p> +<hr><h3><a name="pdf-math.pi"><code>math.pi</code></a></h3> + + +<p> +The value of <em>π</em>. + + + + +<p> +<hr><h3><a name="pdf-math.rad"><code>math.rad (x)</code></a></h3> + + +<p> +Converts the angle <code>x</code> from degrees to radians. + + + + +<p> +<hr><h3><a name="pdf-math.random"><code>math.random ([m [, n]])</code></a></h3> + + +<p> +When called without arguments, +returns a pseudo-random float with uniform distribution +in the range <em>[0,1)</em>. +When called with two integers <code>m</code> and <code>n</code>, +<code>math.random</code> returns a pseudo-random integer +with uniform distribution in the range <em>[m, n]</em>. +The call <code>math.random(n)</code>, for a positive <code>n</code>, +is equivalent to <code>math.random(1,n)</code>. +The call <code>math.random(0)</code> produces an integer with +all bits (pseudo)random. + + +<p> +This function uses the <code>xoshiro256**</code> algorithm to produce +pseudo-random 64-bit integers, +which are the results of calls with argument 0. +Other results (ranges and floats) +are unbiased extracted from these integers. + + +<p> +Lua initializes its pseudo-random generator with the equivalent of +a call to <a href="#pdf-math.randomseed"><code>math.randomseed</code></a> with no arguments, +so that <code>math.random</code> should generate +different sequences of results each time the program runs. + + + + +<p> +<hr><h3><a name="pdf-math.randomseed"><code>math.randomseed ([x [, y]])</code></a></h3> + + +<p> +When called with at least one argument, +the integer parameters <code>x</code> and <code>y</code> are +joined into a 128-bit <em>seed</em> that +is used to reinitialize the pseudo-random generator; +equal seeds produce equal sequences of numbers. +The default for <code>y</code> is zero. + + +<p> +When called with no arguments, +Lua generates a seed with +a weak attempt for randomness. + + +<p> +This function returns the two seed components +that were effectively used, +so that setting them again repeats the sequence. + + +<p> +To ensure a required level of randomness to the initial state +(or contrarily, to have a deterministic sequence, +for instance when debugging a program), +you should call <a href="#pdf-math.randomseed"><code>math.randomseed</code></a> with explicit arguments. + + + + +<p> +<hr><h3><a name="pdf-math.sin"><code>math.sin (x)</code></a></h3> + + +<p> +Returns the sine of <code>x</code> (assumed to be in radians). + + + + +<p> +<hr><h3><a name="pdf-math.sqrt"><code>math.sqrt (x)</code></a></h3> + + +<p> +Returns the square root of <code>x</code>. +(You can also use the expression <code>x^0.5</code> to compute this value.) + + + + +<p> +<hr><h3><a name="pdf-math.tan"><code>math.tan (x)</code></a></h3> + + +<p> +Returns the tangent of <code>x</code> (assumed to be in radians). + + + + +<p> +<hr><h3><a name="pdf-math.tointeger"><code>math.tointeger (x)</code></a></h3> + + +<p> +If the value <code>x</code> is convertible to an integer, +returns that integer. +Otherwise, returns <b>fail</b>. + + + + +<p> +<hr><h3><a name="pdf-math.type"><code>math.type (x)</code></a></h3> + + +<p> +Returns "<code>integer</code>" if <code>x</code> is an integer, +"<code>float</code>" if it is a float, +or <b>fail</b> if <code>x</code> is not a number. + + + + +<p> +<hr><h3><a name="pdf-math.ult"><code>math.ult (m, n)</code></a></h3> + + +<p> +Returns a boolean, +<b>true</b> if and only if integer <code>m</code> is below integer <code>n</code> when +they are compared as unsigned integers. + + + + + + + +<h2>6.8 – <a name="6.8">Input and Output Facilities</a></h2> + +<p> +The I/O library provides two different styles for file manipulation. +The first one uses implicit file handles; +that is, there are operations to set a default input file and a +default output file, +and all input/output operations are done over these default files. +The second style uses explicit file handles. + + +<p> +When using implicit file handles, +all operations are supplied by table <a name="pdf-io"><code>io</code></a>. +When using explicit file handles, +the operation <a href="#pdf-io.open"><code>io.open</code></a> returns a file handle +and then all operations are supplied as methods of the file handle. + + +<p> +The metatable for file handles provides metamethods +for <code>__gc</code> and <code>__close</code> that try +to close the file when called. + + +<p> +The table <code>io</code> also provides +three predefined file handles with their usual meanings from C: +<a name="pdf-io.stdin"><code>io.stdin</code></a>, <a name="pdf-io.stdout"><code>io.stdout</code></a>, and <a name="pdf-io.stderr"><code>io.stderr</code></a>. +The I/O library never closes these files. + + +<p> +Unless otherwise stated, +all I/O functions return <b>fail</b> on failure, +plus an error message as a second result and +a system-dependent error code as a third result, +and some non-false value on success. +On non-POSIX systems, +the computation of the error message and error code +in case of errors +may be not thread safe, +because they rely on the global C variable <code>errno</code>. + + +<p> +<hr><h3><a name="pdf-io.close"><code>io.close ([file])</code></a></h3> + + +<p> +Equivalent to <code>file:close()</code>. +Without a <code>file</code>, closes the default output file. + + + + +<p> +<hr><h3><a name="pdf-io.flush"><code>io.flush ()</code></a></h3> + + +<p> +Equivalent to <code>io.output():flush()</code>. + + + + +<p> +<hr><h3><a name="pdf-io.input"><code>io.input ([file])</code></a></h3> + + +<p> +When called with a file name, it opens the named file (in text mode), +and sets its handle as the default input file. +When called with a file handle, +it simply sets this file handle as the default input file. +When called without arguments, +it returns the current default input file. + + +<p> +In case of errors this function raises the error, +instead of returning an error code. + + + + +<p> +<hr><h3><a name="pdf-io.lines"><code>io.lines ([filename, ···])</code></a></h3> + + +<p> +Opens the given file name in read mode +and returns an iterator function that +works like <code>file:lines(···)</code> over the opened file. +When the iterator function fails to read any value, +it automatically closes the file. +Besides the iterator function, +<code>io.lines</code> returns three other values: +two <b>nil</b> values as placeholders, +plus the created file handle. +Therefore, when used in a generic <b>for</b> loop, +the file is closed also if the loop is interrupted by an +error or a <b>break</b>. + + +<p> +The call <code>io.lines()</code> (with no file name) is equivalent +to <code>io.input():lines("l")</code>; +that is, it iterates over the lines of the default input file. +In this case, the iterator does not close the file when the loop ends. + + +<p> +In case of errors opening the file, +this function raises the error, +instead of returning an error code. + + + + +<p> +<hr><h3><a name="pdf-io.open"><code>io.open (filename [, mode])</code></a></h3> + + +<p> +This function opens a file, +in the mode specified in the string <code>mode</code>. +In case of success, +it returns a new file handle. + + +<p> +The <code>mode</code> string can be any of the following: + +<ul> +<li><b>"<code>r</code>": </b> read mode (the default);</li> +<li><b>"<code>w</code>": </b> write mode;</li> +<li><b>"<code>a</code>": </b> append mode;</li> +<li><b>"<code>r+</code>": </b> update mode, all previous data is preserved;</li> +<li><b>"<code>w+</code>": </b> update mode, all previous data is erased;</li> +<li><b>"<code>a+</code>": </b> append update mode, previous data is preserved, + writing is only allowed at the end of file.</li> +</ul><p> +The <code>mode</code> string can also have a '<code>b</code>' at the end, +which is needed in some systems to open the file in binary mode. + + + + +<p> +<hr><h3><a name="pdf-io.output"><code>io.output ([file])</code></a></h3> + + +<p> +Similar to <a href="#pdf-io.input"><code>io.input</code></a>, but operates over the default output file. + + + + +<p> +<hr><h3><a name="pdf-io.popen"><code>io.popen (prog [, mode])</code></a></h3> + + +<p> +This function is system dependent and is not available +on all platforms. + + +<p> +Starts the program <code>prog</code> in a separated process and returns +a file handle that you can use to read data from this program +(if <code>mode</code> is <code>"r"</code>, the default) +or to write data to this program +(if <code>mode</code> is <code>"w"</code>). + + + + +<p> +<hr><h3><a name="pdf-io.read"><code>io.read (···)</code></a></h3> + + +<p> +Equivalent to <code>io.input():read(···)</code>. + + + + +<p> +<hr><h3><a name="pdf-io.tmpfile"><code>io.tmpfile ()</code></a></h3> + + +<p> +In case of success, +returns a handle for a temporary file. +This file is opened in update mode +and it is automatically removed when the program ends. + + + + +<p> +<hr><h3><a name="pdf-io.type"><code>io.type (obj)</code></a></h3> + + +<p> +Checks whether <code>obj</code> is a valid file handle. +Returns the string <code>"file"</code> if <code>obj</code> is an open file handle, +<code>"closed file"</code> if <code>obj</code> is a closed file handle, +or <b>fail</b> if <code>obj</code> is not a file handle. + + + + +<p> +<hr><h3><a name="pdf-io.write"><code>io.write (···)</code></a></h3> + + +<p> +Equivalent to <code>io.output():write(···)</code>. + + + + +<p> +<hr><h3><a name="pdf-file:close"><code>file:close ()</code></a></h3> + + +<p> +Closes <code>file</code>. +Note that files are automatically closed when +their handles are garbage collected, +but that takes an unpredictable amount of time to happen. + + +<p> +When closing a file handle created with <a href="#pdf-io.popen"><code>io.popen</code></a>, +<a href="#pdf-file:close"><code>file:close</code></a> returns the same values +returned by <a href="#pdf-os.execute"><code>os.execute</code></a>. + + + + +<p> +<hr><h3><a name="pdf-file:flush"><code>file:flush ()</code></a></h3> + + +<p> +Saves any written data to <code>file</code>. + + + + +<p> +<hr><h3><a name="pdf-file:lines"><code>file:lines (···)</code></a></h3> + + +<p> +Returns an iterator function that, +each time it is called, +reads the file according to the given formats. +When no format is given, +uses "<code>l</code>" as a default. +As an example, the construction + +<pre> + for c in file:lines(1) do <em>body</em> end +</pre><p> +will iterate over all characters of the file, +starting at the current position. +Unlike <a href="#pdf-io.lines"><code>io.lines</code></a>, this function does not close the file +when the loop ends. + + + + +<p> +<hr><h3><a name="pdf-file:read"><code>file:read (···)</code></a></h3> + + +<p> +Reads the file <code>file</code>, +according to the given formats, which specify what to read. +For each format, +the function returns a string or a number with the characters read, +or <b>fail</b> if it cannot read data with the specified format. +(In this latter case, +the function does not read subsequent formats.) +When called without arguments, +it uses a default format that reads the next line +(see below). + + +<p> +The available formats are + +<ul> + +<li><b>"<code>n</code>": </b> +reads a numeral and returns it as a float or an integer, +following the lexical conventions of Lua. +(The numeral may have leading whitespaces and a sign.) +This format always reads the longest input sequence that +is a valid prefix for a numeral; +if that prefix does not form a valid numeral +(e.g., an empty string, "<code>0x</code>", or "<code>3.4e-</code>") +or it is too long (more than 200 characters), +it is discarded and the format returns <b>fail</b>. +</li> + +<li><b>"<code>a</code>": </b> +reads the whole file, starting at the current position. +On end of file, it returns the empty string; +this format never fails. +</li> + +<li><b>"<code>l</code>": </b> +reads the next line skipping the end of line, +returning <b>fail</b> on end of file. +This is the default format. +</li> + +<li><b>"<code>L</code>": </b> +reads the next line keeping the end-of-line character (if present), +returning <b>fail</b> on end of file. +</li> + +<li><b><em>number</em>: </b> +reads a string with up to this number of bytes, +returning <b>fail</b> on end of file. +If <code>number</code> is zero, +it reads nothing and returns an empty string, +or <b>fail</b> on end of file. +</li> + +</ul><p> +The formats "<code>l</code>" and "<code>L</code>" should be used only for text files. + + + + +<p> +<hr><h3><a name="pdf-file:seek"><code>file:seek ([whence [, offset]])</code></a></h3> + + +<p> +Sets and gets the file position, +measured from the beginning of the file, +to the position given by <code>offset</code> plus a base +specified by the string <code>whence</code>, as follows: + +<ul> +<li><b>"<code>set</code>": </b> base is position 0 (beginning of the file);</li> +<li><b>"<code>cur</code>": </b> base is current position;</li> +<li><b>"<code>end</code>": </b> base is end of file;</li> +</ul><p> +In case of success, <code>seek</code> returns the final file position, +measured in bytes from the beginning of the file. +If <code>seek</code> fails, it returns <b>fail</b>, +plus a string describing the error. + + +<p> +The default value for <code>whence</code> is <code>"cur"</code>, +and for <code>offset</code> is 0. +Therefore, the call <code>file:seek()</code> returns the current +file position, without changing it; +the call <code>file:seek("set")</code> sets the position to the +beginning of the file (and returns 0); +and the call <code>file:seek("end")</code> sets the position to the +end of the file, and returns its size. + + + + +<p> +<hr><h3><a name="pdf-file:setvbuf"><code>file:setvbuf (mode [, size])</code></a></h3> + + +<p> +Sets the buffering mode for a file. +There are three available modes: + +<ul> +<li><b>"<code>no</code>": </b> no buffering.</li> +<li><b>"<code>full</code>": </b> full buffering.</li> +<li><b>"<code>line</code>": </b> line buffering.</li> +</ul> + +<p> +For the last two cases, +<code>size</code> is a hint for the size of the buffer, in bytes. +The default is an appropriate size. + + +<p> +The specific behavior of each mode is non portable; +check the underlying ISO C function <code>setvbuf</code> in your platform for +more details. + + + + +<p> +<hr><h3><a name="pdf-file:write"><code>file:write (···)</code></a></h3> + + +<p> +Writes the value of each of its arguments to <code>file</code>. +The arguments must be strings or numbers. + + +<p> +In case of success, this function returns <code>file</code>. + + + + + + + +<h2>6.9 – <a name="6.9">Operating System Facilities</a></h2> + +<p> +This library is implemented through table <a name="pdf-os"><code>os</code></a>. + + +<p> +<hr><h3><a name="pdf-os.clock"><code>os.clock ()</code></a></h3> + + +<p> +Returns an approximation of the amount in seconds of CPU time +used by the program, +as returned by the underlying ISO C function <code>clock</code>. + + + + +<p> +<hr><h3><a name="pdf-os.date"><code>os.date ([format [, time]])</code></a></h3> + + +<p> +Returns a string or a table containing date and time, +formatted according to the given string <code>format</code>. + + +<p> +If the <code>time</code> argument is present, +this is the time to be formatted +(see the <a href="#pdf-os.time"><code>os.time</code></a> function for a description of this value). +Otherwise, <code>date</code> formats the current time. + + +<p> +If <code>format</code> starts with '<code>!</code>', +then the date is formatted in Coordinated Universal Time. +After this optional character, +if <code>format</code> is the string "<code>*t</code>", +then <code>date</code> returns a table with the following fields: +<code>year</code>, <code>month</code> (1–12), <code>day</code> (1–31), +<code>hour</code> (0–23), <code>min</code> (0–59), +<code>sec</code> (0–61, due to leap seconds), +<code>wday</code> (weekday, 1–7, Sunday is 1), +<code>yday</code> (day of the year, 1–366), +and <code>isdst</code> (daylight saving flag, a boolean). +This last field may be absent +if the information is not available. + + +<p> +If <code>format</code> is not "<code>*t</code>", +then <code>date</code> returns the date as a string, +formatted according to the same rules as the ISO C function <code>strftime</code>. + + +<p> +If <code>format</code> is absent, it defaults to "<code>%c</code>", +which gives a human-readable date and time representation +using the current locale. + + +<p> +On non-POSIX systems, +this function may be not thread safe +because of its reliance on C function <code>gmtime</code> and C function <code>localtime</code>. + + + + +<p> +<hr><h3><a name="pdf-os.difftime"><code>os.difftime (t2, t1)</code></a></h3> + + +<p> +Returns the difference, in seconds, +from time <code>t1</code> to time <code>t2</code> +(where the times are values returned by <a href="#pdf-os.time"><code>os.time</code></a>). +In POSIX, Windows, and some other systems, +this value is exactly <code>t2</code><em>-</em><code>t1</code>. + + + + +<p> +<hr><h3><a name="pdf-os.execute"><code>os.execute ([command])</code></a></h3> + + +<p> +This function is equivalent to the ISO C function <code>system</code>. +It passes <code>command</code> to be executed by an operating system shell. +Its first result is <b>true</b> +if the command terminated successfully, +or <b>fail</b> otherwise. +After this first result +the function returns a string plus a number, +as follows: + +<ul> + +<li><b>"<code>exit</code>": </b> +the command terminated normally; +the following number is the exit status of the command. +</li> + +<li><b>"<code>signal</code>": </b> +the command was terminated by a signal; +the following number is the signal that terminated the command. +</li> + +</ul> + +<p> +When called without a <code>command</code>, +<code>os.execute</code> returns a boolean that is true if a shell is available. + + + + +<p> +<hr><h3><a name="pdf-os.exit"><code>os.exit ([code [, close]])</code></a></h3> + + +<p> +Calls the ISO C function <code>exit</code> to terminate the host program. +If <code>code</code> is <b>true</b>, +the returned status is <code>EXIT_SUCCESS</code>; +if <code>code</code> is <b>false</b>, +the returned status is <code>EXIT_FAILURE</code>; +if <code>code</code> is a number, +the returned status is this number. +The default value for <code>code</code> is <b>true</b>. + + +<p> +If the optional second argument <code>close</code> is true, +the function closes the Lua state before exiting (see <a href="#lua_close"><code>lua_close</code></a>). + + + + +<p> +<hr><h3><a name="pdf-os.getenv"><code>os.getenv (varname)</code></a></h3> + + +<p> +Returns the value of the process environment variable <code>varname</code> +or <b>fail</b> if the variable is not defined. + + + + +<p> +<hr><h3><a name="pdf-os.remove"><code>os.remove (filename)</code></a></h3> + + +<p> +Deletes the file (or empty directory, on POSIX systems) +with the given name. +If this function fails, it returns <b>fail</b> +plus a string describing the error and the error code. +Otherwise, it returns true. + + + + +<p> +<hr><h3><a name="pdf-os.rename"><code>os.rename (oldname, newname)</code></a></h3> + + +<p> +Renames the file or directory named <code>oldname</code> to <code>newname</code>. +If this function fails, it returns <b>fail</b>, +plus a string describing the error and the error code. +Otherwise, it returns true. + + + + +<p> +<hr><h3><a name="pdf-os.setlocale"><code>os.setlocale (locale [, category])</code></a></h3> + + +<p> +Sets the current locale of the program. +<code>locale</code> is a system-dependent string specifying a locale; +<code>category</code> is an optional string describing which category to change: +<code>"all"</code>, <code>"collate"</code>, <code>"ctype"</code>, +<code>"monetary"</code>, <code>"numeric"</code>, or <code>"time"</code>; +the default category is <code>"all"</code>. +The function returns the name of the new locale, +or <b>fail</b> if the request cannot be honored. + + +<p> +If <code>locale</code> is the empty string, +the current locale is set to an implementation-defined native locale. +If <code>locale</code> is the string "<code>C</code>", +the current locale is set to the standard C locale. + + +<p> +When called with <b>nil</b> as the first argument, +this function only returns the name of the current locale +for the given category. + + +<p> +This function may be not thread safe +because of its reliance on C function <code>setlocale</code>. + + + + +<p> +<hr><h3><a name="pdf-os.time"><code>os.time ([table])</code></a></h3> + + +<p> +Returns the current time when called without arguments, +or a time representing the local date and time specified by the given table. +This table must have fields <code>year</code>, <code>month</code>, and <code>day</code>, +and may have fields +<code>hour</code> (default is 12), +<code>min</code> (default is 0), +<code>sec</code> (default is 0), +and <code>isdst</code> (default is <b>nil</b>). +Other fields are ignored. +For a description of these fields, see the <a href="#pdf-os.date"><code>os.date</code></a> function. + + +<p> +When the function is called, +the values in these fields do not need to be inside their valid ranges. +For instance, if <code>sec</code> is -10, +it means 10 seconds before the time specified by the other fields; +if <code>hour</code> is 1000, +it means 1000 hours after the time specified by the other fields. + + +<p> +The returned value is a number, whose meaning depends on your system. +In POSIX, Windows, and some other systems, +this number counts the number +of seconds since some given start time (the "epoch"). +In other systems, the meaning is not specified, +and the number returned by <code>time</code> can be used only as an argument to +<a href="#pdf-os.date"><code>os.date</code></a> and <a href="#pdf-os.difftime"><code>os.difftime</code></a>. + + +<p> +When called with a table, +<code>os.time</code> also normalizes all the fields +documented in the <a href="#pdf-os.date"><code>os.date</code></a> function, +so that they represent the same time as before the call +but with values inside their valid ranges. + + + + +<p> +<hr><h3><a name="pdf-os.tmpname"><code>os.tmpname ()</code></a></h3> + + +<p> +Returns a string with a file name that can +be used for a temporary file. +The file must be explicitly opened before its use +and explicitly removed when no longer needed. + + +<p> +In POSIX systems, +this function also creates a file with that name, +to avoid security risks. +(Someone else might create the file with wrong permissions +in the time between getting the name and creating the file.) +You still have to open the file to use it +and to remove it (even if you do not use it). + + +<p> +When possible, +you may prefer to use <a href="#pdf-io.tmpfile"><code>io.tmpfile</code></a>, +which automatically removes the file when the program ends. + + + + + + + +<h2>6.10 – <a name="6.10">The Debug Library</a></h2> + +<p> +This library provides +the functionality of the debug interface (<a href="#4.7">§4.7</a>) to Lua programs. +You should exert care when using this library. +Several of its functions +violate basic assumptions about Lua code +(e.g., that variables local to a function +cannot be accessed from outside; +that userdata metatables cannot be changed by Lua code; +that Lua programs do not crash) +and therefore can compromise otherwise secure code. +Moreover, some functions in this library may be slow. + + +<p> +All functions in this library are provided +inside the <a name="pdf-debug"><code>debug</code></a> table. +All functions that operate over a thread +have an optional first argument which is the +thread to operate over. +The default is always the current thread. + + +<p> +<hr><h3><a name="pdf-debug.debug"><code>debug.debug ()</code></a></h3> + + +<p> +Enters an interactive mode with the user, +running each string that the user enters. +Using simple commands and other debug facilities, +the user can inspect global and local variables, +change their values, evaluate expressions, and so on. +A line containing only the word <code>cont</code> finishes this function, +so that the caller continues its execution. + + +<p> +Note that commands for <code>debug.debug</code> are not lexically nested +within any function and so have no direct access to local variables. + + + + +<p> +<hr><h3><a name="pdf-debug.gethook"><code>debug.gethook ([thread])</code></a></h3> + + +<p> +Returns the current hook settings of the thread, as three values: +the current hook function, the current hook mask, +and the current hook count, +as set by the <a href="#pdf-debug.sethook"><code>debug.sethook</code></a> function. + + +<p> +Returns <b>fail</b> if there is no active hook. + + + + +<p> +<hr><h3><a name="pdf-debug.getinfo"><code>debug.getinfo ([thread,] f [, what])</code></a></h3> + + +<p> +Returns a table with information about a function. +You can give the function directly +or you can give a number as the value of <code>f</code>, +which means the function running at level <code>f</code> of the call stack +of the given thread: +level 0 is the current function (<code>getinfo</code> itself); +level 1 is the function that called <code>getinfo</code> +(except for tail calls, which do not count in the stack); +and so on. +If <code>f</code> is a number greater than the number of active functions, +then <code>getinfo</code> returns <b>fail</b>. + + +<p> +The returned table can contain all the fields returned by <a href="#lua_getinfo"><code>lua_getinfo</code></a>, +with the string <code>what</code> describing which fields to fill in. +The default for <code>what</code> is to get all information available, +except the table of valid lines. +If present, +the option '<code>f</code>' +adds a field named <code>func</code> with the function itself. +If present, +the option '<code>L</code>' +adds a field named <code>activelines</code> with the table of +valid lines. + + +<p> +For instance, the expression <code>debug.getinfo(1,"n").name</code> returns +a name for the current function, +if a reasonable name can be found, +and the expression <code>debug.getinfo(print)</code> +returns a table with all available information +about the <a href="#pdf-print"><code>print</code></a> function. + + + + +<p> +<hr><h3><a name="pdf-debug.getlocal"><code>debug.getlocal ([thread,] f, local)</code></a></h3> + + +<p> +This function returns the name and the value of the local variable +with index <code>local</code> of the function at level <code>f</code> of the stack. +This function accesses not only explicit local variables, +but also parameters and temporary values. + + +<p> +The first parameter or local variable has index 1, and so on, +following the order that they are declared in the code, +counting only the variables that are active +in the current scope of the function. +Compile-time constants may not appear in this listing, +if they were optimized away by the compiler. +Negative indices refer to vararg arguments; +-1 is the first vararg argument. +The function returns <b>fail</b> +if there is no variable with the given index, +and raises an error when called with a level out of range. +(You can call <a href="#pdf-debug.getinfo"><code>debug.getinfo</code></a> to check whether the level is valid.) + + +<p> +Variable names starting with '<code>(</code>' (open parenthesis) +represent variables with no known names +(internal variables such as loop control variables, +and variables from chunks saved without debug information). + + +<p> +The parameter <code>f</code> may also be a function. +In that case, <code>getlocal</code> returns only the name of function parameters. + + + + +<p> +<hr><h3><a name="pdf-debug.getmetatable"><code>debug.getmetatable (value)</code></a></h3> + + +<p> +Returns the metatable of the given <code>value</code> +or <b>nil</b> if it does not have a metatable. + + + + +<p> +<hr><h3><a name="pdf-debug.getregistry"><code>debug.getregistry ()</code></a></h3> + + +<p> +Returns the registry table (see <a href="#4.3">§4.3</a>). + + + + +<p> +<hr><h3><a name="pdf-debug.getupvalue"><code>debug.getupvalue (f, up)</code></a></h3> + + +<p> +This function returns the name and the value of the upvalue +with index <code>up</code> of the function <code>f</code>. +The function returns <b>fail</b> +if there is no upvalue with the given index. + + +<p> +(For Lua functions, +upvalues are the external local variables that the function uses, +and that are consequently included in its closure.) + + +<p> +For C functions, this function uses the empty string <code>""</code> +as a name for all upvalues. + + +<p> +Variable name '<code>?</code>' (interrogation mark) +represents variables with no known names +(variables from chunks saved without debug information). + + + + +<p> +<hr><h3><a name="pdf-debug.getuservalue"><code>debug.getuservalue (u, n)</code></a></h3> + + +<p> +Returns the <code>n</code>-th user value associated +to the userdata <code>u</code> plus a boolean, +<b>false</b> if the userdata does not have that value. + + + + +<p> +<hr><h3><a name="pdf-debug.sethook"><code>debug.sethook ([thread,] hook, mask [, count])</code></a></h3> + + +<p> +Sets the given function as the debug hook. +The string <code>mask</code> and the number <code>count</code> describe +when the hook will be called. +The string mask may have any combination of the following characters, +with the given meaning: + +<ul> +<li><b>'<code>c</code>': </b> the hook is called every time Lua calls a function;</li> +<li><b>'<code>r</code>': </b> the hook is called every time Lua returns from a function;</li> +<li><b>'<code>l</code>': </b> the hook is called every time Lua enters a new line of code.</li> +</ul><p> +Moreover, +with a <code>count</code> different from zero, +the hook is called also after every <code>count</code> instructions. + + +<p> +When called without arguments, +<a href="#pdf-debug.sethook"><code>debug.sethook</code></a> turns off the hook. + + +<p> +When the hook is called, its first parameter is a string +describing the event that has triggered its call: +<code>"call"</code>, <code>"tail call"</code>, <code>"return"</code>, +<code>"line"</code>, and <code>"count"</code>. +For line events, +the hook also gets the new line number as its second parameter. +Inside a hook, +you can call <code>getinfo</code> with level 2 to get more information about +the running function. +(Level 0 is the <code>getinfo</code> function, +and level 1 is the hook function.) + + + + +<p> +<hr><h3><a name="pdf-debug.setlocal"><code>debug.setlocal ([thread,] level, local, value)</code></a></h3> + + +<p> +This function assigns the value <code>value</code> to the local variable +with index <code>local</code> of the function at level <code>level</code> of the stack. +The function returns <b>fail</b> if there is no local +variable with the given index, +and raises an error when called with a <code>level</code> out of range. +(You can call <code>getinfo</code> to check whether the level is valid.) +Otherwise, it returns the name of the local variable. + + +<p> +See <a href="#pdf-debug.getlocal"><code>debug.getlocal</code></a> for more information about +variable indices and names. + + + + +<p> +<hr><h3><a name="pdf-debug.setmetatable"><code>debug.setmetatable (value, table)</code></a></h3> + + +<p> +Sets the metatable for the given <code>value</code> to the given <code>table</code> +(which can be <b>nil</b>). +Returns <code>value</code>. + + + + +<p> +<hr><h3><a name="pdf-debug.setupvalue"><code>debug.setupvalue (f, up, value)</code></a></h3> + + +<p> +This function assigns the value <code>value</code> to the upvalue +with index <code>up</code> of the function <code>f</code>. +The function returns <b>fail</b> if there is no upvalue +with the given index. +Otherwise, it returns the name of the upvalue. + + +<p> +See <a href="#pdf-debug.getupvalue"><code>debug.getupvalue</code></a> for more information about upvalues. + + + + +<p> +<hr><h3><a name="pdf-debug.setuservalue"><code>debug.setuservalue (udata, value, n)</code></a></h3> + + +<p> +Sets the given <code>value</code> as +the <code>n</code>-th user value associated to the given <code>udata</code>. +<code>udata</code> must be a full userdata. + + +<p> +Returns <code>udata</code>, +or <b>fail</b> if the userdata does not have that value. + + + + +<p> +<hr><h3><a name="pdf-debug.traceback"><code>debug.traceback ([thread,] [message [, level]])</code></a></h3> + + +<p> +If <code>message</code> is present but is neither a string nor <b>nil</b>, +this function returns <code>message</code> without further processing. +Otherwise, +it returns a string with a traceback of the call stack. +The optional <code>message</code> string is appended +at the beginning of the traceback. +An optional <code>level</code> number tells at which level +to start the traceback +(default is 1, the function calling <code>traceback</code>). + + + + +<p> +<hr><h3><a name="pdf-debug.upvalueid"><code>debug.upvalueid (f, n)</code></a></h3> + + +<p> +Returns a unique identifier (as a light userdata) +for the upvalue numbered <code>n</code> +from the given function. + + +<p> +These unique identifiers allow a program to check whether different +closures share upvalues. +Lua closures that share an upvalue +(that is, that access a same external local variable) +will return identical ids for those upvalue indices. + + + + +<p> +<hr><h3><a name="pdf-debug.upvaluejoin"><code>debug.upvaluejoin (f1, n1, f2, n2)</code></a></h3> + + +<p> +Make the <code>n1</code>-th upvalue of the Lua closure <code>f1</code> +refer to the <code>n2</code>-th upvalue of the Lua closure <code>f2</code>. + + + + + + + +<h1>7 – <a name="7">Lua Standalone</a></h1> + +<p> +Although Lua has been designed as an extension language, +to be embedded in a host C program, +it is also frequently used as a standalone language. +An interpreter for Lua as a standalone language, +called simply <code>lua</code>, +is provided with the standard distribution. +The standalone interpreter includes +all standard libraries. +Its usage is: + +<pre> + lua [options] [script [args]] +</pre><p> +The options are: + +<ul> +<li><b><code>-e <em>stat</em></code>: </b> execute string <em>stat</em>;</li> +<li><b><code>-i</code>: </b> enter interactive mode after running <em>script</em>;</li> +<li><b><code>-l <em>mod</em></code>: </b> "require" <em>mod</em> and assign the + result to global <em>mod</em>;</li> +<li><b><code>-l <em>g=mod</em></code>: </b> "require" <em>mod</em> and assign the + result to global <em>g</em>;</li> +<li><b><code>-v</code>: </b> print version information;</li> +<li><b><code>-E</code>: </b> ignore environment variables;</li> +<li><b><code>-W</code>: </b> turn warnings on;</li> +<li><b><code>--</code>: </b> stop handling options;</li> +<li><b><code>-</code>: </b> execute <code>stdin</code> as a file and stop handling options.</li> +</ul><p> +(The form <code>-l <em>g=mod</em></code> was introduced in release 5.4.4.) + + +<p> +After handling its options, <code>lua</code> runs the given <em>script</em>. +When called without arguments, +<code>lua</code> behaves as <code>lua -v -i</code> +when the standard input (<code>stdin</code>) is a terminal, +and as <code>lua -</code> otherwise. + + +<p> +When called without the option <code>-E</code>, +the interpreter checks for an environment variable <a name="pdf-LUA_INIT_5_4"><code>LUA_INIT_5_4</code></a> +(or <a name="pdf-LUA_INIT"><code>LUA_INIT</code></a> if the versioned name is not defined) +before running any argument. +If the variable content has the format <code>@<em>filename</em></code>, +then <code>lua</code> executes the file. +Otherwise, <code>lua</code> executes the string itself. + + +<p> +When called with the option <code>-E</code>, +Lua does not consult any environment variables. +In particular, +the values of <a href="#pdf-package.path"><code>package.path</code></a> and <a href="#pdf-package.cpath"><code>package.cpath</code></a> +are set with the default paths defined in <code>luaconf.h</code>. + + +<p> +The options <code>-e</code>, <code>-l</code>, and <code>-W</code> are handled in +the order they appear. +For instance, an invocation like + +<pre> + $ lua -e 'a=1' -llib1 script.lua +</pre><p> +will first set <code>a</code> to 1, then require the library <code>lib1</code>, +and finally run the file <code>script.lua</code> with no arguments. +(Here <code>$</code> is the shell prompt. Your prompt may be different.) + + +<p> +Before running any code, +<code>lua</code> collects all command-line arguments +in a global table called <code>arg</code>. +The script name goes to index 0, +the first argument after the script name goes to index 1, +and so on. +Any arguments before the script name +(that is, the interpreter name plus its options) +go to negative indices. +For instance, in the call + +<pre> + $ lua -la b.lua t1 t2 +</pre><p> +the table is like this: + +<pre> + arg = { [-2] = "lua", [-1] = "-la", + [0] = "b.lua", + [1] = "t1", [2] = "t2" } +</pre><p> +If there is no script in the call, +the interpreter name goes to index 0, +followed by the other arguments. +For instance, the call + +<pre> + $ lua -e "print(arg[1])" +</pre><p> +will print "<code>-e</code>". +If there is a script, +the script is called with arguments +<code>arg[1]</code>, ···, <code>arg[#arg]</code>. +Like all chunks in Lua, +the script is compiled as a variadic function. + + +<p> +In interactive mode, +Lua repeatedly prompts and waits for a line. +After reading a line, +Lua first try to interpret the line as an expression. +If it succeeds, it prints its value. +Otherwise, it interprets the line as a statement. +If you write an incomplete statement, +the interpreter waits for its completion +by issuing a different prompt. + + +<p> +If the global variable <a name="pdf-_PROMPT"><code>_PROMPT</code></a> contains a string, +then its value is used as the prompt. +Similarly, if the global variable <a name="pdf-_PROMPT2"><code>_PROMPT2</code></a> contains a string, +its value is used as the secondary prompt +(issued during incomplete statements). + + +<p> +In case of unprotected errors in the script, +the interpreter reports the error to the standard error stream. +If the error object is not a string but +has a metamethod <code>__tostring</code>, +the interpreter calls this metamethod to produce the final message. +Otherwise, the interpreter converts the error object to a string +and adds a stack traceback to it. +When warnings are on, +they are simply printed in the standard error output. + + +<p> +When finishing normally, +the interpreter closes its main Lua state +(see <a href="#lua_close"><code>lua_close</code></a>). +The script can avoid this step by +calling <a href="#pdf-os.exit"><code>os.exit</code></a> to terminate. + + +<p> +To allow the use of Lua as a +script interpreter in Unix systems, +Lua skips the first line of a file chunk if it starts with <code>#</code>. +Therefore, Lua scripts can be made into executable programs +by using <code>chmod +x</code> and the <code>#!</code> form, +as in + +<pre> + #!/usr/local/bin/lua +</pre><p> +Of course, +the location of the Lua interpreter may be different in your machine. +If <code>lua</code> is in your <code>PATH</code>, +then + +<pre> + #!/usr/bin/env lua +</pre><p> +is a more portable solution. + + + +<h1>8 – <a name="8">Incompatibilities with the Previous Version</a></h1> + + + +<p> +Here we list the incompatibilities that you may find when moving a program +from Lua 5.3 to Lua 5.4. + + +<p> +You can avoid some incompatibilities by compiling Lua with +appropriate options (see file <code>luaconf.h</code>). +However, +all these compatibility options will be removed in the future. +More often than not, +compatibility issues arise when these compatibility options +are removed. +So, whenever you have the chance, +you should try to test your code with a version of Lua compiled +with all compatibility options turned off. +That will ease transitions to newer versions of Lua. + + +<p> +Lua versions can always change the C API in ways that +do not imply source-code changes in a program, +such as the numeric values for constants +or the implementation of functions as macros. +Therefore, +you should never assume that binaries are compatible between +different Lua versions. +Always recompile clients of the Lua API when +using a new version. + + +<p> +Similarly, Lua versions can always change the internal representation +of precompiled chunks; +precompiled chunks are not compatible between different Lua versions. + + +<p> +The standard paths in the official distribution may +change between versions. + + + + + +<h2>8.1 – <a name="8.1">Incompatibilities in the Language</a></h2> +<ul> + +<li> +The coercion of strings to numbers in +arithmetic and bitwise operations +has been removed from the core language. +The string library does a similar job +for arithmetic (but not for bitwise) operations +using the string metamethods. +However, unlike in previous versions, +the new implementation preserves the implicit type of the numeral +in the string. +For instance, the result of <code>"1" + "2"</code> now is an integer, +not a float. +</li> + +<li> +Literal decimal integer constants that overflow are read as floats, +instead of wrapping around. +You can use hexadecimal notation for such constants if you +want the old behavior +(reading them as integers with wrap around). +</li> + +<li> +The use of the <code>__lt</code> metamethod to emulate <code>__le</code> +has been removed. +When needed, this metamethod must be explicitly defined. +</li> + +<li> +The semantics of the numerical <b>for</b> loop +over integers changed in some details. +In particular, the control variable never wraps around. +</li> + +<li> +A label for a <b>goto</b> cannot be declared where a label with the same +name is visible, even if this other label is declared in an enclosing +block. +</li> + +<li> +When finalizing an object, +Lua does not ignore <code>__gc</code> metamethods that are not functions. +Any value will be called, if present. +(Non-callable values will generate a warning, +like any other error when calling a finalizer.) +</li> + +</ul> + + + + +<h2>8.2 – <a name="8.2">Incompatibilities in the Libraries</a></h2> +<ul> + +<li> +The function <a href="#pdf-print"><code>print</code></a> does not call <a href="#pdf-tostring"><code>tostring</code></a> +to format its arguments; +instead, it has this functionality hardwired. +You should use <code>__tostring</code> to modify how values are printed. +</li> + +<li> +The pseudo-random number generator used by the function <a href="#pdf-math.random"><code>math.random</code></a> +now starts with a somewhat random seed. +Moreover, it uses a different algorithm. +</li> + +<li> +By default, the decoding functions in the <a href="#pdf-utf8"><code>utf8</code></a> library +do not accept surrogates as valid code points. +An extra parameter in these functions makes them more permissive. +</li> + +<li> +The options "<code>setpause</code>" and "<code>setstepmul</code>" +of the function <a href="#pdf-collectgarbage"><code>collectgarbage</code></a> are deprecated. +You should use the new option "<code>incremental</code>" to set them. +</li> + +<li> +The function <a href="#pdf-io.lines"><code>io.lines</code></a> now returns four values, +instead of just one. +That can be a problem when it is used as the sole +argument to another function that has optional parameters, +such as in <code>load(io.lines(filename, "L"))</code>. +To fix that issue, +you can wrap the call into parentheses, +to adjust its number of results to one. +</li> + +</ul> + + + + +<h2>8.3 – <a name="8.3">Incompatibilities in the API</a></h2> + + +<ul> + +<li> +Full userdata now has an arbitrary number of associated user values. +Therefore, the functions <code>lua_newuserdata</code>, +<code>lua_setuservalue</code>, and <code>lua_getuservalue</code> were +replaced by <a href="#lua_newuserdatauv"><code>lua_newuserdatauv</code></a>, +<a href="#lua_setiuservalue"><code>lua_setiuservalue</code></a>, and <a href="#lua_getiuservalue"><code>lua_getiuservalue</code></a>, +which have an extra argument. + + +<p> +For compatibility, the old names still work as macros assuming +one single user value. +Note, however, that userdata with zero user values +are more efficient memory-wise. +</li> + +<li> +The function <a href="#lua_resume"><code>lua_resume</code></a> has an extra parameter. +This out parameter returns the number of values on +the top of the stack that were yielded or returned by the coroutine. +(In previous versions, +those values were the entire stack.) +</li> + +<li> +The function <a href="#lua_version"><code>lua_version</code></a> returns the version number, +instead of an address of the version number. +The Lua core should work correctly with libraries using their +own static copies of the same core, +so there is no need to check whether they are using the same +address space. +</li> + +<li> +The constant <code>LUA_ERRGCMM</code> was removed. +Errors in finalizers are never propagated; +instead, they generate a warning. +</li> + +<li> +The options <code>LUA_GCSETPAUSE</code> and <code>LUA_GCSETSTEPMUL</code> +of the function <a href="#lua_gc"><code>lua_gc</code></a> are deprecated. +You should use the new option <code>LUA_GCINC</code> to set them. +</li> + +</ul> + + + + +<h1>9 – <a name="9">The Complete Syntax of Lua</a></h1> + +<p> +Here is the complete syntax of Lua in extended BNF. +As usual in extended BNF, +{A} means 0 or more As, +and [A] means an optional A. +(For operator precedences, see <a href="#3.4.8">§3.4.8</a>; +for a description of the terminals +Name, Numeral, +and LiteralString, see <a href="#3.1">§3.1</a>.) + + + + +<pre> + + chunk ::= block + + block ::= {stat} [retstat] + + stat ::= ‘<b>;</b>’ | + varlist ‘<b>=</b>’ explist | + functioncall | + label | + <b>break</b> | + <b>goto</b> Name | + <b>do</b> block <b>end</b> | + <b>while</b> exp <b>do</b> block <b>end</b> | + <b>repeat</b> block <b>until</b> exp | + <b>if</b> exp <b>then</b> block {<b>elseif</b> exp <b>then</b> block} [<b>else</b> block] <b>end</b> | + <b>for</b> Name ‘<b>=</b>’ exp ‘<b>,</b>’ exp [‘<b>,</b>’ exp] <b>do</b> block <b>end</b> | + <b>for</b> namelist <b>in</b> explist <b>do</b> block <b>end</b> | + <b>function</b> funcname funcbody | + <b>local</b> <b>function</b> Name funcbody | + <b>local</b> attnamelist [‘<b>=</b>’ explist] + + attnamelist ::= Name attrib {‘<b>,</b>’ Name attrib} + + attrib ::= [‘<b><</b>’ Name ‘<b>></b>’] + + retstat ::= <b>return</b> [explist] [‘<b>;</b>’] + + label ::= ‘<b>::</b>’ Name ‘<b>::</b>’ + + funcname ::= Name {‘<b>.</b>’ Name} [‘<b>:</b>’ Name] + + varlist ::= var {‘<b>,</b>’ var} + + var ::= Name | prefixexp ‘<b>[</b>’ exp ‘<b>]</b>’ | prefixexp ‘<b>.</b>’ Name + + namelist ::= Name {‘<b>,</b>’ Name} + + explist ::= exp {‘<b>,</b>’ exp} + + exp ::= <b>nil</b> | <b>false</b> | <b>true</b> | Numeral | LiteralString | ‘<b>...</b>’ | functiondef | + prefixexp | tableconstructor | exp binop exp | unop exp + + prefixexp ::= var | functioncall | ‘<b>(</b>’ exp ‘<b>)</b>’ + + functioncall ::= prefixexp args | prefixexp ‘<b>:</b>’ Name args + + args ::= ‘<b>(</b>’ [explist] ‘<b>)</b>’ | tableconstructor | LiteralString + + functiondef ::= <b>function</b> funcbody + + funcbody ::= ‘<b>(</b>’ [parlist] ‘<b>)</b>’ block <b>end</b> + + parlist ::= namelist [‘<b>,</b>’ ‘<b>...</b>’] | ‘<b>...</b>’ + + tableconstructor ::= ‘<b>{</b>’ [fieldlist] ‘<b>}</b>’ + + fieldlist ::= field {fieldsep field} [fieldsep] + + field ::= ‘<b>[</b>’ exp ‘<b>]</b>’ ‘<b>=</b>’ exp | Name ‘<b>=</b>’ exp | exp + + fieldsep ::= ‘<b>,</b>’ | ‘<b>;</b>’ + + binop ::= ‘<b>+</b>’ | ‘<b>-</b>’ | ‘<b>*</b>’ | ‘<b>/</b>’ | ‘<b>//</b>’ | ‘<b>^</b>’ | ‘<b>%</b>’ | + ‘<b>&</b>’ | ‘<b>~</b>’ | ‘<b>|</b>’ | ‘<b>>></b>’ | ‘<b><<</b>’ | ‘<b>..</b>’ | + ‘<b><</b>’ | ‘<b><=</b>’ | ‘<b>></b>’ | ‘<b>>=</b>’ | ‘<b>==</b>’ | ‘<b>~=</b>’ | + <b>and</b> | <b>or</b> + + unop ::= ‘<b>-</b>’ | <b>not</b> | ‘<b>#</b>’ | ‘<b>~</b>’ + +</pre> + +<p> + + + + + + + +<P CLASS="footer"> +Last update: +Tue May 2 20:09:38 UTC 2023 +</P> +<!-- +Last change: revised for Lua 5.4.6 +--> + +</body></html> + diff --git a/src/libs/3rdparty/lua/doc/osi-certified-72x60.png b/src/libs/3rdparty/lua/doc/osi-certified-72x60.png Binary files differnew file mode 100644 index 0000000000..07df5f6ee7 --- /dev/null +++ b/src/libs/3rdparty/lua/doc/osi-certified-72x60.png diff --git a/src/libs/3rdparty/lua/doc/readme.html b/src/libs/3rdparty/lua/doc/readme.html new file mode 100644 index 0000000000..918ec8ed93 --- /dev/null +++ b/src/libs/3rdparty/lua/doc/readme.html @@ -0,0 +1,337 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<HTML> +<HEAD> +<TITLE>Lua 5.4 readme</TITLE> +<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css"> +<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1"> +<STYLE TYPE="text/css"> +blockquote, .display { + border: solid #a0a0a0 2px ; + border-radius: 8px ; + padding: 1em ; + margin: 0px ; +} + +.display { + word-spacing: 0.25em ; +} + +dl.display dd { + padding-bottom: 0.2em ; +} + +tt, kbd, code { + font-size: 12pt ; +} +</STYLE> +</HEAD> + +<BODY> + +<H1> +<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> +Welcome to Lua 5.4 +</H1> + +<DIV CLASS="menubar"> +<A HREF="#about">about</A> +· +<A HREF="#install">installation</A> +· +<A HREF="#changes">changes</A> +· +<A HREF="#license">license</A> +· +<A HREF="contents.html">reference manual</A> +</DIV> + +<H2><A NAME="about">About Lua</A></H2> +<P> +Lua is a powerful, efficient, lightweight, embeddable scripting language +developed by a +<A HREF="http://www.lua.org/authors.html">team</A> +at +<A HREF="http://www.puc-rio.br/">PUC-Rio</A>, +the Pontifical Catholic University of Rio de Janeiro in Brazil. +Lua is +<A HREF="#license">free software</A> +used in +<A HREF="http://www.lua.org/uses.html">many products and projects</A> +around the world. + +<P> +Lua's +<A HREF="http://www.lua.org/">official web site</A> +provides complete information +about Lua, +including +an +<A HREF="http://www.lua.org/about.html">executive summary</A> +and +updated +<A HREF="http://www.lua.org/docs.html">documentation</A>, +especially the +<A HREF="http://www.lua.org/manual/5.4/">reference manual</A>, +which may differ slightly from the +<A HREF="contents.html">local copy</A> +distributed in this package. + +<H2><A NAME="install">Installing Lua</A></H2> +<P> +Lua is distributed in +<A HREF="http://www.lua.org/ftp/">source</A> +form. +You need to build it before using it. +Building Lua should be straightforward +because +Lua is implemented in pure ANSI C and compiles unmodified in all known +platforms that have an ANSI C compiler. +Lua also compiles unmodified as C++. +The instructions given below for building Lua are for Unix-like platforms, +such as Linux and Mac OS X. +See also +<A HREF="#other">instructions for other systems</A> +and +<A HREF="#customization">customization options</A>. + +<P> +If you don't have the time or the inclination to compile Lua yourself, +get a binary from +<A HREF="http://lua-users.org/wiki/LuaBinaries">LuaBinaries</A>. + +<H3>Building Lua</H3> +<P> +In most common Unix-like platforms, simply do "<KBD>make</KBD>". +Here are the details. + +<OL> +<LI> +Open a terminal window and move to +the top-level directory, which is named <TT>lua-5.4.6</TT>. +The <TT>Makefile</TT> there controls both the build process and the installation process. +<P> +<LI> + Do "<KBD>make</KBD>". The <TT>Makefile</TT> will guess your platform and build Lua for it. +<P> +<LI> + If the guess failed, do "<KBD>make help</KBD>" and see if your platform is listed. + The platforms currently supported are: +<P> +<P CLASS="display"> + guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris +</P> +<P> + If your platform is listed, just do "<KBD>make xxx</KBD>", where xxx + is your platform name. +<P> + If your platform is not listed, try the closest one or posix, generic, + c89, in this order. +<P> +<LI> +The compilation takes only a few moments +and produces three files in the <TT>src</TT> directory: +lua (the interpreter), +luac (the compiler), +and liblua.a (the library). +<P> +<LI> + To check that Lua has been built correctly, do "<KBD>make test</KBD>" + after building Lua. This will run the interpreter and print its version. +</OL> +<P> +If you're running Linux, try "<KBD>make linux-readline</KBD>" to build the interactive Lua interpreter with handy line-editing and history capabilities. +If you get compilation errors, +make sure you have installed the <TT>readline</TT> development package +(which is probably named <TT>libreadline-dev</TT> or <TT>readline-devel</TT>). +If you get link errors after that, +then try "<KBD>make linux-readline MYLIBS=-ltermcap</KBD>". + +<H3>Installing Lua</H3> +<P> + Once you have built Lua, you may want to install it in an official + place in your system. In this case, do "<KBD>make install</KBD>". The official + place and the way to install files are defined in the <TT>Makefile</TT>. You'll + probably need the right permissions to install files, and so may need to do "<KBD>sudo make install</KBD>". + +<P> + To build and install Lua in one step, do "<KBD>make all install</KBD>", + or "<KBD>make xxx install</KBD>", + where xxx is your platform name. + +<P> + To install Lua locally after building it, do "<KBD>make local</KBD>". + This will create a directory <TT>install</TT> with subdirectories + <TT>bin</TT>, <TT>include</TT>, <TT>lib</TT>, <TT>man</TT>, <TT>share</TT>, + and install Lua as listed below. + + To install Lua locally, but in some other directory, do + "<KBD>make install INSTALL_TOP=xxx</KBD>", where xxx is your chosen directory. + The installation starts in the <TT>src</TT> and <TT>doc</TT> directories, + so take care if <TT>INSTALL_TOP</TT> is not an absolute path. + +<DL CLASS="display"> +<DT> + bin: +<DD> + lua luac +<DT> + include: +<DD> + lua.h luaconf.h lualib.h lauxlib.h lua.hpp +<DT> + lib: +<DD> + liblua.a +<DT> + man/man1: +<DD> + lua.1 luac.1 +</DL> + +<P> + These are the only directories you need for development. + If you only want to run Lua programs, + you only need the files in <TT>bin</TT> and <TT>man</TT>. + The files in <TT>include</TT> and <TT>lib</TT> are needed for + embedding Lua in C or C++ programs. + +<H3><A NAME="customization">Customization</A></H3> +<P> + Three kinds of things can be customized by editing a file: +<UL> + <LI> Where and how to install Lua — edit <TT>Makefile</TT>. + <LI> How to build Lua — edit <TT>src/Makefile</TT>. + <LI> Lua features — edit <TT>src/luaconf.h</TT>. +</UL> + +<P> + You don't actually need to edit the Makefiles because you may set the + relevant variables in the command line when invoking make. + Nevertheless, it's probably best to edit and save the Makefiles to + record the changes you've made. + +<P> + On the other hand, if you need to customize some Lua features, you'll need + to edit <TT>src/luaconf.h</TT> before building and installing Lua. + The edited file will be the one installed, and + it will be used by any Lua clients that you build, to ensure consistency. + Further customization is available to experts by editing the Lua sources. + +<H3><A NAME="other">Building Lua on other systems</A></H3> +<P> + If you're not using the usual Unix tools, then the instructions for + building Lua depend on the compiler you use. You'll need to create + projects (or whatever your compiler uses) for building the library, + the interpreter, and the compiler, as follows: + +<DL CLASS="display"> +<DT> +library: +<DD> +lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c +lauxlib.c lbaselib.c lcorolib.c ldblib.c liolib.c lmathlib.c loadlib.c loslib.c lstrlib.c ltablib.c lutf8lib.c linit.c +<DT> +interpreter: +<DD> + library, lua.c +<DT> +compiler: +<DD> + library, luac.c +</DL> + +<P> + To use Lua as a library in your own programs, you'll need to know how to + create and use libraries with your compiler. Moreover, to dynamically load + C libraries for Lua, you'll need to know how to create dynamic libraries + and you'll need to make sure that the Lua API functions are accessible to + those dynamic libraries — but <EM>don't</EM> link the Lua library + into each dynamic library. For Unix, we recommend that the Lua library + be linked statically into the host program and its symbols exported for + dynamic linking; <TT>src/Makefile</TT> does this for the Lua interpreter. + For Windows, we recommend that the Lua library be a DLL. + In all cases, the compiler luac should be linked statically. + +<P> + As mentioned above, you may edit <TT>src/luaconf.h</TT> to customize + some features before building Lua. + +<H2><A NAME="changes">Changes since Lua 5.3</A></H2> +<P> +Here are the main changes introduced in Lua 5.4. +The +<A HREF="contents.html">reference manual</A> +lists the +<A HREF="manual.html#8">incompatibilities</A> that had to be introduced. + +<H3>Main changes</H3> +<UL> +<LI> new generational mode for garbage collection +<LI> to-be-closed variables +<LI> const variables +<LI> userdata can have multiple user values +<LI> new implementation for math.random +<LI> warning system +<LI> debug information about function arguments and returns +<LI> new semantics for the integer 'for' loop +<LI> optional 'init' argument to 'string.gmatch' +<LI> new functions 'lua_resetthread' and 'coroutine.close' +<LI> string-to-number coercions moved to the string library +<LI> allocation function allowed to fail when shrinking a memory block +<LI> new format '%p' in 'string.format' +<LI> utf8 library accepts codepoints up to 2^31 +</UL> + +<H2><A NAME="license">License</A></H2> +<P> +<A HREF="http://www.opensource.org/docs/definition.php"> +<IMG SRC="osi-certified-72x60.png" ALIGN="right" ALT="[osi certified]" STYLE="padding-left: 30px ;"> +</A> +Lua is free software distributed under the terms of the +<A HREF="http://www.opensource.org/licenses/mit-license.html">MIT license</A> +reproduced below; +it may be used for any purpose, including commercial purposes, +at absolutely no cost without having to ask us. + +The only requirement is that if you do use Lua, +then you should give us credit by including the appropriate copyright notice somewhere in your product or its documentation. + +For details, see +<A HREF="http://www.lua.org/license.html">this</A>. + +<BLOCKQUOTE STYLE="padding-bottom: 0em"> +Copyright © 1994–2023 Lua.org, PUC-Rio. + +<P> +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +<P> +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +<P> +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +</BLOCKQUOTE> +<P> + +<P CLASS="footer"> +Last update: +Tue May 2 20:08:55 UTC 2023 +</P> +<!-- +Last change: revised for Lua 5.4.6 +--> + +</BODY> +</HTML> diff --git a/src/libs/3rdparty/lua/lua.qbs b/src/libs/3rdparty/lua/lua.qbs new file mode 100644 index 0000000000..73d61b039c --- /dev/null +++ b/src/libs/3rdparty/lua/lua.qbs @@ -0,0 +1,81 @@ +QtcLibrary { + name: "lua546" + type: "staticlibrary" + + cpp.defines: { + var defines = base; + if (qbs.targetOS.contains("windows")) + defines.push("LUA_USE_WINDOWS"); + else if (qbs.targetOS.contains("macos")) + defines.push("LUA_USE_MACOSX"); + else if (qbs.targetOS.contains("linux")) + defines.push("LUA_USE_LINUX"); + return defines; + } + + Group { + name: "Sources" + prefix: "src/" + + files: [ + "lapi.c", + "lapi.h", + "lauxlib.c", + "lauxlib.h", + "lbaselib.c", + "lcode.c", + "lcode.h", + "lcorolib.c", + "lctype.c", + "lctype.h", + "ldblib.c", + "ldebug.c", + "ldebug.h", + "ldo.c", + "ldo.h", + "ldump.c", + "lfunc.c", + "lfunc.h", + "lgc.c", + "lgc.h", + "linit.c", + "liolib.c", + "llex.c", + "llex.h", + "lmathlib.c", + "lmem.c", + "lmem.h", + "loadlib.c", + "lobject.c", + "lobject.h", + "lopcodes.c", + "lopcodes.h", + "loslib.c", + "lparser.c", + "lparser.h", + "lstate.c", + "lstate.h", + "lstring.c", + "lstring.h", + "lstrlib.c", + "ltable.c", + "ltable.h", + "ltablib.c", + "ltm.c", + "ltm.h", + "lua.c", + "lua.h", + "lundump.c", + "lundump.h", + "lutf8lib.c", + "lvm.c", + "lvm.h", + "lzio.c", + "lzio.h", + ] + } + + Export { + cpp.includePaths: project.ide_source_tree + "/src/libs/3rdparty/lua/src" + } +} diff --git a/src/libs/3rdparty/lua/src/lapi.c b/src/libs/3rdparty/lua/src/lapi.c new file mode 100644 index 0000000000..34e64af142 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lapi.c @@ -0,0 +1,1463 @@ +/* +** $Id: lapi.c $ +** Lua API +** See Copyright Notice in lua.h +*/ + +#define lapi_c +#define LUA_CORE + +#include "lprefix.h" + + +#include <limits.h> +#include <stdarg.h> +#include <string.h> + +#include "lua.h" + +#include "lapi.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lundump.h" +#include "lvm.h" + + + +const char lua_ident[] = + "$LuaVersion: " LUA_COPYRIGHT " $" + "$LuaAuthors: " LUA_AUTHORS " $"; + + + +/* +** Test for a valid index (one that is not the 'nilvalue'). +** '!ttisnil(o)' implies 'o != &G(L)->nilvalue', so it is not needed. +** However, it covers the most common cases in a faster way. +*/ +#define isvalid(L, o) (!ttisnil(o) || o != &G(L)->nilvalue) + + +/* test for pseudo index */ +#define ispseudo(i) ((i) <= LUA_REGISTRYINDEX) + +/* test for upvalue */ +#define isupvalue(i) ((i) < LUA_REGISTRYINDEX) + + +/* +** Convert an acceptable index to a pointer to its respective value. +** Non-valid indices return the special nil value 'G(L)->nilvalue'. +*/ +static TValue *index2value (lua_State *L, int idx) { + CallInfo *ci = L->ci; + if (idx > 0) { + StkId o = ci->func.p + idx; + api_check(L, idx <= ci->top.p - (ci->func.p + 1), "unacceptable index"); + if (o >= L->top.p) return &G(L)->nilvalue; + else return s2v(o); + } + else if (!ispseudo(idx)) { /* negative index */ + api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1), + "invalid index"); + return s2v(L->top.p + idx); + } + else if (idx == LUA_REGISTRYINDEX) + return &G(L)->l_registry; + else { /* upvalues */ + idx = LUA_REGISTRYINDEX - idx; + api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); + if (ttisCclosure(s2v(ci->func.p))) { /* C closure? */ + CClosure *func = clCvalue(s2v(ci->func.p)); + return (idx <= func->nupvalues) ? &func->upvalue[idx-1] + : &G(L)->nilvalue; + } + else { /* light C function or Lua function (through a hook)?) */ + api_check(L, ttislcf(s2v(ci->func.p)), "caller not a C function"); + return &G(L)->nilvalue; /* no upvalues */ + } + } +} + + + +/* +** Convert a valid actual index (not a pseudo-index) to its address. +*/ +l_sinline StkId index2stack (lua_State *L, int idx) { + CallInfo *ci = L->ci; + if (idx > 0) { + StkId o = ci->func.p + idx; + api_check(L, o < L->top.p, "invalid index"); + return o; + } + else { /* non-positive index */ + api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1), + "invalid index"); + api_check(L, !ispseudo(idx), "invalid index"); + return L->top.p + idx; + } +} + + +LUA_API int lua_checkstack (lua_State *L, int n) { + int res; + CallInfo *ci; + lua_lock(L); + ci = L->ci; + api_check(L, n >= 0, "negative 'n'"); + if (L->stack_last.p - L->top.p > n) /* stack large enough? */ + res = 1; /* yes; check is OK */ + else /* need to grow stack */ + res = luaD_growstack(L, n, 0); + if (res && ci->top.p < L->top.p + n) + ci->top.p = L->top.p + n; /* adjust frame top */ + lua_unlock(L); + return res; +} + + +LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { + int i; + if (from == to) return; + lua_lock(to); + api_checknelems(from, n); + api_check(from, G(from) == G(to), "moving among independent states"); + api_check(from, to->ci->top.p - to->top.p >= n, "stack overflow"); + from->top.p -= n; + for (i = 0; i < n; i++) { + setobjs2s(to, to->top.p, from->top.p + i); + to->top.p++; /* stack already checked by previous 'api_check' */ + } + lua_unlock(to); +} + + +LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { + lua_CFunction old; + lua_lock(L); + old = G(L)->panic; + G(L)->panic = panicf; + lua_unlock(L); + return old; +} + + +LUA_API lua_Number lua_version (lua_State *L) { + UNUSED(L); + return LUA_VERSION_NUM; +} + + + +/* +** basic stack manipulation +*/ + + +/* +** convert an acceptable stack index into an absolute index +*/ +LUA_API int lua_absindex (lua_State *L, int idx) { + return (idx > 0 || ispseudo(idx)) + ? idx + : cast_int(L->top.p - L->ci->func.p) + idx; +} + + +LUA_API int lua_gettop (lua_State *L) { + return cast_int(L->top.p - (L->ci->func.p + 1)); +} + + +LUA_API void lua_settop (lua_State *L, int idx) { + CallInfo *ci; + StkId func, newtop; + ptrdiff_t diff; /* difference for new top */ + lua_lock(L); + ci = L->ci; + func = ci->func.p; + if (idx >= 0) { + api_check(L, idx <= ci->top.p - (func + 1), "new top too large"); + diff = ((func + 1) + idx) - L->top.p; + for (; diff > 0; diff--) + setnilvalue(s2v(L->top.p++)); /* clear new slots */ + } + else { + api_check(L, -(idx+1) <= (L->top.p - (func + 1)), "invalid new top"); + diff = idx + 1; /* will "subtract" index (as it is negative) */ + } + api_check(L, L->tbclist.p < L->top.p, "previous pop of an unclosed slot"); + newtop = L->top.p + diff; + if (diff < 0 && L->tbclist.p >= newtop) { + lua_assert(hastocloseCfunc(ci->nresults)); + newtop = luaF_close(L, newtop, CLOSEKTOP, 0); + } + L->top.p = newtop; /* correct top only after closing any upvalue */ + lua_unlock(L); +} + + +LUA_API void lua_closeslot (lua_State *L, int idx) { + StkId level; + lua_lock(L); + level = index2stack(L, idx); + api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level, + "no variable to close at given level"); + level = luaF_close(L, level, CLOSEKTOP, 0); + setnilvalue(s2v(level)); + lua_unlock(L); +} + + +/* +** Reverse the stack segment from 'from' to 'to' +** (auxiliary to 'lua_rotate') +** Note that we move(copy) only the value inside the stack. +** (We do not move additional fields that may exist.) +*/ +l_sinline void reverse (lua_State *L, StkId from, StkId to) { + for (; from < to; from++, to--) { + TValue temp; + setobj(L, &temp, s2v(from)); + setobjs2s(L, from, to); + setobj2s(L, to, &temp); + } +} + + +/* +** Let x = AB, where A is a prefix of length 'n'. Then, +** rotate x n == BA. But BA == (A^r . B^r)^r. +*/ +LUA_API void lua_rotate (lua_State *L, int idx, int n) { + StkId p, t, m; + lua_lock(L); + t = L->top.p - 1; /* end of stack segment being rotated */ + p = index2stack(L, idx); /* start of segment */ + api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'"); + m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */ + reverse(L, p, m); /* reverse the prefix with length 'n' */ + reverse(L, m + 1, t); /* reverse the suffix */ + reverse(L, p, t); /* reverse the entire segment */ + lua_unlock(L); +} + + +LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { + TValue *fr, *to; + lua_lock(L); + fr = index2value(L, fromidx); + to = index2value(L, toidx); + api_check(L, isvalid(L, to), "invalid index"); + setobj(L, to, fr); + if (isupvalue(toidx)) /* function upvalue? */ + luaC_barrier(L, clCvalue(s2v(L->ci->func.p)), fr); + /* LUA_REGISTRYINDEX does not need gc barrier + (collector revisits it before finishing collection) */ + lua_unlock(L); +} + + +LUA_API void lua_pushvalue (lua_State *L, int idx) { + lua_lock(L); + setobj2s(L, L->top.p, index2value(L, idx)); + api_incr_top(L); + lua_unlock(L); +} + + + +/* +** access functions (stack -> C) +*/ + + +LUA_API int lua_type (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + return (isvalid(L, o) ? ttype(o) : LUA_TNONE); +} + + +LUA_API const char *lua_typename (lua_State *L, int t) { + UNUSED(L); + api_check(L, LUA_TNONE <= t && t < LUA_NUMTYPES, "invalid type"); + return ttypename(t); +} + + +LUA_API int lua_iscfunction (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + return (ttislcf(o) || (ttisCclosure(o))); +} + + +LUA_API int lua_isinteger (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + return ttisinteger(o); +} + + +LUA_API int lua_isnumber (lua_State *L, int idx) { + lua_Number n; + const TValue *o = index2value(L, idx); + return tonumber(o, &n); +} + + +LUA_API int lua_isstring (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + return (ttisstring(o) || cvt2str(o)); +} + + +LUA_API int lua_isuserdata (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + return (ttisfulluserdata(o) || ttislightuserdata(o)); +} + + +LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { + const TValue *o1 = index2value(L, index1); + const TValue *o2 = index2value(L, index2); + return (isvalid(L, o1) && isvalid(L, o2)) ? luaV_rawequalobj(o1, o2) : 0; +} + + +LUA_API void lua_arith (lua_State *L, int op) { + lua_lock(L); + if (op != LUA_OPUNM && op != LUA_OPBNOT) + api_checknelems(L, 2); /* all other operations expect two operands */ + else { /* for unary operations, add fake 2nd operand */ + api_checknelems(L, 1); + setobjs2s(L, L->top.p, L->top.p - 1); + api_incr_top(L); + } + /* first operand at top - 2, second at top - 1; result go to top - 2 */ + luaO_arith(L, op, s2v(L->top.p - 2), s2v(L->top.p - 1), L->top.p - 2); + L->top.p--; /* remove second operand */ + lua_unlock(L); +} + + +LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { + const TValue *o1; + const TValue *o2; + int i = 0; + lua_lock(L); /* may call tag method */ + o1 = index2value(L, index1); + o2 = index2value(L, index2); + if (isvalid(L, o1) && isvalid(L, o2)) { + switch (op) { + case LUA_OPEQ: i = luaV_equalobj(L, o1, o2); break; + case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break; + case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break; + default: api_check(L, 0, "invalid option"); + } + } + lua_unlock(L); + return i; +} + + +LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) { + size_t sz = luaO_str2num(s, s2v(L->top.p)); + if (sz != 0) + api_incr_top(L); + return sz; +} + + +LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *pisnum) { + lua_Number n = 0; + const TValue *o = index2value(L, idx); + int isnum = tonumber(o, &n); + if (pisnum) + *pisnum = isnum; + return n; +} + + +LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) { + lua_Integer res = 0; + const TValue *o = index2value(L, idx); + int isnum = tointeger(o, &res); + if (pisnum) + *pisnum = isnum; + return res; +} + + +LUA_API int lua_toboolean (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + return !l_isfalse(o); +} + + +LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { + TValue *o; + lua_lock(L); + o = index2value(L, idx); + if (!ttisstring(o)) { + if (!cvt2str(o)) { /* not convertible? */ + if (len != NULL) *len = 0; + lua_unlock(L); + return NULL; + } + luaO_tostring(L, o); + luaC_checkGC(L); + o = index2value(L, idx); /* previous call may reallocate the stack */ + } + if (len != NULL) + *len = vslen(o); + lua_unlock(L); + return svalue(o); +} + + +LUA_API lua_Unsigned lua_rawlen (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + switch (ttypetag(o)) { + case LUA_VSHRSTR: return tsvalue(o)->shrlen; + case LUA_VLNGSTR: return tsvalue(o)->u.lnglen; + case LUA_VUSERDATA: return uvalue(o)->len; + case LUA_VTABLE: return luaH_getn(hvalue(o)); + default: return 0; + } +} + + +LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + if (ttislcf(o)) return fvalue(o); + else if (ttisCclosure(o)) + return clCvalue(o)->f; + else return NULL; /* not a C function */ +} + + +l_sinline void *touserdata (const TValue *o) { + switch (ttype(o)) { + case LUA_TUSERDATA: return getudatamem(uvalue(o)); + case LUA_TLIGHTUSERDATA: return pvalue(o); + default: return NULL; + } +} + + +LUA_API void *lua_touserdata (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + return touserdata(o); +} + + +LUA_API lua_State *lua_tothread (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + return (!ttisthread(o)) ? NULL : thvalue(o); +} + + +/* +** Returns a pointer to the internal representation of an object. +** Note that ANSI C does not allow the conversion of a pointer to +** function to a 'void*', so the conversion here goes through +** a 'size_t'. (As the returned pointer is only informative, this +** conversion should not be a problem.) +*/ +LUA_API const void *lua_topointer (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + switch (ttypetag(o)) { + case LUA_VLCF: return cast_voidp(cast_sizet(fvalue(o))); + case LUA_VUSERDATA: case LUA_VLIGHTUSERDATA: + return touserdata(o); + default: { + if (iscollectable(o)) + return gcvalue(o); + else + return NULL; + } + } +} + + + +/* +** push functions (C -> stack) +*/ + + +LUA_API void lua_pushnil (lua_State *L) { + lua_lock(L); + setnilvalue(s2v(L->top.p)); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { + lua_lock(L); + setfltvalue(s2v(L->top.p), n); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { + lua_lock(L); + setivalue(s2v(L->top.p), n); + api_incr_top(L); + lua_unlock(L); +} + + +/* +** Pushes on the stack a string with given length. Avoid using 's' when +** 'len' == 0 (as 's' can be NULL in that case), due to later use of +** 'memcmp' and 'memcpy'. +*/ +LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { + TString *ts; + lua_lock(L); + ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); + setsvalue2s(L, L->top.p, ts); + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); + return getstr(ts); +} + + +LUA_API const char *lua_pushstring (lua_State *L, const char *s) { + lua_lock(L); + if (s == NULL) + setnilvalue(s2v(L->top.p)); + else { + TString *ts; + ts = luaS_new(L, s); + setsvalue2s(L, L->top.p, ts); + s = getstr(ts); /* internal copy's address */ + } + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); + return s; +} + + +LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, + va_list argp) { + const char *ret; + lua_lock(L); + ret = luaO_pushvfstring(L, fmt, argp); + luaC_checkGC(L); + lua_unlock(L); + return ret; +} + + +LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { + const char *ret; + va_list argp; + lua_lock(L); + va_start(argp, fmt); + ret = luaO_pushvfstring(L, fmt, argp); + va_end(argp); + luaC_checkGC(L); + lua_unlock(L); + return ret; +} + + +LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { + lua_lock(L); + if (n == 0) { + setfvalue(s2v(L->top.p), fn); + api_incr_top(L); + } + else { + CClosure *cl; + api_checknelems(L, n); + api_check(L, n <= MAXUPVAL, "upvalue index too large"); + cl = luaF_newCclosure(L, n); + cl->f = fn; + L->top.p -= n; + while (n--) { + setobj2n(L, &cl->upvalue[n], s2v(L->top.p + n)); + /* does not need barrier because closure is white */ + lua_assert(iswhite(cl)); + } + setclCvalue(L, s2v(L->top.p), cl); + api_incr_top(L); + luaC_checkGC(L); + } + lua_unlock(L); +} + + +LUA_API void lua_pushboolean (lua_State *L, int b) { + lua_lock(L); + if (b) + setbtvalue(s2v(L->top.p)); + else + setbfvalue(s2v(L->top.p)); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { + lua_lock(L); + setpvalue(s2v(L->top.p), p); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API int lua_pushthread (lua_State *L) { + lua_lock(L); + setthvalue(L, s2v(L->top.p), L); + api_incr_top(L); + lua_unlock(L); + return (G(L)->mainthread == L); +} + + + +/* +** get functions (Lua -> stack) +*/ + + +l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) { + const TValue *slot; + TString *str = luaS_new(L, k); + if (luaV_fastget(L, t, str, slot, luaH_getstr)) { + setobj2s(L, L->top.p, slot); + api_incr_top(L); + } + else { + setsvalue2s(L, L->top.p, str); + api_incr_top(L); + luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot); + } + lua_unlock(L); + return ttype(s2v(L->top.p - 1)); +} + + +/* +** Get the global table in the registry. Since all predefined +** indices in the registry were inserted right when the registry +** was created and never removed, they must always be in the array +** part of the registry. +*/ +#define getGtable(L) \ + (&hvalue(&G(L)->l_registry)->array[LUA_RIDX_GLOBALS - 1]) + + +LUA_API int lua_getglobal (lua_State *L, const char *name) { + const TValue *G; + lua_lock(L); + G = getGtable(L); + return auxgetstr(L, G, name); +} + + +LUA_API int lua_gettable (lua_State *L, int idx) { + const TValue *slot; + TValue *t; + lua_lock(L); + t = index2value(L, idx); + if (luaV_fastget(L, t, s2v(L->top.p - 1), slot, luaH_get)) { + setobj2s(L, L->top.p - 1, slot); + } + else + luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot); + lua_unlock(L); + return ttype(s2v(L->top.p - 1)); +} + + +LUA_API int lua_getfield (lua_State *L, int idx, const char *k) { + lua_lock(L); + return auxgetstr(L, index2value(L, idx), k); +} + + +LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { + TValue *t; + const TValue *slot; + lua_lock(L); + t = index2value(L, idx); + if (luaV_fastgeti(L, t, n, slot)) { + setobj2s(L, L->top.p, slot); + } + else { + TValue aux; + setivalue(&aux, n); + luaV_finishget(L, t, &aux, L->top.p, slot); + } + api_incr_top(L); + lua_unlock(L); + return ttype(s2v(L->top.p - 1)); +} + + +l_sinline int finishrawget (lua_State *L, const TValue *val) { + if (isempty(val)) /* avoid copying empty items to the stack */ + setnilvalue(s2v(L->top.p)); + else + setobj2s(L, L->top.p, val); + api_incr_top(L); + lua_unlock(L); + return ttype(s2v(L->top.p - 1)); +} + + +static Table *gettable (lua_State *L, int idx) { + TValue *t = index2value(L, idx); + api_check(L, ttistable(t), "table expected"); + return hvalue(t); +} + + +LUA_API int lua_rawget (lua_State *L, int idx) { + Table *t; + const TValue *val; + lua_lock(L); + api_checknelems(L, 1); + t = gettable(L, idx); + val = luaH_get(t, s2v(L->top.p - 1)); + L->top.p--; /* remove key */ + return finishrawget(L, val); +} + + +LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) { + Table *t; + lua_lock(L); + t = gettable(L, idx); + return finishrawget(L, luaH_getint(t, n)); +} + + +LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) { + Table *t; + TValue k; + lua_lock(L); + t = gettable(L, idx); + setpvalue(&k, cast_voidp(p)); + return finishrawget(L, luaH_get(t, &k)); +} + + +LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { + Table *t; + lua_lock(L); + t = luaH_new(L); + sethvalue2s(L, L->top.p, t); + api_incr_top(L); + if (narray > 0 || nrec > 0) + luaH_resize(L, t, narray, nrec); + luaC_checkGC(L); + lua_unlock(L); +} + + +LUA_API int lua_getmetatable (lua_State *L, int objindex) { + const TValue *obj; + Table *mt; + int res = 0; + lua_lock(L); + obj = index2value(L, objindex); + switch (ttype(obj)) { + case LUA_TTABLE: + mt = hvalue(obj)->metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(obj)->metatable; + break; + default: + mt = G(L)->mt[ttype(obj)]; + break; + } + if (mt != NULL) { + sethvalue2s(L, L->top.p, mt); + api_incr_top(L); + res = 1; + } + lua_unlock(L); + return res; +} + + +LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) { + TValue *o; + int t; + lua_lock(L); + o = index2value(L, idx); + api_check(L, ttisfulluserdata(o), "full userdata expected"); + if (n <= 0 || n > uvalue(o)->nuvalue) { + setnilvalue(s2v(L->top.p)); + t = LUA_TNONE; + } + else { + setobj2s(L, L->top.p, &uvalue(o)->uv[n - 1].uv); + t = ttype(s2v(L->top.p)); + } + api_incr_top(L); + lua_unlock(L); + return t; +} + + +/* +** 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_fastget(L, t, str, slot, luaH_getstr)) { + luaV_finishfastset(L, t, slot, s2v(L->top.p - 1)); + L->top.p--; /* pop value */ + } + else { + setsvalue2s(L, L->top.p, str); /* push 'str' (to make it a TValue) */ + api_incr_top(L); + luaV_finishset(L, t, s2v(L->top.p - 1), s2v(L->top.p - 2), slot); + L->top.p -= 2; /* pop value and key */ + } + lua_unlock(L); /* lock done by caller */ +} + + +LUA_API void lua_setglobal (lua_State *L, const char *name) { + const TValue *G; + lua_lock(L); /* unlock done in 'auxsetstr' */ + G = getGtable(L); + auxsetstr(L, G, name); +} + + +LUA_API void lua_settable (lua_State *L, int idx) { + TValue *t; + const TValue *slot; + lua_lock(L); + api_checknelems(L, 2); + t = index2value(L, idx); + if (luaV_fastget(L, t, s2v(L->top.p - 2), slot, luaH_get)) { + luaV_finishfastset(L, t, slot, s2v(L->top.p - 1)); + } + else + luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), slot); + L->top.p -= 2; /* pop index and value */ + lua_unlock(L); +} + + +LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { + lua_lock(L); /* unlock done in 'auxsetstr' */ + auxsetstr(L, index2value(L, idx), k); +} + + +LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { + TValue *t; + const TValue *slot; + lua_lock(L); + api_checknelems(L, 1); + t = index2value(L, idx); + if (luaV_fastgeti(L, t, n, slot)) { + luaV_finishfastset(L, t, slot, s2v(L->top.p - 1)); + } + else { + TValue aux; + setivalue(&aux, n); + luaV_finishset(L, t, &aux, s2v(L->top.p - 1), slot); + } + L->top.p--; /* pop value */ + lua_unlock(L); +} + + +static void aux_rawset (lua_State *L, int idx, TValue *key, int n) { + Table *t; + lua_lock(L); + api_checknelems(L, n); + t = gettable(L, idx); + luaH_set(L, t, key, s2v(L->top.p - 1)); + invalidateTMcache(t); + luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1)); + L->top.p -= n; + lua_unlock(L); +} + + +LUA_API void lua_rawset (lua_State *L, int idx) { + aux_rawset(L, idx, s2v(L->top.p - 2), 2); +} + + +LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) { + TValue k; + setpvalue(&k, cast_voidp(p)); + aux_rawset(L, idx, &k, 1); +} + + +LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) { + Table *t; + lua_lock(L); + api_checknelems(L, 1); + t = gettable(L, idx); + luaH_setint(L, t, n, s2v(L->top.p - 1)); + luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1)); + L->top.p--; + lua_unlock(L); +} + + +LUA_API int lua_setmetatable (lua_State *L, int objindex) { + TValue *obj; + Table *mt; + lua_lock(L); + api_checknelems(L, 1); + obj = index2value(L, objindex); + if (ttisnil(s2v(L->top.p - 1))) + mt = NULL; + else { + api_check(L, ttistable(s2v(L->top.p - 1)), "table expected"); + mt = hvalue(s2v(L->top.p - 1)); + } + switch (ttype(obj)) { + case LUA_TTABLE: { + hvalue(obj)->metatable = mt; + if (mt) { + luaC_objbarrier(L, gcvalue(obj), mt); + luaC_checkfinalizer(L, gcvalue(obj), mt); + } + break; + } + case LUA_TUSERDATA: { + uvalue(obj)->metatable = mt; + if (mt) { + luaC_objbarrier(L, uvalue(obj), mt); + luaC_checkfinalizer(L, gcvalue(obj), mt); + } + break; + } + default: { + G(L)->mt[ttype(obj)] = mt; + break; + } + } + L->top.p--; + lua_unlock(L); + return 1; +} + + +LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) { + TValue *o; + int res; + lua_lock(L); + api_checknelems(L, 1); + o = index2value(L, idx); + api_check(L, ttisfulluserdata(o), "full userdata expected"); + if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue))) + res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */ + else { + setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top.p - 1)); + luaC_barrierback(L, gcvalue(o), s2v(L->top.p - 1)); + res = 1; + } + L->top.p--; + lua_unlock(L); + return res; +} + + +/* +** 'load' and 'call' functions (run Lua code) +*/ + + +#define checkresults(L,na,nr) \ + api_check(L, (nr) == LUA_MULTRET \ + || (L->ci->top.p - L->top.p >= (nr) - (na)), \ + "results from function overflow current stack size") + + +LUA_API void lua_callk (lua_State *L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k) { + StkId func; + lua_lock(L); + api_check(L, k == NULL || !isLua(L->ci), + "cannot use continuations inside hooks"); + api_checknelems(L, nargs+1); + api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); + checkresults(L, nargs, nresults); + func = L->top.p - (nargs+1); + if (k != NULL && yieldable(L)) { /* need to prepare continuation? */ + L->ci->u.c.k = k; /* save continuation */ + L->ci->u.c.ctx = ctx; /* save context */ + luaD_call(L, func, nresults); /* do the call */ + } + else /* no continuation or no yieldable */ + luaD_callnoyield(L, func, nresults); /* just do the call */ + adjustresults(L, nresults); + lua_unlock(L); +} + + + +/* +** Execute a protected call. +*/ +struct CallS { /* data to 'f_call' */ + StkId func; + int nresults; +}; + + +static void f_call (lua_State *L, void *ud) { + struct CallS *c = cast(struct CallS *, ud); + luaD_callnoyield(L, c->func, c->nresults); +} + + + +LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, + lua_KContext ctx, lua_KFunction k) { + struct CallS c; + int status; + ptrdiff_t func; + lua_lock(L); + api_check(L, k == NULL || !isLua(L->ci), + "cannot use continuations inside hooks"); + api_checknelems(L, nargs+1); + api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); + checkresults(L, nargs, nresults); + if (errfunc == 0) + func = 0; + else { + StkId o = index2stack(L, errfunc); + api_check(L, ttisfunction(s2v(o)), "error handler must be a function"); + func = savestack(L, o); + } + c.func = L->top.p - (nargs+1); /* function to be called */ + if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */ + c.nresults = nresults; /* do a 'conventional' protected call */ + status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); + } + else { /* prepare continuation (call is already protected by 'resume') */ + CallInfo *ci = L->ci; + ci->u.c.k = k; /* save continuation */ + ci->u.c.ctx = ctx; /* save context */ + /* save information for error recovery */ + ci->u2.funcidx = cast_int(savestack(L, c.func)); + ci->u.c.old_errfunc = L->errfunc; + L->errfunc = func; + setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */ + ci->callstatus |= CIST_YPCALL; /* function can do error recovery */ + luaD_call(L, c.func, nresults); /* do the call */ + ci->callstatus &= ~CIST_YPCALL; + L->errfunc = ci->u.c.old_errfunc; + status = LUA_OK; /* if it is here, there were no errors */ + } + adjustresults(L, nresults); + lua_unlock(L); + return status; +} + + +LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, + const char *chunkname, const char *mode) { + ZIO z; + int status; + lua_lock(L); + if (!chunkname) chunkname = "?"; + luaZ_init(L, &z, reader, data); + status = luaD_protectedparser(L, &z, chunkname, mode); + if (status == LUA_OK) { /* no errors? */ + LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new function */ + if (f->nupvalues >= 1) { /* does it have an upvalue? */ + /* get global table from registry */ + const TValue *gt = getGtable(L); + /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ + setobj(L, f->upvals[0]->v.p, gt); + luaC_barrier(L, f->upvals[0], gt); + } + } + lua_unlock(L); + return status; +} + + +LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) { + int status; + TValue *o; + lua_lock(L); + api_checknelems(L, 1); + o = s2v(L->top.p - 1); + if (isLfunction(o)) + status = luaU_dump(L, getproto(o), writer, data, strip); + else + status = 1; + lua_unlock(L); + return status; +} + + +LUA_API int lua_status (lua_State *L) { + return L->status; +} + + +/* +** Garbage-collection function +*/ +LUA_API int lua_gc (lua_State *L, int what, ...) { + va_list argp; + int res = 0; + global_State *g = G(L); + if (g->gcstp & GCSTPGC) /* internal stop? */ + return -1; /* all options are invalid when stopped */ + lua_lock(L); + va_start(argp, what); + switch (what) { + case LUA_GCSTOP: { + g->gcstp = GCSTPUSR; /* stopped by the user */ + break; + } + case LUA_GCRESTART: { + luaE_setdebt(g, 0); + g->gcstp = 0; /* (GCSTPGC must be already zero here) */ + break; + } + case LUA_GCCOLLECT: { + luaC_fullgc(L, 0); + break; + } + case LUA_GCCOUNT: { + /* GC values are expressed in Kbytes: #bytes/2^10 */ + res = cast_int(gettotalbytes(g) >> 10); + break; + } + case LUA_GCCOUNTB: { + res = cast_int(gettotalbytes(g) & 0x3ff); + break; + } + case LUA_GCSTEP: { + int data = va_arg(argp, int); + l_mem debt = 1; /* =1 to signal that it did an actual step */ + lu_byte oldstp = g->gcstp; + g->gcstp = 0; /* allow GC to run (GCSTPGC must be zero here) */ + if (data == 0) { + luaE_setdebt(g, 0); /* do a basic step */ + luaC_step(L); + } + else { /* add 'data' to total debt */ + debt = cast(l_mem, data) * 1024 + g->GCdebt; + luaE_setdebt(g, debt); + luaC_checkGC(L); + } + g->gcstp = oldstp; /* restore previous state */ + if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ + res = 1; /* signal it */ + break; + } + case LUA_GCSETPAUSE: { + int data = va_arg(argp, int); + res = getgcparam(g->gcpause); + setgcparam(g->gcpause, data); + break; + } + case LUA_GCSETSTEPMUL: { + int data = va_arg(argp, int); + res = getgcparam(g->gcstepmul); + setgcparam(g->gcstepmul, data); + break; + } + case LUA_GCISRUNNING: { + res = gcrunning(g); + break; + } + case LUA_GCGEN: { + int minormul = va_arg(argp, int); + int majormul = va_arg(argp, int); + res = isdecGCmodegen(g) ? LUA_GCGEN : LUA_GCINC; + if (minormul != 0) + g->genminormul = minormul; + if (majormul != 0) + setgcparam(g->genmajormul, majormul); + luaC_changemode(L, KGC_GEN); + break; + } + case LUA_GCINC: { + int pause = va_arg(argp, int); + int stepmul = va_arg(argp, int); + int stepsize = va_arg(argp, int); + res = isdecGCmodegen(g) ? LUA_GCGEN : LUA_GCINC; + if (pause != 0) + setgcparam(g->gcpause, pause); + if (stepmul != 0) + setgcparam(g->gcstepmul, stepmul); + if (stepsize != 0) + g->gcstepsize = stepsize; + luaC_changemode(L, KGC_INC); + break; + } + default: res = -1; /* invalid option */ + } + va_end(argp); + lua_unlock(L); + return res; +} + + + +/* +** miscellaneous functions +*/ + + +LUA_API int lua_error (lua_State *L) { + TValue *errobj; + lua_lock(L); + errobj = s2v(L->top.p - 1); + api_checknelems(L, 1); + /* error object is the memory error message? */ + if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg)) + luaM_error(L); /* raise a memory error */ + else + luaG_errormsg(L); /* raise a regular error */ + /* code unreachable; will unlock when control actually leaves the kernel */ + return 0; /* to avoid warnings */ +} + + +LUA_API int lua_next (lua_State *L, int idx) { + Table *t; + int more; + lua_lock(L); + api_checknelems(L, 1); + t = gettable(L, idx); + more = luaH_next(L, t, L->top.p - 1); + if (more) { + api_incr_top(L); + } + else /* no more elements */ + L->top.p -= 1; /* remove key */ + lua_unlock(L); + return more; +} + + +LUA_API void lua_toclose (lua_State *L, int idx) { + int nresults; + StkId o; + lua_lock(L); + o = index2stack(L, idx); + nresults = L->ci->nresults; + api_check(L, L->tbclist.p < o, "given index below or equal a marked one"); + luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */ + if (!hastocloseCfunc(nresults)) /* function not marked yet? */ + L->ci->nresults = codeNresults(nresults); /* mark it */ + lua_assert(hastocloseCfunc(L->ci->nresults)); + lua_unlock(L); +} + + +LUA_API void lua_concat (lua_State *L, int n) { + lua_lock(L); + api_checknelems(L, n); + if (n > 0) + luaV_concat(L, n); + else { /* nothing to concatenate */ + setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */ + api_incr_top(L); + } + luaC_checkGC(L); + lua_unlock(L); +} + + +LUA_API void lua_len (lua_State *L, int idx) { + TValue *t; + lua_lock(L); + t = index2value(L, idx); + luaV_objlen(L, L->top.p, t); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { + lua_Alloc f; + lua_lock(L); + if (ud) *ud = G(L)->ud; + f = G(L)->frealloc; + lua_unlock(L); + return f; +} + + +LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) { + lua_lock(L); + G(L)->ud = ud; + G(L)->frealloc = f; + lua_unlock(L); +} + + +void lua_setwarnf (lua_State *L, lua_WarnFunction f, void *ud) { + lua_lock(L); + G(L)->ud_warn = ud; + G(L)->warnf = f; + lua_unlock(L); +} + + +void lua_warning (lua_State *L, const char *msg, int tocont) { + lua_lock(L); + luaE_warning(L, msg, tocont); + lua_unlock(L); +} + + + +LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) { + Udata *u; + lua_lock(L); + api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value"); + u = luaS_newudata(L, size, nuvalue); + setuvalue(L, s2v(L->top.p), u); + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); + return getudatamem(u); +} + + + +static const char *aux_upvalue (TValue *fi, int n, TValue **val, + GCObject **owner) { + switch (ttypetag(fi)) { + case LUA_VCCL: { /* C closure */ + CClosure *f = clCvalue(fi); + if (!(cast_uint(n) - 1u < cast_uint(f->nupvalues))) + return NULL; /* 'n' not in [1, f->nupvalues] */ + *val = &f->upvalue[n-1]; + if (owner) *owner = obj2gco(f); + return ""; + } + case LUA_VLCL: { /* Lua closure */ + LClosure *f = clLvalue(fi); + TString *name; + Proto *p = f->p; + if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues))) + return NULL; /* 'n' not in [1, p->sizeupvalues] */ + *val = f->upvals[n-1]->v.p; + if (owner) *owner = obj2gco(f->upvals[n - 1]); + name = p->upvalues[n-1].name; + return (name == NULL) ? "(no name)" : getstr(name); + } + default: return NULL; /* not a closure */ + } +} + + +LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { + const char *name; + TValue *val = NULL; /* to avoid warnings */ + lua_lock(L); + name = aux_upvalue(index2value(L, funcindex), n, &val, NULL); + if (name) { + setobj2s(L, L->top.p, val); + api_incr_top(L); + } + lua_unlock(L); + return name; +} + + +LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { + const char *name; + TValue *val = NULL; /* to avoid warnings */ + GCObject *owner = NULL; /* to avoid warnings */ + TValue *fi; + lua_lock(L); + fi = index2value(L, funcindex); + api_checknelems(L, 1); + name = aux_upvalue(fi, n, &val, &owner); + if (name) { + L->top.p--; + setobj(L, val, s2v(L->top.p)); + luaC_barrier(L, owner, val); + } + lua_unlock(L); + return name; +} + + +static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) { + static const UpVal *const nullup = NULL; + LClosure *f; + TValue *fi = index2value(L, fidx); + api_check(L, ttisLclosure(fi), "Lua function expected"); + f = clLvalue(fi); + if (pf) *pf = f; + if (1 <= n && n <= f->p->sizeupvalues) + return &f->upvals[n - 1]; /* get its upvalue pointer */ + else + return (UpVal**)&nullup; +} + + +LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { + TValue *fi = index2value(L, fidx); + switch (ttypetag(fi)) { + case LUA_VLCL: { /* lua closure */ + return *getupvalref(L, fidx, n, NULL); + } + case LUA_VCCL: { /* C closure */ + CClosure *f = clCvalue(fi); + if (1 <= n && n <= f->nupvalues) + return &f->upvalue[n - 1]; + /* else */ + } /* FALLTHROUGH */ + case LUA_VLCF: + return NULL; /* light C functions have no upvalues */ + default: { + api_check(L, 0, "function expected"); + return NULL; + } + } +} + + +LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, + int fidx2, int n2) { + LClosure *f1; + UpVal **up1 = getupvalref(L, fidx1, n1, &f1); + UpVal **up2 = getupvalref(L, fidx2, n2, NULL); + api_check(L, *up1 != NULL && *up2 != NULL, "invalid upvalue index"); + *up1 = *up2; + luaC_objbarrier(L, f1, *up1); +} + + diff --git a/src/libs/3rdparty/lua/src/lapi.h b/src/libs/3rdparty/lua/src/lapi.h new file mode 100644 index 0000000000..a742427cdc --- /dev/null +++ b/src/libs/3rdparty/lua/src/lapi.h @@ -0,0 +1,52 @@ +/* +** $Id: lapi.h $ +** Auxiliary functions from Lua API +** See Copyright Notice in lua.h +*/ + +#ifndef lapi_h +#define lapi_h + + +#include "llimits.h" +#include "lstate.h" + + +/* Increments 'L->top.p', checking for stack overflows */ +#define api_incr_top(L) {L->top.p++; \ + api_check(L, L->top.p <= L->ci->top.p, \ + "stack overflow");} + + +/* +** If a call returns too many multiple returns, the callee may not have +** stack space to accommodate all results. In this case, this macro +** increases its stack space ('L->ci->top.p'). +*/ +#define adjustresults(L,nres) \ + { if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \ + L->ci->top.p = L->top.p; } + + +/* Ensure the stack has at least 'n' elements */ +#define api_checknelems(L,n) \ + api_check(L, (n) < (L->top.p - L->ci->func.p), \ + "not enough elements in the stack") + + +/* +** To reduce the overhead of returning from C functions, the presence of +** to-be-closed variables in these functions is coded in the CallInfo's +** field 'nresults', in a way that functions with no to-be-closed variables +** with zero, one, or "all" wanted results have no overhead. Functions +** with other number of wanted results, as well as functions with +** variables to be closed, have an extra check. +*/ + +#define hastocloseCfunc(n) ((n) < LUA_MULTRET) + +/* Map [-1, inf) (range of 'nresults') into (-inf, -2] */ +#define codeNresults(n) (-(n) - 3) +#define decodeNresults(n) (-(n) - 3) + +#endif diff --git a/src/libs/3rdparty/lua/src/lauxlib.c b/src/libs/3rdparty/lua/src/lauxlib.c new file mode 100644 index 0000000000..4ca6c65488 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lauxlib.c @@ -0,0 +1,1112 @@ +/* +** $Id: lauxlib.c $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + +#define lauxlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +/* +** This file uses only the official API of Lua. +** Any function declared here could be written as an application function. +*/ + +#include "lua.h" + +#include "lauxlib.h" + + +#if !defined(MAX_SIZET) +/* maximum value for size_t */ +#define MAX_SIZET ((size_t)(~(size_t)0)) +#endif + + +/* +** {====================================================== +** Traceback +** ======================================================= +*/ + + +#define LEVELS1 10 /* size of the first part of the stack */ +#define LEVELS2 11 /* size of the second part of the stack */ + + + +/* +** Search for 'objidx' in table at index -1. ('objidx' must be an +** absolute index.) Return 1 + string at top if it found a good name. +*/ +static int findfield (lua_State *L, int objidx, int level) { + if (level == 0 || !lua_istable(L, -1)) + return 0; /* not found */ + lua_pushnil(L); /* start 'next' loop */ + while (lua_next(L, -2)) { /* for each pair in table */ + if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ + if (lua_rawequal(L, objidx, -1)) { /* found object? */ + lua_pop(L, 1); /* remove value (but keep name) */ + return 1; + } + else if (findfield(L, objidx, level - 1)) { /* try recursively */ + /* stack: lib_name, lib_table, field_name (top) */ + lua_pushliteral(L, "."); /* place '.' between the two names */ + lua_replace(L, -3); /* (in the slot occupied by table) */ + lua_concat(L, 3); /* lib_name.field_name */ + return 1; + } + } + lua_pop(L, 1); /* remove value */ + } + return 0; /* not found */ +} + + +/* +** Search for a name for a function in all loaded modules +*/ +static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { + int top = lua_gettop(L); + lua_getinfo(L, "f", ar); /* push function */ + lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + if (findfield(L, top + 1, 2)) { + const char *name = lua_tostring(L, -1); + if (strncmp(name, LUA_GNAME ".", 3) == 0) { /* name start with '_G.'? */ + lua_pushstring(L, name + 3); /* push name without prefix */ + lua_remove(L, -2); /* remove original name */ + } + lua_copy(L, -1, top + 1); /* copy name to proper place */ + lua_settop(L, top + 1); /* remove table "loaded" and name copy */ + return 1; + } + else { + lua_settop(L, top); /* remove function and global table */ + return 0; + } +} + + +static void pushfuncname (lua_State *L, lua_Debug *ar) { + if (pushglobalfuncname(L, ar)) { /* try first a global name */ + lua_pushfstring(L, "function '%s'", lua_tostring(L, -1)); + lua_remove(L, -2); /* remove name */ + } + else if (*ar->namewhat != '\0') /* is there a name from code? */ + lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */ + else if (*ar->what == 'm') /* main? */ + lua_pushliteral(L, "main chunk"); + else if (*ar->what != 'C') /* for Lua functions, use <file:line> */ + lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); + else /* nothing left... */ + lua_pushliteral(L, "?"); +} + + +static int lastlevel (lua_State *L) { + lua_Debug ar; + int li = 1, le = 1; + /* find an upper bound */ + while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } + /* do a binary search */ + while (li < le) { + int m = (li + le)/2; + if (lua_getstack(L, m, &ar)) li = m + 1; + else le = m; + } + return le - 1; +} + + +LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, + const char *msg, int level) { + luaL_Buffer b; + lua_Debug ar; + int last = lastlevel(L1); + int limit2show = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1; + luaL_buffinit(L, &b); + if (msg) { + luaL_addstring(&b, msg); + luaL_addchar(&b, '\n'); + } + luaL_addstring(&b, "stack traceback:"); + while (lua_getstack(L1, level++, &ar)) { + if (limit2show-- == 0) { /* too many levels? */ + int n = last - level - LEVELS2 + 1; /* number of levels to skip */ + lua_pushfstring(L, "\n\t...\t(skipping %d levels)", n); + luaL_addvalue(&b); /* add warning about skip */ + level += n; /* and skip to last levels */ + } + else { + lua_getinfo(L1, "Slnt", &ar); + if (ar.currentline <= 0) + lua_pushfstring(L, "\n\t%s: in ", ar.short_src); + else + lua_pushfstring(L, "\n\t%s:%d: in ", ar.short_src, ar.currentline); + luaL_addvalue(&b); + pushfuncname(L, &ar); + luaL_addvalue(&b); + if (ar.istailcall) + luaL_addstring(&b, "\n\t(...tail calls...)"); + } + } + luaL_pushresult(&b); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Error-report functions +** ======================================================= +*/ + +LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) { + lua_Debug ar; + if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ + return luaL_error(L, "bad argument #%d (%s)", arg, extramsg); + lua_getinfo(L, "n", &ar); + if (strcmp(ar.namewhat, "method") == 0) { + arg--; /* do not count 'self' */ + if (arg == 0) /* error is in the self argument itself? */ + return luaL_error(L, "calling '%s' on bad self (%s)", + ar.name, extramsg); + } + if (ar.name == NULL) + ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; + return luaL_error(L, "bad argument #%d to '%s' (%s)", + arg, ar.name, extramsg); +} + + +LUALIB_API int luaL_typeerror (lua_State *L, int arg, const char *tname) { + const char *msg; + const char *typearg; /* name for the type of the actual argument */ + if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING) + typearg = lua_tostring(L, -1); /* use the given type name */ + else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA) + typearg = "light userdata"; /* special name for messages */ + else + typearg = luaL_typename(L, arg); /* standard name */ + msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg); + return luaL_argerror(L, arg, msg); +} + + +static void tag_error (lua_State *L, int arg, int tag) { + luaL_typeerror(L, arg, lua_typename(L, tag)); +} + + +/* +** The use of 'lua_pushfstring' ensures this function does not +** need reserved stack space when called. +*/ +LUALIB_API void luaL_where (lua_State *L, int level) { + lua_Debug ar; + if (lua_getstack(L, level, &ar)) { /* check function at level */ + lua_getinfo(L, "Sl", &ar); /* get info about it */ + if (ar.currentline > 0) { /* is there info? */ + lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); + return; + } + } + lua_pushfstring(L, ""); /* else, no information available... */ +} + + +/* +** Again, the use of 'lua_pushvfstring' ensures this function does +** not need reserved stack space when called. (At worst, it generates +** an error with "stack overflow" instead of the given message.) +*/ +LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + luaL_where(L, 1); + lua_pushvfstring(L, fmt, argp); + va_end(argp); + lua_concat(L, 2); + return lua_error(L); +} + + +LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { + int en = errno; /* calls to Lua API may change this value */ + if (stat) { + lua_pushboolean(L, 1); + return 1; + } + else { + luaL_pushfail(L); + if (fname) + lua_pushfstring(L, "%s: %s", fname, strerror(en)); + else + lua_pushstring(L, strerror(en)); + lua_pushinteger(L, en); + return 3; + } +} + + +#if !defined(l_inspectstat) /* { */ + +#if defined(LUA_USE_POSIX) + +#include <sys/wait.h> + +/* +** use appropriate macros to interpret 'pclose' return status +*/ +#define l_inspectstat(stat,what) \ + if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ + else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } + +#else + +#define l_inspectstat(stat,what) /* no op */ + +#endif + +#endif /* } */ + + +LUALIB_API int luaL_execresult (lua_State *L, int stat) { + if (stat != 0 && errno != 0) /* error with an 'errno'? */ + return luaL_fileresult(L, 0, NULL); + else { + const char *what = "exit"; /* type of termination */ + l_inspectstat(stat, what); /* interpret result */ + if (*what == 'e' && stat == 0) /* successful termination? */ + lua_pushboolean(L, 1); + else + luaL_pushfail(L); + lua_pushstring(L, what); + lua_pushinteger(L, stat); + return 3; /* return true/fail,what,code */ + } +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** Userdata's metatable manipulation +** ======================================================= +*/ + +LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { + if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */ + return 0; /* leave previous value on top, but return 0 */ + lua_pop(L, 1); + lua_createtable(L, 0, 2); /* create metatable */ + lua_pushstring(L, tname); + lua_setfield(L, -2, "__name"); /* metatable.__name = tname */ + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ + return 1; +} + + +LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) { + luaL_getmetatable(L, tname); + lua_setmetatable(L, -2); +} + + +LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) { + void *p = lua_touserdata(L, ud); + if (p != NULL) { /* value is a userdata? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + luaL_getmetatable(L, tname); /* get correct metatable */ + if (!lua_rawequal(L, -1, -2)) /* not the same? */ + p = NULL; /* value is a userdata with wrong metatable */ + lua_pop(L, 2); /* remove both metatables */ + return p; + } + } + return NULL; /* value is not a userdata with a metatable */ +} + + +LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { + void *p = luaL_testudata(L, ud, tname); + luaL_argexpected(L, p != NULL, ud, tname); + return p; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Argument check functions +** ======================================================= +*/ + +LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def, + const char *const lst[]) { + const char *name = (def) ? luaL_optstring(L, arg, def) : + luaL_checkstring(L, arg); + int i; + for (i=0; lst[i]; i++) + if (strcmp(lst[i], name) == 0) + return i; + return luaL_argerror(L, arg, + lua_pushfstring(L, "invalid option '%s'", name)); +} + + +/* +** 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) { + if (l_unlikely(!lua_checkstack(L, space))) { + if (msg) + luaL_error(L, "stack overflow (%s)", msg); + else + luaL_error(L, "stack overflow"); + } +} + + +LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) { + if (l_unlikely(lua_type(L, arg) != t)) + tag_error(L, arg, t); +} + + +LUALIB_API void luaL_checkany (lua_State *L, int arg) { + if (l_unlikely(lua_type(L, arg) == LUA_TNONE)) + luaL_argerror(L, arg, "value expected"); +} + + +LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) { + const char *s = lua_tolstring(L, arg, len); + if (l_unlikely(!s)) tag_error(L, arg, LUA_TSTRING); + return s; +} + + +LUALIB_API const char *luaL_optlstring (lua_State *L, int arg, + const char *def, size_t *len) { + if (lua_isnoneornil(L, arg)) { + if (len) + *len = (def ? strlen(def) : 0); + return def; + } + else return luaL_checklstring(L, arg, len); +} + + +LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) { + int isnum; + lua_Number d = lua_tonumberx(L, arg, &isnum); + if (l_unlikely(!isnum)) + tag_error(L, arg, LUA_TNUMBER); + return d; +} + + +LUALIB_API lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number def) { + return luaL_opt(L, luaL_checknumber, arg, def); +} + + +static void interror (lua_State *L, int arg) { + if (lua_isnumber(L, arg)) + luaL_argerror(L, arg, "number has no integer representation"); + else + tag_error(L, arg, LUA_TNUMBER); +} + + +LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) { + int isnum; + lua_Integer d = lua_tointegerx(L, arg, &isnum); + if (l_unlikely(!isnum)) { + interror(L, arg); + } + return d; +} + + +LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg, + lua_Integer def) { + return luaL_opt(L, luaL_checkinteger, arg, def); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + +/* 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 (l_unlikely(temp == NULL && newsize > 0)) { /* allocation error? */ + lua_pushliteral(L, "not enough memory"); + lua_error(L); /* raise a memory error */ + } + box->box = temp; + box->bsize = newsize; + return temp; +} + + +static int boxgc (lua_State *L) { + resizebox(L, 1, 0); + return 0; +} + + +static const luaL_Reg boxmt[] = { /* box metamethods */ + {"__gc", boxgc}, + {"__close", boxgc}, + {NULL, NULL} +}; + + +static void newbox (lua_State *L) { + UBox *box = (UBox *)lua_newuserdatauv(L, sizeof(UBox), 0); + box->box = NULL; + box->bsize = 0; + if (luaL_newmetatable(L, "_UBOX*")) /* creating metatable? */ + luaL_setfuncs(L, boxmt, 0); /* set its metamethods */ + lua_setmetatable(L, -2); +} + + +/* +** check whether buffer is using a userdata on the stack as a temporary +** buffer +*/ +#define buffonstack(B) ((B)->b != (B)->init.b) + + +/* +** Whenever buffer is accessed, slot 'idx' must either be a box (which +** cannot be NULL) or it is a placeholder for the buffer. +*/ +#define checkbufferlevel(B,idx) \ + lua_assert(buffonstack(B) ? lua_touserdata(B->L, idx) != NULL \ + : lua_touserdata(B->L, idx) == (void*)B) + + +/* +** Compute new size for buffer 'B', enough to accommodate extra 'sz' +** bytes. (The test for "not big enough" also gets the case when the +** computation of 'newsize' overflows.) +*/ +static size_t newbuffsize (luaL_Buffer *B, size_t sz) { + size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */ + if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */ + return luaL_error(B->L, "buffer too large"); + if (newsize < B->n + sz) /* not big enough? */ + newsize = B->n + sz; + return newsize; +} + + +/* +** Returns a pointer to a free area with at least 'sz' bytes in buffer +** 'B'. 'boxidx' is the relative position in the stack where is the +** buffer's box or its placeholder. +*/ +static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) { + checkbufferlevel(B, boxidx); + if (B->size - B->n >= sz) /* enough space? */ + return B->b + B->n; + else { + lua_State *L = B->L; + char *newbuff; + size_t newsize = newbuffsize(B, sz); + /* create larger buffer */ + if (buffonstack(B)) /* buffer already has a box? */ + newbuff = (char *)resizebox(L, boxidx, newsize); /* resize it */ + else { /* no box yet */ + lua_remove(L, boxidx); /* remove placeholder */ + newbox(L); /* create a new box */ + lua_insert(L, boxidx); /* move box to its intended position */ + lua_toclose(L, boxidx); + newbuff = (char *)resizebox(L, boxidx, newsize); + memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ + } + B->b = newbuff; + B->size = newsize; + return newbuff + B->n; + } +} + +/* +** returns a pointer to a free area with at least 'sz' bytes +*/ +LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { + return prepbuffsize(B, sz, -1); +} + + +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 = prepbuffsize(B, l, -1); + memcpy(b, s, l * sizeof(char)); + luaL_addsize(B, l); + } +} + + +LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { + luaL_addlstring(B, s, strlen(s)); +} + + +LUALIB_API void luaL_pushresult (luaL_Buffer *B) { + lua_State *L = B->L; + checkbufferlevel(B, -1); + lua_pushlstring(L, B->b, B->n); + if (buffonstack(B)) + lua_closeslot(L, -2); /* close the box */ + lua_remove(L, -2); /* remove box or placeholder from the stack */ +} + + +LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) { + luaL_addsize(B, sz); + luaL_pushresult(B); +} + + +/* +** 'luaL_addvalue' is the only function in the Buffer system where the +** box (if existent) is not on the top of the stack. So, instead of +** calling 'luaL_addlstring', it replicates the code using -2 as the +** last argument to 'prepbuffsize', signaling that the box is (or will +** be) below the string being added to the buffer. (Box creation can +** trigger an emergency GC, so we should not remove the string from the +** stack before we have the space guaranteed.) +*/ +LUALIB_API void luaL_addvalue (luaL_Buffer *B) { + lua_State *L = B->L; + size_t len; + const char *s = lua_tolstring(L, -1, &len); + char *b = prepbuffsize(B, len, -2); + memcpy(b, s, len * sizeof(char)); + luaL_addsize(B, len); + lua_pop(L, 1); /* pop string */ +} + + +LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { + B->L = L; + B->b = B->init.b; + B->n = 0; + B->size = LUAL_BUFFERSIZE; + lua_pushlightuserdata(L, (void*)B); /* push placeholder */ +} + + +LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { + luaL_buffinit(L, B); + return prepbuffsize(B, sz, -1); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Reference system +** ======================================================= +*/ + +/* index of free-list header (after the predefined values) */ +#define freelist (LUA_RIDX_LAST + 1) + +/* +** The previously freed references form a linked list: +** t[freelist] is the index of a first free index, or zero if list is +** empty; t[t[freelist]] is the index of the second element; etc. +*/ +LUALIB_API int luaL_ref (lua_State *L, int t) { + int ref; + if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* remove from stack */ + return LUA_REFNIL; /* 'nil' has a unique fixed reference */ + } + t = lua_absindex(L, t); + if (lua_rawgeti(L, t, freelist) == LUA_TNIL) { /* first access? */ + ref = 0; /* list is empty */ + lua_pushinteger(L, 0); /* initialize as an empty list */ + lua_rawseti(L, t, freelist); /* ref = t[freelist] = 0 */ + } + else { /* already initialized */ + lua_assert(lua_isinteger(L, -1)); + ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */ + } + lua_pop(L, 1); /* remove element from stack */ + if (ref != 0) { /* any free element? */ + lua_rawgeti(L, t, ref); /* remove it from list */ + lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ + } + else /* no free elements */ + ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ + lua_rawseti(L, t, ref); + return ref; +} + + +LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { + if (ref >= 0) { + t = lua_absindex(L, t); + lua_rawgeti(L, t, freelist); + lua_assert(lua_isinteger(L, -1)); + lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ + lua_pushinteger(L, ref); + lua_rawseti(L, t, freelist); /* t[freelist] = ref */ + } +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Load functions +** ======================================================= +*/ + +typedef struct LoadF { + int n; /* number of pre-read characters */ + FILE *f; /* file being read */ + char buff[BUFSIZ]; /* area for reading file */ +} LoadF; + + +static const char *getF (lua_State *L, void *ud, size_t *size) { + LoadF *lf = (LoadF *)ud; + (void)L; /* not used */ + if (lf->n > 0) { /* are there pre-read characters to be read? */ + *size = lf->n; /* return them (chars already in buffer) */ + lf->n = 0; /* no more pre-read characters */ + } + else { /* read a block from file */ + /* 'fread' can return > 0 *and* set the EOF flag. If next call to + 'getF' called 'fread', it might still wait for user input. + The next check avoids this problem. */ + if (feof(lf->f)) return NULL; + *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ + } + return lf->buff; +} + + +static int errfile (lua_State *L, const char *what, int fnameindex) { + const char *serr = strerror(errno); + const char *filename = lua_tostring(L, fnameindex) + 1; + lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); + lua_remove(L, fnameindex); + return LUA_ERRFILE; +} + + +/* +** Skip an optional BOM at the start of a stream. If there is an +** incomplete BOM (the first character is correct but the rest is +** not), returns the first character anyway to force an error +** (as no chunk can start with 0xEF). +*/ +static int skipBOM (FILE *f) { + int c = getc(f); /* read first character */ + if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF) /* correct BOM? */ + return getc(f); /* ignore BOM and return next char */ + else /* no (valid) BOM */ + return c; /* return first character */ +} + + +/* +** reads the first character of file 'f' and skips an optional BOM mark +** in its beginning plus its first line if it starts with '#'. Returns +** true if it skipped the first line. In any case, '*cp' has the +** first "valid" character of the file (after the optional BOM and +** a first-line comment). +*/ +static int skipcomment (FILE *f, int *cp) { + int c = *cp = skipBOM(f); + if (c == '#') { /* first line is a comment (Unix exec. file)? */ + do { /* skip first line */ + c = getc(f); + } while (c != EOF && c != '\n'); + *cp = getc(f); /* next character after comment, if present */ + return 1; /* there was a comment */ + } + else return 0; /* no comment */ +} + + +LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, + const char *mode) { + LoadF lf; + int status, readstatus; + int c; + int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ + if (filename == NULL) { + lua_pushliteral(L, "=stdin"); + lf.f = stdin; + } + else { + lua_pushfstring(L, "@%s", filename); + lf.f = fopen(filename, "r"); + if (lf.f == NULL) return errfile(L, "open", fnameindex); + } + lf.n = 0; + if (skipcomment(lf.f, &c)) /* read initial portion */ + lf.buff[lf.n++] = '\n'; /* add newline to correct line numbers */ + if (c == LUA_SIGNATURE[0]) { /* binary file? */ + lf.n = 0; /* remove possible newline */ + if (filename) { /* "real" file? */ + lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ + if (lf.f == NULL) return errfile(L, "reopen", fnameindex); + skipcomment(lf.f, &c); /* re-read initial portion */ + } + } + if (c != EOF) + lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ + status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); + readstatus = ferror(lf.f); + if (filename) fclose(lf.f); /* close file (even in case of errors) */ + if (readstatus) { + lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ + return errfile(L, "read", fnameindex); + } + lua_remove(L, fnameindex); + return status; +} + + +typedef struct LoadS { + const char *s; + size_t size; +} LoadS; + + +static const char *getS (lua_State *L, void *ud, size_t *size) { + LoadS *ls = (LoadS *)ud; + (void)L; /* not used */ + if (ls->size == 0) return NULL; + *size = ls->size; + ls->size = 0; + return ls->s; +} + + +LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size, + const char *name, const char *mode) { + LoadS ls; + ls.s = buff; + ls.size = size; + return lua_load(L, getS, &ls, name, mode); +} + + +LUALIB_API int luaL_loadstring (lua_State *L, const char *s) { + return luaL_loadbuffer(L, s, strlen(s), s); +} + +/* }====================================================== */ + + + +LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { + if (!lua_getmetatable(L, obj)) /* no metatable? */ + return LUA_TNIL; + else { + int tt; + lua_pushstring(L, event); + tt = lua_rawget(L, -2); + if (tt == LUA_TNIL) /* is metafield nil? */ + lua_pop(L, 2); /* remove metatable and metafield */ + else + lua_remove(L, -2); /* remove only metatable */ + return tt; /* return metafield type */ + } +} + + +LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { + obj = lua_absindex(L, obj); + if (luaL_getmetafield(L, obj, event) == LUA_TNIL) /* no metafield? */ + return 0; + lua_pushvalue(L, obj); + lua_call(L, 1, 1); + return 1; +} + + +LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) { + lua_Integer l; + int isnum; + lua_len(L, idx); + l = lua_tointegerx(L, -1, &isnum); + if (l_unlikely(!isnum)) + luaL_error(L, "object length is not an integer"); + lua_pop(L, 1); /* remove object */ + return l; +} + + +LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { + idx = lua_absindex(L,idx); + if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */ + if (!lua_isstring(L, -1)) + luaL_error(L, "'__tostring' must return a string"); + } + else { + switch (lua_type(L, idx)) { + case LUA_TNUMBER: { + if (lua_isinteger(L, idx)) + lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx)); + else + lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx)); + break; + } + case LUA_TSTRING: + lua_pushvalue(L, idx); + break; + case LUA_TBOOLEAN: + lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false")); + break; + case LUA_TNIL: + lua_pushliteral(L, "nil"); + break; + default: { + int tt = luaL_getmetafield(L, idx, "__name"); /* try name */ + const char *kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : + luaL_typename(L, idx); + lua_pushfstring(L, "%s: %p", kind, lua_topointer(L, idx)); + if (tt != LUA_TNIL) + lua_remove(L, -2); /* remove '__name' */ + break; + } + } + } + return lua_tolstring(L, -1, len); +} + + +/* +** set functions from list 'l' into table at top - 'nup'; each +** function gets the 'nup' elements at the top as upvalues. +** Returns with only the table at the stack. +*/ +LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { + luaL_checkstack(L, nup, "too many upvalues"); + for (; l->name != NULL; l++) { /* fill the table with given functions */ + if (l->func == NULL) /* place holder? */ + lua_pushboolean(L, 0); + else { + int i; + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(L, -nup); + lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ + } + lua_setfield(L, -(nup + 2), l->name); + } + lua_pop(L, nup); /* remove upvalues */ +} + + +/* +** ensure that stack[idx][fname] has a table and push that table +** into the stack +*/ +LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) { + if (lua_getfield(L, idx, fname) == LUA_TTABLE) + return 1; /* table already there */ + else { + lua_pop(L, 1); /* remove previous result */ + idx = lua_absindex(L, idx); + lua_newtable(L); + lua_pushvalue(L, -1); /* copy to be left at top */ + lua_setfield(L, idx, fname); /* assign new table to field */ + return 0; /* false, because did not find table there */ + } +} + + +/* +** Stripped-down 'require': After checking "loaded" table, calls 'openf' +** to open a module, registers the result in 'package.loaded' table and, +** if 'glb' is true, also registers the result in the global table. +** Leaves resulting module on the top. +*/ +LUALIB_API void luaL_requiref (lua_State *L, const char *modname, + lua_CFunction openf, int glb) { + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_getfield(L, -1, modname); /* LOADED[modname] */ + if (!lua_toboolean(L, -1)) { /* package not already loaded? */ + lua_pop(L, 1); /* remove field */ + lua_pushcfunction(L, openf); + lua_pushstring(L, modname); /* argument to open function */ + lua_call(L, 1, 1); /* call 'openf' to open module */ + lua_pushvalue(L, -1); /* make copy of module (call result) */ + lua_setfield(L, -3, modname); /* LOADED[modname] = module */ + } + lua_remove(L, -2); /* remove LOADED table */ + if (glb) { + lua_pushvalue(L, -1); /* copy of module */ + lua_setglobal(L, modname); /* _G[modname] = module */ + } +} + + +LUALIB_API void luaL_addgsub (luaL_Buffer *b, const char *s, + const char *p, const char *r) { + const char *wild; + size_t l = strlen(p); + while ((wild = strstr(s, p)) != NULL) { + luaL_addlstring(b, s, wild - s); /* push prefix */ + luaL_addstring(b, r); /* push replacement in place of pattern */ + s = wild + l; /* continue after 'p' */ + } + luaL_addstring(b, s); /* push last suffix */ +} + + +LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, + const char *p, const char *r) { + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addgsub(&b, s, p, r); + luaL_pushresult(&b); + return lua_tostring(L, -1); +} + + +static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { + (void)ud; (void)osize; /* not used */ + if (nsize == 0) { + free(ptr); + return NULL; + } + else + return realloc(ptr, nsize); +} + + +static int panic (lua_State *L) { + const char *msg = lua_tostring(L, -1); + if (msg == NULL) msg = "error object is not a string"; + lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", + msg); + return 0; /* return to Lua to abort */ +} + + +/* +** Warning functions: +** warnfoff: warning system is off +** warnfon: ready to start a new message +** warnfcont: previous message is to be continued +*/ +static void warnfoff (void *ud, const char *message, int tocont); +static void warnfon (void *ud, const char *message, int tocont); +static void warnfcont (void *ud, const char *message, int tocont); + + +/* +** Check whether message is a control message. If so, execute the +** control or ignore it if unknown. +*/ +static int checkcontrol (lua_State *L, const char *message, int tocont) { + if (tocont || *(message++) != '@') /* not a control message? */ + return 0; + else { + if (strcmp(message, "off") == 0) + lua_setwarnf(L, warnfoff, L); /* turn warnings off */ + else if (strcmp(message, "on") == 0) + lua_setwarnf(L, warnfon, L); /* turn warnings on */ + return 1; /* it was a control message */ + } +} + + +static void warnfoff (void *ud, const char *message, int tocont) { + checkcontrol((lua_State *)ud, message, tocont); +} + + +/* +** Writes the message and handle 'tocont', finishing the message +** if needed and setting the next warn function. +*/ +static void warnfcont (void *ud, const char *message, int tocont) { + lua_State *L = (lua_State *)ud; + lua_writestringerror("%s", message); /* write message */ + if (tocont) /* not the last part? */ + lua_setwarnf(L, warnfcont, L); /* to be continued */ + else { /* last part */ + lua_writestringerror("%s", "\n"); /* finish message with end-of-line */ + lua_setwarnf(L, warnfon, L); /* next call is a new message */ + } +} + + +static void warnfon (void *ud, const char *message, int tocont) { + if (checkcontrol((lua_State *)ud, message, tocont)) /* control message? */ + return; /* nothing else to be done */ + lua_writestringerror("%s", "Lua warning: "); /* start a new warning */ + warnfcont(ud, message, tocont); /* finish processing */ +} + + +LUALIB_API lua_State *luaL_newstate (void) { + lua_State *L = lua_newstate(l_alloc, NULL); + if (l_likely(L)) { + lua_atpanic(L, &panic); + lua_setwarnf(L, warnfoff, L); /* default is warnings off */ + } + return L; +} + + +LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) { + lua_Number v = lua_version(L); + if (sz != LUAL_NUMSIZES) /* check numeric types */ + luaL_error(L, "core and library have incompatible numeric types"); + else if (v != ver) + luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f", + (LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)v); +} + diff --git a/src/libs/3rdparty/lua/src/lauxlib.h b/src/libs/3rdparty/lua/src/lauxlib.h new file mode 100644 index 0000000000..5b977e2a39 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lauxlib.h @@ -0,0 +1,301 @@ +/* +** $Id: lauxlib.h $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lauxlib_h +#define lauxlib_h + + +#include <stddef.h> +#include <stdio.h> + +#include "luaconf.h" +#include "lua.h" + + +/* global table */ +#define LUA_GNAME "_G" + + +typedef struct luaL_Buffer luaL_Buffer; + + +/* extra error code for 'luaL_loadfilex' */ +#define LUA_ERRFILE (LUA_ERRERR+1) + + +/* key, in the registry, for table of loaded modules */ +#define LUA_LOADED_TABLE "_LOADED" + + +/* key, in the registry, for table of preloaded loaders */ +#define LUA_PRELOAD_TABLE "_PRELOAD" + + +typedef struct luaL_Reg { + const char *name; + lua_CFunction func; +} luaL_Reg; + + +#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number)) + +LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); +#define luaL_checkversion(L) \ + luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES) + +LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); +LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); +LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); +LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg); +LUALIB_API int (luaL_typeerror) (lua_State *L, int arg, const char *tname); +LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg, + size_t *l); +LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg, + const char *def, size_t *l); +LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg); +LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def); + +LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg); +LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg, + lua_Integer def); + +LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); +LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t); +LUALIB_API void (luaL_checkany) (lua_State *L, int arg); + +LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); +LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname); +LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname); +LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); + +LUALIB_API void (luaL_where) (lua_State *L, int lvl); +LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); + +LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def, + const char *const lst[]); + +LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); +LUALIB_API int (luaL_execresult) (lua_State *L, int stat); + + +/* predefined references */ +#define LUA_NOREF (-2) +#define LUA_REFNIL (-1) + +LUALIB_API int (luaL_ref) (lua_State *L, int t); +LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); + +LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename, + const char *mode); + +#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL) + +LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, + const char *name, const char *mode); +LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); + +LUALIB_API lua_State *(luaL_newstate) (void); + +LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); + +LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s, + const char *p, const char *r); +LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, + const char *p, const char *r); + +LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); + +LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname); + +LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, + const char *msg, int level); + +LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, + lua_CFunction openf, int glb); + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + + +#define luaL_newlibtable(L,l) \ + lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) + +#define luaL_newlib(L,l) \ + (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) + +#define luaL_argcheck(L, cond,arg,extramsg) \ + ((void)(luai_likely(cond) || luaL_argerror(L, (arg), (extramsg)))) + +#define luaL_argexpected(L,cond,arg,tname) \ + ((void)(luai_likely(cond) || luaL_typeerror(L, (arg), (tname)))) + +#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) +#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) + +#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) + +#define luaL_dofile(L, fn) \ + (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) + +#define luaL_dostring(L, s) \ + (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) + +#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) + +#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) + +#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) + + +/* +** Perform arithmetic operations on lua_Integer values with wrap-around +** semantics, as the Lua core does. +*/ +#define luaL_intop(op,v1,v2) \ + ((lua_Integer)((lua_Unsigned)(v1) op (lua_Unsigned)(v2))) + + +/* push the value used to represent failure/error */ +#define luaL_pushfail(L) lua_pushnil(L) + + +/* +** Internal assertions for in-house debugging +*/ +#if !defined(lua_assert) + +#if defined LUAI_ASSERT + #include <assert.h> + #define lua_assert(c) assert(c) +#else + #define lua_assert(c) ((void)0) +#endif + +#endif + + + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + +struct luaL_Buffer { + char *b; /* buffer address */ + size_t size; /* buffer size */ + size_t n; /* number of characters in buffer */ + lua_State *L; + union { + LUAI_MAXALIGN; /* ensure maximum alignment for buffer */ + char b[LUAL_BUFFERSIZE]; /* initial buffer */ + } init; +}; + + +#define luaL_bufflen(bf) ((bf)->n) +#define luaL_buffaddr(bf) ((bf)->b) + + +#define luaL_addchar(B,c) \ + ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ + ((B)->b[(B)->n++] = (c))) + +#define luaL_addsize(B,s) ((B)->n += (s)) + +#define luaL_buffsub(B,s) ((B)->n -= (s)) + +LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); +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_addstring) (luaL_Buffer *B, const char *s); +LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); +LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); +LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz); +LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); + +#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE) + +/* }====================================================== */ + + + +/* +** {====================================================== +** File handles for IO library +** ======================================================= +*/ + +/* +** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and +** initial structure 'luaL_Stream' (it may contain other fields +** after that initial structure). +*/ + +#define LUA_FILEHANDLE "FILE*" + + +typedef struct luaL_Stream { + FILE *f; /* stream (NULL for incompletely created streams) */ + lua_CFunction closef; /* to close stream (NULL for closed streams) */ +} luaL_Stream; + +/* }====================================================== */ + +/* +** {================================================================== +** "Abstraction Layer" for basic report of messages and errors +** =================================================================== +*/ + +/* print a string */ +#if !defined(lua_writestring) +#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) +#endif + +/* print a newline and flush the output */ +#if !defined(lua_writeline) +#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout)) +#endif + +/* print an error message */ +#if !defined(lua_writestringerror) +#define lua_writestringerror(s,p) \ + (fprintf(stderr, (s), (p)), fflush(stderr)) +#endif + +/* }================================================================== */ + + +/* +** {============================================================ +** Compatibility with deprecated conversions +** ============================================================= +*/ +#if defined(LUA_COMPAT_APIINTCASTS) + +#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a)) +#define luaL_optunsigned(L,a,d) \ + ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d))) + +#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) +#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) + +#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) +#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) + +#endif +/* }============================================================ */ + + + +#endif + + diff --git a/src/libs/3rdparty/lua/src/lbaselib.c b/src/libs/3rdparty/lua/src/lbaselib.c new file mode 100644 index 0000000000..1d60c9dede --- /dev/null +++ b/src/libs/3rdparty/lua/src/lbaselib.c @@ -0,0 +1,549 @@ +/* +** $Id: lbaselib.c $ +** Basic library +** See Copyright Notice in lua.h +*/ + +#define lbaselib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +static int luaB_print (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int i; + for (i = 1; i <= n; i++) { /* for each argument */ + size_t l; + const char *s = luaL_tolstring(L, i, &l); /* convert it to string */ + if (i > 1) /* not the first element? */ + lua_writestring("\t", 1); /* add a tab before it */ + lua_writestring(s, l); /* print it */ + lua_pop(L, 1); /* pop result */ + } + lua_writeline(); + return 0; +} + + +/* +** Creates a warning with all given arguments. +** Check first for errors; otherwise an error may interrupt +** the composition of a warning, leaving it unfinished. +*/ +static int luaB_warn (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int i; + luaL_checkstring(L, 1); /* at least one argument */ + for (i = 2; i <= n; i++) + luaL_checkstring(L, i); /* make sure all arguments are strings */ + for (i = 1; i < n; i++) /* compose warning */ + lua_warning(L, lua_tostring(L, i), 1); + lua_warning(L, lua_tostring(L, n), 0); /* close warning */ + return 0; +} + + +#define SPACECHARS " \f\n\r\t\v" + +static const char *b_str2int (const char *s, int base, lua_Integer *pn) { + lua_Unsigned n = 0; + int neg = 0; + s += strspn(s, SPACECHARS); /* skip initial spaces */ + if (*s == '-') { s++; neg = 1; } /* handle sign */ + else if (*s == '+') s++; + if (!isalnum((unsigned char)*s)) /* no digit? */ + return NULL; + do { + int digit = (isdigit((unsigned char)*s)) ? *s - '0' + : (toupper((unsigned char)*s) - 'A') + 10; + if (digit >= base) return NULL; /* invalid numeral */ + n = n * base + digit; + s++; + } while (isalnum((unsigned char)*s)); + s += strspn(s, SPACECHARS); /* skip trailing spaces */ + *pn = (lua_Integer)((neg) ? (0u - n) : n); + return s; +} + + +static int luaB_tonumber (lua_State *L) { + if (lua_isnoneornil(L, 2)) { /* standard conversion? */ + if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */ + lua_settop(L, 1); /* yes; return it */ + return 1; + } + else { + size_t l; + const char *s = lua_tolstring(L, 1, &l); + if (s != NULL && lua_stringtonumber(L, s) == l + 1) + return 1; /* successful conversion to number */ + /* else not a number */ + luaL_checkany(L, 1); /* (but there must be some parameter) */ + } + } + else { + size_t l; + const char *s; + lua_Integer n = 0; /* to avoid warnings */ + lua_Integer base = luaL_checkinteger(L, 2); + luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */ + s = lua_tolstring(L, 1, &l); + luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); + if (b_str2int(s, (int)base, &n) == s + l) { + lua_pushinteger(L, n); + return 1; + } /* else not a number */ + } /* else not a number */ + luaL_pushfail(L); /* not a number */ + return 1; +} + + +static int luaB_error (lua_State *L) { + int level = (int)luaL_optinteger(L, 2, 1); + lua_settop(L, 1); + if (lua_type(L, 1) == LUA_TSTRING && level > 0) { + luaL_where(L, level); /* add extra information */ + lua_pushvalue(L, 1); + lua_concat(L, 2); + } + return lua_error(L); +} + + +static int luaB_getmetatable (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); + return 1; /* no metatable */ + } + luaL_getmetafield(L, 1, "__metatable"); + return 1; /* returns either __metatable field (if present) or metatable */ +} + + +static int luaB_setmetatable (lua_State *L) { + int t = lua_type(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table"); + if (l_unlikely(luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL)) + return luaL_error(L, "cannot change a protected metatable"); + lua_settop(L, 2); + lua_setmetatable(L, 1); + return 1; +} + + +static int luaB_rawequal (lua_State *L) { + luaL_checkany(L, 1); + luaL_checkany(L, 2); + lua_pushboolean(L, lua_rawequal(L, 1, 2)); + return 1; +} + + +static int luaB_rawlen (lua_State *L) { + int t = lua_type(L, 1); + luaL_argexpected(L, t == LUA_TTABLE || t == LUA_TSTRING, 1, + "table or string"); + lua_pushinteger(L, lua_rawlen(L, 1)); + return 1; +} + + +static int luaB_rawget (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_rawget(L, 1); + return 1; +} + +static int luaB_rawset (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + luaL_checkany(L, 3); + lua_settop(L, 3); + lua_rawset(L, 1); + return 1; +} + + +static int pushmode (lua_State *L, int oldmode) { + if (oldmode == -1) + luaL_pushfail(L); /* invalid call to 'lua_gc' */ + else + lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental" + : "generational"); + return 1; +} + + +/* +** check whether call to 'lua_gc' was valid (not inside a finalizer) +*/ +#define checkvalres(res) { if (res == -1) break; } + +static int luaB_collectgarbage (lua_State *L) { + static const char *const opts[] = {"stop", "restart", "collect", + "count", "step", "setpause", "setstepmul", + "isrunning", "generational", "incremental", NULL}; + static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, + LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, + LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC}; + int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; + switch (o) { + case LUA_GCCOUNT: { + int k = lua_gc(L, o); + int b = lua_gc(L, LUA_GCCOUNTB); + checkvalres(k); + lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024)); + return 1; + } + case LUA_GCSTEP: { + int step = (int)luaL_optinteger(L, 2, 0); + int res = lua_gc(L, o, step); + checkvalres(res); + lua_pushboolean(L, res); + return 1; + } + case LUA_GCSETPAUSE: + case LUA_GCSETSTEPMUL: { + int p = (int)luaL_optinteger(L, 2, 0); + int previous = lua_gc(L, o, p); + checkvalres(previous); + lua_pushinteger(L, previous); + return 1; + } + case LUA_GCISRUNNING: { + int res = lua_gc(L, o); + checkvalres(res); + lua_pushboolean(L, res); + return 1; + } + case LUA_GCGEN: { + int minormul = (int)luaL_optinteger(L, 2, 0); + int majormul = (int)luaL_optinteger(L, 3, 0); + return pushmode(L, lua_gc(L, o, minormul, majormul)); + } + case LUA_GCINC: { + int pause = (int)luaL_optinteger(L, 2, 0); + int stepmul = (int)luaL_optinteger(L, 3, 0); + int stepsize = (int)luaL_optinteger(L, 4, 0); + return pushmode(L, lua_gc(L, o, pause, stepmul, stepsize)); + } + default: { + int res = lua_gc(L, o); + checkvalres(res); + lua_pushinteger(L, res); + return 1; + } + } + luaL_pushfail(L); /* invalid call (inside a finalizer) */ + return 1; +} + + +static int luaB_type (lua_State *L) { + int t = lua_type(L, 1); + luaL_argcheck(L, t != LUA_TNONE, 1, "value expected"); + lua_pushstring(L, lua_typename(L, t)); + return 1; +} + + +static int luaB_next (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 2); /* create a 2nd argument if there isn't one */ + if (lua_next(L, 1)) + return 2; + else { + lua_pushnil(L); + return 1; + } +} + + +static int pairscont (lua_State *L, int status, lua_KContext k) { + (void)L; (void)status; (void)k; /* unused */ + return 3; +} + +static int luaB_pairs (lua_State *L) { + luaL_checkany(L, 1); + if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */ + lua_pushcfunction(L, luaB_next); /* will return generator, */ + lua_pushvalue(L, 1); /* state, */ + lua_pushnil(L); /* and initial value */ + } + else { + lua_pushvalue(L, 1); /* argument 'self' to metamethod */ + lua_callk(L, 1, 3, 0, pairscont); /* get 3 values from metamethod */ + } + return 3; +} + + +/* +** Traversal function for 'ipairs' +*/ +static int ipairsaux (lua_State *L) { + lua_Integer i = luaL_checkinteger(L, 2); + i = luaL_intop(+, i, 1); + lua_pushinteger(L, i); + return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; +} + + +/* +** 'ipairs' function. Returns 'ipairsaux', given "table", 0. +** (The given "table" may not be a table.) +*/ +static int luaB_ipairs (lua_State *L) { + luaL_checkany(L, 1); + lua_pushcfunction(L, ipairsaux); /* iteration function */ + lua_pushvalue(L, 1); /* state */ + lua_pushinteger(L, 0); /* initial value */ + return 3; +} + + +static int load_aux (lua_State *L, int status, int envidx) { + if (l_likely(status == LUA_OK)) { + if (envidx != 0) { /* 'env' parameter? */ + lua_pushvalue(L, envidx); /* environment for loaded function */ + if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ + lua_pop(L, 1); /* remove 'env' if not used by previous call */ + } + return 1; + } + else { /* error (message is on top of the stack) */ + luaL_pushfail(L); + lua_insert(L, -2); /* put before error message */ + return 2; /* return fail plus error message */ + } +} + + +static int luaB_loadfile (lua_State *L) { + const char *fname = luaL_optstring(L, 1, NULL); + const char *mode = luaL_optstring(L, 2, NULL); + int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ + int status = luaL_loadfilex(L, fname, mode); + return load_aux(L, status, env); +} + + +/* +** {====================================================== +** Generic Read function +** ======================================================= +*/ + + +/* +** reserved slot, above all arguments, to hold a copy of the returned +** string to avoid it being collected while parsed. 'load' has four +** optional arguments (chunk, source name, mode, and environment). +*/ +#define RESERVEDSLOT 5 + + +/* +** Reader for generic 'load' function: 'lua_load' uses the +** stack for internal stuff, so the reader cannot change the +** stack top. Instead, it keeps its resulting string in a +** reserved slot inside the stack. +*/ +static const char *generic_reader (lua_State *L, void *ud, size_t *size) { + (void)(ud); /* not used */ + luaL_checkstack(L, 2, "too many nested functions"); + lua_pushvalue(L, 1); /* get function */ + lua_call(L, 0, 1); /* call it */ + if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* pop result */ + *size = 0; + return NULL; + } + else if (l_unlikely(!lua_isstring(L, -1))) + luaL_error(L, "reader function must return a string"); + lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ + return lua_tolstring(L, RESERVEDSLOT, size); +} + + +static int luaB_load (lua_State *L) { + int status; + size_t l; + const char *s = lua_tolstring(L, 1, &l); + const char *mode = luaL_optstring(L, 3, "bt"); + int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ + if (s != NULL) { /* loading a string? */ + const char *chunkname = luaL_optstring(L, 2, s); + status = luaL_loadbufferx(L, s, l, chunkname, mode); + } + else { /* loading from a reader function */ + const char *chunkname = luaL_optstring(L, 2, "=(load)"); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, RESERVEDSLOT); /* create reserved slot */ + status = lua_load(L, generic_reader, NULL, chunkname, mode); + } + return load_aux(L, status, env); +} + +/* }====================================================== */ + + +static int dofilecont (lua_State *L, int d1, lua_KContext d2) { + (void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */ + return lua_gettop(L) - 1; +} + + +static int luaB_dofile (lua_State *L) { + const char *fname = luaL_optstring(L, 1, NULL); + lua_settop(L, 1); + if (l_unlikely(luaL_loadfile(L, fname) != LUA_OK)) + return lua_error(L); + lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); + return dofilecont(L, 0, 0); +} + + +static int luaB_assert (lua_State *L) { + if (l_likely(lua_toboolean(L, 1))) /* condition is true? */ + return lua_gettop(L); /* return all arguments */ + else { /* error */ + luaL_checkany(L, 1); /* there must be a condition */ + lua_remove(L, 1); /* remove it */ + lua_pushliteral(L, "assertion failed!"); /* default message */ + lua_settop(L, 1); /* leave only message (default if no other one) */ + return luaB_error(L); /* call 'error' */ + } +} + + +static int luaB_select (lua_State *L) { + int n = lua_gettop(L); + if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { + lua_pushinteger(L, n-1); + return 1; + } + else { + lua_Integer i = luaL_checkinteger(L, 1); + if (i < 0) i = n + i; + else if (i > n) i = n; + luaL_argcheck(L, 1 <= i, 1, "index out of range"); + return n - (int)i; + } +} + + +/* +** Continuation function for 'pcall' and 'xpcall'. Both functions +** already pushed a 'true' before doing the call, so in case of success +** 'finishpcall' only has to return everything in the stack minus +** 'extra' values (where 'extra' is exactly the number of items to be +** ignored). +*/ +static int finishpcall (lua_State *L, int status, lua_KContext extra) { + if (l_unlikely(status != LUA_OK && status != LUA_YIELD)) { /* error? */ + lua_pushboolean(L, 0); /* first result (false) */ + lua_pushvalue(L, -2); /* error message */ + return 2; /* return false, msg */ + } + else + return lua_gettop(L) - (int)extra; /* return all results */ +} + + +static int luaB_pcall (lua_State *L) { + int status; + luaL_checkany(L, 1); + lua_pushboolean(L, 1); /* first result if no errors */ + lua_insert(L, 1); /* put it in place */ + status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall); + return finishpcall(L, status, 0); +} + + +/* +** Do a protected call with error handling. After 'lua_rotate', the +** stack will have <f, err, true, f, [args...]>; so, the function passes +** 2 to 'finishpcall' to skip the 2 first values when returning results. +*/ +static int luaB_xpcall (lua_State *L) { + int status; + int n = lua_gettop(L); + luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */ + lua_pushboolean(L, 1); /* first result */ + lua_pushvalue(L, 1); /* function */ + lua_rotate(L, 3, 2); /* move them below function's arguments */ + status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall); + return finishpcall(L, status, 2); +} + + +static int luaB_tostring (lua_State *L) { + luaL_checkany(L, 1); + luaL_tolstring(L, 1, NULL); + return 1; +} + + +static const luaL_Reg base_funcs[] = { + {"assert", luaB_assert}, + {"collectgarbage", luaB_collectgarbage}, + {"dofile", luaB_dofile}, + {"error", luaB_error}, + {"getmetatable", luaB_getmetatable}, + {"ipairs", luaB_ipairs}, + {"loadfile", luaB_loadfile}, + {"load", luaB_load}, + {"next", luaB_next}, + {"pairs", luaB_pairs}, + {"pcall", luaB_pcall}, + {"print", luaB_print}, + {"warn", luaB_warn}, + {"rawequal", luaB_rawequal}, + {"rawlen", luaB_rawlen}, + {"rawget", luaB_rawget}, + {"rawset", luaB_rawset}, + {"select", luaB_select}, + {"setmetatable", luaB_setmetatable}, + {"tonumber", luaB_tonumber}, + {"tostring", luaB_tostring}, + {"type", luaB_type}, + {"xpcall", luaB_xpcall}, + /* placeholders */ + {LUA_GNAME, NULL}, + {"_VERSION", NULL}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_base (lua_State *L) { + /* open lib into global table */ + lua_pushglobaltable(L); + luaL_setfuncs(L, base_funcs, 0); + /* set global _G */ + lua_pushvalue(L, -1); + lua_setfield(L, -2, LUA_GNAME); + /* set global _VERSION */ + lua_pushliteral(L, LUA_VERSION); + lua_setfield(L, -2, "_VERSION"); + return 1; +} + diff --git a/src/libs/3rdparty/lua/src/lcode.c b/src/libs/3rdparty/lua/src/lcode.c new file mode 100644 index 0000000000..1a371ca943 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lcode.c @@ -0,0 +1,1871 @@ +/* +** $Id: lcode.c $ +** Code generator for Lua +** See Copyright Notice in lua.h +*/ + +#define lcode_c +#define LUA_CORE + +#include "lprefix.h" + + +#include <float.h> +#include <limits.h> +#include <math.h> +#include <stdlib.h> + +#include "lua.h" + +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "llex.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstring.h" +#include "ltable.h" +#include "lvm.h" + + +/* Maximum number of registers in a Lua function (must fit in 8 bits) */ +#define MAXREGS 255 + + +#define hasjumps(e) ((e)->t != (e)->f) + + +static int codesJ (FuncState *fs, OpCode o, int sj, int k); + + + +/* semantic error */ +l_noret luaK_semerror (LexState *ls, const char *msg) { + ls->t.token = 0; /* remove "near <token>" from final message */ + luaX_syntaxerror(ls, msg); +} + + +/* +** If expression is a numeric constant, fills 'v' with its value +** and returns 1. Otherwise, returns 0. +*/ +static int tonumeral (const expdesc *e, TValue *v) { + if (hasjumps(e)) + return 0; /* not a numeral */ + switch (e->k) { + case VKINT: + if (v) setivalue(v, e->u.ival); + return 1; + case VKFLT: + if (v) setfltvalue(v, e->u.nval); + return 1; + default: return 0; + } +} + + +/* +** Get the constant value from a constant expression +*/ +static TValue *const2val (FuncState *fs, const expdesc *e) { + lua_assert(e->k == VCONST); + return &fs->ls->dyd->actvar.arr[e->u.info].k; +} + + +/* +** If expression is a constant, fills 'v' with its value +** and returns 1. Otherwise, returns 0. +*/ +int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v) { + if (hasjumps(e)) + return 0; /* not a constant */ + switch (e->k) { + case VFALSE: + setbfvalue(v); + return 1; + case VTRUE: + setbtvalue(v); + return 1; + case VNIL: + setnilvalue(v); + return 1; + case VKSTR: { + setsvalue(fs->ls->L, v, e->u.strval); + return 1; + } + case VCONST: { + setobj(fs->ls->L, v, const2val(fs, e)); + return 1; + } + default: return tonumeral(e, v); + } +} + + +/* +** Return the previous instruction of the current code. If there +** may be a jump target between the current instruction and the +** previous one, return an invalid instruction (to avoid wrong +** optimizations). +*/ +static Instruction *previousinstruction (FuncState *fs) { + static const Instruction invalidinstruction = ~(Instruction)0; + if (fs->pc > fs->lasttarget) + return &fs->f->code[fs->pc - 1]; /* previous instruction */ + else + return cast(Instruction*, &invalidinstruction); +} + + +/* +** Create a OP_LOADNIL instruction, but try to optimize: if the previous +** instruction is also OP_LOADNIL and ranges are compatible, adjust +** range of previous instruction instead of emitting a new one. (For +** instance, 'local a; local b' will generate a single opcode.) +*/ +void luaK_nil (FuncState *fs, int from, int n) { + int l = from + n - 1; /* last register to set nil */ + Instruction *previous = previousinstruction(fs); + if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */ + int pfrom = GETARG_A(*previous); /* get previous range */ + int pl = pfrom + GETARG_B(*previous); + if ((pfrom <= from && from <= pl + 1) || + (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ + if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ + if (pl > l) l = pl; /* l = max(l, pl) */ + SETARG_A(*previous, from); + SETARG_B(*previous, l - from); + return; + } /* else go through */ + } + luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */ +} + + +/* +** Gets the destination address of a jump instruction. Used to traverse +** a list of jumps. +*/ +static int getjump (FuncState *fs, int pc) { + int offset = GETARG_sJ(fs->f->code[pc]); + if (offset == NO_JUMP) /* point to itself represents end of list */ + return NO_JUMP; /* end of list */ + else + return (pc+1)+offset; /* turn offset into absolute position */ +} + + +/* +** Fix jump instruction at position 'pc' to jump to 'dest'. +** (Jump addresses are relative in Lua) +*/ +static void fixjump (FuncState *fs, int pc, int dest) { + Instruction *jmp = &fs->f->code[pc]; + int offset = dest - (pc + 1); + lua_assert(dest != NO_JUMP); + if (!(-OFFSET_sJ <= offset && offset <= MAXARG_sJ - OFFSET_sJ)) + luaX_syntaxerror(fs->ls, "control structure too long"); + lua_assert(GET_OPCODE(*jmp) == OP_JMP); + SETARG_sJ(*jmp, offset); +} + + +/* +** Concatenate jump-list 'l2' into jump-list 'l1' +*/ +void luaK_concat (FuncState *fs, int *l1, int l2) { + if (l2 == NO_JUMP) return; /* nothing to concatenate? */ + else if (*l1 == NO_JUMP) /* no original list? */ + *l1 = l2; /* 'l1' points to 'l2' */ + else { + int list = *l1; + int next; + while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ + list = next; + fixjump(fs, list, l2); /* last element links to 'l2' */ + } +} + + +/* +** Create a jump instruction and return its position, so its destination +** can be fixed later (with 'fixjump'). +*/ +int luaK_jump (FuncState *fs) { + return codesJ(fs, OP_JMP, NO_JUMP, 0); +} + + +/* +** Code a 'return' instruction +*/ +void luaK_ret (FuncState *fs, int first, int nret) { + OpCode op; + switch (nret) { + case 0: op = OP_RETURN0; break; + case 1: op = OP_RETURN1; break; + default: op = OP_RETURN; break; + } + luaK_codeABC(fs, op, first, nret + 1, 0); +} + + +/* +** Code a "conditional jump", that is, a test or comparison opcode +** followed by a jump. Return jump position. +*/ +static int condjump (FuncState *fs, OpCode op, int A, int B, int C, int k) { + luaK_codeABCk(fs, op, A, B, C, k); + return luaK_jump(fs); +} + + +/* +** returns current 'pc' and marks it as a jump target (to avoid wrong +** optimizations with consecutive instructions not in the same basic block). +*/ +int luaK_getlabel (FuncState *fs) { + fs->lasttarget = fs->pc; + return fs->pc; +} + + +/* +** Returns the position of the instruction "controlling" a given +** jump (that is, its condition), or the jump itself if it is +** unconditional. +*/ +static Instruction *getjumpcontrol (FuncState *fs, int pc) { + Instruction *pi = &fs->f->code[pc]; + if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) + return pi-1; + else + return pi; +} + + +/* +** Patch destination register for a TESTSET instruction. +** If instruction in position 'node' is not a TESTSET, return 0 ("fails"). +** Otherwise, if 'reg' is not 'NO_REG', set it as the destination +** register. Otherwise, change instruction to a simple 'TEST' (produces +** no register value) +*/ +static int patchtestreg (FuncState *fs, int node, int reg) { + Instruction *i = getjumpcontrol(fs, node); + if (GET_OPCODE(*i) != OP_TESTSET) + return 0; /* cannot patch other instructions */ + if (reg != NO_REG && reg != GETARG_B(*i)) + SETARG_A(*i, reg); + else { + /* no register to put value or register already has the value; + change instruction to simple test */ + *i = CREATE_ABCk(OP_TEST, GETARG_B(*i), 0, 0, GETARG_k(*i)); + } + return 1; +} + + +/* +** Traverse a list of tests ensuring no one produces a value +*/ +static void removevalues (FuncState *fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) + patchtestreg(fs, list, NO_REG); +} + + +/* +** Traverse a list of tests, patching their destination address and +** registers: tests producing values jump to 'vtarget' (and put their +** values in 'reg'), other tests jump to 'dtarget'. +*/ +static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, + int dtarget) { + while (list != NO_JUMP) { + int next = getjump(fs, list); + if (patchtestreg(fs, list, reg)) + fixjump(fs, list, vtarget); + else + fixjump(fs, list, dtarget); /* jump to default target */ + list = next; + } +} + + +/* +** Path all jumps in 'list' to jump to 'target'. +** (The assert means that we cannot fix a jump to a forward address +** because we only know addresses once code is generated.) +*/ +void luaK_patchlist (FuncState *fs, int list, int target) { + lua_assert(target <= fs->pc); + patchlistaux(fs, list, target, NO_REG, target); +} + + +void luaK_patchtohere (FuncState *fs, int list) { + int hr = luaK_getlabel(fs); /* mark "here" as a jump target */ + luaK_patchlist(fs, list, hr); +} + + +/* limit for difference between lines in relative line info. */ +#define LIMLINEDIFF 0x80 + + +/* +** Save line info for a new instruction. If difference from last line +** does not fit in a byte, of after that many instructions, save a new +** absolute line info; (in that case, the special value 'ABSLINEINFO' +** in 'lineinfo' signals the existence of this absolute information.) +** Otherwise, store the difference from last line in 'lineinfo'. +*/ +static void savelineinfo (FuncState *fs, Proto *f, int line) { + int linedif = line - fs->previousline; + int pc = fs->pc - 1; /* last instruction coded */ + if (abs(linedif) >= LIMLINEDIFF || fs->iwthabs++ >= MAXIWTHABS) { + luaM_growvector(fs->ls->L, f->abslineinfo, fs->nabslineinfo, + f->sizeabslineinfo, AbsLineInfo, MAX_INT, "lines"); + f->abslineinfo[fs->nabslineinfo].pc = pc; + f->abslineinfo[fs->nabslineinfo++].line = line; + linedif = ABSLINEINFO; /* signal that there is absolute information */ + fs->iwthabs = 1; /* restart counter */ + } + luaM_growvector(fs->ls->L, f->lineinfo, pc, f->sizelineinfo, ls_byte, + MAX_INT, "opcodes"); + f->lineinfo[pc] = linedif; + fs->previousline = line; /* last line saved */ +} + + +/* +** Remove line information from the last instruction. +** If line information for that instruction is absolute, set 'iwthabs' +** above its max to force the new (replacing) instruction to have +** absolute line info, too. +*/ +static void removelastlineinfo (FuncState *fs) { + Proto *f = fs->f; + int pc = fs->pc - 1; /* last instruction coded */ + if (f->lineinfo[pc] != ABSLINEINFO) { /* relative line info? */ + fs->previousline -= f->lineinfo[pc]; /* correct last line saved */ + fs->iwthabs--; /* undo previous increment */ + } + else { /* absolute line information */ + lua_assert(f->abslineinfo[fs->nabslineinfo - 1].pc == pc); + fs->nabslineinfo--; /* remove it */ + fs->iwthabs = MAXIWTHABS + 1; /* force next line info to be absolute */ + } +} + + +/* +** Remove the last instruction created, correcting line information +** accordingly. +*/ +static void removelastinstruction (FuncState *fs) { + removelastlineinfo(fs); + fs->pc--; +} + + +/* +** Emit instruction 'i', checking for array sizes and saving also its +** line information. Return 'i' position. +*/ +int luaK_code (FuncState *fs, Instruction i) { + Proto *f = fs->f; + /* put new instruction in code array */ + luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, + MAX_INT, "opcodes"); + f->code[fs->pc++] = i; + savelineinfo(fs, f, fs->ls->lastline); + return fs->pc - 1; /* index of new instruction */ +} + + +/* +** Format and emit an 'iABC' instruction. (Assertions check consistency +** of parameters versus opcode.) +*/ +int luaK_codeABCk (FuncState *fs, OpCode o, int a, int b, int c, int k) { + lua_assert(getOpMode(o) == iABC); + lua_assert(a <= MAXARG_A && b <= MAXARG_B && + c <= MAXARG_C && (k & ~1) == 0); + return luaK_code(fs, CREATE_ABCk(o, a, b, c, k)); +} + + +/* +** Format and emit an 'iABx' instruction. +*/ +int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { + lua_assert(getOpMode(o) == iABx); + lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx); + return luaK_code(fs, CREATE_ABx(o, a, bc)); +} + + +/* +** Format and emit an 'iAsBx' instruction. +*/ +int luaK_codeAsBx (FuncState *fs, OpCode o, int a, int bc) { + unsigned int b = bc + OFFSET_sBx; + lua_assert(getOpMode(o) == iAsBx); + lua_assert(a <= MAXARG_A && b <= MAXARG_Bx); + return luaK_code(fs, CREATE_ABx(o, a, b)); +} + + +/* +** Format and emit an 'isJ' instruction. +*/ +static int codesJ (FuncState *fs, OpCode o, int sj, int k) { + unsigned int j = sj + OFFSET_sJ; + lua_assert(getOpMode(o) == isJ); + lua_assert(j <= MAXARG_sJ && (k & ~1) == 0); + return luaK_code(fs, CREATE_sJ(o, j, k)); +} + + +/* +** Emit an "extra argument" instruction (format 'iAx') +*/ +static int codeextraarg (FuncState *fs, int a) { + lua_assert(a <= MAXARG_Ax); + return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); +} + + +/* +** Emit a "load constant" instruction, using either 'OP_LOADK' +** (if constant index 'k' fits in 18 bits) or an 'OP_LOADKX' +** instruction with "extra argument". +*/ +static int luaK_codek (FuncState *fs, int reg, int k) { + if (k <= MAXARG_Bx) + return luaK_codeABx(fs, OP_LOADK, reg, k); + else { + int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); + codeextraarg(fs, k); + return p; + } +} + + +/* +** Check register-stack level, keeping track of its maximum size +** in field 'maxstacksize' +*/ +void luaK_checkstack (FuncState *fs, int n) { + int newstack = fs->freereg + n; + if (newstack > fs->f->maxstacksize) { + if (newstack >= MAXREGS) + luaX_syntaxerror(fs->ls, + "function or expression needs too many registers"); + fs->f->maxstacksize = cast_byte(newstack); + } +} + + +/* +** Reserve 'n' registers in register stack +*/ +void luaK_reserveregs (FuncState *fs, int n) { + luaK_checkstack(fs, n); + fs->freereg += n; +} + + +/* +** Free register 'reg', if it is neither a constant index nor +** a local variable. +) +*/ +static void freereg (FuncState *fs, int reg) { + if (reg >= luaY_nvarstack(fs)) { + fs->freereg--; + lua_assert(reg == fs->freereg); + } +} + + +/* +** Free two registers in proper order +*/ +static void freeregs (FuncState *fs, int r1, int r2) { + if (r1 > r2) { + freereg(fs, r1); + freereg(fs, r2); + } + else { + freereg(fs, r2); + freereg(fs, r1); + } +} + + +/* +** Free register used by expression 'e' (if any) +*/ +static void freeexp (FuncState *fs, expdesc *e) { + if (e->k == VNONRELOC) + freereg(fs, e->u.info); +} + + +/* +** Free registers used by expressions 'e1' and 'e2' (if any) in proper +** order. +*/ +static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) { + int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1; + int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1; + freeregs(fs, r1, r2); +} + + +/* +** Add constant 'v' to prototype's list of constants (field 'k'). +** Use scanner's table to cache position of constants in constant list +** and try to reuse constants. Because some values should not be used +** as keys (nil cannot be a key, integer keys can collapse with float +** keys), the caller must provide a useful 'key' for indexing the cache. +** Note that all functions share the same table, so entering or exiting +** a function can make some indices wrong. +*/ +static int addk (FuncState *fs, TValue *key, TValue *v) { + TValue val; + lua_State *L = fs->ls->L; + Proto *f = fs->f; + const TValue *idx = luaH_get(fs->ls->h, key); /* query scanner table */ + int k, oldsize; + if (ttisinteger(idx)) { /* is there an index there? */ + k = cast_int(ivalue(idx)); + /* correct value? (warning: must distinguish floats from integers!) */ + if (k < fs->nk && ttypetag(&f->k[k]) == ttypetag(v) && + luaV_rawequalobj(&f->k[k], v)) + return k; /* reuse index */ + } + /* constant not found; create a new entry */ + oldsize = f->sizek; + k = fs->nk; + /* numerical value does not need GC barrier; + table has no metatable, so it does not need to invalidate cache */ + setivalue(&val, k); + luaH_finishset(L, fs->ls->h, key, idx, &val); + luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); + while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); + setobj(L, &f->k[k], v); + fs->nk++; + luaC_barrier(L, f, v); + return k; +} + + +/* +** Add a string to list of constants and return its index. +*/ +static int stringK (FuncState *fs, TString *s) { + TValue o; + setsvalue(fs->ls->L, &o, s); + return addk(fs, &o, &o); /* use string itself as key */ +} + + +/* +** Add an integer to list of constants and return its index. +*/ +static int luaK_intK (FuncState *fs, lua_Integer n) { + TValue o; + setivalue(&o, n); + return addk(fs, &o, &o); /* use integer itself as key */ +} + +/* +** Add a float to list of constants and return its index. Floats +** with integral values need a different key, to avoid collision +** with actual integers. To that, we add to the number its smaller +** power-of-two fraction that is still significant in its scale. +** For doubles, that would be 1/2^52. +** (This method is not bulletproof: there may be another float +** with that value, and for floats larger than 2^53 the result is +** still an integer. At worst, this only wastes an entry with +** a duplicate.) +*/ +static int luaK_numberK (FuncState *fs, lua_Number r) { + TValue o; + lua_Integer ik; + setfltvalue(&o, r); + if (!luaV_flttointeger(r, &ik, F2Ieq)) /* not an integral value? */ + return addk(fs, &o, &o); /* use number itself as key */ + else { /* must build an alternative key */ + const int nbm = l_floatatt(MANT_DIG); + const lua_Number q = l_mathop(ldexp)(l_mathop(1.0), -nbm + 1); + const lua_Number k = (ik == 0) ? q : r + r*q; /* new key */ + TValue kv; + setfltvalue(&kv, k); + /* result is not an integral value, unless value is too large */ + lua_assert(!luaV_flttointeger(k, &ik, F2Ieq) || + l_mathop(fabs)(r) >= l_mathop(1e6)); + return addk(fs, &kv, &o); + } +} + + +/* +** Add a false to list of constants and return its index. +*/ +static int boolF (FuncState *fs) { + TValue o; + setbfvalue(&o); + return addk(fs, &o, &o); /* use boolean itself as key */ +} + + +/* +** Add a true to list of constants and return its index. +*/ +static int boolT (FuncState *fs) { + TValue o; + setbtvalue(&o); + return addk(fs, &o, &o); /* use boolean itself as key */ +} + + +/* +** Add nil to list of constants and return its index. +*/ +static int nilK (FuncState *fs) { + TValue k, v; + setnilvalue(&v); + /* cannot use nil as key; instead use table itself to represent nil */ + sethvalue(fs->ls->L, &k, fs->ls->h); + return addk(fs, &k, &v); +} + + +/* +** Check whether 'i' can be stored in an 'sC' operand. Equivalent to +** (0 <= int2sC(i) && int2sC(i) <= MAXARG_C) but without risk of +** overflows in the hidden addition inside 'int2sC'. +*/ +static int fitsC (lua_Integer i) { + return (l_castS2U(i) + OFFSET_sC <= cast_uint(MAXARG_C)); +} + + +/* +** Check whether 'i' can be stored in an 'sBx' operand. +*/ +static int fitsBx (lua_Integer i) { + return (-OFFSET_sBx <= i && i <= MAXARG_Bx - OFFSET_sBx); +} + + +void luaK_int (FuncState *fs, int reg, lua_Integer i) { + if (fitsBx(i)) + luaK_codeAsBx(fs, OP_LOADI, reg, cast_int(i)); + else + luaK_codek(fs, reg, luaK_intK(fs, i)); +} + + +static void luaK_float (FuncState *fs, int reg, lua_Number f) { + lua_Integer fi; + if (luaV_flttointeger(f, &fi, F2Ieq) && fitsBx(fi)) + luaK_codeAsBx(fs, OP_LOADF, reg, cast_int(fi)); + else + luaK_codek(fs, reg, luaK_numberK(fs, f)); +} + + +/* +** Convert a constant in 'v' into an expression description 'e' +*/ +static void const2exp (TValue *v, expdesc *e) { + switch (ttypetag(v)) { + case LUA_VNUMINT: + e->k = VKINT; e->u.ival = ivalue(v); + break; + case LUA_VNUMFLT: + e->k = VKFLT; e->u.nval = fltvalue(v); + break; + case LUA_VFALSE: + e->k = VFALSE; + break; + case LUA_VTRUE: + e->k = VTRUE; + break; + case LUA_VNIL: + e->k = VNIL; + break; + case LUA_VSHRSTR: case LUA_VLNGSTR: + e->k = VKSTR; e->u.strval = tsvalue(v); + break; + default: lua_assert(0); + } +} + + +/* +** Fix an expression to return the number of results 'nresults'. +** 'e' must be a multi-ret expression (function call or vararg). +*/ +void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { + Instruction *pc = &getinstruction(fs, e); + if (e->k == VCALL) /* expression is an open function call? */ + SETARG_C(*pc, nresults + 1); + else { + lua_assert(e->k == VVARARG); + SETARG_C(*pc, nresults + 1); + SETARG_A(*pc, fs->freereg); + luaK_reserveregs(fs, 1); + } +} + + +/* +** Convert a VKSTR to a VK +*/ +static void str2K (FuncState *fs, expdesc *e) { + lua_assert(e->k == VKSTR); + e->u.info = stringK(fs, e->u.strval); + e->k = VK; +} + + +/* +** Fix an expression to return one result. +** If expression is not a multi-ret expression (function call or +** vararg), it already returns one result, so nothing needs to be done. +** Function calls become VNONRELOC expressions (as its result comes +** fixed in the base register of the call), while vararg expressions +** become VRELOC (as OP_VARARG puts its results where it wants). +** (Calls are created returning one result, so that does not need +** to be fixed.) +*/ +void luaK_setoneret (FuncState *fs, expdesc *e) { + if (e->k == VCALL) { /* expression is an open function call? */ + /* already returns 1 value */ + lua_assert(GETARG_C(getinstruction(fs, e)) == 2); + e->k = VNONRELOC; /* result has fixed position */ + e->u.info = GETARG_A(getinstruction(fs, e)); + } + else if (e->k == VVARARG) { + SETARG_C(getinstruction(fs, e), 2); + e->k = VRELOC; /* can relocate its simple result */ + } +} + + +/* +** Ensure that expression 'e' is not a variable (nor a <const>). +** (Expression still may have jump lists.) +*/ +void luaK_dischargevars (FuncState *fs, expdesc *e) { + switch (e->k) { + case VCONST: { + const2exp(const2val(fs, e), e); + break; + } + case VLOCAL: { /* already in a register */ + e->u.info = e->u.var.ridx; + e->k = VNONRELOC; /* becomes a non-relocatable value */ + break; + } + case VUPVAL: { /* move value to some (pending) register */ + e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); + e->k = VRELOC; + break; + } + case VINDEXUP: { + e->u.info = luaK_codeABC(fs, OP_GETTABUP, 0, e->u.ind.t, e->u.ind.idx); + e->k = VRELOC; + break; + } + case VINDEXI: { + freereg(fs, e->u.ind.t); + e->u.info = luaK_codeABC(fs, OP_GETI, 0, e->u.ind.t, e->u.ind.idx); + e->k = VRELOC; + break; + } + case VINDEXSTR: { + freereg(fs, e->u.ind.t); + e->u.info = luaK_codeABC(fs, OP_GETFIELD, 0, e->u.ind.t, e->u.ind.idx); + e->k = VRELOC; + break; + } + case VINDEXED: { + freeregs(fs, e->u.ind.t, e->u.ind.idx); + e->u.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.ind.t, e->u.ind.idx); + e->k = VRELOC; + break; + } + case VVARARG: case VCALL: { + luaK_setoneret(fs, e); + break; + } + default: break; /* there is one value available (somewhere) */ + } +} + + +/* +** Ensure expression value is in register 'reg', making 'e' a +** non-relocatable expression. +** (Expression still may have jump lists.) +*/ +static void discharge2reg (FuncState *fs, expdesc *e, int reg) { + luaK_dischargevars(fs, e); + switch (e->k) { + case VNIL: { + luaK_nil(fs, reg, 1); + break; + } + case VFALSE: { + luaK_codeABC(fs, OP_LOADFALSE, reg, 0, 0); + break; + } + case VTRUE: { + luaK_codeABC(fs, OP_LOADTRUE, reg, 0, 0); + break; + } + case VKSTR: { + str2K(fs, e); + } /* FALLTHROUGH */ + case VK: { + luaK_codek(fs, reg, e->u.info); + break; + } + case VKFLT: { + luaK_float(fs, reg, e->u.nval); + break; + } + case VKINT: { + luaK_int(fs, reg, e->u.ival); + break; + } + case VRELOC: { + Instruction *pc = &getinstruction(fs, e); + SETARG_A(*pc, reg); /* instruction will put result in 'reg' */ + break; + } + case VNONRELOC: { + if (reg != e->u.info) + luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0); + break; + } + default: { + lua_assert(e->k == VJMP); + return; /* nothing to do... */ + } + } + e->u.info = reg; + e->k = VNONRELOC; +} + + +/* +** Ensure expression value is in a register, making 'e' a +** non-relocatable expression. +** (Expression still may have jump lists.) +*/ +static void discharge2anyreg (FuncState *fs, expdesc *e) { + if (e->k != VNONRELOC) { /* no fixed register yet? */ + luaK_reserveregs(fs, 1); /* get a register */ + discharge2reg(fs, e, fs->freereg-1); /* put value there */ + } +} + + +static int code_loadbool (FuncState *fs, int A, OpCode op) { + luaK_getlabel(fs); /* those instructions may be jump targets */ + return luaK_codeABC(fs, op, A, 0, 0); +} + + +/* +** check whether list has any jump that do not produce a value +** or produce an inverted value +*/ +static int need_value (FuncState *fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) { + Instruction i = *getjumpcontrol(fs, list); + if (GET_OPCODE(i) != OP_TESTSET) return 1; + } + return 0; /* not found */ +} + + +/* +** Ensures final expression result (which includes results from its +** jump lists) is in register 'reg'. +** If expression has jumps, need to patch these jumps either to +** its final position or to "load" instructions (for those tests +** that do not produce values). +*/ +static void exp2reg (FuncState *fs, expdesc *e, int reg) { + discharge2reg(fs, e, reg); + if (e->k == VJMP) /* expression itself is a test? */ + luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */ + if (hasjumps(e)) { + int final; /* position after whole expression */ + int p_f = NO_JUMP; /* position of an eventual LOAD false */ + int p_t = NO_JUMP; /* position of an eventual LOAD true */ + if (need_value(fs, e->t) || need_value(fs, e->f)) { + int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); + p_f = code_loadbool(fs, reg, OP_LFALSESKIP); /* skip next inst. */ + p_t = code_loadbool(fs, reg, OP_LOADTRUE); + /* jump around these booleans if 'e' is not a test */ + luaK_patchtohere(fs, fj); + } + final = luaK_getlabel(fs); + patchlistaux(fs, e->f, final, reg, p_f); + patchlistaux(fs, e->t, final, reg, p_t); + } + e->f = e->t = NO_JUMP; + e->u.info = reg; + e->k = VNONRELOC; +} + + +/* +** Ensures final expression result is in next available register. +*/ +void luaK_exp2nextreg (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + freeexp(fs, e); + luaK_reserveregs(fs, 1); + exp2reg(fs, e, fs->freereg - 1); +} + + +/* +** Ensures final expression result is in some (any) register +** and return that register. +*/ +int luaK_exp2anyreg (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + if (e->k == VNONRELOC) { /* expression already has a register? */ + if (!hasjumps(e)) /* no jumps? */ + return e->u.info; /* result is already in a register */ + if (e->u.info >= luaY_nvarstack(fs)) { /* reg. is not a local? */ + exp2reg(fs, e, e->u.info); /* put final result in it */ + return e->u.info; + } + /* else expression has jumps and cannot change its register + to hold the jump values, because it is a local variable. + Go through to the default case. */ + } + luaK_exp2nextreg(fs, e); /* default: use next available register */ + return e->u.info; +} + + +/* +** Ensures final expression result is either in a register +** or in an upvalue. +*/ +void luaK_exp2anyregup (FuncState *fs, expdesc *e) { + if (e->k != VUPVAL || hasjumps(e)) + luaK_exp2anyreg(fs, e); +} + + +/* +** Ensures final expression result is either in a register +** or it is a constant. +*/ +void luaK_exp2val (FuncState *fs, expdesc *e) { + if (hasjumps(e)) + luaK_exp2anyreg(fs, e); + else + luaK_dischargevars(fs, e); +} + + +/* +** Try to make 'e' a K expression with an index in the range of R/K +** indices. Return true iff succeeded. +*/ +static int luaK_exp2K (FuncState *fs, expdesc *e) { + if (!hasjumps(e)) { + int info; + switch (e->k) { /* move constants to 'k' */ + case VTRUE: info = boolT(fs); break; + case VFALSE: info = boolF(fs); break; + case VNIL: info = nilK(fs); break; + case VKINT: info = luaK_intK(fs, e->u.ival); break; + case VKFLT: info = luaK_numberK(fs, e->u.nval); break; + case VKSTR: info = stringK(fs, e->u.strval); break; + case VK: info = e->u.info; break; + default: return 0; /* not a constant */ + } + if (info <= MAXINDEXRK) { /* does constant fit in 'argC'? */ + e->k = VK; /* make expression a 'K' expression */ + e->u.info = info; + return 1; + } + } + /* else, expression doesn't fit; leave it unchanged */ + return 0; +} + + +/* +** Ensures final expression result is in a valid R/K index +** (that is, it is either in a register or in 'k' with an index +** in the range of R/K indices). +** Returns 1 iff expression is K. +*/ +int luaK_exp2RK (FuncState *fs, expdesc *e) { + if (luaK_exp2K(fs, e)) + return 1; + else { /* not a constant in the right range: put it in a register */ + luaK_exp2anyreg(fs, e); + return 0; + } +} + + +static void codeABRK (FuncState *fs, OpCode o, int a, int b, + expdesc *ec) { + int k = luaK_exp2RK(fs, ec); + luaK_codeABCk(fs, o, a, b, ec->u.info, k); +} + + +/* +** Generate code to store result of expression 'ex' into variable 'var'. +*/ +void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { + switch (var->k) { + case VLOCAL: { + freeexp(fs, ex); + exp2reg(fs, ex, var->u.var.ridx); /* compute 'ex' into proper place */ + return; + } + case VUPVAL: { + int e = luaK_exp2anyreg(fs, ex); + luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); + break; + } + case VINDEXUP: { + codeABRK(fs, OP_SETTABUP, var->u.ind.t, var->u.ind.idx, ex); + break; + } + case VINDEXI: { + codeABRK(fs, OP_SETI, var->u.ind.t, var->u.ind.idx, ex); + break; + } + case VINDEXSTR: { + codeABRK(fs, OP_SETFIELD, var->u.ind.t, var->u.ind.idx, ex); + break; + } + case VINDEXED: { + codeABRK(fs, OP_SETTABLE, var->u.ind.t, var->u.ind.idx, ex); + break; + } + default: lua_assert(0); /* invalid var kind to store */ + } + freeexp(fs, ex); +} + + +/* +** Emit SELF instruction (convert expression 'e' into 'e:key(e,'). +*/ +void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { + int ereg; + luaK_exp2anyreg(fs, e); + ereg = e->u.info; /* register where 'e' was placed */ + freeexp(fs, e); + e->u.info = fs->freereg; /* base register for op_self */ + e->k = VNONRELOC; /* self expression has a fixed register */ + luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */ + codeABRK(fs, OP_SELF, e->u.info, ereg, key); + freeexp(fs, key); +} + + +/* +** Negate condition 'e' (where 'e' is a comparison). +*/ +static void negatecondition (FuncState *fs, expdesc *e) { + Instruction *pc = getjumpcontrol(fs, e->u.info); + lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && + GET_OPCODE(*pc) != OP_TEST); + SETARG_k(*pc, (GETARG_k(*pc) ^ 1)); +} + + +/* +** Emit instruction to jump if 'e' is 'cond' (that is, if 'cond' +** is true, code will jump if 'e' is true.) Return jump position. +** Optimize when 'e' is 'not' something, inverting the condition +** and removing the 'not'. +*/ +static int jumponcond (FuncState *fs, expdesc *e, int cond) { + if (e->k == VRELOC) { + Instruction ie = getinstruction(fs, e); + if (GET_OPCODE(ie) == OP_NOT) { + removelastinstruction(fs); /* remove previous OP_NOT */ + return condjump(fs, OP_TEST, GETARG_B(ie), 0, 0, !cond); + } + /* else go through */ + } + discharge2anyreg(fs, e); + freeexp(fs, e); + return condjump(fs, OP_TESTSET, NO_REG, e->u.info, 0, cond); +} + + +/* +** Emit code to go through if 'e' is true, jump otherwise. +*/ +void luaK_goiftrue (FuncState *fs, expdesc *e) { + int pc; /* pc of new jump */ + luaK_dischargevars(fs, e); + switch (e->k) { + case VJMP: { /* condition? */ + negatecondition(fs, e); /* jump when it is false */ + pc = e->u.info; /* save jump position */ + break; + } + case VK: case VKFLT: case VKINT: case VKSTR: case VTRUE: { + pc = NO_JUMP; /* always true; do nothing */ + break; + } + default: { + pc = jumponcond(fs, e, 0); /* jump when false */ + break; + } + } + luaK_concat(fs, &e->f, pc); /* insert new jump in false list */ + luaK_patchtohere(fs, e->t); /* true list jumps to here (to go through) */ + e->t = NO_JUMP; +} + + +/* +** Emit code to go through if 'e' is false, jump otherwise. +*/ +void luaK_goiffalse (FuncState *fs, expdesc *e) { + int pc; /* pc of new jump */ + luaK_dischargevars(fs, e); + switch (e->k) { + case VJMP: { + pc = e->u.info; /* already jump if true */ + break; + } + case VNIL: case VFALSE: { + pc = NO_JUMP; /* always false; do nothing */ + break; + } + default: { + pc = jumponcond(fs, e, 1); /* jump if true */ + break; + } + } + luaK_concat(fs, &e->t, pc); /* insert new jump in 't' list */ + luaK_patchtohere(fs, e->f); /* false list jumps to here (to go through) */ + e->f = NO_JUMP; +} + + +/* +** Code 'not e', doing constant folding. +*/ +static void codenot (FuncState *fs, expdesc *e) { + switch (e->k) { + case VNIL: case VFALSE: { + e->k = VTRUE; /* true == not nil == not false */ + break; + } + case VK: case VKFLT: case VKINT: case VKSTR: case VTRUE: { + e->k = VFALSE; /* false == not "x" == not 0.5 == not 1 == not true */ + break; + } + case VJMP: { + negatecondition(fs, e); + break; + } + case VRELOC: + case VNONRELOC: { + discharge2anyreg(fs, e); + freeexp(fs, e); + e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0); + e->k = VRELOC; + break; + } + default: lua_assert(0); /* cannot happen */ + } + /* interchange true and false lists */ + { int temp = e->f; e->f = e->t; e->t = temp; } + removevalues(fs, e->f); /* values are useless when negated */ + removevalues(fs, e->t); +} + + +/* +** Check whether expression 'e' is a small literal string +*/ +static int isKstr (FuncState *fs, expdesc *e) { + return (e->k == VK && !hasjumps(e) && e->u.info <= MAXARG_B && + ttisshrstring(&fs->f->k[e->u.info])); +} + +/* +** Check whether expression 'e' is a literal integer. +*/ +int luaK_isKint (expdesc *e) { + return (e->k == VKINT && !hasjumps(e)); +} + + +/* +** Check whether expression 'e' is a literal integer in +** proper range to fit in register C +*/ +static int isCint (expdesc *e) { + return luaK_isKint(e) && (l_castS2U(e->u.ival) <= l_castS2U(MAXARG_C)); +} + + +/* +** Check whether expression 'e' is a literal integer in +** proper range to fit in register sC +*/ +static int isSCint (expdesc *e) { + return luaK_isKint(e) && fitsC(e->u.ival); +} + + +/* +** Check whether expression 'e' is a literal integer or float in +** proper range to fit in a register (sB or sC). +*/ +static int isSCnumber (expdesc *e, int *pi, int *isfloat) { + lua_Integer i; + if (e->k == VKINT) + i = e->u.ival; + else if (e->k == VKFLT && luaV_flttointeger(e->u.nval, &i, F2Ieq)) + *isfloat = 1; + else + return 0; /* not a number */ + if (!hasjumps(e) && fitsC(i)) { + *pi = int2sC(cast_int(i)); + return 1; + } + else + return 0; +} + + +/* +** Create expression 't[k]'. 't' must have its final result already in a +** register or upvalue. Upvalues can only be indexed by literal strings. +** Keys can be literal strings in the constant table or arbitrary +** values in registers. +*/ +void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { + if (k->k == VKSTR) + str2K(fs, k); + lua_assert(!hasjumps(t) && + (t->k == VLOCAL || t->k == VNONRELOC || t->k == VUPVAL)); + if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */ + luaK_exp2anyreg(fs, t); /* put it in a register */ + if (t->k == VUPVAL) { + t->u.ind.t = t->u.info; /* upvalue index */ + t->u.ind.idx = k->u.info; /* literal string */ + t->k = VINDEXUP; + } + else { + /* register index of the table */ + t->u.ind.t = (t->k == VLOCAL) ? t->u.var.ridx: t->u.info; + if (isKstr(fs, k)) { + t->u.ind.idx = k->u.info; /* literal string */ + t->k = VINDEXSTR; + } + else if (isCint(k)) { + t->u.ind.idx = cast_int(k->u.ival); /* int. constant in proper range */ + t->k = VINDEXI; + } + else { + t->u.ind.idx = luaK_exp2anyreg(fs, k); /* register */ + t->k = VINDEXED; + } + } +} + + +/* +** Return false if folding can raise an error. +** Bitwise operations need operands convertible to integers; division +** operations cannot have 0 as divisor. +*/ +static int validop (int op, TValue *v1, TValue *v2) { + switch (op) { + case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: + case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */ + lua_Integer i; + return (luaV_tointegerns(v1, &i, LUA_FLOORN2I) && + luaV_tointegerns(v2, &i, LUA_FLOORN2I)); + } + case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */ + return (nvalue(v2) != 0); + default: return 1; /* everything else is valid */ + } +} + + +/* +** Try to "constant-fold" an operation; return 1 iff successful. +** (In this case, 'e1' has the final result.) +*/ +static int constfolding (FuncState *fs, int op, expdesc *e1, + const expdesc *e2) { + TValue v1, v2, res; + if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2)) + return 0; /* non-numeric operands or not safe to fold */ + luaO_rawarith(fs->ls->L, op, &v1, &v2, &res); /* does operation */ + if (ttisinteger(&res)) { + e1->k = VKINT; + e1->u.ival = ivalue(&res); + } + else { /* folds neither NaN nor 0.0 (to avoid problems with -0.0) */ + lua_Number n = fltvalue(&res); + if (luai_numisnan(n) || n == 0) + return 0; + e1->k = VKFLT; + e1->u.nval = n; + } + return 1; +} + + +/* +** Convert a BinOpr to an OpCode (ORDER OPR - ORDER OP) +*/ +l_sinline OpCode binopr2op (BinOpr opr, BinOpr baser, OpCode base) { + lua_assert(baser <= opr && + ((baser == OPR_ADD && opr <= OPR_SHR) || + (baser == OPR_LT && opr <= OPR_LE))); + return cast(OpCode, (cast_int(opr) - cast_int(baser)) + cast_int(base)); +} + + +/* +** Convert a UnOpr to an OpCode (ORDER OPR - ORDER OP) +*/ +l_sinline OpCode unopr2op (UnOpr opr) { + return cast(OpCode, (cast_int(opr) - cast_int(OPR_MINUS)) + + cast_int(OP_UNM)); +} + + +/* +** Convert a BinOpr to a tag method (ORDER OPR - ORDER TM) +*/ +l_sinline TMS binopr2TM (BinOpr opr) { + lua_assert(OPR_ADD <= opr && opr <= OPR_SHR); + return cast(TMS, (cast_int(opr) - cast_int(OPR_ADD)) + cast_int(TM_ADD)); +} + + +/* +** Emit code for unary expressions that "produce values" +** (everything but 'not'). +** Expression to produce final result will be encoded in 'e'. +*/ +static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) { + int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */ + freeexp(fs, e); + e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */ + e->k = VRELOC; /* all those operations are relocatable */ + luaK_fixline(fs, line); +} + + +/* +** Emit code for binary expressions that "produce values" +** (everything but logical operators 'and'/'or' and comparison +** operators). +** Expression to produce final result will be encoded in 'e1'. +*/ +static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2, + OpCode op, int v2, int flip, int line, + OpCode mmop, TMS event) { + int v1 = luaK_exp2anyreg(fs, e1); + int pc = luaK_codeABCk(fs, op, 0, v1, v2, 0); + freeexps(fs, e1, e2); + e1->u.info = pc; + e1->k = VRELOC; /* all those operations are relocatable */ + luaK_fixline(fs, line); + luaK_codeABCk(fs, mmop, v1, v2, event, flip); /* to call metamethod */ + luaK_fixline(fs, line); +} + + +/* +** Emit code for binary expressions that "produce values" over +** two registers. +*/ +static void codebinexpval (FuncState *fs, BinOpr opr, + expdesc *e1, expdesc *e2, int line) { + OpCode op = binopr2op(opr, OPR_ADD, OP_ADD); + int v2 = luaK_exp2anyreg(fs, e2); /* make sure 'e2' is in a register */ + /* 'e1' must be already in a register or it is a constant */ + lua_assert((VNIL <= e1->k && e1->k <= VKSTR) || + e1->k == VNONRELOC || e1->k == VRELOC); + lua_assert(OP_ADD <= op && op <= OP_SHR); + finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, binopr2TM(opr)); +} + + +/* +** Code binary operators with immediate operands. +*/ +static void codebini (FuncState *fs, OpCode op, + expdesc *e1, expdesc *e2, int flip, int line, + TMS event) { + int v2 = int2sC(cast_int(e2->u.ival)); /* immediate operand */ + lua_assert(e2->k == VKINT); + finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINI, event); +} + + +/* +** Code binary operators with K operand. +*/ +static void codebinK (FuncState *fs, BinOpr opr, + expdesc *e1, expdesc *e2, int flip, int line) { + TMS event = binopr2TM(opr); + int v2 = e2->u.info; /* K index */ + OpCode op = binopr2op(opr, OPR_ADD, OP_ADDK); + finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event); +} + + +/* Try to code a binary operator negating its second operand. +** For the metamethod, 2nd operand must keep its original value. +*/ +static int finishbinexpneg (FuncState *fs, expdesc *e1, expdesc *e2, + OpCode op, int line, TMS event) { + if (!luaK_isKint(e2)) + return 0; /* not an integer constant */ + else { + lua_Integer i2 = e2->u.ival; + if (!(fitsC(i2) && fitsC(-i2))) + return 0; /* not in the proper range */ + else { /* operating a small integer constant */ + int v2 = cast_int(i2); + finishbinexpval(fs, e1, e2, op, int2sC(-v2), 0, line, OP_MMBINI, event); + /* correct metamethod argument */ + SETARG_B(fs->f->code[fs->pc - 1], int2sC(v2)); + return 1; /* successfully coded */ + } + } +} + + +static void swapexps (expdesc *e1, expdesc *e2) { + expdesc temp = *e1; *e1 = *e2; *e2 = temp; /* swap 'e1' and 'e2' */ +} + + +/* +** Code binary operators with no constant operand. +*/ +static void codebinNoK (FuncState *fs, BinOpr opr, + expdesc *e1, expdesc *e2, int flip, int line) { + if (flip) + swapexps(e1, e2); /* back to original order */ + codebinexpval(fs, opr, e1, e2, line); /* use standard operators */ +} + + +/* +** Code arithmetic operators ('+', '-', ...). If second operand is a +** constant in the proper range, use variant opcodes with K operands. +*/ +static void codearith (FuncState *fs, BinOpr opr, + expdesc *e1, expdesc *e2, int flip, int line) { + if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) /* K operand? */ + codebinK(fs, opr, e1, e2, flip, line); + else /* 'e2' is neither an immediate nor a K operand */ + codebinNoK(fs, opr, e1, e2, flip, line); +} + + +/* +** Code commutative operators ('+', '*'). If first operand is a +** numeric constant, change order of operands to try to use an +** immediate or K operator. +*/ +static void codecommutative (FuncState *fs, BinOpr op, + expdesc *e1, expdesc *e2, int line) { + int flip = 0; + if (tonumeral(e1, NULL)) { /* is first operand a numeric constant? */ + swapexps(e1, e2); /* change order */ + flip = 1; + } + if (op == OPR_ADD && isSCint(e2)) /* immediate operand? */ + codebini(fs, OP_ADDI, e1, e2, flip, line, TM_ADD); + else + codearith(fs, op, e1, e2, flip, line); +} + + +/* +** Code bitwise operations; they are all commutative, so the function +** tries to put an integer constant as the 2nd operand (a K operand). +*/ +static void codebitwise (FuncState *fs, BinOpr opr, + expdesc *e1, expdesc *e2, int line) { + int flip = 0; + if (e1->k == VKINT) { + swapexps(e1, e2); /* 'e2' will be the constant operand */ + flip = 1; + } + if (e2->k == VKINT && luaK_exp2K(fs, e2)) /* K operand? */ + codebinK(fs, opr, e1, e2, flip, line); + else /* no constants */ + codebinNoK(fs, opr, e1, e2, flip, line); +} + + +/* +** Emit code for order comparisons. When using an immediate operand, +** 'isfloat' tells whether the original value was a float. +*/ +static void codeorder (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { + int r1, r2; + int im; + int isfloat = 0; + OpCode op; + if (isSCnumber(e2, &im, &isfloat)) { + /* use immediate operand */ + r1 = luaK_exp2anyreg(fs, e1); + r2 = im; + op = binopr2op(opr, OPR_LT, OP_LTI); + } + else if (isSCnumber(e1, &im, &isfloat)) { + /* transform (A < B) to (B > A) and (A <= B) to (B >= A) */ + r1 = luaK_exp2anyreg(fs, e2); + r2 = im; + op = binopr2op(opr, OPR_LT, OP_GTI); + } + else { /* regular case, compare two registers */ + r1 = luaK_exp2anyreg(fs, e1); + r2 = luaK_exp2anyreg(fs, e2); + op = binopr2op(opr, OPR_LT, OP_LT); + } + freeexps(fs, e1, e2); + e1->u.info = condjump(fs, op, r1, r2, isfloat, 1); + e1->k = VJMP; +} + + +/* +** Emit code for equality comparisons ('==', '~='). +** 'e1' was already put as RK by 'luaK_infix'. +*/ +static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { + int r1, r2; + int im; + int isfloat = 0; /* not needed here, but kept for symmetry */ + OpCode op; + if (e1->k != VNONRELOC) { + lua_assert(e1->k == VK || e1->k == VKINT || e1->k == VKFLT); + swapexps(e1, e2); + } + r1 = luaK_exp2anyreg(fs, e1); /* 1st expression must be in register */ + if (isSCnumber(e2, &im, &isfloat)) { + op = OP_EQI; + r2 = im; /* immediate operand */ + } + else if (luaK_exp2RK(fs, e2)) { /* 2nd expression is constant? */ + op = OP_EQK; + r2 = e2->u.info; /* constant index */ + } + else { + op = OP_EQ; /* will compare two registers */ + r2 = luaK_exp2anyreg(fs, e2); + } + freeexps(fs, e1, e2); + e1->u.info = condjump(fs, op, r1, r2, isfloat, (opr == OPR_EQ)); + e1->k = VJMP; +} + + +/* +** Apply prefix operation 'op' to expression 'e'. +*/ +void luaK_prefix (FuncState *fs, UnOpr opr, expdesc *e, int line) { + static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; + luaK_dischargevars(fs, e); + switch (opr) { + case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */ + if (constfolding(fs, opr + LUA_OPUNM, e, &ef)) + break; + /* else */ /* FALLTHROUGH */ + case OPR_LEN: + codeunexpval(fs, unopr2op(opr), e, line); + break; + case OPR_NOT: codenot(fs, e); break; + default: lua_assert(0); + } +} + + +/* +** Process 1st operand 'v' of binary operation 'op' before reading +** 2nd operand. +*/ +void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { + luaK_dischargevars(fs, v); + switch (op) { + case OPR_AND: { + luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */ + break; + } + case OPR_OR: { + luaK_goiffalse(fs, v); /* go ahead only if 'v' is false */ + break; + } + case OPR_CONCAT: { + luaK_exp2nextreg(fs, v); /* operand must be on the stack */ + break; + } + case OPR_ADD: case OPR_SUB: + case OPR_MUL: case OPR_DIV: case OPR_IDIV: + case OPR_MOD: case OPR_POW: + case OPR_BAND: case OPR_BOR: case OPR_BXOR: + case OPR_SHL: case OPR_SHR: { + if (!tonumeral(v, NULL)) + luaK_exp2anyreg(fs, v); + /* else keep numeral, which may be folded or used as an immediate + operand */ + break; + } + case OPR_EQ: case OPR_NE: { + if (!tonumeral(v, NULL)) + luaK_exp2RK(fs, v); + /* else keep numeral, which may be an immediate operand */ + break; + } + case OPR_LT: case OPR_LE: + case OPR_GT: case OPR_GE: { + int dummy, dummy2; + if (!isSCnumber(v, &dummy, &dummy2)) + luaK_exp2anyreg(fs, v); + /* else keep numeral, which may be an immediate operand */ + break; + } + default: lua_assert(0); + } +} + +/* +** Create code for '(e1 .. e2)'. +** For '(e1 .. e2.1 .. e2.2)' (which is '(e1 .. (e2.1 .. e2.2))', +** because concatenation is right associative), merge both CONCATs. +*/ +static void codeconcat (FuncState *fs, expdesc *e1, expdesc *e2, int line) { + Instruction *ie2 = previousinstruction(fs); + if (GET_OPCODE(*ie2) == OP_CONCAT) { /* is 'e2' a concatenation? */ + int n = GETARG_B(*ie2); /* # of elements concatenated in 'e2' */ + lua_assert(e1->u.info + 1 == GETARG_A(*ie2)); + freeexp(fs, e2); + SETARG_A(*ie2, e1->u.info); /* correct first element ('e1') */ + SETARG_B(*ie2, n + 1); /* will concatenate one more element */ + } + else { /* 'e2' is not a concatenation */ + luaK_codeABC(fs, OP_CONCAT, e1->u.info, 2, 0); /* new concat opcode */ + freeexp(fs, e2); + luaK_fixline(fs, line); + } +} + + +/* +** Finalize code for binary operation, after reading 2nd operand. +*/ +void luaK_posfix (FuncState *fs, BinOpr opr, + expdesc *e1, expdesc *e2, int line) { + luaK_dischargevars(fs, e2); + if (foldbinop(opr) && constfolding(fs, opr + LUA_OPADD, e1, e2)) + return; /* done by folding */ + switch (opr) { + case OPR_AND: { + lua_assert(e1->t == NO_JUMP); /* list closed by 'luaK_infix' */ + luaK_concat(fs, &e2->f, e1->f); + *e1 = *e2; + break; + } + case OPR_OR: { + lua_assert(e1->f == NO_JUMP); /* list closed by 'luaK_infix' */ + luaK_concat(fs, &e2->t, e1->t); + *e1 = *e2; + break; + } + case OPR_CONCAT: { /* e1 .. e2 */ + luaK_exp2nextreg(fs, e2); + codeconcat(fs, e1, e2, line); + break; + } + case OPR_ADD: case OPR_MUL: { + codecommutative(fs, opr, e1, e2, line); + break; + } + case OPR_SUB: { + if (finishbinexpneg(fs, e1, e2, OP_ADDI, line, TM_SUB)) + break; /* coded as (r1 + -I) */ + /* ELSE */ + } /* FALLTHROUGH */ + case OPR_DIV: case OPR_IDIV: case OPR_MOD: case OPR_POW: { + codearith(fs, opr, e1, e2, 0, line); + break; + } + case OPR_BAND: case OPR_BOR: case OPR_BXOR: { + codebitwise(fs, opr, e1, e2, line); + break; + } + case OPR_SHL: { + if (isSCint(e1)) { + swapexps(e1, e2); + codebini(fs, OP_SHLI, e1, e2, 1, line, TM_SHL); /* I << r2 */ + } + else if (finishbinexpneg(fs, e1, e2, OP_SHRI, line, TM_SHL)) { + /* coded as (r1 >> -I) */; + } + else /* regular case (two registers) */ + codebinexpval(fs, opr, e1, e2, line); + break; + } + case OPR_SHR: { + if (isSCint(e2)) + codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); /* r1 >> I */ + else /* regular case (two registers) */ + codebinexpval(fs, opr, e1, e2, line); + break; + } + case OPR_EQ: case OPR_NE: { + codeeq(fs, opr, e1, e2); + break; + } + case OPR_GT: case OPR_GE: { + /* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */ + swapexps(e1, e2); + opr = cast(BinOpr, (opr - OPR_GT) + OPR_LT); + } /* FALLTHROUGH */ + case OPR_LT: case OPR_LE: { + codeorder(fs, opr, e1, e2); + break; + } + default: lua_assert(0); + } +} + + +/* +** Change line information associated with current position, by removing +** previous info and adding it again with new line. +*/ +void luaK_fixline (FuncState *fs, int line) { + removelastlineinfo(fs); + savelineinfo(fs, fs->f, line); +} + + +void luaK_settablesize (FuncState *fs, int pc, int ra, int asize, int hsize) { + Instruction *inst = &fs->f->code[pc]; + int rb = (hsize != 0) ? luaO_ceillog2(hsize) + 1 : 0; /* hash size */ + int extra = asize / (MAXARG_C + 1); /* higher bits of array size */ + int rc = asize % (MAXARG_C + 1); /* lower bits of array size */ + int k = (extra > 0); /* true iff needs extra argument */ + *inst = CREATE_ABCk(OP_NEWTABLE, ra, rb, rc, k); + *(inst + 1) = CREATE_Ax(OP_EXTRAARG, extra); +} + + +/* +** Emit a SETLIST instruction. +** 'base' is register that keeps table; +** 'nelems' is #table plus those to be stored now; +** 'tostore' is number of values (in registers 'base + 1',...) to add to +** table (or LUA_MULTRET to add up to stack top). +*/ +void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { + lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH); + if (tostore == LUA_MULTRET) + tostore = 0; + if (nelems <= MAXARG_C) + luaK_codeABC(fs, OP_SETLIST, base, tostore, nelems); + else { + int extra = nelems / (MAXARG_C + 1); + nelems %= (MAXARG_C + 1); + luaK_codeABCk(fs, OP_SETLIST, base, tostore, nelems, 1); + codeextraarg(fs, extra); + } + fs->freereg = base + 1; /* free registers with list values */ +} + + +/* +** return the final target of a jump (skipping jumps to jumps) +*/ +static int finaltarget (Instruction *code, int i) { + int count; + for (count = 0; count < 100; count++) { /* avoid infinite loops */ + Instruction pc = code[i]; + if (GET_OPCODE(pc) != OP_JMP) + break; + else + i += GETARG_sJ(pc) + 1; + } + return i; +} + + +/* +** Do a final pass over the code of a function, doing small peephole +** optimizations and adjustments. +*/ +void luaK_finish (FuncState *fs) { + int i; + Proto *p = fs->f; + for (i = 0; i < fs->pc; i++) { + Instruction *pc = &p->code[i]; + lua_assert(i == 0 || isOT(*(pc - 1)) == isIT(*pc)); + switch (GET_OPCODE(*pc)) { + case OP_RETURN0: case OP_RETURN1: { + if (!(fs->needclose || p->is_vararg)) + break; /* no extra work */ + /* else use OP_RETURN to do the extra work */ + SET_OPCODE(*pc, OP_RETURN); + } /* FALLTHROUGH */ + case OP_RETURN: case OP_TAILCALL: { + if (fs->needclose) + SETARG_k(*pc, 1); /* signal that it needs to close */ + if (p->is_vararg) + SETARG_C(*pc, p->numparams + 1); /* signal that it is vararg */ + break; + } + case OP_JMP: { + int target = finaltarget(p->code, i); + fixjump(fs, i, target); + break; + } + default: break; + } + } +} diff --git a/src/libs/3rdparty/lua/src/lcode.h b/src/libs/3rdparty/lua/src/lcode.h new file mode 100644 index 0000000000..3265824452 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lcode.h @@ -0,0 +1,104 @@ +/* +** $Id: lcode.h $ +** Code generator for Lua +** See Copyright Notice in lua.h +*/ + +#ifndef lcode_h +#define lcode_h + +#include "llex.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" + + +/* +** Marks the end of a patch list. It is an invalid value both as an absolute +** address, and as a list link (would link an element to itself). +*/ +#define NO_JUMP (-1) + + +/* +** grep "ORDER OPR" if you change these enums (ORDER OP) +*/ +typedef enum BinOpr { + /* arithmetic operators */ + OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW, + OPR_DIV, OPR_IDIV, + /* bitwise operators */ + OPR_BAND, OPR_BOR, OPR_BXOR, + OPR_SHL, OPR_SHR, + /* string operator */ + OPR_CONCAT, + /* comparison operators */ + OPR_EQ, OPR_LT, OPR_LE, + OPR_NE, OPR_GT, OPR_GE, + /* logical operators */ + OPR_AND, OPR_OR, + OPR_NOBINOPR +} BinOpr; + + +/* true if operation is foldable (that is, it is arithmetic or bitwise) */ +#define foldbinop(op) ((op) <= OPR_SHR) + + +#define luaK_codeABC(fs,o,a,b,c) luaK_codeABCk(fs,o,a,b,c,0) + + +typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; + + +/* get (pointer to) instruction of given 'expdesc' */ +#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info]) + + +#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) + +#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) + +LUAI_FUNC int luaK_code (FuncState *fs, Instruction i); +LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); +LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx); +LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, + int B, int C, int k); +LUAI_FUNC int luaK_isKint (expdesc *e); +LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v); +LUAI_FUNC void luaK_fixline (FuncState *fs, int line); +LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); +LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); +LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); +LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n); +LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); +LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); +LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); +LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); +LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_jump (FuncState *fs); +LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); +LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); +LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); +LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); +LUAI_FUNC int luaK_getlabel (FuncState *fs); +LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); +LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); +LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, + expdesc *v2, int line); +LUAI_FUNC void luaK_settablesize (FuncState *fs, int pc, + int ra, int asize, int hsize); +LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); +LUAI_FUNC void luaK_finish (FuncState *fs); +LUAI_FUNC l_noret luaK_semerror (LexState *ls, const char *msg); + + +#endif diff --git a/src/libs/3rdparty/lua/src/lcorolib.c b/src/libs/3rdparty/lua/src/lcorolib.c new file mode 100644 index 0000000000..c64adf08a8 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lcorolib.c @@ -0,0 +1,210 @@ +/* +** $Id: lcorolib.c $ +** Coroutine Library +** See Copyright Notice in lua.h +*/ + +#define lcorolib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include <stdlib.h> + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +static lua_State *getco (lua_State *L) { + lua_State *co = lua_tothread(L, 1); + luaL_argexpected(L, co, 1, "thread"); + return co; +} + + +/* +** Resumes a coroutine. Returns the number of results for non-error +** cases or -1 for errors. +*/ +static int auxresume (lua_State *L, lua_State *co, int narg) { + int status, nres; + if (l_unlikely(!lua_checkstack(co, narg))) { + lua_pushliteral(L, "too many arguments to resume"); + return -1; /* error flag */ + } + lua_xmove(L, co, narg); + status = lua_resume(co, L, narg, &nres); + if (l_likely(status == LUA_OK || status == LUA_YIELD)) { + if (l_unlikely(!lua_checkstack(L, nres + 1))) { + lua_pop(co, nres); /* remove results anyway */ + lua_pushliteral(L, "too many results to resume"); + return -1; /* error flag */ + } + lua_xmove(co, L, nres); /* move yielded values */ + return nres; + } + else { + lua_xmove(co, L, 1); /* move error message */ + return -1; /* error flag */ + } +} + + +static int luaB_coresume (lua_State *L) { + lua_State *co = getco(L); + int r; + r = auxresume(L, co, lua_gettop(L) - 1); + if (l_unlikely(r < 0)) { + lua_pushboolean(L, 0); + lua_insert(L, -2); + return 2; /* return false + error message */ + } + else { + lua_pushboolean(L, 1); + lua_insert(L, -(r + 1)); + return r + 1; /* return true + 'resume' returns */ + } +} + + +static int luaB_auxwrap (lua_State *L) { + lua_State *co = lua_tothread(L, lua_upvalueindex(1)); + int r = auxresume(L, co, lua_gettop(L)); + if (l_unlikely(r < 0)) { /* error? */ + int stat = lua_status(co); + if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */ + stat = lua_closethread(co, L); /* close its tbc variables */ + lua_assert(stat != LUA_OK); + lua_xmove(co, L, 1); /* move error message to the caller */ + } + if (stat != LUA_ERRMEM && /* not a memory error and ... */ + lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */ + luaL_where(L, 1); /* add extra info, if available */ + lua_insert(L, -2); + lua_concat(L, 2); + } + return lua_error(L); /* propagate error */ + } + return r; +} + + +static int luaB_cocreate (lua_State *L) { + lua_State *NL; + luaL_checktype(L, 1, LUA_TFUNCTION); + NL = lua_newthread(L); + lua_pushvalue(L, 1); /* move function to top */ + lua_xmove(L, NL, 1); /* move function from L to NL */ + return 1; +} + + +static int luaB_cowrap (lua_State *L) { + luaB_cocreate(L); + lua_pushcclosure(L, luaB_auxwrap, 1); + return 1; +} + + +static int luaB_yield (lua_State *L) { + return lua_yield(L, lua_gettop(L)); +} + + +#define COS_RUN 0 +#define COS_DEAD 1 +#define COS_YIELD 2 +#define COS_NORM 3 + + +static const char *const statname[] = + {"running", "dead", "suspended", "normal"}; + + +static int auxstatus (lua_State *L, lua_State *co) { + if (L == co) return COS_RUN; + else { + switch (lua_status(co)) { + case LUA_YIELD: + return COS_YIELD; + case LUA_OK: { + lua_Debug ar; + if (lua_getstack(co, 0, &ar)) /* does it have frames? */ + return COS_NORM; /* it is running */ + else if (lua_gettop(co) == 0) + return COS_DEAD; + else + return COS_YIELD; /* initial state */ + } + default: /* some error occurred */ + return COS_DEAD; + } + } +} + + +static int luaB_costatus (lua_State *L) { + lua_State *co = getco(L); + lua_pushstring(L, statname[auxstatus(L, co)]); + return 1; +} + + +static int luaB_yieldable (lua_State *L) { + lua_State *co = lua_isnone(L, 1) ? L : getco(L); + lua_pushboolean(L, lua_isyieldable(co)); + return 1; +} + + +static int luaB_corunning (lua_State *L) { + int ismain = lua_pushthread(L); + lua_pushboolean(L, ismain); + return 2; +} + + +static int luaB_close (lua_State *L) { + lua_State *co = getco(L); + int status = auxstatus(L, co); + switch (status) { + case COS_DEAD: case COS_YIELD: { + status = lua_closethread(co, L); + if (status == LUA_OK) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushboolean(L, 0); + lua_xmove(co, L, 1); /* move error message */ + return 2; + } + } + default: /* normal or running coroutine */ + return luaL_error(L, "cannot close a %s coroutine", statname[status]); + } +} + + +static const luaL_Reg co_funcs[] = { + {"create", luaB_cocreate}, + {"resume", luaB_coresume}, + {"running", luaB_corunning}, + {"status", luaB_costatus}, + {"wrap", luaB_cowrap}, + {"yield", luaB_yield}, + {"isyieldable", luaB_yieldable}, + {"close", luaB_close}, + {NULL, NULL} +}; + + + +LUAMOD_API int luaopen_coroutine (lua_State *L) { + luaL_newlib(L, co_funcs); + return 1; +} + diff --git a/src/libs/3rdparty/lua/src/lctype.c b/src/libs/3rdparty/lua/src/lctype.c new file mode 100644 index 0000000000..9542280942 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lctype.c @@ -0,0 +1,64 @@ +/* +** $Id: lctype.c $ +** 'ctype' functions for Lua +** See Copyright Notice in lua.h +*/ + +#define lctype_c +#define LUA_CORE + +#include "lprefix.h" + + +#include "lctype.h" + +#if !LUA_USE_CTYPE /* { */ + +#include <limits.h> + + +#if defined (LUA_UCID) /* accept UniCode IDentifiers? */ +/* consider all non-ascii codepoints to be alphabetic */ +#define NONA 0x01 +#else +#define NONA 0x00 /* default */ +#endif + + +LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { + 0x00, /* EOZ */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ + 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* 8. */ + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* 9. */ + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* a. */ + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* b. */ + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, + 0x00, 0x00, NONA, NONA, NONA, NONA, NONA, NONA, /* c. */ + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* d. */ + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* e. */ + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, + NONA, NONA, NONA, NONA, NONA, 0x00, 0x00, 0x00, /* f. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +#endif /* } */ diff --git a/src/libs/3rdparty/lua/src/lctype.h b/src/libs/3rdparty/lua/src/lctype.h new file mode 100644 index 0000000000..864e190188 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lctype.h @@ -0,0 +1,101 @@ +/* +** $Id: lctype.h $ +** 'ctype' functions for Lua +** See Copyright Notice in lua.h +*/ + +#ifndef lctype_h +#define lctype_h + +#include "lua.h" + + +/* +** WARNING: the functions defined here do not necessarily correspond +** to the similar functions in the standard C ctype.h. They are +** optimized for the specific needs of Lua. +*/ + +#if !defined(LUA_USE_CTYPE) + +#if 'A' == 65 && '0' == 48 +/* ASCII case: can use its own tables; faster and fixed */ +#define LUA_USE_CTYPE 0 +#else +/* must use standard C ctype */ +#define LUA_USE_CTYPE 1 +#endif + +#endif + + +#if !LUA_USE_CTYPE /* { */ + +#include <limits.h> + +#include "llimits.h" + + +#define ALPHABIT 0 +#define DIGITBIT 1 +#define PRINTBIT 2 +#define SPACEBIT 3 +#define XDIGITBIT 4 + + +#define MASK(B) (1 << (B)) + + +/* +** add 1 to char to allow index -1 (EOZ) +*/ +#define testprop(c,p) (luai_ctype_[(c)+1] & (p)) + +/* +** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_' +*/ +#define lislalpha(c) testprop(c, MASK(ALPHABIT)) +#define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT))) +#define lisdigit(c) testprop(c, MASK(DIGITBIT)) +#define lisspace(c) testprop(c, MASK(SPACEBIT)) +#define lisprint(c) testprop(c, MASK(PRINTBIT)) +#define lisxdigit(c) testprop(c, MASK(XDIGITBIT)) + + +/* +** In ASCII, this 'ltolower' is correct for alphabetic characters and +** for '.'. That is enough for Lua needs. ('check_exp' ensures that +** the character either is an upper-case letter or is unchanged by +** the transformation, which holds for lower-case letters and '.'.) +*/ +#define ltolower(c) \ + check_exp(('A' <= (c) && (c) <= 'Z') || (c) == ((c) | ('A' ^ 'a')), \ + (c) | ('A' ^ 'a')) + + +/* one entry for each character and for -1 (EOZ) */ +LUAI_DDEC(const lu_byte luai_ctype_[UCHAR_MAX + 2];) + + +#else /* }{ */ + +/* +** use standard C ctypes +*/ + +#include <ctype.h> + + +#define lislalpha(c) (isalpha(c) || (c) == '_') +#define lislalnum(c) (isalnum(c) || (c) == '_') +#define lisdigit(c) (isdigit(c)) +#define lisspace(c) (isspace(c)) +#define lisprint(c) (isprint(c)) +#define lisxdigit(c) (isxdigit(c)) + +#define ltolower(c) (tolower(c)) + +#endif /* } */ + +#endif + diff --git a/src/libs/3rdparty/lua/src/ldblib.c b/src/libs/3rdparty/lua/src/ldblib.c new file mode 100644 index 0000000000..6dcbaa9824 --- /dev/null +++ b/src/libs/3rdparty/lua/src/ldblib.c @@ -0,0 +1,483 @@ +/* +** $Id: ldblib.c $ +** Interface from Lua to its debug API +** See Copyright Notice in lua.h +*/ + +#define ldblib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** The hook table at registry[HOOKKEY] maps threads to their current +** hook function. +*/ +static const char *const HOOKKEY = "_HOOKKEY"; + + +/* +** 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_unlikely(L != L1 && !lua_checkstack(L1, n))) + luaL_error(L, "stack overflow"); +} + + +static int db_getregistry (lua_State *L) { + lua_pushvalue(L, LUA_REGISTRYINDEX); + return 1; +} + + +static int db_getmetatable (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); /* no metatable */ + } + return 1; +} + + +static int db_setmetatable (lua_State *L) { + int t = lua_type(L, 2); + luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table"); + lua_settop(L, 2); + lua_setmetatable(L, 1); + return 1; /* return 1st argument */ +} + + +static int db_getuservalue (lua_State *L) { + int n = (int)luaL_optinteger(L, 2, 1); + if (lua_type(L, 1) != LUA_TUSERDATA) + luaL_pushfail(L); + else if (lua_getiuservalue(L, 1, n) != LUA_TNONE) { + lua_pushboolean(L, 1); + return 2; + } + return 1; +} + + +static int db_setuservalue (lua_State *L) { + int n = (int)luaL_optinteger(L, 3, 1); + luaL_checktype(L, 1, LUA_TUSERDATA); + luaL_checkany(L, 2); + lua_settop(L, 2); + if (!lua_setiuservalue(L, 1, n)) + luaL_pushfail(L); + return 1; +} + + +/* +** Auxiliary function used by several library functions: check for +** an optional thread as function's first argument and set 'arg' with +** 1 if this argument is present (so that functions can skip it to +** access their other arguments) +*/ +static lua_State *getthread (lua_State *L, int *arg) { + if (lua_isthread(L, 1)) { + *arg = 1; + return lua_tothread(L, 1); + } + else { + *arg = 0; + return L; /* function will operate over current thread */ + } +} + + +/* +** Variations of 'lua_settable', used by 'db_getinfo' to put results +** from 'lua_getinfo' into result table. Key is always a string; +** value can be a string, an int, or a boolean. +*/ +static void settabss (lua_State *L, const char *k, const char *v) { + lua_pushstring(L, v); + lua_setfield(L, -2, k); +} + +static void settabsi (lua_State *L, const char *k, int v) { + lua_pushinteger(L, v); + lua_setfield(L, -2, k); +} + +static void settabsb (lua_State *L, const char *k, int v) { + lua_pushboolean(L, v); + lua_setfield(L, -2, k); +} + + +/* +** In function 'db_getinfo', the call to 'lua_getinfo' may push +** results on the stack; later it creates the result table to put +** these objects. Function 'treatstackoption' puts the result from +** 'lua_getinfo' on top of the result table so that it can call +** 'lua_setfield'. +*/ +static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { + if (L == L1) + lua_rotate(L, -2, 1); /* exchange object and table */ + else + lua_xmove(L1, L, 1); /* move object to the "main" stack */ + lua_setfield(L, -2, fname); /* put object into 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) { + lua_Debug ar; + int arg; + lua_State *L1 = getthread(L, &arg); + const char *options = luaL_optstring(L, arg+2, "flnSrtu"); + checkstack(L, L1, 3); + luaL_argcheck(L, options[0] != '>', arg + 2, "invalid option '>'"); + if (lua_isfunction(L, arg + 1)) { /* info about a function? */ + options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */ + lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ + lua_xmove(L, L1, 1); + } + else { /* stack level */ + if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) { + luaL_pushfail(L); /* level out of range */ + return 1; + } + } + if (!lua_getinfo(L1, options, &ar)) + return luaL_argerror(L, arg+2, "invalid option"); + lua_newtable(L); /* table to collect results */ + if (strchr(options, 'S')) { + lua_pushlstring(L, ar.source, ar.srclen); + lua_setfield(L, -2, "source"); + settabss(L, "short_src", ar.short_src); + settabsi(L, "linedefined", ar.linedefined); + settabsi(L, "lastlinedefined", ar.lastlinedefined); + settabss(L, "what", ar.what); + } + if (strchr(options, 'l')) + settabsi(L, "currentline", ar.currentline); + if (strchr(options, 'u')) { + settabsi(L, "nups", ar.nups); + settabsi(L, "nparams", ar.nparams); + settabsb(L, "isvararg", ar.isvararg); + } + if (strchr(options, 'n')) { + settabss(L, "name", ar.name); + settabss(L, "namewhat", ar.namewhat); + } + if (strchr(options, 'r')) { + settabsi(L, "ftransfer", ar.ftransfer); + settabsi(L, "ntransfer", ar.ntransfer); + } + if (strchr(options, 't')) + settabsb(L, "istailcall", ar.istailcall); + if (strchr(options, 'L')) + treatstackoption(L, L1, "activelines"); + if (strchr(options, 'f')) + treatstackoption(L, L1, "func"); + return 1; /* return table */ +} + + +static int db_getlocal (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */ + if (lua_isfunction(L, arg + 1)) { /* function argument? */ + lua_pushvalue(L, arg + 1); /* push function */ + lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ + return 1; /* return only name (there is no value) */ + } + else { /* stack-level argument */ + lua_Debug ar; + const char *name; + int level = (int)luaL_checkinteger(L, arg + 1); + if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + checkstack(L, L1, 1); + name = lua_getlocal(L1, &ar, nvar); + if (name) { + lua_xmove(L1, L, 1); /* move local value */ + lua_pushstring(L, name); /* push name */ + lua_rotate(L, -2, 1); /* re-order */ + return 2; + } + else { + luaL_pushfail(L); /* no name (nor value) */ + return 1; + } + } +} + + +static int db_setlocal (lua_State *L) { + int arg; + const char *name; + lua_State *L1 = getthread(L, &arg); + lua_Debug ar; + int level = (int)luaL_checkinteger(L, arg + 1); + int nvar = (int)luaL_checkinteger(L, arg + 2); + if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + luaL_checkany(L, arg+3); + lua_settop(L, arg+3); + checkstack(L, L1, 1); + lua_xmove(L, L1, 1); + name = lua_setlocal(L1, &ar, nvar); + if (name == NULL) + lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */ + lua_pushstring(L, name); + return 1; +} + + +/* +** get (if 'get' is true) or set an upvalue from a closure +*/ +static int auxupvalue (lua_State *L, int get) { + const char *name; + int n = (int)luaL_checkinteger(L, 2); /* upvalue index */ + luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */ + name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); + if (name == NULL) return 0; + lua_pushstring(L, name); + lua_insert(L, -(get+1)); /* no-op if get is false */ + return get + 1; +} + + +static int db_getupvalue (lua_State *L) { + return auxupvalue(L, 1); +} + + +static int db_setupvalue (lua_State *L) { + luaL_checkany(L, 3); + return auxupvalue(L, 0); +} + + +/* +** Check whether a given upvalue from a given closure exists and +** returns its index +*/ +static void *checkupval (lua_State *L, int argf, int argnup, int *pnup) { + void *id; + int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */ + luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */ + id = lua_upvalueid(L, argf, nup); + if (pnup) { + luaL_argcheck(L, id != NULL, argnup, "invalid upvalue index"); + *pnup = nup; + } + return id; +} + + +static int db_upvalueid (lua_State *L) { + void *id = checkupval(L, 1, 2, NULL); + if (id != NULL) + lua_pushlightuserdata(L, id); + else + luaL_pushfail(L); + return 1; +} + + +static int db_upvaluejoin (lua_State *L) { + int n1, n2; + checkupval(L, 1, 2, &n1); + checkupval(L, 3, 4, &n2); + luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected"); + luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected"); + lua_upvaluejoin(L, 1, n1, 3, n2); + return 0; +} + + +/* +** Call hook function registered at hook table for the current +** thread (if there is one) +*/ +static void hookf (lua_State *L, lua_Debug *ar) { + static const char *const hooknames[] = + {"call", "return", "line", "count", "tail call"}; + lua_getfield(L, LUA_REGISTRYINDEX, HOOKKEY); + lua_pushthread(L); + if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */ + lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */ + if (ar->currentline >= 0) + lua_pushinteger(L, ar->currentline); /* push current line */ + else lua_pushnil(L); + lua_assert(lua_getinfo(L, "lS", ar)); + lua_call(L, 2, 0); /* call hook function */ + } +} + + +/* +** Convert a string mask (for 'sethook') into a bit mask +*/ +static int makemask (const char *smask, int count) { + int mask = 0; + if (strchr(smask, 'c')) mask |= LUA_MASKCALL; + if (strchr(smask, 'r')) mask |= LUA_MASKRET; + if (strchr(smask, 'l')) mask |= LUA_MASKLINE; + if (count > 0) mask |= LUA_MASKCOUNT; + return mask; +} + + +/* +** Convert a bit mask (for 'gethook') into a string mask +*/ +static char *unmakemask (int mask, char *smask) { + int i = 0; + if (mask & LUA_MASKCALL) smask[i++] = 'c'; + if (mask & LUA_MASKRET) smask[i++] = 'r'; + if (mask & LUA_MASKLINE) smask[i++] = 'l'; + smask[i] = '\0'; + return smask; +} + + +static int db_sethook (lua_State *L) { + int arg, mask, count; + lua_Hook func; + lua_State *L1 = getthread(L, &arg); + if (lua_isnoneornil(L, arg+1)) { /* no hook? */ + lua_settop(L, arg+1); + func = NULL; mask = 0; count = 0; /* turn off hooks */ + } + else { + const char *smask = luaL_checkstring(L, arg+2); + luaL_checktype(L, arg+1, LUA_TFUNCTION); + count = (int)luaL_optinteger(L, arg + 3, 0); + func = hookf; mask = makemask(smask, count); + } + if (!luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)) { + /* table just created; initialize it */ + lua_pushliteral(L, "k"); + lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ + lua_pushvalue(L, -1); + lua_setmetatable(L, -2); /* metatable(hooktable) = hooktable */ + } + checkstack(L, L1, 1); + lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */ + lua_pushvalue(L, arg + 1); /* value (hook function) */ + lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */ + lua_sethook(L1, func, mask, count); + return 0; +} + + +static int db_gethook (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + char buff[5]; + int mask = lua_gethookmask(L1); + lua_Hook hook = lua_gethook(L1); + if (hook == NULL) { /* no hook? */ + luaL_pushfail(L); + return 1; + } + else if (hook != hookf) /* external hook? */ + lua_pushliteral(L, "external hook"); + else { /* hook table must exist */ + lua_getfield(L, LUA_REGISTRYINDEX, HOOKKEY); + checkstack(L, L1, 1); + lua_pushthread(L1); lua_xmove(L1, L, 1); + lua_rawget(L, -2); /* 1st result = hooktable[L1] */ + lua_remove(L, -2); /* remove hook table */ + } + lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */ + lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */ + return 3; +} + + +static int db_debug (lua_State *L) { + for (;;) { + char buffer[250]; + lua_writestringerror("%s", "lua_debug> "); + if (fgets(buffer, sizeof(buffer), stdin) == NULL || + strcmp(buffer, "cont\n") == 0) + return 0; + if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || + lua_pcall(L, 0, 0, 0)) + lua_writestringerror("%s\n", luaL_tolstring(L, -1, NULL)); + lua_settop(L, 0); /* remove eventual returns */ + } +} + + +static int db_traceback (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + const char *msg = lua_tostring(L, arg + 1); + if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ + lua_pushvalue(L, arg + 1); /* return it untouched */ + else { + int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0); + luaL_traceback(L, L1, msg, level); + } + return 1; +} + + +static int db_setcstacklimit (lua_State *L) { + int limit = (int)luaL_checkinteger(L, 1); + int res = lua_setcstacklimit(L, limit); + lua_pushinteger(L, res); + return 1; +} + + +static const luaL_Reg dblib[] = { + {"debug", db_debug}, + {"getuservalue", db_getuservalue}, + {"gethook", db_gethook}, + {"getinfo", db_getinfo}, + {"getlocal", db_getlocal}, + {"getregistry", db_getregistry}, + {"getmetatable", db_getmetatable}, + {"getupvalue", db_getupvalue}, + {"upvaluejoin", db_upvaluejoin}, + {"upvalueid", db_upvalueid}, + {"setuservalue", db_setuservalue}, + {"sethook", db_sethook}, + {"setlocal", db_setlocal}, + {"setmetatable", db_setmetatable}, + {"setupvalue", db_setupvalue}, + {"traceback", db_traceback}, + {"setcstacklimit", db_setcstacklimit}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_debug (lua_State *L) { + luaL_newlib(L, dblib); + return 1; +} + diff --git a/src/libs/3rdparty/lua/src/ldebug.c b/src/libs/3rdparty/lua/src/ldebug.c new file mode 100644 index 0000000000..28b1caabf7 --- /dev/null +++ b/src/libs/3rdparty/lua/src/ldebug.c @@ -0,0 +1,924 @@ +/* +** $Id: ldebug.c $ +** Debug Interface +** See Copyright Notice in lua.h +*/ + +#define ldebug_c +#define LUA_CORE + +#include "lprefix.h" + + +#include <stdarg.h> +#include <stddef.h> +#include <string.h> + +#include "lua.h" + +#include "lapi.h" +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + + +#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) + + +static const char *funcnamefromcall (lua_State *L, CallInfo *ci, + const char **name); + + +static int currentpc (CallInfo *ci) { + lua_assert(isLua(ci)); + return pcRel(ci->u.l.savedpc, ci_func(ci)->p); +} + + +/* +** Get a "base line" to find the line corresponding to an instruction. +** Base lines are regularly placed at MAXIWTHABS intervals, so usually +** an integer division gets the right place. When the source file has +** large sequences of empty/comment lines, it may need extra entries, +** so the original estimate needs a correction. +** If the original estimate is -1, the initial 'if' ensures that the +** 'while' will run at least once. +** The assertion that the estimate is a lower bound for the correct base +** is valid as long as the debug info has been generated with the same +** value for MAXIWTHABS or smaller. (Previous releases use a little +** smaller value.) +*/ +static int getbaseline (const Proto *f, int pc, int *basepc) { + if (f->sizeabslineinfo == 0 || pc < f->abslineinfo[0].pc) { + *basepc = -1; /* start from the beginning */ + return f->linedefined; + } + else { + int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */ + /* estimate must be a lower bound of the correct base */ + lua_assert(i < 0 || + (i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc)); + while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc) + i++; /* low estimate; adjust it */ + *basepc = f->abslineinfo[i].pc; + return f->abslineinfo[i].line; + } +} + + +/* +** Get the line corresponding to instruction 'pc' in function 'f'; +** first gets a base line and from there does the increments until +** the desired instruction. +*/ +int luaG_getfuncline (const Proto *f, int pc) { + if (f->lineinfo == NULL) /* no debug information? */ + return -1; + else { + int basepc; + int baseline = getbaseline(f, pc, &basepc); + while (basepc++ < pc) { /* walk until given instruction */ + lua_assert(f->lineinfo[basepc] != ABSLINEINFO); + baseline += f->lineinfo[basepc]; /* correct line */ + } + return baseline; + } +} + + +static int getcurrentline (CallInfo *ci) { + return luaG_getfuncline(ci_func(ci)->p, currentpc(ci)); +} + + +/* +** Set 'trap' for all active Lua frames. +** This function can be called during a signal, under "reasonable" +** assumptions. A new 'ci' is completely linked in the list before it +** becomes part of the "active" list, and we assume that pointers are +** atomic; see comment in next function. +** (A compiler doing interprocedural optimizations could, theoretically, +** reorder memory writes in such a way that the list could be +** temporarily broken while inserting a new element. We simply assume it +** has no good reasons to do that.) +*/ +static void settraps (CallInfo *ci) { + for (; ci != NULL; ci = ci->previous) + if (isLua(ci)) + ci->u.l.trap = 1; +} + + +/* +** This function can be called during a signal, under "reasonable" +** assumptions. +** Fields 'basehookcount' and 'hookcount' (set by 'resethookcount') +** are for debug only, and it is no problem if they get arbitrary +** values (causes at most one wrong hook call). 'hookmask' is an atomic +** value. We assume that pointers are atomic too (e.g., gcc ensures that +** for all platforms where it runs). Moreover, 'hook' is always checked +** before being called (see 'luaD_hook'). +*/ +LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { + if (func == NULL || mask == 0) { /* turn off hooks? */ + mask = 0; + func = NULL; + } + L->hook = func; + L->basehookcount = count; + resethookcount(L); + L->hookmask = cast_byte(mask); + if (mask) + settraps(L->ci); /* to trace inside 'luaV_execute' */ +} + + +LUA_API lua_Hook lua_gethook (lua_State *L) { + return L->hook; +} + + +LUA_API int lua_gethookmask (lua_State *L) { + return L->hookmask; +} + + +LUA_API int lua_gethookcount (lua_State *L) { + return L->basehookcount; +} + + +LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { + int status; + CallInfo *ci; + if (level < 0) return 0; /* invalid (negative) level */ + lua_lock(L); + for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous) + level--; + if (level == 0 && ci != &L->base_ci) { /* level found? */ + status = 1; + ar->i_ci = ci; + } + else status = 0; /* no such level */ + lua_unlock(L); + return status; +} + + +static const char *upvalname (const Proto *p, int uv) { + TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name); + if (s == NULL) return "?"; + else return getstr(s); +} + + +static const char *findvararg (CallInfo *ci, int n, StkId *pos) { + if (clLvalue(s2v(ci->func.p))->p->is_vararg) { + int nextra = ci->u.l.nextraargs; + if (n >= -nextra) { /* 'n' is negative */ + *pos = ci->func.p - nextra - (n + 1); + return "(vararg)"; /* generic name for any vararg */ + } + } + return NULL; /* no such vararg */ +} + + +const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) { + StkId base = ci->func.p + 1; + const char *name = NULL; + if (isLua(ci)) { + if (n < 0) /* access to vararg values? */ + return findvararg(ci, n, pos); + else + name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); + } + if (name == NULL) { /* no 'standard' name? */ + StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p; + if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */ + /* generic name for any valid slot */ + name = isLua(ci) ? "(temporary)" : "(C temporary)"; + } + else + return NULL; /* no name */ + } + if (pos) + *pos = base + (n - 1); + return name; +} + + +LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { + const char *name; + lua_lock(L); + if (ar == NULL) { /* information about non-active function? */ + if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */ + name = NULL; + else /* consider live variables at function start (parameters) */ + name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0); + } + else { /* active function; get information through 'ar' */ + StkId pos = NULL; /* to avoid warnings */ + name = luaG_findlocal(L, ar->i_ci, n, &pos); + if (name) { + setobjs2s(L, L->top.p, pos); + api_incr_top(L); + } + } + lua_unlock(L); + return name; +} + + +LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { + StkId pos = NULL; /* to avoid warnings */ + const char *name; + lua_lock(L); + name = luaG_findlocal(L, ar->i_ci, n, &pos); + if (name) { + setobjs2s(L, pos, L->top.p - 1); + L->top.p--; /* pop value */ + } + lua_unlock(L); + return name; +} + + +static void funcinfo (lua_Debug *ar, Closure *cl) { + if (noLuaClosure(cl)) { + ar->source = "=[C]"; + ar->srclen = LL("=[C]"); + ar->linedefined = -1; + ar->lastlinedefined = -1; + ar->what = "C"; + } + else { + const Proto *p = cl->l.p; + if (p->source) { + ar->source = getstr(p->source); + ar->srclen = tsslen(p->source); + } + else { + ar->source = "=?"; + ar->srclen = LL("=?"); + } + ar->linedefined = p->linedefined; + ar->lastlinedefined = p->lastlinedefined; + ar->what = (ar->linedefined == 0) ? "main" : "Lua"; + } + luaO_chunkid(ar->short_src, ar->source, ar->srclen); +} + + +static int nextline (const Proto *p, int currentline, int pc) { + if (p->lineinfo[pc] != ABSLINEINFO) + return currentline + p->lineinfo[pc]; + else + return luaG_getfuncline(p, pc); +} + + +static void collectvalidlines (lua_State *L, Closure *f) { + if (noLuaClosure(f)) { + setnilvalue(s2v(L->top.p)); + api_incr_top(L); + } + else { + int i; + TValue v; + const Proto *p = f->l.p; + int currentline = p->linedefined; + Table *t = luaH_new(L); /* new table to store active lines */ + sethvalue2s(L, L->top.p, t); /* push it on stack */ + api_incr_top(L); + setbtvalue(&v); /* boolean 'true' to be the value of all indices */ + if (!p->is_vararg) /* regular function? */ + i = 0; /* consider all instructions */ + else { /* vararg function */ + lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); + currentline = nextline(p, currentline, 0); + i = 1; /* skip first instruction (OP_VARARGPREP) */ + } + for (; i < p->sizelineinfo; i++) { /* for each instruction */ + currentline = nextline(p, currentline, i); /* get its line */ + luaH_setint(L, t, currentline, &v); /* table[line] = true */ + } + } +} + + +static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { + /* calling function is a known function? */ + if (ci != NULL && !(ci->callstatus & CIST_TAIL)) + return funcnamefromcall(L, ci->previous, name); + else return NULL; /* no way to find a name */ +} + + +static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, + Closure *f, CallInfo *ci) { + int status = 1; + for (; *what; what++) { + switch (*what) { + case 'S': { + funcinfo(ar, f); + break; + } + case 'l': { + ar->currentline = (ci && isLua(ci)) ? getcurrentline(ci) : -1; + break; + } + case 'u': { + ar->nups = (f == NULL) ? 0 : f->c.nupvalues; + if (noLuaClosure(f)) { + ar->isvararg = 1; + ar->nparams = 0; + } + else { + ar->isvararg = f->l.p->is_vararg; + ar->nparams = f->l.p->numparams; + } + break; + } + case 't': { + ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0; + break; + } + case 'n': { + ar->namewhat = getfuncname(L, ci, &ar->name); + if (ar->namewhat == NULL) { + ar->namewhat = ""; /* not found */ + ar->name = NULL; + } + break; + } + case 'r': { + if (ci == NULL || !(ci->callstatus & CIST_TRAN)) + ar->ftransfer = ar->ntransfer = 0; + else { + ar->ftransfer = ci->u2.transferinfo.ftransfer; + ar->ntransfer = ci->u2.transferinfo.ntransfer; + } + break; + } + case 'L': + case 'f': /* handled by lua_getinfo */ + break; + default: status = 0; /* invalid option */ + } + } + return status; +} + + +LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { + int status; + Closure *cl; + CallInfo *ci; + TValue *func; + lua_lock(L); + if (*what == '>') { + ci = NULL; + func = s2v(L->top.p - 1); + api_check(L, ttisfunction(func), "function expected"); + what++; /* skip the '>' */ + L->top.p--; /* pop function */ + } + else { + ci = ar->i_ci; + func = s2v(ci->func.p); + lua_assert(ttisfunction(func)); + } + cl = ttisclosure(func) ? clvalue(func) : NULL; + status = auxgetinfo(L, what, ar, cl, ci); + if (strchr(what, 'f')) { + setobj2s(L, L->top.p, func); + api_incr_top(L); + } + if (strchr(what, 'L')) + collectvalidlines(L, cl); + lua_unlock(L); + return status; +} + + +/* +** {====================================================== +** Symbolic Execution +** ======================================================= +*/ + +static const char *getobjname (const Proto *p, int lastpc, int reg, + const char **name); + + +/* +** Find a "name" for the constant 'c'. +*/ +static void kname (const Proto *p, int c, const char **name) { + TValue *kvalue = &p->k[c]; + *name = (ttisstring(kvalue)) ? svalue(kvalue) : "?"; +} + + +/* +** Find a "name" for the register 'c'. +*/ +static void rname (const Proto *p, int pc, int c, const char **name) { + const char *what = getobjname(p, pc, c, name); /* search for 'c' */ + if (!(what && *what == 'c')) /* did not find a constant name? */ + *name = "?"; +} + + +/* +** Find a "name" for a 'C' value in an RK instruction. +*/ +static void rkname (const Proto *p, int pc, Instruction i, const char **name) { + int c = GETARG_C(i); /* key index */ + if (GETARG_k(i)) /* is 'c' a constant? */ + kname(p, c, name); + else /* 'c' is a register */ + rname(p, pc, c, name); +} + + +static int filterpc (int pc, int jmptarget) { + if (pc < jmptarget) /* is code conditional (inside a jump)? */ + return -1; /* cannot know who sets that register */ + else return pc; /* current position sets that register */ +} + + +/* +** Try to find last instruction before 'lastpc' that modified register 'reg'. +*/ +static int findsetreg (const Proto *p, int lastpc, int reg) { + int pc; + int setreg = -1; /* keep last instruction that changed 'reg' */ + int jmptarget = 0; /* any code before this address is conditional */ + if (testMMMode(GET_OPCODE(p->code[lastpc]))) + lastpc--; /* previous instruction was not actually executed */ + for (pc = 0; pc < lastpc; pc++) { + Instruction i = p->code[pc]; + OpCode op = GET_OPCODE(i); + int a = GETARG_A(i); + int change; /* true if current instruction changed 'reg' */ + switch (op) { + case OP_LOADNIL: { /* set registers from 'a' to 'a+b' */ + int b = GETARG_B(i); + change = (a <= reg && reg <= a + b); + break; + } + case OP_TFORCALL: { /* affect all regs above its base */ + change = (reg >= a + 2); + break; + } + case OP_CALL: + case OP_TAILCALL: { /* affect all registers above base */ + change = (reg >= a); + break; + } + case OP_JMP: { /* doesn't change registers, but changes 'jmptarget' */ + int b = GETARG_sJ(i); + int dest = pc + 1 + b; + /* jump does not skip 'lastpc' and is larger than current one? */ + if (dest <= lastpc && dest > jmptarget) + jmptarget = dest; /* update 'jmptarget' */ + change = 0; + break; + } + default: /* any instruction that sets A */ + change = (testAMode(op) && reg == a); + break; + } + if (change) + setreg = filterpc(pc, jmptarget); + } + return setreg; +} + + +/* +** Check whether table being indexed by instruction 'i' is the +** environment '_ENV' +*/ +static const char *gxf (const Proto *p, int pc, Instruction i, int isup) { + int t = GETARG_B(i); /* table index */ + const char *name; /* name of indexed variable */ + if (isup) /* is an upvalue? */ + name = upvalname(p, t); + else + getobjname(p, pc, t, &name); + return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field"; +} + + +static const char *getobjname (const Proto *p, int lastpc, int reg, + const char **name) { + int pc; + *name = luaF_getlocalname(p, reg + 1, lastpc); + if (*name) /* is a local? */ + return "local"; + /* else try symbolic execution */ + pc = findsetreg(p, lastpc, reg); + if (pc != -1) { /* could find instruction? */ + Instruction i = p->code[pc]; + OpCode op = GET_OPCODE(i); + switch (op) { + case OP_MOVE: { + int b = GETARG_B(i); /* move from 'b' to 'a' */ + if (b < GETARG_A(i)) + return getobjname(p, pc, b, name); /* get name for 'b' */ + break; + } + case OP_GETTABUP: { + int k = GETARG_C(i); /* key index */ + kname(p, k, name); + return gxf(p, pc, i, 1); + } + case OP_GETTABLE: { + int k = GETARG_C(i); /* key index */ + rname(p, pc, k, name); + return gxf(p, pc, i, 0); + } + case OP_GETI: { + *name = "integer index"; + return "field"; + } + case OP_GETFIELD: { + int k = GETARG_C(i); /* key index */ + kname(p, k, name); + return gxf(p, pc, i, 0); + } + case OP_GETUPVAL: { + *name = upvalname(p, GETARG_B(i)); + return "upvalue"; + } + case OP_LOADK: + case OP_LOADKX: { + int b = (op == OP_LOADK) ? GETARG_Bx(i) + : GETARG_Ax(p->code[pc + 1]); + if (ttisstring(&p->k[b])) { + *name = svalue(&p->k[b]); + return "constant"; + } + break; + } + case OP_SELF: { + rkname(p, pc, i, name); + return "method"; + } + default: break; /* go through to return NULL */ + } + } + return NULL; /* could not find reasonable name */ +} + + +/* +** 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, const Proto *p, + int pc, const char **name) { + TMS tm = (TMS)0; /* (initial value avoids warnings) */ + Instruction i = p->code[pc]; /* calling instruction */ + switch (GET_OPCODE(i)) { + case OP_CALL: + case OP_TAILCALL: + return getobjname(p, pc, GETARG_A(i), name); /* get function name */ + case OP_TFORCALL: { /* for iterator */ + *name = "for iterator"; + return "for iterator"; + } + /* other instructions can do calls through metamethods */ + case OP_SELF: case OP_GETTABUP: case OP_GETTABLE: + case OP_GETI: case OP_GETFIELD: + tm = TM_INDEX; + break; + case OP_SETTABUP: case OP_SETTABLE: case OP_SETI: case OP_SETFIELD: + tm = TM_NEWINDEX; + break; + case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: { + tm = cast(TMS, GETARG_C(i)); + break; + } + case OP_UNM: tm = TM_UNM; break; + case OP_BNOT: tm = TM_BNOT; break; + case OP_LEN: tm = TM_LEN; break; + case OP_CONCAT: tm = TM_CONCAT; break; + case OP_EQ: tm = TM_EQ; break; + /* no cases for OP_EQI and OP_EQK, as they don't call metamethods */ + case OP_LT: case OP_LTI: case OP_GTI: tm = TM_LT; break; + case OP_LE: case OP_LEI: case OP_GEI: tm = TM_LE; break; + case OP_CLOSE: case OP_RETURN: tm = TM_CLOSE; break; + default: + return NULL; /* cannot find a reasonable name */ + } + *name = getstr(G(L)->tmname[tm]) + 2; + return "metamethod"; +} + + +/* +** Try to find a name for a function based on how it was called. +*/ +static const char *funcnamefromcall (lua_State *L, CallInfo *ci, + const char **name) { + if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ + *name = "?"; + return "hook"; + } + else if (ci->callstatus & CIST_FIN) { /* was it called as a finalizer? */ + *name = "__gc"; + return "metamethod"; /* report it as such */ + } + else if (isLua(ci)) + return funcnamefromcode(L, ci_func(ci)->p, currentpc(ci), name); + else + return NULL; +} + +/* }====================================================== */ + + + +/* +** Check whether pointer 'o' points to some value in the stack frame of +** the current function and, if so, returns its index. Because 'o' may +** not point to a value in this stack, we cannot compare it with the +** region boundaries (undefined behavior in ISO C). +*/ +static int instack (CallInfo *ci, const TValue *o) { + int pos; + StkId base = ci->func.p + 1; + for (pos = 0; base + pos < ci->top.p; pos++) { + if (o == s2v(base + pos)) + return pos; + } + return -1; /* not found */ +} + + +/* +** Checks whether value 'o' came from an upvalue. (That can only happen +** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on +** upvalues.) +*/ +static const char *getupvalname (CallInfo *ci, const TValue *o, + const char **name) { + LClosure *c = ci_func(ci); + int i; + for (i = 0; i < c->nupvalues; i++) { + if (c->upvals[i]->v.p == o) { + *name = upvalname(c->p, i); + return "upvalue"; + } + } + return NULL; +} + + +static const char *formatvarinfo (lua_State *L, const char *kind, + const char *name) { + if (kind == NULL) + return ""; /* no information */ + else + return luaO_pushfstring(L, " (%s '%s')", kind, name); +} + +/* +** Build a string with a "description" for the value 'o', such as +** "variable 'x'" or "upvalue 'y'". +*/ +static const char *varinfo (lua_State *L, const TValue *o) { + CallInfo *ci = L->ci; + const char *name = NULL; /* to avoid warnings */ + const char *kind = NULL; + if (isLua(ci)) { + kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ + if (!kind) { /* not an upvalue? */ + int reg = instack(ci, o); /* try a register */ + if (reg >= 0) /* is 'o' a register? */ + kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name); + } + } + return formatvarinfo(L, kind, name); +} + + +/* +** Raise a type error +*/ +static l_noret typeerror (lua_State *L, const TValue *o, const char *op, + const char *extra) { + const char *t = luaT_objtypename(L, o); + luaG_runerror(L, "attempt to %s a %s value%s", op, t, extra); +} + + +/* +** Raise a type error with "standard" information about the faulty +** object 'o' (using 'varinfo'). +*/ +l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { + typeerror(L, o, op, varinfo(L, o)); +} + + +/* +** Raise an error for calling a non-callable object. Try to find a name +** for the object based on how it was called ('funcnamefromcall'); if it +** cannot get a name there, try 'varinfo'. +*/ +l_noret luaG_callerror (lua_State *L, const TValue *o) { + CallInfo *ci = L->ci; + const char *name = NULL; /* to avoid warnings */ + const char *kind = funcnamefromcall(L, ci, &name); + const char *extra = kind ? formatvarinfo(L, kind, name) : varinfo(L, o); + typeerror(L, o, "call", extra); +} + + +l_noret luaG_forerror (lua_State *L, const TValue *o, const char *what) { + luaG_runerror(L, "bad 'for' %s (number expected, got %s)", + what, luaT_objtypename(L, o)); +} + + +l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) { + if (ttisstring(p1) || cvt2str(p1)) p1 = p2; + luaG_typeerror(L, p1, "concatenate"); +} + + +l_noret luaG_opinterror (lua_State *L, const TValue *p1, + const TValue *p2, const char *msg) { + if (!ttisnumber(p1)) /* first operand is wrong? */ + p2 = p1; /* now second is wrong */ + luaG_typeerror(L, p2, msg); +} + + +/* +** Error when both values are convertible to numbers, but not to integers +*/ +l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) { + lua_Integer temp; + if (!luaV_tointegerns(p1, &temp, LUA_FLOORN2I)) + p2 = p1; + luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2)); +} + + +l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { + const char *t1 = luaT_objtypename(L, p1); + const char *t2 = luaT_objtypename(L, p2); + if (strcmp(t1, t2) == 0) + luaG_runerror(L, "attempt to compare two %s values", t1); + else + luaG_runerror(L, "attempt to compare %s with %s", t1, t2); +} + + +/* add src:line information to 'msg' */ +const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, + int line) { + char buff[LUA_IDSIZE]; + if (src) + luaO_chunkid(buff, getstr(src), tsslen(src)); + else { /* no source available; use "?" instead */ + buff[0] = '?'; buff[1] = '\0'; + } + return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); +} + + +l_noret luaG_errormsg (lua_State *L) { + if (L->errfunc != 0) { /* is there an error handling function? */ + StkId errfunc = restorestack(L, L->errfunc); + lua_assert(ttisfunction(s2v(errfunc))); + setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */ + setobjs2s(L, L->top.p - 1, errfunc); /* push function */ + L->top.p++; /* assume EXTRA_STACK */ + luaD_callnoyield(L, L->top.p - 2, 1); /* call it */ + } + luaD_throw(L, LUA_ERRRUN); +} + + +l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { + CallInfo *ci = L->ci; + const char *msg; + va_list argp; + luaC_checkGC(L); /* error message uses memory */ + va_start(argp, fmt); + msg = luaO_pushvfstring(L, fmt, argp); /* format message */ + va_end(argp); + if (isLua(ci)) { /* if Lua function, add source:line information */ + luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci)); + setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */ + L->top.p--; + } + luaG_errormsg(L); +} + + +/* +** Check whether new instruction 'newpc' is in a different line from +** previous instruction 'oldpc'. More often than not, 'newpc' is only +** one or a few instructions after 'oldpc' (it must be after, see +** caller), so try to avoid calling 'luaG_getfuncline'. If they are +** too far apart, there is a good chance of a ABSLINEINFO in the way, +** so it goes directly to 'luaG_getfuncline'. +*/ +static int changedline (const Proto *p, int oldpc, int newpc) { + if (p->lineinfo == NULL) /* no debug information? */ + return 0; + if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */ + int delta = 0; /* line difference */ + int pc = oldpc; + for (;;) { + int lineinfo = p->lineinfo[++pc]; + if (lineinfo == ABSLINEINFO) + break; /* cannot compute delta; fall through */ + delta += lineinfo; + if (pc == newpc) + return (delta != 0); /* delta computed successfully */ + } + } + /* either instructions are too far apart or there is an absolute line + info in the way; compute line difference explicitly */ + return (luaG_getfuncline(p, oldpc) != luaG_getfuncline(p, newpc)); +} + + +/* +** Traces the execution of a Lua function. Called before the execution +** of each opcode, when debug is on. 'L->oldpc' stores the last +** instruction traced, to detect line changes. When entering a new +** function, 'npci' will be zero and will test as a new line whatever +** the value of 'oldpc'. Some exceptional conditions may return to +** a function without setting 'oldpc'. In that case, 'oldpc' may be +** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc' +** at most causes an extra call to a line hook.) +** This function is not "Protected" when called, so it should correct +** 'L->top.p' before calling anything that can run the GC. +*/ +int luaG_traceexec (lua_State *L, const Instruction *pc) { + CallInfo *ci = L->ci; + lu_byte mask = L->hookmask; + const Proto *p = ci_func(ci)->p; + int counthook; + if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */ + ci->u.l.trap = 0; /* don't need to stop again */ + return 0; /* turn off 'trap' */ + } + pc++; /* reference is always next instruction */ + ci->u.l.savedpc = pc; /* save 'pc' */ + counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); + if (counthook) + resethookcount(L); /* reset count */ + else if (!(mask & LUA_MASKLINE)) + return 1; /* no line hook and count != 0; nothing to be done now */ + if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ + ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ + return 1; /* do not call hook again (VM yielded, so it did not move) */ + } + if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */ + L->top.p = ci->top.p; /* correct top */ + if (counthook) + luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */ + if (mask & LUA_MASKLINE) { + /* 'L->oldpc' may be invalid; use zero in this case */ + int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0; + int npci = pcRel(pc, p); + if (npci <= oldpc || /* call hook when jump back (loop), */ + changedline(p, oldpc, npci)) { /* or when enter new line */ + int newline = luaG_getfuncline(p, npci); + luaD_hook(L, LUA_HOOKLINE, newline, 0, 0); /* call line hook */ + } + L->oldpc = npci; /* 'pc' of last call to line hook */ + } + if (L->status == LUA_YIELD) { /* did hook yield? */ + if (counthook) + L->hookcount = 1; /* undo decrement to zero */ + ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ + ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ + luaD_throw(L, LUA_YIELD); + } + return 1; /* keep 'trap' on */ +} + diff --git a/src/libs/3rdparty/lua/src/ldebug.h b/src/libs/3rdparty/lua/src/ldebug.h new file mode 100644 index 0000000000..2c3074c61b --- /dev/null +++ b/src/libs/3rdparty/lua/src/ldebug.h @@ -0,0 +1,63 @@ +/* +** $Id: ldebug.h $ +** Auxiliary functions from Debug Interface module +** See Copyright Notice in lua.h +*/ + +#ifndef ldebug_h +#define ldebug_h + + +#include "lstate.h" + + +#define pcRel(pc, p) (cast_int((pc) - (p)->code) - 1) + + +/* Active Lua function (given call info) */ +#define ci_func(ci) (clLvalue(s2v((ci)->func.p))) + + +#define resethookcount(L) (L->hookcount = L->basehookcount) + +/* +** mark for entries in 'lineinfo' array that has absolute information in +** 'abslineinfo' array +*/ +#define ABSLINEINFO (-0x80) + + +/* +** MAXimum number of successive Instructions WiTHout ABSolute line +** information. (A power of two allows fast divisions.) +*/ +#if !defined(MAXIWTHABS) +#define MAXIWTHABS 128 +#endif + + +LUAI_FUNC int luaG_getfuncline (const Proto *f, int pc); +LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, + StkId *pos); +LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, + const char *opname); +LUAI_FUNC l_noret luaG_callerror (lua_State *L, const TValue *o); +LUAI_FUNC l_noret luaG_forerror (lua_State *L, const TValue *o, + const char *what); +LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1, + const TValue *p2, + const char *msg); +LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); +LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, + TString *src, int line); +LUAI_FUNC l_noret luaG_errormsg (lua_State *L); +LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc); + + +#endif diff --git a/src/libs/3rdparty/lua/src/ldo.c b/src/libs/3rdparty/lua/src/ldo.c new file mode 100644 index 0000000000..2a0017ca62 --- /dev/null +++ b/src/libs/3rdparty/lua/src/ldo.c @@ -0,0 +1,1024 @@ +/* +** $Id: ldo.c $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + +#define ldo_c +#define LUA_CORE + +#include "lprefix.h" + + +#include <setjmp.h> +#include <stdlib.h> +#include <string.h> + +#include "lua.h" + +#include "lapi.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lundump.h" +#include "lvm.h" +#include "lzio.h" + + + +#define errorstatus(s) ((s) > LUA_YIELD) + + +/* +** {====================================================== +** Error-recovery functions +** ======================================================= +*/ + +/* +** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By +** default, Lua handles errors with exceptions when compiling as +** C++ code, with _longjmp/_setjmp when asked to use them, and with +** longjmp/setjmp otherwise. +*/ +#if !defined(LUAI_THROW) /* { */ + +#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* { */ + +/* C++ exceptions */ +#define LUAI_THROW(L,c) throw(c) +#define LUAI_TRY(L,c,a) \ + try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; } +#define luai_jmpbuf int /* dummy variable */ + +#elif defined(LUA_USE_POSIX) /* }{ */ + +/* in POSIX, try _longjmp/_setjmp (more efficient) */ +#define LUAI_THROW(L,c) _longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf + +#else /* }{ */ + +/* ISO C handling with long jumps */ +#define LUAI_THROW(L,c) longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf + +#endif /* } */ + +#endif /* } */ + + + +/* chain list of long jump buffers */ +struct lua_longjmp { + struct lua_longjmp *previous; + luai_jmpbuf b; + volatile int status; /* error code */ +}; + + +void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { + switch (errcode) { + case LUA_ERRMEM: { /* memory error? */ + setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ + break; + } + case LUA_ERRERR: { + setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); + break; + } + case LUA_OK: { /* special case only for closing upvalues */ + setnilvalue(s2v(oldtop)); /* no error message */ + break; + } + default: { + lua_assert(errorstatus(errcode)); /* real error */ + setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */ + break; + } + } + L->top.p = oldtop + 1; +} + + +l_noret luaD_throw (lua_State *L, int errcode) { + if (L->errorJmp) { /* thread has an error handler? */ + L->errorJmp->status = errcode; /* set status */ + LUAI_THROW(L, L->errorJmp); /* jump to it */ + } + else { /* thread has no error handler */ + global_State *g = G(L); + errcode = luaE_resetthread(L, errcode); /* close all upvalues */ + if (g->mainthread->errorJmp) { /* main thread has a handler? */ + setobjs2s(L, g->mainthread->top.p++, L->top.p - 1); /* copy error obj. */ + luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ + } + else { /* no handler at all; abort */ + if (g->panic) { /* panic function? */ + lua_unlock(L); + g->panic(L); /* call panic function (last chance to jump out) */ + } + abort(); + } + } +} + + +int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { + l_uint32 oldnCcalls = L->nCcalls; + struct lua_longjmp lj; + lj.status = LUA_OK; + lj.previous = L->errorJmp; /* chain new error handler */ + L->errorJmp = &lj; + LUAI_TRY(L, &lj, + (*f)(L, ud); + ); + L->errorJmp = lj.previous; /* restore old error handler */ + L->nCcalls = oldnCcalls; + return lj.status; +} + +/* }====================================================== */ + + +/* +** {================================================================== +** Stack reallocation +** =================================================================== +*/ + + +/* +** Change all pointers to the stack into offsets. +*/ +static void relstack (lua_State *L) { + CallInfo *ci; + UpVal *up; + L->top.offset = savestack(L, L->top.p); + L->tbclist.offset = savestack(L, L->tbclist.p); + for (up = L->openupval; up != NULL; up = up->u.open.next) + up->v.offset = savestack(L, uplevel(up)); + for (ci = L->ci; ci != NULL; ci = ci->previous) { + ci->top.offset = savestack(L, ci->top.p); + ci->func.offset = savestack(L, ci->func.p); + } +} + + +/* +** Change back all offsets into pointers. +*/ +static void correctstack (lua_State *L) { + CallInfo *ci; + UpVal *up; + L->top.p = restorestack(L, L->top.offset); + L->tbclist.p = restorestack(L, L->tbclist.offset); + for (up = L->openupval; up != NULL; up = up->u.open.next) + up->v.p = s2v(restorestack(L, up->v.offset)); + for (ci = L->ci; ci != NULL; ci = ci->previous) { + ci->top.p = restorestack(L, ci->top.offset); + ci->func.p = restorestack(L, ci->func.offset); + if (isLua(ci)) + ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */ + } +} + + +/* some space for error handling */ +#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) + +/* +** Reallocate the stack to a new size, correcting all pointers into it. +** In ISO C, any pointer use after the pointer has been deallocated is +** undefined behavior. So, before the reallocation, all pointers are +** changed to offsets, and after the reallocation they are changed back +** to pointers. As during the reallocation the pointers are invalid, the +** reallocation cannot run emergency collections. +** +** In case of allocation error, raise an error or return false according +** to 'raiseerror'. +*/ +int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { + int oldsize = stacksize(L); + int i; + StkId newstack; + int oldgcstop = G(L)->gcstopem; + lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); + relstack(L); /* change pointers to offsets */ + G(L)->gcstopem = 1; /* stop emergency collection */ + newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK, + newsize + EXTRA_STACK, StackValue); + G(L)->gcstopem = oldgcstop; /* restore emergency collection */ + if (l_unlikely(newstack == NULL)) { /* reallocation failed? */ + correctstack(L); /* change offsets back to pointers */ + if (raiseerror) + luaM_error(L); + else return 0; /* do not raise an error */ + } + L->stack.p = newstack; + correctstack(L); /* change offsets back to pointers */ + L->stack_last.p = L->stack.p + newsize; + for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++) + setnilvalue(s2v(newstack + i)); /* erase new segment */ + return 1; +} + + +/* +** Try to grow the stack by at least 'n' elements. When 'raiseerror' +** is true, raises any error; otherwise, return 0 in case of errors. +*/ +int luaD_growstack (lua_State *L, int n, int raiseerror) { + int size = stacksize(L); + if (l_unlikely(size > LUAI_MAXSTACK)) { + /* if stack is larger than maximum, thread is already using the + extra space reserved for errors, that is, thread is handling + a stack error; cannot grow further than that. */ + lua_assert(stacksize(L) == ERRORSTACKSIZE); + if (raiseerror) + luaD_throw(L, LUA_ERRERR); /* error inside message handler */ + return 0; /* if not 'raiseerror', just signal it */ + } + else if (n < LUAI_MAXSTACK) { /* avoids arithmetic overflows */ + int newsize = 2 * size; /* tentative new size */ + int needed = cast_int(L->top.p - L->stack.p) + n; + if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */ + newsize = LUAI_MAXSTACK; + if (newsize < needed) /* but must respect what was asked for */ + newsize = needed; + if (l_likely(newsize <= LUAI_MAXSTACK)) + return luaD_reallocstack(L, newsize, raiseerror); + } + /* else stack overflow */ + /* add extra size to be able to handle the error message */ + luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror); + if (raiseerror) + luaG_runerror(L, "stack overflow"); + return 0; +} + + +/* +** Compute how much of the stack is being used, by computing the +** maximum top of all call frames in the stack and the current top. +*/ +static int stackinuse (lua_State *L) { + CallInfo *ci; + int res; + StkId lim = L->top.p; + for (ci = L->ci; ci != NULL; ci = ci->previous) { + if (lim < ci->top.p) lim = ci->top.p; + } + lua_assert(lim <= L->stack_last.p + EXTRA_STACK); + res = cast_int(lim - L->stack.p) + 1; /* part of stack in use */ + if (res < LUA_MINSTACK) + res = LUA_MINSTACK; /* ensure a minimum size */ + return res; +} + + +/* +** If stack size is more than 3 times the current use, reduce that size +** to twice the current use. (So, the final stack size is at most 2/3 the +** previous size, and half of its entries are empty.) +** As a particular case, if stack was handling a stack overflow and now +** it is not, 'max' (limited by LUAI_MAXSTACK) will be smaller than +** stacksize (equal to ERRORSTACKSIZE in this case), and so the stack +** will be reduced to a "regular" size. +*/ +void luaD_shrinkstack (lua_State *L) { + int inuse = stackinuse(L); + int max = (inuse > LUAI_MAXSTACK / 3) ? LUAI_MAXSTACK : inuse * 3; + /* if thread is currently not handling a stack overflow and its + size is larger than maximum "reasonable" size, shrink it */ + if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) { + int nsize = (inuse > LUAI_MAXSTACK / 2) ? LUAI_MAXSTACK : inuse * 2; + luaD_reallocstack(L, nsize, 0); /* ok if that fails */ + } + else /* don't change stack */ + condmovestack(L,{},{}); /* (change only for debugging) */ + luaE_shrinkCI(L); /* shrink CI list */ +} + + +void luaD_inctop (lua_State *L) { + luaD_checkstack(L, 1); + L->top.p++; +} + +/* }================================================================== */ + + +/* +** Call a hook for the given event. Make sure there is a hook to be +** called. (Both 'L->hook' and 'L->hookmask', which trigger this +** function, can be changed asynchronously by signals.) +*/ +void luaD_hook (lua_State *L, int event, int line, + int ftransfer, int ntransfer) { + lua_Hook hook = L->hook; + if (hook && L->allowhook) { /* make sure there is a hook */ + int mask = CIST_HOOKED; + CallInfo *ci = L->ci; + ptrdiff_t top = savestack(L, L->top.p); /* preserve original 'top' */ + ptrdiff_t ci_top = savestack(L, ci->top.p); /* idem for 'ci->top' */ + lua_Debug ar; + ar.event = event; + ar.currentline = line; + ar.i_ci = ci; + if (ntransfer != 0) { + mask |= CIST_TRAN; /* 'ci' has transfer information */ + ci->u2.transferinfo.ftransfer = ftransfer; + ci->u2.transferinfo.ntransfer = ntransfer; + } + if (isLua(ci) && L->top.p < ci->top.p) + L->top.p = ci->top.p; /* protect entire activation register */ + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + if (ci->top.p < L->top.p + LUA_MINSTACK) + ci->top.p = L->top.p + LUA_MINSTACK; + L->allowhook = 0; /* cannot call hooks inside a hook */ + ci->callstatus |= mask; + lua_unlock(L); + (*hook)(L, &ar); + lua_lock(L); + lua_assert(!L->allowhook); + L->allowhook = 1; + ci->top.p = restorestack(L, ci_top); + L->top.p = restorestack(L, top); + ci->callstatus &= ~mask; + } +} + + +/* +** Executes a call hook for Lua functions. This function is called +** whenever 'hookmask' is not zero, so it checks whether call hooks are +** active. +*/ +void luaD_hookcall (lua_State *L, CallInfo *ci) { + L->oldpc = 0; /* set 'oldpc' for new function */ + if (L->hookmask & LUA_MASKCALL) { /* is call hook on? */ + int event = (ci->callstatus & CIST_TAIL) ? LUA_HOOKTAILCALL + : LUA_HOOKCALL; + Proto *p = ci_func(ci)->p; + ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ + luaD_hook(L, event, -1, 1, p->numparams); + ci->u.l.savedpc--; /* correct 'pc' */ + } +} + + +/* +** Executes a return hook for Lua and C functions and sets/corrects +** 'oldpc'. (Note that this correction is needed by the line hook, so it +** is done even when return hooks are off.) +*/ +static void rethook (lua_State *L, CallInfo *ci, int nres) { + if (L->hookmask & LUA_MASKRET) { /* is return hook on? */ + StkId firstres = L->top.p - nres; /* index of first result */ + int delta = 0; /* correction for vararg functions */ + int ftransfer; + if (isLua(ci)) { + Proto *p = ci_func(ci)->p; + if (p->is_vararg) + delta = ci->u.l.nextraargs + p->numparams + 1; + } + ci->func.p += delta; /* if vararg, back to virtual 'func' */ + ftransfer = cast(unsigned short, firstres - ci->func.p); + luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */ + ci->func.p -= delta; + } + if (isLua(ci = ci->previous)) + L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */ +} + + +/* +** Check whether 'func' has a '__call' metafield. If so, put it in the +** stack, below original 'func', so that 'luaD_precall' can call it. Raise +** an error if there is no '__call' metafield. +*/ +StkId luaD_tryfuncTM (lua_State *L, StkId func) { + const TValue *tm; + StkId p; + checkstackGCp(L, 1, func); /* space for metamethod */ + tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */ + if (l_unlikely(ttisnil(tm))) + luaG_callerror(L, s2v(func)); /* nothing to call */ + for (p = L->top.p; p > func; p--) /* open space for metamethod */ + setobjs2s(L, p, p-1); + L->top.p++; /* stack space pre-allocated by the caller */ + setobj2s(L, func, tm); /* metamethod is the new function to be called */ + return func; +} + + +/* +** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'. +** Handle most typical cases (zero results for commands, one result for +** expressions, multiple results for tail calls/single parameters) +** separated. +*/ +l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) { + StkId firstresult; + int i; + switch (wanted) { /* handle typical cases separately */ + case 0: /* no values needed */ + L->top.p = res; + return; + case 1: /* one value needed */ + if (nres == 0) /* no results? */ + setnilvalue(s2v(res)); /* adjust with nil */ + else /* at least one result */ + setobjs2s(L, res, L->top.p - nres); /* move it to proper place */ + L->top.p = res + 1; + return; + case LUA_MULTRET: + wanted = nres; /* we want all results */ + break; + default: /* two/more results and/or to-be-closed variables */ + if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */ + L->ci->callstatus |= CIST_CLSRET; /* in case of yields */ + L->ci->u2.nres = nres; + res = luaF_close(L, res, CLOSEKTOP, 1); + L->ci->callstatus &= ~CIST_CLSRET; + if (L->hookmask) { /* if needed, call hook after '__close's */ + ptrdiff_t savedres = savestack(L, res); + rethook(L, L->ci, nres); + res = restorestack(L, savedres); /* hook can move stack */ + } + wanted = decodeNresults(wanted); + if (wanted == LUA_MULTRET) + wanted = nres; /* we want all results */ + } + break; + } + /* generic case */ + firstresult = L->top.p - nres; /* index of first result */ + if (nres > wanted) /* extra results? */ + nres = wanted; /* don't need them */ + for (i = 0; i < nres; i++) /* move all results to correct place */ + setobjs2s(L, res + i, firstresult + i); + for (; i < wanted; i++) /* complete wanted number of results */ + setnilvalue(s2v(res + i)); + L->top.p = res + wanted; /* top points after the last result */ +} + + +/* +** Finishes a function call: calls hook if necessary, moves current +** number of results to proper place, and returns to previous call +** info. If function has to close variables, hook must be called after +** that. +*/ +void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { + int wanted = ci->nresults; + if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted))) + rethook(L, ci, nres); + /* move results to proper place */ + moveresults(L, ci->func.p, nres, wanted); + /* function cannot be in any of these cases when returning */ + lua_assert(!(ci->callstatus & + (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET))); + L->ci = ci->previous; /* back to caller (after closing variables) */ +} + + + +#define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L)) + + +l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret, + int mask, StkId top) { + CallInfo *ci = L->ci = next_ci(L); /* new frame */ + ci->func.p = func; + ci->nresults = nret; + ci->callstatus = mask; + ci->top.p = top; + return ci; +} + + +/* +** precall for C functions +*/ +l_sinline int precallC (lua_State *L, StkId func, int nresults, + lua_CFunction f) { + int n; /* number of returns */ + CallInfo *ci; + checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ + L->ci = ci = prepCallInfo(L, func, nresults, CIST_C, + L->top.p + LUA_MINSTACK); + lua_assert(ci->top.p <= L->stack_last.p); + if (l_unlikely(L->hookmask & LUA_MASKCALL)) { + int narg = cast_int(L->top.p - func) - 1; + luaD_hook(L, LUA_HOOKCALL, -1, 1, narg); + } + lua_unlock(L); + n = (*f)(L); /* do the actual call */ + lua_lock(L); + api_checknelems(L, n); + luaD_poscall(L, ci, n); + return n; +} + + +/* +** Prepare a function for a tail call, building its call info on top +** of the current call info. 'narg1' is the number of arguments plus 1 +** (so that it includes the function itself). Return the number of +** results, if it was a C function, or -1 for a Lua function. +*/ +int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, + int narg1, int delta) { + retry: + switch (ttypetag(s2v(func))) { + case LUA_VCCL: /* C closure */ + return precallC(L, func, LUA_MULTRET, clCvalue(s2v(func))->f); + case LUA_VLCF: /* light C function */ + return precallC(L, func, LUA_MULTRET, fvalue(s2v(func))); + case LUA_VLCL: { /* Lua function */ + Proto *p = clLvalue(s2v(func))->p; + int fsize = p->maxstacksize; /* frame size */ + int nfixparams = p->numparams; + int i; + checkstackGCp(L, fsize - delta, func); + ci->func.p -= delta; /* restore 'func' (if vararg) */ + for (i = 0; i < narg1; i++) /* move down function and arguments */ + setobjs2s(L, ci->func.p + i, func + i); + func = ci->func.p; /* moved-down function */ + for (; narg1 <= nfixparams; narg1++) + setnilvalue(s2v(func + narg1)); /* complete missing arguments */ + ci->top.p = func + 1 + fsize; /* top for new function */ + lua_assert(ci->top.p <= L->stack_last.p); + ci->u.l.savedpc = p->code; /* starting point */ + ci->callstatus |= CIST_TAIL; + L->top.p = func + narg1; /* set top */ + return -1; + } + default: { /* not a function */ + func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ + /* return luaD_pretailcall(L, ci, func, narg1 + 1, delta); */ + narg1++; + goto retry; /* try again */ + } + } +} + + +/* +** Prepares the call to a function (C or Lua). For C functions, also do +** the call. The function to be called is at '*func'. The arguments +** are on the stack, right after the function. Returns the CallInfo +** to be executed, if it was a Lua function. Otherwise (a C function) +** returns NULL, with all the results on the stack, starting at the +** original function position. +*/ +CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { + retry: + switch (ttypetag(s2v(func))) { + case LUA_VCCL: /* C closure */ + precallC(L, func, nresults, clCvalue(s2v(func))->f); + return NULL; + case LUA_VLCF: /* light C function */ + precallC(L, func, nresults, fvalue(s2v(func))); + return NULL; + case LUA_VLCL: { /* Lua function */ + CallInfo *ci; + Proto *p = clLvalue(s2v(func))->p; + int narg = cast_int(L->top.p - func) - 1; /* number of real arguments */ + int nfixparams = p->numparams; + int fsize = p->maxstacksize; /* frame size */ + checkstackGCp(L, fsize, func); + L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize); + ci->u.l.savedpc = p->code; /* starting point */ + for (; narg < nfixparams; narg++) + setnilvalue(s2v(L->top.p++)); /* complete missing arguments */ + lua_assert(ci->top.p <= L->stack_last.p); + return ci; + } + default: { /* not a function */ + func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ + /* return luaD_precall(L, func, nresults); */ + goto retry; /* try again with metamethod */ + } + } +} + + +/* +** Call a function (C or Lua) through C. 'inc' can be 1 (increment +** number of recursive invocations in the C stack) or nyci (the same +** plus increment number of non-yieldable calls). +** This function can be called with some use of EXTRA_STACK, so it should +** check the stack before doing anything else. 'luaD_precall' already +** does that. +*/ +l_sinline void ccall (lua_State *L, StkId func, int nResults, l_uint32 inc) { + CallInfo *ci; + L->nCcalls += inc; + if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) { + checkstackp(L, 0, func); /* free any use of EXTRA_STACK */ + luaE_checkcstack(L); + } + if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */ + ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */ + luaV_execute(L, ci); /* call it */ + } + L->nCcalls -= inc; +} + + +/* +** External interface for 'ccall' +*/ +void luaD_call (lua_State *L, StkId func, int nResults) { + ccall(L, func, nResults, 1); +} + + +/* +** Similar to 'luaD_call', but does not allow yields during the call. +*/ +void luaD_callnoyield (lua_State *L, StkId func, int nResults) { + ccall(L, func, nResults, nyci); +} + + +/* +** Finish the job of 'lua_pcallk' after it was interrupted by an yield. +** (The caller, 'finishCcall', does the final call to 'adjustresults'.) +** The main job is to complete the 'luaD_pcall' called by 'lua_pcallk'. +** If a '__close' method yields here, eventually control will be back +** to 'finishCcall' (when that '__close' method finally returns) and +** 'finishpcallk' will run again and close any still pending '__close' +** methods. Similarly, if a '__close' method errs, 'precover' calls +** 'unroll' which calls ''finishCcall' and we are back here again, to +** close any pending '__close' methods. +** Note that, up to the call to 'luaF_close', the corresponding +** 'CallInfo' is not modified, so that this repeated run works like the +** first one (except that it has at least one less '__close' to do). In +** particular, field CIST_RECST preserves the error status across these +** multiple runs, changing only if there is a new error. +*/ +static int finishpcallk (lua_State *L, CallInfo *ci) { + int status = getcistrecst(ci); /* get original status */ + if (l_likely(status == LUA_OK)) /* no error? */ + status = LUA_YIELD; /* was interrupted by an yield */ + else { /* error */ + StkId func = restorestack(L, ci->u2.funcidx); + L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */ + func = luaF_close(L, func, status, 1); /* can yield or raise an error */ + luaD_seterrorobj(L, status, func); + luaD_shrinkstack(L); /* restore stack size in case of overflow */ + setcistrecst(ci, LUA_OK); /* clear original status */ + } + ci->callstatus &= ~CIST_YPCALL; + L->errfunc = ci->u.c.old_errfunc; + /* if it is here, there were errors or yields; unlike 'lua_pcallk', + do not change status */ + return status; +} + + +/* +** Completes the execution of a C function interrupted by an yield. +** The interruption must have happened while the function was either +** closing its tbc variables in 'moveresults' or executing +** 'lua_callk'/'lua_pcallk'. In the first case, it just redoes +** 'luaD_poscall'. In the second case, the call to 'finishpcallk' +** finishes the interrupted execution of 'lua_pcallk'. After that, it +** calls the continuation of the interrupted function and finally it +** completes the job of the 'luaD_call' that called the function. In +** the call to 'adjustresults', we do not know the number of results +** of the function called by 'lua_callk'/'lua_pcallk', so we are +** conservative and use LUA_MULTRET (always adjust). +*/ +static void finishCcall (lua_State *L, CallInfo *ci) { + int n; /* actual number of results from C function */ + if (ci->callstatus & CIST_CLSRET) { /* was returning? */ + lua_assert(hastocloseCfunc(ci->nresults)); + n = ci->u2.nres; /* just redo 'luaD_poscall' */ + /* don't need to reset CIST_CLSRET, as it will be set again anyway */ + } + else { + int status = LUA_YIELD; /* default if there were no errors */ + /* must have a continuation and must be able to call it */ + lua_assert(ci->u.c.k != NULL && yieldable(L)); + if (ci->callstatus & CIST_YPCALL) /* was inside a 'lua_pcallk'? */ + status = finishpcallk(L, ci); /* finish it */ + adjustresults(L, LUA_MULTRET); /* finish 'lua_callk' */ + lua_unlock(L); + n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation */ + lua_lock(L); + api_checknelems(L, n); + } + luaD_poscall(L, ci, n); /* finish 'luaD_call' */ +} + + +/* +** Executes "full continuation" (everything in the stack) of a +** previously interrupted coroutine until the stack is empty (or another +** interruption long-jumps out of the loop). +*/ +static void unroll (lua_State *L, void *ud) { + CallInfo *ci; + UNUSED(ud); + while ((ci = L->ci) != &L->base_ci) { /* something in the stack */ + if (!isLua(ci)) /* C function? */ + finishCcall(L, ci); /* complete its execution */ + else { /* Lua function */ + luaV_finishOp(L); /* finish interrupted instruction */ + luaV_execute(L, ci); /* execute down to higher C 'boundary' */ + } + } +} + + +/* +** Try to find a suspended protected call (a "recover point") for the +** given thread. +*/ +static CallInfo *findpcall (lua_State *L) { + CallInfo *ci; + for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */ + if (ci->callstatus & CIST_YPCALL) + return ci; + } + return NULL; /* no pending pcall */ +} + + +/* +** Signal an error in the call to 'lua_resume', not in the execution +** of the coroutine itself. (Such errors should not be handled by any +** coroutine error handler and should not kill the coroutine.) +*/ +static int resume_error (lua_State *L, const char *msg, int narg) { + L->top.p -= narg; /* remove args from the stack */ + setsvalue2s(L, L->top.p, luaS_new(L, msg)); /* push error message */ + api_incr_top(L); + lua_unlock(L); + return LUA_ERRRUN; +} + + +/* +** Do the work for 'lua_resume' in protected mode. Most of the work +** depends on the status of the coroutine: initial state, suspended +** inside a hook, or regularly suspended (optionally with a continuation +** function), plus erroneous cases: non-suspended coroutine or dead +** coroutine. +*/ +static void resume (lua_State *L, void *ud) { + int n = *(cast(int*, ud)); /* number of arguments */ + StkId firstArg = L->top.p - n; /* first argument */ + CallInfo *ci = L->ci; + if (L->status == LUA_OK) /* starting a coroutine? */ + ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */ + else { /* resuming from previous yield */ + lua_assert(L->status == LUA_YIELD); + L->status = LUA_OK; /* mark that it is running (again) */ + if (isLua(ci)) { /* yielded inside a hook? */ + L->top.p = firstArg; /* discard arguments */ + luaV_execute(L, ci); /* just continue running Lua code */ + } + else { /* 'common' yield */ + if (ci->u.c.k != NULL) { /* does it have a continuation function? */ + lua_unlock(L); + n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */ + lua_lock(L); + api_checknelems(L, n); + } + luaD_poscall(L, ci, n); /* finish 'luaD_call' */ + } + unroll(L, NULL); /* run continuation */ + } +} + + +/* +** Unrolls a coroutine in protected mode while there are recoverable +** errors, that is, errors inside a protected call. (Any error +** interrupts 'unroll', and this loop protects it again so it can +** continue.) Stops with a normal end (status == LUA_OK), an yield +** (status == LUA_YIELD), or an unprotected error ('findpcall' doesn't +** find a recover point). +*/ +static int precover (lua_State *L, int status) { + CallInfo *ci; + while (errorstatus(status) && (ci = findpcall(L)) != NULL) { + L->ci = ci; /* go down to recovery functions */ + setcistrecst(ci, status); /* status to finish 'pcall' */ + status = luaD_rawrunprotected(L, unroll, NULL); + } + return status; +} + + +LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, + int *nresults) { + int status; + lua_lock(L); + 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->top.p - (L->ci->func.p + 1) == nargs) /* no function? */ + return resume_error(L, "cannot resume dead coroutine", nargs); + } + else if (L->status != LUA_YIELD) /* ended with errors? */ + return resume_error(L, "cannot resume dead coroutine", nargs); + L->nCcalls = (from) ? getCcalls(from) : 0; + if (getCcalls(L) >= LUAI_MAXCCALLS) + return resume_error(L, "C stack overflow", nargs); + L->nCcalls++; + luai_userstateresume(L, nargs); + api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); + status = luaD_rawrunprotected(L, resume, &nargs); + /* continue running after recoverable errors */ + status = precover(L, status); + if (l_likely(!errorstatus(status))) + lua_assert(status == L->status); /* normal end or yield */ + else { /* unrecoverable error */ + L->status = cast_byte(status); /* mark thread as 'dead' */ + luaD_seterrorobj(L, status, L->top.p); /* push error message */ + L->ci->top.p = L->top.p; + } + *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield + : cast_int(L->top.p - (L->ci->func.p + 1)); + lua_unlock(L); + return status; +} + + +LUA_API int lua_isyieldable (lua_State *L) { + return yieldable(L); +} + + +LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, + lua_KFunction k) { + CallInfo *ci; + luai_userstateyield(L, nresults); + lua_lock(L); + ci = L->ci; + api_checknelems(L, nresults); + if (l_unlikely(!yieldable(L))) { + if (L != G(L)->mainthread) + luaG_runerror(L, "attempt to yield across a C-call boundary"); + else + luaG_runerror(L, "attempt to yield from outside a coroutine"); + } + L->status = LUA_YIELD; + ci->u2.nyield = nresults; /* save number of results */ + if (isLua(ci)) { /* inside a hook? */ + lua_assert(!isLuacode(ci)); + api_check(L, nresults == 0, "hooks cannot yield values"); + api_check(L, k == NULL, "hooks cannot continue after yielding"); + } + else { + if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ + ci->u.c.ctx = ctx; /* save context */ + luaD_throw(L, LUA_YIELD); + } + lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ + lua_unlock(L); + return 0; /* return to 'luaD_hook' */ +} + + +/* +** Auxiliary structure to call 'luaF_close' in protected mode. +*/ +struct CloseP { + StkId level; + int status; +}; + + +/* +** Auxiliary function to call 'luaF_close' in protected mode. +*/ +static void closepaux (lua_State *L, void *ud) { + struct CloseP *pcl = cast(struct CloseP *, ud); + luaF_close(L, pcl->level, pcl->status, 0); +} + + +/* +** Calls 'luaF_close' in protected mode. Return the original status +** or, in case of errors, the new status. +*/ +int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status) { + CallInfo *old_ci = L->ci; + lu_byte old_allowhooks = L->allowhook; + for (;;) { /* keep closing upvalues until no more errors */ + struct CloseP pcl; + pcl.level = restorestack(L, level); pcl.status = status; + status = luaD_rawrunprotected(L, &closepaux, &pcl); + if (l_likely(status == LUA_OK)) /* no more errors? */ + return pcl.status; + else { /* an error occurred; restore saved state and repeat */ + L->ci = old_ci; + L->allowhook = old_allowhooks; + } + } +} + + +/* +** Call the C function 'func' in protected mode, restoring basic +** thread information ('allowhook', etc.) and in particular +** its stack level in case of errors. +*/ +int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t old_top, ptrdiff_t ef) { + int status; + CallInfo *old_ci = L->ci; + lu_byte old_allowhooks = L->allowhook; + ptrdiff_t old_errfunc = L->errfunc; + L->errfunc = ef; + status = luaD_rawrunprotected(L, func, u); + if (l_unlikely(status != LUA_OK)) { /* an error occurred? */ + L->ci = old_ci; + L->allowhook = old_allowhooks; + status = luaD_closeprotected(L, old_top, status); + luaD_seterrorobj(L, status, restorestack(L, old_top)); + luaD_shrinkstack(L); /* restore stack size in case of overflow */ + } + L->errfunc = old_errfunc; + return status; +} + + + +/* +** Execute a protected parser. +*/ +struct SParser { /* data to 'f_parser' */ + ZIO *z; + Mbuffer buff; /* dynamic structure used by the scanner */ + Dyndata dyd; /* dynamic structures used by the parser */ + const char *mode; + const char *name; +}; + + +static void checkmode (lua_State *L, const char *mode, const char *x) { + if (mode && strchr(mode, x[0]) == NULL) { + luaO_pushfstring(L, + "attempt to load a %s chunk (mode is '%s')", x, mode); + luaD_throw(L, LUA_ERRSYNTAX); + } +} + + +static void f_parser (lua_State *L, void *ud) { + LClosure *cl; + struct SParser *p = cast(struct SParser *, ud); + int c = zgetc(p->z); /* read first character */ + if (c == LUA_SIGNATURE[0]) { + checkmode(L, p->mode, "binary"); + cl = luaU_undump(L, p->z, p->name); + } + else { + checkmode(L, p->mode, "text"); + cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); + } + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luaF_initupvals(L, cl); +} + + +int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, + const char *mode) { + struct SParser p; + int status; + incnny(L); /* cannot yield during parsing */ + p.z = z; p.name = name; p.mode = mode; + p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0; + p.dyd.gt.arr = NULL; p.dyd.gt.size = 0; + p.dyd.label.arr = NULL; p.dyd.label.size = 0; + luaZ_initbuffer(L, &p.buff); + status = luaD_pcall(L, f_parser, &p, savestack(L, L->top.p), L->errfunc); + luaZ_freebuffer(L, &p.buff); + luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size); + luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size); + luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size); + decnny(L); + return status; +} + + diff --git a/src/libs/3rdparty/lua/src/ldo.h b/src/libs/3rdparty/lua/src/ldo.h new file mode 100644 index 0000000000..1aa446ad09 --- /dev/null +++ b/src/libs/3rdparty/lua/src/ldo.h @@ -0,0 +1,88 @@ +/* +** $Id: ldo.h $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + +#ifndef ldo_h +#define ldo_h + + +#include "llimits.h" +#include "lobject.h" +#include "lstate.h" +#include "lzio.h" + + +/* +** 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. +** It also allows the running of one GC step when the stack is +** reallocated. +** 'condmovestack' is used in heavy tests to force a stack reallocation +** at every check. +*/ +#define luaD_checkstackaux(L,n,pre,pos) \ + if (l_unlikely(L->stack_last.p - L->top.p <= (n))) \ + { pre; luaD_growstack(L, n, 1); 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 savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p)) +#define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n)) + + +/* macro to check stack size, preserving 'p' */ +#define checkstackp(L,n,p) \ + luaD_checkstackaux(L, n, \ + ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \ + p = restorestack(L, t__)) /* 'pos' part: restore 'p' */ + + +/* macro to check stack size and GC, preserving 'p' */ +#define checkstackGCp(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' */ + + +/* macro to check stack size and GC */ +#define checkstackGC(L,fsize) \ + luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0) + + +/* type of protected functions, to be ran by 'runprotected' */ +typedef void (*Pfunc) (lua_State *L, void *ud); + +LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); +LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, + const char *mode); +LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, + int fTransfer, int nTransfer); +LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); +LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, + int narg1, int delta); +LUAI_FUNC CallInfo *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_callnoyield (lua_State *L, StkId func, int nResults); +LUAI_FUNC StkId luaD_tryfuncTM (lua_State *L, StkId func); +LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status); +LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t oldtop, ptrdiff_t ef); +LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres); +LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror); +LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror); +LUAI_FUNC void luaD_shrinkstack (lua_State *L); +LUAI_FUNC void luaD_inctop (lua_State *L); + +LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); +LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); + +#endif + diff --git a/src/libs/3rdparty/lua/src/ldump.c b/src/libs/3rdparty/lua/src/ldump.c new file mode 100644 index 0000000000..f231691b77 --- /dev/null +++ b/src/libs/3rdparty/lua/src/ldump.c @@ -0,0 +1,230 @@ +/* +** $Id: ldump.c $ +** save precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#define ldump_c +#define LUA_CORE + +#include "lprefix.h" + + +#include <limits.h> +#include <stddef.h> + +#include "lua.h" + +#include "lobject.h" +#include "lstate.h" +#include "lundump.h" + + +typedef struct { + lua_State *L; + lua_Writer writer; + void *data; + int strip; + int status; +} DumpState; + + +/* +** All high-level dumps go through dumpVector; you can change it to +** change the endianness of the result +*/ +#define dumpVector(D,v,n) dumpBlock(D,v,(n)*sizeof((v)[0])) + +#define dumpLiteral(D, s) dumpBlock(D,s,sizeof(s) - sizeof(char)) + + +static void dumpBlock (DumpState *D, const void *b, size_t size) { + if (D->status == 0 && size > 0) { + lua_unlock(D->L); + D->status = (*D->writer)(D->L, b, size, D->data); + lua_lock(D->L); + } +} + + +#define dumpVar(D,x) dumpVector(D,&x,1) + + +static void dumpByte (DumpState *D, int y) { + lu_byte x = (lu_byte)y; + dumpVar(D, x); +} + + +/* +** 'dumpSize' buffer size: each byte can store up to 7 bits. (The "+6" +** rounds up the division.) +*/ +#define DIBS ((sizeof(size_t) * CHAR_BIT + 6) / 7) + +static void dumpSize (DumpState *D, size_t x) { + lu_byte buff[DIBS]; + int n = 0; + do { + buff[DIBS - (++n)] = x & 0x7f; /* fill buffer in reverse order */ + x >>= 7; + } while (x != 0); + buff[DIBS - 1] |= 0x80; /* mark last byte */ + dumpVector(D, buff + DIBS - n, n); +} + + +static void dumpInt (DumpState *D, int x) { + dumpSize(D, x); +} + + +static void dumpNumber (DumpState *D, lua_Number x) { + dumpVar(D, x); +} + + +static void dumpInteger (DumpState *D, lua_Integer x) { + dumpVar(D, x); +} + + +static void dumpString (DumpState *D, const TString *s) { + if (s == NULL) + dumpSize(D, 0); + else { + size_t size = tsslen(s); + const char *str = getstr(s); + dumpSize(D, size + 1); + dumpVector(D, str, size); + } +} + + +static void dumpCode (DumpState *D, const Proto *f) { + dumpInt(D, f->sizecode); + dumpVector(D, f->code, f->sizecode); +} + + +static void dumpFunction(DumpState *D, const Proto *f, TString *psource); + +static void dumpConstants (DumpState *D, const Proto *f) { + int i; + int n = f->sizek; + dumpInt(D, n); + for (i = 0; i < n; i++) { + const TValue *o = &f->k[i]; + int tt = ttypetag(o); + dumpByte(D, tt); + switch (tt) { + case LUA_VNUMFLT: + dumpNumber(D, fltvalue(o)); + break; + case LUA_VNUMINT: + dumpInteger(D, ivalue(o)); + break; + case LUA_VSHRSTR: + case LUA_VLNGSTR: + dumpString(D, tsvalue(o)); + break; + default: + lua_assert(tt == LUA_VNIL || tt == LUA_VFALSE || tt == LUA_VTRUE); + } + } +} + + +static void dumpProtos (DumpState *D, const Proto *f) { + int i; + int n = f->sizep; + dumpInt(D, n); + for (i = 0; i < n; i++) + dumpFunction(D, f->p[i], f->source); +} + + +static void dumpUpvalues (DumpState *D, const Proto *f) { + int i, n = f->sizeupvalues; + dumpInt(D, n); + for (i = 0; i < n; i++) { + dumpByte(D, f->upvalues[i].instack); + dumpByte(D, f->upvalues[i].idx); + dumpByte(D, f->upvalues[i].kind); + } +} + + +static void dumpDebug (DumpState *D, const Proto *f) { + int i, n; + n = (D->strip) ? 0 : f->sizelineinfo; + dumpInt(D, n); + dumpVector(D, f->lineinfo, n); + n = (D->strip) ? 0 : f->sizeabslineinfo; + dumpInt(D, n); + for (i = 0; i < n; i++) { + dumpInt(D, f->abslineinfo[i].pc); + dumpInt(D, f->abslineinfo[i].line); + } + n = (D->strip) ? 0 : f->sizelocvars; + dumpInt(D, n); + for (i = 0; i < n; i++) { + dumpString(D, f->locvars[i].varname); + dumpInt(D, f->locvars[i].startpc); + dumpInt(D, f->locvars[i].endpc); + } + n = (D->strip) ? 0 : f->sizeupvalues; + dumpInt(D, n); + for (i = 0; i < n; i++) + dumpString(D, f->upvalues[i].name); +} + + +static void dumpFunction (DumpState *D, const Proto *f, TString *psource) { + if (D->strip || f->source == psource) + dumpString(D, NULL); /* no debug info or same source as its parent */ + else + dumpString(D, f->source); + dumpInt(D, f->linedefined); + dumpInt(D, f->lastlinedefined); + dumpByte(D, f->numparams); + dumpByte(D, f->is_vararg); + dumpByte(D, f->maxstacksize); + dumpCode(D, f); + dumpConstants(D, f); + dumpUpvalues(D, f); + dumpProtos(D, f); + dumpDebug(D, f); +} + + +static void dumpHeader (DumpState *D) { + dumpLiteral(D, LUA_SIGNATURE); + dumpByte(D, LUAC_VERSION); + dumpByte(D, LUAC_FORMAT); + dumpLiteral(D, LUAC_DATA); + dumpByte(D, sizeof(Instruction)); + dumpByte(D, sizeof(lua_Integer)); + dumpByte(D, sizeof(lua_Number)); + dumpInteger(D, LUAC_INT); + dumpNumber(D, LUAC_NUM); +} + + +/* +** dump Lua function as precompiled chunk +*/ +int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, + int strip) { + DumpState D; + D.L = L; + D.writer = w; + D.data = data; + D.strip = strip; + D.status = 0; + dumpHeader(&D); + dumpByte(&D, f->sizeupvalues); + dumpFunction(&D, f, NULL); + return D.status; +} + diff --git a/src/libs/3rdparty/lua/src/lfunc.c b/src/libs/3rdparty/lua/src/lfunc.c new file mode 100644 index 0000000000..0945f241de --- /dev/null +++ b/src/libs/3rdparty/lua/src/lfunc.c @@ -0,0 +1,294 @@ +/* +** $Id: lfunc.c $ +** Auxiliary functions to manipulate prototypes and closures +** See Copyright Notice in lua.h +*/ + +#define lfunc_c +#define LUA_CORE + +#include "lprefix.h" + + +#include <stddef.h> + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" + + + +CClosure *luaF_newCclosure (lua_State *L, int nupvals) { + GCObject *o = luaC_newobj(L, LUA_VCCL, sizeCclosure(nupvals)); + CClosure *c = gco2ccl(o); + c->nupvalues = cast_byte(nupvals); + return c; +} + + +LClosure *luaF_newLclosure (lua_State *L, int nupvals) { + GCObject *o = luaC_newobj(L, LUA_VLCL, sizeLclosure(nupvals)); + LClosure *c = gco2lcl(o); + c->p = NULL; + c->nupvalues = cast_byte(nupvals); + while (nupvals--) c->upvals[nupvals] = NULL; + return c; +} + + +/* +** fill a closure with new closed upvalues +*/ +void luaF_initupvals (lua_State *L, LClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) { + GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal)); + UpVal *uv = gco2upv(o); + uv->v.p = &uv->u.value; /* make it closed */ + setnilvalue(uv->v.p); + cl->upvals[i] = uv; + luaC_objbarrier(L, cl, uv); + } +} + + +/* +** Create a new upvalue at the given level, and link it to the list of +** open upvalues of 'L' after entry 'prev'. +**/ +static UpVal *newupval (lua_State *L, StkId level, UpVal **prev) { + GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal)); + UpVal *uv = gco2upv(o); + UpVal *next = *prev; + uv->v.p = s2v(level); /* current value lives in the stack */ + uv->u.open.next = next; /* link it to list of open upvalues */ + uv->u.open.previous = prev; + if (next) + next->u.open.previous = &uv->u.open.next; + *prev = uv; + if (!isintwups(L)) { /* thread not in list of threads with upvalues? */ + L->twups = G(L)->twups; /* link it to the list */ + G(L)->twups = L; + } + return uv; +} + + +/* +** Find and reuse, or create if it does not exist, an upvalue +** at the given level. +*/ +UpVal *luaF_findupval (lua_State *L, StkId level) { + UpVal **pp = &L->openupval; + UpVal *p; + lua_assert(isintwups(L) || L->openupval == NULL); + while ((p = *pp) != NULL && uplevel(p) >= level) { /* search for it */ + lua_assert(!isdead(G(L), p)); + if (uplevel(p) == level) /* corresponding upvalue? */ + return p; /* return it */ + pp = &p->u.open.next; + } + /* not found: create a new upvalue after 'pp' */ + return newupval(L, level, pp); +} + + +/* +** Call closing method for object 'obj' with error message 'err'. The +** boolean 'yy' controls whether the call is yieldable. +** (This function assumes EXTRA_STACK.) +*/ +static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) { + StkId top = L->top.p; + const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); + setobj2s(L, top, tm); /* will call metamethod... */ + setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */ + setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */ + L->top.p = top + 3; /* add function and arguments */ + if (yy) + luaD_call(L, top, 0); + else + luaD_callnoyield(L, top, 0); +} + + +/* +** Check whether object at given level has a close metamethod and raise +** an error if not. +*/ +static void checkclosemth (lua_State *L, StkId level) { + const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE); + if (ttisnil(tm)) { /* no metamethod? */ + int idx = cast_int(level - L->ci->func.p); /* variable index */ + const char *vname = luaG_findlocal(L, L->ci, idx, NULL); + if (vname == NULL) vname = "?"; + luaG_runerror(L, "variable '%s' got a non-closable value", vname); + } +} + + +/* +** Prepare and call a closing method. +** If status is CLOSEKTOP, the call to the closing method will be pushed +** at the top of the stack. Otherwise, values can be pushed right after +** the 'level' of the upvalue being closed, as everything after that +** won't be used again. +*/ +static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) { + TValue *uv = s2v(level); /* value being closed */ + TValue *errobj; + if (status == CLOSEKTOP) + errobj = &G(L)->nilvalue; /* error object is nil */ + else { /* 'luaD_seterrorobj' will set top to level + 2 */ + errobj = s2v(level + 1); /* error object goes after 'uv' */ + luaD_seterrorobj(L, status, level + 1); /* set error object */ + } + callclosemethod(L, uv, errobj, yy); +} + + +/* +** Maximum value for deltas in 'tbclist', dependent on the type +** of delta. (This macro assumes that an 'L' is in scope where it +** is used.) +*/ +#define MAXDELTA \ + ((256ul << ((sizeof(L->stack.p->tbclist.delta) - 1) * 8)) - 1) + + +/* +** Insert a variable in the list of to-be-closed variables. +*/ +void luaF_newtbcupval (lua_State *L, StkId level) { + lua_assert(level > L->tbclist.p); + if (l_isfalse(s2v(level))) + return; /* false doesn't need to be closed */ + checkclosemth(L, level); /* value must have a close method */ + while (cast_uint(level - L->tbclist.p) > MAXDELTA) { + L->tbclist.p += MAXDELTA; /* create a dummy node at maximum delta */ + L->tbclist.p->tbclist.delta = 0; + } + level->tbclist.delta = cast(unsigned short, level - L->tbclist.p); + L->tbclist.p = level; +} + + +void luaF_unlinkupval (UpVal *uv) { + lua_assert(upisopen(uv)); + *uv->u.open.previous = uv->u.open.next; + if (uv->u.open.next) + uv->u.open.next->u.open.previous = uv->u.open.previous; +} + + +/* +** Close all upvalues up to the given stack level. +*/ +void luaF_closeupval (lua_State *L, StkId level) { + UpVal *uv; + StkId upl; /* stack index pointed by 'uv' */ + while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { + TValue *slot = &uv->u.value; /* new position for value */ + lua_assert(uplevel(uv) < L->top.p); + luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */ + setobj(L, slot, uv->v.p); /* move value to upvalue slot */ + uv->v.p = slot; /* now current value lives here */ + if (!iswhite(uv)) { /* neither white nor dead? */ + nw2black(uv); /* closed upvalues cannot be gray */ + luaC_barrier(L, uv, slot); + } + } +} + + +/* +** Remove first element from the tbclist plus its dummy nodes. +*/ +static void poptbclist (lua_State *L) { + StkId tbc = L->tbclist.p; + lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */ + tbc -= tbc->tbclist.delta; + while (tbc > L->stack.p && tbc->tbclist.delta == 0) + tbc -= MAXDELTA; /* remove dummy nodes */ + L->tbclist.p = tbc; +} + + +/* +** Close all upvalues and to-be-closed variables up to the given stack +** level. Return restored 'level'. +*/ +StkId luaF_close (lua_State *L, StkId level, int status, int yy) { + ptrdiff_t levelrel = savestack(L, level); + luaF_closeupval(L, level); /* first, close the upvalues */ + while (L->tbclist.p >= level) { /* traverse tbc's down to that level */ + StkId tbc = L->tbclist.p; /* get variable index */ + poptbclist(L); /* remove it from list */ + prepcallclosemth(L, tbc, status, yy); /* close variable */ + level = restorestack(L, levelrel); + } + return level; +} + + +Proto *luaF_newproto (lua_State *L) { + GCObject *o = luaC_newobj(L, LUA_VPROTO, sizeof(Proto)); + Proto *f = gco2p(o); + f->k = NULL; + f->sizek = 0; + f->p = NULL; + f->sizep = 0; + f->code = NULL; + f->sizecode = 0; + f->lineinfo = NULL; + f->sizelineinfo = 0; + f->abslineinfo = NULL; + f->sizeabslineinfo = 0; + f->upvalues = NULL; + f->sizeupvalues = 0; + f->numparams = 0; + f->is_vararg = 0; + f->maxstacksize = 0; + f->locvars = NULL; + f->sizelocvars = 0; + f->linedefined = 0; + f->lastlinedefined = 0; + f->source = NULL; + return f; +} + + +void luaF_freeproto (lua_State *L, Proto *f) { + luaM_freearray(L, f->code, f->sizecode); + luaM_freearray(L, f->p, f->sizep); + luaM_freearray(L, f->k, f->sizek); + luaM_freearray(L, f->lineinfo, f->sizelineinfo); + luaM_freearray(L, f->abslineinfo, f->sizeabslineinfo); + luaM_freearray(L, f->locvars, f->sizelocvars); + luaM_freearray(L, f->upvalues, f->sizeupvalues); + luaM_free(L, f); +} + + +/* +** Look for n-th local variable at line 'line' in function 'func'. +** Returns NULL if not found. +*/ +const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { + int i; + for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) { + if (pc < f->locvars[i].endpc) { /* is variable active? */ + local_number--; + if (local_number == 0) + return getstr(f->locvars[i].varname); + } + } + return NULL; /* not found */ +} + diff --git a/src/libs/3rdparty/lua/src/lfunc.h b/src/libs/3rdparty/lua/src/lfunc.h new file mode 100644 index 0000000000..3be265efb5 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lfunc.h @@ -0,0 +1,64 @@ +/* +** $Id: lfunc.h $ +** Auxiliary functions to manipulate prototypes and closures +** See Copyright Notice in lua.h +*/ + +#ifndef lfunc_h +#define lfunc_h + + +#include "lobject.h" + + +#define sizeCclosure(n) (cast_int(offsetof(CClosure, upvalue)) + \ + cast_int(sizeof(TValue)) * (n)) + +#define sizeLclosure(n) (cast_int(offsetof(LClosure, upvals)) + \ + cast_int(sizeof(TValue *)) * (n)) + + +/* test whether thread is in 'twups' list */ +#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 + + +#define upisopen(up) ((up)->v.p != &(up)->u.value) + + +#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v.p)) + + +/* +** maximum number of misses before giving up the cache of closures +** in prototypes +*/ +#define MAXMISS 10 + + + +/* special status to close upvalues preserving the top of the stack */ +#define CLOSEKTOP (-1) + + +LUAI_FUNC Proto *luaF_newproto (lua_State *L); +LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nupvals); +LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nupvals); +LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); +LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); +LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level); +LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level); +LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, int status, int yy); +LUAI_FUNC void luaF_unlinkupval (UpVal *uv); +LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); +LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, + int pc); + + +#endif diff --git a/src/libs/3rdparty/lua/src/lgc.c b/src/libs/3rdparty/lua/src/lgc.c new file mode 100644 index 0000000000..a3094ff571 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lgc.c @@ -0,0 +1,1739 @@ +/* +** $Id: lgc.c $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +#define lgc_c +#define LUA_CORE + +#include "lprefix.h" + +#include <stdio.h> +#include <string.h> + + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + +/* +** Maximum number of elements to sweep in each single step. +** (Large enough to dissipate fixed overheads but small enough +** to allow small steps for the collector.) +*/ +#define GCSWEEPMAX 100 + +/* +** Maximum number of finalizers to call in each single step. +*/ +#define GCFINMAX 10 + + +/* +** Cost of calling one finalizer. +*/ +#define GCFINALIZECOST 50 + + +/* +** The equivalent, in bytes, of one unit of "work" (visiting a slot, +** sweeping an object, etc.) +*/ +#define WORK2MEM sizeof(TValue) + + +/* +** macro to adjust 'pause': 'pause' is actually used like +** 'pause / PAUSEADJ' (value chosen by tests) +*/ +#define PAUSEADJ 100 + + +/* mask with all color bits */ +#define maskcolors (bitmask(BLACKBIT) | WHITEBITS) + +/* mask with all GC bits */ +#define maskgcbits (maskcolors | AGEBITS) + + +/* macro to erase all color bits then set only the current white bit */ +#define makewhite(g,x) \ + (x->marked = cast_byte((x->marked & ~maskcolors) | luaC_white(g))) + +/* make an object gray (neither white nor black) */ +#define set2gray(x) resetbits(x->marked, maskcolors) + + +/* make an object black (coming from any color) */ +#define set2black(x) \ + (x->marked = cast_byte((x->marked & ~WHITEBITS) | bitmask(BLACKBIT))) + + +#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) + +#define keyiswhite(n) (keyiscollectable(n) && iswhite(gckey(n))) + + +/* +** Protected access to objects in values +*/ +#define gcvalueN(o) (iscollectable(o) ? gcvalue(o) : NULL) + + +#define markvalue(g,o) { checkliveness(g->mainthread,o); \ + if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } + +#define markkey(g, n) { if keyiswhite(n) reallymarkobject(g,gckey(n)); } + +#define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); } + +/* +** mark an object that can be NULL (either because it is really optional, +** or it was stripped as debug info, or inside an uncompleted structure) +*/ +#define markobjectN(g,t) { if (t) markobject(g,t); } + +static void reallymarkobject (global_State *g, GCObject *o); +static lu_mem atomic (lua_State *L); +static void entersweep (lua_State *L); + + +/* +** {====================================================== +** Generic functions +** ======================================================= +*/ + + +/* +** one after last element in a hash array +*/ +#define gnodelast(h) gnode(h, cast_sizet(sizenode(h))) + + +static GCObject **getgclist (GCObject *o) { + switch (o->tt) { + case LUA_VTABLE: return &gco2t(o)->gclist; + case LUA_VLCL: return &gco2lcl(o)->gclist; + case LUA_VCCL: return &gco2ccl(o)->gclist; + case LUA_VTHREAD: return &gco2th(o)->gclist; + case LUA_VPROTO: return &gco2p(o)->gclist; + case LUA_VUSERDATA: { + Udata *u = gco2u(o); + lua_assert(u->nuvalue > 0); + return &u->gclist; + } + default: lua_assert(0); return 0; + } +} + + +/* +** Link a collectable object 'o' with a known type into the list 'p'. +** (Must be a macro to access the 'gclist' field in different types.) +*/ +#define linkgclist(o,p) linkgclist_(obj2gco(o), &(o)->gclist, &(p)) + +static void linkgclist_ (GCObject *o, GCObject **pnext, GCObject **list) { + lua_assert(!isgray(o)); /* cannot be in a gray list */ + *pnext = *list; + *list = o; + set2gray(o); /* now it is */ +} + + +/* +** Link a generic collectable object 'o' into the list 'p'. +*/ +#define linkobjgclist(o,p) linkgclist_(obj2gco(o), getgclist(o), &(p)) + + + +/* +** Clear keys for empty entries in tables. If entry is empty, mark its +** entry as dead. This allows the collection of the key, but keeps its +** entry in the table: its removal could break a chain and could break +** a table traversal. Other places never manipulate dead keys, because +** its associated empty value is enough to signal that the entry is +** logically empty. +*/ +static void clearkey (Node *n) { + lua_assert(isempty(gval(n))); + if (keyiscollectable(n)) + setdeadkey(n); /* unused key; remove it */ +} + + +/* +** tells whether a key or value can be cleared from a weak +** table. Non-collectable objects are never removed from weak +** tables. Strings behave as 'values', so are never removed too. for +** other objects: if really collected, cannot keep them; for objects +** being finalized, keep them in keys, but not in values +*/ +static int iscleared (global_State *g, const GCObject *o) { + if (o == NULL) return 0; /* non-collectable value */ + else if (novariant(o->tt) == LUA_TSTRING) { + markobject(g, o); /* strings are 'values', so are never weak */ + return 0; + } + else return iswhite(o); +} + + +/* +** Barrier that moves collector forward, that is, marks the white object +** 'v' being pointed by the black object 'o'. In the generational +** mode, 'v' must also become old, if 'o' is old; however, it cannot +** be changed directly to OLD, because it may still point to non-old +** objects. So, it is marked as OLD0. In the next cycle it will become +** OLD1, and in the next it will finally become OLD (regular old). By +** then, any object it points to will also be old. If called in the +** incremental sweep phase, it clears the black object to white (sweep +** it) to avoid other barrier calls for this same object. (That cannot +** be done is generational mode, as its sweep does not distinguish +** whites from deads.) +*/ +void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { + global_State *g = G(L); + lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); + if (keepinvariant(g)) { /* must keep invariant? */ + reallymarkobject(g, v); /* restore invariant */ + if (isold(o)) { + lua_assert(!isold(v)); /* white object could not be old */ + setage(v, G_OLD0); /* restore generational invariant */ + } + } + else { /* sweep phase */ + lua_assert(issweepphase(g)); + if (g->gckind == KGC_INC) /* incremental mode? */ + makewhite(g, o); /* mark 'o' as white to avoid other barriers */ + } +} + + +/* +** barrier that moves collector backward, that is, mark the black object +** pointing to a white object as gray again. +*/ +void luaC_barrierback_ (lua_State *L, GCObject *o) { + global_State *g = G(L); + lua_assert(isblack(o) && !isdead(g, o)); + lua_assert((g->gckind == KGC_GEN) == (isold(o) && getage(o) != G_TOUCHED1)); + if (getage(o) == G_TOUCHED2) /* already in gray list? */ + set2gray(o); /* make it gray to become touched1 */ + else /* link it in 'grayagain' and paint it gray */ + linkobjgclist(o, g->grayagain); + if (isold(o)) /* generational mode? */ + setage(o, G_TOUCHED1); /* touched in current cycle */ +} + + +void luaC_fix (lua_State *L, GCObject *o) { + global_State *g = G(L); + lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ + set2gray(o); /* they will be gray forever */ + setage(o, G_OLD); /* and old forever */ + g->allgc = o->next; /* remove object from 'allgc' list */ + o->next = g->fixedgc; /* link it to 'fixedgc' list */ + g->fixedgc = o; +} + + +/* +** create a new collectable object (with given type, size, and offset) +** and link it to 'allgc' list. +*/ +GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) { + global_State *g = G(L); + char *p = cast_charp(luaM_newobject(L, novariant(tt), sz)); + GCObject *o = cast(GCObject *, p + offset); + o->marked = luaC_white(g); + o->tt = tt; + o->next = g->allgc; + g->allgc = o; + return o; +} + + +GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { + return luaC_newobjdt(L, tt, sz, 0); +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** Mark functions +** ======================================================= +*/ + + +/* +** Mark an object. Userdata with no user values, strings, and closed +** upvalues are visited and turned black here. Open upvalues are +** already indirectly linked through their respective threads in the +** 'twups' list, so they don't go to the gray list; nevertheless, they +** are kept gray to avoid barriers, as their values will be revisited +** by the thread or by 'remarkupvals'. Other objects are added to the +** gray list to be visited (and turned black) later. Both userdata and +** upvalues can call this function recursively, but this recursion goes +** for at most two levels: An upvalue cannot refer to another upvalue +** (only closures can), and a userdata's metatable must be a table. +*/ +static void reallymarkobject (global_State *g, GCObject *o) { + switch (o->tt) { + case LUA_VSHRSTR: + case LUA_VLNGSTR: { + set2black(o); /* nothing to visit */ + break; + } + case LUA_VUPVAL: { + UpVal *uv = gco2upv(o); + if (upisopen(uv)) + set2gray(uv); /* open upvalues are kept gray */ + else + set2black(uv); /* closed upvalues are visited here */ + markvalue(g, uv->v.p); /* mark its content */ + break; + } + case LUA_VUSERDATA: { + Udata *u = gco2u(o); + if (u->nuvalue == 0) { /* no user values? */ + markobjectN(g, u->metatable); /* mark its metatable */ + set2black(u); /* nothing else to mark */ + break; + } + /* else... */ + } /* FALLTHROUGH */ + case LUA_VLCL: case LUA_VCCL: case LUA_VTABLE: + case LUA_VTHREAD: case LUA_VPROTO: { + linkobjgclist(o, g->gray); /* to be visited later */ + break; + } + default: lua_assert(0); break; + } +} + + +/* +** mark metamethods for basic types +*/ +static void markmt (global_State *g) { + int i; + for (i=0; i < LUA_NUMTAGS; i++) + markobjectN(g, g->mt[i]); +} + + +/* +** mark all objects in list of being-finalized +*/ +static lu_mem markbeingfnz (global_State *g) { + GCObject *o; + lu_mem count = 0; + for (o = g->tobefnz; o != NULL; o = o->next) { + count++; + markobject(g, o); + } + return count; +} + + +/* +** For each non-marked thread, simulates a barrier between each open +** upvalue and its value. (If the thread is collected, the value will be +** assigned to the upvalue, but then it can be too late for the barrier +** to act. The "barrier" does not need to check colors: A non-marked +** thread must be young; upvalues cannot be older than their threads; so +** any visited upvalue must be young too.) Also removes the thread from +** the list, as it was already visited. Removes also threads with no +** upvalues, as they have nothing to be checked. (If the thread gets an +** upvalue later, it will be linked in the list again.) +*/ +static int remarkupvals (global_State *g) { + lua_State *thread; + lua_State **p = &g->twups; + int work = 0; /* estimate of how much work was done here */ + while ((thread = *p) != NULL) { + work++; + if (!iswhite(thread) && thread->openupval != NULL) + p = &thread->twups; /* keep marked thread with upvalues in the list */ + else { /* thread is not marked or without upvalues */ + UpVal *uv; + lua_assert(!isold(thread) || thread->openupval == NULL); + *p = thread->twups; /* remove thread from the list */ + thread->twups = thread; /* mark that it is out of list */ + for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { + lua_assert(getage(uv) <= getage(thread)); + work++; + if (!iswhite(uv)) { /* upvalue already visited? */ + lua_assert(upisopen(uv) && isgray(uv)); + markvalue(g, uv->v.p); /* mark its value */ + } + } + } + } + return work; +} + + +static void cleargraylists (global_State *g) { + g->gray = g->grayagain = NULL; + g->weak = g->allweak = g->ephemeron = NULL; +} + + +/* +** mark root set and reset all gray lists, to start a new collection +*/ +static void restartcollection (global_State *g) { + cleargraylists(g); + markobject(g, g->mainthread); + markvalue(g, &g->l_registry); + markmt(g); + markbeingfnz(g); /* mark any finalizing object left from previous cycle */ +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Traverse functions +** ======================================================= +*/ + + +/* +** Check whether object 'o' should be kept in the 'grayagain' list for +** post-processing by 'correctgraylist'. (It could put all old objects +** in the list and leave all the work to 'correctgraylist', but it is +** more efficient to avoid adding elements that will be removed.) Only +** TOUCHED1 objects need to be in the list. TOUCHED2 doesn't need to go +** back to a gray list, but then it must become OLD. (That is what +** 'correctgraylist' does when it finds a TOUCHED2 object.) +*/ +static void genlink (global_State *g, GCObject *o) { + lua_assert(isblack(o)); + if (getage(o) == G_TOUCHED1) { /* touched in this cycle? */ + linkobjgclist(o, g->grayagain); /* link it back in 'grayagain' */ + } /* everything else do not need to be linked back */ + else if (getage(o) == G_TOUCHED2) + changeage(o, G_TOUCHED2, G_OLD); /* advance age */ +} + + +/* +** Traverse a table with weak values and link it to proper list. During +** propagate phase, keep it in 'grayagain' list, to be revisited in the +** atomic phase. In the atomic phase, if table has any white value, +** put it in 'weak' list, to be cleared. +*/ +static void traverseweakvalue (global_State *g, Table *h) { + Node *n, *limit = gnodelast(h); + /* if there is array part, assume it may have white values (it is not + worth traversing it now just to check) */ + int hasclears = (h->alimit > 0); + for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ + if (isempty(gval(n))) /* entry is empty? */ + clearkey(n); /* clear its key */ + else { + lua_assert(!keyisnil(n)); + markkey(g, n); + if (!hasclears && iscleared(g, gcvalueN(gval(n)))) /* a white value? */ + hasclears = 1; /* table will have to be cleared */ + } + } + if (g->gcstate == GCSatomic && hasclears) + linkgclist(h, g->weak); /* has to be cleared later */ + else + linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ +} + + +/* +** Traverse an ephemeron table and link it to proper list. Returns true +** iff any object was marked during this traversal (which implies that +** convergence has to continue). During propagation phase, keep table +** in 'grayagain' list, to be visited again in the atomic phase. In +** the atomic phase, if table has any white->white entry, it has to +** be revisited during ephemeron convergence (as that key may turn +** black). Otherwise, if it has any white key, table has to be cleared +** (in the atomic phase). In generational mode, some tables +** must be kept in some gray list for post-processing; this is done +** by 'genlink'. +*/ +static int traverseephemeron (global_State *g, Table *h, int inv) { + int marked = 0; /* true if an object is marked in this traversal */ + int hasclears = 0; /* true if table has white keys */ + int hasww = 0; /* true if table has entry "white-key -> white-value" */ + unsigned int i; + unsigned int asize = luaH_realasize(h); + unsigned int nsize = sizenode(h); + /* traverse array part */ + for (i = 0; i < asize; i++) { + if (valiswhite(&h->array[i])) { + marked = 1; + reallymarkobject(g, gcvalue(&h->array[i])); + } + } + /* traverse hash part; if 'inv', traverse descending + (see 'convergeephemerons') */ + for (i = 0; i < nsize; i++) { + Node *n = inv ? gnode(h, nsize - 1 - i) : gnode(h, i); + if (isempty(gval(n))) /* entry is empty? */ + clearkey(n); /* clear its key */ + else if (iscleared(g, gckeyN(n))) { /* key is not marked (yet)? */ + hasclears = 1; /* table must be cleared */ + if (valiswhite(gval(n))) /* value not marked yet? */ + hasww = 1; /* white-white entry */ + } + else if (valiswhite(gval(n))) { /* value not marked yet? */ + marked = 1; + reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ + } + } + /* link table into proper list */ + if (g->gcstate == GCSpropagate) + linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ + else if (hasww) /* table has white->white entries? */ + linkgclist(h, g->ephemeron); /* have to propagate again */ + else if (hasclears) /* table has white keys? */ + linkgclist(h, g->allweak); /* may have to clean white keys */ + else + genlink(g, obj2gco(h)); /* check whether collector still needs to see it */ + return marked; +} + + +static void traversestrongtable (global_State *g, Table *h) { + Node *n, *limit = gnodelast(h); + unsigned int i; + unsigned int asize = luaH_realasize(h); + for (i = 0; i < asize; i++) /* traverse array part */ + markvalue(g, &h->array[i]); + for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ + if (isempty(gval(n))) /* entry is empty? */ + clearkey(n); /* clear its key */ + else { + lua_assert(!keyisnil(n)); + markkey(g, n); + markvalue(g, gval(n)); + } + } + genlink(g, obj2gco(h)); +} + + +static lu_mem traversetable (global_State *g, Table *h) { + const char *weakkey, *weakvalue; + const TValue *mode = gfasttm(g, h->metatable, TM_MODE); + markobjectN(g, h->metatable); + if (mode && ttisstring(mode) && /* is there a weak mode? */ + (cast_void(weakkey = strchr(svalue(mode), 'k')), + cast_void(weakvalue = strchr(svalue(mode), 'v')), + (weakkey || weakvalue))) { /* is really weak? */ + if (!weakkey) /* strong keys? */ + traverseweakvalue(g, h); + else if (!weakvalue) /* strong values? */ + traverseephemeron(g, h, 0); + else /* all weak */ + linkgclist(h, g->allweak); /* nothing to traverse now */ + } + else /* not weak */ + traversestrongtable(g, h); + return 1 + h->alimit + 2 * allocsizenode(h); +} + + +static int traverseudata (global_State *g, Udata *u) { + int i; + markobjectN(g, u->metatable); /* mark its metatable */ + for (i = 0; i < u->nuvalue; i++) + markvalue(g, &u->uv[i].uv); + genlink(g, obj2gco(u)); + return 1 + u->nuvalue; +} + + +/* +** Traverse a prototype. (While a prototype is being build, its +** arrays can be larger than needed; the extra slots are filled with +** NULL, so the use of 'markobjectN') +*/ +static int traverseproto (global_State *g, Proto *f) { + int i; + markobjectN(g, f->source); + for (i = 0; i < f->sizek; i++) /* mark literals */ + markvalue(g, &f->k[i]); + for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */ + markobjectN(g, f->upvalues[i].name); + for (i = 0; i < f->sizep; i++) /* mark nested protos */ + markobjectN(g, f->p[i]); + for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ + markobjectN(g, f->locvars[i].varname); + return 1 + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars; +} + + +static int traverseCclosure (global_State *g, CClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ + markvalue(g, &cl->upvalue[i]); + return 1 + cl->nupvalues; +} + +/* +** Traverse a Lua closure, marking its prototype and its upvalues. +** (Both can be NULL while closure is being created.) +*/ +static int traverseLclosure (global_State *g, LClosure *cl) { + int i; + markobjectN(g, cl->p); /* mark its prototype */ + for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ + UpVal *uv = cl->upvals[i]; + markobjectN(g, uv); /* mark upvalue */ + } + return 1 + cl->nupvalues; +} + + +/* +** Traverse a thread, marking the elements in the stack up to its top +** and cleaning the rest of the stack in the final traversal. That +** ensures that the entire stack have valid (non-dead) objects. +** Threads have no barriers. In gen. mode, old threads must be visited +** at every cycle, because they might point to young objects. In inc. +** mode, the thread can still be modified before the end of the cycle, +** and therefore it must be visited again in the atomic phase. To ensure +** these visits, threads must return to a gray list if they are not new +** (which can only happen in generational mode) or if the traverse is in +** the propagate phase (which can only happen in incremental mode). +*/ +static int traversethread (global_State *g, lua_State *th) { + UpVal *uv; + StkId o = th->stack.p; + if (isold(th) || g->gcstate == GCSpropagate) + linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ + if (o == NULL) + return 1; /* stack not completely built yet */ + lua_assert(g->gcstate == GCSatomic || + th->openupval == NULL || isintwups(th)); + for (; o < th->top.p; o++) /* mark live elements in the stack */ + markvalue(g, s2v(o)); + for (uv = th->openupval; uv != NULL; uv = uv->u.open.next) + markobject(g, uv); /* open upvalues cannot be collected */ + if (g->gcstate == GCSatomic) { /* final traversal? */ + for (; o < th->stack_last.p + EXTRA_STACK; o++) + setnilvalue(s2v(o)); /* clear dead stack slice */ + /* 'remarkupvals' may have removed thread from 'twups' list */ + if (!isintwups(th) && th->openupval != NULL) { + th->twups = g->twups; /* link it back to the list */ + g->twups = th; + } + } + else if (!g->gcemergency) + luaD_shrinkstack(th); /* do not change stack in emergency cycle */ + return 1 + stacksize(th); +} + + +/* +** traverse one gray object, turning it to black. +*/ +static lu_mem propagatemark (global_State *g) { + GCObject *o = g->gray; + nw2black(o); + g->gray = *getgclist(o); /* remove from 'gray' list */ + switch (o->tt) { + case LUA_VTABLE: return traversetable(g, gco2t(o)); + case LUA_VUSERDATA: return traverseudata(g, gco2u(o)); + case LUA_VLCL: return traverseLclosure(g, gco2lcl(o)); + case LUA_VCCL: return traverseCclosure(g, gco2ccl(o)); + case LUA_VPROTO: return traverseproto(g, gco2p(o)); + case LUA_VTHREAD: return traversethread(g, gco2th(o)); + default: lua_assert(0); return 0; + } +} + + +static lu_mem propagateall (global_State *g) { + lu_mem tot = 0; + while (g->gray) + tot += propagatemark(g); + return tot; +} + + +/* +** Traverse all ephemeron tables propagating marks from keys to values. +** Repeat until it converges, that is, nothing new is marked. 'dir' +** inverts the direction of the traversals, trying to speed up +** convergence on chains in the same table. +** +*/ +static void convergeephemerons (global_State *g) { + int changed; + int dir = 0; + do { + GCObject *w; + GCObject *next = g->ephemeron; /* get ephemeron list */ + g->ephemeron = NULL; /* tables may return to this list when traversed */ + changed = 0; + while ((w = next) != NULL) { /* for each ephemeron table */ + Table *h = gco2t(w); + next = h->gclist; /* list is rebuilt during loop */ + nw2black(h); /* out of the list (for now) */ + if (traverseephemeron(g, h, dir)) { /* marked some value? */ + propagateall(g); /* propagate changes */ + changed = 1; /* will have to revisit all ephemeron tables */ + } + } + dir = !dir; /* invert direction next time */ + } while (changed); /* repeat until no more changes */ +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Sweep Functions +** ======================================================= +*/ + + +/* +** clear entries with unmarked keys from all weaktables in list 'l' +*/ +static void clearbykeys (global_State *g, GCObject *l) { + for (; l; l = gco2t(l)->gclist) { + Table *h = gco2t(l); + Node *limit = gnodelast(h); + Node *n; + for (n = gnode(h, 0); n < limit; n++) { + if (iscleared(g, gckeyN(n))) /* unmarked key? */ + setempty(gval(n)); /* remove entry */ + if (isempty(gval(n))) /* is entry empty? */ + clearkey(n); /* clear its key */ + } + } +} + + +/* +** clear entries with unmarked values from all weaktables in list 'l' up +** to element 'f' +*/ +static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) { + for (; l != f; l = gco2t(l)->gclist) { + Table *h = gco2t(l); + Node *n, *limit = gnodelast(h); + unsigned int i; + unsigned int asize = luaH_realasize(h); + for (i = 0; i < asize; i++) { + TValue *o = &h->array[i]; + if (iscleared(g, gcvalueN(o))) /* value was collected? */ + setempty(o); /* remove entry */ + } + for (n = gnode(h, 0); n < limit; n++) { + if (iscleared(g, gcvalueN(gval(n)))) /* unmarked value? */ + setempty(gval(n)); /* remove entry */ + if (isempty(gval(n))) /* is entry empty? */ + clearkey(n); /* clear its key */ + } + } +} + + +static void freeupval (lua_State *L, UpVal *uv) { + if (upisopen(uv)) + luaF_unlinkupval(uv); + luaM_free(L, uv); +} + + +static void freeobj (lua_State *L, GCObject *o) { + switch (o->tt) { + case LUA_VPROTO: + luaF_freeproto(L, gco2p(o)); + break; + case LUA_VUPVAL: + freeupval(L, gco2upv(o)); + break; + case LUA_VLCL: { + LClosure *cl = gco2lcl(o); + luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); + break; + } + case LUA_VCCL: { + CClosure *cl = gco2ccl(o); + luaM_freemem(L, cl, sizeCclosure(cl->nupvalues)); + break; + } + case LUA_VTABLE: + luaH_free(L, gco2t(o)); + break; + case LUA_VTHREAD: + luaE_freethread(L, gco2th(o)); + break; + case LUA_VUSERDATA: { + Udata *u = gco2u(o); + luaM_freemem(L, o, sizeudata(u->nuvalue, u->len)); + break; + } + case LUA_VSHRSTR: { + TString *ts = gco2ts(o); + luaS_remove(L, ts); /* remove it from hash table */ + luaM_freemem(L, ts, sizelstring(ts->shrlen)); + break; + } + case LUA_VLNGSTR: { + TString *ts = gco2ts(o); + luaM_freemem(L, ts, sizelstring(ts->u.lnglen)); + break; + } + default: lua_assert(0); + } +} + + +/* +** sweep at most 'countin' elements from a list of GCObjects erasing dead +** objects, where a dead object is one marked with the old (non current) +** white; change all non-dead objects back to white, preparing for next +** collection cycle. Return where to continue the traversal or NULL if +** list is finished. ('*countout' gets the number of elements traversed.) +*/ +static GCObject **sweeplist (lua_State *L, GCObject **p, int countin, + int *countout) { + global_State *g = G(L); + int ow = otherwhite(g); + int i; + int white = luaC_white(g); /* current white */ + for (i = 0; *p != NULL && i < countin; i++) { + GCObject *curr = *p; + int marked = curr->marked; + if (isdeadm(ow, marked)) { /* is 'curr' dead? */ + *p = curr->next; /* remove 'curr' from list */ + freeobj(L, curr); /* erase 'curr' */ + } + else { /* change mark to 'white' */ + curr->marked = cast_byte((marked & ~maskgcbits) | white); + p = &curr->next; /* go to next element */ + } + } + if (countout) + *countout = i; /* number of elements traversed */ + return (*p == NULL) ? NULL : p; +} + + +/* +** sweep a list until a live object (or end of list) +*/ +static GCObject **sweeptolive (lua_State *L, GCObject **p) { + GCObject **old = p; + do { + p = sweeplist(L, p, 1, NULL); + } while (p == old); + return p; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Finalization +** ======================================================= +*/ + +/* +** If possible, shrink string table. +*/ +static void checkSizes (lua_State *L, global_State *g) { + if (!g->gcemergency) { + if (g->strt.nuse < g->strt.size / 4) { /* string table too big? */ + l_mem olddebt = g->GCdebt; + luaS_resize(L, g->strt.size / 2); + g->GCestimate += g->GCdebt - olddebt; /* correct estimate */ + } + } +} + + +/* +** Get the next udata to be finalized from the 'tobefnz' list, and +** link it back into the 'allgc' list. +*/ +static GCObject *udata2finalize (global_State *g) { + GCObject *o = g->tobefnz; /* get first element */ + lua_assert(tofinalize(o)); + g->tobefnz = o->next; /* remove it from 'tobefnz' list */ + o->next = g->allgc; /* return it to 'allgc' list */ + g->allgc = o; + resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */ + if (issweepphase(g)) + makewhite(g, o); /* "sweep" object */ + else if (getage(o) == G_OLD1) + g->firstold1 = o; /* it is the first OLD1 object in the list */ + return o; +} + + +static void dothecall (lua_State *L, void *ud) { + UNUSED(ud); + luaD_callnoyield(L, L->top.p - 2, 0); +} + + +static void GCTM (lua_State *L) { + global_State *g = G(L); + const TValue *tm; + TValue v; + lua_assert(!g->gcemergency); + setgcovalue(L, &v, udata2finalize(g)); + tm = luaT_gettmbyobj(L, &v, TM_GC); + if (!notm(tm)) { /* is there a finalizer? */ + int status; + lu_byte oldah = L->allowhook; + int oldgcstp = g->gcstp; + g->gcstp |= GCSTPGC; /* avoid GC steps */ + L->allowhook = 0; /* stop debug hooks during GC metamethod */ + setobj2s(L, L->top.p++, tm); /* push finalizer... */ + setobj2s(L, L->top.p++, &v); /* ... and its argument */ + L->ci->callstatus |= CIST_FIN; /* will run a finalizer */ + status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top.p - 2), 0); + L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ + L->allowhook = oldah; /* restore hooks */ + g->gcstp = oldgcstp; /* restore state */ + if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */ + luaE_warnerror(L, "__gc"); + L->top.p--; /* pops error object */ + } + } +} + + +/* +** Call a few finalizers +*/ +static int runafewfinalizers (lua_State *L, int n) { + global_State *g = G(L); + int i; + for (i = 0; i < n && g->tobefnz; i++) + GCTM(L); /* call one finalizer */ + return i; +} + + +/* +** call all pending finalizers +*/ +static void callallpendingfinalizers (lua_State *L) { + global_State *g = G(L); + while (g->tobefnz) + GCTM(L); +} + + +/* +** find last 'next' field in list 'p' list (to add elements in its end) +*/ +static GCObject **findlast (GCObject **p) { + while (*p != NULL) + p = &(*p)->next; + return p; +} + + +/* +** Move all unreachable objects (or 'all' objects) that need +** finalization from list 'finobj' to list 'tobefnz' (to be finalized). +** (Note that objects after 'finobjold1' cannot be white, so they +** don't need to be traversed. In incremental mode, 'finobjold1' is NULL, +** so the whole list is traversed.) +*/ +static void separatetobefnz (global_State *g, int all) { + GCObject *curr; + GCObject **p = &g->finobj; + GCObject **lastnext = findlast(&g->tobefnz); + while ((curr = *p) != g->finobjold1) { /* traverse all finalizable objects */ + lua_assert(tofinalize(curr)); + if (!(iswhite(curr) || all)) /* not being collected? */ + p = &curr->next; /* don't bother with it */ + else { + if (curr == g->finobjsur) /* removing 'finobjsur'? */ + g->finobjsur = curr->next; /* correct it */ + *p = curr->next; /* remove 'curr' from 'finobj' list */ + curr->next = *lastnext; /* link at the end of 'tobefnz' list */ + *lastnext = curr; + lastnext = &curr->next; + } + } +} + + +/* +** If pointer 'p' points to 'o', move it to the next element. +*/ +static void checkpointer (GCObject **p, GCObject *o) { + if (o == *p) + *p = o->next; +} + + +/* +** Correct pointers to objects inside 'allgc' list when +** object 'o' is being removed from the list. +*/ +static void correctpointers (global_State *g, GCObject *o) { + checkpointer(&g->survival, o); + checkpointer(&g->old1, o); + checkpointer(&g->reallyold, o); + checkpointer(&g->firstold1, o); +} + + +/* +** if object 'o' has a finalizer, remove it from 'allgc' list (must +** search the list to find it) and link it in 'finobj' list. +*/ +void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { + global_State *g = G(L); + if (tofinalize(o) || /* obj. is already marked... */ + gfasttm(g, mt, TM_GC) == NULL || /* or has no finalizer... */ + (g->gcstp & GCSTPCLS)) /* or closing state? */ + return; /* nothing to be done */ + else { /* move 'o' to 'finobj' list */ + GCObject **p; + if (issweepphase(g)) { + makewhite(g, o); /* "sweep" object 'o' */ + if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ + g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */ + } + else + correctpointers(g, o); + /* search for pointer pointing to 'o' */ + for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } + *p = o->next; /* remove 'o' from 'allgc' list */ + o->next = g->finobj; /* link it in 'finobj' list */ + g->finobj = o; + l_setbit(o->marked, FINALIZEDBIT); /* mark it as such */ + } +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Generational Collector +** ======================================================= +*/ + + +/* +** Set the "time" to wait before starting a new GC cycle; cycle will +** start when memory use hits the threshold of ('estimate' * pause / +** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero, +** because Lua cannot even start with less than PAUSEADJ bytes). +*/ +static void setpause (global_State *g) { + l_mem threshold, debt; + int pause = getgcparam(g->gcpause); + l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */ + lua_assert(estimate > 0); + threshold = (pause < MAX_LMEM / estimate) /* overflow? */ + ? estimate * pause /* no overflow */ + : MAX_LMEM; /* overflow; truncate to maximum */ + debt = gettotalbytes(g) - threshold; + if (debt > 0) debt = 0; + luaE_setdebt(g, debt); +} + + +/* +** Sweep a list of objects to enter generational mode. Deletes dead +** objects and turns the non dead to old. All non-dead threads---which +** are now old---must be in a gray list. Everything else is not in a +** gray list. Open upvalues are also kept gray. +*/ +static void sweep2old (lua_State *L, GCObject **p) { + GCObject *curr; + global_State *g = G(L); + while ((curr = *p) != NULL) { + if (iswhite(curr)) { /* is 'curr' dead? */ + lua_assert(isdead(g, curr)); + *p = curr->next; /* remove 'curr' from list */ + freeobj(L, curr); /* erase 'curr' */ + } + else { /* all surviving objects become old */ + setage(curr, G_OLD); + if (curr->tt == LUA_VTHREAD) { /* threads must be watched */ + lua_State *th = gco2th(curr); + linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ + } + else if (curr->tt == LUA_VUPVAL && upisopen(gco2upv(curr))) + set2gray(curr); /* open upvalues are always gray */ + else /* everything else is black */ + nw2black(curr); + p = &curr->next; /* go to next element */ + } + } +} + + +/* +** Sweep for generational mode. Delete dead objects. (Because the +** collection is not incremental, there are no "new white" objects +** during the sweep. So, any white object must be dead.) For +** non-dead objects, advance their ages and clear the color of +** new objects. (Old objects keep their colors.) +** The ages of G_TOUCHED1 and G_TOUCHED2 objects cannot be advanced +** here, because these old-generation objects are usually not swept +** here. They will all be advanced in 'correctgraylist'. That function +** will also remove objects turned white here from any gray list. +*/ +static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, + GCObject *limit, GCObject **pfirstold1) { + static const lu_byte nextage[] = { + G_SURVIVAL, /* from G_NEW */ + G_OLD1, /* from G_SURVIVAL */ + G_OLD1, /* from G_OLD0 */ + G_OLD, /* from G_OLD1 */ + G_OLD, /* from G_OLD (do not change) */ + G_TOUCHED1, /* from G_TOUCHED1 (do not change) */ + G_TOUCHED2 /* from G_TOUCHED2 (do not change) */ + }; + int white = luaC_white(g); + GCObject *curr; + while ((curr = *p) != limit) { + if (iswhite(curr)) { /* is 'curr' dead? */ + lua_assert(!isold(curr) && isdead(g, curr)); + *p = curr->next; /* remove 'curr' from list */ + freeobj(L, curr); /* erase 'curr' */ + } + else { /* correct mark and age */ + if (getage(curr) == G_NEW) { /* new objects go back to white */ + int marked = curr->marked & ~maskgcbits; /* erase GC bits */ + curr->marked = cast_byte(marked | G_SURVIVAL | white); + } + else { /* all other objects will be old, and so keep their color */ + setage(curr, nextage[getage(curr)]); + if (getage(curr) == G_OLD1 && *pfirstold1 == NULL) + *pfirstold1 = curr; /* first OLD1 object in the list */ + } + p = &curr->next; /* go to next element */ + } + } + return p; +} + + +/* +** Traverse a list making all its elements white and clearing their +** age. In incremental mode, all objects are 'new' all the time, +** except for fixed strings (which are always old). +*/ +static void whitelist (global_State *g, GCObject *p) { + int white = luaC_white(g); + for (; p != NULL; p = p->next) + p->marked = cast_byte((p->marked & ~maskgcbits) | white); +} + + +/* +** Correct a list of gray objects. Return pointer to where rest of the +** list should be linked. +** Because this correction is done after sweeping, young objects might +** be turned white and still be in the list. They are only removed. +** 'TOUCHED1' objects are advanced to 'TOUCHED2' and remain on the list; +** Non-white threads also remain on the list; 'TOUCHED2' objects become +** regular old; they and anything else are removed from the list. +*/ +static GCObject **correctgraylist (GCObject **p) { + GCObject *curr; + while ((curr = *p) != NULL) { + GCObject **next = getgclist(curr); + if (iswhite(curr)) + goto remove; /* remove all white objects */ + else if (getage(curr) == G_TOUCHED1) { /* touched in this cycle? */ + lua_assert(isgray(curr)); + nw2black(curr); /* make it black, for next barrier */ + changeage(curr, G_TOUCHED1, G_TOUCHED2); + goto remain; /* keep it in the list and go to next element */ + } + else if (curr->tt == LUA_VTHREAD) { + lua_assert(isgray(curr)); + goto remain; /* keep non-white threads on the list */ + } + else { /* everything else is removed */ + lua_assert(isold(curr)); /* young objects should be white here */ + if (getage(curr) == G_TOUCHED2) /* advance from TOUCHED2... */ + changeage(curr, G_TOUCHED2, G_OLD); /* ... to OLD */ + nw2black(curr); /* make object black (to be removed) */ + goto remove; + } + remove: *p = *next; continue; + remain: p = next; continue; + } + return p; +} + + +/* +** Correct all gray lists, coalescing them into 'grayagain'. +*/ +static void correctgraylists (global_State *g) { + GCObject **list = correctgraylist(&g->grayagain); + *list = g->weak; g->weak = NULL; + list = correctgraylist(list); + *list = g->allweak; g->allweak = NULL; + list = correctgraylist(list); + *list = g->ephemeron; g->ephemeron = NULL; + correctgraylist(list); +} + + +/* +** Mark black 'OLD1' objects when starting a new young collection. +** Gray objects are already in some gray list, and so will be visited +** in the atomic step. +*/ +static void markold (global_State *g, GCObject *from, GCObject *to) { + GCObject *p; + for (p = from; p != to; p = p->next) { + if (getage(p) == G_OLD1) { + lua_assert(!iswhite(p)); + changeage(p, G_OLD1, G_OLD); /* now they are old */ + if (isblack(p)) + reallymarkobject(g, p); + } + } +} + + +/* +** Finish a young-generation collection. +*/ +static void finishgencycle (lua_State *L, global_State *g) { + correctgraylists(g); + checkSizes(L, g); + g->gcstate = GCSpropagate; /* skip restart */ + if (!g->gcemergency) + callallpendingfinalizers(L); +} + + +/* +** Does a young collection. First, mark 'OLD1' objects. Then does the +** atomic step. Then, sweep all lists and advance pointers. Finally, +** finish the collection. +*/ +static void youngcollection (lua_State *L, global_State *g) { + GCObject **psurvival; /* to point to first non-dead survival object */ + GCObject *dummy; /* dummy out parameter to 'sweepgen' */ + lua_assert(g->gcstate == GCSpropagate); + if (g->firstold1) { /* are there regular OLD1 objects? */ + markold(g, g->firstold1, g->reallyold); /* mark them */ + g->firstold1 = NULL; /* no more OLD1 objects (for now) */ + } + markold(g, g->finobj, g->finobjrold); + markold(g, g->tobefnz, NULL); + atomic(L); + + /* sweep nursery and get a pointer to its last live element */ + g->gcstate = GCSswpallgc; + psurvival = sweepgen(L, g, &g->allgc, g->survival, &g->firstold1); + /* sweep 'survival' */ + sweepgen(L, g, psurvival, g->old1, &g->firstold1); + g->reallyold = g->old1; + g->old1 = *psurvival; /* 'survival' survivals are old now */ + g->survival = g->allgc; /* all news are survivals */ + + /* repeat for 'finobj' lists */ + dummy = NULL; /* no 'firstold1' optimization for 'finobj' lists */ + psurvival = sweepgen(L, g, &g->finobj, g->finobjsur, &dummy); + /* sweep 'survival' */ + sweepgen(L, g, psurvival, g->finobjold1, &dummy); + g->finobjrold = g->finobjold1; + g->finobjold1 = *psurvival; /* 'survival' survivals are old now */ + g->finobjsur = g->finobj; /* all news are survivals */ + + sweepgen(L, g, &g->tobefnz, NULL, &dummy); + finishgencycle(L, g); +} + + +/* +** Clears all gray lists, sweeps objects, and prepare sublists to enter +** generational mode. The sweeps remove dead objects and turn all +** surviving objects to old. Threads go back to 'grayagain'; everything +** else is turned black (not in any gray list). +*/ +static void atomic2gen (lua_State *L, global_State *g) { + cleargraylists(g); + /* sweep all elements making them old */ + g->gcstate = GCSswpallgc; + sweep2old(L, &g->allgc); + /* everything alive now is old */ + g->reallyold = g->old1 = g->survival = g->allgc; + g->firstold1 = NULL; /* there are no OLD1 objects anywhere */ + + /* repeat for 'finobj' lists */ + sweep2old(L, &g->finobj); + g->finobjrold = g->finobjold1 = g->finobjsur = g->finobj; + + sweep2old(L, &g->tobefnz); + + g->gckind = KGC_GEN; + g->lastatomic = 0; + g->GCestimate = gettotalbytes(g); /* base for memory control */ + finishgencycle(L, g); +} + + +/* +** Set debt for the next minor collection, which will happen when +** memory grows 'genminormul'%. +*/ +static void setminordebt (global_State *g) { + luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul)); +} + + +/* +** Enter generational mode. Must go until the end of an atomic cycle +** to ensure that all objects are correctly marked and weak tables +** are cleared. Then, turn all objects into old and finishes the +** collection. +*/ +static lu_mem entergen (lua_State *L, global_State *g) { + lu_mem numobjs; + luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */ + luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ + numobjs = atomic(L); /* propagates all and then do the atomic stuff */ + atomic2gen(L, g); + setminordebt(g); /* set debt assuming next cycle will be minor */ + return numobjs; +} + + +/* +** Enter incremental mode. Turn all objects white, make all +** intermediate lists point to NULL (to avoid invalid pointers), +** and go to the pause state. +*/ +static void enterinc (global_State *g) { + whitelist(g, g->allgc); + g->reallyold = g->old1 = g->survival = NULL; + whitelist(g, g->finobj); + whitelist(g, g->tobefnz); + g->finobjrold = g->finobjold1 = g->finobjsur = NULL; + g->gcstate = GCSpause; + g->gckind = KGC_INC; + g->lastatomic = 0; +} + + +/* +** Change collector mode to 'newmode'. +*/ +void luaC_changemode (lua_State *L, int newmode) { + global_State *g = G(L); + if (newmode != g->gckind) { + if (newmode == KGC_GEN) /* entering generational mode? */ + entergen(L, g); + else + enterinc(g); /* entering incremental mode */ + } + g->lastatomic = 0; +} + + +/* +** Does a full collection in generational mode. +*/ +static lu_mem fullgen (lua_State *L, global_State *g) { + enterinc(g); + return entergen(L, g); +} + + +/* +** Does a major collection after last collection was a "bad collection". +** +** When the program is building a big structure, it allocates lots of +** memory but generates very little garbage. In those scenarios, +** the generational mode just wastes time doing small collections, and +** major collections are frequently what we call a "bad collection", a +** collection that frees too few objects. To avoid the cost of switching +** between generational mode and the incremental mode needed for full +** (major) collections, the collector tries to stay in incremental mode +** after a bad collection, and to switch back to generational mode only +** after a "good" collection (one that traverses less than 9/8 objects +** of the previous one). +** The collector must choose whether to stay in incremental mode or to +** switch back to generational mode before sweeping. At this point, it +** does not know the real memory in use, so it cannot use memory to +** decide whether to return to generational mode. Instead, it uses the +** number of objects traversed (returned by 'atomic') as a proxy. The +** field 'g->lastatomic' keeps this count from the last collection. +** ('g->lastatomic != 0' also means that the last collection was bad.) +*/ +static void stepgenfull (lua_State *L, global_State *g) { + lu_mem newatomic; /* count of traversed objects */ + lu_mem lastatomic = g->lastatomic; /* count from last collection */ + if (g->gckind == KGC_GEN) /* still in generational mode? */ + enterinc(g); /* enter incremental mode */ + luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ + newatomic = atomic(L); /* mark everybody */ + if (newatomic < lastatomic + (lastatomic >> 3)) { /* good collection? */ + atomic2gen(L, g); /* return to generational mode */ + setminordebt(g); + } + else { /* another bad collection; stay in incremental mode */ + g->GCestimate = gettotalbytes(g); /* first estimate */; + entersweep(L); + luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ + setpause(g); + g->lastatomic = newatomic; + } +} + + +/* +** Does a generational "step". +** Usually, this means doing a minor collection and setting the debt to +** make another collection when memory grows 'genminormul'% larger. +** +** However, there are exceptions. If memory grows 'genmajormul'% +** larger than it was at the end of the last major collection (kept +** in 'g->GCestimate'), the function does a major collection. At the +** end, it checks whether the major collection was able to free a +** decent amount of memory (at least half the growth in memory since +** previous major collection). If so, the collector keeps its state, +** and the next collection will probably be minor again. Otherwise, +** we have what we call a "bad collection". In that case, set the field +** 'g->lastatomic' to signal that fact, so that the next collection will +** go to 'stepgenfull'. +** +** 'GCdebt <= 0' means an explicit call to GC step with "size" zero; +** in that case, do a minor collection. +*/ +static void genstep (lua_State *L, global_State *g) { + if (g->lastatomic != 0) /* last collection was a bad one? */ + stepgenfull(L, g); /* do a full step */ + else { + lu_mem majorbase = g->GCestimate; /* memory after last major collection */ + lu_mem majorinc = (majorbase / 100) * getgcparam(g->genmajormul); + if (g->GCdebt > 0 && gettotalbytes(g) > majorbase + majorinc) { + lu_mem numobjs = fullgen(L, g); /* do a major collection */ + if (gettotalbytes(g) < majorbase + (majorinc / 2)) { + /* collected at least half of memory growth since last major + collection; keep doing minor collections. */ + lua_assert(g->lastatomic == 0); + } + else { /* bad collection */ + g->lastatomic = numobjs; /* signal that last collection was bad */ + setpause(g); /* do a long wait for next (major) collection */ + } + } + else { /* regular case; do a minor collection */ + youngcollection(L, g); + setminordebt(g); + g->GCestimate = majorbase; /* preserve base value */ + } + } + lua_assert(isdecGCmodegen(g)); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** GC control +** ======================================================= +*/ + + +/* +** Enter first sweep phase. +** The call to 'sweeptolive' makes the pointer point to an object +** inside the list (instead of to the header), so that the real sweep do +** not need to skip objects created between "now" and the start of the +** real sweep. +*/ +static void entersweep (lua_State *L) { + global_State *g = G(L); + g->gcstate = GCSswpallgc; + lua_assert(g->sweepgc == NULL); + g->sweepgc = sweeptolive(L, &g->allgc); +} + + +/* +** Delete all objects in list 'p' until (but not including) object +** 'limit'. +*/ +static void deletelist (lua_State *L, GCObject *p, GCObject *limit) { + while (p != limit) { + GCObject *next = p->next; + freeobj(L, p); + p = next; + } +} + + +/* +** Call all finalizers of the objects in the given Lua state, and +** then free all objects, except for the main thread. +*/ +void luaC_freeallobjects (lua_State *L) { + global_State *g = G(L); + g->gcstp = GCSTPCLS; /* no extra finalizers after here */ + luaC_changemode(L, KGC_INC); + separatetobefnz(g, 1); /* separate all objects with finalizers */ + lua_assert(g->finobj == NULL); + callallpendingfinalizers(L); + deletelist(L, g->allgc, obj2gco(g->mainthread)); + lua_assert(g->finobj == NULL); /* no new finalizers */ + deletelist(L, g->fixedgc, NULL); /* collect fixed objects */ + lua_assert(g->strt.nuse == 0); +} + + +static lu_mem atomic (lua_State *L) { + global_State *g = G(L); + lu_mem work = 0; + GCObject *origweak, *origall; + GCObject *grayagain = g->grayagain; /* save original list */ + g->grayagain = NULL; + lua_assert(g->ephemeron == NULL && g->weak == NULL); + lua_assert(!iswhite(g->mainthread)); + g->gcstate = GCSatomic; + markobject(g, L); /* mark running thread */ + /* registry and global metatables may be changed by API */ + markvalue(g, &g->l_registry); + markmt(g); /* mark global metatables */ + work += propagateall(g); /* empties 'gray' list */ + /* remark occasional upvalues of (maybe) dead threads */ + work += remarkupvals(g); + work += propagateall(g); /* propagate changes */ + g->gray = grayagain; + work += propagateall(g); /* traverse 'grayagain' list */ + convergeephemerons(g); + /* at this point, all strongly accessible objects are marked. */ + /* Clear values from weak tables, before checking finalizers */ + clearbyvalues(g, g->weak, NULL); + clearbyvalues(g, g->allweak, NULL); + origweak = g->weak; origall = g->allweak; + separatetobefnz(g, 0); /* separate objects to be finalized */ + work += markbeingfnz(g); /* mark objects that will be finalized */ + work += propagateall(g); /* remark, to propagate 'resurrection' */ + convergeephemerons(g); + /* at this point, all resurrected objects are marked. */ + /* remove dead objects from weak tables */ + clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron tables */ + clearbykeys(g, g->allweak); /* clear keys from all 'allweak' tables */ + /* clear values from resurrected weak tables */ + clearbyvalues(g, g->weak, origweak); + clearbyvalues(g, g->allweak, origall); + luaS_clearcache(g); + g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ + lua_assert(g->gray == NULL); + return work; /* estimate of slots marked by 'atomic' */ +} + + +static int sweepstep (lua_State *L, global_State *g, + int nextstate, GCObject **nextlist) { + if (g->sweepgc) { + l_mem olddebt = g->GCdebt; + int count; + g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX, &count); + g->GCestimate += g->GCdebt - olddebt; /* update estimate */ + return count; + } + else { /* enter next state */ + g->gcstate = nextstate; + g->sweepgc = nextlist; + return 0; /* no work done */ + } +} + + +static lu_mem singlestep (lua_State *L) { + global_State *g = G(L); + lu_mem work; + lua_assert(!g->gcstopem); /* collector is not reentrant */ + g->gcstopem = 1; /* no emergency collections while collecting */ + switch (g->gcstate) { + case GCSpause: { + restartcollection(g); + g->gcstate = GCSpropagate; + work = 1; + break; + } + case GCSpropagate: { + if (g->gray == NULL) { /* no more gray objects? */ + g->gcstate = GCSenteratomic; /* finish propagate phase */ + work = 0; + } + else + work = propagatemark(g); /* traverse one gray object */ + break; + } + case GCSenteratomic: { + work = atomic(L); /* work is what was traversed by 'atomic' */ + entersweep(L); + g->GCestimate = gettotalbytes(g); /* first estimate */; + break; + } + case GCSswpallgc: { /* sweep "regular" objects */ + work = sweepstep(L, g, GCSswpfinobj, &g->finobj); + break; + } + case GCSswpfinobj: { /* sweep objects with finalizers */ + work = sweepstep(L, g, GCSswptobefnz, &g->tobefnz); + break; + } + case GCSswptobefnz: { /* sweep objects to be finalized */ + work = sweepstep(L, g, GCSswpend, NULL); + break; + } + case GCSswpend: { /* finish sweeps */ + checkSizes(L, g); + g->gcstate = GCScallfin; + work = 0; + break; + } + case GCScallfin: { /* call remaining finalizers */ + if (g->tobefnz && !g->gcemergency) { + g->gcstopem = 0; /* ok collections during finalizers */ + work = runafewfinalizers(L, GCFINMAX) * GCFINALIZECOST; + } + else { /* emergency mode or no more finalizers */ + g->gcstate = GCSpause; /* finish collection */ + work = 0; + } + break; + } + default: lua_assert(0); return 0; + } + g->gcstopem = 0; + return work; +} + + +/* +** advances the garbage collector until it reaches a state allowed +** by 'statemask' +*/ +void luaC_runtilstate (lua_State *L, int statesmask) { + global_State *g = G(L); + while (!testbit(statesmask, g->gcstate)) + singlestep(L); +} + + + +/* +** Performs a basic incremental step. The debt and step size are +** converted from bytes to "units of work"; then the function loops +** running single steps until adding that many units of work or +** finishing a cycle (pause state). Finally, it sets the debt that +** controls when next step will be performed. +*/ +static void incstep (lua_State *L, global_State *g) { + int stepmul = (getgcparam(g->gcstepmul) | 1); /* avoid division by 0 */ + l_mem debt = (g->GCdebt / WORK2MEM) * stepmul; + l_mem stepsize = (g->gcstepsize <= log2maxs(l_mem)) + ? ((cast(l_mem, 1) << g->gcstepsize) / WORK2MEM) * stepmul + : MAX_LMEM; /* overflow; keep maximum value */ + do { /* repeat until pause or enough "credit" (negative debt) */ + lu_mem work = singlestep(L); /* perform one single step */ + debt -= work; + } while (debt > -stepsize && g->gcstate != GCSpause); + if (g->gcstate == GCSpause) + setpause(g); /* pause until next cycle */ + else { + debt = (debt / stepmul) * WORK2MEM; /* convert 'work units' to bytes */ + luaE_setdebt(g, debt); + } +} + +/* +** Performs a basic GC step if collector is running. (If collector is +** not running, set a reasonable debt to avoid it being called at +** every single check.) +*/ +void luaC_step (lua_State *L) { + global_State *g = G(L); + if (!gcrunning(g)) /* not running? */ + luaE_setdebt(g, -2000); + else { + if(isdecGCmodegen(g)) + genstep(L, g); + else + incstep(L, g); + } +} + + +/* +** Perform a full collection in incremental mode. +** Before running the collection, check 'keepinvariant'; if it is true, +** there may be some objects marked as black, so the collector has +** to sweep all objects to turn them back to white (as white has not +** changed, nothing will be collected). +*/ +static void fullinc (lua_State *L, global_State *g) { + if (keepinvariant(g)) /* black objects? */ + entersweep(L); /* sweep everything to turn them back to white */ + /* finish any pending sweep phase to start a new cycle */ + luaC_runtilstate(L, bitmask(GCSpause)); + luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ + /* estimate must be correct after a full GC cycle */ + lua_assert(g->GCestimate == gettotalbytes(g)); + luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ + setpause(g); +} + + +/* +** Performs a full GC cycle; if 'isemergency', set a flag to avoid +** some operations which could change the interpreter state in some +** unexpected ways (running finalizers and shrinking some structures). +*/ +void luaC_fullgc (lua_State *L, int isemergency) { + global_State *g = G(L); + lua_assert(!g->gcemergency); + g->gcemergency = isemergency; /* set flag */ + if (g->gckind == KGC_INC) + fullinc(L, g); + else + fullgen(L, g); + g->gcemergency = 0; +} + +/* }====================================================== */ + + diff --git a/src/libs/3rdparty/lua/src/lgc.h b/src/libs/3rdparty/lua/src/lgc.h new file mode 100644 index 0000000000..538f6edccc --- /dev/null +++ b/src/libs/3rdparty/lua/src/lgc.h @@ -0,0 +1,202 @@ +/* +** $Id: lgc.h $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +#ifndef lgc_h +#define lgc_h + + +#include "lobject.h" +#include "lstate.h" + +/* +** Collectable objects may have one of three colors: white, which means +** the object is not marked; gray, which means the object is marked, but +** its references may be not marked; and black, which means that the +** object and all its references are marked. The main invariant of the +** garbage collector, while marking objects, is that a black object can +** never point to a white one. Moreover, any gray object must be in a +** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it +** can be visited again before finishing the collection cycle. (Open +** upvalues are an exception to this rule.) These lists have no meaning +** when the invariant is not being enforced (e.g., sweep phase). +*/ + + +/* +** Possible states of the Garbage Collector +*/ +#define GCSpropagate 0 +#define GCSenteratomic 1 +#define GCSatomic 2 +#define GCSswpallgc 3 +#define GCSswpfinobj 4 +#define GCSswptobefnz 5 +#define GCSswpend 6 +#define GCScallfin 7 +#define GCSpause 8 + + +#define issweepphase(g) \ + (GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend) + + +/* +** macro to tell when main invariant (white objects cannot point to black +** ones) must be kept. During a collection, the sweep +** phase may break the invariant, as objects turned white may point to +** still-black objects. The invariant is restored when sweep ends and +** all objects are white again. +*/ + +#define keepinvariant(g) ((g)->gcstate <= GCSatomic) + + +/* +** some useful bit tricks +*/ +#define resetbits(x,m) ((x) &= cast_byte(~(m))) +#define setbits(x,m) ((x) |= (m)) +#define testbits(x,m) ((x) & (m)) +#define bitmask(b) (1<<(b)) +#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) +#define l_setbit(x,b) setbits(x, bitmask(b)) +#define resetbit(x,b) resetbits(x, bitmask(b)) +#define testbit(x,b) testbits(x, bitmask(b)) + + +/* +** Layout for bit use in 'marked' field. First three bits are +** used for object "age" in generational mode. Last bit is used +** by tests. +*/ +#define WHITE0BIT 3 /* object is white (type 0) */ +#define WHITE1BIT 4 /* object is white (type 1) */ +#define BLACKBIT 5 /* object is black */ +#define FINALIZEDBIT 6 /* object has been marked for finalization */ + +#define TESTBIT 7 + + + +#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) + + +#define iswhite(x) testbits((x)->marked, WHITEBITS) +#define isblack(x) testbit((x)->marked, BLACKBIT) +#define isgray(x) /* neither white nor black */ \ + (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT))) + +#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) + +#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS) +#define isdeadm(ow,m) ((m) & (ow)) +#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked) + +#define changewhite(x) ((x)->marked ^= WHITEBITS) +#define nw2black(x) \ + check_exp(!iswhite(x), l_setbit((x)->marked, BLACKBIT)) + +#define luaC_white(g) cast_byte((g)->currentwhite & WHITEBITS) + + +/* object age in generational mode */ +#define G_NEW 0 /* created in current cycle */ +#define G_SURVIVAL 1 /* created in previous cycle */ +#define G_OLD0 2 /* marked old by frw. barrier in this cycle */ +#define G_OLD1 3 /* first full cycle as old */ +#define G_OLD 4 /* really old object (not to be visited) */ +#define G_TOUCHED1 5 /* old object touched this cycle */ +#define G_TOUCHED2 6 /* old object touched in previous cycle */ + +#define AGEBITS 7 /* all age bits (111) */ + +#define getage(o) ((o)->marked & AGEBITS) +#define setage(o,a) ((o)->marked = cast_byte(((o)->marked & (~AGEBITS)) | a)) +#define isold(o) (getage(o) > G_SURVIVAL) + +#define changeage(o,f,t) \ + check_exp(getage(o) == (f), (o)->marked ^= ((f)^(t))) + + +/* Default Values for GC parameters */ +#define LUAI_GENMAJORMUL 100 +#define LUAI_GENMINORMUL 20 + +/* wait memory to double before starting new cycle */ +#define LUAI_GCPAUSE 200 + +/* +** some gc parameters are stored divided by 4 to allow a maximum value +** up to 1023 in a 'lu_byte'. +*/ +#define getgcparam(p) ((p) * 4) +#define setgcparam(p,v) ((p) = (v) / 4) + +#define LUAI_GCMUL 100 + +/* how much to allocate before next GC step (log2) */ +#define LUAI_GCSTEPSIZE 13 /* 8 KB */ + + +/* +** Check whether the declared GC mode is generational. While in +** generational mode, the collector can go temporarily to incremental +** mode to improve performance. This is signaled by 'g->lastatomic != 0'. +*/ +#define isdecGCmodegen(g) (g->gckind == KGC_GEN || g->lastatomic != 0) + + +/* +** Control when GC is running: +*/ +#define GCSTPUSR 1 /* bit true when GC stopped by user */ +#define GCSTPGC 2 /* bit true when GC stopped by itself */ +#define GCSTPCLS 4 /* bit true when closing Lua state */ +#define gcrunning(g) ((g)->gcstp == 0) + + +/* +** Does one step of collection when debt becomes positive. 'pre'/'pos' +** allows some adjustments to be done only when needed. macro +** 'condchangemem' is used only for heavy tests (forcing a full +** GC cycle on every opportunity) +*/ +#define luaC_condGC(L,pre,pos) \ + { if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \ + condchangemem(L,pre,pos); } + +/* more often than not, 'pre'/'pos' are empty */ +#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0) + + +#define luaC_objbarrier(L,p,o) ( \ + (isblack(p) && iswhite(o)) ? \ + luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) + +#define luaC_barrier(L,p,v) ( \ + iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0)) + +#define luaC_objbarrierback(L,p,o) ( \ + (isblack(p) && iswhite(o)) ? luaC_barrierback_(L,p) : cast_void(0)) + +#define luaC_barrierback(L,p,v) ( \ + iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0)) + +LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); +LUAI_FUNC void luaC_freeallobjects (lua_State *L); +LUAI_FUNC void luaC_step (lua_State *L); +LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); +LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); +LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); +LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, + size_t offset); +LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); +LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o); +LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); +LUAI_FUNC void luaC_changemode (lua_State *L, int newmode); + + +#endif diff --git a/src/libs/3rdparty/lua/src/linit.c b/src/libs/3rdparty/lua/src/linit.c new file mode 100644 index 0000000000..69808f84f4 --- /dev/null +++ b/src/libs/3rdparty/lua/src/linit.c @@ -0,0 +1,65 @@ +/* +** $Id: linit.c $ +** Initialization of libraries for lua.c and other clients +** See Copyright Notice in lua.h +*/ + + +#define linit_c +#define LUA_LIB + +/* +** If you embed Lua in your program and need to open the standard +** libraries, call luaL_openlibs in your program. If you need a +** different set of libraries, copy this file to your project and edit +** it to suit your needs. +** +** You can also *preload* libraries, so that a later 'require' can +** open the library, which is already linked to the application. +** For that, do the following code: +** +** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); +** lua_pushcfunction(L, luaopen_modname); +** lua_setfield(L, -2, modname); +** lua_pop(L, 1); // remove PRELOAD table +*/ + +#include "lprefix.h" + + +#include <stddef.h> + +#include "lua.h" + +#include "lualib.h" +#include "lauxlib.h" + + +/* +** these libs are loaded by lua.c and are readily available to any Lua +** program +*/ +static const luaL_Reg loadedlibs[] = { + {LUA_GNAME, luaopen_base}, + {LUA_LOADLIBNAME, luaopen_package}, + {LUA_COLIBNAME, luaopen_coroutine}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_IOLIBNAME, luaopen_io}, + {LUA_OSLIBNAME, luaopen_os}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_UTF8LIBNAME, luaopen_utf8}, + {LUA_DBLIBNAME, luaopen_debug}, + {NULL, NULL} +}; + + +LUALIB_API void luaL_openlibs (lua_State *L) { + const luaL_Reg *lib; + /* "require" functions from 'loadedlibs' and set results to global table */ + for (lib = loadedlibs; lib->func; lib++) { + luaL_requiref(L, lib->name, lib->func, 1); + lua_pop(L, 1); /* remove lib */ + } +} + diff --git a/src/libs/3rdparty/lua/src/liolib.c b/src/libs/3rdparty/lua/src/liolib.c new file mode 100644 index 0000000000..b08397da45 --- /dev/null +++ b/src/libs/3rdparty/lua/src/liolib.c @@ -0,0 +1,828 @@ +/* +** $Id: liolib.c $ +** Standard I/O (and system) library +** See Copyright Notice in lua.h +*/ + +#define liolib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include <ctype.h> +#include <errno.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + + +/* +** Change this macro to accept other modes for 'fopen' besides +** the standard ones. +*/ +#if !defined(l_checkmode) + +/* accepted extensions to 'mode' in 'fopen' */ +#if !defined(L_MODEEXT) +#define L_MODEEXT "b" +#endif + +/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */ +static int l_checkmode (const char *mode) { + return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && + (*mode != '+' || ((void)(++mode), 1)) && /* skip if char is '+' */ + (strspn(mode, L_MODEEXT) == strlen(mode))); /* check extensions */ +} + +#endif + +/* +** {====================================================== +** l_popen spawns a new process connected to the current +** one through the file streams. +** ======================================================= +*/ + +#if !defined(l_popen) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#define l_popen(L,c,m) (fflush(NULL), popen(c,m)) +#define l_pclose(L,file) (pclose(file)) + +#elif defined(LUA_USE_WINDOWS) /* }{ */ + +#define l_popen(L,c,m) (_popen(c,m)) +#define l_pclose(L,file) (_pclose(file)) + +#if !defined(l_checkmodep) +/* Windows accepts "[rw][bt]?" as valid modes */ +#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && \ + (m[1] == '\0' || ((m[1] == 'b' || m[1] == 't') && m[2] == '\0'))) +#endif + +#else /* }{ */ + +/* ISO C definitions */ +#define l_popen(L,c,m) \ + ((void)c, (void)m, \ + luaL_error(L, "'popen' not supported"), \ + (FILE*)0) +#define l_pclose(L,file) ((void)L, (void)file, -1) + +#endif /* } */ + +#endif /* } */ + + +#if !defined(l_checkmodep) +/* By default, Lua accepts only "r" or "w" as valid modes */ +#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && m[1] == '\0') +#endif + +/* }====================================================== */ + + +#if !defined(l_getc) /* { */ + +#if defined(LUA_USE_POSIX) +#define l_getc(f) getc_unlocked(f) +#define l_lockfile(f) flockfile(f) +#define l_unlockfile(f) funlockfile(f) +#else +#define l_getc(f) getc(f) +#define l_lockfile(f) ((void)0) +#define l_unlockfile(f) ((void)0) +#endif + +#endif /* } */ + + +/* +** {====================================================== +** l_fseek: configuration for longer offsets +** ======================================================= +*/ + +#if !defined(l_fseek) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#include <sys/types.h> + +#define l_fseek(f,o,w) fseeko(f,o,w) +#define l_ftell(f) ftello(f) +#define l_seeknum off_t + +#elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \ + && defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */ + +/* Windows (but not DDK) and Visual C++ 2005 or higher */ +#define l_fseek(f,o,w) _fseeki64(f,o,w) +#define l_ftell(f) _ftelli64(f) +#define l_seeknum __int64 + +#else /* }{ */ + +/* ISO C definitions */ +#define l_fseek(f,o,w) fseek(f,o,w) +#define l_ftell(f) ftell(f) +#define l_seeknum long + +#endif /* } */ + +#endif /* } */ + +/* }====================================================== */ + + + +#define IO_PREFIX "_IO_" +#define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1) +#define IO_INPUT (IO_PREFIX "input") +#define IO_OUTPUT (IO_PREFIX "output") + + +typedef luaL_Stream LStream; + + +#define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) + +#define isclosed(p) ((p)->closef == NULL) + + +static int io_type (lua_State *L) { + LStream *p; + luaL_checkany(L, 1); + p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE); + if (p == NULL) + luaL_pushfail(L); /* not a file */ + else if (isclosed(p)) + lua_pushliteral(L, "closed file"); + else + lua_pushliteral(L, "file"); + return 1; +} + + +static int f_tostring (lua_State *L) { + LStream *p = tolstream(L); + if (isclosed(p)) + lua_pushliteral(L, "file (closed)"); + else + lua_pushfstring(L, "file (%p)", p->f); + return 1; +} + + +static FILE *tofile (lua_State *L) { + LStream *p = tolstream(L); + if (l_unlikely(isclosed(p))) + luaL_error(L, "attempt to use a closed file"); + lua_assert(p->f); + return p->f; +} + + +/* +** When creating file handles, always creates a 'closed' file handle +** before opening the actual file; so, if there is a memory error, the +** handle is in a consistent state. +*/ +static LStream *newprefile (lua_State *L) { + LStream *p = (LStream *)lua_newuserdatauv(L, sizeof(LStream), 0); + p->closef = NULL; /* mark file handle as 'closed' */ + luaL_setmetatable(L, LUA_FILEHANDLE); + return p; +} + + +/* +** Calls the 'close' function from a file handle. The 'volatile' avoids +** a bug in some versions of the Clang compiler (e.g., clang 3.0 for +** 32 bits). +*/ +static int aux_close (lua_State *L) { + LStream *p = tolstream(L); + volatile lua_CFunction cf = p->closef; + p->closef = NULL; /* mark stream as closed */ + return (*cf)(L); /* close it */ +} + + +static int f_close (lua_State *L) { + tofile(L); /* make sure argument is an open stream */ + return aux_close(L); +} + + +static int io_close (lua_State *L) { + if (lua_isnone(L, 1)) /* no argument? */ + lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use default output */ + return f_close(L); +} + + +static int f_gc (lua_State *L) { + LStream *p = tolstream(L); + if (!isclosed(p) && p->f != NULL) + aux_close(L); /* ignore closed and incompletely open files */ + return 0; +} + + +/* +** function to close regular files +*/ +static int io_fclose (lua_State *L) { + LStream *p = tolstream(L); + int res = fclose(p->f); + return luaL_fileresult(L, (res == 0), NULL); +} + + +static LStream *newfile (lua_State *L) { + LStream *p = newprefile(L); + p->f = NULL; + p->closef = &io_fclose; + return p; +} + + +static void opencheck (lua_State *L, const char *fname, const char *mode) { + LStream *p = newfile(L); + p->f = fopen(fname, mode); + if (l_unlikely(p->f == NULL)) + luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); +} + + +static int io_open (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + LStream *p = newfile(L); + const char *md = mode; /* to traverse/check mode */ + luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); + p->f = fopen(filename, mode); + return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; +} + + +/* +** function to close 'popen' files +*/ +static int io_pclose (lua_State *L) { + LStream *p = tolstream(L); + errno = 0; + return luaL_execresult(L, l_pclose(L, p->f)); +} + + +static int io_popen (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + LStream *p = newprefile(L); + luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode"); + p->f = l_popen(L, filename, mode); + p->closef = &io_pclose; + return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; +} + + +static int io_tmpfile (lua_State *L) { + LStream *p = newfile(L); + p->f = tmpfile(); + return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; +} + + +static FILE *getiofile (lua_State *L, const char *findex) { + LStream *p; + lua_getfield(L, LUA_REGISTRYINDEX, findex); + p = (LStream *)lua_touserdata(L, -1); + if (l_unlikely(isclosed(p))) + luaL_error(L, "default %s file is closed", findex + IOPREF_LEN); + return p->f; +} + + +static int g_iofile (lua_State *L, const char *f, const char *mode) { + if (!lua_isnoneornil(L, 1)) { + const char *filename = lua_tostring(L, 1); + if (filename) + opencheck(L, filename, mode); + else { + tofile(L); /* check that it's a valid file handle */ + lua_pushvalue(L, 1); + } + lua_setfield(L, LUA_REGISTRYINDEX, f); + } + /* return current value */ + lua_getfield(L, LUA_REGISTRYINDEX, f); + return 1; +} + + +static int io_input (lua_State *L) { + return g_iofile(L, IO_INPUT, "r"); +} + + +static int io_output (lua_State *L) { + return g_iofile(L, IO_OUTPUT, "w"); +} + + +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 + +/* +** Auxiliary function to create the iteration function for 'lines'. +** The iteration function is a closure over 'io_readline', with +** the following upvalues: +** 1) The file being read (first value in the stack) +** 2) the number of arguments to read +** 3) a boolean, true iff file has to be closed when finished ('toclose') +** *) a variable number of format arguments (rest of the stack) +*/ +static void aux_lines (lua_State *L, int toclose) { + int n = lua_gettop(L) - 1; /* number of arguments to read */ + luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments"); + lua_pushvalue(L, 1); /* file */ + lua_pushinteger(L, n); /* number of arguments to read */ + lua_pushboolean(L, toclose); /* close/not close file when finished */ + lua_rotate(L, 2, 3); /* move the three values to their positions */ + lua_pushcclosure(L, io_readline, 3 + n); +} + + +static int f_lines (lua_State *L) { + tofile(L); /* check that it's a valid file handle */ + aux_lines(L, 0); + return 1; +} + + +/* +** Return an iteration function for 'io.lines'. If file has to be +** closed, also returns the file itself as a second result (to be +** closed as the state at the exit of a generic for). +*/ +static int io_lines (lua_State *L) { + int toclose; + if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ + if (lua_isnil(L, 1)) { /* no file name? */ + lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */ + lua_replace(L, 1); /* put it at index 1 */ + tofile(L); /* check that it's a valid file handle */ + toclose = 0; /* do not close it after iteration */ + } + else { /* open a new file */ + const char *filename = luaL_checkstring(L, 1); + opencheck(L, filename, "r"); + lua_replace(L, 1); /* put file at index 1 */ + toclose = 1; /* close it after iteration */ + } + aux_lines(L, toclose); /* push iteration function */ + if (toclose) { + lua_pushnil(L); /* state */ + lua_pushnil(L); /* control */ + lua_pushvalue(L, 1); /* file is the to-be-closed variable (4th result) */ + return 4; + } + else + return 1; +} + + +/* +** {====================================================== +** READ +** ======================================================= +*/ + + +/* maximum length of a numeral */ +#if !defined (L_MAXLENNUM) +#define L_MAXLENNUM 200 +#endif + + +/* auxiliary structure used by 'read_number' */ +typedef struct { + FILE *f; /* file being read */ + int c; /* current character (look ahead) */ + int n; /* number of elements in buffer 'buff' */ + char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */ +} RN; + + +/* +** Add current char to buffer (if not out of space) and read next one +*/ +static int nextc (RN *rn) { + if (l_unlikely(rn->n >= L_MAXLENNUM)) { /* buffer overflow? */ + rn->buff[0] = '\0'; /* invalidate result */ + return 0; /* fail */ + } + else { + rn->buff[rn->n++] = rn->c; /* save current char */ + rn->c = l_getc(rn->f); /* read next one */ + return 1; + } +} + + +/* +** Accept current char if it is in 'set' (of size 2) +*/ +static int test2 (RN *rn, const char *set) { + if (rn->c == set[0] || rn->c == set[1]) + return nextc(rn); + else return 0; +} + + +/* +** Read a sequence of (hex)digits +*/ +static int readdigits (RN *rn, int hex) { + int count = 0; + while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn)) + count++; + return count; +} + + +/* +** 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 +** correct and to convert it to a Lua number. +*/ +static int read_number (lua_State *L, FILE *f) { + RN rn; + int count = 0; + int hex = 0; + char decp[2]; + rn.f = f; rn.n = 0; + decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */ + decp[1] = '.'; /* always accept a dot */ + l_lockfile(rn.f); + do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ + test2(&rn, "-+"); /* optional sign */ + if (test2(&rn, "00")) { + if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ + else count = 1; /* count initial '0' as a valid digit */ + } + count += readdigits(&rn, hex); /* integral part */ + if (test2(&rn, decp)) /* decimal point? */ + count += readdigits(&rn, hex); /* fractional part */ + if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) { /* exponent mark? */ + test2(&rn, "-+"); /* exponent sign */ + readdigits(&rn, 0); /* exponent digits */ + } + ungetc(rn.c, rn.f); /* unread look-ahead char */ + l_unlockfile(rn.f); + rn.buff[rn.n] = '\0'; /* finish string */ + if (l_likely(lua_stringtonumber(L, rn.buff))) + return 1; /* ok, it is a valid number */ + else { /* invalid format */ + lua_pushnil(L); /* "result" to be removed */ + return 0; /* read fails */ + } +} + + +static int test_eof (lua_State *L, FILE *f) { + int c = getc(f); + ungetc(c, f); /* no-op when c == EOF */ + lua_pushliteral(L, ""); + return (c != EOF); +} + + +static int read_line (lua_State *L, FILE *f, int chop) { + luaL_Buffer b; + int c; + luaL_buffinit(L, &b); + do { /* may need to read several chunks to get whole line */ + char *buff = luaL_prepbuffer(&b); /* preallocate buffer space */ + int i = 0; + l_lockfile(f); /* no memory errors can happen inside the lock */ + while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n') + buff[i++] = c; /* read up to end of line or buffer limit */ + l_unlockfile(f); + luaL_addsize(&b, i); + } while (c != EOF && c != '\n'); /* repeat until end of line */ + if (!chop && c == '\n') /* want a newline and have one? */ + luaL_addchar(&b, c); /* add ending newline to result */ + luaL_pushresult(&b); /* close buffer */ + /* return ok if read something (either a newline or something else) */ + return (c == '\n' || lua_rawlen(L, -1) > 0); +} + + +static void read_all (lua_State *L, FILE *f) { + size_t nr; + luaL_Buffer b; + luaL_buffinit(L, &b); + do { /* read file in chunks of LUAL_BUFFERSIZE bytes */ + char *p = luaL_prepbuffer(&b); + nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f); + luaL_addsize(&b, nr); + } while (nr == LUAL_BUFFERSIZE); + luaL_pushresult(&b); /* close buffer */ +} + + +static int read_chars (lua_State *L, FILE *f, size_t n) { + size_t nr; /* number of chars actually read */ + char *p; + luaL_Buffer b; + luaL_buffinit(L, &b); + p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */ + nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */ + luaL_addsize(&b, nr); + luaL_pushresult(&b); /* close buffer */ + return (nr > 0); /* true iff read something */ +} + + +static int g_read (lua_State *L, FILE *f, int first) { + int nargs = lua_gettop(L) - 1; + int n, success; + clearerr(f); + if (nargs == 0) { /* no arguments? */ + success = read_line(L, f, 1); + n = first + 1; /* to return 1 result */ + } + else { + /* ensure stack space for all results and for auxlib's buffer */ + luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); + success = 1; + for (n = first; nargs-- && success; n++) { + if (lua_type(L, n) == LUA_TNUMBER) { + size_t l = (size_t)luaL_checkinteger(L, n); + success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); + } + else { + const char *p = luaL_checkstring(L, n); + if (*p == '*') p++; /* skip optional '*' (for compatibility) */ + switch (*p) { + case 'n': /* number */ + success = read_number(L, f); + break; + case 'l': /* line */ + success = read_line(L, f, 1); + break; + case 'L': /* line with end-of-line */ + success = read_line(L, f, 0); + break; + case 'a': /* file */ + read_all(L, f); /* read entire file */ + success = 1; /* always success */ + break; + default: + return luaL_argerror(L, n, "invalid format"); + } + } + } + } + if (ferror(f)) + return luaL_fileresult(L, 0, NULL); + if (!success) { + lua_pop(L, 1); /* remove last result */ + luaL_pushfail(L); /* push nil instead */ + } + return n - first; +} + + +static int io_read (lua_State *L) { + return g_read(L, getiofile(L, IO_INPUT), 1); +} + + +static int f_read (lua_State *L) { + return g_read(L, tofile(L), 2); +} + + +/* +** Iteration function for 'lines'. +*/ +static int io_readline (lua_State *L) { + LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); + int i; + int n = (int)lua_tointeger(L, lua_upvalueindex(2)); + if (isclosed(p)) /* file is already closed? */ + return luaL_error(L, "file is already closed"); + lua_settop(L , 1); + luaL_checkstack(L, n, "too many arguments"); + for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ + lua_pushvalue(L, lua_upvalueindex(3 + i)); + n = g_read(L, p->f, 2); /* 'n' is number of results */ + lua_assert(n > 0); /* should return at least a nil */ + if (lua_toboolean(L, -n)) /* read at least one value? */ + return n; /* return them */ + else { /* first result is false: EOF or error */ + if (n > 1) { /* is there error information? */ + /* 2nd result is error message */ + return luaL_error(L, "%s", lua_tostring(L, -n + 1)); + } + if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ + lua_settop(L, 0); /* clear stack */ + lua_pushvalue(L, lua_upvalueindex(1)); /* push file at index 1 */ + aux_close(L); /* close it */ + } + return 0; + } +} + +/* }====================================================== */ + + +static int g_write (lua_State *L, FILE *f, int arg) { + int nargs = lua_gettop(L) - arg; + int status = 1; + for (; nargs--; arg++) { + if (lua_type(L, arg) == LUA_TNUMBER) { + /* optimization: could be done exactly as for strings */ + int len = lua_isinteger(L, arg) + ? fprintf(f, LUA_INTEGER_FMT, + (LUAI_UACINT)lua_tointeger(L, arg)) + : fprintf(f, LUA_NUMBER_FMT, + (LUAI_UACNUMBER)lua_tonumber(L, arg)); + status = status && (len > 0); + } + else { + size_t l; + const char *s = luaL_checklstring(L, arg, &l); + status = status && (fwrite(s, sizeof(char), l, f) == l); + } + } + if (l_likely(status)) + return 1; /* file handle already on stack top */ + else return luaL_fileresult(L, status, NULL); +} + + +static int io_write (lua_State *L) { + return g_write(L, getiofile(L, IO_OUTPUT), 1); +} + + +static int f_write (lua_State *L) { + FILE *f = tofile(L); + lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ + return g_write(L, f, 2); +} + + +static int f_seek (lua_State *L) { + static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; + static const char *const modenames[] = {"set", "cur", "end", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, "cur", modenames); + lua_Integer p3 = luaL_optinteger(L, 3, 0); + l_seeknum offset = (l_seeknum)p3; + luaL_argcheck(L, (lua_Integer)offset == p3, 3, + "not an integer in proper range"); + op = l_fseek(f, offset, mode[op]); + if (l_unlikely(op)) + return luaL_fileresult(L, 0, NULL); /* error */ + else { + lua_pushinteger(L, (lua_Integer)l_ftell(f)); + return 1; + } +} + + +static int f_setvbuf (lua_State *L) { + static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; + static const char *const modenames[] = {"no", "full", "line", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, NULL, modenames); + lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); + int res = setvbuf(f, NULL, mode[op], (size_t)sz); + return luaL_fileresult(L, res == 0, NULL); +} + + + +static int io_flush (lua_State *L) { + return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); +} + + +static int f_flush (lua_State *L) { + return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); +} + + +/* +** functions for 'io' library +*/ +static const luaL_Reg iolib[] = { + {"close", io_close}, + {"flush", io_flush}, + {"input", io_input}, + {"lines", io_lines}, + {"open", io_open}, + {"output", io_output}, + {"popen", io_popen}, + {"read", io_read}, + {"tmpfile", io_tmpfile}, + {"type", io_type}, + {"write", io_write}, + {NULL, NULL} +}; + + +/* +** methods for file handles +*/ +static const luaL_Reg meth[] = { + {"read", f_read}, + {"write", f_write}, + {"lines", f_lines}, + {"flush", f_flush}, + {"seek", f_seek}, + {"close", f_close}, + {"setvbuf", f_setvbuf}, + {NULL, NULL} +}; + + +/* +** metamethods for file handles +*/ +static const luaL_Reg metameth[] = { + {"__index", NULL}, /* place holder */ + {"__gc", f_gc}, + {"__close", f_gc}, + {"__tostring", f_tostring}, + {NULL, NULL} +}; + + +static void createmeta (lua_State *L) { + luaL_newmetatable(L, LUA_FILEHANDLE); /* metatable for file handles */ + luaL_setfuncs(L, metameth, 0); /* add metamethods to new metatable */ + luaL_newlibtable(L, meth); /* create method table */ + luaL_setfuncs(L, meth, 0); /* add file methods to method table */ + lua_setfield(L, -2, "__index"); /* metatable.__index = method table */ + lua_pop(L, 1); /* pop metatable */ +} + + +/* +** function to (not) close the standard files stdin, stdout, and stderr +*/ +static int io_noclose (lua_State *L) { + LStream *p = tolstream(L); + p->closef = &io_noclose; /* keep file opened */ + luaL_pushfail(L); + lua_pushliteral(L, "cannot close standard file"); + return 2; +} + + +static void createstdfile (lua_State *L, FILE *f, const char *k, + const char *fname) { + LStream *p = newprefile(L); + p->f = f; + p->closef = &io_noclose; + if (k != NULL) { + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ + } + lua_setfield(L, -2, fname); /* add file to module */ +} + + +LUAMOD_API int luaopen_io (lua_State *L) { + luaL_newlib(L, iolib); /* new module */ + createmeta(L); + /* create (and set) default files */ + createstdfile(L, stdin, IO_INPUT, "stdin"); + createstdfile(L, stdout, IO_OUTPUT, "stdout"); + createstdfile(L, stderr, NULL, "stderr"); + return 1; +} + diff --git a/src/libs/3rdparty/lua/src/ljumptab.h b/src/libs/3rdparty/lua/src/ljumptab.h new file mode 100644 index 0000000000..8306f250cc --- /dev/null +++ b/src/libs/3rdparty/lua/src/ljumptab.h @@ -0,0 +1,112 @@ +/* +** $Id: ljumptab.h $ +** Jump Table for the Lua interpreter +** See Copyright Notice in lua.h +*/ + + +#undef vmdispatch +#undef vmcase +#undef vmbreak + +#define vmdispatch(x) goto *disptab[x]; + +#define vmcase(l) L_##l: + +#define vmbreak vmfetch(); vmdispatch(GET_OPCODE(i)); + + +static const void *const disptab[NUM_OPCODES] = { + +#if 0 +** you can update the following list with this command: +** +** sed -n '/^OP_/\!d; s/OP_/\&\&L_OP_/ ; s/,.*/,/ ; s/\/.*// ; p' lopcodes.h +** +#endif + +&&L_OP_MOVE, +&&L_OP_LOADI, +&&L_OP_LOADF, +&&L_OP_LOADK, +&&L_OP_LOADKX, +&&L_OP_LOADFALSE, +&&L_OP_LFALSESKIP, +&&L_OP_LOADTRUE, +&&L_OP_LOADNIL, +&&L_OP_GETUPVAL, +&&L_OP_SETUPVAL, +&&L_OP_GETTABUP, +&&L_OP_GETTABLE, +&&L_OP_GETI, +&&L_OP_GETFIELD, +&&L_OP_SETTABUP, +&&L_OP_SETTABLE, +&&L_OP_SETI, +&&L_OP_SETFIELD, +&&L_OP_NEWTABLE, +&&L_OP_SELF, +&&L_OP_ADDI, +&&L_OP_ADDK, +&&L_OP_SUBK, +&&L_OP_MULK, +&&L_OP_MODK, +&&L_OP_POWK, +&&L_OP_DIVK, +&&L_OP_IDIVK, +&&L_OP_BANDK, +&&L_OP_BORK, +&&L_OP_BXORK, +&&L_OP_SHRI, +&&L_OP_SHLI, +&&L_OP_ADD, +&&L_OP_SUB, +&&L_OP_MUL, +&&L_OP_MOD, +&&L_OP_POW, +&&L_OP_DIV, +&&L_OP_IDIV, +&&L_OP_BAND, +&&L_OP_BOR, +&&L_OP_BXOR, +&&L_OP_SHL, +&&L_OP_SHR, +&&L_OP_MMBIN, +&&L_OP_MMBINI, +&&L_OP_MMBINK, +&&L_OP_UNM, +&&L_OP_BNOT, +&&L_OP_NOT, +&&L_OP_LEN, +&&L_OP_CONCAT, +&&L_OP_CLOSE, +&&L_OP_TBC, +&&L_OP_JMP, +&&L_OP_EQ, +&&L_OP_LT, +&&L_OP_LE, +&&L_OP_EQK, +&&L_OP_EQI, +&&L_OP_LTI, +&&L_OP_LEI, +&&L_OP_GTI, +&&L_OP_GEI, +&&L_OP_TEST, +&&L_OP_TESTSET, +&&L_OP_CALL, +&&L_OP_TAILCALL, +&&L_OP_RETURN, +&&L_OP_RETURN0, +&&L_OP_RETURN1, +&&L_OP_FORLOOP, +&&L_OP_FORPREP, +&&L_OP_TFORPREP, +&&L_OP_TFORCALL, +&&L_OP_TFORLOOP, +&&L_OP_SETLIST, +&&L_OP_CLOSURE, +&&L_OP_VARARG, +&&L_OP_VARARGPREP, +&&L_OP_EXTRAARG + +}; diff --git a/src/libs/3rdparty/lua/src/llex.c b/src/libs/3rdparty/lua/src/llex.c new file mode 100644 index 0000000000..5fc39a5cde --- /dev/null +++ b/src/libs/3rdparty/lua/src/llex.c @@ -0,0 +1,581 @@ +/* +** $Id: llex.c $ +** Lexical Analyzer +** See Copyright Notice in lua.h +*/ + +#define llex_c +#define LUA_CORE + +#include "lprefix.h" + + +#include <locale.h> +#include <string.h> + +#include "lua.h" + +#include "lctype.h" +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "llex.h" +#include "lobject.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "lzio.h" + + + +#define next(ls) (ls->current = zgetc(ls->z)) + + + +#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') + + +/* ORDER RESERVED */ +static const char *const luaX_tokens [] = { + "and", "break", "do", "else", "elseif", + "end", "false", "for", "function", "goto", "if", + "in", "local", "nil", "not", "or", "repeat", + "return", "then", "true", "until", "while", + "//", "..", "...", "==", ">=", "<=", "~=", + "<<", ">>", "::", "<eof>", + "<number>", "<integer>", "<name>", "<string>" +}; + + +#define save_and_next(ls) (save(ls, ls->current), next(ls)) + + +static l_noret lexerror (LexState *ls, const char *msg, int token); + + +static void save (LexState *ls, int c) { + Mbuffer *b = ls->buff; + if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) { + size_t newsize; + if (luaZ_sizebuffer(b) >= MAX_SIZE/2) + lexerror(ls, "lexical element too long", 0); + newsize = luaZ_sizebuffer(b) * 2; + luaZ_resizebuffer(ls->L, b, newsize); + } + b->buffer[luaZ_bufflen(b)++] = cast_char(c); +} + + +void luaX_init (lua_State *L) { + int i; + TString *e = luaS_newliteral(L, LUA_ENV); /* create env name */ + luaC_fix(L, obj2gco(e)); /* never collect this name */ + for (i=0; i<NUM_RESERVED; i++) { + TString *ts = luaS_new(L, luaX_tokens[i]); + luaC_fix(L, obj2gco(ts)); /* reserved words are never collected */ + ts->extra = cast_byte(i+1); /* reserved word */ + } +} + + +const char *luaX_token2str (LexState *ls, int token) { + if (token < FIRST_RESERVED) { /* single-byte symbols? */ + if (lisprint(token)) + return luaO_pushfstring(ls->L, "'%c'", token); + else /* control character */ + return luaO_pushfstring(ls->L, "'<\\%d>'", token); + } + else { + const char *s = luaX_tokens[token - FIRST_RESERVED]; + if (token < TK_EOS) /* fixed format (symbols and reserved words)? */ + return luaO_pushfstring(ls->L, "'%s'", s); + else /* names, strings, and numerals */ + return s; + } +} + + +static const char *txtToken (LexState *ls, int token) { + switch (token) { + case TK_NAME: case TK_STRING: + case TK_FLT: case TK_INT: + save(ls, '\0'); + return luaO_pushfstring(ls->L, "'%s'", luaZ_buffer(ls->buff)); + default: + return luaX_token2str(ls, token); + } +} + + +static l_noret lexerror (LexState *ls, const char *msg, int token) { + msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber); + if (token) + luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token)); + luaD_throw(ls->L, LUA_ERRSYNTAX); +} + + +l_noret luaX_syntaxerror (LexState *ls, const char *msg) { + lexerror(ls, msg, ls->t.token); +} + + +/* +** Creates a new string and anchors it in scanner's table so that it +** will not be collected until the end of the compilation; by that time +** it should be anchored somewhere. It also internalizes long strings, +** ensuring there is only one copy of each unique string. The table +** here is used as a set: the string enters as the key, while its value +** is irrelevant. We use the string itself as the value only because it +** is a TValue readily available. Later, the code generation can change +** this value. +*/ +TString *luaX_newstring (LexState *ls, const char *str, size_t l) { + lua_State *L = ls->L; + TString *ts = luaS_newlstr(L, str, l); /* create new string */ + const TValue *o = luaH_getstr(ls->h, ts); + if (!ttisnil(o)) /* string already present? */ + ts = keystrval(nodefromval(o)); /* get saved copy */ + else { /* not in use yet */ + TValue *stv = s2v(L->top.p++); /* reserve stack space for string */ + setsvalue(L, stv, ts); /* temporarily anchor the string */ + luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */ + /* table is not a metatable, so it does not need to invalidate cache */ + luaC_checkGC(L); + L->top.p--; /* remove string from stack */ + } + return ts; +} + + +/* +** increment line number and skips newline sequence (any of +** \n, \r, \n\r, or \r\n) +*/ +static void inclinenumber (LexState *ls) { + int old = ls->current; + lua_assert(currIsNewline(ls)); + next(ls); /* skip '\n' or '\r' */ + if (currIsNewline(ls) && ls->current != old) + next(ls); /* skip '\n\r' or '\r\n' */ + if (++ls->linenumber >= MAX_INT) + lexerror(ls, "chunk has too many lines", 0); +} + + +void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, + int firstchar) { + ls->t.token = 0; + ls->L = L; + ls->current = firstchar; + ls->lookahead.token = TK_EOS; /* no look-ahead token */ + ls->z = z; + ls->fs = NULL; + ls->linenumber = 1; + ls->lastline = 1; + ls->source = source; + ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */ + luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ +} + + + +/* +** ======================================================= +** LEXICAL ANALYZER +** ======================================================= +*/ + + +static int check_next1 (LexState *ls, int c) { + if (ls->current == c) { + next(ls); + return 1; + } + else return 0; +} + + +/* +** Check whether current char is in set 'set' (with two chars) and +** saves it +*/ +static int check_next2 (LexState *ls, const char *set) { + lua_assert(set[2] == '\0'); + if (ls->current == set[0] || ls->current == set[1]) { + save_and_next(ls); + return 1; + } + else return 0; +} + + +/* LUA_NUMBER */ +/* +** This function is quite liberal in what it accepts, as 'luaO_str2num' +** will reject ill-formed numerals. Roughly, it accepts the following +** pattern: +** +** %d(%x|%.|([Ee][+-]?))* | 0[Xx](%x|%.|([Pp][+-]?))* +** +** The only tricky part is to accept [+-] only after a valid exponent +** mark, to avoid reading '3-4' or '0xe+1' as a single number. +** +** The caller might have already read an initial dot. +*/ +static int read_numeral (LexState *ls, SemInfo *seminfo) { + TValue obj; + const char *expo = "Ee"; + int first = ls->current; + lua_assert(lisdigit(ls->current)); + save_and_next(ls); + if (first == '0' && check_next2(ls, "xX")) /* hexadecimal? */ + expo = "Pp"; + for (;;) { + if (check_next2(ls, expo)) /* exponent mark? */ + check_next2(ls, "-+"); /* optional exponent sign */ + else if (lisxdigit(ls->current) || ls->current == '.') /* '%x|%.' */ + save_and_next(ls); + else break; + } + if (lislalpha(ls->current)) /* is numeral touching a letter? */ + save_and_next(ls); /* force an error */ + save(ls, '\0'); + if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */ + lexerror(ls, "malformed number", TK_FLT); + if (ttisinteger(&obj)) { + seminfo->i = ivalue(&obj); + return TK_INT; + } + else { + lua_assert(ttisfloat(&obj)); + seminfo->r = fltvalue(&obj); + return TK_FLT; + } +} + + +/* +** read a sequence '[=*[' or ']=*]', leaving the last bracket. If +** sequence is well formed, return its number of '='s + 2; otherwise, +** return 1 if it is a single bracket (no '='s and no 2nd bracket); +** otherwise (an unfinished '[==...') return 0. +*/ +static size_t skip_sep (LexState *ls) { + size_t count = 0; + int s = ls->current; + lua_assert(s == '[' || s == ']'); + save_and_next(ls); + while (ls->current == '=') { + save_and_next(ls); + count++; + } + return (ls->current == s) ? count + 2 + : (count == 0) ? 1 + : 0; +} + + +static void read_long_string (LexState *ls, SemInfo *seminfo, size_t sep) { + int line = ls->linenumber; /* initial line (for error message) */ + save_and_next(ls); /* skip 2nd '[' */ + if (currIsNewline(ls)) /* string starts with a newline? */ + inclinenumber(ls); /* skip it */ + for (;;) { + switch (ls->current) { + case EOZ: { /* error */ + const char *what = (seminfo ? "string" : "comment"); + const char *msg = luaO_pushfstring(ls->L, + "unfinished long %s (starting at line %d)", what, line); + lexerror(ls, msg, TK_EOS); + break; /* to avoid warnings */ + } + case ']': { + if (skip_sep(ls) == sep) { + save_and_next(ls); /* skip 2nd ']' */ + goto endloop; + } + break; + } + case '\n': case '\r': { + save(ls, '\n'); + inclinenumber(ls); + if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ + break; + } + default: { + if (seminfo) save_and_next(ls); + else next(ls); + } + } + } endloop: + if (seminfo) + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + sep, + luaZ_bufflen(ls->buff) - 2 * sep); +} + + +static void esccheck (LexState *ls, int c, const char *msg) { + if (!c) { + if (ls->current != EOZ) + save_and_next(ls); /* add current to buffer for error message */ + lexerror(ls, msg, TK_STRING); + } +} + + +static int gethexa (LexState *ls) { + save_and_next(ls); + esccheck (ls, lisxdigit(ls->current), "hexadecimal digit expected"); + return luaO_hexavalue(ls->current); +} + + +static int readhexaesc (LexState *ls) { + int r = gethexa(ls); + r = (r << 4) + gethexa(ls); + luaZ_buffremove(ls->buff, 2); /* remove saved chars from buffer */ + return r; +} + + +static unsigned long readutf8esc (LexState *ls) { + unsigned long r; + int i = 4; /* chars to be removed: '\', 'u', '{', and first digit */ + save_and_next(ls); /* skip 'u' */ + esccheck(ls, ls->current == '{', "missing '{'"); + r = gethexa(ls); /* must have at least one digit */ + while (cast_void(save_and_next(ls)), lisxdigit(ls->current)) { + i++; + esccheck(ls, r <= (0x7FFFFFFFu >> 4), "UTF-8 value too large"); + r = (r << 4) + luaO_hexavalue(ls->current); + } + esccheck(ls, ls->current == '}', "missing '}'"); + next(ls); /* skip '}' */ + luaZ_buffremove(ls->buff, i); /* remove saved chars from buffer */ + return r; +} + + +static void utf8esc (LexState *ls) { + char buff[UTF8BUFFSZ]; + int n = luaO_utf8esc(buff, readutf8esc(ls)); + for (; n > 0; n--) /* add 'buff' to string */ + save(ls, buff[UTF8BUFFSZ - n]); +} + + +static int readdecesc (LexState *ls) { + int i; + int r = 0; /* result accumulator */ + for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */ + r = 10*r + ls->current - '0'; + save_and_next(ls); + } + esccheck(ls, r <= UCHAR_MAX, "decimal escape too large"); + luaZ_buffremove(ls->buff, i); /* remove read digits from buffer */ + return r; +} + + +static void read_string (LexState *ls, int del, SemInfo *seminfo) { + save_and_next(ls); /* keep delimiter (for error messages) */ + while (ls->current != del) { + switch (ls->current) { + case EOZ: + lexerror(ls, "unfinished string", TK_EOS); + break; /* to avoid warnings */ + case '\n': + case '\r': + lexerror(ls, "unfinished string", TK_STRING); + break; /* to avoid warnings */ + case '\\': { /* escape sequences */ + int c; /* final character to be saved */ + save_and_next(ls); /* keep '\\' for error messages */ + switch (ls->current) { + case 'a': c = '\a'; goto read_save; + case 'b': c = '\b'; goto read_save; + case 'f': c = '\f'; goto read_save; + case 'n': c = '\n'; goto read_save; + case 'r': c = '\r'; goto read_save; + case 't': c = '\t'; goto read_save; + case 'v': c = '\v'; goto read_save; + case 'x': c = readhexaesc(ls); goto read_save; + case 'u': utf8esc(ls); goto no_save; + case '\n': case '\r': + inclinenumber(ls); c = '\n'; goto only_save; + case '\\': case '\"': case '\'': + c = ls->current; goto read_save; + case EOZ: goto no_save; /* will raise an error next loop */ + case 'z': { /* zap following span of spaces */ + luaZ_buffremove(ls->buff, 1); /* remove '\\' */ + next(ls); /* skip the 'z' */ + while (lisspace(ls->current)) { + if (currIsNewline(ls)) inclinenumber(ls); + else next(ls); + } + goto no_save; + } + default: { + esccheck(ls, lisdigit(ls->current), "invalid escape sequence"); + c = readdecesc(ls); /* digital escape '\ddd' */ + goto only_save; + } + } + read_save: + next(ls); + /* go through */ + only_save: + luaZ_buffremove(ls->buff, 1); /* remove '\\' */ + save(ls, c); + /* go through */ + no_save: break; + } + default: + save_and_next(ls); + } + } + save_and_next(ls); /* skip delimiter */ + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, + luaZ_bufflen(ls->buff) - 2); +} + + +static int llex (LexState *ls, SemInfo *seminfo) { + luaZ_resetbuffer(ls->buff); + for (;;) { + switch (ls->current) { + case '\n': case '\r': { /* line breaks */ + inclinenumber(ls); + break; + } + case ' ': case '\f': case '\t': case '\v': { /* spaces */ + next(ls); + break; + } + case '-': { /* '-' or '--' (comment) */ + next(ls); + if (ls->current != '-') return '-'; + /* else is a comment */ + next(ls); + if (ls->current == '[') { /* long comment? */ + size_t sep = skip_sep(ls); + luaZ_resetbuffer(ls->buff); /* 'skip_sep' may dirty the buffer */ + if (sep >= 2) { + read_long_string(ls, NULL, sep); /* skip long comment */ + luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */ + break; + } + } + /* else short comment */ + while (!currIsNewline(ls) && ls->current != EOZ) + next(ls); /* skip until end of line (or end of file) */ + break; + } + case '[': { /* long string or simply '[' */ + size_t sep = skip_sep(ls); + if (sep >= 2) { + read_long_string(ls, seminfo, sep); + return TK_STRING; + } + else if (sep == 0) /* '[=...' missing second bracket? */ + lexerror(ls, "invalid long string delimiter", TK_STRING); + return '['; + } + case '=': { + next(ls); + if (check_next1(ls, '=')) return TK_EQ; /* '==' */ + else return '='; + } + case '<': { + next(ls); + if (check_next1(ls, '=')) return TK_LE; /* '<=' */ + else if (check_next1(ls, '<')) return TK_SHL; /* '<<' */ + else return '<'; + } + case '>': { + next(ls); + if (check_next1(ls, '=')) return TK_GE; /* '>=' */ + else if (check_next1(ls, '>')) return TK_SHR; /* '>>' */ + else return '>'; + } + case '/': { + next(ls); + if (check_next1(ls, '/')) return TK_IDIV; /* '//' */ + else return '/'; + } + case '~': { + next(ls); + if (check_next1(ls, '=')) return TK_NE; /* '~=' */ + else return '~'; + } + case ':': { + next(ls); + if (check_next1(ls, ':')) return TK_DBCOLON; /* '::' */ + else return ':'; + } + case '"': case '\'': { /* short literal strings */ + read_string(ls, ls->current, seminfo); + return TK_STRING; + } + case '.': { /* '.', '..', '...', or number */ + save_and_next(ls); + if (check_next1(ls, '.')) { + if (check_next1(ls, '.')) + return TK_DOTS; /* '...' */ + else return TK_CONCAT; /* '..' */ + } + else if (!lisdigit(ls->current)) return '.'; + else return read_numeral(ls, seminfo); + } + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + return read_numeral(ls, seminfo); + } + case EOZ: { + return TK_EOS; + } + default: { + if (lislalpha(ls->current)) { /* identifier or reserved word? */ + TString *ts; + do { + save_and_next(ls); + } while (lislalnum(ls->current)); + ts = luaX_newstring(ls, luaZ_buffer(ls->buff), + luaZ_bufflen(ls->buff)); + seminfo->ts = ts; + if (isreserved(ts)) /* reserved word? */ + return ts->extra - 1 + FIRST_RESERVED; + else { + return TK_NAME; + } + } + else { /* single-char tokens ('+', '*', '%', '{', '}', ...) */ + int c = ls->current; + next(ls); + return c; + } + } + } + } +} + + +void luaX_next (LexState *ls) { + ls->lastline = ls->linenumber; + if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ + ls->t = ls->lookahead; /* use this one */ + ls->lookahead.token = TK_EOS; /* and discharge it */ + } + else + ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ +} + + +int luaX_lookahead (LexState *ls) { + lua_assert(ls->lookahead.token == TK_EOS); + ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); + return ls->lookahead.token; +} + diff --git a/src/libs/3rdparty/lua/src/llex.h b/src/libs/3rdparty/lua/src/llex.h new file mode 100644 index 0000000000..389d2f8635 --- /dev/null +++ b/src/libs/3rdparty/lua/src/llex.h @@ -0,0 +1,91 @@ +/* +** $Id: llex.h $ +** Lexical Analyzer +** See Copyright Notice in lua.h +*/ + +#ifndef llex_h +#define llex_h + +#include <limits.h> + +#include "lobject.h" +#include "lzio.h" + + +/* +** Single-char tokens (terminal symbols) are represented by their own +** numeric code. Other tokens start at the following value. +*/ +#define FIRST_RESERVED (UCHAR_MAX + 1) + + +#if !defined(LUA_ENV) +#define LUA_ENV "_ENV" +#endif + + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER RESERVED" +*/ +enum RESERVED { + /* terminal symbols denoted by reserved words */ + TK_AND = FIRST_RESERVED, TK_BREAK, + TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, + TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, + TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, + /* other terminal symbols */ + TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, + TK_SHL, TK_SHR, + TK_DBCOLON, TK_EOS, + TK_FLT, TK_INT, TK_NAME, TK_STRING +}; + +/* number of reserved words */ +#define NUM_RESERVED (cast_int(TK_WHILE-FIRST_RESERVED + 1)) + + +typedef union { + lua_Number r; + lua_Integer i; + TString *ts; +} SemInfo; /* semantics information */ + + +typedef struct Token { + int token; + SemInfo seminfo; +} Token; + + +/* state of the lexer plus state of the parser when shared by all + functions */ +typedef struct LexState { + int current; /* current character (charint) */ + int linenumber; /* input line counter */ + int lastline; /* line of last token 'consumed' */ + Token t; /* current token */ + Token lookahead; /* look ahead token */ + struct FuncState *fs; /* current function (parser) */ + struct lua_State *L; + ZIO *z; /* input stream */ + Mbuffer *buff; /* buffer for tokens */ + Table *h; /* to avoid collection/reuse strings */ + struct Dyndata *dyd; /* dynamic structures used by the parser */ + TString *source; /* current source name */ + TString *envn; /* environment variable name */ +} LexState; + + +LUAI_FUNC void luaX_init (lua_State *L); +LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, + TString *source, int firstchar); +LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); +LUAI_FUNC void luaX_next (LexState *ls); +LUAI_FUNC int luaX_lookahead (LexState *ls); +LUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s); +LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); + + +#endif diff --git a/src/libs/3rdparty/lua/src/llimits.h b/src/libs/3rdparty/lua/src/llimits.h new file mode 100644 index 0000000000..1c826f7be2 --- /dev/null +++ b/src/libs/3rdparty/lua/src/llimits.h @@ -0,0 +1,380 @@ +/* +** $Id: llimits.h $ +** Limits, basic types, and some other 'installation-dependent' definitions +** See Copyright Notice in lua.h +*/ + +#ifndef llimits_h +#define llimits_h + + +#include <limits.h> +#include <stddef.h> + + +#include "lua.h" + + +/* +** 'lu_mem' and 'l_mem' are unsigned/signed integers big enough to count +** the total memory used by Lua (in bytes). Usually, 'size_t' and +** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines. +*/ +#if defined(LUAI_MEM) /* { external definitions? */ +typedef LUAI_UMEM lu_mem; +typedef LUAI_MEM l_mem; +#elif LUAI_IS32INT /* }{ */ +typedef size_t lu_mem; +typedef ptrdiff_t l_mem; +#else /* 16-bit ints */ /* }{ */ +typedef unsigned long lu_mem; +typedef long l_mem; +#endif /* } */ + + +/* chars used as small naturals (so that 'char' is reserved for characters) */ +typedef unsigned char lu_byte; +typedef signed char ls_byte; + + +/* maximum value for size_t */ +#define MAX_SIZET ((size_t)(~(size_t)0)) + +/* maximum size visible for Lua (must be representable in a lua_Integer) */ +#define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \ + : (size_t)(LUA_MAXINTEGER)) + + +#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)) + +#define MAX_LMEM ((l_mem)(MAX_LUMEM >> 1)) + + +#define MAX_INT INT_MAX /* maximum value of an int */ + + +/* +** floor of the log2 of the maximum signed value for integral type 't'. +** (That is, maximum 'n' such that '2^n' fits in the given signed type.) +*/ +#define log2maxs(t) (sizeof(t) * 8 - 2) + + +/* +** test whether an unsigned value is a power of 2 (or zero) +*/ +#define ispow2(x) (((x) & ((x) - 1)) == 0) + + +/* number of chars of a literal string without the ending \0 */ +#define LL(x) (sizeof(x)/sizeof(char) - 1) + + +/* +** conversion of pointer to unsigned integer: this is for hashing only; +** there is no problem if the integer cannot hold the whole pointer +** value. (In strict ISO C this may cause undefined behavior, but no +** actual machine seems to bother.) +*/ +#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \ + __STDC_VERSION__ >= 199901L +#include <stdint.h> +#if defined(UINTPTR_MAX) /* even in C99 this type is optional */ +#define L_P2I uintptr_t +#else /* no 'intptr'? */ +#define L_P2I uintmax_t /* use the largest available integer */ +#endif +#else /* C89 option */ +#define L_P2I size_t +#endif + +#define point2uint(p) ((unsigned int)((L_P2I)(p) & UINT_MAX)) + + + +/* types of 'usual argument conversions' for lua_Number and lua_Integer */ +typedef LUAI_UACNUMBER l_uacNumber; +typedef LUAI_UACINT l_uacInt; + + +/* +** Internal assertions for in-house debugging +*/ +#if defined LUAI_ASSERT +#undef NDEBUG +#include <assert.h> +#define lua_assert(c) assert(c) +#endif + +#if defined(lua_assert) +#define check_exp(c,e) (lua_assert(c), (e)) +/* to avoid problems with conditions too long */ +#define lua_longassert(c) ((c) ? (void)0 : lua_assert(0)) +#else +#define lua_assert(c) ((void)0) +#define check_exp(c,e) (e) +#define lua_longassert(c) ((void)0) +#endif + +/* +** assertion for checking API calls +*/ +#if !defined(luai_apicheck) +#define luai_apicheck(l,e) ((void)l, lua_assert(e)) +#endif + +#define api_check(l,e,msg) luai_apicheck(l,(e) && msg) + + +/* macro to avoid warnings about unused variables */ +#if !defined(UNUSED) +#define UNUSED(x) ((void)(x)) +#endif + + +/* type casts (a macro highlights casts in the code) */ +#define cast(t, exp) ((t)(exp)) + +#define cast_void(i) cast(void, (i)) +#define cast_voidp(i) cast(void *, (i)) +#define cast_num(i) cast(lua_Number, (i)) +#define cast_int(i) cast(int, (i)) +#define cast_uint(i) cast(unsigned int, (i)) +#define cast_byte(i) cast(lu_byte, (i)) +#define cast_uchar(i) cast(unsigned char, (i)) +#define cast_char(i) cast(char, (i)) +#define cast_charp(i) cast(char *, (i)) +#define cast_sizet(i) cast(size_t, (i)) + + +/* cast a signed lua_Integer to lua_Unsigned */ +#if !defined(l_castS2U) +#define l_castS2U(i) ((lua_Unsigned)(i)) +#endif + +/* +** cast a lua_Unsigned to a signed lua_Integer; this cast is +** not strict ISO C, but two-complement architectures should +** work fine. +*/ +#if !defined(l_castU2S) +#define l_castU2S(i) ((lua_Integer)(i)) +#endif + + +/* +** non-return type +*/ +#if !defined(l_noret) + +#if defined(__GNUC__) +#define l_noret void __attribute__((noreturn)) +#elif defined(_MSC_VER) && _MSC_VER >= 1200 +#define l_noret void __declspec(noreturn) +#else +#define l_noret void +#endif + +#endif + + +/* +** Inline functions +*/ +#if !defined(LUA_USE_C89) +#define l_inline inline +#elif defined(__GNUC__) +#define l_inline __inline__ +#else +#define l_inline /* empty */ +#endif + +#define l_sinline static l_inline + + +/* +** type for virtual-machine instructions; +** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) +*/ +#if LUAI_IS32INT +typedef unsigned int l_uint32; +#else +typedef unsigned long l_uint32; +#endif + +typedef l_uint32 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 + + +/* +** Initial size for the string table (must be power of 2). +** The Lua core alone registers ~50 strings (reserved words + +** metaevent keys + a few others). Libraries would typically add +** a few dozens more. +*/ +#if !defined(MINSTRTABSIZE) +#define MINSTRTABSIZE 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 + + +/* minimum size for string buffer */ +#if !defined(LUA_MINBUFFER) +#define LUA_MINBUFFER 32 +#endif + + +/* +** Maximum depth for nested C calls, syntactical nested non-terminals, +** and other features implemented through recursion in C. (Value must +** fit in a 16-bit unsigned integer. It must also be compatible with +** the size of the C stack.) +*/ +#if !defined(LUAI_MAXCCALLS) +#define LUAI_MAXCCALLS 200 +#endif + + +/* +** macros that are executed whenever program enters the Lua core +** ('lua_lock') and leaves the core ('lua_unlock') +*/ +#if !defined(lua_lock) +#define lua_lock(L) ((void) 0) +#define lua_unlock(L) ((void) 0) +#endif + +/* +** macro executed during Lua functions at points where the +** function can yield. +*/ +#if !defined(luai_threadyield) +#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} +#endif + + +/* +** these macros allow user-specific actions when a thread is +** created/deleted/resumed/yielded. +*/ +#if !defined(luai_userstateopen) +#define luai_userstateopen(L) ((void)L) +#endif + +#if !defined(luai_userstateclose) +#define luai_userstateclose(L) ((void)L) +#endif + +#if !defined(luai_userstatethread) +#define luai_userstatethread(L,L1) ((void)L) +#endif + +#if !defined(luai_userstatefree) +#define luai_userstatefree(L,L1) ((void)L) +#endif + +#if !defined(luai_userstateresume) +#define luai_userstateresume(L,n) ((void)L) +#endif + +#if !defined(luai_userstateyield) +#define luai_userstateyield(L,n) ((void)L) +#endif + + + +/* +** 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'; the direct computation +** using this definition has several problems with rounding errors, +** so it is better to use 'fmod'. '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: non-integer result is equivalent to +** a non-zero remainder 'm'; negative result is equivalent to 'a' and +** 'b' with different signs, or 'm' and 'b' with different signs +** (as the result 'm' of 'fmod' has the same sign of 'a'). +*/ +#if !defined(luai_nummod) +#define luai_nummod(L,a,b,m) \ + { (void)L; (m) = l_mathop(fmod)(a,b); \ + if (((m) > 0) ? (b) < 0 : ((m) < 0 && (b) > 0)) (m) += (b); } +#endif + +/* exponentiation */ +#if !defined(luai_numpow) +#define luai_numpow(L,a,b) \ + ((void)L, (b == 2) ? (a)*(a) : 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_numgt(a,b) ((a)>(b)) +#define luai_numge(a,b) ((a)>=(b)) +#define luai_numisnan(a) (!luai_numeq((a), (a))) +#endif + + + + + +/* +** macro to control inclusion of some hard tests on stack reallocation +*/ +#if !defined(HARDSTACKTESTS) +#define condmovestack(L,pre,pos) ((void)0) +#else +/* realloc stack keeping its size */ +#define condmovestack(L,pre,pos) \ + { int sz_ = stacksize(L); pre; luaD_reallocstack((L), sz_, 0); pos; } +#endif + +#if !defined(HARDMEMTESTS) +#define condchangemem(L,pre,pos) ((void)0) +#else +#define condchangemem(L,pre,pos) \ + { if (gcrunning(G(L))) { pre; luaC_fullgc(L, 0); pos; } } +#endif + +#endif diff --git a/src/libs/3rdparty/lua/src/lmathlib.c b/src/libs/3rdparty/lua/src/lmathlib.c new file mode 100644 index 0000000000..d0b1e1e5d6 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lmathlib.c @@ -0,0 +1,764 @@ +/* +** $Id: lmathlib.c $ +** Standard mathematical library +** See Copyright Notice in lua.h +*/ + +#define lmathlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include <float.h> +#include <limits.h> +#include <math.h> +#include <stdlib.h> +#include <time.h> + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#undef PI +#define PI (l_mathop(3.141592653589793238462643383279502884)) + + +static int math_abs (lua_State *L) { + if (lua_isinteger(L, 1)) { + lua_Integer n = lua_tointeger(L, 1); + if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n); + lua_pushinteger(L, n); + } + else + lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sin (lua_State *L) { + lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_cos (lua_State *L) { + lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tan (lua_State *L) { + lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_asin (lua_State *L) { + lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_acos (lua_State *L) { + lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_atan (lua_State *L) { + lua_Number y = luaL_checknumber(L, 1); + lua_Number x = luaL_optnumber(L, 2, 1); + lua_pushnumber(L, l_mathop(atan2)(y, x)); + return 1; +} + + +static int math_toint (lua_State *L) { + int valid; + lua_Integer n = lua_tointegerx(L, 1, &valid); + if (l_likely(valid)) + lua_pushinteger(L, n); + else { + luaL_checkany(L, 1); + luaL_pushfail(L); /* value is not convertible to integer */ + } + return 1; +} + + +static void pushnumint (lua_State *L, lua_Number d) { + lua_Integer n; + if (lua_numbertointeger(d, &n)) /* does 'd' fit in an integer? */ + lua_pushinteger(L, n); /* result is integer */ + else + lua_pushnumber(L, d); /* result is float */ +} + + +static int math_floor (lua_State *L) { + if (lua_isinteger(L, 1)) + lua_settop(L, 1); /* integer is its own floor */ + else { + lua_Number d = l_mathop(floor)(luaL_checknumber(L, 1)); + pushnumint(L, d); + } + return 1; +} + + +static int math_ceil (lua_State *L) { + if (lua_isinteger(L, 1)) + lua_settop(L, 1); /* integer is its own ceil */ + else { + lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1)); + pushnumint(L, d); + } + return 1; +} + + +static int math_fmod (lua_State *L) { + if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) { + lua_Integer d = lua_tointeger(L, 2); + if ((lua_Unsigned)d + 1u <= 1u) { /* special cases: -1 or 0 */ + luaL_argcheck(L, d != 0, 2, "zero"); + lua_pushinteger(L, 0); /* avoid overflow with 0x80000... / -1 */ + } + else + lua_pushinteger(L, lua_tointeger(L, 1) % d); + } + else + lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), + luaL_checknumber(L, 2))); + return 1; +} + + +/* +** next function does not use 'modf', avoiding problems with 'double*' +** (which is not compatible with 'float*') when lua_Number is not +** 'double'. +*/ +static int math_modf (lua_State *L) { + if (lua_isinteger(L ,1)) { + lua_settop(L, 1); /* number is its own integer part */ + lua_pushnumber(L, 0); /* no fractional part */ + } + else { + lua_Number n = luaL_checknumber(L, 1); + /* integer part (rounds toward zero) */ + lua_Number ip = (n < 0) ? l_mathop(ceil)(n) : l_mathop(floor)(n); + pushnumint(L, ip); + /* fractional part (test needed for inf/-inf) */ + lua_pushnumber(L, (n == ip) ? l_mathop(0.0) : (n - ip)); + } + return 2; +} + + +static int math_sqrt (lua_State *L) { + lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1))); + return 1; +} + + +static int math_ult (lua_State *L) { + lua_Integer a = luaL_checkinteger(L, 1); + lua_Integer b = luaL_checkinteger(L, 2); + lua_pushboolean(L, (lua_Unsigned)a < (lua_Unsigned)b); + return 1; +} + +static int math_log (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + lua_Number res; + if (lua_isnoneornil(L, 2)) + res = l_mathop(log)(x); + else { + lua_Number base = luaL_checknumber(L, 2); +#if !defined(LUA_USE_C89) + if (base == l_mathop(2.0)) + res = l_mathop(log2)(x); + else +#endif + if (base == l_mathop(10.0)) + res = l_mathop(log10)(x); + else + res = l_mathop(log)(x)/l_mathop(log)(base); + } + lua_pushnumber(L, res); + return 1; +} + +static int math_exp (lua_State *L) { + lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_deg (lua_State *L) { + lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI)); + return 1; +} + +static int math_rad (lua_State *L) { + lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0))); + return 1; +} + + +static int math_min (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int imin = 1; /* index of current minimum value */ + int i; + luaL_argcheck(L, n >= 1, 1, "value expected"); + for (i = 2; i <= n; i++) { + if (lua_compare(L, i, imin, LUA_OPLT)) + imin = i; + } + lua_pushvalue(L, imin); + return 1; +} + + +static int math_max (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int imax = 1; /* index of current maximum value */ + int i; + luaL_argcheck(L, n >= 1, 1, "value expected"); + for (i = 2; i <= n; i++) { + if (lua_compare(L, imax, i, LUA_OPLT)) + imax = i; + } + lua_pushvalue(L, imax); + return 1; +} + + +static int math_type (lua_State *L) { + if (lua_type(L, 1) == LUA_TNUMBER) + lua_pushstring(L, (lua_isinteger(L, 1)) ? "integer" : "float"); + else { + luaL_checkany(L, 1); + luaL_pushfail(L); + } + return 1; +} + + + +/* +** {================================================================== +** Pseudo-Random Number Generator based on 'xoshiro256**'. +** =================================================================== +*/ + +/* number of binary digits in the mantissa of a float */ +#define FIGS l_floatatt(MANT_DIG) + +#if FIGS > 64 +/* there are only 64 random bits; use them all */ +#undef FIGS +#define FIGS 64 +#endif + + +/* +** LUA_RAND32 forces the use of 32-bit integers in the implementation +** of the PRN generator (mainly for testing). +*/ +#if !defined(LUA_RAND32) && !defined(Rand64) + +/* try to find an integer type with at least 64 bits */ + +#if ((ULONG_MAX >> 31) >> 31) >= 3 + +/* 'long' has at least 64 bits */ +#define Rand64 unsigned long + +#elif !defined(LUA_USE_C89) && defined(LLONG_MAX) + +/* there is a 'long long' type (which must have at least 64 bits) */ +#define Rand64 unsigned long long + +#elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3 + +/* 'lua_Unsigned' has at least 64 bits */ +#define Rand64 lua_Unsigned + +#endif + +#endif + + +#if defined(Rand64) /* { */ + +/* +** Standard implementation, using 64-bit integers. +** If 'Rand64' has more than 64 bits, the extra bits do not interfere +** with the 64 initial bits, except in a right shift. Moreover, the +** final result has to discard the extra bits. +*/ + +/* avoid using extra bits when needed */ +#define trim64(x) ((x) & 0xffffffffffffffffu) + + +/* rotate left 'x' by 'n' bits */ +static Rand64 rotl (Rand64 x, int n) { + return (x << n) | (trim64(x) >> (64 - n)); +} + +static Rand64 nextrand (Rand64 *state) { + Rand64 state0 = state[0]; + Rand64 state1 = state[1]; + Rand64 state2 = state[2] ^ state0; + Rand64 state3 = state[3] ^ state1; + Rand64 res = rotl(state1 * 5, 7) * 9; + state[0] = state0 ^ state3; + state[1] = state1 ^ state2; + state[2] = state2 ^ (state1 << 17); + state[3] = rotl(state3, 45); + return res; +} + + +/* must take care to not shift stuff by more than 63 slots */ + + +/* +** Convert bits from a random integer into a float in the +** interval [0,1), getting the higher FIG bits from the +** random unsigned integer and converting that to a float. +*/ + +/* must throw out the extra (64 - FIGS) bits */ +#define shift64_FIG (64 - FIGS) + +/* to scale to [0, 1), multiply by scaleFIG = 2^(-FIGS) */ +#define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1))) + +static lua_Number I2d (Rand64 x) { + return (lua_Number)(trim64(x) >> shift64_FIG) * scaleFIG; +} + +/* convert a 'Rand64' to a 'lua_Unsigned' */ +#define I2UInt(x) ((lua_Unsigned)trim64(x)) + +/* convert a 'lua_Unsigned' to a 'Rand64' */ +#define Int2I(x) ((Rand64)(x)) + + +#else /* no 'Rand64' }{ */ + +/* get an integer with at least 32 bits */ +#if LUAI_IS32INT +typedef unsigned int lu_int32; +#else +typedef unsigned long lu_int32; +#endif + + +/* +** Use two 32-bit integers to represent a 64-bit quantity. +*/ +typedef struct Rand64 { + lu_int32 h; /* higher half */ + lu_int32 l; /* lower half */ +} Rand64; + + +/* +** If 'lu_int32' has more than 32 bits, the extra bits do not interfere +** with the 32 initial bits, except in a right shift and comparisons. +** Moreover, the final result has to discard the extra bits. +*/ + +/* avoid using extra bits when needed */ +#define trim32(x) ((x) & 0xffffffffu) + + +/* +** basic operations on 'Rand64' values +*/ + +/* build a new Rand64 value */ +static Rand64 packI (lu_int32 h, lu_int32 l) { + Rand64 result; + result.h = h; + result.l = l; + return result; +} + +/* return i << n */ +static Rand64 Ishl (Rand64 i, int n) { + lua_assert(n > 0 && n < 32); + return packI((i.h << n) | (trim32(i.l) >> (32 - n)), i.l << n); +} + +/* i1 ^= i2 */ +static void Ixor (Rand64 *i1, Rand64 i2) { + i1->h ^= i2.h; + i1->l ^= i2.l; +} + +/* return i1 + i2 */ +static Rand64 Iadd (Rand64 i1, Rand64 i2) { + Rand64 result = packI(i1.h + i2.h, i1.l + i2.l); + if (trim32(result.l) < trim32(i1.l)) /* carry? */ + result.h++; + return result; +} + +/* return i * 5 */ +static Rand64 times5 (Rand64 i) { + return Iadd(Ishl(i, 2), i); /* i * 5 == (i << 2) + i */ +} + +/* return i * 9 */ +static Rand64 times9 (Rand64 i) { + return Iadd(Ishl(i, 3), i); /* i * 9 == (i << 3) + i */ +} + +/* return 'i' rotated left 'n' bits */ +static Rand64 rotl (Rand64 i, int n) { + lua_assert(n > 0 && n < 32); + return packI((i.h << n) | (trim32(i.l) >> (32 - n)), + (trim32(i.h) >> (32 - n)) | (i.l << n)); +} + +/* for offsets larger than 32, rotate right by 64 - offset */ +static Rand64 rotl1 (Rand64 i, int n) { + lua_assert(n > 32 && n < 64); + n = 64 - n; + return packI((trim32(i.h) >> n) | (i.l << (32 - n)), + (i.h << (32 - n)) | (trim32(i.l) >> n)); +} + +/* +** implementation of 'xoshiro256**' algorithm on 'Rand64' values +*/ +static Rand64 nextrand (Rand64 *state) { + Rand64 res = times9(rotl(times5(state[1]), 7)); + Rand64 t = Ishl(state[1], 17); + Ixor(&state[2], state[0]); + Ixor(&state[3], state[1]); + Ixor(&state[1], state[2]); + Ixor(&state[0], state[3]); + Ixor(&state[2], t); + state[3] = rotl1(state[3], 45); + return res; +} + + +/* +** Converts a 'Rand64' into a float. +*/ + +/* an unsigned 1 with proper type */ +#define UONE ((lu_int32)1) + + +#if FIGS <= 32 + +/* 2^(-FIGS) */ +#define scaleFIG (l_mathop(0.5) / (UONE << (FIGS - 1))) + +/* +** get up to 32 bits from higher half, shifting right to +** throw out the extra bits. +*/ +static lua_Number I2d (Rand64 x) { + lua_Number h = (lua_Number)(trim32(x.h) >> (32 - FIGS)); + return h * scaleFIG; +} + +#else /* 32 < FIGS <= 64 */ + +/* must take care to not shift stuff by more than 31 slots */ + +/* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */ +#define scaleFIG \ + (l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33))) + +/* +** use FIGS - 32 bits from lower half, throwing out the other +** (32 - (FIGS - 32)) = (64 - FIGS) bits +*/ +#define shiftLOW (64 - FIGS) + +/* +** higher 32 bits go after those (FIGS - 32) bits: shiftHI = 2^(FIGS - 32) +*/ +#define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * l_mathop(2.0)) + + +static lua_Number I2d (Rand64 x) { + lua_Number h = (lua_Number)trim32(x.h) * shiftHI; + lua_Number l = (lua_Number)(trim32(x.l) >> shiftLOW); + return (h + l) * scaleFIG; +} + +#endif + + +/* convert a 'Rand64' to a 'lua_Unsigned' */ +static lua_Unsigned I2UInt (Rand64 x) { + return (((lua_Unsigned)trim32(x.h) << 31) << 1) | (lua_Unsigned)trim32(x.l); +} + +/* convert a 'lua_Unsigned' to a 'Rand64' */ +static Rand64 Int2I (lua_Unsigned n) { + return packI((lu_int32)((n >> 31) >> 1), (lu_int32)n); +} + +#endif /* } */ + + +/* +** A state uses four 'Rand64' values. +*/ +typedef struct { + Rand64 s[4]; +} RanState; + + +/* +** Project the random integer 'ran' into the interval [0, n]. +** Because 'ran' has 2^B possible values, the projection can only be +** uniform when the size of the interval is a power of 2 (exact +** division). Otherwise, to get a uniform projection into [0, n], we +** first compute 'lim', the smallest Mersenne number not smaller than +** 'n'. We then project 'ran' into the interval [0, lim]. If the result +** is inside [0, n], we are done. Otherwise, we try with another 'ran', +** until we have a result inside the interval. +*/ +static lua_Unsigned project (lua_Unsigned ran, lua_Unsigned n, + RanState *state) { + if ((n & (n + 1)) == 0) /* is 'n + 1' a power of 2? */ + return ran & n; /* no bias */ + else { + lua_Unsigned lim = n; + /* compute the smallest (2^b - 1) not smaller than 'n' */ + lim |= (lim >> 1); + lim |= (lim >> 2); + lim |= (lim >> 4); + lim |= (lim >> 8); + lim |= (lim >> 16); +#if (LUA_MAXUNSIGNED >> 31) >= 3 + lim |= (lim >> 32); /* integer type has more than 32 bits */ +#endif + lua_assert((lim & (lim + 1)) == 0 /* 'lim + 1' is a power of 2, */ + && lim >= n /* not smaller than 'n', */ + && (lim >> 1) < n); /* and it is the smallest one */ + while ((ran &= lim) > n) /* project 'ran' into [0..lim] */ + ran = I2UInt(nextrand(state->s)); /* not inside [0..n]? try again */ + return ran; + } +} + + +static int math_random (lua_State *L) { + lua_Integer low, up; + lua_Unsigned p; + RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1)); + Rand64 rv = nextrand(state->s); /* next pseudo-random value */ + switch (lua_gettop(L)) { /* check number of arguments */ + case 0: { /* no arguments */ + lua_pushnumber(L, I2d(rv)); /* float between 0 and 1 */ + return 1; + } + case 1: { /* only upper limit */ + low = 1; + up = luaL_checkinteger(L, 1); + if (up == 0) { /* single 0 as argument? */ + lua_pushinteger(L, I2UInt(rv)); /* full random integer */ + return 1; + } + break; + } + case 2: { /* lower and upper limits */ + low = luaL_checkinteger(L, 1); + up = luaL_checkinteger(L, 2); + break; + } + default: return luaL_error(L, "wrong number of arguments"); + } + /* random integer in the interval [low, up] */ + luaL_argcheck(L, low <= up, 1, "interval is empty"); + /* project random integer into the interval [0, up - low] */ + p = project(I2UInt(rv), (lua_Unsigned)up - (lua_Unsigned)low, state); + lua_pushinteger(L, p + (lua_Unsigned)low); + return 1; +} + + +static void setseed (lua_State *L, Rand64 *state, + lua_Unsigned n1, lua_Unsigned n2) { + int i; + state[0] = Int2I(n1); + state[1] = Int2I(0xff); /* avoid a zero state */ + state[2] = Int2I(n2); + state[3] = Int2I(0); + for (i = 0; i < 16; i++) + nextrand(state); /* discard initial values to "spread" seed */ + lua_pushinteger(L, n1); + lua_pushinteger(L, n2); +} + + +/* +** Set a "random" seed. To get some randomness, use the current time +** and the address of 'L' (in case the machine does address space layout +** randomization). +*/ +static void randseed (lua_State *L, RanState *state) { + lua_Unsigned seed1 = (lua_Unsigned)time(NULL); + lua_Unsigned seed2 = (lua_Unsigned)(size_t)L; + setseed(L, state->s, seed1, seed2); +} + + +static int math_randomseed (lua_State *L) { + RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1)); + if (lua_isnone(L, 1)) { + randseed(L, state); + } + else { + lua_Integer n1 = luaL_checkinteger(L, 1); + lua_Integer n2 = luaL_optinteger(L, 2, 0); + setseed(L, state->s, n1, n2); + } + return 2; /* return seeds */ +} + + +static const luaL_Reg randfuncs[] = { + {"random", math_random}, + {"randomseed", math_randomseed}, + {NULL, NULL} +}; + + +/* +** Register the random functions and initialize their state. +*/ +static void setrandfunc (lua_State *L) { + RanState *state = (RanState *)lua_newuserdatauv(L, sizeof(RanState), 0); + randseed(L, state); /* initialize with a "random" seed */ + lua_pop(L, 2); /* remove pushed seeds */ + luaL_setfuncs(L, randfuncs, 1); +} + +/* }================================================================== */ + + +/* +** {================================================================== +** Deprecated functions (for compatibility only) +** =================================================================== +*/ +#if defined(LUA_COMPAT_MATHLIB) + +static int math_cosh (lua_State *L) { + lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sinh (lua_State *L) { + lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tanh (lua_State *L) { + lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_pow (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + lua_Number y = luaL_checknumber(L, 2); + lua_pushnumber(L, l_mathop(pow)(x, y)); + return 1; +} + +static int math_frexp (lua_State *L) { + int e; + lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e)); + lua_pushinteger(L, e); + return 2; +} + +static int math_ldexp (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + int ep = (int)luaL_checkinteger(L, 2); + lua_pushnumber(L, l_mathop(ldexp)(x, ep)); + return 1; +} + +static int math_log10 (lua_State *L) { + lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1))); + return 1; +} + +#endif +/* }================================================================== */ + + + +static const luaL_Reg mathlib[] = { + {"abs", math_abs}, + {"acos", math_acos}, + {"asin", math_asin}, + {"atan", math_atan}, + {"ceil", math_ceil}, + {"cos", math_cos}, + {"deg", math_deg}, + {"exp", math_exp}, + {"tointeger", math_toint}, + {"floor", math_floor}, + {"fmod", math_fmod}, + {"ult", math_ult}, + {"log", math_log}, + {"max", math_max}, + {"min", math_min}, + {"modf", math_modf}, + {"rad", math_rad}, + {"sin", math_sin}, + {"sqrt", math_sqrt}, + {"tan", math_tan}, + {"type", math_type}, +#if defined(LUA_COMPAT_MATHLIB) + {"atan2", math_atan}, + {"cosh", math_cosh}, + {"sinh", math_sinh}, + {"tanh", math_tanh}, + {"pow", math_pow}, + {"frexp", math_frexp}, + {"ldexp", math_ldexp}, + {"log10", math_log10}, +#endif + /* placeholders */ + {"random", NULL}, + {"randomseed", NULL}, + {"pi", NULL}, + {"huge", NULL}, + {"maxinteger", NULL}, + {"mininteger", NULL}, + {NULL, NULL} +}; + + +/* +** Open math library +*/ +LUAMOD_API int luaopen_math (lua_State *L) { + luaL_newlib(L, mathlib); + lua_pushnumber(L, PI); + lua_setfield(L, -2, "pi"); + lua_pushnumber(L, (lua_Number)HUGE_VAL); + lua_setfield(L, -2, "huge"); + lua_pushinteger(L, LUA_MAXINTEGER); + lua_setfield(L, -2, "maxinteger"); + lua_pushinteger(L, LUA_MININTEGER); + lua_setfield(L, -2, "mininteger"); + setrandfunc(L); + return 1; +} + diff --git a/src/libs/3rdparty/lua/src/lmem.c b/src/libs/3rdparty/lua/src/lmem.c new file mode 100644 index 0000000000..9800a86fc0 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lmem.c @@ -0,0 +1,215 @@ +/* +** $Id: lmem.c $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + +#define lmem_c +#define LUA_CORE + +#include "lprefix.h" + + +#include <stddef.h> + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" + + + +/* +** About the realloc function: +** void *frealloc (void *ud, void *ptr, size_t osize, size_t nsize); +** ('osize' is the old size, 'nsize' is the new size) +** +** - frealloc(ud, p, x, 0) frees the block 'p' and returns NULL. +** Particularly, frealloc(ud, NULL, 0, 0) does nothing, +** which is equivalent to free(NULL) in ISO C. +** +** - frealloc(ud, NULL, x, s) creates a new block of size 's' +** (no matter 'x'). Returns NULL if it cannot create the new block. +** +** - otherwise, frealloc(ud, b, x, y) reallocates the block 'b' from +** size 'x' to size 'y'. Returns NULL if it cannot reallocate the +** block to the new size. +*/ + + +/* +** Macro to call the allocation function. +*/ +#define callfrealloc(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns)) + + +/* +** When an allocation fails, it will try again after an emergency +** collection, except when it cannot run a collection. The GC should +** not be called while the state is not fully built, as the collector +** is not yet fully initialized. Also, it should not be called when +** 'gcstopem' is true, because then the interpreter is in the middle of +** a collection step. +*/ +#define cantryagain(g) (completestate(g) && !g->gcstopem) + + + + +#if defined(EMERGENCYGCTESTS) +/* +** First allocation will fail except when freeing a block (frees never +** fail) and when it cannot try again; this fail will trigger 'tryagain' +** and a full GC cycle at every allocation. +*/ +static void *firsttry (global_State *g, void *block, size_t os, size_t ns) { + if (ns > 0 && cantryagain(g)) + return NULL; /* fail */ + else /* normal allocation */ + return callfrealloc(g, block, os, ns); +} +#else +#define firsttry(g,block,os,ns) callfrealloc(g, block, os, ns) +#endif + + + + + +/* +** {================================================================== +** Functions to allocate/deallocate arrays for the Parser +** =================================================================== +*/ + +/* +** Minimum size for arrays during parsing, to avoid overhead of +** reallocating to size 1, then 2, and then 4. All these arrays +** will be reallocated to exact sizes or erased when parsing ends. +*/ +#define MINSIZEARRAY 4 + + +void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize, + int size_elems, int limit, const char *what) { + void *newblock; + int size = *psize; + if (nelems + 1 <= size) /* does one extra element still fit? */ + return block; /* nothing to be done */ + if (size >= limit / 2) { /* cannot double it? */ + if (l_unlikely(size >= limit)) /* cannot grow even a little? */ + luaG_runerror(L, "too many %s (limit is %d)", what, limit); + size = limit; /* still have at least one free place */ + } + else { + size *= 2; + if (size < MINSIZEARRAY) + size = MINSIZEARRAY; /* minimum size */ + } + lua_assert(nelems + 1 <= size && size <= limit); + /* 'limit' ensures that multiplication will not overflow */ + newblock = luaM_saferealloc_(L, block, cast_sizet(*psize) * size_elems, + cast_sizet(size) * size_elems); + *psize = size; /* update only when everything else is OK */ + return newblock; +} + + +/* +** In prototypes, the size of the array is also its number of +** elements (to save memory). So, if it cannot shrink an array +** to its number of elements, the only option is to raise an +** error. +*/ +void *luaM_shrinkvector_ (lua_State *L, void *block, int *size, + int final_n, int size_elem) { + void *newblock; + size_t oldsize = cast_sizet((*size) * size_elem); + size_t newsize = cast_sizet(final_n * size_elem); + lua_assert(newsize <= oldsize); + newblock = luaM_saferealloc_(L, block, oldsize, newsize); + *size = final_n; + return newblock; +} + +/* }================================================================== */ + + +l_noret luaM_toobig (lua_State *L) { + luaG_runerror(L, "memory allocation error: block too big"); +} + + +/* +** Free memory +*/ +void luaM_free_ (lua_State *L, void *block, size_t osize) { + global_State *g = G(L); + lua_assert((osize == 0) == (block == NULL)); + callfrealloc(g, block, osize, 0); + g->GCdebt -= osize; +} + + +/* +** In case of allocation fail, this function will do an emergency +** collection to free some memory and then try the allocation again. +*/ +static void *tryagain (lua_State *L, void *block, + size_t osize, size_t nsize) { + global_State *g = G(L); + if (cantryagain(g)) { + luaC_fullgc(L, 1); /* try to free some memory... */ + return callfrealloc(g, block, osize, nsize); /* try again */ + } + else return NULL; /* cannot run an emergency collection */ +} + + +/* +** Generic allocation routine. +*/ +void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { + void *newblock; + global_State *g = G(L); + lua_assert((osize == 0) == (block == NULL)); + newblock = firsttry(g, block, osize, nsize); + if (l_unlikely(newblock == NULL && nsize > 0)) { + newblock = tryagain(L, block, osize, nsize); + if (newblock == NULL) /* still no memory? */ + return NULL; /* do not update 'GCdebt' */ + } + lua_assert((nsize == 0) == (newblock == NULL)); + g->GCdebt = (g->GCdebt + nsize) - osize; + return newblock; +} + + +void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize, + size_t nsize) { + void *newblock = luaM_realloc_(L, block, osize, nsize); + if (l_unlikely(newblock == NULL && nsize > 0)) /* allocation failed? */ + luaM_error(L); + return newblock; +} + + +void *luaM_malloc_ (lua_State *L, size_t size, int tag) { + if (size == 0) + return NULL; /* that's all */ + else { + global_State *g = G(L); + void *newblock = firsttry(g, NULL, tag, size); + if (l_unlikely(newblock == NULL)) { + newblock = tryagain(L, NULL, tag, size); + if (newblock == NULL) + luaM_error(L); + } + g->GCdebt += size; + return newblock; + } +} diff --git a/src/libs/3rdparty/lua/src/lmem.h b/src/libs/3rdparty/lua/src/lmem.h new file mode 100644 index 0000000000..8c75a44beb --- /dev/null +++ b/src/libs/3rdparty/lua/src/lmem.h @@ -0,0 +1,93 @@ +/* +** $Id: lmem.h $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + +#ifndef lmem_h +#define lmem_h + + +#include <stddef.h> + +#include "llimits.h" +#include "lua.h" + + +#define luaM_error(L) luaD_throw(L, LUA_ERRMEM) + + +/* +** This macro tests whether it is safe to multiply 'n' by the size of +** type 't' without overflows. Because 'e' is always constant, it avoids +** the runtime division MAX_SIZET/(e). +** (The macro is somewhat complex to avoid warnings: The 'sizeof' +** comparison avoids a runtime comparison when overflow cannot occur. +** The compiler should be able to optimize the real test by itself, but +** when it does it, it may give a warning about "comparison is always +** false due to limited range of data type"; the +1 tricks the compiler, +** avoiding this warning but also this optimization.) +*/ +#define luaM_testsize(n,e) \ + (sizeof(n) >= sizeof(size_t) && cast_sizet((n)) + 1 > MAX_SIZET/(e)) + +#define luaM_checksize(L,n,e) \ + (luaM_testsize(n,e) ? luaM_toobig(L) : cast_void(0)) + + +/* +** Computes the minimum between 'n' and 'MAX_SIZET/sizeof(t)', so that +** the result is not larger than 'n' and cannot overflow a 'size_t' +** when multiplied by the size of type 't'. (Assumes that 'n' is an +** 'int' or 'unsigned int' and that 'int' is not larger than 'size_t'.) +*/ +#define luaM_limitN(n,t) \ + ((cast_sizet(n) <= MAX_SIZET/sizeof(t)) ? (n) : \ + cast_uint((MAX_SIZET/sizeof(t)))) + + +/* +** Arrays of chars do not need any test +*/ +#define luaM_reallocvchar(L,b,on,n) \ + cast_charp(luaM_saferealloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char))) + +#define luaM_freemem(L, b, s) luaM_free_(L, (b), (s)) +#define luaM_free(L, b) luaM_free_(L, (b), sizeof(*(b))) +#define luaM_freearray(L, b, n) luaM_free_(L, (b), (n)*sizeof(*(b))) + +#define luaM_new(L,t) cast(t*, luaM_malloc_(L, sizeof(t), 0)) +#define luaM_newvector(L,n,t) cast(t*, luaM_malloc_(L, (n)*sizeof(t), 0)) +#define luaM_newvectorchecked(L,n,t) \ + (luaM_checksize(L,n,sizeof(t)), luaM_newvector(L,n,t)) + +#define luaM_newobject(L,tag,s) luaM_malloc_(L, (s), tag) + +#define luaM_growvector(L,v,nelems,size,t,limit,e) \ + ((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \ + luaM_limitN(limit,t),e))) + +#define luaM_reallocvector(L, v,oldn,n,t) \ + (cast(t *, luaM_realloc_(L, v, cast_sizet(oldn) * sizeof(t), \ + cast_sizet(n) * sizeof(t)))) + +#define luaM_shrinkvector(L,v,size,fs,t) \ + ((v)=cast(t *, luaM_shrinkvector_(L, v, &(size), fs, sizeof(t)))) + +LUAI_FUNC l_noret luaM_toobig (lua_State *L); + +/* not to be called directly */ +LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, + size_t size); +LUAI_FUNC void *luaM_saferealloc_ (lua_State *L, void *block, size_t oldsize, + size_t size); +LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize); +LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems, + int *size, int size_elem, int limit, + const char *what); +LUAI_FUNC void *luaM_shrinkvector_ (lua_State *L, void *block, int *nelem, + int final_n, int size_elem); +LUAI_FUNC void *luaM_malloc_ (lua_State *L, size_t size, int tag); + +#endif + diff --git a/src/libs/3rdparty/lua/src/loadlib.c b/src/libs/3rdparty/lua/src/loadlib.c new file mode 100644 index 0000000000..d792dffaa0 --- /dev/null +++ b/src/libs/3rdparty/lua/src/loadlib.c @@ -0,0 +1,767 @@ +/* +** $Id: loadlib.c $ +** Dynamic library loader for Lua +** See Copyright Notice in lua.h +** +** This module contains an implementation of loadlib for Unix systems +** that have dlfcn, an implementation for Windows, and a stub for other +** systems. +*/ + +#define loadlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** LUA_IGMARK is a mark to ignore all before it when building the +** luaopen_ function name. +*/ +#if !defined (LUA_IGMARK) +#define LUA_IGMARK "-" +#endif + + +/* +** LUA_CSUBSEP is the character that replaces dots in submodule names +** when searching for a C loader. +** LUA_LSUBSEP is the character that replaces dots in submodule names +** when searching for a Lua loader. +*/ +#if !defined(LUA_CSUBSEP) +#define LUA_CSUBSEP LUA_DIRSEP +#endif + +#if !defined(LUA_LSUBSEP) +#define LUA_LSUBSEP LUA_DIRSEP +#endif + + +/* prefix for open functions in C libraries */ +#define LUA_POF "luaopen_" + +/* separator for open functions in C libraries */ +#define LUA_OFSEP "_" + + +/* +** key for table in the registry that keeps handles +** for all loaded C libraries +*/ +static const char *const CLIBS = "_CLIBS"; + +#define LIB_FAIL "open" + + +#define setprogdir(L) ((void)0) + + +/* +** Special type equivalent to '(void*)' for functions in gcc +** (to suppress warnings when converting function pointers) +*/ +typedef void (*voidf)(void); + + +/* +** system-dependent functions +*/ + +/* +** unload library 'lib' +*/ +static void lsys_unloadlib (void *lib); + +/* +** load C library in file 'path'. If 'seeglb', load with all names in +** the library global. +** Returns the library; in case of error, returns NULL plus an +** error string in the stack. +*/ +static void *lsys_load (lua_State *L, const char *path, int seeglb); + +/* +** Try to find a function named 'sym' in library 'lib'. +** Returns the function; in case of error, returns NULL plus an +** error string in the stack. +*/ +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym); + + + + +#if defined(LUA_USE_DLOPEN) /* { */ +/* +** {======================================================================== +** This is an implementation of loadlib based on the dlfcn interface. +** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, +** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least +** as an emulation layer on top of native functions. +** ========================================================================= +*/ + +#include <dlfcn.h> + +/* +** Macro to convert pointer-to-void* to pointer-to-function. This cast +** is undefined according to ISO C, but POSIX assumes that it works. +** (The '__extension__' in gnu compilers is only to avoid warnings.) +*/ +#if defined(__GNUC__) +#define cast_func(p) (__extension__ (lua_CFunction)(p)) +#else +#define cast_func(p) ((lua_CFunction)(p)) +#endif + + +static void lsys_unloadlib (void *lib) { + dlclose(lib); +} + + +static void *lsys_load (lua_State *L, const char *path, int seeglb) { + void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); + if (l_unlikely(lib == NULL)) + lua_pushstring(L, dlerror()); + return lib; +} + + +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = cast_func(dlsym(lib, sym)); + if (l_unlikely(f == NULL)) + lua_pushstring(L, dlerror()); + return f; +} + +/* }====================================================== */ + + + +#elif defined(LUA_DL_DLL) /* }{ */ +/* +** {====================================================================== +** This is an implementation of loadlib for Windows using native functions. +** ======================================================================= +*/ + +#include <windows.h> + + +/* +** optional flags for LoadLibraryEx +*/ +#if !defined(LUA_LLE_FLAGS) +#define LUA_LLE_FLAGS 0 +#endif + + +#undef setprogdir + + +/* +** Replace in the path (on the top of the stack) any occurrence +** of LUA_EXEC_DIR with the executable's path. +*/ +static void setprogdir (lua_State *L) { + char buff[MAX_PATH + 1]; + char *lb; + DWORD nsize = sizeof(buff)/sizeof(char); + DWORD n = GetModuleFileNameA(NULL, buff, nsize); /* get exec. name */ + if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) + luaL_error(L, "unable to get ModuleFileName"); + else { + *lb = '\0'; /* cut name on the last '\\' to get the path */ + luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff); + lua_remove(L, -2); /* remove original string */ + } +} + + + + +static void pusherror (lua_State *L) { + int error = GetLastError(); + char buffer[128]; + if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL)) + lua_pushstring(L, buffer); + else + lua_pushfstring(L, "system error %d\n", error); +} + +static void lsys_unloadlib (void *lib) { + FreeLibrary((HMODULE)lib); +} + + +static void *lsys_load (lua_State *L, const char *path, int seeglb) { + HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); + (void)(seeglb); /* not used: symbols are 'global' by default */ + if (lib == NULL) pusherror(L); + return lib; +} + + +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = (lua_CFunction)(voidf)GetProcAddress((HMODULE)lib, sym); + if (f == NULL) pusherror(L); + return f; +} + +/* }====================================================== */ + + +#else /* }{ */ +/* +** {====================================================== +** Fallback for other systems +** ======================================================= +*/ + +#undef LIB_FAIL +#define LIB_FAIL "absent" + + +#define DLMSG "dynamic libraries not enabled; check your Lua installation" + + +static void lsys_unloadlib (void *lib) { + (void)(lib); /* not used */ +} + + +static void *lsys_load (lua_State *L, const char *path, int seeglb) { + (void)(path); (void)(seeglb); /* not used */ + lua_pushliteral(L, DLMSG); + return NULL; +} + + +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { + (void)(lib); (void)(sym); /* not used */ + lua_pushliteral(L, DLMSG); + return NULL; +} + +/* }====================================================== */ +#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 + + + +/* +** 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 *dftmark; + const char *nver = lua_pushfstring(L, "%s%s", envname, LUA_VERSUFFIX); + const char *path = getenv(nver); /* try versioned name */ + if (path == NULL) /* no versioned environment variable? */ + path = getenv(envname); /* try unversioned name */ + if (path == NULL || noenv(L)) /* no environment variable? */ + lua_pushstring(L, dft); /* use default */ + else if ((dftmark = strstr(path, LUA_PATH_SEP LUA_PATH_SEP)) == NULL) + lua_pushstring(L, path); /* nothing to change */ + else { /* path contains a ";;": insert default path in its place */ + size_t len = strlen(path); + luaL_Buffer b; + luaL_buffinit(L, &b); + if (path < dftmark) { /* is there a prefix before ';;'? */ + luaL_addlstring(&b, path, dftmark - path); /* add it */ + luaL_addchar(&b, *LUA_PATH_SEP); + } + luaL_addstring(&b, dft); /* add default */ + if (dftmark < path + len - 2) { /* is there a suffix after ';;'? */ + luaL_addchar(&b, *LUA_PATH_SEP); + luaL_addlstring(&b, dftmark + 2, (path + len - 2) - dftmark); + } + luaL_pushresult(&b); + } + setprogdir(L); + lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */ + lua_pop(L, 1); /* pop versioned variable name ('nver') */ +} + +/* }================================================================== */ + + +/* +** return registry.CLIBS[path] +*/ +static void *checkclib (lua_State *L, const char *path) { + void *plib; + lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); + lua_getfield(L, -1, path); + plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ + lua_pop(L, 2); /* pop CLIBS table and 'plib' */ + return plib; +} + + +/* +** registry.CLIBS[path] = plib -- for queries +** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries +*/ +static void addtoclib (lua_State *L, const char *path, void *plib) { + lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); + lua_pushlightuserdata(L, plib); + lua_pushvalue(L, -1); + lua_setfield(L, -3, path); /* CLIBS[path] = plib */ + lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ + lua_pop(L, 1); /* pop CLIBS table */ +} + + +/* +** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib +** handles in list CLIBS +*/ +static int gctm (lua_State *L) { + lua_Integer n = luaL_len(L, 1); + for (; n >= 1; n--) { /* for each handle, in reverse order */ + lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ + lsys_unloadlib(lua_touserdata(L, -1)); + lua_pop(L, 1); /* pop handle */ + } + return 0; +} + + + +/* error codes for 'lookforfunc' */ +#define ERRLIB 1 +#define ERRFUNC 2 + +/* +** Look for a C function named 'sym' in a dynamically loaded library +** 'path'. +** First, check whether the library is already loaded; if not, try +** to load it. +** Then, if 'sym' is '*', return true (as library has been loaded). +** Otherwise, look for symbol 'sym' in the library and push a +** C function with that symbol. +** Return 0 and 'true' or a function in the stack; in case of +** errors, return an error code and an error message in the stack. +*/ +static int lookforfunc (lua_State *L, const char *path, const char *sym) { + void *reg = checkclib(L, path); /* check loaded C libraries */ + if (reg == NULL) { /* must load library? */ + reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */ + if (reg == NULL) return ERRLIB; /* unable to load library */ + addtoclib(L, path, reg); + } + if (*sym == '*') { /* loading only library (no function)? */ + lua_pushboolean(L, 1); /* return 'true' */ + return 0; /* no errors */ + } + else { + lua_CFunction f = lsys_sym(L, reg, sym); + if (f == NULL) + return ERRFUNC; /* unable to find function */ + lua_pushcfunction(L, f); /* else create new function */ + return 0; /* no errors */ + } +} + + +static int ll_loadlib (lua_State *L) { + const char *path = luaL_checkstring(L, 1); + const char *init = luaL_checkstring(L, 2); + int stat = lookforfunc(L, path, init); + if (l_likely(stat == 0)) /* no errors? */ + return 1; /* return the loaded function */ + else { /* error; error message is on stack top */ + luaL_pushfail(L); + lua_insert(L, -2); + lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); + return 3; /* return fail, error message, and where */ + } +} + + + +/* +** {====================================================== +** 'require' function +** ======================================================= +*/ + + +static int readable (const char *filename) { + FILE *f = fopen(filename, "r"); /* try to open file */ + if (f == NULL) return 0; /* open failed */ + fclose(f); + return 1; +} + + +/* +** Get the next name in '*path' = 'name1;name2;name3;...', changing +** the ending ';' to '\0' to create a zero-terminated string. Return +** NULL when list ends. +*/ +static const char *getnextfilename (char **path, char *end) { + char *sep; + char *name = *path; + if (name == end) + return NULL; /* no more names */ + else if (*name == '\0') { /* from previous iteration? */ + *name = *LUA_PATH_SEP; /* restore separator */ + name++; /* skip it */ + } + sep = strchr(name, *LUA_PATH_SEP); /* find next separator */ + if (sep == NULL) /* separator not found? */ + sep = end; /* name goes until the end */ + *sep = '\0'; /* finish file name */ + *path = sep; /* will start next search from here */ + return name; +} + + +/* +** Given a path such as ";blabla.so;blublu.so", pushes the string +** +** no file 'blabla.so' +** no file 'blublu.so' +*/ +static void pusherrornotfound (lua_State *L, const char *path) { + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addstring(&b, "no file '"); + luaL_addgsub(&b, path, LUA_PATH_SEP, "'\n\tno file '"); + luaL_addstring(&b, "'"); + luaL_pushresult(&b); +} + + +static const char *searchpath (lua_State *L, const char *name, + const char *path, + const char *sep, + const char *dirsep) { + luaL_Buffer buff; + char *pathname; /* path with name inserted */ + char *endpathname; /* its end */ + const char *filename; + /* separator is non-empty and appears in 'name'? */ + if (*sep != '\0' && strchr(name, *sep) != NULL) + name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ + luaL_buffinit(L, &buff); + /* add path to the buffer, replacing marks ('?') with the file name */ + luaL_addgsub(&buff, path, LUA_PATH_MARK, name); + luaL_addchar(&buff, '\0'); + pathname = luaL_buffaddr(&buff); /* writable list of file names */ + endpathname = pathname + luaL_bufflen(&buff) - 1; + while ((filename = getnextfilename(&pathname, endpathname)) != NULL) { + if (readable(filename)) /* does file exist and is readable? */ + return lua_pushstring(L, filename); /* save and return name */ + } + luaL_pushresult(&buff); /* push path to create error message */ + pusherrornotfound(L, lua_tostring(L, -1)); /* create error message */ + return NULL; /* not found */ +} + + +static int ll_searchpath (lua_State *L) { + const char *f = searchpath(L, luaL_checkstring(L, 1), + luaL_checkstring(L, 2), + luaL_optstring(L, 3, "."), + luaL_optstring(L, 4, LUA_DIRSEP)); + if (f != NULL) return 1; + else { /* error message is on top of the stack */ + luaL_pushfail(L); + lua_insert(L, -2); + return 2; /* return fail + error message */ + } +} + + +static const char *findfile (lua_State *L, const char *name, + const char *pname, + const char *dirsep) { + const char *path; + lua_getfield(L, lua_upvalueindex(1), pname); + path = lua_tostring(L, -1); + if (l_unlikely(path == NULL)) + luaL_error(L, "'package.%s' must be a string", pname); + return searchpath(L, name, path, ".", dirsep); +} + + +static int checkload (lua_State *L, int stat, const char *filename) { + if (l_likely(stat)) { /* module loaded successfully? */ + lua_pushstring(L, filename); /* will be 2nd argument to module */ + return 2; /* return open function and file name */ + } + else + return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s", + lua_tostring(L, 1), filename, lua_tostring(L, -1)); +} + + +static int searcher_Lua (lua_State *L) { + const char *filename; + const char *name = luaL_checkstring(L, 1); + filename = findfile(L, name, "path", LUA_LSUBSEP); + if (filename == NULL) return 1; /* module not found in this path */ + return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename); +} + + +/* +** Try to find a load function for module 'modname' at file 'filename'. +** First, change '.' to '_' in 'modname'; then, if 'modname' has +** the form X-Y (that is, it has an "ignore mark"), build a function +** name "luaopen_X" and look for it. (For compatibility, if that +** fails, it also tries "luaopen_Y".) If there is no ignore mark, +** look for a function named "luaopen_modname". +*/ +static int loadfunc (lua_State *L, const char *filename, const char *modname) { + const char *openfunc; + const char *mark; + modname = luaL_gsub(L, modname, ".", LUA_OFSEP); + mark = strchr(modname, *LUA_IGMARK); + if (mark) { + int stat; + openfunc = lua_pushlstring(L, modname, mark - modname); + openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc); + stat = lookforfunc(L, filename, openfunc); + if (stat != ERRFUNC) return stat; + modname = mark + 1; /* else go ahead and try old-style name */ + } + openfunc = lua_pushfstring(L, LUA_POF"%s", modname); + return lookforfunc(L, filename, openfunc); +} + + +static int searcher_C (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + const char *filename = findfile(L, name, "cpath", LUA_CSUBSEP); + if (filename == NULL) return 1; /* module not found in this path */ + return checkload(L, (loadfunc(L, filename, name) == 0), filename); +} + + +static int searcher_Croot (lua_State *L) { + const char *filename; + const char *name = luaL_checkstring(L, 1); + const char *p = strchr(name, '.'); + int stat; + if (p == NULL) return 0; /* is root */ + lua_pushlstring(L, name, p - name); + filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP); + if (filename == NULL) return 1; /* root not found */ + if ((stat = loadfunc(L, filename, name)) != 0) { + if (stat != ERRFUNC) + return checkload(L, 0, filename); /* real error */ + else { /* open function not found */ + lua_pushfstring(L, "no module '%s' in file '%s'", name, filename); + return 1; + } + } + lua_pushstring(L, filename); /* will be 2nd argument to module */ + return 2; +} + + +static int searcher_preload (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + if (lua_getfield(L, -1, name) == LUA_TNIL) { /* not found? */ + lua_pushfstring(L, "no field package.preload['%s']", name); + return 1; + } + else { + lua_pushliteral(L, ":preload:"); + return 2; + } +} + + +static void findloader (lua_State *L, const char *name) { + int i; + luaL_Buffer msg; /* to build error message */ + /* push 'package.searchers' to index 3 in the stack */ + if (l_unlikely(lua_getfield(L, lua_upvalueindex(1), "searchers") + != LUA_TTABLE)) + luaL_error(L, "'package.searchers' must be a table"); + luaL_buffinit(L, &msg); + /* iterate over available searchers to find a loader */ + for (i = 1; ; i++) { + luaL_addstring(&msg, "\n\t"); /* error-message prefix */ + if (l_unlikely(lua_rawgeti(L, 3, i) == LUA_TNIL)) { /* no more searchers? */ + lua_pop(L, 1); /* remove nil */ + luaL_buffsub(&msg, 2); /* remove prefix */ + luaL_pushresult(&msg); /* create error message */ + luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1)); + } + lua_pushstring(L, name); + lua_call(L, 1, 2); /* call it */ + if (lua_isfunction(L, -2)) /* did it find a loader? */ + return; /* module loader found */ + else if (lua_isstring(L, -2)) { /* searcher returned error message? */ + lua_pop(L, 1); /* remove extra return */ + luaL_addvalue(&msg); /* concatenate error message */ + } + else { /* no error message */ + lua_pop(L, 2); /* remove both returns */ + luaL_buffsub(&msg, 2); /* remove prefix */ + } + } +} + + +static int ll_require (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_settop(L, 1); /* LOADED table will be at index 2 */ + lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_getfield(L, 2, name); /* LOADED[name] */ + if (lua_toboolean(L, -1)) /* is it there? */ + return 1; /* package is already loaded */ + /* else must load package */ + lua_pop(L, 1); /* remove 'getfield' result */ + findloader(L, name); + lua_rotate(L, -2, 1); /* function <-> loader data */ + lua_pushvalue(L, 1); /* name is 1st argument to module loader */ + lua_pushvalue(L, -3); /* loader data is 2nd argument */ + /* stack: ...; loader data; loader function; mod. name; loader data */ + lua_call(L, 2, 1); /* run loader to load module */ + /* stack: ...; loader data; result from loader */ + if (!lua_isnil(L, -1)) /* non-nil return? */ + lua_setfield(L, 2, name); /* LOADED[name] = returned value */ + else + lua_pop(L, 1); /* pop nil */ + if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */ + lua_pushboolean(L, 1); /* use true as result */ + lua_copy(L, -1, -2); /* replace loader result */ + lua_setfield(L, 2, name); /* LOADED[name] = true */ + } + lua_rotate(L, -2, 1); /* loader data <-> module result */ + return 2; /* return module result and loader data */ +} + +/* }====================================================== */ + + + + +static const luaL_Reg pk_funcs[] = { + {"loadlib", ll_loadlib}, + {"searchpath", ll_searchpath}, + /* placeholders */ + {"preload", NULL}, + {"cpath", NULL}, + {"path", NULL}, + {"searchers", NULL}, + {"loaded", NULL}, + {NULL, NULL} +}; + + +static const luaL_Reg ll_funcs[] = { + {"require", ll_require}, + {NULL, NULL} +}; + + +static void createsearcherstable (lua_State *L) { + static const lua_CFunction searchers[] = { + searcher_preload, + searcher_Lua, + searcher_C, + searcher_Croot, + NULL + }; + int i; + /* create 'searchers' table */ + lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); + /* fill it with predefined searchers */ + for (i=0; searchers[i] != NULL; i++) { + lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ + lua_pushcclosure(L, searchers[i], 1); + lua_rawseti(L, -2, i+1); + } + lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ +} + + +/* +** create table CLIBS to keep track of loaded C libraries, +** setting a finalizer to close all libraries when closing state. +*/ +static void createclibstable (lua_State *L) { + luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); /* create CLIBS table */ + lua_createtable(L, 0, 1); /* create metatable for CLIBS */ + lua_pushcfunction(L, gctm); + lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ + lua_setmetatable(L, -2); +} + + +LUAMOD_API int luaopen_package (lua_State *L) { + createclibstable(L); + luaL_newlib(L, pk_funcs); /* create 'package' table */ + createsearcherstable(L); + /* set paths */ + setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT); + setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT); + /* store config information */ + lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" + LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); + lua_setfield(L, -2, "config"); + /* set field 'loaded' */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_setfield(L, -2, "loaded"); + /* set field 'preload' */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + lua_setfield(L, -2, "preload"); + lua_pushglobaltable(L); + lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ + luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */ + lua_pop(L, 1); /* pop global table */ + return 1; /* return 'package' table */ +} + diff --git a/src/libs/3rdparty/lua/src/lobject.c b/src/libs/3rdparty/lua/src/lobject.c new file mode 100644 index 0000000000..f73ffc6d92 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lobject.c @@ -0,0 +1,602 @@ +/* +** $Id: lobject.c $ +** Some generic functions over Lua objects +** See Copyright Notice in lua.h +*/ + +#define lobject_c +#define LUA_CORE + +#include "lprefix.h" + + +#include <locale.h> +#include <math.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "lua.h" + +#include "lctype.h" +#include "ldebug.h" +#include "ldo.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "lvm.h" + + +/* +** Computes ceil(log2(x)) +*/ +int luaO_ceillog2 (unsigned int x) { + static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */ + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 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, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 + }; + int l = 0; + x--; + while (x >= 256) { l += 8; x >>= 8; } + return l + log_2[x]; +} + + +static lua_Integer intarith (lua_State *L, int op, lua_Integer v1, + lua_Integer v2) { + switch (op) { + case LUA_OPADD: return intop(+, v1, v2); + case LUA_OPSUB:return intop(-, v1, v2); + case LUA_OPMUL:return intop(*, v1, v2); + case LUA_OPMOD: return luaV_mod(L, v1, v2); + case LUA_OPIDIV: return luaV_idiv(L, v1, v2); + case LUA_OPBAND: return intop(&, v1, v2); + case LUA_OPBOR: return intop(|, v1, v2); + case LUA_OPBXOR: return intop(^, v1, v2); + case LUA_OPSHL: return luaV_shiftl(v1, v2); + case LUA_OPSHR: return luaV_shiftr(v1, v2); + case LUA_OPUNM: return intop(-, 0, v1); + case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); + default: lua_assert(0); return 0; + } +} + + +static lua_Number numarith (lua_State *L, int op, lua_Number v1, + lua_Number v2) { + switch (op) { + case LUA_OPADD: return luai_numadd(L, v1, v2); + case LUA_OPSUB: return luai_numsub(L, v1, v2); + case LUA_OPMUL: return luai_nummul(L, v1, v2); + case LUA_OPDIV: return luai_numdiv(L, v1, v2); + case LUA_OPPOW: return luai_numpow(L, v1, v2); + case LUA_OPIDIV: return luai_numidiv(L, v1, v2); + case LUA_OPUNM: return luai_numunm(L, v1); + case LUA_OPMOD: return luaV_modf(L, v1, v2); + default: lua_assert(0); return 0; + } +} + + +int luaO_rawarith (lua_State *L, int op, const TValue *p1, const TValue *p2, + TValue *res) { + switch (op) { + case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: + case LUA_OPSHL: case LUA_OPSHR: + case LUA_OPBNOT: { /* operate only on integers */ + lua_Integer i1; lua_Integer i2; + if (tointegerns(p1, &i1) && tointegerns(p2, &i2)) { + setivalue(res, intarith(L, op, i1, i2)); + return 1; + } + else return 0; /* fail */ + } + case LUA_OPDIV: case LUA_OPPOW: { /* operate only on floats */ + lua_Number n1; lua_Number n2; + if (tonumberns(p1, n1) && tonumberns(p2, n2)) { + setfltvalue(res, numarith(L, op, n1, n2)); + return 1; + } + else return 0; /* fail */ + } + default: { /* other operations */ + lua_Number n1; lua_Number n2; + if (ttisinteger(p1) && ttisinteger(p2)) { + setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2))); + return 1; + } + else if (tonumberns(p1, n1) && tonumberns(p2, n2)) { + setfltvalue(res, numarith(L, op, n1, n2)); + return 1; + } + else return 0; /* fail */ + } + } +} + + +void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2, + StkId res) { + if (!luaO_rawarith(L, op, p1, p2, s2v(res))) { + /* could not perform raw operation; try metamethod */ + luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD)); + } +} + + +int luaO_hexavalue (int c) { + if (lisdigit(c)) return c - '0'; + else return (ltolower(c) - 'a') + 10; +} + + +static int isneg (const char **s) { + if (**s == '-') { (*s)++; return 1; } + else if (**s == '+') (*s)++; + return 0; +} + + + +/* +** {================================================================== +** Lua's implementation for 'lua_strx2number' +** =================================================================== +*/ + +#if !defined(lua_strx2number) + +/* maximum number of significant digits to read (to avoid overflows + even with single floats) */ +#define MAXSIGDIG 30 + +/* +** convert a hexadecimal numeric string to a number, following +** C99 specification for 'strtod' +*/ +static lua_Number lua_strx2number (const char *s, char **endptr) { + int dot = lua_getlocaledecpoint(); + lua_Number r = l_mathop(0.0); /* result (accumulator) */ + int sigdig = 0; /* number of significant digits */ + int nosigdig = 0; /* number of non-significant digits */ + int e = 0; /* exponent correction */ + int neg; /* 1 if number is negative */ + int hasdot = 0; /* true after seen a dot */ + *endptr = cast_charp(s); /* nothing is valid yet */ + while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ + neg = isneg(&s); /* check sign */ + if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ + return l_mathop(0.0); /* invalid format (no '0x') */ + for (s += 2; ; s++) { /* skip '0x' and read numeral */ + if (*s == dot) { + if (hasdot) break; /* second dot? stop loop */ + else hasdot = 1; + } + else if (lisxdigit(cast_uchar(*s))) { + if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */ + nosigdig++; + else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */ + r = (r * l_mathop(16.0)) + luaO_hexavalue(*s); + else e++; /* too many digits; ignore, but still count for exponent */ + if (hasdot) e--; /* decimal digit? correct exponent */ + } + else break; /* neither a dot nor a digit */ + } + if (nosigdig + sigdig == 0) /* no digits? */ + return l_mathop(0.0); /* invalid format */ + *endptr = cast_charp(s); /* valid up to here */ + e *= 4; /* each digit multiplies/divides value by 2^4 */ + if (*s == 'p' || *s == 'P') { /* exponent part? */ + int exp1 = 0; /* exponent value */ + int neg1; /* exponent sign */ + s++; /* skip 'p' */ + neg1 = isneg(&s); /* sign */ + if (!lisdigit(cast_uchar(*s))) + return l_mathop(0.0); /* invalid; must have at least one digit */ + while (lisdigit(cast_uchar(*s))) /* read exponent */ + exp1 = exp1 * 10 + *(s++) - '0'; + if (neg1) exp1 = -exp1; + e += exp1; + *endptr = cast_charp(s); /* valid up to here */ + } + if (neg) r = -r; + return l_mathop(ldexp)(r, e); +} + +#endif +/* }====================================================== */ + + +/* maximum length of a numeral to be converted to a number */ +#if !defined (L_MAXLENNUM) +#define L_MAXLENNUM 200 +#endif + +/* +** Convert string 's' to a Lua number (put in 'result'). Return NULL on +** fail or the address of the ending '\0' on success. ('mode' == 'x') +** means a hexadecimal numeral. +*/ +static const char *l_str2dloc (const char *s, lua_Number *result, int mode) { + char *endptr; + *result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */ + : lua_str2number(s, &endptr); + if (endptr == s) return NULL; /* nothing recognized? */ + while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */ + return (*endptr == '\0') ? endptr : NULL; /* OK iff no trailing chars */ +} + + +/* +** Convert string 's' to a Lua number (put in 'result') handling the +** current locale. +** This function accepts both the current locale or a dot as the radix +** mark. If the conversion 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. +** The variable 'mode' checks for special characters in the string: +** - 'n' means 'inf' or 'nan' (which should be rejected) +** - 'x' means a hexadecimal numeral +** - '.' just optimizes the search for the common case (no special chars) +*/ +static const char *l_str2d (const char *s, lua_Number *result) { + const char *endptr; + const char *pmode = strpbrk(s, ".xXnN"); /* look for special chars */ + 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 (pdot == NULL || strlen(s) > L_MAXLENNUM) + return NULL; /* string too long or no dot; fail */ + strcpy(buff, s); /* copy string to buffer */ + buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */ + endptr = l_str2dloc(buff, result, mode); /* try again */ + if (endptr != NULL) + endptr = s + (endptr - buff); /* make relative to 's' */ + } + return endptr; +} + + +#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10) +#define MAXLASTD cast_int(LUA_MAXINTEGER % 10) + +static const char *l_str2int (const char *s, lua_Integer *result) { + lua_Unsigned a = 0; + int empty = 1; + int neg; + while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ + neg = isneg(&s); + if (s[0] == '0' && + (s[1] == 'x' || s[1] == 'X')) { /* hex? */ + s += 2; /* skip '0x' */ + for (; lisxdigit(cast_uchar(*s)); s++) { + a = a * 16 + luaO_hexavalue(*s); + empty = 0; + } + } + else { /* decimal */ + for (; lisdigit(cast_uchar(*s)); s++) { + 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; + } + } + while (lisspace(cast_uchar(*s))) s++; /* skip trailing spaces */ + if (empty || *s != '\0') return NULL; /* something wrong in the numeral */ + else { + *result = l_castU2S((neg) ? 0u - a : a); + return s; + } +} + + +size_t luaO_str2num (const char *s, TValue *o) { + lua_Integer i; lua_Number n; + const char *e; + if ((e = l_str2int(s, &i)) != NULL) { /* try as an integer */ + setivalue(o, i); + } + else if ((e = l_str2d(s, &n)) != NULL) { /* else try as a float */ + setfltvalue(o, n); + } + else + return 0; /* conversion failed */ + return (e - s) + 1; /* success; return string size */ +} + + +int luaO_utf8esc (char *buff, unsigned long x) { + int n = 1; /* number of bytes put in buffer (backwards) */ + lua_assert(x <= 0x7FFFFFFFu); + if (x < 0x80) /* ascii? */ + buff[UTF8BUFFSZ - 1] = cast_char(x); + else { /* need continuation bytes */ + unsigned int mfb = 0x3f; /* maximum that fits in first byte */ + do { /* add continuation bytes */ + buff[UTF8BUFFSZ - (n++)] = cast_char(0x80 | (x & 0x3f)); + x >>= 6; /* remove added bits */ + mfb >>= 1; /* now there is one less bit available in first byte */ + } while (x > mfb); /* still needs continuation byte? */ + buff[UTF8BUFFSZ - n] = cast_char((~mfb << 1) | x); /* add first byte */ + } + return n; +} + + +/* +** Maximum length of the conversion of a number to a string. Must be +** enough to accommodate both LUA_INTEGER_FMT and LUA_NUMBER_FMT. +** (For a long long int, this is 19 digits plus a sign and a final '\0', +** adding to 21. For a long double, it can go to a sign, 33 digits, +** the dot, an exponent letter, an exponent sign, 5 exponent digits, +** and a final '\0', adding to 43.) +*/ +#define MAXNUMBER2STR 44 + + +/* +** Convert a number object to a string, adding it to a buffer +*/ +static int tostringbuff (TValue *obj, char *buff) { + int len; + lua_assert(ttisnumber(obj)); + if (ttisinteger(obj)) + len = lua_integer2str(buff, MAXNUMBER2STR, ivalue(obj)); + else { + len = lua_number2str(buff, MAXNUMBER2STR, fltvalue(obj)); + if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */ + buff[len++] = lua_getlocaledecpoint(); + buff[len++] = '0'; /* adds '.0' to result */ + } + } + return len; +} + + +/* +** Convert a number object to a Lua string, replacing the value at 'obj' +*/ +void luaO_tostring (lua_State *L, TValue *obj) { + char buff[MAXNUMBER2STR]; + int len = tostringbuff(obj, buff); + setsvalue(L, obj, luaS_newlstr(L, buff, len)); +} + + + + +/* +** {================================================================== +** 'luaO_pushvfstring' +** =================================================================== +*/ + +/* +** Size for buffer space used by 'luaO_pushvfstring'. It should be +** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages, +** so that 'luaG_addinfo' can work directly on the buffer. +*/ +#define BUFVFS (LUA_IDSIZE + MAXNUMBER2STR + 95) + +/* buffer used by 'luaO_pushvfstring' */ +typedef struct BuffFS { + lua_State *L; + int pushed; /* true if there is a part of the result on the stack */ + int blen; /* length of partial string in 'space' */ + char space[BUFVFS]; /* holds last part of the result */ +} BuffFS; + + +/* +** Push given string to the stack, as part of the result, and +** join it to previous partial result if there is one. +** It may call 'luaV_concat' while using one slot from EXTRA_STACK. +** This call cannot invoke metamethods, as both operands must be +** strings. It can, however, raise an error if the result is too +** long. In that case, 'luaV_concat' frees the extra slot before +** raising the error. +*/ +static void pushstr (BuffFS *buff, const char *str, size_t lstr) { + lua_State *L = buff->L; + setsvalue2s(L, L->top.p, luaS_newlstr(L, str, lstr)); + L->top.p++; /* may use one slot from EXTRA_STACK */ + if (!buff->pushed) /* no previous string on the stack? */ + buff->pushed = 1; /* now there is one */ + else /* join previous string with new one */ + luaV_concat(L, 2); +} + + +/* +** empty the buffer space into the stack +*/ +static void clearbuff (BuffFS *buff) { + pushstr(buff, buff->space, buff->blen); /* push buffer contents */ + buff->blen = 0; /* space now is empty */ +} + + +/* +** Get a space of size 'sz' in the buffer. If buffer has not enough +** space, empty it. 'sz' must fit in an empty buffer. +*/ +static char *getbuff (BuffFS *buff, int sz) { + lua_assert(buff->blen <= BUFVFS); lua_assert(sz <= BUFVFS); + if (sz > BUFVFS - buff->blen) /* not enough space? */ + clearbuff(buff); + return buff->space + buff->blen; +} + + +#define addsize(b,sz) ((b)->blen += (sz)) + + +/* +** Add 'str' to the buffer. If string is larger than the buffer space, +** push the string directly to the stack. +*/ +static void addstr2buff (BuffFS *buff, const char *str, size_t slen) { + if (slen <= BUFVFS) { /* does string fit into buffer? */ + char *bf = getbuff(buff, cast_int(slen)); + memcpy(bf, str, slen); /* add string to buffer */ + addsize(buff, cast_int(slen)); + } + else { /* string larger than buffer */ + clearbuff(buff); /* string comes after buffer's content */ + pushstr(buff, str, slen); /* push string */ + } +} + + +/* +** Add a numeral to the buffer. +*/ +static void addnum2buff (BuffFS *buff, TValue *num) { + char *numbuff = getbuff(buff, MAXNUMBER2STR); + int len = tostringbuff(num, numbuff); /* format number into 'numbuff' */ + addsize(buff, len); +} + + +/* +** this function handles only '%d', '%c', '%f', '%p', '%s', and '%%' + conventional formats, plus Lua-specific '%I' and '%U' +*/ +const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { + BuffFS buff; /* holds last part of the result */ + const char *e; /* points to next '%' */ + buff.pushed = buff.blen = 0; + buff.L = L; + while ((e = strchr(fmt, '%')) != NULL) { + addstr2buff(&buff, fmt, e - fmt); /* add 'fmt' up to '%' */ + switch (*(e + 1)) { /* conversion specifier */ + case 's': { /* zero-terminated string */ + const char *s = va_arg(argp, char *); + if (s == NULL) s = "(null)"; + addstr2buff(&buff, s, strlen(s)); + break; + } + case 'c': { /* an 'int' as a character */ + char c = cast_uchar(va_arg(argp, int)); + addstr2buff(&buff, &c, sizeof(char)); + break; + } + case 'd': { /* an 'int' */ + TValue num; + setivalue(&num, va_arg(argp, int)); + addnum2buff(&buff, &num); + break; + } + case 'I': { /* a 'lua_Integer' */ + TValue num; + setivalue(&num, cast(lua_Integer, va_arg(argp, l_uacInt))); + addnum2buff(&buff, &num); + break; + } + case 'f': { /* a 'lua_Number' */ + TValue num; + setfltvalue(&num, cast_num(va_arg(argp, l_uacNumber))); + addnum2buff(&buff, &num); + break; + } + case 'p': { /* a pointer */ + const int sz = 3 * sizeof(void*) + 8; /* enough space for '%p' */ + char *bf = getbuff(&buff, sz); + void *p = va_arg(argp, void *); + int len = lua_pointer2str(bf, sz, p); + addsize(&buff, len); + break; + } + case 'U': { /* a 'long' as a UTF-8 sequence */ + char bf[UTF8BUFFSZ]; + int len = luaO_utf8esc(bf, va_arg(argp, long)); + addstr2buff(&buff, bf + UTF8BUFFSZ - len, len); + break; + } + case '%': { + addstr2buff(&buff, "%", 1); + break; + } + default: { + luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'", + *(e + 1)); + } + } + fmt = e + 2; /* skip '%' and the specifier */ + } + addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */ + clearbuff(&buff); /* empty buffer into the stack */ + lua_assert(buff.pushed == 1); + return svalue(s2v(L->top.p - 1)); +} + + +const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { + const char *msg; + va_list argp; + va_start(argp, fmt); + msg = luaO_pushvfstring(L, fmt, argp); + va_end(argp); + return msg; +} + +/* }================================================================== */ + + +#define RETS "..." +#define PRE "[string \"" +#define POS "\"]" + +#define addstr(a,b,l) ( memcpy(a,b,(l) * sizeof(char)), a += (l) ) + +void luaO_chunkid (char *out, const char *source, size_t srclen) { + size_t bufflen = LUA_IDSIZE; /* free space in buffer */ + if (*source == '=') { /* 'literal' source */ + if (srclen <= bufflen) /* small enough? */ + memcpy(out, source + 1, srclen * sizeof(char)); + else { /* truncate it */ + addstr(out, source + 1, bufflen - 1); + *out = '\0'; + } + } + else if (*source == '@') { /* file name */ + if (srclen <= bufflen) /* small enough? */ + memcpy(out, source + 1, srclen * sizeof(char)); + else { /* add '...' before rest of name */ + addstr(out, RETS, LL(RETS)); + bufflen -= LL(RETS); + memcpy(out, source + 1 + srclen - bufflen, bufflen * sizeof(char)); + } + } + else { /* string; format as [string "source"] */ + const char *nl = strchr(source, '\n'); /* find first new line (if any) */ + addstr(out, PRE, LL(PRE)); /* add prefix */ + bufflen -= LL(PRE RETS POS) + 1; /* save space for prefix+suffix+'\0' */ + if (srclen < bufflen && nl == NULL) { /* small one-line source? */ + addstr(out, source, srclen); /* keep it */ + } + else { + if (nl != NULL) srclen = nl - source; /* stop at first newline */ + if (srclen > bufflen) srclen = bufflen; + addstr(out, source, srclen); + addstr(out, RETS, LL(RETS)); + } + memcpy(out, POS, (LL(POS) + 1) * sizeof(char)); + } +} + diff --git a/src/libs/3rdparty/lua/src/lobject.h b/src/libs/3rdparty/lua/src/lobject.h new file mode 100644 index 0000000000..556608e4aa --- /dev/null +++ b/src/libs/3rdparty/lua/src/lobject.h @@ -0,0 +1,815 @@ +/* +** $Id: lobject.h $ +** Type definitions for Lua objects +** See Copyright Notice in lua.h +*/ + + +#ifndef lobject_h +#define lobject_h + + +#include <stdarg.h> + + +#include "llimits.h" +#include "lua.h" + + +/* +** Extra types for collectable non-values +*/ +#define LUA_TUPVAL LUA_NUMTYPES /* upvalues */ +#define LUA_TPROTO (LUA_NUMTYPES+1) /* function prototypes */ +#define LUA_TDEADKEY (LUA_NUMTYPES+2) /* removed keys in tables */ + + + +/* +** number of all possible types (including LUA_TNONE but excluding DEADKEY) +*/ +#define LUA_TOTALTYPES (LUA_TPROTO + 2) + + +/* +** tags for Tagged Values have the following use of bits: +** bits 0-3: actual tag (a LUA_T* constant) +** bits 4-5: variant bits +** bit 6: whether value is collectable +*/ + +/* add variant bits to a type */ +#define makevariant(t,v) ((t) | ((v) << 4)) + + + +/* +** Union of all Lua values +*/ +typedef union Value { + struct GCObject *gc; /* collectable objects */ + void *p; /* light userdata */ + lua_CFunction f; /* light C functions */ + lua_Integer i; /* integer numbers */ + lua_Number n; /* float numbers */ + /* not used, but may avoid warnings for uninitialized value */ + lu_byte ub; +} Value; + + +/* +** Tagged Values. This is the basic representation of values in Lua: +** an actual value plus a tag with its type. +*/ + +#define TValuefields Value value_; lu_byte tt_ + +typedef struct TValue { + TValuefields; +} TValue; + + +#define val_(o) ((o)->value_) +#define valraw(o) (val_(o)) + + +/* raw type tag of a TValue */ +#define rawtt(o) ((o)->tt_) + +/* tag with no variants (bits 0-3) */ +#define novariant(t) ((t) & 0x0F) + +/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */ +#define withvariant(t) ((t) & 0x3F) +#define ttypetag(o) withvariant(rawtt(o)) + +/* type of a TValue */ +#define ttype(o) (novariant(rawtt(o))) + + +/* Macros to test type */ +#define checktag(o,t) (rawtt(o) == (t)) +#define checktype(o,t) (ttype(o) == (t)) + + +/* Macros for internal tests */ + +/* collectable object has the same tag as the original value */ +#define righttt(obj) (ttypetag(obj) == gcvalue(obj)->tt) + +/* +** Any value being manipulated by the program either is non +** collectable, or the collectable object has the right tag +** and it is not dead. The option 'L == NULL' allows other +** macros using this one to be used where L is not available. +*/ +#define checkliveness(L,obj) \ + ((void)L, lua_longassert(!iscollectable(obj) || \ + (righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj)))))) + + +/* Macros to set values */ + +/* set a value's tag */ +#define settt_(o,t) ((o)->tt_=(t)) + + +/* main macro to copy values (from 'obj2' to 'obj1') */ +#define setobj(L,obj1,obj2) \ + { TValue *io1=(obj1); const TValue *io2=(obj2); \ + io1->value_ = io2->value_; settt_(io1, io2->tt_); \ + checkliveness(L,io1); lua_assert(!isnonstrictnil(io1)); } + +/* +** Different types of assignments, according to source and destination. +** (They are mostly equal now, but may be different in the future.) +*/ + +/* from stack to stack */ +#define setobjs2s(L,o1,o2) setobj(L,s2v(o1),s2v(o2)) +/* to stack (not from same stack) */ +#define setobj2s(L,o1,o2) setobj(L,s2v(o1),o2) +/* from table to same table */ +#define setobjt2t setobj +/* to new object */ +#define setobj2n setobj +/* to table */ +#define setobj2t setobj + + +/* +** Entries in a Lua stack. Field 'tbclist' forms a list of all +** to-be-closed variables active in this stack. Dummy entries are +** used when the distance between two tbc variables does not fit +** in an unsigned short. They are represented by delta==0, and +** their real delta is always the maximum value that fits in +** that field. +*/ +typedef union StackValue { + TValue val; + struct { + TValuefields; + unsigned short delta; + } tbclist; +} StackValue; + + +/* index to stack elements */ +typedef StackValue *StkId; + + +/* +** When reallocating the stack, change all pointers to the stack into +** proper offsets. +*/ +typedef union { + StkId p; /* actual pointer */ + ptrdiff_t offset; /* used while the stack is being reallocated */ +} StkIdRel; + + +/* convert a 'StackValue' to a 'TValue' */ +#define s2v(o) (&(o)->val) + + + +/* +** {================================================================== +** Nil +** =================================================================== +*/ + +/* Standard nil */ +#define LUA_VNIL makevariant(LUA_TNIL, 0) + +/* Empty slot (which might be different from a slot containing nil) */ +#define LUA_VEMPTY makevariant(LUA_TNIL, 1) + +/* Value returned for a key not found in a table (absent key) */ +#define LUA_VABSTKEY makevariant(LUA_TNIL, 2) + + +/* macro to test for (any kind of) nil */ +#define ttisnil(v) checktype((v), LUA_TNIL) + + +/* macro to test for a standard nil */ +#define ttisstrictnil(o) checktag((o), LUA_VNIL) + + +#define setnilvalue(obj) settt_(obj, LUA_VNIL) + + +#define isabstkey(v) checktag((v), LUA_VABSTKEY) + + +/* +** macro to detect non-standard nils (used only in assertions) +*/ +#define isnonstrictnil(v) (ttisnil(v) && !ttisstrictnil(v)) + + +/* +** By default, entries with any kind of nil are considered empty. +** (In any definition, values associated with absent keys must also +** be accepted as empty.) +*/ +#define isempty(v) ttisnil(v) + + +/* macro defining a value corresponding to an absent key */ +#define ABSTKEYCONSTANT {NULL}, LUA_VABSTKEY + + +/* mark an entry as empty */ +#define setempty(v) settt_(v, LUA_VEMPTY) + + + +/* }================================================================== */ + + +/* +** {================================================================== +** Booleans +** =================================================================== +*/ + + +#define LUA_VFALSE makevariant(LUA_TBOOLEAN, 0) +#define LUA_VTRUE makevariant(LUA_TBOOLEAN, 1) + +#define ttisboolean(o) checktype((o), LUA_TBOOLEAN) +#define ttisfalse(o) checktag((o), LUA_VFALSE) +#define ttistrue(o) checktag((o), LUA_VTRUE) + + +#define l_isfalse(o) (ttisfalse(o) || ttisnil(o)) + + +#define setbfvalue(obj) settt_(obj, LUA_VFALSE) +#define setbtvalue(obj) settt_(obj, LUA_VTRUE) + +/* }================================================================== */ + + +/* +** {================================================================== +** Threads +** =================================================================== +*/ + +#define LUA_VTHREAD makevariant(LUA_TTHREAD, 0) + +#define ttisthread(o) checktag((o), ctb(LUA_VTHREAD)) + +#define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc)) + +#define setthvalue(L,obj,x) \ + { TValue *io = (obj); lua_State *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VTHREAD)); \ + checkliveness(L,io); } + +#define setthvalue2s(L,o,t) setthvalue(L,s2v(o),t) + +/* }================================================================== */ + + +/* +** {================================================================== +** Collectable Objects +** =================================================================== +*/ + +/* +** Common Header for all collectable objects (in macro form, to be +** included in other objects) +*/ +#define CommonHeader struct GCObject *next; lu_byte tt; lu_byte marked + + +/* Common type for all collectable objects */ +typedef struct GCObject { + CommonHeader; +} GCObject; + + +/* Bit mark for collectable types */ +#define BIT_ISCOLLECTABLE (1 << 6) + +#define iscollectable(o) (rawtt(o) & BIT_ISCOLLECTABLE) + +/* mark a tag as collectable */ +#define ctb(t) ((t) | BIT_ISCOLLECTABLE) + +#define gcvalue(o) check_exp(iscollectable(o), val_(o).gc) + +#define gcvalueraw(v) ((v).gc) + +#define setgcovalue(L,obj,x) \ + { TValue *io = (obj); GCObject *i_g=(x); \ + val_(io).gc = i_g; settt_(io, ctb(i_g->tt)); } + +/* }================================================================== */ + + +/* +** {================================================================== +** Numbers +** =================================================================== +*/ + +/* Variant tags for numbers */ +#define LUA_VNUMINT makevariant(LUA_TNUMBER, 0) /* integer numbers */ +#define LUA_VNUMFLT makevariant(LUA_TNUMBER, 1) /* float numbers */ + +#define ttisnumber(o) checktype((o), LUA_TNUMBER) +#define ttisfloat(o) checktag((o), LUA_VNUMFLT) +#define ttisinteger(o) checktag((o), LUA_VNUMINT) + +#define nvalue(o) check_exp(ttisnumber(o), \ + (ttisinteger(o) ? cast_num(ivalue(o)) : fltvalue(o))) +#define fltvalue(o) check_exp(ttisfloat(o), val_(o).n) +#define ivalue(o) check_exp(ttisinteger(o), val_(o).i) + +#define fltvalueraw(v) ((v).n) +#define ivalueraw(v) ((v).i) + +#define setfltvalue(obj,x) \ + { TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_VNUMFLT); } + +#define chgfltvalue(obj,x) \ + { TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); } + +#define setivalue(obj,x) \ + { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_VNUMINT); } + +#define chgivalue(obj,x) \ + { TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); } + +/* }================================================================== */ + + +/* +** {================================================================== +** Strings +** =================================================================== +*/ + +/* Variant tags for strings */ +#define LUA_VSHRSTR makevariant(LUA_TSTRING, 0) /* short strings */ +#define LUA_VLNGSTR makevariant(LUA_TSTRING, 1) /* long strings */ + +#define ttisstring(o) checktype((o), LUA_TSTRING) +#define ttisshrstring(o) checktag((o), ctb(LUA_VSHRSTR)) +#define ttislngstring(o) checktag((o), ctb(LUA_VLNGSTR)) + +#define tsvalueraw(v) (gco2ts((v).gc)) + +#define tsvalue(o) check_exp(ttisstring(o), gco2ts(val_(o).gc)) + +#define setsvalue(L,obj,x) \ + { TValue *io = (obj); TString *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \ + checkliveness(L,io); } + +/* set a string to the stack */ +#define setsvalue2s(L,o,s) setsvalue(L,s2v(o),s) + +/* set a string to a new object */ +#define setsvalue2n setsvalue + + +/* +** Header for a string value. +*/ +typedef struct TString { + CommonHeader; + lu_byte extra; /* reserved words for short strings; "has hash" for longs */ + lu_byte shrlen; /* length for short strings */ + unsigned int hash; + union { + size_t lnglen; /* length for long strings */ + struct TString *hnext; /* linked list for hash table */ + } u; + char contents[1]; +} TString; + + + +/* +** Get the actual string (array of bytes) from a 'TString'. +*/ +#define getstr(ts) ((ts)->contents) + + +/* get the actual string (array of bytes) from a Lua value */ +#define svalue(o) getstr(tsvalue(o)) + +/* get string length from 'TString *s' */ +#define tsslen(s) ((s)->tt == LUA_VSHRSTR ? (s)->shrlen : (s)->u.lnglen) + +/* get string length from 'TValue *o' */ +#define vslen(o) tsslen(tsvalue(o)) + +/* }================================================================== */ + + +/* +** {================================================================== +** Userdata +** =================================================================== +*/ + + +/* +** Light userdata should be a variant of userdata, but for compatibility +** reasons they are also different types. +*/ +#define LUA_VLIGHTUSERDATA makevariant(LUA_TLIGHTUSERDATA, 0) + +#define LUA_VUSERDATA makevariant(LUA_TUSERDATA, 0) + +#define ttislightuserdata(o) checktag((o), LUA_VLIGHTUSERDATA) +#define ttisfulluserdata(o) checktag((o), ctb(LUA_VUSERDATA)) + +#define pvalue(o) check_exp(ttislightuserdata(o), val_(o).p) +#define uvalue(o) check_exp(ttisfulluserdata(o), gco2u(val_(o).gc)) + +#define pvalueraw(v) ((v).p) + +#define setpvalue(obj,x) \ + { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_VLIGHTUSERDATA); } + +#define setuvalue(L,obj,x) \ + { TValue *io = (obj); Udata *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VUSERDATA)); \ + checkliveness(L,io); } + + +/* Ensures that addresses after this type are always fully aligned. */ +typedef union UValue { + TValue uv; + LUAI_MAXALIGN; /* ensures maximum alignment for udata bytes */ +} UValue; + + +/* +** Header for userdata with user values; +** memory area follows the end of this structure. +*/ +typedef struct Udata { + CommonHeader; + unsigned short nuvalue; /* number of user values */ + size_t len; /* number of bytes */ + struct Table *metatable; + GCObject *gclist; + UValue uv[1]; /* user values */ +} Udata; + + +/* +** Header for userdata with no user values. These userdata do not need +** to be gray during GC, and therefore do not need a 'gclist' field. +** To simplify, the code always use 'Udata' for both kinds of userdata, +** making sure it never accesses 'gclist' on userdata with no user values. +** This structure here is used only to compute the correct size for +** this representation. (The 'bindata' field in its end ensures correct +** alignment for binary data following this header.) +*/ +typedef struct Udata0 { + CommonHeader; + unsigned short nuvalue; /* number of user values */ + size_t len; /* number of bytes */ + struct Table *metatable; + union {LUAI_MAXALIGN;} bindata; +} Udata0; + + +/* compute the offset of the memory area of a userdata */ +#define udatamemoffset(nuv) \ + ((nuv) == 0 ? offsetof(Udata0, bindata) \ + : offsetof(Udata, uv) + (sizeof(UValue) * (nuv))) + +/* get the address of the memory block inside 'Udata' */ +#define getudatamem(u) (cast_charp(u) + udatamemoffset((u)->nuvalue)) + +/* compute the size of a userdata */ +#define sizeudata(nuv,nb) (udatamemoffset(nuv) + (nb)) + +/* }================================================================== */ + + +/* +** {================================================================== +** Prototypes +** =================================================================== +*/ + +#define LUA_VPROTO makevariant(LUA_TPROTO, 0) + + +/* +** Description of an upvalue for function prototypes +*/ +typedef struct Upvaldesc { + TString *name; /* upvalue name (for debug information) */ + 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 kind; /* kind of corresponding variable */ +} Upvaldesc; + + +/* +** Description of a local variable for function prototypes +** (used for debug information) +*/ +typedef struct LocVar { + TString *varname; + int startpc; /* first point where variable is active */ + int endpc; /* first point where variable is dead */ +} LocVar; + + +/* +** Associates the absolute line source for a given instruction ('pc'). +** The array 'lineinfo' gives, for each instruction, the difference in +** lines from the previous instruction. When that difference does not +** fit into a byte, Lua saves the absolute line for that instruction. +** (Lua also saves the absolute line periodically, to speed up the +** computation of a line number: we can use binary search in the +** absolute-line array, but we must traverse the 'lineinfo' array +** linearly to compute a line.) +*/ +typedef struct AbsLineInfo { + int pc; + int line; +} AbsLineInfo; + +/* +** Function Prototypes +*/ +typedef struct Proto { + CommonHeader; + lu_byte numparams; /* number of fixed (named) parameters */ + lu_byte is_vararg; + lu_byte maxstacksize; /* number of registers needed by this function */ + int sizeupvalues; /* size of 'upvalues' */ + int sizek; /* size of 'k' */ + int sizecode; + int sizelineinfo; + int sizep; /* size of 'p' */ + int sizelocvars; + int sizeabslineinfo; /* size of 'abslineinfo' */ + int linedefined; /* debug information */ + int lastlinedefined; /* debug information */ + TValue *k; /* constants used by the function */ + Instruction *code; /* opcodes */ + struct Proto **p; /* functions defined inside the function */ + Upvaldesc *upvalues; /* upvalue information */ + ls_byte *lineinfo; /* information about source lines (debug information) */ + AbsLineInfo *abslineinfo; /* idem */ + LocVar *locvars; /* information about local variables (debug information) */ + TString *source; /* used for debug information */ + GCObject *gclist; +} Proto; + +/* }================================================================== */ + + +/* +** {================================================================== +** Functions +** =================================================================== +*/ + +#define LUA_VUPVAL makevariant(LUA_TUPVAL, 0) + + +/* Variant tags for functions */ +#define LUA_VLCL makevariant(LUA_TFUNCTION, 0) /* Lua closure */ +#define LUA_VLCF makevariant(LUA_TFUNCTION, 1) /* light C function */ +#define LUA_VCCL makevariant(LUA_TFUNCTION, 2) /* C closure */ + +#define ttisfunction(o) checktype(o, LUA_TFUNCTION) +#define ttisLclosure(o) checktag((o), ctb(LUA_VLCL)) +#define ttislcf(o) checktag((o), LUA_VLCF) +#define ttisCclosure(o) checktag((o), ctb(LUA_VCCL)) +#define ttisclosure(o) (ttisLclosure(o) || ttisCclosure(o)) + + +#define isLfunction(o) ttisLclosure(o) + +#define clvalue(o) check_exp(ttisclosure(o), gco2cl(val_(o).gc)) +#define clLvalue(o) check_exp(ttisLclosure(o), gco2lcl(val_(o).gc)) +#define fvalue(o) check_exp(ttislcf(o), val_(o).f) +#define clCvalue(o) check_exp(ttisCclosure(o), gco2ccl(val_(o).gc)) + +#define fvalueraw(v) ((v).f) + +#define setclLvalue(L,obj,x) \ + { TValue *io = (obj); LClosure *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VLCL)); \ + checkliveness(L,io); } + +#define setclLvalue2s(L,o,cl) setclLvalue(L,s2v(o),cl) + +#define setfvalue(obj,x) \ + { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_VLCF); } + +#define setclCvalue(L,obj,x) \ + { TValue *io = (obj); CClosure *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VCCL)); \ + checkliveness(L,io); } + + +/* +** Upvalues for Lua closures +*/ +typedef struct UpVal { + CommonHeader; + union { + TValue *p; /* points to stack or to its own value */ + ptrdiff_t offset; /* used while the stack is being reallocated */ + } v; + union { + struct { /* (when open) */ + struct UpVal *next; /* linked list */ + struct UpVal **previous; + } open; + TValue value; /* the value (when closed) */ + } u; +} UpVal; + + + +#define ClosureHeader \ + CommonHeader; lu_byte nupvalues; GCObject *gclist + +typedef struct CClosure { + ClosureHeader; + lua_CFunction f; + TValue upvalue[1]; /* list of upvalues */ +} CClosure; + + +typedef struct LClosure { + ClosureHeader; + struct Proto *p; + UpVal *upvals[1]; /* list of upvalues */ +} LClosure; + + +typedef union Closure { + CClosure c; + LClosure l; +} Closure; + + +#define getproto(o) (clLvalue(o)->p) + +/* }================================================================== */ + + +/* +** {================================================================== +** Tables +** =================================================================== +*/ + +#define LUA_VTABLE makevariant(LUA_TTABLE, 0) + +#define ttistable(o) checktag((o), ctb(LUA_VTABLE)) + +#define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc)) + +#define sethvalue(L,obj,x) \ + { TValue *io = (obj); Table *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VTABLE)); \ + checkliveness(L,io); } + +#define sethvalue2s(L,o,h) sethvalue(L,s2v(o),h) + + +/* +** Nodes for Hash tables: A pack of two TValue's (key-value pairs) +** plus a 'next' field to link colliding entries. The distribution +** of the key's fields ('key_tt' and 'key_val') not forming a proper +** 'TValue' allows for a smaller size for 'Node' both in 4-byte +** and 8-byte alignments. +*/ +typedef union Node { + struct NodeKey { + TValuefields; /* fields for value */ + lu_byte key_tt; /* key type */ + int next; /* for chaining */ + Value key_val; /* key value */ + } u; + TValue i_val; /* direct access to node's value as a proper 'TValue' */ +} Node; + + +/* copy a value into a key */ +#define setnodekey(L,node,obj) \ + { Node *n_=(node); const TValue *io_=(obj); \ + n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; \ + checkliveness(L,io_); } + + +/* copy a value from a key */ +#define getnodekey(L,obj,node) \ + { TValue *io_=(obj); const Node *n_=(node); \ + io_->value_ = n_->u.key_val; io_->tt_ = n_->u.key_tt; \ + checkliveness(L,io_); } + + +/* +** About 'alimit': if 'isrealasize(t)' is true, then 'alimit' is the +** real size of 'array'. Otherwise, the real size of 'array' is the +** smallest power of two not smaller than 'alimit' (or zero iff 'alimit' +** is zero); 'alimit' is then used as a hint for #t. +*/ + +#define BITRAS (1 << 7) +#define isrealasize(t) (!((t)->flags & BITRAS)) +#define setrealasize(t) ((t)->flags &= cast_byte(~BITRAS)) +#define setnorealasize(t) ((t)->flags |= BITRAS) + + +typedef struct Table { + CommonHeader; + lu_byte flags; /* 1<<p means tagmethod(p) is not present */ + lu_byte lsizenode; /* log2 of size of 'node' array */ + unsigned int alimit; /* "limit" of 'array' array */ + TValue *array; /* array part */ + Node *node; + Node *lastfree; /* any free position is before this position */ + struct Table *metatable; + GCObject *gclist; +} Table; + + +/* +** Macros to manipulate keys inserted in nodes +*/ +#define keytt(node) ((node)->u.key_tt) +#define keyval(node) ((node)->u.key_val) + +#define keyisnil(node) (keytt(node) == LUA_TNIL) +#define keyisinteger(node) (keytt(node) == LUA_VNUMINT) +#define keyival(node) (keyval(node).i) +#define keyisshrstr(node) (keytt(node) == ctb(LUA_VSHRSTR)) +#define keystrval(node) (gco2ts(keyval(node).gc)) + +#define setnilkey(node) (keytt(node) = LUA_TNIL) + +#define keyiscollectable(n) (keytt(n) & BIT_ISCOLLECTABLE) + +#define gckey(n) (keyval(n).gc) +#define gckeyN(n) (keyiscollectable(n) ? gckey(n) : NULL) + + +/* +** Dead keys in tables have the tag DEADKEY but keep their original +** gcvalue. This distinguishes them from regular keys but allows them to +** be found when searched in a special way. ('next' needs that to find +** keys removed from a table during a traversal.) +*/ +#define setdeadkey(node) (keytt(node) = LUA_TDEADKEY) +#define keyisdead(node) (keytt(node) == LUA_TDEADKEY) + +/* }================================================================== */ + + + +/* +** 'module' operation for hashing (size is always a power of 2) +*/ +#define lmod(s,size) \ + (check_exp((size&(size-1))==0, (cast_int((s) & ((size)-1))))) + + +#define twoto(x) (1<<(x)) +#define sizenode(t) (twoto((t)->lsizenode)) + + +/* size of buffer for 'luaO_utf8esc' function */ +#define UTF8BUFFSZ 8 + +LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x); +LUAI_FUNC int luaO_ceillog2 (unsigned int x); +LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1, + const TValue *p2, TValue *res); +LUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1, + const TValue *p2, StkId res); +LUAI_FUNC size_t luaO_str2num (const char *s, TValue *o); +LUAI_FUNC int luaO_hexavalue (int c); +LUAI_FUNC void luaO_tostring (lua_State *L, TValue *obj); +LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, + va_list argp); +LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); +LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t srclen); + + +#endif + diff --git a/src/libs/3rdparty/lua/src/lopcodes.c b/src/libs/3rdparty/lua/src/lopcodes.c new file mode 100644 index 0000000000..c67aa227c5 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lopcodes.c @@ -0,0 +1,104 @@ +/* +** $Id: lopcodes.c $ +** Opcodes for Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#define lopcodes_c +#define LUA_CORE + +#include "lprefix.h" + + +#include "lopcodes.h" + + +/* ORDER OP */ + +LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { +/* MM OT IT T A mode opcode */ + opmode(0, 0, 0, 0, 1, iABC) /* OP_MOVE */ + ,opmode(0, 0, 0, 0, 1, iAsBx) /* OP_LOADI */ + ,opmode(0, 0, 0, 0, 1, iAsBx) /* OP_LOADF */ + ,opmode(0, 0, 0, 0, 1, iABx) /* OP_LOADK */ + ,opmode(0, 0, 0, 0, 1, iABx) /* OP_LOADKX */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_LOADFALSE */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_LFALSESKIP */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_LOADTRUE */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_LOADNIL */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETUPVAL */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETUPVAL */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETTABUP */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETTABLE */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETI */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETFIELD */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETTABUP */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETTABLE */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETI */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETFIELD */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_NEWTABLE */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SELF */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDI */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SUBK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_MULK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_MODK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_POWK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_DIVK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_IDIVK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BANDK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BORK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BXORK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHRI */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHLI */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADD */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SUB */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_MUL */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_MOD */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_POW */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_DIV */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_IDIV */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BAND */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BOR */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BXOR */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHL */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHR */ + ,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBIN */ + ,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBINI*/ + ,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBINK*/ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_UNM */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BNOT */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_NOT */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_LEN */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_CONCAT */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_CLOSE */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_TBC */ + ,opmode(0, 0, 0, 0, 0, isJ) /* OP_JMP */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_EQ */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_LT */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_LE */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_EQK */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_EQI */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_LTI */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_LEI */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_GTI */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_GEI */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_TEST */ + ,opmode(0, 0, 0, 1, 1, iABC) /* OP_TESTSET */ + ,opmode(0, 1, 1, 0, 1, iABC) /* OP_CALL */ + ,opmode(0, 1, 1, 0, 1, iABC) /* OP_TAILCALL */ + ,opmode(0, 0, 1, 0, 0, iABC) /* OP_RETURN */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_RETURN0 */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_RETURN1 */ + ,opmode(0, 0, 0, 0, 1, iABx) /* OP_FORLOOP */ + ,opmode(0, 0, 0, 0, 1, iABx) /* OP_FORPREP */ + ,opmode(0, 0, 0, 0, 0, iABx) /* OP_TFORPREP */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_TFORCALL */ + ,opmode(0, 0, 0, 0, 1, iABx) /* OP_TFORLOOP */ + ,opmode(0, 0, 1, 0, 0, iABC) /* OP_SETLIST */ + ,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */ + ,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */ + ,opmode(0, 0, 1, 0, 1, iABC) /* OP_VARARGPREP */ + ,opmode(0, 0, 0, 0, 0, iAx) /* OP_EXTRAARG */ +}; + diff --git a/src/libs/3rdparty/lua/src/lopcodes.h b/src/libs/3rdparty/lua/src/lopcodes.h new file mode 100644 index 0000000000..4c55145399 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lopcodes.h @@ -0,0 +1,405 @@ +/* +** $Id: lopcodes.h $ +** Opcodes for Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#ifndef lopcodes_h +#define lopcodes_h + +#include "llimits.h" + + +/*=========================================================================== + We assume that instructions are unsigned 32-bit integers. + All instructions have an opcode in the first 7 bits. + Instructions can have the following formats: + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +iABC C(8) | B(8) |k| A(8) | Op(7) | +iABx Bx(17) | A(8) | Op(7) | +iAsBx sBx (signed)(17) | A(8) | Op(7) | +iAx Ax(25) | Op(7) | +isJ sJ (signed)(25) | Op(7) | + + A signed argument is represented in excess K: the represented value is + the written unsigned value minus K, where K is half the maximum for the + corresponding unsigned argument. +===========================================================================*/ + + +enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */ + + +/* +** size and position of opcode arguments. +*/ +#define SIZE_C 8 +#define SIZE_B 8 +#define SIZE_Bx (SIZE_C + SIZE_B + 1) +#define SIZE_A 8 +#define SIZE_Ax (SIZE_Bx + SIZE_A) +#define SIZE_sJ (SIZE_Bx + SIZE_A) + +#define SIZE_OP 7 + +#define POS_OP 0 + +#define POS_A (POS_OP + SIZE_OP) +#define POS_k (POS_A + SIZE_A) +#define POS_B (POS_k + 1) +#define POS_C (POS_B + SIZE_B) + +#define POS_Bx POS_k + +#define POS_Ax POS_A + +#define POS_sJ POS_A + + +/* +** limits for opcode arguments. +** we use (signed) 'int' to manipulate most arguments, +** so they must fit in ints. +*/ + +/* Check whether type 'int' has at least 'b' bits ('b' < 32) */ +#define L_INTHASBITS(b) ((UINT_MAX >> ((b) - 1)) >= 1) + + +#if L_INTHASBITS(SIZE_Bx) +#define MAXARG_Bx ((1<<SIZE_Bx)-1) +#else +#define MAXARG_Bx MAX_INT +#endif + +#define OFFSET_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */ + + +#if L_INTHASBITS(SIZE_Ax) +#define MAXARG_Ax ((1<<SIZE_Ax)-1) +#else +#define MAXARG_Ax MAX_INT +#endif + +#if L_INTHASBITS(SIZE_sJ) +#define MAXARG_sJ ((1 << SIZE_sJ) - 1) +#else +#define MAXARG_sJ MAX_INT +#endif + +#define OFFSET_sJ (MAXARG_sJ >> 1) + + +#define MAXARG_A ((1<<SIZE_A)-1) +#define MAXARG_B ((1<<SIZE_B)-1) +#define MAXARG_C ((1<<SIZE_C)-1) +#define OFFSET_sC (MAXARG_C >> 1) + +#define int2sC(i) ((i) + OFFSET_sC) +#define sC2int(i) ((i) - OFFSET_sC) + + +/* creates a mask with 'n' 1 bits at position 'p' */ +#define MASK1(n,p) ((~((~(Instruction)0)<<(n)))<<(p)) + +/* creates a mask with 'n' 0 bits at position 'p' */ +#define MASK0(n,p) (~MASK1(n,p)) + +/* +** the following macros help to manipulate instructions +*/ + +#define GET_OPCODE(i) (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0))) +#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ + ((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP)))) + +#define checkopm(i,m) (getOpMode(GET_OPCODE(i)) == m) + + +#define getarg(i,pos,size) (cast_int(((i)>>(pos)) & MASK1(size,0))) +#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \ + ((cast(Instruction, v)<<pos)&MASK1(size,pos)))) + +#define GETARG_A(i) getarg(i, POS_A, SIZE_A) +#define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A) + +#define GETARG_B(i) check_exp(checkopm(i, iABC), getarg(i, POS_B, SIZE_B)) +#define GETARG_sB(i) sC2int(GETARG_B(i)) +#define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B) + +#define GETARG_C(i) check_exp(checkopm(i, iABC), getarg(i, POS_C, SIZE_C)) +#define GETARG_sC(i) sC2int(GETARG_C(i)) +#define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C) + +#define TESTARG_k(i) check_exp(checkopm(i, iABC), (cast_int(((i) & (1u << POS_k))))) +#define GETARG_k(i) check_exp(checkopm(i, iABC), getarg(i, POS_k, 1)) +#define SETARG_k(i,v) setarg(i, v, POS_k, 1) + +#define GETARG_Bx(i) check_exp(checkopm(i, iABx), getarg(i, POS_Bx, SIZE_Bx)) +#define SETARG_Bx(i,v) setarg(i, v, POS_Bx, SIZE_Bx) + +#define GETARG_Ax(i) check_exp(checkopm(i, iAx), getarg(i, POS_Ax, SIZE_Ax)) +#define SETARG_Ax(i,v) setarg(i, v, POS_Ax, SIZE_Ax) + +#define GETARG_sBx(i) \ + check_exp(checkopm(i, iAsBx), getarg(i, POS_Bx, SIZE_Bx) - OFFSET_sBx) +#define SETARG_sBx(i,b) SETARG_Bx((i),cast_uint((b)+OFFSET_sBx)) + +#define GETARG_sJ(i) \ + check_exp(checkopm(i, isJ), getarg(i, POS_sJ, SIZE_sJ) - OFFSET_sJ) +#define SETARG_sJ(i,j) \ + setarg(i, cast_uint((j)+OFFSET_sJ), POS_sJ, SIZE_sJ) + + +#define CREATE_ABCk(o,a,b,c,k) ((cast(Instruction, o)<<POS_OP) \ + | (cast(Instruction, a)<<POS_A) \ + | (cast(Instruction, b)<<POS_B) \ + | (cast(Instruction, c)<<POS_C) \ + | (cast(Instruction, k)<<POS_k)) + +#define CREATE_ABx(o,a,bc) ((cast(Instruction, o)<<POS_OP) \ + | (cast(Instruction, a)<<POS_A) \ + | (cast(Instruction, bc)<<POS_Bx)) + +#define CREATE_Ax(o,a) ((cast(Instruction, o)<<POS_OP) \ + | (cast(Instruction, a)<<POS_Ax)) + +#define CREATE_sJ(o,j,k) ((cast(Instruction, o) << POS_OP) \ + | (cast(Instruction, j) << POS_sJ) \ + | (cast(Instruction, k) << POS_k)) + + +#if !defined(MAXINDEXRK) /* (for debugging only) */ +#define MAXINDEXRK MAXARG_B +#endif + + +/* +** invalid register that fits in 8 bits +*/ +#define NO_REG MAXARG_A + + +/* +** R[x] - register +** K[x] - constant (in constant table) +** RK(x) == if k(i) then K[x] else R[x] +*/ + + +/* +** Grep "ORDER OP" if you change these enums. Opcodes marked with a (*) +** has extra descriptions in the notes after the enumeration. +*/ + +typedef enum { +/*---------------------------------------------------------------------- + name args description +------------------------------------------------------------------------*/ +OP_MOVE,/* A B R[A] := R[B] */ +OP_LOADI,/* A sBx R[A] := sBx */ +OP_LOADF,/* A sBx R[A] := (lua_Number)sBx */ +OP_LOADK,/* A Bx R[A] := K[Bx] */ +OP_LOADKX,/* A R[A] := K[extra arg] */ +OP_LOADFALSE,/* A R[A] := false */ +OP_LFALSESKIP,/*A R[A] := false; pc++ (*) */ +OP_LOADTRUE,/* A R[A] := true */ +OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */ +OP_GETUPVAL,/* A B R[A] := UpValue[B] */ +OP_SETUPVAL,/* A B UpValue[B] := R[A] */ + +OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:string] */ +OP_GETTABLE,/* A B C R[A] := R[B][R[C]] */ +OP_GETI,/* A B C R[A] := R[B][C] */ +OP_GETFIELD,/* A B C R[A] := R[B][K[C]:string] */ + +OP_SETTABUP,/* A B C UpValue[A][K[B]:string] := RK(C) */ +OP_SETTABLE,/* A B C R[A][R[B]] := RK(C) */ +OP_SETI,/* A B C R[A][B] := RK(C) */ +OP_SETFIELD,/* A B C R[A][K[B]:string] := RK(C) */ + +OP_NEWTABLE,/* A B C k R[A] := {} */ + +OP_SELF,/* A B C R[A+1] := R[B]; R[A] := R[B][RK(C):string] */ + +OP_ADDI,/* A B sC R[A] := R[B] + sC */ + +OP_ADDK,/* A B C R[A] := R[B] + K[C]:number */ +OP_SUBK,/* A B C R[A] := R[B] - K[C]:number */ +OP_MULK,/* A B C R[A] := R[B] * K[C]:number */ +OP_MODK,/* A B C R[A] := R[B] % K[C]:number */ +OP_POWK,/* A B C R[A] := R[B] ^ K[C]:number */ +OP_DIVK,/* A B C R[A] := R[B] / K[C]:number */ +OP_IDIVK,/* A B C R[A] := R[B] // K[C]:number */ + +OP_BANDK,/* A B C R[A] := R[B] & K[C]:integer */ +OP_BORK,/* A B C R[A] := R[B] | K[C]:integer */ +OP_BXORK,/* A B C R[A] := R[B] ~ K[C]:integer */ + +OP_SHRI,/* A B sC R[A] := R[B] >> sC */ +OP_SHLI,/* A B sC R[A] := sC << R[B] */ + +OP_ADD,/* A B C R[A] := R[B] + R[C] */ +OP_SUB,/* A B C R[A] := R[B] - R[C] */ +OP_MUL,/* A B C R[A] := R[B] * R[C] */ +OP_MOD,/* A B C R[A] := R[B] % R[C] */ +OP_POW,/* A B C R[A] := R[B] ^ R[C] */ +OP_DIV,/* A B C R[A] := R[B] / R[C] */ +OP_IDIV,/* A B C R[A] := R[B] // R[C] */ + +OP_BAND,/* A B C R[A] := R[B] & R[C] */ +OP_BOR,/* A B C R[A] := R[B] | R[C] */ +OP_BXOR,/* A B C R[A] := R[B] ~ R[C] */ +OP_SHL,/* A B C R[A] := R[B] << R[C] */ +OP_SHR,/* A B C R[A] := R[B] >> R[C] */ + +OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] (*) */ +OP_MMBINI,/* A sB C k call C metamethod over R[A] and sB */ +OP_MMBINK,/* A B C k call C metamethod over R[A] and K[B] */ + +OP_UNM,/* A B R[A] := -R[B] */ +OP_BNOT,/* A B R[A] := ~R[B] */ +OP_NOT,/* A B R[A] := not R[B] */ +OP_LEN,/* A B R[A] := #R[B] (length operator) */ + +OP_CONCAT,/* A B R[A] := R[A].. ... ..R[A + B - 1] */ + +OP_CLOSE,/* A close all upvalues >= R[A] */ +OP_TBC,/* A mark variable A "to be closed" */ +OP_JMP,/* sJ pc += sJ */ +OP_EQ,/* A B k if ((R[A] == R[B]) ~= k) then pc++ */ +OP_LT,/* A B k if ((R[A] < R[B]) ~= k) then pc++ */ +OP_LE,/* A B k if ((R[A] <= R[B]) ~= k) then pc++ */ + +OP_EQK,/* A B k if ((R[A] == K[B]) ~= k) then pc++ */ +OP_EQI,/* A sB k if ((R[A] == sB) ~= k) then pc++ */ +OP_LTI,/* A sB k if ((R[A] < sB) ~= k) then pc++ */ +OP_LEI,/* A sB k if ((R[A] <= sB) ~= k) then pc++ */ +OP_GTI,/* A sB k if ((R[A] > sB) ~= k) then pc++ */ +OP_GEI,/* A sB k if ((R[A] >= sB) ~= k) then pc++ */ + +OP_TEST,/* A k if (not R[A] == k) then pc++ */ +OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] (*) */ + +OP_CALL,/* A B C R[A], ... ,R[A+C-2] := R[A](R[A+1], ... ,R[A+B-1]) */ +OP_TAILCALL,/* A B C k return R[A](R[A+1], ... ,R[A+B-1]) */ + +OP_RETURN,/* A B C k return R[A], ... ,R[A+B-2] (see note) */ +OP_RETURN0,/* return */ +OP_RETURN1,/* A return R[A] */ + +OP_FORLOOP,/* A Bx update counters; if loop continues then pc-=Bx; */ +OP_FORPREP,/* A Bx <check values and prepare counters>; + if not to run then pc+=Bx+1; */ + +OP_TFORPREP,/* A Bx create upvalue for R[A + 3]; pc+=Bx */ +OP_TFORCALL,/* A C R[A+4], ... ,R[A+3+C] := R[A](R[A+1], R[A+2]); */ +OP_TFORLOOP,/* A Bx if R[A+2] ~= nil then { R[A]=R[A+2]; pc -= Bx } */ + +OP_SETLIST,/* A B C k R[A][C+i] := R[A+i], 1 <= i <= B */ + +OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */ + +OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */ + +OP_VARARGPREP,/*A (adjust vararg parameters) */ + +OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ +} OpCode; + + +#define NUM_OPCODES ((int)(OP_EXTRAARG) + 1) + + + +/*=========================================================================== + Notes: + + (*) Opcode OP_LFALSESKIP is used to convert a condition to a boolean + value, in a code equivalent to (not cond ? false : true). (It + produces false and skips the next instruction producing true.) + + (*) Opcodes OP_MMBIN and variants follow each arithmetic and + bitwise opcode. If the operation succeeds, it skips this next + opcode. Otherwise, this opcode calls the corresponding metamethod. + + (*) Opcode OP_TESTSET is used in short-circuit expressions that need + both to jump and to produce a value, such as (a = b or c). + + (*) In OP_CALL, if (B == 0) then B = top - A. If (C == 0), then + 'top' is set to last_result+1, so next open instruction (OP_CALL, + OP_RETURN*, OP_SETLIST) may use 'top'. + + (*) In OP_VARARG, if (C == 0) then use actual number of varargs and + set top (like in OP_CALL with C == 0). + + (*) In OP_RETURN, if (B == 0) then return up to 'top'. + + (*) In OP_LOADKX and OP_NEWTABLE, the next instruction is always + OP_EXTRAARG. + + (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if k, then + real C = EXTRAARG _ C (the bits of EXTRAARG concatenated with the + bits of C). + + (*) In OP_NEWTABLE, B is log2 of the hash size (which is always a + power of 2) plus 1, or zero for size zero. If not k, the array size + is C. Otherwise, the array size is EXTRAARG _ C. + + (*) For comparisons, k specifies what condition the test should accept + (true or false). + + (*) In OP_MMBINI/OP_MMBINK, k means the arguments were flipped + (the constant is the first operand). + + (*) All 'skips' (pc++) assume that next instruction is a jump. + + (*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the + function builds upvalues, which may need to be closed. C > 0 means + the function is vararg, so that its 'func' must be corrected before + returning; in this case, (C - 1) is its number of fixed parameters. + + (*) In comparisons with an immediate operand, C signals whether the + original operand was a float. (It must be corrected in case of + metamethods.) + +===========================================================================*/ + + +/* +** masks for instruction properties. The format is: +** bits 0-2: op mode +** bit 3: instruction set register A +** bit 4: operator is a test (next instruction must be a jump) +** bit 5: instruction uses 'L->top' set by previous instruction (when B == 0) +** bit 6: instruction sets 'L->top' for next instruction (when C == 0) +** bit 7: instruction is an MM instruction (call a metamethod) +*/ + +LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];) + +#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 7)) +#define testAMode(m) (luaP_opmodes[m] & (1 << 3)) +#define testTMode(m) (luaP_opmodes[m] & (1 << 4)) +#define testITMode(m) (luaP_opmodes[m] & (1 << 5)) +#define testOTMode(m) (luaP_opmodes[m] & (1 << 6)) +#define testMMMode(m) (luaP_opmodes[m] & (1 << 7)) + +/* "out top" (set top for next instruction) */ +#define isOT(i) \ + ((testOTMode(GET_OPCODE(i)) && GETARG_C(i) == 0) || \ + GET_OPCODE(i) == OP_TAILCALL) + +/* "in top" (uses top from previous instruction) */ +#define isIT(i) (testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0) + +#define opmode(mm,ot,it,t,a,m) \ + (((mm) << 7) | ((ot) << 6) | ((it) << 5) | ((t) << 4) | ((a) << 3) | (m)) + + +/* number of list items to accumulate before a SETLIST instruction */ +#define LFIELDS_PER_FLUSH 50 + +#endif diff --git a/src/libs/3rdparty/lua/src/lopnames.h b/src/libs/3rdparty/lua/src/lopnames.h new file mode 100644 index 0000000000..965cec9bf2 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lopnames.h @@ -0,0 +1,103 @@ +/* +** $Id: lopnames.h $ +** Opcode names +** See Copyright Notice in lua.h +*/ + +#if !defined(lopnames_h) +#define lopnames_h + +#include <stddef.h> + + +/* ORDER OP */ + +static const char *const opnames[] = { + "MOVE", + "LOADI", + "LOADF", + "LOADK", + "LOADKX", + "LOADFALSE", + "LFALSESKIP", + "LOADTRUE", + "LOADNIL", + "GETUPVAL", + "SETUPVAL", + "GETTABUP", + "GETTABLE", + "GETI", + "GETFIELD", + "SETTABUP", + "SETTABLE", + "SETI", + "SETFIELD", + "NEWTABLE", + "SELF", + "ADDI", + "ADDK", + "SUBK", + "MULK", + "MODK", + "POWK", + "DIVK", + "IDIVK", + "BANDK", + "BORK", + "BXORK", + "SHRI", + "SHLI", + "ADD", + "SUB", + "MUL", + "MOD", + "POW", + "DIV", + "IDIV", + "BAND", + "BOR", + "BXOR", + "SHL", + "SHR", + "MMBIN", + "MMBINI", + "MMBINK", + "UNM", + "BNOT", + "NOT", + "LEN", + "CONCAT", + "CLOSE", + "TBC", + "JMP", + "EQ", + "LT", + "LE", + "EQK", + "EQI", + "LTI", + "LEI", + "GTI", + "GEI", + "TEST", + "TESTSET", + "CALL", + "TAILCALL", + "RETURN", + "RETURN0", + "RETURN1", + "FORLOOP", + "FORPREP", + "TFORPREP", + "TFORCALL", + "TFORLOOP", + "SETLIST", + "CLOSURE", + "VARARG", + "VARARGPREP", + "EXTRAARG", + NULL +}; + +#endif + diff --git a/src/libs/3rdparty/lua/src/loslib.c b/src/libs/3rdparty/lua/src/loslib.c new file mode 100644 index 0000000000..ad5a927688 --- /dev/null +++ b/src/libs/3rdparty/lua/src/loslib.c @@ -0,0 +1,428 @@ +/* +** $Id: loslib.c $ +** Standard Operating System library +** See Copyright Notice in lua.h +*/ + +#define loslib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include <errno.h> +#include <locale.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** {================================================================== +** 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_WINDOWS) +#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \ + "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */ +#elif defined(LUA_USE_C89) /* ANSI C 89 (only 1-char options) */ +#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%" +#else /* C99 specification */ +#define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \ + "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */ +#endif + +#endif /* } */ +/* }================================================================== */ + + +/* +** {================================================================== +** Configuration for time-related stuff +** =================================================================== +*/ + +/* +** type to represent time_t in Lua +*/ +#if !defined(LUA_NUMTIME) /* { */ + +#define l_timet lua_Integer +#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t)) +#define l_gettime(L,arg) luaL_checkinteger(L, arg) + +#else /* }{ */ + +#define l_timet lua_Number +#define l_pushtime(L,t) lua_pushnumber(L,(lua_Number)(t)) +#define l_gettime(L,arg) luaL_checknumber(L, arg) + +#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 /* } */ + +/* }================================================================== */ + + +/* +** {================================================================== +** 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> + +#define LUA_TMPNAMBUFSIZE 32 + +#if !defined(LUA_TMPNAMTEMPLATE) +#define LUA_TMPNAMTEMPLATE "/tmp/lua_XXXXXX" +#endif + +#define lua_tmpnam(b,e) { \ + strcpy(b, LUA_TMPNAMTEMPLATE); \ + e = mkstemp(b); \ + if (e != -1) close(e); \ + e = (e == -1); } + +#else /* }{ */ + +/* ISO C definitions */ +#define LUA_TMPNAMBUFSIZE L_tmpnam +#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } + +#endif /* } */ + +#endif /* } */ +/* }================================================================== */ + + +#if !defined(l_system) +#if defined(LUA_USE_IOS) +/* Despite claiming to be ISO C, iOS does not implement 'system'. */ +#define l_system(cmd) ((cmd) == NULL ? 0 : -1) +#else +#define l_system(cmd) system(cmd) /* default definition */ +#endif +#endif + + +static int os_execute (lua_State *L) { + const char *cmd = luaL_optstring(L, 1, NULL); + int stat; + errno = 0; + stat = l_system(cmd); + if (cmd != NULL) + return luaL_execresult(L, stat); + else { + lua_pushboolean(L, stat); /* true if there is a shell */ + return 1; + } +} + + +static int os_remove (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + return luaL_fileresult(L, remove(filename) == 0, filename); +} + + +static int os_rename (lua_State *L) { + const char *fromname = luaL_checkstring(L, 1); + const char *toname = luaL_checkstring(L, 2); + return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); +} + + +static int os_tmpname (lua_State *L) { + char buff[LUA_TMPNAMBUFSIZE]; + int err; + lua_tmpnam(buff, err); + if (l_unlikely(err)) + return luaL_error(L, "unable to generate a unique filename"); + lua_pushstring(L, buff); + return 1; +} + + +static int os_getenv (lua_State *L) { + lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ + return 1; +} + + +static int os_clock (lua_State *L) { + lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); + return 1; +} + + +/* +** {====================================================== +** Time/Date operations +** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, +** wday=%w+1, yday=%j, isdst=? } +** ======================================================= +*/ + +/* +** About the overflow check: an overflow cannot occur when time +** is represented by a lua_Integer, because either lua_Integer is +** large enough to represent all int fields or it is not large enough +** to represent a time that cause a field to overflow. However, if +** times are represented as doubles and lua_Integer is int, then the +** time 0x1.e1853b0d184f6p+55 would cause an overflow when adding 1900 +** to compute the year. +*/ +static void setfield (lua_State *L, const char *key, int value, int delta) { + #if (defined(LUA_NUMTIME) && LUA_MAXINTEGER <= INT_MAX) + if (l_unlikely(value > LUA_MAXINTEGER - delta)) + luaL_error(L, "field '%s' is out-of-bound", key); + #endif + lua_pushinteger(L, (lua_Integer)value + delta); + lua_setfield(L, -2, key); +} + + +static void setboolfield (lua_State *L, const char *key, int value) { + if (value < 0) /* undefined? */ + return; /* does not set field */ + lua_pushboolean(L, value); + lua_setfield(L, -2, key); +} + + +/* +** Set all fields from structure 'tm' in the table on top of the stack +*/ +static void setallfields (lua_State *L, struct tm *stm) { + setfield(L, "year", stm->tm_year, 1900); + setfield(L, "month", stm->tm_mon, 1); + setfield(L, "day", stm->tm_mday, 0); + setfield(L, "hour", stm->tm_hour, 0); + setfield(L, "min", stm->tm_min, 0); + setfield(L, "sec", stm->tm_sec, 0); + setfield(L, "yday", stm->tm_yday, 1); + setfield(L, "wday", stm->tm_wday, 1); + setboolfield(L, "isdst", stm->tm_isdst); +} + + +static int getboolfield (lua_State *L, const char *key) { + int res; + res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1); + lua_pop(L, 1); + return res; +} + + +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 (l_unlikely(t != LUA_TNIL)) /* some other value? */ + return luaL_error(L, "field '%s' is not an integer", key); + else if (l_unlikely(d < 0)) /* absent field; no default? */ + return luaL_error(L, "field '%s' missing in date table", key); + res = d; + } + else { + if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res)) + return luaL_error(L, "field '%s' is out-of-bound", key); + res -= delta; + } + lua_pop(L, 1); + return (int)res; +} + + +static const char *checkoption (lua_State *L, const char *conv, + ptrdiff_t convlen, char *buff) { + const char *option = LUA_STRFTIMEOPTIONS; + int oplen = 1; /* length of options being checked */ + for (; *option != '\0' && oplen <= convlen; option += oplen) { + if (*option == '|') /* next block? */ + oplen++; /* will check options with next length (+1) */ + else if (memcmp(conv, option, oplen) == 0) { /* match? */ + memcpy(buff, conv, oplen); /* copy valid option to buffer */ + buff[oplen] = '\0'; + return conv + oplen; /* return next item */ + } + } + luaL_argerror(L, 1, + lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv)); + return conv; /* to avoid warnings */ +} + + +static time_t l_checktime (lua_State *L, int arg) { + l_timet t = l_gettime(L, arg); + luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds"); + return (time_t)t; +} + + +/* maximum size for an individual 'strftime' item */ +#define SIZETIMEFMT 250 + + +static int os_date (lua_State *L) { + size_t slen; + const char *s = luaL_optlstring(L, 1, "%c", &slen); + time_t t = luaL_opt(L, l_checktime, 2, time(NULL)); + const char *se = s + slen; /* 's' end */ + struct tm tmr, *stm; + if (*s == '!') { /* UTC? */ + stm = l_gmtime(&t, &tmr); + s++; /* skip '!' */ + } + else + stm = l_localtime(&t, &tmr); + if (stm == NULL) /* invalid date? */ + return luaL_error(L, + "date result cannot be represented in this installation"); + if (strcmp(s, "*t") == 0) { + lua_createtable(L, 0, 9); /* 9 = number of fields */ + setallfields(L, stm); + } + else { + char cc[4]; /* buffer for individual conversion specifiers */ + luaL_Buffer b; + cc[0] = '%'; + luaL_buffinit(L, &b); + while (s < se) { + if (*s != '%') /* not a conversion specifier? */ + luaL_addchar(&b, *s++); + else { + size_t reslen; + char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); + s++; /* skip '%' */ + s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */ + reslen = strftime(buff, SIZETIMEFMT, cc, stm); + luaL_addsize(&b, reslen); + } + } + luaL_pushresult(&b); + } + return 1; +} + + +static int os_time (lua_State *L) { + time_t t; + if (lua_isnoneornil(L, 1)) /* called without args? */ + t = time(NULL); /* get current time */ + else { + struct tm ts; + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); /* make sure table is at the top */ + ts.tm_year = getfield(L, "year", -1, 1900); + ts.tm_mon = getfield(L, "month", -1, 1); + ts.tm_mday = getfield(L, "day", -1, 0); + ts.tm_hour = getfield(L, "hour", 12, 0); + ts.tm_min = getfield(L, "min", 0, 0); + ts.tm_sec = getfield(L, "sec", 0, 0); + ts.tm_isdst = getboolfield(L, "isdst"); + t = mktime(&ts); + setallfields(L, &ts); /* update fields with normalized values */ + } + if (t != (time_t)(l_timet)t || t == (time_t)(-1)) + return luaL_error(L, + "time result cannot be represented in this installation"); + l_pushtime(L, t); + return 1; +} + + +static int os_difftime (lua_State *L) { + time_t t1 = l_checktime(L, 1); + time_t t2 = l_checktime(L, 2); + lua_pushnumber(L, (lua_Number)difftime(t1, t2)); + return 1; +} + +/* }====================================================== */ + + +static int os_setlocale (lua_State *L) { + static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, + LC_NUMERIC, LC_TIME}; + static const char *const catnames[] = {"all", "collate", "ctype", "monetary", + "numeric", "time", NULL}; + const char *l = luaL_optstring(L, 1, NULL); + int op = luaL_checkoption(L, 2, "all", catnames); + lua_pushstring(L, setlocale(cat[op], l)); + return 1; +} + + +static int os_exit (lua_State *L) { + int status; + if (lua_isboolean(L, 1)) + status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE); + else + status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS); + if (lua_toboolean(L, 2)) + lua_close(L); + if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */ + return 0; +} + + +static const luaL_Reg syslib[] = { + {"clock", os_clock}, + {"date", os_date}, + {"difftime", os_difftime}, + {"execute", os_execute}, + {"exit", os_exit}, + {"getenv", os_getenv}, + {"remove", os_remove}, + {"rename", os_rename}, + {"setlocale", os_setlocale}, + {"time", os_time}, + {"tmpname", os_tmpname}, + {NULL, NULL} +}; + +/* }====================================================== */ + + + +LUAMOD_API int luaopen_os (lua_State *L) { + luaL_newlib(L, syslib); + return 1; +} + diff --git a/src/libs/3rdparty/lua/src/lparser.c b/src/libs/3rdparty/lua/src/lparser.c new file mode 100644 index 0000000000..b745f236f0 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lparser.c @@ -0,0 +1,1967 @@ +/* +** $Id: lparser.c $ +** Lua Parser +** See Copyright Notice in lua.h +*/ + +#define lparser_c +#define LUA_CORE + +#include "lprefix.h" + + +#include <limits.h> +#include <string.h> + +#include "lua.h" + +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "llex.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" + + + +/* maximum number of local variables per function (must be smaller + than 250, due to the bytecode format) */ +#define MAXVARS 200 + + +#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) + + +/* because all strings are unified by the scanner, the parser + can use pointer equality for string equality */ +#define eqstr(a,b) ((a) == (b)) + + +/* +** nodes for block list (list of active blocks) +*/ +typedef struct BlockCnt { + struct BlockCnt *previous; /* chain */ + int firstlabel; /* index of first label in this block */ + int firstgoto; /* index of first pending goto in this block */ + lu_byte nactvar; /* # active locals outside the block */ + lu_byte upval; /* true if some variable in the block is an upvalue */ + lu_byte isloop; /* true if 'block' is a loop */ + lu_byte insidetbc; /* true if inside the scope of a to-be-closed var. */ +} BlockCnt; + + + +/* +** prototypes for recursive non-terminal functions +*/ +static void statement (LexState *ls); +static void expr (LexState *ls, expdesc *v); + + +static l_noret error_expected (LexState *ls, int token) { + luaX_syntaxerror(ls, + luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token))); +} + + +static l_noret errorlimit (FuncState *fs, int limit, const char *what) { + lua_State *L = fs->ls->L; + const char *msg; + int line = fs->f->linedefined; + const char *where = (line == 0) + ? "main function" + : luaO_pushfstring(L, "function at line %d", line); + msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s", + what, limit, where); + luaX_syntaxerror(fs->ls, msg); +} + + +static void checklimit (FuncState *fs, int v, int l, const char *what) { + if (v > l) errorlimit(fs, l, what); +} + + +/* +** Test whether next token is 'c'; if so, skip it. +*/ +static int testnext (LexState *ls, int c) { + if (ls->t.token == c) { + luaX_next(ls); + return 1; + } + else return 0; +} + + +/* +** Check that next token is 'c'. +*/ +static void check (LexState *ls, int c) { + if (ls->t.token != c) + error_expected(ls, c); +} + + +/* +** Check that next token is 'c' and skip it. +*/ +static void checknext (LexState *ls, int c) { + check(ls, c); + luaX_next(ls); +} + + +#define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } + + +/* +** Check that next token is 'what' and skip it. In case of error, +** raise an error that the expected 'what' should match a 'who' +** in line 'where' (if that is not the current line). +*/ +static void check_match (LexState *ls, int what, int who, int where) { + if (l_unlikely(!testnext(ls, what))) { + if (where == ls->linenumber) /* all in the same line? */ + error_expected(ls, what); /* do not need a complex message */ + else { + luaX_syntaxerror(ls, luaO_pushfstring(ls->L, + "%s expected (to close %s at line %d)", + luaX_token2str(ls, what), luaX_token2str(ls, who), where)); + } + } +} + + +static TString *str_checkname (LexState *ls) { + TString *ts; + check(ls, TK_NAME); + ts = ls->t.seminfo.ts; + luaX_next(ls); + return ts; +} + + +static void init_exp (expdesc *e, expkind k, int i) { + e->f = e->t = NO_JUMP; + e->k = k; + e->u.info = i; +} + + +static void codestring (expdesc *e, TString *s) { + e->f = e->t = NO_JUMP; + e->k = VKSTR; + e->u.strval = s; +} + + +static void codename (LexState *ls, expdesc *e) { + codestring(e, str_checkname(ls)); +} + + +/* +** Register a new local variable in the active 'Proto' (for debug +** information). +*/ +static int registerlocalvar (LexState *ls, FuncState *fs, TString *varname) { + Proto *f = fs->f; + int oldsize = f->sizelocvars; + luaM_growvector(ls->L, f->locvars, fs->ndebugvars, f->sizelocvars, + LocVar, SHRT_MAX, "local variables"); + while (oldsize < f->sizelocvars) + f->locvars[oldsize++].varname = NULL; + f->locvars[fs->ndebugvars].varname = varname; + f->locvars[fs->ndebugvars].startpc = fs->pc; + luaC_objbarrier(ls->L, f, varname); + return fs->ndebugvars++; +} + + +/* +** Create a new local variable with the given 'name'. Return its index +** in the function. +*/ +static int new_localvar (LexState *ls, TString *name) { + lua_State *L = ls->L; + FuncState *fs = ls->fs; + Dyndata *dyd = ls->dyd; + Vardesc *var; + checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, + MAXVARS, "local variables"); + luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1, + dyd->actvar.size, Vardesc, USHRT_MAX, "local variables"); + var = &dyd->actvar.arr[dyd->actvar.n++]; + var->vd.kind = VDKREG; /* default */ + var->vd.name = name; + return dyd->actvar.n - 1 - fs->firstlocal; +} + +#define new_localvarliteral(ls,v) \ + new_localvar(ls, \ + luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char)) - 1)); + + + +/* +** Return the "variable description" (Vardesc) of a given variable. +** (Unless noted otherwise, all variables are referred to by their +** compiler indices.) +*/ +static Vardesc *getlocalvardesc (FuncState *fs, int vidx) { + return &fs->ls->dyd->actvar.arr[fs->firstlocal + vidx]; +} + + +/* +** Convert 'nvar', a compiler index level, to its corresponding +** register. For that, search for the highest variable below that level +** that is in a register and uses its register index ('ridx') plus one. +*/ +static int reglevel (FuncState *fs, int nvar) { + while (nvar-- > 0) { + Vardesc *vd = getlocalvardesc(fs, nvar); /* get previous variable */ + if (vd->vd.kind != RDKCTC) /* is in a register? */ + return vd->vd.ridx + 1; + } + return 0; /* no variables in registers */ +} + + +/* +** Return the number of variables in the register stack for the given +** function. +*/ +int luaY_nvarstack (FuncState *fs) { + return reglevel(fs, fs->nactvar); +} + + +/* +** Get the debug-information entry for current variable 'vidx'. +*/ +static LocVar *localdebuginfo (FuncState *fs, int vidx) { + Vardesc *vd = getlocalvardesc(fs, vidx); + if (vd->vd.kind == RDKCTC) + return NULL; /* no debug info. for constants */ + else { + int idx = vd->vd.pidx; + lua_assert(idx < fs->ndebugvars); + return &fs->f->locvars[idx]; + } +} + + +/* +** Create an expression representing variable 'vidx' +*/ +static void init_var (FuncState *fs, expdesc *e, int vidx) { + e->f = e->t = NO_JUMP; + e->k = VLOCAL; + e->u.var.vidx = vidx; + e->u.var.ridx = getlocalvardesc(fs, vidx)->vd.ridx; +} + + +/* +** Raises an error if variable described by 'e' is read only +*/ +static void check_readonly (LexState *ls, expdesc *e) { + FuncState *fs = ls->fs; + TString *varname = NULL; /* to be set if variable is const */ + switch (e->k) { + case VCONST: { + varname = ls->dyd->actvar.arr[e->u.info].vd.name; + break; + } + case VLOCAL: { + Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx); + if (vardesc->vd.kind != VDKREG) /* not a regular variable? */ + varname = vardesc->vd.name; + break; + } + case VUPVAL: { + Upvaldesc *up = &fs->f->upvalues[e->u.info]; + if (up->kind != VDKREG) + varname = up->name; + break; + } + default: + return; /* other cases cannot be read-only */ + } + if (varname) { + const char *msg = luaO_pushfstring(ls->L, + "attempt to assign to const variable '%s'", getstr(varname)); + luaK_semerror(ls, msg); /* error */ + } +} + + +/* +** Start the scope for the last 'nvars' created variables. +*/ +static void adjustlocalvars (LexState *ls, int nvars) { + FuncState *fs = ls->fs; + int reglevel = luaY_nvarstack(fs); + int i; + for (i = 0; i < nvars; i++) { + int vidx = fs->nactvar++; + Vardesc *var = getlocalvardesc(fs, vidx); + var->vd.ridx = reglevel++; + var->vd.pidx = registerlocalvar(ls, fs, var->vd.name); + } +} + + +/* +** Close the scope for all variables up to level 'tolevel'. +** (debug info.) +*/ +static void removevars (FuncState *fs, int tolevel) { + fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel); + while (fs->nactvar > tolevel) { + LocVar *var = localdebuginfo(fs, --fs->nactvar); + if (var) /* does it have debug information? */ + var->endpc = fs->pc; + } +} + + +/* +** Search the upvalues of the function 'fs' for one +** with the given 'name'. +*/ +static int searchupvalue (FuncState *fs, TString *name) { + int i; + Upvaldesc *up = fs->f->upvalues; + for (i = 0; i < fs->nups; i++) { + if (eqstr(up[i].name, name)) return i; + } + return -1; /* not found */ +} + + +static Upvaldesc *allocupvalue (FuncState *fs) { + Proto *f = fs->f; + int oldsize = f->sizeupvalues; + checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); + luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues, + Upvaldesc, MAXUPVAL, "upvalues"); + while (oldsize < f->sizeupvalues) + f->upvalues[oldsize++].name = NULL; + return &f->upvalues[fs->nups++]; +} + + +static int newupvalue (FuncState *fs, TString *name, expdesc *v) { + Upvaldesc *up = allocupvalue(fs); + FuncState *prev = fs->prev; + if (v->k == VLOCAL) { + up->instack = 1; + up->idx = v->u.var.ridx; + up->kind = getlocalvardesc(prev, v->u.var.vidx)->vd.kind; + lua_assert(eqstr(name, getlocalvardesc(prev, v->u.var.vidx)->vd.name)); + } + else { + up->instack = 0; + up->idx = cast_byte(v->u.info); + up->kind = prev->f->upvalues[v->u.info].kind; + lua_assert(eqstr(name, prev->f->upvalues[v->u.info].name)); + } + up->name = name; + luaC_objbarrier(fs->ls->L, fs->f, name); + return fs->nups - 1; +} + + +/* +** Look for an active local variable with the name 'n' in the +** function 'fs'. If found, initialize 'var' with it and return +** its expression kind; otherwise return -1. +*/ +static int searchvar (FuncState *fs, TString *n, expdesc *var) { + int i; + for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { + Vardesc *vd = getlocalvardesc(fs, i); + if (eqstr(n, vd->vd.name)) { /* found? */ + if (vd->vd.kind == RDKCTC) /* compile-time constant? */ + init_exp(var, VCONST, fs->firstlocal + i); + else /* real variable */ + init_var(fs, var, i); + return var->k; + } + } + return -1; /* not found */ +} + + +/* +** Mark block where variable at given level was defined +** (to emit close instructions later). +*/ +static void markupval (FuncState *fs, int level) { + BlockCnt *bl = fs->bl; + while (bl->nactvar > level) + bl = bl->previous; + bl->upval = 1; + fs->needclose = 1; +} + + +/* +** Mark that current block has a to-be-closed variable. +*/ +static void marktobeclosed (FuncState *fs) { + BlockCnt *bl = fs->bl; + bl->upval = 1; + bl->insidetbc = 1; + fs->needclose = 1; +} + + +/* +** Find a variable with the given name 'n'. If it is an upvalue, add +** this upvalue into all intermediate functions. If it is a global, set +** 'var' as 'void' as a flag. +*/ +static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { + if (fs == NULL) /* no more levels? */ + init_exp(var, VVOID, 0); /* default is global */ + else { + int v = searchvar(fs, n, var); /* look up locals at current level */ + if (v >= 0) { /* found? */ + if (v == VLOCAL && !base) + markupval(fs, var->u.var.vidx); /* local will be used as an upval */ + } + else { /* not found as local at current level; try upvalues */ + int idx = searchupvalue(fs, n); /* try existing upvalues */ + if (idx < 0) { /* not found? */ + singlevaraux(fs->prev, n, var, 0); /* try upper levels */ + if (var->k == VLOCAL || var->k == VUPVAL) /* local or upvalue? */ + idx = newupvalue(fs, n, var); /* will be a new upvalue */ + else /* it is a global or a constant */ + return; /* don't need to do anything at this level */ + } + init_exp(var, VUPVAL, idx); /* new or old upvalue */ + } + } +} + + +/* +** Find a variable with the given name 'n', handling global variables +** too. +*/ +static void singlevar (LexState *ls, expdesc *var) { + TString *varname = str_checkname(ls); + FuncState *fs = ls->fs; + singlevaraux(fs, varname, var, 1); + if (var->k == VVOID) { /* global name? */ + expdesc key; + singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ + lua_assert(var->k != VVOID); /* this one must exist */ + luaK_exp2anyregup(fs, var); /* but could be a constant */ + codestring(&key, varname); /* key is variable name */ + luaK_indexed(fs, var, &key); /* env[varname] */ + } +} + + +/* +** Adjust the number of results from an expression list 'e' with 'nexps' +** expressions to 'nvars' values. +*/ +static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { + FuncState *fs = ls->fs; + int needed = nvars - nexps; /* extra values needed */ + if (hasmultret(e->k)) { /* last expression has multiple returns? */ + int extra = needed + 1; /* discount last expression itself */ + if (extra < 0) + extra = 0; + luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ + } + else { + if (e->k != VVOID) /* at least one expression? */ + luaK_exp2nextreg(fs, e); /* close last expression */ + if (needed > 0) /* missing values? */ + luaK_nil(fs, fs->freereg, needed); /* complete with nils */ + } + if (needed > 0) + luaK_reserveregs(fs, needed); /* registers for extra values */ + else /* adding 'needed' is actually a subtraction */ + fs->freereg += needed; /* remove extra values */ +} + + +#define enterlevel(ls) luaE_incCstack(ls->L) + + +#define leavelevel(ls) ((ls)->L->nCcalls--) + + +/* +** Generates an error that a goto jumps into the scope of some +** local variable. +*/ +static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) { + const char *varname = getstr(getlocalvardesc(ls->fs, gt->nactvar)->vd.name); + const char *msg = "<goto %s> at line %d jumps into the scope of local '%s'"; + msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line, varname); + luaK_semerror(ls, msg); /* raise the error */ +} + + +/* +** Solves the goto at index 'g' to given 'label' and removes it +** from the list of pending gotos. +** If it jumps into the scope of some variable, raises an error. +*/ +static void solvegoto (LexState *ls, int g, Labeldesc *label) { + int i; + Labellist *gl = &ls->dyd->gt; /* list of gotos */ + Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */ + lua_assert(eqstr(gt->name, label->name)); + if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */ + jumpscopeerror(ls, gt); + luaK_patchlist(ls->fs, gt->pc, label->pc); + for (i = g; i < gl->n - 1; i++) /* remove goto from pending list */ + gl->arr[i] = gl->arr[i + 1]; + gl->n--; +} + + +/* +** Search for an active label with the given name. +*/ +static Labeldesc *findlabel (LexState *ls, TString *name) { + int i; + Dyndata *dyd = ls->dyd; + /* check labels in current function for a match */ + for (i = ls->fs->firstlabel; i < dyd->label.n; i++) { + Labeldesc *lb = &dyd->label.arr[i]; + if (eqstr(lb->name, name)) /* correct label? */ + return lb; + } + return NULL; /* label not found */ +} + + +/* +** Adds a new label/goto in the corresponding list. +*/ +static int newlabelentry (LexState *ls, Labellist *l, TString *name, + int line, int pc) { + int n = l->n; + luaM_growvector(ls->L, l->arr, n, l->size, + Labeldesc, SHRT_MAX, "labels/gotos"); + l->arr[n].name = name; + l->arr[n].line = line; + l->arr[n].nactvar = ls->fs->nactvar; + l->arr[n].close = 0; + l->arr[n].pc = pc; + l->n = n + 1; + return n; +} + + +static int newgotoentry (LexState *ls, TString *name, int line, int pc) { + return newlabelentry(ls, &ls->dyd->gt, name, line, pc); +} + + +/* +** Solves forward jumps. Check whether new label 'lb' matches any +** pending gotos in current block and solves them. Return true +** if any of the gotos need to close upvalues. +*/ +static int solvegotos (LexState *ls, Labeldesc *lb) { + Labellist *gl = &ls->dyd->gt; + int i = ls->fs->bl->firstgoto; + int needsclose = 0; + while (i < gl->n) { + if (eqstr(gl->arr[i].name, lb->name)) { + needsclose |= gl->arr[i].close; + solvegoto(ls, i, lb); /* will remove 'i' from the list */ + } + else + i++; + } + return needsclose; +} + + +/* +** Create a new label with the given 'name' at the given 'line'. +** 'last' tells whether label is the last non-op statement in its +** block. Solves all pending gotos to this new label and adds +** a close instruction if necessary. +** Returns true iff it added a close instruction. +*/ +static int createlabel (LexState *ls, TString *name, int line, + int last) { + FuncState *fs = ls->fs; + Labellist *ll = &ls->dyd->label; + int l = newlabelentry(ls, ll, name, line, luaK_getlabel(fs)); + if (last) { /* label is last no-op statement in the block? */ + /* assume that locals are already out of scope */ + ll->arr[l].nactvar = fs->bl->nactvar; + } + if (solvegotos(ls, &ll->arr[l])) { /* need close? */ + luaK_codeABC(fs, OP_CLOSE, luaY_nvarstack(fs), 0, 0); + return 1; + } + return 0; +} + + +/* +** Adjust pending gotos to outer level of a block. +*/ +static void movegotosout (FuncState *fs, BlockCnt *bl) { + int i; + Labellist *gl = &fs->ls->dyd->gt; + /* correct pending gotos to current block */ + for (i = bl->firstgoto; i < gl->n; i++) { /* for each pending goto */ + Labeldesc *gt = &gl->arr[i]; + /* leaving a variable scope? */ + if (reglevel(fs, gt->nactvar) > reglevel(fs, bl->nactvar)) + gt->close |= bl->upval; /* jump may need a close */ + gt->nactvar = bl->nactvar; /* update goto level */ + } +} + + +static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { + bl->isloop = isloop; + bl->nactvar = fs->nactvar; + bl->firstlabel = fs->ls->dyd->label.n; + bl->firstgoto = fs->ls->dyd->gt.n; + bl->upval = 0; + bl->insidetbc = (fs->bl != NULL && fs->bl->insidetbc); + bl->previous = fs->bl; + fs->bl = bl; + lua_assert(fs->freereg == luaY_nvarstack(fs)); +} + + +/* +** generates an error for an undefined 'goto'. +*/ +static l_noret undefgoto (LexState *ls, Labeldesc *gt) { + const char *msg; + if (eqstr(gt->name, luaS_newliteral(ls->L, "break"))) { + msg = "break outside loop at line %d"; + msg = luaO_pushfstring(ls->L, msg, gt->line); + } + else { + msg = "no visible label '%s' for <goto> at line %d"; + msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); + } + luaK_semerror(ls, msg); +} + + +static void leaveblock (FuncState *fs) { + BlockCnt *bl = fs->bl; + LexState *ls = fs->ls; + int hasclose = 0; + int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */ + removevars(fs, bl->nactvar); /* remove block locals */ + lua_assert(bl->nactvar == fs->nactvar); /* back to level on entry */ + if (bl->isloop) /* has to fix pending breaks? */ + hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0); + if (!hasclose && bl->previous && bl->upval) /* still need a 'close'? */ + luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0); + fs->freereg = stklevel; /* free registers */ + ls->dyd->label.n = bl->firstlabel; /* remove local labels */ + fs->bl = bl->previous; /* current block now is previous one */ + if (bl->previous) /* was it a nested block? */ + movegotosout(fs, bl); /* update pending gotos to enclosing block */ + else { + if (bl->firstgoto < ls->dyd->gt.n) /* still pending gotos? */ + undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ + } +} + + +/* +** adds a new prototype into list of prototypes +*/ +static Proto *addprototype (LexState *ls) { + Proto *clp; + lua_State *L = ls->L; + FuncState *fs = ls->fs; + Proto *f = fs->f; /* prototype of current function */ + if (fs->np >= f->sizep) { + int oldsize = f->sizep; + luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions"); + while (oldsize < f->sizep) + f->p[oldsize++] = NULL; + } + f->p[fs->np++] = clp = luaF_newproto(L); + luaC_objbarrier(L, f, clp); + return clp; +} + + +/* +** codes instruction to create new closure in parent function. +** The OP_CLOSURE instruction uses the last available register, +** so that, if it invokes the GC, the GC knows which registers +** are in use at that time. + +*/ +static void codeclosure (LexState *ls, expdesc *v) { + FuncState *fs = ls->fs->prev; + init_exp(v, VRELOC, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); + luaK_exp2nextreg(fs, v); /* fix it at the last register */ +} + + +static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { + Proto *f = fs->f; + fs->prev = ls->fs; /* linked list of funcstates */ + fs->ls = ls; + ls->fs = fs; + fs->pc = 0; + fs->previousline = f->linedefined; + fs->iwthabs = 0; + fs->lasttarget = 0; + fs->freereg = 0; + fs->nk = 0; + fs->nabslineinfo = 0; + fs->np = 0; + fs->nups = 0; + fs->ndebugvars = 0; + fs->nactvar = 0; + fs->needclose = 0; + fs->firstlocal = ls->dyd->actvar.n; + fs->firstlabel = ls->dyd->label.n; + fs->bl = NULL; + f->source = ls->source; + luaC_objbarrier(ls->L, f, f->source); + f->maxstacksize = 2; /* registers 0/1 are always valid */ + enterblock(fs, bl, 0); +} + + +static void close_func (LexState *ls) { + lua_State *L = ls->L; + FuncState *fs = ls->fs; + Proto *f = fs->f; + luaK_ret(fs, luaY_nvarstack(fs), 0); /* final return */ + leaveblock(fs); + lua_assert(fs->bl == NULL); + luaK_finish(fs); + luaM_shrinkvector(L, f->code, f->sizecode, fs->pc, Instruction); + luaM_shrinkvector(L, f->lineinfo, f->sizelineinfo, fs->pc, ls_byte); + luaM_shrinkvector(L, f->abslineinfo, f->sizeabslineinfo, + fs->nabslineinfo, AbsLineInfo); + luaM_shrinkvector(L, f->k, f->sizek, fs->nk, TValue); + luaM_shrinkvector(L, f->p, f->sizep, fs->np, Proto *); + luaM_shrinkvector(L, f->locvars, f->sizelocvars, fs->ndebugvars, LocVar); + luaM_shrinkvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); + ls->fs = fs->prev; + luaC_checkGC(L); +} + + + +/*============================================================*/ +/* GRAMMAR RULES */ +/*============================================================*/ + + +/* +** check whether current token is in the follow set of a block. +** 'until' closes syntactical blocks, but do not close scope, +** so it is handled in separate. +*/ +static int block_follow (LexState *ls, int withuntil) { + switch (ls->t.token) { + case TK_ELSE: case TK_ELSEIF: + case TK_END: case TK_EOS: + return 1; + case TK_UNTIL: return withuntil; + default: return 0; + } +} + + +static void statlist (LexState *ls) { + /* statlist -> { stat [';'] } */ + while (!block_follow(ls, 1)) { + if (ls->t.token == TK_RETURN) { + statement(ls); + return; /* 'return' must be last statement */ + } + statement(ls); + } +} + + +static void fieldsel (LexState *ls, expdesc *v) { + /* fieldsel -> ['.' | ':'] NAME */ + FuncState *fs = ls->fs; + expdesc key; + luaK_exp2anyregup(fs, v); + luaX_next(ls); /* skip the dot or colon */ + codename(ls, &key); + luaK_indexed(fs, v, &key); +} + + +static void yindex (LexState *ls, expdesc *v) { + /* index -> '[' expr ']' */ + luaX_next(ls); /* skip the '[' */ + expr(ls, v); + luaK_exp2val(ls->fs, v); + checknext(ls, ']'); +} + + +/* +** {====================================================================== +** Rules for Constructors +** ======================================================================= +*/ + + +typedef struct ConsControl { + expdesc v; /* last list item read */ + expdesc *t; /* table descriptor */ + int nh; /* total number of 'record' elements */ + int na; /* number of array elements already stored */ + int tostore; /* number of array elements pending to be stored */ +} ConsControl; + + +static void recfield (LexState *ls, ConsControl *cc) { + /* recfield -> (NAME | '['exp']') = exp */ + FuncState *fs = ls->fs; + int reg = ls->fs->freereg; + expdesc tab, key, val; + if (ls->t.token == TK_NAME) { + checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); + codename(ls, &key); + } + else /* ls->t.token == '[' */ + yindex(ls, &key); + cc->nh++; + checknext(ls, '='); + tab = *cc->t; + luaK_indexed(fs, &tab, &key); + expr(ls, &val); + luaK_storevar(fs, &tab, &val); + fs->freereg = reg; /* free registers */ +} + + +static void closelistfield (FuncState *fs, ConsControl *cc) { + if (cc->v.k == VVOID) return; /* there is no list item */ + luaK_exp2nextreg(fs, &cc->v); + cc->v.k = VVOID; + if (cc->tostore == LFIELDS_PER_FLUSH) { + luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ + cc->na += cc->tostore; + cc->tostore = 0; /* no more items pending */ + } +} + + +static void lastlistfield (FuncState *fs, ConsControl *cc) { + if (cc->tostore == 0) return; + if (hasmultret(cc->v.k)) { + luaK_setmultret(fs, &cc->v); + luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET); + cc->na--; /* do not count last expression (unknown number of elements) */ + } + else { + if (cc->v.k != VVOID) + luaK_exp2nextreg(fs, &cc->v); + luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); + } + cc->na += cc->tostore; +} + + +static void listfield (LexState *ls, ConsControl *cc) { + /* listfield -> exp */ + expr(ls, &cc->v); + cc->tostore++; +} + + +static void field (LexState *ls, ConsControl *cc) { + /* field -> listfield | recfield */ + switch(ls->t.token) { + case TK_NAME: { /* may be 'listfield' or 'recfield' */ + if (luaX_lookahead(ls) != '=') /* expression? */ + listfield(ls, cc); + else + recfield(ls, cc); + break; + } + case '[': { + recfield(ls, cc); + break; + } + default: { + listfield(ls, cc); + break; + } + } +} + + +static void constructor (LexState *ls, expdesc *t) { + /* constructor -> '{' [ field { sep field } [sep] ] '}' + sep -> ',' | ';' */ + FuncState *fs = ls->fs; + int line = ls->linenumber; + int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); + ConsControl cc; + luaK_code(fs, 0); /* space for extra arg. */ + cc.na = cc.nh = cc.tostore = 0; + cc.t = t; + init_exp(t, VNONRELOC, fs->freereg); /* table will be at stack top */ + luaK_reserveregs(fs, 1); + init_exp(&cc.v, VVOID, 0); /* no value (yet) */ + checknext(ls, '{'); + do { + lua_assert(cc.v.k == VVOID || cc.tostore > 0); + if (ls->t.token == '}') break; + closelistfield(fs, &cc); + field(ls, &cc); + } while (testnext(ls, ',') || testnext(ls, ';')); + check_match(ls, '}', '{', line); + lastlistfield(fs, &cc); + luaK_settablesize(fs, pc, t->u.info, cc.na, cc.nh); +} + +/* }====================================================================== */ + + +static void setvararg (FuncState *fs, int nparams) { + fs->f->is_vararg = 1; + luaK_codeABC(fs, OP_VARARGPREP, nparams, 0, 0); +} + + +static void parlist (LexState *ls) { + /* parlist -> [ {NAME ','} (NAME | '...') ] */ + FuncState *fs = ls->fs; + Proto *f = fs->f; + int nparams = 0; + int isvararg = 0; + if (ls->t.token != ')') { /* is 'parlist' not empty? */ + do { + switch (ls->t.token) { + case TK_NAME: { + new_localvar(ls, str_checkname(ls)); + nparams++; + break; + } + case TK_DOTS: { + luaX_next(ls); + isvararg = 1; + break; + } + default: luaX_syntaxerror(ls, "<name> or '...' expected"); + } + } while (!isvararg && testnext(ls, ',')); + } + adjustlocalvars(ls, nparams); + f->numparams = cast_byte(fs->nactvar); + if (isvararg) + setvararg(fs, f->numparams); /* declared vararg */ + luaK_reserveregs(fs, fs->nactvar); /* reserve registers for parameters */ +} + + +static void body (LexState *ls, expdesc *e, int ismethod, int line) { + /* body -> '(' parlist ')' block END */ + FuncState new_fs; + BlockCnt bl; + new_fs.f = addprototype(ls); + new_fs.f->linedefined = line; + open_func(ls, &new_fs, &bl); + checknext(ls, '('); + if (ismethod) { + new_localvarliteral(ls, "self"); /* create 'self' parameter */ + adjustlocalvars(ls, 1); + } + parlist(ls); + checknext(ls, ')'); + statlist(ls); + new_fs.f->lastlinedefined = ls->linenumber; + check_match(ls, TK_END, TK_FUNCTION, line); + codeclosure(ls, e); + close_func(ls); +} + + +static int explist (LexState *ls, expdesc *v) { + /* explist -> expr { ',' expr } */ + int n = 1; /* at least one expression */ + expr(ls, v); + while (testnext(ls, ',')) { + luaK_exp2nextreg(ls->fs, v); + expr(ls, v); + n++; + } + return n; +} + + +static void funcargs (LexState *ls, expdesc *f, int line) { + FuncState *fs = ls->fs; + expdesc args; + int base, nparams; + switch (ls->t.token) { + case '(': { /* funcargs -> '(' [ explist ] ')' */ + luaX_next(ls); + if (ls->t.token == ')') /* arg list is empty? */ + args.k = VVOID; + else { + explist(ls, &args); + if (hasmultret(args.k)) + luaK_setmultret(fs, &args); + } + check_match(ls, ')', '(', line); + break; + } + case '{': { /* funcargs -> constructor */ + constructor(ls, &args); + break; + } + case TK_STRING: { /* funcargs -> STRING */ + codestring(&args, ls->t.seminfo.ts); + luaX_next(ls); /* must use 'seminfo' before 'next' */ + break; + } + default: { + luaX_syntaxerror(ls, "function arguments expected"); + } + } + lua_assert(f->k == VNONRELOC); + base = f->u.info; /* base register for call */ + if (hasmultret(args.k)) + nparams = LUA_MULTRET; /* open call */ + else { + if (args.k != VVOID) + luaK_exp2nextreg(fs, &args); /* close last argument */ + nparams = fs->freereg - (base+1); + } + init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); + luaK_fixline(fs, line); + fs->freereg = base+1; /* call remove function and arguments and leaves + (unless changed) one result */ +} + + + + +/* +** {====================================================================== +** Expression parsing +** ======================================================================= +*/ + + +static void primaryexp (LexState *ls, expdesc *v) { + /* primaryexp -> NAME | '(' expr ')' */ + switch (ls->t.token) { + case '(': { + int line = ls->linenumber; + luaX_next(ls); + expr(ls, v); + check_match(ls, ')', '(', line); + luaK_dischargevars(ls->fs, v); + return; + } + case TK_NAME: { + singlevar(ls, v); + return; + } + default: { + luaX_syntaxerror(ls, "unexpected symbol"); + } + } +} + + +static void suffixedexp (LexState *ls, expdesc *v) { + /* suffixedexp -> + primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ + FuncState *fs = ls->fs; + int line = ls->linenumber; + primaryexp(ls, v); + for (;;) { + switch (ls->t.token) { + case '.': { /* fieldsel */ + fieldsel(ls, v); + break; + } + case '[': { /* '[' exp ']' */ + expdesc key; + luaK_exp2anyregup(fs, v); + yindex(ls, &key); + luaK_indexed(fs, v, &key); + break; + } + case ':': { /* ':' NAME funcargs */ + expdesc key; + luaX_next(ls); + codename(ls, &key); + luaK_self(fs, v, &key); + funcargs(ls, v, line); + break; + } + case '(': case TK_STRING: case '{': { /* funcargs */ + luaK_exp2nextreg(fs, v); + funcargs(ls, v, line); + break; + } + default: return; + } + } +} + + +static void simpleexp (LexState *ls, expdesc *v) { + /* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... | + constructor | FUNCTION body | suffixedexp */ + switch (ls->t.token) { + case TK_FLT: { + init_exp(v, VKFLT, 0); + v->u.nval = ls->t.seminfo.r; + break; + } + case TK_INT: { + init_exp(v, VKINT, 0); + v->u.ival = ls->t.seminfo.i; + break; + } + case TK_STRING: { + codestring(v, ls->t.seminfo.ts); + break; + } + case TK_NIL: { + init_exp(v, VNIL, 0); + break; + } + case TK_TRUE: { + init_exp(v, VTRUE, 0); + break; + } + case TK_FALSE: { + init_exp(v, VFALSE, 0); + break; + } + case TK_DOTS: { /* vararg */ + FuncState *fs = ls->fs; + check_condition(ls, fs->f->is_vararg, + "cannot use '...' outside a vararg function"); + init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 0, 1)); + break; + } + case '{': { /* constructor */ + constructor(ls, v); + return; + } + case TK_FUNCTION: { + luaX_next(ls); + body(ls, v, 0, ls->linenumber); + return; + } + default: { + suffixedexp(ls, v); + return; + } + } + luaX_next(ls); +} + + +static UnOpr getunopr (int op) { + switch (op) { + case TK_NOT: return OPR_NOT; + case '-': return OPR_MINUS; + case '~': return OPR_BNOT; + case '#': return OPR_LEN; + default: return OPR_NOUNOPR; + } +} + + +static BinOpr getbinopr (int op) { + switch (op) { + case '+': return OPR_ADD; + case '-': return OPR_SUB; + case '*': return OPR_MUL; + case '%': return OPR_MOD; + case '^': return OPR_POW; + case '/': return OPR_DIV; + case TK_IDIV: return OPR_IDIV; + case '&': return OPR_BAND; + case '|': return OPR_BOR; + case '~': return OPR_BXOR; + case TK_SHL: return OPR_SHL; + case TK_SHR: return OPR_SHR; + case TK_CONCAT: return OPR_CONCAT; + case TK_NE: return OPR_NE; + case TK_EQ: return OPR_EQ; + case '<': return OPR_LT; + case TK_LE: return OPR_LE; + case '>': return OPR_GT; + case TK_GE: return OPR_GE; + case TK_AND: return OPR_AND; + case TK_OR: return OPR_OR; + default: return OPR_NOBINOPR; + } +} + + +/* +** Priority table for binary operators. +*/ +static const struct { + lu_byte left; /* left priority for each binary operator */ + lu_byte right; /* right priority */ +} priority[] = { /* ORDER OPR */ + {10, 10}, {10, 10}, /* '+' '-' */ + {11, 11}, {11, 11}, /* '*' '%' */ + {14, 13}, /* '^' (right associative) */ + {11, 11}, {11, 11}, /* '/' '//' */ + {6, 6}, {4, 4}, {5, 5}, /* '&' '|' '~' */ + {7, 7}, {7, 7}, /* '<<' '>>' */ + {9, 8}, /* '..' (right associative) */ + {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ + {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ + {2, 2}, {1, 1} /* and, or */ +}; + +#define UNARY_PRIORITY 12 /* priority for unary operators */ + + +/* +** subexpr -> (simpleexp | unop subexpr) { binop subexpr } +** where 'binop' is any binary operator with a priority higher than 'limit' +*/ +static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { + BinOpr op; + UnOpr uop; + enterlevel(ls); + uop = getunopr(ls->t.token); + if (uop != OPR_NOUNOPR) { /* prefix (unary) operator? */ + int line = ls->linenumber; + luaX_next(ls); /* skip operator */ + subexpr(ls, v, UNARY_PRIORITY); + luaK_prefix(ls->fs, uop, v, line); + } + else simpleexp(ls, v); + /* expand while operators have priorities higher than 'limit' */ + op = getbinopr(ls->t.token); + while (op != OPR_NOBINOPR && priority[op].left > limit) { + expdesc v2; + BinOpr nextop; + int line = ls->linenumber; + luaX_next(ls); /* skip operator */ + luaK_infix(ls->fs, op, v); + /* read sub-expression with higher priority */ + nextop = subexpr(ls, &v2, priority[op].right); + luaK_posfix(ls->fs, op, v, &v2, line); + op = nextop; + } + leavelevel(ls); + return op; /* return first untreated operator */ +} + + +static void expr (LexState *ls, expdesc *v) { + subexpr(ls, v, 0); +} + +/* }==================================================================== */ + + + +/* +** {====================================================================== +** Rules for Statements +** ======================================================================= +*/ + + +static void block (LexState *ls) { + /* block -> statlist */ + FuncState *fs = ls->fs; + BlockCnt bl; + enterblock(fs, &bl, 0); + statlist(ls); + leaveblock(fs); +} + + +/* +** structure to chain all variables in the left-hand side of an +** assignment +*/ +struct LHS_assign { + struct LHS_assign *prev; + expdesc v; /* variable (global, local, upvalue, or indexed) */ +}; + + +/* +** check whether, in an assignment to an upvalue/local variable, the +** upvalue/local variable is begin used in a previous assignment to a +** table. If so, save original upvalue/local value in a safe place and +** use this safe copy in the previous assignment. +*/ +static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { + FuncState *fs = ls->fs; + int extra = fs->freereg; /* eventual position to save local variable */ + int conflict = 0; + for (; lh; lh = lh->prev) { /* check all previous assignments */ + if (vkisindexed(lh->v.k)) { /* assignment to table field? */ + if (lh->v.k == VINDEXUP) { /* is table an upvalue? */ + if (v->k == VUPVAL && lh->v.u.ind.t == v->u.info) { + conflict = 1; /* table is the upvalue being assigned now */ + lh->v.k = VINDEXSTR; + lh->v.u.ind.t = extra; /* assignment will use safe copy */ + } + } + else { /* table is a register */ + if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.ridx) { + conflict = 1; /* table is the local being assigned now */ + lh->v.u.ind.t = extra; /* assignment will use safe copy */ + } + /* is index the local being assigned? */ + if (lh->v.k == VINDEXED && v->k == VLOCAL && + lh->v.u.ind.idx == v->u.var.ridx) { + conflict = 1; + lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ + } + } + } + } + if (conflict) { + /* copy upvalue/local value to a temporary (in position 'extra') */ + if (v->k == VLOCAL) + luaK_codeABC(fs, OP_MOVE, extra, v->u.var.ridx, 0); + else + luaK_codeABC(fs, OP_GETUPVAL, extra, v->u.info, 0); + luaK_reserveregs(fs, 1); + } +} + +/* +** Parse and compile a multiple assignment. The first "variable" +** (a 'suffixedexp') was already read by the caller. +** +** assignment -> suffixedexp restassign +** restassign -> ',' suffixedexp restassign | '=' explist +*/ +static void restassign (LexState *ls, struct LHS_assign *lh, int nvars) { + expdesc e; + check_condition(ls, vkisvar(lh->v.k), "syntax error"); + check_readonly(ls, &lh->v); + if (testnext(ls, ',')) { /* restassign -> ',' suffixedexp restassign */ + struct LHS_assign nv; + nv.prev = lh; + suffixedexp(ls, &nv.v); + if (!vkisindexed(nv.v.k)) + check_conflict(ls, lh, &nv.v); + enterlevel(ls); /* control recursion depth */ + restassign(ls, &nv, nvars+1); + leavelevel(ls); + } + else { /* restassign -> '=' explist */ + int nexps; + checknext(ls, '='); + nexps = explist(ls, &e); + if (nexps != nvars) + adjust_assign(ls, nvars, nexps, &e); + else { + luaK_setoneret(ls->fs, &e); /* close last expression */ + luaK_storevar(ls->fs, &lh->v, &e); + return; /* avoid default */ + } + } + init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ + luaK_storevar(ls->fs, &lh->v, &e); +} + + +static int cond (LexState *ls) { + /* cond -> exp */ + expdesc v; + expr(ls, &v); /* read condition */ + if (v.k == VNIL) v.k = VFALSE; /* 'falses' are all equal here */ + luaK_goiftrue(ls->fs, &v); + return v.f; +} + + +static void gotostat (LexState *ls) { + FuncState *fs = ls->fs; + int line = ls->linenumber; + TString *name = str_checkname(ls); /* label's name */ + Labeldesc *lb = findlabel(ls, name); + if (lb == NULL) /* no label? */ + /* forward jump; will be resolved when the label is declared */ + newgotoentry(ls, name, line, luaK_jump(fs)); + else { /* found a label */ + /* backward jump; will be resolved here */ + int lblevel = reglevel(fs, lb->nactvar); /* label level */ + if (luaY_nvarstack(fs) > lblevel) /* leaving the scope of a variable? */ + luaK_codeABC(fs, OP_CLOSE, lblevel, 0, 0); + /* create jump and link it to the label */ + luaK_patchlist(fs, luaK_jump(fs), lb->pc); + } +} + + +/* +** Break statement. Semantically equivalent to "goto break". +*/ +static void breakstat (LexState *ls) { + int line = ls->linenumber; + luaX_next(ls); /* skip break */ + newgotoentry(ls, luaS_newliteral(ls->L, "break"), line, luaK_jump(ls->fs)); +} + + +/* +** Check whether there is already a label with the given 'name'. +*/ +static void checkrepeated (LexState *ls, TString *name) { + Labeldesc *lb = findlabel(ls, name); + if (l_unlikely(lb != NULL)) { /* already defined? */ + const char *msg = "label '%s' already defined on line %d"; + msg = luaO_pushfstring(ls->L, msg, getstr(name), lb->line); + luaK_semerror(ls, msg); /* error */ + } +} + + +static void labelstat (LexState *ls, TString *name, int line) { + /* label -> '::' NAME '::' */ + checknext(ls, TK_DBCOLON); /* skip double colon */ + while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) + statement(ls); /* skip other no-op statements */ + checkrepeated(ls, name); /* check for repeated labels */ + createlabel(ls, name, line, block_follow(ls, 0)); +} + + +static void whilestat (LexState *ls, int line) { + /* whilestat -> WHILE cond DO block END */ + FuncState *fs = ls->fs; + int whileinit; + int condexit; + BlockCnt bl; + luaX_next(ls); /* skip WHILE */ + whileinit = luaK_getlabel(fs); + condexit = cond(ls); + enterblock(fs, &bl, 1); + checknext(ls, TK_DO); + block(ls); + luaK_jumpto(fs, whileinit); + check_match(ls, TK_END, TK_WHILE, line); + leaveblock(fs); + luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ +} + + +static void repeatstat (LexState *ls, int line) { + /* repeatstat -> REPEAT block UNTIL cond */ + int condexit; + FuncState *fs = ls->fs; + int repeat_init = luaK_getlabel(fs); + BlockCnt bl1, bl2; + enterblock(fs, &bl1, 1); /* loop block */ + enterblock(fs, &bl2, 0); /* scope block */ + luaX_next(ls); /* skip REPEAT */ + statlist(ls); + check_match(ls, TK_UNTIL, TK_REPEAT, line); + condexit = cond(ls); /* read condition (inside scope block) */ + leaveblock(fs); /* finish scope */ + if (bl2.upval) { /* upvalues? */ + int exit = luaK_jump(fs); /* normal exit must jump over fix */ + luaK_patchtohere(fs, condexit); /* repetition must close upvalues */ + luaK_codeABC(fs, OP_CLOSE, reglevel(fs, bl2.nactvar), 0, 0); + condexit = luaK_jump(fs); /* repeat after closing upvalues */ + luaK_patchtohere(fs, exit); /* normal exit comes to here */ + } + luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ + leaveblock(fs); /* finish loop */ +} + + +/* +** Read an expression and generate code to put its results in next +** stack slot. +** +*/ +static void exp1 (LexState *ls) { + expdesc e; + expr(ls, &e); + luaK_exp2nextreg(ls->fs, &e); + lua_assert(e.k == VNONRELOC); +} + + +/* +** Fix for instruction at position 'pc' to jump to 'dest'. +** (Jump addresses are relative in Lua). 'back' true means +** a back jump. +*/ +static void fixforjump (FuncState *fs, int pc, int dest, int back) { + Instruction *jmp = &fs->f->code[pc]; + int offset = dest - (pc + 1); + if (back) + offset = -offset; + if (l_unlikely(offset > MAXARG_Bx)) + luaX_syntaxerror(fs->ls, "control structure too long"); + SETARG_Bx(*jmp, offset); +} + + +/* +** Generate code for a 'for' loop. +*/ +static void forbody (LexState *ls, int base, int line, int nvars, int isgen) { + /* forbody -> DO block */ + static const OpCode forprep[2] = {OP_FORPREP, OP_TFORPREP}; + static const OpCode forloop[2] = {OP_FORLOOP, OP_TFORLOOP}; + BlockCnt bl; + FuncState *fs = ls->fs; + int prep, endfor; + checknext(ls, TK_DO); + prep = luaK_codeABx(fs, forprep[isgen], base, 0); + enterblock(fs, &bl, 0); /* scope for declared variables */ + adjustlocalvars(ls, nvars); + luaK_reserveregs(fs, nvars); + block(ls); + leaveblock(fs); /* end of scope for declared variables */ + fixforjump(fs, prep, luaK_getlabel(fs), 0); + if (isgen) { /* generic for? */ + luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); + luaK_fixline(fs, line); + } + endfor = luaK_codeABx(fs, forloop[isgen], base, 0); + fixforjump(fs, endfor, prep + 1, 1); + luaK_fixline(fs, line); +} + + +static void fornum (LexState *ls, TString *varname, int line) { + /* fornum -> NAME = exp,exp[,exp] forbody */ + FuncState *fs = ls->fs; + int base = fs->freereg; + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for state)"); + new_localvar(ls, varname); + checknext(ls, '='); + exp1(ls); /* initial value */ + checknext(ls, ','); + exp1(ls); /* limit */ + if (testnext(ls, ',')) + exp1(ls); /* optional step */ + else { /* default step = 1 */ + luaK_int(fs, fs->freereg, 1); + luaK_reserveregs(fs, 1); + } + adjustlocalvars(ls, 3); /* control variables */ + forbody(ls, base, line, 1, 0); +} + + +static void forlist (LexState *ls, TString *indexname) { + /* forlist -> NAME {,NAME} IN explist forbody */ + FuncState *fs = ls->fs; + expdesc e; + int nvars = 5; /* gen, state, control, toclose, 'indexname' */ + int line; + int base = fs->freereg; + /* create control variables */ + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for state)"); + /* create declared variables */ + new_localvar(ls, indexname); + while (testnext(ls, ',')) { + new_localvar(ls, str_checkname(ls)); + nvars++; + } + checknext(ls, TK_IN); + line = ls->linenumber; + adjust_assign(ls, 4, explist(ls, &e), &e); + adjustlocalvars(ls, 4); /* control variables */ + marktobeclosed(fs); /* last control var. must be closed */ + luaK_checkstack(fs, 3); /* extra space to call generator */ + forbody(ls, base, line, nvars - 4, 1); +} + + +static void forstat (LexState *ls, int line) { + /* forstat -> FOR (fornum | forlist) END */ + FuncState *fs = ls->fs; + TString *varname; + BlockCnt bl; + enterblock(fs, &bl, 1); /* scope for loop and control variables */ + luaX_next(ls); /* skip 'for' */ + varname = str_checkname(ls); /* first variable name */ + switch (ls->t.token) { + case '=': fornum(ls, varname, line); break; + case ',': case TK_IN: forlist(ls, varname); break; + default: luaX_syntaxerror(ls, "'=' or 'in' expected"); + } + check_match(ls, TK_END, TK_FOR, line); + leaveblock(fs); /* loop scope ('break' jumps to this point) */ +} + + +static void test_then_block (LexState *ls, int *escapelist) { + /* test_then_block -> [IF | ELSEIF] cond THEN block */ + BlockCnt bl; + FuncState *fs = ls->fs; + expdesc v; + int jf; /* instruction to skip 'then' code (if condition is false) */ + luaX_next(ls); /* skip IF or ELSEIF */ + expr(ls, &v); /* read condition */ + checknext(ls, TK_THEN); + if (ls->t.token == TK_BREAK) { /* 'if x then break' ? */ + int line = ls->linenumber; + luaK_goiffalse(ls->fs, &v); /* will jump if condition is true */ + luaX_next(ls); /* skip 'break' */ + enterblock(fs, &bl, 0); /* must enter block before 'goto' */ + newgotoentry(ls, luaS_newliteral(ls->L, "break"), line, v.t); + while (testnext(ls, ';')) {} /* skip semicolons */ + if (block_follow(ls, 0)) { /* jump is the entire block? */ + leaveblock(fs); + return; /* and that is it */ + } + else /* must skip over 'then' part if condition is false */ + jf = luaK_jump(fs); + } + else { /* regular case (not a break) */ + luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */ + enterblock(fs, &bl, 0); + jf = v.f; + } + statlist(ls); /* 'then' part */ + leaveblock(fs); + if (ls->t.token == TK_ELSE || + ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ + luaK_concat(fs, escapelist, luaK_jump(fs)); /* must jump over it */ + luaK_patchtohere(fs, jf); +} + + +static void ifstat (LexState *ls, int line) { + /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ + FuncState *fs = ls->fs; + int escapelist = NO_JUMP; /* exit list for finished parts */ + test_then_block(ls, &escapelist); /* IF cond THEN block */ + while (ls->t.token == TK_ELSEIF) + test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */ + if (testnext(ls, TK_ELSE)) + block(ls); /* 'else' part */ + check_match(ls, TK_END, TK_IF, line); + luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ +} + + +static void localfunc (LexState *ls) { + expdesc b; + FuncState *fs = ls->fs; + int fvar = fs->nactvar; /* function's variable index */ + new_localvar(ls, str_checkname(ls)); /* new local variable */ + adjustlocalvars(ls, 1); /* enter its scope */ + body(ls, &b, 0, ls->linenumber); /* function created in next register */ + /* debug information will only see the variable after this point! */ + localdebuginfo(fs, fvar)->startpc = fs->pc; +} + + +static int getlocalattribute (LexState *ls) { + /* ATTRIB -> ['<' Name '>'] */ + if (testnext(ls, '<')) { + const char *attr = getstr(str_checkname(ls)); + checknext(ls, '>'); + if (strcmp(attr, "const") == 0) + return RDKCONST; /* read-only variable */ + else if (strcmp(attr, "close") == 0) + return RDKTOCLOSE; /* to-be-closed variable */ + else + luaK_semerror(ls, + luaO_pushfstring(ls->L, "unknown attribute '%s'", attr)); + } + return VDKREG; /* regular variable */ +} + + +static void checktoclose (FuncState *fs, int level) { + if (level != -1) { /* is there a to-be-closed variable? */ + marktobeclosed(fs); + luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0); + } +} + + +static void localstat (LexState *ls) { + /* stat -> LOCAL NAME ATTRIB { ',' NAME ATTRIB } ['=' explist] */ + FuncState *fs = ls->fs; + int toclose = -1; /* index of to-be-closed variable (if any) */ + Vardesc *var; /* last variable */ + int vidx, kind; /* index and kind of last variable */ + int nvars = 0; + int nexps; + expdesc e; + do { + vidx = new_localvar(ls, str_checkname(ls)); + kind = getlocalattribute(ls); + getlocalvardesc(fs, vidx)->vd.kind = kind; + if (kind == RDKTOCLOSE) { /* to-be-closed? */ + if (toclose != -1) /* one already present? */ + luaK_semerror(ls, "multiple to-be-closed variables in local list"); + toclose = fs->nactvar + nvars; + } + nvars++; + } while (testnext(ls, ',')); + if (testnext(ls, '=')) + nexps = explist(ls, &e); + else { + e.k = VVOID; + nexps = 0; + } + var = getlocalvardesc(fs, vidx); /* get last variable */ + if (nvars == nexps && /* no adjustments? */ + var->vd.kind == RDKCONST && /* last variable is const? */ + luaK_exp2const(fs, &e, &var->k)) { /* compile-time constant? */ + var->vd.kind = RDKCTC; /* variable is a compile-time constant */ + adjustlocalvars(ls, nvars - 1); /* exclude last variable */ + fs->nactvar++; /* but count it */ + } + else { + adjust_assign(ls, nvars, nexps, &e); + adjustlocalvars(ls, nvars); + } + checktoclose(fs, toclose); +} + + +static int funcname (LexState *ls, expdesc *v) { + /* funcname -> NAME {fieldsel} [':' NAME] */ + int ismethod = 0; + singlevar(ls, v); + while (ls->t.token == '.') + fieldsel(ls, v); + if (ls->t.token == ':') { + ismethod = 1; + fieldsel(ls, v); + } + return ismethod; +} + + +static void funcstat (LexState *ls, int line) { + /* funcstat -> FUNCTION funcname body */ + int ismethod; + expdesc v, b; + luaX_next(ls); /* skip FUNCTION */ + ismethod = funcname(ls, &v); + body(ls, &b, ismethod, line); + check_readonly(ls, &v); + luaK_storevar(ls->fs, &v, &b); + luaK_fixline(ls->fs, line); /* definition "happens" in the first line */ +} + + +static void exprstat (LexState *ls) { + /* stat -> func | assignment */ + FuncState *fs = ls->fs; + struct LHS_assign v; + suffixedexp(ls, &v.v); + if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */ + v.prev = NULL; + restassign(ls, &v, 1); + } + else { /* stat -> func */ + Instruction *inst; + check_condition(ls, v.v.k == VCALL, "syntax error"); + inst = &getinstruction(fs, &v.v); + SETARG_C(*inst, 1); /* call statement uses no results */ + } +} + + +static void retstat (LexState *ls) { + /* stat -> RETURN [explist] [';'] */ + FuncState *fs = ls->fs; + expdesc e; + int nret; /* number of values being returned */ + int first = luaY_nvarstack(fs); /* first slot to be returned */ + if (block_follow(ls, 1) || ls->t.token == ';') + nret = 0; /* return no values */ + else { + nret = explist(ls, &e); /* optional return values */ + if (hasmultret(e.k)) { + luaK_setmultret(fs, &e); + if (e.k == VCALL && nret == 1 && !fs->bl->insidetbc) { /* tail call? */ + SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL); + lua_assert(GETARG_A(getinstruction(fs,&e)) == luaY_nvarstack(fs)); + } + nret = LUA_MULTRET; /* return all values */ + } + else { + if (nret == 1) /* only one single value? */ + first = luaK_exp2anyreg(fs, &e); /* can use original slot */ + else { /* values must go to the top of the stack */ + luaK_exp2nextreg(fs, &e); + lua_assert(nret == fs->freereg - first); + } + } + } + luaK_ret(fs, first, nret); + testnext(ls, ';'); /* skip optional semicolon */ +} + + +static void statement (LexState *ls) { + int line = ls->linenumber; /* may be needed for error messages */ + enterlevel(ls); + switch (ls->t.token) { + case ';': { /* stat -> ';' (empty statement) */ + luaX_next(ls); /* skip ';' */ + break; + } + case TK_IF: { /* stat -> ifstat */ + ifstat(ls, line); + break; + } + case TK_WHILE: { /* stat -> whilestat */ + whilestat(ls, line); + break; + } + case TK_DO: { /* stat -> DO block END */ + luaX_next(ls); /* skip DO */ + block(ls); + check_match(ls, TK_END, TK_DO, line); + break; + } + case TK_FOR: { /* stat -> forstat */ + forstat(ls, line); + break; + } + case TK_REPEAT: { /* stat -> repeatstat */ + repeatstat(ls, line); + break; + } + case TK_FUNCTION: { /* stat -> funcstat */ + funcstat(ls, line); + break; + } + case TK_LOCAL: { /* stat -> localstat */ + luaX_next(ls); /* skip LOCAL */ + if (testnext(ls, TK_FUNCTION)) /* local function? */ + localfunc(ls); + else + localstat(ls); + break; + } + case TK_DBCOLON: { /* stat -> label */ + luaX_next(ls); /* skip double colon */ + labelstat(ls, str_checkname(ls), line); + break; + } + case TK_RETURN: { /* stat -> retstat */ + luaX_next(ls); /* skip RETURN */ + retstat(ls); + break; + } + case TK_BREAK: { /* stat -> breakstat */ + breakstat(ls); + break; + } + case TK_GOTO: { /* stat -> 'goto' NAME */ + luaX_next(ls); /* skip 'goto' */ + gotostat(ls); + break; + } + default: { /* stat -> func | assignment */ + exprstat(ls); + break; + } + } + lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && + ls->fs->freereg >= luaY_nvarstack(ls->fs)); + ls->fs->freereg = luaY_nvarstack(ls->fs); /* free registers */ + leavelevel(ls); +} + +/* }====================================================================== */ + + +/* +** compiles the main function, which is a regular vararg function with an +** upvalue named LUA_ENV +*/ +static void mainfunc (LexState *ls, FuncState *fs) { + BlockCnt bl; + Upvaldesc *env; + open_func(ls, fs, &bl); + setvararg(fs, 0); /* main function is always declared vararg */ + env = allocupvalue(fs); /* ...set environment upvalue */ + env->instack = 1; + env->idx = 0; + env->kind = VDKREG; + env->name = ls->envn; + luaC_objbarrier(ls->L, fs->f, env->name); + luaX_next(ls); /* read first token */ + statlist(ls); /* parse main body */ + check(ls, TK_EOS); + close_func(ls); +} + + +LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar) { + LexState lexstate; + FuncState funcstate; + LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */ + setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */ + luaD_inctop(L); + lexstate.h = luaH_new(L); /* create table for scanner */ + sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */ + luaD_inctop(L); + funcstate.f = cl->p = luaF_newproto(L); + luaC_objbarrier(L, cl, cl->p); + funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ + luaC_objbarrier(L, funcstate.f, funcstate.f->source); + lexstate.buff = buff; + lexstate.dyd = dyd; + dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; + luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar); + mainfunc(&lexstate, &funcstate); + lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); + /* all scopes should be correctly finished */ + lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); + L->top.p--; /* remove scanner's table */ + return cl; /* closure is on the stack, too */ +} + diff --git a/src/libs/3rdparty/lua/src/lparser.h b/src/libs/3rdparty/lua/src/lparser.h new file mode 100644 index 0000000000..5e4500f181 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lparser.h @@ -0,0 +1,171 @@ +/* +** $Id: lparser.h $ +** Lua Parser +** See Copyright Notice in lua.h +*/ + +#ifndef lparser_h +#define lparser_h + +#include "llimits.h" +#include "lobject.h" +#include "lzio.h" + + +/* +** Expression and variable descriptor. +** Code generation for variables and expressions can be delayed to allow +** optimizations; An 'expdesc' structure describes a potentially-delayed +** variable/expression. It has a description of its "main" value plus a +** list of conditional jumps that can also produce its value (generated +** by short-circuit operators 'and'/'or'). +*/ + +/* kinds of variables/expressions */ +typedef enum { + VVOID, /* when 'expdesc' describes the last expression of a list, + this kind means an empty list (so, no expression) */ + VNIL, /* constant nil */ + VTRUE, /* constant true */ + VFALSE, /* constant false */ + VK, /* constant in 'k'; info = index of constant in 'k' */ + VKFLT, /* floating constant; nval = numerical float value */ + VKINT, /* integer constant; ival = numerical integer value */ + VKSTR, /* string constant; strval = TString address; + (string is fixed by the lexer) */ + VNONRELOC, /* expression has its value in a fixed register; + info = result register */ + VLOCAL, /* local variable; var.ridx = register index; + var.vidx = relative index in 'actvar.arr' */ + VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */ + VCONST, /* compile-time <const> variable; + info = absolute index in 'actvar.arr' */ + VINDEXED, /* indexed variable; + ind.t = table register; + ind.idx = key's R index */ + VINDEXUP, /* indexed upvalue; + ind.t = table upvalue; + ind.idx = key's K index */ + VINDEXI, /* indexed variable with constant integer; + ind.t = table register; + ind.idx = key's value */ + VINDEXSTR, /* indexed variable with literal string; + ind.t = table register; + ind.idx = key's K index */ + VJMP, /* expression is a test/comparison; + info = pc of corresponding jump instruction */ + VRELOC, /* 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; + + +#define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXSTR) +#define vkisindexed(k) (VINDEXED <= (k) && (k) <= VINDEXSTR) + + +typedef struct expdesc { + expkind k; + union { + lua_Integer ival; /* for VKINT */ + lua_Number nval; /* for VKFLT */ + TString *strval; /* for VKSTR */ + int info; /* for generic use */ + struct { /* for indexed variables */ + short idx; /* index (R or "long" K) */ + lu_byte t; /* table (register or upvalue) */ + } ind; + struct { /* for local variables */ + lu_byte ridx; /* register holding the variable */ + unsigned short vidx; /* compiler index (in 'actvar.arr') */ + } var; + } u; + int t; /* patch list of 'exit when true' */ + int f; /* patch list of 'exit when false' */ +} expdesc; + + +/* kinds of variables */ +#define VDKREG 0 /* regular */ +#define RDKCONST 1 /* constant */ +#define RDKTOCLOSE 2 /* to-be-closed */ +#define RDKCTC 3 /* compile-time constant */ + +/* description of an active local variable */ +typedef union Vardesc { + struct { + TValuefields; /* constant value (if it is a compile-time constant) */ + lu_byte kind; + lu_byte ridx; /* register holding the variable */ + short pidx; /* index of the variable in the Proto's 'locvars' array */ + TString *name; /* variable name */ + } vd; + TValue k; /* constant value (if any) */ +} Vardesc; + + + +/* description of pending goto statements and label statements */ +typedef struct Labeldesc { + TString *name; /* label identifier */ + int pc; /* position in code */ + int line; /* line where it appeared */ + lu_byte nactvar; /* number of active variables in that position */ + lu_byte close; /* goto that escapes upvalues */ +} Labeldesc; + + +/* list of labels or gotos */ +typedef struct Labellist { + Labeldesc *arr; /* array */ + int n; /* number of entries in use */ + int size; /* array size */ +} Labellist; + + +/* dynamic structures used by the parser */ +typedef struct Dyndata { + struct { /* list of all active local variables */ + Vardesc *arr; + int n; + int size; + } actvar; + Labellist gt; /* list of pending gotos */ + Labellist label; /* list of active labels */ +} Dyndata; + + +/* control of blocks */ +struct BlockCnt; /* defined in lparser.c */ + + +/* state needed to generate code for a given function */ +typedef struct FuncState { + Proto *f; /* current function header */ + struct FuncState *prev; /* enclosing function */ + struct LexState *ls; /* lexical state */ + struct BlockCnt *bl; /* chain of current blocks */ + int pc; /* next position to code (equivalent to 'ncode') */ + int lasttarget; /* 'label' of last 'jump label' */ + int previousline; /* last line that was saved in 'lineinfo' */ + int nk; /* number of elements in 'k' */ + int np; /* number of elements in 'p' */ + int nabslineinfo; /* number of elements in 'abslineinfo' */ + int firstlocal; /* index of first local var (in Dyndata array) */ + int firstlabel; /* index of first label (in 'dyd->label->arr') */ + short ndebugvars; /* number of elements in 'f->locvars' */ + lu_byte nactvar; /* number of active local variables */ + lu_byte nups; /* number of upvalues */ + lu_byte freereg; /* first free register */ + lu_byte iwthabs; /* instructions issued since last absolute line info */ + lu_byte needclose; /* function needs to close upvalues when returning */ +} FuncState; + + +LUAI_FUNC int luaY_nvarstack (FuncState *fs); +LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar); + + +#endif diff --git a/src/libs/3rdparty/lua/src/lprefix.h b/src/libs/3rdparty/lua/src/lprefix.h new file mode 100644 index 0000000000..484f2ad6fb --- /dev/null +++ b/src/libs/3rdparty/lua/src/lprefix.h @@ -0,0 +1,45 @@ +/* +** $Id: lprefix.h $ +** Definitions for Lua code that must come before any other header file +** See Copyright Notice in lua.h +*/ + +#ifndef lprefix_h +#define lprefix_h + + +/* +** Allows POSIX/XSI stuff +*/ +#if !defined(LUA_USE_C89) /* { */ + +#if !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE 600 +#elif _XOPEN_SOURCE == 0 +#undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ +#endif + +/* +** Allows manipulation of large files in gcc and some other compilers +*/ +#if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) +#define _LARGEFILE_SOURCE 1 +#define _FILE_OFFSET_BITS 64 +#endif + +#endif /* } */ + + +/* +** Windows stuff +*/ +#if defined(_WIN32) /* { */ + +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ +#endif + +#endif /* } */ + +#endif + diff --git a/src/libs/3rdparty/lua/src/lstate.c b/src/libs/3rdparty/lua/src/lstate.c new file mode 100644 index 0000000000..1e925e5ad4 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lstate.c @@ -0,0 +1,445 @@ +/* +** $Id: lstate.c $ +** Global State +** See Copyright Notice in lua.h +*/ + +#define lstate_c +#define LUA_CORE + +#include "lprefix.h" + + +#include <stddef.h> +#include <string.h> + +#include "lua.h" + +#include "lapi.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "llex.h" +#include "lmem.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + + +/* +** thread state + extra space +*/ +typedef struct LX { + lu_byte extra_[LUA_EXTRASPACE]; + lua_State l; +} LX; + + +/* +** Main thread combines a thread state and the global state +*/ +typedef struct LG { + LX l; + global_State g; +} LG; + + + +#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l))) + + +/* +** A macro to create a "random" seed when a state is created; +** the seed is used to randomize string hashes. +*/ +#if !defined(luai_makeseed) + +#include <time.h> + +/* +** Compute an initial seed with some level of randomness. +** Rely on Address Space Layout Randomization (if present) and +** current time. +*/ +#define addbuff(b,p,e) \ + { size_t t = cast_sizet(e); \ + memcpy(b + p, &t, sizeof(t)); p += sizeof(t); } + +static unsigned int luai_makeseed (lua_State *L) { + char buff[3 * sizeof(size_t)]; + unsigned int h = cast_uint(time(NULL)); + int p = 0; + addbuff(buff, p, L); /* heap variable */ + addbuff(buff, p, &h); /* local variable */ + addbuff(buff, p, &lua_newstate); /* public function */ + lua_assert(p == sizeof(buff)); + return luaS_hash(buff, p, h); +} + +#endif + + +/* +** set GCdebt to a new value keeping the value (totalbytes + GCdebt) +** invariant (and avoiding underflows in 'totalbytes') +*/ +void luaE_setdebt (global_State *g, l_mem debt) { + 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; +} + + +LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) { + UNUSED(L); UNUSED(limit); + return LUAI_MAXCCALLS; /* warning?? */ +} + + +CallInfo *luaE_extendCI (lua_State *L) { + CallInfo *ci; + lua_assert(L->ci->next == NULL); + ci = luaM_new(L, CallInfo); + lua_assert(L->ci->next == NULL); + L->ci->next = ci; + ci->previous = L->ci; + ci->next = NULL; + ci->u.l.trap = 0; + L->nci++; + return ci; +} + + +/* +** free all CallInfo structures not in use by a thread +*/ +void luaE_freeCI (lua_State *L) { + CallInfo *ci = L->ci; + CallInfo *next = ci->next; + ci->next = NULL; + while ((ci = next) != NULL) { + next = ci->next; + luaM_free(L, ci); + L->nci--; + } +} + + +/* +** free half of the CallInfo structures not in use by a thread, +** keeping the first one. +*/ +void luaE_shrinkCI (lua_State *L) { + CallInfo *ci = L->ci->next; /* first free CallInfo */ + CallInfo *next; + if (ci == NULL) + return; /* no extra elements */ + while ((next = ci->next) != NULL) { /* two extra elements? */ + CallInfo *next2 = next->next; /* next's next */ + ci->next = next2; /* remove next from the list */ + L->nci--; + luaM_free(L, next); /* free next */ + if (next2 == NULL) + break; /* no more elements */ + else { + next2->previous = ci; + ci = next2; /* continue */ + } + } +} + + +/* +** Called when 'getCcalls(L)' larger or equal to LUAI_MAXCCALLS. +** If equal, raises an overflow error. If value is larger than +** LUAI_MAXCCALLS (which means it is handling an overflow) but +** not much larger, does not report an error (to allow overflow +** handling to work). +*/ +void luaE_checkcstack (lua_State *L) { + if (getCcalls(L) == LUAI_MAXCCALLS) + luaG_runerror(L, "C stack overflow"); + else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11)) + luaD_throw(L, LUA_ERRERR); /* error while handling stack error */ +} + + +LUAI_FUNC void luaE_incCstack (lua_State *L) { + L->nCcalls++; + if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) + luaE_checkcstack(L); +} + + +static void stack_init (lua_State *L1, lua_State *L) { + int i; CallInfo *ci; + /* initialize stack array */ + L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue); + L1->tbclist.p = L1->stack.p; + for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++) + setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */ + L1->top.p = L1->stack.p; + L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE; + /* initialize first ci */ + ci = &L1->base_ci; + ci->next = ci->previous = NULL; + ci->callstatus = CIST_C; + ci->func.p = L1->top.p; + ci->u.c.k = NULL; + ci->nresults = 0; + setnilvalue(s2v(L1->top.p)); /* 'function' entry for this 'ci' */ + L1->top.p++; + ci->top.p = L1->top.p + LUA_MINSTACK; + L1->ci = ci; +} + + +static void freestack (lua_State *L) { + if (L->stack.p == NULL) + return; /* stack not completely built yet */ + L->ci = &L->base_ci; /* free the entire 'ci' list */ + luaE_freeCI(L); + lua_assert(L->nci == 0); + luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */ +} + + +/* +** Create registry table and its predefined values +*/ +static void init_registry (lua_State *L, global_State *g) { + /* create registry */ + Table *registry = luaH_new(L); + sethvalue(L, &g->l_registry, registry); + luaH_resize(L, registry, LUA_RIDX_LAST, 0); + /* registry[LUA_RIDX_MAINTHREAD] = L */ + setthvalue(L, ®istry->array[LUA_RIDX_MAINTHREAD - 1], L); + /* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */ + sethvalue(L, ®istry->array[LUA_RIDX_GLOBALS - 1], luaH_new(L)); +} + + +/* +** open parts of the state that may cause memory-allocation errors. +*/ +static void f_luaopen (lua_State *L, void *ud) { + global_State *g = G(L); + UNUSED(ud); + stack_init(L, L); /* init stack */ + init_registry(L, g); + luaS_init(L); + luaT_init(L); + luaX_init(L); + g->gcstp = 0; /* allow gc */ + setnilvalue(&g->nilvalue); /* now state is complete */ + luai_userstateopen(L); +} + + +/* +** preinitialize a thread with consistent values without allocating +** any memory (to avoid errors) +*/ +static void preinit_thread (lua_State *L, global_State *g) { + G(L) = g; + L->stack.p = NULL; + L->ci = NULL; + L->nci = 0; + L->twups = L; /* thread has no upvalues */ + L->nCcalls = 0; + L->errorJmp = NULL; + L->hook = NULL; + L->hookmask = 0; + L->basehookcount = 0; + L->allowhook = 1; + resethookcount(L); + L->openupval = NULL; + L->status = LUA_OK; + L->errfunc = 0; + L->oldpc = 0; +} + + +static void close_state (lua_State *L) { + global_State *g = G(L); + if (!completestate(g)) /* closing a partially built state? */ + luaC_freeallobjects(L); /* just collect its objects */ + else { /* closing a fully built state */ + L->ci = &L->base_ci; /* unwind CallInfo list */ + luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */ + luaC_freeallobjects(L); /* collect all objects */ + luai_userstateclose(L); + } + luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); + freestack(L); + lua_assert(gettotalbytes(g) == sizeof(LG)); + (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ +} + + +LUA_API lua_State *lua_newthread (lua_State *L) { + global_State *g = G(L); + GCObject *o; + lua_State *L1; + lua_lock(L); + luaC_checkGC(L); + /* create new thread */ + o = luaC_newobjdt(L, LUA_TTHREAD, sizeof(LX), offsetof(LX, l)); + L1 = gco2th(o); + /* anchor it on L stack */ + setthvalue2s(L, L->top.p, L1); + api_incr_top(L); + preinit_thread(L1, g); + L1->hookmask = L->hookmask; + L1->basehookcount = L->basehookcount; + L1->hook = L->hook; + resethookcount(L1); + /* initialize L1 extra space */ + memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread), + LUA_EXTRASPACE); + luai_userstatethread(L, L1); + stack_init(L1, L); /* init stack */ + lua_unlock(L); + return L1; +} + + +void luaE_freethread (lua_State *L, lua_State *L1) { + LX *l = fromstate(L1); + luaF_closeupval(L1, L1->stack.p); /* close all upvalues */ + lua_assert(L1->openupval == NULL); + luai_userstatefree(L, L1); + freestack(L1); + luaM_free(L, l); +} + + +int luaE_resetthread (lua_State *L, int status) { + CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */ + setnilvalue(s2v(L->stack.p)); /* 'function' entry for basic 'ci' */ + ci->func.p = L->stack.p; + ci->callstatus = CIST_C; + if (status == LUA_YIELD) + status = LUA_OK; + L->status = LUA_OK; /* so it can run __close metamethods */ + status = luaD_closeprotected(L, 1, status); + if (status != LUA_OK) /* errors? */ + luaD_seterrorobj(L, status, L->stack.p + 1); + else + L->top.p = L->stack.p + 1; + ci->top.p = L->top.p + LUA_MINSTACK; + luaD_reallocstack(L, cast_int(ci->top.p - L->stack.p), 0); + return status; +} + + +LUA_API int lua_closethread (lua_State *L, lua_State *from) { + int status; + lua_lock(L); + L->nCcalls = (from) ? getCcalls(from) : 0; + status = luaE_resetthread(L, L->status); + lua_unlock(L); + return status; +} + + +/* +** Deprecated! Use 'lua_closethread' instead. +*/ +LUA_API int lua_resetthread (lua_State *L) { + return lua_closethread(L, NULL); +} + + +LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { + int i; + lua_State *L; + global_State *g; + LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG))); + if (l == NULL) return NULL; + L = &l->l.l; + g = &l->g; + L->tt = LUA_VTHREAD; + g->currentwhite = bitmask(WHITE0BIT); + L->marked = luaC_white(g); + preinit_thread(L, g); + g->allgc = obj2gco(L); /* by now, only object is the main thread */ + L->next = NULL; + incnny(L); /* main thread is always non yieldable */ + g->frealloc = f; + g->ud = ud; + g->warnf = NULL; + g->ud_warn = NULL; + g->mainthread = L; + g->seed = luai_makeseed(L); + g->gcstp = GCSTPGC; /* no GC while building state */ + g->strt.size = g->strt.nuse = 0; + g->strt.hash = NULL; + setnilvalue(&g->l_registry); + g->panic = NULL; + g->gcstate = GCSpause; + g->gckind = KGC_INC; + g->gcstopem = 0; + g->gcemergency = 0; + g->finobj = g->tobefnz = g->fixedgc = NULL; + g->firstold1 = g->survival = g->old1 = g->reallyold = NULL; + g->finobjsur = g->finobjold1 = g->finobjrold = NULL; + g->sweepgc = NULL; + g->gray = g->grayagain = NULL; + g->weak = g->ephemeron = g->allweak = NULL; + g->twups = NULL; + g->totalbytes = sizeof(LG); + g->GCdebt = 0; + g->lastatomic = 0; + setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */ + setgcparam(g->gcpause, LUAI_GCPAUSE); + setgcparam(g->gcstepmul, LUAI_GCMUL); + g->gcstepsize = LUAI_GCSTEPSIZE; + setgcparam(g->genmajormul, LUAI_GENMAJORMUL); + g->genminormul = LUAI_GENMINORMUL; + for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; + if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { + /* memory allocation error: free partial state */ + close_state(L); + L = NULL; + } + return L; +} + + +LUA_API void lua_close (lua_State *L) { + lua_lock(L); + L = G(L)->mainthread; /* only the main thread can be closed */ + close_state(L); +} + + +void luaE_warning (lua_State *L, const char *msg, int tocont) { + lua_WarnFunction wf = G(L)->warnf; + if (wf != NULL) + wf(G(L)->ud_warn, msg, tocont); +} + + +/* +** Generate a warning from an error message +*/ +void luaE_warnerror (lua_State *L, const char *where) { + TValue *errobj = s2v(L->top.p - 1); /* error object */ + const char *msg = (ttisstring(errobj)) + ? svalue(errobj) + : "error object is not a string"; + /* produce warning "error in %s (%s)" (where, msg) */ + luaE_warning(L, "error in ", 1); + luaE_warning(L, where, 1); + luaE_warning(L, " (", 1); + luaE_warning(L, msg, 1); + luaE_warning(L, ")", 0); +} + diff --git a/src/libs/3rdparty/lua/src/lstate.h b/src/libs/3rdparty/lua/src/lstate.h new file mode 100644 index 0000000000..8bf6600e34 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lstate.h @@ -0,0 +1,409 @@ +/* +** $Id: lstate.h $ +** Global State +** See Copyright Notice in lua.h +*/ + +#ifndef lstate_h +#define lstate_h + +#include "lua.h" + + +/* Some header files included here need this definition */ +typedef struct CallInfo CallInfo; + + +#include "lobject.h" +#include "ltm.h" +#include "lzio.h" + + +/* +** Some notes about garbage-collected objects: All objects in Lua must +** be kept somehow accessible until being freed, so all objects always +** belong to one (and only one) of these lists, using field 'next' of +** the 'CommonHeader' for the link: +** +** 'allgc': all objects not marked for finalization; +** 'finobj': all objects marked for finalization; +** 'tobefnz': all objects ready to be finalized; +** 'fixedgc': all objects that are not to be collected (currently +** only small strings, such as reserved words). +** +** For the generational collector, some of these lists have marks for +** generations. Each mark points to the first element in the list for +** that particular generation; that generation goes until the next mark. +** +** 'allgc' -> 'survival': new objects; +** 'survival' -> 'old': objects that survived one collection; +** 'old1' -> 'reallyold': objects that became old in last collection; +** 'reallyold' -> NULL: objects old for more than one cycle. +** +** 'finobj' -> 'finobjsur': new objects marked for finalization; +** 'finobjsur' -> 'finobjold1': survived """"; +** 'finobjold1' -> 'finobjrold': just old """"; +** 'finobjrold' -> NULL: really old """". +** +** All lists can contain elements older than their main ages, due +** to 'luaC_checkfinalizer' and 'udata2finalize', which move +** objects between the normal lists and the "marked for finalization" +** lists. Moreover, barriers can age young objects in young lists as +** OLD0, which then become OLD1. However, a list never contains +** elements younger than their main ages. +** +** The generational collector also uses a pointer 'firstold1', which +** points to the first OLD1 object in the list. It is used to optimize +** 'markold'. (Potentially OLD1 objects can be anywhere between 'allgc' +** and 'reallyold', but often the list has no OLD1 objects or they are +** after 'old1'.) Note the difference between it and 'old1': +** 'firstold1': no OLD1 objects before this point; there can be all +** ages after it. +** 'old1': no objects younger than OLD1 after this point. +*/ + +/* +** Moreover, there is another set of lists that control gray objects. +** These lists are linked by fields 'gclist'. (All objects that +** can become gray have such a field. The field is not the same +** in all objects, but it always has this name.) Any gray object +** must belong to one of these lists, and all objects in these lists +** must be gray (with two exceptions explained below): +** +** 'gray': regular gray objects, still waiting to be visited. +** 'grayagain': objects that must be revisited at the atomic phase. +** That includes +** - black objects got in a write barrier; +** - all kinds of weak tables during propagation phase; +** - all threads. +** 'weak': tables with weak values to be cleared; +** 'ephemeron': ephemeron tables with white->white entries; +** 'allweak': tables with weak keys and/or weak values to be cleared. +** +** The exceptions to that "gray rule" are: +** - TOUCHED2 objects in generational mode stay in a gray list (because +** they must be visited again at the end of the cycle), but they are +** marked black because assignments to them must activate barriers (to +** move them back to TOUCHED1). +** - Open upvales are kept gray to avoid barriers, but they stay out +** of gray lists. (They don't even have a 'gclist' field.) +*/ + + + +/* +** About 'nCcalls': This count has two parts: the lower 16 bits counts +** the number of recursive invocations in the C stack; the higher +** 16 bits counts the number of non-yieldable calls in the stack. +** (They are together so that we can change and save both with one +** instruction.) +*/ + + +/* true if this thread does not have non-yieldable calls in the stack */ +#define yieldable(L) (((L)->nCcalls & 0xffff0000) == 0) + +/* real number of C calls */ +#define getCcalls(L) ((L)->nCcalls & 0xffff) + + +/* Increment the number of non-yieldable calls */ +#define incnny(L) ((L)->nCcalls += 0x10000) + +/* Decrement the number of non-yieldable calls */ +#define decnny(L) ((L)->nCcalls -= 0x10000) + +/* Non-yieldable call increment */ +#define nyci (0x10000 | 1) + + + + +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. This +** space is not included in 'stack_last'. It is used only to avoid stack +** checks, either because the element will be promptly popped or because +** there will be a stack check soon after the push. Function frames +** never use this extra space, so it does not need to be kept clean. +*/ +#define EXTRA_STACK 5 + + +#define BASIC_STACK_SIZE (2*LUA_MINSTACK) + +#define stacksize(th) cast_int((th)->stack_last.p - (th)->stack.p) + + +/* kinds of Garbage Collection */ +#define KGC_INC 0 /* incremental gc */ +#define KGC_GEN 1 /* generational gc */ + + +typedef struct stringtable { + TString **hash; + int nuse; /* number of elements */ + int size; +} stringtable; + + +/* +** Information about a call. +** About union 'u': +** - field 'l' is used only for Lua functions; +** - field 'c' is used only for C functions. +** About union 'u2': +** - field 'funcidx' is used only by C functions while doing a +** protected call; +** - field 'nyield' is used only while a function is "doing" an +** yield (from the yield until the next resume); +** - field 'nres' is used only while closing tbc variables when +** returning from a function; +** - field 'transferinfo' is used only during call/returnhooks, +** before the function starts or after it ends. +*/ +struct CallInfo { + StkIdRel func; /* function index in the stack */ + StkIdRel top; /* top for this function */ + struct CallInfo *previous, *next; /* dynamic call link */ + union { + struct { /* only for Lua functions */ + const Instruction *savedpc; + volatile l_signalT trap; + int nextraargs; /* # of extra arguments in vararg functions */ + } l; + struct { /* only for C functions */ + lua_KFunction k; /* continuation in case of yields */ + ptrdiff_t old_errfunc; + lua_KContext ctx; /* context info. in case of yields */ + } c; + } u; + union { + int funcidx; /* called-function index */ + int nyield; /* number of values yielded */ + int nres; /* number of values returned */ + struct { /* info about transferred values (for call/return hooks) */ + unsigned short ftransfer; /* offset of first value transferred */ + unsigned short ntransfer; /* number of values transferred */ + } transferinfo; + } u2; + short nresults; /* expected number of results from this function */ + unsigned short callstatus; +}; + + +/* +** Bits in CallInfo status +*/ +#define CIST_OAH (1<<0) /* original value of 'allowhook' */ +#define CIST_C (1<<1) /* call is running a C function */ +#define CIST_FRESH (1<<2) /* call is on a fresh "luaV_execute" frame */ +#define CIST_HOOKED (1<<3) /* call is running a debug hook */ +#define CIST_YPCALL (1<<4) /* doing a yieldable protected call */ +#define CIST_TAIL (1<<5) /* call was tail called */ +#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ +#define CIST_FIN (1<<7) /* function "called" a finalizer */ +#define CIST_TRAN (1<<8) /* 'ci' has transfer information */ +#define CIST_CLSRET (1<<9) /* function is closing tbc variables */ +/* Bits 10-12 are used for CIST_RECST (see below) */ +#define CIST_RECST 10 +#if defined(LUA_COMPAT_LT_LE) +#define CIST_LEQ (1<<13) /* using __lt for __le */ +#endif + + +/* +** Field CIST_RECST stores the "recover status", used to keep the error +** status while closing to-be-closed variables in coroutines, so that +** Lua can correctly resume after an yield from a __close method called +** because of an error. (Three bits are enough for error status.) +*/ +#define getcistrecst(ci) (((ci)->callstatus >> CIST_RECST) & 7) +#define setcistrecst(ci,st) \ + check_exp(((st) & 7) == (st), /* status must fit in three bits */ \ + ((ci)->callstatus = ((ci)->callstatus & ~(7 << CIST_RECST)) \ + | ((st) << CIST_RECST))) + + +/* active function is a Lua function */ +#define isLua(ci) (!((ci)->callstatus & CIST_C)) + +/* call is running Lua code (not a hook) */ +#define isLuacode(ci) (!((ci)->callstatus & (CIST_C | CIST_HOOKED))) + +/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */ +#define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v)) +#define getoah(st) ((st) & CIST_OAH) + + +/* +** 'global state', shared by all threads of this state +*/ +typedef struct global_State { + lua_Alloc frealloc; /* function to reallocate memory */ + void *ud; /* auxiliary data to 'frealloc' */ + l_mem totalbytes; /* number of bytes currently allocated - GCdebt */ + l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ + lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ + lu_mem lastatomic; /* see function 'genstep' in file 'lgc.c' */ + stringtable strt; /* hash table for strings */ + TValue l_registry; + TValue nilvalue; /* a nil value */ + unsigned int seed; /* randomized seed for hashes */ + lu_byte currentwhite; + lu_byte gcstate; /* state of garbage collector */ + lu_byte gckind; /* kind of GC running */ + lu_byte gcstopem; /* stops emergency collections */ + lu_byte genminormul; /* control for minor generational collections */ + lu_byte genmajormul; /* control for major generational collections */ + lu_byte gcstp; /* control whether GC is running */ + lu_byte gcemergency; /* true if this is an emergency collection */ + lu_byte gcpause; /* size of pause between successive GCs */ + lu_byte gcstepmul; /* GC "speed" */ + lu_byte gcstepsize; /* (log2 of) GC granularity */ + GCObject *allgc; /* list of all collectable objects */ + GCObject **sweepgc; /* current position of sweep in list */ + GCObject *finobj; /* list of collectable objects with finalizers */ + GCObject *gray; /* list of gray objects */ + GCObject *grayagain; /* list of objects to be traversed atomically */ + GCObject *weak; /* list of tables with weak values */ + GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ + GCObject *allweak; /* list of all-weak tables */ + GCObject *tobefnz; /* list of userdata to be GC */ + GCObject *fixedgc; /* list of objects not to be collected */ + /* fields for generational collector */ + GCObject *survival; /* start of objects that survived one GC cycle */ + GCObject *old1; /* start of old1 objects */ + GCObject *reallyold; /* objects more than one cycle old ("really old") */ + GCObject *firstold1; /* first OLD1 object in the list (if any) */ + GCObject *finobjsur; /* list of survival objects with finalizers */ + GCObject *finobjold1; /* list of old1 objects with finalizers */ + GCObject *finobjrold; /* list of really old objects with finalizers */ + struct lua_State *twups; /* list of threads with open upvalues */ + lua_CFunction panic; /* to be called in unprotected errors */ + struct lua_State *mainthread; + TString *memerrmsg; /* message for memory-allocation errors */ + TString *tmname[TM_N]; /* array with tag-method names */ + struct Table *mt[LUA_NUMTYPES]; /* metatables for basic types */ + TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ + lua_WarnFunction warnf; /* warning function */ + void *ud_warn; /* auxiliary data to 'warnf' */ +} global_State; + + +/* +** 'per thread' state +*/ +struct lua_State { + CommonHeader; + lu_byte status; + lu_byte allowhook; + unsigned short nci; /* number of items in 'ci' list */ + StkIdRel top; /* first free slot in the stack */ + global_State *l_G; + CallInfo *ci; /* call info for current function */ + StkIdRel stack_last; /* end of stack (last element + 1) */ + StkIdRel stack; /* stack base */ + UpVal *openupval; /* list of open upvalues in this stack */ + StkIdRel tbclist; /* list of to-be-closed variables */ + GCObject *gclist; + struct lua_State *twups; /* list of threads with open upvalues */ + struct lua_longjmp *errorJmp; /* current error recover point */ + CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ + volatile lua_Hook hook; + ptrdiff_t errfunc; /* current error handling function (stack index) */ + l_uint32 nCcalls; /* number of nested (non-yieldable | C) calls */ + int oldpc; /* last pc traced */ + int basehookcount; + int hookcount; + volatile l_signalT hookmask; +}; + + +#define G(L) (L->l_G) + +/* +** 'g->nilvalue' being a nil value flags that the state was completely +** build. +*/ +#define completestate(g) ttisnil(&g->nilvalue) + + +/* +** Union of all collectable objects (only for conversions) +** ISO C99, 6.5.2.3 p.5: +** "if a union contains several structures that share a common initial +** sequence [...], and if the union object currently contains one +** of these structures, it is permitted to inspect the common initial +** part of any of them anywhere that a declaration of the complete type +** of the union is visible." +*/ +union GCUnion { + GCObject gc; /* common header */ + struct TString ts; + struct Udata u; + union Closure cl; + struct Table h; + struct Proto p; + struct lua_State th; /* thread */ + struct UpVal upv; +}; + + +/* +** ISO C99, 6.7.2.1 p.14: +** "A pointer to a union object, suitably converted, points to each of +** its members [...], and vice versa." +*/ +#define cast_u(o) cast(union GCUnion *, (o)) + +/* macros to convert a GCObject into a specific value */ +#define gco2ts(o) \ + check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts)) +#define gco2u(o) check_exp((o)->tt == LUA_VUSERDATA, &((cast_u(o))->u)) +#define gco2lcl(o) check_exp((o)->tt == LUA_VLCL, &((cast_u(o))->cl.l)) +#define gco2ccl(o) check_exp((o)->tt == LUA_VCCL, &((cast_u(o))->cl.c)) +#define gco2cl(o) \ + check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl)) +#define gco2t(o) check_exp((o)->tt == LUA_VTABLE, &((cast_u(o))->h)) +#define gco2p(o) check_exp((o)->tt == LUA_VPROTO, &((cast_u(o))->p)) +#define gco2th(o) check_exp((o)->tt == LUA_VTHREAD, &((cast_u(o))->th)) +#define gco2upv(o) check_exp((o)->tt == LUA_VUPVAL, &((cast_u(o))->upv)) + + +/* +** macro to convert a Lua object into a GCObject +** (The access to 'tt' tries to ensure that 'v' is actually a Lua object.) +*/ +#define obj2gco(v) check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc)) + + +/* actual number of total bytes allocated */ +#define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt) + +LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); +LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); +LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); +LUAI_FUNC void luaE_freeCI (lua_State *L); +LUAI_FUNC void luaE_shrinkCI (lua_State *L); +LUAI_FUNC void luaE_checkcstack (lua_State *L); +LUAI_FUNC void luaE_incCstack (lua_State *L); +LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont); +LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where); +LUAI_FUNC int luaE_resetthread (lua_State *L, int status); + + +#endif + diff --git a/src/libs/3rdparty/lua/src/lstring.c b/src/libs/3rdparty/lua/src/lstring.c new file mode 100644 index 0000000000..13dcaf4259 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lstring.c @@ -0,0 +1,273 @@ +/* +** $Id: lstring.c $ +** String table (keeps all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + +#define lstring_c +#define LUA_CORE + +#include "lprefix.h" + + +#include <string.h> + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" + + +/* +** Maximum size for string table. +*/ +#define MAXSTRTB cast_int(luaM_limitN(MAX_INT, TString*)) + + +/* +** equality for long strings +*/ +int luaS_eqlngstr (TString *a, TString *b) { + size_t len = a->u.lnglen; + lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR); + return (a == b) || /* same instance or... */ + ((len == b->u.lnglen) && /* equal length and ... */ + (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ +} + + +unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { + unsigned int h = seed ^ cast_uint(l); + for (; l > 0; l--) + h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1])); + return h; +} + + +unsigned int luaS_hashlongstr (TString *ts) { + lua_assert(ts->tt == LUA_VLNGSTR); + if (ts->extra == 0) { /* no hash? */ + size_t len = ts->u.lnglen; + ts->hash = luaS_hash(getstr(ts), len, ts->hash); + ts->extra = 1; /* now it has its hash */ + } + return ts->hash; +} + + +static void tablerehash (TString **vect, int osize, int nsize) { + int i; + for (i = osize; i < nsize; i++) /* clear new elements */ + vect[i] = NULL; + for (i = 0; i < osize; i++) { /* rehash old part of the array */ + TString *p = vect[i]; + vect[i] = NULL; + while (p) { /* for each string in the list */ + TString *hnext = p->u.hnext; /* save next */ + unsigned int h = lmod(p->hash, nsize); /* new position */ + p->u.hnext = vect[h]; /* chain it into array */ + vect[h] = p; + p = hnext; + } + } +} + + +/* +** Resize the string table. If allocation fails, keep the current size. +** (This can degrade performance, but any non-zero size should work +** correctly.) +*/ +void luaS_resize (lua_State *L, int nsize) { + stringtable *tb = &G(L)->strt; + int osize = tb->size; + TString **newvect; + if (nsize < osize) /* shrinking table? */ + tablerehash(tb->hash, osize, nsize); /* depopulate shrinking part */ + newvect = luaM_reallocvector(L, tb->hash, osize, nsize, TString*); + if (l_unlikely(newvect == NULL)) { /* reallocation failed? */ + if (nsize < osize) /* was it shrinking table? */ + tablerehash(tb->hash, nsize, osize); /* restore to original size */ + /* leave table as it was */ + } + else { /* allocation succeeded */ + tb->hash = newvect; + tb->size = nsize; + if (nsize > osize) + tablerehash(newvect, osize, nsize); /* rehash for new size */ + } +} + + +/* +** 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; + stringtable *tb = &G(L)->strt; + tb->hash = luaM_newvector(L, MINSTRTABSIZE, TString*); + tablerehash(tb->hash, 0, MINSTRTABSIZE); /* clear array */ + tb->size = MINSTRTABSIZE; + /* pre-create memory-error message */ + g->memerrmsg = luaS_newliteral(L, MEMERRMSG); + luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */ + for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */ + for (j = 0; j < STRCACHE_M; j++) + g->strcache[i][j] = g->memerrmsg; +} + + + +/* +** creates a new string object +*/ +static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) { + TString *ts; + GCObject *o; + size_t totalsize; /* total size of TString object */ + totalsize = sizelstring(l); + o = luaC_newobj(L, tag, totalsize); + ts = gco2ts(o); + ts->hash = h; + ts->extra = 0; + getstr(ts)[l] = '\0'; /* ending 0 */ + return ts; +} + + +TString *luaS_createlngstrobj (lua_State *L, size_t l) { + TString *ts = createstrobj(L, l, LUA_VLNGSTR, G(L)->seed); + ts->u.lnglen = l; + return ts; +} + + +void luaS_remove (lua_State *L, TString *ts) { + stringtable *tb = &G(L)->strt; + TString **p = &tb->hash[lmod(ts->hash, tb->size)]; + while (*p != ts) /* find previous element */ + p = &(*p)->u.hnext; + *p = (*p)->u.hnext; /* remove element from its list */ + tb->nuse--; +} + + +static void growstrtab (lua_State *L, stringtable *tb) { + if (l_unlikely(tb->nuse == MAX_INT)) { /* too many strings? */ + luaC_fullgc(L, 1); /* try to free some... */ + if (tb->nuse == MAX_INT) /* still too many? */ + luaM_error(L); /* cannot even create a message... */ + } + if (tb->size <= MAXSTRTB / 2) /* can grow string table? */ + luaS_resize(L, tb->size * 2); +} + + +/* +** Checks whether short string exists and reuses it or creates a new one. +*/ +static TString *internshrstr (lua_State *L, const char *str, size_t l) { + TString *ts; + global_State *g = G(L); + stringtable *tb = &g->strt; + unsigned int h = luaS_hash(str, l, g->seed); + TString **list = &tb->hash[lmod(h, tb->size)]; + lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ + for (ts = *list; ts != NULL; ts = ts->u.hnext) { + if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { + /* found! */ + if (isdead(g, ts)) /* dead (but not collected yet)? */ + changewhite(ts); /* resurrect it */ + return ts; + } + } + /* else must create a new string */ + if (tb->nuse >= tb->size) { /* need to grow string table? */ + growstrtab(L, tb); + list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */ + } + ts = createstrobj(L, l, LUA_VSHRSTR, h); + memcpy(getstr(ts), str, l * sizeof(char)); + ts->shrlen = cast_byte(l); + ts->u.hnext = *list; + *list = ts; + tb->nuse++; + return ts; +} + + +/* +** new string (with explicit length) +*/ +TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { + if (l <= LUAI_MAXSHORTLEN) /* short string? */ + return internshrstr(L, str, l); + else { + TString *ts; + if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char))) + luaM_toobig(L); + ts = luaS_createlngstrobj(L, l); + memcpy(getstr(ts), str, l * sizeof(char)); + return ts; + } +} + + +/* +** 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) { + 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]; +} + + +Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue) { + Udata *u; + int i; + GCObject *o; + if (l_unlikely(s > MAX_SIZE - udatamemoffset(nuvalue))) + luaM_toobig(L); + o = luaC_newobj(L, LUA_VUSERDATA, sizeudata(nuvalue, s)); + u = gco2u(o); + u->len = s; + u->nuvalue = nuvalue; + u->metatable = NULL; + for (i = 0; i < nuvalue; i++) + setnilvalue(&u->uv[i].uv); + return u; +} + diff --git a/src/libs/3rdparty/lua/src/lstring.h b/src/libs/3rdparty/lua/src/lstring.h new file mode 100644 index 0000000000..450c2390d1 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lstring.h @@ -0,0 +1,57 @@ +/* +** $Id: lstring.h $ +** String table (keep all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + +#ifndef lstring_h +#define lstring_h + +#include "lgc.h" +#include "lobject.h" +#include "lstate.h" + + +/* +** Memory-allocation error message must be preallocated (it cannot +** be created after memory is exhausted) +*/ +#define MEMERRMSG "not enough memory" + + +/* +** Size of a TString: Size of the header plus space for the string +** itself (including final '\0'). +*/ +#define sizelstring(l) (offsetof(TString, contents) + ((l) + 1) * sizeof(char)) + +#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ + (sizeof(s)/sizeof(char))-1)) + + +/* +** test whether a string is a reserved word +*/ +#define isreserved(s) ((s)->tt == LUA_VSHRSTR && (s)->extra > 0) + + +/* +** equality for short strings, which are always internalized +*/ +#define eqshrstr(a,b) check_exp((a)->tt == LUA_VSHRSTR, (a) == (b)) + + +LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); +LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts); +LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); +LUAI_FUNC void luaS_resize (lua_State *L, int newsize); +LUAI_FUNC void luaS_clearcache (global_State *g); +LUAI_FUNC void luaS_init (lua_State *L); +LUAI_FUNC void luaS_remove (lua_State *L, TString *ts); +LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue); +LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); +LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); +LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l); + + +#endif diff --git a/src/libs/3rdparty/lua/src/lstrlib.c b/src/libs/3rdparty/lua/src/lstrlib.c new file mode 100644 index 0000000000..03167161df --- /dev/null +++ b/src/libs/3rdparty/lua/src/lstrlib.c @@ -0,0 +1,1874 @@ +/* +** $Id: lstrlib.c $ +** Standard library for string operations and pattern-matching +** See Copyright Notice in lua.h +*/ + +#define lstrlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include <ctype.h> +#include <float.h> +#include <limits.h> +#include <locale.h> +#include <math.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** maximum number of captures that a pattern can do during +** pattern-matching. This limit is arbitrary, but must fit in +** an unsigned char. +*/ +#if !defined(LUA_MAXCAPTURES) +#define LUA_MAXCAPTURES 32 +#endif + + +/* macro to 'unsign' a character */ +#define uchar(c) ((unsigned char)(c)) + + +/* +** Some sizes are better limited to fit in 'int', but must also fit in +** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.) +*/ +#define MAX_SIZET ((size_t)(~(size_t)0)) + +#define MAXSIZE \ + (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) + + + + +static int str_len (lua_State *L) { + size_t l; + luaL_checklstring(L, 1, &l); + lua_pushinteger(L, (lua_Integer)l); + return 1; +} + + +/* +** translate a relative initial string position +** (negative means back from end): clip result to [1, inf). +** The length of any string in Lua must fit in a lua_Integer, +** so there are no overflows in the casts. +** The inverted comparison avoids a possible overflow +** computing '-pos'. +*/ +static size_t posrelatI (lua_Integer pos, size_t len) { + if (pos > 0) + return (size_t)pos; + else if (pos == 0) + return 1; + else if (pos < -(lua_Integer)len) /* inverted comparison */ + return 1; /* clip to 1 */ + else return len + (size_t)pos + 1; +} + + +/* +** Gets an optional ending string position from argument 'arg', +** with default value 'def'. +** Negative means back from end: clip result to [0, len] +*/ +static size_t getendpos (lua_State *L, int arg, lua_Integer def, + size_t len) { + lua_Integer pos = luaL_optinteger(L, arg, def); + if (pos > (lua_Integer)len) + return len; + else if (pos >= 0) + return (size_t)pos; + else if (pos < -(lua_Integer)len) + return 0; + else return len + (size_t)pos + 1; +} + + +static int str_sub (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + size_t start = posrelatI(luaL_checkinteger(L, 2), l); + size_t end = getendpos(L, 3, -1, l); + if (start <= end) + lua_pushlstring(L, s + start - 1, (end - start) + 1); + else lua_pushliteral(L, ""); + return 1; +} + + +static int str_reverse (lua_State *L) { + size_t l, i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + char *p = luaL_buffinitsize(L, &b, l); + for (i = 0; i < l; i++) + p[i] = s[l - i - 1]; + luaL_pushresultsize(&b, l); + return 1; +} + + +static int str_lower (lua_State *L) { + size_t l; + size_t i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + char *p = luaL_buffinitsize(L, &b, l); + for (i=0; i<l; i++) + p[i] = tolower(uchar(s[i])); + luaL_pushresultsize(&b, l); + return 1; +} + + +static int str_upper (lua_State *L) { + size_t l; + size_t i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + char *p = luaL_buffinitsize(L, &b, l); + for (i=0; i<l; i++) + p[i] = toupper(uchar(s[i])); + luaL_pushresultsize(&b, l); + return 1; +} + + +static int str_rep (lua_State *L) { + size_t l, lsep; + const char *s = luaL_checklstring(L, 1, &l); + lua_Integer n = luaL_checkinteger(L, 2); + const char *sep = luaL_optlstring(L, 3, "", &lsep); + if (n <= 0) + lua_pushliteral(L, ""); + else if (l_unlikely(l + lsep < l || l + lsep > MAXSIZE / n)) + return luaL_error(L, "resulting string too large"); + else { + size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; + luaL_Buffer b; + char *p = luaL_buffinitsize(L, &b, totallen); + while (n-- > 1) { /* first n-1 copies (followed by separator) */ + memcpy(p, s, l * sizeof(char)); p += l; + if (lsep > 0) { /* empty 'memcpy' is not that cheap */ + memcpy(p, sep, lsep * sizeof(char)); + p += lsep; + } + } + memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ + luaL_pushresultsize(&b, totallen); + } + return 1; +} + + +static int str_byte (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + lua_Integer pi = luaL_optinteger(L, 2, 1); + size_t posi = posrelatI(pi, l); + size_t pose = getendpos(L, 3, pi, l); + int n, i; + if (posi > pose) return 0; /* empty interval; return no values */ + if (l_unlikely(pose - posi >= (size_t)INT_MAX)) /* arithmetic overflow? */ + return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; + luaL_checkstack(L, n, "string slice too long"); + for (i=0; i<n; i++) + lua_pushinteger(L, uchar(s[posi+i-1])); + return n; +} + + +static int str_char (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int i; + luaL_Buffer b; + char *p = luaL_buffinitsize(L, &b, n); + for (i=1; i<=n; i++) { + lua_Unsigned c = (lua_Unsigned)luaL_checkinteger(L, i); + luaL_argcheck(L, c <= (lua_Unsigned)UCHAR_MAX, i, "value out of range"); + p[i - 1] = uchar(c); + } + luaL_pushresultsize(&b, n); + return 1; +} + + +/* +** Buffer to store the result of 'string.dump'. It must be initialized +** after the call to 'lua_dump', to ensure that the function is on the +** top of the stack when 'lua_dump' is called. ('luaL_buffinit' might +** push stuff.) +*/ +struct str_Writer { + int init; /* true iff buffer has been initialized */ + luaL_Buffer B; +}; + + +static int writer (lua_State *L, const void *b, size_t size, void *ud) { + struct str_Writer *state = (struct str_Writer *)ud; + if (!state->init) { + state->init = 1; + luaL_buffinit(L, &state->B); + } + luaL_addlstring(&state->B, (const char *)b, size); + return 0; +} + + +static int str_dump (lua_State *L) { + struct str_Writer state; + int strip = lua_toboolean(L, 2); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, 1); /* ensure function is on the top of the stack */ + state.init = 0; + if (l_unlikely(lua_dump(L, writer, &state, strip) != 0)) + return luaL_error(L, "unable to dump given function"); + luaL_pushresult(&state.B); + return 1; +} + + + +/* +** {====================================================== +** METAMETHODS +** ======================================================= +*/ + +#if defined(LUA_NOCVTS2N) /* { */ + +/* no coercion from strings to numbers */ + +static const luaL_Reg stringmetamethods[] = { + {"__index", NULL}, /* placeholder */ + {NULL, NULL} +}; + +#else /* }{ */ + +static int tonum (lua_State *L, int arg) { + if (lua_type(L, arg) == LUA_TNUMBER) { /* already a number? */ + lua_pushvalue(L, arg); + return 1; + } + else { /* check whether it is a numerical string */ + size_t len; + const char *s = lua_tolstring(L, arg, &len); + return (s != NULL && lua_stringtonumber(L, s) == len + 1); + } +} + + +static void trymt (lua_State *L, const char *mtname) { + lua_settop(L, 2); /* back to the original arguments */ + if (l_unlikely(lua_type(L, 2) == LUA_TSTRING || + !luaL_getmetafield(L, 2, mtname))) + luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2, + luaL_typename(L, -2), luaL_typename(L, -1)); + lua_insert(L, -3); /* put metamethod before arguments */ + lua_call(L, 2, 1); /* call metamethod */ +} + + +static int arith (lua_State *L, int op, const char *mtname) { + if (tonum(L, 1) && tonum(L, 2)) + lua_arith(L, op); /* result will be on the top */ + else + trymt(L, mtname); + return 1; +} + + +static int arith_add (lua_State *L) { + return arith(L, LUA_OPADD, "__add"); +} + +static int arith_sub (lua_State *L) { + return arith(L, LUA_OPSUB, "__sub"); +} + +static int arith_mul (lua_State *L) { + return arith(L, LUA_OPMUL, "__mul"); +} + +static int arith_mod (lua_State *L) { + return arith(L, LUA_OPMOD, "__mod"); +} + +static int arith_pow (lua_State *L) { + return arith(L, LUA_OPPOW, "__pow"); +} + +static int arith_div (lua_State *L) { + return arith(L, LUA_OPDIV, "__div"); +} + +static int arith_idiv (lua_State *L) { + return arith(L, LUA_OPIDIV, "__idiv"); +} + +static int arith_unm (lua_State *L) { + return arith(L, LUA_OPUNM, "__unm"); +} + + +static const luaL_Reg stringmetamethods[] = { + {"__add", arith_add}, + {"__sub", arith_sub}, + {"__mul", arith_mul}, + {"__mod", arith_mod}, + {"__pow", arith_pow}, + {"__div", arith_div}, + {"__idiv", arith_idiv}, + {"__unm", arith_unm}, + {"__index", NULL}, /* placeholder */ + {NULL, NULL} +}; + +#endif /* } */ + +/* }====================================================== */ + +/* +** {====================================================== +** PATTERN MATCHING +** ======================================================= +*/ + + +#define CAP_UNFINISHED (-1) +#define CAP_POSITION (-2) + + +typedef struct MatchState { + const char *src_init; /* init of source string */ + const char *src_end; /* end ('\0') of source string */ + const char *p_end; /* end ('\0') of pattern */ + lua_State *L; + int matchdepth; /* control for recursive depth (to avoid C stack overflow) */ + unsigned char level; /* total number of captures (finished or unfinished) */ + struct { + const char *init; + ptrdiff_t len; + } capture[LUA_MAXCAPTURES]; +} MatchState; + + +/* recursive function */ +static const char *match (MatchState *ms, const char *s, const char *p); + + +/* maximum recursion depth for 'match' */ +#if !defined(MAXCCALLS) +#define MAXCCALLS 200 +#endif + + +#define L_ESC '%' +#define SPECIALS "^$*+?.([%-" + + +static int check_capture (MatchState *ms, int l) { + l -= '1'; + if (l_unlikely(l < 0 || l >= ms->level || + ms->capture[l].len == CAP_UNFINISHED)) + return luaL_error(ms->L, "invalid capture index %%%d", l + 1); + return l; +} + + +static int capture_to_close (MatchState *ms) { + int level = ms->level; + for (level--; level>=0; level--) + if (ms->capture[level].len == CAP_UNFINISHED) return level; + return luaL_error(ms->L, "invalid pattern capture"); +} + + +static const char *classend (MatchState *ms, const char *p) { + switch (*p++) { + case L_ESC: { + if (l_unlikely(p == ms->p_end)) + luaL_error(ms->L, "malformed pattern (ends with '%%')"); + return p+1; + } + case '[': { + if (*p == '^') p++; + do { /* look for a ']' */ + if (l_unlikely(p == ms->p_end)) + luaL_error(ms->L, "malformed pattern (missing ']')"); + if (*(p++) == L_ESC && p < ms->p_end) + p++; /* skip escapes (e.g. '%]') */ + } while (*p != ']'); + return p+1; + } + default: { + return p; + } + } +} + + +static int match_class (int c, int cl) { + int res; + switch (tolower(cl)) { + case 'a' : res = isalpha(c); break; + case 'c' : res = iscntrl(c); break; + case 'd' : res = isdigit(c); break; + case 'g' : res = isgraph(c); break; + case 'l' : res = islower(c); break; + case 'p' : res = ispunct(c); break; + case 's' : res = isspace(c); break; + case 'u' : res = isupper(c); break; + case 'w' : res = isalnum(c); break; + case 'x' : res = isxdigit(c); break; + case 'z' : res = (c == 0); break; /* deprecated option */ + default: return (cl == c); + } + return (islower(cl) ? res : !res); +} + + +static int matchbracketclass (int c, const char *p, const char *ec) { + int sig = 1; + if (*(p+1) == '^') { + sig = 0; + p++; /* skip the '^' */ + } + while (++p < ec) { + if (*p == L_ESC) { + p++; + if (match_class(c, uchar(*p))) + return sig; + } + else if ((*(p+1) == '-') && (p+2 < ec)) { + p+=2; + if (uchar(*(p-2)) <= c && c <= uchar(*p)) + return sig; + } + else if (uchar(*p) == c) return sig; + } + return !sig; +} + + +static int singlematch (MatchState *ms, const char *s, const char *p, + const char *ep) { + if (s >= ms->src_end) + return 0; + else { + int c = uchar(*s); + switch (*p) { + case '.': return 1; /* matches any char */ + case L_ESC: return match_class(c, uchar(*(p+1))); + case '[': return matchbracketclass(c, p, ep-1); + default: return (uchar(*p) == c); + } + } +} + + +static const char *matchbalance (MatchState *ms, const char *s, + const char *p) { + if (l_unlikely(p >= ms->p_end - 1)) + luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); + if (*s != *p) return NULL; + else { + int b = *p; + int e = *(p+1); + int cont = 1; + while (++s < ms->src_end) { + if (*s == e) { + if (--cont == 0) return s+1; + } + else if (*s == b) cont++; + } + } + return NULL; /* string ends out of balance */ +} + + +static const char *max_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + ptrdiff_t i = 0; /* counts maximum expand for item */ + while (singlematch(ms, s + i, p, ep)) + i++; + /* keeps trying to match with the maximum repetitions */ + while (i>=0) { + const char *res = match(ms, (s+i), ep+1); + if (res) return res; + i--; /* else didn't match; reduce 1 repetition to try again */ + } + return NULL; +} + + +static const char *min_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + for (;;) { + const char *res = match(ms, s, ep+1); + if (res != NULL) + return res; + else if (singlematch(ms, s, p, ep)) + s++; /* try with one more repetition */ + else return NULL; + } +} + + +static const char *start_capture (MatchState *ms, const char *s, + const char *p, int what) { + const char *res; + int level = ms->level; + if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); + ms->capture[level].init = s; + ms->capture[level].len = what; + ms->level = level+1; + if ((res=match(ms, s, p)) == NULL) /* match failed? */ + ms->level--; /* undo capture */ + return res; +} + + +static const char *end_capture (MatchState *ms, const char *s, + const char *p) { + int l = capture_to_close(ms); + const char *res; + ms->capture[l].len = s - ms->capture[l].init; /* close capture */ + if ((res = match(ms, s, p)) == NULL) /* match failed? */ + ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ + return res; +} + + +static const char *match_capture (MatchState *ms, const char *s, int l) { + size_t len; + l = check_capture(ms, l); + len = ms->capture[l].len; + if ((size_t)(ms->src_end-s) >= len && + memcmp(ms->capture[l].init, s, len) == 0) + return s+len; + else return NULL; +} + + +static const char *match (MatchState *ms, const char *s, const char *p) { + if (l_unlikely(ms->matchdepth-- == 0)) + luaL_error(ms->L, "pattern too complex"); + init: /* using goto to optimize tail recursion */ + if (p != ms->p_end) { /* end of pattern? */ + switch (*p) { + case '(': { /* start capture */ + if (*(p + 1) == ')') /* position capture? */ + s = start_capture(ms, s, p + 2, CAP_POSITION); + else + s = start_capture(ms, s, p + 1, CAP_UNFINISHED); + break; + } + case ')': { /* end capture */ + s = end_capture(ms, s, p + 1); + break; + } + case '$': { + if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */ + goto dflt; /* no; go to default */ + s = (s == ms->src_end) ? s : NULL; /* check end of string */ + break; + } + case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ + switch (*(p + 1)) { + case 'b': { /* balanced string? */ + s = matchbalance(ms, s, p + 2); + if (s != NULL) { + p += 4; goto init; /* return match(ms, s, p + 4); */ + } /* else fail (s == NULL) */ + break; + } + case 'f': { /* frontier? */ + const char *ep; char previous; + p += 2; + if (l_unlikely(*p != '[')) + luaL_error(ms->L, "missing '[' after '%%f' in pattern"); + ep = classend(ms, p); /* points to what is next */ + previous = (s == ms->src_init) ? '\0' : *(s - 1); + if (!matchbracketclass(uchar(previous), p, ep - 1) && + matchbracketclass(uchar(*s), p, ep - 1)) { + p = ep; goto init; /* return match(ms, s, ep); */ + } + s = NULL; /* match failed */ + break; + } + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': { /* capture results (%0-%9)? */ + s = match_capture(ms, s, uchar(*(p + 1))); + if (s != NULL) { + p += 2; goto init; /* return match(ms, s, p + 2) */ + } + break; + } + default: goto dflt; + } + break; + } + default: dflt: { /* pattern class plus optional suffix */ + const char *ep = classend(ms, p); /* points to optional suffix */ + /* does not match at least once? */ + if (!singlematch(ms, s, p, ep)) { + if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */ + p = ep + 1; goto init; /* return match(ms, s, ep + 1); */ + } + else /* '+' or no suffix */ + s = NULL; /* fail */ + } + else { /* matched once */ + switch (*ep) { /* handle optional suffix */ + case '?': { /* optional */ + const char *res; + if ((res = match(ms, s + 1, ep + 1)) != NULL) + s = res; + else { + p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ + } + break; + } + case '+': /* 1 or more repetitions */ + s++; /* 1 match already done */ + /* FALLTHROUGH */ + case '*': /* 0 or more repetitions */ + s = max_expand(ms, s, p, ep); + break; + case '-': /* 0 or more repetitions (minimum) */ + s = min_expand(ms, s, p, ep); + break; + default: /* no suffix */ + s++; p = ep; goto init; /* return match(ms, s + 1, ep); */ + } + } + break; + } + } + } + ms->matchdepth++; + return s; +} + + + +static const char *lmemfind (const char *s1, size_t l1, + const char *s2, size_t l2) { + if (l2 == 0) return s1; /* empty strings are everywhere */ + else if (l2 > l1) return NULL; /* avoids a negative 'l1' */ + else { + const char *init; /* to search for a '*s2' inside 's1' */ + l2--; /* 1st char will be checked by 'memchr' */ + l1 = l1-l2; /* 's2' cannot be found after that */ + while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { + init++; /* 1st char is already checked */ + if (memcmp(init, s2+1, l2) == 0) + return init-1; + else { /* correct 'l1' and 's1' to try again */ + l1 -= init-s1; + s1 = init; + } + } + return NULL; /* not found */ + } +} + + +/* +** get information about the i-th capture. If there are no captures +** and 'i==0', return information about the whole match, which +** is the range 's'..'e'. If the capture is a string, return +** its length and put its address in '*cap'. If it is an integer +** (a position), push it on the stack and return CAP_POSITION. +*/ +static size_t get_onecapture (MatchState *ms, int i, const char *s, + const char *e, const char **cap) { + if (i >= ms->level) { + if (l_unlikely(i != 0)) + luaL_error(ms->L, "invalid capture index %%%d", i + 1); + *cap = s; + return e - s; + } + else { + ptrdiff_t capl = ms->capture[i].len; + *cap = ms->capture[i].init; + if (l_unlikely(capl == CAP_UNFINISHED)) + luaL_error(ms->L, "unfinished capture"); + else if (capl == CAP_POSITION) + lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); + return capl; + } +} + + +/* +** Push the i-th capture on the stack. +*/ +static void push_onecapture (MatchState *ms, int i, const char *s, + const char *e) { + const char *cap; + ptrdiff_t l = get_onecapture(ms, i, s, e, &cap); + if (l != CAP_POSITION) + lua_pushlstring(ms->L, cap, l); + /* else position was already pushed */ +} + + +static int push_captures (MatchState *ms, const char *s, const char *e) { + int i; + int nlevels = (ms->level == 0 && s) ? 1 : ms->level; + luaL_checkstack(ms->L, nlevels, "too many captures"); + for (i = 0; i < nlevels; i++) + push_onecapture(ms, i, s, e); + return nlevels; /* number of strings pushed */ +} + + +/* check whether pattern has no special characters */ +static int nospecials (const char *p, size_t l) { + size_t upto = 0; + do { + if (strpbrk(p + upto, SPECIALS)) + return 0; /* pattern has a special character */ + upto += strlen(p + upto) + 1; /* may have more after \0 */ + } while (upto <= l); + return 1; /* no special chars found */ +} + + +static void prepstate (MatchState *ms, lua_State *L, + const char *s, size_t ls, const char *p, size_t lp) { + ms->L = L; + ms->matchdepth = MAXCCALLS; + ms->src_init = s; + ms->src_end = s + ls; + ms->p_end = p + lp; +} + + +static void reprepstate (MatchState *ms) { + ms->level = 0; + lua_assert(ms->matchdepth == MAXCCALLS); +} + + +static int str_find_aux (lua_State *L, int find) { + size_t ls, lp; + const char *s = luaL_checklstring(L, 1, &ls); + const char *p = luaL_checklstring(L, 2, &lp); + size_t init = posrelatI(luaL_optinteger(L, 3, 1), ls) - 1; + if (init > ls) { /* start after string's end? */ + luaL_pushfail(L); /* cannot find anything */ + return 1; + } + /* explicit request or no special characters? */ + if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { + /* do a plain search */ + const char *s2 = lmemfind(s + init, ls - init, p, lp); + if (s2) { + lua_pushinteger(L, (s2 - s) + 1); + lua_pushinteger(L, (s2 - s) + lp); + return 2; + } + } + else { + MatchState ms; + const char *s1 = s + init; + int anchor = (*p == '^'); + if (anchor) { + p++; lp--; /* skip anchor character */ + } + prepstate(&ms, L, s, ls, p, lp); + do { + const char *res; + reprepstate(&ms); + if ((res=match(&ms, s1, p)) != NULL) { + if (find) { + lua_pushinteger(L, (s1 - s) + 1); /* start */ + lua_pushinteger(L, res - s); /* end */ + return push_captures(&ms, NULL, 0) + 2; + } + else + return push_captures(&ms, s1, res); + } + } while (s1++ < ms.src_end && !anchor); + } + luaL_pushfail(L); /* not found */ + return 1; +} + + +static int str_find (lua_State *L) { + return str_find_aux(L, 1); +} + + +static int str_match (lua_State *L) { + return str_find_aux(L, 0); +} + + +/* 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) { + GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); + const char *src; + gm->ms.L = L; + for (src = gm->src; src <= gm->ms.src_end; src++) { + const char *e; + reprepstate(&gm->ms); + if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) { + gm->src = gm->lastmatch = e; + return push_captures(&gm->ms, src, e); + } + } + return 0; /* not found */ +} + + +static int gmatch (lua_State *L) { + size_t ls, lp; + const char *s = luaL_checklstring(L, 1, &ls); + const char *p = luaL_checklstring(L, 2, &lp); + size_t init = posrelatI(luaL_optinteger(L, 3, 1), ls) - 1; + GMatchState *gm; + lua_settop(L, 2); /* keep strings on closure to avoid being collected */ + gm = (GMatchState *)lua_newuserdatauv(L, sizeof(GMatchState), 0); + if (init > ls) /* start after string's end? */ + init = ls + 1; /* avoid overflows in 's + init' */ + prepstate(&gm->ms, L, s, ls, p, lp); + gm->src = s + init; gm->p = p; gm->lastmatch = NULL; + lua_pushcclosure(L, gmatch_aux, 3); + return 1; +} + + +static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e) { + size_t l; + lua_State *L = ms->L; + const char *news = lua_tolstring(L, 3, &l); + const char *p; + while ((p = (char *)memchr(news, L_ESC, l)) != NULL) { + luaL_addlstring(b, news, p - news); + p++; /* skip ESC */ + if (*p == L_ESC) /* '%%' */ + luaL_addchar(b, *p); + else if (*p == '0') /* '%0' */ + luaL_addlstring(b, s, e - s); + else if (isdigit(uchar(*p))) { /* '%n' */ + const char *cap; + ptrdiff_t resl = get_onecapture(ms, *p - '1', s, e, &cap); + if (resl == CAP_POSITION) + luaL_addvalue(b); /* add position to accumulated result */ + else + luaL_addlstring(b, cap, resl); + } + else + luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); + l -= p + 1 - news; + news = p + 1; + } + luaL_addlstring(b, news, l); +} + + +/* +** Add the replacement value to the string buffer 'b'. +** Return true if the original string was changed. (Function calls and +** table indexing resulting in nil or false do not change the subject.) +*/ +static int add_value (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e, int tr) { + lua_State *L = ms->L; + switch (tr) { + case LUA_TFUNCTION: { /* call the function */ + int n; + lua_pushvalue(L, 3); /* push the function */ + n = push_captures(ms, s, e); /* all captures as arguments */ + lua_call(L, n, 1); /* call it */ + break; + } + case LUA_TTABLE: { /* index the table */ + push_onecapture(ms, 0, s, e); /* first capture is the index */ + lua_gettable(L, 3); + break; + } + default: { /* LUA_TNUMBER or LUA_TSTRING */ + add_s(ms, b, s, e); /* add value to the buffer */ + return 1; /* something changed */ + } + } + if (!lua_toboolean(L, -1)) { /* nil or false? */ + lua_pop(L, 1); /* remove value */ + luaL_addlstring(b, s, e - s); /* keep original text */ + return 0; /* no changes */ + } + else if (l_unlikely(!lua_isstring(L, -1))) + return luaL_error(L, "invalid replacement value (a %s)", + luaL_typename(L, -1)); + else { + luaL_addvalue(b); /* add result to accumulator */ + return 1; /* something changed */ + } +} + + +static int str_gsub (lua_State *L) { + size_t srcl, lp; + const char *src = luaL_checklstring(L, 1, &srcl); /* subject */ + const char *p = luaL_checklstring(L, 2, &lp); /* pattern */ + const char *lastmatch = NULL; /* end of last match */ + int tr = lua_type(L, 3); /* replacement type */ + lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ + int anchor = (*p == '^'); + lua_Integer n = 0; /* replacement count */ + int changed = 0; /* change flag */ + MatchState ms; + luaL_Buffer b; + luaL_argexpected(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || + tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, + "string/function/table"); + luaL_buffinit(L, &b); + if (anchor) { + p++; lp--; /* skip anchor character */ + } + prepstate(&ms, L, src, srcl, p, lp); + while (n < max_s) { + const char *e; + reprepstate(&ms); /* (re)prepare state for new match */ + if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ + n++; + changed = add_value(&ms, &b, src, e, tr) | changed; + src = lastmatch = e; + } + else if (src < ms.src_end) /* otherwise, skip one character */ + luaL_addchar(&b, *src++); + else break; /* end of subject */ + if (anchor) break; + } + if (!changed) /* no changes? */ + lua_pushvalue(L, 1); /* return original string */ + else { /* something changed */ + luaL_addlstring(&b, src, ms.src_end-src); + luaL_pushresult(&b); /* create and return new string */ + } + lua_pushinteger(L, n); /* number of substitutions */ + return 2; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** STRING FORMAT +** ======================================================= +*/ + +#if !defined(lua_number2strx) /* { */ + +/* +** Hexadecimal floating-point formatter +*/ + +#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_floatatt(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 sign */ + 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 (l_unlikely(fmt[SIZELENMOD] != 'a')) + return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); + return n; +} + +#endif /* } */ + + +/* +** Maximum size for items formatted with '%f'. This 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, adding some extra, 110) +*/ +#define MAX_ITEMF (110 + l_floatatt(MAX_10_EXP)) + + +/* +** All formats except '%f' do not need that large limit. The other +** float formats use exponents, so that they fit in the 99 limit for +** significant digits; 's' for large strings and 'q' add items directly +** to the buffer; all integer formats also fit in the 99 limit. The +** worst case are floats: they may need 99 significant digits, plus +** '0x', '-', '.', 'e+XXXX', and '\0'. Adding some extra, 120. +*/ +#define MAX_ITEM 120 + + +/* valid flags in a format specification */ +#if !defined(L_FMTFLAGSF) + +/* valid flags for a, A, e, E, f, F, g, and G conversions */ +#define L_FMTFLAGSF "-+#0 " + +/* valid flags for o, x, and X conversions */ +#define L_FMTFLAGSX "-#0" + +/* valid flags for d and i conversions */ +#define L_FMTFLAGSI "-+0 " + +/* valid flags for u conversions */ +#define L_FMTFLAGSU "-0" + +/* valid flags for c, p, and s conversions */ +#define L_FMTFLAGSC "-" + +#endif + + +/* +** Maximum size of each format specification (such as "%-099.99d"): +** Initial '%', flags (up to 5), width (2), period, precision (2), +** length modifier (8), conversion specifier, and final '\0', plus some +** extra. +*/ +#define MAX_FORMAT 32 + + +static void addquoted (luaL_Buffer *b, const char *s, size_t len) { + luaL_addchar(b, '"'); + while (len--) { + if (*s == '"' || *s == '\\' || *s == '\n') { + luaL_addchar(b, '\\'); + luaL_addchar(b, *s); + } + else if (iscntrl(uchar(*s))) { + char buff[10]; + if (!isdigit(uchar(*(s+1)))) + l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); + else + l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s)); + luaL_addstring(b, buff); + } + else + luaL_addchar(b, *s); + s++; + } + luaL_addchar(b, '"'); +} + + +/* +** Serialize a floating-point number in such a way that it can be +** scanned back by Lua. Use hexadecimal format for "common" numbers +** (to preserve precision); inf, -inf, and NaN are handled separately. +** (NaN cannot be expressed as a numeral, so we write '(0/0)' for it.) +*/ +static int quotefloat (lua_State *L, char *buff, lua_Number n) { + const char *s; /* for the fixed representations */ + if (n == (lua_Number)HUGE_VAL) /* inf? */ + s = "1e9999"; + else if (n == -(lua_Number)HUGE_VAL) /* -inf? */ + s = "-1e9999"; + else if (n != n) /* NaN? */ + s = "(0/0)"; + else { /* format number as hexadecimal */ + int nb = lua_number2strx(L, buff, MAX_ITEM, + "%" LUA_NUMBER_FRMLEN "a", n); + /* ensures that 'buff' string uses a dot as the radix character */ + 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 */ + } + return nb; + } + /* for the fixed representations */ + return l_sprintf(buff, MAX_ITEM, "%s", s); +} + + +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? */ + nb = quotefloat(L, buff, lua_tonumber(L, arg)); + else { /* integers */ + lua_Integer n = lua_tointeger(L, arg); + const char *format = (n == LUA_MININTEGER) /* corner case? */ + ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hex */ + : 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 *get2digits (const char *s) { + if (isdigit(uchar(*s))) { + s++; + if (isdigit(uchar(*s))) s++; /* (2 digits at most) */ + } + return s; +} + + +/* +** Check whether a conversion specification is valid. When called, +** first character in 'form' must be '%' and last character must +** be a valid conversion specifier. 'flags' are the accepted flags; +** 'precision' signals whether to accept a precision. +*/ +static void checkformat (lua_State *L, const char *form, const char *flags, + int precision) { + const char *spec = form + 1; /* skip '%' */ + spec += strspn(spec, flags); /* skip flags */ + if (*spec != '0') { /* a width cannot start with '0' */ + spec = get2digits(spec); /* skip width */ + if (*spec == '.' && precision) { + spec++; + spec = get2digits(spec); /* skip precision */ + } + } + if (!isalpha(uchar(*spec))) /* did not go to the end? */ + luaL_error(L, "invalid conversion specification: '%s'", form); +} + + +/* +** Get a conversion specification and copy it to 'form'. +** Return the address of its last character. +*/ +static const char *getformat (lua_State *L, const char *strfrmt, + char *form) { + /* spans flags, width, and precision ('0' is included as a flag) */ + size_t len = strspn(strfrmt, L_FMTFLAGSF "123456789."); + len++; /* adds following character (should be the specifier) */ + /* still needs space for '%', '\0', plus a length modifier */ + if (len >= MAX_FORMAT - 10) + luaL_error(L, "invalid format (too long)"); + *(form++) = '%'; + memcpy(form, strfrmt, len * sizeof(char)); + *(form + len) = '\0'; + return strfrmt + len - 1; +} + + +/* +** add length modifier into formats +*/ +static void addlenmod (char *form, const char *lenmod) { + size_t l = strlen(form); + size_t lm = strlen(lenmod); + char spec = form[l - 1]; + strcpy(form + l - 1, lenmod); + form[l + lm - 1] = spec; + form[l + lm] = '\0'; +} + + +static int str_format (lua_State *L) { + int top = lua_gettop(L); + int arg = 1; + size_t sfl; + const char *strfrmt = luaL_checklstring(L, arg, &sfl); + const char *strfrmt_end = strfrmt+sfl; + const char *flags; + luaL_Buffer b; + luaL_buffinit(L, &b); + while (strfrmt < strfrmt_end) { + if (*strfrmt != L_ESC) + luaL_addchar(&b, *strfrmt++); + else if (*++strfrmt == L_ESC) + luaL_addchar(&b, *strfrmt++); /* %% */ + else { /* format item */ + char form[MAX_FORMAT]; /* to store the format ('%...') */ + int maxitem = MAX_ITEM; /* maximum length for the result */ + char *buff = luaL_prepbuffsize(&b, maxitem); /* to put result */ + int nb = 0; /* number of bytes in result */ + if (++arg > top) + return luaL_argerror(L, arg, "no value"); + strfrmt = getformat(L, strfrmt, form); + switch (*strfrmt++) { + case 'c': { + checkformat(L, form, L_FMTFLAGSC, 0); + nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg)); + break; + } + case 'd': case 'i': + flags = L_FMTFLAGSI; + goto intcase; + case 'u': + flags = L_FMTFLAGSU; + goto intcase; + case 'o': case 'x': case 'X': + flags = L_FMTFLAGSX; + intcase: { + lua_Integer n = luaL_checkinteger(L, arg); + checkformat(L, form, flags, 1); + addlenmod(form, LUA_INTEGER_FRMLEN); + nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n); + break; + } + case 'a': case 'A': + checkformat(L, form, L_FMTFLAGSF, 1); + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = lua_number2strx(L, buff, maxitem, form, + luaL_checknumber(L, arg)); + break; + case 'f': + maxitem = MAX_ITEMF; /* extra space for '%f' */ + buff = luaL_prepbuffsize(&b, maxitem); + /* FALLTHROUGH */ + case 'e': case 'E': case 'g': case 'G': { + lua_Number n = luaL_checknumber(L, arg); + checkformat(L, form, L_FMTFLAGSF, 1); + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n); + break; + } + case 'p': { + const void *p = lua_topointer(L, arg); + checkformat(L, form, L_FMTFLAGSC, 0); + if (p == NULL) { /* avoid calling 'printf' with argument NULL */ + p = "(null)"; /* result */ + form[strlen(form) - 1] = 's'; /* format it as a string */ + } + nb = l_sprintf(buff, maxitem, form, p); + break; + } + case 'q': { + if (form[2] != '\0') /* modifiers? */ + return luaL_error(L, "specifier '%%q' cannot have modifiers"); + addliteral(L, &b, arg); + break; + } + case 's': { + size_t l; + const char *s = luaL_tolstring(L, arg, &l); + if (form[2] == '\0') /* no modifiers? */ + luaL_addvalue(&b); /* keep entire string */ + else { + luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); + checkformat(L, form, L_FMTFLAGSC, 1); + if (strchr(form, '.') == NULL && l >= 100) { + /* no precision and string is too long to be formatted */ + luaL_addvalue(&b); /* keep entire string */ + } + else { /* format the string into 'buff' */ + nb = l_sprintf(buff, maxitem, form, s); + lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ + } + } + break; + } + default: { /* also treat cases 'pnLlh' */ + return luaL_error(L, "invalid conversion '%s' to 'format'", form); + } + } + lua_assert(nb < maxitem); + luaL_addsize(&b, nb); + } + } + luaL_pushresult(&b); + return 1; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** PACK/UNPACK +** ======================================================= +*/ + + +/* value used for padding */ +#if !defined(LUAL_PACKPADBYTE) +#define LUAL_PACKPADBYTE 0x00 +#endif + +/* maximum size for the binary representation of an integer */ +#define MAXINTSIZE 16 + +/* number of bits in a character */ +#define NB CHAR_BIT + +/* mask for one character (NB 1's) */ +#define MC ((1 << NB) - 1) + +/* size of a lua_Integer */ +#define SZINT ((int)sizeof(lua_Integer)) + + +/* dummy union to get native endianness */ +static const union { + int dummy; + char little; /* true iff machine is little endian */ +} nativeendian = {1}; + + +/* +** information to pack/unpack stuff +*/ +typedef struct Header { + lua_State *L; + int islittle; + int maxalign; +} Header; + + +/* +** options for pack/unpack +*/ +typedef enum KOption { + Kint, /* signed integers */ + Kuint, /* unsigned integers */ + Kfloat, /* single-precision floating-point numbers */ + Knumber, /* Lua "native" floating-point numbers */ + Kdouble, /* double-precision floating-point numbers */ + Kchar, /* fixed-length strings */ + Kstring, /* strings with prefixed length */ + Kzstr, /* zero-terminated strings */ + Kpadding, /* padding */ + Kpaddalign, /* padding for alignment */ + Knop /* no-op (configuration or spaces) */ +} KOption; + + +/* +** Read an integer numeral from string 'fmt' or return 'df' if +** there is no numeral +*/ +static int digit (int c) { return '0' <= c && c <= '9'; } + +static int getnum (const char **fmt, int df) { + if (!digit(**fmt)) /* no number? */ + return df; /* return default value */ + else { + int a = 0; + do { + a = a*10 + (*((*fmt)++) - '0'); + } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10); + return a; + } +} + + +/* +** Read an integer numeral and raises an error if it is larger +** than the maximum size for integers. +*/ +static int getnumlimit (Header *h, const char **fmt, int df) { + int sz = getnum(fmt, df); + if (l_unlikely(sz > MAXINTSIZE || sz <= 0)) + return luaL_error(h->L, "integral size (%d) out of limits [1,%d]", + sz, MAXINTSIZE); + return sz; +} + + +/* +** Initialize Header +*/ +static void initheader (lua_State *L, Header *h) { + h->L = L; + h->islittle = nativeendian.little; + h->maxalign = 1; +} + + +/* +** Read and classify next option. 'size' is filled with option's size. +*/ +static KOption getoption (Header *h, const char **fmt, int *size) { + /* dummy structure to get native alignment requirements */ + struct cD { char c; union { LUAI_MAXALIGN; } u; }; + int opt = *((*fmt)++); + *size = 0; /* default */ + switch (opt) { + case 'b': *size = sizeof(char); return Kint; + case 'B': *size = sizeof(char); return Kuint; + case 'h': *size = sizeof(short); return Kint; + case 'H': *size = sizeof(short); return Kuint; + case 'l': *size = sizeof(long); return Kint; + case 'L': *size = sizeof(long); return Kuint; + case 'j': *size = sizeof(lua_Integer); return Kint; + case 'J': *size = sizeof(lua_Integer); return Kuint; + case 'T': *size = sizeof(size_t); return Kuint; + case 'f': *size = sizeof(float); return Kfloat; + case 'n': *size = sizeof(lua_Number); return Knumber; + case 'd': *size = sizeof(double); return Kdouble; + case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; + case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; + case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; + case 'c': + *size = getnum(fmt, -1); + if (l_unlikely(*size == -1)) + luaL_error(h->L, "missing size for format option 'c'"); + return Kchar; + case 'z': return Kzstr; + case 'x': *size = 1; return Kpadding; + case 'X': return Kpaddalign; + case ' ': break; + case '<': h->islittle = 1; break; + case '>': h->islittle = 0; break; + case '=': h->islittle = nativeendian.little; break; + case '!': { + const int maxalign = offsetof(struct cD, u); + h->maxalign = getnumlimit(h, fmt, maxalign); + break; + } + default: luaL_error(h->L, "invalid format option '%c'", opt); + } + return Knop; +} + + +/* +** Read, classify, and fill other details about the next option. +** 'psize' is filled with option's size, 'notoalign' with its +** alignment requirements. +** Local variable 'size' gets the size to be aligned. (Kpadal option +** always gets its full alignment, other options are limited by +** the maximum alignment ('maxalign'). Kchar option needs no alignment +** despite its size. +*/ +static KOption getdetails (Header *h, size_t totalsize, + const char **fmt, int *psize, int *ntoalign) { + KOption opt = getoption(h, fmt, psize); + int align = *psize; /* usually, alignment follows size */ + if (opt == Kpaddalign) { /* 'X' gets alignment from following option */ + if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0) + luaL_argerror(h->L, 1, "invalid next option for option 'X'"); + } + if (align <= 1 || opt == Kchar) /* need no alignment? */ + *ntoalign = 0; + else { + if (align > h->maxalign) /* enforce maximum alignment */ + align = h->maxalign; + if (l_unlikely((align & (align - 1)) != 0)) /* not a power of 2? */ + luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); + *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); + } + return opt; +} + + +/* +** Pack integer 'n' with 'size' bytes and 'islittle' endianness. +** The final 'if' handles the case when 'size' is larger than +** the size of a Lua integer, correcting the extra sign-extension +** bytes if necessary (by default they would be zeros). +*/ +static void packint (luaL_Buffer *b, lua_Unsigned n, + int islittle, int size, int neg) { + char *buff = luaL_prepbuffsize(b, size); + int i; + buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */ + for (i = 1; i < size; i++) { + n >>= NB; + buff[islittle ? i : size - 1 - i] = (char)(n & MC); + } + if (neg && size > SZINT) { /* negative number need sign extension? */ + for (i = SZINT; i < size; i++) /* correct extra bytes */ + buff[islittle ? i : size - 1 - i] = (char)MC; + } + luaL_addsize(b, size); /* add result to buffer */ +} + + +/* +** Copy 'size' bytes from 'src' to 'dest', correcting endianness if +** given 'islittle' is different from native endianness. +*/ +static void copywithendian (char *dest, const char *src, + int size, int islittle) { + if (islittle == nativeendian.little) + memcpy(dest, src, size); + else { + dest += size - 1; + while (size-- != 0) + *(dest--) = *(src++); + } +} + + +static int str_pack (lua_State *L) { + luaL_Buffer b; + Header h; + const char *fmt = luaL_checkstring(L, 1); /* format string */ + int arg = 1; /* current argument to pack */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + lua_pushnil(L); /* mark to separate arguments from string buffer */ + luaL_buffinit(L, &b); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + totalsize += ntoalign + size; + while (ntoalign-- > 0) + luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */ + arg++; + switch (opt) { + case Kint: { /* signed integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) { /* need overflow check? */ + lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); + luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); + } + packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0)); + break; + } + case Kuint: { /* unsigned integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) /* need overflow check? */ + luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), + arg, "unsigned overflow"); + packint(&b, (lua_Unsigned)n, h.islittle, size, 0); + break; + } + case Kfloat: { /* C float */ + float f = (float)luaL_checknumber(L, arg); /* get argument */ + char *buff = luaL_prepbuffsize(&b, sizeof(f)); + /* move 'f' to final result, correcting endianness if needed */ + copywithendian(buff, (char *)&f, sizeof(f), h.islittle); + luaL_addsize(&b, size); + break; + } + case Knumber: { /* Lua float */ + lua_Number f = luaL_checknumber(L, arg); /* get argument */ + char *buff = luaL_prepbuffsize(&b, sizeof(f)); + /* move 'f' to final result, correcting endianness if needed */ + copywithendian(buff, (char *)&f, sizeof(f), h.islittle); + luaL_addsize(&b, size); + break; + } + case Kdouble: { /* C double */ + double f = (double)luaL_checknumber(L, arg); /* get argument */ + char *buff = luaL_prepbuffsize(&b, sizeof(f)); + /* move 'f' to final result, correcting endianness if needed */ + copywithendian(buff, (char *)&f, sizeof(f), h.islittle); + luaL_addsize(&b, size); + break; + } + case Kchar: { /* fixed-size string */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, len <= (size_t)size, arg, + "string longer than given size"); + luaL_addlstring(&b, s, len); /* add string */ + while (len++ < (size_t)size) /* pad extra space */ + luaL_addchar(&b, LUAL_PACKPADBYTE); + break; + } + case Kstring: { /* strings with length count */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, size >= (int)sizeof(size_t) || + len < ((size_t)1 << (size * NB)), + arg, "string length does not fit in given size"); + packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ + luaL_addlstring(&b, s, len); + totalsize += len; + break; + } + case Kzstr: { /* zero-terminated string */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); + luaL_addlstring(&b, s, len); + luaL_addchar(&b, '\0'); /* add zero at the end */ + totalsize += len + 1; + break; + } + case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */ + case Kpaddalign: case Knop: + arg--; /* undo increment */ + break; + } + } + luaL_pushresult(&b); + return 1; +} + + +static int str_packsize (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); /* format string */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + luaL_argcheck(L, opt != Kstring && opt != Kzstr, 1, + "variable-length format"); + size += ntoalign; /* total space used by option */ + luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, + "format result too large"); + totalsize += size; + } + lua_pushinteger(L, (lua_Integer)totalsize); + return 1; +} + + +/* +** Unpack an integer with 'size' bytes and 'islittle' endianness. +** If size is smaller than the size of a Lua integer and integer +** is signed, must do sign extension (propagating the sign to the +** higher bits); if size is larger than the size of a Lua integer, +** it must check the unread bytes to see whether they do not cause an +** overflow. +*/ +static lua_Integer unpackint (lua_State *L, const char *str, + int islittle, int size, int issigned) { + lua_Unsigned res = 0; + int i; + int limit = (size <= SZINT) ? size : SZINT; + for (i = limit - 1; i >= 0; i--) { + res <<= NB; + res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; + } + if (size < SZINT) { /* real size smaller than lua_Integer? */ + if (issigned) { /* needs sign extension? */ + lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); + res = ((res ^ mask) - mask); /* do sign extension */ + } + } + else if (size > SZINT) { /* must check unread bytes */ + int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; + for (i = limit; i < size; i++) { + if (l_unlikely((unsigned char)str[islittle ? i : size - 1 - i] != mask)) + luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); + } + } + return (lua_Integer)res; +} + + +static int str_unpack (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); + size_t ld; + const char *data = luaL_checklstring(L, 2, &ld); + size_t pos = posrelatI(luaL_optinteger(L, 3, 1), ld) - 1; + int n = 0; /* number of results */ + luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); + initheader(L, &h); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); + luaL_argcheck(L, (size_t)ntoalign + size <= ld - pos, 2, + "data string too short"); + pos += ntoalign; /* skip alignment */ + /* stack space for item + next position */ + luaL_checkstack(L, 2, "too many results"); + n++; + switch (opt) { + case Kint: + case Kuint: { + lua_Integer res = unpackint(L, data + pos, h.islittle, size, + (opt == Kint)); + lua_pushinteger(L, res); + break; + } + case Kfloat: { + float f; + copywithendian((char *)&f, data + pos, sizeof(f), h.islittle); + lua_pushnumber(L, (lua_Number)f); + break; + } + case Knumber: { + lua_Number f; + copywithendian((char *)&f, data + pos, sizeof(f), h.islittle); + lua_pushnumber(L, f); + break; + } + case Kdouble: { + double f; + copywithendian((char *)&f, data + pos, sizeof(f), h.islittle); + lua_pushnumber(L, (lua_Number)f); + break; + } + case Kchar: { + lua_pushlstring(L, data + pos, size); + break; + } + case Kstring: { + size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); + luaL_argcheck(L, len <= ld - pos - size, 2, "data string too short"); + lua_pushlstring(L, data + pos + size, len); + pos += len; /* skip string */ + break; + } + case Kzstr: { + size_t len = strlen(data + pos); + luaL_argcheck(L, pos + len < ld, 2, + "unfinished string for format 'z'"); + lua_pushlstring(L, data + pos, len); + pos += len + 1; /* skip string plus final '\0' */ + break; + } + case Kpaddalign: case Kpadding: case Knop: + n--; /* undo increment */ + break; + } + pos += size; + } + lua_pushinteger(L, pos + 1); /* next position */ + return n + 1; +} + +/* }====================================================== */ + + +static const luaL_Reg strlib[] = { + {"byte", str_byte}, + {"char", str_char}, + {"dump", str_dump}, + {"find", str_find}, + {"format", str_format}, + {"gmatch", gmatch}, + {"gsub", str_gsub}, + {"len", str_len}, + {"lower", str_lower}, + {"match", str_match}, + {"rep", str_rep}, + {"reverse", str_reverse}, + {"sub", str_sub}, + {"upper", str_upper}, + {"pack", str_pack}, + {"packsize", str_packsize}, + {"unpack", str_unpack}, + {NULL, NULL} +}; + + +static void createmetatable (lua_State *L) { + /* table to be metatable for strings */ + luaL_newlibtable(L, stringmetamethods); + luaL_setfuncs(L, stringmetamethods, 0); + lua_pushliteral(L, ""); /* dummy string */ + lua_pushvalue(L, -2); /* copy table */ + lua_setmetatable(L, -2); /* set table as metatable for strings */ + lua_pop(L, 1); /* pop dummy string */ + lua_pushvalue(L, -2); /* get string library */ + lua_setfield(L, -2, "__index"); /* metatable.__index = string */ + lua_pop(L, 1); /* pop metatable */ +} + + +/* +** Open string library +*/ +LUAMOD_API int luaopen_string (lua_State *L) { + luaL_newlib(L, strlib); + createmetatable(L); + return 1; +} + diff --git a/src/libs/3rdparty/lua/src/ltable.c b/src/libs/3rdparty/lua/src/ltable.c new file mode 100644 index 0000000000..3c690c5f17 --- /dev/null +++ b/src/libs/3rdparty/lua/src/ltable.c @@ -0,0 +1,980 @@ +/* +** $Id: ltable.c $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + +#define ltable_c +#define LUA_CORE + +#include "lprefix.h" + + +/* +** Implementation of tables (aka arrays, objects, or hash tables). +** Tables keep its elements in two parts: an array part and a hash part. +** Non-negative integer keys are all candidates to be kept in the array +** part. The actual size of the array is the largest 'n' such that +** more than half the slots between 1 and n are in use. +** Hash uses a mix of chained scatter table with Brent's variation. +** A main invariant of these tables is that, if an element is not +** in its main position (i.e. the 'original' position that its hash gives +** to it), then the colliding element is in its own main position. +** Hence even when the load factor reaches 100%, performance remains good. +*/ + +#include <math.h> +#include <limits.h> + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "lvm.h" + + +/* +** MAXABITS is the largest integer such that MAXASIZE fits in an +** unsigned int. +*/ +#define MAXABITS cast_int(sizeof(int) * CHAR_BIT - 1) + + +/* +** MAXASIZE is the maximum size of the array part. It is the minimum +** between 2^MAXABITS and the maximum size that, measured in bytes, +** fits in a 'size_t'. +*/ +#define MAXASIZE luaM_limitN(1u << MAXABITS, TValue) + +/* +** MAXHBITS is the largest integer such that 2^MAXHBITS fits in a +** signed int. +*/ +#define MAXHBITS (MAXABITS - 1) + + +/* +** MAXHSIZE is the maximum size of the hash part. It is the minimum +** between 2^MAXHBITS and the maximum size such that, measured in bytes, +** it fits in a 'size_t'. +*/ +#define MAXHSIZE luaM_limitN(1u << MAXHBITS, Node) + + +/* +** When the original hash value is good, hashing by a power of 2 +** avoids the cost of '%'. +*/ +#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) + +/* +** for other types, it is better to avoid modulo by power of 2, as +** they can have many 2 factors. +*/ +#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) + + +#define hashstr(t,str) hashpow2(t, (str)->hash) +#define hashboolean(t,p) hashpow2(t, p) + + +#define hashpointer(t,p) hashmod(t, point2uint(p)) + + +#define dummynode (&dummynode_) + +static const Node dummynode_ = { + {{NULL}, LUA_VEMPTY, /* value's value and type */ + LUA_VNIL, 0, {NULL}} /* key type, next, and key value */ +}; + + +static const TValue absentkey = {ABSTKEYCONSTANT}; + + +/* +** Hash for integers. To allow a good hash, use the remainder operator +** ('%'). If integer fits as a non-negative int, compute an int +** remainder, which is faster. Otherwise, use an unsigned-integer +** remainder, which uses all bits and ensures a non-negative result. +*/ +static Node *hashint (const Table *t, lua_Integer i) { + lua_Unsigned ui = l_castS2U(i); + if (ui <= cast_uint(INT_MAX)) + return hashmod(t, cast_int(ui)); + else + return hashmod(t, ui); +} + + +/* +** Hash for floating-point numbers. +** The main computation should be just +** n = frexp(n, &i); return (n * INT_MAX) + i +** but there are some numerical subtleties. +** In a two-complement representation, INT_MAX does not has an exact +** representation as a float, but INT_MIN does; because the absolute +** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the +** absolute value of the product 'frexp * -INT_MIN' is smaller or equal +** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when +** adding 'i'; the use of '~u' (instead of '-u') avoids problems with +** INT_MIN. +*/ +#if !defined(l_hashfloat) +static int l_hashfloat (lua_Number n) { + int i; + lua_Integer ni; + n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN); + if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */ + lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL)); + return 0; + } + else { /* normal case */ + unsigned int u = cast_uint(i) + cast_uint(ni); + return cast_int(u <= cast_uint(INT_MAX) ? u : ~u); + } +} +#endif + + +/* +** returns the 'main' position of an element in a table (that is, +** the index of its hash value). +*/ +static Node *mainpositionTV (const Table *t, const TValue *key) { + switch (ttypetag(key)) { + case LUA_VNUMINT: { + lua_Integer i = ivalue(key); + return hashint(t, i); + } + case LUA_VNUMFLT: { + lua_Number n = fltvalue(key); + return hashmod(t, l_hashfloat(n)); + } + case LUA_VSHRSTR: { + TString *ts = tsvalue(key); + return hashstr(t, ts); + } + case LUA_VLNGSTR: { + TString *ts = tsvalue(key); + return hashpow2(t, luaS_hashlongstr(ts)); + } + case LUA_VFALSE: + return hashboolean(t, 0); + case LUA_VTRUE: + return hashboolean(t, 1); + case LUA_VLIGHTUSERDATA: { + void *p = pvalue(key); + return hashpointer(t, p); + } + case LUA_VLCF: { + lua_CFunction f = fvalue(key); + return hashpointer(t, f); + } + default: { + GCObject *o = gcvalue(key); + return hashpointer(t, o); + } + } +} + + +l_sinline Node *mainpositionfromnode (const Table *t, Node *nd) { + TValue key; + getnodekey(cast(lua_State *, NULL), &key, nd); + return mainpositionTV(t, &key); +} + + +/* +** Check whether key 'k1' is equal to the key in node 'n2'. This +** equality is raw, so there are no metamethods. Floats with integer +** values have been normalized, so integers cannot be equal to +** floats. It is assumed that 'eqshrstr' is simply pointer equality, so +** that short strings are handled in the default case. +** A true 'deadok' means to accept dead keys as equal to their original +** values. All dead keys are compared in the default case, by pointer +** identity. (Only collectable objects can produce dead keys.) Note that +** dead long strings are also compared by identity. +** Once a key is dead, its corresponding value may be collected, and +** then another value can be created with the same address. If this +** other value is given to 'next', 'equalkey' will signal a false +** positive. In a regular traversal, this situation should never happen, +** as all keys given to 'next' came from the table itself, and therefore +** could not have been collected. Outside a regular traversal, we +** have garbage in, garbage out. What is relevant is that this false +** positive does not break anything. (In particular, 'next' will return +** some other valid item on the table or nil.) +*/ +static int equalkey (const TValue *k1, const Node *n2, int deadok) { + if ((rawtt(k1) != keytt(n2)) && /* not the same variants? */ + !(deadok && keyisdead(n2) && iscollectable(k1))) + return 0; /* cannot be same key */ + switch (keytt(n2)) { + case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE: + return 1; + case LUA_VNUMINT: + return (ivalue(k1) == keyival(n2)); + case LUA_VNUMFLT: + return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2))); + case LUA_VLIGHTUSERDATA: + return pvalue(k1) == pvalueraw(keyval(n2)); + case LUA_VLCF: + return fvalue(k1) == fvalueraw(keyval(n2)); + case ctb(LUA_VLNGSTR): + return luaS_eqlngstr(tsvalue(k1), keystrval(n2)); + default: + return gcvalue(k1) == gcvalueraw(keyval(n2)); + } +} + + +/* +** True if value of 'alimit' is equal to the real size of the array +** part of table 't'. (Otherwise, the array part must be larger than +** 'alimit'.) +*/ +#define limitequalsasize(t) (isrealasize(t) || ispow2((t)->alimit)) + + +/* +** Returns the real size of the 'array' array +*/ +LUAI_FUNC unsigned int luaH_realasize (const Table *t) { + if (limitequalsasize(t)) + return t->alimit; /* this is the size */ + else { + unsigned int size = t->alimit; + /* compute the smallest power of 2 not smaller than 'n' */ + size |= (size >> 1); + size |= (size >> 2); + size |= (size >> 4); + size |= (size >> 8); +#if (UINT_MAX >> 14) > 3 /* unsigned int has more than 16 bits */ + size |= (size >> 16); +#if (UINT_MAX >> 30) > 3 + size |= (size >> 32); /* unsigned int has more than 32 bits */ +#endif +#endif + size++; + lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size); + return size; + } +} + + +/* +** Check whether real size of the array is a power of 2. +** (If it is not, 'alimit' cannot be changed to any other value +** without changing the real size.) +*/ +static int ispow2realasize (const Table *t) { + return (!isrealasize(t) || ispow2(t->alimit)); +} + + +static unsigned int setlimittosize (Table *t) { + t->alimit = luaH_realasize(t); + setrealasize(t); + return t->alimit; +} + + +#define limitasasize(t) check_exp(isrealasize(t), t->alimit) + + + +/* +** "Generic" get version. (Not that generic: not valid for integers, +** which may be in array part, nor for floats with integral values.) +** See explanation about 'deadok' in function 'equalkey'. +*/ +static const TValue *getgeneric (Table *t, const TValue *key, int deadok) { + Node *n = mainpositionTV(t, key); + for (;;) { /* check whether 'key' is somewhere in the chain */ + if (equalkey(key, n, deadok)) + return gval(n); /* that's it */ + else { + int nx = gnext(n); + if (nx == 0) + return &absentkey; /* not found */ + n += nx; + } + } +} + + +/* +** returns the index for 'k' if 'k' is an appropriate key to live in +** the array part of a table, 0 otherwise. +*/ +static unsigned int arrayindex (lua_Integer k) { + if (l_castS2U(k) - 1u < MAXASIZE) /* 'k' in [1, MAXASIZE]? */ + return cast_uint(k); /* 'key' is an appropriate array index */ + else + return 0; +} + + +/* +** returns the index of a 'key' for table traversals. First goes all +** elements in the array part, then elements in the hash part. The +** beginning of a traversal is signaled by 0. +*/ +static unsigned int findindex (lua_State *L, Table *t, TValue *key, + unsigned int asize) { + unsigned int i; + if (ttisnil(key)) return 0; /* first iteration */ + i = ttisinteger(key) ? arrayindex(ivalue(key)) : 0; + if (i - 1u < asize) /* is 'key' inside array part? */ + return i; /* yes; that's the index */ + else { + const TValue *n = getgeneric(t, key, 1); + if (l_unlikely(isabstkey(n))) + luaG_runerror(L, "invalid key to 'next'"); /* key not found */ + i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */ + /* hash elements are numbered after array ones */ + return (i + 1) + asize; + } +} + + +int luaH_next (lua_State *L, Table *t, StkId key) { + unsigned int asize = luaH_realasize(t); + unsigned int i = findindex(L, t, s2v(key), asize); /* find original key */ + for (; i < asize; i++) { /* try first array part */ + if (!isempty(&t->array[i])) { /* a non-empty entry? */ + setivalue(s2v(key), i + 1); + setobj2s(L, key + 1, &t->array[i]); + return 1; + } + } + for (i -= asize; cast_int(i) < sizenode(t); i++) { /* hash part */ + if (!isempty(gval(gnode(t, i)))) { /* a non-empty entry? */ + Node *n = gnode(t, i); + getnodekey(L, s2v(key), n); + setobj2s(L, key + 1, gval(n)); + return 1; + } + } + return 0; /* no more elements */ +} + + +static void freehash (lua_State *L, Table *t) { + if (!isdummy(t)) + luaM_freearray(L, t->node, cast_sizet(sizenode(t))); +} + + +/* +** {============================================================= +** Rehash +** ============================================================== +*/ + +/* +** Compute the optimal size for the array part of table 't'. 'nums' is a +** "count array" where 'nums[i]' is the number of integers in the table +** between 2^(i - 1) + 1 and 2^i. 'pna' enters with the total number of +** integer keys in the table and leaves with the number of keys that +** will go to the array part; return the optimal size. (The condition +** 'twotoi > 0' in the for loop stops the loop if 'twotoi' overflows.) +*/ +static unsigned int computesizes (unsigned int nums[], unsigned int *pna) { + int i; + unsigned int twotoi; /* 2^i (candidate for optimal size) */ + unsigned int a = 0; /* number of elements smaller than 2^i */ + unsigned int na = 0; /* number of elements to go to array part */ + unsigned int optimal = 0; /* optimal size for array part */ + /* loop while keys can fill more than half of total size */ + for (i = 0, twotoi = 1; + twotoi > 0 && *pna > twotoi / 2; + i++, twotoi *= 2) { + a += nums[i]; + if (a > twotoi/2) { /* more than half elements present? */ + optimal = twotoi; /* optimal size (till now) */ + na = a; /* all elements up to 'optimal' will go to array part */ + } + } + lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal); + *pna = na; + return optimal; +} + + +static int countint (lua_Integer key, unsigned int *nums) { + unsigned int k = arrayindex(key); + if (k != 0) { /* is 'key' an appropriate array index? */ + nums[luaO_ceillog2(k)]++; /* count as such */ + return 1; + } + else + return 0; +} + + +/* +** Count keys in array part of table 't': Fill 'nums[i]' with +** number of keys that will go into corresponding slice and return +** total number of non-nil keys. +*/ +static unsigned int numusearray (const Table *t, unsigned int *nums) { + int lg; + unsigned int ttlg; /* 2^lg */ + unsigned int ause = 0; /* summation of 'nums' */ + unsigned int i = 1; /* count to traverse all array keys */ + unsigned int asize = limitasasize(t); /* real array size */ + /* traverse each slice */ + for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) { + unsigned int lc = 0; /* counter */ + unsigned int lim = ttlg; + if (lim > asize) { + lim = asize; /* adjust upper limit */ + if (i > lim) + break; /* no more elements to count */ + } + /* count elements in range (2^(lg - 1), 2^lg] */ + for (; i <= lim; i++) { + if (!isempty(&t->array[i-1])) + lc++; + } + nums[lg] += lc; + ause += lc; + } + return ause; +} + + +static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) { + int totaluse = 0; /* total number of elements */ + int ause = 0; /* elements added to 'nums' (can go to array part) */ + int i = sizenode(t); + while (i--) { + Node *n = &t->node[i]; + if (!isempty(gval(n))) { + if (keyisinteger(n)) + ause += countint(keyival(n), nums); + totaluse++; + } + } + *pna += ause; + return totaluse; +} + + +/* +** Creates an array for the hash part of a table with the given +** size, or reuses the dummy node if size is zero. +** The computation for size overflow is in two steps: the first +** comparison ensures that the shift in the second one does not +** overflow. +*/ +static void setnodevector (lua_State *L, Table *t, unsigned int size) { + if (size == 0) { /* no elements to hash part? */ + t->node = cast(Node *, dummynode); /* use common 'dummynode' */ + t->lsizenode = 0; + t->lastfree = NULL; /* signal that it is using dummy node */ + } + else { + int i; + int lsize = luaO_ceillog2(size); + if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE) + luaG_runerror(L, "table overflow"); + size = twoto(lsize); + t->node = luaM_newvector(L, size, Node); + for (i = 0; i < cast_int(size); i++) { + Node *n = gnode(t, i); + gnext(n) = 0; + setnilkey(n); + setempty(gval(n)); + } + t->lsizenode = cast_byte(lsize); + t->lastfree = gnode(t, size); /* all positions are free */ + } +} + + +/* +** (Re)insert all elements from the hash part of 'ot' into table 't'. +*/ +static void reinsert (lua_State *L, Table *ot, Table *t) { + int j; + int size = sizenode(ot); + for (j = 0; j < size; j++) { + Node *old = gnode(ot, j); + if (!isempty(gval(old))) { + /* doesn't need barrier/invalidate cache, as entry was + already present in the table */ + TValue k; + getnodekey(L, &k, old); + luaH_set(L, t, &k, gval(old)); + } + } +} + + +/* +** Exchange the hash part of 't1' and 't2'. +*/ +static void exchangehashpart (Table *t1, Table *t2) { + lu_byte lsizenode = t1->lsizenode; + Node *node = t1->node; + Node *lastfree = t1->lastfree; + t1->lsizenode = t2->lsizenode; + t1->node = t2->node; + t1->lastfree = t2->lastfree; + t2->lsizenode = lsizenode; + t2->node = node; + t2->lastfree = lastfree; +} + + +/* +** Resize table 't' for the new given sizes. Both allocations (for +** the hash part and for the array part) can fail, which creates some +** subtleties. If the first allocation, for the hash part, fails, an +** error is raised and that is it. Otherwise, it copies the elements from +** the shrinking part of the array (if it is shrinking) into the new +** hash. Then it reallocates the array part. If that fails, the table +** is in its original state; the function frees the new hash part and then +** raises the allocation error. Otherwise, it sets the new hash part +** into the table, initializes the new part of the array (if any) with +** nils and reinserts the elements of the old hash back into the new +** parts of the table. +*/ +void luaH_resize (lua_State *L, Table *t, unsigned int newasize, + unsigned int nhsize) { + unsigned int i; + Table newt; /* to keep the new hash part */ + unsigned int oldasize = setlimittosize(t); + TValue *newarray; + /* create new hash part with appropriate size into 'newt' */ + setnodevector(L, &newt, nhsize); + if (newasize < oldasize) { /* will array shrink? */ + t->alimit = newasize; /* pretend array has new size... */ + exchangehashpart(t, &newt); /* and new hash */ + /* re-insert into the new hash the elements from vanishing slice */ + for (i = newasize; i < oldasize; i++) { + if (!isempty(&t->array[i])) + luaH_setint(L, t, i + 1, &t->array[i]); + } + t->alimit = oldasize; /* restore current size... */ + exchangehashpart(t, &newt); /* and hash (in case of errors) */ + } + /* allocate new array */ + newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue); + if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ + freehash(L, &newt); /* release new hash part */ + luaM_error(L); /* raise error (with array unchanged) */ + } + /* allocation ok; initialize new part of the array */ + exchangehashpart(t, &newt); /* 't' has the new hash ('newt' has the old) */ + t->array = newarray; /* set new array part */ + t->alimit = newasize; + for (i = oldasize; i < newasize; i++) /* clear new slice of the array */ + setempty(&t->array[i]); + /* re-insert elements from old hash part into new parts */ + reinsert(L, &newt, t); /* 'newt' now has the old hash */ + freehash(L, &newt); /* free old hash part */ +} + + +void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) { + int nsize = allocsizenode(t); + luaH_resize(L, t, nasize, nsize); +} + +/* +** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i +*/ +static void rehash (lua_State *L, Table *t, const TValue *ek) { + unsigned int asize; /* optimal size for array part */ + unsigned int na; /* number of keys in the array part */ + unsigned int nums[MAXABITS + 1]; + int i; + int totaluse; + for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */ + setlimittosize(t); + na = numusearray(t, nums); /* count keys in array part */ + totaluse = na; /* all those keys are integer keys */ + totaluse += numusehash(t, nums, &na); /* count keys in hash part */ + /* count extra key */ + if (ttisinteger(ek)) + na += countint(ivalue(ek), nums); + totaluse++; + /* compute new size for array part */ + asize = computesizes(nums, &na); + /* resize the table to new computed sizes */ + luaH_resize(L, t, asize, totaluse - na); +} + + + +/* +** }============================================================= +*/ + + +Table *luaH_new (lua_State *L) { + GCObject *o = luaC_newobj(L, LUA_VTABLE, sizeof(Table)); + Table *t = gco2t(o); + t->metatable = NULL; + t->flags = cast_byte(maskflags); /* table has no metamethod fields */ + t->array = NULL; + t->alimit = 0; + setnodevector(L, t, 0); + return t; +} + + +void luaH_free (lua_State *L, Table *t) { + freehash(L, t); + luaM_freearray(L, t->array, luaH_realasize(t)); + luaM_free(L, t); +} + + +static Node *getfreepos (Table *t) { + if (!isdummy(t)) { + while (t->lastfree > t->node) { + t->lastfree--; + if (keyisnil(t->lastfree)) + return t->lastfree; + } + } + return NULL; /* could not find a free place */ +} + + + +/* +** inserts a new key into a hash table; first, check whether key's main +** position is free. If not, check whether colliding node is in its main +** position or not: if it is not, move colliding node to an empty place and +** put new key in its main position; otherwise (colliding node is in its main +** position), new key goes to an empty position. +*/ +void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { + Node *mp; + TValue aux; + if (l_unlikely(ttisnil(key))) + luaG_runerror(L, "table index is nil"); + else if (ttisfloat(key)) { + lua_Number f = fltvalue(key); + lua_Integer k; + if (luaV_flttointeger(f, &k, F2Ieq)) { /* does key fit in an integer? */ + setivalue(&aux, k); + key = &aux; /* insert it as an integer */ + } + else if (l_unlikely(luai_numisnan(f))) + luaG_runerror(L, "table index is NaN"); + } + if (ttisnil(value)) + return; /* do not insert nil values */ + mp = mainpositionTV(t, key); + if (!isempty(gval(mp)) || isdummy(t)) { /* main position is taken? */ + Node *othern; + Node *f = getfreepos(t); /* get a free place */ + if (f == NULL) { /* cannot find a free place? */ + rehash(L, t, key); /* grow table */ + /* whatever called 'newkey' takes care of TM cache */ + luaH_set(L, t, key, value); /* insert key into grown table */ + return; + } + lua_assert(!isdummy(t)); + othern = mainpositionfromnode(t, mp); + if (othern != mp) { /* is colliding node out of its main position? */ + /* yes; move colliding node into free position */ + while (othern + gnext(othern) != mp) /* find previous */ + othern += gnext(othern); + gnext(othern) = cast_int(f - othern); /* rechain to point to 'f' */ + *f = *mp; /* copy colliding node into free pos. (mp->next also goes) */ + if (gnext(mp) != 0) { + gnext(f) += cast_int(mp - f); /* correct 'next' */ + gnext(mp) = 0; /* now 'mp' is free */ + } + setempty(gval(mp)); + } + else { /* colliding node is in its own main position */ + /* new node will go into free position */ + if (gnext(mp) != 0) + gnext(f) = cast_int((mp + gnext(mp)) - f); /* chain new position */ + else lua_assert(gnext(f) == 0); + gnext(mp) = cast_int(f - mp); + mp = f; + } + } + setnodekey(L, mp, key); + luaC_barrierback(L, obj2gco(t), key); + lua_assert(isempty(gval(mp))); + setobj2t(L, gval(mp), value); +} + + +/* +** Search function for integers. If integer is inside 'alimit', get it +** directly from the array part. Otherwise, if 'alimit' is not equal to +** the real size of the array, key still can be in the array part. In +** this case, try to avoid a call to 'luaH_realasize' when key is just +** one more than the limit (so that it can be incremented without +** changing the real size of the array). +*/ +const TValue *luaH_getint (Table *t, lua_Integer key) { + if (l_castS2U(key) - 1u < t->alimit) /* 'key' in [1, t->alimit]? */ + return &t->array[key - 1]; + else if (!limitequalsasize(t) && /* key still may be in the array part? */ + (l_castS2U(key) == t->alimit + 1 || + l_castS2U(key) - 1u < luaH_realasize(t))) { + t->alimit = cast_uint(key); /* probably '#t' is here now */ + return &t->array[key - 1]; + } + else { + Node *n = hashint(t, key); + for (;;) { /* check whether 'key' is somewhere in the chain */ + if (keyisinteger(n) && keyival(n) == key) + return gval(n); /* that's it */ + else { + int nx = gnext(n); + if (nx == 0) break; + n += nx; + } + } + return &absentkey; + } +} + + +/* +** search function for short strings +*/ +const TValue *luaH_getshortstr (Table *t, TString *key) { + Node *n = hashstr(t, key); + lua_assert(key->tt == LUA_VSHRSTR); + for (;;) { /* check whether 'key' is somewhere in the chain */ + if (keyisshrstr(n) && eqshrstr(keystrval(n), key)) + return gval(n); /* that's it */ + else { + int nx = gnext(n); + if (nx == 0) + return &absentkey; /* not found */ + n += nx; + } + } +} + + +const TValue *luaH_getstr (Table *t, TString *key) { + if (key->tt == LUA_VSHRSTR) + 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, 0); + } +} + + +/* +** main search function +*/ +const TValue *luaH_get (Table *t, const TValue *key) { + switch (ttypetag(key)) { + case LUA_VSHRSTR: return luaH_getshortstr(t, tsvalue(key)); + case LUA_VNUMINT: return luaH_getint(t, ivalue(key)); + case LUA_VNIL: return &absentkey; + case LUA_VNUMFLT: { + lua_Integer k; + if (luaV_flttointeger(fltvalue(key), &k, F2Ieq)) /* integral index? */ + return luaH_getint(t, k); /* use specialized version */ + /* else... */ + } /* FALLTHROUGH */ + default: + return getgeneric(t, key, 0); + } +} + + +/* +** Finish a raw "set table" operation, where 'slot' is where the value +** should have been (the result of a previous "get table"). +** Beware: when using this function you probably need to check a GC +** barrier and invalidate the TM cache. +*/ +void luaH_finishset (lua_State *L, Table *t, const TValue *key, + const TValue *slot, TValue *value) { + if (isabstkey(slot)) + luaH_newkey(L, t, key, value); + else + setobj2t(L, cast(TValue *, slot), value); +} + + +/* +** beware: when using this function you probably need to check a GC +** barrier and invalidate the TM cache. +*/ +void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) { + const TValue *slot = luaH_get(t, key); + luaH_finishset(L, t, key, slot, value); +} + + +void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { + const TValue *p = luaH_getint(t, key); + if (isabstkey(p)) { + TValue k; + setivalue(&k, key); + luaH_newkey(L, t, &k, value); + } + else + setobj2t(L, cast(TValue *, p), value); +} + + +/* +** Try to find a boundary in the hash part of table 't'. From the +** caller, we know that 'j' is zero or present and that 'j + 1' is +** present. We want to find a larger key that is absent from the +** table, so that we can do a binary search between the two keys to +** find a boundary. We keep doubling 'j' until we get an absent index. +** If the doubling would overflow, we try LUA_MAXINTEGER. If it is +** absent, we are ready for the binary search. ('j', being max integer, +** is larger or equal to 'i', but it cannot be equal because it is +** absent while 'i' is present; so 'j > i'.) Otherwise, 'j' is a +** boundary. ('j + 1' cannot be a present integer key because it is +** not a valid integer in Lua.) +*/ +static lua_Unsigned hash_search (Table *t, lua_Unsigned j) { + lua_Unsigned i; + if (j == 0) j++; /* the caller ensures 'j + 1' is present */ + do { + i = j; /* 'i' is a present index */ + if (j <= l_castS2U(LUA_MAXINTEGER) / 2) + j *= 2; + else { + j = LUA_MAXINTEGER; + if (isempty(luaH_getint(t, j))) /* t[j] not present? */ + break; /* 'j' now is an absent index */ + else /* weird case */ + return j; /* well, max integer is a boundary... */ + } + } while (!isempty(luaH_getint(t, j))); /* repeat until an absent t[j] */ + /* i < j && t[i] present && t[j] absent */ + while (j - i > 1u) { /* do a binary search between them */ + lua_Unsigned m = (i + j) / 2; + if (isempty(luaH_getint(t, m))) j = m; + else i = m; + } + return i; +} + + +static unsigned int binsearch (const TValue *array, unsigned int i, + unsigned int j) { + while (j - i > 1u) { /* binary search */ + unsigned int m = (i + j) / 2; + if (isempty(&array[m - 1])) j = m; + else i = m; + } + return i; +} + + +/* +** Try to find a boundary in table 't'. (A 'boundary' is an integer index +** such that t[i] is present and t[i+1] is absent, or 0 if t[1] is absent +** and 'maxinteger' if t[maxinteger] is present.) +** (In the next explanation, we use Lua indices, that is, with base 1. +** The code itself uses base 0 when indexing the array part of the table.) +** The code starts with 'limit = t->alimit', a position in the array +** part that may be a boundary. +** +** (1) If 't[limit]' is empty, there must be a boundary before it. +** As a common case (e.g., after 't[#t]=nil'), check whether 'limit-1' +** is present. If so, it is a boundary. Otherwise, do a binary search +** between 0 and limit to find a boundary. In both cases, try to +** use this boundary as the new 'alimit', as a hint for the next call. +** +** (2) If 't[limit]' is not empty and the array has more elements +** after 'limit', try to find a boundary there. Again, try first +** the special case (which should be quite frequent) where 'limit+1' +** is empty, so that 'limit' is a boundary. Otherwise, check the +** last element of the array part. If it is empty, there must be a +** boundary between the old limit (present) and the last element +** (absent), which is found with a binary search. (This boundary always +** can be a new limit.) +** +** (3) The last case is when there are no elements in the array part +** (limit == 0) or its last element (the new limit) is present. +** In this case, must check the hash part. If there is no hash part +** or 'limit+1' is absent, 'limit' is a boundary. Otherwise, call +** 'hash_search' to find a boundary in the hash part of the table. +** (In those cases, the boundary is not inside the array part, and +** therefore cannot be used as a new limit.) +*/ +lua_Unsigned luaH_getn (Table *t) { + unsigned int limit = t->alimit; + if (limit > 0 && isempty(&t->array[limit - 1])) { /* (1)? */ + /* there must be a boundary before 'limit' */ + if (limit >= 2 && !isempty(&t->array[limit - 2])) { + /* 'limit - 1' is a boundary; can it be a new limit? */ + if (ispow2realasize(t) && !ispow2(limit - 1)) { + t->alimit = limit - 1; + setnorealasize(t); /* now 'alimit' is not the real size */ + } + return limit - 1; + } + else { /* must search for a boundary in [0, limit] */ + unsigned int boundary = binsearch(t->array, 0, limit); + /* can this boundary represent the real size of the array? */ + if (ispow2realasize(t) && boundary > luaH_realasize(t) / 2) { + t->alimit = boundary; /* use it as the new limit */ + setnorealasize(t); + } + return boundary; + } + } + /* 'limit' is zero or present in table */ + if (!limitequalsasize(t)) { /* (2)? */ + /* 'limit' > 0 and array has more elements after 'limit' */ + if (isempty(&t->array[limit])) /* 'limit + 1' is empty? */ + return limit; /* this is the boundary */ + /* else, try last element in the array */ + limit = luaH_realasize(t); + if (isempty(&t->array[limit - 1])) { /* empty? */ + /* there must be a boundary in the array after old limit, + and it must be a valid new limit */ + unsigned int boundary = binsearch(t->array, t->alimit, limit); + t->alimit = boundary; + return boundary; + } + /* else, new limit is present in the table; check the hash part */ + } + /* (3) 'limit' is the last element and either is zero or present in table */ + lua_assert(limit == luaH_realasize(t) && + (limit == 0 || !isempty(&t->array[limit - 1]))); + if (isdummy(t) || isempty(luaH_getint(t, cast(lua_Integer, limit + 1)))) + return limit; /* 'limit + 1' is absent */ + else /* 'limit + 1' is also present */ + return hash_search(t, limit); +} + + + +#if defined(LUA_DEBUG) + +/* export these functions for the test library */ + +Node *luaH_mainposition (const Table *t, const TValue *key) { + return mainpositionTV(t, key); +} + +#endif diff --git a/src/libs/3rdparty/lua/src/ltable.h b/src/libs/3rdparty/lua/src/ltable.h new file mode 100644 index 0000000000..75dd9e26e0 --- /dev/null +++ b/src/libs/3rdparty/lua/src/ltable.h @@ -0,0 +1,65 @@ +/* +** $Id: ltable.h $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + +#ifndef ltable_h +#define ltable_h + +#include "lobject.h" + + +#define gnode(t,i) (&(t)->node[i]) +#define gval(n) (&(n)->i_val) +#define gnext(n) ((n)->u.next) + + +/* +** Clear all bits of fast-access metamethods, which means that the table +** may have any of these metamethods. (First access that fails after the +** clearing will set the bit again.) +*/ +#define invalidateTMcache(t) ((t)->flags &= ~maskflags) + + +/* 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 Node, given the value of a table entry */ +#define nodefromval(v) cast(Node *, (v)) + + +LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); +LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, + TValue *value); +LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); +LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); +LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); +LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key, + TValue *value); +LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key, + TValue *value); +LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key, + const TValue *slot, TValue *value); +LUAI_FUNC Table *luaH_new (lua_State *L); +LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, + unsigned int nhsize); +LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize); +LUAI_FUNC void luaH_free (lua_State *L, Table *t); +LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); +LUAI_FUNC lua_Unsigned luaH_getn (Table *t); +LUAI_FUNC unsigned int luaH_realasize (const Table *t); + + +#if defined(LUA_DEBUG) +LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); +#endif + + +#endif diff --git a/src/libs/3rdparty/lua/src/ltablib.c b/src/libs/3rdparty/lua/src/ltablib.c new file mode 100644 index 0000000000..e6bc4d04af --- /dev/null +++ b/src/libs/3rdparty/lua/src/ltablib.c @@ -0,0 +1,430 @@ +/* +** $Id: ltablib.c $ +** Library for Table Manipulation +** See Copyright Notice in lua.h +*/ + +#define ltablib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include <limits.h> +#include <stddef.h> +#include <string.h> + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** Operations that an object must define to mimic a table +** (some functions only need some of them) +*/ +#define TAB_R 1 /* read */ +#define TAB_W 2 /* write */ +#define TAB_L 4 /* length */ +#define TAB_RW (TAB_R | TAB_W) /* read/write */ + + +#define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n)) + + +static int checkfield (lua_State *L, const char *key, int n) { + lua_pushstring(L, key); + return (lua_rawget(L, -n) != LUA_TNIL); +} + + +/* +** Check that 'arg' 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 */ + } +} + + +static int tinsert (lua_State *L) { + lua_Integer pos; /* where to insert new element */ + lua_Integer e = aux_getn(L, 1, TAB_RW); + e = luaL_intop(+, e, 1); /* first empty element */ + switch (lua_gettop(L)) { + case 2: { /* called with only 2 arguments */ + pos = e; /* insert new element at the end */ + break; + } + case 3: { + lua_Integer i; + pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ + /* check whether 'pos' is in [1, e] */ + luaL_argcheck(L, (lua_Unsigned)pos - 1u < (lua_Unsigned)e, 2, + "position out of bounds"); + for (i = e; i > pos; i--) { /* move up elements */ + lua_geti(L, 1, i - 1); + lua_seti(L, 1, i); /* t[i] = t[i - 1] */ + } + break; + } + default: { + return luaL_error(L, "wrong number of arguments to 'insert'"); + } + } + lua_seti(L, 1, pos); /* t[pos] = v */ + return 0; +} + + +static int tremove (lua_State *L) { + lua_Integer size = aux_getn(L, 1, TAB_RW); + lua_Integer pos = luaL_optinteger(L, 2, size); + if (pos != size) /* validate 'pos' if given */ + /* check whether 'pos' is in [1, size + 1] */ + luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2, + "position out of bounds"); + lua_geti(L, 1, pos); /* result = t[pos] */ + for ( ; pos < size; pos++) { + lua_geti(L, 1, pos + 1); + lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ + } + lua_pushnil(L); + lua_seti(L, 1, pos); /* remove entry t[pos] */ + 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) { + lua_Integer f = luaL_checkinteger(L, 2); + lua_Integer e = luaL_checkinteger(L, 3); + lua_Integer t = luaL_checkinteger(L, 4); + int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ + checktab(L, 1, TAB_R); + checktab(L, tt, TAB_W); + if (e >= f) { /* otherwise, nothing to move */ + lua_Integer n, i; + luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, + "too many elements to move"); + n = e - f + 1; /* number of elements to move */ + luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, + "destination wrap around"); + if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { + for (i = 0; i < n; i++) { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); + } + } + else { + for (i = n - 1; i >= 0; i--) { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); + } + } + } + lua_pushvalue(L, tt); /* return destination table */ + return 1; +} + + +static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { + lua_geti(L, 1, i); + if (l_unlikely(!lua_isstring(L, -1))) + luaL_error(L, "invalid value (%s) at index %I in table for 'concat'", + luaL_typename(L, -1), (LUAI_UACINT)i); + luaL_addvalue(b); +} + + +static int tconcat (lua_State *L) { + luaL_Buffer b; + lua_Integer last = aux_getn(L, 1, TAB_R); + size_t lsep; + const char *sep = luaL_optlstring(L, 2, "", &lsep); + lua_Integer i = luaL_optinteger(L, 3, 1); + last = luaL_optinteger(L, 4, last); + luaL_buffinit(L, &b); + for (; i < last; i++) { + addfield(L, &b, i); + luaL_addlstring(&b, sep, lsep); + } + if (i == last) /* add last value (if interval was not empty) */ + addfield(L, &b, i); + luaL_pushresult(&b); + return 1; +} + + +/* +** {====================================================== +** Pack/unpack +** ======================================================= +*/ + +static int tpack (lua_State *L) { + int i; + int n = lua_gettop(L); /* number of elements to pack */ + lua_createtable(L, n, 1); /* create result table */ + lua_insert(L, 1); /* put it at index 1 */ + for (i = n; i >= 1; i--) /* assign elements */ + lua_seti(L, 1, i); + lua_pushinteger(L, n); + lua_setfield(L, 1, "n"); /* t.n = number of elements */ + return 1; /* return table */ +} + + +static int tunpack (lua_State *L) { + lua_Unsigned n; + lua_Integer i = luaL_optinteger(L, 2, 1); + lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); + if (i > e) return 0; /* empty range */ + n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ + if (l_unlikely(n >= (unsigned int)INT_MAX || + !lua_checkstack(L, (int)(++n)))) + return luaL_error(L, "too many results to unpack"); + for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ + lua_geti(L, 1, i); + } + lua_geti(L, 1, e); /* push last element */ + return (int)n; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** Quicksort +** (based on 'Algorithms in MODULA-3', Robert Sedgewick; +** Addison-Wesley, 1993.) +** ======================================================= +*/ + + +/* type for array indices */ +typedef unsigned int IdxT; + + +/* +** Produce a "random" 'unsigned int' to randomize pivot choice. This +** macro is used only when 'sort' detects a big imbalance in the result +** of a partition. (If you don't want/need this "randomness", ~0 is a +** good choice.) +*/ +#if !defined(l_randomizePivot) /* { */ + +#include <time.h> + +/* size of 'e' measured in number of 'unsigned int's */ +#define sof(e) (sizeof(e) / sizeof(unsigned int)) + +/* +** Use 'time' and 'clock' as sources of "randomness". Because we don't +** know the types 'clock_t' and 'time_t', we cannot cast them to +** anything without risking overflows. A safe way to use their values +** is to copy them to an array of a known type and use the array values. +*/ +static unsigned int l_randomizePivot (void) { + clock_t c = clock(); + time_t t = time(NULL); + unsigned int buff[sof(c) + sof(t)]; + unsigned int i, rnd = 0; + memcpy(buff, &c, sof(c) * sizeof(unsigned int)); + memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); + for (i = 0; i < sof(buff); i++) + rnd += buff[i]; + return rnd; +} + +#endif /* } */ + + +/* arrays larger than 'RANLIMIT' may use randomized pivots */ +#define RANLIMIT 100u + + +static void set2 (lua_State *L, IdxT i, IdxT j) { + lua_seti(L, 1, i); + lua_seti(L, 1, j); +} + + +/* +** Return true iff value at stack index 'a' is less than the value at +** index 'b' (according to the order of the sort). +*/ +static int sort_comp (lua_State *L, int a, int b) { + if (lua_isnil(L, 2)) /* no function? */ + return lua_compare(L, a, b, LUA_OPLT); /* a < b */ + else { /* function */ + int res; + lua_pushvalue(L, 2); /* push function */ + lua_pushvalue(L, a-1); /* -1 to compensate function */ + lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ + lua_call(L, 2, 1); /* call function */ + res = lua_toboolean(L, -1); /* get result */ + lua_pop(L, 1); /* pop result */ + return res; + } +} + + +/* +** Does the partition: Pivot P is at the top of the stack. +** precondition: a[lo] <= P == a[up-1] <= a[up], +** so it only needs to do the partition from lo + 1 to up - 2. +** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] +** returns 'i'. +*/ +static IdxT partition (lua_State *L, IdxT lo, IdxT up) { + IdxT i = lo; /* will be incremented before first use */ + IdxT j = up - 1; /* will be decremented before first use */ + /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ + for (;;) { + /* next loop: repeat ++i while a[i] < P */ + while ((void)lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { + if (l_unlikely(i == up - 1)) /* a[i] < P but a[up - 1] == P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[i] */ + } + /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ + /* next loop: repeat --j while P < a[j] */ + while ((void)lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { + if (l_unlikely(j < i)) /* j < i but a[j] > P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[j] */ + } + /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ + if (j < i) { /* no elements out of place? */ + /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ + lua_pop(L, 1); /* pop a[j] */ + /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ + set2(L, up - 1, i); + return i; + } + /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ + set2(L, i, j); + } +} + + +/* +** Choose an element in the middle (2nd-3th quarters) of [lo,up] +** "randomized" by 'rnd' +*/ +static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { + IdxT r4 = (up - lo) / 4; /* range/4 */ + IdxT p = rnd % (r4 * 2) + (lo + r4); + lua_assert(lo + r4 <= p && p <= up - r4); + return p; +} + + +/* +** Quicksort algorithm (recursive function) +*/ +static void auxsort (lua_State *L, IdxT lo, IdxT up, + unsigned int rnd) { + while (lo < up) { /* loop for tail recursion */ + IdxT p; /* Pivot index */ + IdxT n; /* to be used later */ + /* sort elements 'lo', 'p', and 'up' */ + lua_geti(L, 1, lo); + lua_geti(L, 1, up); + if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ + set2(L, lo, up); /* swap a[lo] - a[up] */ + else + lua_pop(L, 2); /* 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) { + lua_Integer n = aux_getn(L, 1, TAB_RW); + if (n > 1) { /* non-trivial interval? */ + luaL_argcheck(L, n < INT_MAX, 1, "array too big"); + if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ + luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ + lua_settop(L, 2); /* make sure there are two arguments */ + auxsort(L, 1, (IdxT)n, 0); + } + return 0; +} + +/* }====================================================== */ + + +static const luaL_Reg tab_funcs[] = { + {"concat", tconcat}, + {"insert", tinsert}, + {"pack", tpack}, + {"unpack", tunpack}, + {"remove", tremove}, + {"move", tmove}, + {"sort", sort}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_table (lua_State *L) { + luaL_newlib(L, tab_funcs); + return 1; +} + diff --git a/src/libs/3rdparty/lua/src/ltm.c b/src/libs/3rdparty/lua/src/ltm.c new file mode 100644 index 0000000000..07a060811d --- /dev/null +++ b/src/libs/3rdparty/lua/src/ltm.c @@ -0,0 +1,271 @@ +/* +** $Id: ltm.c $ +** Tag methods +** See Copyright Notice in lua.h +*/ + +#define ltm_c +#define LUA_CORE + +#include "lprefix.h" + + +#include <string.h> + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + +static const char udatatypename[] = "userdata"; + +LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTYPES] = { + "no value", + "nil", "boolean", udatatypename, "number", + "string", "table", "function", udatatypename, "thread", + "upvalue", "proto" /* these last cases are used for tests only */ +}; + + +void luaT_init (lua_State *L) { + static const char *const luaT_eventname[] = { /* ORDER TM */ + "__index", "__newindex", + "__gc", "__mode", "__len", "__eq", + "__add", "__sub", "__mul", "__mod", "__pow", + "__div", "__idiv", + "__band", "__bor", "__bxor", "__shl", "__shr", + "__unm", "__bnot", "__lt", "__le", + "__concat", "__call", "__close" + }; + int i; + for (i=0; i<TM_N; i++) { + G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]); + luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */ + } +} + + +/* +** function to be used with macro "fasttm": optimized for absence of +** tag methods +*/ +const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { + const TValue *tm = luaH_getshortstr(events, ename); + lua_assert(event <= TM_EQ); + if (notm(tm)) { /* no tag method? */ + events->flags |= cast_byte(1u<<event); /* cache this fact */ + return NULL; + } + else return tm; +} + + +const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { + Table *mt; + switch (ttype(o)) { + case LUA_TTABLE: + mt = hvalue(o)->metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(o)->metatable; + break; + default: + mt = G(L)->mt[ttype(o)]; + } + return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : &G(L)->nilvalue); +} + + +/* +** 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(ttype(o)); /* else use standard type name */ +} + + +void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, const TValue *p3) { + StkId func = L->top.p; + setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ + setobj2s(L, func + 1, p1); /* 1st argument */ + setobj2s(L, func + 2, p2); /* 2nd argument */ + setobj2s(L, func + 3, p3); /* 3rd argument */ + L->top.p = func + 4; + /* metamethod may yield only when called from Lua code */ + if (isLuacode(L->ci)) + luaD_call(L, func, 0); + else + luaD_callnoyield(L, func, 0); +} + + +void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, StkId res) { + ptrdiff_t result = savestack(L, res); + StkId func = L->top.p; + setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ + setobj2s(L, func + 1, p1); /* 1st argument */ + setobj2s(L, func + 2, p2); /* 2nd argument */ + L->top.p += 3; + /* metamethod may yield only when called from Lua code */ + if (isLuacode(L->ci)) + luaD_call(L, func, 1); + else + luaD_callnoyield(L, func, 1); + res = restorestack(L, result); + setobjs2s(L, res, --L->top.p); /* move result to its place */ +} + + +static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event) { + const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ + if (notm(tm)) + tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ + if (notm(tm)) return 0; + luaT_callTMres(L, tm, p1, p2, res); + return 1; +} + + +void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event) { + if (l_unlikely(!callbinTM(L, p1, p2, res, event))) { + switch (event) { + case TM_BAND: case TM_BOR: case TM_BXOR: + case TM_SHL: case TM_SHR: case TM_BNOT: { + if (ttisnumber(p1) && ttisnumber(p2)) + luaG_tointerror(L, p1, p2); + else + luaG_opinterror(L, p1, p2, "perform bitwise operation on"); + } + /* calls never return, but to avoid warnings: *//* FALLTHROUGH */ + default: + luaG_opinterror(L, p1, p2, "perform arithmetic on"); + } + } +} + + +void luaT_tryconcatTM (lua_State *L) { + StkId top = L->top.p; + if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2, + TM_CONCAT))) + luaG_concaterror(L, s2v(top - 2), s2v(top - 1)); +} + + +void luaT_trybinassocTM (lua_State *L, const TValue *p1, const TValue *p2, + int flip, StkId res, TMS event) { + if (flip) + luaT_trybinTM(L, p2, p1, res, event); + else + luaT_trybinTM(L, p1, p2, res, event); +} + + +void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2, + int flip, StkId res, TMS event) { + TValue aux; + setivalue(&aux, i2); + luaT_trybinassocTM(L, p1, &aux, flip, res, event); +} + + +/* +** Calls an order tag method. +** For lessequal, LUA_COMPAT_LT_LE keeps compatibility with old +** behavior: if 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 luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, + TMS event) { + if (callbinTM(L, p1, p2, L->top.p, event)) /* try original event */ + return !l_isfalse(s2v(L->top.p)); +#if defined(LUA_COMPAT_LT_LE) + else if (event == TM_LE) { + /* try '!(p2 < p1)' for '(p1 <= p2)' */ + L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ + if (callbinTM(L, p2, p1, L->top.p, TM_LT)) { + L->ci->callstatus ^= CIST_LEQ; /* clear mark */ + return l_isfalse(s2v(L->top.p)); + } + /* else error will remove this 'ci'; no need to clear mark */ + } +#endif + luaG_ordererror(L, p1, p2); /* no metamethod found */ + return 0; /* to avoid warnings */ +} + + +int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, + int flip, int isfloat, TMS event) { + TValue aux; const TValue *p2; + if (isfloat) { + setfltvalue(&aux, cast_num(v2)); + } + else + setivalue(&aux, v2); + if (flip) { /* arguments were exchanged? */ + p2 = p1; p1 = &aux; /* correct them */ + } + else + p2 = &aux; + return luaT_callorderTM(L, p1, p2, event); +} + + +void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci, + const Proto *p) { + int i; + int actual = cast_int(L->top.p - ci->func.p) - 1; /* number of arguments */ + int nextra = actual - nfixparams; /* number of extra arguments */ + ci->u.l.nextraargs = nextra; + luaD_checkstack(L, p->maxstacksize + 1); + /* copy function to the top of the stack */ + setobjs2s(L, L->top.p++, ci->func.p); + /* move fixed parameters to the top of the stack */ + for (i = 1; i <= nfixparams; i++) { + setobjs2s(L, L->top.p++, ci->func.p + i); + setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */ + } + ci->func.p += actual + 1; + ci->top.p += actual + 1; + lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p); +} + + +void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) { + int i; + int nextra = ci->u.l.nextraargs; + if (wanted < 0) { + wanted = nextra; /* get all extra arguments available */ + checkstackGCp(L, nextra, where); /* ensure stack space */ + L->top.p = where + nextra; /* next instruction will need top */ + } + for (i = 0; i < wanted && i < nextra; i++) + setobjs2s(L, where + i, ci->func.p - nextra + i); + for (; i < wanted; i++) /* complete required results with nil */ + setnilvalue(s2v(where + i)); +} + diff --git a/src/libs/3rdparty/lua/src/ltm.h b/src/libs/3rdparty/lua/src/ltm.h new file mode 100644 index 0000000000..c309e2ae10 --- /dev/null +++ b/src/libs/3rdparty/lua/src/ltm.h @@ -0,0 +1,104 @@ +/* +** $Id: ltm.h $ +** Tag methods +** See Copyright Notice in lua.h +*/ + +#ifndef ltm_h +#define ltm_h + + +#include "lobject.h" +#include "lstate.h" + + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER TM" and "ORDER OP" +*/ +typedef enum { + TM_INDEX, + TM_NEWINDEX, + TM_GC, + TM_MODE, + TM_LEN, + TM_EQ, /* last tag method with fast access */ + TM_ADD, + TM_SUB, + TM_MUL, + TM_MOD, + TM_POW, + TM_DIV, + TM_IDIV, + TM_BAND, + TM_BOR, + TM_BXOR, + TM_SHL, + TM_SHR, + TM_UNM, + TM_BNOT, + TM_LT, + TM_LE, + TM_CONCAT, + TM_CALL, + TM_CLOSE, + TM_N /* number of elements in the enum */ +} TMS; + + +/* +** Mask with 1 in all fast-access methods. A 1 in any of these bits +** in the flag of a (meta)table means the metatable does not have the +** corresponding metamethod field. (Bit 7 of the flag is used for +** 'isrealasize'.) +*/ +#define maskflags (~(~0u << (TM_EQ + 1))) + + +/* +** Test whether there is no tagmethod. +** (Because tagmethods use raw accesses, the result may be an "empty" nil.) +*/ +#define notm(tm) ttisnil(tm) + + +#define gfasttm(g,et,e) ((et) == NULL ? NULL : \ + ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) + +#define fasttm(l,et,e) gfasttm(G(l), et, e) + +#define ttypename(x) luaT_typenames_[(x) + 1] + +LUAI_DDEC(const char *const luaT_typenames_[LUA_TOTALTYPES];) + + +LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o); + +LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); +LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, + TMS event); +LUAI_FUNC void luaT_init (lua_State *L); + +LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, const TValue *p3); +LUAI_FUNC void luaT_callTMres (lua_State *L, const TValue *f, + const TValue *p1, const TValue *p2, StkId p3); +LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event); +LUAI_FUNC void luaT_tryconcatTM (lua_State *L); +LUAI_FUNC void luaT_trybinassocTM (lua_State *L, const TValue *p1, + const TValue *p2, int inv, StkId res, TMS event); +LUAI_FUNC void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2, + int inv, StkId res, TMS event); +LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, + const TValue *p2, TMS event); +LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, + int inv, int isfloat, TMS event); + +LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams, + CallInfo *ci, const Proto *p); +LUAI_FUNC void luaT_getvarargs (lua_State *L, CallInfo *ci, + StkId where, int wanted); + + +#endif diff --git a/src/libs/3rdparty/lua/src/lua.c b/src/libs/3rdparty/lua/src/lua.c new file mode 100644 index 0000000000..0ff8845453 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lua.c @@ -0,0 +1,679 @@ +/* +** $Id: lua.c $ +** Lua stand-alone interpreter +** See Copyright Notice in lua.h +*/ + +#define lua_c + +#include "lprefix.h" + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <signal.h> + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#if !defined(LUA_PROGNAME) +#define LUA_PROGNAME "lua" +#endif + +#if !defined(LUA_INIT_VAR) +#define LUA_INIT_VAR "LUA_INIT" +#endif + +#define LUA_INITVARVERSION LUA_INIT_VAR LUA_VERSUFFIX + + +static lua_State *globalL = NULL; + +static const char *progname = LUA_PROGNAME; + + +#if defined(LUA_USE_POSIX) /* { */ + +/* +** Use 'sigaction' when available. +*/ +static void setsignal (int sig, void (*handler)(int)) { + struct sigaction sa; + sa.sa_handler = handler; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); /* do not mask any signal */ + sigaction(sig, &sa, NULL); +} + +#else /* }{ */ + +#define setsignal signal + +#endif /* } */ + + +/* +** Hook set by signal function to stop the interpreter. +*/ +static void lstop (lua_State *L, lua_Debug *ar) { + (void)ar; /* unused arg. */ + lua_sethook(L, NULL, 0, 0); /* reset hook */ + luaL_error(L, "interrupted!"); +} + + +/* +** Function to be called at a C signal. Because a C signal cannot +** just change a Lua state (as there is no proper synchronization), +** this function only sets a hook that, when called, will stop the +** interpreter. +*/ +static void laction (int i) { + int flag = LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE | LUA_MASKCOUNT; + setsignal(i, SIG_DFL); /* if another SIGINT happens, terminate process */ + lua_sethook(globalL, lstop, flag, 1); +} + + +static void print_usage (const char *badoption) { + lua_writestringerror("%s: ", progname); + if (badoption[1] == 'e' || badoption[1] == 'l') + lua_writestringerror("'%s' needs argument\n", badoption); + else + lua_writestringerror("unrecognized option '%s'\n", badoption); + lua_writestringerror( + "usage: %s [options] [script [args]]\n" + "Available options are:\n" + " -e stat execute string 'stat'\n" + " -i enter interactive mode after executing 'script'\n" + " -l mod require library 'mod' into global 'mod'\n" + " -l g=mod require library 'mod' into global 'g'\n" + " -v show version information\n" + " -E ignore environment variables\n" + " -W turn warnings on\n" + " -- stop handling options\n" + " - stop handling options and execute stdin\n" + , + progname); +} + + +/* +** Prints an error message, adding the program name in front of it +** (if present) +*/ +static void l_message (const char *pname, const char *msg) { + if (pname) lua_writestringerror("%s: ", pname); + lua_writestringerror("%s\n", msg); +} + + +/* +** Check whether 'status' is not OK and, if so, prints the error +** message on the top of the stack. It assumes that the error object +** is a string, as it was either generated by Lua or by 'msghandler'. +*/ +static int report (lua_State *L, int status) { + if (status != LUA_OK) { + const char *msg = lua_tostring(L, -1); + l_message(progname, msg); + lua_pop(L, 1); /* remove message */ + } + return status; +} + + +/* +** Message handler used to run all chunks +*/ +static int msghandler (lua_State *L) { + const char *msg = lua_tostring(L, 1); + if (msg == NULL) { /* is error object not a string? */ + if (luaL_callmeta(L, 1, "__tostring") && /* does it have a metamethod */ + lua_type(L, -1) == LUA_TSTRING) /* that produces a string? */ + return 1; /* that is the message */ + else + msg = lua_pushfstring(L, "(error object is a %s value)", + luaL_typename(L, 1)); + } + luaL_traceback(L, L, msg, 1); /* append a standard traceback */ + return 1; /* return the traceback */ +} + + +/* +** Interface to 'lua_pcall', which sets appropriate message function +** and C-signal handler. Used to run all chunks. +*/ +static int docall (lua_State *L, int narg, int nres) { + int status; + int base = lua_gettop(L) - narg; /* function index */ + lua_pushcfunction(L, msghandler); /* push message handler */ + lua_insert(L, base); /* put it under function and args */ + globalL = L; /* to be available to 'laction' */ + setsignal(SIGINT, laction); /* set C-signal handler */ + status = lua_pcall(L, narg, nres, base); + setsignal(SIGINT, SIG_DFL); /* reset C-signal handler */ + lua_remove(L, base); /* remove message handler from the stack */ + return status; +} + + +static void print_version (void) { + lua_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT)); + lua_writeline(); +} + + +/* +** Create the 'arg' table, which stores all arguments from the +** command line ('argv'). It should be aligned so that, at index 0, +** it has 'argv[script]', which is the script name. The arguments +** to the script (everything after 'script') go to positive indices; +** other arguments (before the script name) go to negative indices. +** If there is no script name, assume interpreter's name as base. +** (If there is no interpreter's name either, 'script' is -1, so +** table sizes are zero.) +*/ +static void createargtable (lua_State *L, char **argv, int argc, int script) { + int i, narg; + narg = argc - (script + 1); /* number of positive indices */ + lua_createtable(L, narg, script + 1); + for (i = 0; i < argc; i++) { + lua_pushstring(L, argv[i]); + lua_rawseti(L, -2, i - script); + } + lua_setglobal(L, "arg"); +} + + +static int dochunk (lua_State *L, int status) { + if (status == LUA_OK) status = docall(L, 0, 0); + return report(L, status); +} + + +static int dofile (lua_State *L, const char *name) { + return dochunk(L, luaL_loadfile(L, name)); +} + + +static int dostring (lua_State *L, const char *s, const char *name) { + return dochunk(L, luaL_loadbuffer(L, s, strlen(s), name)); +} + + +/* +** Receives 'globname[=modname]' and runs 'globname = require(modname)'. +*/ +static int dolibrary (lua_State *L, char *globname) { + int status; + char *modname = strchr(globname, '='); + if (modname == NULL) /* no explicit name? */ + modname = globname; /* module name is equal to global name */ + else { + *modname = '\0'; /* global name ends here */ + modname++; /* module name starts after the '=' */ + } + lua_getglobal(L, "require"); + lua_pushstring(L, modname); + status = docall(L, 1, 1); /* call 'require(modname)' */ + if (status == LUA_OK) + lua_setglobal(L, globname); /* globname = require(modname) */ + return report(L, status); +} + + +/* +** Push on the stack the contents of table 'arg' from 1 to #arg +*/ +static int pushargs (lua_State *L) { + int i, n; + if (lua_getglobal(L, "arg") != LUA_TTABLE) + luaL_error(L, "'arg' is not a table"); + n = (int)luaL_len(L, -1); + luaL_checkstack(L, n + 3, "too many arguments to script"); + for (i = 1; i <= n; i++) + lua_rawgeti(L, -i, i); + lua_remove(L, -i); /* remove table from the stack */ + return n; +} + + +static int handle_script (lua_State *L, char **argv) { + int status; + const char *fname = argv[0]; + if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0) + fname = NULL; /* stdin */ + status = luaL_loadfile(L, fname); + if (status == LUA_OK) { + int n = pushargs(L); /* push arguments to script */ + status = docall(L, n, LUA_MULTRET); + } + return report(L, status); +} + + +/* bits of various argument indicators in 'args' */ +#define has_error 1 /* bad option */ +#define has_i 2 /* -i */ +#define has_v 4 /* -v */ +#define has_e 8 /* -e */ +#define has_E 16 /* -E */ + + +/* +** Traverses all arguments from 'argv', returning a mask with those +** needed before running any Lua code or an error code if it finds any +** invalid argument. In case of error, 'first' is the index of the bad +** argument. Otherwise, 'first' is -1 if there is no program name, +** 0 if there is no script name, or the index of the script name. +*/ +static int collectargs (char **argv, int *first) { + int args = 0; + int i; + if (argv[0] != NULL) { /* is there a program name? */ + if (argv[0][0]) /* not empty? */ + progname = argv[0]; /* save it */ + } + else { /* no program name */ + *first = -1; + return 0; + } + for (i = 1; argv[i] != NULL; i++) { /* handle arguments */ + *first = i; + if (argv[i][0] != '-') /* not an option? */ + return args; /* stop handling options */ + switch (argv[i][1]) { /* else check option */ + case '-': /* '--' */ + if (argv[i][2] != '\0') /* extra characters after '--'? */ + return has_error; /* invalid option */ + *first = i + 1; + return args; + case '\0': /* '-' */ + return args; /* script "name" is '-' */ + case 'E': + if (argv[i][2] != '\0') /* extra characters? */ + return has_error; /* invalid option */ + args |= has_E; + break; + case 'W': + if (argv[i][2] != '\0') /* extra characters? */ + return has_error; /* invalid option */ + break; + case 'i': + args |= has_i; /* (-i implies -v) *//* FALLTHROUGH */ + case 'v': + if (argv[i][2] != '\0') /* extra characters? */ + return has_error; /* invalid option */ + args |= has_v; + break; + case 'e': + args |= has_e; /* FALLTHROUGH */ + case 'l': /* both options need an argument */ + if (argv[i][2] == '\0') { /* no concatenated argument? */ + i++; /* try next 'argv' */ + if (argv[i] == NULL || argv[i][0] == '-') + return has_error; /* no next argument or it is another option */ + } + break; + default: /* invalid option */ + return has_error; + } + } + *first = 0; /* no script name */ + return args; +} + + +/* +** Processes options 'e' and 'l', which involve running Lua code, and +** 'W', which also affects the state. +** Returns 0 if some code raises an error. +*/ +static int runargs (lua_State *L, char **argv, int n) { + int i; + for (i = 1; i < n; i++) { + int option = argv[i][1]; + lua_assert(argv[i][0] == '-'); /* already checked */ + switch (option) { + case 'e': case 'l': { + int status; + char *extra = argv[i] + 2; /* both options need an argument */ + if (*extra == '\0') extra = argv[++i]; + lua_assert(extra != NULL); + status = (option == 'e') + ? dostring(L, extra, "=(command line)") + : dolibrary(L, extra); + if (status != LUA_OK) return 0; + break; + } + case 'W': + lua_warning(L, "@on", 0); /* warnings on */ + break; + } + } + return 1; +} + + +static int handle_luainit (lua_State *L) { + const char *name = "=" LUA_INITVARVERSION; + const char *init = getenv(name + 1); + if (init == NULL) { + name = "=" LUA_INIT_VAR; + init = getenv(name + 1); /* try alternative name */ + } + if (init == NULL) return LUA_OK; + else if (init[0] == '@') + return dofile(L, init+1); + else + return dostring(L, init, name); +} + + +/* +** {================================================================== +** Read-Eval-Print Loop (REPL) +** =================================================================== +*/ + +#if !defined(LUA_PROMPT) +#define LUA_PROMPT "> " +#define LUA_PROMPT2 ">> " +#endif + +#if !defined(LUA_MAXINPUT) +#define LUA_MAXINPUT 512 +#endif + + +/* +** lua_stdin_is_tty detects whether the standard input is a 'tty' (that +** is, whether we're running lua interactively). +*/ +#if !defined(lua_stdin_is_tty) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#include <unistd.h> +#define lua_stdin_is_tty() isatty(0) + +#elif defined(LUA_USE_WINDOWS) /* }{ */ + +#include <io.h> +#include <windows.h> + +#define lua_stdin_is_tty() _isatty(_fileno(stdin)) + +#else /* }{ */ + +/* ISO C definition */ +#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ + +#endif /* } */ + +#endif /* } */ + + +/* +** lua_readline defines how to show a prompt and then read a line from +** the standard input. +** lua_saveline defines how to "save" a read line in a "history". +** lua_freeline defines how to free a line read by lua_readline. +*/ +#if !defined(lua_readline) /* { */ + +#if defined(LUA_USE_READLINE) /* { */ + +#include <readline/readline.h> +#include <readline/history.h> +#define lua_initreadline(L) ((void)L, rl_readline_name="lua") +#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) +#define lua_saveline(L,line) ((void)L, add_history(line)) +#define lua_freeline(L,b) ((void)L, free(b)) + +#else /* }{ */ + +#define lua_initreadline(L) ((void)L) +#define lua_readline(L,b,p) \ + ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ + fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ +#define lua_saveline(L,line) { (void)L; (void)line; } +#define lua_freeline(L,b) { (void)L; (void)b; } + +#endif /* } */ + +#endif /* } */ + + +/* +** Return the string to be used as a prompt by the interpreter. Leave +** the string (or nil, if using the default value) on the stack, to keep +** it anchored. +*/ +static const char *get_prompt (lua_State *L, int firstline) { + if (lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2") == LUA_TNIL) + return (firstline ? LUA_PROMPT : LUA_PROMPT2); /* use the default */ + else { /* apply 'tostring' over the value */ + const char *p = luaL_tolstring(L, -1, NULL); + lua_remove(L, -2); /* remove original value */ + return p; + } +} + +/* mark in error messages for incomplete statements */ +#define EOFMARK "<eof>" +#define marklen (sizeof(EOFMARK)/sizeof(char) - 1) + + +/* +** Check whether 'status' signals a syntax error and the error +** message at the top of the stack ends with the above mark for +** incomplete statements. +*/ +static int incomplete (lua_State *L, int status) { + if (status == LUA_ERRSYNTAX) { + size_t lmsg; + const char *msg = lua_tolstring(L, -1, &lmsg); + if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) { + lua_pop(L, 1); + return 1; + } + } + return 0; /* else... */ +} + + +/* +** Prompt the user, read a line, and push it into the Lua stack. +*/ +static int pushline (lua_State *L, int firstline) { + char buffer[LUA_MAXINPUT]; + char *b = buffer; + size_t l; + const char *prmt = get_prompt(L, firstline); + int readstatus = lua_readline(L, b, prmt); + if (readstatus == 0) + return 0; /* no input (prompt will be popped by caller) */ + lua_pop(L, 1); /* remove prompt */ + l = strlen(b); + if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ + b[--l] = '\0'; /* remove it */ + if (firstline && b[0] == '=') /* for compatibility with 5.2, ... */ + lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */ + else + lua_pushlstring(L, b, l); + lua_freeline(L, b); + return 1; +} + + +/* +** Try to compile line on the stack as 'return <line>;'; on return, stack +** has either compiled chunk or original line (if compilation failed). +*/ +static int addreturn (lua_State *L) { + const char *line = lua_tostring(L, -1); /* original line */ + const char *retline = lua_pushfstring(L, "return %s;", line); + int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin"); + if (status == LUA_OK) { + lua_remove(L, -2); /* remove modified line */ + if (line[0] != '\0') /* non empty? */ + lua_saveline(L, line); /* keep history */ + } + else + lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */ + return status; +} + + +/* +** Read multiple lines until a complete Lua statement +*/ +static int multiline (lua_State *L) { + for (;;) { /* repeat until gets a complete statement */ + size_t len; + const char *line = lua_tolstring(L, 1, &len); /* get what it has */ + int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */ + if (!incomplete(L, status) || !pushline(L, 0)) { + lua_saveline(L, line); /* keep history */ + return status; /* cannot or should not try to add continuation line */ + } + lua_pushliteral(L, "\n"); /* add newline... */ + lua_insert(L, -2); /* ...between the two lines */ + lua_concat(L, 3); /* join them */ + } +} + + +/* +** Read a line and try to load (compile) it first as an expression (by +** adding "return " in front of it) and second as a statement. Return +** the final status of load/call with the resulting function (if any) +** in the top of the stack. +*/ +static int loadline (lua_State *L) { + int status; + lua_settop(L, 0); + if (!pushline(L, 1)) + return -1; /* no input */ + if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */ + status = multiline(L); /* try as command, maybe with continuation lines */ + lua_remove(L, 1); /* remove line from the stack */ + lua_assert(lua_gettop(L) == 1); + return status; +} + + +/* +** Prints (calling the Lua 'print' function) any values on the stack +*/ +static void l_print (lua_State *L) { + int n = lua_gettop(L); + if (n > 0) { /* any result to be printed? */ + luaL_checkstack(L, LUA_MINSTACK, "too many results to print"); + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, n, 0, 0) != LUA_OK) + l_message(progname, lua_pushfstring(L, "error calling 'print' (%s)", + lua_tostring(L, -1))); + } +} + + +/* +** Do the REPL: repeatedly read (load) a line, evaluate (call) it, and +** print any results. +*/ +static void doREPL (lua_State *L) { + int status; + const char *oldprogname = progname; + progname = NULL; /* no 'progname' on errors in interactive mode */ + lua_initreadline(L); + while ((status = loadline(L)) != -1) { + if (status == LUA_OK) + status = docall(L, 0, LUA_MULTRET); + if (status == LUA_OK) l_print(L); + else report(L, status); + } + lua_settop(L, 0); /* clear stack */ + lua_writeline(); + progname = oldprogname; +} + +/* }================================================================== */ + + +/* +** Main body of stand-alone interpreter (to be called in protected mode). +** Reads the options and handles them all. +*/ +static int pmain (lua_State *L) { + int argc = (int)lua_tointeger(L, 1); + char **argv = (char **)lua_touserdata(L, 2); + int script; + int args = collectargs(argv, &script); + int optlim = (script > 0) ? script : argc; /* first argv not an option */ + luaL_checkversion(L); /* check that interpreter has correct version */ + if (args == has_error) { /* bad arg? */ + print_usage(argv[script]); /* 'script' has index of bad arg. */ + return 0; + } + if (args & has_v) /* option '-v'? */ + print_version(); + if (args & has_E) { /* option '-E'? */ + lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */ + lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); + } + luaL_openlibs(L); /* open standard libraries */ + createargtable(L, argv, argc, script); /* create table 'arg' */ + lua_gc(L, LUA_GCRESTART); /* start GC... */ + lua_gc(L, LUA_GCGEN, 0, 0); /* ...in generational mode */ + if (!(args & has_E)) { /* no option '-E'? */ + if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */ + return 0; /* error running LUA_INIT */ + } + if (!runargs(L, argv, optlim)) /* execute arguments -e and -l */ + return 0; /* something failed */ + if (script > 0) { /* execute main script (if there is one) */ + if (handle_script(L, argv + script) != LUA_OK) + return 0; /* interrupt in case of error */ + } + if (args & has_i) /* -i option? */ + doREPL(L); /* do read-eval-print loop */ + else if (script < 1 && !(args & (has_e | has_v))) { /* no active option? */ + if (lua_stdin_is_tty()) { /* running in interactive mode? */ + print_version(); + doREPL(L); /* do read-eval-print loop */ + } + else dofile(L, NULL); /* executes stdin as a file */ + } + lua_pushboolean(L, 1); /* signal no errors */ + return 1; +} + + +int main (int argc, char **argv) { + int status, result; + lua_State *L = luaL_newstate(); /* create state */ + if (L == NULL) { + l_message(argv[0], "cannot create state: not enough memory"); + return EXIT_FAILURE; + } + lua_gc(L, LUA_GCSTOP); /* stop GC while building state */ + lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */ + lua_pushinteger(L, argc); /* 1st argument */ + lua_pushlightuserdata(L, argv); /* 2nd argument */ + status = lua_pcall(L, 2, 1, 0); /* do the call */ + result = lua_toboolean(L, -1); /* get result */ + report(L, status); + lua_close(L); + return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE; +} + diff --git a/src/libs/3rdparty/lua/src/lua.h b/src/libs/3rdparty/lua/src/lua.h new file mode 100644 index 0000000000..fd16cf8050 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lua.h @@ -0,0 +1,523 @@ +/* +** $Id: lua.h $ +** Lua - A Scripting Language +** Lua.org, PUC-Rio, Brazil (http://www.lua.org) +** See Copyright Notice at the end of this file +*/ + + +#ifndef lua_h +#define lua_h + +#include <stdarg.h> +#include <stddef.h> + + +#include "luaconf.h" + + +#define LUA_VERSION_MAJOR "5" +#define LUA_VERSION_MINOR "4" +#define LUA_VERSION_RELEASE "6" + +#define LUA_VERSION_NUM 504 +#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 6) + +#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR +#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio" +#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" + + +/* mark for precompiled code ('<esc>Lua') */ +#define LUA_SIGNATURE "\x1bLua" + +/* option for multiple returns in 'lua_pcall' and 'lua_call' */ +#define LUA_MULTRET (-1) + + +/* +** 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_MAXSTACK - 1000) +#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) + + +/* thread status */ +#define LUA_OK 0 +#define LUA_YIELD 1 +#define LUA_ERRRUN 2 +#define LUA_ERRSYNTAX 3 +#define LUA_ERRMEM 4 +#define LUA_ERRERR 5 + + +typedef struct lua_State lua_State; + + +/* +** basic types +*/ +#define LUA_TNONE (-1) + +#define LUA_TNIL 0 +#define LUA_TBOOLEAN 1 +#define LUA_TLIGHTUSERDATA 2 +#define LUA_TNUMBER 3 +#define LUA_TSTRING 4 +#define LUA_TTABLE 5 +#define LUA_TFUNCTION 6 +#define LUA_TUSERDATA 7 +#define LUA_TTHREAD 8 + +#define LUA_NUMTYPES 9 + + + +/* minimum Lua stack available to a C function */ +#define LUA_MINSTACK 20 + + +/* predefined values in the registry */ +#define LUA_RIDX_MAINTHREAD 1 +#define LUA_RIDX_GLOBALS 2 +#define LUA_RIDX_LAST LUA_RIDX_GLOBALS + + +/* type of numbers in Lua */ +typedef LUA_NUMBER lua_Number; + + +/* type for integer functions */ +typedef LUA_INTEGER lua_Integer; + +/* unsigned integer type */ +typedef LUA_UNSIGNED lua_Unsigned; + +/* type for continuation-function contexts */ +typedef LUA_KCONTEXT lua_KContext; + + +/* +** Type for C functions registered with Lua +*/ +typedef int (*lua_CFunction) (lua_State *L); + +/* +** Type for continuation functions +*/ +typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx); + + +/* +** Type for functions that read/write blocks when loading/dumping Lua chunks +*/ +typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); + +typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud); + + +/* +** Type for memory-allocation functions +*/ +typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); + + +/* +** Type for warning functions +*/ +typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont); + + +/* +** Type used by the debug API to collect debug information +*/ +typedef struct lua_Debug lua_Debug; + + +/* +** Functions to be called by the debugger in specific events +*/ +typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); + + +/* +** generic extra include file +*/ +#if defined(LUA_USER_H) +#include LUA_USER_H +#endif + + +/* +** RCS ident string +*/ +extern const char lua_ident[]; + + +/* +** state manipulation +*/ +LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); +LUA_API void (lua_close) (lua_State *L); +LUA_API lua_State *(lua_newthread) (lua_State *L); +LUA_API int (lua_closethread) (lua_State *L, lua_State *from); +LUA_API int (lua_resetthread) (lua_State *L); /* Deprecated! */ + +LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); + + +LUA_API lua_Number (lua_version) (lua_State *L); + + +/* +** basic stack manipulation +*/ +LUA_API int (lua_absindex) (lua_State *L, int idx); +LUA_API int (lua_gettop) (lua_State *L); +LUA_API void (lua_settop) (lua_State *L, int idx); +LUA_API void (lua_pushvalue) (lua_State *L, int idx); +LUA_API void (lua_rotate) (lua_State *L, int idx, int n); +LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx); +LUA_API int (lua_checkstack) (lua_State *L, int n); + +LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); + + +/* +** access functions (stack -> C) +*/ + +LUA_API int (lua_isnumber) (lua_State *L, int idx); +LUA_API int (lua_isstring) (lua_State *L, int idx); +LUA_API int (lua_iscfunction) (lua_State *L, int idx); +LUA_API int (lua_isinteger) (lua_State *L, int idx); +LUA_API int (lua_isuserdata) (lua_State *L, int idx); +LUA_API int (lua_type) (lua_State *L, int idx); +LUA_API const char *(lua_typename) (lua_State *L, int tp); + +LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum); +LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum); +LUA_API int (lua_toboolean) (lua_State *L, int idx); +LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); +LUA_API lua_Unsigned (lua_rawlen) (lua_State *L, int idx); +LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); +LUA_API void *(lua_touserdata) (lua_State *L, int idx); +LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); +LUA_API const void *(lua_topointer) (lua_State *L, int idx); + + +/* +** Comparison and arithmetic functions +*/ + +#define LUA_OPADD 0 /* ORDER TM, ORDER OP */ +#define LUA_OPSUB 1 +#define LUA_OPMUL 2 +#define LUA_OPMOD 3 +#define LUA_OPPOW 4 +#define LUA_OPDIV 5 +#define LUA_OPIDIV 6 +#define LUA_OPBAND 7 +#define LUA_OPBOR 8 +#define LUA_OPBXOR 9 +#define LUA_OPSHL 10 +#define LUA_OPSHR 11 +#define LUA_OPUNM 12 +#define LUA_OPBNOT 13 + +LUA_API void (lua_arith) (lua_State *L, int op); + +#define LUA_OPEQ 0 +#define LUA_OPLT 1 +#define LUA_OPLE 2 + +LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op); + + +/* +** push functions (C -> stack) +*/ +LUA_API void (lua_pushnil) (lua_State *L); +LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); +LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); +LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len); +LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); +LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, + va_list argp); +LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); +LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); +LUA_API void (lua_pushboolean) (lua_State *L, int b); +LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); +LUA_API int (lua_pushthread) (lua_State *L); + + +/* +** get functions (Lua -> stack) +*/ +LUA_API int (lua_getglobal) (lua_State *L, const char *name); +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_geti) (lua_State *L, int idx, lua_Integer n); +LUA_API int (lua_rawget) (lua_State *L, int idx); +LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n); +LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p); + +LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); +LUA_API void *(lua_newuserdatauv) (lua_State *L, size_t sz, int nuvalue); +LUA_API int (lua_getmetatable) (lua_State *L, int objindex); +LUA_API int (lua_getiuservalue) (lua_State *L, int idx, int n); + + +/* +** set functions (stack -> Lua) +*/ +LUA_API void (lua_setglobal) (lua_State *L, const char *name); +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_seti) (lua_State *L, int idx, lua_Integer n); +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_rawsetp) (lua_State *L, int idx, const void *p); +LUA_API int (lua_setmetatable) (lua_State *L, int objindex); +LUA_API int (lua_setiuservalue) (lua_State *L, int idx, int n); + + +/* +** 'load' and 'call' functions (load and run Lua code) +*/ +LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k); +#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) + +LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, + lua_KContext ctx, lua_KFunction k); +#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) + +LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, + const char *chunkname, const char *mode); + +LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); + + +/* +** coroutine functions +*/ +LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, + lua_KFunction k); +LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg, + int *nres); +LUA_API int (lua_status) (lua_State *L); +LUA_API int (lua_isyieldable) (lua_State *L); + +#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) + + +/* +** Warning-related functions +*/ +LUA_API void (lua_setwarnf) (lua_State *L, lua_WarnFunction f, void *ud); +LUA_API void (lua_warning) (lua_State *L, const char *msg, int tocont); + + +/* +** garbage-collection function and options +*/ + +#define LUA_GCSTOP 0 +#define LUA_GCRESTART 1 +#define LUA_GCCOLLECT 2 +#define LUA_GCCOUNT 3 +#define LUA_GCCOUNTB 4 +#define LUA_GCSTEP 5 +#define LUA_GCSETPAUSE 6 +#define LUA_GCSETSTEPMUL 7 +#define LUA_GCISRUNNING 9 +#define LUA_GCGEN 10 +#define LUA_GCINC 11 + +LUA_API int (lua_gc) (lua_State *L, int what, ...); + + +/* +** miscellaneous functions +*/ + +LUA_API int (lua_error) (lua_State *L); + +LUA_API int (lua_next) (lua_State *L, int idx); + +LUA_API void (lua_concat) (lua_State *L, int n); +LUA_API void (lua_len) (lua_State *L, int idx); + +LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s); + +LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); +LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); + +LUA_API void (lua_toclose) (lua_State *L, int idx); +LUA_API void (lua_closeslot) (lua_State *L, int idx); + + +/* +** {============================================================== +** some useful macros +** =============================================================== +*/ + +#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE)) + +#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL) +#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL) + +#define lua_pop(L,n) lua_settop(L, -(n)-1) + +#define lua_newtable(L) lua_createtable(L, 0, 0) + +#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) + +#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) + +#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) +#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) +#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) +#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) +#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) +#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) +#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) +#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) + +#define lua_pushliteral(L, s) lua_pushstring(L, "" s) + +#define lua_pushglobaltable(L) \ + ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)) + +#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) + + +#define lua_insert(L,idx) lua_rotate(L, (idx), 1) + +#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1)) + +#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1)) + +/* }============================================================== */ + + +/* +** {============================================================== +** compatibility macros +** =============================================================== +*/ +#if defined(LUA_COMPAT_APIINTCASTS) + +#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) +#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is)) +#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL) + +#endif + +#define lua_newuserdata(L,s) lua_newuserdatauv(L,s,1) +#define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1) +#define lua_setuservalue(L,idx) lua_setiuservalue(L,idx,1) + +#define LUA_NUMTAGS LUA_NUMTYPES + +/* }============================================================== */ + +/* +** {====================================================================== +** Debug API +** ======================================================================= +*/ + + +/* +** Event codes +*/ +#define LUA_HOOKCALL 0 +#define LUA_HOOKRET 1 +#define LUA_HOOKLINE 2 +#define LUA_HOOKCOUNT 3 +#define LUA_HOOKTAILCALL 4 + + +/* +** Event masks +*/ +#define LUA_MASKCALL (1 << LUA_HOOKCALL) +#define LUA_MASKRET (1 << LUA_HOOKRET) +#define LUA_MASKLINE (1 << LUA_HOOKLINE) +#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) + + +LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); +LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); +LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n); +LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n); + +LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n); +LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1, + int fidx2, int n2); + +LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); +LUA_API lua_Hook (lua_gethook) (lua_State *L); +LUA_API int (lua_gethookmask) (lua_State *L); +LUA_API int (lua_gethookcount) (lua_State *L); + +LUA_API int (lua_setcstacklimit) (lua_State *L, unsigned int limit); + +struct lua_Debug { + int event; + const char *name; /* (n) */ + const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */ + const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */ + const char *source; /* (S) */ + size_t srclen; /* (S) */ + int currentline; /* (l) */ + int linedefined; /* (S) */ + int lastlinedefined; /* (S) */ + unsigned char nups; /* (u) number of upvalues */ + unsigned char nparams;/* (u) number of parameters */ + char isvararg; /* (u) */ + char istailcall; /* (t) */ + unsigned short ftransfer; /* (r) index of first value transferred */ + unsigned short ntransfer; /* (r) number of transferred values */ + char short_src[LUA_IDSIZE]; /* (S) */ + /* private part */ + struct CallInfo *i_ci; /* active function */ +}; + +/* }====================================================================== */ + + +/****************************************************************************** +* Copyright (C) 1994-2023 Lua.org, PUC-Rio. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +******************************************************************************/ + + +#endif diff --git a/src/libs/3rdparty/lua/src/lua.hpp b/src/libs/3rdparty/lua/src/lua.hpp new file mode 100644 index 0000000000..ec417f5946 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lua.hpp @@ -0,0 +1,9 @@ +// lua.hpp +// Lua header files for C++ +// <<extern "C">> not supplied automatically because Lua also compiles as C++ + +extern "C" { +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +} diff --git a/src/libs/3rdparty/lua/src/luac.c b/src/libs/3rdparty/lua/src/luac.c new file mode 100644 index 0000000000..5f4a141bdd --- /dev/null +++ b/src/libs/3rdparty/lua/src/luac.c @@ -0,0 +1,723 @@ +/* +** $Id: luac.c $ +** Lua compiler (saves bytecodes to files; also lists bytecodes) +** See Copyright Notice in lua.h +*/ + +#define luac_c +#define LUA_CORE + +#include "lprefix.h" + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "lua.h" +#include "lauxlib.h" + +#include "ldebug.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lopnames.h" +#include "lstate.h" +#include "lundump.h" + +static void PrintFunction(const Proto* f, int full); +#define luaU_print PrintFunction + +#define PROGNAME "luac" /* default program name */ +#define OUTPUT PROGNAME ".out" /* default output file */ + +static int listing=0; /* list bytecodes? */ +static int dumping=1; /* dump bytecodes? */ +static int stripping=0; /* strip debug information? */ +static char Output[]={ OUTPUT }; /* default output file name */ +static const char* output=Output; /* actual output file name */ +static const char* progname=PROGNAME; /* actual program name */ +static TString **tmname; + +static void fatal(const char* message) +{ + fprintf(stderr,"%s: %s\n",progname,message); + exit(EXIT_FAILURE); +} + +static void cannot(const char* what) +{ + fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno)); + exit(EXIT_FAILURE); +} + +static void usage(const char* message) +{ + if (*message=='-') + fprintf(stderr,"%s: unrecognized option '%s'\n",progname,message); + else + fprintf(stderr,"%s: %s\n",progname,message); + fprintf(stderr, + "usage: %s [options] [filenames]\n" + "Available options are:\n" + " -l list (use -l -l for full listing)\n" + " -o name output to file 'name' (default is \"%s\")\n" + " -p parse only\n" + " -s strip debug information\n" + " -v show version information\n" + " -- stop handling options\n" + " - stop handling options and process stdin\n" + ,progname,Output); + exit(EXIT_FAILURE); +} + +#define IS(s) (strcmp(argv[i],s)==0) + +static int doargs(int argc, char* argv[]) +{ + int i; + int version=0; + if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0]; + for (i=1; i<argc; i++) + { + if (*argv[i]!='-') /* end of options; keep it */ + break; + else if (IS("--")) /* end of options; skip it */ + { + ++i; + if (version) ++version; + break; + } + else if (IS("-")) /* end of options; use stdin */ + break; + else if (IS("-l")) /* list */ + ++listing; + else if (IS("-o")) /* output file */ + { + output=argv[++i]; + if (output==NULL || *output==0 || (*output=='-' && output[1]!=0)) + usage("'-o' needs argument"); + if (IS("-")) output=NULL; + } + else if (IS("-p")) /* parse only */ + dumping=0; + else if (IS("-s")) /* strip debug information */ + stripping=1; + else if (IS("-v")) /* show version */ + ++version; + else /* unknown option */ + usage(argv[i]); + } + if (i==argc && (listing || !dumping)) + { + dumping=0; + argv[--i]=Output; + } + if (version) + { + printf("%s\n",LUA_COPYRIGHT); + if (version==argc-1) exit(EXIT_SUCCESS); + } + return i; +} + +#define FUNCTION "(function()end)();\n" + +static const char* reader(lua_State* L, void* ud, size_t* size) +{ + UNUSED(L); + if ((*(int*)ud)--) + { + *size=sizeof(FUNCTION)-1; + return FUNCTION; + } + else + { + *size=0; + return NULL; + } +} + +#define toproto(L,i) getproto(s2v(L->top.p+(i))) + +static const Proto* combine(lua_State* L, int n) +{ + if (n==1) + return toproto(L,-1); + else + { + Proto* f; + int i=n; + if (lua_load(L,reader,&i,"=(" PROGNAME ")",NULL)!=LUA_OK) fatal(lua_tostring(L,-1)); + f=toproto(L,-1); + for (i=0; i<n; i++) + { + f->p[i]=toproto(L,i-n-1); + if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0; + } + return f; + } +} + +static int writer(lua_State* L, const void* p, size_t size, void* u) +{ + UNUSED(L); + return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); +} + +static int pmain(lua_State* L) +{ + int argc=(int)lua_tointeger(L,1); + char** argv=(char**)lua_touserdata(L,2); + const Proto* f; + int i; + tmname=G(L)->tmname; + if (!lua_checkstack(L,argc)) fatal("too many input files"); + for (i=0; i<argc; i++) + { + const char* filename=IS("-") ? NULL : argv[i]; + if (luaL_loadfile(L,filename)!=LUA_OK) fatal(lua_tostring(L,-1)); + } + f=combine(L,argc); + if (listing) luaU_print(f,listing>1); + if (dumping) + { + FILE* D= (output==NULL) ? stdout : fopen(output,"wb"); + if (D==NULL) cannot("open"); + lua_lock(L); + luaU_dump(L,f,writer,D,stripping); + lua_unlock(L); + if (ferror(D)) cannot("write"); + if (fclose(D)) cannot("close"); + } + return 0; +} + +int main(int argc, char* argv[]) +{ + lua_State* L; + int i=doargs(argc,argv); + argc-=i; argv+=i; + if (argc<=0) usage("no input files given"); + L=luaL_newstate(); + if (L==NULL) fatal("cannot create state: not enough memory"); + lua_pushcfunction(L,&pmain); + lua_pushinteger(L,argc); + lua_pushlightuserdata(L,argv); + if (lua_pcall(L,2,0,0)!=LUA_OK) fatal(lua_tostring(L,-1)); + lua_close(L); + return EXIT_SUCCESS; +} + +/* +** print bytecodes +*/ + +#define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-") +#define VOID(p) ((const void*)(p)) +#define eventname(i) (getstr(tmname[i])) + +static void PrintString(const TString* ts) +{ + const char* s=getstr(ts); + size_t i,n=tsslen(ts); + printf("\""); + for (i=0; i<n; i++) + { + int c=(int)(unsigned char)s[i]; + switch (c) + { + case '"': + printf("\\\""); + break; + case '\\': + printf("\\\\"); + break; + case '\a': + printf("\\a"); + break; + case '\b': + printf("\\b"); + break; + case '\f': + printf("\\f"); + break; + case '\n': + printf("\\n"); + break; + case '\r': + printf("\\r"); + break; + case '\t': + printf("\\t"); + break; + case '\v': + printf("\\v"); + break; + default: + if (isprint(c)) printf("%c",c); else printf("\\%03d",c); + break; + } + } + printf("\""); +} + +static void PrintType(const Proto* f, int i) +{ + const TValue* o=&f->k[i]; + switch (ttypetag(o)) + { + case LUA_VNIL: + printf("N"); + break; + case LUA_VFALSE: + case LUA_VTRUE: + printf("B"); + break; + case LUA_VNUMFLT: + printf("F"); + break; + case LUA_VNUMINT: + printf("I"); + break; + case LUA_VSHRSTR: + case LUA_VLNGSTR: + printf("S"); + break; + default: /* cannot happen */ + printf("?%d",ttypetag(o)); + break; + } + printf("\t"); +} + +static void PrintConstant(const Proto* f, int i) +{ + const TValue* o=&f->k[i]; + switch (ttypetag(o)) + { + case LUA_VNIL: + printf("nil"); + break; + case LUA_VFALSE: + printf("false"); + break; + case LUA_VTRUE: + printf("true"); + break; + case LUA_VNUMFLT: + { + char buff[100]; + sprintf(buff,LUA_NUMBER_FMT,fltvalue(o)); + printf("%s",buff); + if (buff[strspn(buff,"-0123456789")]=='\0') printf(".0"); + break; + } + case LUA_VNUMINT: + printf(LUA_INTEGER_FMT,ivalue(o)); + break; + case LUA_VSHRSTR: + case LUA_VLNGSTR: + PrintString(tsvalue(o)); + break; + default: /* cannot happen */ + printf("?%d",ttypetag(o)); + break; + } +} + +#define COMMENT "\t; " +#define EXTRAARG GETARG_Ax(code[pc+1]) +#define EXTRAARGC (EXTRAARG*(MAXARG_C+1)) +#define ISK (isk ? "k" : "") + +static void PrintCode(const Proto* f) +{ + const Instruction* code=f->code; + int pc,n=f->sizecode; + for (pc=0; pc<n; pc++) + { + Instruction i=code[pc]; + OpCode o=GET_OPCODE(i); + int a=GETARG_A(i); + int b=GETARG_B(i); + int c=GETARG_C(i); + int ax=GETARG_Ax(i); + int bx=GETARG_Bx(i); + int sb=GETARG_sB(i); + int sc=GETARG_sC(i); + int sbx=GETARG_sBx(i); + int isk=GETARG_k(i); + int line=luaG_getfuncline(f,pc); + printf("\t%d\t",pc+1); + if (line>0) printf("[%d]\t",line); else printf("[-]\t"); + printf("%-9s\t",opnames[o]); + switch (o) + { + case OP_MOVE: + printf("%d %d",a,b); + break; + case OP_LOADI: + printf("%d %d",a,sbx); + break; + case OP_LOADF: + printf("%d %d",a,sbx); + break; + case OP_LOADK: + printf("%d %d",a,bx); + printf(COMMENT); PrintConstant(f,bx); + break; + case OP_LOADKX: + printf("%d",a); + printf(COMMENT); PrintConstant(f,EXTRAARG); + break; + case OP_LOADFALSE: + printf("%d",a); + break; + case OP_LFALSESKIP: + printf("%d",a); + break; + case OP_LOADTRUE: + printf("%d",a); + break; + case OP_LOADNIL: + printf("%d %d",a,b); + printf(COMMENT "%d out",b+1); + break; + case OP_GETUPVAL: + printf("%d %d",a,b); + printf(COMMENT "%s",UPVALNAME(b)); + break; + case OP_SETUPVAL: + printf("%d %d",a,b); + printf(COMMENT "%s",UPVALNAME(b)); + break; + case OP_GETTABUP: + printf("%d %d %d",a,b,c); + printf(COMMENT "%s",UPVALNAME(b)); + printf(" "); PrintConstant(f,c); + break; + case OP_GETTABLE: + printf("%d %d %d",a,b,c); + break; + case OP_GETI: + printf("%d %d %d",a,b,c); + break; + case OP_GETFIELD: + printf("%d %d %d",a,b,c); + printf(COMMENT); PrintConstant(f,c); + break; + case OP_SETTABUP: + printf("%d %d %d%s",a,b,c,ISK); + printf(COMMENT "%s",UPVALNAME(a)); + printf(" "); PrintConstant(f,b); + if (isk) { printf(" "); PrintConstant(f,c); } + break; + case OP_SETTABLE: + printf("%d %d %d%s",a,b,c,ISK); + if (isk) { printf(COMMENT); PrintConstant(f,c); } + break; + case OP_SETI: + printf("%d %d %d%s",a,b,c,ISK); + if (isk) { printf(COMMENT); PrintConstant(f,c); } + break; + case OP_SETFIELD: + printf("%d %d %d%s",a,b,c,ISK); + printf(COMMENT); PrintConstant(f,b); + if (isk) { printf(" "); PrintConstant(f,c); } + break; + case OP_NEWTABLE: + printf("%d %d %d",a,b,c); + printf(COMMENT "%d",c+EXTRAARGC); + break; + case OP_SELF: + printf("%d %d %d%s",a,b,c,ISK); + if (isk) { printf(COMMENT); PrintConstant(f,c); } + break; + case OP_ADDI: + printf("%d %d %d",a,b,sc); + break; + case OP_ADDK: + printf("%d %d %d",a,b,c); + printf(COMMENT); PrintConstant(f,c); + break; + case OP_SUBK: + printf("%d %d %d",a,b,c); + printf(COMMENT); PrintConstant(f,c); + break; + case OP_MULK: + printf("%d %d %d",a,b,c); + printf(COMMENT); PrintConstant(f,c); + break; + case OP_MODK: + printf("%d %d %d",a,b,c); + printf(COMMENT); PrintConstant(f,c); + break; + case OP_POWK: + printf("%d %d %d",a,b,c); + printf(COMMENT); PrintConstant(f,c); + break; + case OP_DIVK: + printf("%d %d %d",a,b,c); + printf(COMMENT); PrintConstant(f,c); + break; + case OP_IDIVK: + printf("%d %d %d",a,b,c); + printf(COMMENT); PrintConstant(f,c); + break; + case OP_BANDK: + printf("%d %d %d",a,b,c); + printf(COMMENT); PrintConstant(f,c); + break; + case OP_BORK: + printf("%d %d %d",a,b,c); + printf(COMMENT); PrintConstant(f,c); + break; + case OP_BXORK: + printf("%d %d %d",a,b,c); + printf(COMMENT); PrintConstant(f,c); + break; + case OP_SHRI: + printf("%d %d %d",a,b,sc); + break; + case OP_SHLI: + printf("%d %d %d",a,b,sc); + break; + case OP_ADD: + printf("%d %d %d",a,b,c); + break; + case OP_SUB: + printf("%d %d %d",a,b,c); + break; + case OP_MUL: + printf("%d %d %d",a,b,c); + break; + case OP_MOD: + printf("%d %d %d",a,b,c); + break; + case OP_POW: + printf("%d %d %d",a,b,c); + break; + case OP_DIV: + printf("%d %d %d",a,b,c); + break; + case OP_IDIV: + printf("%d %d %d",a,b,c); + break; + case OP_BAND: + printf("%d %d %d",a,b,c); + break; + case OP_BOR: + printf("%d %d %d",a,b,c); + break; + case OP_BXOR: + printf("%d %d %d",a,b,c); + break; + case OP_SHL: + printf("%d %d %d",a,b,c); + break; + case OP_SHR: + printf("%d %d %d",a,b,c); + break; + case OP_MMBIN: + printf("%d %d %d",a,b,c); + printf(COMMENT "%s",eventname(c)); + break; + case OP_MMBINI: + printf("%d %d %d %d",a,sb,c,isk); + printf(COMMENT "%s",eventname(c)); + if (isk) printf(" flip"); + break; + case OP_MMBINK: + printf("%d %d %d %d",a,b,c,isk); + printf(COMMENT "%s ",eventname(c)); PrintConstant(f,b); + if (isk) printf(" flip"); + break; + case OP_UNM: + printf("%d %d",a,b); + break; + case OP_BNOT: + printf("%d %d",a,b); + break; + case OP_NOT: + printf("%d %d",a,b); + break; + case OP_LEN: + printf("%d %d",a,b); + break; + case OP_CONCAT: + printf("%d %d",a,b); + break; + case OP_CLOSE: + printf("%d",a); + break; + case OP_TBC: + printf("%d",a); + break; + case OP_JMP: + printf("%d",GETARG_sJ(i)); + printf(COMMENT "to %d",GETARG_sJ(i)+pc+2); + break; + case OP_EQ: + printf("%d %d %d",a,b,isk); + break; + case OP_LT: + printf("%d %d %d",a,b,isk); + break; + case OP_LE: + printf("%d %d %d",a,b,isk); + break; + case OP_EQK: + printf("%d %d %d",a,b,isk); + printf(COMMENT); PrintConstant(f,b); + break; + case OP_EQI: + printf("%d %d %d",a,sb,isk); + break; + case OP_LTI: + printf("%d %d %d",a,sb,isk); + break; + case OP_LEI: + printf("%d %d %d",a,sb,isk); + break; + case OP_GTI: + printf("%d %d %d",a,sb,isk); + break; + case OP_GEI: + printf("%d %d %d",a,sb,isk); + break; + case OP_TEST: + printf("%d %d",a,isk); + break; + case OP_TESTSET: + printf("%d %d %d",a,b,isk); + break; + case OP_CALL: + printf("%d %d %d",a,b,c); + printf(COMMENT); + if (b==0) printf("all in "); else printf("%d in ",b-1); + if (c==0) printf("all out"); else printf("%d out",c-1); + break; + case OP_TAILCALL: + printf("%d %d %d%s",a,b,c,ISK); + printf(COMMENT "%d in",b-1); + break; + case OP_RETURN: + printf("%d %d %d%s",a,b,c,ISK); + printf(COMMENT); + if (b==0) printf("all out"); else printf("%d out",b-1); + break; + case OP_RETURN0: + break; + case OP_RETURN1: + printf("%d",a); + break; + case OP_FORLOOP: + printf("%d %d",a,bx); + printf(COMMENT "to %d",pc-bx+2); + break; + case OP_FORPREP: + printf("%d %d",a,bx); + printf(COMMENT "exit to %d",pc+bx+3); + break; + case OP_TFORPREP: + printf("%d %d",a,bx); + printf(COMMENT "to %d",pc+bx+2); + break; + case OP_TFORCALL: + printf("%d %d",a,c); + break; + case OP_TFORLOOP: + printf("%d %d",a,bx); + printf(COMMENT "to %d",pc-bx+2); + break; + case OP_SETLIST: + printf("%d %d %d",a,b,c); + if (isk) printf(COMMENT "%d",c+EXTRAARGC); + break; + case OP_CLOSURE: + printf("%d %d",a,bx); + printf(COMMENT "%p",VOID(f->p[bx])); + break; + case OP_VARARG: + printf("%d %d",a,c); + printf(COMMENT); + if (c==0) printf("all out"); else printf("%d out",c-1); + break; + case OP_VARARGPREP: + printf("%d",a); + break; + case OP_EXTRAARG: + printf("%d",ax); + break; +#if 0 + default: + printf("%d %d %d",a,b,c); + printf(COMMENT "not handled"); + break; +#endif + } + printf("\n"); + } +} + + +#define SS(x) ((x==1)?"":"s") +#define S(x) (int)(x),SS(x) + +static void PrintHeader(const Proto* f) +{ + const char* s=f->source ? getstr(f->source) : "=?"; + if (*s=='@' || *s=='=') + s++; + else if (*s==LUA_SIGNATURE[0]) + s="(bstring)"; + else + s="(string)"; + printf("\n%s <%s:%d,%d> (%d instruction%s at %p)\n", + (f->linedefined==0)?"main":"function",s, + f->linedefined,f->lastlinedefined, + S(f->sizecode),VOID(f)); + printf("%d%s param%s, %d slot%s, %d upvalue%s, ", + (int)(f->numparams),f->is_vararg?"+":"",SS(f->numparams), + S(f->maxstacksize),S(f->sizeupvalues)); + printf("%d local%s, %d constant%s, %d function%s\n", + S(f->sizelocvars),S(f->sizek),S(f->sizep)); +} + +static void PrintDebug(const Proto* f) +{ + int i,n; + n=f->sizek; + printf("constants (%d) for %p:\n",n,VOID(f)); + for (i=0; i<n; i++) + { + printf("\t%d\t",i); + PrintType(f,i); + PrintConstant(f,i); + printf("\n"); + } + n=f->sizelocvars; + printf("locals (%d) for %p:\n",n,VOID(f)); + for (i=0; i<n; i++) + { + printf("\t%d\t%s\t%d\t%d\n", + i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1); + } + n=f->sizeupvalues; + printf("upvalues (%d) for %p:\n",n,VOID(f)); + for (i=0; i<n; i++) + { + printf("\t%d\t%s\t%d\t%d\n", + i,UPVALNAME(i),f->upvalues[i].instack,f->upvalues[i].idx); + } +} + +static void PrintFunction(const Proto* f, int full) +{ + int i,n=f->sizep; + PrintHeader(f); + PrintCode(f); + if (full) PrintDebug(f); + for (i=0; i<n; i++) PrintFunction(f->p[i],full); +} diff --git a/src/libs/3rdparty/lua/src/luaconf.h b/src/libs/3rdparty/lua/src/luaconf.h new file mode 100644 index 0000000000..433df49295 --- /dev/null +++ b/src/libs/3rdparty/lua/src/luaconf.h @@ -0,0 +1,793 @@ +/* +** $Id: luaconf.h $ +** Configuration file for Lua +** See Copyright Notice in lua.h +*/ + + +#ifndef luaconf_h +#define luaconf_h + +#include <limits.h> +#include <stddef.h> + + +/* +** =================================================================== +** General Configuration File for Lua +** +** Some definitions here can be changed externally, through the compiler +** (e.g., with '-D' options): They are commented out or protected +** by '#if !defined' guards. However, several other definitions +** should be changed directly here, either because they affect the +** Lua ABI (by making the changes here, you ensure that all software +** connected to Lua, such as C libraries, will be compiled with the same +** configuration); or because they are seldom changed. +** +** Search for "@@" to find all configurable definitions. +** =================================================================== +*/ + + +/* +** {==================================================================== +** System Configuration: macros to adapt (if needed) Lua to some +** particular platform, for instance restricting it to C89. +** ===================================================================== +*/ + +/* +@@ LUA_USE_C89 controls the use of non-ISO-C89 features. +** Define it if you want Lua to avoid the use of a few C99 features +** or Windows-specific features on Windows. +*/ +/* #define LUA_USE_C89 */ + + +/* +** By default, Lua on Windows use (some) specific Windows features +*/ +#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE) &&!defined(LUA_USE_WINDOWS) +#define LUA_USE_WINDOWS /* enable goodies for regular Windows */ +#endif + + +#if defined(LUA_USE_WINDOWS) +#define LUA_DL_DLL /* enable support for DLL */ +#define LUA_USE_C89 /* broadly, Windows is C89 */ +#endif + + +#if defined(LUA_USE_LINUX) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN /* needs an extra library: -ldl */ +#endif + + +#if defined(LUA_USE_MACOSX) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN /* MacOS does not need -ldl */ +#endif + + +#if defined(LUA_USE_IOS) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN +#endif + + +/* +@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits. +*/ +#define LUAI_IS32INT ((UINT_MAX >> 30) >= 3) + +/* }================================================================== */ + + + +/* +** {================================================================== +** Configuration for Number types. These options should not be +** set externally, because any other code connected to Lua must +** use the same configuration. +** =================================================================== +*/ + +/* +@@ LUA_INT_TYPE defines the type for Lua integers. +@@ LUA_FLOAT_TYPE defines the type for Lua floats. +** Lua should work fine with any mix of these options supported +** by your C compiler. The usual configurations are 64-bit integers +** and 'double' (the default), 32-bit integers and 'float' (for +** restricted platforms), and 'long'/'double' (for C compilers not +** 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 + + +/* Default configuration ('long long' and 'double', for 64-bit Lua) */ +#define LUA_INT_DEFAULT LUA_INT_LONGLONG +#define LUA_FLOAT_DEFAULT LUA_FLOAT_DOUBLE + + +/* +@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. +*/ +#define LUA_32BITS 0 + + +/* +@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for +** C89 ('long' and 'double'); Windows always has '__int64', so it does +** not need to use this case. +*/ +#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) +#define LUA_C89_NUMBERS 1 +#else +#define LUA_C89_NUMBERS 0 +#endif + + +#if LUA_32BITS /* { */ +/* +** 32-bit integers and 'float' +*/ +#if LUAI_IS32INT /* use 'int' if big enough */ +#define LUA_INT_TYPE LUA_INT_INT +#else /* otherwise use 'long' */ +#define LUA_INT_TYPE LUA_INT_LONG +#endif +#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT + +#elif LUA_C89_NUMBERS /* }{ */ +/* +** largest types available for C89 ('long' and 'double') +*/ +#define LUA_INT_TYPE LUA_INT_LONG +#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE + +#else /* }{ */ +/* use defaults */ + +#define LUA_INT_TYPE LUA_INT_DEFAULT +#define LUA_FLOAT_TYPE LUA_FLOAT_DEFAULT + +#endif /* } */ + + +/* }================================================================== */ + + + +/* +** {================================================================== +** Configuration for Paths. +** =================================================================== +*/ + +/* +** LUA_PATH_SEP is the character that separates templates in a path. +** LUA_PATH_MARK is the string that marks the substitution points in a +** template. +** LUA_EXEC_DIR in a Windows path is replaced by the executable's +** directory. +*/ +#define LUA_PATH_SEP ";" +#define LUA_PATH_MARK "?" +#define LUA_EXEC_DIR "!" + + +/* +@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for +** Lua libraries. +@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for +** C libraries. +** CHANGE them if your machine has a non-conventional directory +** hierarchy or if you want to install your libraries in +** non-conventional directories. +*/ + +#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR +#if defined(_WIN32) /* { */ +/* +** In Windows, any exclamation mark ('!') in the path is replaced by the +** path of the directory of the executable file of the current process. +*/ +#define LUA_LDIR "!\\lua\\" +#define LUA_CDIR "!\\" +#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\" + +#if !defined(LUA_PATH_DEFAULT) +#define LUA_PATH_DEFAULT \ + LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \ + LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \ + ".\\?.lua;" ".\\?\\init.lua" +#endif + +#if !defined(LUA_CPATH_DEFAULT) +#define LUA_CPATH_DEFAULT \ + LUA_CDIR"?.dll;" \ + LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \ + LUA_CDIR"loadall.dll;" ".\\?.dll" +#endif + +#else /* }{ */ + +#define LUA_ROOT "/usr/local/" +#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/" +#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/" + +#if !defined(LUA_PATH_DEFAULT) +#define LUA_PATH_DEFAULT \ + LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \ + "./?.lua;" "./?/init.lua" +#endif + +#if !defined(LUA_CPATH_DEFAULT) +#define LUA_CPATH_DEFAULT \ + LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" +#endif + +#endif /* } */ + + +/* +@@ LUA_DIRSEP is the directory separator (for submodules). +** CHANGE it if your machine does not use "/" as the directory separator +** and is not Windows. (On Windows Lua automatically uses "\".) +*/ +#if !defined(LUA_DIRSEP) + +#if defined(_WIN32) +#define LUA_DIRSEP "\\" +#else +#define LUA_DIRSEP "/" +#endif + +#endif + +/* }================================================================== */ + + +/* +** {================================================================== +** Marks for exported symbols in the C code +** =================================================================== +*/ + +/* +@@ LUA_API is a mark for all core API functions. +@@ LUALIB_API is a mark for all auxiliary library functions. +@@ LUAMOD_API is a mark for all standard library opening functions. +** CHANGE them if you need to define those functions in some special way. +** For instance, if you want to create one Windows DLL with the core and +** the libraries, you may want to use the following definition (define +** LUA_BUILD_AS_DLL to get it). +*/ +#if defined(LUA_BUILD_AS_DLL) /* { */ + +#if defined(LUA_CORE) || defined(LUA_LIB) /* { */ +#define LUA_API __declspec(dllexport) +#else /* }{ */ +#define LUA_API __declspec(dllimport) +#endif /* } */ + +#else /* }{ */ + +#define LUA_API extern + +#endif /* } */ + + +/* +** More often than not the libs go together with the core. +*/ +#define LUALIB_API LUA_API +#define LUAMOD_API LUA_API + + +/* +@@ LUAI_FUNC is a mark for all extern functions that are not to be +** exported to outside modules. +@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables, +** none of which to be exported to outside modules (LUAI_DDEF for +** definitions and LUAI_DDEC for declarations). +** CHANGE them if you need to mark them in some special way. Elf/gcc +** (versions 3.2 and later) mark them as "hidden" to optimize access +** when Lua is compiled as a shared library. Not all elf targets support +** this attribute. Unfortunately, gcc does not offer a way to check +** whether the target offers that support, and those without support +** give a warning about it. To avoid these warnings, change to the +** default definition. +*/ +#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ + defined(__ELF__) /* { */ +#define LUAI_FUNC __attribute__((visibility("internal"))) extern +#else /* }{ */ +#define LUAI_FUNC extern +#endif /* } */ + +#define LUAI_DDEC(dec) LUAI_FUNC dec +#define LUAI_DDEF /* empty */ + +/* }================================================================== */ + + +/* +** {================================================================== +** Compatibility with previous versions +** =================================================================== +*/ + +/* +@@ LUA_COMPAT_5_3 controls other macros for compatibility with Lua 5.3. +** You can define it to get all options, or change specific options +** to fit your specific needs. +*/ +#if defined(LUA_COMPAT_5_3) /* { */ + +/* +@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated +** functions in the mathematical library. +** (These functions were already officially removed in 5.3; +** nevertheless they are still available here.) +*/ +#define LUA_COMPAT_MATHLIB + +/* +@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for +** manipulating other integer types (lua_pushunsigned, lua_tounsigned, +** luaL_checkint, luaL_checklong, etc.) +** (These macros were also officially removed in 5.3, but they are still +** available here.) +*/ +#define LUA_COMPAT_APIINTCASTS + + +/* +@@ LUA_COMPAT_LT_LE controls the emulation of the '__le' metamethod +** using '__lt'. +*/ +#define LUA_COMPAT_LT_LE + + +/* +@@ The following macros supply trivial compatibility for some +** changes in the API. The macros themselves document how to +** change your code to avoid using them. +** (Once more, these macros were officially removed in 5.3, but they are +** still available here.) +*/ +#define lua_strlen(L,i) lua_rawlen(L, (i)) + +#define lua_objlen(L,i) lua_rawlen(L, (i)) + +#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) +#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT) + +#endif /* } */ + +/* }================================================================== */ + + + +/* +** {================================================================== +** Configuration for Numbers (low-level part). +** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_* +** satisfy your needs. +** =================================================================== +*/ + +/* +@@ LUAI_UACNUMBER is the result of a 'default argument promotion' +@@ over a floating number. +@@ l_floatatt(x) corrects float attribute 'x' to the proper float type +** by prefixing it with one of FLT/DBL/LDBL. +@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats. +@@ LUA_NUMBER_FMT is the format for writing floats. +@@ lua_number2str converts a float to a string. +@@ l_mathop allows the addition of an 'l' or 'f' to all math operations. +@@ l_floor takes the floor of a float. +@@ lua_str2number converts a decimal numeral to a number. +*/ + + +/* The following definitions are good for most cases here */ + +#define l_floor(x) (l_mathop(floor)(x)) + +#define lua_number2str(s,sz,n) \ + l_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n)) + +/* +@@ lua_numbertointeger converts a float number with an integral value +** to an integer, or returns 0 if float is not within the range of +** a lua_Integer. (The range comparisons are tricky because of +** rounding. The tests here assume a two-complement representation, +** where MININTEGER always has an exact representation as a float; +** MAXINTEGER may not have one, and therefore its conversion to float +** may have an ill-defined value.) +*/ +#define lua_numbertointeger(n,p) \ + ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \ + (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \ + (*(p) = (LUA_INTEGER)(n), 1)) + + +/* now the variable definitions */ + +#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */ + +#define LUA_NUMBER float + +#define l_floatatt(n) (FLT_##n) + +#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 LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */ + +#define LUA_NUMBER long double + +#define l_floatatt(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_floatatt(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 /* } */ + + + +/* +@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. +@@ LUAI_UACINT is the result of a 'default argument promotion' +@@ over a LUA_INTEGER. +@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. +@@ LUA_INTEGER_FMT is the format for writing integers. +@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. +@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. +@@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED. +@@ lua_integer2str converts an integer to a string. +*/ + + +/* The following definitions are good for most cases here */ + +#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d" + +#define LUAI_UACINT LUA_INTEGER + +#define lua_integer2str(s,sz,n) \ + l_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n)) + +/* +** use LUAI_UACINT here to avoid problems with promotions (which +** can turn a comparison between unsigneds into a signed comparison) +*/ +#define LUA_UNSIGNED unsigned LUAI_UACINT + + +/* now the variable definitions */ + +#if LUA_INT_TYPE == LUA_INT_INT /* { int */ + +#define LUA_INTEGER int +#define LUA_INTEGER_FRMLEN "" + +#define LUA_MAXINTEGER INT_MAX +#define LUA_MININTEGER INT_MIN + +#define LUA_MAXUNSIGNED UINT_MAX + +#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */ + +#define LUA_INTEGER long +#define LUA_INTEGER_FRMLEN "l" + +#define LUA_MAXINTEGER LONG_MAX +#define LUA_MININTEGER LONG_MIN + +#define LUA_MAXUNSIGNED ULONG_MAX + +#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */ + +/* use presence of macro LLONG_MAX as proxy for C99 compliance */ +#if defined(LLONG_MAX) /* { */ +/* use ISO C99 stuff */ + +#define LUA_INTEGER long long +#define LUA_INTEGER_FRMLEN "ll" + +#define LUA_MAXINTEGER LLONG_MAX +#define LUA_MININTEGER LLONG_MIN + +#define LUA_MAXUNSIGNED ULLONG_MAX + +#elif defined(LUA_USE_WINDOWS) /* }{ */ +/* in Windows, can use specific Windows types */ + +#define LUA_INTEGER __int64 +#define LUA_INTEGER_FRMLEN "I64" + +#define LUA_MAXINTEGER _I64_MAX +#define LUA_MININTEGER _I64_MIN + +#define LUA_MAXUNSIGNED _UI64_MAX + +#else /* }{ */ + +#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \ + or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)" + +#endif /* } */ + +#else /* }{ */ + +#error "numeric integer type not defined" + +#endif /* } */ + +/* }================================================================== */ + + +/* +** {================================================================== +** 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 a hexadecimal numeral to a number. +** In C99, 'strtod' does that conversion. Otherwise, you can +** leave 'lua_strx2number' undefined and Lua will provide its own +** implementation. +*/ +#if !defined(LUA_USE_C89) +#define lua_strx2number(s,p) lua_str2number(s,p) +#endif + + +/* +@@ lua_pointer2str converts a pointer to a readable string in a +** non-specified way. +*/ +#define lua_pointer2str(buff,sz,p) l_sprintf(buff,sz,"%p",p) + + +/* +@@ lua_number2strx converts a float to a hexadecimal numeral. +** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that. +** Otherwise, you can leave 'lua_number2strx' undefined and Lua will +** provide its own implementation. +*/ +#if !defined(LUA_USE_C89) +#define lua_number2strx(L,b,sz,f,n) \ + ((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n))) +#endif + + +/* +** 'strtof' and 'opf' variants for math functions are not valid in +** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the +** availability of these variants. ('math.h' is already included in +** all files that use these macros.) +*/ +#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF)) +#undef l_mathop /* variants not available */ +#undef lua_str2number +#define l_mathop(op) (lua_Number)op /* no variant */ +#define lua_str2number(s,p) ((lua_Number)strtod((s), (p))) +#endif + + +/* +@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation +** functions. It must be a numerical type; Lua will use 'intptr_t' if +** available, otherwise it will use 'ptrdiff_t' (the nearest thing to +** 'intptr_t' in C89) +*/ +#define LUA_KCONTEXT ptrdiff_t + +#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \ + __STDC_VERSION__ >= 199901L +#include <stdint.h> +#if defined(INTPTR_MAX) /* even in C99 this type is optional */ +#undef LUA_KCONTEXT +#define LUA_KCONTEXT intptr_t +#endif +#endif + + +/* +@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point). +** Change that if you do not want to use C locales. (Code using this +** macro must include the header 'locale.h'.) +*/ +#if !defined(lua_getlocaledecpoint) +#define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) +#endif + + +/* +** macros to improve jump prediction, used mostly for error handling +** and debug facilities. (Some macros in the Lua API use these macros. +** Define LUA_NOBUILTIN if you do not want '__builtin_expect' in your +** code.) +*/ +#if !defined(luai_likely) + +#if defined(__GNUC__) && !defined(LUA_NOBUILTIN) +#define luai_likely(x) (__builtin_expect(((x) != 0), 1)) +#define luai_unlikely(x) (__builtin_expect(((x) != 0), 0)) +#else +#define luai_likely(x) (x) +#define luai_unlikely(x) (x) +#endif + +#endif + + +#if defined(LUA_CORE) || defined(LUA_LIB) +/* shorter names for Lua's own use */ +#define l_likely(x) luai_likely(x) +#define l_unlikely(x) luai_unlikely(x) +#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 + +/* }================================================================== */ + + +/* +** {================================================================== +** Macros that affect the API and must be stable (that is, must be the +** same when you compile Lua and when you compile code that links to +** Lua). +** ===================================================================== +*/ + +/* +@@ LUAI_MAXSTACK limits the size of the Lua stack. +** CHANGE it if you need a different limit. This limit is arbitrary; +** its only purpose is to stop Lua from consuming unlimited stack +** space (and to reserve some numbers for pseudo-indices). +** (It must fit into max(size_t)/32 and max(int)/2.) +*/ +#if LUAI_IS32INT +#define LUAI_MAXSTACK 1000000 +#else +#define LUAI_MAXSTACK 15000 +#endif + + +/* +@@ LUA_EXTRASPACE defines the size of a raw memory area associated with +** a Lua state with very fast access. +** CHANGE it if you need a different size. +*/ +#define LUA_EXTRASPACE (sizeof(void *)) + + +/* +@@ LUA_IDSIZE gives the maximum size for the description of the source +** of a function in debug information. +** CHANGE it if you want a different size. +*/ +#define LUA_IDSIZE 60 + + +/* +@@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib +** buffer system. +*/ +#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number))) + + +/* +@@ LUAI_MAXALIGN defines fields that, when used in a union, ensure +** maximum alignment for the other items in that union. +*/ +#define LUAI_MAXALIGN lua_Number n; double u; void *s; lua_Integer i; long l + +/* }================================================================== */ + + + + + +/* =================================================================== */ + +/* +** Local configuration. You can use this space to add your redefinitions +** without modifying the main part of the file. +*/ + + + + + +#endif + diff --git a/src/libs/3rdparty/lua/src/lualib.h b/src/libs/3rdparty/lua/src/lualib.h new file mode 100644 index 0000000000..2625529076 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lualib.h @@ -0,0 +1,52 @@ +/* +** $Id: lualib.h $ +** Lua standard libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lualib_h +#define lualib_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); + +#define LUA_COLIBNAME "coroutine" +LUAMOD_API int (luaopen_coroutine) (lua_State *L); + +#define LUA_TABLIBNAME "table" +LUAMOD_API int (luaopen_table) (lua_State *L); + +#define LUA_IOLIBNAME "io" +LUAMOD_API int (luaopen_io) (lua_State *L); + +#define LUA_OSLIBNAME "os" +LUAMOD_API int (luaopen_os) (lua_State *L); + +#define LUA_STRLIBNAME "string" +LUAMOD_API int (luaopen_string) (lua_State *L); + +#define LUA_UTF8LIBNAME "utf8" +LUAMOD_API int (luaopen_utf8) (lua_State *L); + +#define LUA_MATHLIBNAME "math" +LUAMOD_API int (luaopen_math) (lua_State *L); + +#define LUA_DBLIBNAME "debug" +LUAMOD_API int (luaopen_debug) (lua_State *L); + +#define LUA_LOADLIBNAME "package" +LUAMOD_API int (luaopen_package) (lua_State *L); + + +/* open all previous libraries */ +LUALIB_API void (luaL_openlibs) (lua_State *L); + + +#endif diff --git a/src/libs/3rdparty/lua/src/lundump.c b/src/libs/3rdparty/lua/src/lundump.c new file mode 100644 index 0000000000..02aed64fb6 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lundump.c @@ -0,0 +1,335 @@ +/* +** $Id: lundump.c $ +** load precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#define lundump_c +#define LUA_CORE + +#include "lprefix.h" + + +#include <limits.h> +#include <string.h> + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstring.h" +#include "lundump.h" +#include "lzio.h" + + +#if !defined(luai_verifycode) +#define luai_verifycode(L,f) /* empty */ +#endif + + +typedef struct { + lua_State *L; + ZIO *Z; + const char *name; +} LoadState; + + +static l_noret error (LoadState *S, const char *why) { + luaO_pushfstring(S->L, "%s: bad binary format (%s)", S->name, why); + luaD_throw(S->L, LUA_ERRSYNTAX); +} + + +/* +** All high-level loads go through loadVector; you can change it to +** adapt to the endianness of the input +*/ +#define loadVector(S,b,n) loadBlock(S,b,(n)*sizeof((b)[0])) + +static void loadBlock (LoadState *S, void *b, size_t size) { + if (luaZ_read(S->Z, b, size) != 0) + error(S, "truncated chunk"); +} + + +#define loadVar(S,x) loadVector(S,&x,1) + + +static lu_byte loadByte (LoadState *S) { + int b = zgetc(S->Z); + if (b == EOZ) + error(S, "truncated chunk"); + return cast_byte(b); +} + + +static size_t loadUnsigned (LoadState *S, size_t limit) { + size_t x = 0; + int b; + limit >>= 7; + do { + b = loadByte(S); + if (x >= limit) + error(S, "integer overflow"); + x = (x << 7) | (b & 0x7f); + } while ((b & 0x80) == 0); + return x; +} + + +static size_t loadSize (LoadState *S) { + return loadUnsigned(S, ~(size_t)0); +} + + +static int loadInt (LoadState *S) { + return cast_int(loadUnsigned(S, INT_MAX)); +} + + +static lua_Number loadNumber (LoadState *S) { + lua_Number x; + loadVar(S, x); + return x; +} + + +static lua_Integer loadInteger (LoadState *S) { + lua_Integer x; + loadVar(S, x); + return x; +} + + +/* +** Load a nullable string into prototype 'p'. +*/ +static TString *loadStringN (LoadState *S, Proto *p) { + lua_State *L = S->L; + TString *ts; + size_t size = loadSize(S); + if (size == 0) /* no string? */ + return NULL; + else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */ + char buff[LUAI_MAXSHORTLEN]; + loadVector(S, buff, size); /* load string into buffer */ + ts = luaS_newlstr(L, buff, size); /* create string */ + } + else { /* long string */ + ts = luaS_createlngstrobj(L, size); /* create string */ + setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */ + luaD_inctop(L); + loadVector(S, getstr(ts), size); /* load directly in final place */ + L->top.p--; /* pop string */ + } + luaC_objbarrier(L, p, ts); + return ts; +} + + +/* +** Load a non-nullable string into prototype 'p'. +*/ +static TString *loadString (LoadState *S, Proto *p) { + TString *st = loadStringN(S, p); + if (st == NULL) + error(S, "bad format for constant string"); + return st; +} + + +static void loadCode (LoadState *S, Proto *f) { + int n = loadInt(S); + f->code = luaM_newvectorchecked(S->L, n, Instruction); + f->sizecode = n; + loadVector(S, f->code, n); +} + + +static void loadFunction(LoadState *S, Proto *f, TString *psource); + + +static void loadConstants (LoadState *S, Proto *f) { + int i; + int n = loadInt(S); + f->k = luaM_newvectorchecked(S->L, n, TValue); + f->sizek = n; + for (i = 0; i < n; i++) + setnilvalue(&f->k[i]); + for (i = 0; i < n; i++) { + TValue *o = &f->k[i]; + int t = loadByte(S); + switch (t) { + case LUA_VNIL: + setnilvalue(o); + break; + case LUA_VFALSE: + setbfvalue(o); + break; + case LUA_VTRUE: + setbtvalue(o); + break; + case LUA_VNUMFLT: + setfltvalue(o, loadNumber(S)); + break; + case LUA_VNUMINT: + setivalue(o, loadInteger(S)); + break; + case LUA_VSHRSTR: + case LUA_VLNGSTR: + setsvalue2n(S->L, o, loadString(S, f)); + break; + default: lua_assert(0); + } + } +} + + +static void loadProtos (LoadState *S, Proto *f) { + int i; + int n = loadInt(S); + f->p = luaM_newvectorchecked(S->L, n, Proto *); + f->sizep = n; + for (i = 0; i < n; i++) + f->p[i] = NULL; + for (i = 0; i < n; i++) { + f->p[i] = luaF_newproto(S->L); + luaC_objbarrier(S->L, f, f->p[i]); + loadFunction(S, f->p[i], f->source); + } +} + + +/* +** Load the upvalues for a function. The names must be filled first, +** because the filling of the other fields can raise read errors and +** the creation of the error message can call an emergency collection; +** in that case all prototypes must be consistent for the GC. +*/ +static void loadUpvalues (LoadState *S, Proto *f) { + int i, n; + n = loadInt(S); + f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc); + f->sizeupvalues = n; + for (i = 0; i < n; i++) /* make array valid for GC */ + f->upvalues[i].name = NULL; + for (i = 0; i < n; i++) { /* following calls can raise errors */ + f->upvalues[i].instack = loadByte(S); + f->upvalues[i].idx = loadByte(S); + f->upvalues[i].kind = loadByte(S); + } +} + + +static void loadDebug (LoadState *S, Proto *f) { + int i, n; + n = loadInt(S); + f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte); + f->sizelineinfo = n; + loadVector(S, f->lineinfo, n); + n = loadInt(S); + f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo); + f->sizeabslineinfo = n; + for (i = 0; i < n; i++) { + f->abslineinfo[i].pc = loadInt(S); + f->abslineinfo[i].line = loadInt(S); + } + n = loadInt(S); + f->locvars = luaM_newvectorchecked(S->L, n, LocVar); + f->sizelocvars = n; + for (i = 0; i < n; i++) + f->locvars[i].varname = NULL; + for (i = 0; i < n; i++) { + f->locvars[i].varname = loadStringN(S, f); + f->locvars[i].startpc = loadInt(S); + f->locvars[i].endpc = loadInt(S); + } + n = loadInt(S); + if (n != 0) /* does it have debug information? */ + n = f->sizeupvalues; /* must be this many */ + for (i = 0; i < n; i++) + f->upvalues[i].name = loadStringN(S, f); +} + + +static void loadFunction (LoadState *S, Proto *f, TString *psource) { + f->source = loadStringN(S, f); + if (f->source == NULL) /* no source in dump? */ + f->source = psource; /* reuse parent's source */ + f->linedefined = loadInt(S); + f->lastlinedefined = loadInt(S); + f->numparams = loadByte(S); + f->is_vararg = loadByte(S); + f->maxstacksize = loadByte(S); + loadCode(S, f); + loadConstants(S, f); + loadUpvalues(S, f); + loadProtos(S, f); + loadDebug(S, f); +} + + +static void checkliteral (LoadState *S, const char *s, const char *msg) { + char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */ + size_t len = strlen(s); + loadVector(S, buff, len); + if (memcmp(s, buff, len) != 0) + error(S, msg); +} + + +static void fchecksize (LoadState *S, size_t size, const char *tname) { + if (loadByte(S) != size) + error(S, luaO_pushfstring(S->L, "%s size mismatch", tname)); +} + + +#define checksize(S,t) fchecksize(S,sizeof(t),#t) + +static void checkHeader (LoadState *S) { + /* skip 1st char (already read and checked) */ + checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk"); + if (loadByte(S) != LUAC_VERSION) + error(S, "version mismatch"); + if (loadByte(S) != LUAC_FORMAT) + error(S, "format mismatch"); + checkliteral(S, LUAC_DATA, "corrupted chunk"); + checksize(S, Instruction); + checksize(S, lua_Integer); + checksize(S, lua_Number); + if (loadInteger(S) != LUAC_INT) + error(S, "integer format mismatch"); + if (loadNumber(S) != LUAC_NUM) + error(S, "float format mismatch"); +} + + +/* +** Load precompiled chunk. +*/ +LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) { + LoadState S; + LClosure *cl; + if (*name == '@' || *name == '=') + S.name = name + 1; + else if (*name == LUA_SIGNATURE[0]) + S.name = "binary string"; + else + S.name = name; + S.L = L; + S.Z = Z; + checkHeader(&S); + cl = luaF_newLclosure(L, loadByte(&S)); + setclLvalue2s(L, L->top.p, cl); + luaD_inctop(L); + cl->p = luaF_newproto(L); + luaC_objbarrier(L, cl, cl->p); + loadFunction(&S, cl->p, NULL); + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luai_verifycode(L, cl->p); + return cl; +} + diff --git a/src/libs/3rdparty/lua/src/lundump.h b/src/libs/3rdparty/lua/src/lundump.h new file mode 100644 index 0000000000..f3748a9980 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lundump.h @@ -0,0 +1,36 @@ +/* +** $Id: lundump.h $ +** load precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#ifndef lundump_h +#define lundump_h + +#include "llimits.h" +#include "lobject.h" +#include "lzio.h" + + +/* data to catch conversion errors */ +#define LUAC_DATA "\x19\x93\r\n\x1a\n" + +#define LUAC_INT 0x5678 +#define LUAC_NUM cast_num(370.5) + +/* +** Encode major-minor version in one byte, one nibble for each +*/ +#define MYINT(s) (s[0]-'0') /* assume one-digit numerals */ +#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)) + +#define LUAC_FORMAT 0 /* this is the official format */ + +/* load one chunk; from lundump.c */ +LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); + +/* dump one chunk; from ldump.c */ +LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, + void* data, int strip); + +#endif diff --git a/src/libs/3rdparty/lua/src/lutf8lib.c b/src/libs/3rdparty/lua/src/lutf8lib.c new file mode 100644 index 0000000000..3a5b9bc38a --- /dev/null +++ b/src/libs/3rdparty/lua/src/lutf8lib.c @@ -0,0 +1,291 @@ +/* +** $Id: lutf8lib.c $ +** Standard library for UTF-8 manipulation +** See Copyright Notice in lua.h +*/ + +#define lutf8lib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include <assert.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#define MAXUNICODE 0x10FFFFu + +#define MAXUTF 0x7FFFFFFFu + + +#define MSGInvalid "invalid UTF-8 code" + +/* +** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits. +*/ +#if (UINT_MAX >> 30) >= 1 +typedef unsigned int utfint; +#else +typedef unsigned long utfint; +#endif + + +#define iscont(c) (((c) & 0xC0) == 0x80) +#define iscontp(p) iscont(*(p)) + + +/* from strlib */ +/* translate a relative string position: negative means back from end */ +static lua_Integer u_posrelat (lua_Integer pos, size_t len) { + if (pos >= 0) return pos; + else if (0u - (size_t)pos > len) return 0; + else return (lua_Integer)len + pos + 1; +} + + +/* +** Decode one UTF-8 sequence, returning NULL if byte sequence is +** invalid. The array 'limits' stores the minimum value for each +** sequence length, to check for overlong representations. Its first +** entry forces an error for non-ascii bytes with no continuation +** bytes (count == 0). +*/ +static const char *utf8_decode (const char *s, utfint *val, int strict) { + static const utfint limits[] = + {~(utfint)0, 0x80, 0x800, 0x10000u, 0x200000u, 0x4000000u}; + unsigned int c = (unsigned char)s[0]; + utfint res = 0; /* final result */ + if (c < 0x80) /* ascii? */ + res = c; + else { + int count = 0; /* to count number of continuation bytes */ + for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */ + unsigned int cc = (unsigned char)s[++count]; /* read next byte */ + if (!iscont(cc)) /* not a continuation byte? */ + return NULL; /* invalid byte sequence */ + res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ + } + res |= ((utfint)(c & 0x7F) << (count * 5)); /* add first byte */ + if (count > 5 || res > MAXUTF || res < limits[count]) + return NULL; /* invalid byte sequence */ + s += count; /* skip continuation bytes read */ + } + if (strict) { + /* check for invalid code points; too large or surrogates */ + if (res > MAXUNICODE || (0xD800u <= res && res <= 0xDFFFu)) + return NULL; + } + if (val) *val = res; + return s + 1; /* +1 to include first byte */ +} + + +/* +** utf8len(s [, i [, j [, lax]]]) --> number of characters that +** start in the range [i,j], or nil + current position if 's' is not +** well formed in that interval +*/ +static int utflen (lua_State *L) { + lua_Integer n = 0; /* counter for the number of characters */ + size_t len; /* string length in bytes */ + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); + int lax = lua_toboolean(L, 4); + luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, + "initial position out of bounds"); + luaL_argcheck(L, --posj < (lua_Integer)len, 3, + "final position out of bounds"); + while (posi <= posj) { + const char *s1 = utf8_decode(s + posi, NULL, !lax); + if (s1 == NULL) { /* conversion error? */ + luaL_pushfail(L); /* return fail ... */ + lua_pushinteger(L, posi + 1); /* ... and current position */ + return 2; + } + posi = s1 - s; + n++; + } + lua_pushinteger(L, n); + return 1; +} + + +/* +** codepoint(s, [i, [j [, lax]]]) -> returns codepoints for all +** characters that start in the range [i,j] +*/ +static int codepoint (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); + int lax = lua_toboolean(L, 4); + int n; + const char *se; + luaL_argcheck(L, posi >= 1, 2, "out of bounds"); + luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of bounds"); + if (posi > pose) return 0; /* empty interval; return no values */ + if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ + return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; /* upper bound for number of returns */ + luaL_checkstack(L, n, "string slice too long"); + n = 0; /* count the number of returns */ + se = s + pose; /* string end */ + for (s += posi - 1; s < se;) { + utfint code; + s = utf8_decode(s, &code, !lax); + if (s == NULL) + return luaL_error(L, MSGInvalid); + lua_pushinteger(L, code); + n++; + } + return n; +} + + +static void pushutfchar (lua_State *L, int arg) { + lua_Unsigned code = (lua_Unsigned)luaL_checkinteger(L, arg); + luaL_argcheck(L, code <= MAXUTF, arg, "value out of range"); + lua_pushfstring(L, "%U", (long)code); +} + + +/* +** utfchar(n1, n2, ...) -> char(n1)..char(n2)... +*/ +static int utfchar (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + if (n == 1) /* optimize common case of single char */ + pushutfchar(L, 1); + else { + int i; + luaL_Buffer b; + luaL_buffinit(L, &b); + for (i = 1; i <= n; i++) { + pushutfchar(L, i); + luaL_addvalue(&b); + } + luaL_pushresult(&b); + } + return 1; +} + + +/* +** offset(s, n, [i]) -> index where n-th character counting from +** position 'i' starts; 0 means character at 'i'. +*/ +static int byteoffset (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer n = luaL_checkinteger(L, 2); + lua_Integer posi = (n >= 0) ? 1 : len + 1; + posi = u_posrelat(luaL_optinteger(L, 3, posi), len); + luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, + "position out of bounds"); + if (n == 0) { + /* find beginning of current byte sequence */ + while (posi > 0 && iscontp(s + posi)) posi--; + } + else { + if (iscontp(s + posi)) + return luaL_error(L, "initial position is a continuation byte"); + if (n < 0) { + while (n < 0 && posi > 0) { /* move back */ + do { /* find beginning of previous character */ + posi--; + } while (posi > 0 && iscontp(s + posi)); + n++; + } + } + else { + n--; /* do not move for 1st character */ + while (n > 0 && posi < (lua_Integer)len) { + do { /* find beginning of next character */ + posi++; + } while (iscontp(s + posi)); /* (cannot pass final '\0') */ + n--; + } + } + } + if (n == 0) /* did it find given character? */ + lua_pushinteger(L, posi + 1); + else /* no such character */ + luaL_pushfail(L); + return 1; +} + + +static int iter_aux (lua_State *L, int strict) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2); + if (n < len) { + while (iscontp(s + n)) n++; /* go to next character */ + } + if (n >= len) /* (also handles original 'n' being negative) */ + return 0; /* no more codepoints */ + else { + utfint code; + const char *next = utf8_decode(s + n, &code, strict); + if (next == NULL || iscontp(next)) + return luaL_error(L, MSGInvalid); + lua_pushinteger(L, n + 1); + lua_pushinteger(L, code); + return 2; + } +} + + +static int iter_auxstrict (lua_State *L) { + return iter_aux(L, 1); +} + +static int iter_auxlax (lua_State *L) { + return iter_aux(L, 0); +} + + +static int iter_codes (lua_State *L) { + int lax = lua_toboolean(L, 2); + const char *s = luaL_checkstring(L, 1); + luaL_argcheck(L, !iscontp(s), 1, MSGInvalid); + lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict); + lua_pushvalue(L, 1); + lua_pushinteger(L, 0); + return 3; +} + + +/* pattern to match a single UTF-8 character */ +#define UTF8PATT "[\0-\x7F\xC2-\xFD][\x80-\xBF]*" + + +static const luaL_Reg funcs[] = { + {"offset", byteoffset}, + {"codepoint", codepoint}, + {"char", utfchar}, + {"len", utflen}, + {"codes", iter_codes}, + /* placeholders */ + {"charpattern", NULL}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_utf8 (lua_State *L) { + luaL_newlib(L, funcs); + lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1); + lua_setfield(L, -2, "charpattern"); + return 1; +} + diff --git a/src/libs/3rdparty/lua/src/lvm.c b/src/libs/3rdparty/lua/src/lvm.c new file mode 100644 index 0000000000..8493a770c5 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lvm.c @@ -0,0 +1,1901 @@ +/* +** $Id: lvm.c $ +** Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#define lvm_c +#define LUA_CORE + +#include "lprefix.h" + +#include <float.h> +#include <limits.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + +/* +** By default, use jump tables in the main interpreter loop on gcc +** and compatible compilers. +*/ +#if !defined(LUA_USE_JUMPTABLE) +#if defined(__GNUC__) +#define LUA_USE_JUMPTABLE 1 +#else +#define LUA_USE_JUMPTABLE 0 +#endif +#endif + + + +/* limit for table tag-method chains (to avoid infinite loops) */ +#define MAXTAGLOOP 2000 + + +/* +** 'l_intfitsf' checks whether a given integer is in the range that +** can be converted to a float without rounding. Used in comparisons. +*/ + +/* number of bits in the mantissa of a float */ +#define NBM (l_floatatt(MANT_DIG)) + +/* +** Check whether some integers may not fit in a float, testing whether +** (maxinteger >> NBM) > 0. (That implies (1 << NBM) <= maxinteger.) +** (The shifts are done in parts, to avoid shifting by more than the size +** of an integer. In a worst case, NBM == 113 for long double and +** sizeof(long) == 32.) +*/ +#if ((((LUA_MAXINTEGER >> (NBM / 4)) >> (NBM / 4)) >> (NBM / 4)) \ + >> (NBM - (3 * (NBM / 4)))) > 0 + +/* limit for integers that fit in a float */ +#define MAXINTFITSF ((lua_Unsigned)1 << NBM) + +/* check whether 'i' is in the interval [-MAXINTFITSF, MAXINTFITSF] */ +#define l_intfitsf(i) ((MAXINTFITSF + l_castS2U(i)) <= (2 * MAXINTFITSF)) + +#else /* all integers fit in a float precisely */ + +#define l_intfitsf(i) 1 + +#endif + + +/* +** Try to convert a value from string to a number value. +** If the value is not a string or is a string not representing +** a valid numeral (or if coercions from strings to numbers +** are disabled via macro 'cvt2num'), do not modify 'result' +** and return 0. +*/ +static int l_strton (const TValue *obj, TValue *result) { + lua_assert(obj != result); + if (!cvt2num(obj)) /* is object not a string? */ + return 0; + else + return (luaO_str2num(svalue(obj), result) == vslen(obj) + 1); +} + + +/* +** Try to convert a value to a float. The float case is already handled +** by the macro 'tonumber'. +*/ +int luaV_tonumber_ (const TValue *obj, lua_Number *n) { + TValue v; + if (ttisinteger(obj)) { + *n = cast_num(ivalue(obj)); + return 1; + } + else if (l_strton(obj, &v)) { /* string coercible to number? */ + *n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */ + return 1; + } + else + return 0; /* conversion failed */ +} + + +/* +** try to convert a float to an integer, rounding according to 'mode'. +*/ +int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode) { + lua_Number f = l_floor(n); + if (n != f) { /* not an integral value? */ + if (mode == F2Ieq) return 0; /* fails if mode demands integral value */ + else if (mode == F2Iceil) /* needs ceil? */ + f += 1; /* convert floor to ceil (remember: n != f) */ + } + return lua_numbertointeger(f, p); +} + + +/* +** try to convert a value to an integer, rounding according to 'mode', +** without string coercion. +** ("Fast track" handled by macro 'tointegerns'.) +*/ +int luaV_tointegerns (const TValue *obj, lua_Integer *p, F2Imod mode) { + if (ttisfloat(obj)) + return luaV_flttointeger(fltvalue(obj), p, mode); + else if (ttisinteger(obj)) { + *p = ivalue(obj); + return 1; + } + else + return 0; +} + + +/* +** try to convert a value to an integer. +*/ +int luaV_tointeger (const TValue *obj, lua_Integer *p, F2Imod mode) { + TValue v; + if (l_strton(obj, &v)) /* does 'obj' point to a numerical string? */ + obj = &v; /* change it to point to its corresponding number */ + return luaV_tointegerns(obj, p, mode); +} + + +/* +** Try to convert a 'for' limit to an integer, preserving the semantics +** of the loop. Return true if the loop must not run; otherwise, '*p' +** gets the integer limit. +** (The following explanation assumes a positive step; it is valid for +** negative steps mutatis mutandis.) +** If the limit is an integer or can be converted to an integer, +** rounding down, that is the limit. +** Otherwise, check whether the limit can be converted to a float. If +** the float is too large, clip it to LUA_MAXINTEGER. If the float +** is too negative, the loop should not run, because any initial +** integer value is greater than such limit; so, the function returns +** true to signal that. (For this latter case, no integer limit would be +** correct; even a limit of LUA_MININTEGER would run the loop once for +** an initial value equal to LUA_MININTEGER.) +*/ +static int forlimit (lua_State *L, lua_Integer init, const TValue *lim, + lua_Integer *p, lua_Integer step) { + if (!luaV_tointeger(lim, p, (step < 0 ? F2Iceil : F2Ifloor))) { + /* not coercible to in integer */ + lua_Number flim; /* try to convert to float */ + if (!tonumber(lim, &flim)) /* cannot convert to float? */ + luaG_forerror(L, lim, "limit"); + /* else 'flim' is a float out of integer bounds */ + if (luai_numlt(0, flim)) { /* if it is positive, it is too large */ + if (step < 0) return 1; /* initial value must be less than it */ + *p = LUA_MAXINTEGER; /* truncate */ + } + else { /* it is less than min integer */ + if (step > 0) return 1; /* initial value must be greater than it */ + *p = LUA_MININTEGER; /* truncate */ + } + } + return (step > 0 ? init > *p : init < *p); /* not to run? */ +} + + +/* +** Prepare a numerical for loop (opcode OP_FORPREP). +** Return true to skip the loop. Otherwise, +** after preparation, stack will be as follows: +** ra : internal index (safe copy of the control variable) +** ra + 1 : loop counter (integer loops) or limit (float loops) +** ra + 2 : step +** ra + 3 : control variable +*/ +static int forprep (lua_State *L, StkId ra) { + TValue *pinit = s2v(ra); + TValue *plimit = s2v(ra + 1); + TValue *pstep = s2v(ra + 2); + if (ttisinteger(pinit) && ttisinteger(pstep)) { /* integer loop? */ + lua_Integer init = ivalue(pinit); + lua_Integer step = ivalue(pstep); + lua_Integer limit; + if (step == 0) + luaG_runerror(L, "'for' step is zero"); + setivalue(s2v(ra + 3), init); /* control variable */ + if (forlimit(L, init, plimit, &limit, step)) + return 1; /* skip the loop */ + else { /* prepare loop counter */ + lua_Unsigned count; + if (step > 0) { /* ascending loop? */ + count = l_castS2U(limit) - l_castS2U(init); + if (step != 1) /* avoid division in the too common case */ + count /= l_castS2U(step); + } + else { /* step < 0; descending loop */ + count = l_castS2U(init) - l_castS2U(limit); + /* 'step+1' avoids negating 'mininteger' */ + count /= l_castS2U(-(step + 1)) + 1u; + } + /* store the counter in place of the limit (which won't be + needed anymore) */ + setivalue(plimit, l_castU2S(count)); + } + } + else { /* try making all values floats */ + lua_Number init; lua_Number limit; lua_Number step; + if (l_unlikely(!tonumber(plimit, &limit))) + luaG_forerror(L, plimit, "limit"); + if (l_unlikely(!tonumber(pstep, &step))) + luaG_forerror(L, pstep, "step"); + if (l_unlikely(!tonumber(pinit, &init))) + luaG_forerror(L, pinit, "initial value"); + if (step == 0) + luaG_runerror(L, "'for' step is zero"); + if (luai_numlt(0, step) ? luai_numlt(limit, init) + : luai_numlt(init, limit)) + return 1; /* skip the loop */ + else { + /* make sure internal values are all floats */ + setfltvalue(plimit, limit); + setfltvalue(pstep, step); + setfltvalue(s2v(ra), init); /* internal index */ + setfltvalue(s2v(ra + 3), init); /* control variable */ + } + } + return 0; +} + + +/* +** Execute a step of a float numerical for loop, returning +** true iff the loop must continue. (The integer case is +** written online with opcode OP_FORLOOP, for performance.) +*/ +static int floatforloop (StkId ra) { + lua_Number step = fltvalue(s2v(ra + 2)); + lua_Number limit = fltvalue(s2v(ra + 1)); + lua_Number idx = fltvalue(s2v(ra)); /* internal index */ + idx = luai_numadd(L, idx, step); /* increment index */ + if (luai_numlt(0, step) ? luai_numle(idx, limit) + : luai_numle(limit, idx)) { + chgfltvalue(s2v(ra), idx); /* update internal index */ + setfltvalue(s2v(ra + 3), idx); /* and control variable */ + return 1; /* jump back */ + } + else + return 0; /* finish the loop */ +} + + +/* +** Finish the table access 'val = t[key]'. +** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to +** t[k] entry (which must be empty). +*/ +void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, + const TValue *slot) { + int loop; /* counter to avoid infinite loops */ + const TValue *tm; /* metamethod */ + for (loop = 0; loop < MAXTAGLOOP; loop++) { + if (slot == NULL) { /* 't' is not a table? */ + lua_assert(!ttistable(t)); + tm = luaT_gettmbyobj(L, t, TM_INDEX); + if (l_unlikely(notm(tm))) + luaG_typeerror(L, t, "index"); /* no metamethod */ + /* else will try the metamethod */ + } + else { /* 't' is a table */ + lua_assert(isempty(slot)); + tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ + if (tm == NULL) { /* no metamethod? */ + setnilvalue(s2v(val)); /* result is nil */ + return; + } + /* else will try the metamethod */ + } + if (ttisfunction(tm)) { /* is metamethod a function? */ + luaT_callTMres(L, tm, t, key, val); /* 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"); +} + + +/* +** Finish a table assignment 't[key] = val'. +** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points +** to the entry 't[key]', or to a value with an absent key if there +** is no such entry. (The value at 'slot' must be empty, otherwise +** 'luaV_fastget' would have done the job.) +*/ +void luaV_finishset (lua_State *L, const TValue *t, TValue *key, + TValue *val, const TValue *slot) { + int loop; /* counter to avoid infinite loops */ + for (loop = 0; loop < MAXTAGLOOP; loop++) { + const TValue *tm; /* '__newindex' metamethod */ + if (slot != NULL) { /* is 't' a table? */ + Table *h = hvalue(t); /* save 't' table */ + lua_assert(isempty(slot)); /* slot must be empty */ + tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ + if (tm == NULL) { /* no metamethod? */ + luaH_finishset(L, h, key, slot, val); /* set new value */ + invalidateTMcache(h); + luaC_barrierback(L, obj2gco(h), val); + return; + } + /* else will try the metamethod */ + } + else { /* not a table; check metamethod */ + tm = luaT_gettmbyobj(L, t, TM_NEWINDEX); + if (l_unlikely(notm(tm))) + luaG_typeerror(L, t, "index"); + } + /* try the metamethod */ + if (ttisfunction(tm)) { + luaT_callTM(L, tm, t, key, val); + return; + } + t = tm; /* else repeat assignment over 'tm' */ + if (luaV_fastget(L, t, key, slot, luaH_get)) { + luaV_finishfastset(L, t, slot, val); + return; /* done */ + } + /* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */ + } + luaG_runerror(L, "'__newindex' chain too long; possible loop"); +} + + +/* +** Compare two strings 'ls' x 'rs', returning an integer less-equal- +** -greater than zero if 'ls' is less-equal-greater than 'rs'. +** The code is a little tricky because it allows '\0' in the strings +** and it uses 'strcoll' (to respect locales) for each segments +** of the strings. +*/ +static int l_strcmp (const TString *ls, const TString *rs) { + const char *l = getstr(ls); + size_t ll = tsslen(ls); + const char *r = getstr(rs); + size_t lr = tsslen(rs); + for (;;) { /* for each segment */ + int temp = strcoll(l, r); + if (temp != 0) /* not equal? */ + return temp; /* done */ + else { /* strings are equal up to a '\0' */ + size_t len = strlen(l); /* index of first '\0' in both strings */ + if (len == lr) /* 'rs' is finished? */ + return (len == ll) ? 0 : 1; /* check 'ls' */ + else if (len == ll) /* 'ls' is finished? */ + return -1; /* 'ls' is less than 'rs' ('rs' is not finished) */ + /* both strings longer than 'len'; go on comparing after the '\0' */ + len++; + l += len; ll -= len; r += len; lr -= len; + } + } +} + + +/* +** 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, use the equivalence 'i < f <=> i < ceil(f)'. +** If 'ceil(f)' is out of integer range, either 'f' is greater than +** all integers or less than all integers. +** (The test with 'l_intfitsf' is only for performance; the else +** case is correct for all values, but it is slow due to the conversion +** from float to int.) +** When 'f' is NaN, comparisons must result in false. +*/ +l_sinline int LTintfloat (lua_Integer i, lua_Number f) { + if (l_intfitsf(i)) + return luai_numlt(cast_num(i), f); /* compare them as floats */ + else { /* i < f <=> i < ceil(f) */ + lua_Integer fi; + if (luaV_flttointeger(f, &fi, F2Iceil)) /* fi = ceil(f) */ + return i < fi; /* compare them as integers */ + else /* 'f' is either greater or less than all integers */ + return f > 0; /* greater? */ + } +} + + +/* +** Check whether integer 'i' is less than or equal to float 'f'. +** See comments on previous function. +*/ +l_sinline int LEintfloat (lua_Integer i, lua_Number f) { + if (l_intfitsf(i)) + return luai_numle(cast_num(i), f); /* compare them as floats */ + else { /* i <= f <=> i <= floor(f) */ + lua_Integer fi; + if (luaV_flttointeger(f, &fi, F2Ifloor)) /* fi = floor(f) */ + return i <= fi; /* compare them as integers */ + else /* 'f' is either greater or less than all integers */ + return f > 0; /* greater? */ + } +} + + +/* +** Check whether float 'f' is less than integer 'i'. +** See comments on previous function. +*/ +l_sinline int LTfloatint (lua_Number f, lua_Integer i) { + if (l_intfitsf(i)) + return luai_numlt(f, cast_num(i)); /* compare them as floats */ + else { /* f < i <=> floor(f) < i */ + lua_Integer fi; + if (luaV_flttointeger(f, &fi, F2Ifloor)) /* fi = floor(f) */ + return fi < i; /* compare them as integers */ + else /* 'f' is either greater or less than all integers */ + return f < 0; /* less? */ + } +} + + +/* +** Check whether float 'f' is less than or equal to integer 'i'. +** See comments on previous function. +*/ +l_sinline int LEfloatint (lua_Number f, lua_Integer i) { + if (l_intfitsf(i)) + return luai_numle(f, cast_num(i)); /* compare them as floats */ + else { /* f <= i <=> ceil(f) <= i */ + lua_Integer fi; + if (luaV_flttointeger(f, &fi, F2Iceil)) /* fi = ceil(f) */ + return fi <= i; /* compare them as integers */ + else /* 'f' is either greater or less than all integers */ + return f < 0; /* less? */ + } +} + + +/* +** Return 'l < r', for numbers. +*/ +l_sinline int LTnum (const TValue *l, const TValue *r) { + lua_assert(ttisnumber(l) && ttisnumber(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 /* 'l' is float and 'r' is int */ + return LTfloatint(lf, ivalue(r)); + } +} + + +/* +** Return 'l <= r', for numbers. +*/ +l_sinline int LEnum (const TValue *l, const TValue *r) { + lua_assert(ttisnumber(l) && ttisnumber(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 /* 'l' is float and 'r' is int */ + return LEfloatint(lf, ivalue(r)); + } +} + + +/* +** return 'l < r' for non-numbers. +*/ +static int lessthanothers (lua_State *L, const TValue *l, const TValue *r) { + lua_assert(!ttisnumber(l) || !ttisnumber(r)); + if (ttisstring(l) && ttisstring(r)) /* both are strings? */ + return l_strcmp(tsvalue(l), tsvalue(r)) < 0; + else + return luaT_callorderTM(L, l, r, TM_LT); +} + + +/* +** Main operation less than; return 'l < r'. +*/ +int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { + if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ + return LTnum(l, r); + else return lessthanothers(L, l, r); +} + + +/* +** return 'l <= r' for non-numbers. +*/ +static int lessequalothers (lua_State *L, const TValue *l, const TValue *r) { + lua_assert(!ttisnumber(l) || !ttisnumber(r)); + if (ttisstring(l) && ttisstring(r)) /* both are strings? */ + return l_strcmp(tsvalue(l), tsvalue(r)) <= 0; + else + return luaT_callorderTM(L, l, r, TM_LE); +} + + +/* +** Main operation less than or equal to; return 'l <= r'. +*/ +int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { + if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ + return LEnum(l, r); + else return lessequalothers(L, l, r); +} + + +/* +** Main operation for equality of Lua values; return 't1 == t2'. +** L == NULL means raw equality (no metamethods) +*/ +int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { + const TValue *tm; + if (ttypetag(t1) != ttypetag(t2)) { /* not the same variant? */ + if (ttype(t1) != ttype(t2) || ttype(t1) != LUA_TNUMBER) + return 0; /* only numbers can be equal with different variants */ + else { /* two numbers with different variants */ + /* One of them is an integer. If the other does not have an + integer value, they cannot be equal; otherwise, compare their + integer values. */ + lua_Integer i1, i2; + return (luaV_tointegerns(t1, &i1, F2Ieq) && + luaV_tointegerns(t2, &i2, F2Ieq) && + i1 == i2); + } + } + /* values have same type and same variant */ + switch (ttypetag(t1)) { + case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE: return 1; + case LUA_VNUMINT: return (ivalue(t1) == ivalue(t2)); + case LUA_VNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2)); + case LUA_VLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); + case LUA_VLCF: return fvalue(t1) == fvalue(t2); + case LUA_VSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2)); + case LUA_VLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2)); + case LUA_VUSERDATA: { + if (uvalue(t1) == uvalue(t2)) return 1; + else if (L == NULL) return 0; + tm = fasttm(L, uvalue(t1)->metatable, TM_EQ); + if (tm == NULL) + tm = fasttm(L, uvalue(t2)->metatable, TM_EQ); + break; /* will try TM */ + } + case LUA_VTABLE: { + if (hvalue(t1) == hvalue(t2)) return 1; + else if (L == NULL) return 0; + tm = fasttm(L, hvalue(t1)->metatable, TM_EQ); + if (tm == NULL) + tm = fasttm(L, hvalue(t2)->metatable, TM_EQ); + break; /* will try TM */ + } + default: + return gcvalue(t1) == gcvalue(t2); + } + if (tm == NULL) /* no TM? */ + return 0; /* objects are different */ + else { + luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */ + return !l_isfalse(s2v(L->top.p)); + } +} + + +/* macro used by 'luaV_concat' to ensure that element at 'o' is a string */ +#define tostring(L,o) \ + (ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1))) + +#define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0) + +/* copy strings in stack from top - n up to top - 1 to buffer */ +static void copy2buff (StkId top, int n, char *buff) { + size_t tl = 0; /* size already copied */ + do { + size_t l = vslen(s2v(top - n)); /* length of string being copied */ + memcpy(buff + tl, svalue(s2v(top - n)), l * sizeof(char)); + tl += l; + } while (--n > 0); +} + + +/* +** Main operation for concatenation: concat 'total' values in the stack, +** from 'L->top.p - total' up to 'L->top.p - 1'. +*/ +void luaV_concat (lua_State *L, int total) { + if (total == 1) + return; /* "all" values already concatenated */ + do { + StkId top = L->top.p; + int n = 2; /* number of elements handled in this pass (at least 2) */ + if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) || + !tostring(L, s2v(top - 1))) + luaT_tryconcatTM(L); /* may invalidate 'top' */ + else if (isemptystr(s2v(top - 1))) /* second operand is empty? */ + cast_void(tostring(L, s2v(top - 2))); /* result is first operand */ + else if (isemptystr(s2v(top - 2))) { /* first operand is empty string? */ + setobjs2s(L, top - 2, top - 1); /* result is second op. */ + } + else { + /* at least two non-empty string values; get as many as possible */ + size_t tl = vslen(s2v(top - 1)); + TString *ts; + /* collect total length and number of strings */ + for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) { + size_t l = vslen(s2v(top - n - 1)); + if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) { + L->top.p = top - total; /* pop strings to avoid wasting stack */ + luaG_runerror(L, "string length overflow"); + } + tl += l; + } + if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */ + char buff[LUAI_MAXSHORTLEN]; + copy2buff(top, n, buff); /* copy strings to buffer */ + ts = luaS_newlstr(L, buff, tl); + } + else { /* long string; copy strings directly to final result */ + ts = luaS_createlngstrobj(L, tl); + copy2buff(top, n, getstr(ts)); + } + setsvalue2s(L, top - n, ts); /* create result */ + } + total -= n - 1; /* got 'n' strings to create one new */ + L->top.p -= n - 1; /* popped 'n' strings and pushed one */ + } while (total > 1); /* repeat until only 1 result left */ +} + + +/* +** Main operation 'ra = #rb'. +*/ +void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { + const TValue *tm; + switch (ttypetag(rb)) { + case LUA_VTABLE: { + Table *h = hvalue(rb); + tm = fasttm(L, h->metatable, TM_LEN); + if (tm) break; /* metamethod? break switch to call it */ + setivalue(s2v(ra), luaH_getn(h)); /* else primitive len */ + return; + } + case LUA_VSHRSTR: { + setivalue(s2v(ra), tsvalue(rb)->shrlen); + return; + } + case LUA_VLNGSTR: { + setivalue(s2v(ra), tsvalue(rb)->u.lnglen); + return; + } + default: { /* try metamethod */ + tm = luaT_gettmbyobj(L, rb, TM_LEN); + if (l_unlikely(notm(tm))) /* no metamethod? */ + luaG_typeerror(L, rb, "get length of"); + break; + } + } + luaT_callTMres(L, tm, rb, rb, ra); +} + + +/* +** Integer division; return 'm // n', that is, floor(m/n). +** C division truncates its result (rounds towards zero). +** 'floor(q) == trunc(q)' when 'q >= 0' or when 'q' is integer, +** otherwise 'floor(q) == trunc(q) - 1'. +*/ +lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) { + if (l_unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */ + if (n == 0) + luaG_runerror(L, "attempt to divide by zero"); + return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ + } + else { + lua_Integer q = m / n; /* perform C division */ + if ((m ^ n) < 0 && m % n != 0) /* 'm/n' would be negative non-integer? */ + q -= 1; /* correct result for different rounding */ + return q; + } +} + + +/* +** Integer modulus; return 'm % n'. (Assume that C '%' with +** negative operands follows C99 behavior. See previous comment +** about luaV_idiv.) +*/ +lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { + if (l_unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */ + if (n == 0) + luaG_runerror(L, "attempt to perform 'n%%0'"); + return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ + } + else { + lua_Integer r = m % n; + if (r != 0 && (r ^ n) < 0) /* 'm/n' would be non-integer negative? */ + r += n; /* correct result for different rounding */ + return r; + } +} + + +/* +** Float modulus +*/ +lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) { + lua_Number r; + luai_nummod(L, m, n, r); + return r; +} + + +/* number of bits in an integer */ +#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT) + + +/* +** Shift left operation. (Shift right just negates 'y'.) +*/ +lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { + if (y < 0) { /* shift right? */ + if (y <= -NBITS) return 0; + else return intop(>>, x, -y); + } + else { /* shift left */ + if (y >= NBITS) return 0; + else return intop(<<, x, y); + } +} + + +/* +** create a new Lua closure, push it in the stack, and initialize +** its upvalues. +*/ +static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, + StkId ra) { + int nup = p->sizeupvalues; + Upvaldesc *uv = p->upvalues; + int i; + LClosure *ncl = luaF_newLclosure(L, nup); + ncl->p = p; + setclLvalue2s(L, ra, ncl); /* anchor new closure in stack */ + for (i = 0; i < nup; i++) { /* fill in its upvalues */ + if (uv[i].instack) /* upvalue refers to local variable? */ + ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx); + else /* get upvalue from enclosing function */ + ncl->upvals[i] = encup[uv[i].idx]; + luaC_objbarrier(L, ncl, ncl->upvals[i]); + } +} + + +/* +** finish execution of an opcode interrupted by a yield +*/ +void luaV_finishOp (lua_State *L) { + CallInfo *ci = L->ci; + StkId base = ci->func.p + 1; + Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ + OpCode op = GET_OPCODE(inst); + switch (op) { /* finish its execution */ + case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: { + setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top.p); + break; + } + case OP_UNM: case OP_BNOT: case OP_LEN: + case OP_GETTABUP: case OP_GETTABLE: case OP_GETI: + case OP_GETFIELD: case OP_SELF: { + setobjs2s(L, base + GETARG_A(inst), --L->top.p); + break; + } + case OP_LT: case OP_LE: + case OP_LTI: case OP_LEI: + case OP_GTI: case OP_GEI: + case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */ + int res = !l_isfalse(s2v(L->top.p - 1)); + L->top.p--; +#if defined(LUA_COMPAT_LT_LE) + if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ + ci->callstatus ^= CIST_LEQ; /* clear mark */ + res = !res; /* negate result */ + } +#endif + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); + if (res != GETARG_k(inst)) /* condition failed? */ + ci->u.l.savedpc++; /* skip jump instruction */ + break; + } + case OP_CONCAT: { + StkId top = L->top.p - 1; /* top when 'luaT_tryconcatTM' was called */ + int a = GETARG_A(inst); /* first element to concatenate */ + int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */ + setobjs2s(L, top - 2, top); /* put TM result in proper position */ + L->top.p = top - 1; /* top is one after last element (at top-2) */ + luaV_concat(L, total); /* concat them (may yield again) */ + break; + } + case OP_CLOSE: { /* yielded closing variables */ + ci->u.l.savedpc--; /* repeat instruction to close other vars. */ + break; + } + case OP_RETURN: { /* yielded closing variables */ + StkId ra = base + GETARG_A(inst); + /* adjust top to signal correct number of returns, in case the + return is "up to top" ('isIT') */ + L->top.p = ra + ci->u2.nres; + /* repeat instruction to close other vars. and complete the return */ + ci->u.l.savedpc--; + break; + } + default: { + /* only these other opcodes can yield */ + lua_assert(op == OP_TFORCALL || op == OP_CALL || + op == OP_TAILCALL || op == OP_SETTABUP || op == OP_SETTABLE || + op == OP_SETI || op == OP_SETFIELD); + break; + } + } +} + + + + +/* +** {================================================================== +** Macros for arithmetic/bitwise/comparison opcodes in 'luaV_execute' +** =================================================================== +*/ + +#define l_addi(L,a,b) intop(+, a, b) +#define l_subi(L,a,b) intop(-, a, b) +#define l_muli(L,a,b) intop(*, a, b) +#define l_band(a,b) intop(&, a, b) +#define l_bor(a,b) intop(|, a, b) +#define l_bxor(a,b) intop(^, a, b) + +#define l_lti(a,b) (a < b) +#define l_lei(a,b) (a <= b) +#define l_gti(a,b) (a > b) +#define l_gei(a,b) (a >= b) + + +/* +** Arithmetic operations with immediate operands. 'iop' is the integer +** operation, 'fop' is the float operation. +*/ +#define op_arithI(L,iop,fop) { \ + StkId ra = RA(i); \ + TValue *v1 = vRB(i); \ + int imm = GETARG_sC(i); \ + if (ttisinteger(v1)) { \ + lua_Integer iv1 = ivalue(v1); \ + pc++; setivalue(s2v(ra), iop(L, iv1, imm)); \ + } \ + else if (ttisfloat(v1)) { \ + lua_Number nb = fltvalue(v1); \ + lua_Number fimm = cast_num(imm); \ + pc++; setfltvalue(s2v(ra), fop(L, nb, fimm)); \ + }} + + +/* +** Auxiliary function for arithmetic operations over floats and others +** with two register operands. +*/ +#define op_arithf_aux(L,v1,v2,fop) { \ + lua_Number n1; lua_Number n2; \ + if (tonumberns(v1, n1) && tonumberns(v2, n2)) { \ + pc++; setfltvalue(s2v(ra), fop(L, n1, n2)); \ + }} + + +/* +** Arithmetic operations over floats and others with register operands. +*/ +#define op_arithf(L,fop) { \ + StkId ra = RA(i); \ + TValue *v1 = vRB(i); \ + TValue *v2 = vRC(i); \ + op_arithf_aux(L, v1, v2, fop); } + + +/* +** Arithmetic operations with K operands for floats. +*/ +#define op_arithfK(L,fop) { \ + StkId ra = RA(i); \ + TValue *v1 = vRB(i); \ + TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \ + op_arithf_aux(L, v1, v2, fop); } + + +/* +** Arithmetic operations over integers and floats. +*/ +#define op_arith_aux(L,v1,v2,iop,fop) { \ + StkId ra = RA(i); \ + if (ttisinteger(v1) && ttisinteger(v2)) { \ + lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \ + pc++; setivalue(s2v(ra), iop(L, i1, i2)); \ + } \ + else op_arithf_aux(L, v1, v2, fop); } + + +/* +** Arithmetic operations with register operands. +*/ +#define op_arith(L,iop,fop) { \ + TValue *v1 = vRB(i); \ + TValue *v2 = vRC(i); \ + op_arith_aux(L, v1, v2, iop, fop); } + + +/* +** Arithmetic operations with K operands. +*/ +#define op_arithK(L,iop,fop) { \ + TValue *v1 = vRB(i); \ + TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \ + op_arith_aux(L, v1, v2, iop, fop); } + + +/* +** Bitwise operations with constant operand. +*/ +#define op_bitwiseK(L,op) { \ + StkId ra = RA(i); \ + TValue *v1 = vRB(i); \ + TValue *v2 = KC(i); \ + lua_Integer i1; \ + lua_Integer i2 = ivalue(v2); \ + if (tointegerns(v1, &i1)) { \ + pc++; setivalue(s2v(ra), op(i1, i2)); \ + }} + + +/* +** Bitwise operations with register operands. +*/ +#define op_bitwise(L,op) { \ + StkId ra = RA(i); \ + TValue *v1 = vRB(i); \ + TValue *v2 = vRC(i); \ + lua_Integer i1; lua_Integer i2; \ + if (tointegerns(v1, &i1) && tointegerns(v2, &i2)) { \ + pc++; setivalue(s2v(ra), op(i1, i2)); \ + }} + + +/* +** Order operations with register operands. 'opn' actually works +** for all numbers, but the fast track improves performance for +** integers. +*/ +#define op_order(L,opi,opn,other) { \ + StkId ra = RA(i); \ + int cond; \ + TValue *rb = vRB(i); \ + if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \ + lua_Integer ia = ivalue(s2v(ra)); \ + lua_Integer ib = ivalue(rb); \ + cond = opi(ia, ib); \ + } \ + else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \ + cond = opn(s2v(ra), rb); \ + else \ + Protect(cond = other(L, s2v(ra), rb)); \ + docondjump(); } + + +/* +** Order operations with immediate operand. (Immediate operand is +** always small enough to have an exact representation as a float.) +*/ +#define op_orderI(L,opi,opf,inv,tm) { \ + StkId ra = RA(i); \ + int cond; \ + int im = GETARG_sB(i); \ + if (ttisinteger(s2v(ra))) \ + cond = opi(ivalue(s2v(ra)), im); \ + else if (ttisfloat(s2v(ra))) { \ + lua_Number fa = fltvalue(s2v(ra)); \ + lua_Number fim = cast_num(im); \ + cond = opf(fa, fim); \ + } \ + else { \ + int isf = GETARG_C(i); \ + Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \ + } \ + docondjump(); } + +/* }================================================================== */ + + +/* +** {================================================================== +** Function 'luaV_execute': main interpreter loop +** =================================================================== +*/ + +/* +** some macros for common tasks in 'luaV_execute' +*/ + + +#define RA(i) (base+GETARG_A(i)) +#define RB(i) (base+GETARG_B(i)) +#define vRB(i) s2v(RB(i)) +#define KB(i) (k+GETARG_B(i)) +#define RC(i) (base+GETARG_C(i)) +#define vRC(i) s2v(RC(i)) +#define KC(i) (k+GETARG_C(i)) +#define RKC(i) ((TESTARG_k(i)) ? k + GETARG_C(i) : s2v(base + GETARG_C(i))) + + + +#define updatetrap(ci) (trap = ci->u.l.trap) + +#define updatebase(ci) (base = ci->func.p + 1) + + +#define updatestack(ci) \ + { if (l_unlikely(trap)) { updatebase(ci); ra = RA(i); } } + + +/* +** Execute a jump instruction. The 'updatetrap' allows signals to stop +** tight loops. (Without it, the local copy of 'trap' could never change.) +*/ +#define dojump(ci,i,e) { pc += GETARG_sJ(i) + e; updatetrap(ci); } + + +/* for test instructions, execute the jump instruction that follows it */ +#define donextjump(ci) { Instruction ni = *pc; dojump(ci, ni, 1); } + +/* +** do a conditional jump: skip next instruction if 'cond' is not what +** was expected (parameter 'k'), else do next instruction, which must +** be a jump. +*/ +#define docondjump() if (cond != GETARG_k(i)) pc++; else donextjump(ci); + + +/* +** Correct global 'pc'. +*/ +#define savepc(L) (ci->u.l.savedpc = pc) + + +/* +** Whenever code can raise errors, the global 'pc' and the global +** 'top' must be correct to report occasional errors. +*/ +#define savestate(L,ci) (savepc(L), L->top.p = ci->top.p) + + +/* +** Protect code that, in general, can raise errors, reallocate the +** stack, and change the hooks. +*/ +#define Protect(exp) (savestate(L,ci), (exp), updatetrap(ci)) + +/* special version that does not change the top */ +#define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci)) + +/* +** Protect code that can only raise errors. (That is, it cannot change +** the stack or hooks.) +*/ +#define halfProtect(exp) (savestate(L,ci), (exp)) + +/* 'c' is the limit of live values in the stack */ +#define checkGC(L,c) \ + { luaC_condGC(L, (savepc(L), L->top.p = (c)), \ + updatetrap(ci)); \ + luai_threadyield(L); } + + +/* fetch an instruction and prepare its execution */ +#define vmfetch() { \ + if (l_unlikely(trap)) { /* stack reallocation or hooks? */ \ + trap = luaG_traceexec(L, pc); /* handle hooks */ \ + updatebase(ci); /* correct stack */ \ + } \ + i = *(pc++); \ +} + +#define vmdispatch(o) switch(o) +#define vmcase(l) case l: +#define vmbreak break + + +void luaV_execute (lua_State *L, CallInfo *ci) { + LClosure *cl; + TValue *k; + StkId base; + const Instruction *pc; + int trap; +#if LUA_USE_JUMPTABLE +#include "ljumptab.h" +#endif + startfunc: + trap = L->hookmask; + returning: /* trap already set */ + cl = clLvalue(s2v(ci->func.p)); + k = cl->p->k; + pc = ci->u.l.savedpc; + if (l_unlikely(trap)) { + if (pc == cl->p->code) { /* first instruction (not resuming)? */ + if (cl->p->is_vararg) + trap = 0; /* hooks will start after VARARGPREP instruction */ + else /* check 'call' hook */ + luaD_hookcall(L, ci); + } + ci->u.l.trap = 1; /* assume trap is on, for now */ + } + base = ci->func.p + 1; + /* main loop of interpreter */ + for (;;) { + Instruction i; /* instruction being executed */ + vmfetch(); + #if 0 + /* low-level line tracing for debugging Lua */ + printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p))); + #endif + lua_assert(base == ci->func.p + 1); + lua_assert(base <= L->top.p && L->top.p <= L->stack_last.p); + /* invalidate top for instructions not expecting it */ + lua_assert(isIT(i) || (cast_void(L->top.p = base), 1)); + vmdispatch (GET_OPCODE(i)) { + vmcase(OP_MOVE) { + StkId ra = RA(i); + setobjs2s(L, ra, RB(i)); + vmbreak; + } + vmcase(OP_LOADI) { + StkId ra = RA(i); + lua_Integer b = GETARG_sBx(i); + setivalue(s2v(ra), b); + vmbreak; + } + vmcase(OP_LOADF) { + StkId ra = RA(i); + int b = GETARG_sBx(i); + setfltvalue(s2v(ra), cast_num(b)); + vmbreak; + } + vmcase(OP_LOADK) { + StkId ra = RA(i); + TValue *rb = k + GETARG_Bx(i); + setobj2s(L, ra, rb); + vmbreak; + } + vmcase(OP_LOADKX) { + StkId ra = RA(i); + TValue *rb; + rb = k + GETARG_Ax(*pc); pc++; + setobj2s(L, ra, rb); + vmbreak; + } + vmcase(OP_LOADFALSE) { + StkId ra = RA(i); + setbfvalue(s2v(ra)); + vmbreak; + } + vmcase(OP_LFALSESKIP) { + StkId ra = RA(i); + setbfvalue(s2v(ra)); + pc++; /* skip next instruction */ + vmbreak; + } + vmcase(OP_LOADTRUE) { + StkId ra = RA(i); + setbtvalue(s2v(ra)); + vmbreak; + } + vmcase(OP_LOADNIL) { + StkId ra = RA(i); + int b = GETARG_B(i); + do { + setnilvalue(s2v(ra++)); + } while (b--); + vmbreak; + } + vmcase(OP_GETUPVAL) { + StkId ra = RA(i); + int b = GETARG_B(i); + setobj2s(L, ra, cl->upvals[b]->v.p); + vmbreak; + } + vmcase(OP_SETUPVAL) { + StkId ra = RA(i); + UpVal *uv = cl->upvals[GETARG_B(i)]; + setobj(L, uv->v.p, s2v(ra)); + luaC_barrier(L, uv, s2v(ra)); + vmbreak; + } + vmcase(OP_GETTABUP) { + StkId ra = RA(i); + const TValue *slot; + TValue *upval = cl->upvals[GETARG_B(i)]->v.p; + TValue *rc = KC(i); + TString *key = tsvalue(rc); /* key must be a string */ + if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { + setobj2s(L, ra, slot); + } + else + Protect(luaV_finishget(L, upval, rc, ra, slot)); + vmbreak; + } + vmcase(OP_GETTABLE) { + StkId ra = RA(i); + const TValue *slot; + TValue *rb = vRB(i); + TValue *rc = vRC(i); + lua_Unsigned n; + if (ttisinteger(rc) /* fast track for integers? */ + ? (cast_void(n = ivalue(rc)), luaV_fastgeti(L, rb, n, slot)) + : luaV_fastget(L, rb, rc, slot, luaH_get)) { + setobj2s(L, ra, slot); + } + else + Protect(luaV_finishget(L, rb, rc, ra, slot)); + vmbreak; + } + vmcase(OP_GETI) { + StkId ra = RA(i); + const TValue *slot; + TValue *rb = vRB(i); + int c = GETARG_C(i); + if (luaV_fastgeti(L, rb, c, slot)) { + setobj2s(L, ra, slot); + } + else { + TValue key; + setivalue(&key, c); + Protect(luaV_finishget(L, rb, &key, ra, slot)); + } + vmbreak; + } + vmcase(OP_GETFIELD) { + StkId ra = RA(i); + const TValue *slot; + TValue *rb = vRB(i); + TValue *rc = KC(i); + TString *key = tsvalue(rc); /* key must be a string */ + if (luaV_fastget(L, rb, key, slot, luaH_getshortstr)) { + setobj2s(L, ra, slot); + } + else + Protect(luaV_finishget(L, rb, rc, ra, slot)); + vmbreak; + } + vmcase(OP_SETTABUP) { + const TValue *slot; + TValue *upval = cl->upvals[GETARG_A(i)]->v.p; + TValue *rb = KB(i); + TValue *rc = RKC(i); + TString *key = tsvalue(rb); /* key must be a string */ + if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { + luaV_finishfastset(L, upval, slot, rc); + } + else + Protect(luaV_finishset(L, upval, rb, rc, slot)); + vmbreak; + } + vmcase(OP_SETTABLE) { + StkId ra = RA(i); + const TValue *slot; + TValue *rb = vRB(i); /* key (table is in 'ra') */ + TValue *rc = RKC(i); /* value */ + lua_Unsigned n; + if (ttisinteger(rb) /* fast track for integers? */ + ? (cast_void(n = ivalue(rb)), luaV_fastgeti(L, s2v(ra), n, slot)) + : luaV_fastget(L, s2v(ra), rb, slot, luaH_get)) { + luaV_finishfastset(L, s2v(ra), slot, rc); + } + else + Protect(luaV_finishset(L, s2v(ra), rb, rc, slot)); + vmbreak; + } + vmcase(OP_SETI) { + StkId ra = RA(i); + const TValue *slot; + int c = GETARG_B(i); + TValue *rc = RKC(i); + if (luaV_fastgeti(L, s2v(ra), c, slot)) { + luaV_finishfastset(L, s2v(ra), slot, rc); + } + else { + TValue key; + setivalue(&key, c); + Protect(luaV_finishset(L, s2v(ra), &key, rc, slot)); + } + vmbreak; + } + vmcase(OP_SETFIELD) { + StkId ra = RA(i); + const TValue *slot; + TValue *rb = KB(i); + TValue *rc = RKC(i); + TString *key = tsvalue(rb); /* key must be a string */ + if (luaV_fastget(L, s2v(ra), key, slot, luaH_getshortstr)) { + luaV_finishfastset(L, s2v(ra), slot, rc); + } + else + Protect(luaV_finishset(L, s2v(ra), rb, rc, slot)); + vmbreak; + } + vmcase(OP_NEWTABLE) { + StkId ra = RA(i); + int b = GETARG_B(i); /* log2(hash size) + 1 */ + int c = GETARG_C(i); /* array size */ + Table *t; + if (b > 0) + b = 1 << (b - 1); /* size is 2^(b - 1) */ + lua_assert((!TESTARG_k(i)) == (GETARG_Ax(*pc) == 0)); + if (TESTARG_k(i)) /* non-zero extra argument? */ + c += GETARG_Ax(*pc) * (MAXARG_C + 1); /* add it to size */ + pc++; /* skip extra argument */ + L->top.p = ra + 1; /* correct top in case of emergency GC */ + t = luaH_new(L); /* memory allocation */ + sethvalue2s(L, ra, t); + if (b != 0 || c != 0) + luaH_resize(L, t, c, b); /* idem */ + checkGC(L, ra + 1); + vmbreak; + } + vmcase(OP_SELF) { + StkId ra = RA(i); + const TValue *slot; + TValue *rb = vRB(i); + TValue *rc = RKC(i); + TString *key = tsvalue(rc); /* key must be a string */ + setobj2s(L, ra + 1, rb); + if (luaV_fastget(L, rb, key, slot, luaH_getstr)) { + setobj2s(L, ra, slot); + } + else + Protect(luaV_finishget(L, rb, rc, ra, slot)); + vmbreak; + } + vmcase(OP_ADDI) { + op_arithI(L, l_addi, luai_numadd); + vmbreak; + } + vmcase(OP_ADDK) { + op_arithK(L, l_addi, luai_numadd); + vmbreak; + } + vmcase(OP_SUBK) { + op_arithK(L, l_subi, luai_numsub); + vmbreak; + } + vmcase(OP_MULK) { + op_arithK(L, l_muli, luai_nummul); + vmbreak; + } + vmcase(OP_MODK) { + savestate(L, ci); /* in case of division by 0 */ + op_arithK(L, luaV_mod, luaV_modf); + vmbreak; + } + vmcase(OP_POWK) { + op_arithfK(L, luai_numpow); + vmbreak; + } + vmcase(OP_DIVK) { + op_arithfK(L, luai_numdiv); + vmbreak; + } + vmcase(OP_IDIVK) { + savestate(L, ci); /* in case of division by 0 */ + op_arithK(L, luaV_idiv, luai_numidiv); + vmbreak; + } + vmcase(OP_BANDK) { + op_bitwiseK(L, l_band); + vmbreak; + } + vmcase(OP_BORK) { + op_bitwiseK(L, l_bor); + vmbreak; + } + vmcase(OP_BXORK) { + op_bitwiseK(L, l_bxor); + vmbreak; + } + vmcase(OP_SHRI) { + StkId ra = RA(i); + TValue *rb = vRB(i); + int ic = GETARG_sC(i); + lua_Integer ib; + if (tointegerns(rb, &ib)) { + pc++; setivalue(s2v(ra), luaV_shiftl(ib, -ic)); + } + vmbreak; + } + vmcase(OP_SHLI) { + StkId ra = RA(i); + TValue *rb = vRB(i); + int ic = GETARG_sC(i); + lua_Integer ib; + if (tointegerns(rb, &ib)) { + pc++; setivalue(s2v(ra), luaV_shiftl(ic, ib)); + } + vmbreak; + } + vmcase(OP_ADD) { + op_arith(L, l_addi, luai_numadd); + vmbreak; + } + vmcase(OP_SUB) { + op_arith(L, l_subi, luai_numsub); + vmbreak; + } + vmcase(OP_MUL) { + op_arith(L, l_muli, luai_nummul); + vmbreak; + } + vmcase(OP_MOD) { + savestate(L, ci); /* in case of division by 0 */ + op_arith(L, luaV_mod, luaV_modf); + vmbreak; + } + vmcase(OP_POW) { + op_arithf(L, luai_numpow); + vmbreak; + } + vmcase(OP_DIV) { /* float division (always with floats) */ + op_arithf(L, luai_numdiv); + vmbreak; + } + vmcase(OP_IDIV) { /* floor division */ + savestate(L, ci); /* in case of division by 0 */ + op_arith(L, luaV_idiv, luai_numidiv); + vmbreak; + } + vmcase(OP_BAND) { + op_bitwise(L, l_band); + vmbreak; + } + vmcase(OP_BOR) { + op_bitwise(L, l_bor); + vmbreak; + } + vmcase(OP_BXOR) { + op_bitwise(L, l_bxor); + vmbreak; + } + vmcase(OP_SHR) { + op_bitwise(L, luaV_shiftr); + vmbreak; + } + vmcase(OP_SHL) { + op_bitwise(L, luaV_shiftl); + vmbreak; + } + vmcase(OP_MMBIN) { + StkId ra = RA(i); + Instruction pi = *(pc - 2); /* original arith. expression */ + TValue *rb = vRB(i); + TMS tm = (TMS)GETARG_C(i); + StkId result = RA(pi); + lua_assert(OP_ADD <= GET_OPCODE(pi) && GET_OPCODE(pi) <= OP_SHR); + Protect(luaT_trybinTM(L, s2v(ra), rb, result, tm)); + vmbreak; + } + vmcase(OP_MMBINI) { + StkId ra = RA(i); + Instruction pi = *(pc - 2); /* original arith. expression */ + int imm = GETARG_sB(i); + TMS tm = (TMS)GETARG_C(i); + int flip = GETARG_k(i); + StkId result = RA(pi); + Protect(luaT_trybiniTM(L, s2v(ra), imm, flip, result, tm)); + vmbreak; + } + vmcase(OP_MMBINK) { + StkId ra = RA(i); + Instruction pi = *(pc - 2); /* original arith. expression */ + TValue *imm = KB(i); + TMS tm = (TMS)GETARG_C(i); + int flip = GETARG_k(i); + StkId result = RA(pi); + Protect(luaT_trybinassocTM(L, s2v(ra), imm, flip, result, tm)); + vmbreak; + } + vmcase(OP_UNM) { + StkId ra = RA(i); + TValue *rb = vRB(i); + lua_Number nb; + if (ttisinteger(rb)) { + lua_Integer ib = ivalue(rb); + setivalue(s2v(ra), intop(-, 0, ib)); + } + else if (tonumberns(rb, nb)) { + setfltvalue(s2v(ra), luai_numunm(L, nb)); + } + else + Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM)); + vmbreak; + } + vmcase(OP_BNOT) { + StkId ra = RA(i); + TValue *rb = vRB(i); + lua_Integer ib; + if (tointegerns(rb, &ib)) { + setivalue(s2v(ra), intop(^, ~l_castS2U(0), ib)); + } + else + Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT)); + vmbreak; + } + vmcase(OP_NOT) { + StkId ra = RA(i); + TValue *rb = vRB(i); + if (l_isfalse(rb)) + setbtvalue(s2v(ra)); + else + setbfvalue(s2v(ra)); + vmbreak; + } + vmcase(OP_LEN) { + StkId ra = RA(i); + Protect(luaV_objlen(L, ra, vRB(i))); + vmbreak; + } + vmcase(OP_CONCAT) { + StkId ra = RA(i); + int n = GETARG_B(i); /* number of elements to concatenate */ + L->top.p = ra + n; /* mark the end of concat operands */ + ProtectNT(luaV_concat(L, n)); + checkGC(L, L->top.p); /* 'luaV_concat' ensures correct top */ + vmbreak; + } + vmcase(OP_CLOSE) { + StkId ra = RA(i); + Protect(luaF_close(L, ra, LUA_OK, 1)); + vmbreak; + } + vmcase(OP_TBC) { + StkId ra = RA(i); + /* create new to-be-closed upvalue */ + halfProtect(luaF_newtbcupval(L, ra)); + vmbreak; + } + vmcase(OP_JMP) { + dojump(ci, i, 0); + vmbreak; + } + vmcase(OP_EQ) { + StkId ra = RA(i); + int cond; + TValue *rb = vRB(i); + Protect(cond = luaV_equalobj(L, s2v(ra), rb)); + docondjump(); + vmbreak; + } + vmcase(OP_LT) { + op_order(L, l_lti, LTnum, lessthanothers); + vmbreak; + } + vmcase(OP_LE) { + op_order(L, l_lei, LEnum, lessequalothers); + vmbreak; + } + vmcase(OP_EQK) { + StkId ra = RA(i); + TValue *rb = KB(i); + /* basic types do not use '__eq'; we can use raw equality */ + int cond = luaV_rawequalobj(s2v(ra), rb); + docondjump(); + vmbreak; + } + vmcase(OP_EQI) { + StkId ra = RA(i); + int cond; + int im = GETARG_sB(i); + if (ttisinteger(s2v(ra))) + cond = (ivalue(s2v(ra)) == im); + else if (ttisfloat(s2v(ra))) + cond = luai_numeq(fltvalue(s2v(ra)), cast_num(im)); + else + cond = 0; /* other types cannot be equal to a number */ + docondjump(); + vmbreak; + } + vmcase(OP_LTI) { + op_orderI(L, l_lti, luai_numlt, 0, TM_LT); + vmbreak; + } + vmcase(OP_LEI) { + op_orderI(L, l_lei, luai_numle, 0, TM_LE); + vmbreak; + } + vmcase(OP_GTI) { + op_orderI(L, l_gti, luai_numgt, 1, TM_LT); + vmbreak; + } + vmcase(OP_GEI) { + op_orderI(L, l_gei, luai_numge, 1, TM_LE); + vmbreak; + } + vmcase(OP_TEST) { + StkId ra = RA(i); + int cond = !l_isfalse(s2v(ra)); + docondjump(); + vmbreak; + } + vmcase(OP_TESTSET) { + StkId ra = RA(i); + TValue *rb = vRB(i); + if (l_isfalse(rb) == GETARG_k(i)) + pc++; + else { + setobj2s(L, ra, rb); + donextjump(ci); + } + vmbreak; + } + vmcase(OP_CALL) { + StkId ra = RA(i); + CallInfo *newci; + int b = GETARG_B(i); + int nresults = GETARG_C(i) - 1; + if (b != 0) /* fixed number of arguments? */ + L->top.p = ra + b; /* top signals number of arguments */ + /* else previous instruction set top */ + savepc(L); /* in case of errors */ + if ((newci = luaD_precall(L, ra, nresults)) == NULL) + updatetrap(ci); /* C call; nothing else to be done */ + else { /* Lua call: run function in this same C frame */ + ci = newci; + goto startfunc; + } + vmbreak; + } + vmcase(OP_TAILCALL) { + StkId ra = RA(i); + int b = GETARG_B(i); /* number of arguments + 1 (function) */ + int n; /* number of results when calling a C function */ + int nparams1 = GETARG_C(i); + /* delta is virtual 'func' - real 'func' (vararg functions) */ + int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0; + if (b != 0) + L->top.p = ra + b; + else /* previous instruction set top */ + b = cast_int(L->top.p - ra); + savepc(ci); /* several calls here can raise errors */ + if (TESTARG_k(i)) { + luaF_closeupval(L, base); /* close upvalues from current call */ + lua_assert(L->tbclist.p < base); /* no pending tbc variables */ + lua_assert(base == ci->func.p + 1); + } + if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */ + goto startfunc; /* execute the callee */ + else { /* C function? */ + ci->func.p -= delta; /* restore 'func' (if vararg) */ + luaD_poscall(L, ci, n); /* finish caller */ + updatetrap(ci); /* 'luaD_poscall' can change hooks */ + goto ret; /* caller returns after the tail call */ + } + } + vmcase(OP_RETURN) { + StkId ra = RA(i); + int n = GETARG_B(i) - 1; /* number of results */ + int nparams1 = GETARG_C(i); + if (n < 0) /* not fixed? */ + n = cast_int(L->top.p - ra); /* get what is available */ + savepc(ci); + if (TESTARG_k(i)) { /* may there be open upvalues? */ + ci->u2.nres = n; /* save number of returns */ + if (L->top.p < ci->top.p) + L->top.p = ci->top.p; + luaF_close(L, base, CLOSEKTOP, 1); + updatetrap(ci); + updatestack(ci); + } + if (nparams1) /* vararg function? */ + ci->func.p -= ci->u.l.nextraargs + nparams1; + L->top.p = ra + n; /* set call for 'luaD_poscall' */ + luaD_poscall(L, ci, n); + updatetrap(ci); /* 'luaD_poscall' can change hooks */ + goto ret; + } + vmcase(OP_RETURN0) { + if (l_unlikely(L->hookmask)) { + StkId ra = RA(i); + L->top.p = ra; + savepc(ci); + luaD_poscall(L, ci, 0); /* no hurry... */ + trap = 1; + } + else { /* do the 'poscall' here */ + int nres; + L->ci = ci->previous; /* back to caller */ + L->top.p = base - 1; + for (nres = ci->nresults; l_unlikely(nres > 0); nres--) + setnilvalue(s2v(L->top.p++)); /* all results are nil */ + } + goto ret; + } + vmcase(OP_RETURN1) { + if (l_unlikely(L->hookmask)) { + StkId ra = RA(i); + L->top.p = ra + 1; + savepc(ci); + luaD_poscall(L, ci, 1); /* no hurry... */ + trap = 1; + } + else { /* do the 'poscall' here */ + int nres = ci->nresults; + L->ci = ci->previous; /* back to caller */ + if (nres == 0) + L->top.p = base - 1; /* asked for no results */ + else { + StkId ra = RA(i); + setobjs2s(L, base - 1, ra); /* at least this result */ + L->top.p = base; + for (; l_unlikely(nres > 1); nres--) + setnilvalue(s2v(L->top.p++)); /* complete missing results */ + } + } + ret: /* return from a Lua function */ + if (ci->callstatus & CIST_FRESH) + return; /* end this frame */ + else { + ci = ci->previous; + goto returning; /* continue running caller in this frame */ + } + } + vmcase(OP_FORLOOP) { + StkId ra = RA(i); + if (ttisinteger(s2v(ra + 2))) { /* integer loop? */ + lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1))); + if (count > 0) { /* still more iterations? */ + lua_Integer step = ivalue(s2v(ra + 2)); + lua_Integer idx = ivalue(s2v(ra)); /* internal index */ + chgivalue(s2v(ra + 1), count - 1); /* update counter */ + idx = intop(+, idx, step); /* add step to index */ + chgivalue(s2v(ra), idx); /* update internal index */ + setivalue(s2v(ra + 3), idx); /* and control variable */ + pc -= GETARG_Bx(i); /* jump back */ + } + } + else if (floatforloop(ra)) /* float loop */ + pc -= GETARG_Bx(i); /* jump back */ + updatetrap(ci); /* allows a signal to break the loop */ + vmbreak; + } + vmcase(OP_FORPREP) { + StkId ra = RA(i); + savestate(L, ci); /* in case of errors */ + if (forprep(L, ra)) + pc += GETARG_Bx(i) + 1; /* skip the loop */ + vmbreak; + } + vmcase(OP_TFORPREP) { + StkId ra = RA(i); + /* create to-be-closed upvalue (if needed) */ + halfProtect(luaF_newtbcupval(L, ra + 3)); + pc += GETARG_Bx(i); + i = *(pc++); /* go to next instruction */ + lua_assert(GET_OPCODE(i) == OP_TFORCALL && ra == RA(i)); + goto l_tforcall; + } + vmcase(OP_TFORCALL) { + l_tforcall: { + StkId ra = RA(i); + /* 'ra' has the iterator function, 'ra + 1' has the state, + 'ra + 2' has the control variable, and 'ra + 3' has the + to-be-closed variable. The call will use the stack after + these values (starting at 'ra + 4') + */ + /* push function, state, and control variable */ + memcpy(ra + 4, ra, 3 * sizeof(*ra)); + L->top.p = ra + 4 + 3; + ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */ + updatestack(ci); /* stack may have changed */ + i = *(pc++); /* go to next instruction */ + lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i)); + goto l_tforloop; + }} + vmcase(OP_TFORLOOP) { + l_tforloop: { + StkId ra = RA(i); + if (!ttisnil(s2v(ra + 4))) { /* continue loop? */ + setobjs2s(L, ra + 2, ra + 4); /* save control variable */ + pc -= GETARG_Bx(i); /* jump back */ + } + vmbreak; + }} + vmcase(OP_SETLIST) { + StkId ra = RA(i); + int n = GETARG_B(i); + unsigned int last = GETARG_C(i); + Table *h = hvalue(s2v(ra)); + if (n == 0) + n = cast_int(L->top.p - ra) - 1; /* get up to the top */ + else + L->top.p = ci->top.p; /* correct top in case of emergency GC */ + last += n; + if (TESTARG_k(i)) { + last += GETARG_Ax(*pc) * (MAXARG_C + 1); + pc++; + } + if (last > luaH_realasize(h)) /* needs more space? */ + luaH_resizearray(L, h, last); /* preallocate it at once */ + for (; n > 0; n--) { + TValue *val = s2v(ra + n); + setobj2t(L, &h->array[last - 1], val); + last--; + luaC_barrierback(L, obj2gco(h), val); + } + vmbreak; + } + vmcase(OP_CLOSURE) { + StkId ra = RA(i); + Proto *p = cl->p->p[GETARG_Bx(i)]; + halfProtect(pushclosure(L, p, cl->upvals, base, ra)); + checkGC(L, ra + 1); + vmbreak; + } + vmcase(OP_VARARG) { + StkId ra = RA(i); + int n = GETARG_C(i) - 1; /* required results */ + Protect(luaT_getvarargs(L, ci, ra, n)); + vmbreak; + } + vmcase(OP_VARARGPREP) { + ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p)); + if (l_unlikely(trap)) { /* previous "Protect" updated trap */ + luaD_hookcall(L, ci); + L->oldpc = 1; /* next opcode will be seen as a "new" line */ + } + updatebase(ci); /* function has new base after adjustment */ + vmbreak; + } + vmcase(OP_EXTRAARG) { + lua_assert(0); + vmbreak; + } + } + } +} + +/* }================================================================== */ diff --git a/src/libs/3rdparty/lua/src/lvm.h b/src/libs/3rdparty/lua/src/lvm.h new file mode 100644 index 0000000000..dba1ad2770 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lvm.h @@ -0,0 +1,141 @@ +/* +** $Id: lvm.h $ +** Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#ifndef lvm_h +#define lvm_h + + +#include "ldo.h" +#include "lobject.h" +#include "ltm.h" + + +#if !defined(LUA_NOCVTN2S) +#define cvt2str(o) ttisnumber(o) +#else +#define cvt2str(o) 0 /* no conversion from numbers to strings */ +#endif + + +#if !defined(LUA_NOCVTS2N) +#define cvt2num(o) ttisstring(o) +#else +#define cvt2num(o) 0 /* no conversion from strings to numbers */ +#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 F2Ieq +#endif + + +/* +** Rounding modes for float->integer coercion + */ +typedef enum { + F2Ieq, /* no rounding; accepts only integral values */ + F2Ifloor, /* takes the floor of the number */ + F2Iceil /* takes the ceil of the number */ +} F2Imod; + + +/* convert an object to a float (including string coercion) */ +#define tonumber(o,n) \ + (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n)) + + +/* convert an object to a float (without string coercion) */ +#define tonumberns(o,n) \ + (ttisfloat(o) ? ((n) = fltvalue(o), 1) : \ + (ttisinteger(o) ? ((n) = cast_num(ivalue(o)), 1) : 0)) + + +/* convert an object to an integer (including string coercion) */ +#define tointeger(o,i) \ + (l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \ + : luaV_tointeger(o,i,LUA_FLOORN2I)) + + +/* convert an object to an integer (without string coercion) */ +#define tointegerns(o,i) \ + (l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \ + : luaV_tointegerns(o,i,LUA_FLOORN2I)) + + +#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2)) + +#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2) + + +/* +** fast track for 'gettable': if 't' is a table and 't[k]' is present, +** return 1 with 'slot' pointing to 't[k]' (position of final result). +** Otherwise, return 0 (meaning it will have to check metamethod) +** with 'slot' pointing to an empty '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 */ \ + !isempty(slot))) /* result not empty? */ + + +/* +** Special case of 'luaV_fastget' for integers, inlining the fast case +** of 'luaH_getint'. +*/ +#define luaV_fastgeti(L,t,k,slot) \ + (!ttistable(t) \ + ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ + : (slot = (l_castS2U(k) - 1u < hvalue(t)->alimit) \ + ? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \ + !isempty(slot))) /* result not empty? */ + + +/* +** Finish a fast set operation (when fast get succeeds). In that case, +** 'slot' points to the place to put the value. +*/ +#define luaV_finishfastset(L,t,slot,v) \ + { setobj2t(L, cast(TValue *,slot), v); \ + luaC_barrierback(L, gcvalue(t), v); } + + +/* +** Shift right is the same as shift left with a negative 'y' +*/ +#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y)) + + + +LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); +LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); +LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r); +LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); +LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, F2Imod mode); +LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p, + F2Imod mode); +LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode); +LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *slot); +LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, + TValue *val, const TValue *slot); +LUAI_FUNC void luaV_finishOp (lua_State *L); +LUAI_FUNC void luaV_execute (lua_State *L, CallInfo *ci); +LUAI_FUNC void luaV_concat (lua_State *L, int total); +LUAI_FUNC lua_Integer luaV_idiv (lua_State *L, lua_Integer x, lua_Integer y); +LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y); +LUAI_FUNC lua_Number luaV_modf (lua_State *L, lua_Number x, lua_Number y); +LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y); +LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb); + +#endif diff --git a/src/libs/3rdparty/lua/src/lzio.c b/src/libs/3rdparty/lua/src/lzio.c new file mode 100644 index 0000000000..cd0a02d5f9 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lzio.c @@ -0,0 +1,68 @@ +/* +** $Id: lzio.c $ +** Buffered streams +** See Copyright Notice in lua.h +*/ + +#define lzio_c +#define LUA_CORE + +#include "lprefix.h" + + +#include <string.h> + +#include "lua.h" + +#include "llimits.h" +#include "lmem.h" +#include "lstate.h" +#include "lzio.h" + + +int luaZ_fill (ZIO *z) { + size_t size; + lua_State *L = z->L; + const char *buff; + lua_unlock(L); + buff = z->reader(L, z->data, &size); + lua_lock(L); + if (buff == NULL || size == 0) + return EOZ; + z->n = size - 1; /* discount char being returned */ + z->p = buff; + return cast_uchar(*(z->p++)); +} + + +void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { + z->L = L; + z->reader = reader; + z->data = data; + z->n = 0; + z->p = NULL; +} + + +/* --------------------------------------------------------------- read --- */ +size_t luaZ_read (ZIO *z, void *b, size_t n) { + while (n) { + size_t m; + if (z->n == 0) { /* no bytes in buffer? */ + if (luaZ_fill(z) == EOZ) /* try to read more */ + return n; /* no more input; return number of missing bytes */ + else { + z->n++; /* luaZ_fill consumed first byte; put it back */ + z->p--; + } + } + m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ + memcpy(b, z->p, m); + z->n -= m; + z->p += m; + b = (char *)b + m; + n -= m; + } + return 0; +} + diff --git a/src/libs/3rdparty/lua/src/lzio.h b/src/libs/3rdparty/lua/src/lzio.h new file mode 100644 index 0000000000..38f397fd28 --- /dev/null +++ b/src/libs/3rdparty/lua/src/lzio.h @@ -0,0 +1,66 @@ +/* +** $Id: lzio.h $ +** Buffered streams +** See Copyright Notice in lua.h +*/ + + +#ifndef lzio_h +#define lzio_h + +#include "lua.h" + +#include "lmem.h" + + +#define EOZ (-1) /* end of stream */ + +typedef struct Zio ZIO; + +#define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) + + +typedef struct Mbuffer { + char *buffer; + size_t n; + size_t buffsize; +} Mbuffer; + +#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) + +#define luaZ_buffer(buff) ((buff)->buffer) +#define luaZ_sizebuffer(buff) ((buff)->buffsize) +#define luaZ_bufflen(buff) ((buff)->n) + +#define luaZ_buffremove(buff,i) ((buff)->n -= (i)) +#define luaZ_resetbuffer(buff) ((buff)->n = 0) + + +#define luaZ_resizebuffer(L, buff, size) \ + ((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \ + (buff)->buffsize, size), \ + (buff)->buffsize = size) + +#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) + + +LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, + void *data); +LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ + + + +/* --------- Private Part ------------------ */ + +struct Zio { + size_t n; /* bytes still unread */ + const char *p; /* current position in buffer */ + lua_Reader reader; /* reader function */ + void *data; /* additional data */ + lua_State *L; /* Lua state (for reader) */ +}; + + +LUAI_FUNC int luaZ_fill (ZIO *z); + +#endif diff --git a/src/libs/3rdparty/sol2/CMakeLists.txt b/src/libs/3rdparty/sol2/CMakeLists.txt new file mode 100644 index 0000000000..1afdb1bdbb --- /dev/null +++ b/src/libs/3rdparty/sol2/CMakeLists.txt @@ -0,0 +1,12 @@ +add_library(sol2 INTERFACE) + +target_include_directories(sol2 INTERFACE + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> + $<INSTALL_INTERFACE:include> +) + +install(TARGETS sol2 EXPORT QtCreator) + +qtc_add_public_header(include/sol/sol.hpp) +qtc_add_public_header(include/sol/config.hpp) +qtc_add_public_header(include/sol/forward.hpp) diff --git a/src/libs/3rdparty/sol2/LICENSE.txt b/src/libs/3rdparty/sol2/LICENSE.txt new file mode 100644 index 0000000000..5813440548 --- /dev/null +++ b/src/libs/3rdparty/sol2/LICENSE.txt @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013-2022 Rapptz, ThePhD, and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/libs/3rdparty/sol2/include/sol/config.hpp b/src/libs/3rdparty/sol2/include/sol/config.hpp new file mode 100644 index 0000000000..36ef3fe47e --- /dev/null +++ b/src/libs/3rdparty/sol2/include/sol/config.hpp @@ -0,0 +1,57 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2020 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// This file was generated with a script. +// Generated 2024-01-13 14:25:56.570832 UTC +// This header was generated with sol v3.3.1 (revision 9c882a28) +// https://github.com/ThePhD/sol2 + +#ifndef SOL_SINGLE_SOL_CONFIG_HPP +#define SOL_SINGLE_SOL_CONFIG_HPP + +// beginning of sol/config.hpp + +/* Base, empty configuration file! + + To override, place a file in your include paths of the form: + +. (your include path here) +| sol (directory, or equivalent) + | config.hpp (your config.hpp file) + + So that when sol2 includes the file + +#include <sol/config.hpp> + + it gives you the configuration values you desire. Configuration values can be +seen in the safety.rst of the doc/src, or at +https://sol2.readthedocs.io/en/latest/safety.html ! You can also pass them through +the build system, or the command line options of your compiler. + +*/ + +#define SOL_SAFE_FUNCTIONS 1 +#define SOL_SAFE_USERTYPE 1 +#define SOL_NO_NIL 1 + +// end of sol/config.hpp + +#endif // SOL_SINGLE_SOL_CONFIG_HPP diff --git a/src/libs/3rdparty/sol2/include/sol/forward.hpp b/src/libs/3rdparty/sol2/include/sol/forward.hpp new file mode 100644 index 0000000000..83fba4d254 --- /dev/null +++ b/src/libs/3rdparty/sol2/include/sol/forward.hpp @@ -0,0 +1,1340 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2020 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// This file was generated with a script. +// Generated 2024-01-13 14:25:56.569197 UTC +// This header was generated with sol v3.3.1 (revision 9c882a28) +// https://github.com/ThePhD/sol2 + +#ifndef SOL_SINGLE_INCLUDE_SOL_FORWARD_HPP +#define SOL_SINGLE_INCLUDE_SOL_FORWARD_HPP + +// beginning of sol/forward.hpp + +#ifndef SOL_FORWARD_HPP +#define SOL_FORWARD_HPP + +// beginning of sol/version.hpp + +#include "config.hpp" + +#define SOL_VERSION_MAJOR 3 +#define SOL_VERSION_MINOR 2 +#define SOL_VERSION_PATCH 3 +#define SOL_VERSION_STRING "3.2.3" +#define SOL_VERSION ((SOL_VERSION_MAJOR * 100000) + (SOL_VERSION_MINOR * 100) + (SOL_VERSION_PATCH)) + +#define SOL_TOKEN_TO_STRING_POST_EXPANSION_I_(_TOKEN) #_TOKEN +#define SOL_TOKEN_TO_STRING_I_(_TOKEN) SOL_TOKEN_TO_STRING_POST_EXPANSION_I_(_TOKEN) + +#define SOL_CONCAT_TOKENS_POST_EXPANSION_I_(_LEFT, _RIGHT) _LEFT##_RIGHT +#define SOL_CONCAT_TOKENS_I_(_LEFT, _RIGHT) SOL_CONCAT_TOKENS_POST_EXPANSION_I_(_LEFT, _RIGHT) + +#define SOL_RAW_IS_ON(OP_SYMBOL) ((3 OP_SYMBOL 3) != 0) +#define SOL_RAW_IS_OFF(OP_SYMBOL) ((3 OP_SYMBOL 3) == 0) +#define SOL_RAW_IS_DEFAULT_ON(OP_SYMBOL) ((3 OP_SYMBOL 3) > 3) +#define SOL_RAW_IS_DEFAULT_OFF(OP_SYMBOL) ((3 OP_SYMBOL 3 OP_SYMBOL 3) < 0) + +#define SOL_IS_ON(OP_SYMBOL) SOL_RAW_IS_ON(OP_SYMBOL ## _I_) +#define SOL_IS_OFF(OP_SYMBOL) SOL_RAW_IS_OFF(OP_SYMBOL ## _I_) +#define SOL_IS_DEFAULT_ON(OP_SYMBOL) SOL_RAW_IS_DEFAULT_ON(OP_SYMBOL ## _I_) +#define SOL_IS_DEFAULT_OFF(OP_SYMBOL) SOL_RAW_IS_DEFAULT_OFF(OP_SYMBOL ## _I_) + +#define SOL_ON | +#define SOL_OFF ^ +#define SOL_DEFAULT_ON + +#define SOL_DEFAULT_OFF - + +#if defined(SOL_BUILD_CXX_MODE) + #if (SOL_BUILD_CXX_MODE != 0) + #define SOL_BUILD_CXX_MODE_I_ SOL_ON + #else + #define SOL_BUILD_CXX_MODE_I_ SOL_OFF + #endif +#elif defined(__cplusplus) + #define SOL_BUILD_CXX_MODE_I_ SOL_DEFAULT_ON +#else + #define SOL_BUILD_CXX_MODE_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_BUILD_C_MODE) + #if (SOL_BUILD_C_MODE != 0) + #define SOL_BUILD_C_MODE_I_ SOL_ON + #else + #define SOL_BUILD_C_MODE_I_ SOL_OFF + #endif +#elif defined(__STDC__) + #define SOL_BUILD_C_MODE_I_ SOL_DEFAULT_ON +#else + #define SOL_BUILD_C_MODE_I_ SOL_DEFAULT_OFF +#endif + +#if SOL_IS_ON(SOL_BUILD_C_MODE) + #include <stddef.h> + #include <stdint.h> + #include <limits.h> +#else + #include <cstddef> + #include <cstdint> + #include <climits> +#endif + +#if defined(SOL_HAS_BUILTIN) + #define SOL_HAS_BUILTIN_I_(...) SOL_HAS_BUILTIN(__VA_ARGS__) +#elif defined(__has_builtin) + #define SOL_HAS_BUILTIN_I_(...) __has_builtin(__VA_ARGS__) +#else + #define SOL_HAS_BUILTIN_I_(...) 0 +#endif + +#if defined(SOL_COMPILER_VCXX) + #if defined(SOL_COMPILER_VCXX != 0) + #define SOL_COMPILER_VCXX_I_ SOL_ON + #else + #define SOL_COMPILER_VCXX_I_ SOL_OFF + #endif +#elif defined(_MSC_VER) + #define SOL_COMPILER_VCXX_I_ SOL_DEFAULT_ON +#else + #define SOL_COMPILER_VCXX_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_COMPILER_GCC) + #if defined(SOL_COMPILER_GCC != 0) + #define SOL_COMPILER_GCC_I_ SOL_ON + #else + #define SOL_COMPILER_GCC_I_ SOL_OFF + #endif +#elif defined(__GNUC__) + #define SOL_COMPILER_GCC_I_ SOL_DEFAULT_ON +#else + #define SOL_COMPILER_GCC_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_COMPILER_CLANG) + #if defined(SOL_COMPILER_CLANG != 0) + #define SOL_COMPILER_CLANG_I_ SOL_ON + #else + #define SOL_COMPILER_CLANG_I_ SOL_OFF + #endif +#elif defined(__clang__) + #define SOL_COMPILER_CLANG_I_ SOL_DEFAULT_ON +#else + #define SOL_COMPILER_CLANG_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_COMPILER_EDG) + #if defined(SOL_COMPILER_EDG != 0) + #define SOL_COMPILER_EDG_I_ SOL_ON + #else + #define SOL_COMPILER_EDG_I_ SOL_OFF + #endif +#else + #define SOL_COMPILER_EDG_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_COMPILER_MINGW) + #if (SOL_COMPILER_MINGW != 0) + #define SOL_COMPILER_MINGW_I_ SOL_ON + #else + #define SOL_COMPILER_MINGW_I_ SOL_OFF + #endif +#elif defined(__MINGW32__) + #define SOL_COMPILER_MINGW_I_ SOL_DEFAULT_ON +#else + #define SOL_COMPILER_MINGW_I_ SOL_DEFAULT_OFF +#endif + +#if SIZE_MAX <= 0xFFFFULL + #define SOL_PLATFORM_X16_I_ SOL_ON + #define SOL_PLATFORM_X86_I_ SOL_OFF + #define SOL_PLATFORM_X64_I_ SOL_OFF +#elif SIZE_MAX <= 0xFFFFFFFFULL + #define SOL_PLATFORM_X16_I_ SOL_OFF + #define SOL_PLATFORM_X86_I_ SOL_ON + #define SOL_PLATFORM_X64_I_ SOL_OFF +#else + #define SOL_PLATFORM_X16_I_ SOL_OFF + #define SOL_PLATFORM_X86_I_ SOL_OFF + #define SOL_PLATFORM_X64_I_ SOL_ON +#endif + +#define SOL_PLATFORM_ARM32_I_ SOL_OFF +#define SOL_PLATFORM_ARM64_I_ SOL_OFF + +#if defined(SOL_PLATFORM_WINDOWS) + #if (SOL_PLATFORM_WINDOWS != 0) + #define SOL_PLATFORM_WINDOWS_I_ SOL_ON + #else + #define SOL_PLATFORM_WINDOWS_I_ SOL_OFF + #endif +#elif defined(_WIN32) + #define SOL_PLATFORM_WINDOWS_I_ SOL_DEFAULT_ON +#else + #define SOL_PLATFORM_WINDOWS_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_PLATFORM_CYGWIN) + #if (SOL_PLATFORM_CYGWIN != 0) + #define SOL_PLATFORM_CYGWIN_I_ SOL_ON + #else + #define SOL_PLATFORM_CYGWIN_I_ SOL_ON + #endif +#elif defined(__CYGWIN__) + #define SOL_PLATFORM_CYGWIN_I_ SOL_DEFAULT_ON +#else + #define SOL_PLATFORM_CYGWIN_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_PLATFORM_APPLE) + #if (SOL_PLATFORM_APPLE != 0) + #define SOL_PLATFORM_APPLE_I_ SOL_ON + #else + #define SOL_PLATFORM_APPLE_I_ SOL_OFF + #endif +#elif defined(__APPLE__) + #define SOL_PLATFORM_APPLE_I_ SOL_DEFAULT_ON +#else + #define SOL_PLATFORM_APPLE_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_PLATFORM_UNIX) + #if (SOL_PLATFORM_UNIX != 0) + #define SOL_PLATFORM_UNIXLIKE_I_ SOL_ON + #else + #define SOL_PLATFORM_UNIXLIKE_I_ SOL_OFF + #endif +#elif defined(__unix__) + #define SOL_PLATFORM_UNIXLIKE_I_ SOL_DEFAUKT_ON +#else + #define SOL_PLATFORM_UNIXLIKE_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_PLATFORM_LINUX) + #if (SOL_PLATFORM_LINUX != 0) + #define SOL_PLATFORM_LINUXLIKE_I_ SOL_ON + #else + #define SOL_PLATFORM_LINUXLIKE_I_ SOL_OFF + #endif +#elif defined(__LINUX__) + #define SOL_PLATFORM_LINUXLIKE_I_ SOL_DEFAUKT_ON +#else + #define SOL_PLATFORM_LINUXLIKE_I_ SOL_DEFAULT_OFF +#endif + +#define SOL_PLATFORM_APPLE_IPHONE_I_ SOL_OFF +#define SOL_PLATFORM_BSDLIKE_I_ SOL_OFF + +#if defined(SOL_IN_DEBUG_DETECTED) + #if SOL_IN_DEBUG_DETECTED != 0 + #define SOL_DEBUG_BUILD_I_ SOL_ON + #else + #define SOL_DEBUG_BUILD_I_ SOL_OFF + #endif +#elif !defined(NDEBUG) + #if SOL_IS_ON(SOL_COMPILER_VCXX) && defined(_DEBUG) + #define SOL_DEBUG_BUILD_I_ SOL_ON + #elif (SOL_IS_ON(SOL_COMPILER_CLANG) || SOL_IS_ON(SOL_COMPILER_GCC)) && !defined(__OPTIMIZE__) + #define SOL_DEBUG_BUILD_I_ SOL_ON + #else + #define SOL_DEBUG_BUILD_I_ SOL_OFF + #endif +#else + #define SOL_DEBUG_BUILD_I_ SOL_DEFAULT_OFF +#endif // We are in a debug mode of some sort + +#if defined(SOL_NO_EXCEPTIONS) + #if (SOL_NO_EXCEPTIONS != 0) + #define SOL_EXCEPTIONS_I_ SOL_OFF + #else + #define SOL_EXCEPTIONS_I_ SOL_ON + #endif +#elif SOL_IS_ON(SOL_COMPILER_VCXX) + #if !defined(_CPPUNWIND) + #define SOL_EXCEPTIONS_I_ SOL_OFF + #else + #define SOL_EXCEPTIONS_I_ SOL_ON + #endif +#elif SOL_IS_ON(SOL_COMPILER_CLANG) || SOL_IS_ON(SOL_COMPILER_GCC) + #if !defined(__EXCEPTIONS) + #define SOL_EXCEPTIONS_I_ SOL_OFF + #else + #define SOL_EXCEPTIONS_I_ SOL_ON + #endif +#else + #define SOL_EXCEPTIONS_I_ SOL_DEFAULT_ON +#endif + +#if defined(SOL_NO_RTTI) + #if (SOL_NO_RTTI != 0) + #define SOL_RTTI_I_ SOL_OFF + #else + #define SOL_RTTI_I_ SOL_ON + #endif +#elif SOL_IS_ON(SOL_COMPILER_VCXX) + #if !defined(_CPPRTTI) + #define SOL_RTTI_I_ SOL_OFF + #else + #define SOL_RTTI_I_ SOL_ON + #endif +#elif SOL_IS_ON(SOL_COMPILER_CLANG) || SOL_IS_ON(SOL_COMPILER_GCC) + #if !defined(__GXX_RTTI) + #define SOL_RTTI_I_ SOL_OFF + #else + #define SOL_RTTI_I_ SOL_ON + #endif +#else + #define SOL_RTTI_I_ SOL_DEFAULT_ON +#endif + +#if defined(SOL_NO_THREAD_LOCAL) + #if SOL_NO_THREAD_LOCAL != 0 + #define SOL_USE_THREAD_LOCAL_I_ SOL_OFF + #else + #define SOL_USE_THREAD_LOCAL_I_ SOL_ON + #endif +#else + #define SOL_USE_THREAD_LOCAL_I_ SOL_DEFAULT_ON +#endif // thread_local keyword is bjorked on some platforms + +#if defined(SOL_ALL_SAFETIES_ON) + #if SOL_ALL_SAFETIES_ON != 0 + #define SOL_ALL_SAFETIES_ON_I_ SOL_ON + #else + #define SOL_ALL_SAFETIES_ON_I_ SOL_OFF + #endif +#else + #define SOL_ALL_SAFETIES_ON_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_SAFE_GETTER) + #if SOL_SAFE_GETTER != 0 + #define SOL_SAFE_GETTER_I_ SOL_ON + #else + #define SOL_SAFE_GETTER_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_SAFE_GETTER_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_SAFE_GETTER_I_ SOL_DEFAULT_ON + #else + #define SOL_SAFE_GETTER_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_SAFE_USERTYPE) + #if SOL_SAFE_USERTYPE != 0 + #define SOL_SAFE_USERTYPE_I_ SOL_ON + #else + #define SOL_SAFE_USERTYPE_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_SAFE_USERTYPE_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_SAFE_USERTYPE_I_ SOL_DEFAULT_ON + #else + #define SOL_SAFE_USERTYPE_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_SAFE_REFERENCES) + #if SOL_SAFE_REFERENCES != 0 + #define SOL_SAFE_REFERENCES_I_ SOL_ON + #else + #define SOL_SAFE_REFERENCES_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_SAFE_REFERENCES_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_SAFE_REFERENCES_I_ SOL_DEFAULT_ON + #else + #define SOL_SAFE_REFERENCES_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_SAFE_FUNCTIONS) + #if SOL_SAFE_FUNCTIONS != 0 + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON + #else + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_OFF + #endif +#elif defined (SOL_SAFE_FUNCTION_OBJECTS) + #if SOL_SAFE_FUNCTION_OBJECTS != 0 + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON + #else + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_DEFAULT_ON + #else + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_SAFE_FUNCTION_CALLS) + #if SOL_SAFE_FUNCTION_CALLS != 0 + #define SOL_SAFE_FUNCTION_CALLS_I_ SOL_ON + #else + #define SOL_SAFE_FUNCTION_CALLS_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_SAFE_FUNCTION_CALLS_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_SAFE_FUNCTION_CALLS_I_ SOL_DEFAULT_ON + #else + #define SOL_SAFE_FUNCTION_CALLS_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_SAFE_PROXIES) + #if SOL_SAFE_PROXIES != 0 + #define SOL_SAFE_PROXIES_I_ SOL_ON + #else + #define SOL_SAFE_PROXIES_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_SAFE_PROXIES_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_SAFE_PROXIES_I_ SOL_DEFAULT_ON + #else + #define SOL_SAFE_PROXIES_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_SAFE_NUMERICS) + #if SOL_SAFE_NUMERICS != 0 + #define SOL_SAFE_NUMERICS_I_ SOL_ON + #else + #define SOL_SAFE_NUMERICS_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_SAFE_NUMERICS_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_SAFE_NUMERICS_I_ SOL_DEFAULT_ON + #else + #define SOL_SAFE_NUMERICS_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_ALL_INTEGER_VALUES_FIT) + #if (SOL_ALL_INTEGER_VALUES_FIT != 0) + #define SOL_ALL_INTEGER_VALUES_FIT_I_ SOL_ON + #else + #define SOL_ALL_INTEGER_VALUES_FIT_I_ SOL_OFF + #endif +#elif !SOL_IS_DEFAULT_OFF(SOL_SAFE_NUMERICS) && SOL_IS_OFF(SOL_SAFE_NUMERICS) + // if numerics is intentionally turned off, flip this on + #define SOL_ALL_INTEGER_VALUES_FIT_I_ SOL_DEFAULT_ON +#else + // default to off + #define SOL_ALL_INTEGER_VALUES_FIT_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_SAFE_STACK_CHECK) + #if SOL_SAFE_STACK_CHECK != 0 + #define SOL_SAFE_STACK_CHECK_I_ SOL_ON + #else + #define SOL_SAFE_STACK_CHECK_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_SAFE_STACK_CHECK_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_SAFE_STACK_CHECK_I_ SOL_DEFAULT_ON + #else + #define SOL_SAFE_STACK_CHECK_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_NO_CHECK_NUMBER_PRECISION) + #if SOL_NO_CHECK_NUMBER_PRECISION != 0 + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_OFF + #else + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON + #endif +#elif defined(SOL_NO_CHECKING_NUMBER_PRECISION) + #if SOL_NO_CHECKING_NUMBER_PRECISION != 0 + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_OFF + #else + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON + #elif SOL_IS_ON(SOL_SAFE_NUMERICS) + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_DEFAULT_ON + #else + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_STRINGS_ARE_NUMBERS) + #if (SOL_STRINGS_ARE_NUMBERS != 0) + #define SOL_STRINGS_ARE_NUMBERS_I_ SOL_ON + #else + #define SOL_STRINGS_ARE_NUMBERS_I_ SOL_OFF + #endif +#else + #define SOL_STRINGS_ARE_NUMBERS_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_ENABLE_INTEROP) + #if SOL_ENABLE_INTEROP != 0 + #define SOL_USE_INTEROP_I_ SOL_ON + #else + #define SOL_USE_INTEROP_I_ SOL_OFF + #endif +#elif defined(SOL_USE_INTEROP) + #if SOL_USE_INTEROP != 0 + #define SOL_USE_INTEROP_I_ SOL_ON + #else + #define SOL_USE_INTEROP_I_ SOL_OFF + #endif +#else + #define SOL_USE_INTEROP_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_NO_NIL) + #if (SOL_NO_NIL != 0) + #define SOL_NIL_I_ SOL_OFF + #else + #define SOL_NIL_I_ SOL_ON + #endif +#elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) || defined(__OBJC__) || defined(nil) + #define SOL_NIL_I_ SOL_DEFAULT_OFF +#else + #define SOL_NIL_I_ SOL_DEFAULT_ON +#endif + +#if defined(SOL_USERTYPE_TYPE_BINDING_INFO) + #if (SOL_USERTYPE_TYPE_BINDING_INFO != 0) + #define SOL_USERTYPE_TYPE_BINDING_INFO_I_ SOL_ON + #else + #define SOL_USERTYPE_TYPE_BINDING_INFO_I_ SOL_OFF + #endif +#else + #define SOL_USERTYPE_TYPE_BINDING_INFO_I_ SOL_DEFAULT_ON +#endif // We should generate a my_type.__type table with lots of class information for usertypes + +#if defined(SOL_AUTOMAGICAL_TYPES_BY_DEFAULT) + #if (SOL_AUTOMAGICAL_TYPES_BY_DEFAULT != 0) + #define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_ON + #else + #define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_OFF + #endif +#elif defined(SOL_DEFAULT_AUTOMAGICAL_USERTYPES) + #if (SOL_DEFAULT_AUTOMAGICAL_USERTYPES != 0) + #define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_ON + #else + #define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_OFF + #endif +#else + #define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_DEFAULT_ON +#endif // make is_automagical on/off by default + +#if defined(SOL_STD_VARIANT) + #if (SOL_STD_VARIANT != 0) + #define SOL_STD_VARIANT_I_ SOL_ON + #else + #define SOL_STD_VARIANT_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_COMPILER_CLANG) && SOL_IS_ON(SOL_PLATFORM_APPLE) + #if defined(__has_include) + #if __has_include(<variant>) + #define SOL_STD_VARIANT_I_ SOL_DEFAULT_ON + #else + #define SOL_STD_VARIANT_I_ SOL_DEFAULT_OFF + #endif + #else + #define SOL_STD_VARIANT_I_ SOL_DEFAULT_OFF + #endif + #else + #define SOL_STD_VARIANT_I_ SOL_DEFAULT_ON + #endif +#endif // make is_automagical on/off by default + +#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) + #if (SOL_NOEXCEPT_FUNCTION_TYPE != 0) + #define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_ON + #else + #define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_OFF + #endif +#else + #if defined(__cpp_noexcept_function_type) + #define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_ON + #elif SOL_IS_ON(SOL_COMPILER_VCXX) && (defined(_MSVC_LANG) && (_MSVC_LANG < 201403L)) + // There is a bug in the VC++ compiler?? + // on /std:c++latest under x86 conditions (VS 15.5.2), + // compiler errors are tossed for noexcept markings being on function types + // that are identical in every other way to their non-noexcept marked types function types... + // VS 2019: There is absolutely a bug. + #define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_OFF + #else + #define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_DEFAULT_ON + #endif +#endif // noexcept is part of a function's type + +#if defined(SOL_STACK_STRING_OPTIMIZATION_SIZE) && SOL_STACK_STRING_OPTIMIZATION_SIZE > 0 + #define SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_ SOL_STACK_STRING_OPTIMIZATION_SIZE +#else + #define SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_ 1024 +#endif + +#if defined(SOL_ID_SIZE) && SOL_ID_SIZE > 0 + #define SOL_ID_SIZE_I_ SOL_ID_SIZE +#else + #define SOL_ID_SIZE_I_ 512 +#endif + +#if defined(LUA_IDSIZE) && LUA_IDSIZE > 0 + #define SOL_FILE_ID_SIZE_I_ LUA_IDSIZE +#elif defined(SOL_ID_SIZE) && SOL_ID_SIZE > 0 + #define SOL_FILE_ID_SIZE_I_ SOL_FILE_ID_SIZE +#else + #define SOL_FILE_ID_SIZE_I_ 2048 +#endif + +#if defined(SOL_PRINT_ERRORS) + #if (SOL_PRINT_ERRORS != 0) + #define SOL_PRINT_ERRORS_I_ SOL_ON + #else + #define SOL_PRINT_ERRORS_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_PRINT_ERRORS_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_PRINT_ERRORS_I_ SOL_DEFAULT_ON + #else + #define SOL_PRINT_ERRORS_I_ SOL_OFF + #endif +#endif + +#if defined(SOL_DEFAULT_PASS_ON_ERROR) + #if (SOL_DEFAULT_PASS_ON_ERROR != 0) + #define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_ON + #else + #define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_OFF + #endif +#else + #define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_USING_CXX_LUA) + #if (SOL_USING_CXX_LUA != 0) + #define SOL_USING_CXX_LUA_I_ SOL_ON + #else + #define SOL_USING_CXX_LUA_I_ SOL_OFF + #endif +#elif defined(SOL_USE_CXX_LUA) + // alternative spelling + #if (SOL_USE_CXX_LUA != 0) + #define SOL_USING_CXX_LUA_I_ SOL_ON + #else + #define SOL_USING_CXX_LUA_I_ SOL_OFF + #endif +#else + #define SOL_USING_CXX_LUA_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_USING_CXX_LUAJIT) + #if (SOL_USING_CXX_LUAJIT != 0) + #define SOL_USING_CXX_LUAJIT_I_ SOL_ON + #else + #define SOL_USING_CXX_LUAJIT_I_ SOL_OFF + #endif +#elif defined(SOL_USE_CXX_LUAJIT) + #if (SOL_USE_CXX_LUAJIT != 0) + #define SOL_USING_CXX_LUAJIT_I_ SOL_ON + #else + #define SOL_USING_CXX_LUAJIT_I_ SOL_OFF + #endif +#else + #define SOL_USING_CXX_LUAJIT_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_NO_LUA_HPP) + #if (SOL_NO_LUA_HPP != 0) + #define SOL_USE_LUA_HPP_I_ SOL_OFF + #else + #define SOL_USE_LUA_HPP_I_ SOL_ON + #endif +#elif SOL_IS_ON(SOL_USING_CXX_LUA) + #define SOL_USE_LUA_HPP_I_ SOL_OFF +#elif defined(__has_include) + #if __has_include(<lua.hpp>) + #define SOL_USE_LUA_HPP_I_ SOL_ON + #else + #define SOL_USE_LUA_HPP_I_ SOL_OFF + #endif +#else + #define SOL_USE_LUA_HPP_I_ SOL_DEFAULT_ON +#endif + +#if defined(SOL_CONTAINERS_START) + #define SOL_CONTAINER_START_INDEX_I_ SOL_CONTAINERS_START +#elif defined(SOL_CONTAINERS_START_INDEX) + #define SOL_CONTAINER_START_INDEX_I_ SOL_CONTAINERS_START_INDEX +#elif defined(SOL_CONTAINER_START_INDEX) + #define SOL_CONTAINER_START_INDEX_I_ SOL_CONTAINER_START_INDEX +#else + #define SOL_CONTAINER_START_INDEX_I_ 1 +#endif + +#if defined (SOL_NO_MEMORY_ALIGNMENT) + #if (SOL_NO_MEMORY_ALIGNMENT != 0) + #define SOL_ALIGN_MEMORY_I_ SOL_OFF + #else + #define SOL_ALIGN_MEMORY_I_ SOL_ON + #endif +#else + #define SOL_ALIGN_MEMORY_I_ SOL_DEFAULT_ON +#endif + +#if defined(SOL_USE_BOOST) + #if (SOL_USE_BOOST != 0) + #define SOL_USE_BOOST_I_ SOL_ON + #else + #define SOL_USE_BOOST_I_ SOL_OFF + #endif +#else + #define SOL_USE_BOOST_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_USE_UNSAFE_BASE_LOOKUP) + #if (SOL_USE_UNSAFE_BASE_LOOKUP != 0) + #define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_ON + #else + #define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_OFF + #endif +#else + #define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_INSIDE_UNREAL) + #if (SOL_INSIDE_UNREAL != 0) + #define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_ON + #else + #define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_OFF + #endif +#else + #if defined(UE_BUILD_DEBUG) || defined(UE_BUILD_DEVELOPMENT) || defined(UE_BUILD_TEST) || defined(UE_BUILD_SHIPPING) || defined(UE_SERVER) + #define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_DEFAULT_ON + #else + #define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_NO_COMPAT) + #if (SOL_NO_COMPAT != 0) + #define SOL_USE_COMPATIBILITY_LAYER_I_ SOL_OFF + #else + #define SOL_USE_COMPATIBILITY_LAYER_I_ SOL_ON + #endif +#else + #define SOL_USE_COMPATIBILITY_LAYER_I_ SOL_DEFAULT_ON +#endif + +#if defined(SOL_GET_FUNCTION_POINTER_UNSAFE) + #if (SOL_GET_FUNCTION_POINTER_UNSAFE != 0) + #define SOL_GET_FUNCTION_POINTER_UNSAFE_I_ SOL_ON + #else + #define SOL_GET_FUNCTION_POINTER_UNSAFE_I_ SOL_OFF + #endif +#else + #define SOL_GET_FUNCTION_POINTER_UNSAFE_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_CONTAINER_CHECK_IS_EXHAUSTIVE) + #if (SOL_CONTAINER_CHECK_IS_EXHAUSTIVE != 0) + #define SOL_CONTAINER_CHECK_IS_EXHAUSTIVE_I_ SOL_ON + #else + #define SOL_CONTAINER_CHECK_IS_EXHAUSTIVE_I_ SOL_OFF + #endif +#else + #define SOL_CONTAINER_CHECK_IS_EXHAUSTIVE_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_FUNCTION_CALL_VALUE_SEMANTICS) + #if (SOL_FUNCTION_CALL_VALUE_SEMANTICS != 0) + #define SOL_FUNCTION_CALL_VALUE_SEMANTICS_I_ SOL_ON + #else + #define SOL_FUNCTION_CALL_VALUE_SEMANTICS_I_ SOL_OFF + #endif +#else + #define SOL_FUNCTION_CALL_VALUE_SEMANTICS_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_MINGW_CCTYPE_IS_POISONED) + #if (SOL_MINGW_CCTYPE_IS_POISONED != 0) + #define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_ON + #else + #define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_OFF + #endif +#elif SOL_IS_ON(SOL_COMPILER_MINGW) && defined(__GNUC__) && (__GNUC__ < 6) + // MinGW is off its rocker in some places... + #define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_DEFAULT_ON +#else + #define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_CHAR8_T) + #if (SOL_CHAR8_T != 0) + #define SOL_CHAR8_T_I_ SOL_ON + #else + #define SOL_CHAR8_T_I_ SOL_OFF + #endif +#else + #if defined(__cpp_char8_t) + #define SOL_CHAR8_T_I_ SOL_DEFAULT_ON + #else + #define SOL_CHAR8_T_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if SOL_IS_ON(SOL_USE_BOOST) + #include <boost/version.hpp> + + #if BOOST_VERSION >= 107500 // Since Boost 1.75.0 boost::none is constexpr + #define SOL_BOOST_NONE_CONSTEXPR_I_ constexpr + #else + #define SOL_BOOST_NONE_CONSTEXPR_I_ const + #endif // BOOST_VERSION +#else + // assume boost isn't using a garbage version + #define SOL_BOOST_NONE_CONSTEXPR_I_ constexpr +#endif + +#if defined(SOL2_CI) + #if (SOL2_CI != 0) + #define SOL2_CI_I_ SOL_ON + #else + #define SOL2_CI_I_ SOL_OFF + #endif +#else + #define SOL2_CI_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_ASSERT) + #define SOL_USER_ASSERT_I_ SOL_ON +#else + #define SOL_USER_ASSERT_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_ASSERT_MSG) + #define SOL_USER_ASSERT_MSG_I_ SOL_ON +#else + #define SOL_USER_ASSERT_MSG_I_ SOL_DEFAULT_OFF +#endif + +// beginning of sol/prologue.hpp + +#if defined(SOL_PROLOGUE_I_) + #error "[sol2] Library Prologue was already included in translation unit and not properly ended with an epilogue." +#endif + +#define SOL_PROLOGUE_I_ 1 + +#if SOL_IS_ON(SOL_BUILD_CXX_MODE) + #define _FWD(...) static_cast<decltype( __VA_ARGS__ )&&>( __VA_ARGS__ ) + + #if SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) + #define _MOVE(...) static_cast<__typeof( __VA_ARGS__ )&&>( __VA_ARGS__ ) + #else + #include <type_traits> + + #define _MOVE(...) static_cast<::std::remove_reference_t<( __VA_ARGS__ )>&&>( __VA_OPT__(,) ) + #endif +#endif + +// end of sol/prologue.hpp + +// beginning of sol/epilogue.hpp + +#if !defined(SOL_PROLOGUE_I_) + #error "[sol2] Library Prologue is missing from this translation unit." +#else + #undef SOL_PROLOGUE_I_ +#endif + +#if SOL_IS_ON(SOL_BUILD_CXX_MODE) + #undef _FWD + #undef _MOVE +#endif + +// end of sol/epilogue.hpp + +// beginning of sol/detail/build_version.hpp + +#if defined(SOL_DLL) + #if (SOL_DLL != 0) + #define SOL_DLL_I_ SOL_ON + #else + #define SOL_DLL_I_ SOL_OFF + #endif +#elif SOL_IS_ON(SOL_COMPILER_VCXX) && (defined(DLL_) || defined(_DLL)) + #define SOL_DLL_I_ SOL_DEFAULT_ON +#else + #define SOL_DLL_I_ SOL_DEFAULT_OFF +#endif // DLL definition + +#if defined(SOL_HEADER_ONLY) + #if (SOL_HEADER_ONLY != 0) + #define SOL_HEADER_ONLY_I_ SOL_ON + #else + #define SOL_HEADER_ONLY_I_ SOL_OFF + #endif +#else + #define SOL_HEADER_ONLY_I_ SOL_DEFAULT_OFF +#endif // Header only library + +#if defined(SOL_BUILD) + #if (SOL_BUILD != 0) + #define SOL_BUILD_I_ SOL_ON + #else + #define SOL_BUILD_I_ SOL_OFF + #endif +#elif SOL_IS_ON(SOL_HEADER_ONLY) + #define SOL_BUILD_I_ SOL_DEFAULT_OFF +#else + #define SOL_BUILD_I_ SOL_DEFAULT_ON +#endif + +#if defined(SOL_UNITY_BUILD) + #if (SOL_UNITY_BUILD != 0) + #define SOL_UNITY_BUILD_I_ SOL_ON + #else + #define SOL_UNITY_BUILD_I_ SOL_OFF + #endif +#else + #define SOL_UNITY_BUILD_I_ SOL_DEFAULT_OFF +#endif // Header only library + +#if defined(SOL_C_FUNCTION_LINKAGE) + #define SOL_C_FUNCTION_LINKAGE_I_ SOL_C_FUNCTION_LINKAGE +#else + #if SOL_IS_ON(SOL_BUILD_CXX_MODE) + // C++ + #define SOL_C_FUNCTION_LINKAGE_I_ extern "C" + #else + // normal + #define SOL_C_FUNCTION_LINKAGE_I_ + #endif // C++ or not +#endif // Linkage specification for C functions + +#if defined(SOL_API_LINKAGE) + #define SOL_API_LINKAGE_I_ SOL_API_LINKAGE +#else + #if SOL_IS_ON(SOL_DLL) + #if SOL_IS_ON(SOL_COMPILER_VCXX) || SOL_IS_ON(SOL_PLATFORM_WINDOWS) || SOL_IS_ON(SOL_PLATFORM_CYGWIN) + // MSVC Compiler; or, Windows, or Cygwin platforms + #if SOL_IS_ON(SOL_BUILD) + // Building the library + #if SOL_IS_ON(SOL_COMPILER_GCC) + // Using GCC + #define SOL_API_LINKAGE_I_ __attribute__((dllexport)) + #else + // Using Clang, MSVC, etc... + #define SOL_API_LINKAGE_I_ __declspec(dllexport) + #endif + #else + #if SOL_IS_ON(SOL_COMPILER_GCC) + #define SOL_API_LINKAGE_I_ __attribute__((dllimport)) + #else + #define SOL_API_LINKAGE_I_ __declspec(dllimport) + #endif + #endif + #else + // extern if building normally on non-MSVC + #define SOL_API_LINKAGE_I_ extern + #endif + #elif SOL_IS_ON(SOL_UNITY_BUILD) + // Built-in library, like how stb typical works + #if SOL_IS_ON(SOL_HEADER_ONLY) + // Header only, so functions are defined "inline" + #define SOL_API_LINKAGE_I_ inline + #else + // Not header only, so seperately compiled files + #define SOL_API_LINKAGE_I_ extern + #endif + #else + // Normal static library + #if SOL_IS_ON(SOL_BUILD_CXX_MODE) + #define SOL_API_LINKAGE_I_ + #else + #define SOL_API_LINKAGE_I_ extern + #endif + #endif // DLL or not +#endif // Build definitions + +#if defined(SOL_PUBLIC_FUNC_DECL) + #define SOL_PUBLIC_FUNC_DECL_I_ SOL_PUBLIC_FUNC_DECL +#else + #define SOL_PUBLIC_FUNC_DECL_I_ SOL_API_LINKAGE_I_ +#endif + +#if defined(SOL_INTERNAL_FUNC_DECL_) + #define SOL_INTERNAL_FUNC_DECL_I_ SOL_INTERNAL_FUNC_DECL_ +#else + #define SOL_INTERNAL_FUNC_DECL_I_ SOL_API_LINKAGE_I_ +#endif + +#if defined(SOL_PUBLIC_FUNC_DEF) + #define SOL_PUBLIC_FUNC_DEF_I_ SOL_PUBLIC_FUNC_DEF +#else + #define SOL_PUBLIC_FUNC_DEF_I_ SOL_API_LINKAGE_I_ +#endif + +#if defined(SOL_INTERNAL_FUNC_DEF) + #define SOL_INTERNAL_FUNC_DEF_I_ SOL_INTERNAL_FUNC_DEF +#else + #define SOL_INTERNAL_FUNC_DEF_I_ SOL_API_LINKAGE_I_ +#endif + +#if defined(SOL_FUNC_DECL) + #define SOL_FUNC_DECL_I_ SOL_FUNC_DECL +#elif SOL_IS_ON(SOL_HEADER_ONLY) + #define SOL_FUNC_DECL_I_ +#elif SOL_IS_ON(SOL_DLL) + #if SOL_IS_ON(SOL_COMPILER_VCXX) + #if SOL_IS_ON(SOL_BUILD) + #define SOL_FUNC_DECL_I_ extern __declspec(dllexport) + #else + #define SOL_FUNC_DECL_I_ extern __declspec(dllimport) + #endif + #elif SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) + #define SOL_FUNC_DECL_I_ extern __attribute__((visibility("default"))) + #else + #define SOL_FUNC_DECL_I_ extern + #endif +#endif + +#if defined(SOL_FUNC_DEFN) + #define SOL_FUNC_DEFN_I_ SOL_FUNC_DEFN +#elif SOL_IS_ON(SOL_HEADER_ONLY) + #define SOL_FUNC_DEFN_I_ inline +#elif SOL_IS_ON(SOL_DLL) + #if SOL_IS_ON(SOL_COMPILER_VCXX) + #if SOL_IS_ON(SOL_BUILD) + #define SOL_FUNC_DEFN_I_ __declspec(dllexport) + #else + #define SOL_FUNC_DEFN_I_ __declspec(dllimport) + #endif + #elif SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) + #define SOL_FUNC_DEFN_I_ __attribute__((visibility("default"))) + #else + #define SOL_FUNC_DEFN_I_ + #endif +#endif + +#if defined(SOL_HIDDEN_FUNC_DECL) + #define SOL_HIDDEN_FUNC_DECL_I_ SOL_HIDDEN_FUNC_DECL +#elif SOL_IS_ON(SOL_HEADER_ONLY) + #define SOL_HIDDEN_FUNC_DECL_I_ +#elif SOL_IS_ON(SOL_DLL) + #if SOL_IS_ON(SOL_COMPILER_VCXX) + #if SOL_IS_ON(SOL_BUILD) + #define SOL_HIDDEN_FUNC_DECL_I_ extern __declspec(dllexport) + #else + #define SOL_HIDDEN_FUNC_DECL_I_ extern __declspec(dllimport) + #endif + #elif SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) + #define SOL_HIDDEN_FUNC_DECL_I_ extern __attribute__((visibility("default"))) + #else + #define SOL_HIDDEN_FUNC_DECL_I_ extern + #endif +#endif + +#if defined(SOL_HIDDEN_FUNC_DEFN) + #define SOL_HIDDEN_FUNC_DEFN_I_ SOL_HIDDEN_FUNC_DEFN +#elif SOL_IS_ON(SOL_HEADER_ONLY) + #define SOL_HIDDEN_FUNC_DEFN_I_ inline +#elif SOL_IS_ON(SOL_DLL) + #if SOL_IS_ON(SOL_COMPILER_VCXX) + #if SOL_IS_ON(SOL_BUILD) + #define SOL_HIDDEN_FUNC_DEFN_I_ + #else + #define SOL_HIDDEN_FUNC_DEFN_I_ + #endif + #elif SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) + #define SOL_HIDDEN_FUNC_DEFN_I_ __attribute__((visibility("hidden"))) + #else + #define SOL_HIDDEN_FUNC_DEFN_I_ + #endif +#endif + +// end of sol/detail/build_version.hpp + +// end of sol/version.hpp + +#include <utility> +#include <type_traits> +#include <string_view> + +#if SOL_IS_ON(SOL_USING_CXX_LUA) || SOL_IS_ON(SOL_USING_CXX_LUAJIT) +struct lua_State; +#else +extern "C" { +struct lua_State; +} +#endif // C++ Mangling for Lua vs. Not + +namespace sol { + + enum class type; + + class stateless_reference; + template <bool b> + class basic_reference; + using reference = basic_reference<false>; + using main_reference = basic_reference<true>; + class stateless_stack_reference; + class stack_reference; + + template <typename A> + class basic_bytecode; + + struct lua_value; + + struct proxy_base_tag; + template <typename> + struct proxy_base; + template <typename, typename> + struct table_proxy; + + template <bool, typename> + class basic_table_core; + template <bool b> + using table_core = basic_table_core<b, reference>; + template <bool b> + using main_table_core = basic_table_core<b, main_reference>; + template <bool b> + using stack_table_core = basic_table_core<b, stack_reference>; + template <typename base_type> + using basic_table = basic_table_core<false, base_type>; + using table = table_core<false>; + using global_table = table_core<true>; + using main_table = main_table_core<false>; + using main_global_table = main_table_core<true>; + using stack_table = stack_table_core<false>; + using stack_global_table = stack_table_core<true>; + + template <typename> + struct basic_lua_table; + using lua_table = basic_lua_table<reference>; + using stack_lua_table = basic_lua_table<stack_reference>; + + template <typename T, typename base_type> + class basic_usertype; + template <typename T> + using usertype = basic_usertype<T, reference>; + template <typename T> + using stack_usertype = basic_usertype<T, stack_reference>; + + template <typename base_type> + class basic_metatable; + using metatable = basic_metatable<reference>; + using stack_metatable = basic_metatable<stack_reference>; + + template <typename base_t> + struct basic_environment; + using environment = basic_environment<reference>; + using main_environment = basic_environment<main_reference>; + using stack_environment = basic_environment<stack_reference>; + + template <typename T, bool> + class basic_function; + template <typename T, bool, typename H> + class basic_protected_function; + using unsafe_function = basic_function<reference, false>; + using safe_function = basic_protected_function<reference, false, reference>; + using main_unsafe_function = basic_function<main_reference, false>; + using main_safe_function = basic_protected_function<main_reference, false, reference>; + using stack_unsafe_function = basic_function<stack_reference, false>; + using stack_safe_function = basic_protected_function<stack_reference, false, reference>; + using stack_aligned_unsafe_function = basic_function<stack_reference, true>; + using stack_aligned_safe_function = basic_protected_function<stack_reference, true, reference>; + using protected_function = safe_function; + using main_protected_function = main_safe_function; + using stack_protected_function = stack_safe_function; + using stack_aligned_protected_function = stack_aligned_safe_function; +#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS) + using function = protected_function; + using main_function = main_protected_function; + using stack_function = stack_protected_function; + using stack_aligned_function = stack_aligned_safe_function; +#else + using function = unsafe_function; + using main_function = main_unsafe_function; + using stack_function = stack_unsafe_function; + using stack_aligned_function = stack_aligned_unsafe_function; +#endif + using stack_aligned_stack_handler_function = basic_protected_function<stack_reference, true, stack_reference>; + + struct unsafe_function_result; + struct protected_function_result; + using safe_function_result = protected_function_result; +#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS) + using function_result = safe_function_result; +#else + using function_result = unsafe_function_result; +#endif + + template <typename base_t> + class basic_object_base; + template <typename base_t> + class basic_object; + template <typename base_t> + class basic_userdata; + template <typename base_t> + class basic_lightuserdata; + template <typename base_t> + class basic_coroutine; + template <typename base_t> + class basic_packaged_coroutine; + template <typename base_t> + class basic_thread; + + using object = basic_object<reference>; + using userdata = basic_userdata<reference>; + using lightuserdata = basic_lightuserdata<reference>; + using thread = basic_thread<reference>; + using coroutine = basic_coroutine<reference>; + using packaged_coroutine = basic_packaged_coroutine<reference>; + using main_object = basic_object<main_reference>; + using main_userdata = basic_userdata<main_reference>; + using main_lightuserdata = basic_lightuserdata<main_reference>; + using main_coroutine = basic_coroutine<main_reference>; + using stack_object = basic_object<stack_reference>; + using stack_userdata = basic_userdata<stack_reference>; + using stack_lightuserdata = basic_lightuserdata<stack_reference>; + using stack_thread = basic_thread<stack_reference>; + using stack_coroutine = basic_coroutine<stack_reference>; + + struct stack_proxy_base; + struct stack_proxy; + struct variadic_args; + struct variadic_results; + struct stack_count; + struct this_state; + struct this_main_state; + struct this_environment; + + class state_view; + class state; + + template <typename T> + struct as_table_t; + template <typename T> + struct as_container_t; + template <typename T> + struct nested; + template <typename T> + struct light; + template <typename T> + struct user; + template <typename T> + struct as_args_t; + template <typename T> + struct protect_t; + template <typename F, typename... Policies> + struct policy_wrapper; + + template <typename T> + struct usertype_traits; + template <typename T> + struct unique_usertype_traits; + + template <typename... Args> + struct types { + typedef std::make_index_sequence<sizeof...(Args)> indices; + static constexpr std::size_t size() { + return sizeof...(Args); + } + }; + + template <typename T> + struct derive : std::false_type { + typedef types<> type; + }; + + template <typename T> + struct base : std::false_type { + typedef types<> type; + }; + + template <typename T> + struct weak_derive { + static bool value; + }; + + template <typename T> + bool weak_derive<T>::value = false; + + namespace stack { + struct record; + } + +#if SOL_IS_OFF(SOL_USE_BOOST) + template <class T> + class optional; + + template <class T> + class optional<T&>; +#endif + + using check_handler_type = int(lua_State*, int, type, type, const char*); + +} // namespace sol + +#define SOL_BASE_CLASSES(T, ...) \ + namespace sol { \ + template <> \ + struct base<T> : std::true_type { \ + typedef ::sol::types<__VA_ARGS__> type; \ + }; \ + } \ + static_assert(true, "") +#define SOL_DERIVED_CLASSES(T, ...) \ + namespace sol { \ + template <> \ + struct derive<T> : std::true_type { \ + typedef ::sol::types<__VA_ARGS__> type; \ + }; \ + } \ + static_assert(true, "") + +#endif // SOL_FORWARD_HPP +// end of sol/forward.hpp + +#endif // SOL_SINGLE_INCLUDE_SOL_FORWARD_HPP diff --git a/src/libs/3rdparty/sol2/include/sol/sol.hpp b/src/libs/3rdparty/sol2/include/sol/sol.hpp new file mode 100644 index 0000000000..063ea72165 --- /dev/null +++ b/src/libs/3rdparty/sol2/include/sol/sol.hpp @@ -0,0 +1,29202 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2020 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// This file was generated with a script. +// Generated 2024-01-13 14:25:56.532275 UTC +// This header was generated with sol v3.3.1 (revision 9c882a28) +// https://github.com/ThePhD/sol2 + +#ifndef SOL_SINGLE_INCLUDE_SOL_HPP +#define SOL_SINGLE_INCLUDE_SOL_HPP + +// beginning of sol/sol.hpp + +#ifndef SOL_HPP +#define SOL_HPP + +// beginning of sol/version.hpp + +#include "config.hpp" + +#define SOL_VERSION_MAJOR 3 +#define SOL_VERSION_MINOR 2 +#define SOL_VERSION_PATCH 3 +#define SOL_VERSION_STRING "3.2.3" +#define SOL_VERSION ((SOL_VERSION_MAJOR * 100000) + (SOL_VERSION_MINOR * 100) + (SOL_VERSION_PATCH)) + +#define SOL_TOKEN_TO_STRING_POST_EXPANSION_I_(_TOKEN) #_TOKEN +#define SOL_TOKEN_TO_STRING_I_(_TOKEN) SOL_TOKEN_TO_STRING_POST_EXPANSION_I_(_TOKEN) + +#define SOL_CONCAT_TOKENS_POST_EXPANSION_I_(_LEFT, _RIGHT) _LEFT##_RIGHT +#define SOL_CONCAT_TOKENS_I_(_LEFT, _RIGHT) SOL_CONCAT_TOKENS_POST_EXPANSION_I_(_LEFT, _RIGHT) + +#define SOL_RAW_IS_ON(OP_SYMBOL) ((3 OP_SYMBOL 3) != 0) +#define SOL_RAW_IS_OFF(OP_SYMBOL) ((3 OP_SYMBOL 3) == 0) +#define SOL_RAW_IS_DEFAULT_ON(OP_SYMBOL) ((3 OP_SYMBOL 3) > 3) +#define SOL_RAW_IS_DEFAULT_OFF(OP_SYMBOL) ((3 OP_SYMBOL 3 OP_SYMBOL 3) < 0) + +#define SOL_IS_ON(OP_SYMBOL) SOL_RAW_IS_ON(OP_SYMBOL ## _I_) +#define SOL_IS_OFF(OP_SYMBOL) SOL_RAW_IS_OFF(OP_SYMBOL ## _I_) +#define SOL_IS_DEFAULT_ON(OP_SYMBOL) SOL_RAW_IS_DEFAULT_ON(OP_SYMBOL ## _I_) +#define SOL_IS_DEFAULT_OFF(OP_SYMBOL) SOL_RAW_IS_DEFAULT_OFF(OP_SYMBOL ## _I_) + +#define SOL_ON | +#define SOL_OFF ^ +#define SOL_DEFAULT_ON + +#define SOL_DEFAULT_OFF - + +#if defined(SOL_BUILD_CXX_MODE) + #if (SOL_BUILD_CXX_MODE != 0) + #define SOL_BUILD_CXX_MODE_I_ SOL_ON + #else + #define SOL_BUILD_CXX_MODE_I_ SOL_OFF + #endif +#elif defined(__cplusplus) + #define SOL_BUILD_CXX_MODE_I_ SOL_DEFAULT_ON +#else + #define SOL_BUILD_CXX_MODE_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_BUILD_C_MODE) + #if (SOL_BUILD_C_MODE != 0) + #define SOL_BUILD_C_MODE_I_ SOL_ON + #else + #define SOL_BUILD_C_MODE_I_ SOL_OFF + #endif +#elif defined(__STDC__) + #define SOL_BUILD_C_MODE_I_ SOL_DEFAULT_ON +#else + #define SOL_BUILD_C_MODE_I_ SOL_DEFAULT_OFF +#endif + +#if SOL_IS_ON(SOL_BUILD_C_MODE) + #include <stddef.h> + #include <stdint.h> + #include <limits.h> +#else + #include <cstddef> + #include <cstdint> + #include <climits> +#endif + +#if defined(SOL_HAS_BUILTIN) + #define SOL_HAS_BUILTIN_I_(...) SOL_HAS_BUILTIN(__VA_ARGS__) +#elif defined(__has_builtin) + #define SOL_HAS_BUILTIN_I_(...) __has_builtin(__VA_ARGS__) +#else + #define SOL_HAS_BUILTIN_I_(...) 0 +#endif + +#if defined(SOL_COMPILER_VCXX) + #if defined(SOL_COMPILER_VCXX != 0) + #define SOL_COMPILER_VCXX_I_ SOL_ON + #else + #define SOL_COMPILER_VCXX_I_ SOL_OFF + #endif +#elif defined(_MSC_VER) + #define SOL_COMPILER_VCXX_I_ SOL_DEFAULT_ON +#else + #define SOL_COMPILER_VCXX_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_COMPILER_GCC) + #if defined(SOL_COMPILER_GCC != 0) + #define SOL_COMPILER_GCC_I_ SOL_ON + #else + #define SOL_COMPILER_GCC_I_ SOL_OFF + #endif +#elif defined(__GNUC__) + #define SOL_COMPILER_GCC_I_ SOL_DEFAULT_ON +#else + #define SOL_COMPILER_GCC_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_COMPILER_CLANG) + #if defined(SOL_COMPILER_CLANG != 0) + #define SOL_COMPILER_CLANG_I_ SOL_ON + #else + #define SOL_COMPILER_CLANG_I_ SOL_OFF + #endif +#elif defined(__clang__) + #define SOL_COMPILER_CLANG_I_ SOL_DEFAULT_ON +#else + #define SOL_COMPILER_CLANG_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_COMPILER_EDG) + #if defined(SOL_COMPILER_EDG != 0) + #define SOL_COMPILER_EDG_I_ SOL_ON + #else + #define SOL_COMPILER_EDG_I_ SOL_OFF + #endif +#else + #define SOL_COMPILER_EDG_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_COMPILER_MINGW) + #if (SOL_COMPILER_MINGW != 0) + #define SOL_COMPILER_MINGW_I_ SOL_ON + #else + #define SOL_COMPILER_MINGW_I_ SOL_OFF + #endif +#elif defined(__MINGW32__) + #define SOL_COMPILER_MINGW_I_ SOL_DEFAULT_ON +#else + #define SOL_COMPILER_MINGW_I_ SOL_DEFAULT_OFF +#endif + +#if SIZE_MAX <= 0xFFFFULL + #define SOL_PLATFORM_X16_I_ SOL_ON + #define SOL_PLATFORM_X86_I_ SOL_OFF + #define SOL_PLATFORM_X64_I_ SOL_OFF +#elif SIZE_MAX <= 0xFFFFFFFFULL + #define SOL_PLATFORM_X16_I_ SOL_OFF + #define SOL_PLATFORM_X86_I_ SOL_ON + #define SOL_PLATFORM_X64_I_ SOL_OFF +#else + #define SOL_PLATFORM_X16_I_ SOL_OFF + #define SOL_PLATFORM_X86_I_ SOL_OFF + #define SOL_PLATFORM_X64_I_ SOL_ON +#endif + +#define SOL_PLATFORM_ARM32_I_ SOL_OFF +#define SOL_PLATFORM_ARM64_I_ SOL_OFF + +#if defined(SOL_PLATFORM_WINDOWS) + #if (SOL_PLATFORM_WINDOWS != 0) + #define SOL_PLATFORM_WINDOWS_I_ SOL_ON + #else + #define SOL_PLATFORM_WINDOWS_I_ SOL_OFF + #endif +#elif defined(_WIN32) + #define SOL_PLATFORM_WINDOWS_I_ SOL_DEFAULT_ON +#else + #define SOL_PLATFORM_WINDOWS_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_PLATFORM_CYGWIN) + #if (SOL_PLATFORM_CYGWIN != 0) + #define SOL_PLATFORM_CYGWIN_I_ SOL_ON + #else + #define SOL_PLATFORM_CYGWIN_I_ SOL_ON + #endif +#elif defined(__CYGWIN__) + #define SOL_PLATFORM_CYGWIN_I_ SOL_DEFAULT_ON +#else + #define SOL_PLATFORM_CYGWIN_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_PLATFORM_APPLE) + #if (SOL_PLATFORM_APPLE != 0) + #define SOL_PLATFORM_APPLE_I_ SOL_ON + #else + #define SOL_PLATFORM_APPLE_I_ SOL_OFF + #endif +#elif defined(__APPLE__) + #define SOL_PLATFORM_APPLE_I_ SOL_DEFAULT_ON +#else + #define SOL_PLATFORM_APPLE_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_PLATFORM_UNIX) + #if (SOL_PLATFORM_UNIX != 0) + #define SOL_PLATFORM_UNIXLIKE_I_ SOL_ON + #else + #define SOL_PLATFORM_UNIXLIKE_I_ SOL_OFF + #endif +#elif defined(__unix__) + #define SOL_PLATFORM_UNIXLIKE_I_ SOL_DEFAUKT_ON +#else + #define SOL_PLATFORM_UNIXLIKE_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_PLATFORM_LINUX) + #if (SOL_PLATFORM_LINUX != 0) + #define SOL_PLATFORM_LINUXLIKE_I_ SOL_ON + #else + #define SOL_PLATFORM_LINUXLIKE_I_ SOL_OFF + #endif +#elif defined(__LINUX__) + #define SOL_PLATFORM_LINUXLIKE_I_ SOL_DEFAUKT_ON +#else + #define SOL_PLATFORM_LINUXLIKE_I_ SOL_DEFAULT_OFF +#endif + +#define SOL_PLATFORM_APPLE_IPHONE_I_ SOL_OFF +#define SOL_PLATFORM_BSDLIKE_I_ SOL_OFF + +#if defined(SOL_IN_DEBUG_DETECTED) + #if SOL_IN_DEBUG_DETECTED != 0 + #define SOL_DEBUG_BUILD_I_ SOL_ON + #else + #define SOL_DEBUG_BUILD_I_ SOL_OFF + #endif +#elif !defined(NDEBUG) + #if SOL_IS_ON(SOL_COMPILER_VCXX) && defined(_DEBUG) + #define SOL_DEBUG_BUILD_I_ SOL_ON + #elif (SOL_IS_ON(SOL_COMPILER_CLANG) || SOL_IS_ON(SOL_COMPILER_GCC)) && !defined(__OPTIMIZE__) + #define SOL_DEBUG_BUILD_I_ SOL_ON + #else + #define SOL_DEBUG_BUILD_I_ SOL_OFF + #endif +#else + #define SOL_DEBUG_BUILD_I_ SOL_DEFAULT_OFF +#endif // We are in a debug mode of some sort + +#if defined(SOL_NO_EXCEPTIONS) + #if (SOL_NO_EXCEPTIONS != 0) + #define SOL_EXCEPTIONS_I_ SOL_OFF + #else + #define SOL_EXCEPTIONS_I_ SOL_ON + #endif +#elif SOL_IS_ON(SOL_COMPILER_VCXX) + #if !defined(_CPPUNWIND) + #define SOL_EXCEPTIONS_I_ SOL_OFF + #else + #define SOL_EXCEPTIONS_I_ SOL_ON + #endif +#elif SOL_IS_ON(SOL_COMPILER_CLANG) || SOL_IS_ON(SOL_COMPILER_GCC) + #if !defined(__EXCEPTIONS) + #define SOL_EXCEPTIONS_I_ SOL_OFF + #else + #define SOL_EXCEPTIONS_I_ SOL_ON + #endif +#else + #define SOL_EXCEPTIONS_I_ SOL_DEFAULT_ON +#endif + +#if defined(SOL_NO_RTTI) + #if (SOL_NO_RTTI != 0) + #define SOL_RTTI_I_ SOL_OFF + #else + #define SOL_RTTI_I_ SOL_ON + #endif +#elif SOL_IS_ON(SOL_COMPILER_VCXX) + #if !defined(_CPPRTTI) + #define SOL_RTTI_I_ SOL_OFF + #else + #define SOL_RTTI_I_ SOL_ON + #endif +#elif SOL_IS_ON(SOL_COMPILER_CLANG) || SOL_IS_ON(SOL_COMPILER_GCC) + #if !defined(__GXX_RTTI) + #define SOL_RTTI_I_ SOL_OFF + #else + #define SOL_RTTI_I_ SOL_ON + #endif +#else + #define SOL_RTTI_I_ SOL_DEFAULT_ON +#endif + +#if defined(SOL_NO_THREAD_LOCAL) + #if SOL_NO_THREAD_LOCAL != 0 + #define SOL_USE_THREAD_LOCAL_I_ SOL_OFF + #else + #define SOL_USE_THREAD_LOCAL_I_ SOL_ON + #endif +#else + #define SOL_USE_THREAD_LOCAL_I_ SOL_DEFAULT_ON +#endif // thread_local keyword is bjorked on some platforms + +#if defined(SOL_ALL_SAFETIES_ON) + #if SOL_ALL_SAFETIES_ON != 0 + #define SOL_ALL_SAFETIES_ON_I_ SOL_ON + #else + #define SOL_ALL_SAFETIES_ON_I_ SOL_OFF + #endif +#else + #define SOL_ALL_SAFETIES_ON_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_SAFE_GETTER) + #if SOL_SAFE_GETTER != 0 + #define SOL_SAFE_GETTER_I_ SOL_ON + #else + #define SOL_SAFE_GETTER_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_SAFE_GETTER_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_SAFE_GETTER_I_ SOL_DEFAULT_ON + #else + #define SOL_SAFE_GETTER_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_SAFE_USERTYPE) + #if SOL_SAFE_USERTYPE != 0 + #define SOL_SAFE_USERTYPE_I_ SOL_ON + #else + #define SOL_SAFE_USERTYPE_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_SAFE_USERTYPE_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_SAFE_USERTYPE_I_ SOL_DEFAULT_ON + #else + #define SOL_SAFE_USERTYPE_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_SAFE_REFERENCES) + #if SOL_SAFE_REFERENCES != 0 + #define SOL_SAFE_REFERENCES_I_ SOL_ON + #else + #define SOL_SAFE_REFERENCES_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_SAFE_REFERENCES_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_SAFE_REFERENCES_I_ SOL_DEFAULT_ON + #else + #define SOL_SAFE_REFERENCES_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_SAFE_FUNCTIONS) + #if SOL_SAFE_FUNCTIONS != 0 + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON + #else + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_OFF + #endif +#elif defined (SOL_SAFE_FUNCTION_OBJECTS) + #if SOL_SAFE_FUNCTION_OBJECTS != 0 + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON + #else + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_DEFAULT_ON + #else + #define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_SAFE_FUNCTION_CALLS) + #if SOL_SAFE_FUNCTION_CALLS != 0 + #define SOL_SAFE_FUNCTION_CALLS_I_ SOL_ON + #else + #define SOL_SAFE_FUNCTION_CALLS_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_SAFE_FUNCTION_CALLS_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_SAFE_FUNCTION_CALLS_I_ SOL_DEFAULT_ON + #else + #define SOL_SAFE_FUNCTION_CALLS_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_SAFE_PROXIES) + #if SOL_SAFE_PROXIES != 0 + #define SOL_SAFE_PROXIES_I_ SOL_ON + #else + #define SOL_SAFE_PROXIES_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_SAFE_PROXIES_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_SAFE_PROXIES_I_ SOL_DEFAULT_ON + #else + #define SOL_SAFE_PROXIES_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_SAFE_NUMERICS) + #if SOL_SAFE_NUMERICS != 0 + #define SOL_SAFE_NUMERICS_I_ SOL_ON + #else + #define SOL_SAFE_NUMERICS_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_SAFE_NUMERICS_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_SAFE_NUMERICS_I_ SOL_DEFAULT_ON + #else + #define SOL_SAFE_NUMERICS_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_ALL_INTEGER_VALUES_FIT) + #if (SOL_ALL_INTEGER_VALUES_FIT != 0) + #define SOL_ALL_INTEGER_VALUES_FIT_I_ SOL_ON + #else + #define SOL_ALL_INTEGER_VALUES_FIT_I_ SOL_OFF + #endif +#elif !SOL_IS_DEFAULT_OFF(SOL_SAFE_NUMERICS) && SOL_IS_OFF(SOL_SAFE_NUMERICS) + // if numerics is intentionally turned off, flip this on + #define SOL_ALL_INTEGER_VALUES_FIT_I_ SOL_DEFAULT_ON +#else + // default to off + #define SOL_ALL_INTEGER_VALUES_FIT_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_SAFE_STACK_CHECK) + #if SOL_SAFE_STACK_CHECK != 0 + #define SOL_SAFE_STACK_CHECK_I_ SOL_ON + #else + #define SOL_SAFE_STACK_CHECK_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_SAFE_STACK_CHECK_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_SAFE_STACK_CHECK_I_ SOL_DEFAULT_ON + #else + #define SOL_SAFE_STACK_CHECK_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_NO_CHECK_NUMBER_PRECISION) + #if SOL_NO_CHECK_NUMBER_PRECISION != 0 + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_OFF + #else + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON + #endif +#elif defined(SOL_NO_CHECKING_NUMBER_PRECISION) + #if SOL_NO_CHECKING_NUMBER_PRECISION != 0 + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_OFF + #else + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON + #elif SOL_IS_ON(SOL_SAFE_NUMERICS) + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_DEFAULT_ON + #else + #define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_STRINGS_ARE_NUMBERS) + #if (SOL_STRINGS_ARE_NUMBERS != 0) + #define SOL_STRINGS_ARE_NUMBERS_I_ SOL_ON + #else + #define SOL_STRINGS_ARE_NUMBERS_I_ SOL_OFF + #endif +#else + #define SOL_STRINGS_ARE_NUMBERS_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_ENABLE_INTEROP) + #if SOL_ENABLE_INTEROP != 0 + #define SOL_USE_INTEROP_I_ SOL_ON + #else + #define SOL_USE_INTEROP_I_ SOL_OFF + #endif +#elif defined(SOL_USE_INTEROP) + #if SOL_USE_INTEROP != 0 + #define SOL_USE_INTEROP_I_ SOL_ON + #else + #define SOL_USE_INTEROP_I_ SOL_OFF + #endif +#else + #define SOL_USE_INTEROP_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_NO_NIL) + #if (SOL_NO_NIL != 0) + #define SOL_NIL_I_ SOL_OFF + #else + #define SOL_NIL_I_ SOL_ON + #endif +#elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) || defined(__OBJC__) || defined(nil) + #define SOL_NIL_I_ SOL_DEFAULT_OFF +#else + #define SOL_NIL_I_ SOL_DEFAULT_ON +#endif + +#if defined(SOL_USERTYPE_TYPE_BINDING_INFO) + #if (SOL_USERTYPE_TYPE_BINDING_INFO != 0) + #define SOL_USERTYPE_TYPE_BINDING_INFO_I_ SOL_ON + #else + #define SOL_USERTYPE_TYPE_BINDING_INFO_I_ SOL_OFF + #endif +#else + #define SOL_USERTYPE_TYPE_BINDING_INFO_I_ SOL_DEFAULT_ON +#endif // We should generate a my_type.__type table with lots of class information for usertypes + +#if defined(SOL_AUTOMAGICAL_TYPES_BY_DEFAULT) + #if (SOL_AUTOMAGICAL_TYPES_BY_DEFAULT != 0) + #define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_ON + #else + #define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_OFF + #endif +#elif defined(SOL_DEFAULT_AUTOMAGICAL_USERTYPES) + #if (SOL_DEFAULT_AUTOMAGICAL_USERTYPES != 0) + #define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_ON + #else + #define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_OFF + #endif +#else + #define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_DEFAULT_ON +#endif // make is_automagical on/off by default + +#if defined(SOL_STD_VARIANT) + #if (SOL_STD_VARIANT != 0) + #define SOL_STD_VARIANT_I_ SOL_ON + #else + #define SOL_STD_VARIANT_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_COMPILER_CLANG) && SOL_IS_ON(SOL_PLATFORM_APPLE) + #if defined(__has_include) + #if __has_include(<variant>) + #define SOL_STD_VARIANT_I_ SOL_DEFAULT_ON + #else + #define SOL_STD_VARIANT_I_ SOL_DEFAULT_OFF + #endif + #else + #define SOL_STD_VARIANT_I_ SOL_DEFAULT_OFF + #endif + #else + #define SOL_STD_VARIANT_I_ SOL_DEFAULT_ON + #endif +#endif // make is_automagical on/off by default + +#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) + #if (SOL_NOEXCEPT_FUNCTION_TYPE != 0) + #define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_ON + #else + #define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_OFF + #endif +#else + #if defined(__cpp_noexcept_function_type) + #define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_ON + #elif SOL_IS_ON(SOL_COMPILER_VCXX) && (defined(_MSVC_LANG) && (_MSVC_LANG < 201403L)) + // There is a bug in the VC++ compiler?? + // on /std:c++latest under x86 conditions (VS 15.5.2), + // compiler errors are tossed for noexcept markings being on function types + // that are identical in every other way to their non-noexcept marked types function types... + // VS 2019: There is absolutely a bug. + #define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_OFF + #else + #define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_DEFAULT_ON + #endif +#endif // noexcept is part of a function's type + +#if defined(SOL_STACK_STRING_OPTIMIZATION_SIZE) && SOL_STACK_STRING_OPTIMIZATION_SIZE > 0 + #define SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_ SOL_STACK_STRING_OPTIMIZATION_SIZE +#else + #define SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_ 1024 +#endif + +#if defined(SOL_ID_SIZE) && SOL_ID_SIZE > 0 + #define SOL_ID_SIZE_I_ SOL_ID_SIZE +#else + #define SOL_ID_SIZE_I_ 512 +#endif + +#if defined(LUA_IDSIZE) && LUA_IDSIZE > 0 + #define SOL_FILE_ID_SIZE_I_ LUA_IDSIZE +#elif defined(SOL_ID_SIZE) && SOL_ID_SIZE > 0 + #define SOL_FILE_ID_SIZE_I_ SOL_FILE_ID_SIZE +#else + #define SOL_FILE_ID_SIZE_I_ 2048 +#endif + +#if defined(SOL_PRINT_ERRORS) + #if (SOL_PRINT_ERRORS != 0) + #define SOL_PRINT_ERRORS_I_ SOL_ON + #else + #define SOL_PRINT_ERRORS_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_ALL_SAFETIES_ON) + #define SOL_PRINT_ERRORS_I_ SOL_ON + #elif SOL_IS_ON(SOL_DEBUG_BUILD) + #define SOL_PRINT_ERRORS_I_ SOL_DEFAULT_ON + #else + #define SOL_PRINT_ERRORS_I_ SOL_OFF + #endif +#endif + +#if defined(SOL_DEFAULT_PASS_ON_ERROR) + #if (SOL_DEFAULT_PASS_ON_ERROR != 0) + #define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_ON + #else + #define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_OFF + #endif +#else + #define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_USING_CXX_LUA) + #if (SOL_USING_CXX_LUA != 0) + #define SOL_USING_CXX_LUA_I_ SOL_ON + #else + #define SOL_USING_CXX_LUA_I_ SOL_OFF + #endif +#elif defined(SOL_USE_CXX_LUA) + // alternative spelling + #if (SOL_USE_CXX_LUA != 0) + #define SOL_USING_CXX_LUA_I_ SOL_ON + #else + #define SOL_USING_CXX_LUA_I_ SOL_OFF + #endif +#else + #define SOL_USING_CXX_LUA_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_USING_CXX_LUAJIT) + #if (SOL_USING_CXX_LUAJIT != 0) + #define SOL_USING_CXX_LUAJIT_I_ SOL_ON + #else + #define SOL_USING_CXX_LUAJIT_I_ SOL_OFF + #endif +#elif defined(SOL_USE_CXX_LUAJIT) + #if (SOL_USE_CXX_LUAJIT != 0) + #define SOL_USING_CXX_LUAJIT_I_ SOL_ON + #else + #define SOL_USING_CXX_LUAJIT_I_ SOL_OFF + #endif +#else + #define SOL_USING_CXX_LUAJIT_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_NO_LUA_HPP) + #if (SOL_NO_LUA_HPP != 0) + #define SOL_USE_LUA_HPP_I_ SOL_OFF + #else + #define SOL_USE_LUA_HPP_I_ SOL_ON + #endif +#elif SOL_IS_ON(SOL_USING_CXX_LUA) + #define SOL_USE_LUA_HPP_I_ SOL_OFF +#elif defined(__has_include) + #if __has_include(<lua.hpp>) + #define SOL_USE_LUA_HPP_I_ SOL_ON + #else + #define SOL_USE_LUA_HPP_I_ SOL_OFF + #endif +#else + #define SOL_USE_LUA_HPP_I_ SOL_DEFAULT_ON +#endif + +#if defined(SOL_CONTAINERS_START) + #define SOL_CONTAINER_START_INDEX_I_ SOL_CONTAINERS_START +#elif defined(SOL_CONTAINERS_START_INDEX) + #define SOL_CONTAINER_START_INDEX_I_ SOL_CONTAINERS_START_INDEX +#elif defined(SOL_CONTAINER_START_INDEX) + #define SOL_CONTAINER_START_INDEX_I_ SOL_CONTAINER_START_INDEX +#else + #define SOL_CONTAINER_START_INDEX_I_ 1 +#endif + +#if defined (SOL_NO_MEMORY_ALIGNMENT) + #if (SOL_NO_MEMORY_ALIGNMENT != 0) + #define SOL_ALIGN_MEMORY_I_ SOL_OFF + #else + #define SOL_ALIGN_MEMORY_I_ SOL_ON + #endif +#else + #define SOL_ALIGN_MEMORY_I_ SOL_DEFAULT_ON +#endif + +#if defined(SOL_USE_BOOST) + #if (SOL_USE_BOOST != 0) + #define SOL_USE_BOOST_I_ SOL_ON + #else + #define SOL_USE_BOOST_I_ SOL_OFF + #endif +#else + #define SOL_USE_BOOST_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_USE_UNSAFE_BASE_LOOKUP) + #if (SOL_USE_UNSAFE_BASE_LOOKUP != 0) + #define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_ON + #else + #define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_OFF + #endif +#else + #define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_INSIDE_UNREAL) + #if (SOL_INSIDE_UNREAL != 0) + #define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_ON + #else + #define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_OFF + #endif +#else + #if defined(UE_BUILD_DEBUG) || defined(UE_BUILD_DEVELOPMENT) || defined(UE_BUILD_TEST) || defined(UE_BUILD_SHIPPING) || defined(UE_SERVER) + #define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_DEFAULT_ON + #else + #define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_NO_COMPAT) + #if (SOL_NO_COMPAT != 0) + #define SOL_USE_COMPATIBILITY_LAYER_I_ SOL_OFF + #else + #define SOL_USE_COMPATIBILITY_LAYER_I_ SOL_ON + #endif +#else + #define SOL_USE_COMPATIBILITY_LAYER_I_ SOL_DEFAULT_ON +#endif + +#if defined(SOL_GET_FUNCTION_POINTER_UNSAFE) + #if (SOL_GET_FUNCTION_POINTER_UNSAFE != 0) + #define SOL_GET_FUNCTION_POINTER_UNSAFE_I_ SOL_ON + #else + #define SOL_GET_FUNCTION_POINTER_UNSAFE_I_ SOL_OFF + #endif +#else + #define SOL_GET_FUNCTION_POINTER_UNSAFE_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_CONTAINER_CHECK_IS_EXHAUSTIVE) + #if (SOL_CONTAINER_CHECK_IS_EXHAUSTIVE != 0) + #define SOL_CONTAINER_CHECK_IS_EXHAUSTIVE_I_ SOL_ON + #else + #define SOL_CONTAINER_CHECK_IS_EXHAUSTIVE_I_ SOL_OFF + #endif +#else + #define SOL_CONTAINER_CHECK_IS_EXHAUSTIVE_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_FUNCTION_CALL_VALUE_SEMANTICS) + #if (SOL_FUNCTION_CALL_VALUE_SEMANTICS != 0) + #define SOL_FUNCTION_CALL_VALUE_SEMANTICS_I_ SOL_ON + #else + #define SOL_FUNCTION_CALL_VALUE_SEMANTICS_I_ SOL_OFF + #endif +#else + #define SOL_FUNCTION_CALL_VALUE_SEMANTICS_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_MINGW_CCTYPE_IS_POISONED) + #if (SOL_MINGW_CCTYPE_IS_POISONED != 0) + #define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_ON + #else + #define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_OFF + #endif +#elif SOL_IS_ON(SOL_COMPILER_MINGW) && defined(__GNUC__) && (__GNUC__ < 6) + // MinGW is off its rocker in some places... + #define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_DEFAULT_ON +#else + #define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_CHAR8_T) + #if (SOL_CHAR8_T != 0) + #define SOL_CHAR8_T_I_ SOL_ON + #else + #define SOL_CHAR8_T_I_ SOL_OFF + #endif +#else + #if defined(__cpp_char8_t) + #define SOL_CHAR8_T_I_ SOL_DEFAULT_ON + #else + #define SOL_CHAR8_T_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if SOL_IS_ON(SOL_USE_BOOST) + #include <boost/version.hpp> + + #if BOOST_VERSION >= 107500 // Since Boost 1.75.0 boost::none is constexpr + #define SOL_BOOST_NONE_CONSTEXPR_I_ constexpr + #else + #define SOL_BOOST_NONE_CONSTEXPR_I_ const + #endif // BOOST_VERSION +#else + // assume boost isn't using a garbage version + #define SOL_BOOST_NONE_CONSTEXPR_I_ constexpr +#endif + +#if defined(SOL2_CI) + #if (SOL2_CI != 0) + #define SOL2_CI_I_ SOL_ON + #else + #define SOL2_CI_I_ SOL_OFF + #endif +#else + #define SOL2_CI_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_ASSERT) + #define SOL_USER_ASSERT_I_ SOL_ON +#else + #define SOL_USER_ASSERT_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_ASSERT_MSG) + #define SOL_USER_ASSERT_MSG_I_ SOL_ON +#else + #define SOL_USER_ASSERT_MSG_I_ SOL_DEFAULT_OFF +#endif + +// beginning of sol/prologue.hpp + +#if defined(SOL_PROLOGUE_I_) + #error "[sol2] Library Prologue was already included in translation unit and not properly ended with an epilogue." +#endif + +#define SOL_PROLOGUE_I_ 1 + +#if SOL_IS_ON(SOL_BUILD_CXX_MODE) + #define _FWD(...) static_cast<decltype( __VA_ARGS__ )&&>( __VA_ARGS__ ) + + #if SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) + #define _MOVE(...) static_cast<__typeof( __VA_ARGS__ )&&>( __VA_ARGS__ ) + #else + #include <type_traits> + + #define _MOVE(...) static_cast<::std::remove_reference_t<( __VA_ARGS__ )>&&>( __VA_OPT__(,) ) + #endif +#endif + +// end of sol/prologue.hpp + +// beginning of sol/epilogue.hpp + +#if !defined(SOL_PROLOGUE_I_) + #error "[sol2] Library Prologue is missing from this translation unit." +#else + #undef SOL_PROLOGUE_I_ +#endif + +#if SOL_IS_ON(SOL_BUILD_CXX_MODE) + #undef _FWD + #undef _MOVE +#endif + +// end of sol/epilogue.hpp + +// beginning of sol/detail/build_version.hpp + +#if defined(SOL_DLL) + #if (SOL_DLL != 0) + #define SOL_DLL_I_ SOL_ON + #else + #define SOL_DLL_I_ SOL_OFF + #endif +#elif SOL_IS_ON(SOL_COMPILER_VCXX) && (defined(DLL_) || defined(_DLL)) + #define SOL_DLL_I_ SOL_DEFAULT_ON +#else + #define SOL_DLL_I_ SOL_DEFAULT_OFF +#endif // DLL definition + +#if defined(SOL_HEADER_ONLY) + #if (SOL_HEADER_ONLY != 0) + #define SOL_HEADER_ONLY_I_ SOL_ON + #else + #define SOL_HEADER_ONLY_I_ SOL_OFF + #endif +#else + #define SOL_HEADER_ONLY_I_ SOL_DEFAULT_OFF +#endif // Header only library + +#if defined(SOL_BUILD) + #if (SOL_BUILD != 0) + #define SOL_BUILD_I_ SOL_ON + #else + #define SOL_BUILD_I_ SOL_OFF + #endif +#elif SOL_IS_ON(SOL_HEADER_ONLY) + #define SOL_BUILD_I_ SOL_DEFAULT_OFF +#else + #define SOL_BUILD_I_ SOL_DEFAULT_ON +#endif + +#if defined(SOL_UNITY_BUILD) + #if (SOL_UNITY_BUILD != 0) + #define SOL_UNITY_BUILD_I_ SOL_ON + #else + #define SOL_UNITY_BUILD_I_ SOL_OFF + #endif +#else + #define SOL_UNITY_BUILD_I_ SOL_DEFAULT_OFF +#endif // Header only library + +#if defined(SOL_C_FUNCTION_LINKAGE) + #define SOL_C_FUNCTION_LINKAGE_I_ SOL_C_FUNCTION_LINKAGE +#else + #if SOL_IS_ON(SOL_BUILD_CXX_MODE) + // C++ + #define SOL_C_FUNCTION_LINKAGE_I_ extern "C" + #else + // normal + #define SOL_C_FUNCTION_LINKAGE_I_ + #endif // C++ or not +#endif // Linkage specification for C functions + +#if defined(SOL_API_LINKAGE) + #define SOL_API_LINKAGE_I_ SOL_API_LINKAGE +#else + #if SOL_IS_ON(SOL_DLL) + #if SOL_IS_ON(SOL_COMPILER_VCXX) || SOL_IS_ON(SOL_PLATFORM_WINDOWS) || SOL_IS_ON(SOL_PLATFORM_CYGWIN) + // MSVC Compiler; or, Windows, or Cygwin platforms + #if SOL_IS_ON(SOL_BUILD) + // Building the library + #if SOL_IS_ON(SOL_COMPILER_GCC) + // Using GCC + #define SOL_API_LINKAGE_I_ __attribute__((dllexport)) + #else + // Using Clang, MSVC, etc... + #define SOL_API_LINKAGE_I_ __declspec(dllexport) + #endif + #else + #if SOL_IS_ON(SOL_COMPILER_GCC) + #define SOL_API_LINKAGE_I_ __attribute__((dllimport)) + #else + #define SOL_API_LINKAGE_I_ __declspec(dllimport) + #endif + #endif + #else + // extern if building normally on non-MSVC + #define SOL_API_LINKAGE_I_ extern + #endif + #elif SOL_IS_ON(SOL_UNITY_BUILD) + // Built-in library, like how stb typical works + #if SOL_IS_ON(SOL_HEADER_ONLY) + // Header only, so functions are defined "inline" + #define SOL_API_LINKAGE_I_ inline + #else + // Not header only, so seperately compiled files + #define SOL_API_LINKAGE_I_ extern + #endif + #else + // Normal static library + #if SOL_IS_ON(SOL_BUILD_CXX_MODE) + #define SOL_API_LINKAGE_I_ + #else + #define SOL_API_LINKAGE_I_ extern + #endif + #endif // DLL or not +#endif // Build definitions + +#if defined(SOL_PUBLIC_FUNC_DECL) + #define SOL_PUBLIC_FUNC_DECL_I_ SOL_PUBLIC_FUNC_DECL +#else + #define SOL_PUBLIC_FUNC_DECL_I_ SOL_API_LINKAGE_I_ +#endif + +#if defined(SOL_INTERNAL_FUNC_DECL_) + #define SOL_INTERNAL_FUNC_DECL_I_ SOL_INTERNAL_FUNC_DECL_ +#else + #define SOL_INTERNAL_FUNC_DECL_I_ SOL_API_LINKAGE_I_ +#endif + +#if defined(SOL_PUBLIC_FUNC_DEF) + #define SOL_PUBLIC_FUNC_DEF_I_ SOL_PUBLIC_FUNC_DEF +#else + #define SOL_PUBLIC_FUNC_DEF_I_ SOL_API_LINKAGE_I_ +#endif + +#if defined(SOL_INTERNAL_FUNC_DEF) + #define SOL_INTERNAL_FUNC_DEF_I_ SOL_INTERNAL_FUNC_DEF +#else + #define SOL_INTERNAL_FUNC_DEF_I_ SOL_API_LINKAGE_I_ +#endif + +#if defined(SOL_FUNC_DECL) + #define SOL_FUNC_DECL_I_ SOL_FUNC_DECL +#elif SOL_IS_ON(SOL_HEADER_ONLY) + #define SOL_FUNC_DECL_I_ +#elif SOL_IS_ON(SOL_DLL) + #if SOL_IS_ON(SOL_COMPILER_VCXX) + #if SOL_IS_ON(SOL_BUILD) + #define SOL_FUNC_DECL_I_ extern __declspec(dllexport) + #else + #define SOL_FUNC_DECL_I_ extern __declspec(dllimport) + #endif + #elif SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) + #define SOL_FUNC_DECL_I_ extern __attribute__((visibility("default"))) + #else + #define SOL_FUNC_DECL_I_ extern + #endif +#endif + +#if defined(SOL_FUNC_DEFN) + #define SOL_FUNC_DEFN_I_ SOL_FUNC_DEFN +#elif SOL_IS_ON(SOL_HEADER_ONLY) + #define SOL_FUNC_DEFN_I_ inline +#elif SOL_IS_ON(SOL_DLL) + #if SOL_IS_ON(SOL_COMPILER_VCXX) + #if SOL_IS_ON(SOL_BUILD) + #define SOL_FUNC_DEFN_I_ __declspec(dllexport) + #else + #define SOL_FUNC_DEFN_I_ __declspec(dllimport) + #endif + #elif SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) + #define SOL_FUNC_DEFN_I_ __attribute__((visibility("default"))) + #else + #define SOL_FUNC_DEFN_I_ + #endif +#endif + +#if defined(SOL_HIDDEN_FUNC_DECL) + #define SOL_HIDDEN_FUNC_DECL_I_ SOL_HIDDEN_FUNC_DECL +#elif SOL_IS_ON(SOL_HEADER_ONLY) + #define SOL_HIDDEN_FUNC_DECL_I_ +#elif SOL_IS_ON(SOL_DLL) + #if SOL_IS_ON(SOL_COMPILER_VCXX) + #if SOL_IS_ON(SOL_BUILD) + #define SOL_HIDDEN_FUNC_DECL_I_ extern __declspec(dllexport) + #else + #define SOL_HIDDEN_FUNC_DECL_I_ extern __declspec(dllimport) + #endif + #elif SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) + #define SOL_HIDDEN_FUNC_DECL_I_ extern __attribute__((visibility("default"))) + #else + #define SOL_HIDDEN_FUNC_DECL_I_ extern + #endif +#endif + +#if defined(SOL_HIDDEN_FUNC_DEFN) + #define SOL_HIDDEN_FUNC_DEFN_I_ SOL_HIDDEN_FUNC_DEFN +#elif SOL_IS_ON(SOL_HEADER_ONLY) + #define SOL_HIDDEN_FUNC_DEFN_I_ inline +#elif SOL_IS_ON(SOL_DLL) + #if SOL_IS_ON(SOL_COMPILER_VCXX) + #if SOL_IS_ON(SOL_BUILD) + #define SOL_HIDDEN_FUNC_DEFN_I_ + #else + #define SOL_HIDDEN_FUNC_DEFN_I_ + #endif + #elif SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) + #define SOL_HIDDEN_FUNC_DEFN_I_ __attribute__((visibility("hidden"))) + #else + #define SOL_HIDDEN_FUNC_DEFN_I_ + #endif +#endif + +// end of sol/detail/build_version.hpp + +// end of sol/version.hpp + +#if SOL_IS_ON(SOL_INSIDE_UNREAL_ENGINE) +#ifdef check +#pragma push_macro("check") +#undef check +#endif +#endif // Unreal Engine 4 Bullshit + +#if SOL_IS_ON(SOL_COMPILER_GCC) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wconversion" +#if __GNUC__ > 6 +#pragma GCC diagnostic ignored "-Wnoexcept-type" +#endif +#elif SOL_IS_ON(SOL_COMPILER_CLANG) +#elif SOL_IS_ON(SOL_COMPILER_VCXX) +#pragma warning(push) +#pragma warning(disable : 4505) // unreferenced local function has been removed GEE THANKS +#endif // clang++ vs. g++ vs. VC++ + +// beginning of sol/forward.hpp + +#ifndef SOL_FORWARD_HPP +#define SOL_FORWARD_HPP + +#include <utility> +#include <type_traits> +#include <string_view> + +#if SOL_IS_ON(SOL_USING_CXX_LUA) || SOL_IS_ON(SOL_USING_CXX_LUAJIT) +struct lua_State; +#else +extern "C" { +struct lua_State; +} +#endif // C++ Mangling for Lua vs. Not + +namespace sol { + + enum class type; + + class stateless_reference; + template <bool b> + class basic_reference; + using reference = basic_reference<false>; + using main_reference = basic_reference<true>; + class stateless_stack_reference; + class stack_reference; + + template <typename A> + class basic_bytecode; + + struct lua_value; + + struct proxy_base_tag; + template <typename> + struct proxy_base; + template <typename, typename> + struct table_proxy; + + template <bool, typename> + class basic_table_core; + template <bool b> + using table_core = basic_table_core<b, reference>; + template <bool b> + using main_table_core = basic_table_core<b, main_reference>; + template <bool b> + using stack_table_core = basic_table_core<b, stack_reference>; + template <typename base_type> + using basic_table = basic_table_core<false, base_type>; + using table = table_core<false>; + using global_table = table_core<true>; + using main_table = main_table_core<false>; + using main_global_table = main_table_core<true>; + using stack_table = stack_table_core<false>; + using stack_global_table = stack_table_core<true>; + + template <typename> + struct basic_lua_table; + using lua_table = basic_lua_table<reference>; + using stack_lua_table = basic_lua_table<stack_reference>; + + template <typename T, typename base_type> + class basic_usertype; + template <typename T> + using usertype = basic_usertype<T, reference>; + template <typename T> + using stack_usertype = basic_usertype<T, stack_reference>; + + template <typename base_type> + class basic_metatable; + using metatable = basic_metatable<reference>; + using stack_metatable = basic_metatable<stack_reference>; + + template <typename base_t> + struct basic_environment; + using environment = basic_environment<reference>; + using main_environment = basic_environment<main_reference>; + using stack_environment = basic_environment<stack_reference>; + + template <typename T, bool> + class basic_function; + template <typename T, bool, typename H> + class basic_protected_function; + using unsafe_function = basic_function<reference, false>; + using safe_function = basic_protected_function<reference, false, reference>; + using main_unsafe_function = basic_function<main_reference, false>; + using main_safe_function = basic_protected_function<main_reference, false, reference>; + using stack_unsafe_function = basic_function<stack_reference, false>; + using stack_safe_function = basic_protected_function<stack_reference, false, reference>; + using stack_aligned_unsafe_function = basic_function<stack_reference, true>; + using stack_aligned_safe_function = basic_protected_function<stack_reference, true, reference>; + using protected_function = safe_function; + using main_protected_function = main_safe_function; + using stack_protected_function = stack_safe_function; + using stack_aligned_protected_function = stack_aligned_safe_function; +#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS) + using function = protected_function; + using main_function = main_protected_function; + using stack_function = stack_protected_function; + using stack_aligned_function = stack_aligned_safe_function; +#else + using function = unsafe_function; + using main_function = main_unsafe_function; + using stack_function = stack_unsafe_function; + using stack_aligned_function = stack_aligned_unsafe_function; +#endif + using stack_aligned_stack_handler_function = basic_protected_function<stack_reference, true, stack_reference>; + + struct unsafe_function_result; + struct protected_function_result; + using safe_function_result = protected_function_result; +#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS) + using function_result = safe_function_result; +#else + using function_result = unsafe_function_result; +#endif + + template <typename base_t> + class basic_object_base; + template <typename base_t> + class basic_object; + template <typename base_t> + class basic_userdata; + template <typename base_t> + class basic_lightuserdata; + template <typename base_t> + class basic_coroutine; + template <typename base_t> + class basic_packaged_coroutine; + template <typename base_t> + class basic_thread; + + using object = basic_object<reference>; + using userdata = basic_userdata<reference>; + using lightuserdata = basic_lightuserdata<reference>; + using thread = basic_thread<reference>; + using coroutine = basic_coroutine<reference>; + using packaged_coroutine = basic_packaged_coroutine<reference>; + using main_object = basic_object<main_reference>; + using main_userdata = basic_userdata<main_reference>; + using main_lightuserdata = basic_lightuserdata<main_reference>; + using main_coroutine = basic_coroutine<main_reference>; + using stack_object = basic_object<stack_reference>; + using stack_userdata = basic_userdata<stack_reference>; + using stack_lightuserdata = basic_lightuserdata<stack_reference>; + using stack_thread = basic_thread<stack_reference>; + using stack_coroutine = basic_coroutine<stack_reference>; + + struct stack_proxy_base; + struct stack_proxy; + struct variadic_args; + struct variadic_results; + struct stack_count; + struct this_state; + struct this_main_state; + struct this_environment; + + class state_view; + class state; + + template <typename T> + struct as_table_t; + template <typename T> + struct as_container_t; + template <typename T> + struct nested; + template <typename T> + struct light; + template <typename T> + struct user; + template <typename T> + struct as_args_t; + template <typename T> + struct protect_t; + template <typename F, typename... Policies> + struct policy_wrapper; + + template <typename T> + struct usertype_traits; + template <typename T> + struct unique_usertype_traits; + + template <typename... Args> + struct types { + typedef std::make_index_sequence<sizeof...(Args)> indices; + static constexpr std::size_t size() { + return sizeof...(Args); + } + }; + + template <typename T> + struct derive : std::false_type { + typedef types<> type; + }; + + template <typename T> + struct base : std::false_type { + typedef types<> type; + }; + + template <typename T> + struct weak_derive { + static bool value; + }; + + template <typename T> + bool weak_derive<T>::value = false; + + namespace stack { + struct record; + } + +#if SOL_IS_OFF(SOL_USE_BOOST) + template <class T> + class optional; + + template <class T> + class optional<T&>; +#endif + + using check_handler_type = int(lua_State*, int, type, type, const char*); + +} // namespace sol + +#define SOL_BASE_CLASSES(T, ...) \ + namespace sol { \ + template <> \ + struct base<T> : std::true_type { \ + typedef ::sol::types<__VA_ARGS__> type; \ + }; \ + } \ + static_assert(true, "") +#define SOL_DERIVED_CLASSES(T, ...) \ + namespace sol { \ + template <> \ + struct derive<T> : std::true_type { \ + typedef ::sol::types<__VA_ARGS__> type; \ + }; \ + } \ + static_assert(true, "") + +#endif // SOL_FORWARD_HPP +// end of sol/forward.hpp + +// beginning of sol/forward_detail.hpp + +#ifndef SOL_FORWARD_DETAIL_HPP +#define SOL_FORWARD_DETAIL_HPP + +// beginning of sol/traits.hpp + +// beginning of sol/tuple.hpp + +// beginning of sol/base_traits.hpp + +#include <type_traits> + +namespace sol { + namespace detail { + struct unchecked_t { }; + const unchecked_t unchecked = unchecked_t {}; + } // namespace detail + + namespace meta { + using sfinae_yes_t = std::true_type; + using sfinae_no_t = std::false_type; + + template <typename...> + using void_t = void; + + template <typename T> + using unqualified = std::remove_cv<std::remove_reference_t<T>>; + + template <typename T> + using unqualified_t = typename unqualified<T>::type; + + namespace meta_detail { + template <typename T> + struct unqualified_non_alias : unqualified<T> { }; + + template <template <class...> class Test, class, class... Args> + struct is_detected : std::false_type { }; + + template <template <class...> class Test, class... Args> + struct is_detected<Test, void_t<Test<Args...>>, Args...> : std::true_type { }; + } // namespace meta_detail + + template <template <class...> class Trait, class... Args> + using is_detected = typename meta_detail::is_detected<Trait, void, Args...>::type; + + template <template <class...> class Trait, class... Args> + constexpr inline bool is_detected_v = is_detected<Trait, Args...>::value; + + template <typename _Default, typename _Void, template <typename...> typename _Op, typename... _Args> + class detector { + public: + using value_t = ::std::false_type; + using type = _Default; + }; + + template <typename _Default, template <typename...> typename _Op, typename... _Args> + class detector<_Default, void_t<_Op<_Args...>>, _Op, _Args...> { + public: + using value_t = ::std::true_type; + using type = _Op<_Args...>; + }; + + class nonesuch { + public: + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch& operator=(nonesuch const&) = delete; + }; + + template <template <typename...> typename _Op, typename... _Args> + using detected_t = typename detector<nonesuch, void, _Op, _Args...>::type; + + template <typename _Default, template <typename...> typename _Op, typename... _Args> + using detected_or = detector<_Default, void, _Op, _Args...>; + + template <typename _Default, template <typename...> typename _Op, typename... _Args> + using detected_or_t = typename detector<_Default, void, _Op, _Args...>::type; + + template <typename _Default, template <typename...> typename _Op, typename... _Args> + constexpr inline bool detected_or_v = detector<_Default, void, _Op, _Args...>::value; + + template <std::size_t I> + using index_value = std::integral_constant<std::size_t, I>; + + template <bool> + struct conditional { + template <typename T, typename U> + using type = T; + }; + + template <> + struct conditional<false> { + template <typename T, typename U> + using type = U; + }; + + template <bool B, typename T, typename U> + using conditional_t = typename conditional<B>::template type<T, U>; + + namespace meta_detail { + template <typename T, template <typename...> class Templ> + struct is_specialization_of : std::false_type { }; + template <typename... T, template <typename...> class Templ> + struct is_specialization_of<Templ<T...>, Templ> : std::true_type { }; + } // namespace meta_detail + + template <typename T, template <typename...> class Templ> + using is_specialization_of = meta_detail::is_specialization_of<std::remove_cv_t<T>, Templ>; + + template <typename T, template <typename...> class Templ> + inline constexpr bool is_specialization_of_v = is_specialization_of<std::remove_cv_t<T>, Templ>::value; + + template <typename T> + struct identity { + typedef T type; + }; + + template <typename T> + using identity_t = typename identity<T>::type; + + template <typename T> + using is_builtin_type = std::integral_constant<bool, std::is_arithmetic<T>::value || std::is_pointer<T>::value || std::is_array<T>::value>; + + namespace meta_detail { + template <typename T, typename = void> + struct has_internal_marker_impl : std::false_type { }; + template <typename T> + struct has_internal_marker_impl<T, void_t<typename T::SOL_INTERNAL_UNSPECIALIZED_MARKER_>> : std::true_type { }; + + template <typename T> + using has_internal_marker = has_internal_marker_impl<T>; + + template <typename T> + constexpr inline bool has_internal_marker_v = has_internal_marker<T>::value; + } // namespace meta_detail + + } // namespace meta +} // namespace sol + +// end of sol/base_traits.hpp + +#include <tuple> +#include <cstddef> + +namespace sol { + namespace detail { + using swallow = std::initializer_list<int>; + } // namespace detail + + namespace meta { + template <typename T> + using is_tuple = is_specialization_of<T, std::tuple>; + + template <typename T> + constexpr inline bool is_tuple_v = is_tuple<T>::value; + + namespace detail { + template <typename... Args> + struct tuple_types_ { + typedef types<Args...> type; + }; + + template <typename... Args> + struct tuple_types_<std::tuple<Args...>> { + typedef types<Args...> type; + }; + } // namespace detail + + template <typename... Args> + using tuple_types = typename detail::tuple_types_<Args...>::type; + + template <typename Arg> + struct pop_front_type; + + template <typename Arg> + using pop_front_type_t = typename pop_front_type<Arg>::type; + + template <typename... Args> + struct pop_front_type<types<Args...>> { + typedef void front_type; + typedef types<Args...> type; + }; + + template <typename Arg, typename... Args> + struct pop_front_type<types<Arg, Args...>> { + typedef Arg front_type; + typedef types<Args...> type; + }; + + template <std::size_t N, typename Tuple> + using tuple_element = std::tuple_element<N, std::remove_reference_t<Tuple>>; + + template <std::size_t N, typename Tuple> + using tuple_element_t = std::tuple_element_t<N, std::remove_reference_t<Tuple>>; + + template <std::size_t N, typename Tuple> + using unqualified_tuple_element = unqualified<tuple_element_t<N, Tuple>>; + + template <std::size_t N, typename Tuple> + using unqualified_tuple_element_t = unqualified_t<tuple_element_t<N, Tuple>>; + + } // namespace meta +} // namespace sol + +// end of sol/tuple.hpp + +// beginning of sol/bind_traits.hpp + +namespace sol { namespace meta { + namespace meta_detail { + template <typename F> + using detect_deducible_signature = decltype(&F::operator()); + } // namespace meta_detail + + template <typename F> + using call_operator_deducible = typename is_detected<meta_detail::detect_deducible_signature, F>::type; + + template <typename F> + constexpr inline bool call_operator_deducible_v = call_operator_deducible<F>::value; + + namespace meta_detail { + + template <std::size_t I, typename T> + struct void_tuple_element : meta::tuple_element<I, T> { }; + + template <std::size_t I> + struct void_tuple_element<I, std::tuple<>> { + typedef void type; + }; + + template <std::size_t I, typename T> + using void_tuple_element_t = typename void_tuple_element<I, T>::type; + + template <bool it_is_noexcept, bool has_c_variadic, typename T, typename R, typename... Args> + struct basic_traits { + private: + using first_type = meta::conditional_t<std::is_void<T>::value, int, T>&; + + public: + inline static constexpr const bool is_noexcept = it_is_noexcept; + inline static constexpr bool is_member_function = std::is_void<T>::value; + inline static constexpr bool has_c_var_arg = has_c_variadic; + inline static constexpr std::size_t arity = sizeof...(Args); + inline static constexpr std::size_t free_arity = sizeof...(Args) + static_cast<std::size_t>(!std::is_void<T>::value); + typedef types<Args...> args_list; + typedef std::tuple<Args...> args_tuple; + typedef T object_type; + typedef R return_type; + typedef tuple_types<R> returns_list; + typedef R(function_type)(Args...); + typedef meta::conditional_t<std::is_void<T>::value, args_list, types<first_type, Args...>> free_args_list; + typedef meta::conditional_t<std::is_void<T>::value, R(Args...), R(first_type, Args...)> free_function_type; + typedef meta::conditional_t<std::is_void<T>::value, R (*)(Args...), R (*)(first_type, Args...)> free_function_pointer_type; + typedef std::remove_pointer_t<free_function_pointer_type> signature_type; + template <std::size_t i> + using arg_at = void_tuple_element_t<i, args_tuple>; + }; + + template <typename Signature, bool b = call_operator_deducible<Signature>::value> + struct fx_traits : public basic_traits<false, false, void, void> { }; + + // Free Functions + template <typename R, typename... Args> + struct fx_traits<R(Args...), false> : public basic_traits<false, false, void, R, Args...> { + typedef R (*function_pointer_type)(Args...); + }; + + template <typename R, typename... Args> + struct fx_traits<R (*)(Args...), false> : public basic_traits<false, false, void, R, Args...> { + typedef R (*function_pointer_type)(Args...); + }; + + template <typename R, typename... Args> + struct fx_traits<R(Args..., ...), false> : public basic_traits<false, true, void, R, Args...> { + typedef R (*function_pointer_type)(Args..., ...); + }; + + template <typename R, typename... Args> + struct fx_traits<R (*)(Args..., ...), false> : public basic_traits<false, true, void, R, Args...> { + typedef R (*function_pointer_type)(Args..., ...); + }; + + // Member Functions + /* C-Style Variadics */ + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...), false> : public basic_traits<false, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...); + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...), false> : public basic_traits<false, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...); + }; + + /* Const Volatile */ + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...) const, false> : public basic_traits<false, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) const; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...) const, false> : public basic_traits<false, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) const; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...) const volatile, false> : public basic_traits<false, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) const volatile; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...) const volatile, false> : public basic_traits<false, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) const volatile; + }; + + /* Member Function Qualifiers */ + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...)&, false> : public basic_traits<false, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) &; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...)&, false> : public basic_traits<false, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) &; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...) const&, false> : public basic_traits<false, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) const&; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...) const&, false> : public basic_traits<false, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) const&; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...) const volatile&, false> : public basic_traits<false, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) const volatile&; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...) const volatile&, false> : public basic_traits<false, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) const volatile&; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...)&&, false> : public basic_traits<false, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) &&; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...)&&, false> : public basic_traits<false, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) &&; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...) const&&, false> : public basic_traits<false, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) const&&; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...) const&&, false> : public basic_traits<false, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) const&&; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...) const volatile&&, false> : public basic_traits<false, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) const volatile&&; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...) const volatile&&, false> : public basic_traits<false, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) const volatile&&; + }; + +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) + + template <typename R, typename... Args> + struct fx_traits<R(Args...) noexcept, false> : public basic_traits<true, false, void, R, Args...> { + typedef R (*function_pointer_type)(Args...) noexcept; + }; + + template <typename R, typename... Args> + struct fx_traits<R (*)(Args...) noexcept, false> : public basic_traits<true, false, void, R, Args...> { + typedef R (*function_pointer_type)(Args...) noexcept; + }; + + template <typename R, typename... Args> + struct fx_traits<R(Args..., ...) noexcept, false> : public basic_traits<true, true, void, R, Args...> { + typedef R (*function_pointer_type)(Args..., ...) noexcept; + }; + + template <typename R, typename... Args> + struct fx_traits<R (*)(Args..., ...) noexcept, false> : public basic_traits<true, true, void, R, Args...> { + typedef R (*function_pointer_type)(Args..., ...) noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...) noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...) noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) noexcept; + }; + + /* Const Volatile */ + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...) const noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) const noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...) const noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) const noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...) const volatile noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) const volatile noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...) const volatile noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) const volatile noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...)& noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) & noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...)& noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) & noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...) const& noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) const& noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...) const& noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) const& noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...) const volatile& noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) const volatile& noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...) const volatile& noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) const volatile& noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...)&& noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) && noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...)&& noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) && noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...) const&& noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) const&& noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...) const&& noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) const&& noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args...) const volatile&& noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args...) const volatile&& noexcept; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (T::*)(Args..., ...) const volatile&& noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (T::*function_pointer_type)(Args..., ...) const volatile&& noexcept; + }; + +#endif // noexcept is part of a function's type + +#if SOL_IS_ON(SOL_COMPILER_VCXX) && SOL_IS_ON(SOL_PLATFORM_X86) + template <typename R, typename... Args> + struct fx_traits<R __stdcall(Args...), false> : public basic_traits<false, false, void, R, Args...> { + typedef R(__stdcall* function_pointer_type)(Args...); + }; + + template <typename R, typename... Args> + struct fx_traits<R(__stdcall*)(Args...), false> : public basic_traits<false, false, void, R, Args...> { + typedef R(__stdcall* function_pointer_type)(Args...); + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...), false> : public basic_traits<false, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...); + }; + + /* Const Volatile */ + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...) const, false> : public basic_traits<false, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) const; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...) const volatile, false> : public basic_traits<false, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile; + }; + + /* Member Function Qualifiers */ + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...)&, false> : public basic_traits<false, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) &; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...) const&, false> : public basic_traits<false, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) const&; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...) const volatile&, false> : public basic_traits<false, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile&; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...)&&, false> : public basic_traits<false, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) &&; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...) const&&, false> : public basic_traits<false, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) const&&; + }; + + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...) const volatile&&, false> : public basic_traits<false, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile&&; + }; + +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) + + template <typename R, typename... Args> + struct fx_traits<R __stdcall(Args...) noexcept, false> : public basic_traits<true, false, void, R, Args...> { + typedef R(__stdcall* function_pointer_type)(Args...) noexcept; + }; + + template <typename R, typename... Args> + struct fx_traits<R(__stdcall*)(Args...) noexcept, false> : public basic_traits<true, false, void, R, Args...> { + typedef R(__stdcall* function_pointer_type)(Args...) noexcept; + }; + + /* __stdcall cannot be applied to functions with varargs*/ + /*template <typename R, typename... Args> + struct fx_traits<__stdcall R(Args..., ...) noexcept, false> : public basic_traits<true, true, void, R, Args...> { + typedef R(__stdcall* function_pointer_type)(Args..., ...) noexcept; + }; + + template <typename R, typename... Args> + struct fx_traits<R (__stdcall *)(Args..., ...) noexcept, false> : public basic_traits<true, true, void, R, Args...> { + typedef R(__stdcall* function_pointer_type)(Args..., ...) noexcept; + };*/ + + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...) noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args..., ...) noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) noexcept; + };*/ + + /* Const Volatile */ + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...) const noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) const noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args..., ...) const noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const noexcept; + };*/ + + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...) const volatile noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args..., ...) const volatile noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile noexcept; + };*/ + + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...)& noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) & noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args..., ...) & noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) & noexcept; + };*/ + + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...) const& noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) const& noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args..., ...) const& noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const& noexcept; + };*/ + + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...) const volatile& noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile& noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args..., ...) const volatile& noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile& noexcept; + };*/ + + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...)&& noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) && noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args..., ...) && noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) && noexcept; + };*/ + + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...) const&& noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) const&& noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args..., ...) const&& noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const&& noexcept; + };*/ + + template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args...) const volatile&& noexcept, false> : public basic_traits<true, false, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile&& noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template <typename T, typename R, typename... Args> + struct fx_traits<R (__stdcall T::*)(Args..., ...) const volatile&& noexcept, false> : public basic_traits<true, true, T, R, Args...> { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile&& noexcept; + };*/ +#endif // noexcept is part of a function's type +#endif // __stdcall x86 VC++ bug + + template <typename Signature> + struct fx_traits<Signature, true> : public fx_traits<typename fx_traits<decltype(&Signature::operator())>::function_type, false> { }; + + template <typename Signature, bool b = std::is_member_object_pointer<Signature>::value> + struct callable_traits : public fx_traits<std::decay_t<Signature>> { }; + + template <typename R, typename T> + struct callable_traits<R(T::*), true> { + typedef meta::conditional_t<std::is_array_v<R>, std::add_lvalue_reference_t<R>, R> return_type; + typedef return_type Arg; + typedef T object_type; + using signature_type = R(T::*); + inline static constexpr bool is_noexcept = false; + inline static constexpr bool is_member_function = false; + inline static constexpr std::size_t arity = 1; + inline static constexpr std::size_t free_arity = 2; + typedef std::tuple<Arg> args_tuple; + typedef types<Arg> args_list; + typedef types<T, Arg> free_args_list; + typedef meta::tuple_types<return_type> returns_list; + typedef return_type(function_type)(T&, return_type); + typedef return_type (*function_pointer_type)(T&, Arg); + typedef return_type (*free_function_pointer_type)(T&, Arg); + template <std::size_t i> + using arg_at = void_tuple_element_t<i, args_tuple>; + }; + + } // namespace meta_detail + + template <typename Signature> + using bind_traits = meta_detail::callable_traits<Signature>; + + namespace meta_detail { + template <typename, bool> + struct is_probably_stateless_lambda : std::false_type { }; + + template <typename T> + struct is_probably_stateless_lambda<T, true> : std::is_convertible<T, typename bind_traits<T>::function_type*>::type { }; + } // namespace meta_detail + + template <typename T> + using is_probably_stateless_lambda = typename meta_detail::is_probably_stateless_lambda<T, std::is_empty_v<T> && call_operator_deducible_v<T>>::type; + + template <typename T> + inline constexpr bool is_probably_stateless_lambda_v = is_probably_stateless_lambda<T>::value; + + template <typename Signature> + using function_args_t = typename bind_traits<Signature>::args_list; + + template <typename Signature> + using function_signature_t = typename bind_traits<Signature>::signature_type; + + template <typename Signature> + using function_return_t = typename bind_traits<Signature>::return_type; +}} // namespace sol::meta + +// end of sol/bind_traits.hpp + +// beginning of sol/pointer_like.hpp + +#include <utility> +#include <type_traits> +#include <memory> + +namespace sol { + + namespace meta { + namespace meta_detail { + template <typename T> + using is_dereferenceable_test = decltype(*std::declval<T>()); + + template <typename T> + using is_explicitly_dereferenceable_test = decltype(std::declval<T>().operator*()); + } // namespace meta_detail + + template <typename T> + using is_pointer_like = std::integral_constant<bool, + !std::is_array_v<T> && (std::is_pointer_v<T> || is_detected_v<meta_detail::is_explicitly_dereferenceable_test, T>)>; + + template <typename T> + constexpr inline bool is_pointer_like_v = is_pointer_like<T>::value; + } // namespace meta + + namespace detail { + + template <typename T> + auto unwrap(T&& item) -> decltype(std::forward<T>(item)) { + return std::forward<T>(item); + } + + template <typename T> + T& unwrap(std::reference_wrapper<T> arg) { + return arg.get(); + } + + template <typename T> + inline decltype(auto) deref(T&& item) { + using Tu = meta::unqualified_t<T>; + if constexpr (meta::is_pointer_like_v<Tu>) { + return *std::forward<T>(item); + } + else { + return std::forward<T>(item); + } + } + + template <typename T> + inline decltype(auto) deref_move_only(T&& item) { + using Tu = meta::unqualified_t<T>; + if constexpr (meta::is_pointer_like_v<Tu> && !std::is_pointer_v<Tu> && !std::is_copy_constructible_v<Tu>) { + return *std::forward<T>(item); + } + else { + return std::forward<T>(item); + } + } + + template <typename T> + inline T* ptr(T& val) { + return std::addressof(val); + } + + template <typename T> + inline T* ptr(std::reference_wrapper<T> val) { + return std::addressof(val.get()); + } + + template <typename T> + inline T* ptr(T* val) { + return val; + } + } // namespace detail +} // namespace sol + +// end of sol/pointer_like.hpp + +// beginning of sol/string_view.hpp + +#include <cstddef> +#include <string> +#include <string_view> +#include <functional> + +namespace sol { + template <typename C, typename T = std::char_traits<C>> + using basic_string_view = std::basic_string_view<C, T>; + + typedef std::string_view string_view; + typedef std::wstring_view wstring_view; + typedef std::u16string_view u16string_view; + typedef std::u32string_view u32string_view; + typedef std::hash<std::string_view> string_view_hash; +} // namespace sol + +// end of sol/string_view.hpp + +#include <type_traits> +#include <cstdint> +#include <memory> +#include <functional> +#include <array> +#include <iterator> +#include <iosfwd> +#if SOL_IS_ON(SOL_STD_VARIANT) +#include <variant> +#endif // variant is weird on XCode, thanks XCode + +namespace sol { namespace meta { + template <typename T> + struct unwrapped { + typedef T type; + }; + + template <typename T> + struct unwrapped<std::reference_wrapper<T>> { + typedef T type; + }; + + template <typename T> + using unwrapped_t = typename unwrapped<T>::type; + + template <typename T> + struct unwrap_unqualified : unwrapped<unqualified_t<T>> { }; + + template <typename T> + using unwrap_unqualified_t = typename unwrap_unqualified<T>::type; + + template <typename T> + struct remove_member_pointer; + + template <typename R, typename T> + struct remove_member_pointer<R T::*> { + typedef R type; + }; + + template <typename R, typename T> + struct remove_member_pointer<R T::*const> { + typedef R type; + }; + + template <typename T> + using remove_member_pointer_t = remove_member_pointer<T>; + + template <typename T, typename...> + struct all_same : std::true_type { }; + + template <typename T, typename U, typename... Args> + struct all_same<T, U, Args...> : std::integral_constant<bool, std::is_same<T, U>::value && all_same<T, Args...>::value> { }; + + template <typename T, typename...> + struct any_same : std::false_type { }; + + template <typename T, typename U, typename... Args> + struct any_same<T, U, Args...> : std::integral_constant<bool, std::is_same<T, U>::value || any_same<T, Args...>::value> { }; + + template <typename T, typename... Args> + constexpr inline bool any_same_v = any_same<T, Args...>::value; + + template <bool B> + using boolean = std::integral_constant<bool, B>; + + template <bool B> + constexpr inline bool boolean_v = boolean<B>::value; + + template <typename T> + using neg = boolean<!T::value>; + + template <typename T> + constexpr inline bool neg_v = neg<T>::value; + + template <typename... Args> + struct all : boolean<true> { }; + + template <typename T, typename... Args> + struct all<T, Args...> : std::conditional_t<T::value, all<Args...>, boolean<false>> { }; + + template <typename... Args> + struct any : boolean<false> { }; + + template <typename T, typename... Args> + struct any<T, Args...> : std::conditional_t<T::value, boolean<true>, any<Args...>> { }; + + template <typename... Args> + constexpr inline bool all_v = all<Args...>::value; + + template <typename... Args> + constexpr inline bool any_v = any<Args...>::value; + + enum class enable_t { _ }; + + constexpr const auto enabler = enable_t::_; + + template <bool value, typename T = void> + using disable_if_t = std::enable_if_t<!value, T>; + + template <typename... Args> + using enable = std::enable_if_t<all<Args...>::value, enable_t>; + + template <typename... Args> + using disable = std::enable_if_t<neg<all<Args...>>::value, enable_t>; + + template <typename... Args> + using enable_any = std::enable_if_t<any<Args...>::value, enable_t>; + + template <typename... Args> + using disable_any = std::enable_if_t<neg<any<Args...>>::value, enable_t>; + + template <typename V, typename... Vs> + struct find_in_pack_v : boolean<false> { }; + + template <typename V, typename Vs1, typename... Vs> + struct find_in_pack_v<V, Vs1, Vs...> : any<boolean<(V::value == Vs1::value)>, find_in_pack_v<V, Vs...>> { }; + + namespace meta_detail { + template <std::size_t I, typename T, typename... Args> + struct index_in_pack : std::integral_constant<std::size_t, SIZE_MAX> { }; + + template <std::size_t I, typename T, typename T1, typename... Args> + struct index_in_pack<I, T, T1, Args...> + : conditional_t<std::is_same<T, T1>::value, std::integral_constant<std::ptrdiff_t, I>, index_in_pack<I + 1, T, Args...>> { }; + } // namespace meta_detail + + template <typename T, typename... Args> + struct index_in_pack : meta_detail::index_in_pack<0, T, Args...> { }; + + template <typename T, typename List> + struct index_in : meta_detail::index_in_pack<0, T, List> { }; + + template <typename T, typename... Args> + struct index_in<T, types<Args...>> : meta_detail::index_in_pack<0, T, Args...> { }; + + template <std::size_t I, typename... Args> + struct at_in_pack { }; + + template <std::size_t I, typename... Args> + using at_in_pack_t = typename at_in_pack<I, Args...>::type; + + template <std::size_t I, typename Arg, typename... Args> + struct at_in_pack<I, Arg, Args...> : std::conditional<I == 0, Arg, at_in_pack_t<I - 1, Args...>> { }; + + template <typename Arg, typename... Args> + struct at_in_pack<0, Arg, Args...> { + typedef Arg type; + }; + + namespace meta_detail { + template <typename, typename TI> + using on_even = meta::boolean<(TI::value % 2) == 0>; + + template <typename, typename TI> + using on_odd = meta::boolean<(TI::value % 2) == 1>; + + template <typename, typename> + using on_always = std::true_type; + + template <template <typename...> class When, std::size_t Limit, std::size_t I, template <typename...> class Pred, typename... Ts> + struct count_when_for_pack : std::integral_constant<std::size_t, 0> { }; + template <template <typename...> class When, std::size_t Limit, std::size_t I, template <typename...> class Pred, typename T, typename... Ts> + struct count_when_for_pack<When, Limit, I, Pred, T, Ts...> : conditional_t < sizeof...(Ts) + == 0 + || Limit<2, std::integral_constant<std::size_t, I + static_cast<std::size_t>(Limit != 0 && Pred<T>::value)>, + count_when_for_pack<When, Limit - static_cast<std::size_t>(When<T, std::integral_constant<std::size_t, I>>::value), + I + static_cast<std::size_t>(When<T, std::integral_constant<std::size_t, I>>::value&& Pred<T>::value), Pred, Ts...>> { }; + } // namespace meta_detail + + template <template <typename...> class Pred, typename... Ts> + struct count_for_pack : meta_detail::count_when_for_pack<meta_detail::on_always, sizeof...(Ts), 0, Pred, Ts...> { }; + + template <template <typename...> class Pred, typename... Ts> + inline constexpr std::size_t count_for_pack_v = count_for_pack<Pred, Ts...>::value; + + template <template <typename...> class Pred, typename List> + struct count_for; + + template <template <typename...> class Pred, typename... Args> + struct count_for<Pred, types<Args...>> : count_for_pack<Pred, Args...> { }; + + template <std::size_t Limit, template <typename...> class Pred, typename... Ts> + struct count_for_to_pack : meta_detail::count_when_for_pack<meta_detail::on_always, Limit, 0, Pred, Ts...> { }; + + template <std::size_t Limit, template <typename...> class Pred, typename... Ts> + inline constexpr std::size_t count_for_to_pack_v = count_for_to_pack<Limit, Pred, Ts...>::value; + + template <template <typename...> class When, std::size_t Limit, template <typename...> class Pred, typename... Ts> + struct count_when_for_to_pack : meta_detail::count_when_for_pack<When, Limit, 0, Pred, Ts...> { }; + + template <template <typename...> class When, std::size_t Limit, template <typename...> class Pred, typename... Ts> + inline constexpr std::size_t count_when_for_to_pack_v = count_when_for_to_pack<When, Limit, Pred, Ts...>::value; + + template <template <typename...> class Pred, typename... Ts> + using count_even_for_pack = count_when_for_to_pack<meta_detail::on_even, sizeof...(Ts), Pred, Ts...>; + + template <template <typename...> class Pred, typename... Ts> + inline constexpr std::size_t count_even_for_pack_v = count_even_for_pack<Pred, Ts...>::value; + + template <template <typename...> class Pred, typename... Ts> + using count_odd_for_pack = count_when_for_to_pack<meta_detail::on_odd, sizeof...(Ts), Pred, Ts...>; + + template <template <typename...> class Pred, typename... Ts> + inline constexpr std::size_t count_odd_for_pack_v = count_odd_for_pack<Pred, Ts...>::value; + + template <typename... Args> + struct return_type { + typedef std::tuple<Args...> type; + }; + + template <typename T> + struct return_type<T> { + typedef T type; + }; + + template <> + struct return_type<> { + typedef void type; + }; + + template <typename... Args> + using return_type_t = typename return_type<Args...>::type; + + namespace meta_detail { + template <typename> + struct always_true : std::true_type { }; + struct is_invokable_tester { + template <typename Fun, typename... Args> + static always_true<decltype(std::declval<Fun>()(std::declval<Args>()...))> test(int); + template <typename...> + static std::false_type test(...); + }; + } // namespace meta_detail + + template <typename T> + struct is_invokable; + template <typename Fun, typename... Args> + struct is_invokable<Fun(Args...)> : decltype(meta_detail::is_invokable_tester::test<Fun, Args...>(0)) { }; + + namespace meta_detail { + + template <typename T, typename = void> + struct is_invocable : std::is_function<std::remove_pointer_t<T>> { }; + + template <typename T> + struct is_invocable<T, + std::enable_if_t<std::is_final<unqualified_t<T>>::value && std::is_class<unqualified_t<T>>::value + && std::is_same<decltype(void(&T::operator())), void>::value>> { }; + + template <typename T> + struct is_invocable<T, + std::enable_if_t<!std::is_final<unqualified_t<T>>::value && std::is_class<unqualified_t<T>>::value + && std::is_destructible<unqualified_t<T>>::value>> { + struct F { + void operator()() {}; + }; + struct Derived : T, F { }; + template <typename U, U> + struct Check; + + template <typename V> + static sfinae_no_t test(Check<void (F::*)(), &V::operator()>*); + + template <typename> + static sfinae_yes_t test(...); + + static constexpr bool value = std::is_same_v<decltype(test<Derived>(0)), sfinae_yes_t>; + }; + + template <typename T> + struct is_invocable<T, + std::enable_if_t<!std::is_final<unqualified_t<T>>::value && std::is_class<unqualified_t<T>>::value + && !std::is_destructible<unqualified_t<T>>::value>> { + struct F { + void operator()() {}; + }; + struct Derived : T, F { + ~Derived() = delete; + }; + template <typename U, U> + struct Check; + + template <typename V> + static sfinae_no_t test(Check<void (F::*)(), &V::operator()>*); + + template <typename> + static sfinae_yes_t test(...); + + static constexpr bool value = std::is_same_v<decltype(test<Derived>(0)), sfinae_yes_t>; + }; + + struct has_begin_end_impl { + template <typename T, typename U = unqualified_t<T>, typename B = decltype(std::declval<U&>().begin()), + typename E = decltype(std::declval<U&>().end())> + static std::true_type test(int); + + template <typename...> + static std::false_type test(...); + }; + + struct has_key_type_impl { + template <typename T, typename U = unqualified_t<T>, typename V = typename U::key_type> + static std::true_type test(int); + + template <typename...> + static std::false_type test(...); + }; + + struct has_key_comp_impl { + template <typename T, typename V = decltype(std::declval<unqualified_t<T>>().key_comp())> + static std::true_type test(int); + + template <typename...> + static std::false_type test(...); + }; + + struct has_load_factor_impl { + template <typename T, typename V = decltype(std::declval<unqualified_t<T>>().load_factor())> + static std::true_type test(int); + + template <typename...> + static std::false_type test(...); + }; + + struct has_mapped_type_impl { + template <typename T, typename V = typename unqualified_t<T>::mapped_type> + static std::true_type test(int); + + template <typename...> + static std::false_type test(...); + }; + + struct has_value_type_impl { + template <typename T, typename V = typename unqualified_t<T>::value_type> + static std::true_type test(int); + + template <typename...> + static std::false_type test(...); + }; + + struct has_iterator_impl { + template <typename T, typename V = typename unqualified_t<T>::iterator> + static std::true_type test(int); + + template <typename...> + static std::false_type test(...); + }; + + struct has_key_value_pair_impl { + template <typename T, typename U = unqualified_t<T>, typename V = typename U::value_type, typename F = decltype(std::declval<V&>().first), + typename S = decltype(std::declval<V&>().second)> + static std::true_type test(int); + + template <typename...> + static std::false_type test(...); + }; + + template <typename T> + struct has_push_back_test { + private: + template <typename C> + static sfinae_yes_t test(decltype(std::declval<C>().push_back(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*); + template <typename C> + static sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), sfinae_yes_t>; + }; + + template <typename T> + struct has_insert_with_iterator_test { + private: + template <typename C> + static sfinae_yes_t test(decltype(std::declval<C>().insert( + std::declval<std::add_rvalue_reference_t<typename C::iterator>>(), std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*); + template <typename C> + static sfinae_no_t test(...); + + public: + static constexpr bool value = !std::is_same_v<decltype(test<T>(0)), sfinae_no_t>; + }; + + template <typename T> + struct has_insert_test { + private: + template <typename C> + static sfinae_yes_t test(decltype(std::declval<C>().insert(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*); + template <typename C> + static sfinae_no_t test(...); + + public: + static constexpr bool value = !std::is_same_v<decltype(test<T>(0)), sfinae_no_t>; + }; + + template <typename T> + struct has_insert_after_test { + private: + template <typename C> + static sfinae_yes_t test(decltype(std::declval<C>().insert_after(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(), + std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*); + template <typename C> + static sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), sfinae_yes_t>; + }; + + template <typename T> + struct has_size_test { + private: + template <typename C> + static sfinae_yes_t test(decltype(std::declval<C>().size())*); + template <typename C> + static sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), sfinae_yes_t>; + }; + + template <typename T> + struct has_max_size_test { + private: + template <typename C> + static sfinae_yes_t test(decltype(std::declval<C>().max_size())*); + template <typename C> + static sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), sfinae_yes_t>; + }; + + template <typename T> + struct has_to_string_test { + private: + template <typename C> + static sfinae_yes_t test(decltype(std::declval<C>().to_string())*); + template <typename C> + static sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), sfinae_yes_t>; + }; + + template <typename T, typename U, typename = void> + class supports_op_less_test : public std::false_type { }; + template <typename T, typename U> + class supports_op_less_test<T, U, void_t<decltype(std::declval<T&>() < std::declval<U&>())>> + : public std::integral_constant<bool, +#if SOL_IS_ON(SOL_STD_VARIANT) + !is_specialization_of_v<unqualified_t<T>, std::variant> && !is_specialization_of_v<unqualified_t<U>, std::variant> +#else + true +#endif + > { + }; + + template <typename T, typename U, typename = void> + class supports_op_equal_test : public std::false_type { }; + template <typename T, typename U> + class supports_op_equal_test<T, U, void_t<decltype(std::declval<T&>() == std::declval<U&>())>> + : public std::integral_constant<bool, +#if SOL_IS_ON(SOL_STD_VARIANT) + !is_specialization_of_v<unqualified_t<T>, std::variant> && !is_specialization_of_v<unqualified_t<U>, std::variant> +#else + true +#endif + > { + }; + + template <typename T, typename U, typename = void> + class supports_op_less_equal_test : public std::false_type { }; + template <typename T, typename U> + class supports_op_less_equal_test<T, U, void_t<decltype(std::declval<T&>() <= std::declval<U&>())>> + : public std::integral_constant<bool, +#if SOL_IS_ON(SOL_STD_VARIANT) + !is_specialization_of_v<unqualified_t<T>, std::variant> && !is_specialization_of_v<unqualified_t<U>, std::variant> +#else + true +#endif + > { + }; + + template <typename T, typename U, typename = void> + class supports_op_left_shift_test : public std::false_type { }; + template <typename T, typename U> + class supports_op_left_shift_test<T, U, void_t<decltype(std::declval<T&>() << std::declval<U&>())>> : public std::true_type { }; + + template <typename T, typename = void> + class supports_adl_to_string_test : public std::false_type { }; + template <typename T> + class supports_adl_to_string_test<T, void_t<decltype(to_string(std::declval<const T&>()))>> : public std::true_type { }; + + template <typename T, bool b> + struct is_matched_lookup_impl : std::false_type { }; + template <typename T> + struct is_matched_lookup_impl<T, true> : std::is_same<typename T::key_type, typename T::value_type> { }; + + template <typename T> + using non_void_t = meta::conditional_t<std::is_void_v<T>, ::sol::detail::unchecked_t, T>; + + template <typename T> + using detect_sentinel = typename T::sentinel; + } // namespace meta_detail + + template <typename T, typename Fallback> + class sentinel_or { + public: + using type = detected_or_t<Fallback, meta_detail::detect_sentinel, T>; + }; + + template <typename T, typename Fallback> + using sentinel_or_t = typename sentinel_or<T, Fallback>::type; + + template <typename T, typename U = T> + class supports_op_less : public meta_detail::supports_op_less_test<T, U> { }; + + template <typename T, typename U = T> + class supports_op_equal : public meta_detail::supports_op_equal_test<T, U> { }; + + template <typename T, typename U = T> + class supports_op_less_equal : public meta_detail::supports_op_less_equal_test<T, U> { }; + + template <typename T, typename U = T> + class supports_op_left_shift : public meta_detail::supports_op_left_shift_test<T, U> { }; + + template <typename T> + class supports_adl_to_string : public meta_detail::supports_adl_to_string_test<T> { }; + + template <typename T> + class supports_to_string_member : public meta::boolean<meta_detail::has_to_string_test<meta_detail::non_void_t<T>>::value> { }; + + template <typename T> + using is_invocable = boolean<meta_detail::is_invocable<T>::value>; + + template <typename T> + constexpr inline bool is_invocable_v = is_invocable<T>::value; + + template <typename T> + struct has_begin_end : decltype(meta_detail::has_begin_end_impl::test<T>(0)) { }; + + template <typename T> + constexpr inline bool has_begin_end_v = has_begin_end<T>::value; + + template <typename T> + struct has_key_value_pair : decltype(meta_detail::has_key_value_pair_impl::test<T>(0)) { }; + + template <typename T> + struct has_key_type : decltype(meta_detail::has_key_type_impl::test<T>(0)) { }; + + template <typename T> + struct has_key_comp : decltype(meta_detail::has_key_comp_impl::test<T>(0)) { }; + + template <typename T> + struct has_load_factor : decltype(meta_detail::has_load_factor_impl::test<T>(0)) { }; + + template <typename T> + struct has_mapped_type : decltype(meta_detail::has_mapped_type_impl::test<T>(0)) { }; + + template <typename T> + struct has_iterator : decltype(meta_detail::has_iterator_impl::test<T>(0)) { }; + + template <typename T> + struct has_value_type : decltype(meta_detail::has_value_type_impl::test<T>(0)) { }; + + template <typename T> + using has_push_back = meta::boolean<meta_detail::has_push_back_test<T>::value>; + + template <typename T> + using has_max_size = meta::boolean<meta_detail::has_max_size_test<T>::value>; + + template <typename T> + using has_insert = meta::boolean<meta_detail::has_insert_test<T>::value>; + + template <typename T> + using has_insert_with_iterator = meta::boolean<meta_detail::has_insert_with_iterator_test<T>::value>; + + template <typename T> + using has_insert_after = meta::boolean<meta_detail::has_insert_after_test<T>::value>; + + template <typename T> + using has_size = meta::boolean<meta_detail::has_size_test<T>::value>; + + template <typename T> + using is_associative = meta::all<has_key_type<T>, has_key_value_pair<T>, has_mapped_type<T>>; + + template <typename T> + using is_lookup = meta::all<has_key_type<T>, has_value_type<T>>; + + template <typename T> + using is_ordered = meta::all<has_key_comp<T>, meta::neg<has_load_factor<T>>>; + + template <typename T> + using is_matched_lookup = meta_detail::is_matched_lookup_impl<T, is_lookup<T>::value>; + + template <typename T> + using is_initializer_list = meta::is_specialization_of<T, std::initializer_list>; + + template <typename T> + constexpr inline bool is_initializer_list_v = is_initializer_list<T>::value; + + template <typename T, typename CharT = char> + using is_string_literal_array_of = boolean<std::is_array_v<T> && std::is_same_v<std::remove_all_extents_t<T>, CharT>>; + + template <typename T, typename CharT = char> + constexpr inline bool is_string_literal_array_of_v = is_string_literal_array_of<T, CharT>::value; + + template <typename T> + using is_string_literal_array = boolean<std::is_array_v<T> + && any_same_v<std::remove_all_extents_t<T>, char, +#if SOL_IS_ON(SOL_CHAR8_T) + char8_t, +#endif + char16_t, char32_t, wchar_t>>; + + template <typename T> + constexpr inline bool is_string_literal_array_v = is_string_literal_array<T>::value; + + template <typename T, typename CharT> + struct is_string_of : std::false_type { }; + + template <typename CharT, typename CharTargetT, typename TraitsT, typename AllocT> + struct is_string_of<std::basic_string<CharT, TraitsT, AllocT>, CharTargetT> : std::is_same<CharT, CharTargetT> { }; + + template <typename T, typename CharT> + constexpr inline bool is_string_of_v = is_string_of<T, CharT>::value; + + template <typename T, typename CharT> + struct is_string_view_of : std::false_type { }; + + template <typename CharT, typename CharTargetT, typename TraitsT> + struct is_string_view_of<std::basic_string_view<CharT, TraitsT>, CharTargetT> : std::is_same<CharT, CharTargetT> { }; + + template <typename T, typename CharT> + constexpr inline bool is_string_view_of_v = is_string_view_of<T, CharT>::value; + + template <typename T> + using is_string_like + = meta::boolean<is_specialization_of_v<T, std::basic_string> || is_specialization_of_v<T, std::basic_string_view> || is_string_literal_array_v<T>>; + + template <typename T> + constexpr inline bool is_string_like_v = is_string_like<T>::value; + + template <typename T, typename CharT = char> + using is_string_constructible = meta::boolean<is_string_literal_array_of_v<T, CharT> || std::is_same_v<T, const CharT*> || std::is_same_v<T, CharT> + || is_string_of_v<T, CharT> || std::is_same_v<T, std::initializer_list<CharT>> || is_string_view_of_v<T, CharT> || std::is_null_pointer_v<T>>; + + template <typename T, typename CharT = char> + constexpr inline bool is_string_constructible_v = is_string_constructible<T, CharT>::value; + + template <typename T> + using is_string_like_or_constructible = meta::boolean<is_string_like_v<T> || is_string_constructible_v<T>>; + + template <typename T> + struct is_pair : std::false_type { }; + + template <typename T1, typename T2> + struct is_pair<std::pair<T1, T2>> : std::true_type { }; + + template <typename T, typename Char> + using is_c_str_of = any<std::is_same<T, const Char*>, std::is_same<T, Char const* const>, std::is_same<T, Char*>, is_string_literal_array_of<T, Char>>; + + template <typename T, typename Char> + constexpr inline bool is_c_str_of_v = is_c_str_of<T, Char>::value; + + template <typename T> + using is_c_str = is_c_str_of<T, char>; + + template <typename T> + constexpr inline bool is_c_str_v = is_c_str<T>::value; + + template <typename T, typename Char> + using is_c_str_or_string_of = any<is_c_str_of<T, Char>, is_string_of<T, Char>>; + + template <typename T, typename Char> + constexpr inline bool is_c_str_or_string_of_v = is_c_str_or_string_of<T, Char>::value; + + template <typename T> + using is_c_str_or_string = is_c_str_or_string_of<T, char>; + + template <typename T> + constexpr inline bool is_c_str_or_string_v = is_c_str_or_string<T>::value; + + template <typename T> + struct is_move_only : all<neg<std::is_reference<T>>, neg<std::is_copy_constructible<unqualified_t<T>>>, std::is_move_constructible<unqualified_t<T>>> { }; + + template <typename T> + using is_not_move_only = neg<is_move_only<T>>; + + namespace meta_detail { + template <typename T> + decltype(auto) force_tuple(T&& x) { + if constexpr (meta::is_specialization_of_v<meta::unqualified_t<T>, std::tuple>) { + return std::forward<T>(x); + } + else { + return std::tuple<T>(std::forward<T>(x)); + } + } + } // namespace meta_detail + + template <typename... X> + decltype(auto) tuplefy(X&&... x) { + return std::tuple_cat(meta_detail::force_tuple(std::forward<X>(x))...); + } + + template <typename T, typename = void> + struct iterator_tag { + using type = std::input_iterator_tag; + }; + + template <typename T> + struct iterator_tag<T, conditional_t<false, typename std::iterator_traits<T>::iterator_category, void>> { + using type = typename std::iterator_traits<T>::iterator_category; + }; +}} // namespace sol::meta + +// end of sol/traits.hpp + +namespace sol { + namespace detail { + const bool default_safe_function_calls = +#if SOL_IS_ON(SOL_SAFE_FUNCTION_CALLS) + true; +#else + false; +#endif + } // namespace detail + + namespace meta { namespace meta_detail { + }} // namespace meta::meta_detail + + namespace stack { namespace stack_detail { + using undefined_method_func = void (*)(stack_reference); + + template <typename T> + void set_undefined_methods_on(stack_reference); + + struct undefined_metatable; + }} // namespace stack::stack_detail +} // namespace sol + +#endif // SOL_FORWARD_DETAIL_HPP +// end of sol/forward_detail.hpp + +// beginning of sol/assert.hpp + +#if SOL_IS_ON(SOL2_CI) + +struct pre_main { + pre_main() { +#ifdef _MSC_VER + _set_abort_behavior(0, _WRITE_ABORT_MSG); +#endif + } +} inline sol2_ci_dont_lock_ci_please = {}; + +#endif // Prevent lockup when doing Continuous Integration + +#if SOL_IS_ON(SOL_USER_ASSERT) + #define SOL_ASSERT(...) SOL_C_ASSERT(__VA_ARGS__) +#else + #if SOL_IS_ON(SOL_DEBUG_BUILD) + #include <exception> + #include <iostream> + #include <cstdlib> + + #define SOL_ASSERT(...) \ + do { \ + if (!(__VA_ARGS__)) { \ + std::cerr << "Assertion `" #__VA_ARGS__ "` failed in " << __FILE__ << " line " << __LINE__ << std::endl; \ + std::terminate(); \ + } \ + } while (false) + #else + #define SOL_ASSERT(...) \ + do { \ + if (false) { \ + (void)(__VA_ARGS__); \ + } \ + } while (false) + #endif +#endif + +#if SOL_IS_ON(SOL_USER_ASSERT_MSG) + #define SOL_ASSERT_MSG(message, ...) SOL_ASSERT_MSG(message, __VA_ARGS__) +#else + #if SOL_IS_ON(SOL_DEBUG_BUILD) + #include <exception> + #include <iostream> + #include <cstdlib> + + #define SOL_ASSERT_MSG(message, ...) \ + do { \ + if (!(__VA_ARGS__)) { \ + std::cerr << "Assertion `" #__VA_ARGS__ "` failed in " << __FILE__ << " line " << __LINE__ << ": " << message << std::endl; \ + std::terminate(); \ + } \ + } while (false) + #else + #define SOL_ASSERT_MSG(message, ...) \ + do { \ + if (false) { \ + (void)(__VA_ARGS__); \ + (void)sizeof(message); \ + } \ + } while (false) + #endif +#endif + +// end of sol/assert.hpp + +// beginning of sol/bytecode.hpp + +// beginning of sol/compatibility.hpp + +// beginning of sol/compatibility/lua_version.hpp + +#if SOL_IS_ON(SOL_USING_CXX_LUA) + #include <lua.h> + #include <lualib.h> + #include <lauxlib.h> +#elif SOL_IS_ON(SOL_USE_LUA_HPP) + #include <lua.hpp> +#else + extern "C" { + #include <lua.h> + #include <lauxlib.h> + #include <lualib.h> + } +#endif // C++ Mangling for Lua vs. Not + +#if defined(SOL_LUAJIT) + #if (SOL_LUAJIT != 0) + #define SOL_USE_LUAJIT_I_ SOL_ON + #else + #define SOL_USE_LUAJIT_I_ SOL_OFF + #endif +#elif defined(LUAJIT_VERSION) + #define SOL_USE_LUAJIT_I_ SOL_ON +#else + #define SOL_USE_LUAJIT_I_ SOL_DEFAULT_OFF +#endif // luajit + +#if SOL_IS_ON(SOL_USING_CXX_LUAJIT) + #include <luajit.h> +#elif SOL_IS_ON(SOL_USE_LUAJIT) + extern "C" { + #include <luajit.h> + } +#endif // C++ LuaJIT ... whatever that means + +#if defined(SOL_LUAJIT_VERSION) + #define SOL_LUAJIT_VERSION_I_ SOL_LUAJIT_VERSION +#elif SOL_IS_ON(SOL_USE_LUAJIT) + #define SOL_LUAJIT_VERSION_I_ LUAJIT_VERSION_NUM +#else + #define SOL_LUAJIT_VERSION_I_ 0 +#endif + +#if defined(SOL_LUAJIT_FFI_DISABLED) + #define SOL_LUAJIT_FFI_DISABLED_I_ SOL_ON +#elif defined(LUAJIT_DISABLE_FFI) + #define SOL_LUAJIT_FFI_DISABLED_I_ SOL_ON +#else + #define SOL_LUAJIT_FFI_DISABLED_I_ SOL_DEFAULT_OFF +#endif + +#if defined(MOONJIT_VERSION) + #define SOL_USE_MOONJIT_I_ SOL_ON +#else + #define SOL_USE_MOONJIT_I_ SOL_OFF +#endif + +#if !defined(SOL_LUA_VERSION) + #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 502 + #define SOL_LUA_VERSION LUA_VERSION_NUM + #elif defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 + #define SOL_LUA_VERSION LUA_VERSION_NUM + #elif !defined(LUA_VERSION_NUM) || !(LUA_VERSION_NUM) + // Definitely 5.0 + #define SOL_LUA_VERSION 500 + #else + // ??? Not sure, assume latest? + #define SOL_LUA_VERSION 504 + #endif // Lua Version 503, 502, 501 || luajit, 500 +#endif // SOL_LUA_VERSION + +#if defined(SOL_LUA_VERSION) + #define SOL_LUA_VERSION_I_ SOL_LUA_VERSION +#else + #define SOL_LUA_VERSION_I_ 504 +#endif + +#if defined(SOL_EXCEPTIONS_ALWAYS_UNSAFE) + #if (SOL_EXCEPTIONS_ALWAYS_UNSAFE != 0) + #define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_OFF + #else + #define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_ON + #endif +#elif defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) + #if (SOL_EXCEPTIONS_SAFE_PROPAGATION != 0) + #define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_ON + #else + #define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_OFF + #endif +#elif SOL_LUAJIT_VERSION_I_ >= 20100 + // LuaJIT 2.1.0-beta3 and better have exception support locked in for all platforms (mostly) + #define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_DEFAULT_ON +#elif SOL_LUAJIT_VERSION_I_ >= 20000 + // LuaJIT 2.0.x have exception support only on x64 builds + #if SOL_IS_ON(SOL_PLATFORM_X64) + #define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_DEFAULT_ON + #else + #define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_OFF + #endif +#else + // otherwise, there is no exception safety for + // shoving exceptions through Lua and errors should + // always be serialized + #define SOL_PROPAGATE_EXCEPTIONS_I_ SOL_DEFAULT_OFF +#endif + +#if defined(SOL_EXCEPTIONS_CATCH_ALL) + #if (SOL_EXCEPTIONS_CATCH_ALL != 0) + #define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_ON + #else + #define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_OFF + #endif +#else + #if SOL_IS_ON(SOL_USE_LUAJIT) + #define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_DEFAULT_OFF + #elif SOL_IS_ON(SOL_USING_CXX_LUAJIT) + #define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_DEFAULT_OFF + #elif SOL_IS_ON(SOL_USING_CXX_LUA) + #define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_DEFAULT_OFF + #else + #define SOL_EXCEPTIONS_CATCH_ALL_I_ SOL_DEFAULT_ON + #endif +#endif + +#if defined(SOL_LUAJIT_USE_EXCEPTION_TRAMPOLINE) + #if (SOL_LUAJIT_USE_EXCEPTION_TRAMPOLINE != 0) + #define SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE_I_ SOL_ON + #else + #define SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE_I_ SOL_OFF + #endif +#else + #if SOL_IS_OFF(SOL_PROPAGATE_EXCEPTIONS) && SOL_IS_ON(SOL_USE_LUAJIT) + #define SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE_I_ SOL_ON + #else + #define SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined(SOL_LUAL_STREAM_HAS_CLOSE_FUNCTION) + #if (SOL_LUAL_STREAM_HAS_CLOSE_FUNCTION != 0) + #define SOL_LUAL_STREAM_USE_CLOSE_FUNCTION_I_ SOL_ON + #else + #define SOL_LUAL_STREAM_USE_CLOSE_FUNCTION_I_ SOL_OFF + #endif +#else + #if SOL_IS_OFF(SOL_USE_LUAJIT) && (SOL_LUA_VERSION > 501) + #define SOL_LUAL_STREAM_USE_CLOSE_FUNCTION_I_ SOL_ON + #else + #define SOL_LUAL_STREAM_USE_CLOSE_FUNCTION_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined (SOL_LUA_BIT32_LIB) + #if SOL_LUA_BIT32_LIB != 0 + #define SOL_LUA_BIT32_LIB_I_ SOL_ON + #else + #define SOL_LUA_BIT32_LIB_I_ SOL_OFF + #endif +#else + // Lua 5.2 only (deprecated in 5.3 (503)) (Can be turned on with Compat flags) + // Lua 5.2, or other versions of Lua with the compat flag, or Lua that is not 5.2 with the specific define (5.4.1 either removed it entirely or broke it) + #if (SOL_LUA_VERSION_I_ == 502) + #define SOL_LUA_BIT32_LIB_I_ SOL_ON + #elif defined(LUA_COMPAT_BITLIB) + #define SOL_LUA_BIT32_LIB_I_ SOL_ON + #elif (SOL_LUA_VERSION_I_ < 504 && defined(LUA_COMPAT_5_2)) + #define SOL_LUA_BIT32_LIB_I_ SOL_ON + #else + #define SOL_LUA_BIT32_LIB_I_ SOL_DEFAULT_OFF + #endif +#endif + +#if defined (SOL_LUA_NIL_IN_TABLES) + #if SOL_LUA_NIL_IN_TABLES != 0 + #define SOL_LUA_NIL_IN_TABLES_I_ SOL_ON + #else + #define SOL_LUA_NIL_IN_TABLES_I_ SOL_OFF + #endif +#else + #if defined(LUA_NILINTABLE) && (LUA_NILINTABLE != 0) + #define SOL_LUA_NIL_IN_TABLES_I_ SOL_DEFAULT_ON + #else + #define SOL_LUA_NIL_IN_TABLES_I_ SOL_DEFAULT_OFF + #endif +#endif + +// end of sol/compatibility/lua_version.hpp + +#if SOL_IS_ON(SOL_USE_COMPATIBILITY_LAYER) + +#if SOL_IS_ON(SOL_USING_CXX_LUA) || SOL_IS_ON(SOL_USING_CXX_LUAJIT) + #ifndef COMPAT53_LUA_CPP + #define COMPAT53_LUA_CPP 1 + #endif // Build Lua Compat layer as C++ +#endif + #ifndef COMPAT53_INCLUDE_SOURCE + #define COMPAT53_INCLUDE_SOURCE 1 + #endif // Build Compat Layer Inline +// beginning of sol/compatibility/compat-5.3.h + +#ifndef KEPLER_PROJECT_COMPAT53_H_ +#define KEPLER_PROJECT_COMPAT53_H_ + +#include <stddef.h> +#include <limits.h> +#include <string.h> +#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) +extern "C" { +#endif +#include <lua.h> +#include <lauxlib.h> +#include <lualib.h> +#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) +} +#endif + +#ifndef COMPAT53_PREFIX +/* we chose this name because many other lua bindings / libs have +* their own compatibility layer, and that use the compat53 declaration +* frequently, causing all kinds of linker / compiler issues +*/ +# define COMPAT53_PREFIX kp_compat53 +#endif // COMPAT53_PREFIX + +#ifndef COMPAT53_API +# if defined(COMPAT53_INCLUDE_SOURCE) && COMPAT53_INCLUDE_SOURCE +# if defined(__GNUC__) || defined(__clang__) +# define COMPAT53_API __attribute__((__unused__)) static inline +# else +# define COMPAT53_API static inline +# endif /* Clang/GCC */ +# else /* COMPAT53_INCLUDE_SOURCE */ +/* we are not including source, so everything is extern */ +# define COMPAT53_API extern +# endif /* COMPAT53_INCLUDE_SOURCE */ +#endif /* COMPAT53_PREFIX */ + +#define COMPAT53_CONCAT_HELPER(a, b) a##b +#define COMPAT53_CONCAT(a, b) COMPAT53_CONCAT_HELPER(a, b) + +/* declarations for Lua 5.1 */ +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 + +/* XXX not implemented: +* lua_arith (new operators) +* lua_upvalueid +* lua_upvaluejoin +* lua_version +* lua_yieldk +*/ + +#ifndef LUA_OK +# define LUA_OK 0 +#endif +#ifndef LUA_OPADD +# define LUA_OPADD 0 +#endif +#ifndef LUA_OPSUB +# define LUA_OPSUB 1 +#endif +#ifndef LUA_OPMUL +# define LUA_OPMUL 2 +#endif +#ifndef LUA_OPDIV +# define LUA_OPDIV 3 +#endif +#ifndef LUA_OPMOD +# define LUA_OPMOD 4 +#endif +#ifndef LUA_OPPOW +# define LUA_OPPOW 5 +#endif +#ifndef LUA_OPUNM +# define LUA_OPUNM 6 +#endif +#ifndef LUA_OPEQ +# define LUA_OPEQ 0 +#endif +#ifndef LUA_OPLT +# define LUA_OPLT 1 +#endif +#ifndef LUA_OPLE +# define LUA_OPLE 2 +#endif + +/* LuaJIT/Lua 5.1 does not have the updated +* error codes for thread status/function returns (but some patched versions do) +* define it only if it's not found +*/ +#if !defined(LUA_ERRGCMM) +/* Use + 2 because in some versions of Lua (Lua 5.1) +* LUA_ERRFILE is defined as (LUA_ERRERR+1) +* so we need to avoid it (LuaJIT might have something at this +* integer value too) +*/ +# define LUA_ERRGCMM (LUA_ERRERR + 2) +#endif /* LUA_ERRGCMM define */ + +#if !defined(MOONJIT_VERSION) +typedef size_t lua_Unsigned; +#endif + +typedef struct luaL_Buffer_53 { + luaL_Buffer b; /* make incorrect code crash! */ + char *ptr; + size_t nelems; + size_t capacity; + lua_State *L2; +} luaL_Buffer_53; +#define luaL_Buffer luaL_Buffer_53 + +/* In PUC-Rio 5.1, userdata is a simple FILE* +* In LuaJIT, it's a struct where the first member is a FILE* +* We can't support the `closef` member +*/ +typedef struct luaL_Stream { + FILE *f; +} luaL_Stream; + +#define lua_absindex COMPAT53_CONCAT(COMPAT53_PREFIX, _absindex) +COMPAT53_API int lua_absindex(lua_State *L, int i); + +#define lua_arith COMPAT53_CONCAT(COMPAT53_PREFIX, _arith) +COMPAT53_API void lua_arith(lua_State *L, int op); + +#define lua_compare COMPAT53_CONCAT(COMPAT53_PREFIX, _compare) +COMPAT53_API int lua_compare(lua_State *L, int idx1, int idx2, int op); + +#define lua_copy COMPAT53_CONCAT(COMPAT53_PREFIX, _copy) +COMPAT53_API void lua_copy(lua_State *L, int from, int to); + +#define lua_getuservalue(L, i) \ + (lua_getfenv((L), (i)), lua_type((L), -1)) +#define lua_setuservalue(L, i) \ + (luaL_checktype((L), -1, LUA_TTABLE), lua_setfenv((L), (i))) + +#define lua_len COMPAT53_CONCAT(COMPAT53_PREFIX, _len) +COMPAT53_API void lua_len(lua_State *L, int i); + +#define lua_pushstring(L, s) \ + (lua_pushstring((L), (s)), lua_tostring((L), -1)) + +#define lua_pushlstring(L, s, len) \ + ((((len) == 0) ? lua_pushlstring((L), "", 0) : lua_pushlstring((L), (s), (len))), lua_tostring((L), -1)) + +#ifndef luaL_newlibtable +# define luaL_newlibtable(L, l) \ + (lua_createtable((L), 0, sizeof((l))/sizeof(*(l))-1)) +#endif +#ifndef luaL_newlib +# define luaL_newlib(L, l) \ + (luaL_newlibtable((L), (l)), luaL_register((L), NULL, (l))) +#endif + +#ifndef lua_pushglobaltable +# define lua_pushglobaltable(L) \ + lua_pushvalue((L), LUA_GLOBALSINDEX) +#endif +#define lua_rawgetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawgetp) +COMPAT53_API int lua_rawgetp(lua_State *L, int i, const void *p); + +#define lua_rawsetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawsetp) +COMPAT53_API void lua_rawsetp(lua_State *L, int i, const void *p); + +#define lua_rawlen(L, i) lua_objlen((L), (i)) + +#define lua_tointeger(L, i) lua_tointegerx((L), (i), NULL) + +#define lua_tonumberx COMPAT53_CONCAT(COMPAT53_PREFIX, _tonumberx) +COMPAT53_API lua_Number lua_tonumberx(lua_State *L, int i, int *isnum); + +#define luaL_checkversion COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkversion) +COMPAT53_API void luaL_checkversion(lua_State *L); + +#define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53) +COMPAT53_API int lua_load(lua_State *L, lua_Reader reader, void *data, const char* source, const char* mode); + +#define luaL_loadfilex COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadfilex) +COMPAT53_API int luaL_loadfilex(lua_State *L, const char *filename, const char *mode); + +#define luaL_loadbufferx COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadbufferx) +COMPAT53_API int luaL_loadbufferx(lua_State *L, const char *buff, size_t sz, const char *name, const char *mode); + +#define luaL_checkstack COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkstack_53) +COMPAT53_API void luaL_checkstack(lua_State *L, int sp, const char *msg); + +#define luaL_getsubtable COMPAT53_CONCAT(COMPAT53_PREFIX, L_getsubtable) +COMPAT53_API int luaL_getsubtable(lua_State* L, int i, const char *name); + +#define luaL_len COMPAT53_CONCAT(COMPAT53_PREFIX, L_len) +COMPAT53_API lua_Integer luaL_len(lua_State *L, int i); + +#define luaL_setfuncs COMPAT53_CONCAT(COMPAT53_PREFIX, L_setfuncs) +COMPAT53_API void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup); + +#define luaL_setmetatable COMPAT53_CONCAT(COMPAT53_PREFIX, L_setmetatable) +COMPAT53_API void luaL_setmetatable(lua_State *L, const char *tname); + +#define luaL_testudata COMPAT53_CONCAT(COMPAT53_PREFIX, L_testudata) +COMPAT53_API void *luaL_testudata(lua_State *L, int i, const char *tname); + +#define luaL_traceback COMPAT53_CONCAT(COMPAT53_PREFIX, L_traceback) +COMPAT53_API void luaL_traceback(lua_State *L, lua_State *L1, const char *msg, int level); + +#define luaL_fileresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_fileresult) +COMPAT53_API int luaL_fileresult(lua_State *L, int stat, const char *fname); + +#define luaL_execresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_execresult) +COMPAT53_API int luaL_execresult(lua_State *L, int stat); + +#define lua_callk(L, na, nr, ctx, cont) \ + ((void)(ctx), (void)(cont), lua_call((L), (na), (nr))) +#define lua_pcallk(L, na, nr, err, ctx, cont) \ + ((void)(ctx), (void)(cont), lua_pcall((L), (na), (nr), (err))) + +#define lua_resume(L, from, nargs) \ + ((void)(from), lua_resume((L), (nargs))) + +#define luaL_buffinit COMPAT53_CONCAT(COMPAT53_PREFIX, _buffinit_53) +COMPAT53_API void luaL_buffinit(lua_State *L, luaL_Buffer_53 *B); + +#define luaL_prepbuffsize COMPAT53_CONCAT(COMPAT53_PREFIX, _prepbufsize_53) +COMPAT53_API char *luaL_prepbuffsize(luaL_Buffer_53 *B, size_t s); + +#define luaL_addlstring COMPAT53_CONCAT(COMPAT53_PREFIX, _addlstring_53) +COMPAT53_API void luaL_addlstring(luaL_Buffer_53 *B, const char *s, size_t l); + +#define luaL_addvalue COMPAT53_CONCAT(COMPAT53_PREFIX, _addvalue_53) +COMPAT53_API void luaL_addvalue(luaL_Buffer_53 *B); + +#define luaL_pushresult COMPAT53_CONCAT(COMPAT53_PREFIX, _pushresult_53) +COMPAT53_API void luaL_pushresult(luaL_Buffer_53 *B); + +#undef luaL_buffinitsize +#define luaL_buffinitsize(L, B, s) \ + (luaL_buffinit((L), (B)), luaL_prepbuffsize((B), (s))) + +#undef luaL_prepbuffer +#define luaL_prepbuffer(B) \ + luaL_prepbuffsize((B), LUAL_BUFFERSIZE) + +#undef luaL_addchar +#define luaL_addchar(B, c) \ + ((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize((B), 1)), \ + ((B)->ptr[(B)->nelems++] = (c))) + +#undef luaL_addsize +#define luaL_addsize(B, s) \ + ((B)->nelems += (s)) + +#undef luaL_addstring +#define luaL_addstring(B, s) \ + luaL_addlstring((B), (s), strlen((s))) + +#undef luaL_pushresultsize +#define luaL_pushresultsize(B, s) \ + (luaL_addsize((B), (s)), luaL_pushresult((B))) + +#if defined(LUA_COMPAT_APIINTCASTS) +#define lua_pushunsigned(L, n) \ + lua_pushinteger((L), (lua_Integer)(n)) +#define lua_tounsignedx(L, i, is) \ + ((lua_Unsigned)lua_tointegerx((L), (i), (is))) +#define lua_tounsigned(L, i) \ + lua_tounsignedx((L), (i), NULL) +#define luaL_checkunsigned(L, a) \ + ((lua_Unsigned)luaL_checkinteger((L), (a))) +#define luaL_optunsigned(L, a, d) \ + ((lua_Unsigned)luaL_optinteger((L), (a), (lua_Integer)(d))) +#endif + +#endif /* Lua 5.1 only */ + +/* declarations for Lua 5.1 and 5.2 */ +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 502 + +typedef int lua_KContext; + +typedef int(*lua_KFunction)(lua_State *L, int status, lua_KContext ctx); + +#define lua_dump(L, w, d, s) \ + ((void)(s), lua_dump((L), (w), (d))) + +#define lua_getfield(L, i, k) \ + (lua_getfield((L), (i), (k)), lua_type((L), -1)) + +#define lua_gettable(L, i) \ + (lua_gettable((L), (i)), lua_type((L), -1)) + +#define lua_geti COMPAT53_CONCAT(COMPAT53_PREFIX, _geti) +COMPAT53_API int lua_geti(lua_State *L, int index, lua_Integer i); + +#define lua_isinteger COMPAT53_CONCAT(COMPAT53_PREFIX, _isinteger) +COMPAT53_API int lua_isinteger(lua_State *L, int index); + +#define lua_tointegerx COMPAT53_CONCAT(COMPAT53_PREFIX, _tointegerx_53) +COMPAT53_API lua_Integer lua_tointegerx(lua_State *L, int i, int *isnum); + +#define lua_numbertointeger(n, p) \ + ((*(p) = (lua_Integer)(n)), 1) + +#define lua_rawget(L, i) \ + (lua_rawget((L), (i)), lua_type((L), -1)) + +#define lua_rawgeti(L, i, n) \ + (lua_rawgeti((L), (i), (n)), lua_type((L), -1)) + +#define lua_rotate COMPAT53_CONCAT(COMPAT53_PREFIX, _rotate) +COMPAT53_API void lua_rotate(lua_State *L, int idx, int n); + +#define lua_seti COMPAT53_CONCAT(COMPAT53_PREFIX, _seti) +COMPAT53_API void lua_seti(lua_State *L, int index, lua_Integer i); + +#define lua_stringtonumber COMPAT53_CONCAT(COMPAT53_PREFIX, _stringtonumber) +COMPAT53_API size_t lua_stringtonumber(lua_State *L, const char *s); + +#define luaL_tolstring COMPAT53_CONCAT(COMPAT53_PREFIX, L_tolstring) +COMPAT53_API const char *luaL_tolstring(lua_State *L, int idx, size_t *len); + +#define luaL_getmetafield(L, o, e) \ + (luaL_getmetafield((L), (o), (e)) ? lua_type((L), -1) : LUA_TNIL) + +#define luaL_newmetatable(L, tn) \ + (luaL_newmetatable((L), (tn)) ? (lua_pushstring((L), (tn)), lua_setfield((L), -2, "__name"), 1) : 0) + +#define luaL_requiref COMPAT53_CONCAT(COMPAT53_PREFIX, L_requiref_53) +COMPAT53_API void luaL_requiref(lua_State *L, const char *modname, + lua_CFunction openf, int glb); + +#endif /* Lua 5.1 and Lua 5.2 */ + +/* declarations for Lua 5.2 */ +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 502 + +/* XXX not implemented: +* lua_isyieldable +* lua_getextraspace +* lua_arith (new operators) +* lua_pushfstring (new formats) +*/ + +#define lua_getglobal(L, n) \ + (lua_getglobal((L), (n)), lua_type((L), -1)) + +#define lua_getuservalue(L, i) \ + (lua_getuservalue((L), (i)), lua_type((L), -1)) + +#define lua_pushlstring(L, s, len) \ + (((len) == 0) ? lua_pushlstring((L), "", 0) : lua_pushlstring((L), (s), (len))) + +#define lua_rawgetp(L, i, p) \ + (lua_rawgetp((L), (i), (p)), lua_type((L), -1)) + +#define LUA_KFUNCTION(_name) \ + static int (_name)(lua_State *L, int status, lua_KContext ctx); \ + static int (_name ## _52)(lua_State *L) { \ + lua_KContext ctx; \ + int status = lua_getctx(L, &ctx); \ + return (_name)(L, status, ctx); \ + } \ + static int (_name)(lua_State *L, int status, lua_KContext ctx) + +#define lua_pcallk(L, na, nr, err, ctx, cont) \ + lua_pcallk((L), (na), (nr), (err), (ctx), cont ## _52) + +#define lua_callk(L, na, nr, ctx, cont) \ + lua_callk((L), (na), (nr), (ctx), cont ## _52) + +#define lua_yieldk(L, nr, ctx, cont) \ + lua_yieldk((L), (nr), (ctx), cont ## _52) + +#ifdef lua_call +# undef lua_call +# define lua_call(L, na, nr) \ + (lua_callk)((L), (na), (nr), 0, NULL) +#endif + +#ifdef lua_pcall +# undef lua_pcall +# define lua_pcall(L, na, nr, err) \ + (lua_pcallk)((L), (na), (nr), (err), 0, NULL) +#endif + +#ifdef lua_yield +# undef lua_yield +# define lua_yield(L, nr) \ + (lua_yieldk)((L), (nr), 0, NULL) +#endif + +#endif /* Lua 5.2 only */ + +/* other Lua versions */ +#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 || LUA_VERSION_NUM > 504 + +# error "unsupported Lua version (i.e. not Lua 5.1, 5.2, 5.3, or 5.4)" + +#endif /* other Lua versions except 5.1, 5.2, 5.3, and 5.4 */ + +/* helper macro for defining continuation functions (for every version +* *except* Lua 5.2) */ +#ifndef LUA_KFUNCTION +#define LUA_KFUNCTION(_name) \ + static int (_name)(lua_State *L, int status, lua_KContext ctx) +#endif + +#if defined(COMPAT53_INCLUDE_SOURCE) && COMPAT53_INCLUDE_SOURCE == 1 +// beginning of sol/compatibility/compat-5.3.c.h + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <stdio.h> + +/* don't compile it again if it already is included via compat53.h */ +#ifndef KEPLER_PROJECT_COMPAT53_C_ +#define KEPLER_PROJECT_COMPAT53_C_ + +/* definitions for Lua 5.1 only */ +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 + +#ifndef COMPAT53_FOPEN_NO_LOCK +#if defined(_MSC_VER) +#define COMPAT53_FOPEN_NO_LOCK 1 +#else /* otherwise */ +#define COMPAT53_FOPEN_NO_LOCK 0 +#endif /* VC++ only so far */ +#endif /* No-lock fopen_s usage if possible */ + +#if defined(_MSC_VER) && COMPAT53_FOPEN_NO_LOCK +#include <share.h> +#endif /* VC++ _fsopen for share-allowed file read */ + +#ifndef COMPAT53_HAVE_STRERROR_R +#if defined(__GLIBC__) || defined(_POSIX_VERSION) || defined(__APPLE__) || (!defined(__MINGW32__) && defined(__GNUC__) && (__GNUC__ < 6)) +#define COMPAT53_HAVE_STRERROR_R 1 +#else /* none of the defines matched: define to 0 */ +#define COMPAT53_HAVE_STRERROR_R 0 +#endif /* have strerror_r of some form */ +#endif /* strerror_r */ + +#ifndef COMPAT53_HAVE_STRERROR_S +#if defined(_MSC_VER) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || (defined(__STDC_LIB_EXT1__) && __STDC_LIB_EXT1__) +#define COMPAT53_HAVE_STRERROR_S 1 +#else /* not VC++ or C11 */ +#define COMPAT53_HAVE_STRERROR_S 0 +#endif /* strerror_s from VC++ or C11 */ +#endif /* strerror_s */ + +#ifndef COMPAT53_LUA_FILE_BUFFER_SIZE +#define COMPAT53_LUA_FILE_BUFFER_SIZE 4096 +#endif /* Lua File Buffer Size */ + +static char* compat53_strerror(int en, char* buff, size_t sz) { +#if COMPAT53_HAVE_STRERROR_R + /* use strerror_r here, because it's available on these specific platforms */ + if (sz > 0) { + buff[0] = '\0'; + /* we don't care whether the GNU version or the XSI version is used: */ + if (strerror_r(en, buff, sz)) { + /* Yes, we really DO want to ignore the return value! + * GCC makes that extra hard, not even a (void) cast will do. */ + } + if (buff[0] == '\0') { + /* Buffer is unchanged, so we probably have called GNU strerror_r which + * returned a static constant string. Chances are that strerror will + * return the same static constant string and therefore be thread-safe. */ + return strerror(en); + } + } + return buff; /* sz is 0 *or* strerror_r wrote into the buffer */ +#elif COMPAT53_HAVE_STRERROR_S + /* for MSVC and other C11 implementations, use strerror_s since it's + * provided by default by the libraries */ + strerror_s(buff, sz, en); + return buff; +#else + /* fallback, but strerror is not guaranteed to be threadsafe due to modifying + * errno itself and some impls not locking a static buffer for it ... but most + * known systems have threadsafe errno: this might only change if the locale + * is changed out from under someone while this function is being called */ + (void)buff; + (void)sz; + return strerror(en); +#endif +} + +COMPAT53_API int lua_absindex(lua_State* L, int i) { + if (i < 0 && i > LUA_REGISTRYINDEX) + i += lua_gettop(L) + 1; + return i; +} + +static void compat53_call_lua(lua_State* L, char const code[], size_t len, int nargs, int nret) { + lua_rawgetp(L, LUA_REGISTRYINDEX, (void*)code); + if (lua_type(L, -1) != LUA_TFUNCTION) { + lua_pop(L, 1); + if (luaL_loadbuffer(L, code, len, "=none")) + lua_error(L); + lua_pushvalue(L, -1); + lua_rawsetp(L, LUA_REGISTRYINDEX, (void*)code); + } + lua_insert(L, -nargs - 1); + lua_call(L, nargs, nret); +} + +COMPAT53_API void lua_arith(lua_State* L, int op) { + static const char compat53_arith_code[] + = "local op,a,b=...\n" + "if op==0 then return a+b\n" + "elseif op==1 then return a-b\n" + "elseif op==2 then return a*b\n" + "elseif op==3 then return a/b\n" + "elseif op==4 then return a%b\n" + "elseif op==5 then return a^b\n" + "elseif op==6 then return -a\n" + "end\n"; + + if (op < LUA_OPADD || op > LUA_OPUNM) + luaL_error(L, "invalid 'op' argument for lua_arith"); + luaL_checkstack(L, 5, "not enough stack slots"); + if (op == LUA_OPUNM) + lua_pushvalue(L, -1); + lua_pushnumber(L, op); + lua_insert(L, -3); + compat53_call_lua(L, compat53_arith_code, sizeof(compat53_arith_code) - 1, 3, 1); +} + +COMPAT53_API int lua_compare(lua_State* L, int idx1, int idx2, int op) { + static const char compat53_compare_code[] + = "local a,b=...\n" + "return a<=b\n"; + + int result = 0; + switch (op) { + case LUA_OPEQ: + return lua_equal(L, idx1, idx2); + case LUA_OPLT: + return lua_lessthan(L, idx1, idx2); + case LUA_OPLE: + luaL_checkstack(L, 5, "not enough stack slots"); + idx1 = lua_absindex(L, idx1); + idx2 = lua_absindex(L, idx2); + lua_pushvalue(L, idx1); + lua_pushvalue(L, idx2); + compat53_call_lua(L, compat53_compare_code, sizeof(compat53_compare_code) - 1, 2, 1); + result = lua_toboolean(L, -1); + lua_pop(L, 1); + return result; + default: + luaL_error(L, "invalid 'op' argument for lua_compare"); + } + return 0; +} + +COMPAT53_API void lua_copy(lua_State* L, int from, int to) { + int abs_to = lua_absindex(L, to); + luaL_checkstack(L, 1, "not enough stack slots"); + lua_pushvalue(L, from); + lua_replace(L, abs_to); +} + +COMPAT53_API void lua_len(lua_State* L, int i) { + switch (lua_type(L, i)) { + case LUA_TSTRING: + lua_pushnumber(L, (lua_Number)lua_objlen(L, i)); + break; + case LUA_TTABLE: + if (!luaL_callmeta(L, i, "__len")) + lua_pushnumber(L, (lua_Number)lua_objlen(L, i)); + break; + case LUA_TUSERDATA: + if (luaL_callmeta(L, i, "__len")) + break; + /* FALLTHROUGH */ + default: + luaL_error(L, "attempt to get length of a %s value", lua_typename(L, lua_type(L, i))); + } +} + +COMPAT53_API int lua_rawgetp(lua_State* L, int i, const void* p) { + int abs_i = lua_absindex(L, i); + lua_pushlightuserdata(L, (void*)p); + lua_rawget(L, abs_i); + return lua_type(L, -1); +} + +COMPAT53_API void lua_rawsetp(lua_State* L, int i, const void* p) { + int abs_i = lua_absindex(L, i); + luaL_checkstack(L, 1, "not enough stack slots"); + lua_pushlightuserdata(L, (void*)p); + lua_insert(L, -2); + lua_rawset(L, abs_i); +} + +COMPAT53_API lua_Number lua_tonumberx(lua_State* L, int i, int* isnum) { + lua_Number n = lua_tonumber(L, i); + if (isnum != NULL) { + *isnum = (n != 0 || lua_isnumber(L, i)); + } + return n; +} + +COMPAT53_API void luaL_checkversion(lua_State* L) { + (void)L; +} + +COMPAT53_API void luaL_checkstack(lua_State* L, int sp, const char* msg) { + if (!lua_checkstack(L, sp + LUA_MINSTACK)) { + if (msg != NULL) + luaL_error(L, "stack overflow (%s)", msg); + else { + lua_pushliteral(L, "stack overflow"); + lua_error(L); + } + } +} + +COMPAT53_API int luaL_getsubtable(lua_State* L, int i, const char* name) { + int abs_i = lua_absindex(L, i); + luaL_checkstack(L, 3, "not enough stack slots"); + lua_pushstring(L, name); + lua_gettable(L, abs_i); + if (lua_istable(L, -1)) + return 1; + lua_pop(L, 1); + lua_newtable(L); + lua_pushstring(L, name); + lua_pushvalue(L, -2); + lua_settable(L, abs_i); + return 0; +} + +COMPAT53_API lua_Integer luaL_len(lua_State* L, int i) { + lua_Integer res = 0; + int isnum = 0; + luaL_checkstack(L, 1, "not enough stack slots"); + lua_len(L, i); + res = lua_tointegerx(L, -1, &isnum); + lua_pop(L, 1); + if (!isnum) + luaL_error(L, "object length is not an integer"); + return res; +} + +COMPAT53_API void luaL_setfuncs(lua_State* L, const luaL_Reg* l, int nup) { + luaL_checkstack(L, nup + 1, "too many upvalues"); + for (; l->name != NULL; l++) { /* fill the table with given functions */ + int i; + lua_pushstring(L, l->name); + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(L, -(nup + 1)); + lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ + lua_settable(L, -(nup + 3)); /* table must be below the upvalues, the name and the closure */ + } + lua_pop(L, nup); /* remove upvalues */ +} + +COMPAT53_API void luaL_setmetatable(lua_State* L, const char* tname) { + luaL_checkstack(L, 1, "not enough stack slots"); + luaL_getmetatable(L, tname); + lua_setmetatable(L, -2); +} + +COMPAT53_API void* luaL_testudata(lua_State* L, int i, const char* tname) { + void* p = lua_touserdata(L, i); + luaL_checkstack(L, 2, "not enough stack slots"); + if (p == NULL || !lua_getmetatable(L, i)) + return NULL; + else { + int res = 0; + luaL_getmetatable(L, tname); + res = lua_rawequal(L, -1, -2); + lua_pop(L, 2); + if (!res) + p = NULL; + } + return p; +} + +static int compat53_countlevels(lua_State* L) { + lua_Debug ar; + int li = 1, le = 1; + /* find an upper bound */ + while (lua_getstack(L, le, &ar)) { + li = le; + le *= 2; + } + /* do a binary search */ + while (li < le) { + int m = (li + le) / 2; + if (lua_getstack(L, m, &ar)) + li = m + 1; + else + le = m; + } + return le - 1; +} + +static int compat53_findfield(lua_State* L, int objidx, int level) { + if (level == 0 || !lua_istable(L, -1)) + return 0; /* not found */ + lua_pushnil(L); /* start 'next' loop */ + while (lua_next(L, -2)) { /* for each pair in table */ + if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ + if (lua_rawequal(L, objidx, -1)) { /* found object? */ + lua_pop(L, 1); /* remove value (but keep name) */ + return 1; + } + else if (compat53_findfield(L, objidx, level - 1)) { /* try recursively */ + lua_remove(L, -2); /* remove table (but keep name) */ + lua_pushliteral(L, "."); + lua_insert(L, -2); /* place '.' between the two names */ + lua_concat(L, 3); + return 1; + } + } + lua_pop(L, 1); /* remove value */ + } + return 0; /* not found */ +} + +static int compat53_pushglobalfuncname(lua_State* L, lua_Debug* ar) { + int top = lua_gettop(L); + lua_getinfo(L, "f", ar); /* push function */ + lua_pushvalue(L, LUA_GLOBALSINDEX); + if (compat53_findfield(L, top + 1, 2)) { + lua_copy(L, -1, top + 1); /* move name to proper place */ + lua_pop(L, 2); /* remove pushed values */ + return 1; + } + else { + lua_settop(L, top); /* remove function and global table */ + return 0; + } +} + +static void compat53_pushfuncname(lua_State* L, lua_Debug* ar) { + if (*ar->namewhat != '\0') /* is there a name? */ + lua_pushfstring(L, "function " LUA_QS, ar->name); + else if (*ar->what == 'm') /* main? */ + lua_pushliteral(L, "main chunk"); + else if (*ar->what == 'C') { + if (compat53_pushglobalfuncname(L, ar)) { + lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); + lua_remove(L, -2); /* remove name */ + } + else + lua_pushliteral(L, "?"); + } + else + lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); +} + +#define COMPAT53_LEVELS1 12 /* size of the first part of the stack */ +#define COMPAT53_LEVELS2 10 /* size of the second part of the stack */ + +COMPAT53_API void luaL_traceback(lua_State* L, lua_State* L1, const char* msg, int level) { + lua_Debug ar; + int top = lua_gettop(L); + int numlevels = compat53_countlevels(L1); + int mark = (numlevels > COMPAT53_LEVELS1 + COMPAT53_LEVELS2) ? COMPAT53_LEVELS1 : 0; + if (msg) + lua_pushfstring(L, "%s\n", msg); + lua_pushliteral(L, "stack traceback:"); + while (lua_getstack(L1, level++, &ar)) { + if (level == mark) { /* too many levels? */ + lua_pushliteral(L, "\n\t..."); /* add a '...' */ + level = numlevels - COMPAT53_LEVELS2; /* and skip to last ones */ + } + else { + lua_getinfo(L1, "Slnt", &ar); + lua_pushfstring(L, "\n\t%s:", ar.short_src); + if (ar.currentline > 0) + lua_pushfstring(L, "%d:", ar.currentline); + lua_pushliteral(L, " in "); + compat53_pushfuncname(L, &ar); + lua_concat(L, lua_gettop(L) - top); + } + } + lua_concat(L, lua_gettop(L) - top); +} + +COMPAT53_API int luaL_fileresult(lua_State* L, int stat, const char* fname) { + const char* serr = NULL; + int en = errno; /* calls to Lua API may change this value */ + char buf[512] = { 0 }; + if (stat) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushnil(L); + serr = compat53_strerror(en, buf, sizeof(buf)); + if (fname) + lua_pushfstring(L, "%s: %s", fname, serr); + else + lua_pushstring(L, serr); + lua_pushnumber(L, (lua_Number)en); + return 3; + } +} + +static int compat53_checkmode(lua_State* L, const char* mode, const char* modename, int err) { + if (mode && strchr(mode, modename[0]) == NULL) { + lua_pushfstring(L, "attempt to load a %s chunk (mode is '%s')", modename, mode); + return err; + } + return LUA_OK; +} + +typedef struct { + lua_Reader reader; + void* ud; + int has_peeked_data; + const char* peeked_data; + size_t peeked_data_size; +} compat53_reader_data; + +static const char* compat53_reader(lua_State* L, void* ud, size_t* size) { + compat53_reader_data* data = (compat53_reader_data*)ud; + if (data->has_peeked_data) { + data->has_peeked_data = 0; + *size = data->peeked_data_size; + return data->peeked_data; + } + else + return data->reader(L, data->ud, size); +} + +COMPAT53_API int lua_load(lua_State* L, lua_Reader reader, void* data, const char* source, const char* mode) { + int status = LUA_OK; + compat53_reader_data compat53_data = { reader, data, 1, 0, 0 }; + compat53_data.peeked_data = reader(L, data, &(compat53_data.peeked_data_size)); + if (compat53_data.peeked_data && compat53_data.peeked_data_size && compat53_data.peeked_data[0] == LUA_SIGNATURE[0]) /* binary file? */ + status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX); + else + status = compat53_checkmode(L, mode, "text", LUA_ERRSYNTAX); + if (status != LUA_OK) + return status; + /* we need to call the original 5.1 version of lua_load! */ +#undef lua_load + return lua_load(L, compat53_reader, &compat53_data, source); +#define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53) +} + +typedef struct { + int n; /* number of pre-read characters */ + FILE* f; /* file being read */ + char buff[COMPAT53_LUA_FILE_BUFFER_SIZE]; /* area for reading file */ +} compat53_LoadF; + +static const char* compat53_getF(lua_State* L, void* ud, size_t* size) { + compat53_LoadF* lf = (compat53_LoadF*)ud; + (void)L; /* not used */ + if (lf->n > 0) { /* are there pre-read characters to be read? */ + *size = lf->n; /* return them (chars already in buffer) */ + lf->n = 0; /* no more pre-read characters */ + } + else { /* read a block from file */ + /* 'fread' can return > 0 *and* set the EOF flag. If next call to + 'compat53_getF' called 'fread', it might still wait for user input. + The next check avoids this problem. */ + if (feof(lf->f)) + return NULL; + *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ + } + return lf->buff; +} + +static int compat53_errfile(lua_State* L, const char* what, int fnameindex) { + char buf[512] = { 0 }; + const char* serr = compat53_strerror(errno, buf, sizeof(buf)); + const char* filename = lua_tostring(L, fnameindex) + 1; + lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); + lua_remove(L, fnameindex); + return LUA_ERRFILE; +} + +static int compat53_skipBOM(compat53_LoadF* lf) { + const char* p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ + int c; + lf->n = 0; + do { + c = getc(lf->f); + if (c == EOF || c != *(const unsigned char*)p++) + return c; + lf->buff[lf->n++] = (char)c; /* to be read by the parser */ + } while (*p != '\0'); + lf->n = 0; /* prefix matched; discard it */ + return getc(lf->f); /* return next character */ +} + +/* +** reads the first character of file 'f' and skips an optional BOM mark +** in its beginning plus its first line if it starts with '#'. Returns +** true if it skipped the first line. In any case, '*cp' has the +** first "valid" character of the file (after the optional BOM and +** a first-line comment). +*/ +static int compat53_skipcomment(compat53_LoadF* lf, int* cp) { + int c = *cp = compat53_skipBOM(lf); + if (c == '#') { /* first line is a comment (Unix exec. file)? */ + do { /* skip first line */ + c = getc(lf->f); + } while (c != EOF && c != '\n'); + *cp = getc(lf->f); /* skip end-of-line, if present */ + return 1; /* there was a comment */ + } + else + return 0; /* no comment */ +} + +COMPAT53_API int luaL_loadfilex(lua_State* L, const char* filename, const char* mode) { + compat53_LoadF lf; + int status, readstatus; + int c; + int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ + if (filename == NULL) { + lua_pushliteral(L, "=stdin"); + lf.f = stdin; + } + else { + lua_pushfstring(L, "@%s", filename); +#if defined(_MSC_VER) + /* This code is here to stop a deprecation error that stops builds + * if a certain macro is defined. While normally not caring would + * be best, some header-only libraries and builds can't afford to + * dictate this to the user. A quick check shows that fopen_s this + * goes back to VS 2005, and _fsopen goes back to VS 2003 .NET, + * possibly even before that so we don't need to do any version + * number checks, since this has been there since forever. */ + + /* TO USER: if you want the behavior of typical fopen_s/fopen, + * which does lock the file on VC++, define the macro used below to 0 */ +#if COMPAT53_FOPEN_NO_LOCK + lf.f = _fsopen(filename, "r", _SH_DENYNO); /* do not lock the file in any way */ + if (lf.f == NULL) + return compat53_errfile(L, "open", fnameindex); +#else /* use default locking version */ + if (fopen_s(&lf.f, filename, "r") != 0) + return compat53_errfile(L, "open", fnameindex); +#endif /* Locking vs. No-locking fopen variants */ +#else + lf.f = fopen(filename, "r"); /* default stdlib doesn't forcefully lock files here */ + if (lf.f == NULL) + return compat53_errfile(L, "open", fnameindex); +#endif + } + if (compat53_skipcomment(&lf, &c)) /* read initial portion */ + lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ + if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ +#if defined(_MSC_VER) + if (freopen_s(&lf.f, filename, "rb", lf.f) != 0) + return compat53_errfile(L, "reopen", fnameindex); +#else + lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ + if (lf.f == NULL) + return compat53_errfile(L, "reopen", fnameindex); +#endif + compat53_skipcomment(&lf, &c); /* re-read initial portion */ + } + if (c != EOF) + lf.buff[lf.n++] = (char)c; /* 'c' is the first character of the stream */ + status = lua_load(L, &compat53_getF, &lf, lua_tostring(L, -1), mode); + readstatus = ferror(lf.f); + if (filename) + fclose(lf.f); /* close file (even in case of errors) */ + if (readstatus) { + lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ + return compat53_errfile(L, "read", fnameindex); + } + lua_remove(L, fnameindex); + return status; +} + +COMPAT53_API int luaL_loadbufferx(lua_State* L, const char* buff, size_t sz, const char* name, const char* mode) { + int status = LUA_OK; + if (sz > 0 && buff[0] == LUA_SIGNATURE[0]) { + status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX); + } + else { + status = compat53_checkmode(L, mode, "text", LUA_ERRSYNTAX); + } + if (status != LUA_OK) + return status; + return luaL_loadbuffer(L, buff, sz, name); +} + +#if !defined(l_inspectstat) \ + && (defined(unix) || defined(__unix) || defined(__unix__) || defined(__TOS_AIX__) || defined(_SYSTYPE_BSD) || (defined(__APPLE__) && defined(__MACH__))) +/* some form of unix; check feature macros in unistd.h for details */ +#include <unistd.h> +/* check posix version; the relevant include files and macros probably + * were available before 2001, but I'm not sure */ +#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L +#include <sys/wait.h> +#define l_inspectstat(stat, what) \ + if (WIFEXITED(stat)) { \ + stat = WEXITSTATUS(stat); \ + } \ + else if (WIFSIGNALED(stat)) { \ + stat = WTERMSIG(stat); \ + what = "signal"; \ + } +#endif +#endif + +/* provide default (no-op) version */ +#if !defined(l_inspectstat) +#define l_inspectstat(stat, what) ((void)0) +#endif + +COMPAT53_API int luaL_execresult(lua_State* L, int stat) { + const char* what = "exit"; + if (stat == -1) + return luaL_fileresult(L, 0, NULL); + else { + l_inspectstat(stat, what); + if (*what == 'e' && stat == 0) + lua_pushboolean(L, 1); + else + lua_pushnil(L); + lua_pushstring(L, what); + lua_pushinteger(L, stat); + return 3; + } +} + +COMPAT53_API void luaL_buffinit(lua_State* L, luaL_Buffer_53* B) { + /* make it crash if used via pointer to a 5.1-style luaL_Buffer */ + B->b.p = NULL; + B->b.L = NULL; + B->b.lvl = 0; + /* reuse the buffer from the 5.1-style luaL_Buffer though! */ + B->ptr = B->b.buffer; + B->capacity = LUAL_BUFFERSIZE; + B->nelems = 0; + B->L2 = L; +} + +COMPAT53_API char* luaL_prepbuffsize(luaL_Buffer_53* B, size_t s) { + if (B->capacity - B->nelems < s) { /* needs to grow */ + char* newptr = NULL; + size_t newcap = B->capacity * 2; + if (newcap - B->nelems < s) + newcap = B->nelems + s; + if (newcap < B->capacity) /* overflow */ + luaL_error(B->L2, "buffer too large"); +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504 + newptr = (char*)lua_newuserdatauv(B->L2, newcap, 0); +#else + newptr = (char*)lua_newuserdata(B->L2, newcap); +#endif + memcpy(newptr, B->ptr, B->nelems); + if (B->ptr != B->b.buffer) + lua_replace(B->L2, -2); /* remove old buffer */ + B->ptr = newptr; + B->capacity = newcap; + } + return B->ptr + B->nelems; +} + +COMPAT53_API void luaL_addlstring(luaL_Buffer_53* B, const char* s, size_t l) { + memcpy(luaL_prepbuffsize(B, l), s, l); + luaL_addsize(B, l); +} + +COMPAT53_API void luaL_addvalue(luaL_Buffer_53* B) { + size_t len = 0; + const char* s = lua_tolstring(B->L2, -1, &len); + if (!s) + luaL_error(B->L2, "cannot convert value to string"); + if (B->ptr != B->b.buffer) + lua_insert(B->L2, -2); /* userdata buffer must be at stack top */ + luaL_addlstring(B, s, len); + lua_remove(B->L2, B->ptr != B->b.buffer ? -2 : -1); +} + +void luaL_pushresult(luaL_Buffer_53* B) { + lua_pushlstring(B->L2, B->ptr, B->nelems); + if (B->ptr != B->b.buffer) + lua_replace(B->L2, -2); /* remove userdata buffer */ +} + +#endif /* Lua 5.1 */ + +/* definitions for Lua 5.1 and Lua 5.2 */ +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 502 + +COMPAT53_API int lua_geti(lua_State* L, int index, lua_Integer i) { + index = lua_absindex(L, index); + lua_pushinteger(L, i); + lua_gettable(L, index); + return lua_type(L, -1); +} + +COMPAT53_API int lua_isinteger(lua_State* L, int index) { + if (lua_type(L, index) == LUA_TNUMBER) { + lua_Number n = lua_tonumber(L, index); + lua_Integer i = lua_tointeger(L, index); + if (i == n) + return 1; + } + return 0; +} + +COMPAT53_API lua_Integer lua_tointegerx(lua_State* L, int i, int* isnum) { + int ok = 0; + lua_Number n = lua_tonumberx(L, i, &ok); + if (ok) { + if (n == (lua_Integer)n) { + if (isnum) + *isnum = 1; + return (lua_Integer)n; + } + } + if (isnum) + *isnum = 0; + return 0; +} + +static void compat53_reverse(lua_State* L, int a, int b) { + for (; a < b; ++a, --b) { + lua_pushvalue(L, a); + lua_pushvalue(L, b); + lua_replace(L, a); + lua_replace(L, b); + } +} + +COMPAT53_API void lua_rotate(lua_State* L, int idx, int n) { + int n_elems = 0; + idx = lua_absindex(L, idx); + n_elems = lua_gettop(L) - idx + 1; + if (n < 0) + n += n_elems; + if (n > 0 && n < n_elems) { + luaL_checkstack(L, 2, "not enough stack slots available"); + n = n_elems - n; + compat53_reverse(L, idx, idx + n - 1); + compat53_reverse(L, idx + n, idx + n_elems - 1); + compat53_reverse(L, idx, idx + n_elems - 1); + } +} + +COMPAT53_API void lua_seti(lua_State* L, int index, lua_Integer i) { + luaL_checkstack(L, 1, "not enough stack slots available"); + index = lua_absindex(L, index); + lua_pushinteger(L, i); + lua_insert(L, -2); + lua_settable(L, index); +} + +#if !defined(lua_str2number) +#define lua_str2number(s, p) strtod((s), (p)) +#endif + +COMPAT53_API size_t lua_stringtonumber(lua_State* L, const char* s) { + char* endptr; + lua_Number n = lua_str2number(s, &endptr); + if (endptr != s) { + while (*endptr != '\0' && isspace((unsigned char)*endptr)) + ++endptr; + if (*endptr == '\0') { + lua_pushnumber(L, n); + return endptr - s + 1; + } + } + return 0; +} + +COMPAT53_API const char* luaL_tolstring(lua_State* L, int idx, size_t* len) { + if (!luaL_callmeta(L, idx, "__tostring")) { + int t = lua_type(L, idx), tt = 0; + char const* name = NULL; + switch (t) { + case LUA_TNIL: + lua_pushliteral(L, "nil"); + break; + case LUA_TSTRING: + case LUA_TNUMBER: + lua_pushvalue(L, idx); + break; + case LUA_TBOOLEAN: + if (lua_toboolean(L, idx)) + lua_pushliteral(L, "true"); + else + lua_pushliteral(L, "false"); + break; + default: + tt = luaL_getmetafield(L, idx, "__name"); + name = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : lua_typename(L, t); + lua_pushfstring(L, "%s: %p", name, lua_topointer(L, idx)); + if (tt != LUA_TNIL) + lua_replace(L, -2); + break; + } + } + else { + if (!lua_isstring(L, -1)) + luaL_error(L, "'__tostring' must return a string"); + } + return lua_tolstring(L, -1, len); +} + +COMPAT53_API void luaL_requiref(lua_State* L, const char* modname, lua_CFunction openf, int glb) { + luaL_checkstack(L, 3, "not enough stack slots available"); + luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); + if (lua_getfield(L, -1, modname) == LUA_TNIL) { + lua_pop(L, 1); + lua_pushcfunction(L, openf); + lua_pushstring(L, modname); + lua_call(L, 1, 1); + lua_pushvalue(L, -1); + lua_setfield(L, -3, modname); + } + if (glb) { + lua_pushvalue(L, -1); + lua_setglobal(L, modname); + } + lua_replace(L, -2); +} + +#endif /* Lua 5.1 and 5.2 */ + +#endif /* KEPLER_PROJECT_COMPAT53_C_ */ + +/********************************************************************* + * This file contains parts of Lua 5.2's and Lua 5.3's source code: + * + * Copyright (C) 1994-2014 Lua.org, PUC-Rio. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *********************************************************************/ +// end of sol/compatibility/compat-5.3.c.h + +#endif + +#endif /* KEPLER_PROJECT_COMPAT53_H_ */ + +// end of sol/compatibility/compat-5.3.h + +// beginning of sol/compatibility/compat-5.4.h + +#ifndef NOT_KEPLER_PROJECT_COMPAT54_H_ +#define NOT_KEPLER_PROJECT_COMPAT54_H_ + +#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) +extern "C" { +#endif +#include <lua.h> +#include <lauxlib.h> +#include <lualib.h> +#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) +} +#endif + +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 504 + +#if !defined(LUA_ERRGCMM) +/* So Lua 5.4 actually removes this, which breaks sol2... + man, this API is quite unstable...! +*/ +# define LUA_ERRGCMM (LUA_ERRERR + 2) +#endif /* LUA_ERRGCMM define */ + +#endif // Lua 5.4 only + +#endif // NOT_KEPLER_PROJECT_COMPAT54_H_// end of sol/compatibility/compat-5.4.h + +#endif + +// end of sol/compatibility.hpp + +#include <vector> +#include <cstdint> +#include <cstddef> + +namespace sol { + + template <typename Allocator = std::allocator<std::byte>> + class basic_bytecode : private std::vector<std::byte, Allocator> { + private: + using base_t = std::vector<std::byte, Allocator>; + + public: + using typename base_t::allocator_type; + using typename base_t::const_iterator; + using typename base_t::const_pointer; + using typename base_t::const_reference; + using typename base_t::const_reverse_iterator; + using typename base_t::difference_type; + using typename base_t::iterator; + using typename base_t::pointer; + using typename base_t::reference; + using typename base_t::reverse_iterator; + using typename base_t::size_type; + using typename base_t::value_type; + + using base_t::base_t; + using base_t::operator=; + + using base_t::data; + using base_t::empty; + using base_t::max_size; + using base_t::size; + + using base_t::at; + using base_t::operator[]; + using base_t::back; + using base_t::front; + + using base_t::begin; + using base_t::cbegin; + using base_t::cend; + using base_t::end; + + using base_t::crbegin; + using base_t::crend; + using base_t::rbegin; + using base_t::rend; + + using base_t::get_allocator; + using base_t::swap; + + using base_t::clear; + using base_t::emplace; + using base_t::emplace_back; + using base_t::erase; + using base_t::insert; + using base_t::pop_back; + using base_t::push_back; + using base_t::reserve; + using base_t::resize; + using base_t::shrink_to_fit; + + string_view as_string_view() const { + return string_view(reinterpret_cast<const char*>(this->data()), this->size()); + } + }; + + template <typename Container> + inline int basic_insert_dump_writer(lua_State*, const void* memory, size_t memory_size, void* userdata_pointer) { + using storage_t = Container; + const std::byte* p_code = static_cast<const std::byte*>(memory); + storage_t& bc = *static_cast<storage_t*>(userdata_pointer); +#if SOL_IS_OFF(SOL_EXCEPTIONS) + bc.insert(bc.cend(), p_code, p_code + memory_size); +#else + try { + bc.insert(bc.cend(), p_code, p_code + memory_size); + } + catch (...) { + return -1; + } +#endif + return 0; + } + + using bytecode = basic_bytecode<>; + + constexpr inline auto bytecode_dump_writer = &basic_insert_dump_writer<bytecode>; + +} // namespace sol + +// end of sol/bytecode.hpp + +// beginning of sol/stack.hpp + +// beginning of sol/trampoline.hpp + +// beginning of sol/types.hpp + +// beginning of sol/error.hpp + +#include <stdexcept> +#include <string> +#include <array> + +namespace sol { + namespace detail { + struct direct_error_tag { }; + const auto direct_error = direct_error_tag {}; + + struct error_result { + int results; + const char* format_string; + std::array<const char*, 4> argument_strings; + + error_result() : results(0), format_string(nullptr) { + } + + error_result(int results_) : results(results_), format_string(nullptr) { + } + + error_result(const char* format_string_, const char* first_message_) : results(0), format_string(format_string_), argument_strings() { + argument_strings[0] = first_message_; + } + }; + + inline int handle_errors(lua_State* L, const error_result& er) { + if (er.format_string == nullptr) { + return er.results; + } + return luaL_error(L, er.format_string, er.argument_strings[0], er.argument_strings[1], er.argument_strings[2], er.argument_strings[3]); + } + } // namespace detail + + class error : public std::runtime_error { + private: + // Because VC++ is upsetting, most of the time! + std::string what_reason; + + public: + error(const std::string& str) : error(detail::direct_error, "lua: error: " + str) { + } + error(std::string&& str) : error(detail::direct_error, "lua: error: " + std::move(str)) { + } + error(detail::direct_error_tag, const std::string& str) : std::runtime_error(""), what_reason(str) { + } + error(detail::direct_error_tag, std::string&& str) : std::runtime_error(""), what_reason(std::move(str)) { + } + + error(const error& e) = default; + error(error&& e) = default; + error& operator=(const error& e) = default; + error& operator=(error&& e) = default; + + virtual const char* what() const noexcept override { + return what_reason.c_str(); + } + }; + +} // namespace sol + +// end of sol/error.hpp + +// beginning of sol/optional.hpp + +// beginning of sol/in_place.hpp + +#include <cstddef> +#include <utility> + +namespace sol { + + using in_place_t = std::in_place_t; + constexpr std::in_place_t in_place {}; + constexpr std::in_place_t in_place_of {}; + + template <typename T> + using in_place_type_t = std::in_place_type_t<T>; + template <typename T> + constexpr std::in_place_type_t<T> in_place_type {}; + + template <size_t I> + using in_place_index_t = std::in_place_index_t<I>; + template <size_t I> + constexpr in_place_index_t<I> in_place_index {}; + +} // namespace sol + +// end of sol/in_place.hpp + +#if SOL_IS_ON(SOL_USE_BOOST) +#include <boost/optional.hpp> +#else +// beginning of sol/optional_implementation.hpp + +#define SOL_TL_OPTIONAL_VERSION_MAJOR 0 +#define SOL_TL_OPTIONAL_VERSION_MINOR 5 + +#include <exception> +#include <functional> +#include <new> +#include <type_traits> +#include <utility> +#include <cstdlib> +#include <optional> + +#if (defined(_MSC_VER) && _MSC_VER == 1900) +#define SOL_TL_OPTIONAL_MSVC2015 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__)) +#define SOL_TL_OPTIONAL_GCC49 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && !defined(__clang__)) +#define SOL_TL_OPTIONAL_GCC54 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && !defined(__clang__)) +#define SOL_TL_OPTIONAL_GCC55 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__)) +#define SOL_TL_OPTIONAL_NO_CONSTRR + +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) std::has_trivial_copy_constructor<T>::value +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::has_trivial_copy_assign<T>::value + +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value + +#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__)) +#ifndef SOL_TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +#define SOL_TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +namespace sol { namespace detail { + template <class T> + struct is_trivially_copy_constructible : std::is_trivially_copy_constructible<T> { }; +#ifdef _GLIBCXX_VECTOR + template <class T, class A> + struct is_trivially_copy_constructible<std::vector<T, A>> : std::is_trivially_copy_constructible<T> { }; +#endif +}} // namespace sol::detail +#endif + +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) sol::detail::is_trivially_copy_constructible<T>::value +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::is_trivially_copy_assignable<T>::value +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value +#else +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) std::is_trivially_copy_constructible<T>::value +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::is_trivially_copy_assignable<T>::value +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value +#endif + +#if __cplusplus > 201103L +#define SOL_TL_OPTIONAL_CXX14 +#endif + +#if (__cplusplus == 201103L || defined(SOL_TL_OPTIONAL_MSVC2015) || defined(SOL_TL_OPTIONAL_GCC49)) +#define SOL_TL_OPTIONAL_11_CONSTEXPR +#else + /// \exclude +#define SOL_TL_OPTIONAL_11_CONSTEXPR constexpr +#endif + +namespace sol { +#ifndef SOL_TL_MONOSTATE_INPLACE_MUTEX +#define SOL_TL_MONOSTATE_INPLACE_MUTEX + /// \brief Used to represent an optional with no data; essentially a bool + class monostate { }; +#endif + + template <class T> + class optional; + + /// \exclude + namespace detail { +#ifndef SOL_TL_TRAITS_MUTEX +#define SOL_TL_TRAITS_MUTEX + // C++14-style aliases for brevity + template <class T> + using remove_const_t = typename std::remove_const<T>::type; + template <class T> + using remove_reference_t = typename std::remove_reference<T>::type; + template <class T> + using decay_t = typename std::decay<T>::type; + template <bool E, class T = void> + using enable_if_t = typename std::enable_if<E, T>::type; + template <bool B, class T, class F> + using conditional_t = typename std::conditional<B, T, F>::type; + + // std::conjunction from C++17 + template <class...> + struct conjunction : std::true_type { }; + template <class B> + struct conjunction<B> : B { }; + template <class B, class... Bs> + struct conjunction<B, Bs...> : std::conditional<bool(B::value), conjunction<Bs...>, B>::type { }; + +#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L +#define SOL_TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND +#endif + +#ifdef SOL_TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND + template <class T> + struct is_pointer_to_non_const_member_func : std::false_type { }; + template <class T, class Ret, class... Args> + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)> : std::true_type { }; + template <class T, class Ret, class... Args> + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)&> : std::true_type { }; + template <class T, class Ret, class... Args> + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&> : std::true_type { }; + template <class T, class Ret, class... Args> + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile> : std::true_type { }; + template <class T, class Ret, class... Args> + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile&> : std::true_type { }; + template <class T, class Ret, class... Args> + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile&&> : std::true_type { }; + + template <class T> + struct is_const_or_const_ref : std::false_type { }; + template <class T> + struct is_const_or_const_ref<T const&> : std::true_type { }; + template <class T> + struct is_const_or_const_ref<T const> : std::true_type { }; +#endif + + // std::invoke from C++17 + // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround + template <typename Fn, typename... Args, +#ifdef SOL_TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND + typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value && is_const_or_const_ref<Args...>::value)>, +#endif + typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0> + constexpr auto invoke(Fn&& f, Args&&... args) noexcept(noexcept(std::mem_fn(f)(std::forward<Args>(args)...))) + -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) { + return std::mem_fn(f)(std::forward<Args>(args)...); + } + + template <typename Fn, typename... Args, typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>> + constexpr auto invoke(Fn&& f, Args&&... args) noexcept(noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...))) + -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) { + return std::forward<Fn>(f)(std::forward<Args>(args)...); + } + + // std::invoke_result from C++17 + template <class F, class, class... Us> + struct invoke_result_impl; + + template <class F, class... Us> + struct invoke_result_impl<F, decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()), Us...> { + using type = decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...)); + }; + + template <class F, class... Us> + using invoke_result = invoke_result_impl<F, void, Us...>; + + template <class F, class... Us> + using invoke_result_t = typename invoke_result<F, Us...>::type; +#endif + + // std::void_t from C++17 + template <class...> + struct voider { + using type = void; + }; + template <class... Ts> + using void_t = typename voider<Ts...>::type; + + // Trait for checking if a type is a sol::optional + template <class T> + struct is_optional_impl : std::false_type { }; + template <class T> + struct is_optional_impl<optional<T>> : std::true_type { }; + template <class T> + using is_optional = is_optional_impl<decay_t<T>>; + + // Change void to sol::monostate + template <class U> + using fixup_void = conditional_t<std::is_void<U>::value, monostate, U>; + + template <class F, class U, class = invoke_result_t<F, U>> + using get_map_return = optional<fixup_void<invoke_result_t<F, U>>>; + + // Check if invoking F for some Us returns void + template <class F, class = void, class... U> + struct returns_void_impl; + template <class F, class... U> + struct returns_void_impl<F, void_t<invoke_result_t<F, U...>>, U...> : std::is_void<invoke_result_t<F, U...>> { }; + template <class F, class... U> + using returns_void = returns_void_impl<F, void, U...>; + + template <class T, class... U> + using enable_if_ret_void = enable_if_t<returns_void<T&&, U...>::value>; + + template <class T, class... U> + using disable_if_ret_void = enable_if_t<!returns_void<T&&, U...>::value>; + + template <class T, class U> + using enable_forward_value = detail::enable_if_t<std::is_constructible<T, U&&>::value && !std::is_same<detail::decay_t<U>, in_place_t>::value + && !std::is_same<optional<T>, detail::decay_t<U>>::value>; + + template <class T, class U, class Other> + using enable_from_other = detail::enable_if_t<std::is_constructible<T, Other>::value && !std::is_constructible<T, optional<U>&>::value + && !std::is_constructible<T, optional<U>&&>::value && !std::is_constructible<T, const optional<U>&>::value + && !std::is_constructible<T, const optional<U>&&>::value && !std::is_convertible<optional<U>&, T>::value + && !std::is_convertible<optional<U>&&, T>::value && !std::is_convertible<const optional<U>&, T>::value + && !std::is_convertible<const optional<U>&&, T>::value>; + + template <class T, class U> + using enable_assign_forward = detail::enable_if_t<!std::is_same<optional<T>, detail::decay_t<U>>::value + && !detail::conjunction<std::is_scalar<T>, std::is_same<T, detail::decay_t<U>>>::value && std::is_constructible<T, U>::value + && std::is_assignable<T&, U>::value>; + + template <class T, class U, class Other> + using enable_assign_from_other = detail::enable_if_t<std::is_constructible<T, Other>::value && std::is_assignable<T&, Other>::value + && !std::is_constructible<T, optional<U>&>::value && !std::is_constructible<T, optional<U>&&>::value + && !std::is_constructible<T, const optional<U>&>::value && !std::is_constructible<T, const optional<U>&&>::value + && !std::is_convertible<optional<U>&, T>::value && !std::is_convertible<optional<U>&&, T>::value + && !std::is_convertible<const optional<U>&, T>::value && !std::is_convertible<const optional<U>&&, T>::value + && !std::is_assignable<T&, optional<U>&>::value && !std::is_assignable<T&, optional<U>&&>::value + && !std::is_assignable<T&, const optional<U>&>::value && !std::is_assignable<T&, const optional<U>&&>::value>; + +#ifdef _MSC_VER + // TODO make a version which works with MSVC + template <class T, class U = T> + struct is_swappable : std::true_type { }; + + template <class T, class U = T> + struct is_nothrow_swappable : std::true_type { }; +#else + // https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept + namespace swap_adl_tests { + // if swap ADL finds this then it would call std::swap otherwise (same + // signature) + struct tag { }; + + template <class T> + tag swap(T&, T&); + template <class T, std::size_t N> + tag swap(T (&a)[N], T (&b)[N]); + + // helper functions to test if an unqualified swap is possible, and if it + // becomes std::swap + template <class, class> + std::false_type can_swap(...) noexcept(false); + template <class T, class U, class = decltype(swap(std::declval<T&>(), std::declval<U&>()))> + std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T&>(), std::declval<U&>()))); + + template <class, class> + std::false_type uses_std(...); + template <class T, class U> + std::is_same<decltype(swap(std::declval<T&>(), std::declval<U&>())), tag> uses_std(int); + + template <class T> + struct is_std_swap_noexcept + : std::integral_constant<bool, std::is_nothrow_move_constructible<T>::value && std::is_nothrow_move_assignable<T>::value> { }; + + template <class T, std::size_t N> + struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> { }; + + template <class T, class U> + struct is_adl_swap_noexcept : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> { }; + } // namespace swap_adl_tests + + template <class T, class U = T> + struct is_swappable : std::integral_constant<bool, + decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value + && (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value + || (std::is_move_assignable<T>::value && std::is_move_constructible<T>::value))> { }; + + template <class T, std::size_t N> + struct is_swappable<T[N], T[N]> : std::integral_constant<bool, + decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value + && (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value || is_swappable<T, T>::value)> { }; + + template <class T, class U = T> + struct is_nothrow_swappable + : std::integral_constant<bool, + is_swappable<T, U>::value + && ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value&& detail::swap_adl_tests::is_std_swap_noexcept<T>::value) + || (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value&& detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> { }; +#endif + + // The storage base manages the actual storage, and correctly propagates + // trivial destroyion from T. This case is for when T is not trivially + // destructible. + template <class T, bool = ::std::is_trivially_destructible<T>::value> + struct optional_storage_base { + SOL_TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept : m_dummy(), m_has_value(false) { + } + + template <class... U> + SOL_TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U&&... u) : m_value(std::forward<U>(u)...), m_has_value(true) { + } + + ~optional_storage_base() { + if (m_has_value) { + m_value.~T(); + m_has_value = false; + } + } + + struct dummy { }; + union { + dummy m_dummy; + T m_value; + }; + + bool m_has_value; + }; + + // This case is for when T is trivially destructible. + template <class T> + struct optional_storage_base<T, true> { + SOL_TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept : m_dummy(), m_has_value(false) { + } + + template <class... U> + SOL_TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U&&... u) : m_value(std::forward<U>(u)...), m_has_value(true) { + } + + // No destructor, so this class is trivially destructible + + struct dummy { }; + union { + dummy m_dummy; + T m_value; + }; + + bool m_has_value = false; + }; + + // This base class provides some handy member functions which can be used in + // further derived classes + template <class T> + struct optional_operations_base : optional_storage_base<T> { + using optional_storage_base<T>::optional_storage_base; + + void hard_reset() noexcept { + get().~T(); + this->m_has_value = false; + } + + template <class... Args> + void construct(Args&&... args) noexcept { + new (std::addressof(this->m_value)) T(std::forward<Args>(args)...); + this->m_has_value = true; + } + + template <class Opt> + void assign(Opt&& rhs) { + if (this->has_value()) { + if (rhs.has_value()) { + this->m_value = std::forward<Opt>(rhs).get(); + } + else { + this->m_value.~T(); + this->m_has_value = false; + } + } + + else if (rhs.has_value()) { + construct(std::forward<Opt>(rhs).get()); + } + } + + bool has_value() const { + return this->m_has_value; + } + + SOL_TL_OPTIONAL_11_CONSTEXPR T& get() & { + return this->m_value; + } + SOL_TL_OPTIONAL_11_CONSTEXPR const T& get() const& { + return this->m_value; + } + SOL_TL_OPTIONAL_11_CONSTEXPR T&& get() && { + return std::move(this->m_value); + } +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + constexpr const T&& get() const&& { + return std::move(this->m_value); + } +#endif + }; + + // This class manages conditionally having a trivial copy constructor + // This specialization is for when T is trivially copy constructible + template <class T, bool = SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)> + struct optional_copy_base : optional_operations_base<T> { + using optional_operations_base<T>::optional_operations_base; + }; + + // This specialization is for when T is not trivially copy constructible + template <class T> + struct optional_copy_base<T, false> : optional_operations_base<T> { + using base_t = optional_operations_base<T>; + + using base_t::base_t; + + optional_copy_base() = default; + optional_copy_base(const optional_copy_base& rhs) : base_t() { + if (rhs.has_value()) { + this->construct(rhs.get()); + } + else { + this->m_has_value = false; + } + } + + optional_copy_base(optional_copy_base&& rhs) = default; + optional_copy_base& operator=(const optional_copy_base& rhs) = default; + optional_copy_base& operator=(optional_copy_base&& rhs) = default; + }; + +#ifndef SOL_TL_OPTIONAL_GCC49 + template <class T, bool = std::is_trivially_move_constructible<T>::value> + struct optional_move_base : optional_copy_base<T> { + using optional_copy_base<T>::optional_copy_base; + }; +#else + template <class T, bool = false> + struct optional_move_base; +#endif + template <class T> + struct optional_move_base<T, false> : optional_copy_base<T> { + using optional_copy_base<T>::optional_copy_base; + + optional_move_base() = default; + optional_move_base(const optional_move_base& rhs) = default; + + optional_move_base(optional_move_base&& rhs) noexcept(std::is_nothrow_move_constructible<T>::value) { + if (rhs.has_value()) { + this->construct(std::move(rhs.get())); + } + else { + this->m_has_value = false; + } + } + optional_move_base& operator=(const optional_move_base& rhs) = default; + optional_move_base& operator=(optional_move_base&& rhs) = default; + }; + + // This class manages conditionally having a trivial copy assignment operator + template <class T, + bool = SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) && SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) + && SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T)> + struct optional_copy_assign_base : optional_move_base<T> { + using optional_move_base<T>::optional_move_base; + }; + + template <class T> + struct optional_copy_assign_base<T, false> : optional_move_base<T> { + using optional_move_base<T>::optional_move_base; + + optional_copy_assign_base() = default; + optional_copy_assign_base(const optional_copy_assign_base& rhs) = default; + + optional_copy_assign_base(optional_copy_assign_base&& rhs) = default; + optional_copy_assign_base& operator=(const optional_copy_assign_base& rhs) { + this->assign(rhs); + return *this; + } + optional_copy_assign_base& operator=(optional_copy_assign_base&& rhs) = default; + }; + +#ifndef SOL_TL_OPTIONAL_GCC49 + template <class T, + bool = std::is_trivially_destructible<T>::value&& std::is_trivially_move_constructible<T>::value&& std::is_trivially_move_assignable<T>::value> + struct optional_move_assign_base : optional_copy_assign_base<T> { + using optional_copy_assign_base<T>::optional_copy_assign_base; + }; +#else + template <class T, bool = false> + struct optional_move_assign_base; +#endif + + template <class T> + struct optional_move_assign_base<T, false> : optional_copy_assign_base<T> { + using optional_copy_assign_base<T>::optional_copy_assign_base; + + optional_move_assign_base() = default; + optional_move_assign_base(const optional_move_assign_base& rhs) = default; + + optional_move_assign_base(optional_move_assign_base&& rhs) = default; + + optional_move_assign_base& operator=(const optional_move_assign_base& rhs) = default; + + optional_move_assign_base& operator=(optional_move_assign_base&& rhs) noexcept( + std::is_nothrow_move_constructible<T>::value&& std::is_nothrow_move_assignable<T>::value) { + this->assign(std::move(rhs)); + return *this; + } + }; + + // optional_delete_ctor_base will conditionally delete copy and move + // constructors depending on whether T is copy/move constructible + template <class T, bool EnableCopy = std::is_copy_constructible<T>::value, bool EnableMove = std::is_move_constructible<T>::value> + struct optional_delete_ctor_base { + optional_delete_ctor_base() = default; + optional_delete_ctor_base(const optional_delete_ctor_base&) = default; + optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = default; + optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default; + optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default; + }; + + template <class T> + struct optional_delete_ctor_base<T, true, false> { + optional_delete_ctor_base() = default; + optional_delete_ctor_base(const optional_delete_ctor_base&) = default; + optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = delete; + optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default; + optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default; + }; + + template <class T> + struct optional_delete_ctor_base<T, false, true> { + optional_delete_ctor_base() = default; + optional_delete_ctor_base(const optional_delete_ctor_base&) = delete; + optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = default; + optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default; + optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default; + }; + + template <class T> + struct optional_delete_ctor_base<T, false, false> { + optional_delete_ctor_base() = default; + optional_delete_ctor_base(const optional_delete_ctor_base&) = delete; + optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = delete; + optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default; + optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default; + }; + + // optional_delete_assign_base will conditionally delete copy and move + // constructors depending on whether T is copy/move constructible + assignable + template <class T, bool EnableCopy = (std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value), + bool EnableMove = (std::is_move_constructible<T>::value && std::is_move_assignable<T>::value)> + struct optional_delete_assign_base { + optional_delete_assign_base() = default; + optional_delete_assign_base(const optional_delete_assign_base&) = default; + optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default; + optional_delete_assign_base& operator=(const optional_delete_assign_base&) = default; + optional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = default; + }; + + template <class T> + struct optional_delete_assign_base<T, true, false> { + optional_delete_assign_base() = default; + optional_delete_assign_base(const optional_delete_assign_base&) = default; + optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default; + optional_delete_assign_base& operator=(const optional_delete_assign_base&) = default; + optional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = delete; + }; + + template <class T> + struct optional_delete_assign_base<T, false, true> { + optional_delete_assign_base() = default; + optional_delete_assign_base(const optional_delete_assign_base&) = default; + optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default; + optional_delete_assign_base& operator=(const optional_delete_assign_base&) = delete; + optional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = default; + }; + + template <class T> + struct optional_delete_assign_base<T, false, false> { + optional_delete_assign_base() = default; + optional_delete_assign_base(const optional_delete_assign_base&) = default; + optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default; + optional_delete_assign_base& operator=(const optional_delete_assign_base&) = delete; + optional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = delete; + }; + + } // namespace detail + + /// \brief A tag type to represent an empty optional + using nullopt_t = std::nullopt_t; + + /// \brief Represents an empty optional + /// \synopsis static constexpr nullopt_t nullopt; + /// + /// *Examples*: + /// ``` + /// sol::optional<int> a = sol::nullopt; + /// void foo (sol::optional<int>); + /// foo(sol::nullopt); //pass an empty optional + /// ``` + using std::nullopt; + + /// @brief An exception for when an optional is accessed through specific methods while it is not engaged. + class bad_optional_access : public std::exception { + public: + /// @brief Default-constructs an optional exception. + bad_optional_access() = default; + /// @brief Returns a pointer to a null-terminated string containing the reason for the exception. + const char* what() const noexcept override { + return "Optional has no value"; + } + }; + + /// An optional object is an object that contains the storage for another + /// object and manages the lifetime of this contained object, if any. The + /// contained object may be initialized after the optional object has been + /// initialized, and may be destroyed before the optional object has been + /// destroyed. The initialization state of the contained object is tracked by + /// the optional object. + template <class T> + class optional : private detail::optional_move_assign_base<T>, + private detail::optional_delete_ctor_base<T>, + private detail::optional_delete_assign_base<T> { + using base = detail::optional_move_assign_base<T>; + + static_assert(!std::is_same<T, in_place_t>::value, "instantiation of optional with in_place_t is ill-formed"); + static_assert(!std::is_same<detail::decay_t<T>, nullopt_t>::value, "instantiation of optional with nullopt_t is ill-formed"); + + public: +#if defined(SOL_TL_OPTIONAL_CXX14) && !defined(SOL_TL_OPTIONAL_GCC49) && !defined(SOL_TL_OPTIONAL_GCC54) && !defined(SOL_TL_OPTIONAL_GCC55) + /// \group and_then + /// Carries out some operation which returns an optional on the stored + /// object if there is one. \requires `std::invoke(std::forward<F>(f), + /// value())` returns a `std::optional<U>` for some `U`. \returns Let `U` be + /// the result of `std::invoke(std::forward<F>(f), value())`. Returns a + /// `std::optional<U>`. The return value is empty if `*this` is empty, + /// otherwise the return value of `std::invoke(std::forward<F>(f), value())` + /// is returned. + /// \group and_then + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) & { + using result = detail::invoke_result_t<F, T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + + /// \group and_then + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &&; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) && { + using result = detail::invoke_result_t<F, T&&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt); + } + + /// \group and_then + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &; + template <class F> + constexpr auto and_then(F&& f) const& { + using result = detail::invoke_result_t<F, const T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group and_then + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &&; + template <class F> + constexpr auto and_then(F&& f) const&& { + using result = detail::invoke_result_t<F, const T&&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt); + } +#endif +#else + /// \group and_then + /// Carries out some operation which returns an optional on the stored + /// object if there is one. \requires `std::invoke(std::forward<F>(f), + /// value())` returns a `std::optional<U>` for some `U`. + /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), + /// value())`. Returns a `std::optional<U>`. The return value is empty if + /// `*this` is empty, otherwise the return value of + /// `std::invoke(std::forward<F>(f), value())` is returned. + /// \group and_then + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&> and_then(F&& f) & { + using result = detail::invoke_result_t<F, T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + + /// \group and_then + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &&; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&&> and_then(F&& f) && { + using result = detail::invoke_result_t<F, T&&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt); + } + + /// \group and_then + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &; + template <class F> + constexpr detail::invoke_result_t<F, const T&> and_then(F&& f) const& { + using result = detail::invoke_result_t<F, const T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group and_then + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &&; + template <class F> + constexpr detail::invoke_result_t<F, const T&&> and_then(F&& f) const&& { + using result = detail::invoke_result_t<F, const T&&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt); + } +#endif +#endif + +#if defined(SOL_TL_OPTIONAL_CXX14) && !defined(SOL_TL_OPTIONAL_GCC49) && !defined(SOL_TL_OPTIONAL_GCC54) && !defined(SOL_TL_OPTIONAL_GCC55) + /// \brief Carries out some operation on the stored object if there is one. + /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), + /// value())`. Returns a `std::optional<U>`. The return value is empty if + /// `*this` is empty, otherwise an `optional<U>` is constructed from the + /// return value of `std::invoke(std::forward<F>(f), value())` and is + /// returned. + /// + /// \group map + /// \synopsis template <class F> constexpr auto map(F &&f) &; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) & { + return optional_map_impl(*this, std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> constexpr auto map(F &&f) &&; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) && { + return optional_map_impl(std::move(*this), std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> constexpr auto map(F &&f) const&; + template <class F> + constexpr auto map(F&& f) const& { + return optional_map_impl(*this, std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> constexpr auto map(F &&f) const&&; + template <class F> + constexpr auto map(F&& f) const&& { + return optional_map_impl(std::move(*this), std::forward<F>(f)); + } +#else + /// \brief Carries out some operation on the stored object if there is one. + /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), + /// value())`. Returns a `std::optional<U>`. The return value is empty if + /// `*this` is empty, otherwise an `optional<U>` is constructed from the + /// return value of `std::invoke(std::forward<F>(f), value())` and is + /// returned. + /// + /// \group map + /// \synopsis template <class F> auto map(F &&f) &; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval<optional&>(), std::declval<F&&>())) map(F&& f) & { + return optional_map_impl(*this, std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> auto map(F &&f) &&; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval<optional&&>(), std::declval<F&&>())) map(F&& f) && { + return optional_map_impl(std::move(*this), std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> auto map(F &&f) const&; + template <class F> + constexpr decltype(optional_map_impl(std::declval<const optional&>(), std::declval<F&&>())) map(F&& f) const& { + return optional_map_impl(*this, std::forward<F>(f)); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group map + /// \synopsis template <class F> auto map(F &&f) const&&; + template <class F> + constexpr decltype(optional_map_impl(std::declval<const optional&&>(), std::declval<F&&>())) map(F&& f) const&& { + return optional_map_impl(std::move(*this), std::forward<F>(f)); + } +#endif +#endif + + /// \brief Calls `f` if the optional is empty + /// \requires `std::invoke_result_t<F>` must be void or convertible to + /// `optional<T>`. + /// \effects If `*this` has a value, returns `*this`. + /// Otherwise, if `f` returns `void`, calls `std::forward<F>(f)` and returns + /// `std::nullopt`. Otherwise, returns `std::forward<F>(f)()`. + /// + /// \group or_else + /// \synopsis template <class F> optional<T> or_else (F &&f) &; + template <class F, detail::enable_if_ret_void<F>* = nullptr> + optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & { + if (has_value()) + return *this; + + std::forward<F>(f)(); + return nullopt; + } + + /// \exclude + template <class F, detail::disable_if_ret_void<F>* = nullptr> + optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & { + return has_value() ? *this : std::forward<F>(f)(); + } + + /// \group or_else + /// \synopsis template <class F> optional<T> or_else (F &&f) &&; + template <class F, detail::enable_if_ret_void<F>* = nullptr> + optional<T> or_else(F&& f) && { + if (has_value()) + return std::move(*this); + + std::forward<F>(f)(); + return nullopt; + } + + /// \exclude + template <class F, detail::disable_if_ret_void<F>* = nullptr> + optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) && { + return has_value() ? std::move(*this) : std::forward<F>(f)(); + } + + /// \group or_else + /// \synopsis template <class F> optional<T> or_else (F &&f) const &; + template <class F, detail::enable_if_ret_void<F>* = nullptr> + optional<T> or_else(F&& f) const& { + if (has_value()) + return *this; + + std::forward<F>(f)(); + return nullopt; + } + + /// \exclude + template <class F, detail::disable_if_ret_void<F>* = nullptr> + optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) const& { + return has_value() ? *this : std::forward<F>(f)(); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \exclude + template <class F, detail::enable_if_ret_void<F>* = nullptr> + optional<T> or_else(F&& f) const&& { + if (has_value()) + return std::move(*this); + + std::forward<F>(f)(); + return nullopt; + } + + /// \exclude + template <class F, detail::disable_if_ret_void<F>* = nullptr> + optional<T> or_else(F&& f) const&& { + return has_value() ? std::move(*this) : std::forward<F>(f)(); + } +#endif + + /// \brief Maps the stored value with `f` if there is one, otherwise returns + /// `u`. + /// + /// \details If there is a value stored, then `f` is called with `**this` + /// and the value is returned. Otherwise `u` is returned. + /// + /// \group map_or + template <class F, class U> + U map_or(F&& f, U&& u) & { + return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u); + } + + /// \group map_or + template <class F, class U> + U map_or(F&& f, U&& u) && { + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u); + } + + /// \group map_or + template <class F, class U> + U map_or(F&& f, U&& u) const& { + return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group map_or + template <class F, class U> + U map_or(F&& f, U&& u) const&& { + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u); + } +#endif + + /// \brief Maps the stored value with `f` if there is one, otherwise calls + /// `u` and returns the result. + /// + /// \details If there is a value stored, then `f` is + /// called with `**this` and the value is returned. Otherwise + /// `std::forward<U>(u)()` is returned. + /// + /// \group map_or_else + /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) &; + template <class F, class U> + detail::invoke_result_t<U> map_or_else(F&& f, U&& u) & { + return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)(); + } + + /// \group map_or_else + /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) + /// &&; + template <class F, class U> + detail::invoke_result_t<U> map_or_else(F&& f, U&& u) && { + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u)(); + } + + /// \group map_or_else + /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) + /// const &; + template <class F, class U> + detail::invoke_result_t<U> map_or_else(F&& f, U&& u) const& { + return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)(); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group map_or_else + /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) + /// const &&; + template <class F, class U> + detail::invoke_result_t<U> map_or_else(F&& f, U&& u) const&& { + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u)(); + } +#endif + + /// \returns `u` if `*this` has a value, otherwise an empty optional. + template <class U> + constexpr optional<typename std::decay<U>::type> conjunction(U&& u) const { + using result = optional<detail::decay_t<U>>; + return has_value() ? result { u } : result { nullopt }; + } + + /// \returns `rhs` if `*this` is empty, otherwise the current value. + /// \group disjunction + SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) & { + return has_value() ? *this : rhs; + } + + /// \group disjunction + constexpr optional disjunction(const optional& rhs) const& { + return has_value() ? *this : rhs; + } + + /// \group disjunction + SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) && { + return has_value() ? std::move(*this) : rhs; + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group disjunction + constexpr optional disjunction(const optional& rhs) const&& { + return has_value() ? std::move(*this) : rhs; + } +#endif + + /// \group disjunction + SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) & { + return has_value() ? *this : std::move(rhs); + } + + /// \group disjunction + constexpr optional disjunction(optional&& rhs) const& { + return has_value() ? *this : std::move(rhs); + } + + /// \group disjunction + SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) && { + return has_value() ? std::move(*this) : std::move(rhs); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group disjunction + constexpr optional disjunction(optional&& rhs) const&& { + return has_value() ? std::move(*this) : std::move(rhs); + } +#endif + + /// Takes the value out of the optional, leaving it empty + /// \group take + optional take() & { + optional ret = *this; + reset(); + return ret; + } + + /// \group take + optional take() const& { + optional ret = *this; + reset(); + return ret; + } + + /// \group take + optional take() && { + optional ret = std::move(*this); + reset(); + return ret; + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group take + optional take() const&& { + optional ret = std::move(*this); + reset(); + return ret; + } +#endif + + using value_type = T; + + /// Constructs an optional that does not contain a value. + /// \group ctor_empty + constexpr optional() noexcept = default; + + /// \group ctor_empty + constexpr optional(nullopt_t) noexcept { + } + + /// Copy constructor + /// + /// If `rhs` contains a value, the stored value is direct-initialized with + /// it. Otherwise, the constructed optional is empty. + SOL_TL_OPTIONAL_11_CONSTEXPR optional(const optional& rhs) = default; + + /// Move constructor + /// + /// If `rhs` contains a value, the stored value is direct-initialized with + /// it. Otherwise, the constructed optional is empty. + SOL_TL_OPTIONAL_11_CONSTEXPR optional(optional&& rhs) = default; + + /// Constructs the stored value in-place using the given arguments. + /// \group in_place + /// \synopsis template <class... Args> constexpr explicit optional(in_place_t, Args&&... args); + template <class... Args> + constexpr explicit optional(detail::enable_if_t<std::is_constructible<T, Args...>::value, in_place_t>, Args&&... args) + : base(in_place, std::forward<Args>(args)...) { + } + + /// \group in_place + /// \synopsis template <class U, class... Args> \n constexpr explicit optional(in_place_t, std::initializer_list<U>&, Args&&... args); + template <class U, class... Args> + SOL_TL_OPTIONAL_11_CONSTEXPR explicit optional(detail::enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, in_place_t>, + std::initializer_list<U> il, Args&&... args) { + this->construct(il, std::forward<Args>(args)...); + } + +#if 0 // SOL_MODIFICATION + /// Constructs the stored value with `u`. + /// \synopsis template <class U=T> constexpr optional(U &&u); + template <class U = T, detail::enable_if_t<std::is_convertible<U&&, T>::value>* = nullptr, detail::enable_forward_value<T, U>* = nullptr> + constexpr optional(U&& u) : base(in_place, std::forward<U>(u)) { + } + + /// \exclude + template <class U = T, detail::enable_if_t<!std::is_convertible<U&&, T>::value>* = nullptr, detail::enable_forward_value<T, U>* = nullptr> + constexpr explicit optional(U&& u) : base(in_place, std::forward<U>(u)) { + } +#else + /// Constructs the stored value with `u`. + /// \synopsis template <class U=T> constexpr optional(U &&u); + constexpr optional(T&& u) : base(in_place, std::move(u)) { + } + + /// \exclude + constexpr optional(const T& u) : base(in_place, u) { + } +#endif // sol2 modification + + /// Converting copy constructor. + /// \synopsis template <class U> optional(const optional<U> &rhs); + template <class U, detail::enable_from_other<T, U, const U&>* = nullptr, detail::enable_if_t<std::is_convertible<const U&, T>::value>* = nullptr> + optional(const optional<U>& rhs) { + if (rhs.has_value()) { + this->construct(*rhs); + } + } + + /// \exclude + template <class U, detail::enable_from_other<T, U, const U&>* = nullptr, detail::enable_if_t<!std::is_convertible<const U&, T>::value>* = nullptr> + explicit optional(const optional<U>& rhs) { + if (rhs.has_value()) { + this->construct(*rhs); + } + } + + /// Converting move constructor. + /// \synopsis template <class U> optional(optional<U> &&rhs); + template <class U, detail::enable_from_other<T, U, U&&>* = nullptr, detail::enable_if_t<std::is_convertible<U&&, T>::value>* = nullptr> + optional(optional<U>&& rhs) { + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } + } + + /// \exclude + template <class U, detail::enable_from_other<T, U, U&&>* = nullptr, detail::enable_if_t<!std::is_convertible<U&&, T>::value>* = nullptr> + explicit optional(optional<U>&& rhs) { + this->construct(std::move(*rhs)); + } + + /// Destroys the stored value if there is one. + ~optional() = default; + + /// Assignment to empty. + /// + /// Destroys the current value if there is one. + optional& operator=(nullopt_t) noexcept { + if (has_value()) { + this->m_value.~T(); + this->m_has_value = false; + } + + return *this; + } + + /// Copy assignment. + /// + /// Copies the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + optional& operator=(const optional& rhs) = default; + + /// Move assignment. + /// + /// Moves the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + optional& operator=(optional&& rhs) = default; + + /// Assigns the stored value from `u`, destroying the old value if there was + /// one. + /// \synopsis optional &operator=(U &&u); + template <class U = T, detail::enable_assign_forward<T, U>* = nullptr> + optional& operator=(U&& u) { + if (has_value()) { + this->m_value = std::forward<U>(u); + } + else { + this->construct(std::forward<U>(u)); + } + + return *this; + } + + /// Converting copy assignment operator. + /// + /// Copies the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + /// \synopsis optional &operator=(const optional<U> & rhs); + template <class U, detail::enable_assign_from_other<T, U, const U&>* = nullptr> + optional& operator=(const optional<U>& rhs) { + if (has_value()) { + if (rhs.has_value()) { + this->m_value = *rhs; + } + else { + this->hard_reset(); + } + } + + if (rhs.has_value()) { + this->construct(*rhs); + } + + return *this; + } + + // TODO check exception guarantee + /// Converting move assignment operator. + /// + /// Moves the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + /// \synopsis optional &operator=(optional<U> && rhs); + template <class U, detail::enable_assign_from_other<T, U, U>* = nullptr> + optional& operator=(optional<U>&& rhs) { + if (has_value()) { + if (rhs.has_value()) { + this->m_value = std::move(*rhs); + } + else { + this->hard_reset(); + } + } + + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } + + return *this; + } + + /// Constructs the value in-place, destroying the current one if there is + /// one. + /// \group emplace + template <class... Args> + T& emplace(Args&&... args) { + static_assert(std::is_constructible<T, Args&&...>::value, "T must be constructible with Args"); + + *this = nullopt; + this->construct(std::forward<Args>(args)...); + return value(); + } + + /// \group emplace + /// \synopsis template <class U, class... Args> \n T& emplace(std::initializer_list<U> il, Args &&... args); + template <class U, class... Args> + detail::enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, T&> emplace(std::initializer_list<U> il, Args&&... args) { + *this = nullopt; + this->construct(il, std::forward<Args>(args)...); + return value(); + } + + /// Swaps this optional with the other. + /// + /// If neither optionals have a value, nothing happens. + /// If both have a value, the values are swapped. + /// If one has a value, it is moved to the other and the movee is left + /// valueless. + void swap(optional& rhs) noexcept(std::is_nothrow_move_constructible<T>::value&& detail::is_nothrow_swappable<T>::value) { + if (has_value()) { + if (rhs.has_value()) { + using std::swap; + swap(**this, *rhs); + } + else { + new (std::addressof(rhs.m_value)) T(std::move(this->m_value)); + this->m_value.T::~T(); + } + } + else if (rhs.has_value()) { + new (std::addressof(this->m_value)) T(std::move(rhs.m_value)); + rhs.m_value.T::~T(); + } + } + + /// \returns a pointer to the stored value + /// \requires a value is stored + /// \group pointer + /// \synopsis constexpr const T *operator->() const; + constexpr const T* operator->() const { + return std::addressof(this->m_value); + } + + /// \group pointer + /// \synopsis constexpr T *operator->(); + SOL_TL_OPTIONAL_11_CONSTEXPR T* operator->() { + return std::addressof(this->m_value); + } + + /// \returns the stored value + /// \requires a value is stored + /// \group deref + /// \synopsis constexpr T &operator*(); + SOL_TL_OPTIONAL_11_CONSTEXPR T& operator*() & { + return this->m_value; + } + + /// \group deref + /// \synopsis constexpr const T &operator*() const; + constexpr const T& operator*() const& { + return this->m_value; + } + + /// \exclude + SOL_TL_OPTIONAL_11_CONSTEXPR T&& operator*() && { + return std::move(this->m_value); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \exclude + constexpr const T&& operator*() const&& { + return std::move(this->m_value); + } +#endif + + /// \returns whether or not the optional has a value + /// \group has_value + constexpr bool has_value() const noexcept { + return this->m_has_value; + } + + /// \group has_value + constexpr explicit operator bool() const noexcept { + return this->m_has_value; + } + + /// \returns the contained value if there is one, otherwise throws + /// [bad_optional_access] + /// \group value + /// \synopsis constexpr T &value(); + SOL_TL_OPTIONAL_11_CONSTEXPR T& value() & { + if (has_value()) + return this->m_value; +#if SOL_IS_OFF(SOL_EXCEPTIONS) + std::abort(); +#else + throw bad_optional_access(); +#endif // No exceptions allowed + } + /// \group value + /// \synopsis constexpr const T &value() const; + SOL_TL_OPTIONAL_11_CONSTEXPR const T& value() const& { + if (has_value()) + return this->m_value; +#if SOL_IS_OFF(SOL_EXCEPTIONS) + std::abort(); +#else + throw bad_optional_access(); +#endif // No exceptions allowed + } + /// \exclude + SOL_TL_OPTIONAL_11_CONSTEXPR T&& value() && { + if (has_value()) + return std::move(this->m_value); +#if SOL_IS_OFF(SOL_EXCEPTIONS) + std::abort(); +#else + throw bad_optional_access(); +#endif // No exceptions allowed + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \exclude + SOL_TL_OPTIONAL_11_CONSTEXPR const T&& value() const&& { + if (has_value()) + return std::move(this->m_value); +#if SOL_IS_OFF(SOL_EXCEPTIONS) + std::abort(); +#else + throw bad_optional_access(); +#endif // No exceptions allowed + } +#endif + + /// \returns the stored value if there is one, otherwise returns `u` + /// \group value_or + template <class U> + constexpr T value_or(U&& u) const& { + static_assert(std::is_copy_constructible<T>::value && std::is_convertible<U&&, T>::value, "T must be copy constructible and convertible from U"); + return has_value() ? **this : static_cast<T>(std::forward<U>(u)); + } + + /// \group value_or + template <class U> + SOL_TL_OPTIONAL_11_CONSTEXPR T value_or(U&& u) && { + static_assert(std::is_move_constructible<T>::value && std::is_convertible<U&&, T>::value, "T must be move constructible and convertible from U"); + return has_value() ? **this : static_cast<T>(std::forward<U>(u)); + } + + /// Destroys the stored value if one exists, making the optional empty + void reset() noexcept { + if (has_value()) { + this->m_value.~T(); + this->m_has_value = false; + } + } + }; // namespace sol + + /// \group relop + /// \brief Compares two optional objects + /// \details If both optionals contain a value, they are compared with `T`s + /// relational operators. Otherwise `lhs` and `rhs` are equal only if they are + /// both empty, and `lhs` is less than `rhs` only if `rhs` is empty and `lhs` + /// is not. + template <class T, class U> + inline constexpr bool operator==(const optional<T>& lhs, const optional<U>& rhs) { + return lhs.has_value() == rhs.has_value() && (!lhs.has_value() || *lhs == *rhs); + } + /// \group relop + template <class T, class U> + inline constexpr bool operator!=(const optional<T>& lhs, const optional<U>& rhs) { + return lhs.has_value() != rhs.has_value() || (lhs.has_value() && *lhs != *rhs); + } + /// \group relop + template <class T, class U> + inline constexpr bool operator<(const optional<T>& lhs, const optional<U>& rhs) { + return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs); + } + /// \group relop + template <class T, class U> + inline constexpr bool operator>(const optional<T>& lhs, const optional<U>& rhs) { + return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs); + } + /// \group relop + template <class T, class U> + inline constexpr bool operator<=(const optional<T>& lhs, const optional<U>& rhs) { + return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs); + } + /// \group relop + template <class T, class U> + inline constexpr bool operator>=(const optional<T>& lhs, const optional<U>& rhs) { + return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs); + } + + /// \group relop_nullopt + /// \brief Compares an optional to a `nullopt` + /// \details Equivalent to comparing the optional to an empty optional + template <class T> + inline constexpr bool operator==(const optional<T>& lhs, nullopt_t) noexcept { + return !lhs.has_value(); + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator==(nullopt_t, const optional<T>& rhs) noexcept { + return !rhs.has_value(); + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator!=(const optional<T>& lhs, nullopt_t) noexcept { + return lhs.has_value(); + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator!=(nullopt_t, const optional<T>& rhs) noexcept { + return rhs.has_value(); + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator<(const optional<T>&, nullopt_t) noexcept { + return false; + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator<(nullopt_t, const optional<T>& rhs) noexcept { + return rhs.has_value(); + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator<=(const optional<T>& lhs, nullopt_t) noexcept { + return !lhs.has_value(); + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept { + return true; + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator>(const optional<T>& lhs, nullopt_t) noexcept { + return lhs.has_value(); + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator>(nullopt_t, const optional<T>&) noexcept { + return false; + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept { + return true; + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator>=(nullopt_t, const optional<T>& rhs) noexcept { + return !rhs.has_value(); + } + + /// \group relop_t + /// \brief Compares the optional with a value. + /// \details If the optional has a value, it is compared with the other value + /// using `T`s relational operators. Otherwise, the optional is considered + /// less than the value. + template <class T, class U> + inline constexpr bool operator==(const optional<T>& lhs, const U& rhs) { + return lhs.has_value() ? *lhs == rhs : false; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator==(const U& lhs, const optional<T>& rhs) { + return rhs.has_value() ? lhs == *rhs : false; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator!=(const optional<T>& lhs, const U& rhs) { + return lhs.has_value() ? *lhs != rhs : true; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator!=(const U& lhs, const optional<T>& rhs) { + return rhs.has_value() ? lhs != *rhs : true; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator<(const optional<T>& lhs, const U& rhs) { + return lhs.has_value() ? *lhs < rhs : true; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator<(const U& lhs, const optional<T>& rhs) { + return rhs.has_value() ? lhs < *rhs : false; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator<=(const optional<T>& lhs, const U& rhs) { + return lhs.has_value() ? *lhs <= rhs : true; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator<=(const U& lhs, const optional<T>& rhs) { + return rhs.has_value() ? lhs <= *rhs : false; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator>(const optional<T>& lhs, const U& rhs) { + return lhs.has_value() ? *lhs > rhs : false; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator>(const U& lhs, const optional<T>& rhs) { + return rhs.has_value() ? lhs > *rhs : true; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator>=(const optional<T>& lhs, const U& rhs) { + return lhs.has_value() ? *lhs >= rhs : false; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator>=(const U& lhs, const optional<T>& rhs) { + return rhs.has_value() ? lhs >= *rhs : true; + } + + /// \synopsis template <class T> \n void swap(optional<T> &lhs, optional<T> &rhs); + template <class T, detail::enable_if_t<std::is_move_constructible<T>::value>* = nullptr, detail::enable_if_t<detail::is_swappable<T>::value>* = nullptr> + void swap(optional<T>& lhs, optional<T>& rhs) noexcept(noexcept(lhs.swap(rhs))) { + return lhs.swap(rhs); + } + + namespace detail { + struct i_am_secret { }; + } // namespace detail + + template <class T = detail::i_am_secret, class U, class Ret = detail::conditional_t<std::is_same<T, detail::i_am_secret>::value, detail::decay_t<U>, T>> + inline constexpr optional<Ret> make_optional(U&& v) { + return optional<Ret>(std::forward<U>(v)); + } + + template <class T, class... Args> + inline constexpr optional<T> make_optional(Args&&... args) { + return optional<T>(in_place, std::forward<Args>(args)...); + } + template <class T, class U, class... Args> + inline constexpr optional<T> make_optional(std::initializer_list<U> il, Args&&... args) { + return optional<T>(in_place, il, std::forward<Args>(args)...); + } + +#if __cplusplus >= 201703L + template <class T> + optional(T) -> optional<T>; +#endif + + /// \exclude + namespace detail { +#ifdef SOL_TL_OPTIONAL_CXX14 + template <class Opt, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Opt>())), + detail::enable_if_t<!std::is_void<Ret>::value>* = nullptr> + constexpr auto optional_map_impl(Opt&& opt, F&& f) { + return opt.has_value() ? detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt)) : optional<Ret>(nullopt); + } + + template <class Opt, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Opt>())), + detail::enable_if_t<std::is_void<Ret>::value>* = nullptr> + auto optional_map_impl(Opt&& opt, F&& f) { + if (opt.has_value()) { + detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt)); + return make_optional(monostate {}); + } + + return optional<monostate>(nullopt); + } +#else + template <class Opt, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Opt>())), + detail::enable_if_t<!std::is_void<Ret>::value>* = nullptr> + + constexpr auto optional_map_impl(Opt&& opt, F&& f) -> optional<Ret> { + return opt.has_value() ? detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt)) : optional<Ret>(nullopt); + } + + template <class Opt, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Opt>())), + detail::enable_if_t<std::is_void<Ret>::value>* = nullptr> + + auto optional_map_impl(Opt&& opt, F&& f) -> optional<monostate> { + if (opt.has_value()) { + detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt)); + return monostate {}; + } + + return nullopt; + } +#endif + } // namespace detail + + /// Specialization for when `T` is a reference. `optional<T&>` acts similarly + /// to a `T*`, but provides more operations and shows intent more clearly. + /// + /// *Examples*: + /// + /// ``` + /// int i = 42; + /// sol::optional<int&> o = i; + /// *o == 42; //true + /// i = 12; + /// *o = 12; //true + /// &*o == &i; //true + /// ``` + /// + /// Assignment has rebind semantics rather than assign-through semantics: + /// + /// ``` + /// int j = 8; + /// o = j; + /// + /// &*o == &j; //true + /// ``` + template <class T> + class optional<T&> { + public: +#if defined(SOL_TL_OPTIONAL_CXX14) && !defined(SOL_TL_OPTIONAL_GCC49) && !defined(SOL_TL_OPTIONAL_GCC54) && !defined(SOL_TL_OPTIONAL_GCC55) + /// \group and_then + /// Carries out some operation which returns an optional on the stored + /// object if there is one. \requires `std::invoke(std::forward<F>(f), + /// value())` returns a `std::optional<U>` for some `U`. \returns Let `U` be + /// the result of `std::invoke(std::forward<F>(f), value())`. Returns a + /// `std::optional<U>`. The return value is empty if `*this` is empty, + /// otherwise the return value of `std::invoke(std::forward<F>(f), value())` + /// is returned. + /// \group and_then + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) & { + using result = detail::invoke_result_t<F, T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + + /// \group and_then + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &&; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) && { + using result = detail::invoke_result_t<F, T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + + /// \group and_then + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &; + template <class F> + constexpr auto and_then(F&& f) const& { + using result = detail::invoke_result_t<F, const T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group and_then + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &&; + template <class F> + constexpr auto and_then(F&& f) const&& { + using result = detail::invoke_result_t<F, const T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } +#endif +#else + /// \group and_then + /// Carries out some operation which returns an optional on the stored + /// object if there is one. \requires `std::invoke(std::forward<F>(f), + /// value())` returns a `std::optional<U>` for some `U`. \returns Let `U` be + /// the result of `std::invoke(std::forward<F>(f), value())`. Returns a + /// `std::optional<U>`. The return value is empty if `*this` is empty, + /// otherwise the return value of `std::invoke(std::forward<F>(f), value())` + /// is returned. + /// \group and_then + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&> and_then(F&& f) & { + using result = detail::invoke_result_t<F, T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + + /// \group and_then + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &&; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&> and_then(F&& f) && { + using result = detail::invoke_result_t<F, T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + + /// \group and_then + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &; + template <class F> + constexpr detail::invoke_result_t<F, const T&> and_then(F&& f) const& { + using result = detail::invoke_result_t<F, const T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group and_then + /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &&; + template <class F> + constexpr detail::invoke_result_t<F, const T&> and_then(F&& f) const&& { + using result = detail::invoke_result_t<F, const T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } +#endif +#endif + +#if defined(SOL_TL_OPTIONAL_CXX14) && !defined(SOL_TL_OPTIONAL_GCC49) && !defined(SOL_TL_OPTIONAL_GCC54) && !defined(SOL_TL_OPTIONAL_GCC55) + /// \brief Carries out some operation on the stored object if there is one. + /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), + /// value())`. Returns a `std::optional<U>`. The return value is empty if + /// `*this` is empty, otherwise an `optional<U>` is constructed from the + /// return value of `std::invoke(std::forward<F>(f), value())` and is + /// returned. + /// + /// \group map + /// \synopsis template <class F> constexpr auto map(F &&f) &; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) & { + return detail::optional_map_impl(*this, std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> constexpr auto map(F &&f) &&; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) && { + return detail::optional_map_impl(std::move(*this), std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> constexpr auto map(F &&f) const&; + template <class F> + constexpr auto map(F&& f) const& { + return detail::optional_map_impl(*this, std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> constexpr auto map(F &&f) const&&; + template <class F> + constexpr auto map(F&& f) const&& { + return detail::optional_map_impl(std::move(*this), std::forward<F>(f)); + } +#else + /// \brief Carries out some operation on the stored object if there is one. + /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), + /// value())`. Returns a `std::optional<U>`. The return value is empty if + /// `*this` is empty, otherwise an `optional<U>` is constructed from the + /// return value of `std::invoke(std::forward<F>(f), value())` and is + /// returned. + /// + /// \group map + /// \synopsis template <class F> auto map(F &&f) &; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval<optional&>(), std::declval<F&&>())) map(F&& f) & { + return detail::optional_map_impl(*this, std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> auto map(F &&f) &&; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval<optional&&>(), std::declval<F&&>())) map(F&& f) && { + return detail::optional_map_impl(std::move(*this), std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> auto map(F &&f) const&; + template <class F> + constexpr decltype(detail::optional_map_impl(std::declval<const optional&>(), std::declval<F&&>())) map(F&& f) const& { + return detail::optional_map_impl(*this, std::forward<F>(f)); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group map + /// \synopsis template <class F> auto map(F &&f) const&&; + template <class F> + constexpr decltype(detail::optional_map_impl(std::declval<const optional&&>(), std::declval<F&&>())) map(F&& f) const&& { + return detail::optional_map_impl(std::move(*this), std::forward<F>(f)); + } +#endif +#endif + + /// \brief Calls `f` if the optional is empty + /// \requires `std::invoke_result_t<F>` must be void or convertible to + /// `optional<T>`. \effects If `*this` has a value, returns `*this`. + /// Otherwise, if `f` returns `void`, calls `std::forward<F>(f)` and returns + /// `std::nullopt`. Otherwise, returns `std::forward<F>(f)()`. + /// + /// \group or_else + /// \synopsis template <class F> optional<T> or_else (F &&f) &; + template <class F, detail::enable_if_ret_void<F>* = nullptr> + optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & { + if (has_value()) + return *this; + + std::forward<F>(f)(); + return nullopt; + } + + /// \exclude + template <class F, detail::disable_if_ret_void<F>* = nullptr> + optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & { + return has_value() ? *this : std::forward<F>(f)(); + } + + /// \group or_else + /// \synopsis template <class F> optional<T> or_else (F &&f) &&; + template <class F, detail::enable_if_ret_void<F>* = nullptr> + optional<T> or_else(F&& f) && { + if (has_value()) + return std::move(*this); + + std::forward<F>(f)(); + return nullopt; + } + + /// \exclude + template <class F, detail::disable_if_ret_void<F>* = nullptr> + optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) && { + return has_value() ? std::move(*this) : std::forward<F>(f)(); + } + + /// \group or_else + /// \synopsis template <class F> optional<T> or_else (F &&f) const &; + template <class F, detail::enable_if_ret_void<F>* = nullptr> + optional<T> or_else(F&& f) const& { + if (has_value()) + return *this; + + std::forward<F>(f)(); + return nullopt; + } + + /// \exclude + template <class F, detail::disable_if_ret_void<F>* = nullptr> + optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) const& { + return has_value() ? *this : std::forward<F>(f)(); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \exclude + template <class F, detail::enable_if_ret_void<F>* = nullptr> + optional<T> or_else(F&& f) const&& { + if (has_value()) + return std::move(*this); + + std::forward<F>(f)(); + return nullopt; + } + + /// \exclude + template <class F, detail::disable_if_ret_void<F>* = nullptr> + optional<T> or_else(F&& f) const&& { + return has_value() ? std::move(*this) : std::forward<F>(f)(); + } +#endif + + /// \brief Maps the stored value with `f` if there is one, otherwise returns + /// `u`. + /// + /// \details If there is a value stored, then `f` is called with `**this` + /// and the value is returned. Otherwise `u` is returned. + /// + /// \group map_or + template <class F, class U> + U map_or(F&& f, U&& u) & { + return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u); + } + + /// \group map_or + template <class F, class U> + U map_or(F&& f, U&& u) && { + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u); + } + + /// \group map_or + template <class F, class U> + U map_or(F&& f, U&& u) const& { + return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group map_or + template <class F, class U> + U map_or(F&& f, U&& u) const&& { + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u); + } +#endif + + /// \brief Maps the stored value with `f` if there is one, otherwise calls + /// `u` and returns the result. + /// + /// \details If there is a value stored, then `f` is + /// called with `**this` and the value is returned. Otherwise + /// `std::forward<U>(u)()` is returned. + /// + /// \group map_or_else + /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) &; + template <class F, class U> + detail::invoke_result_t<U> map_or_else(F&& f, U&& u) & { + return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)(); + } + + /// \group map_or_else + /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) + /// &&; + template <class F, class U> + detail::invoke_result_t<U> map_or_else(F&& f, U&& u) && { + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u)(); + } + + /// \group map_or_else + /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) + /// const &; + template <class F, class U> + detail::invoke_result_t<U> map_or_else(F&& f, U&& u) const& { + return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)(); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group map_or_else + /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) + /// const &&; + template <class F, class U> + detail::invoke_result_t<U> map_or_else(F&& f, U&& u) const&& { + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u)(); + } +#endif + + /// \returns `u` if `*this` has a value, otherwise an empty optional. + template <class U> + constexpr optional<typename std::decay<U>::type> conjunction(U&& u) const { + using result = optional<detail::decay_t<U>>; + return has_value() ? result { u } : result { nullopt }; + } + + /// \returns `rhs` if `*this` is empty, otherwise the current value. + /// \group disjunction + SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) & { + return has_value() ? *this : rhs; + } + + /// \group disjunction + constexpr optional disjunction(const optional& rhs) const& { + return has_value() ? *this : rhs; + } + + /// \group disjunction + SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) && { + return has_value() ? std::move(*this) : rhs; + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group disjunction + constexpr optional disjunction(const optional& rhs) const&& { + return has_value() ? std::move(*this) : rhs; + } +#endif + + /// \group disjunction + SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) & { + return has_value() ? *this : std::move(rhs); + } + + /// \group disjunction + constexpr optional disjunction(optional&& rhs) const& { + return has_value() ? *this : std::move(rhs); + } + + /// \group disjunction + SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) && { + return has_value() ? std::move(*this) : std::move(rhs); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group disjunction + constexpr optional disjunction(optional&& rhs) const&& { + return has_value() ? std::move(*this) : std::move(rhs); + } +#endif + + /// Takes the value out of the optional, leaving it empty + /// \group take + optional take() & { + optional ret = *this; + reset(); + return ret; + } + + /// \group take + optional take() const& { + optional ret = *this; + reset(); + return ret; + } + + /// \group take + optional take() && { + optional ret = std::move(*this); + reset(); + return ret; + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group take + optional take() const&& { + optional ret = std::move(*this); + reset(); + return ret; + } +#endif + + using value_type = T&; + + /// Constructs an optional that does not contain a value. + /// \group ctor_empty + constexpr optional() noexcept : m_value(nullptr) { + } + + /// \group ctor_empty + constexpr optional(nullopt_t) noexcept : m_value(nullptr) { + } + + /// Copy constructor + /// + /// If `rhs` contains a value, the stored value is direct-initialized with + /// it. Otherwise, the constructed optional is empty. + SOL_TL_OPTIONAL_11_CONSTEXPR optional(const optional& rhs) noexcept = default; + + /// Move constructor + /// + /// If `rhs` contains a value, the stored value is direct-initialized with + /// it. Otherwise, the constructed optional is empty. + SOL_TL_OPTIONAL_11_CONSTEXPR optional(optional&& rhs) = default; + + /// Constructs the stored value with `u`. + /// \synopsis template <class U=T> constexpr optional(U &&u); + template <class U = T, detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>::value>* = nullptr> + constexpr optional(U&& u) : m_value(std::addressof(u)) { + static_assert(std::is_lvalue_reference<U>::value, "U must be an lvalue"); + } + + /// \exclude + template <class U> + constexpr explicit optional(const optional<U>& rhs) : optional(*rhs) { + } + + /// No-op + ~optional() = default; + + /// Assignment to empty. + /// + /// Destroys the current value if there is one. + optional& operator=(nullopt_t) noexcept { + m_value = nullptr; + return *this; + } + + /// Copy assignment. + /// + /// Rebinds this optional to the referee of `rhs` if there is one. Otherwise + /// resets the stored value in `*this`. + optional& operator=(const optional& rhs) = default; + + /// Rebinds this optional to `u`. + /// + /// \requires `U` must be an lvalue reference. + /// \synopsis optional &operator=(U &&u); + template <class U = T, detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>::value>* = nullptr> + optional& operator=(U&& u) { + static_assert(std::is_lvalue_reference<U>::value, "U must be an lvalue"); + m_value = std::addressof(u); + return *this; + } + + /// Converting copy assignment operator. + /// + /// Rebinds this optional to the referee of `rhs` if there is one. Otherwise + /// resets the stored value in `*this`. + template <class U> + optional& operator=(const optional<U>& rhs) { + m_value = std::addressof(rhs.value()); + return *this; + } + + /// Constructs the value in-place, destroying the current one if there is + /// one. + /// + /// \group emplace + template <class... Args> + T& emplace(Args&&... args) noexcept { + static_assert(std::is_constructible<T, Args&&...>::value, "T must be constructible with Args"); + + *this = nullopt; + this->construct(std::forward<Args>(args)...); + } + + /// Swaps this optional with the other. + /// + /// If neither optionals have a value, nothing happens. + /// If both have a value, the values are swapped. + /// If one has a value, it is moved to the other and the movee is left + /// valueless. + void swap(optional& rhs) noexcept { + std::swap(m_value, rhs.m_value); + } + + /// \returns a pointer to the stored value + /// \requires a value is stored + /// \group pointer + /// \synopsis constexpr const T *operator->() const; + constexpr const T* operator->() const { + return m_value; + } + + /// \group pointer + /// \synopsis constexpr T *operator->(); + SOL_TL_OPTIONAL_11_CONSTEXPR T* operator->() { + return m_value; + } + + /// \returns the stored value + /// \requires a value is stored + /// \group deref + /// \synopsis constexpr T &operator*(); + SOL_TL_OPTIONAL_11_CONSTEXPR T& operator*() { + return *m_value; + } + + /// \group deref + /// \synopsis constexpr const T &operator*() const; + constexpr const T& operator*() const { + return *m_value; + } + + /// \returns whether or not the optional has a value + /// \group has_value + constexpr bool has_value() const noexcept { + return m_value != nullptr; + } + + /// \group has_value + constexpr explicit operator bool() const noexcept { + return m_value != nullptr; + } + + /// \returns the contained value if there is one, otherwise throws + /// [bad_optional_access] + /// \group value + /// synopsis constexpr T &value(); + SOL_TL_OPTIONAL_11_CONSTEXPR T& value() { + if (has_value()) + return *m_value; +#if SOL_IS_OFF(SOL_EXCEPTIONS) + std::abort(); +#else + throw bad_optional_access(); +#endif // No exceptions allowed + } + /// \group value + /// \synopsis constexpr const T &value() const; + SOL_TL_OPTIONAL_11_CONSTEXPR const T& value() const { + if (has_value()) + return *m_value; +#if SOL_IS_OFF(SOL_EXCEPTIONS) + std::abort(); +#else + throw bad_optional_access(); +#endif // No exceptions allowed + } + + /// \returns the stored value if there is one, otherwise returns `u` + /// \group value_or + template <class U> + constexpr T& value_or(U&& u) const { + static_assert(std::is_convertible<U&&, T&>::value, "T must be convertible from U"); + return has_value() ? const_cast<T&>(**this) : static_cast<T&>(std::forward<U>(u)); + } + + /// Destroys the stored value if one exists, making the optional empty + void reset() noexcept { + m_value = nullptr; + } + + private: + T* m_value; + }; + +} // namespace sol + +namespace std { + // TODO SFINAE + template <class T> + struct hash<::sol::optional<T>> { + ::std::size_t operator()(const ::sol::optional<T>& o) const { + if (!o.has_value()) + return 0; + + return ::std::hash<::sol::detail::remove_const_t<T>>()(*o); + } + }; +} // namespace std + +// end of sol/optional_implementation.hpp + +#endif // Boost vs. Better optional + +#include <optional> + +namespace sol { + +#if SOL_IS_ON(SOL_USE_BOOST) + template <typename T> + using optional = boost::optional<T>; + using nullopt_t = boost::none_t; + SOL_BOOST_NONE_CONSTEXPR_I_ nullopt_t nullopt = boost::none; +#endif // Boost vs. Better optional + + namespace meta { + template <typename T> + using is_optional = any<is_specialization_of<T, optional>, is_specialization_of<T, std::optional>>; + + template <typename T> + constexpr inline bool is_optional_v = is_optional<T>::value; + } // namespace meta + + namespace detail { + template <typename T> + struct associated_nullopt { + inline static constexpr std::nullopt_t value = std::nullopt; + }; + +#if SOL_IS_ON(SOL_USE_BOOST) + template <typename T> + struct associated_nullopt<boost::optional<T>> { + inline static SOL_BOOST_NONE_CONSTEXPR_I_ boost::none_t value = boost::none; + }; +#endif // Boost nullopt + +#if SOL_IS_ON(SOL_USE_BOOST) + template <typename T> + inline SOL_BOOST_NONE_CONSTEXPR_I_ auto associated_nullopt_v = associated_nullopt<T>::value; +#else + template <typename T> + inline constexpr auto associated_nullopt_v = associated_nullopt<T>::value; +#endif // Boost continues to lag behind, to not many people's surprise... + } // namespace detail +} // namespace sol + +#if SOL_IS_ON(SOL_USE_BOOST) +#undef SOL_BOOST_NONE_CONSTEXPR_I_ +#endif + +// end of sol/optional.hpp + +// beginning of sol/raii.hpp + +#include <memory> + +namespace sol { + namespace detail { + struct default_construct { + template <typename T, typename... Args> + static void construct(T&& obj, Args&&... args) { + typedef meta::unqualified_t<T> Tu; + std::allocator<Tu> alloc {}; + std::allocator_traits<std::allocator<Tu>>::construct(alloc, std::forward<T>(obj), std::forward<Args>(args)...); + } + + template <typename T, typename... Args> + void operator()(T&& obj, Args&&... args) const { + construct(std::forward<T>(obj), std::forward<Args>(args)...); + } + }; + + struct default_destroy { + template <typename T> + static void destroy(T&& obj) { + std::allocator<meta::unqualified_t<T>> alloc {}; + alloc.destroy(obj); + } + + template <typename T> + void operator()(T&& obj) const { + destroy(std::forward<T>(obj)); + } + }; + + struct deleter { + template <typename T> + void operator()(T* p) const { + delete p; + } + }; + + struct state_deleter { + void operator()(lua_State* L) const { + lua_close(L); + } + }; + + template <typename T, typename Dx, typename... Args> + inline std::unique_ptr<T, Dx> make_unique_deleter(Args&&... args) { + return std::unique_ptr<T, Dx>(new T(std::forward<Args>(args)...)); + } + + template <typename Tag, typename T> + struct tagged { + private: + T value_; + + public: + template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, tagged>> = meta::enabler> + tagged(Arg&& arg, Args&&... args) : value_(std::forward<Arg>(arg), std::forward<Args>(args)...) { + } + + T& value() & { + return value_; + } + + T const& value() const& { + return value_; + } + + T&& value() && { + return std::move(value_); + } + }; + } // namespace detail + + template <typename... Args> + struct constructor_list { }; + + template <typename... Args> + using constructors = constructor_list<Args...>; + + const auto default_constructor = constructors<types<>> {}; + + struct no_construction { }; + const auto no_constructor = no_construction {}; + + struct call_construction { }; + const auto call_constructor = call_construction {}; + + template <typename... Functions> + struct constructor_wrapper { + std::tuple<Functions...> functions; + template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, constructor_wrapper>> = meta::enabler> + constructor_wrapper(Arg&& arg, Args&&... args) : functions(std::forward<Arg>(arg), std::forward<Args>(args)...) { + } + }; + + template <typename... Functions> + inline auto initializers(Functions&&... functions) { + return constructor_wrapper<std::decay_t<Functions>...>(std::forward<Functions>(functions)...); + } + + template <typename... Functions> + struct factory_wrapper { + std::tuple<Functions...> functions; + template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, factory_wrapper>> = meta::enabler> + factory_wrapper(Arg&& arg, Args&&... args) : functions(std::forward<Arg>(arg), std::forward<Args>(args)...) { + } + }; + + template <typename... Functions> + inline auto factories(Functions&&... functions) { + return factory_wrapper<std::decay_t<Functions>...>(std::forward<Functions>(functions)...); + } + + template <typename Function> + struct destructor_wrapper { + Function fx; + destructor_wrapper(Function f) : fx(std::move(f)) { + } + }; + + template <> + struct destructor_wrapper<void> { }; + + const destructor_wrapper<void> default_destructor {}; + + template <typename Fx> + inline auto destructor(Fx&& fx) { + return destructor_wrapper<std::decay_t<Fx>>(std::forward<Fx>(fx)); + } + +} // namespace sol + +// end of sol/raii.hpp + +// beginning of sol/policies.hpp + +#include <array> + +namespace sol { + namespace detail { + struct policy_base_tag { }; + } // namespace detail + + template <int Target, int... In> + struct static_stack_dependencies : detail::policy_base_tag { }; + typedef static_stack_dependencies<-1, 1> self_dependency; + template <int... In> + struct returns_self_with : detail::policy_base_tag { }; + typedef returns_self_with<> returns_self; + + struct stack_dependencies : detail::policy_base_tag { + int target; + std::array<int, 64> stack_indices; + std::size_t len; + + template <typename... Args> + stack_dependencies(int stack_target, Args&&... args) : target(stack_target), stack_indices(), len(sizeof...(Args)) { + std::size_t i = 0; + (void)detail::swallow { int(), (stack_indices[i++] = static_cast<int>(std::forward<Args>(args)), int())... }; + } + + int& operator[](std::size_t i) { + return stack_indices[i]; + } + + const int& operator[](std::size_t i) const { + return stack_indices[i]; + } + + std::size_t size() const { + return len; + } + }; + + template <typename F, typename... Policies> + struct policy_wrapper { + typedef std::index_sequence_for<Policies...> indices; + + F value; + std::tuple<Policies...> policies; + + template <typename Fx, typename... Args, meta::enable<meta::neg<std::is_same<meta::unqualified_t<Fx>, policy_wrapper>>> = meta::enabler> + policy_wrapper(Fx&& fx, Args&&... args) : value(std::forward<Fx>(fx)), policies(std::forward<Args>(args)...) { + } + + policy_wrapper(const policy_wrapper&) = default; + policy_wrapper& operator=(const policy_wrapper&) = default; + policy_wrapper(policy_wrapper&&) = default; + policy_wrapper& operator=(policy_wrapper&&) = default; + }; + + template <typename F, typename... Args> + auto policies(F&& f, Args&&... args) { + return policy_wrapper<std::decay_t<F>, std::decay_t<Args>...>(std::forward<F>(f), std::forward<Args>(args)...); + } + + namespace detail { + template <typename T> + using is_policy = meta::is_specialization_of<T, policy_wrapper>; + + template <typename T> + inline constexpr bool is_policy_v = is_policy<T>::value; + } // namespace detail +} // namespace sol + +// end of sol/policies.hpp + +// beginning of sol/ebco.hpp + +#include <type_traits> +#include <utility> +#include <memory> + +namespace sol { namespace detail { + + template <typename T, std::size_t tag = 0, typename = void> + struct ebco { + T m_value; + + ebco() = default; + ebco(const ebco&) = default; + ebco(ebco&&) = default; + ebco& operator=(const ebco&) = default; + ebco& operator=(ebco&&) = default; + ebco(const T& v) noexcept(std::is_nothrow_copy_constructible_v<T>) : m_value(v) {}; + ebco(T&& v) noexcept(std::is_nothrow_move_constructible_v<T>) : m_value(std::move(v)) {}; + ebco& operator=(const T& v) noexcept(std::is_nothrow_copy_assignable_v<T>) { + m_value = v; + return *this; + } + ebco& operator=(T&& v) noexcept(std::is_nothrow_move_assignable_v<T>) { + m_value = std::move(v); + return *this; + }; + template <typename Arg, typename... Args, + typename = std::enable_if_t< + !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, + ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T> && (sizeof...(Args) > 0 || !std::is_convertible_v<Arg, T>)>> + ebco(Arg&& arg, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Arg, Args...>) + : m_value(std::forward<Arg>(arg), std::forward<Args>(args)...) { + } + + T& value() & noexcept { + return m_value; + } + + T const& value() const& noexcept { + return m_value; + } + + T&& value() && noexcept { + return std::move(m_value); + } + }; + + template <typename T, std::size_t tag> + struct ebco<T, tag, std::enable_if_t<!std::is_reference_v<T> && std::is_class_v<T> && !std::is_final_v<T>>> : T { + ebco() = default; + ebco(const ebco&) = default; + ebco(ebco&&) = default; + ebco(const T& v) noexcept(std::is_nothrow_copy_constructible_v<T>) : T(v) {}; + ebco(T&& v) noexcept(std::is_nothrow_move_constructible_v<T>) : T(std::move(v)) {}; + template <typename Arg, typename... Args, + typename = std::enable_if_t< + !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, + ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T> && (sizeof...(Args) > 0 || !std::is_convertible_v<Arg, T>)>> + ebco(Arg&& arg, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Arg, Args...>) : T(std::forward<Arg>(arg), std::forward<Args>(args)...) { + } + + ebco& operator=(const ebco&) = default; + ebco& operator=(ebco&&) = default; + ebco& operator=(const T& v) noexcept(std::is_nothrow_copy_assignable_v<T>) { + static_cast<T&>(*this) = v; + return *this; + } + ebco& operator=(T&& v) noexcept(std::is_nothrow_move_assignable_v<T>) { + static_cast<T&>(*this) = std::move(v); + return *this; + }; + + T& value() & noexcept { + return static_cast<T&>(*this); + } + + T const& value() const& noexcept { + return static_cast<T const&>(*this); + } + + T&& value() && noexcept { + return std::move(static_cast<T&>(*this)); + } + }; + + template <typename T, std::size_t tag> + struct ebco<T&, tag> { + private: + T* m_ref; + + public: + ebco() = default; + ebco(const ebco&) = default; + ebco(ebco&&) = default; + ebco(T& v) noexcept : m_ref(std::addressof(v)) {}; + + ebco& operator=(const ebco&) = default; + ebco& operator=(ebco&&) = default; + ebco& operator=(T& v) noexcept { + m_ref = std::addressof(v); + return *this; + } + + T& value() const noexcept { + return *(const_cast<ebco<T&, tag>&>(*this).m_ref); + } + }; + + template <typename T, std::size_t tag> + struct ebco<T&&, tag> { + T&& ref; + + ebco() = default; + ebco(const ebco&) = delete; + ebco(ebco&&) = default; + ebco(T&& v) noexcept : ref(v) {}; + + ebco& operator=(const ebco&) = delete; + ebco& operator=(ebco&&) = delete; + + T& value() & noexcept { + return ref; + } + + const T& value() const& noexcept { + return ref; + } + + T&& value() && noexcept { + return std::move(ref); + } + }; + +}} // namespace sol::detail + +// end of sol/ebco.hpp + +#include <array> +#include <initializer_list> +#include <string> +#include <string_view> +#include <limits> +#include <optional> +#include <memory> +#if SOL_IS_ON(SOL_STD_VARIANT) +#include <variant> +#endif // variant shenanigans (thanks, Mac OSX) + +namespace sol { + namespace d { + // shortest possible hidden detail namespace + // when types are transcribed, this saves + // quite a bit of space, actually. + // it's a little unfortunate, but here we are? + template <typename T> + struct u { }; + } // namespace d + + namespace detail { +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) + typedef int (*lua_CFunction_noexcept)(lua_State* L) noexcept; +#else + typedef int (*lua_CFunction_noexcept)(lua_State* L); +#endif // noexcept function type for lua_CFunction + + template <typename T> + struct implicit_wrapper { + T& value; + + implicit_wrapper(T* value_) : value(*value_) { + } + + implicit_wrapper(T& value_) : value(value_) { + } + + operator T&() { + return value; + } + + operator T*() { + return std::addressof(value); + } + }; + + struct yield_tag_t { }; + inline constexpr yield_tag_t yield_tag {}; + } // namespace detail + + struct lua_nil_t { }; + inline constexpr lua_nil_t lua_nil {}; + inline bool operator==(lua_nil_t, lua_nil_t) { + return true; + } + inline bool operator!=(lua_nil_t, lua_nil_t) { + return false; + } +#if SOL_IS_ON(SOL_NIL) + using nil_t = lua_nil_t; + inline constexpr const nil_t& nil = lua_nil; +#endif + + namespace detail { + struct non_lua_nil_t { }; + } // namespace detail + + struct metatable_key_t { }; + inline constexpr metatable_key_t metatable_key {}; + + struct global_tag_t { + } inline constexpr global_tag {}; + + struct env_key_t { }; + inline constexpr env_key_t env_key {}; + + struct no_metatable_t { }; + inline constexpr no_metatable_t no_metatable {}; + + template <typename T> + struct yielding_t { + T func; + + yielding_t() = default; + yielding_t(const yielding_t&) = default; + yielding_t(yielding_t&&) = default; + yielding_t& operator=(const yielding_t&) = default; + yielding_t& operator=(yielding_t&&) = default; + template <typename Arg, + meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, yielding_t>>, + meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler> + yielding_t(Arg&& arg) : func(std::forward<Arg>(arg)) { + } + template <typename Arg0, typename Arg1, typename... Args> + yielding_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) : func(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) { + } + }; + + template <typename F> + inline yielding_t<std::decay_t<F>> yielding(F&& f) { + return yielding_t<std::decay_t<F>>(std::forward<F>(f)); + } + + typedef std::remove_pointer_t<lua_CFunction> lua_CFunction_ref; + + template <typename T> + struct non_null { }; + + template <typename... Args> + struct function_sig { }; + + struct upvalue_index { + int index; + upvalue_index(int idx) : index(lua_upvalueindex(idx)) { + } + + operator int() const { + return index; + } + }; + + struct raw_index { + int index; + raw_index(int i) : index(i) { + } + + operator int() const { + return index; + } + }; + + struct absolute_index { + int index; + absolute_index(lua_State* L, int idx) : index(lua_absindex(L, idx)) { + } + + operator int() const { + return index; + } + }; + + struct ref_index { + int index; + ref_index(int idx) : index(idx) { + } + + operator int() const { + return index; + } + }; + + struct stack_count { + int count; + + stack_count(int cnt) : count(cnt) { + } + }; + + struct lightuserdata_value { + void* value; + lightuserdata_value(void* data) : value(data) { + } + operator void*() const { + return value; + } + }; + + struct userdata_value { + private: + void* m_value; + + public: + userdata_value(void* data) : m_value(data) { + } + + void* value() const { + return m_value; + } + + operator void*() const { + return value(); + } + }; + + template <typename T> + struct light { + private: + static_assert(!std::is_void_v<T>, "the type for light will never be void"); + T* m_value; + + public: + light(T& x) : m_value(std::addressof(x)) { + } + light(T* x) : m_value(x) { + } + explicit light(void* x) : m_value(static_cast<T*>(x)) { + } + + T* value() const { + return m_value; + } + + operator T*() const { + return m_value; + } + operator T&() const { + return *m_value; + } + + void* void_value() const { + return m_value; + } + }; + + template <typename T> + auto make_light(T& l) { + typedef meta::unwrapped_t<std::remove_pointer_t<std::remove_pointer_t<T>>> L; + return light<L>(l); + } + + template <typename T> + struct user : private detail::ebco<T> { + private: + using base_t = detail::ebco<T>; + + public: + using base_t::base_t; + + using base_t::value; + + operator std::add_pointer_t<std::remove_reference_t<T>>() { + return std::addressof(this->base_t::value()); + } + + operator std::add_pointer_t<std::add_const_t<std::remove_reference_t<T>>>() const { + return std::addressof(this->base_t::value()); + } + + operator std::add_lvalue_reference_t<T>() { + return this->base_t::value(); + } + + operator std::add_const_t<std::add_lvalue_reference_t<T>>&() const { + return this->base_t::value(); + } + }; + + template <typename T> + auto make_user(T&& u) { + typedef meta::unwrapped_t<meta::unqualified_t<T>> U; + return user<U>(std::forward<T>(u)); + } + + template <typename T> + struct metatable_registry_key : private detail::ebco<T> { + private: + using base_t = detail::ebco<T>; + + public: + using base_t::base_t; + + using base_t::value; + }; + + template <typename T> + auto meta_registry_key(T&& key) { + typedef meta::unqualified_t<T> K; + return metatable_registry_key<K>(std::forward<T>(key)); + } + + template <typename... Upvalues> + struct closure { + lua_CFunction c_function; + std::tuple<Upvalues...> upvalues; + closure(lua_CFunction f, Upvalues... targetupvalues) : c_function(f), upvalues(std::forward<Upvalues>(targetupvalues)...) { + } + }; + + template <> + struct closure<> { + lua_CFunction c_function; + int upvalues; + closure(lua_CFunction f, int upvalue_count = 0) : c_function(f), upvalues(upvalue_count) { + } + }; + + typedef closure<> c_closure; + + template <typename... Args> + closure<Args...> make_closure(lua_CFunction f, Args&&... args) { + return closure<Args...>(f, std::forward<Args>(args)...); + } + + template <typename Sig, typename... Ps> + struct function_arguments { + std::tuple<Ps...> arguments; + template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, function_arguments>> = meta::enabler> + function_arguments(Arg&& arg, Args&&... args) : arguments(std::forward<Arg>(arg), std::forward<Args>(args)...) { + } + }; + + template <typename Sig = function_sig<>, typename... Args> + auto as_function(Args&&... args) { + return function_arguments<Sig, std::decay_t<Args>...>(std::forward<Args>(args)...); + } + + template <typename Sig = function_sig<>, typename... Args> + auto as_function_reference(Args&&... args) { + return function_arguments<Sig, Args...>(std::forward<Args>(args)...); + } + + template <typename T> + struct as_table_t : private detail::ebco<T> { + private: + using base_t = detail::ebco<T>; + + public: + as_table_t() = default; + as_table_t(const as_table_t&) = default; + as_table_t(as_table_t&&) = default; + as_table_t& operator=(const as_table_t&) = default; + as_table_t& operator=(as_table_t&&) = default; + as_table_t(const meta::unqualified_t<T>& obj) noexcept(std::is_nothrow_constructible_v<base_t, const meta::unqualified_t<T>&>) : base_t(obj) { + } + as_table_t(meta::unqualified_t<T>&& obj) noexcept(std::is_nothrow_constructible_v<base_t, meta::unqualified_t<T>&&>) : base_t(std::move(obj)) { + } + template <typename Arg, typename... Args, + std::enable_if_t< + !std::is_same_v<as_table_t, meta::unqualified_t<Arg>> && !std::is_same_v<meta::unqualified_t<T>, meta::unqualified_t<Arg>>>* = nullptr> + as_table_t(Arg&& arg, Args&&... args) noexcept(std::is_nothrow_constructible_v<base_t, Arg, Args...>) + : base_t(std::forward<Arg>(arg), std::forward<Args>(args)...) { + } + + using base_t::value; + + operator std::add_lvalue_reference_t<T>() { + return this->base_t::value(); + } + + operator std::add_const_t<std::add_lvalue_reference_t<T>>() const { + return this->base_t::value(); + } + }; + + template <typename T> + struct nested : private detail::ebco<T> { + private: + using base_t = detail::ebco<T>; + + public: + using nested_type = T; + + nested() = default; + nested(const nested&) = default; + nested(nested&&) = default; + nested& operator=(const nested&) = default; + nested& operator=(nested&&) = default; + nested(const meta::unqualified_t<T>& obj) noexcept(std::is_nothrow_constructible_v<base_t, const meta::unqualified_t<T>&>) : base_t(obj) { + } + nested(meta::unqualified_t<T>&& obj) noexcept(std::is_nothrow_constructible_v<base_t, meta::unqualified_t<T>&&>) : base_t(std::move(obj)) { + } + template <typename Arg, typename... Args, + std::enable_if_t< + !std::is_same_v<nested, meta::unqualified_t<Arg>> && !std::is_same_v<meta::unqualified_t<T>, meta::unqualified_t<Arg>>>* = nullptr> + nested(Arg&& arg, Args&&... args) noexcept(std::is_nothrow_constructible_v<base_t, Arg, Args...>) + : base_t(std::forward<Arg>(arg), std::forward<Args>(args)...) { + } + + using base_t::value; + + operator std::add_lvalue_reference_t<T>() { + return this->base_t::value(); + } + + operator std::add_const_t<std::add_lvalue_reference_t<T>>() const { + return this->base_t::value(); + } + }; + + struct nested_tag_t { }; + constexpr inline nested_tag_t nested_tag {}; + + template <typename T> + as_table_t<T> as_table_ref(T&& container) { + return as_table_t<T>(std::forward<T>(container)); + } + + template <typename T> + as_table_t<meta::unqualified_t<T>> as_table(T&& container) { + return as_table_t<meta::unqualified_t<T>>(std::forward<T>(container)); + } + + template <typename T> + nested<T> as_nested_ref(T&& container) { + return nested<T>(std::forward<T>(container)); + } + + template <typename T> + nested<meta::unqualified_t<T>> as_nested(T&& container) { + return nested<meta::unqualified_t<T>>(std::forward<T>(container)); + } + + template <typename T> + struct as_container_t : private detail::ebco<T> { + private: + using base_t = detail::ebco<T>; + + public: + using type = T; + + as_container_t() = default; + as_container_t(const as_container_t&) = default; + as_container_t(as_container_t&&) = default; + as_container_t& operator=(const as_container_t&) = default; + as_container_t& operator=(as_container_t&&) = default; + + using base_t::base_t; + + using base_t::value; + + operator std::add_lvalue_reference_t<T>() { + return value(); + } + }; + + template <typename T> + auto as_container(T&& value) { + return as_container_t<T>(std::forward<T>(value)); + } + + template <typename T, std::size_t Limit = 15> + struct exhaustive_until : private detail::ebco<T> { + private: + using base_t = detail::ebco<T>; + + public: + using base_t::base_t; + + using base_t::value; + + operator std::add_pointer_t<std::remove_reference_t<T>>() { + return std::addressof(this->base_t::value()); + } + + operator std::add_pointer_t<std::add_const_t<std::remove_reference_t<T>>>() const { + return std::addressof(this->base_t::value()); + } + + operator std::add_lvalue_reference_t<T>() { + return this->base_t::value(); + } + + operator std::add_const_t<std::add_lvalue_reference_t<T>>&() const { + return this->base_t::value(); + } + }; + + template <typename T> + using exhaustive = exhaustive_until<T, (std::numeric_limits<size_t>::max)()>; + + template <typename T> + struct non_exhaustive : private detail::ebco<T> { + private: + using base_t = detail::ebco<T>; + + public: + using base_t::base_t; + + using base_t::value; + + operator std::add_pointer_t<std::remove_reference_t<T>>() { + return std::addressof(this->base_t::value()); + } + + operator std::add_pointer_t<std::add_const_t<std::remove_reference_t<T>>>() const { + return std::addressof(this->base_t::value()); + } + + operator std::add_lvalue_reference_t<T>() { + return this->base_t::value(); + } + + operator std::add_const_t<std::add_lvalue_reference_t<T>>&() const { + return this->base_t::value(); + } + }; + + template <typename T> + struct push_invoke_t : private detail::ebco<T> { + private: + using base_t = detail::ebco<T>; + + public: + push_invoke_t() = default; + push_invoke_t(const push_invoke_t&) = default; + push_invoke_t(push_invoke_t&&) = default; + push_invoke_t& operator=(const push_invoke_t&) = default; + push_invoke_t& operator=(push_invoke_t&&) = default; + + using base_t::base_t; + + using base_t::value; + }; + + template <typename Fx> + auto push_invoke(Fx&& fx) { + return push_invoke_t<Fx>(std::forward<Fx>(fx)); + } + + template <typename T> + struct forward_as_value_t : private detail::ebco<T> { + private: + using base_t = detail::ebco<T>; + + public: + forward_as_value_t() = default; + forward_as_value_t(const forward_as_value_t&) = default; + forward_as_value_t(forward_as_value_t&&) = default; + forward_as_value_t& operator=(const forward_as_value_t&) = default; + forward_as_value_t& operator=(forward_as_value_t&&) = default; + + using base_t::base_t; + + using base_t::value; + }; + + template <typename T> + auto pass_as_value(T& value_ref_) { + return forward_as_value_t<T>(value_ref_); + } + + struct override_value_t { }; + constexpr inline override_value_t override_value = override_value_t(); + struct update_if_empty_t { }; + constexpr inline update_if_empty_t update_if_empty = update_if_empty_t(); + struct create_if_nil_t { }; + constexpr inline create_if_nil_t create_if_nil = create_if_nil_t(); + + namespace detail { + enum insert_mode { none = 0x0, update_if_empty = 0x01, override_value = 0x02, create_if_nil = 0x04 }; + + template <typename T, typename...> + using is_insert_mode = std::integral_constant<bool, + std::is_same_v<T, override_value_t> || std::is_same_v<T, update_if_empty_t> || std::is_same_v<T, create_if_nil_t>>; + + template <typename T, typename...> + using is_not_insert_mode = meta::neg<is_insert_mode<T>>; + } // namespace detail + + struct this_state { + lua_State* L; + + this_state(lua_State* Ls) : L(Ls) { + } + + operator lua_State*() const noexcept { + return lua_state(); + } + + lua_State* operator->() const noexcept { + return lua_state(); + } + + lua_State* lua_state() const noexcept { + return L; + } + }; + + struct this_main_state { + lua_State* L; + + this_main_state(lua_State* Ls) : L(Ls) { + } + + operator lua_State*() const noexcept { + return lua_state(); + } + + lua_State* operator->() const noexcept { + return lua_state(); + } + + lua_State* lua_state() const noexcept { + return L; + } + }; + + struct new_table { + int sequence_hint = 0; + int map_hint = 0; + + new_table() = default; + new_table(const new_table&) = default; + new_table(new_table&&) = default; + new_table& operator=(const new_table&) = default; + new_table& operator=(new_table&&) = default; + + new_table(int sequence_hint_, int map_hint_ = 0) noexcept : sequence_hint(sequence_hint_), map_hint(map_hint_) { + } + }; + + const new_table create = {}; + + enum class lib : unsigned char { + // print, assert, and other base functions + base, + // require and other package functions + package, + // coroutine functions and utilities + coroutine, + // string library + string, + // functionality from the OS + os, + // all things math + math, + // the table manipulator and observer functions + table, + // the debug library + debug, + // the bit library: different based on which you're using + bit32, + // input/output library + io, + // LuaJIT only + ffi, + // LuaJIT only + jit, + // library for handling utf8: new to Lua + utf8, + // do not use + count + }; + + enum class call_syntax { dot = 0, colon = 1 }; + + enum class load_mode { + any = 0, + text = 1, + binary = 2, + }; + + enum class call_status : int { + ok = LUA_OK, + yielded = LUA_YIELD, + runtime = LUA_ERRRUN, + memory = LUA_ERRMEM, + handler = LUA_ERRERR, + gc = LUA_ERRGCMM, + syntax = LUA_ERRSYNTAX, + file = LUA_ERRFILE, + }; + + enum class thread_status : int { + ok = LUA_OK, + yielded = LUA_YIELD, + runtime = LUA_ERRRUN, + memory = LUA_ERRMEM, + gc = LUA_ERRGCMM, + handler = LUA_ERRERR, + dead = -1, + }; + + enum class load_status : int { + ok = LUA_OK, + syntax = LUA_ERRSYNTAX, + memory = LUA_ERRMEM, + gc = LUA_ERRGCMM, + file = LUA_ERRFILE, + }; + + enum class gc_mode : int { + incremental = 0, + generational = 1, + default_value = incremental, + }; + + enum class type : int { + none = LUA_TNONE, + lua_nil = LUA_TNIL, +#if SOL_IS_ON(SOL_NIL) + nil = lua_nil, +#endif // Objective C/C++ Keyword that's found in OSX SDK and OBJC -- check for all forms to protect + string = LUA_TSTRING, + number = LUA_TNUMBER, + thread = LUA_TTHREAD, + boolean = LUA_TBOOLEAN, + function = LUA_TFUNCTION, + userdata = LUA_TUSERDATA, + lightuserdata = LUA_TLIGHTUSERDATA, + table = LUA_TTABLE, + poly = -0xFFFF + }; + + inline const std::string& to_string(call_status c) { + static const std::array<std::string, 10> names { { "ok", + "yielded", + "runtime", + "memory", + "handler", + "gc", + "syntax", + "file", + "CRITICAL_EXCEPTION_FAILURE", + "CRITICAL_INDETERMINATE_STATE_FAILURE" } }; + switch (c) { + case call_status::ok: + return names[0]; + case call_status::yielded: + return names[1]; + case call_status::runtime: + return names[2]; + case call_status::memory: + return names[3]; + case call_status::handler: + return names[4]; + case call_status::gc: + return names[5]; + case call_status::syntax: + return names[6]; + case call_status::file: + return names[7]; + } + if (static_cast<std::ptrdiff_t>(c) == -1) { + // One of the many cases where a critical exception error has occurred + return names[8]; + } + return names[9]; + } + + inline bool is_indeterminate_call_failure(call_status c) { + switch (c) { + case call_status::ok: + case call_status::yielded: + case call_status::runtime: + case call_status::memory: + case call_status::handler: + case call_status::gc: + case call_status::syntax: + case call_status::file: + return false; + } + return true; + } + + inline const std::string& to_string(load_status c) { + static const std::array<std::string, 7> names { + { "ok", "memory", "gc", "syntax", "file", "CRITICAL_EXCEPTION_FAILURE", "CRITICAL_INDETERMINATE_STATE_FAILURE" } + }; + switch (c) { + case load_status::ok: + return names[0]; + case load_status::memory: + return names[1]; + case load_status::gc: + return names[2]; + case load_status::syntax: + return names[3]; + case load_status::file: + return names[4]; + } + if (static_cast<int>(c) == -1) { + // One of the many cases where a critical exception error has occurred + return names[5]; + } + return names[6]; + } + + inline const std::string& to_string(load_mode c) { + static const std::array<std::string, 3> names { { + "bt", + "t", + "b", + } }; + return names[static_cast<std::size_t>(c)]; + } + + enum class meta_function : unsigned { + construct, + index, + new_index, + mode, + call, + call_function = call, + metatable, + to_string, + length, + unary_minus, + addition, + subtraction, + multiplication, + division, + modulus, + power_of, + involution = power_of, + concatenation, + equal_to, + less_than, + less_than_or_equal_to, + garbage_collect, + floor_division, + bitwise_left_shift, + bitwise_right_shift, + bitwise_not, + bitwise_and, + bitwise_or, + bitwise_xor, + pairs, + ipairs, + next, + type, + type_info, + call_construct, + storage, + gc_names, + static_index, + static_new_index, + }; + + typedef meta_function meta_method; + + inline const std::array<std::string, 37>& meta_function_names() { + static const std::array<std::string, 37> names = { { "new", + "__index", + "__newindex", + "__mode", + "__call", + "__metatable", + "__tostring", + "__len", + "__unm", + "__add", + "__sub", + "__mul", + "__div", + "__mod", + "__pow", + "__concat", + "__eq", + "__lt", + "__le", + "__gc", + + "__idiv", + "__shl", + "__shr", + "__bnot", + "__band", + "__bor", + "__bxor", + + "__pairs", + "__ipairs", + "next", + + "__type", + "__typeinfo", + "__sol.call_new", + "__sol.storage", + "__sol.gc_names", + "__sol.static_index", + "__sol.static_new_index" } }; + return names; + } + + inline const std::string& to_string(meta_function mf) { + return meta_function_names()[static_cast<std::size_t>(mf)]; + } + + inline type type_of(lua_State* L, int index) { + return static_cast<type>(lua_type(L, index)); + } + + inline std::string type_name(lua_State* L, type t) { + return lua_typename(L, static_cast<int>(t)); + } + + template <typename T> + struct is_stateless_lua_reference + : std::integral_constant<bool, + (std::is_base_of_v<stateless_stack_reference, T> || std::is_base_of_v<stateless_reference, T>)&&( + !std::is_base_of_v<stack_reference, T> && !std::is_base_of_v<reference, T> && !std::is_base_of_v<main_reference, T>)> { }; + + template <typename T> + inline constexpr bool is_stateless_lua_reference_v = is_stateless_lua_reference<T>::value; + + template <typename T> + struct is_lua_reference + : std::integral_constant<bool, + std::is_base_of_v<reference, + T> || std::is_base_of_v<main_reference, T> || std::is_base_of_v<stack_reference, T> || std::is_base_of_v<stateless_stack_reference, T> || std::is_base_of_v<stateless_reference, T>> { + }; + + template <typename T> + inline constexpr bool is_lua_reference_v = is_lua_reference<T>::value; + + template <typename T> + struct is_lua_reference_or_proxy : std::integral_constant<bool, is_lua_reference_v<T> || meta::is_specialization_of_v<T, table_proxy>> { }; + + template <typename T> + inline constexpr bool is_lua_reference_or_proxy_v = is_lua_reference_or_proxy<T>::value; + + template <typename T> + struct is_transparent_argument + : std::integral_constant<bool, + std::is_same_v<meta::unqualified_t<T>, + this_state> || std::is_same_v<meta::unqualified_t<T>, this_main_state> || std::is_same_v<meta::unqualified_t<T>, this_environment> || std::is_same_v<meta::unqualified_t<T>, variadic_args>> { + }; + + template <typename T> + constexpr inline bool is_transparent_argument_v = is_transparent_argument<T>::value; + + template <typename T> + struct is_variadic_arguments : meta::any<std::is_same<T, variadic_args>, meta::is_optional<T>> { }; + + template <typename T> + struct is_container + : std::integral_constant<bool, + !std::is_same_v<state_view, + T> && !std::is_same_v<state, T> && !meta::is_initializer_list_v<T> && !meta::is_string_like_v<T> && !meta::is_string_literal_array_v<T> && !is_transparent_argument_v<T> && !is_lua_reference_v<T> && (meta::has_begin_end_v<T> || std::is_array_v<T>)> { + }; + + template <typename T> + constexpr inline bool is_container_v = is_container<T>::value; + + template <typename T> + struct is_to_stringable : meta::any<meta::supports_to_string_member<meta::unqualified_t<T>>, meta::supports_adl_to_string<meta::unqualified_t<T>>, + meta::supports_op_left_shift<std::ostream, meta::unqualified_t<T>>> { }; + + template <typename T> + inline constexpr bool is_to_stringable_v = is_to_stringable<T>::value; + + template <typename T> + struct is_callable : std::true_type { }; + + template <typename T> + inline constexpr bool is_callable_v = is_callable<T>::value; + + namespace detail { + template <typename T, typename = void> + struct lua_type_of : std::integral_constant<type, type::userdata> { }; + + template <typename C, typename T, typename A> + struct lua_type_of<std::basic_string<C, T, A>> : std::integral_constant<type, type::string> { }; + + template <typename C, typename T> + struct lua_type_of<basic_string_view<C, T>> : std::integral_constant<type, type::string> { }; + + template <std::size_t N> + struct lua_type_of<char[N]> : std::integral_constant<type, type::string> { }; + + template <std::size_t N> + struct lua_type_of<wchar_t[N]> : std::integral_constant<type, type::string> { }; + +#if SOL_IS_ON(SOL_CHAR8_T) + template <std::size_t N> + struct lua_type_of<char8_t[N]> : std::integral_constant<type, type::string> { }; +#endif + + template <std::size_t N> + struct lua_type_of<char16_t[N]> : std::integral_constant<type, type::string> { }; + + template <std::size_t N> + struct lua_type_of<char32_t[N]> : std::integral_constant<type, type::string> { }; + + template <> + struct lua_type_of<char> : std::integral_constant<type, type::string> { }; + + template <> + struct lua_type_of<wchar_t> : std::integral_constant<type, type::string> { }; + +#if SOL_IS_ON(SOL_CHAR8_T) + template <> + struct lua_type_of<char8_t> : std::integral_constant<type, type::string> { }; +#endif + + template <> + struct lua_type_of<char16_t> : std::integral_constant<type, type::string> { }; + + template <> + struct lua_type_of<char32_t> : std::integral_constant<type, type::string> { }; + + template <> + struct lua_type_of<const char*> : std::integral_constant<type, type::string> { }; + + template <> + struct lua_type_of<const wchar_t*> : std::integral_constant<type, type::string> { }; + +#if SOL_IS_ON(SOL_CHAR8_T) + template <> + struct lua_type_of<const char8_t*> : std::integral_constant<type, type::string> { }; +#endif + + template <> + struct lua_type_of<const char16_t*> : std::integral_constant<type, type::string> { }; + + template <> + struct lua_type_of<const char32_t*> : std::integral_constant<type, type::string> { }; + + template <> + struct lua_type_of<bool> : std::integral_constant<type, type::boolean> { }; + + template <> + struct lua_type_of<lua_nil_t> : std::integral_constant<type, type::lua_nil> { }; + + template <> + struct lua_type_of<nullopt_t> : std::integral_constant<type, type::lua_nil> { }; + + template <> + struct lua_type_of<lua_value> : std::integral_constant<type, type::poly> { }; + + template <> + struct lua_type_of<detail::non_lua_nil_t> : std::integral_constant<type, type::poly> { }; + + template <> + struct lua_type_of<std::nullptr_t> : std::integral_constant<type, type::lua_nil> { }; + + template <> + struct lua_type_of<error> : std::integral_constant<type, type::string> { }; + + template <bool b, typename Base> + struct lua_type_of<basic_table_core<b, Base>> : std::integral_constant<type, type::table> { }; + + template <typename Base> + struct lua_type_of<basic_lua_table<Base>> : std::integral_constant<type, type::table> { }; + + template <typename Base> + struct lua_type_of<basic_metatable<Base>> : std::integral_constant<type, type::table> { }; + + template <typename T, typename Base> + struct lua_type_of<basic_usertype<T, Base>> : std::integral_constant<type, type::table> { }; + + template <> + struct lua_type_of<metatable_key_t> : std::integral_constant<type, type::table> { }; + + template <typename B> + struct lua_type_of<basic_environment<B>> : std::integral_constant<type, type::poly> { }; + + template <> + struct lua_type_of<env_key_t> : std::integral_constant<type, type::poly> { }; + + template <> + struct lua_type_of<new_table> : std::integral_constant<type, type::table> { }; + + template <typename T> + struct lua_type_of<as_table_t<T>> : std::integral_constant<type, type::table> { }; + + template <typename T> + struct lua_type_of<std::initializer_list<T>> : std::integral_constant<type, type::table> { }; + + template <bool b> + struct lua_type_of<basic_reference<b>> : std::integral_constant<type, type::poly> { }; + + template <> + struct lua_type_of<stack_reference> : std::integral_constant<type, type::poly> { }; + + template <typename Base> + struct lua_type_of<basic_object<Base>> : std::integral_constant<type, type::poly> { }; + + template <typename... Args> + struct lua_type_of<std::tuple<Args...>> : std::integral_constant<type, type::poly> { }; + + template <typename A, typename B> + struct lua_type_of<std::pair<A, B>> : std::integral_constant<type, type::poly> { }; + + template <> + struct lua_type_of<void*> : std::integral_constant<type, type::lightuserdata> { }; + + template <> + struct lua_type_of<const void*> : std::integral_constant<type, type::lightuserdata> { }; + + template <> + struct lua_type_of<lightuserdata_value> : std::integral_constant<type, type::lightuserdata> { }; + + template <> + struct lua_type_of<userdata_value> : std::integral_constant<type, type::userdata> { }; + + template <typename T> + struct lua_type_of<light<T>> : std::integral_constant<type, type::lightuserdata> { }; + + template <typename T> + struct lua_type_of<user<T>> : std::integral_constant<type, type::userdata> { }; + + template <typename Base> + struct lua_type_of<basic_lightuserdata<Base>> : std::integral_constant<type, type::lightuserdata> { }; + + template <typename Base> + struct lua_type_of<basic_userdata<Base>> : std::integral_constant<type, type::userdata> { }; + + template <> + struct lua_type_of<lua_CFunction> : std::integral_constant<type, type::function> { }; + + template <> + struct lua_type_of<std::remove_pointer_t<lua_CFunction>> : std::integral_constant<type, type::function> { }; + + template <typename Base, bool aligned> + struct lua_type_of<basic_function<Base, aligned>> : std::integral_constant<type, type::function> { }; + + template <typename Base, bool aligned, typename Handler> + struct lua_type_of<basic_protected_function<Base, aligned, Handler>> : std::integral_constant<type, type::function> { }; + + template <typename Base> + struct lua_type_of<basic_coroutine<Base>> : std::integral_constant<type, type::function> { }; + + template <typename Base> + struct lua_type_of<basic_thread<Base>> : std::integral_constant<type, type::thread> { }; + + template <typename Signature> + struct lua_type_of<std::function<Signature>> : std::integral_constant<type, type::function> { }; + + template <typename T> + struct lua_type_of<optional<T>> : std::integral_constant<type, type::poly> { }; + + template <typename T> + struct lua_type_of<std::optional<T>> : std::integral_constant<type, type::poly> { }; + + template <> + struct lua_type_of<variadic_args> : std::integral_constant<type, type::poly> { }; + + template <> + struct lua_type_of<variadic_results> : std::integral_constant<type, type::poly> { }; + + template <> + struct lua_type_of<stack_count> : std::integral_constant<type, type::poly> { }; + + template <> + struct lua_type_of<this_state> : std::integral_constant<type, type::poly> { }; + + template <> + struct lua_type_of<this_main_state> : std::integral_constant<type, type::poly> { }; + + template <> + struct lua_type_of<this_environment> : std::integral_constant<type, type::poly> { }; + + template <> + struct lua_type_of<type> : std::integral_constant<type, type::poly> { }; + +#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE) + template <typename T> + struct lua_type_of<T*> : std::integral_constant<type, std::is_function_v<T> ? type::function : type::userdata> { }; +#else + template <typename T> + struct lua_type_of<T*> : std::integral_constant<type, type::userdata> { }; +#endif + + template <typename T> + struct lua_type_of<T, std::enable_if_t<std::is_arithmetic_v<T> || std::is_same_v<T, lua_Number> || std::is_same_v<T, lua_Integer>>> + : std::integral_constant<type, type::number> { }; + + template <typename T> + struct lua_type_of<T, std::enable_if_t<std::is_function_v<T>>> : std::integral_constant<type, type::function> { }; + + template <typename T> + struct lua_type_of<T, std::enable_if_t<std::is_enum_v<T>>> : std::integral_constant<type, type::number> { }; + + template <> + struct lua_type_of<meta_function> : std::integral_constant<type, type::string> { }; + +#if SOL_IS_ON(SOL_STD_VARIANT) + template <typename... Tn> + struct lua_type_of<std::variant<Tn...>> : std::integral_constant<type, type::poly> { }; +#endif // std::variant deployment sucks on Clang + + template <typename T> + struct lua_type_of<nested<T>> : meta::conditional_t<::sol::is_container_v<T>, std::integral_constant<type, type::table>, lua_type_of<T>> { }; + + template <typename C, C v, template <typename...> class V, typename... Args> + struct accumulate : std::integral_constant<C, v> { }; + + template <typename C, C v, template <typename...> class V, typename T, typename... Args> + struct accumulate<C, v, V, T, Args...> : accumulate<C, v + V<T>::value, V, Args...> { }; + + template <typename C, C v, template <typename...> class V, typename List> + struct accumulate_list; + + template <typename C, C v, template <typename...> class V, typename... Args> + struct accumulate_list<C, v, V, types<Args...>> : accumulate<C, v, V, Args...> { }; + } // namespace detail + + template <typename T> + struct lua_type_of : detail::lua_type_of<T> { + typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_; + }; + + template <typename T> + inline constexpr type lua_type_of_v = lua_type_of<T>::value; + + template <typename T> + struct lua_size : std::integral_constant<int, 1> { + typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_; + }; + + template <typename A, typename B> + struct lua_size<std::pair<A, B>> : std::integral_constant<int, lua_size<A>::value + lua_size<B>::value> { }; + + template <typename... Args> + struct lua_size<std::tuple<Args...>> : std::integral_constant<int, detail::accumulate<int, 0, lua_size, Args...>::value> { }; + + template <typename T> + inline constexpr int lua_size_v = lua_size<T>::value; + + namespace detail { + // MSVC's decltype detection is broken, which breaks other + // parts of the code. So we add more workarounds. The moment it's fixed, + // we take it away and break everyone that doesn't upgrade. + template <typename T> + using is_msvc_callable_rigged = meta::any<meta::is_specialization_of<T, push_invoke_t>, meta::is_specialization_of<T, as_table_t>, + meta::is_specialization_of<T, forward_as_value_t>, meta::is_specialization_of<T, as_container_t>, meta::is_specialization_of<T, nested>, + meta::is_specialization_of<T, yielding_t>>; + + template <typename T> + inline constexpr bool is_msvc_callable_rigged_v = is_msvc_callable_rigged<T>::value; + } // namespace detail + + template <typename T> + struct is_lua_primitive : std::integral_constant<bool, + type::userdata != lua_type_of_v<T> // cf + || ((type::userdata == lua_type_of_v<T>) // cf + &&meta::meta_detail::has_internal_marker_v<lua_type_of<T>> // cf + && !meta::meta_detail::has_internal_marker_v<lua_size<T>>) // cf + || is_lua_reference_or_proxy_v<T> // cf + || meta::is_specialization_of_v<T, std::tuple> // cf + || meta::is_specialization_of_v<T, std::pair>> { }; + + template <typename T> + constexpr inline bool is_lua_primitive_v = is_lua_primitive<T>::value; + + template <typename T> + struct is_value_semantic_for_function +#if SOL_IS_ON(SOL_FUNCTION_CALL_VALUE_SEMANTICS) + : std::true_type { + }; +#else + : std::false_type { + }; +#endif + + template <typename T> + constexpr inline bool is_value_semantic_for_function_v = is_value_semantic_for_function<T>::value; + + template <typename T> + struct is_main_threaded : std::is_base_of<main_reference, T> { }; + + template <typename T> + inline constexpr bool is_main_threaded_v = is_main_threaded<T>::value; + + template <typename T> + struct is_stack_based : std::is_base_of<stack_reference, T> { }; + template <> + struct is_stack_based<variadic_args> : std::true_type { }; + template <> + struct is_stack_based<unsafe_function_result> : std::true_type { }; + template <> + struct is_stack_based<protected_function_result> : std::true_type { }; + template <> + struct is_stack_based<stack_proxy> : std::true_type { }; + template <> + struct is_stack_based<stack_proxy_base> : std::true_type { }; + template <> + struct is_stack_based<stack_count> : std::true_type { }; + + template <typename T> + constexpr inline bool is_stack_based_v = is_stack_based<T>::value; + + template <typename T> + struct is_lua_primitive<T*> : std::true_type { }; + template <> + struct is_lua_primitive<unsafe_function_result> : std::true_type { }; + template <> + struct is_lua_primitive<protected_function_result> : std::true_type { }; + template <typename T> + struct is_lua_primitive<std::reference_wrapper<T>> : std::true_type { }; + template <typename T> + struct is_lua_primitive<user<T>> : std::true_type { }; + template <typename T> + struct is_lua_primitive<light<T>> : is_lua_primitive<T*> { }; + template <typename T> + struct is_lua_primitive<optional<T>> : std::true_type { }; + template <typename T> + struct is_lua_primitive<std::optional<T>> : std::true_type { }; + template <typename T> + struct is_lua_primitive<as_table_t<T>> : std::true_type { }; + template <typename T> + struct is_lua_primitive<nested<T>> : std::true_type { }; + template <> + struct is_lua_primitive<userdata_value> : std::true_type { }; + template <> + struct is_lua_primitive<lightuserdata_value> : std::true_type { }; + template <> + struct is_lua_primitive<stack_proxy> : std::true_type { }; + template <> + struct is_lua_primitive<stack_proxy_base> : std::true_type { }; + template <typename T> + struct is_lua_primitive<non_null<T>> : is_lua_primitive<T*> { }; + + template <typename T> + struct is_lua_index : std::is_integral<T> { }; + template <> + struct is_lua_index<raw_index> : std::true_type { }; + template <> + struct is_lua_index<absolute_index> : std::true_type { }; + template <> + struct is_lua_index<ref_index> : std::true_type { }; + template <> + struct is_lua_index<upvalue_index> : std::true_type { }; + + template <typename Signature> + struct lua_bind_traits : meta::bind_traits<Signature> { + private: + typedef meta::bind_traits<Signature> base_t; + + public: + typedef std::integral_constant<bool, meta::count_for<is_variadic_arguments, typename base_t::args_list>::value != 0> runtime_variadics_t; + static const std::size_t true_arity = base_t::arity; + static const std::size_t arity = detail::accumulate_list<std::size_t, 0, lua_size, typename base_t::args_list>::value + - meta::count_for<is_transparent_argument, typename base_t::args_list>::value; + static const std::size_t true_free_arity = base_t::free_arity; + static const std::size_t free_arity = detail::accumulate_list<std::size_t, 0, lua_size, typename base_t::free_args_list>::value + - meta::count_for<is_transparent_argument, typename base_t::args_list>::value; + }; + + template <typename T> + struct is_table : std::false_type { }; + template <bool x, typename T> + struct is_table<basic_table_core<x, T>> : std::true_type { }; + template <typename T> + struct is_table<basic_lua_table<T>> : std::true_type { }; + + template <typename T> + inline constexpr bool is_table_v = is_table<T>::value; + + template <typename T> + struct is_global_table : std::false_type { }; + template <typename T> + struct is_global_table<basic_table_core<true, T>> : std::true_type { }; + + template <typename T> + inline constexpr bool is_global_table_v = is_global_table<T>::value; + + template <typename T> + struct is_stack_table : std::false_type { }; + template <bool x, typename T> + struct is_stack_table<basic_table_core<x, T>> : std::integral_constant<bool, std::is_base_of_v<stack_reference, T>> { }; + template <typename T> + struct is_stack_table<basic_lua_table<T>> : std::integral_constant<bool, std::is_base_of_v<stack_reference, T>> { }; + + template <typename T> + inline constexpr bool is_stack_table_v = is_stack_table<T>::value; + + template <typename T> + struct is_function : std::false_type { }; + template <typename T, bool aligned> + struct is_function<basic_function<T, aligned>> : std::true_type { }; + template <typename T, bool aligned, typename Handler> + struct is_function<basic_protected_function<T, aligned, Handler>> : std::true_type { }; + + template <typename T> + using is_lightuserdata = meta::is_specialization_of<T, basic_lightuserdata>; + + template <typename T> + inline constexpr bool is_lightuserdata_v = is_lightuserdata<T>::value; + + template <typename T> + using is_userdata = meta::is_specialization_of<T, basic_userdata>; + + template <typename T> + inline constexpr bool is_userdata_v = is_userdata<T>::value; + + template <typename T> + using is_environment = std::integral_constant<bool, is_userdata_v<T> || is_table_v<T> || meta::is_specialization_of_v<T, basic_environment>>; + + template <typename T> + inline constexpr bool is_environment_v = is_environment<T>::value; + + template <typename T> + using is_table_like = std::integral_constant<bool, is_table_v<T> || is_environment_v<T> || is_userdata_v<T>>; + + template <typename T> + inline constexpr bool is_table_like_v = is_table_like<T>::value; + + template <typename T> + struct is_automagical + : std::integral_constant<bool, + (SOL_IS_ON(SOL_DEFAULT_AUTOMAGICAL_USERTYPES)) + || (std::is_array_v< + meta::unqualified_t<T>> || (!std::is_same_v<meta::unqualified_t<T>, state> && !std::is_same_v<meta::unqualified_t<T>, state_view>))> { + }; + + template <typename T> + inline type type_of() { + return lua_type_of<meta::unqualified_t<T>>::value; + } + + namespace detail { + template <typename T> + struct is_non_factory_constructor : std::false_type { }; + + template <typename... Args> + struct is_non_factory_constructor<constructors<Args...>> : std::true_type { }; + + template <typename... Args> + struct is_non_factory_constructor<constructor_wrapper<Args...>> : std::true_type { }; + + template <> + struct is_non_factory_constructor<no_construction> : std::true_type { }; + + template <typename T> + inline constexpr bool is_non_factory_constructor_v = is_non_factory_constructor<T>::value; + + template <typename T> + struct is_constructor : is_non_factory_constructor<T> { }; + + template <typename... Args> + struct is_constructor<factory_wrapper<Args...>> : std::true_type { }; + + template <typename T> + struct is_constructor<protect_t<T>> : is_constructor<meta::unqualified_t<T>> { }; + + template <typename F, typename... Policies> + struct is_constructor<policy_wrapper<F, Policies...>> : is_constructor<meta::unqualified_t<F>> { }; + + template <typename T> + inline constexpr bool is_constructor_v = is_constructor<T>::value; + + template <typename... Args> + using any_is_constructor = meta::any<is_constructor<meta::unqualified_t<Args>>...>; + + template <typename... Args> + inline constexpr bool any_is_constructor_v = any_is_constructor<Args...>::value; + + template <typename T> + struct is_destructor : std::false_type { }; + + template <typename Fx> + struct is_destructor<destructor_wrapper<Fx>> : std::true_type { }; + + template <typename... Args> + using any_is_destructor = meta::any<is_destructor<meta::unqualified_t<Args>>...>; + + template <typename... Args> + inline constexpr bool any_is_destructor_v = any_is_destructor<Args...>::value; + } // namespace detail + + template <typename T> + using is_lua_c_function = meta::any<std::is_same<lua_CFunction, T>, std::is_same<detail::lua_CFunction_noexcept, T>, std::is_same<lua_CFunction_ref, T>>; + + template <typename T> + inline constexpr bool is_lua_c_function_v = is_lua_c_function<T>::value; + + enum class automagic_flags : unsigned { + none = 0x000u, + default_constructor = 0x001, + destructor = 0x002u, + pairs_operator = 0x004u, + to_string_operator = 0x008u, + call_operator = 0x010u, + less_than_operator = 0x020u, + less_than_or_equal_to_operator = 0x040u, + length_operator = 0x080u, + equal_to_operator = 0x100u, + all = default_constructor | destructor | pairs_operator | to_string_operator | call_operator | less_than_operator | less_than_or_equal_to_operator + | length_operator | equal_to_operator + }; + + inline constexpr automagic_flags operator|(automagic_flags left, automagic_flags right) noexcept { + return static_cast<automagic_flags>( + static_cast<std::underlying_type_t<automagic_flags>>(left) | static_cast<std::underlying_type_t<automagic_flags>>(right)); + } + + inline constexpr automagic_flags operator&(automagic_flags left, automagic_flags right) noexcept { + return static_cast<automagic_flags>( + static_cast<std::underlying_type_t<automagic_flags>>(left) & static_cast<std::underlying_type_t<automagic_flags>>(right)); + } + + inline constexpr automagic_flags& operator|=(automagic_flags& left, automagic_flags right) noexcept { + left = left | right; + return left; + } + + inline constexpr automagic_flags& operator&=(automagic_flags& left, automagic_flags right) noexcept { + left = left & right; + return left; + } + + template <typename Left, typename Right> + constexpr bool has_flag(Left left, Right right) noexcept { + return (left & right) == right; + } + + template <typename Left, typename Right> + constexpr bool has_any_flag(Left left, Right right) noexcept { + return (left & right) != static_cast<Left>(static_cast<std::underlying_type_t<Left>>(0)); + } + + template <typename Left, typename Right> + constexpr auto clear_flags(Left left, Right right) noexcept { + return static_cast<Left>(static_cast<std::underlying_type_t<Left>>(left) & ~static_cast<std::underlying_type_t<Right>>(right)); + } + + struct automagic_enrollments { + bool default_constructor = true; + bool destructor = true; + bool pairs_operator = true; + bool to_string_operator = true; + bool call_operator = true; + bool less_than_operator = true; + bool less_than_or_equal_to_operator = true; + bool length_operator = true; + bool equal_to_operator = true; + }; + + template <automagic_flags compile_time_defaults = automagic_flags::all> + struct constant_automagic_enrollments : public automagic_enrollments { }; + +} // namespace sol + +// end of sol/types.hpp + +#include <exception> +#include <cstring> + +#if SOL_IS_ON(SOL_PRINT_ERRORS) +#include <iostream> +#endif + +namespace sol { + // must push a single object to be the error object + // NOTE: the VAST MAJORITY of all Lua libraries -- C or otherwise -- expect a string for the type of error + // break this convention at your own risk + using exception_handler_function = int (*)(lua_State*, optional<const std::exception&>, string_view); + + namespace detail { + inline const char (&default_exception_handler_name())[11] { + static const char name[11] = "sol.\xE2\x98\xA2\xE2\x98\xA2"; + return name; + } + + // must push at least 1 object on the stack + inline int default_exception_handler(lua_State* L, optional<const std::exception&>, string_view what) { +#if SOL_IS_ON(SOL_PRINT_ERRORS) + std::cerr << "[sol2] An exception occurred: "; + std::cerr.write(what.data(), static_cast<std::streamsize>(what.size())); + std::cerr << std::endl; +#endif + lua_pushlstring(L, what.data(), what.size()); + return 1; + } + + inline int call_exception_handler(lua_State* L, optional<const std::exception&> maybe_ex, string_view what) { + lua_getglobal(L, default_exception_handler_name()); + type t = static_cast<type>(lua_type(L, -1)); + if (t != type::lightuserdata) { + lua_pop(L, 1); + return default_exception_handler(L, std::move(maybe_ex), std::move(what)); + } + void* vfunc = lua_touserdata(L, -1); + lua_pop(L, 1); + if (vfunc == nullptr) { + return default_exception_handler(L, std::move(maybe_ex), std::move(what)); + } + exception_handler_function exfunc = reinterpret_cast<exception_handler_function>(vfunc); + return exfunc(L, std::move(maybe_ex), std::move(what)); + } + +#if SOL_IS_OFF(SOL_EXCEPTIONS) + template <lua_CFunction f> + int static_trampoline(lua_State* L) noexcept { + return f(L); + } + +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) + template <lua_CFunction_noexcept f> + int static_trampoline_noexcept(lua_State* L) noexcept { + return f(L); + } +#else + template <lua_CFunction f> + int static_trampoline_noexcept(lua_State* L) noexcept { + return f(L); + } +#endif + + template <typename Fx, typename... Args> + int trampoline(lua_State* L, Fx&& f, Args&&... args) noexcept { + return f(L, std::forward<Args>(args)...); + } + + inline int c_trampoline(lua_State* L, lua_CFunction f) noexcept { + return trampoline(L, f); + } +#else + + inline int lua_cfunction_trampoline(lua_State* L, lua_CFunction f) { +#if SOL_IS_ON(SOL_PROPAGATE_EXCEPTIONS) + return f(L); +#else + try { + return f(L); + } + catch (const char* cs) { + call_exception_handler(L, optional<const std::exception&>(nullopt), string_view(cs)); + } + catch (const std::string& s) { + call_exception_handler(L, optional<const std::exception&>(nullopt), string_view(s.c_str(), s.size())); + } + catch (const std::exception& e) { + call_exception_handler(L, optional<const std::exception&>(e), e.what()); + } +#if SOL_IS_ON(SOL_EXCEPTIONS_CATCH_ALL) + // LuaJIT cannot have the catchall when the safe propagation is on + // but LuaJIT will swallow all C++ errors + // if we don't at least catch std::exception ones + catch (...) { + call_exception_handler(L, optional<const std::exception&>(nullopt), "caught (...) exception"); + } +#endif // LuaJIT cannot have the catchall, but we must catch std::exceps for it + return lua_error(L); +#endif // Safe exceptions + } + + template <lua_CFunction f> + int static_trampoline(lua_State* L) { + return lua_cfunction_trampoline(L, f); + } + +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) + template <lua_CFunction_noexcept f> + int static_trampoline_noexcept(lua_State* L) noexcept { + return f(L); + } +#else + template <lua_CFunction f> + int static_trampoline_noexcept(lua_State* L) noexcept { + return f(L); + } +#endif + + template <typename Fx, typename... Args> + int trampoline(lua_State* L, Fx&& f, Args&&... args) { + if constexpr (meta::bind_traits<meta::unqualified_t<Fx>>::is_noexcept) { + return f(L, std::forward<Args>(args)...); + } + else { +#if SOL_IS_ON(SOL_PROPAGATE_EXCEPTIONS) + return f(L, std::forward<Args>(args)...); +#else + try { + return f(L, std::forward<Args>(args)...); + } + catch (const char* cs) { + call_exception_handler(L, optional<const std::exception&>(nullopt), string_view(cs)); + } + catch (const std::string& s) { + call_exception_handler(L, optional<const std::exception&>(nullopt), string_view(s.c_str(), s.size())); + } + catch (const std::exception& e) { + call_exception_handler(L, optional<const std::exception&>(e), e.what()); + } +#if SOL_IS_ON(SOL_EXCEPTIONS_CATCH_ALL) + // LuaJIT cannot have the catchall when the safe propagation is on + // but LuaJIT will swallow all C++ errors + // if we don't at least catch std::exception ones + catch (...) { + call_exception_handler(L, optional<const std::exception&>(nullopt), "caught (...) exception"); + } +#endif + return lua_error(L); +#endif + } + } + + inline int c_trampoline(lua_State* L, lua_CFunction f) { + return trampoline(L, f); + } +#endif // Exceptions vs. No Exceptions + + template <typename F, F fx> + inline int typed_static_trampoline(lua_State* L) { +#if 0 + // TODO: you must evaluate the get/check_get of every + // argument, to ensure it doesn't throw + // (e.g., for the sol_lua_check_access extension point!) + // This incluudes properly noexcept-ing all the above + // trampolines / safety nets + if constexpr (meta::bind_traits<F>::is_noexcept) { + return static_trampoline_noexcept<fx>(L); + } + else +#endif + { return static_trampoline<fx>(L); } + } + } // namespace detail + + inline void set_default_exception_handler(lua_State* L, exception_handler_function exf = &detail::default_exception_handler) { + static_assert(sizeof(void*) >= sizeof(exception_handler_function), + "void* storage is too small to transport the exception handler: please file a bug on the sol2 issue tracker to get this looked at!"); + void* storage; + std::memcpy(&storage, &exf, sizeof(exception_handler_function)); + lua_pushlightuserdata(L, storage); + lua_setglobal(L, detail::default_exception_handler_name()); + } +} // namespace sol + +// end of sol/trampoline.hpp + +// beginning of sol/stack_core.hpp + +// beginning of sol/inheritance.hpp + +// beginning of sol/usertype_traits.hpp + +// beginning of sol/demangle.hpp + +#include <string> +#include <array> +#include <cctype> +#if SOL_IS_ON(SOL_MINGW_CCTYPE_IS_POISONED) +extern "C" { +#include <ctype.h> +} +#endif // MinGW is on some stuff +#include <locale> + +namespace sol { namespace detail { + inline constexpr std::array<string_view, 9> removals { { "{anonymous}", + "(anonymous namespace)", + "public:", + "private:", + "protected:", + "struct ", + "class ", + "`anonymous-namespace'", + "`anonymous namespace'" } }; + +#if SOL_IS_ON(SOL_COMPILER_GCC) || SOL_IS_ON(SOL_COMPILER_CLANG) + inline std::string ctti_get_type_name_from_sig(std::string name) { + // cardinal sins from MINGW + using namespace std; + std::size_t start = name.find_first_of('['); + start = name.find_first_of('=', start); + std::size_t end = name.find_last_of(']'); + if (end == std::string::npos) + end = name.size(); + if (start == std::string::npos) + start = 0; + if (start < name.size() - 1) + start += 1; + name = name.substr(start, end - start); + start = name.rfind("seperator_mark"); + if (start != std::string::npos) { + name.erase(start - 2, name.length()); + } + while (!name.empty() && isblank(name.front())) + name.erase(name.begin()); + while (!name.empty() && isblank(name.back())) + name.pop_back(); + + for (std::size_t r = 0; r < removals.size(); ++r) { + auto found = name.find(removals[r]); + while (found != std::string::npos) { + name.erase(found, removals[r].size()); + found = name.find(removals[r]); + } + } + + return name; + } + + template <typename T, class seperator_mark = int> + inline std::string ctti_get_type_name() { + return ctti_get_type_name_from_sig(__PRETTY_FUNCTION__); + } +#elif SOL_IS_ON(SOL_COMPILER_VCXX) + inline std::string ctti_get_type_name_from_sig(std::string name) { + std::size_t start = name.find("get_type_name"); + if (start == std::string::npos) + start = 0; + else + start += 13; + if (start < name.size() - 1) + start += 1; + std::size_t end = name.find_last_of('>'); + if (end == std::string::npos) + end = name.size(); + name = name.substr(start, end - start); + if (name.find("struct", 0) == 0) + name.replace(0, 6, "", 0); + if (name.find("class", 0) == 0) + name.replace(0, 5, "", 0); + while (!name.empty() && isblank(name.front())) + name.erase(name.begin()); + while (!name.empty() && isblank(name.back())) + name.pop_back(); + + for (std::size_t r = 0; r < removals.size(); ++r) { + auto found = name.find(removals[r]); + while (found != std::string::npos) { + name.erase(found, removals[r].size()); + found = name.find(removals[r]); + } + } + + return name; + } + + template <typename T> + std::string ctti_get_type_name() { + return ctti_get_type_name_from_sig(__FUNCSIG__); + } +#else +#error Compiler not supported for demangling +#endif // compilers + + template <typename T> + std::string demangle_once() { + std::string realname = ctti_get_type_name<T>(); + return realname; + } + + inline std::string short_demangle_from_type_name(std::string realname) { + // This isn't the most complete but it'll do for now...? + static const std::array<std::string, 10> ops = { + { "operator<", "operator<<", "operator<<=", "operator<=", "operator>", "operator>>", "operator>>=", "operator>=", "operator->", "operator->*" } + }; + int level = 0; + std::size_t idx = 0; + for (idx = static_cast<std::size_t>(realname.empty() ? 0 : realname.size() - 1); idx > 0; --idx) { + if (level == 0 && realname[idx] == ':') { + break; + } + bool isleft = realname[idx] == '<'; + bool isright = realname[idx] == '>'; + if (!isleft && !isright) + continue; + bool earlybreak = false; + for (const auto& op : ops) { + std::size_t nisop = realname.rfind(op, idx); + if (nisop == std::string::npos) + continue; + std::size_t nisopidx = idx - op.size() + 1; + if (nisop == nisopidx) { + idx = static_cast<std::size_t>(nisopidx); + earlybreak = true; + } + break; + } + if (earlybreak) { + continue; + } + level += isleft ? -1 : 1; + } + if (idx > 0) { + realname.erase(0, realname.length() < static_cast<std::size_t>(idx) ? realname.length() : idx + 1); + } + return realname; + } + + template <typename T> + std::string short_demangle_once() { + std::string realname = ctti_get_type_name<T>(); + return short_demangle_from_type_name(realname); + } + + template <typename T> + const std::string& demangle() { + static const std::string d = demangle_once<T>(); + return d; + } + + template <typename T> + const std::string& short_demangle() { + static const std::string d = short_demangle_once<T>(); + return d; + } +}} // namespace sol::detail + +// end of sol/demangle.hpp + +namespace sol { + + template <typename T> + struct usertype_traits { + static const std::string& name() { + static const std::string& n = detail::short_demangle<T>(); + return n; + } + static const std::string& qualified_name() { + static const std::string& q_n = detail::demangle<T>(); + return q_n; + } + static const std::string& metatable() { + static const std::string m = std::string("sol.").append(detail::demangle<T>()); + return m; + } + static const std::string& user_metatable() { + static const std::string u_m = std::string("sol.").append(detail::demangle<T>()).append(".user"); + return u_m; + } + static const std::string& user_gc_metatable() { + static const std::string u_g_m = std::string("sol.").append(detail::demangle<T>()).append(".user\xE2\x99\xBB"); + return u_g_m; + } + static const std::string& gc_table() { + static const std::string g_t = std::string("sol.").append(detail::demangle<T>()).append(".\xE2\x99\xBB"); + return g_t; + } + }; + +} // namespace sol + +// end of sol/usertype_traits.hpp + +// beginning of sol/unique_usertype_traits.hpp + +#include <memory> + +namespace sol { + + namespace detail { + template <typename T> + struct unique_fallback { + using SOL_INTERNAL_UNSPECIALIZED_MARKER_ = int; + }; + + template <typename T> + struct unique_fallback<std::shared_ptr<T>> { + private: + using pointer = typename std::pointer_traits<std::shared_ptr<T>>::element_type*; + + public: + // rebind is non-void + // if and only if unique usertype + // is cast-capable + template <typename X> + using rebind_actual_type = std::shared_ptr<X>; + + static bool is_null(lua_State*, const std::shared_ptr<T>& p) noexcept { + return p == nullptr; + } + + static pointer get(lua_State*, const std::shared_ptr<T>& p) noexcept { + return p.get(); + } + }; + + template <typename T, typename D> + struct unique_fallback<std::unique_ptr<T, D>> { + private: + using pointer = typename std::unique_ptr<T, D>::pointer; + + public: + static bool is_null(lua_State*, const std::unique_ptr<T, D>& p) noexcept { + return p == nullptr; + } + + static pointer get(lua_State*, const std::unique_ptr<T, D>& p) noexcept { + return p.get(); + } + }; + } // namespace detail + + namespace meta { namespace meta_detail { + template <typename T, typename = void> + struct unique_actual_type; + + template <typename T> + struct unique_actual_type<T, meta::void_t<typename T::actual_type>> { + using type = typename T::actual_type; + }; + + template <typename T, typename... Rest, template <typename...> class Templ> + struct unique_actual_type<Templ<T, Rest...>> { + using type = T; + }; + + }} // namespace meta::meta_detail + + template <typename T> + using unique_usertype_actual_t = typename meta::meta_detail::unique_actual_type<unique_usertype_traits<T>>::type; + + namespace meta { namespace meta_detail { + template <typename T> + using value_test_t = decltype(T::value); + + template <typename T> + using type_test_t = typename T::type; + + template <typename T> + using type_element_type_t = typename T::element_type; + + template <typename T, typename = void> + struct unique_element_type { + using type = typename std::pointer_traits<typename unique_actual_type<T>::type>::element_type; + }; + + template <typename T> + struct unique_element_type<T, std::enable_if_t<meta::is_detected_v<type_element_type_t, T>>> { + using type = typename T::element_type; + }; + + template <typename T> + struct unique_element_type<T, std::enable_if_t<meta::is_detected_v<type_test_t, T>>> { + using type = typename T::type; + }; + + template <typename T, typename = void> + struct unique_valid : std::integral_constant<bool, !has_internal_marker_v<T>> { }; + + template <typename T> + struct unique_valid<T, meta::void_t<decltype(T::value)>> : std::integral_constant<bool, T::value> { }; + }} // namespace meta::meta_detail + + template <typename T> + using unique_usertype_element_t = typename meta::meta_detail::unique_element_type<unique_usertype_traits<T>>::type; + + template <typename T, typename Element = void> + using unique_usertype_rebind_actual_t = typename unique_usertype_traits<T>::template rebind_actual_type<Element>; + + template <typename T> + struct unique_usertype_traits : public detail::unique_fallback<T> { }; + + template <typename T> + struct is_unique_usertype : std::integral_constant<bool, meta::meta_detail::unique_valid<unique_usertype_traits<T>>::value> { }; + + template <typename T> + inline constexpr bool is_unique_usertype_v = is_unique_usertype<T>::value; + + namespace meta { namespace meta_detail { + template <typename T> + using adl_sol_lua_check_access_test_t + = decltype(sol_lua_check_access(types<T>(), static_cast<lua_State*>(nullptr), -1, std::declval<stack::record&>())); + + template <typename T> + inline constexpr bool is_adl_sol_lua_check_access_v = meta::is_detected_v<adl_sol_lua_check_access_test_t, T>; + + template <typename T> + using unique_usertype_get_with_state_test_t + = decltype(unique_usertype_traits<T>::get(static_cast<lua_State*>(nullptr), std::declval<unique_usertype_actual_t<T>>())); + + template <typename T> + inline constexpr bool unique_usertype_get_with_state_v = meta::is_detected_v<unique_usertype_get_with_state_test_t, T>; + + template <typename T> + using unique_usertype_is_null_with_state_test_t + = decltype(unique_usertype_traits<T>::is_null(static_cast<lua_State*>(nullptr), std::declval<unique_usertype_actual_t<T>>())); + + template <typename T> + inline constexpr bool unique_usertype_is_null_with_state_v = meta::is_detected_v<unique_usertype_is_null_with_state_test_t, T>; + }} // namespace meta::meta_detail + + namespace detail { + template <typename T> + constexpr bool unique_is_null_noexcept() noexcept { + if constexpr (meta::meta_detail::unique_usertype_is_null_with_state_v<std::remove_cv_t<T>>) { + return noexcept( + unique_usertype_traits<T>::is_null(static_cast<lua_State*>(nullptr), std::declval<unique_usertype_actual_t<std::remove_cv_t<T>>>())); + } + else { + return noexcept(unique_usertype_traits<T>::is_null(std::declval<unique_usertype_actual_t<std::remove_cv_t<T>>>())); + } + } + + template <typename T> + bool unique_is_null(lua_State* L_, T& value_) noexcept(unique_is_null_noexcept<std::remove_cv_t<T>>()) { + using Tu = std::remove_cv_t<T>; + if constexpr (meta::meta_detail::unique_usertype_is_null_with_state_v<Tu>) { + return unique_usertype_traits<Tu>::is_null(L_, value_); + } + else { + return unique_usertype_traits<Tu>::is_null(value_); + } + } + + template <typename T> + constexpr bool unique_get_noexcept() noexcept { + if constexpr (meta::meta_detail::unique_usertype_get_with_state_v<std::remove_cv_t<T>>) { + return noexcept( + unique_usertype_traits<T>::get(static_cast<lua_State*>(nullptr), std::declval<unique_usertype_actual_t<std::remove_cv_t<T>>>())); + } + else { + return noexcept(unique_usertype_traits<T>::get(std::declval<unique_usertype_actual_t<std::remove_cv_t<T>>>())); + } + } + + template <typename T> + auto unique_get(lua_State* L_, T& value_) noexcept(unique_get_noexcept<std::remove_cv_t<T>>()) { + using Tu = std::remove_cv_t<T>; + if constexpr (meta::meta_detail::unique_usertype_get_with_state_v<Tu>) { + return unique_usertype_traits<Tu>::get(L_, value_); + } + else { + return unique_usertype_traits<Tu>::get(value_); + } + } + } // namespace detail + + namespace meta { namespace meta_detail { + template <typename T, typename Element = void> + using is_rebind_actual_type_test_t = typename T::template rebind_actual_type<Element>; + + template <typename T, typename Element = void> + using is_rebind_actual_type = meta::is_detected<is_rebind_actual_type_test_t, T, Element>; + + template <typename T, typename Element = void> + inline constexpr bool is_rebind_actual_type_v = is_rebind_actual_type<T, Element>::value; + + template <typename T, typename Element, bool = is_rebind_actual_type_v<T, Element>> + struct is_actual_type_rebindable_for_test : std::false_type { }; + + template <typename T, typename Element> + struct is_actual_type_rebindable_for_test<T, Element, true> + : std::integral_constant<bool, !std::is_void_v<typename T::template rebind_actual_type<Element>>> { }; + }} // namespace meta::meta_detail + + template <typename T, typename Element = void> + using is_actual_type_rebindable_for = typename meta::meta_detail::is_actual_type_rebindable_for_test<unique_usertype_traits<T>, Element>::type; + + template <typename T, typename Element = void> + inline constexpr bool is_actual_type_rebindable_for_v = is_actual_type_rebindable_for<T, Element>::value; + +} // namespace sol + +// end of sol/unique_usertype_traits.hpp + +namespace sol { + template <typename... Args> + struct base_list { }; + template <typename... Args> + using bases = base_list<Args...>; + + typedef bases<> base_classes_tag; + const auto base_classes = base_classes_tag(); + + template <typename... Args> + struct is_to_stringable<base_list<Args...>> : std::false_type { }; + + namespace detail { + + inline decltype(auto) base_class_check_key() { + static const auto& key = "class_check"; + return key; + } + + inline decltype(auto) base_class_cast_key() { + static const auto& key = "class_cast"; + return key; + } + + inline decltype(auto) base_class_index_propogation_key() { + static const auto& key = u8"\xF0\x9F\x8C\xB2.index"; + return key; + } + + inline decltype(auto) base_class_new_index_propogation_key() { + static const auto& key = u8"\xF0\x9F\x8C\xB2.new_index"; + return key; + } + + template <typename T> + struct inheritance { + typedef typename base<T>::type bases_t; + + static bool type_check_bases(types<>, const string_view&) { + return false; + } + + template <typename Base, typename... Args> + static bool type_check_bases(types<Base, Args...>, const string_view& ti) { + return ti == usertype_traits<Base>::qualified_name() || type_check_bases(types<Args...>(), ti); + } + + static bool type_check(const string_view& ti) { + return ti == usertype_traits<T>::qualified_name() || type_check_bases(bases_t(), ti); + } + + template <typename... Bases> + static bool type_check_with(const string_view& ti) { + return ti == usertype_traits<T>::qualified_name() || type_check_bases(types<Bases...>(), ti); + } + + static void* type_cast_bases(types<>, T*, const string_view&) { + return nullptr; + } + + template <typename Base, typename... Args> + static void* type_cast_bases(types<Base, Args...>, T* data, const string_view& ti) { + // Make sure to convert to T first, and then dynamic cast to the proper type + return ti != usertype_traits<Base>::qualified_name() ? type_cast_bases(types<Args...>(), data, ti) + : static_cast<void*>(static_cast<Base*>(data)); + } + + static void* type_cast(void* voiddata, const string_view& ti) { + T* data = static_cast<T*>(voiddata); + return static_cast<void*>(ti != usertype_traits<T>::qualified_name() ? type_cast_bases(bases_t(), data, ti) : data); + } + + template <typename... Bases> + static void* type_cast_with(void* voiddata, const string_view& ti) { + T* data = static_cast<T*>(voiddata); + return static_cast<void*>(ti != usertype_traits<T>::qualified_name() ? type_cast_bases(types<Bases...>(), data, ti) : data); + } + + template <typename U> + static bool type_unique_cast_bases(types<>, void*, void*, const string_view&) { + return 0; + } + + template <typename U, typename Base, typename... Args> + static int type_unique_cast_bases(types<Base, Args...>, void* source_data, void* target_data, const string_view& ti) { + using uu_traits = unique_usertype_traits<U>; + using base_ptr = typename uu_traits::template rebind_actual_type<Base>; + string_view base_ti = usertype_traits<Base>::qualified_name(); + if (base_ti == ti) { + if (target_data != nullptr) { + U* source = static_cast<U*>(source_data); + base_ptr* target = static_cast<base_ptr*>(target_data); + // perform proper derived -> base conversion + *target = *source; + } + return 2; + } + return type_unique_cast_bases<U>(types<Args...>(), source_data, target_data, ti); + } + + template <typename U> + static int type_unique_cast(void* source_data, void* target_data, const string_view& ti, const string_view& rebind_ti) { + if constexpr (is_actual_type_rebindable_for_v<U>) { + using rebound_actual_type = unique_usertype_rebind_actual_t<U>; + using maybe_bases_or_empty = meta::conditional_t<std::is_void_v<rebound_actual_type>, types<>, bases_t>; + string_view this_rebind_ti = usertype_traits<rebound_actual_type>::qualified_name(); + if (rebind_ti != this_rebind_ti) { + // this is not even of the same unique type + return 0; + } + string_view this_ti = usertype_traits<T>::qualified_name(); + if (ti == this_ti) { + // direct match, return 1 + return 1; + } + return type_unique_cast_bases<U>(maybe_bases_or_empty(), source_data, target_data, ti); + } + else { + (void)rebind_ti; + string_view this_ti = usertype_traits<T>::qualified_name(); + if (ti == this_ti) { + // direct match, return 1 + return 1; + } + return type_unique_cast_bases<U>(types<>(), source_data, target_data, ti); + } + } + + template <typename U, typename... Bases> + static int type_unique_cast_with(void* source_data, void* target_data, const string_view& ti, const string_view& rebind_ti) { + using uc_bases_t = types<Bases...>; + if constexpr (is_actual_type_rebindable_for_v<U>) { + using rebound_actual_type = unique_usertype_rebind_actual_t<U>; + using cond_bases_t = meta::conditional_t<std::is_void_v<rebound_actual_type>, types<>, uc_bases_t>; + string_view this_rebind_ti = usertype_traits<rebound_actual_type>::qualified_name(); + if (rebind_ti != this_rebind_ti) { + // this is not even of the same unique type + return 0; + } + string_view this_ti = usertype_traits<T>::qualified_name(); + if (ti == this_ti) { + // direct match, return 1 + return 1; + } + return type_unique_cast_bases<U>(cond_bases_t(), source_data, target_data, ti); + } + else { + (void)rebind_ti; + string_view this_ti = usertype_traits<T>::qualified_name(); + if (ti == this_ti) { + // direct match, return 1 + return 1; + } + return type_unique_cast_bases<U>(types<>(), source_data, target_data, ti); + } + } + }; + + using inheritance_check_function = decltype(&inheritance<void>::type_check); + using inheritance_cast_function = decltype(&inheritance<void>::type_cast); + using inheritance_unique_cast_function = decltype(&inheritance<void>::type_unique_cast<void>); + } // namespace detail +} // namespace sol + +// end of sol/inheritance.hpp + +// beginning of sol/error_handler.hpp + +#include <cstdio> + +namespace sol { + + namespace detail { + constexpr const char* not_a_number = "not a numeric type"; + constexpr const char* not_a_number_or_number_string = "not a numeric type or numeric string"; + constexpr const char* not_a_number_integral = "not a numeric type that fits exactly an integer (number maybe has significant decimals)"; + constexpr const char* not_a_number_or_number_string_integral + = "not a numeric type or a numeric string that fits exactly an integer (e.g. number maybe has significant decimals)"; + + constexpr const char* not_enough_stack_space = "not enough space left on Lua stack"; + constexpr const char* not_enough_stack_space_floating = "not enough space left on Lua stack for a floating point number"; + constexpr const char* not_enough_stack_space_integral = "not enough space left on Lua stack for an integral number"; + constexpr const char* not_enough_stack_space_string = "not enough space left on Lua stack for a string"; + constexpr const char* not_enough_stack_space_meta_function_name = "not enough space left on Lua stack for the name of a meta_function"; + constexpr const char* not_enough_stack_space_userdata = "not enough space left on Lua stack to create a sol2 userdata"; + constexpr const char* not_enough_stack_space_generic = "not enough space left on Lua stack to push valuees"; + constexpr const char* not_enough_stack_space_environment = "not enough space left on Lua stack to retrieve environment"; + constexpr const char* protected_function_error = "caught (...) unknown error during protected_function call"; + + inline void accumulate_and_mark(const std::string& n, std::string& aux_message, int& marker) { + if (marker > 0) { + aux_message += ", "; + } + aux_message += n; + ++marker; + } + } // namespace detail + + inline std::string associated_type_name(lua_State* L, int index, type t) { + switch (t) { + case type::poly: + return "anything"; + case type::userdata: { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 2, "not enough space to push get the type name"); +#endif // make sure stack doesn't overflow + if (lua_getmetatable(L, index) == 0) { + break; + } + lua_pushlstring(L, "__name", 6); + lua_rawget(L, -2); + size_t sz; + const char* name = lua_tolstring(L, -1, &sz); + std::string tn(name, static_cast<std::string::size_type>(sz)); + lua_pop(L, 2); + return tn; + } + default: + break; + } + return lua_typename(L, static_cast<int>(t)); + } + + inline int push_type_panic_string(lua_State* L, int index, type expected, type actual, string_view message, string_view aux_message) noexcept { + const char* err = message.size() == 0 + ? (aux_message.size() == 0 ? "stack index %d, expected %s, received %s" : "stack index %d, expected %s, received %s: %s") + : "stack index %d, expected %s, received %s: %s %s"; + const char* type_name = expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)); + { + std::string actual_name = associated_type_name(L, index, actual); + lua_pushfstring(L, err, index, type_name, actual_name.c_str(), message.data(), aux_message.data()); + } + return 1; + } + + inline int type_panic_string(lua_State* L, int index, type expected, type actual, string_view message = "") noexcept(false) { + push_type_panic_string(L, index, expected, actual, message, ""); + return lua_error(L); + } + + inline int type_panic_c_str(lua_State* L, int index, type expected, type actual, const char* message = nullptr) noexcept(false) { + push_type_panic_string(L, index, expected, actual, message == nullptr ? "" : message, ""); + return lua_error(L); + } + + struct type_panic_t { + int operator()(lua_State* L, int index, type expected, type actual) const noexcept(false) { + return type_panic_c_str(L, index, expected, actual, nullptr); + } + int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) { + return type_panic_c_str(L, index, expected, actual, message.data()); + } + }; + + const type_panic_t type_panic = {}; + + struct constructor_handler { + int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) { + push_type_panic_string(L, index, expected, actual, message, "(type check failed in constructor)"); + return lua_error(L); + } + }; + + template <typename F = void> + struct argument_handler { + int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) { + push_type_panic_string(L, index, expected, actual, message, "(bad argument to variable or function call)"); + return lua_error(L); + } + }; + + template <typename R, typename... Args> + struct argument_handler<types<R, Args...>> { + int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) { + { + std::string aux_message = "(bad argument into '"; + aux_message += detail::demangle<R>(); + aux_message += "("; + int marker = 0; + (void)detail::swallow { int(), (detail::accumulate_and_mark(detail::demangle<Args>(), aux_message, marker), int())... }; + aux_message += ")')"; + push_type_panic_string(L, index, expected, actual, message, aux_message); + } + return lua_error(L); + } + }; + + // Specify this function as the handler for lua::check if you know there's nothing wrong + inline int no_panic(lua_State*, int, type, type, const char* = nullptr) noexcept { + return 0; + } + + inline void type_error(lua_State* L, int expected, int actual) noexcept(false) { + luaL_error(L, "expected %s, received %s", lua_typename(L, expected), lua_typename(L, actual)); + } + + inline void type_error(lua_State* L, type expected, type actual) noexcept(false) { + type_error(L, static_cast<int>(expected), static_cast<int>(actual)); + } + + inline void type_assert(lua_State* L, int index, type expected, type actual) noexcept(false) { + if (expected != type::poly && expected != actual) { + type_panic_c_str(L, index, expected, actual, nullptr); + } + } + + inline void type_assert(lua_State* L, int index, type expected) { + type actual = type_of(L, index); + type_assert(L, index, expected, actual); + } + +} // namespace sol + +// end of sol/error_handler.hpp + +// beginning of sol/reference.hpp + +// beginning of sol/stack_reference.hpp + +namespace sol { + namespace detail { + inline bool xmovable(lua_State* leftL, lua_State* rightL) { + if (rightL == nullptr || leftL == nullptr || leftL == rightL) { + return false; + } + const void* leftregistry = lua_topointer(leftL, LUA_REGISTRYINDEX); + const void* rightregistry = lua_topointer(rightL, LUA_REGISTRYINDEX); + return leftregistry == rightregistry; + } + } // namespace detail + + class stateless_stack_reference { + private: + friend class stack_reference; + + int m_index = 0; + + int registry_index() const noexcept { + return LUA_NOREF; + } + + public: + stateless_stack_reference() noexcept = default; + stateless_stack_reference(lua_nil_t) noexcept : stateless_stack_reference() {}; + stateless_stack_reference(lua_State* L_, int index_) noexcept : stateless_stack_reference(absolute_index(L_, index_)) { + } + stateless_stack_reference(lua_State*, absolute_index index_) noexcept : stateless_stack_reference(index_) { + } + stateless_stack_reference(lua_State*, raw_index index_) noexcept : stateless_stack_reference(index_) { + } + stateless_stack_reference(absolute_index index_) noexcept : m_index(index_) { + } + stateless_stack_reference(raw_index index_) noexcept : m_index(index_) { + } + stateless_stack_reference(lua_State*, ref_index) noexcept = delete; + stateless_stack_reference(ref_index) noexcept = delete; + stateless_stack_reference(const reference&) noexcept = delete; + stateless_stack_reference(const stateless_stack_reference&) noexcept = default; + stateless_stack_reference(stateless_stack_reference&& o) noexcept = default; + stateless_stack_reference& operator=(stateless_stack_reference&&) noexcept = default; + stateless_stack_reference& operator=(const stateless_stack_reference&) noexcept = default; + + int push(lua_State* L_) const noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L_, 1, "not enough Lua stack space to push a single reference value"); +#endif // make sure stack doesn't overflow + lua_pushvalue(L_, m_index); + return 1; + } + + void pop(lua_State* L_, int pop_count = 1) const noexcept { + lua_pop(L_, pop_count); + } + + int stack_index() const noexcept { + return m_index; + } + + const void* pointer(lua_State* L_) const noexcept { + const void* pointer_id = lua_topointer(L_, stack_index()); + return pointer_id; + } + + type get_type(lua_State* L_) const noexcept { + int untyped_value = lua_type(L_, stack_index()); + return static_cast<type>(untyped_value); + } + + bool valid(lua_State* L) const noexcept { + type t = get_type(L); + return t != type::lua_nil && t != type::none; + } + + void reset(lua_State*) noexcept { + m_index = 0; + } + + void reset(lua_State* L_, int index_) noexcept { + m_index = absolute_index(L_, index_); + } + + void abandon(lua_State* = nullptr) noexcept { + m_index = 0; + } + + stateless_stack_reference copy(lua_State* L_) const noexcept { + return stateless_stack_reference(L_, raw_index(m_index)); + } + + void copy_assign(lua_State*, const stateless_stack_reference& right) noexcept { + m_index = right.m_index; + } + + bool equals(lua_State* L_, const stateless_stack_reference& r) const noexcept { + return lua_compare(L_, this->stack_index(), r.stack_index(), LUA_OPEQ) == 1; + } + + bool equals(lua_State* L_, lua_nil_t) const noexcept { + return valid(L_); + } + }; + + class stack_reference : public stateless_stack_reference { + private: + lua_State* luastate = nullptr; + + public: + stack_reference() noexcept = default; + stack_reference(lua_nil_t) noexcept : stack_reference() {}; + stack_reference(lua_State* L, lua_nil_t) noexcept : stateless_stack_reference(L, 0), luastate(L) { + } + stack_reference(lua_State* L, int i) noexcept : stateless_stack_reference(L, i), luastate(L) { + } + stack_reference(lua_State* L, absolute_index i) noexcept : stateless_stack_reference(L, i), luastate(L) { + } + stack_reference(lua_State* L, raw_index i) noexcept : stateless_stack_reference(L, i), luastate(L) { + } + stack_reference(lua_State* L, ref_index i) noexcept = delete; + stack_reference(lua_State* L, const reference& r) noexcept = delete; + stack_reference(lua_State* L, const stack_reference& r) noexcept : luastate(L) { + if (!r.valid()) { + m_index = 0; + return; + } + int i = r.stack_index(); + if (detail::xmovable(lua_state(), r.lua_state())) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, "not enough Lua stack space to push a single reference value"); +#endif // make sure stack doesn't overflow + lua_pushvalue(r.lua_state(), r.stack_index()); + lua_xmove(r.lua_state(), luastate, 1); + i = absolute_index(luastate, -1); + } + m_index = i; + } + stack_reference(stack_reference&& o) noexcept = default; + stack_reference& operator=(stack_reference&&) noexcept = default; + stack_reference(const stack_reference&) noexcept = default; + stack_reference& operator=(const stack_reference&) noexcept = default; + + int push() const noexcept { + return push(lua_state()); + } + + int push(lua_State* L_) const noexcept { + return stateless_stack_reference::push(L_); + } + + void pop() const noexcept { + pop(lua_state()); + } + + void pop(lua_State* L_, int pop_count_ = 1) const noexcept { + stateless_stack_reference::pop(L_, pop_count_); + } + + const void* pointer() const noexcept { + return stateless_stack_reference::pointer(lua_state()); + } + + type get_type() const noexcept { + return stateless_stack_reference::get_type(lua_state()); + } + + lua_State* lua_state() const noexcept { + return luastate; + } + + bool valid() const noexcept { + return stateless_stack_reference::valid(lua_state()); + } + + void abandon() { + stateless_stack_reference::abandon(lua_state()); + } + }; + + inline bool operator==(const stack_reference& l, const stack_reference& r) { + return lua_compare(l.lua_state(), l.stack_index(), r.stack_index(), LUA_OPEQ) == 1; + } + + inline bool operator!=(const stack_reference& l, const stack_reference& r) { + return !operator==(l, r); + } + + inline bool operator==(const stack_reference& lhs, const lua_nil_t&) { + return !lhs.valid(); + } + + inline bool operator==(const lua_nil_t&, const stack_reference& rhs) { + return !rhs.valid(); + } + + inline bool operator!=(const stack_reference& lhs, const lua_nil_t&) { + return lhs.valid(); + } + + inline bool operator!=(const lua_nil_t&, const stack_reference& rhs) { + return rhs.valid(); + } + + inline bool operator==(const stateless_stack_reference& l, const stateless_stack_reference& r) { + return l.stack_index() == r.stack_index(); + } + + inline bool operator!=(const stateless_stack_reference& l, const stateless_stack_reference& r) { + return l.stack_index() != r.stack_index(); + } + + struct stateless_stack_reference_equals { + using is_transparent = std::true_type; + + stateless_stack_reference_equals(lua_State* L_) noexcept : m_L(L_) { + } + + lua_State* lua_state() const noexcept { + return m_L; + } + + bool operator()(const stateless_stack_reference& lhs, const stateless_stack_reference& rhs) const { + return lhs.equals(lua_state(), rhs); + } + + bool operator()(lua_nil_t lhs, const stateless_stack_reference& rhs) const { + return rhs.equals(lua_state(), lhs); + } + + bool operator()(const stateless_stack_reference& lhs, lua_nil_t rhs) const { + return lhs.equals(lua_state(), rhs); + } + + private: + lua_State* m_L; + }; + + struct stack_reference_equals { + using is_transparent = std::true_type; + + bool operator()(const lua_nil_t& lhs, const stack_reference& rhs) const { + return lhs == rhs; + } + + bool operator()(const stack_reference& lhs, const lua_nil_t& rhs) const { + return lhs == rhs; + } + + bool operator()(const stack_reference& lhs, const stack_reference& rhs) const { + return lhs == rhs; + } + }; + + struct stateless_stack_reference_hash { + using argument_type = stateless_stack_reference; + using result_type = std::size_t; + using is_transparent = std::true_type; + + stateless_stack_reference_hash(lua_State* L_) noexcept : m_L(L_) { + } + + lua_State* lua_state() const noexcept { + return m_L; + } + + result_type operator()(const argument_type& lhs) const noexcept { + std::hash<const void*> h; + return h(lhs.pointer(lua_state())); + } + + private: + lua_State* m_L; + }; + + struct stack_reference_hash { + using argument_type = stack_reference; + using result_type = std::size_t; + using is_transparent = std::true_type; + + result_type operator()(const argument_type& lhs) const noexcept { + std::hash<const void*> h; + return h(lhs.pointer()); + } + }; +} // namespace sol + +// end of sol/stack_reference.hpp + +#include <functional> + +namespace sol { + namespace detail { + inline const char (&default_main_thread_name())[9] { + static const char name[9] = "sol.\xF0\x9F\x93\x8C"; + return name; + } + } // namespace detail + + namespace stack { + inline void remove(lua_State* L_, int rawindex, int count) { + if (count < 1) + return; + int top = lua_gettop(L_); + if (top < 1) { + return; + } + if (rawindex == -count || top == rawindex) { + // Slice them right off the top + lua_pop(L_, static_cast<int>(count)); + return; + } + + // Remove each item one at a time using stack operations + // Probably slower, maybe, haven't benchmarked, + // but necessary + int index = lua_absindex(L_, rawindex); + if (index < 0) { + index = lua_gettop(L_) + (index + 1); + } + int last = index + count; + for (int i = index; i < last; ++i) { + lua_remove(L_, index); + } + } + + struct push_popper_at { + lua_State* L; + int index; + int count; + push_popper_at(lua_State* L_, int index_ = -1, int count_ = 1) : L(L_), index(index_), count(count_) { + } + ~push_popper_at() { + remove(L, index, count); + } + }; + + template <bool top_level> + struct push_popper_n { + lua_State* L; + int pop_count; + push_popper_n(lua_State* L_, int pop_count_) : L(L_), pop_count(pop_count_) { + } + push_popper_n(const push_popper_n&) = delete; + push_popper_n(push_popper_n&&) = default; + push_popper_n& operator=(const push_popper_n&) = delete; + push_popper_n& operator=(push_popper_n&&) = default; + ~push_popper_n() { + lua_pop(L, pop_count); + } + }; + + template <> + struct push_popper_n<true> { + push_popper_n(lua_State*, int) { + } + }; + + template <bool, typename T, typename = void> + struct push_popper { + using Tu = meta::unqualified_t<T>; + T m_object; + int m_index; + + push_popper(T object_) noexcept : m_object(object_), m_index(lua_absindex(m_object.lua_state(), -m_object.push())) { + } + + int index_of(const Tu&) const noexcept { + return m_index; + } + + ~push_popper() { + m_object.pop(); + } + }; + + template <typename T, typename C> + struct push_popper<true, T, C> { + using Tu = meta::unqualified_t<T>; + + push_popper(T) noexcept { + } + + int index_of(const Tu&) const noexcept { + return -1; + } + + ~push_popper() { + } + }; + + template <typename T> + struct push_popper<false, T, std::enable_if_t<is_stack_based_v<meta::unqualified_t<T>>>> { + using Tu = meta::unqualified_t<T>; + + push_popper(T) noexcept { + } + + int index_of(const Tu& object_) const noexcept { + return object_.stack_index(); + } + + ~push_popper() { + } + }; + + template <bool, typename T, typename = void> + struct stateless_push_popper { + using Tu = meta::unqualified_t<T>; + lua_State* m_L; + T m_object; + int m_index; + + stateless_push_popper(lua_State* L_, T object_) noexcept : m_L(L_), m_object(object_), m_index(lua_absindex(m_L, -m_object.push(m_L))) { + } + + int index_of(const Tu&) const noexcept { + return m_index; + } + + ~stateless_push_popper() { + m_object.pop(m_L); + } + }; + + template <typename T, typename C> + struct stateless_push_popper<true, T, C> { + using Tu = meta::unqualified_t<T>; + + stateless_push_popper(lua_State*, T) noexcept { + } + + int index_of(lua_State*, const Tu&) const noexcept { + return -1; + } + + ~stateless_push_popper() { + } + }; + + template <typename T> + struct stateless_push_popper<false, T, std::enable_if_t<is_stack_based_v<meta::unqualified_t<T>>>> { + using Tu = meta::unqualified_t<T>; + lua_State* m_L; + + stateless_push_popper(lua_State* L_, T) noexcept : m_L(L_) { + } + + int index_of(const Tu& object_) const noexcept { + return object_.stack_index(); + } + + ~stateless_push_popper() { + } + }; + + template <bool top_level = false, typename T> + push_popper<top_level, T> push_pop(T&& x) { + return push_popper<top_level, T>(std::forward<T>(x)); + } + + template <bool top_level = false, typename T> + stateless_push_popper<top_level, T> push_pop(lua_State* L_, T&& object_) { + return stateless_push_popper<top_level, T>(L_, std::forward<T>(object_)); + } + + template <typename T> + push_popper_at push_pop_at(T&& object_) { + int push_count = object_.push(); + lua_State* L = object_.lua_state(); + return push_popper_at(L, lua_absindex(L, -push_count), push_count); + } + + template <bool top_level = false> + push_popper_n<top_level> pop_n(lua_State* L_, int pop_count_) { + return push_popper_n<top_level>(L_, pop_count_); + } + } // namespace stack + + inline lua_State* main_thread(lua_State* L_, lua_State* backup_if_unsupported_ = nullptr) { +#if SOL_LUA_VERSION_I_ < 502 + if (L_ == nullptr) + return backup_if_unsupported_; + lua_getglobal(L_, detail::default_main_thread_name()); + auto pp = stack::pop_n(L_, 1); + if (type_of(L_, -1) == type::thread) { + return lua_tothread(L_, -1); + } + return backup_if_unsupported_; +#else + if (L_ == nullptr) + return backup_if_unsupported_; + lua_rawgeti(L_, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); + lua_State* Lmain = lua_tothread(L_, -1); + lua_pop(L_, 1); + return Lmain; +#endif // Lua 5.2+ has the main thread unqualified_getter + } + + namespace detail { + struct no_safety_tag { + } inline constexpr no_safety {}; + + template <bool b> + inline lua_State* pick_main_thread(lua_State* L_, lua_State* backup_if_unsupported = nullptr) { + (void)L_; + (void)backup_if_unsupported; + if (b) { + return main_thread(L_, backup_if_unsupported); + } + return L_; + } + } // namespace detail + + class stateless_reference { + private: + template <bool o_main_only> + friend class basic_reference; + + int ref = LUA_NOREF; + + int copy_ref(lua_State* L_) const noexcept { + if (ref == LUA_NOREF) + return LUA_NOREF; + push(L_); + return luaL_ref(L_, LUA_REGISTRYINDEX); + } + + lua_State* copy_assign_ref(lua_State* L_, lua_State* rL, const stateless_reference& r) { + if (valid(L_)) { + deref(L_); + } + ref = r.copy_ref(L_); + return rL; + } + + lua_State* move_assign(lua_State* L_, lua_State* rL, stateless_reference&& r) { + if (valid(L_)) { + deref(L_); + } + ref = r.ref; + r.ref = LUA_NOREF; + return rL; + } + + protected: + int stack_index() const noexcept { + return -1; + } + + stateless_reference(lua_State* L_, global_tag_t) noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); +#endif // make sure stack doesn't overflow + lua_pushglobaltable(L_); + ref = luaL_ref(L_, LUA_REGISTRYINDEX); + } + + stateless_reference(int raw_ref_index) noexcept : ref(raw_ref_index) { + } + + public: + stateless_reference() noexcept = default; + stateless_reference(lua_nil_t) noexcept : stateless_reference() { + } + stateless_reference(const stack_reference& r) noexcept : stateless_reference(r.lua_state(), r.stack_index()) { + } + stateless_reference(stack_reference&& r) noexcept : stateless_reference(r.lua_state(), r.stack_index()) { + } + stateless_reference(lua_State* L_, const stateless_reference& r) noexcept { + if (r.ref == LUA_REFNIL) { + ref = LUA_REFNIL; + return; + } + if (r.ref == LUA_NOREF || L_ == nullptr) { + ref = LUA_NOREF; + return; + } + ref = r.copy_ref(L_); + } + + stateless_reference(lua_State* L_, stateless_reference&& r) noexcept { + if (r.ref == LUA_REFNIL) { + ref = LUA_REFNIL; + return; + } + if (r.ref == LUA_NOREF || L_ == nullptr) { + ref = LUA_NOREF; + return; + } + ref = r.ref; + r.ref = LUA_NOREF; + } + + stateless_reference(lua_State* L_, const stack_reference& r) noexcept { + if (L_ == nullptr || r.lua_state() == nullptr || r.get_type() == type::none) { + ref = LUA_NOREF; + return; + } + if (r.get_type() == type::lua_nil) { + ref = LUA_REFNIL; + return; + } + if (L_ != r.lua_state() && !detail::xmovable(L_, r.lua_state())) { + return; + } + r.push(L_); + ref = luaL_ref(L_, LUA_REGISTRYINDEX); + } + + stateless_reference(lua_State* L_, const stateless_stack_reference& r) noexcept : stateless_reference(L_, r.stack_index()) { + } + + stateless_reference(lua_State* L_, int index = -1) noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); +#endif // make sure stack doesn't overflow + lua_pushvalue(L_, index); + ref = luaL_ref(L_, LUA_REGISTRYINDEX); + } + stateless_reference(lua_State* L_, absolute_index index_) noexcept : stateless_reference(L_, index_.index) { + } + stateless_reference(lua_State* L_, ref_index index_) noexcept { + lua_rawgeti(L_, LUA_REGISTRYINDEX, index_.index); + ref = luaL_ref(L_, LUA_REGISTRYINDEX); + } + stateless_reference(lua_State*, lua_nil_t) noexcept { + } + + ~stateless_reference() noexcept = default; + + stateless_reference(const stateless_reference& o) noexcept = delete; + stateless_reference& operator=(const stateless_reference& r) noexcept = delete; + + stateless_reference(stateless_reference&& o) noexcept : ref(o.ref) { + o.ref = LUA_NOREF; + } + + stateless_reference& operator=(stateless_reference&& o) noexcept { + ref = o.ref; + o.ref = LUA_NOREF; + return *this; + } + + int push(lua_State* L_) const noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); +#endif // make sure stack doesn't overflow + lua_rawgeti(L_, LUA_REGISTRYINDEX, ref); + return 1; + } + + void pop(lua_State* L_, int n = 1) const noexcept { + lua_pop(L_, n); + } + + int registry_index() const noexcept { + return ref; + } + + void reset(lua_State* L_) noexcept { + if (valid(L_)) { + deref(L_); + } + ref = LUA_NOREF; + } + + void reset(lua_State* L_, int index_) noexcept { + reset(L_); +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); +#endif // make sure stack doesn't overflow + lua_pushvalue(L_, index_); + ref = luaL_ref(L_, LUA_REGISTRYINDEX); + } + + bool valid(lua_State*) const noexcept { + return !(ref == LUA_NOREF || ref == LUA_REFNIL); + } + + const void* pointer(lua_State* L_) const noexcept { + int si = push(L_); + const void* vp = lua_topointer(L_, -si); + lua_pop(L_, si); + return vp; + } + + type get_type(lua_State* L_) const noexcept { + int p = push(L_); + int result = lua_type(L_, -1); + pop(L_, p); + return static_cast<type>(result); + } + + void abandon(lua_State* = nullptr) { + ref = LUA_NOREF; + } + + void deref(lua_State* L_) const noexcept { + luaL_unref(L_, LUA_REGISTRYINDEX, ref); + } + + stateless_reference copy(lua_State* L_) const noexcept { + if (!valid(L_)) { + return {}; + } + return stateless_reference(copy_ref(L_)); + } + + void copy_assign(lua_State* L_, const stateless_reference& right) noexcept { + if (valid(L_)) { + deref(L_); + } + if (!right.valid(L_)) { + return; + } + ref = right.copy_ref(L_); + } + + bool equals(lua_State* L_, const stateless_reference& r) const noexcept { + auto ppl = stack::push_pop(L_, *this); + auto ppr = stack::push_pop(L_, r); + return lua_compare(L_, -1, -2, LUA_OPEQ) == 1; + } + + bool equals(lua_State* L_, const stateless_stack_reference& r) const noexcept { + auto ppl = stack::push_pop(L_, *this); + return lua_compare(L_, -1, r.stack_index(), LUA_OPEQ) == 1; + } + + bool equals(lua_State* L_, lua_nil_t) const noexcept { + return valid(L_); + } + }; + + template <bool main_only = false> + class basic_reference : public stateless_reference { + private: + template <bool o_main_only> + friend class basic_reference; + lua_State* luastate = nullptr; // non-owning + + template <bool r_main_only> + void copy_assign_complex(const basic_reference<r_main_only>& r) { + if (valid()) { + deref(); + } + if (r.ref == LUA_REFNIL) { + luastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state()); + ref = LUA_REFNIL; + return; + } + if (r.ref == LUA_NOREF) { + luastate = r.luastate; + ref = LUA_NOREF; + return; + } + if (detail::xmovable(lua_state(), r.lua_state())) { + r.push(lua_state()); + ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); + return; + } + luastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state()); + ref = r.copy_ref(); + } + + template <bool r_main_only> + void move_assign(basic_reference<r_main_only>&& r) { + if (valid()) { + deref(); + } + if (r.ref == LUA_REFNIL) { + luastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state()); + ref = LUA_REFNIL; + return; + } + if (r.ref == LUA_NOREF) { + luastate = r.luastate; + ref = LUA_NOREF; + return; + } + if (detail::xmovable(lua_state(), r.lua_state())) { + r.push(lua_state()); + ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); + return; + } + + luastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state()); + ref = r.ref; + r.ref = LUA_NOREF; + r.luastate = nullptr; + } + + protected: + basic_reference(lua_State* L_, global_tag_t) noexcept : basic_reference(detail::pick_main_thread<main_only>(L_, L_), global_tag, global_tag) { + } + + basic_reference(lua_State* L_, global_tag_t, global_tag_t) noexcept : stateless_reference(L_, global_tag), luastate(L_) { + } + + basic_reference(lua_State* oL, const basic_reference<!main_only>& o) noexcept : stateless_reference(oL, o), luastate(oL) { + } + + void deref() const noexcept { + return stateless_reference::deref(lua_state()); + } + + int copy_ref() const noexcept { + return copy_ref(lua_state()); + } + + int copy_ref(lua_State* L_) const noexcept { + return stateless_reference::copy_ref(L_); + } + + public: + basic_reference() noexcept = default; + basic_reference(lua_nil_t) noexcept : basic_reference() { + } + basic_reference(const stack_reference& r) noexcept : basic_reference(r.lua_state(), r.stack_index()) { + } + basic_reference(stack_reference&& r) noexcept : basic_reference(r.lua_state(), r.stack_index()) { + } + template <bool r_main_only> + basic_reference(lua_State* L_, const basic_reference<r_main_only>& r) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { + if (r.ref == LUA_REFNIL) { + ref = LUA_REFNIL; + return; + } + if (r.ref == LUA_NOREF || lua_state() == nullptr) { + ref = LUA_NOREF; + return; + } + if (detail::xmovable(lua_state(), r.lua_state())) { + r.push(lua_state()); + ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); + return; + } + ref = r.copy_ref(); + } + + template <bool r_main_only> + basic_reference(lua_State* L_, basic_reference<r_main_only>&& r) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { + if (r.ref == LUA_REFNIL) { + ref = LUA_REFNIL; + return; + } + if (r.ref == LUA_NOREF || lua_state() == nullptr) { + ref = LUA_NOREF; + return; + } + if (detail::xmovable(lua_state(), r.lua_state())) { + r.push(lua_state()); + ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); + return; + } + ref = r.ref; + r.ref = LUA_NOREF; + r.luastate = nullptr; + } + + basic_reference(lua_State* L_, const stack_reference& r) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { + if (lua_state() == nullptr || r.lua_state() == nullptr || r.get_type() == type::none) { + ref = LUA_NOREF; + return; + } + if (r.get_type() == type::lua_nil) { + ref = LUA_REFNIL; + return; + } + if (lua_state() != r.lua_state() && !detail::xmovable(lua_state(), r.lua_state())) { + return; + } + r.push(lua_state()); + ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); + } + basic_reference(lua_State* L_, int index = -1) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { + // use L_ to stick with that state's execution stack +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); +#endif // make sure stack doesn't overflow + lua_pushvalue(L_, index); + ref = luaL_ref(L_, LUA_REGISTRYINDEX); + } + basic_reference(lua_State* L_, ref_index index) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { + lua_rawgeti(lua_state(), LUA_REGISTRYINDEX, index.index); + ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); + } + basic_reference(lua_State* L_, lua_nil_t) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { + } + + ~basic_reference() noexcept { + if (lua_state() == nullptr || ref == LUA_NOREF) + return; + deref(); + } + + basic_reference(const basic_reference& o) noexcept : stateless_reference(o.copy_ref()), luastate(o.lua_state()) { + } + + basic_reference(basic_reference&& o) noexcept : stateless_reference(std::move(o)), luastate(o.lua_state()) { + o.luastate = nullptr; + } + + basic_reference(const basic_reference<!main_only>& o) noexcept + : basic_reference(detail::pick_main_thread<main_only>(o.lua_state(), o.lua_state()), o) { + } + + basic_reference(basic_reference<!main_only>&& o) noexcept + : stateless_reference(std::move(o)), luastate(detail::pick_main_thread<main_only>(o.lua_state(), o.lua_state())) { + o.luastate = nullptr; + o.ref = LUA_NOREF; + } + + basic_reference& operator=(basic_reference&& r) noexcept { + move_assign(std::move(r)); + return *this; + } + + basic_reference& operator=(const basic_reference& r) noexcept { + copy_assign_complex(r); + return *this; + } + + basic_reference& operator=(basic_reference<!main_only>&& r) noexcept { + move_assign(std::move(r)); + return *this; + } + + basic_reference& operator=(const basic_reference<!main_only>& r) noexcept { + copy_assign_complex(r); + return *this; + } + + basic_reference& operator=(const lua_nil_t&) noexcept { + reset(); + return *this; + } + + template <typename Super> + basic_reference& operator=(proxy_base<Super>&& r); + + template <typename Super> + basic_reference& operator=(const proxy_base<Super>& r); + + int push() const noexcept { + return push(lua_state()); + } + + void reset() noexcept { + stateless_reference::reset(luastate); + luastate = nullptr; + } + + int push(lua_State* L_) const noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); +#endif // make sure stack doesn't overflow + if (lua_state() == nullptr) { + lua_pushnil(L_); + return 1; + } + lua_rawgeti(lua_state(), LUA_REGISTRYINDEX, ref); + if (L_ != lua_state()) { + lua_xmove(lua_state(), L_, 1); + } + return 1; + } + + void pop() const noexcept { + pop(lua_state()); + } + + void pop(lua_State* L_, int n = 1) const noexcept { + stateless_reference::pop(L_, n); + } + + int registry_index() const noexcept { + return stateless_reference::registry_index(); + } + + bool valid() const noexcept { + return stateless_reference::valid(lua_state()); + } + + bool valid(lua_State* L_) const noexcept { + return stateless_reference::valid(L_); + } + + const void* pointer() const noexcept { + return stateless_reference::pointer(lua_state()); + } + + explicit operator bool() const noexcept { + return valid(); + } + + type get_type() const noexcept { + return stateless_reference::get_type(lua_state()); + } + + lua_State* lua_state() const noexcept { + return luastate; + } + }; + + template <bool lb, bool rb> + inline bool operator==(const basic_reference<lb>& l, const basic_reference<rb>& r) noexcept { + auto ppl = stack::push_pop(l); + auto ppr = stack::push_pop(r); + return lua_compare(l.lua_state(), -1, -2, LUA_OPEQ) == 1; + } + + template <bool lb, bool rb> + inline bool operator!=(const basic_reference<lb>& l, const basic_reference<rb>& r) noexcept { + return !operator==(l, r); + } + + template <bool lb> + inline bool operator==(const basic_reference<lb>& l, const stack_reference& r) noexcept { + auto ppl = stack::push_pop(l); + return lua_compare(l.lua_state(), -1, r.stack_index(), LUA_OPEQ) == 1; + } + + template <bool lb> + inline bool operator!=(const basic_reference<lb>& l, const stack_reference& r) noexcept { + return !operator==(l, r); + } + + template <bool rb> + inline bool operator==(const stack_reference& l, const basic_reference<rb>& r) noexcept { + auto ppr = stack::push_pop(r); + return lua_compare(l.lua_state(), -1, r.stack_index(), LUA_OPEQ) == 1; + } + + template <bool rb> + inline bool operator!=(const stack_reference& l, const basic_reference<rb>& r) noexcept { + return !operator==(l, r); + } + + template <bool lb> + inline bool operator==(const basic_reference<lb>& lhs, const lua_nil_t&) noexcept { + return !lhs.valid(); + } + + template <bool rb> + inline bool operator==(const lua_nil_t&, const basic_reference<rb>& rhs) noexcept { + return !rhs.valid(); + } + + template <bool lb> + inline bool operator!=(const basic_reference<lb>& lhs, const lua_nil_t&) noexcept { + return lhs.valid(); + } + + template <bool rb> + inline bool operator!=(const lua_nil_t&, const basic_reference<rb>& rhs) noexcept { + return rhs.valid(); + } + + inline bool operator==(const stateless_reference& l, const stateless_reference& r) noexcept { + return l.registry_index() == r.registry_index(); + } + + inline bool operator!=(const stateless_reference& l, const stateless_reference& r) noexcept { + return l.registry_index() != r.registry_index(); + } + + inline bool operator==(const stateless_reference& lhs, const lua_nil_t&) noexcept { + return lhs.registry_index() == LUA_REFNIL; + } + + inline bool operator==(const lua_nil_t&, const stateless_reference& rhs) noexcept { + return rhs.registry_index() == LUA_REFNIL; + } + + inline bool operator!=(const stateless_reference& lhs, const lua_nil_t&) noexcept { + return lhs.registry_index() != LUA_REFNIL; + } + + inline bool operator!=(const lua_nil_t&, const stateless_reference& rhs) noexcept { + return rhs.registry_index() != LUA_REFNIL; + } + + struct stateless_reference_equals : public stateless_stack_reference_equals { + using is_transparent = std::true_type; + + stateless_reference_equals(lua_State* L_) noexcept : stateless_stack_reference_equals(L_) { + } + + bool operator()(const lua_nil_t& lhs, const stateless_reference& rhs) const noexcept { + return rhs.equals(lua_state(), lhs); + } + + bool operator()(const stateless_reference& lhs, const lua_nil_t& rhs) const noexcept { + return lhs.equals(lua_state(), rhs); + } + + bool operator()(const stateless_reference& lhs, const stateless_reference& rhs) const noexcept { + return lhs.equals(lua_state(), rhs); + } + }; + + struct reference_equals : public stack_reference_equals { + using is_transparent = std::true_type; + + template <bool rb> + bool operator()(const lua_nil_t& lhs, const basic_reference<rb>& rhs) const noexcept { + return lhs == rhs; + } + + template <bool lb> + bool operator()(const basic_reference<lb>& lhs, const lua_nil_t& rhs) const noexcept { + return lhs == rhs; + } + + template <bool lb, bool rb> + bool operator()(const basic_reference<lb>& lhs, const basic_reference<rb>& rhs) const noexcept { + return lhs == rhs; + } + + template <bool lb> + bool operator()(const basic_reference<lb>& lhs, const stack_reference& rhs) const noexcept { + return lhs == rhs; + } + + template <bool rb> + bool operator()(const stack_reference& lhs, const basic_reference<rb>& rhs) const noexcept { + return lhs == rhs; + } + }; + + struct stateless_reference_hash : public stateless_stack_reference_hash { + using argument_type = stateless_reference; + using result_type = std::size_t; + using is_transparent = std::true_type; + + stateless_reference_hash(lua_State* L_) noexcept : stateless_stack_reference_hash(L_) { + } + + result_type operator()(const stateless_reference& lhs) const noexcept { + std::hash<const void*> h; + return h(lhs.pointer(lua_state())); + } + }; + + struct reference_hash : public stack_reference_hash { + using argument_type = reference; + using result_type = std::size_t; + using is_transparent = std::true_type; + + template <bool lb> + result_type operator()(const basic_reference<lb>& lhs) const noexcept { + std::hash<const void*> h; + return h(lhs.pointer()); + } + }; +} // namespace sol + +// end of sol/reference.hpp + +// beginning of sol/tie.hpp + +namespace sol { + + namespace detail { + template <typename T> + struct is_speshul : std::false_type { }; + } // namespace detail + + template <typename T> + struct tie_size : std::tuple_size<T> { }; + + template <typename T> + struct is_tieable : std::integral_constant<bool, (::sol::tie_size<T>::value > 0)> { }; + + template <typename... Tn> + struct tie_t : public std::tuple<std::add_lvalue_reference_t<Tn>...> { + private: + typedef std::tuple<std::add_lvalue_reference_t<Tn>...> base_t; + + template <typename T> + void set(std::false_type, T&& target) { + std::get<0>(*this) = std::forward<T>(target); + } + + template <typename T> + void set(std::true_type, T&& target) { + typedef tie_size<meta::unqualified_t<T>> value_size; + typedef tie_size<std::tuple<Tn...>> tie_size; + typedef meta::conditional_t<(value_size::value < tie_size::value), value_size, tie_size> indices_size; + typedef std::make_index_sequence<indices_size::value> indices; + set_extra(detail::is_speshul<meta::unqualified_t<T>>(), indices(), std::forward<T>(target)); + } + + template <std::size_t... I, typename T> + void set_extra(std::true_type, std::index_sequence<I...>, T&& target) { + using std::get; + (void)detail::swallow { 0, (get<I>(static_cast<base_t&>(*this)) = get<I>(types<Tn...>(), target), 0)..., 0 }; + } + + template <std::size_t... I, typename T> + void set_extra(std::false_type, std::index_sequence<I...>, T&& target) { + using std::get; + (void)detail::swallow { 0, (get<I>(static_cast<base_t&>(*this)) = get<I>(target), 0)..., 0 }; + } + + public: + using base_t::base_t; + + template <typename T> + tie_t& operator=(T&& value) { + typedef is_tieable<meta::unqualified_t<T>> tieable; + set(tieable(), std::forward<T>(value)); + return *this; + } + }; + + template <typename... Tn> + struct tie_size<tie_t<Tn...>> : std::tuple_size<std::tuple<Tn...>> { }; + + namespace adl_barrier_detail { + template <typename... Tn> + inline tie_t<std::remove_reference_t<Tn>...> tie(Tn&&... argn) { + return tie_t<std::remove_reference_t<Tn>...>(std::forward<Tn>(argn)...); + } + } // namespace adl_barrier_detail + + using namespace adl_barrier_detail; + +} // namespace sol + +// end of sol/tie.hpp + +// beginning of sol/stack_guard.hpp + +#include <functional> + +namespace sol { + namespace detail { + inline void stack_fail(int, int) { +#if SOL_IS_ON(SOL_EXCEPTIONS) + throw error(detail::direct_error, "imbalanced stack after operation finish"); +#else + // Lol, what do you want, an error printout? :3c + // There's no sane default here. The right way would be C-style abort(), and that's not acceptable, so + // hopefully someone will register their own stack_fail thing for the `fx` parameter of stack_guard. +#endif // No Exceptions + } + } // namespace detail + + struct stack_guard { + lua_State* L; + int top; + std::function<void(int, int)> on_mismatch; + + stack_guard(lua_State* L) : stack_guard(L, lua_gettop(L)) { + } + stack_guard(lua_State* L, int top, std::function<void(int, int)> fx = detail::stack_fail) : L(L), top(top), on_mismatch(std::move(fx)) { + } + bool check_stack(int modification = 0) const { + int bottom = lua_gettop(L) + modification; + if (top == bottom) { + return true; + } + on_mismatch(top, bottom); + return false; + } + ~stack_guard() { + check_stack(); + } + }; +} // namespace sol + +// end of sol/stack_guard.hpp + +#include <vector> +#include <bitset> +#include <forward_list> +#include <string> +#include <limits> +#include <algorithm> +#include <sstream> +#include <optional> +#include <type_traits> + +namespace sol { + namespace detail { + struct with_function_tag { }; + struct as_reference_tag { }; + template <typename T> + struct as_pointer_tag { }; + template <typename T> + struct as_value_tag { }; + template <typename T> + struct as_unique_tag { }; + template <typename T> + struct as_table_tag { }; + + template <typename Tag> + inline constexpr bool is_tagged_v + = meta::is_specialization_of_v<Tag, + detail:: + as_pointer_tag> || meta::is_specialization_of_v<Tag, as_value_tag> || meta::is_specialization_of_v<Tag, as_unique_tag> || meta::is_specialization_of_v<Tag, as_table_tag> || std::is_same_v<Tag, as_reference_tag> || std::is_same_v<Tag, with_function_tag>; + + using lua_reg_table = luaL_Reg[64]; + + using unique_destructor = void (*)(void*); + using unique_tag = detail::inheritance_unique_cast_function; + + inline void* alloc_newuserdata(lua_State* L, std::size_t bytesize) { +#if SOL_LUA_VERSION_I_ >= 504 + return lua_newuserdatauv(L, bytesize, 1); +#else + return lua_newuserdata(L, bytesize); +#endif + } + + constexpr std::uintptr_t align(std::size_t alignment, std::uintptr_t ptr, std::size_t& space) { + // this handles arbitrary alignments... + // make this into a power-of-2-only? + // actually can't: this is a C++14-compatible framework, + // power of 2 alignment is C++17 + std::uintptr_t offby = static_cast<std::uintptr_t>(ptr % alignment); + std::uintptr_t padding = (alignment - offby) % alignment; + ptr += padding; + space -= padding; + return ptr; + } + + inline void* align(std::size_t alignment, void* ptr, std::size_t& space) { + return reinterpret_cast<void*>(align(alignment, reinterpret_cast<std::uintptr_t>(ptr), space)); + } + + constexpr std::uintptr_t align_one(std::size_t alignment, std::size_t size, std::uintptr_t ptr) { + std::size_t space = (std::numeric_limits<std::size_t>::max)(); + return align(alignment, ptr, space) + size; + } + + template <typename... Args> + constexpr std::size_t aligned_space_for(std::uintptr_t ptr) { + std::uintptr_t end = ptr; + ((end = align_one(alignof(Args), sizeof(Args), end)), ...); + return static_cast<std::size_t>(end - ptr); + } + + template <typename... Args> + constexpr std::size_t aligned_space_for() { + static_assert(sizeof...(Args) > 0); + + constexpr std::size_t max_arg_alignment = (std::max)({ alignof(Args)... }); + if constexpr (max_arg_alignment <= alignof(std::max_align_t)) { + // If all types are `good enough`, simply calculate alignment in case of the worst allocator + std::size_t worst_required_size = 0; + for (std::size_t ptr = 0; ptr < max_arg_alignment; ptr++) { + worst_required_size = (std::max)(worst_required_size, aligned_space_for<Args...>(ptr)); + } + return worst_required_size; + } + else { + // For over-aligned types let's assume that every Arg in Args starts at the worst aligned address + return (aligned_space_for<Args>(0x1) + ...); + } + } + + inline void* align_usertype_pointer(void* ptr) { + using use_align = std::integral_constant<bool, +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) + false +#else + (std::alignment_of<void*>::value > 1) +#endif + >; + if (!use_align::value) { + return ptr; + } + std::size_t space = (std::numeric_limits<std::size_t>::max)(); + return align(std::alignment_of<void*>::value, ptr, space); + } + + template <bool pre_aligned = false, bool pre_shifted = false> + void* align_usertype_unique_destructor(void* ptr) { + using use_align = std::integral_constant<bool, +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) + false +#else + (std::alignment_of<unique_destructor>::value > 1) +#endif + >; + if (!pre_aligned) { + ptr = align_usertype_pointer(ptr); + } + if (!pre_shifted) { + ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(void*)); + } + if (!use_align::value) { + return static_cast<void*>(static_cast<void**>(ptr) + 1); + } + std::size_t space = (std::numeric_limits<std::size_t>::max)(); + return align(std::alignment_of<unique_destructor>::value, ptr, space); + } + + template <bool pre_aligned = false, bool pre_shifted = false> + void* align_usertype_unique_tag(void* ptr) { + using use_align = std::integral_constant<bool, +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) + false +#else + (std::alignment_of<unique_tag>::value > 1) +#endif + >; + if (!pre_aligned) { + ptr = align_usertype_unique_destructor(ptr); + } + if (!pre_shifted) { + ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(unique_destructor)); + } + if (!use_align::value) { + return ptr; + } + std::size_t space = (std::numeric_limits<std::size_t>::max)(); + return align(std::alignment_of<unique_tag>::value, ptr, space); + } + + template <typename T, bool pre_aligned = false, bool pre_shifted = false> + void* align_usertype_unique(void* ptr) { + typedef std::integral_constant<bool, +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) + false +#else + (std::alignment_of_v<T> > 1) +#endif + > + use_align; + if (!pre_aligned) { + ptr = align_usertype_unique_tag(ptr); + } + if (!pre_shifted) { + ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(unique_tag)); + } + if (!use_align::value) { + return ptr; + } + std::size_t space = (std::numeric_limits<std::size_t>::max)(); + return align(std::alignment_of_v<T>, ptr, space); + } + + template <typename T> + void* align_user(void* ptr) { + typedef std::integral_constant<bool, +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) + false +#else + (std::alignment_of_v<T> > 1) +#endif + > + use_align; + if (!use_align::value) { + return ptr; + } + std::size_t space = (std::numeric_limits<std::size_t>::max)(); + return align(std::alignment_of_v<T>, ptr, space); + } + + template <typename T> + T** usertype_allocate_pointer(lua_State* L) { + typedef std::integral_constant<bool, +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) + false +#else + (std::alignment_of<T*>::value > 1) +#endif + > + use_align; + if (!use_align::value) { + T** pointerpointer = static_cast<T**>(alloc_newuserdata(L, sizeof(T*))); + return pointerpointer; + } + constexpr std::size_t initial_size = aligned_space_for<T*>(); + + std::size_t allocated_size = initial_size; + void* unadjusted = alloc_newuserdata(L, initial_size); + void* adjusted = align(std::alignment_of<T*>::value, unadjusted, allocated_size); + if (adjusted == nullptr) { + // trash allocator can burn in hell + lua_pop(L, 1); + // luaL_error(L, "if you are the one that wrote this allocator you should feel bad for doing a + // worse job than malloc/realloc and should go read some books, yeah?"); + luaL_error(L, "cannot properly align memory for '%s'", detail::demangle<T*>().data()); + } + return static_cast<T**>(adjusted); + } + + inline bool attempt_alloc(lua_State* L, std::size_t ptr_align, std::size_t ptr_size, std::size_t value_align, + std::size_t allocated_size, void*& pointer_adjusted, void*& data_adjusted) { + void* adjusted = alloc_newuserdata(L, allocated_size); + pointer_adjusted = align(ptr_align, adjusted, allocated_size); + if (pointer_adjusted == nullptr) { + lua_pop(L, 1); + return false; + } + // subtract size of what we're going to allocate there + allocated_size -= ptr_size; + adjusted = static_cast<void*>(static_cast<char*>(pointer_adjusted) + ptr_size); + data_adjusted = align(value_align, adjusted, allocated_size); + if (data_adjusted == nullptr) { + lua_pop(L, 1); + return false; + } + return true; + } + + inline bool attempt_alloc_unique(lua_State* L, std::size_t ptr_align, std::size_t ptr_size, std::size_t real_align, + std::size_t allocated_size, void*& pointer_adjusted, void*& dx_adjusted, void*& id_adjusted, void*& data_adjusted) { + void* adjusted = alloc_newuserdata(L, allocated_size); + pointer_adjusted = align(ptr_align, adjusted, allocated_size); + if (pointer_adjusted == nullptr) { + lua_pop(L, 1); + return false; + } + allocated_size -= ptr_size; + + adjusted = static_cast<void*>(static_cast<char*>(pointer_adjusted) + ptr_size); + dx_adjusted = align(std::alignment_of_v<unique_destructor>, adjusted, allocated_size); + if (dx_adjusted == nullptr) { + lua_pop(L, 1); + return false; + } + allocated_size -= sizeof(unique_destructor); + + adjusted = static_cast<void*>(static_cast<char*>(dx_adjusted) + sizeof(unique_destructor)); + + id_adjusted = align(std::alignment_of_v<unique_tag>, adjusted, allocated_size); + if (id_adjusted == nullptr) { + lua_pop(L, 1); + return false; + } + allocated_size -= sizeof(unique_tag); + + adjusted = static_cast<void*>(static_cast<char*>(id_adjusted) + sizeof(unique_tag)); + data_adjusted = align(real_align, adjusted, allocated_size); + if (data_adjusted == nullptr) { + lua_pop(L, 1); + return false; + } + return true; + } + + template <typename T> + T* usertype_allocate(lua_State* L) { + typedef std::integral_constant<bool, +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) + false +#else + (std::alignment_of<T*>::value > 1 || std::alignment_of_v<T> > 1) +#endif + > + use_align; + if (!use_align::value) { + T** pointerpointer = static_cast<T**>(alloc_newuserdata(L, sizeof(T*) + sizeof(T))); + T*& pointerreference = *pointerpointer; + T* allocationtarget = reinterpret_cast<T*>(pointerpointer + 1); + pointerreference = allocationtarget; + return allocationtarget; + } + + constexpr std::size_t initial_size = aligned_space_for<T*, T>(); + + void* pointer_adjusted; + void* data_adjusted; + bool result + = attempt_alloc(L, std::alignment_of_v<T*>, sizeof(T*), std::alignment_of_v<T>, initial_size, pointer_adjusted, data_adjusted); + if (!result) { + if (pointer_adjusted == nullptr) { + luaL_error(L, "aligned allocation of userdata block (pointer section) for '%s' failed", detail::demangle<T>().c_str()); + } + else { + luaL_error(L, "aligned allocation of userdata block (data section) for '%s' failed", detail::demangle<T>().c_str()); + } + return nullptr; + } + + T** pointerpointer = reinterpret_cast<T**>(pointer_adjusted); + T*& pointerreference = *pointerpointer; + T* allocationtarget = reinterpret_cast<T*>(data_adjusted); + pointerreference = allocationtarget; + return allocationtarget; + } + + template <typename T, typename Real> + Real* usertype_unique_allocate(lua_State* L, T**& pref, unique_destructor*& dx, unique_tag*& id) { + typedef std::integral_constant<bool, +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) + false +#else + (std::alignment_of<T*>::value > 1 || std::alignment_of<unique_tag>::value > 1 || std::alignment_of<unique_destructor>::value > 1 + || std::alignment_of<Real>::value > 1) +#endif + > + use_align; + if (!use_align::value) { + pref = static_cast<T**>(alloc_newuserdata(L, sizeof(T*) + sizeof(detail::unique_destructor) + sizeof(unique_tag) + sizeof(Real))); + dx = static_cast<detail::unique_destructor*>(static_cast<void*>(pref + 1)); + id = static_cast<unique_tag*>(static_cast<void*>(dx + 1)); + Real* mem = static_cast<Real*>(static_cast<void*>(id + 1)); + return mem; + } + + constexpr std::size_t initial_size = aligned_space_for<T*, unique_destructor, unique_tag, Real>(); + + void* pointer_adjusted = nullptr; + void* dx_adjusted = nullptr; + void* id_adjusted = nullptr; + void* data_adjusted = nullptr; + bool result = attempt_alloc_unique(L, + std::alignment_of_v<T*>, + sizeof(T*), + std::alignment_of_v<Real>, + initial_size, + pointer_adjusted, + dx_adjusted, + id_adjusted, + data_adjusted); + if (!result) { + if (pointer_adjusted == nullptr) { + luaL_error(L, "aligned allocation of userdata block (pointer section) for '%s' failed", detail::demangle<T>().c_str()); + } + else if (dx_adjusted == nullptr) { + luaL_error(L, "aligned allocation of userdata block (deleter section) for '%s' failed", detail::demangle<T>().c_str()); + } + else { + luaL_error(L, "aligned allocation of userdata block (data section) for '%s' failed", detail::demangle<T>().c_str()); + } + return nullptr; + } + + pref = static_cast<T**>(pointer_adjusted); + dx = static_cast<detail::unique_destructor*>(dx_adjusted); + id = static_cast<unique_tag*>(id_adjusted); + Real* mem = static_cast<Real*>(data_adjusted); + return mem; + } + + template <typename T> + T* user_allocate(lua_State* L) { + typedef std::integral_constant<bool, +#if SOL_IS_OFF(SOL_ALIGN_MEMORY) + false +#else + (std::alignment_of_v<T> > 1) +#endif + > + use_align; + if (!use_align::value) { + T* pointer = static_cast<T*>(alloc_newuserdata(L, sizeof(T))); + return pointer; + } + + constexpr std::size_t initial_size = aligned_space_for<T>(); + + std::size_t allocated_size = initial_size; + void* unadjusted = alloc_newuserdata(L, allocated_size); + void* adjusted = align(std::alignment_of_v<T>, unadjusted, allocated_size); + if (adjusted == nullptr) { + lua_pop(L, 1); + luaL_error(L, "cannot properly align memory for '%s'", detail::demangle<T>().data()); + } + return static_cast<T*>(adjusted); + } + + template <typename T> + int usertype_alloc_destroy(lua_State* L) noexcept { + void* memory = lua_touserdata(L, 1); + memory = align_usertype_pointer(memory); + T** pdata = static_cast<T**>(memory); + T* data = *pdata; + std::allocator<T> alloc {}; + std::allocator_traits<std::allocator<T>>::destroy(alloc, data); + return 0; + } + + template <typename T> + int unique_destroy(lua_State* L) noexcept { + void* memory = lua_touserdata(L, 1); + memory = align_usertype_unique_destructor(memory); + unique_destructor& dx = *static_cast<unique_destructor*>(memory); + memory = align_usertype_unique_tag<true>(memory); + (dx)(memory); + return 0; + } + + template <typename T> + int user_alloc_destroy(lua_State* L) noexcept { + void* memory = lua_touserdata(L, 1); + void* aligned_memory = align_user<T>(memory); + T* typed_memory = static_cast<T*>(aligned_memory); + std::allocator<T> alloc; + std::allocator_traits<std::allocator<T>>::destroy(alloc, typed_memory); + return 0; + } + + template <typename T, typename Real> + void usertype_unique_alloc_destroy(void* memory) { + void* aligned_memory = align_usertype_unique<Real, true>(memory); + Real* typed_memory = static_cast<Real*>(aligned_memory); + std::allocator<Real> alloc; + std::allocator_traits<std::allocator<Real>>::destroy(alloc, typed_memory); + } + + template <typename T> + int cannot_destroy(lua_State* L) { + return luaL_error(L, + "cannot call the destructor for '%s': it is either hidden (protected/private) or removed with '= " + "delete' and thusly this type is being destroyed without properly destroying, invoking undefined " + "behavior: please bind a usertype and specify a custom destructor to define the behavior properly", + detail::demangle<T>().data()); + } + + template <typename T> + void reserve(T&, std::size_t) { + } + + template <typename T, typename Al> + void reserve(std::vector<T, Al>& vec, std::size_t hint) { + vec.reserve(hint); + } + + template <typename T, typename Tr, typename Al> + void reserve(std::basic_string<T, Tr, Al>& str, std::size_t hint) { + str.reserve(hint); + } + + inline bool property_always_true(meta_function) { + return true; + } + + struct properties_enrollment_allowed { + int& times_through; + std::bitset<64>& properties; + automagic_enrollments& enrollments; + + properties_enrollment_allowed(int& times_through_, std::bitset<64>& properties_, automagic_enrollments& enrollments_) + : times_through(times_through_), properties(properties_), enrollments(enrollments_) { + } + + bool operator()(meta_function mf) const { + bool p = properties[static_cast<std::size_t>(mf)]; + if (times_through > 0) { + return p; + } + switch (mf) { + case meta_function::length: + return enrollments.length_operator && !p; + case meta_function::pairs: + return enrollments.pairs_operator && !p; + case meta_function::call: + return enrollments.call_operator && !p; + case meta_function::less_than: + return enrollments.less_than_operator && !p; + case meta_function::less_than_or_equal_to: + return enrollments.less_than_or_equal_to_operator && !p; + case meta_function::equal_to: + return enrollments.equal_to_operator && !p; + default: + break; + } + return !p; + } + }; + + struct indexed_insert { + lua_reg_table& registration_table; + int& index; + + indexed_insert(lua_reg_table& registration_table_, int& index_ref_) : registration_table(registration_table_), index(index_ref_) { + } + void operator()(meta_function meta_function_name_, lua_CFunction c_function_) { + registration_table[index] = luaL_Reg { to_string(meta_function_name_).c_str(), c_function_ }; + ++index; + } + }; + } // namespace detail + + namespace stack { + + template <typename T, bool global = false, bool raw = false, typename = void> + struct field_getter; + template <typename T, typename P, bool global = false, bool raw = false, typename = void> + struct probe_field_getter; + + template <typename T, bool global = false, bool raw = false, typename = void> + struct field_setter; + + template <typename T, typename = void> + struct unqualified_getter; + template <typename T, typename = void> + struct qualified_getter; + + template <typename T, typename = void> + struct qualified_interop_getter; + template <typename T, typename = void> + struct unqualified_interop_getter; + + template <typename T, typename = void> + struct popper; + + template <typename T, typename = void> + struct unqualified_pusher; + + template <typename T, type t, typename = void> + struct unqualified_checker; + template <typename T, type t, typename = void> + struct qualified_checker; + + template <typename T, typename = void> + struct unqualified_check_getter; + template <typename T, typename = void> + struct qualified_check_getter; + + struct probe { + bool success; + int levels; + + probe(bool s, int l) : success(s), levels(l) { + } + + operator bool() const { + return success; + }; + }; + + struct record { + int last; + int used; + + record() noexcept : last(), used() { + } + void use(int count) noexcept { + last = count; + used += count; + } + }; + + namespace stack_detail { + template <typename Function> + Function* get_function_pointer(lua_State*, int, record&) noexcept; + template <typename Function, typename Handler> + bool check_function_pointer(lua_State* L, int index, Handler&& handler, record& tracking) noexcept; + } // namespace stack_detail + + } // namespace stack + + namespace meta { namespace meta_detail { + template <typename T> + using adl_sol_lua_get_test_t = decltype(sol_lua_get(types<T>(), static_cast<lua_State*>(nullptr), -1, std::declval<stack::record&>())); + + template <typename T> + using adl_sol_lua_interop_get_test_t + = decltype(sol_lua_interop_get(types<T>(), static_cast<lua_State*>(nullptr), -1, static_cast<void*>(nullptr), std::declval<stack::record&>())); + + template <typename T> + using adl_sol_lua_check_test_t = decltype(sol_lua_check(types<T>(), static_cast<lua_State*>(nullptr), -1, &no_panic, std::declval<stack::record&>())); + + template <typename T> + using adl_sol_lua_interop_check_test_t + = decltype(sol_lua_interop_check(types<T>(), static_cast<lua_State*>(nullptr), -1, type::none, &no_panic, std::declval<stack::record&>())); + + template <typename T> + using adl_sol_lua_check_get_test_t + = decltype(sol_lua_check_get(types<T>(), static_cast<lua_State*>(nullptr), -1, &no_panic, std::declval<stack::record&>())); + + template <typename... Args> + using adl_sol_lua_push_test_t = decltype(sol_lua_push(static_cast<lua_State*>(nullptr), std::declval<Args>()...)); + + template <typename T, typename... Args> + using adl_sol_lua_push_exact_test_t = decltype(sol_lua_push(types<T>(), static_cast<lua_State*>(nullptr), std::declval<Args>()...)); + + template <typename T> + inline constexpr bool is_adl_sol_lua_get_v = meta::is_detected_v<adl_sol_lua_get_test_t, T>; + + template <typename T> + inline constexpr bool is_adl_sol_lua_interop_get_v = meta::is_detected_v<adl_sol_lua_interop_get_test_t, T>; + + template <typename T> + inline constexpr bool is_adl_sol_lua_check_v = meta::is_detected_v<adl_sol_lua_check_test_t, T>; + + template <typename T> + inline constexpr bool is_adl_sol_lua_interop_check_v = meta::is_detected_v<adl_sol_lua_interop_check_test_t, T>; + + template <typename T> + inline constexpr bool is_adl_sol_lua_check_get_v = meta::is_detected_v<adl_sol_lua_check_get_test_t, T>; + + template <typename... Args> + inline constexpr bool is_adl_sol_lua_push_v = meta::is_detected_v<adl_sol_lua_push_test_t, Args...>; + + template <typename T, typename... Args> + inline constexpr bool is_adl_sol_lua_push_exact_v = meta::is_detected_v<adl_sol_lua_push_exact_test_t, T, Args...>; + }} // namespace meta::meta_detail + + namespace stack { + namespace stack_detail { + constexpr const char* not_enough_stack_space = "not enough space left on Lua stack"; + constexpr const char* not_enough_stack_space_floating = "not enough space left on Lua stack for a floating point number"; + constexpr const char* not_enough_stack_space_integral = "not enough space left on Lua stack for an integral number"; + constexpr const char* not_enough_stack_space_string = "not enough space left on Lua stack for a string"; + constexpr const char* not_enough_stack_space_meta_function_name = "not enough space left on Lua stack for the name of a meta_function"; + constexpr const char* not_enough_stack_space_userdata = "not enough space left on Lua stack to create a sol2 userdata"; + constexpr const char* not_enough_stack_space_generic = "not enough space left on Lua stack to push valuees"; + constexpr const char* not_enough_stack_space_environment = "not enough space left on Lua stack to retrieve environment"; + + template <typename T> + struct strip { + typedef T type; + }; + template <typename T> + struct strip<std::reference_wrapper<T>> { + typedef T& type; + }; + template <typename T> + struct strip<user<T>> { + typedef T& type; + }; + template <typename T> + struct strip<non_null<T>> { + typedef T type; + }; + template <typename T> + using strip_t = typename strip<T>::type; + + template <typename C> + static int get_size_hint(C& c) { + return static_cast<int>(c.size()); + } + + template <typename V, typename Al> + static int get_size_hint(const std::forward_list<V, Al>&) { + // forward_list makes me sad + return static_cast<int>(32); + } + + template <typename T> + decltype(auto) unchecked_unqualified_get(lua_State* L, int index, record& tracking) { + using Tu = meta::unqualified_t<T>; + if constexpr (meta::meta_detail::is_adl_sol_lua_get_v<Tu>) { + return sol_lua_get(types<Tu>(), L, index, tracking); + } + else { + unqualified_getter<Tu> g {}; + return g.get(L, index, tracking); + } + } + + template <typename T> + decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) { + if constexpr (meta::meta_detail::is_adl_sol_lua_get_v<T>) { + return sol_lua_get(types<T>(), L, index, tracking); + } + else { + qualified_getter<T> g {}; + return g.get(L, index, tracking); + } + } + + template <typename T> + decltype(auto) unqualified_interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) { + using Tu = meta::unqualified_t<T>; + if constexpr (meta::meta_detail::is_adl_sol_lua_interop_get_v<Tu>) { + return sol_lua_interop_get(types<Tu>(), L, index, unadjusted_pointer, tracking); + } + else { + (void)L; + (void)index; + (void)unadjusted_pointer; + (void)tracking; + using Ti = stack_detail::strip_t<Tu>; + return std::pair<bool, Ti*> { false, nullptr }; + } + } + + template <typename T> + decltype(auto) interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) { + if constexpr (meta::meta_detail::is_adl_sol_lua_interop_get_v<T>) { + return sol_lua_interop_get(types<T>(), L, index, unadjusted_pointer, tracking); + } + else { + return unqualified_interop_get<T>(L, index, unadjusted_pointer, tracking); + } + } + + template <typename T, typename Handler> + bool unqualified_interop_check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) { + using Tu = meta::unqualified_t<T>; + if constexpr (meta::meta_detail::is_adl_sol_lua_interop_check_v<Tu>) { + return sol_lua_interop_check(types<Tu>(), L, index, index_type, std::forward<Handler>(handler), tracking); + } + else { + (void)L; + (void)index; + (void)index_type; + (void)handler; + (void)tracking; + return false; + } + } + + template <typename T, typename Handler> + bool interop_check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) { + if constexpr (meta::meta_detail::is_adl_sol_lua_interop_check_v<T>) { + return sol_lua_interop_check(types<T>(), L, index, index_type, std::forward<Handler>(handler), tracking); + } + else { + return unqualified_interop_check<T>(L, index, index_type, std::forward<Handler>(handler), tracking); + } + } + + using undefined_method_func = void (*)(stack_reference); + + struct undefined_metatable { + lua_State* L; + const char* key; + undefined_method_func on_new_table; + + undefined_metatable(lua_State* l, const char* k, undefined_method_func umf) : L(l), key(k), on_new_table(umf) { + } + + void operator()() const { + if (luaL_newmetatable(L, key) == 1) { + on_new_table(stack_reference(L, -1)); + } + lua_setmetatable(L, -2); + } + }; + } // namespace stack_detail + + inline bool maybe_indexable(lua_State* L, int index = -1) { + type t = type_of(L, index); + return t == type::userdata || t == type::table; + } + + inline int top(lua_State* L) { + return lua_gettop(L); + } + + inline bool is_main_thread(lua_State* L) { + int ismainthread = lua_pushthread(L); + lua_pop(L, 1); + return ismainthread == 1; + } + + inline void coroutine_create_guard(lua_State* L) { + if (is_main_thread(L)) { + return; + } + int stacksize = lua_gettop(L); + if (stacksize < 1) { + return; + } + if (type_of(L, 1) != type::function) { + return; + } + // well now we're screwed... + // we can clean the stack and pray it doesn't destroy anything? + lua_pop(L, stacksize); + } + + inline void clear(lua_State* L, int table_index) { + lua_pushnil(L); + while (lua_next(L, table_index) != 0) { + // remove value + lua_pop(L, 1); + // duplicate key to protect form rawset + lua_pushvalue(L, -1); + // push new value + lua_pushnil(L); + // table_index%[key] = nil + lua_rawset(L, table_index); + } + } + + inline void clear(reference& r) { + auto pp = push_pop<false>(r); + int stack_index = pp.index_of(r); + clear(r.lua_state(), stack_index); + } + + inline void clear(stack_reference& r) { + clear(r.lua_state(), r.stack_index()); + } + + inline void clear(lua_State* L_, stateless_reference& r) { + r.push(L_); + int stack_index = absolute_index(L_, -1); + clear(L_, stack_index); + r.pop(L_); + } + + inline void clear(lua_State* L_, stateless_stack_reference& r) { + clear(L_, r.stack_index()); + } + + template <typename T, typename... Args> + int push(lua_State* L, T&& t, Args&&... args) { + using Tu = meta::unqualified_t<T>; + if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v<T, T, Args...>) { + return sol_lua_push(types<T>(), L, std::forward<T>(t), std::forward<Args>(args)...); + } + else if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v<Tu, T, Args...>) { + return sol_lua_push(types<Tu>(), L, std::forward<T>(t), std::forward<Args>(args)...); + } + else if constexpr (meta::meta_detail::is_adl_sol_lua_push_v<T, Args...>) { + return sol_lua_push(L, std::forward<T>(t), std::forward<Args>(args)...); + } + else { + unqualified_pusher<Tu> p {}; + return p.push(L, std::forward<T>(t), std::forward<Args>(args)...); + } + } + + // overload allows to use a pusher of a specific type, but pass in any kind of args + template <typename T, typename Arg, typename... Args, typename = std::enable_if_t<!std::is_same<T, Arg>::value>> + int push(lua_State* L, Arg&& arg, Args&&... args) { + using Tu = meta::unqualified_t<T>; + if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v<T, Arg, Args...>) { + return sol_lua_push(types<T>(), L, std::forward<Arg>(arg), std::forward<Args>(args)...); + } + else if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v<Tu, Arg, Args...>) { + return sol_lua_push(types<Tu>(), L, std::forward<Arg>(arg), std::forward<Args>(args)...); + } + else if constexpr (meta::meta_detail::is_adl_sol_lua_push_v<Arg, Args...> && !detail::is_tagged_v<Tu>) { + return sol_lua_push(L, std::forward<Arg>(arg), std::forward<Args>(args)...); + } + else { + unqualified_pusher<Tu> p {}; + return p.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...); + } + } + + template <typename T, typename... Args> + int push_userdata(lua_State* L, T&& t, Args&&... args) { + using U = meta::unqualified_t<T>; + using Tr = meta::conditional_t<std::is_pointer_v<U>, + detail::as_pointer_tag<std::remove_pointer_t<U>>, + meta::conditional_t<is_unique_usertype_v<U>, detail::as_unique_tag<U>, detail::as_value_tag<U>>>; + return stack::push<Tr>(L, std::forward<T>(t), std::forward<Args>(args)...); + } + + template <typename T, typename Arg, typename... Args> + int push_userdata(lua_State* L, Arg&& arg, Args&&... args) { + using U = meta::unqualified_t<T>; + using Tr = meta::conditional_t<std::is_pointer_v<U>, + detail::as_pointer_tag<std::remove_pointer_t<U>>, + meta::conditional_t<is_unique_usertype_v<U>, detail::as_unique_tag<U>, detail::as_value_tag<U>>>; + return stack::push<Tr>(L, std::forward<Arg>(arg), std::forward<Args>(args)...); + } + + namespace stack_detail { + + template <typename T, typename Arg, typename... Args> + int push_reference(lua_State* L, Arg&& arg, Args&&... args) { + // clang-format off + using use_reference_tag = + meta::all< + meta::neg<is_value_semantic_for_function<T>> +#if SOL_IS_OFF(SOL_FUNCTION_CALL_VALUE_SEMANTICS) + , std::is_lvalue_reference<T>, + meta::neg<std::is_const<std::remove_reference_t<T>>>, + meta::neg<is_lua_primitive<meta::unqualified_t<T>>>, + meta::neg<is_unique_usertype<meta::unqualified_t<T>>> +#endif + >; + // clang-format on + using Tr = meta::conditional_t<use_reference_tag::value, detail::as_reference_tag, meta::unqualified_t<T>>; + return stack::push<Tr>(L, std::forward<Arg>(arg), std::forward<Args>(args)...); + } + + } // namespace stack_detail + + template <typename T, typename... Args> + int push_reference(lua_State* L, T&& t, Args&&... args) { + return stack_detail::push_reference<T>(L, std::forward<T>(t), std::forward<Args>(args)...); + } + + template <typename T, typename Arg, typename... Args> + int push_reference(lua_State* L, Arg&& arg, Args&&... args) { + return stack_detail::push_reference<T>(L, std::forward<Arg>(arg), std::forward<Args>(args)...); + } + + inline int multi_push(lua_State*) { + // do nothing + return 0; + } + + template <typename T, typename... Args> + int multi_push(lua_State* L, T&& t, Args&&... args) { + int pushcount = push(L, std::forward<T>(t)); + void(detail::swallow { (pushcount += stack::push(L, std::forward<Args>(args)), 0)... }); + return pushcount; + } + + inline int multi_push_reference(lua_State*) { + // do nothing + return 0; + } + + template <typename T, typename... Args> + int multi_push_reference(lua_State* L, T&& t, Args&&... args) { + int pushcount = stack::push_reference(L, std::forward<T>(t)); + void(detail::swallow { (pushcount += stack::push_reference(L, std::forward<Args>(args)), 0)... }); + return pushcount; + } + + template <typename T, typename Handler> + bool unqualified_check(lua_State* L, int index, Handler&& handler, record& tracking) { + using Tu = meta::unqualified_t<T>; + if constexpr (meta::meta_detail::is_adl_sol_lua_check_v<Tu>) { + return sol_lua_check(types<Tu>(), L, index, std::forward<Handler>(handler), tracking); + } + else { + unqualified_checker<Tu, lua_type_of_v<Tu>> c{}; + return c.check(L, index, std::forward<Handler>(handler), tracking); + } + } + + template <typename T, typename Handler> + bool unqualified_check(lua_State* L, int index, Handler&& handler) { + record tracking {}; + return unqualified_check<T>(L, index, std::forward<Handler>(handler), tracking); + } + + template <typename T> + bool unqualified_check(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { + auto handler = &no_panic; + return unqualified_check<T>(L, index, handler); + } + + template <typename T, typename Handler> + bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + if constexpr (meta::meta_detail::is_adl_sol_lua_check_v<T>) { + return sol_lua_check(types<T>(), L, index, std::forward<Handler>(handler), tracking); + } + else { + using Tu = meta::unqualified_t<T>; + qualified_checker<T, lua_type_of_v<Tu>> c{}; + return c.check(L, index, std::forward<Handler>(handler), tracking); + } + } + + template <typename T, typename Handler> + bool check(lua_State* L, int index, Handler&& handler) { + record tracking {}; + return check<T>(L, index, std::forward<Handler>(handler), tracking); + } + + template <typename T> + bool check(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { + auto handler = &no_panic; + return check<T>(L, index, handler); + } + + template <typename T, typename Handler> + bool check_usertype(lua_State* L, int index, type, Handler&& handler, record& tracking) { + using Tu = meta::unqualified_t<T>; + using detail_t = meta::conditional_t<std::is_pointer_v<T>, detail::as_pointer_tag<Tu>, detail::as_value_tag<Tu>>; + return check<detail_t>(L, index, std::forward<Handler>(handler), tracking); + } + + template <typename T, typename Handler> + bool check_usertype(lua_State* L, int index, Handler&& handler, record& tracking) { + using Tu = meta::unqualified_t<T>; + using detail_t = meta::conditional_t<std::is_pointer_v<T>, detail::as_pointer_tag<Tu>, detail::as_value_tag<Tu>>; + return check<detail_t>(L, index, std::forward<Handler>(handler), tracking); + } + + template <typename T, typename Handler> + bool check_usertype(lua_State* L, int index, Handler&& handler) { + record tracking {}; + return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking); + } + + template <typename T> + bool check_usertype(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { + auto handler = &no_panic; + return check_usertype<T>(L, index, handler); + } + + template <typename T, typename Handler> + decltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler, record& tracking) { + using Tu = meta::unqualified_t<T>; + if constexpr (meta::meta_detail::is_adl_sol_lua_check_get_v<T>) { + return sol_lua_check_get(types<T>(), L, index, std::forward<Handler>(handler), tracking); + } + else if constexpr (meta::meta_detail::is_adl_sol_lua_check_get_v<Tu>) { + return sol_lua_check_get(types<Tu>(), L, index, std::forward<Handler>(handler), tracking); + } + else { + unqualified_check_getter<Tu> cg {}; + return cg.get(L, index, std::forward<Handler>(handler), tracking); + } + } + + template <typename T, typename Handler> + decltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler) { + record tracking {}; + return unqualified_check_get<T>(L, index, handler, tracking); + } + + template <typename T> + decltype(auto) unqualified_check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { + auto handler = &no_panic; + return unqualified_check_get<T>(L, index, handler); + } + + template <typename T, typename Handler> + decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) { + if constexpr (meta::meta_detail::is_adl_sol_lua_check_get_v<T>) { + return sol_lua_check_get(types<T>(), L, index, std::forward<Handler>(handler), tracking); + } + else { + qualified_check_getter<T> cg {}; + return cg.get(L, index, std::forward<Handler>(handler), tracking); + } + } + + template <typename T, typename Handler> + decltype(auto) check_get(lua_State* L, int index, Handler&& handler) { + record tracking {}; + return check_get<T>(L, index, handler, tracking); + } + + template <typename T> + decltype(auto) check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { + auto handler = &no_panic; + return check_get<T>(L, index, handler); + } + + namespace stack_detail { + + template <typename Handler> + bool check_types(lua_State*, int, Handler&&, record&) { + return true; + } + + template <typename T, typename... Args, typename Handler> + bool check_types(lua_State* L, int firstargument, Handler&& handler, record& tracking) { + if (!stack::check<T>(L, firstargument + tracking.used, handler, tracking)) + return false; + return check_types<Args...>(L, firstargument, std::forward<Handler>(handler), tracking); + } + + template <typename... Args, typename Handler> + bool check_types(types<Args...>, lua_State* L, int index, Handler&& handler, record& tracking) { + return check_types<Args...>(L, index, std::forward<Handler>(handler), tracking); + } + + } // namespace stack_detail + + template <typename... Args, typename Handler> + bool multi_check(lua_State* L, int index, Handler&& handler, record& tracking) { + return stack_detail::check_types<Args...>(L, index, std::forward<Handler>(handler), tracking); + } + + template <typename... Args, typename Handler> + bool multi_check(lua_State* L, int index, Handler&& handler) { + record tracking {}; + return multi_check<Args...>(L, index, std::forward<Handler>(handler), tracking); + } + + template <typename... Args> + bool multi_check(lua_State* L, int index) { + return multi_check<Args...>(L, index); + } + + template <typename T> + auto unqualified_get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_unqualified_get<T>(L, index, tracking)) { +#if SOL_IS_ON(SOL_SAFE_GETTER) + static constexpr bool is_op = meta::is_optional_v<T>; + if constexpr (is_op) { + return stack_detail::unchecked_unqualified_get<T>(L, index, tracking); + } + else { + if (is_lua_reference<T>::value) { + return stack_detail::unchecked_unqualified_get<T>(L, index, tracking); + } + auto op = unqualified_check_get<T>(L, index, type_panic_c_str, tracking); + return *std::move(op); + } +#else + return stack_detail::unchecked_unqualified_get<T>(L, index, tracking); +#endif + } + + template <typename T> + decltype(auto) unqualified_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { + record tracking {}; + return unqualified_get<T>(L, index, tracking); + } + + template <typename T> + auto get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get<T>(L, index, tracking)) { +#if SOL_IS_ON(SOL_SAFE_GETTER) + static constexpr bool is_op = meta::is_optional_v<T>; + if constexpr (is_op) { + return stack_detail::unchecked_get<T>(L, index, tracking); + } + else { + if (is_lua_reference<T>::value) { + return stack_detail::unchecked_get<T>(L, index, tracking); + } + auto op = check_get<T>(L, index, type_panic_c_str, tracking); + return *std::move(op); + } +#else + return stack_detail::unchecked_get<T>(L, index, tracking); +#endif + } + + template <typename T> + decltype(auto) get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { + record tracking {}; + return get<T>(L, index, tracking); + } + + template <typename T> + decltype(auto) get_usertype(lua_State* L, int index, record& tracking) { + using UT = meta::conditional_t<std::is_pointer<T>::value, detail::as_pointer_tag<std::remove_pointer_t<T>>, detail::as_value_tag<T>>; + return get<UT>(L, index, tracking); + } + + template <typename T> + decltype(auto) get_usertype(lua_State* L, int index = -lua_size_v<meta::unqualified_t<T>>) { + record tracking {}; + return get_usertype<T>(L, index, tracking); + } + + template <typename T> + decltype(auto) pop(lua_State* L) { + return popper<T> {}.pop(L); + } + + template <bool global = false, bool raw = false, typename Key> + void get_field(lua_State* L, Key&& key) { + field_getter<meta::unqualified_t<Key>, global, raw> {}.get(L, std::forward<Key>(key)); + } + + template <bool global = false, bool raw = false, typename Key> + void get_field(lua_State* L, Key&& key, int tableindex) { + field_getter<meta::unqualified_t<Key>, global, raw> {}.get(L, std::forward<Key>(key), tableindex); + } + + template <bool global = false, typename Key> + void raw_get_field(lua_State* L, Key&& key) { + get_field<global, true>(L, std::forward<Key>(key)); + } + + template <bool global = false, typename Key> + void raw_get_field(lua_State* L, Key&& key, int tableindex) { + get_field<global, true>(L, std::forward<Key>(key), tableindex); + } + + template <bool global = false, bool raw = false, typename C = detail::non_lua_nil_t, typename Key> + probe probe_get_field(lua_State* L, Key&& key) { + return probe_field_getter<meta::unqualified_t<Key>, C, global, raw> {}.get(L, std::forward<Key>(key)); + } + + template <bool global = false, bool raw = false, typename C = detail::non_lua_nil_t, typename Key> + probe probe_get_field(lua_State* L, Key&& key, int tableindex) { + return probe_field_getter<meta::unqualified_t<Key>, C, global, raw> {}.get(L, std::forward<Key>(key), tableindex); + } + + template <bool global = false, typename C = detail::non_lua_nil_t, typename Key> + probe probe_raw_get_field(lua_State* L, Key&& key) { + return probe_get_field<global, true, C>(L, std::forward<Key>(key)); + } + + template <bool global = false, typename C = detail::non_lua_nil_t, typename Key> + probe probe_raw_get_field(lua_State* L, Key&& key, int tableindex) { + return probe_get_field<global, true, C>(L, std::forward<Key>(key), tableindex); + } + + template <bool global = false, bool raw = false, typename Key, typename Value> + void set_field(lua_State* L, Key&& key, Value&& value) { + field_setter<meta::unqualified_t<Key>, global, raw> {}.set(L, std::forward<Key>(key), std::forward<Value>(value)); + } + + template <bool global = false, bool raw = false, typename Key, typename Value> + void set_field(lua_State* L, Key&& key, Value&& value, int tableindex) { + field_setter<meta::unqualified_t<Key>, global, raw> {}.set(L, std::forward<Key>(key), std::forward<Value>(value), tableindex); + } + + template <bool global = false, typename Key, typename Value> + void raw_set_field(lua_State* L, Key&& key, Value&& value) { + set_field<global, true>(L, std::forward<Key>(key), std::forward<Value>(value)); + } + + template <bool global = false, typename Key, typename Value> + void raw_set_field(lua_State* L, Key&& key, Value&& value, int tableindex) { + set_field<global, true>(L, std::forward<Key>(key), std::forward<Value>(value), tableindex); + } + + template <typename T, typename F> + void modify_unique_usertype_as(const stack_reference& obj, F&& f) { + void* raw = lua_touserdata(obj.lua_state(), obj.stack_index()); + void* ptr_memory = detail::align_usertype_pointer(raw); + void* uu_memory = detail::align_usertype_unique<T>(raw); + T& uu = *static_cast<T*>(uu_memory); + f(uu); + *static_cast<void**>(ptr_memory) = static_cast<void*>(detail::unique_get(obj.lua_state(), uu)); + } + + template <typename F> + void modify_unique_usertype(const stack_reference& obj, F&& f) { + using bt = meta::bind_traits<meta::unqualified_t<F>>; + using T = typename bt::template arg_at<0>; + using Tu = meta::unqualified_t<T>; + modify_unique_usertype_as<Tu>(obj, std::forward<F>(f)); + } + + namespace stack_detail { + template <typename T, typename Handler> + decltype(auto) check_get_arg(lua_State* L_, int index_, Handler&& handler_, record& tracking_) { + if constexpr (meta::meta_detail::is_adl_sol_lua_check_access_v<T>) { + sol_lua_check_access(types<meta::unqualified_t<T>>(), L_, index_, tracking_); + } + return check_get<T>(L_, index_, std::forward<Handler>(handler_), tracking_); + } + + template <typename T> + decltype(auto) unchecked_get_arg(lua_State* L_, int index_, record& tracking_) { + if constexpr (meta::meta_detail::is_adl_sol_lua_check_access_v<T>) { + sol_lua_check_access(types<meta::unqualified_t<T>>(), L_, index_, tracking_); + } + return unchecked_get<T>(L_, index_, tracking_); + } + } // namespace stack_detail + + } // namespace stack + + namespace detail { + + template <typename T> + lua_CFunction make_destructor(std::true_type) { + if constexpr (is_unique_usertype_v<T>) { + return &unique_destroy<T>; + } + else if constexpr (!std::is_pointer_v<T>) { + return &usertype_alloc_destroy<T>; + } + else { + return &cannot_destroy<T>; + } + } + + template <typename T> + lua_CFunction make_destructor(std::false_type) { + return &cannot_destroy<T>; + } + + template <typename T> + lua_CFunction make_destructor() { + return make_destructor<T>(std::is_destructible<T>()); + } + + struct no_comp { + template <typename A, typename B> + bool operator()(A&&, B&&) const { + return false; + } + }; + + template <typename T> + int is_check(lua_State* L) { + return stack::push(L, stack::check<T>(L, 1, &no_panic)); + } + + template <typename T> + int member_default_to_string(std::true_type, lua_State* L) { + decltype(auto) ts = stack::get<T>(L, 1).to_string(); + return stack::push(L, std::forward<decltype(ts)>(ts)); + } + + template <typename T> + int member_default_to_string(std::false_type, lua_State* L) { + return luaL_error(L, + "cannot perform to_string on '%s': no 'to_string' overload in namespace, 'to_string' member " + "function, or operator<<(ostream&, ...) present", + detail::demangle<T>().data()); + } + + template <typename T> + int adl_default_to_string(std::true_type, lua_State* L) { + using namespace std; + decltype(auto) ts = to_string(stack::get<T>(L, 1)); + return stack::push(L, std::forward<decltype(ts)>(ts)); + } + + template <typename T> + int adl_default_to_string(std::false_type, lua_State* L) { + return member_default_to_string<T>(meta::supports_to_string_member<T>(), L); + } + + template <typename T> + int oss_default_to_string(std::true_type, lua_State* L) { + std::ostringstream oss; + oss << stack::unqualified_get<T>(L, 1); + return stack::push(L, oss.str()); + } + + template <typename T> + int oss_default_to_string(std::false_type, lua_State* L) { + return adl_default_to_string<T>(meta::supports_adl_to_string<T>(), L); + } + + template <typename T> + int default_to_string(lua_State* L) { + return oss_default_to_string<T>(meta::supports_op_left_shift<std::ostream, T>(), L); + } + + template <typename T> + int default_size(lua_State* L) { + decltype(auto) self = stack::unqualified_get<T>(L, 1); + return stack::push(L, self.size()); + } + + template <typename T, typename Op> + int comparsion_operator_wrap(lua_State* L) { + if constexpr (std::is_void_v<T>) { + return stack::push(L, false); + } + else { + auto maybel = stack::unqualified_check_get<T>(L, 1); + if (!maybel) { + return stack::push(L, false); + } + auto mayber = stack::unqualified_check_get<T>(L, 2); + if (!mayber) { + return stack::push(L, false); + } + decltype(auto) l = *maybel; + decltype(auto) r = *mayber; + if constexpr (std::is_same_v<no_comp, Op>) { + std::equal_to<> op; + return stack::push(L, op(detail::ptr(l), detail::ptr(r))); + } + else { + if constexpr (std::is_same_v<std::equal_to<>, Op> // clang-format hack + || std::is_same_v<std::less_equal<>, Op> // + || std::is_same_v<std::less_equal<>, Op>) { // + if (detail::ptr(l) == detail::ptr(r)) { + return stack::push(L, true); + } + } + Op op; + return stack::push(L, op(detail::deref(l), detail::deref(r))); + } + } + } + + template <typename T, typename IFx, typename Fx> + void insert_default_registrations(IFx&& ifx, Fx&& fx); + + template <typename T, bool, bool> + struct get_is_primitive : is_lua_primitive<T> { }; + + template <typename T> + struct get_is_primitive<T, true, false> + : meta::neg<std::is_reference<decltype(sol_lua_get(types<T>(), nullptr, -1, std::declval<stack::record&>()))>> { }; + + template <typename T> + struct get_is_primitive<T, false, true> + : meta::neg<std::is_reference<decltype(sol_lua_get(types<meta::unqualified_t<T>>(), nullptr, -1, std::declval<stack::record&>()))>> { }; + + template <typename T> + struct get_is_primitive<T, true, true> : get_is_primitive<T, true, false> { }; + + } // namespace detail + + template <typename T> + struct is_proxy_primitive + : detail::get_is_primitive<T, meta::meta_detail::is_adl_sol_lua_get_v<T>, meta::meta_detail::is_adl_sol_lua_get_v<meta::unqualified_t<T>>> { }; + +} // namespace sol + +// end of sol/stack_core.hpp + +// beginning of sol/stack_check.hpp + +// beginning of sol/stack_check_unqualified.hpp + +#include <memory> +#include <functional> +#include <utility> +#include <cmath> +#include <optional> +#if SOL_IS_ON(SOL_STD_VARIANT) +#include <variant> +#endif // variant shenanigans + +namespace sol { namespace stack { + template <typename Handler> + bool loose_table_check(lua_State* L_, int index, Handler&& handler, record& tracking) { + tracking.use(1); + type t = type_of(L_, index); + if (t == type::table) { + return true; + } + if (t != type::userdata) { + handler(L_, index, type::table, t, "value is not a table or a userdata that can behave like one"); + return false; + } + return true; + } + + namespace stack_detail { + inline bool impl_check_metatable(lua_State* L_, int index, const std::string& metakey, bool poptable) { + luaL_getmetatable(L_, &metakey[0]); + const type expectedmetatabletype = static_cast<type>(lua_type(L_, -1)); + if (expectedmetatabletype != type::lua_nil) { + if (lua_rawequal(L_, -1, index) == 1) { + lua_pop(L_, 1 + static_cast<int>(poptable)); + return true; + } + } + lua_pop(L_, 1); + return false; + } + + template <typename T, bool poptable = true> + inline bool check_metatable(lua_State* L_, int index = -2) { + return impl_check_metatable(L_, index, usertype_traits<T>::metatable(), poptable); + } + + template <type expected, int (*check_func)(lua_State*, int)> + struct basic_check { + template <typename Handler> + static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) { + tracking.use(1); + bool success = check_func(L_, index) == 1; + if (!success) { + // expected type, actual type + handler(L_, index, expected, type_of(L_, index), ""); + } + return success; + } + }; + } // namespace stack_detail + + template <typename T, typename> + struct unqualified_interop_checker { + template <typename Handler> + static bool check(lua_State*, int, type, Handler&&, record&) { + return false; + } + }; + + template <typename T, typename> + struct qualified_interop_checker { + template <typename Handler> + static bool check(lua_State* L_, int index, type index_type, Handler&& handler, record& tracking) { + return stack_detail::unqualified_interop_check<T>(L_, index, index_type, std::forward<Handler>(handler), tracking); + } + }; + + template <typename T, type expected, typename> + struct unqualified_checker { + template <typename Handler> + static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) { + if constexpr (std::is_same_v<T, bool>) { + tracking.use(1); + bool success = lua_isboolean(L_, index) == 1; + if (!success) { + // expected type, actual type + handler(L_, index, expected, type_of(L_, index), ""); + } + return success; + } + else if constexpr (meta::any_same_v<T, + char +#if SOL_IS_ON(SOL_CHAR8_T) + , + char8_t +#endif + , + char16_t, + char32_t>) { + return stack::check<std::basic_string<T>>(L_, index, std::forward<Handler>(handler), tracking); + } + else if constexpr (std::is_integral_v<T> || std::is_same_v<T, lua_Integer>) { + tracking.use(1); +#if SOL_LUA_VERSION_I_ >= 503 + // Lua 5.3 and greater checks for numeric precision +#if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS) + // imprecise, sloppy conversions + int isnum = 0; + lua_tointegerx(L_, index, &isnum); + const bool success = isnum != 0; + if (!success) { + // expected type, actual type + handler(L_, index, type::number, type_of(L_, index), detail::not_a_number_or_number_string_integral); + } +#elif SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS) + // this check is precise, do not convert + if (lua_isinteger(L_, index) == 1) { + return true; + } + const bool success = false; + if (!success) { + // expected type, actual type + handler(L_, index, type::number, type_of(L_, index), detail::not_a_number_integral); + } +#else + // Numerics are neither safe nor string-convertible + type t = type_of(L_, index); + const bool success = t == type::number; +#endif + if (!success) { + // expected type, actual type + handler(L_, index, type::number, type_of(L_, index), detail::not_a_number); + } + return success; +#else + // Lua 5.2 and below checks +#if SOL_IS_OFF(SOL_STRINGS_ARE_NUMBERS) + // must pre-check, because it will convert + type t = type_of(L_, index); + if (t != type::number) { + // expected type, actual type + handler(L_, index, type::number, t, detail::not_a_number); + return false; + } +#endif // Do not allow strings to be numbers + +#if SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS) + int isnum = 0; + const lua_Number v = lua_tonumberx(L_, index, &isnum); + const bool success = isnum != 0 && static_cast<lua_Number>(llround(v)) == v; +#else + const bool success = true; +#endif // Safe numerics and number precision checking + if (!success) { + // Use defines to provide a better error message! +#if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS) + handler(L_, index, type::number, type_of(L_, index), detail::not_a_number_or_number_string); +#elif SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS) + handler(L_, index, type::number, t, detail::not_a_number_or_number_string); +#else + handler(L_, index, type::number, t, detail::not_a_number); +#endif + } + return success; +#endif + } + else if constexpr (std::is_floating_point_v<T> || std::is_same_v<T, lua_Number>) { + tracking.use(1); +#if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS) + bool success = lua_isnumber(L_, index) == 1; + if (!success) { + // expected type, actual type + handler(L_, index, type::number, type_of(L_, index), detail::not_a_number_or_number_string); + } + return success; +#else + type t = type_of(L_, index); + bool success = t == type::number; + if (!success) { + // expected type, actual type + handler(L_, index, type::number, t, detail::not_a_number); + } + return success; +#endif // Strings are Numbers + } + else if constexpr (meta::any_same_v<T, type, this_state, this_main_state, this_environment, variadic_args>) { + (void)L_; + (void)index; + (void)handler; + tracking.use(0); + return true; + } + else if constexpr (is_unique_usertype_v<T>) { + using element = unique_usertype_element_t<T>; + using actual = unique_usertype_actual_t<T>; + const type indextype = type_of(L_, index); + tracking.use(1); + if (indextype != type::userdata) { + handler(L_, index, type::userdata, indextype, "value is not a userdata"); + return false; + } + if (lua_getmetatable(L_, index) == 0) { + return true; + } + int metatableindex = lua_gettop(L_); + if (stack_detail::check_metatable<d::u<element>>(L_, metatableindex)) { + void* memory = lua_touserdata(L_, index); + memory = detail::align_usertype_unique_destructor(memory); + detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory); + bool success = &detail::usertype_unique_alloc_destroy<element, actual> == pdx; + if (!success) { + memory = detail::align_usertype_unique_tag<true>(memory); +#if 0 + // New version, one day +#else + const char*& name_tag = *static_cast<const char**>(memory); + success = usertype_traits<T>::qualified_name() == name_tag; +#endif + if (!success) { + handler(L_, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype"); + } + } + return success; + } + lua_pop(L_, 1); + handler(L_, index, type::userdata, indextype, "unrecognized userdata (not pushed by sol?)"); + return false; + } + else if constexpr (meta::any_same_v<T, lua_nil_t, std::nullopt_t, nullopt_t>) { + bool success = lua_isnil(L_, index); + if (success) { + tracking.use(1); + return success; + } + tracking.use(0); + success = lua_isnone(L_, index); + if (!success) { + // expected type, actual type + handler(L_, index, expected, type_of(L_, index), ""); + } + return success; + } + else if constexpr (std::is_same_v<T, env_key_t>) { + tracking.use(1); + type t = type_of(L_, index); + if (t == type::table || t == type::none || t == type::lua_nil || t == type::userdata) { + return true; + } + handler(L_, index, type::table, t, "value cannot not have a valid environment"); + return true; + } + else if constexpr (std::is_same_v<T, detail::non_lua_nil_t>) { + return !stack::unqualified_check<lua_nil_t>(L_, index, std::forward<Handler>(handler), tracking); + } + else if constexpr (meta::is_specialization_of_v<T, basic_lua_table>) { + tracking.use(1); + type t = type_of(L_, index); + if (t != type::table) { + handler(L_, index, type::table, t, "value is not a table"); + return false; + } + return true; + } + else if constexpr (meta::is_specialization_of_v<T, basic_bytecode>) { + tracking.use(1); + type t = type_of(L_, index); + if (t != type::function) { + handler(L_, index, type::function, t, "value is not a function that can be dumped"); + return false; + } + return true; + } + else if constexpr (meta::is_specialization_of_v<T, basic_environment>) { + tracking.use(1); + if (lua_getmetatable(L_, index) == 0) { + return true; + } + type t = type_of(L_, -1); + if (t == type::table || t == type::none || t == type::lua_nil) { + lua_pop(L_, 1); + return true; + } + if (t != type::userdata) { + lua_pop(L_, 1); + handler(L_, index, type::table, t, "value does not have a valid metatable"); + return false; + } + return true; + } + else if constexpr (std::is_same_v<T, metatable_key_t>) { + tracking.use(1); + if (lua_getmetatable(L_, index) == 0) { + return true; + } + type t = type_of(L_, -1); + if (t == type::table || t == type::none || t == type::lua_nil) { + lua_pop(L_, 1); + return true; + } + if (t != type::userdata) { + lua_pop(L_, 1); + handler(L_, index, expected, t, "value does not have a valid metatable"); + return false; + } + return true; + } + else if constexpr (std::is_same_v<T, luaL_Stream*> || std::is_same_v<T, luaL_Stream>) { + if (lua_getmetatable(L_, index) == 0) { + type t = type_of(L_, index); + handler(L_, index, expected, t, "value is not a valid luaL_Stream (has no metatable/is not a valid value)"); + return false; + } + luaL_getmetatable(L_, LUA_FILEHANDLE); + if (type_of(L_, index) != type::table) { + type t = type_of(L_, index); + lua_pop(L_, 1); + handler(L_, + index, + expected, + t, + "value is not a valid luaL_Stream (there is no metatable for luaL_Stream -- did you forget to " + "my_lua_state.open_libraries(sol::lib::state) or equivalent?)"); + return false; + } + int is_stream_table = lua_compare(L_, -1, -2, LUA_OPEQ); + lua_pop(L_, 2); + if (is_stream_table == 0) { + type t = type_of(L_, index); + handler(L_, index, expected, t, "value is not a valid luaL_Stream (incorrect metatable)"); + return false; + } + return true; + } + else if constexpr (meta::is_optional_v<T>) { + using ValueType = typename T::value_type; + (void)handler; + type t = type_of(L_, index); + if (t == type::none) { + tracking.use(0); + return true; + } + if (t == type::lua_nil) { + tracking.use(1); + return true; + } + return stack::unqualified_check<ValueType>(L_, index, &no_panic, tracking); + } +#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE) + else if constexpr (std::is_function_v<T> || (std::is_pointer_v<T> && std::is_function_v<std::remove_pointer_t<T>>)) { + return stack_detail::check_function_pointer<std::remove_pointer_t<T>>(L_, index, std::forward<Handler>(handler), tracking); + } +#endif + else if constexpr (expected == type::userdata) { + if constexpr (meta::any_same_v<T, userdata_value> || meta::is_specialization_of_v<T, basic_userdata>) { + tracking.use(1); + type t = type_of(L_, index); + bool success = t == type::userdata; + if (!success) { + // expected type, actual type + handler(L_, index, type::userdata, t, ""); + } + return success; + } + else if constexpr (meta::is_specialization_of_v<T, user>) { + unqualified_checker<lightuserdata_value, type::userdata> c; + (void)c; + return c.check(L_, index, std::forward<Handler>(handler), tracking); + } + else { + if constexpr (std::is_pointer_v<T>) { + return check_usertype<T>(L_, index, std::forward<Handler>(handler), tracking); + } + else if constexpr (meta::is_specialization_of_v<T, std::reference_wrapper>) { + using T_internal = typename T::type; + return stack::check<T_internal>(L_, index, std::forward<Handler>(handler), tracking); + } + else { + return check_usertype<T>(L_, index, std::forward<Handler>(handler), tracking); + } + } + } + else if constexpr (expected == type::poly) { + tracking.use(1); + bool success = is_lua_reference_v<T> || !lua_isnone(L_, index); + if (!success) { + // expected type, actual type + handler(L_, index, type::poly, type_of(L_, index), ""); + } + return success; + } + else if constexpr (expected == type::lightuserdata) { + tracking.use(1); + type t = type_of(L_, index); + bool success = t == type::userdata || t == type::lightuserdata; + if (!success) { + // expected type, actual type + handler(L_, index, type::lightuserdata, t, ""); + } + return success; + } + else if constexpr (expected == type::function) { + if constexpr (meta::any_same_v<T, lua_CFunction, std::remove_pointer_t<lua_CFunction>, c_closure>) { + tracking.use(1); + bool success = lua_iscfunction(L_, index) == 1; + if (!success) { + // expected type, actual type + handler(L_, index, expected, type_of(L_, index), ""); + } + return success; + } + else { + tracking.use(1); + type t = type_of(L_, index); + if (t == type::lua_nil || t == type::none || t == type::function) { + // allow for lua_nil to be returned + return true; + } + if (t != type::userdata && t != type::table) { + handler(L_, index, type::function, t, "must be a function or table or a userdata"); + return false; + } + // Do advanced check for call-style userdata? + static const auto& callkey = to_string(meta_function::call); + if (lua_getmetatable(L_, index) == 0) { + // No metatable, no __call key possible + handler(L_, index, type::function, t, "value is not a function and does not have overriden metatable"); + return false; + } + if (lua_isnoneornil(L_, -1)) { + lua_pop(L_, 1); + handler(L_, index, type::function, t, "value is not a function and does not have valid metatable"); + return false; + } + lua_getfield(L_, -1, &callkey[0]); + if (lua_isnoneornil(L_, -1)) { + lua_pop(L_, 2); + handler(L_, index, type::function, t, "value's metatable does not have __call overridden in metatable, cannot call this type"); + return false; + } + // has call, is definitely a function + lua_pop(L_, 2); + return true; + } + } + else if constexpr (expected == type::table) { + return stack::loose_table_check(L_, index, std::forward<Handler>(handler), tracking); + } + else { + tracking.use(1); + const type indextype = type_of(L_, index); + bool success = expected == indextype; + if (!success) { + // expected type, actual type, message + handler(L_, index, expected, indextype, ""); + } + return success; + } + } + }; + + template <typename T> + struct unqualified_checker<non_null<T>, type::userdata> : unqualified_checker<T, lua_type_of_v<T>> { }; + + template <typename T> + struct unqualified_checker<detail::as_value_tag<T>, type::userdata> { + template <typename Handler> + static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) { + const type indextype = type_of(L_, index); + return check(types<T>(), L_, index, indextype, std::forward<Handler>(handler), tracking); + } + + template <typename U, typename Handler> + static bool check(types<U>, lua_State* L_, int index, type indextype, Handler&& handler, record& tracking) { + if constexpr ( + std::is_same_v<T, + lightuserdata_value> || std::is_same_v<T, userdata_value> || std::is_same_v<T, userdata> || std::is_same_v<T, lightuserdata>) { + tracking.use(1); + if (indextype != type::userdata) { + handler(L_, index, type::userdata, indextype, "value is not a valid userdata"); + return false; + } + return true; + } + else { +#if SOL_IS_ON(SOL_USE_INTEROP) + if (stack_detail::interop_check<U>(L_, index, indextype, handler, tracking)) { + return true; + } +#endif // interop extensibility + tracking.use(1); +#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE) + if (lua_iscfunction(L_, index) != 0) { + // a potential match... + return true; + } +#endif + if (indextype != type::userdata) { + handler(L_, index, type::userdata, indextype, "value is not a valid userdata"); + return false; + } + if (lua_getmetatable(L_, index) == 0) { + return true; + } + int metatableindex = lua_gettop(L_); + if (stack_detail::check_metatable<U>(L_, metatableindex)) + return true; + if (stack_detail::check_metatable<U*>(L_, metatableindex)) + return true; + if (stack_detail::check_metatable<d::u<U>>(L_, metatableindex)) + return true; + if (stack_detail::check_metatable<as_container_t<U>>(L_, metatableindex)) + return true; + bool success = false; + bool has_derived = derive<T>::value || weak_derive<T>::value; + if (has_derived) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L_, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + auto pn = stack::pop_n(L_, 1); + lua_pushstring(L_, &detail::base_class_check_key()[0]); + lua_rawget(L_, metatableindex); + if (type_of(L_, -1) != type::lua_nil) { + void* basecastdata = lua_touserdata(L_, -1); + detail::inheritance_check_function ic = reinterpret_cast<detail::inheritance_check_function>(basecastdata); + success = ic(usertype_traits<T>::qualified_name()); + } + } + lua_pop(L_, 1); + if (!success) { + handler(L_, index, type::userdata, indextype, "value at this index does not properly reflect the desired type"); + return false; + } + return true; + } + } + }; + + template <typename T> + struct unqualified_checker<detail::as_pointer_tag<T>, type::userdata> { + template <typename Handler> + static bool check(lua_State* L_, int index, type indextype, Handler&& handler, record& tracking) { + if (indextype == type::lua_nil) { + tracking.use(1); + return true; + } + return check_usertype<std::remove_pointer_t<T>>(L_, index, std::forward<Handler>(handler), tracking); + } + + template <typename Handler> + static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) { + const type indextype = type_of(L_, index); + return check(L_, index, indextype, std::forward<Handler>(handler), tracking); + } + }; + + template <typename T, std::size_t N, type expect> + struct unqualified_checker<exhaustive_until<T, N>, expect> { + template <typename K, typename V, typename Handler> + static bool check_two(types<K, V>, lua_State* arg_L, int relindex, type, Handler&& handler, record& tracking) { + tracking.use(1); + +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(arg_L, 3, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + + int index = lua_absindex(arg_L, relindex); + lua_pushnil(arg_L); + while (lua_next(arg_L, index) != 0) { + const bool is_key_okay = stack::check<K>(arg_L, -2, std::forward<Handler>(handler), tracking); + if (!is_key_okay) { + lua_pop(arg_L, 2); + return false; + } + const bool is_value_okay = stack::check<V>(arg_L, -1, std::forward<Handler>(handler), tracking); + if (!is_value_okay) { + lua_pop(arg_L, 2); + return false; + } + lua_pop(arg_L, 1); + } + return true; + } + + template <typename V, typename Handler> + static bool check_one(types<V>, lua_State* arg_L, int relindex, type, Handler&& handler, record& tracking) { + tracking.use(1); + + size_t index = lua_absindex(arg_L, relindex); + // Zzzz slower but necessary thanks to the lower version API and missing functions qq + std::size_t idx = 0; + int vi = 0; + for (lua_Integer i = 0;; (void)(i += lua_size<V>::value), lua_pop(arg_L, static_cast<int>(vi))) { + vi = 0; + if (idx >= N) { + return true; + } +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(arg_L, 2, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + bool isnil = false; + for (; vi < static_cast<int>(lua_size<V>::value); ++vi) { + lua_pushinteger(arg_L, i); + lua_gettable(arg_L, static_cast<int>(index)); + type vt = type_of(arg_L, -1); + isnil = vt == type::lua_nil; + if (isnil) { + if (i == 0) { + vi += 1; + goto loop_continue; + } + lua_pop(arg_L, static_cast<int>(vi + 1)); + return true; + } + } + if (!stack::check<V>(arg_L, -lua_size<V>::value, std::forward<Handler>(handler), tracking)) { + lua_pop(arg_L, lua_size<V>::value); + return false; + } + ++idx; + loop_continue:; + } + } + + template <typename Handler> + static bool check(lua_State* arg_L, int index, Handler&& handler, record& tracking) { + using Tu = meta::unqualified_t<T>; + if constexpr (is_container_v<Tu>) { + if constexpr (meta::is_associative<Tu>::value) { + typedef typename Tu::value_type P; + typedef typename P::first_type K; + typedef typename P::second_type V; + return check_two(types<K, V>(), arg_L, index, expect, std::forward<Handler>(handler), tracking); + } + else { + typedef typename Tu::value_type V; + return check_one(types<V>(), arg_L, index, expect, std::forward<Handler>(handler), tracking); + } + } + else { + unqualified_checker<Tu, expect> c {}; + return c.check(arg_L, index, std::forward<Handler>(handler), tracking); + } + } + }; + + template <typename T, type expect> + struct unqualified_checker<non_exhaustive<T>, expect> { + template <typename Handler> + static bool check(lua_State* arg_L, int index, Handler&& handler, record& tracking) { + return stack::check<T>(arg_L, index, std::forward<Handler>(handler), tracking); + } + }; + + template <typename... Args> + struct unqualified_checker<std::tuple<Args...>, type::poly> { + template <typename Handler> + static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) { + return stack::multi_check<Args...>(L_, index, std::forward<Handler>(handler), tracking); + } + }; + + template <typename A, typename B> + struct unqualified_checker<std::pair<A, B>, type::poly> { + template <typename Handler> + static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) { + return stack::multi_check<A, B>(L_, index, std::forward<Handler>(handler), tracking); + } + }; + +#if SOL_IS_ON(SOL_STD_VARIANT) + + template <typename... Tn> + struct unqualified_checker<std::variant<Tn...>, type::poly> { + typedef std::variant<Tn...> V; + typedef std::variant_size<V> V_size; + typedef std::integral_constant<bool, V_size::value == 0> V_is_empty; + + template <typename Handler> + static bool is_one(std::integral_constant<std::size_t, 0>, lua_State* L_, int index, Handler&& handler, record& tracking) { + if constexpr (V_is_empty::value) { + if (lua_isnone(L_, index)) { + return true; + } + } + tracking.use(1); + handler(L_, index, type::poly, type_of(L_, index), "value does not fit any type present in the variant"); + return false; + } + + template <std::size_t I, typename Handler> + static bool is_one(std::integral_constant<std::size_t, I>, lua_State* L_, int index, Handler&& handler, record& tracking) { + typedef std::variant_alternative_t<I - 1, V> T; + record temp_tracking = tracking; + if (stack::check<T>(L_, index, &no_panic, temp_tracking)) { + tracking = temp_tracking; + return true; + } + return is_one(std::integral_constant<std::size_t, I - 1>(), L_, index, std::forward<Handler>(handler), tracking); + } + + template <typename Handler> + static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) { + return is_one(std::integral_constant<std::size_t, V_size::value>(), L_, index, std::forward<Handler>(handler), tracking); + } + }; + +#endif // variant shenanigans + +}} // namespace sol::stack + +// end of sol/stack_check_unqualified.hpp + +// beginning of sol/stack_check_qualified.hpp + +namespace sol { namespace stack { + + template <typename X, type expected, typename> + struct qualified_checker { + template <typename Handler> + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + using no_cv_X = meta::unqualified_t<X>; + if constexpr (!std::is_reference_v<X> && is_unique_usertype_v<no_cv_X>) { + using element = unique_usertype_element_t<no_cv_X>; + if constexpr (is_actual_type_rebindable_for_v<no_cv_X>) { + using rebound_actual_type = unique_usertype_rebind_actual_t<no_cv_X>; + // we have a unique pointer type that can be + // rebound to a base/derived type + const type indextype = type_of(L, index); + tracking.use(1); + if (indextype != type::userdata) { + handler(L, index, type::userdata, indextype, "value is not a userdata"); + return false; + } + void* memory = lua_touserdata(L, index); + memory = detail::align_usertype_unique_destructor(memory); + detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory); + if (&detail::usertype_unique_alloc_destroy<element, no_cv_X> == pdx) { + return true; + } + if constexpr (derive<element>::value) { + memory = detail::align_usertype_unique_tag<true, false>(memory); + detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory); + string_view ti = usertype_traits<element>::qualified_name(); + string_view rebind_ti = usertype_traits<rebound_actual_type>::qualified_name(); + if (ic(nullptr, nullptr, ti, rebind_ti) != 0) { + return true; + } + } + handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype"); + return false; + } + else { + return stack::unqualified_check<X>(L, index, std::forward<Handler>(handler), tracking); + } + } + else if constexpr (!std::is_reference_v<X> && is_container_v<no_cv_X>) { + if (type_of(L, index) == type::userdata) { + return stack::unqualified_check<X>(L, index, std::forward<Handler>(handler), tracking); + } + else { + return stack::unqualified_check<nested<X>>(L, index, std::forward<Handler>(handler), tracking); + } + } + else if constexpr (!std::is_reference_v<X> && meta::is_specialization_of_v<X, nested>) { + using NestedX = typename meta::unqualified_t<X>::nested_type; + return stack::check<NestedX>(L, index, ::std::forward<Handler>(handler), tracking); + } + else { + return stack::unqualified_check<X>(L, index, std::forward<Handler>(handler), tracking); + } + } + }; +}} // namespace sol::stack + +// end of sol/stack_check_qualified.hpp + +// end of sol/stack_check.hpp + +// beginning of sol/stack_get.hpp + +// beginning of sol/stack_get_unqualified.hpp + +// beginning of sol/overload.hpp + +#include <utility> + +namespace sol { + template <typename... Functions> + struct overload_set { + std::tuple<Functions...> functions; + template <typename Arg, typename... Args, meta::disable<std::is_same<overload_set, meta::unqualified_t<Arg>>> = meta::enabler> + overload_set(Arg&& arg, Args&&... args) : functions(std::forward<Arg>(arg), std::forward<Args>(args)...) { + } + overload_set(const overload_set&) = default; + overload_set(overload_set&&) = default; + overload_set& operator=(const overload_set&) = default; + overload_set& operator=(overload_set&&) = default; + }; + + template <typename... Args> + decltype(auto) overload(Args&&... args) { + return overload_set<std::decay_t<Args>...>(std::forward<Args>(args)...); + } +} // namespace sol + +// end of sol/overload.hpp + +// beginning of sol/unicode.hpp + +#include <array> +#include <cstring> + +namespace sol { + // Everything here was lifted pretty much straight out of + // ogonek, because fuck figuring it out= + namespace unicode { + enum class error_code { + ok = 0, + invalid_code_point, + invalid_code_unit, + invalid_leading_surrogate, + invalid_trailing_surrogate, + sequence_too_short, + overlong_sequence, + }; + + inline const string_view& to_string(error_code ec) { + static const string_view storage[7] = { "ok", + "invalid code points", + "invalid code unit", + "invalid leading surrogate", + "invalid trailing surrogate", + "sequence too short", + "overlong sequence" }; + return storage[static_cast<std::size_t>(ec)]; + } + + template <typename It> + struct decoded_result { + error_code error; + char32_t codepoint; + It next; + }; + + template <typename C> + struct encoded_result { + error_code error; + std::size_t code_units_size; + std::array<C, 4> code_units; + }; + + struct unicode_detail { + // codepoint related + static constexpr char32_t last_code_point = 0x10FFFF; + + static constexpr char32_t first_lead_surrogate = 0xD800; + static constexpr char32_t last_lead_surrogate = 0xDBFF; + + static constexpr char32_t first_trail_surrogate = 0xDC00; + static constexpr char32_t last_trail_surrogate = 0xDFFF; + + static constexpr char32_t first_surrogate = first_lead_surrogate; + static constexpr char32_t last_surrogate = last_trail_surrogate; + + static constexpr bool is_lead_surrogate(char32_t u) { + return u >= first_lead_surrogate && u <= last_lead_surrogate; + } + static constexpr bool is_trail_surrogate(char32_t u) { + return u >= first_trail_surrogate && u <= last_trail_surrogate; + } + static constexpr bool is_surrogate(char32_t u) { + return u >= first_surrogate && u <= last_surrogate; + } + + // utf8 related + static constexpr auto last_1byte_value = 0x7Fu; + static constexpr auto last_2byte_value = 0x7FFu; + static constexpr auto last_3byte_value = 0xFFFFu; + + static constexpr auto start_2byte_mask = 0x80u; + static constexpr auto start_3byte_mask = 0xE0u; + static constexpr auto start_4byte_mask = 0xF0u; + + static constexpr auto continuation_mask = 0xC0u; + static constexpr auto continuation_signature = 0x80u; + + static constexpr bool is_invalid(unsigned char b) { + return b == 0xC0 || b == 0xC1 || b > 0xF4; + } + + static constexpr bool is_continuation(unsigned char b) { + return (b & unicode_detail::continuation_mask) == unicode_detail::continuation_signature; + } + + static constexpr bool is_overlong(char32_t u, std::size_t bytes) { + return u <= unicode_detail::last_1byte_value || (u <= unicode_detail::last_2byte_value && bytes > 2) + || (u <= unicode_detail::last_3byte_value && bytes > 3); + } + + static constexpr int sequence_length(unsigned char b) { + return (b & start_2byte_mask) == 0 ? 1 + : (b & start_3byte_mask) != start_3byte_mask ? 2 + : (b & start_4byte_mask) != start_4byte_mask ? 3 + : 4; + } + + static constexpr char32_t decode(unsigned char b0, unsigned char b1) { + return (static_cast<char32_t>((b0 & 0x1Fu) << 6u) | static_cast<char32_t>(b1 & 0x3Fu)); + } + static constexpr char32_t decode(unsigned char b0, unsigned char b1, unsigned char b2) { + return static_cast<char32_t>((b0 & 0x0Fu) << 12u) | static_cast<char32_t>((b1 & 0x3Fu) << 6u) | static_cast<char32_t>(b2 & 0x3Fu); + } + static constexpr char32_t decode(unsigned char b0, unsigned char b1, unsigned char b2, unsigned char b3) { + return static_cast<char32_t>(static_cast<char32_t>((b0 & 0x07u) << 18u) | static_cast<char32_t>((b1 & 0x3F) << 12) + | static_cast<char32_t>((b2 & 0x3Fu) << 6u) | static_cast<char32_t>(b3 & 0x3Fu)); + } + + // utf16 related + static constexpr char32_t last_bmp_value = 0xFFFF; + static constexpr char32_t normalizing_value = 0x10000; + static constexpr int lead_surrogate_bitmask = 0xFFC00; + static constexpr int trail_surrogate_bitmask = 0x3FF; + static constexpr int lead_shifted_bits = 10; + static constexpr char32_t replacement = 0xFFFD; + + static char32_t combine_surrogates(char16_t lead, char16_t trail) { + auto hi = lead - first_lead_surrogate; + auto lo = trail - first_trail_surrogate; + return normalizing_value + ((hi << lead_shifted_bits) | lo); + } + }; + + inline encoded_result<char> code_point_to_utf8(char32_t codepoint) { + encoded_result<char> er; + er.error = error_code::ok; + if (codepoint <= unicode_detail::last_1byte_value) { + er.code_units_size = 1; + er.code_units = std::array<char, 4> { { static_cast<char>(codepoint) } }; + } + else if (codepoint <= unicode_detail::last_2byte_value) { + er.code_units_size = 2; + er.code_units = std::array<char, 4> { { + static_cast<char>(0xC0 | ((codepoint & 0x7C0) >> 6)), + static_cast<char>(0x80 | (codepoint & 0x3F)), + } }; + } + else if (codepoint <= unicode_detail::last_3byte_value) { + er.code_units_size = 3; + er.code_units = std::array<char, 4> { { + static_cast<char>(0xE0 | ((codepoint & 0xF000) >> 12)), + static_cast<char>(0x80 | ((codepoint & 0xFC0) >> 6)), + static_cast<char>(0x80 | (codepoint & 0x3F)), + } }; + } + else { + er.code_units_size = 4; + er.code_units = std::array<char, 4> { { + static_cast<char>(0xF0 | ((codepoint & 0x1C0000) >> 18)), + static_cast<char>(0x80 | ((codepoint & 0x3F000) >> 12)), + static_cast<char>(0x80 | ((codepoint & 0xFC0) >> 6)), + static_cast<char>(0x80 | (codepoint & 0x3F)), + } }; + } + return er; + } + + inline encoded_result<char16_t> code_point_to_utf16(char32_t codepoint) { + encoded_result<char16_t> er; + + if (codepoint <= unicode_detail::last_bmp_value) { + er.code_units_size = 1; + er.code_units = std::array<char16_t, 4> { { static_cast<char16_t>(codepoint) } }; + er.error = error_code::ok; + } + else { + auto normal = codepoint - unicode_detail::normalizing_value; + auto lead = unicode_detail::first_lead_surrogate + ((normal & unicode_detail::lead_surrogate_bitmask) >> unicode_detail::lead_shifted_bits); + auto trail = unicode_detail::first_trail_surrogate + (normal & unicode_detail::trail_surrogate_bitmask); + er.code_units = std::array<char16_t, 4> { { static_cast<char16_t>(lead), static_cast<char16_t>(trail) } }; + er.code_units_size = 2; + er.error = error_code::ok; + } + return er; + } + + inline encoded_result<char32_t> code_point_to_utf32(char32_t codepoint) { + encoded_result<char32_t> er; + er.code_units_size = 1; + er.code_units[0] = codepoint; + er.error = error_code::ok; + return er; + } + + template <typename It> + inline decoded_result<It> utf8_to_code_point(It it, It last) { + decoded_result<It> dr; + if (it == last) { + dr.next = it; + dr.error = error_code::sequence_too_short; + return dr; + } + + unsigned char b0 = static_cast<unsigned char>(*it); + std::size_t length = static_cast<std::size_t>(unicode_detail::sequence_length(b0)); + + if (length == 1) { + dr.codepoint = static_cast<char32_t>(b0); + dr.error = error_code::ok; + ++it; + dr.next = it; + return dr; + } + + if (unicode_detail::is_invalid(b0) || unicode_detail::is_continuation(b0)) { + dr.error = error_code::invalid_code_unit; + dr.next = it; + return dr; + } + + ++it; + std::array<unsigned char, 4> b; + b[0] = b0; + for (std::size_t i = 1; i < length; ++i) { + b[i] = static_cast<unsigned char>(*it); + if (!unicode_detail::is_continuation(b[i])) { + dr.error = error_code::invalid_code_unit; + dr.next = it; + return dr; + } + ++it; + } + + char32_t decoded; + switch (length) { + case 2: + decoded = unicode_detail::decode(b[0], b[1]); + break; + case 3: + decoded = unicode_detail::decode(b[0], b[1], b[2]); + break; + default: + decoded = unicode_detail::decode(b[0], b[1], b[2], b[3]); + break; + } + + if (unicode_detail::is_overlong(decoded, length)) { + dr.error = error_code::overlong_sequence; + return dr; + } + if (unicode_detail::is_surrogate(decoded) || decoded > unicode_detail::last_code_point) { + dr.error = error_code::invalid_code_point; + return dr; + } + + // then everything is fine + dr.codepoint = decoded; + dr.error = error_code::ok; + dr.next = it; + return dr; + } + + template <typename It> + inline decoded_result<It> utf16_to_code_point(It it, It last) { + decoded_result<It> dr; + if (it == last) { + dr.next = it; + dr.error = error_code::sequence_too_short; + return dr; + } + + char16_t lead = static_cast<char16_t>(*it); + + if (!unicode_detail::is_surrogate(lead)) { + ++it; + dr.codepoint = static_cast<char32_t>(lead); + dr.next = it; + dr.error = error_code::ok; + return dr; + } + if (!unicode_detail::is_lead_surrogate(lead)) { + dr.error = error_code::invalid_leading_surrogate; + dr.next = it; + return dr; + } + + ++it; + auto trail = *it; + if (!unicode_detail::is_trail_surrogate(trail)) { + dr.error = error_code::invalid_trailing_surrogate; + dr.next = it; + return dr; + } + + dr.codepoint = unicode_detail::combine_surrogates(lead, trail); + dr.next = ++it; + dr.error = error_code::ok; + return dr; + } + + template <typename It> + inline decoded_result<It> utf32_to_code_point(It it, It last) { + decoded_result<It> dr; + if (it == last) { + dr.next = it; + dr.error = error_code::sequence_too_short; + return dr; + } + dr.codepoint = static_cast<char32_t>(*it); + dr.next = ++it; + dr.error = error_code::ok; + return dr; + } + } // namespace unicode +} // namespace sol +// end of sol/unicode.hpp + +// beginning of sol/abort.hpp + +#include <cstdlib> + +#if SOL_IS_ON(SOL_DEBUG_BUILD) + #if SOL_IS_ON(SOL_COMPILER_VCXX) + #define SOL_DEBUG_ABORT() \ + if (true) { ::std::abort(); } \ + static_assert(true, "") + #else + #define SOL_DEBUG_ABORT() ::std::abort() + #endif +#else + #define SOL_DEBUG_ABORT() static_assert(true, "") +#endif + +// end of sol/abort.hpp + +#include <memory> +#include <functional> +#include <utility> +#include <cstdlib> +#include <cmath> +#include <string_view> +#if SOL_IS_ON(SOL_STD_VARIANT) +#include <variant> +#endif // Apple clang screwed up + +namespace sol { namespace stack { + + namespace stack_detail { + template <typename Ch> + struct count_code_units_utf { + std::size_t needed_size; + + count_code_units_utf() : needed_size(0) { + } + + void operator()(const unicode::encoded_result<Ch> er) { + needed_size += er.code_units_size; + } + }; + + template <typename Ch, typename ErCh> + struct copy_code_units_utf { + Ch* target_; + + copy_code_units_utf(Ch* target) : target_(target) { + } + + void operator()(const unicode::encoded_result<ErCh> er) { + std::memcpy(target_, er.code_units.data(), er.code_units_size * sizeof(ErCh)); + target_ += er.code_units_size; + } + }; + + template <typename Ch, typename F> + inline void convert(const char* strb, const char* stre, F&& f) { + char32_t cp = 0; + for (const char* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf8_to_code_point(strtarget, stre); + if (dr.error != unicode::error_code::ok) { + cp = unicode::unicode_detail::replacement; + ++strtarget; + } + else { + cp = dr.codepoint; + strtarget = dr.next; + } + if constexpr (std::is_same_v<Ch, char32_t>) { + auto er = unicode::code_point_to_utf32(cp); + f(er); + } + else { + auto er = unicode::code_point_to_utf16(cp); + f(er); + } + } + } + + template <typename BaseCh, typename S> + inline S get_into(lua_State* L, int index, record& tracking) { + using Ch = typename S::value_type; + tracking.use(1); + size_t len; + auto utf8p = lua_tolstring(L, index, &len); + if (len < 1) + return S(); + const char* strb = utf8p; + const char* stre = utf8p + len; + stack_detail::count_code_units_utf<BaseCh> count_units; + convert<BaseCh>(strb, stre, count_units); + S r(count_units.needed_size, static_cast<Ch>(0)); + r.resize(count_units.needed_size); + Ch* target = &r[0]; + stack_detail::copy_code_units_utf<Ch, BaseCh> copy_units(target); + convert<BaseCh>(strb, stre, copy_units); + return r; + } + } // namespace stack_detail + + template <typename T, typename> + struct unqualified_getter { + static decltype(auto) get(lua_State* L, int index, record& tracking) { + if constexpr (std::is_same_v<T, bool>) { + tracking.use(1); + return lua_toboolean(L, index) != 0; + } + else if constexpr (std::is_enum_v<T>) { + tracking.use(1); + return static_cast<T>(lua_tointegerx(L, index, nullptr)); + } + else if constexpr (std::is_integral_v<T> || std::is_same_v<T, lua_Integer>) { + tracking.use(1); +#if SOL_LUA_VERSION_I_ >= 503 + if (lua_isinteger(L, index) != 0) { + return static_cast<T>(lua_tointeger(L, index)); + } +#endif + return static_cast<T>(llround(lua_tonumber(L, index))); + } + else if constexpr (std::is_floating_point_v<T> || std::is_same_v<T, lua_Number>) { + tracking.use(1); + return static_cast<T>(lua_tonumber(L, index)); + } + else if constexpr (is_lua_reference_v<T>) { + if constexpr (is_global_table_v<T>) { + tracking.use(1); + return T(L, global_tag); + } + else { + tracking.use(1); + return T(L, index); + } + } + else if constexpr (is_unique_usertype_v<T>) { + using actual = unique_usertype_actual_t<T>; + + tracking.use(1); + void* memory = lua_touserdata(L, index); + void* aligned_memory = detail::align_usertype_unique<actual>(memory); + actual* typed_memory = static_cast<actual*>(aligned_memory); + return *typed_memory; + } + else if constexpr (meta::is_optional_v<T>) { + using ValueType = typename T::value_type; + return unqualified_check_getter<ValueType>::template get_using<T>(L, index, &no_panic, tracking); + } + else if constexpr (std::is_same_v<T, luaL_Stream*>) { + luaL_Stream* pstream = static_cast<luaL_Stream*>(lua_touserdata(L, index)); + return pstream; + } + else if constexpr (std::is_same_v<T, luaL_Stream>) { + luaL_Stream* pstream = static_cast<luaL_Stream*>(lua_touserdata(L, index)); + return *pstream; + } +#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE) + else if constexpr (std::is_function_v<T> || (std::is_pointer_v<T> && std::is_function_v<std::remove_pointer_t<T>>)) { + return stack_detail::get_function_pointer<std::remove_pointer_t<T>>(L, index, tracking); + } +#endif + else { + return stack_detail::unchecked_unqualified_get<detail::as_value_tag<T>>(L, index, tracking); + } + } + }; + + template <typename X, typename> + struct qualified_getter { + static decltype(auto) get(lua_State* L, int index, record& tracking) { + using Tu = meta::unqualified_t<X>; + static constexpr bool is_maybe_userdata_of_some_kind + = !std::is_reference_v< + X> && is_container_v<Tu> && std::is_default_constructible_v<Tu> && !is_lua_primitive_v<Tu> && !is_transparent_argument_v<Tu>; + if constexpr (is_maybe_userdata_of_some_kind) { + if (type_of(L, index) == type::userdata) { + return static_cast<Tu>(stack_detail::unchecked_unqualified_get<Tu>(L, index, tracking)); + } + else { + return stack_detail::unchecked_unqualified_get<sol::nested<Tu>>(L, index, tracking); + } + } + else if constexpr (!std::is_reference_v<X> && is_unique_usertype_v<Tu> && !is_actual_type_rebindable_for_v<Tu>) { + using element = unique_usertype_element_t<Tu>; + using actual = unique_usertype_actual_t<Tu>; + tracking.use(1); + void* memory = lua_touserdata(L, index); + memory = detail::align_usertype_unique_destructor(memory); + detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory); + if (&detail::usertype_unique_alloc_destroy<element, Tu> == pdx) { + memory = detail::align_usertype_unique_tag<true, false>(memory); + memory = detail::align_usertype_unique<actual, true, false>(memory); + actual* mem = static_cast<actual*>(memory); + return static_cast<actual>(*mem); + } + actual r {}; + if constexpr (!derive<element>::value) { + // In debug mode we would rather abort you for this grave failure rather + // than let you deref a null pointer and fuck everything over + SOL_DEBUG_ABORT(); + return static_cast<actual>(std::move(r)); + } + else { + memory = detail::align_usertype_unique_tag<true, false>(memory); + detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory); + memory = detail::align_usertype_unique<actual, true, false>(memory); + string_view ti = usertype_traits<element>::qualified_name(); + int cast_operation; + if constexpr (is_actual_type_rebindable_for_v<Tu>) { + using rebound_actual_type = unique_usertype_rebind_actual_t<Tu, void>; + string_view rebind_ti = usertype_traits<rebound_actual_type>::qualified_name(); + cast_operation = ic(memory, &r, ti, rebind_ti); + } + else { + string_view rebind_ti(""); + cast_operation = ic(memory, &r, ti, rebind_ti); + } + switch (cast_operation) { + case 1: { + // it's a perfect match, + // alias memory directly + actual* mem = static_cast<actual*>(memory); + return static_cast<actual>(*mem); + } + case 2: + // it's a base match, return the + // aliased creation + return static_cast<actual>(std::move(r)); + default: + // uh oh.. + break; + } + SOL_DEBUG_ABORT(); + return static_cast<actual>(r); + } + } + else { + return stack_detail::unchecked_unqualified_get<Tu>(L, index, tracking); + } + } + }; + + template <typename T> + struct unqualified_getter<as_table_t<T>> { + using Tu = meta::unqualified_t<T>; + + template <typename V> + static void push_back_at_end(std::true_type, types<V>, lua_State* L, T& cont, std::size_t) { + cont.push_back(stack::get<V>(L, -lua_size<V>::value)); + } + + template <typename V> + static void push_back_at_end(std::false_type, types<V> t, lua_State* L, T& cont, std::size_t idx) { + insert_at_end(meta::has_insert<Tu>(), t, L, cont, idx); + } + + template <typename V> + static void insert_at_end(std::true_type, types<V>, lua_State* L, T& cont, std::size_t) { + using std::cend; + cont.insert(cend(cont), stack::get<V>(L, -lua_size<V>::value)); + } + + template <typename V> + static void insert_at_end(std::false_type, types<V>, lua_State* L, T& cont, std::size_t idx) { + cont[idx] = stack::get<V>(L, -lua_size<V>::value); + } + + static bool max_size_check(std::false_type, T&, std::size_t) { + return false; + } + + static bool max_size_check(std::true_type, T& cont, std::size_t idx) { + return idx >= cont.max_size(); + } + + static T get(lua_State* L, int relindex, record& tracking) { + return get(meta::is_associative<Tu>(), L, relindex, tracking); + } + + static T get(std::false_type, lua_State* L, int relindex, record& tracking) { + typedef typename Tu::value_type V; + return get(types<V>(), L, relindex, tracking); + } + + template <typename V> + static T get(types<V> t, lua_State* L, int relindex, record& tracking) { + tracking.use(1); + + // the W4 flag is really great, + // so great that it can tell my for loops (twice nested) + // below never actually terminate + // without hitting where the gotos have infested + + // so now I would get the error W4XXX unreachable + // me that the return cont at the end of this function + // which is fair until other compilers complain + // that there isn't a return and that based on + // SOME MAGICAL FORCE + // control flow falls off the end of a non-void function + // so it needs to be there for the compilers that are + // too flimsy to analyze the basic blocks... + // (I'm sure I should file a bug but those compilers are already + // in the wild; it doesn't matter if I fix them, + // someone else is still going to get some old-ass compiler + // and then bother me about the unclean build for the 30th + // time) + + // "Why not an IIFE?" + // Because additional lambdas / functions which serve as + // capture-all-and-then-invoke bloat binary sizes + // by an actually detectable amount + // (one user uses sol2 pretty heavily and 22 MB of binary size + // was saved by reducing reliance on lambdas in templates) + + // This would really be solved by having break N; + // be a real, proper thing... + // but instead, we have to use labels and gotos + // and earn the universal vitriol of the dogmatic + // programming community + + // all in all: W4 is great!~ + + int index = lua_absindex(L, relindex); + T cont; + std::size_t idx = 0; +#if SOL_LUA_VERSION_I_ >= 503 + // This method is HIGHLY performant over regular table iteration + // thanks to the Lua API changes in 5.3 + // Questionable in 5.4 + for (lua_Integer i = 0;; i += lua_size<V>::value) { + if (max_size_check(meta::has_max_size<Tu>(), cont, idx)) { + // see above comment + goto done; + } + bool isnil = false; + for (int vi = 0; vi < lua_size<V>::value; ++vi) { +#if SOL_IS_ON(SOL_LUA_NIL_IN_TABLES) && SOL_LUA_VERSION_I_ >= 600 +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushinteger(L, static_cast<lua_Integer>(i + vi)); + if (lua_keyin(L, index) == 0) { + // it's time to stop + isnil = true; + } + else { + // we have a key, have to get the value + lua_geti(L, index, i + vi); + } +#else + type vt = static_cast<type>(lua_geti(L, index, i + vi)); + isnil = vt == type::none || vt == type::lua_nil; +#endif + if (isnil) { + if (i == 0) { + break; + } +#if SOL_IS_ON(SOL_LUA_NIL_IN_TABLES) && SOL_LUA_VERSION_I_ >= 600 + lua_pop(L, vi); +#else + lua_pop(L, (vi + 1)); +#endif + // see above comment + goto done; + } + } + if (isnil) { +#if SOL_IS_ON(SOL_LUA_NIL_IN_TABLES) && SOL_LUA_VERSION_I_ >= 600 +#else + lua_pop(L, lua_size<V>::value); +#endif + continue; + } + + push_back_at_end(meta::has_push_back<Tu>(), t, L, cont, idx); + ++idx; + lua_pop(L, lua_size<V>::value); + } +#else + // Zzzz slower but necessary thanks to the lower version API and missing functions qq + for (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) { + if (idx >= cont.max_size()) { + // see above comment + goto done; + } +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 2, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + bool isnil = false; + for (int vi = 0; vi < lua_size<V>::value; ++vi) { + lua_pushinteger(L, i); + lua_gettable(L, index); + type vt = type_of(L, -1); + isnil = vt == type::lua_nil; + if (isnil) { + if (i == 0) { + break; + } + lua_pop(L, (vi + 1)); + // see above comment + goto done; + } + } + if (isnil) + continue; + push_back_at_end(meta::has_push_back<Tu>(), t, L, cont, idx); + ++idx; + } +#endif + done: + return cont; + } + + static T get(std::true_type, lua_State* L, int index, record& tracking) { + typedef typename Tu::value_type P; + typedef typename P::first_type K; + typedef typename P::second_type V; + return get(types<K, V>(), L, index, tracking); + } + + template <typename K, typename V> + static T get(types<K, V>, lua_State* L, int relindex, record& tracking) { + tracking.use(1); + +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 3, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + + T associative; + int index = lua_absindex(L, relindex); + lua_pushnil(L); + while (lua_next(L, index) != 0) { + decltype(auto) key = stack::check_get<K>(L, -2); + if (!key) { + lua_pop(L, 1); + continue; + } + associative.emplace(std::forward<decltype(*key)>(*key), stack::get<V>(L, -1)); + lua_pop(L, 1); + } + return associative; + } + }; + + template <typename T, typename Al> + struct unqualified_getter<as_table_t<std::forward_list<T, Al>>> { + typedef std::forward_list<T, Al> C; + + static C get(lua_State* L, int relindex, record& tracking) { + return get(meta::has_key_value_pair<C>(), L, relindex, tracking); + } + + static C get(std::true_type, lua_State* L, int index, record& tracking) { + typedef typename T::value_type P; + typedef typename P::first_type K; + typedef typename P::second_type V; + return get(types<K, V>(), L, index, tracking); + } + + static C get(std::false_type, lua_State* L, int relindex, record& tracking) { + typedef typename C::value_type V; + return get(types<V>(), L, relindex, tracking); + } + + template <typename V> + static C get(types<V>, lua_State* L, int relindex, record& tracking) { + tracking.use(1); +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 3, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + + int index = lua_absindex(L, relindex); + C cont; + auto at = cont.cbefore_begin(); + std::size_t idx = 0; +#if SOL_LUA_VERSION_I_ >= 503 + // This method is HIGHLY performant over regular table iteration thanks to the Lua API changes in 5.3 + for (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) { + if (idx >= cont.max_size()) { + goto done; + } + bool isnil = false; + for (int vi = 0; vi < lua_size<V>::value; ++vi) { + type t = static_cast<type>(lua_geti(L, index, i + vi)); + isnil = t == type::lua_nil; + if (isnil) { + if (i == 0) { + break; + } + lua_pop(L, (vi + 1)); + goto done; + } + } + if (isnil) + continue; + at = cont.insert_after(at, stack::get<V>(L, -lua_size<V>::value)); + ++idx; + } +#else + // Zzzz slower but necessary thanks to the lower version API and missing functions qq + for (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) { + if (idx >= cont.max_size()) { + goto done; + } + bool isnil = false; + for (int vi = 0; vi < lua_size<V>::value; ++vi) { + lua_pushinteger(L, i); + lua_gettable(L, index); + type t = type_of(L, -1); + isnil = t == type::lua_nil; + if (isnil) { + if (i == 0) { + break; + } + lua_pop(L, (vi + 1)); + goto done; + } + } + if (isnil) + continue; + at = cont.insert_after(at, stack::get<V>(L, -lua_size<V>::value)); + ++idx; + } +#endif + done: + return cont; + } + + template <typename K, typename V> + static C get(types<K, V>, lua_State* L, int relindex, record& tracking) { + tracking.use(1); + +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 3, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + + C associative; + auto at = associative.cbefore_begin(); + int index = lua_absindex(L, relindex); + lua_pushnil(L); + while (lua_next(L, index) != 0) { + decltype(auto) key = stack::check_get<K>(L, -2); + if (!key) { + lua_pop(L, 1); + continue; + } + at = associative.emplace_after(at, std::forward<decltype(*key)>(*key), stack::get<V>(L, -1)); + lua_pop(L, 1); + } + return associative; + } + }; + + template <typename T> + struct unqualified_getter<nested<T>> { + static T get(lua_State* L, int index, record& tracking) { + using Tu = meta::unqualified_t<T>; + if constexpr (is_container_v<Tu>) { + if constexpr (meta::is_associative<Tu>::value) { + typedef typename Tu::value_type P; + typedef typename P::first_type K; + typedef typename P::second_type V; + unqualified_getter<as_table_t<T>> g {}; + return g.get(types<K, nested<V>>(), L, index, tracking); + } + else { + typedef typename Tu::value_type V; + unqualified_getter<as_table_t<T>> g {}; + return g.get(types<nested<V>>(), L, index, tracking); + } + } + else { + unqualified_getter<Tu> g {}; + return g.get(L, index, tracking); + } + } + }; + + template <typename T> + struct unqualified_getter<as_container_t<T>> { + static decltype(auto) get(lua_State* L, int index, record& tracking) { + return stack::unqualified_get<T>(L, index, tracking); + } + }; + + template <typename T> + struct unqualified_getter<as_container_t<T>*> { + static decltype(auto) get(lua_State* L, int index, record& tracking) { + return stack::unqualified_get<T*>(L, index, tracking); + } + }; + + template <typename T> + struct unqualified_getter<exhaustive<T>> { + static decltype(auto) get(lua_State* arg_L, int index, record& tracking) { + return stack::get<T>(arg_L, index, tracking); + } + }; + + template <typename T> + struct unqualified_getter<non_exhaustive<T>> { + static decltype(auto) get(lua_State* arg_L, int index, record& tracking) { + return stack::get<T>(arg_L, index, tracking); + } + }; + + template <> + struct unqualified_getter<userdata_value> { + static userdata_value get(lua_State* L, int index, record& tracking) { + tracking.use(1); + return userdata_value(lua_touserdata(L, index)); + } + }; + + template <> + struct unqualified_getter<lightuserdata_value> { + static lightuserdata_value get(lua_State* L, int index, record& tracking) { + tracking.use(1); + return lightuserdata_value(lua_touserdata(L, index)); + } + }; + + template <typename T> + struct unqualified_getter<light<T>> { + static light<T> get(lua_State* L, int index, record& tracking) { + tracking.use(1); + void* memory = lua_touserdata(L, index); + return light<T>(static_cast<T*>(memory)); + } + }; + + template <typename T> + struct unqualified_getter<user<T>> { + static std::add_lvalue_reference_t<T> get(lua_State* L, int index, record& tracking) { + tracking.use(1); + void* memory = lua_touserdata(L, index); + memory = detail::align_user<T>(memory); + return *static_cast<std::remove_reference_t<T>*>(memory); + } + }; + + template <typename T> + struct unqualified_getter<user<T*>> { + static T* get(lua_State* L, int index, record& tracking) { + tracking.use(1); + void* memory = lua_touserdata(L, index); + memory = detail::align_user<T*>(memory); + return static_cast<T*>(memory); + } + }; + + template <> + struct unqualified_getter<type> { + static type get(lua_State* L, int index, record& tracking) { + tracking.use(1); + return static_cast<type>(lua_type(L, index)); + } + }; + + template <> + struct unqualified_getter<std::string> { + static std::string get(lua_State* L, int index, record& tracking) { + tracking.use(1); + std::size_t len; + auto str = lua_tolstring(L, index, &len); + return std::string(str, len); + } + }; + + template <> + struct unqualified_getter<const char*> { + static const char* get(lua_State* L, int index, record& tracking) { + tracking.use(1); + size_t sz; + return lua_tolstring(L, index, &sz); + } + }; + + template <> + struct unqualified_getter<char> { + static char get(lua_State* L, int index, record& tracking) { + tracking.use(1); + size_t len; + auto str = lua_tolstring(L, index, &len); + return len > 0 ? str[0] : '\0'; + } + }; + + template <typename Traits> + struct unqualified_getter<basic_string_view<char, Traits>> { + static string_view get(lua_State* L, int index, record& tracking) { + tracking.use(1); + size_t sz; + const char* str = lua_tolstring(L, index, &sz); + return basic_string_view<char, Traits>(str, sz); + } + }; + + template <typename Traits, typename Al> + struct unqualified_getter<std::basic_string<wchar_t, Traits, Al>> { + using S = std::basic_string<wchar_t, Traits, Al>; + static S get(lua_State* L, int index, record& tracking) { + using Ch = meta::conditional_t<sizeof(wchar_t) == 2, char16_t, char32_t>; + return stack_detail::get_into<Ch, S>(L, index, tracking); + } + }; + + template <typename Traits, typename Al> + struct unqualified_getter<std::basic_string<char16_t, Traits, Al>> { + static std::basic_string<char16_t, Traits, Al> get(lua_State* L, int index, record& tracking) { + return stack_detail::get_into<char16_t, std::basic_string<char16_t, Traits, Al>>(L, index, tracking); + } + }; + + template <typename Traits, typename Al> + struct unqualified_getter<std::basic_string<char32_t, Traits, Al>> { + static std::basic_string<char32_t, Traits, Al> get(lua_State* L, int index, record& tracking) { + return stack_detail::get_into<char32_t, std::basic_string<char32_t, Traits, Al>>(L, index, tracking); + } + }; + + template <> + struct unqualified_getter<char16_t> { + static char16_t get(lua_State* L, int index, record& tracking) { + string_view utf8 = stack::get<string_view>(L, index, tracking); + const char* strb = utf8.data(); + const char* stre = utf8.data() + utf8.size(); + char32_t cp = 0; + auto dr = unicode::utf8_to_code_point(strb, stre); + if (dr.error != unicode::error_code::ok) { + cp = unicode::unicode_detail::replacement; + } + else { + cp = dr.codepoint; + } + auto er = unicode::code_point_to_utf16(cp); + return er.code_units[0]; + } + }; + + template <> + struct unqualified_getter<char32_t> { + static char32_t get(lua_State* L, int index, record& tracking) { + string_view utf8 = stack::get<string_view>(L, index, tracking); + const char* strb = utf8.data(); + const char* stre = utf8.data() + utf8.size(); + char32_t cp = 0; + auto dr = unicode::utf8_to_code_point(strb, stre); + if (dr.error != unicode::error_code::ok) { + cp = unicode::unicode_detail::replacement; + } + else { + cp = dr.codepoint; + } + auto er = unicode::code_point_to_utf32(cp); + return er.code_units[0]; + } + }; + + template <> + struct unqualified_getter<wchar_t> { + static wchar_t get(lua_State* L, int index, record& tracking) { + typedef meta::conditional_t<sizeof(wchar_t) == 2, char16_t, char32_t> Ch; + unqualified_getter<Ch> g; + (void)g; + auto c = g.get(L, index, tracking); + return static_cast<wchar_t>(c); + } + }; + + template <> + struct unqualified_getter<meta_function> { + static meta_function get(lua_State* L, int index, record& tracking) { + tracking.use(1); + const char* name = unqualified_getter<const char*> {}.get(L, index, tracking); + const auto& mfnames = meta_function_names(); + for (std::size_t i = 0; i < mfnames.size(); ++i) + if (mfnames[i] == name) + return static_cast<meta_function>(i); + return meta_function::construct; + } + }; + + template <> + struct unqualified_getter<lua_nil_t> { + static lua_nil_t get(lua_State*, int, record& tracking) { + tracking.use(1); + return lua_nil; + } + }; + + template <> + struct unqualified_getter<std::nullptr_t> { + static std::nullptr_t get(lua_State*, int, record& tracking) { + tracking.use(1); + return nullptr; + } + }; + + template <> + struct unqualified_getter<nullopt_t> { + static nullopt_t get(lua_State*, int, record& tracking) { + tracking.use(1); + return nullopt; + } + }; + + template <> + struct unqualified_getter<this_state> { + static this_state get(lua_State* L, int, record& tracking) { + tracking.use(0); + return this_state(L); + } + }; + + template <> + struct unqualified_getter<this_main_state> { + static this_main_state get(lua_State* L, int, record& tracking) { + tracking.use(0); + return this_main_state(main_thread(L, L)); + } + }; + + template <> + struct unqualified_getter<lua_CFunction> { + static lua_CFunction get(lua_State* L, int index, record& tracking) { + tracking.use(1); + return lua_tocfunction(L, index); + } + }; + + template <> + struct unqualified_getter<c_closure> { + static c_closure get(lua_State* L, int index, record& tracking) { + tracking.use(1); + return c_closure(lua_tocfunction(L, index), -1); + } + }; + + template <> + struct unqualified_getter<error> { + static error get(lua_State* L, int index, record& tracking) { + tracking.use(1); + size_t sz = 0; + const char* err = lua_tolstring(L, index, &sz); + if (err == nullptr) { + return error(detail::direct_error, ""); + } + return error(detail::direct_error, std::string(err, sz)); + } + }; + + template <> + struct unqualified_getter<void*> { + static void* get(lua_State* L, int index, record& tracking) { + tracking.use(1); + return lua_touserdata(L, index); + } + }; + + template <> + struct unqualified_getter<const void*> { + static const void* get(lua_State* L, int index, record& tracking) { + tracking.use(1); + return lua_touserdata(L, index); + } + }; + + template <typename T> + struct unqualified_getter<detail::as_value_tag<T>> { + static T* get_no_lua_nil(lua_State* L, int index, record& tracking) { + void* memory = lua_touserdata(L, index); +#if SOL_IS_ON(SOL_USE_INTEROP) + auto ugr = stack_detail::interop_get<T>(L, index, memory, tracking); + if (ugr.first) { + return ugr.second; + } +#endif // interop extensibility + tracking.use(1); + void* rawdata = detail::align_usertype_pointer(memory); + void** pudata = static_cast<void**>(rawdata); + void* udata = *pudata; + return get_no_lua_nil_from(L, udata, index, tracking); + } + + static T* get_no_lua_nil_from(lua_State* L, void* udata, int index, record&) { + bool has_derived = derive<T>::value || weak_derive<T>::value; + if (has_derived) { + if (lua_getmetatable(L, index) == 1) { + lua_getfield(L, -1, &detail::base_class_cast_key()[0]); + if (type_of(L, -1) != type::lua_nil) { + void* basecastdata = lua_touserdata(L, -1); + detail::inheritance_cast_function ic = reinterpret_cast<detail::inheritance_cast_function>(basecastdata); + // use the casting function to properly adjust the pointer for the desired T + udata = ic(udata, usertype_traits<T>::qualified_name()); + } + lua_pop(L, 2); + } + } + if constexpr (std::is_function_v<T>) { + T* func = reinterpret_cast<T*>(udata); + return func; + } + else { + T* obj = static_cast<T*>(udata); + return obj; + } + } + + static T& get(lua_State* L, int index, record& tracking) { + return *get_no_lua_nil(L, index, tracking); + } + }; + + template <typename T> + struct unqualified_getter<detail::as_pointer_tag<T>> { + static T* get(lua_State* L, int index, record& tracking) { + type t = type_of(L, index); + if (t == type::lua_nil) { + tracking.use(1); + return nullptr; + } + unqualified_getter<detail::as_value_tag<T>> g{}; + return g.get_no_lua_nil(L, index, tracking); + } + }; + + template <typename T> + struct unqualified_getter<non_null<T*>> { + static T* get(lua_State* L, int index, record& tracking) { + unqualified_getter<detail::as_value_tag<T>> g{}; + return g.get_no_lua_nil(L, index, tracking); + } + }; + + template <typename T> + struct unqualified_getter<T&> { + static T& get(lua_State* L, int index, record& tracking) { + unqualified_getter<detail::as_value_tag<T>> g{}; + return g.get(L, index, tracking); + } + }; + + template <typename T> + struct unqualified_getter<std::reference_wrapper<T>> { + static T& get(lua_State* L, int index, record& tracking) { + unqualified_getter<T&> g{}; + return g.get(L, index, tracking); + } + }; + + template <typename T> + struct unqualified_getter<T*> { + static T* get(lua_State* L, int index, record& tracking) { +#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE) + if constexpr (std::is_function_v<T>) { + return stack_detail::get_function_pointer<T>(L, index, tracking); + } + else { + unqualified_getter<detail::as_pointer_tag<T>> g{}; + return g.get(L, index, tracking); + } +#else + unqualified_getter<detail::as_pointer_tag<T>> g{}; + return g.get(L, index, tracking); +#endif + } + }; + + template <typename... Tn> + struct unqualified_getter<std::tuple<Tn...>> { + typedef std::tuple<decltype(stack::get<Tn>(nullptr, 0))...> R; + + template <typename... Args> + static R apply(std::index_sequence<>, lua_State*, int, record&, Args&&... args) { + // Fuck you too, VC++ + return R { std::forward<Args>(args)... }; + } + + template <std::size_t I, std::size_t... Ix, typename... Args> + static R apply(std::index_sequence<I, Ix...>, lua_State* L, int index, record& tracking, Args&&... args) { + // Fuck you too, VC++ + typedef std::tuple_element_t<I, std::tuple<Tn...>> T; + return apply(std::index_sequence<Ix...>(), L, index, tracking, std::forward<Args>(args)..., stack::get<T>(L, index + tracking.used, tracking)); + } + + static R get(lua_State* L, int index, record& tracking) { + return apply(std::make_index_sequence<sizeof...(Tn)>(), L, index, tracking); + } + }; + + template <typename A, typename B> + struct unqualified_getter<std::pair<A, B>> { + static decltype(auto) get(lua_State* L, int index, record& tracking) { + return std::pair<decltype(stack::get<A>(L, index)), decltype(stack::get<B>(L, index))> { stack::get<A>(L, index, tracking), + stack::get<B>(L, index + tracking.used, tracking) }; + } + }; + +#if SOL_IS_ON(SOL_STD_VARIANT) + + template <typename... Tn> + struct unqualified_getter<std::variant<Tn...>> { + using V = std::variant<Tn...>; + + static V get_one(std::integral_constant<std::size_t, std::variant_size_v<V>>, lua_State* L, int index, record& tracking) { + (void)L; + (void)index; + (void)tracking; + if constexpr (std::variant_size_v<V> == 0) { + return V(); + } + else { + // using T = std::variant_alternative_t<0, V>; + std::abort(); + // return V(std::in_place_index<0>, stack::get<T>(L, index, tracking)); + } + } + + template <std::size_t I> + static V get_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, record& tracking) { + typedef std::variant_alternative_t<I, V> T; + record temp_tracking = tracking; + if (stack::check<T>(L, index, &no_panic, temp_tracking)) { + tracking = temp_tracking; + return V(std::in_place_index<I>, stack::get<T>(L, index)); + } + return get_one(std::integral_constant<std::size_t, I + 1>(), L, index, tracking); + } + + static V get(lua_State* L, int index, record& tracking) { + return get_one(std::integral_constant<std::size_t, 0>(), L, index, tracking); + } + }; +#endif // variant + +}} // namespace sol::stack + +// end of sol/stack_get_unqualified.hpp + +// beginning of sol/stack_get_qualified.hpp + +namespace sol { namespace stack { + + // There are no more enable_ifs that can be used here, + // so this is just for posterity, I guess? + // maybe I'll fill this file in later. + +}} // namespace sol::stack + +// end of sol/stack_get_qualified.hpp + +// end of sol/stack_get.hpp + +// beginning of sol/stack_check_get.hpp + +// beginning of sol/stack_check_get_unqualified.hpp + +#include <cstdlib> +#include <cmath> +#include <optional> +#if SOL_IS_ON(SOL_STD_VARIANT) +#include <variant> +#endif // variant shenanigans (thanks, Mac OSX) + +namespace sol { namespace stack { + template <typename T, typename> + struct unqualified_check_getter { + typedef decltype(stack_detail::unchecked_unqualified_get<T>(nullptr, -1, std::declval<record&>())) R; + + template <typename Optional, typename Handler> + static Optional get_using(lua_State* L, int index, Handler&& handler, record& tracking) { + if constexpr (!meta::meta_detail::is_adl_sol_lua_check_v<T> && !meta::meta_detail::is_adl_sol_lua_get_v<T>) { + if constexpr (is_lua_reference_v<T>) { + if constexpr (is_global_table_v<T>) { + (void)L; + (void)index; + (void)handler; + tracking.use(1); + return true; + } + else { + // actually check if it's none here, otherwise + // we'll have a none object inside an optional! + bool success = lua_isnoneornil(L, index) == 0 && stack::check<T>(L, index, &no_panic); + if (!success) { + // expected type, actual type + tracking.use(static_cast<int>(success)); + handler(L, index, type::poly, type_of(L, index), ""); + return detail::associated_nullopt_v<Optional>; + } + return stack_detail::unchecked_get<T>(L, index, tracking); + } + } + else if constexpr ((std::is_integral_v<T> || std::is_same_v<T, lua_Integer>)&&!std::is_same_v<T, bool>) { +#if SOL_LUA_VERSION_I_ >= 503 + if (lua_isinteger(L, index) != 0) { + tracking.use(1); + return static_cast<T>(lua_tointeger(L, index)); + } +#endif + int isnum = 0; + const lua_Number value = lua_tonumberx(L, index, &isnum); + if (isnum != 0) { +#if SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS) + const auto integer_value = llround(value); + if (static_cast<lua_Number>(integer_value) == value) { + tracking.use(1); + return static_cast<T>(integer_value); + } +#else + tracking.use(1); + return static_cast<T>(value); +#endif + } + const type t = type_of(L, index); + tracking.use(static_cast<int>(t != type::none)); + handler(L, index, type::number, t, "not an integer"); + return detail::associated_nullopt_v<Optional>; + } + else if constexpr (std::is_floating_point_v<T> || std::is_same_v<T, lua_Number>) { + int isnum = 0; + lua_Number value = lua_tonumberx(L, index, &isnum); + if (isnum == 0) { + type t = type_of(L, index); + tracking.use(static_cast<int>(t != type::none)); + handler(L, index, type::number, t, "not a valid floating point number"); + return detail::associated_nullopt_v<Optional>; + } + tracking.use(1); + return static_cast<T>(value); + } + else if constexpr (std::is_enum_v<T> && !meta::any_same_v<T, meta_function, type>) { + int isnum = 0; + lua_Integer value = lua_tointegerx(L, index, &isnum); + if (isnum == 0) { + type t = type_of(L, index); + tracking.use(static_cast<int>(t != type::none)); + handler(L, index, type::number, t, "not a valid enumeration value"); + return detail::associated_nullopt_v<Optional>; + } + tracking.use(1); + return static_cast<T>(value); + } + else { + if (!unqualified_check<T>(L, index, std::forward<Handler>(handler))) { + tracking.use(static_cast<int>(!lua_isnone(L, index))); + return detail::associated_nullopt_v<Optional>; + } + return stack_detail::unchecked_unqualified_get<T>(L, index, tracking); + } + } + else { + if (!unqualified_check<T>(L, index, std::forward<Handler>(handler))) { + tracking.use(static_cast<int>(!lua_isnone(L, index))); + return detail::associated_nullopt_v<Optional>; + } + return stack_detail::unchecked_unqualified_get<T>(L, index, tracking); + } + } + + template <typename Handler> + static optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) { + return get_using<optional<R>>(L, index, std::forward<Handler>(handler), tracking); + } + }; + +#if SOL_IS_ON(SOL_STD_VARIANT) + template <typename... Tn, typename C> + struct unqualified_check_getter<std::variant<Tn...>, C> { + typedef std::variant<Tn...> V; + typedef std::variant_size<V> V_size; + typedef std::integral_constant<bool, V_size::value == 0> V_is_empty; + + template <typename Handler> + static optional<V> get_empty(std::true_type, lua_State*, int, Handler&&, record&) { + return nullopt; + } + + template <typename Handler> + static optional<V> get_empty(std::false_type, lua_State* L, int index, Handler&& handler, record&) { + // This should never be reached... + // please check your code and understand what you did to bring yourself here + // maybe file a bug report, or 5 + handler( + L, index, type::poly, type_of(L, index), "this variant code should never be reached: if it has, you have done something so terribly wrong"); + return nullopt; + } + + template <typename Handler> + static optional<V> get_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, Handler&& handler, record& tracking) { + return get_empty(V_is_empty(), L, index, std::forward<Handler>(handler), tracking); + } + + template <std::size_t I, typename Handler> + static optional<V> get_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, Handler&& handler, record& tracking) { + typedef std::variant_alternative_t<I - 1, V> T; + if (stack::check<T>(L, index, &no_panic, tracking)) { + return V(std::in_place_index<I - 1>, stack::get<T>(L, index)); + } + return get_one(std::integral_constant<std::size_t, I - 1>(), L, index, std::forward<Handler>(handler), tracking); + } + + template <typename Handler> + static optional<V> get(lua_State* L, int index, Handler&& handler, record& tracking) { + return get_one(std::integral_constant<std::size_t, V_size::value>(), L, index, std::forward<Handler>(handler), tracking); + } + }; +#endif // standard variant +}} // namespace sol::stack + +// end of sol/stack_check_get_unqualified.hpp + +// beginning of sol/stack_check_get_qualified.hpp + +namespace sol { namespace stack { + +#if SOL_IS_ON(SOL_COMPILER_GCC) +#pragma GCC diagnostic push +#if !SOL_IS_ON(SOL_COMPILER_CLANG) +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif +#endif + + namespace stack_detail { + template <typename OptionalType, typename T, typename Handler> + OptionalType get_optional(lua_State* L, int index, Handler&& handler, record& tracking) { + using Tu = meta::unqualified_t<T>; + + if constexpr (is_lua_reference_v<T>) { + if constexpr (is_global_table_v<Tu>) { + (void)L; + (void)index; + (void)handler; + tracking.use(1); + return true; + } + else { + // actually check if it's none here, otherwise + // we'll have a none object inside an optional! + bool success = lua_isnoneornil(L, index) == 0 && stack::check<T>(L, index, &no_panic); + if (!success) { + // expected type, actual type + tracking.use(static_cast<int>(success)); + handler(L, index, type::poly, type_of(L, index), ""); + return {}; + } + return OptionalType(stack_detail::unchecked_get<T>(L, index, tracking)); + } + } + else if constexpr (!std::is_reference_v<T> && is_unique_usertype_v<Tu> && !is_actual_type_rebindable_for_v<Tu>) { + // we can take shortcuts here to save on separate checking, and just return nullopt! + using element = unique_usertype_element_t<Tu>; + using actual = unique_usertype_actual_t<Tu>; + tracking.use(1); + void* memory = lua_touserdata(L, index); + memory = detail::align_usertype_unique_destructor(memory); + detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory); + if (&detail::usertype_unique_alloc_destroy<element, Tu> == pdx) { + memory = detail::align_usertype_unique_tag<true, false>(memory); + memory = detail::align_usertype_unique<actual, true, false>(memory); + actual* mem = static_cast<actual*>(memory); + return static_cast<actual>(*mem); + } + if constexpr (!derive<element>::value) { + return OptionalType(); + } + else { + memory = detail::align_usertype_unique_tag<true, false>(memory); + detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory); + memory = detail::align_usertype_unique<actual, true, false>(memory); + string_view ti = usertype_traits<element>::qualified_name(); + int cast_operation; + actual r {}; + if constexpr (is_actual_type_rebindable_for_v<Tu>) { + using rebound_actual_type = unique_usertype_rebind_actual_t<Tu, void>; + string_view rebind_ti = usertype_traits<rebound_actual_type>::qualified_name(); + cast_operation = ic(memory, &r, ti, rebind_ti); + } + else { + string_view rebind_ti(""); + cast_operation = ic(memory, &r, ti, rebind_ti); + } + switch (cast_operation) { + case 1: { + // it's a perfect match, + // alias memory directly + actual* mem = static_cast<actual*>(memory); + return OptionalType(*mem); + } + case 2: + // it's a base match, return the + // aliased creation + return OptionalType(std::move(r)); + default: + break; + } + return OptionalType(); + } + } + else { + if (!check<T>(L, index, std::forward<Handler>(handler))) { + tracking.use(static_cast<int>(!lua_isnone(L, index))); + return OptionalType(); + } + return OptionalType(stack_detail::unchecked_get<T>(L, index, tracking)); + } + } + } // namespace stack_detail + +#if SOL_IS_ON(SOL_COMPILER_GCC) +#pragma GCC diagnostic pop +#endif + + template <typename T, typename> + struct qualified_check_getter { + typedef decltype(stack_detail::unchecked_get<T>(nullptr, -1, std::declval<record&>())) R; + + template <typename Handler> + optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) { + return stack_detail::get_optional<optional<R>, T>(L, index, std::forward<Handler>(handler), tracking); + } + }; + + template <typename Optional> + struct qualified_getter<Optional, std::enable_if_t<meta::is_optional_v<Optional>>> { + static Optional get(lua_State* L, int index, record& tracking) { + using T = typename meta::unqualified_t<Optional>::value_type; + return stack_detail::get_optional<Optional, T>(L, index, &no_panic, tracking); + } + }; + +}} // namespace sol::stack + +// end of sol/stack_check_get_qualified.hpp + +// end of sol/stack_check_get.hpp + +// beginning of sol/stack_push.hpp + +#include <memory> +#include <type_traits> +#include <cassert> +#include <limits> +#include <cmath> +#include <string_view> +#if SOL_IS_ON(SOL_STD_VARIANT) +#include <variant> +#endif // Can use variant + +// beginning of sol/debug.hpp + +#include <iostream> + +namespace sol { namespace detail { namespace debug { + inline std::string dump_types(lua_State* L) { + std::string visual; + std::size_t size = lua_gettop(L) + 1; + for (std::size_t i = 1; i < size; ++i) { + if (i != 1) { + visual += " | "; + } + visual += type_name(L, stack::get<type>(L, static_cast<int>(i))); + } + return visual; + } + + inline void print_stack(lua_State* L) { + std::cout << dump_types(L) << std::endl; + } + + inline void print_section(const std::string& message, lua_State* L) { + std::cout << "-- " << message << " -- [ " << dump_types(L) << " ]" << std::endl; + } +}}} // namespace sol::detail::debug + +// end of sol/debug.hpp + +namespace sol { namespace stack { + namespace stack_detail { + template <typename T> + inline bool integer_value_fits(const T& value) { + // We check if we can rely on casts or a lack of padding bits to satisfy + // the requirements here + // If it lacks padding bits, we can jump back and forth between lua_Integer and whatever type without + // loss of information + constexpr bool is_same_signedness + = (std::is_signed_v<T> && std::is_signed_v<lua_Integer>) || (std::is_unsigned_v<T> && std::is_unsigned_v<lua_Integer>); + constexpr bool probaby_fits_within_lua_Integer = sizeof(T) == sizeof(lua_Integer) +#if SOL_IS_ON(SOL_ALL_INTEGER_VALUES_FIT) + && ((std::has_unique_object_representations_v<T> && std::has_unique_object_representations_v<lua_Integer>) ? true : is_same_signedness) +#else + && is_same_signedness +#endif + ; + if constexpr (sizeof(T) < sizeof(lua_Integer) || probaby_fits_within_lua_Integer) { + (void)value; + return true; + } + else { + auto u_min = static_cast<std::intmax_t>((std::numeric_limits<lua_Integer>::min)()); + auto u_max = static_cast<std::uintmax_t>((std::numeric_limits<lua_Integer>::max)()); + auto t_min = static_cast<std::intmax_t>((std::numeric_limits<T>::min)()); + auto t_max = static_cast<std::uintmax_t>((std::numeric_limits<T>::max)()); + return (u_min <= t_min || value >= static_cast<T>(u_min)) && (u_max >= t_max || value <= static_cast<T>(u_max)); + } + } + + template <typename T> + int msvc_is_ass_with_if_constexpr_push_enum(std::true_type, lua_State* L, const T& value) { + if constexpr (meta::any_same_v<std::underlying_type_t<T>, + char +#if SOL_IS_ON(SOL_CHAR8_T) + , + char8_t +#endif + , + char16_t, + char32_t>) { + if constexpr (std::is_signed_v<T>) { + return stack::push(L, static_cast<std::int_least32_t>(value)); + } + else { + return stack::push(L, static_cast<std::uint_least32_t>(value)); + } + } + else { + return stack::push(L, static_cast<std::underlying_type_t<T>>(value)); + } + } + + template <typename T> + int msvc_is_ass_with_if_constexpr_push_enum(std::false_type, lua_State*, const T&) { + return 0; + } + } // namespace stack_detail + + inline int push_environment_of(lua_State* L, int target_index = -1) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_environment); +#endif // make sure stack doesn't overflow +#if SOL_LUA_VERSION_I_ < 502 + // Use lua_getfenv + lua_getfenv(L, target_index); +#else + + if (lua_iscfunction(L, target_index) != 0) { + const char* maybe_upvalue_name = lua_getupvalue(L, target_index, 1); + if (maybe_upvalue_name != nullptr) { + // it worked, take this one + return 1; + } + } + // Nominally, we search for the `"_ENV"` value. + // If we don't find it.... uh, well. We've got a problem? + for (int upvalue_index = 1;; ++upvalue_index) { + const char* maybe_upvalue_name = lua_getupvalue(L, target_index, upvalue_index); + if (maybe_upvalue_name == nullptr) { + push(L, lua_nil); + break; + } + + string_view upvalue_name(maybe_upvalue_name); + if (upvalue_name == "_ENV") { + // Keep this one! + break; + } + // Discard what we received, loop back around + lua_pop(L, 1); + } +#endif + return 1; + } + + template <typename T> + int push_environment_of(const T& target) { + lua_State* target_L = target.lua_state(); + int target_index = absolute_index(target_L, -target.push()); + int env_count = push_environment_of(target_L, target_index); + SOL_ASSERT(env_count == 1); + lua_rotate(target_L, target_index, 1); + lua_pop(target_L, 1); + return env_count; + } + + template <typename T> + struct unqualified_pusher<detail::as_value_tag<T>> { + template <typename F, typename... Args> + static int push_fx(lua_State* L, F&& f, Args&&... args) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); +#endif // make sure stack doesn't overflow + // Basically, we store all user-data like this: + // If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new + // data in the first sizeof(T*) bytes, and then however many bytes it takes to + // do the actual object. Things that are std::ref or plain T* are stored as + // just the sizeof(T*), and nothing else. + T* obj = detail::usertype_allocate<T>(L); + f(); + std::allocator<T> alloc {}; + std::allocator_traits<std::allocator<T>>::construct(alloc, obj, std::forward<Args>(args)...); + return 1; + } + + template <typename K, typename... Args> + static int push_keyed(lua_State* L, K&& k, Args&&... args) { + stack_detail::undefined_metatable fx(L, &k[0], &stack::stack_detail::set_undefined_methods_on<T>); + return push_fx(L, fx, std::forward<Args>(args)...); + } + + template <typename Arg, typename... Args> + static int push(lua_State* L, Arg&& arg, Args&&... args) { + if constexpr (std::is_same_v<meta::unqualified_t<Arg>, detail::with_function_tag>) { + (void)arg; + return push_fx(L, std::forward<Args>(args)...); + } + else { + return push_keyed(L, usertype_traits<T>::metatable(), std::forward<Arg>(arg), std::forward<Args>(args)...); + } + } + + static int push(lua_State* L) { + return push_keyed(L, usertype_traits<T>::metatable()); + } + }; + + template <typename T> + struct unqualified_pusher<detail::as_pointer_tag<T>> { + typedef meta::unqualified_t<T> U; + + template <typename F> + static int push_fx(lua_State* L, F&& f, T* obj) { + if (obj == nullptr) + return stack::push(L, lua_nil); +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); +#endif // make sure stack doesn't overflow + T** pref = detail::usertype_allocate_pointer<T>(L); + f(); + *pref = obj; + return 1; + } + + template <typename K> + static int push_keyed(lua_State* L, K&& k, T* obj) { + stack_detail::undefined_metatable fx(L, &k[0], &stack::stack_detail::set_undefined_methods_on<U*>); + return push_fx(L, fx, obj); + } + + template <typename Arg, typename... Args> + static int push(lua_State* L, Arg&& arg, Args&&... args) { + if constexpr (std::is_same_v<meta::unqualified_t<Arg>, detail::with_function_tag>) { + (void)arg; + return push_fx(L, std::forward<Args>(args)...); + } + else { + return push_keyed(L, usertype_traits<U*>::metatable(), std::forward<Arg>(arg), std::forward<Args>(args)...); + } + } + }; + + template <> + struct unqualified_pusher<detail::as_reference_tag> { + template <typename T> + static int push(lua_State* L, T&& obj) { + return stack::push(L, detail::ptr(obj)); + } + }; + + namespace stack_detail { + template <typename T> + struct uu_pusher { + using element = unique_usertype_element_t<T>; + using actual = unique_usertype_actual_t<T>; + + template <typename Arg, typename... Args> + static int push(lua_State* L, Arg&& arg, Args&&... args) { + if constexpr (std::is_base_of_v<actual, meta::unqualified_t<Arg>>) { + if (detail::unique_is_null(L, arg)) { + return stack::push(L, lua_nil); + } + return push_deep(L, std::forward<Arg>(arg), std::forward<Args>(args)...); + } + else { + return push_deep(L, std::forward<Arg>(arg), std::forward<Args>(args)...); + } + } + + template <typename... Args> + static int push_deep(lua_State* L, Args&&... args) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); +#endif // make sure stack doesn't overflow + element** pointer_to_memory = nullptr; + detail::unique_destructor* fx = nullptr; + detail::unique_tag* id = nullptr; + actual* typed_memory = detail::usertype_unique_allocate<element, actual>(L, pointer_to_memory, fx, id); + if (luaL_newmetatable(L, &usertype_traits<d::u<std::remove_cv_t<element>>>::metatable()[0]) == 1) { + detail::lua_reg_table registration_table {}; + int index = 0; + detail::indexed_insert insert_callable(registration_table, index); + detail::insert_default_registrations<element>(insert_callable, detail::property_always_true); + registration_table[index] = { to_string(meta_function::garbage_collect).c_str(), detail::make_destructor<T>() }; + luaL_setfuncs(L, registration_table, 0); + } + lua_setmetatable(L, -2); + *fx = detail::usertype_unique_alloc_destroy<element, actual>; + *id = &detail::inheritance<element>::template type_unique_cast<actual>; + detail::default_construct::construct(typed_memory, std::forward<Args>(args)...); + *pointer_to_memory = detail::unique_get<T>(L, *typed_memory); + return 1; + } + }; + } // namespace stack_detail + + template <typename T> + struct unqualified_pusher<detail::as_unique_tag<T>> { + template <typename... Args> + static int push(lua_State* L, Args&&... args) { + stack_detail::uu_pusher<T> p; + (void)p; + return p.push(L, std::forward<Args>(args)...); + } + }; + + template <typename T, typename> + struct unqualified_pusher { + template <typename... Args> + static int push(lua_State* L, Args&&... args) { + using Tu = meta::unqualified_t<T>; + if constexpr (is_lua_reference_v<Tu>) { + using int_arr = int[]; + int_arr p { (std::forward<Args>(args).push(L))... }; + return p[0]; + } + else if constexpr (std::is_same_v<Tu, bool>) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushboolean(L, std::forward<Args>(args)...); + return 1; + } + else if constexpr (std::is_integral_v<Tu> || std::is_same_v<Tu, lua_Integer>) { + const Tu& value(std::forward<Args>(args)...); +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_integral); +#endif // make sure stack doesn't overflow +#if SOL_LUA_VERSION_I_ >= 503 + if (stack_detail::integer_value_fits<Tu>(value)) { + lua_pushinteger(L, static_cast<lua_Integer>(value)); + return 1; + } +#endif // Lua 5.3 and above +#if SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS) + if (static_cast<T>(llround(static_cast<lua_Number>(value))) != value) { +#if SOL_IS_OFF(SOL_EXCEPTIONS) + // Is this really worth it? + SOL_ASSERT_MSG(false, "integer value will be misrepresented in lua"); + lua_pushinteger(L, static_cast<lua_Integer>(value)); + return 1; +#else + throw error(detail::direct_error, "integer value will be misrepresented in lua"); +#endif // No Exceptions + } +#endif // Safe Numerics and Number Precision Check + lua_pushnumber(L, static_cast<lua_Number>(value)); + return 1; + } + else if constexpr (std::is_floating_point_v<Tu> || std::is_same_v<Tu, lua_Number>) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_floating); +#endif // make sure stack doesn't overflow + lua_pushnumber(L, std::forward<Args>(args)...); + return 1; + } + else if constexpr (std::is_same_v<Tu, luaL_Stream*>) { + luaL_Stream* source { std::forward<Args>(args)... }; + luaL_Stream* stream = static_cast<luaL_Stream*>(detail::alloc_newuserdata(L, sizeof(luaL_Stream))); + stream->f = source->f; +#if SOL_IS_ON(SOL_LUAL_STREAM_USE_CLOSE_FUNCTION) + stream->closef = source->closef; +#endif // LuaJIT and Lua 5.1 and below do not have + return 1; + } + else if constexpr (std::is_same_v<Tu, luaL_Stream>) { + luaL_Stream& source(std::forward<Args>(args)...); + luaL_Stream* stream = static_cast<luaL_Stream*>(detail::alloc_newuserdata(L, sizeof(luaL_Stream))); + stream->f = source.f; +#if SOL_IS_ON(SOL_LUAL_STREAM_USE_CLOSE_FUNCTION) + stream->closef = source.closef; +#endif // LuaJIT and Lua 5.1 and below do not have + return 1; + } + else if constexpr (std::is_enum_v<Tu>) { + return stack_detail::msvc_is_ass_with_if_constexpr_push_enum(std::true_type(), L, std::forward<Args>(args)...); + } + else if constexpr (std::is_pointer_v<Tu>) { + return stack::push<detail::as_pointer_tag<std::remove_pointer_t<T>>>(L, std::forward<Args>(args)...); + } + else if constexpr (is_unique_usertype_v<Tu>) { + return stack::push<detail::as_unique_tag<T>>(L, std::forward<Args>(args)...); + } + else { + return stack::push<detail::as_value_tag<T>>(L, std::forward<Args>(args)...); + } + } + }; + + template <typename T> + struct unqualified_pusher<std::reference_wrapper<T>> { + static int push(lua_State* L, const std::reference_wrapper<T>& t) { + return stack::push(L, std::addressof(detail::deref(t.get()))); + } + }; + + template <typename T> + struct unqualified_pusher<detail::as_table_tag<T>> { + using has_kvp = meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>>; + + static int push(lua_State* L, const T& tablecont) { + return push(has_kvp(), std::false_type(), L, tablecont); + } + + static int push(lua_State* L, const T& tablecont, nested_tag_t) { + return push(has_kvp(), std::true_type(), L, tablecont); + } + + static int push(std::true_type, lua_State* L, const T& tablecont) { + return push(has_kvp(), std::true_type(), L, tablecont); + } + + static int push(std::false_type, lua_State* L, const T& tablecont) { + return push(has_kvp(), std::false_type(), L, tablecont); + } + + template <bool is_nested> + static int push(std::true_type, std::integral_constant<bool, is_nested>, lua_State* L, const T& tablecont) { + auto& cont = detail::deref(detail::unwrap(tablecont)); + lua_createtable(L, static_cast<int>(cont.size()), 0); + int tableindex = lua_gettop(L); + for (const auto& pair : cont) { + if (is_nested) { + set_field(L, pair.first, as_nested_ref(pair.second), tableindex); + } + else { + set_field(L, pair.first, pair.second, tableindex); + } + } + return 1; + } + + template <bool is_nested> + static int push(std::false_type, std::integral_constant<bool, is_nested>, lua_State* L, const T& tablecont) { + auto& cont = detail::deref(detail::unwrap(tablecont)); + lua_createtable(L, stack_detail::get_size_hint(cont), 0); + int tableindex = lua_gettop(L); + std::size_t index = 1; + for (const auto& i : cont) { +#if SOL_LUA_VERSION_I_ >= 503 + int p = is_nested ? stack::push(L, as_nested_ref(i)) : stack::push(L, i); + for (int pi = 0; pi < p; ++pi) { + lua_seti(L, tableindex, static_cast<lua_Integer>(index++)); + } +#else +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushinteger(L, static_cast<lua_Integer>(index)); + int p = is_nested ? stack::push(L, as_nested_ref(i)) : stack::push(L, i); + if (p == 1) { + ++index; + lua_settable(L, tableindex); + } + else { + int firstindex = tableindex + 1 + 1; + for (int pi = 0; pi < p; ++pi) { + stack::push(L, index); +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushvalue(L, firstindex); + lua_settable(L, tableindex); + ++index; + ++firstindex; + } + lua_pop(L, 1 + p); + } +#endif // Lua Version 5.3 and others + } + // TODO: figure out a better way to do this...? + // set_field(L, -1, cont.size()); + return 1; + } + }; + + template <typename T> + struct unqualified_pusher<as_table_t<T>> { + static int push(lua_State* L, const as_table_t<T>& value_) { + using inner_t = std::remove_pointer_t<meta::unwrap_unqualified_t<T>>; + if constexpr (is_container_v<inner_t>) { + return stack::push<detail::as_table_tag<T>>(L, value_.value()); + } + else { + return stack::push(L, value_.value()); + } + } + + static int push(lua_State* L, const T& value_) { + using inner_t = std::remove_pointer_t<meta::unwrap_unqualified_t<T>>; + if constexpr (is_container_v<inner_t>) { + return stack::push<detail::as_table_tag<T>>(L, value_); + } + else { + return stack::push(L, value_); + } + } + }; + + template <typename T> + struct unqualified_pusher<nested<T>> { + static int push(lua_State* L, const T& nested_value) noexcept { + using Tu = meta::unwrap_unqualified_t<T>; + using inner_t = std::remove_pointer_t<Tu>; + if constexpr (is_container_v<inner_t>) { + return stack::push<detail::as_table_tag<T>>(L, nested_value, nested_tag); + } + else { + return stack::push<Tu>(L, nested_value); + } + } + + static int push(lua_State* L, const nested<T>& nested_wrapper_) noexcept { + using Tu = meta::unwrap_unqualified_t<T>; + using inner_t = std::remove_pointer_t<Tu>; + if constexpr (is_container_v<inner_t>) { + return stack::push<detail::as_table_tag<T>>(L, nested_wrapper_.value(), nested_tag); + } + else { + return stack::push<Tu>(L, nested_wrapper_.value()); + } + } + }; + + template <typename T> + struct unqualified_pusher<std::initializer_list<T>> { + static int push(lua_State* L, const std::initializer_list<T>& il) noexcept { + unqualified_pusher<detail::as_table_tag<std::initializer_list<T>>> p {}; + return p.push(L, il); + } + }; + + template <> + struct unqualified_pusher<lua_nil_t> { + static int push(lua_State* L, lua_nil_t) noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushnil(L); + return 1; + } + }; + + template <> + struct unqualified_pusher<stack_count> { + static int push(lua_State*, stack_count st) noexcept { + return st.count; + } + }; + + template <> + struct unqualified_pusher<metatable_key_t> { + static int push(lua_State* L, metatable_key_t) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, to_string(meta_function::metatable).c_str(), 4); + return 1; + } + }; + + template <> + struct unqualified_pusher<std::remove_pointer_t<lua_CFunction>> { + static int push(lua_State* L, lua_CFunction func, int n = 0) noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushcclosure(L, func, n); + return 1; + } + }; + + template <> + struct unqualified_pusher<lua_CFunction> { + static int push(lua_State* L, lua_CFunction func, int n = 0) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushcclosure(L, func, n); + return 1; + } + }; + +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) + template <> + struct unqualified_pusher<std::remove_pointer_t<detail::lua_CFunction_noexcept>> { + static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushcclosure(L, func, n); + return 1; + } + }; + + template <> + struct unqualified_pusher<detail::lua_CFunction_noexcept> { + static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushcclosure(L, func, n); + return 1; + } + }; +#endif // noexcept function type + + template <> + struct unqualified_pusher<c_closure> { + static int push(lua_State* L, c_closure cc) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushcclosure(L, cc.c_function, cc.upvalues); + return 1; + } + }; + + template <typename Arg, typename... Args> + struct unqualified_pusher<closure<Arg, Args...>> { + template <std::size_t... I, typename T> + static int push(std::index_sequence<I...>, lua_State* L, T&& c) { + using f_tuple = decltype(std::forward<T>(c).upvalues); + int pushcount = multi_push(L, std::get<I>(std::forward<f_tuple>(std::forward<T>(c).upvalues))...); + return stack::push(L, c_closure(c.c_function, pushcount)); + } + + template <typename T> + static int push(lua_State* L, T&& c) { + return push(std::make_index_sequence<1 + sizeof...(Args)>(), L, std::forward<T>(c)); + } + }; + + template <> + struct unqualified_pusher<void*> { + static int push(lua_State* L, void* userdata) noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushlightuserdata(L, userdata); + return 1; + } + }; + + template <> + struct unqualified_pusher<const void*> { + static int push(lua_State* L, const void* userdata) noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushlightuserdata(L, const_cast<void*>(userdata)); + return 1; + } + }; + + template <> + struct unqualified_pusher<lightuserdata_value> { + static int push(lua_State* L, lightuserdata_value userdata) noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushlightuserdata(L, userdata); + return 1; + } + }; + + template <typename T> + struct unqualified_pusher<light<T>> { + static int push(lua_State* L, light<T> l) noexcept { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushlightuserdata(L, static_cast<void*>(l.value())); + return 1; + } + }; + + template <typename T> + struct unqualified_pusher<user<T>> { + template <bool with_meta = true, typename Key, typename... Args> + static int push_with(lua_State* L, Key&& name, Args&&... args) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); +#endif // make sure stack doesn't overflow + // A dumb pusher + T* data = detail::user_allocate<T>(L); + if (with_meta) { + // Make sure we have a plain GC set for this data +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + if (luaL_newmetatable(L, name) != 0) { + lua_CFunction cdel = detail::user_alloc_destroy<T>; + lua_pushcclosure(L, cdel, 0); + lua_setfield(L, -2, "__gc"); + } + lua_setmetatable(L, -2); + } + std::allocator<T> alloc {}; + std::allocator_traits<std::allocator<T>>::construct(alloc, data, std::forward<Args>(args)...); + return 1; + } + + template <typename Arg, typename... Args> + static int push(lua_State* L, Arg&& arg, Args&&... args) { + if constexpr (std::is_same_v<meta::unqualified_t<Arg>, metatable_key_t>) { + const auto name = &arg[0]; + return push_with<true>(L, name, std::forward<Args>(args)...); + } + else if constexpr (std::is_same_v<meta::unqualified_t<Arg>, no_metatable_t>) { + (void)arg; + const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; + return push_with<false>(L, name, std::forward<Args>(args)...); + } + else { + const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; + return push_with(L, name, std::forward<Arg>(arg), std::forward<Args>(args)...); + } + } + + static int push(lua_State* L, const user<T>& u) { + const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; + return push_with(L, name, u.value); + } + + static int push(lua_State* L, user<T>&& u) { + const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; + return push_with(L, name, std::move(u.value())); + } + + static int push(lua_State* L, no_metatable_t, const user<T>& u) { + const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; + return push_with<false>(L, name, u.value()); + } + + static int push(lua_State* L, no_metatable_t, user<T>&& u) { + const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; + return push_with<false>(L, name, std::move(u.value())); + } + }; + + template <> + struct unqualified_pusher<userdata_value> { + static int push(lua_State* L, userdata_value data) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); +#endif // make sure stack doesn't overflow + void** ud = detail::usertype_allocate_pointer<void>(L); + *ud = data.value(); + return 1; + } + }; + + template <> + struct unqualified_pusher<const char*> { + static int push_sized(lua_State* L, const char* str, std::size_t len) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str, len); + return 1; + } + + static int push(lua_State* L, const char* str) { + if (str == nullptr) + return stack::push(L, lua_nil); + return push_sized(L, str, std::char_traits<char>::length(str)); + } + + static int push(lua_State* L, const char* strb, const char* stre) { + return push_sized(L, strb, static_cast<std::size_t>(stre - strb)); + } + + static int push(lua_State* L, const char* str, std::size_t len) { + return push_sized(L, str, len); + } + }; + + template <> + struct unqualified_pusher<char*> { + static int push_sized(lua_State* L, const char* str, std::size_t len) { + unqualified_pusher<const char*> p {}; + (void)p; + return p.push_sized(L, str, len); + } + + static int push(lua_State* L, const char* str) { + unqualified_pusher<const char*> p {}; + (void)p; + return p.push(L, str); + } + + static int push(lua_State* L, const char* strb, const char* stre) { + unqualified_pusher<const char*> p {}; + (void)p; + return p.push(L, strb, stre); + } + + static int push(lua_State* L, const char* str, std::size_t len) { + unqualified_pusher<const char*> p {}; + (void)p; + return p.push(L, str, len); + } + }; + + template <size_t N> + struct unqualified_pusher<char[N]> { + static int push(lua_State* L, const char (&str)[N]) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str, std::char_traits<char>::length(str)); + return 1; + } + + static int push(lua_State* L, const char (&str)[N], std::size_t sz) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str, sz); + return 1; + } + }; + + template <> + struct unqualified_pusher<char> { + static int push(lua_State* L, char c) { + const char str[2] = { c, '\0' }; + return stack::push(L, static_cast<const char*>(str), 1u); + } + }; + +#if SOL_IS_ON(SOL_CHAR8_T) + template <> + struct unqualified_pusher<const char8_t*> { + static int push_sized(lua_State* L, const char8_t* str, std::size_t len) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, reinterpret_cast<const char*>(str), len); + return 1; + } + + static int push(lua_State* L, const char8_t* str) { + if (str == nullptr) + return stack::push(L, lua_nil); + return push_sized(L, str, std::char_traits<char>::length(reinterpret_cast<const char*>(str))); + } + + static int push(lua_State* L, const char8_t* strb, const char8_t* stre) { + return push_sized(L, strb, static_cast<std::size_t>(stre - strb)); + } + + static int push(lua_State* L, const char8_t* str, std::size_t len) { + return push_sized(L, str, len); + } + }; + + template <> + struct unqualified_pusher<char8_t*> { + static int push_sized(lua_State* L, const char8_t* str, std::size_t len) { + unqualified_pusher<const char8_t*> p {}; + (void)p; + return p.push_sized(L, str, len); + } + + static int push(lua_State* L, const char8_t* str) { + unqualified_pusher<const char8_t*> p {}; + (void)p; + return p.push(L, str); + } + + static int push(lua_State* L, const char8_t* strb, const char8_t* stre) { + unqualified_pusher<const char8_t*> p {}; + (void)p; + return p.push(L, strb, stre); + } + + static int push(lua_State* L, const char8_t* str, std::size_t len) { + unqualified_pusher<const char8_t*> p {}; + (void)p; + return p.push(L, str, len); + } + }; + + template <size_t N> + struct unqualified_pusher<char8_t[N]> { + static int push(lua_State* L, const char8_t (&str)[N]) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + const char* str_as_char = reinterpret_cast<const char*>(static_cast<const char8_t*>(str)); + lua_pushlstring(L, str_as_char, std::char_traits<char>::length(str_as_char)); + return 1; + } + + static int push(lua_State* L, const char8_t (&str)[N], std::size_t sz) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str, sz); + return 1; + } + }; + + template <> + struct unqualified_pusher<char8_t> { + static int push(lua_State* L, char8_t c) { + const char8_t str[2] = { c, '\0' }; + return stack::push(L, static_cast<const char8_t*>(str), 1u); + } + }; +#endif // char8_t + + template <typename Ch, typename Traits, typename Al> + struct unqualified_pusher<std::basic_string<Ch, Traits, Al>> { + static int push(lua_State* L, const std::basic_string<Ch, Traits, Al>& str) { + if constexpr (!std::is_same_v<Ch, char>) { + return stack::push(L, str.data(), str.size()); + } + else { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str.c_str(), str.size()); + return 1; + } + } + + static int push(lua_State* L, const std::basic_string<Ch, Traits, Al>& str, std::size_t sz) { + if constexpr (!std::is_same_v<Ch, char>) { + return stack::push(L, str.data(), sz); + } + else { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); +#endif // make sure stack doesn't overflow + lua_pushlstring(L, str.c_str(), sz); + return 1; + } + } + }; + + template <typename Ch, typename Traits> + struct unqualified_pusher<basic_string_view<Ch, Traits>> { + static int push(lua_State* L, const basic_string_view<Ch, Traits>& sv) { + return stack::push(L, sv.data(), sv.length()); + } + + static int push(lua_State* L, const basic_string_view<Ch, Traits>& sv, std::size_t n) { + return stack::push(L, sv.data(), n); + } + }; + + template <> + struct unqualified_pusher<meta_function> { + static int push(lua_State* L, meta_function m) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_meta_function_name); +#endif // make sure stack doesn't overflow + const std::string& str = to_string(m); + lua_pushlstring(L, str.c_str(), str.size()); + return 1; + } + }; + + template <> + struct unqualified_pusher<absolute_index> { + static int push(lua_State* L, absolute_index ai) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushvalue(L, ai); + return 1; + } + }; + + template <> + struct unqualified_pusher<raw_index> { + static int push(lua_State* L, raw_index ri) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushvalue(L, ri); + return 1; + } + }; + + template <> + struct unqualified_pusher<ref_index> { + static int push(lua_State* L, ref_index ri) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_rawgeti(L, LUA_REGISTRYINDEX, ri); + return 1; + } + }; + + template <> + struct unqualified_pusher<const wchar_t*> { + static int push(lua_State* L, const wchar_t* wstr) { + return push(L, wstr, std::char_traits<wchar_t>::length(wstr)); + } + + static int push(lua_State* L, const wchar_t* wstr, std::size_t sz) { + return push(L, wstr, wstr + sz); + } + + static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) { + if constexpr (sizeof(wchar_t) == 2) { + const char16_t* sb = reinterpret_cast<const char16_t*>(strb); + const char16_t* se = reinterpret_cast<const char16_t*>(stre); + return stack::push(L, sb, se); + } + else { + const char32_t* sb = reinterpret_cast<const char32_t*>(strb); + const char32_t* se = reinterpret_cast<const char32_t*>(stre); + return stack::push(L, sb, se); + } + } + }; + + template <> + struct unqualified_pusher<wchar_t*> { + static int push(lua_State* L, const wchar_t* str) { + unqualified_pusher<const wchar_t*> p {}; + (void)p; + return p.push(L, str); + } + + static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) { + unqualified_pusher<const wchar_t*> p {}; + (void)p; + return p.push(L, strb, stre); + } + + static int push(lua_State* L, const wchar_t* str, std::size_t len) { + unqualified_pusher<const wchar_t*> p {}; + (void)p; + return p.push(L, str, len); + } + }; + + template <> + struct unqualified_pusher<const char16_t*> { + static int convert_into(lua_State* L, char* start, std::size_t, const char16_t* strb, const char16_t* stre) { + char* target = start; + char32_t cp = 0; + for (const char16_t* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf16_to_code_point(strtarget, stre); + if (dr.error != unicode::error_code::ok) { + cp = unicode::unicode_detail::replacement; + } + else { + cp = dr.codepoint; + } + auto er = unicode::code_point_to_utf8(cp); + const char* utf8data = er.code_units.data(); + std::memcpy(target, utf8data, er.code_units_size); + target += er.code_units_size; + strtarget = dr.next; + } + + return stack::push(L, start, target); + } + + static int push(lua_State* L, const char16_t* u16str) { + return push(L, u16str, std::char_traits<char16_t>::length(u16str)); + } + + static int push(lua_State* L, const char16_t* u16str, std::size_t sz) { + return push(L, u16str, u16str + sz); + } + + static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { + char sbo[SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_]; + // if our max string space is small enough, use SBO + // right off the bat + std::size_t max_possible_code_units = static_cast<std::size_t>(static_cast<std::size_t>(stre - strb) * static_cast<std::size_t>(4)); + if (max_possible_code_units <= SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_) { + return convert_into(L, sbo, max_possible_code_units, strb, stre); + } + // otherwise, we must manually count/check size + std::size_t needed_size = 0; + for (const char16_t* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf16_to_code_point(strtarget, stre); + auto er = unicode::code_point_to_utf8(dr.codepoint); + needed_size += er.code_units_size; + strtarget = dr.next; + } + if (needed_size < SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_) { + return convert_into(L, sbo, needed_size, strb, stre); + } + std::string u8str("", 0); + u8str.resize(needed_size); + char* target = const_cast<char*>(u8str.data()); + return convert_into(L, target, needed_size, strb, stre); + } + }; + + template <> + struct unqualified_pusher<char16_t*> { + static int push(lua_State* L, const char16_t* str) { + unqualified_pusher<const char16_t*> p {}; + (void)p; + return p.push(L, str); + } + + static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { + unqualified_pusher<const char16_t*> p {}; + (void)p; + return p.push(L, strb, stre); + } + + static int push(lua_State* L, const char16_t* str, std::size_t len) { + unqualified_pusher<const char16_t*> p {}; + (void)p; + return p.push(L, str, len); + } + }; + + template <> + struct unqualified_pusher<const char32_t*> { + static int convert_into(lua_State* L, char* start, std::size_t, const char32_t* strb, const char32_t* stre) { + char* target = start; + char32_t cp = 0; + for (const char32_t* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf32_to_code_point(strtarget, stre); + if (dr.error != unicode::error_code::ok) { + cp = unicode::unicode_detail::replacement; + } + else { + cp = dr.codepoint; + } + auto er = unicode::code_point_to_utf8(cp); + const char* data = er.code_units.data(); + std::memcpy(target, data, er.code_units_size); + target += er.code_units_size; + strtarget = dr.next; + } + return stack::push(L, start, target); + } + + static int push(lua_State* L, const char32_t* u32str) { + return push(L, u32str, u32str + std::char_traits<char32_t>::length(u32str)); + } + + static int push(lua_State* L, const char32_t* u32str, std::size_t sz) { + return push(L, u32str, u32str + sz); + } + + static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { + char sbo[SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_]; + // if our max string space is small enough, use SBO + // right off the bat + std::size_t max_possible_code_units = static_cast<std::size_t>(static_cast<std::size_t>(stre - strb) * static_cast<std::size_t>(4)); + if (max_possible_code_units <= SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_) { + return convert_into(L, sbo, max_possible_code_units, strb, stre); + } + // otherwise, we must manually count/check size + std::size_t needed_size = 0; + for (const char32_t* strtarget = strb; strtarget < stre;) { + auto dr = unicode::utf32_to_code_point(strtarget, stre); + auto er = unicode::code_point_to_utf8(dr.codepoint); + needed_size += er.code_units_size; + strtarget = dr.next; + } + if (needed_size < SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_) { + return convert_into(L, sbo, needed_size, strb, stre); + } + std::string u8str("", 0); + u8str.resize(needed_size); + char* target = const_cast<char*>(u8str.data()); + return convert_into(L, target, needed_size, strb, stre); + } + }; + + template <> + struct unqualified_pusher<char32_t*> { + static int push(lua_State* L, const char32_t* str) { + unqualified_pusher<const char32_t*> p {}; + (void)p; + return p.push(L, str); + } + + static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { + unqualified_pusher<const char32_t*> p {}; + (void)p; + return p.push(L, strb, stre); + } + + static int push(lua_State* L, const char32_t* str, std::size_t len) { + unqualified_pusher<const char32_t*> p {}; + (void)p; + return p.push(L, str, len); + } + }; + + template <size_t N> + struct unqualified_pusher<wchar_t[N]> { + static int push(lua_State* L, const wchar_t (&str)[N]) { + return push(L, str, std::char_traits<wchar_t>::length(str)); + } + + static int push(lua_State* L, const wchar_t (&str)[N], std::size_t sz) { + const wchar_t* str_ptr = static_cast<const wchar_t*>(str); + return stack::push<const wchar_t*>(L, str_ptr, str_ptr + sz); + } + }; + + template <size_t N> + struct unqualified_pusher<char16_t[N]> { + static int push(lua_State* L, const char16_t (&str)[N]) { + return push(L, str, std::char_traits<char16_t>::length(str)); + } + + static int push(lua_State* L, const char16_t (&str)[N], std::size_t sz) { + const char16_t* str_ptr = static_cast<const char16_t*>(str); + return stack::push<const char16_t*>(L, str_ptr, str_ptr + sz); + } + }; + + template <size_t N> + struct unqualified_pusher<char32_t[N]> { + static int push(lua_State* L, const char32_t (&str)[N]) { + return push(L, str, std::char_traits<char32_t>::length(str)); + } + + static int push(lua_State* L, const char32_t (&str)[N], std::size_t sz) { + const char32_t* str_ptr = static_cast<const char32_t*>(str); + return stack::push<const char32_t*>(L, str_ptr, str_ptr + sz); + } + }; + + template <> + struct unqualified_pusher<wchar_t> { + static int push(lua_State* L, wchar_t c) { + const wchar_t str[2] = { c, '\0' }; + return stack::push(L, static_cast<const wchar_t*>(str), 1u); + } + }; + + template <> + struct unqualified_pusher<char16_t> { + static int push(lua_State* L, char16_t c) { + const char16_t str[2] = { c, '\0' }; + return stack::push(L, static_cast<const char16_t*>(str), 1u); + } + }; + + template <> + struct unqualified_pusher<char32_t> { + static int push(lua_State* L, char32_t c) { + const char32_t str[2] = { c, '\0' }; + return stack::push(L, static_cast<const char32_t*>(str), 1u); + } + }; + + template <typename... Args> + struct unqualified_pusher<std::tuple<Args...>> { + template <std::size_t... I, typename T> + static int push(std::index_sequence<I...>, lua_State* L, T&& t) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, static_cast<int>(sizeof...(I)), detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + int pushcount = 0; + (void)detail::swallow { 0, (pushcount += stack::push(L, std::get<I>(std::forward<T>(t))), 0)... }; + return pushcount; + } + + template <typename T> + static int push(lua_State* L, T&& t) { + return push(std::index_sequence_for<Args...>(), L, std::forward<T>(t)); + } + }; + + template <typename A, typename B> + struct unqualified_pusher<std::pair<A, B>> { + template <typename T> + static int push(lua_State* L, T&& t) { + int pushcount = stack::push(L, std::get<0>(std::forward<T>(t))); + pushcount += stack::push(L, std::get<1>(std::forward<T>(t))); + return pushcount; + } + }; + + template <typename T> + struct unqualified_pusher<T, std::enable_if_t<meta::is_optional_v<T>>> { + using ValueType = typename meta::unqualified_t<T>::value_type; + + template <typename Optional> + static int push(lua_State* L, Optional&& op) { + using QualifiedValueType = meta::conditional_t<std::is_lvalue_reference_v<Optional>, ValueType&, ValueType&&>; + if (!op) { + return stack::push(L, nullopt); + } + return stack::push(L, static_cast<QualifiedValueType>(op.value())); + } + }; + + template <typename T> + struct unqualified_pusher<forward_as_value_t<T>> { + static int push(lua_State* L, const forward_as_value_t<T>& value_) { + return stack::push<T>(L, value_.value()); + } + + static int push(lua_State* L, forward_as_value_t<T>&& value_) { + return stack::push<T>(L, std::move(value_).value()); + } + }; + + template <> + struct unqualified_pusher<nullopt_t> { + static int push(lua_State* L, nullopt_t) noexcept { + return stack::push(L, lua_nil); + } + }; + + template <> + struct unqualified_pusher<std::nullptr_t> { + static int push(lua_State* L, std::nullptr_t) noexcept { + return stack::push(L, lua_nil); + } + }; + + template <> + struct unqualified_pusher<this_state> { + static int push(lua_State*, const this_state&) noexcept { + return 0; + } + }; + + template <> + struct unqualified_pusher<this_main_state> { + static int push(lua_State*, const this_main_state&) noexcept { + return 0; + } + }; + + template <> + struct unqualified_pusher<new_table> { + static int push(lua_State* L, const new_table& nt) { + lua_createtable(L, nt.sequence_hint, nt.map_hint); + return 1; + } + }; + + template <typename Allocator> + struct unqualified_pusher<basic_bytecode<Allocator>> { + template <typename T> + static int push(lua_State* L, T&& bc, const char* bytecode_name) { + const auto first = bc.data(); + const auto bcsize = bc.size(); + // pushes either the function, or an error + // if it errors, shit goes south, and people can test that upstream + (void)luaL_loadbuffer( + L, reinterpret_cast<const char*>(first), static_cast<std::size_t>(bcsize * (sizeof(*first) / sizeof(const char))), bytecode_name); + return 1; + } + + template <typename T> + static int push(lua_State* L, T&& bc) { + return push(L, std::forward<bc>(bc), "bytecode"); + } + }; + +#if SOL_IS_ON(SOL_STD_VARIANT) + namespace stack_detail { + + struct push_function { + lua_State* L; + + push_function(lua_State* L_) noexcept : L(L_) { + } + + template <typename T> + int operator()(T&& value) const { + return stack::push<T>(L, std::forward<T>(value)); + } + }; + + } // namespace stack_detail + + template <typename... Tn> + struct unqualified_pusher<std::variant<Tn...>> { + static int push(lua_State* L, const std::variant<Tn...>& v) { + return std::visit(stack_detail::push_function(L), v); + } + + static int push(lua_State* L, std::variant<Tn...>&& v) { + return std::visit(stack_detail::push_function(L), std::move(v)); + } + }; +#endif // Variant because Clang is terrible + +}} // namespace sol::stack + +// end of sol/stack_push.hpp + +// beginning of sol/stack_pop.hpp + +#include <utility> +#include <tuple> + +namespace sol { namespace stack { + template <typename T, typename> + struct popper { + inline static decltype(auto) pop(lua_State* L) { + if constexpr (is_stack_based_v<meta::unqualified_t<T>>) { + static_assert(!is_stack_based_v<meta::unqualified_t<T>>, + "You cannot pop something that lives solely on the stack: it will not remain on the stack when popped and thusly will go out of " + "scope!"); + } + else { + record tracking {}; + decltype(auto) r = get<T>(L, -lua_size<T>::value, tracking); + lua_pop(L, tracking.used); + return r; + } + } + }; +}} // namespace sol::stack + +// end of sol/stack_pop.hpp + +// beginning of sol/stack_field.hpp + +namespace sol { namespace stack { + + namespace stack_detail { + template <typename T, bool global, bool raw> + inline constexpr bool is_get_direct_tableless_v = (global && !raw && meta::is_c_str_or_string_v<T>); + + template <typename T, bool global, bool raw> + inline constexpr bool is_get_direct_v = (is_get_direct_tableless_v<T, global, raw>) // cf-hack + || (!global && !raw && (meta::is_c_str_or_string_v<T> || meta::is_string_of_v<T, char>)) // cf-hack + || (!global && raw && (std::is_integral_v<T> && !std::is_same_v<T, bool>)) +#if SOL_LUA_VERSION_I_ >= 503 + || (!global && !raw && (std::is_integral_v<T> && !std::is_same_v<T, bool>)) +#endif // integer keys 5.3 or better +#if SOL_LUA_VERSION_I_ >= 502 + || (!global && raw && std::is_pointer_v<T> && std::is_void_v<std::remove_pointer_t<T>>) +#endif // void pointer keys 5.2 or better + ; + + template <typename T, bool global, bool raw> + inline constexpr bool is_set_direct_tableless_v = (global && !raw && meta::is_c_str_or_string_v<T>); + + template <typename T, bool global, bool raw> + inline constexpr bool is_set_direct_v = (is_set_direct_tableless_v<T, global, raw>) // cf-hack + || (!global && !raw && (meta::is_c_str_or_string_v<T> || meta::is_string_of_v<T, char>)) // cf-hack + || (!global && raw && (std::is_integral_v<T> && !std::is_same_v<T, bool>)) // cf-hack +#if SOL_LUA_VERSION_I_ >= 503 + || (!global && !raw && (std::is_integral_v<T> && !std::is_same_v<T, bool>)) +#endif // integer keys 5.3 or better +#if SOL_LUA_VERSION_I_ >= 502 + || (!global && raw && (std::is_pointer_v<T> && std::is_void_v<std::remove_pointer_t<T>>)) +#endif // void pointer keys 5.2 or better + ; + } // namespace stack_detail + + template <typename T, bool global, bool raw, typename> + struct field_getter { + static inline constexpr int default_table_index + = meta::conditional_t<stack_detail::is_get_direct_v<T, global, raw>, std::integral_constant<int, -1>, std::integral_constant<int, -2>>::value; + + template <typename Key> + void get(lua_State* L, Key&& key, int tableindex = default_table_index) { + if constexpr (std::is_same_v<T, update_if_empty_t> || std::is_same_v<T, override_value_t> || std::is_same_v<T, create_if_nil_t>) { + (void)L; + (void)key; + (void)tableindex; + } + else if constexpr (std::is_same_v<T, env_key_t>) { + (void)key; +#if SOL_LUA_VERSION_I_ < 502 + // Use lua_setfenv + lua_getfenv(L, tableindex); +#else + // Use upvalues as explained in Lua 5.2 and beyond's manual + if (lua_getupvalue(L, tableindex, 1) == nullptr) { + push(L, lua_nil); + } +#endif + } + else if constexpr (std::is_same_v<T, metatable_key_t>) { + (void)key; + if (lua_getmetatable(L, tableindex) == 0) + push(L, lua_nil); + } + else if constexpr (raw) { + if constexpr (std::is_integral_v<T> && !std::is_same_v<bool, T>) { + lua_rawgeti(L, tableindex, static_cast<lua_Integer>(key)); + } +#if SOL_LUA_VERSION_I_ >= 502 + else if constexpr (std::is_pointer_v<T> && std::is_void_v<std::remove_pointer_t<T>>) { + lua_rawgetp(L, tableindex, key); + } +#endif // Lua 5.2.x+ + else { + push(L, std::forward<Key>(key)); + lua_rawget(L, tableindex); + } + } + else { + if constexpr (meta::is_c_str_or_string_v<T>) { + if constexpr (global) { + (void)tableindex; + lua_getglobal(L, &key[0]); + } + else { + lua_getfield(L, tableindex, &key[0]); + } + } + else if constexpr (std::is_same_v<T, meta_function>) { + const auto& real_key = to_string(key); + lua_getfield(L, tableindex, &real_key[0]); + } +#if SOL_LUA_VERSION_I_ >= 503 + else if constexpr (std::is_integral_v<T> && !std::is_same_v<bool, T>) { + lua_geti(L, tableindex, static_cast<lua_Integer>(key)); + } +#endif // Lua 5.3.x+ + else { + push(L, std::forward<Key>(key)); + lua_gettable(L, tableindex); + } + } + } + }; + + template <typename... Args, bool b, bool raw, typename C> + struct field_getter<std::tuple<Args...>, b, raw, C> { + template <std::size_t... I, typename Keys> + void apply(std::index_sequence<0, I...>, lua_State* L, Keys&& keys, int tableindex) { + get_field<b, raw>(L, std::get<0>(std::forward<Keys>(keys)), tableindex); + void(detail::swallow { (get_field<false, raw>(L, std::get<I>(std::forward<Keys>(keys))), 0)... }); + reference saved(L, -1); + lua_pop(L, static_cast<int>(sizeof...(I))); + saved.push(); + } + + template <typename Keys> + void get(lua_State* L, Keys&& keys) { + apply(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<Keys>(keys), lua_absindex(L, -1)); + } + + template <typename Keys> + void get(lua_State* L, Keys&& keys, int tableindex) { + apply(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<Keys>(keys), tableindex); + } + }; + + template <typename A, typename B, bool b, bool raw, typename C> + struct field_getter<std::pair<A, B>, b, raw, C> { + template <typename Keys> + void get(lua_State* L, Keys&& keys, int tableindex) { + get_field<b, raw>(L, std::get<0>(std::forward<Keys>(keys)), tableindex); + get_field<false, raw>(L, std::get<1>(std::forward<Keys>(keys))); + reference saved(L, -1); + lua_pop(L, static_cast<int>(2)); + saved.push(); + } + + template <typename Keys> + void get(lua_State* L, Keys&& keys) { + get_field<b, raw>(L, std::get<0>(std::forward<Keys>(keys))); + get_field<false, raw>(L, std::get<1>(std::forward<Keys>(keys))); + reference saved(L, -1); + lua_pop(L, static_cast<int>(2)); + saved.push(); + } + }; + + template <typename T, bool global, bool raw, typename> + struct field_setter { + static constexpr int default_table_index + = meta::conditional_t<stack_detail::is_set_direct_v<T, global, raw>, std::integral_constant<int, -2>, std::integral_constant<int, -3>>::value; + + template <typename Key, typename Value> + void set(lua_State* L, Key&& key, Value&& value, int tableindex = default_table_index) { + if constexpr (std::is_same_v<T, update_if_empty_t> || std::is_same_v<T, override_value_t>) { + (void)L; + (void)key; + (void)value; + (void)tableindex; + } + else if constexpr (std::is_same_v<T, metatable_key_t>) { + (void)key; + push(L, std::forward<Value>(value)); + lua_setmetatable(L, tableindex); + } + else if constexpr (raw) { + if constexpr (std::is_integral_v<T> && !std::is_same_v<bool, T>) { + push(L, std::forward<Value>(value)); + lua_rawseti(L, tableindex, static_cast<lua_Integer>(key)); + } +#if SOL_LUA_VERSION_I_ >= 502 + else if constexpr (std::is_pointer_v<T> && std::is_void_v<std::remove_pointer_t<T>>) { + push(L, std::forward<Value>(value)); + lua_rawsetp(L, tableindex, std::forward<Key>(key)); + } +#endif // Lua 5.2.x + else { + push(L, std::forward<Key>(key)); + push(L, std::forward<Value>(value)); + lua_rawset(L, tableindex); + } + } + else { + if constexpr (meta::is_c_str_or_string_v<T>) { + if constexpr (global) { + push(L, std::forward<Value>(value)); + lua_setglobal(L, &key[0]); + (void)tableindex; + } + else { + push(L, std::forward<Value>(value)); + lua_setfield(L, tableindex, &key[0]); + } + } +#if SOL_LUA_VERSION_I_ >= 503 + else if constexpr (std::is_integral_v<T> && !std::is_same_v<bool, T>) { + push(L, std::forward<Value>(value)); + lua_seti(L, tableindex, static_cast<lua_Integer>(key)); + } +#endif // Lua 5.3.x + else { + push(L, std::forward<Key>(key)); + push(L, std::forward<Value>(value)); + lua_settable(L, tableindex); + } + } + } + }; + + template <typename... Args, bool b, bool raw, typename C> + struct field_setter<std::tuple<Args...>, b, raw, C> { + template <bool g, std::size_t I, typename Keys, typename Value> + void apply(std::index_sequence<I>, lua_State* L, Keys&& keys, Value&& value, int tableindex) { + I < 1 ? set_field<g, raw>(L, std::get<I>(std::forward<Keys>(keys)), std::forward<Value>(value), tableindex) + : set_field<g, raw>(L, std::get<I>(std::forward<Keys>(keys)), std::forward<Value>(value)); + } + + template <bool g, std::size_t I0, std::size_t I1, std::size_t... I, typename Keys, typename Value> + void apply(std::index_sequence<I0, I1, I...>, lua_State* L, Keys&& keys, Value&& value, int tableindex) { + I0 < 1 ? get_field<g, raw>(L, std::get<I0>(std::forward<Keys>(keys)), tableindex) + : get_field<g, raw>(L, std::get<I0>(std::forward<Keys>(keys)), -1); + apply<false>(std::index_sequence<I1, I...>(), L, std::forward<Keys>(keys), std::forward<Value>(value), -1); + } + + template <bool g, std::size_t I0, std::size_t... I, typename Keys, typename Value> + void top_apply(std::index_sequence<I0, I...>, lua_State* L, Keys&& keys, Value&& value, int tableindex) { + apply<g>(std::index_sequence<I0, I...>(), L, std::forward<Keys>(keys), std::forward<Value>(value), tableindex); + lua_pop(L, static_cast<int>(sizeof...(I))); + } + + template <typename Keys, typename Value> + void set(lua_State* L, Keys&& keys, Value&& value, int tableindex = -3) { + top_apply<b>(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<Keys>(keys), std::forward<Value>(value), tableindex); + } + }; + + template <typename A, typename B, bool b, bool raw, typename C> + struct field_setter<std::pair<A, B>, b, raw, C> { + template <typename Keys, typename Value> + void set(lua_State* L, Keys&& keys, Value&& value, int tableindex = -1) { + get_field<b, raw>(L, std::get<0>(std::forward<Keys>(keys)), tableindex); + set_field<false, raw>(L, std::get<1>(std::forward<Keys>(keys)), std::forward<Value>(value), lua_gettop(L)); + lua_pop(L, 1); + } + }; +}} // namespace sol::stack + +// end of sol/stack_field.hpp + +// beginning of sol/stack_probe.hpp + +namespace sol { namespace stack { + template <typename T, typename P, bool b, bool raw, typename> + struct probe_field_getter { + template <typename Key> + probe get(lua_State* L, Key&& key, int tableindex = -2) { + if constexpr (!b) { + if (!maybe_indexable(L, tableindex)) { + return probe(false, 0); + } + } + get_field<b, raw>(L, std::forward<Key>(key), tableindex); + return probe(check<P>(L), 1); + } + }; + + template <typename A, typename B, typename P, bool b, bool raw, typename C> + struct probe_field_getter<std::pair<A, B>, P, b, raw, C> { + template <typename Keys> + probe get(lua_State* L, Keys&& keys, int tableindex = -2) { + if (!b && !maybe_indexable(L, tableindex)) { + return probe(false, 0); + } + get_field<b, raw>(L, std::get<0>(keys), tableindex); + if (!maybe_indexable(L)) { + return probe(false, 1); + } + get_field<false, raw>(L, std::get<1>(keys), tableindex); + return probe(check<P>(L), 2); + } + }; + + template <typename... Args, typename P, bool b, bool raw, typename C> + struct probe_field_getter<std::tuple<Args...>, P, b, raw, C> { + template <std::size_t I, typename Keys> + probe apply(std::index_sequence<I>, int sofar, lua_State* L, Keys&& keys, int tableindex) { + get_field<(I < 1) && b, raw>(L, std::get<I>(keys), tableindex); + return probe(check<P>(L), sofar); + } + + template <std::size_t I, std::size_t I1, std::size_t... In, typename Keys> + probe apply(std::index_sequence<I, I1, In...>, int sofar, lua_State* L, Keys&& keys, int tableindex) { + get_field < I<1 && b, raw>(L, std::get<I>(keys), tableindex); + if (!maybe_indexable(L)) { + return probe(false, sofar); + } + return apply(std::index_sequence<I1, In...>(), sofar + 1, L, std::forward<Keys>(keys), -1); + } + + template <typename Keys> + probe get(lua_State* L, Keys&& keys, int tableindex = -2) { + if constexpr (!b) { + if (!maybe_indexable(L, tableindex)) { + return probe(false, 0); + } + return apply(std::index_sequence_for<Args...>(), 1, L, std::forward<Keys>(keys), tableindex); + } + else { + return apply(std::index_sequence_for<Args...>(), 1, L, std::forward<Keys>(keys), tableindex); + } + } + }; +}} // namespace sol::stack + +// end of sol/stack_probe.hpp + +#include <cstring> +#include <array> + +namespace sol { + namespace detail { + using typical_chunk_name_t = char[SOL_ID_SIZE_I_]; + using typical_file_chunk_name_t = char[SOL_FILE_ID_SIZE_I_]; + + inline const std::string& default_chunk_name() { + static const std::string name = ""; + return name; + } + + template <std::size_t N> + const char* make_chunk_name(const string_view& code, const std::string& chunkname, char (&basechunkname)[N]) { + if (chunkname.empty()) { + auto it = code.cbegin(); + auto e = code.cend(); + std::size_t i = 0; + static const std::size_t n = N - 4; + for (i = 0; i < n && it != e; ++i, ++it) { + basechunkname[i] = *it; + } + if (it != e) { + for (std::size_t c = 0; c < 3; ++i, ++c) { + basechunkname[i] = '.'; + } + } + basechunkname[i] = '\0'; + return &basechunkname[0]; + } + else { + return chunkname.c_str(); + } + } + + inline void clear_entries(stack_reference r) { + stack::push(r.lua_state(), lua_nil); + while (lua_next(r.lua_state(), -2)) { + absolute_index key(r.lua_state(), -2); + auto pn = stack::pop_n(r.lua_state(), 1); + stack::set_field<false, true>(r.lua_state(), key, lua_nil, r.stack_index()); + } + } + + inline void clear_entries(const reference& registry_reference) { + auto pp = stack::push_pop(registry_reference); + stack_reference ref(registry_reference.lua_state(), -1); + clear_entries(ref); + } + } // namespace detail + + namespace stack { + namespace stack_detail { + template <typename T> + inline int push_as_upvalues(lua_State* L, T& item) { + typedef std::decay_t<T> TValue; + static const std::size_t itemsize = sizeof(TValue); + static const std::size_t voidsize = sizeof(void*); + static const std::size_t voidsizem1 = voidsize - 1; + static const std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize; + typedef std::array<void*, data_t_count> data_t; + + data_t data { {} }; + std::memcpy(&data[0], std::addressof(item), itemsize); + int pushcount = 0; + for (const auto& v : data) { + lua_pushlightuserdata(L, v); + pushcount += 1; + } + return pushcount; + } + + template <typename T> + inline std::pair<T, int> get_as_upvalues(lua_State* L, int index = 2) { + static const std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*); + typedef std::array<void*, data_t_count> data_t; + data_t voiddata { {} }; + for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) { + voiddata[i] = lua_touserdata(L, upvalue_index(index++)); + } + return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index); + } + + template <typename T> + inline std::pair<T, int> get_as_upvalues_using_function(lua_State* L, int function_index = -1) { + static const std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*); + typedef std::array<void*, data_t_count> data_t; + function_index = lua_absindex(L, function_index); + int index = 0; + data_t voiddata { {} }; + for (std::size_t d = 0; d < sizeof(T); d += sizeof(void*)) { + // first upvalue is nullptr to respect environment shenanigans + // So +2 instead of +1 + const char* upvalue_name = lua_getupvalue(L, function_index, index + 2); + if (upvalue_name == nullptr) { + // We should freak out here... + break; + } + voiddata[index] = lua_touserdata(L, -1); + ++index; + } + lua_pop(L, index); + return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index); + } + + template <bool checked, typename Handler, typename Fx, typename... Args> + static decltype(auto) eval(types<>, std::index_sequence<>, lua_State*, int, Handler&&, record&, Fx&& fx, Args&&... args) { + return std::forward<Fx>(fx)(std::forward<Args>(args)...); + } + + template <bool checked, typename Arg, typename... Args, std::size_t I, std::size_t... Is, typename Handler, typename Fx, typename... FxArgs> + static decltype(auto) eval(types<Arg, Args...>, std::index_sequence<I, Is...>, lua_State* L_, int start_index_, Handler&& handler_, + record& tracking_, Fx&& fx_, FxArgs&&... fxargs_) { +#if 0 && SOL_IS_ON(SOL_PROPAGATE_EXCEPTIONS) + // NOTE: THIS IS TERMPORARILY TURNED OFF BECAUSE IT IMPACTS ACTUAL SEMANTICS W.R.T. THINGS LIKE LUAJIT, + // SO IT MUST REMAIN OFF UNTIL WE CAN ESTABLISH SIMILAR BEHAVIOR IN MODES WHERE `checked == false`! + + // We can save performance/time by letting errors unwind produced arguments + // rather than checking everything once, and then potentially re-doing work + if constexpr (checked) { + return eval<checked>(types<Args...>(), + std::index_sequence<Is...>(), + L_, + start_index_, + std::forward<Handler>(handler_), + tracking_, + std::forward<Fx>(fx_), + std::forward<FxArgs>(fxargs_)..., + *stack_detail::check_get_arg<Arg>(L_, start_index_ + tracking_.used, handler_, tracking_)); + } + else +#endif + { + return eval<checked>(types<Args...>(), + std::index_sequence<Is...>(), + L_, + start_index_, + std::forward<Handler>(handler_), + tracking_, + std::forward<Fx>(fx_), + std::forward<FxArgs>(fxargs_)..., + stack_detail::unchecked_get_arg<Arg>(L_, start_index_ + tracking_.used, tracking_)); + } + } + + template <bool checkargs = detail::default_safe_function_calls, std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs> + inline decltype(auto) call(types<R>, types<Args...> argument_types_, std::index_sequence<I...> argument_indices_, lua_State* L_, + int start_index_, Fx&& fx_, FxArgs&&... args_) { + static_assert(meta::all_v<meta::is_not_move_only<Args>...>, + "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take " + "a reference and std::move it manually if this was your intention."); + argument_handler<types<R, Args...>> handler {}; + record tracking {}; +#if SOL_IS_OFF(SOL_PROPAGATE_EXCEPTIONS) + if constexpr (checkargs) { + multi_check<Args...>(L_, start_index_, handler); + } +#endif + if constexpr (std::is_void_v<R>) { + eval<checkargs>( + argument_types_, argument_indices_, L_, start_index_, handler, tracking, std::forward<Fx>(fx_), std::forward<FxArgs>(args_)...); + } + else { + return eval<checkargs>( + argument_types_, argument_indices_, L_, start_index_, handler, tracking, std::forward<Fx>(fx_), std::forward<FxArgs>(args_)...); + } + } + + template <typename T> + void raw_table_set(lua_State* L, T&& arg, int tableindex = -2) { + int push_count = push(L, std::forward<T>(arg)); + SOL_ASSERT(push_count == 1); + std::size_t unique_index = static_cast<std::size_t>(luaL_len(L, tableindex) + 1u); + lua_rawseti(L, tableindex, static_cast<int>(unique_index)); + } + + } // namespace stack_detail + + template <typename T> + int set_ref(lua_State* L, T&& arg, int tableindex = -2) { + int push_count = push(L, std::forward<T>(arg)); + SOL_ASSERT(push_count == 1); + return luaL_ref(L, tableindex); + } + + template <bool check_args = detail::default_safe_function_calls, typename R, typename... Args, typename Fx, typename... FxArgs> + inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { + using args_indices = std::make_index_sequence<sizeof...(Args)>; + if constexpr (std::is_void_v<R>) { + stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); + } + else { + return stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); + } + } + + template <bool check_args = detail::default_safe_function_calls, typename R, typename... Args, typename Fx, typename... FxArgs> + inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) { + if constexpr (std::is_void_v<R>) { + call<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); + } + else { + return call<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); + } + } + + template <bool check_args = detail::default_safe_function_calls, typename R, typename... Args, typename Fx, typename... FxArgs> + inline decltype(auto) call_from_top(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) { + using expected_count_t = meta::count_for_pack<lua_size, Args...>; + if constexpr (std::is_void_v<R>) { + call<check_args>(tr, + ta, + L, + (std::max)(static_cast<int>(lua_gettop(L) - expected_count_t::value), static_cast<int>(0)), + std::forward<Fx>(fx), + std::forward<FxArgs>(args)...); + } + else { + return call<check_args>(tr, + ta, + L, + (std::max)(static_cast<int>(lua_gettop(L) - expected_count_t::value), static_cast<int>(0)), + std::forward<Fx>(fx), + std::forward<FxArgs>(args)...); + } + } + + template <bool check_args = detail::default_safe_function_calls, bool clean_stack = true, typename Ret0, typename... Ret, typename... Args, + typename Fx, typename... FxArgs> + inline int call_into_lua(types<Ret0, Ret...> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { + if constexpr (std::is_void_v<Ret0>) { + call<check_args>(tr, ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...); + if constexpr (clean_stack) { + lua_settop(L, 0); + } + return 0; + } + else { + (void)tr; + decltype(auto) r + = call<check_args>(types<meta::return_type_t<Ret0, Ret...>>(), ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...); + using R = meta::unqualified_t<decltype(r)>; + using is_stack = meta::any<is_stack_based<R>, std::is_same<R, absolute_index>, std::is_same<R, ref_index>, std::is_same<R, raw_index>>; + if constexpr (clean_stack && !is_stack::value) { + lua_settop(L, 0); + } + return push_reference(L, std::forward<decltype(r)>(r)); + } + } + + template <bool check_args = detail::default_safe_function_calls, bool clean_stack = true, typename Fx, typename... FxArgs> + inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { + using traits_type = lua_bind_traits<meta::unqualified_t<Fx>>; + using args_list = typename traits_type::args_list; + using returns_list = typename traits_type::returns_list; + return call_into_lua<check_args, clean_stack>(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...); + } + + inline call_syntax get_call_syntax(lua_State* L, const string_view& key, int index) { + if (lua_gettop(L) < 1) { + return call_syntax::dot; + } + luaL_getmetatable(L, key.data()); + auto pn = pop_n(L, 1); + if (lua_compare(L, -1, index, LUA_OPEQ) != 1) { + return call_syntax::dot; + } + return call_syntax::colon; + } + + inline void script( + lua_State* L, lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + detail::typical_chunk_name_t basechunkname = {}; + const char* chunknametarget = detail::make_chunk_name("lua_Reader", chunkname, basechunkname); + if (lua_load(L, reader, data, chunknametarget, to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) { + lua_error(L); + } + } + + inline void script( + lua_State* L, const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + + detail::typical_chunk_name_t basechunkname = {}; + const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); + if (luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) { + lua_error(L); + } + } + + inline void script_file(lua_State* L, const std::string& filename, load_mode mode = load_mode::any) { + if (luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) { + lua_error(L); + } + } + + inline void luajit_exception_handler(lua_State* L, int (*handler)(lua_State*, lua_CFunction) = detail::c_trampoline) { +#if SOL_IS_ON(SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE) + if (L == nullptr) { + return; + } +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushlightuserdata(L, (void*)handler); + auto pn = pop_n(L, 1); + luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON); +#else + (void)L; + (void)handler; +#endif + } + + inline void luajit_exception_off(lua_State* L) { +#if SOL_IS_ON(SOL_USE_LUAJIT_EXCEPTION_TRAMPOLINE) + if (L == nullptr) { + return; + } + luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_OFF); +#else + (void)L; +#endif + } + } // namespace stack +} // namespace sol + +// end of sol/stack.hpp + +// beginning of sol/object.hpp + +// beginning of sol/make_reference.hpp + +namespace sol { + + template <typename R = reference, bool should_pop = !is_stack_based_v<R>, typename T> + R make_reference(lua_State* L, T&& value) { + int backpedal = stack::push(L, std::forward<T>(value)); + R r = stack::get<R>(L, -backpedal); + if (should_pop) { + lua_pop(L, backpedal); + } + return r; + } + + template <typename T, typename R = reference, bool should_pop = !is_stack_based_v<R>, typename... Args> + R make_reference(lua_State* L, Args&&... args) { + int backpedal = stack::push<T>(L, std::forward<Args>(args)...); + R r = stack::get<R>(L, -backpedal); + if (should_pop) { + lua_pop(L, backpedal); + } + return r; + } + + template <typename R = reference, bool should_pop = !is_stack_based_v<R>, typename T> + R make_reference_userdata(lua_State* L, T&& value) { + int backpedal = stack::push_userdata(L, std::forward<T>(value)); + R r = stack::get<R>(L, -backpedal); + if (should_pop) { + lua_pop(L, backpedal); + } + return r; + } + + template <typename T, typename R = reference, bool should_pop = !is_stack_based_v<R>, typename... Args> + R make_reference_userdata(lua_State* L, Args&&... args) { + int backpedal = stack::push_userdata<T>(L, std::forward<Args>(args)...); + R r = stack::get<R>(L, -backpedal); + if (should_pop) { + lua_pop(L, backpedal); + } + return r; + } + +} // namespace sol + +// end of sol/make_reference.hpp + +// beginning of sol/object_base.hpp + +namespace sol { + + template <typename ref_t> + class basic_object_base : public ref_t { + private: + using base_t = ref_t; + + template <typename T> + decltype(auto) as_stack(std::true_type) const { + return stack::get<T>(base_t::lua_state(), base_t::stack_index()); + } + + template <typename T> + decltype(auto) as_stack(std::false_type) const { + base_t::push(); + return stack::pop<T>(base_t::lua_state()); + } + + template <typename T> + bool is_stack(std::true_type) const { + return stack::check<T>(base_t::lua_state(), base_t::stack_index(), &no_panic); + } + + template <typename T> + bool is_stack(std::false_type) const { + int r = base_t::registry_index(); + if (r == LUA_REFNIL) + return meta::any_same<meta::unqualified_t<T>, lua_nil_t, nullopt_t, std::nullptr_t>::value ? true : false; + if (r == LUA_NOREF) + return false; + auto pp = stack::push_pop(*this); + return stack::check<T>(base_t::lua_state(), -1, &no_panic); + } + + public: + basic_object_base() noexcept = default; + basic_object_base(const basic_object_base&) = default; + basic_object_base(basic_object_base&&) = default; + basic_object_base& operator=(const basic_object_base&) = default; + basic_object_base& operator=(basic_object_base&&) = default; + template <typename T, typename... Args, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_object_base>>> = meta::enabler> + basic_object_base(T&& arg, Args&&... args) : base_t(std::forward<T>(arg), std::forward<Args>(args)...) { + } + + template <typename T> + decltype(auto) as() const { + return as_stack<T>(is_stack_based<base_t>()); + } + + template <typename T> + bool is() const { + return is_stack<T>(is_stack_based<base_t>()); + } + }; +} // namespace sol + +// end of sol/object_base.hpp + +namespace sol { + + template <typename base_type> + class basic_object : public basic_object_base<base_type> { + private: + typedef basic_object_base<base_type> base_t; + + template <bool invert_and_pop = false> + basic_object(std::integral_constant<bool, invert_and_pop>, lua_State* L_, int index_ = -1) noexcept : base_t(L_, index_) { + if (invert_and_pop) { + lua_pop(L_, -index_); + } + } + + protected: + basic_object(detail::no_safety_tag, lua_nil_t n) : base_t(n) { + } + basic_object(detail::no_safety_tag, lua_State* L_, int index_) : base_t(L_, index_) { + } + basic_object(detail::no_safety_tag, lua_State* L_, ref_index index_) : base_t(L_, index_) { + } + template <typename T, + meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_object>>, meta::neg<std::is_same<base_type, stack_reference>>, + meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_object(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward<T>(r)) { + } + + template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_object(detail::no_safety_tag, lua_State* L_, T&& r) noexcept : base_t(L_, std::forward<T>(r)) { + } + + public: + basic_object() noexcept = default; + template <typename T, + meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_object>>, meta::neg<std::is_same<base_type, stack_reference>>, + is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_object(T&& r) : base_t(std::forward<T>(r)) { + } + template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_object(lua_State* L_, T&& r) : base_t(L_, std::forward<T>(r)) { + } + basic_object(lua_State* L_, global_tag_t t) : base_t(L_, t) { + } + basic_object(lua_nil_t r) : base_t(r) { + } + basic_object(const basic_object&) = default; + basic_object(basic_object&&) = default; + basic_object(const stack_reference& r) noexcept : basic_object(r.lua_state(), r.stack_index()) { + } + basic_object(stack_reference&& r) noexcept : basic_object(r.lua_state(), r.stack_index()) { + } + template <typename Super> + basic_object(const proxy_base<Super>& r) noexcept : basic_object(r.operator basic_object()) { + } + template <typename Super> + basic_object(proxy_base<Super>&& r) noexcept : basic_object(r.operator basic_object()) { + } + basic_object(lua_State* L_, lua_nil_t r) noexcept : base_t(L_, r) { + } + basic_object(lua_State* L_, int index_ = -1) noexcept : base_t(L_, index_) { + } + basic_object(lua_State* L_, absolute_index index_) noexcept : base_t(L_, index_) { + } + basic_object(lua_State* L_, raw_index index_) noexcept : base_t(L_, index_) { + } + basic_object(lua_State* L_, ref_index index_) noexcept : base_t(L_, index_) { + } + template <typename T, typename... Args> + basic_object(lua_State* L_, in_place_type_t<T>, Args&&... args) noexcept + : basic_object(std::integral_constant<bool, !is_stack_based<base_t>::value>(), L_, -stack::push<T>(L_, std::forward<Args>(args)...)) { + } + template <typename T, typename... Args> + basic_object(lua_State* L_, in_place_t, T&& arg, Args&&... args) noexcept + : basic_object(L_, in_place_type<T>, std::forward<T>(arg), std::forward<Args>(args)...) { + } + basic_object& operator=(const basic_object&) = default; + basic_object& operator=(basic_object&&) = default; + basic_object& operator=(const base_type& b) { + base_t::operator=(b); + return *this; + } + basic_object& operator=(base_type&& b) { + base_t::operator=(std::move(b)); + return *this; + } + template <typename Super> + basic_object& operator=(const proxy_base<Super>& r) { + this->operator=(r.operator basic_object()); + return *this; + } + template <typename Super> + basic_object& operator=(proxy_base<Super>&& r) { + this->operator=(r.operator basic_object()); + return *this; + } + }; + + template <typename T> + object make_object(lua_State* L_, T&& value) { + return make_reference<object, true>(L_, std::forward<T>(value)); + } + + template <typename T, typename... Args> + object make_object(lua_State* L_, Args&&... args) { + return make_reference<T, object, true>(L_, std::forward<Args>(args)...); + } + + template <typename T> + object make_object_userdata(lua_State* L_, T&& value) { + return make_reference_userdata<object, true>(L_, std::forward<T>(value)); + } + + template <typename T, typename... Args> + object make_object_userdata(lua_State* L_, Args&&... args) { + return make_reference_userdata<T, object, true>(L_, std::forward<Args>(args)...); + } +} // namespace sol + +// end of sol/object.hpp + +// beginning of sol/function.hpp + +// beginning of sol/unsafe_function.hpp + +// beginning of sol/function_result.hpp + +// beginning of sol/protected_function_result.hpp + +// beginning of sol/proxy_base.hpp + +namespace sol { + struct proxy_base_tag { }; + + namespace detail { + template <typename T> + using proxy_key_t = meta::conditional_t<meta::is_specialization_of_v<meta::unqualified_t<T>, std::tuple>, T, + std::tuple<meta::conditional_t<std::is_array_v<meta::unqualified_t<T>>, std::remove_reference_t<T>&, meta::unqualified_t<T>>>>; + } + + template <typename Super> + struct proxy_base : public proxy_base_tag { + lua_State* lua_state() const { + const Super& super = *static_cast<const Super*>(static_cast<const void*>(this)); + return super.lua_state(); + } + + operator std::string() const { + const Super& super = *static_cast<const Super*>(static_cast<const void*>(this)); + return super.template get<std::string>(); + } + + template <typename T, meta::enable<meta::neg<meta::is_string_constructible<T>>, is_proxy_primitive<meta::unqualified_t<T>>> = meta::enabler> + operator T() const { + const Super& super = *static_cast<const Super*>(static_cast<const void*>(this)); + return super.template get<T>(); + } + + template <typename T, + meta::enable<meta::neg<meta::is_string_constructible<T>>, meta::neg<is_proxy_primitive<meta::unqualified_t<T>>>> = meta::enabler> + operator T&() const { + const Super& super = *static_cast<const Super*>(static_cast<const void*>(this)); + return super.template get<T&>(); + } + }; + +} // namespace sol + +// end of sol/proxy_base.hpp + +// beginning of sol/stack_iterator.hpp + +#include <limits> +#include <iterator> + +namespace sol { + template <typename proxy_t, bool is_const> + struct stack_iterator { + typedef meta::conditional_t<is_const, const proxy_t, proxy_t> reference; + typedef meta::conditional_t<is_const, const proxy_t*, proxy_t*> pointer; + typedef proxy_t value_type; + typedef std::ptrdiff_t difference_type; + typedef std::random_access_iterator_tag iterator_category; + lua_State* L; + int index; + int stacktop; + proxy_t sp; + + stack_iterator() : L(nullptr), index((std::numeric_limits<int>::max)()), stacktop((std::numeric_limits<int>::max)()), sp() { + } + stack_iterator(const stack_iterator<proxy_t, true>& r) : L(r.L), index(r.index), stacktop(r.stacktop), sp(r.sp) { + } + stack_iterator(lua_State* luastate, int idx, int topidx) : L(luastate), index(idx), stacktop(topidx), sp(luastate, idx) { + } + + reference operator*() { + return proxy_t(L, index); + } + + reference operator*() const { + return proxy_t(L, index); + } + + pointer operator->() { + sp = proxy_t(L, index); + return &sp; + } + + pointer operator->() const { + const_cast<proxy_t&>(sp) = proxy_t(L, index); + return &sp; + } + + stack_iterator& operator++() { + ++index; + return *this; + } + + stack_iterator operator++(int) { + auto r = *this; + this->operator++(); + return r; + } + + stack_iterator& operator--() { + --index; + return *this; + } + + stack_iterator operator--(int) { + auto r = *this; + this->operator--(); + return r; + } + + stack_iterator& operator+=(difference_type idx) { + index += static_cast<int>(idx); + return *this; + } + + stack_iterator& operator-=(difference_type idx) { + index -= static_cast<int>(idx); + return *this; + } + + difference_type operator-(const stack_iterator& r) const { + return index - r.index; + } + + stack_iterator operator+(difference_type idx) const { + stack_iterator r = *this; + r += idx; + return r; + } + + reference operator[](difference_type idx) const { + return proxy_t(L, index + static_cast<int>(idx)); + } + + bool operator==(const stack_iterator& r) const { + if (stacktop == (std::numeric_limits<int>::max)()) { + return r.index == r.stacktop; + } + else if (r.stacktop == (std::numeric_limits<int>::max)()) { + return index == stacktop; + } + return index == r.index; + } + + bool operator!=(const stack_iterator& r) const { + return !(this->operator==(r)); + } + + bool operator<(const stack_iterator& r) const { + return index < r.index; + } + + bool operator>(const stack_iterator& r) const { + return index > r.index; + } + + bool operator<=(const stack_iterator& r) const { + return index <= r.index; + } + + bool operator>=(const stack_iterator& r) const { + return index >= r.index; + } + }; + + template <typename proxy_t, bool is_const> + inline stack_iterator<proxy_t, is_const> operator+( + typename stack_iterator<proxy_t, is_const>::difference_type n, const stack_iterator<proxy_t, is_const>& r) { + return r + n; + } +} // namespace sol + +// end of sol/stack_iterator.hpp + +// beginning of sol/stack_proxy.hpp + +// beginning of sol/stack_proxy_base.hpp + +namespace sol { + struct stack_proxy_base : public proxy_base<stack_proxy_base> { + private: + lua_State* m_L; + int m_index; + + public: + stack_proxy_base() : m_L(nullptr), m_index(0) { + } + stack_proxy_base(lua_State* L_, int index_) : m_L(L_), m_index(index_) { + } + + template <typename T> + decltype(auto) get() const { + return stack::get<T>(m_L, stack_index()); + } + + template <typename T> + bool is() const { + return stack::check<T>(m_L, stack_index()); + } + + template <typename T> + decltype(auto) as() const { + return get<T>(); + } + + type get_type() const noexcept { + return type_of(lua_state(), stack_index()); + } + + int push() const { + return push(m_L); + } + + int push(lua_State* L_) const { + lua_pushvalue(L_, m_index); + return 1; + } + + lua_State* lua_state() const { + return m_L; + } + int stack_index() const { + return m_index; + } + }; + + namespace stack { + template <> + struct unqualified_getter<stack_proxy_base> { + static stack_proxy_base get(lua_State* L_, int index_ = -1) { + return stack_proxy_base(L_, index_); + } + }; + + template <> + struct unqualified_pusher<stack_proxy_base> { + static int push(lua_State*, const stack_proxy_base& proxy_reference) { + return proxy_reference.push(); + } + }; + } // namespace stack + +} // namespace sol + +// end of sol/stack_proxy_base.hpp + +namespace sol { + struct stack_proxy : public stack_proxy_base { + public: + stack_proxy() : stack_proxy_base() { + } + stack_proxy(lua_State* L, int index) : stack_proxy_base(L, index) { + } + + template <typename... Ret, typename... Args> + decltype(auto) call(Args&&... args); + + template <typename... Args> + decltype(auto) operator()(Args&&... args) { + return call<>(std::forward<Args>(args)...); + } + }; + + namespace stack { + template <> + struct unqualified_getter<stack_proxy> { + static stack_proxy get(lua_State* L, int index, record& tracking) { + tracking.use(0); + return stack_proxy(L, index); + } + }; + + template <> + struct unqualified_pusher<stack_proxy> { + static int push(lua_State*, const stack_proxy& ref) { + return ref.push(); + } + }; + } // namespace stack +} // namespace sol + +// end of sol/stack_proxy.hpp + +#include <cstdint> + +namespace sol { + struct protected_function_result : public proxy_base<protected_function_result> { + private: + lua_State* L; + int index; + int returncount; + int popcount; + call_status err; + + public: + typedef stack_proxy reference_type; + typedef stack_proxy value_type; + typedef stack_proxy* pointer; + typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + typedef stack_iterator<stack_proxy, false> iterator; + typedef stack_iterator<stack_proxy, true> const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + protected_function_result() noexcept : protected_function_result(nullptr) {} + protected_function_result(lua_State* Ls, int idx = -1, int retnum = 0, int popped = 0, call_status pferr = call_status::ok) noexcept + : L(Ls), index(idx), returncount(retnum), popcount(popped), err(pferr) { + } + + // We do not want anyone to copy these around willy-nilly + // Will likely break people, but also will probably get rid of quiet bugs that have + // been lurking. (E.g., Vanilla Lua will just quietly discard over-pops and under-pops: + // LuaJIT and other Lua engines will implode and segfault at random later times.) + protected_function_result(const protected_function_result&) = delete; + protected_function_result& operator=(const protected_function_result&) = delete; + + protected_function_result(protected_function_result&& o) noexcept + : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), err(o.err) { + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but we will be thorough + o.abandon(); + } + protected_function_result& operator=(protected_function_result&& o) noexcept { + L = o.L; + index = o.index; + returncount = o.returncount; + popcount = o.popcount; + err = o.err; + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but we will be thorough + o.abandon(); + return *this; + } + + protected_function_result(const unsafe_function_result& o) = delete; + protected_function_result& operator=(const unsafe_function_result& o) = delete; + protected_function_result(unsafe_function_result&& o) noexcept; + protected_function_result& operator=(unsafe_function_result&& o) noexcept; + + call_status status() const noexcept { + return err; + } + + bool valid() const noexcept { + return status() == call_status::ok || status() == call_status::yielded; + } + +#if SOL_IS_ON(SOL_COMPILER_GCC) +#pragma GCC diagnostic push +#if !SOL_IS_ON(SOL_COMPILER_CLANG) +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif +#endif + + template <typename T> + decltype(auto) get(int index_offset = 0) const { + using UT = meta::unqualified_t<T>; + int target = index + index_offset; + if constexpr (meta::is_optional_v<UT>) { + using ValueType = typename UT::value_type; + if constexpr (std::is_same_v<ValueType, error>) { + if (valid()) { + return UT(); + } + return UT(error(detail::direct_error, stack::get<std::string>(L, target))); + } + else { + if (!valid()) { + return UT(); + } + return stack::get<UT>(L, target); + } + } + else { + if constexpr (std::is_same_v<T, error>) { +#if SOL_IS_ON(SOL_SAFE_PROXIES) + if (valid()) { + type t = type_of(L, target); + type_panic_c_str(L, target, t, type::none, "bad get from protected_function_result (is an error)"); + } +#endif // Check Argument Safety + return error(detail::direct_error, stack::get<std::string>(L, target)); + } + else { +#if SOL_IS_ON(SOL_SAFE_PROXIES) + if (!valid()) { + type t = type_of(L, target); + type_panic_c_str(L, target, t, type::none, "bad get from protected_function_result (is not an error)"); + } +#endif // Check Argument Safety + return stack::get<T>(L, target); + } + } + } + +#if SOL_IS_ON(SOL_COMPILER_GCC) +#pragma GCC diagnostic pop +#endif + + type get_type(int index_offset = 0) const noexcept { + return type_of(L, index + static_cast<int>(index_offset)); + } + + stack_proxy operator[](difference_type index_offset) const { + return stack_proxy(L, index + static_cast<int>(index_offset)); + } + + iterator begin() { + return iterator(L, index, stack_index() + return_count()); + } + iterator end() { + return iterator(L, stack_index() + return_count(), stack_index() + return_count()); + } + const_iterator begin() const { + return const_iterator(L, index, stack_index() + return_count()); + } + const_iterator end() const { + return const_iterator(L, stack_index() + return_count(), stack_index() + return_count()); + } + const_iterator cbegin() const { + return begin(); + } + const_iterator cend() const { + return end(); + } + + reverse_iterator rbegin() { + return std::reverse_iterator<iterator>(begin()); + } + reverse_iterator rend() { + return std::reverse_iterator<iterator>(end()); + } + const_reverse_iterator rbegin() const { + return std::reverse_iterator<const_iterator>(begin()); + } + const_reverse_iterator rend() const { + return std::reverse_iterator<const_iterator>(end()); + } + const_reverse_iterator crbegin() const { + return std::reverse_iterator<const_iterator>(cbegin()); + } + const_reverse_iterator crend() const { + return std::reverse_iterator<const_iterator>(cend()); + } + + lua_State* lua_state() const noexcept { + return L; + }; + int stack_index() const noexcept { + return index; + }; + int return_count() const noexcept { + return returncount; + }; + int pop_count() const noexcept { + return popcount; + }; + void abandon() noexcept { + // L = nullptr; + index = 0; + returncount = 0; + popcount = 0; + err = call_status::runtime; + } + ~protected_function_result() { + if (L == nullptr) + return; + stack::remove(L, index, popcount); + } + }; + + namespace stack { + template <> + struct unqualified_pusher<protected_function_result> { + static int push(lua_State* L, const protected_function_result& pfr) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, static_cast<int>(pfr.pop_count()), detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + int p = 0; + for (int i = 0; i < pfr.pop_count(); ++i) { + lua_pushvalue(L, i + pfr.stack_index()); + ++p; + } + return p; + } + }; + } // namespace stack +} // namespace sol + +// end of sol/protected_function_result.hpp + +// beginning of sol/unsafe_function_result.hpp + +#include <cstdint> + +namespace sol { + struct unsafe_function_result : public proxy_base<unsafe_function_result> { + private: + lua_State* L; + int index; + int returncount; + + public: + typedef stack_proxy reference_type; + typedef stack_proxy value_type; + typedef stack_proxy* pointer; + typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + typedef stack_iterator<stack_proxy, false> iterator; + typedef stack_iterator<stack_proxy, true> const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + unsafe_function_result() noexcept : unsafe_function_result(nullptr) {} + unsafe_function_result(lua_State* Ls, int idx = -1, int retnum = 0) noexcept : L(Ls), index(idx), returncount(retnum) { + } + + // We do not want anyone to copy these around willy-nilly + // Will likely break people, but also will probably get rid of quiet bugs that have + // been lurking. (E.g., Vanilla Lua will just quietly discard over-pops and under-pops: + // LuaJIT and other Lua engines will implode and segfault at random later times.) + unsafe_function_result(const unsafe_function_result&) = delete; + unsafe_function_result& operator=(const unsafe_function_result&) = delete; + + unsafe_function_result(unsafe_function_result&& o) noexcept : L(o.L), index(o.index), returncount(o.returncount) { + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but will be thorough + o.abandon(); + } + unsafe_function_result& operator=(unsafe_function_result&& o) noexcept { + L = o.L; + index = o.index; + returncount = o.returncount; + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but will be thorough + o.abandon(); + return *this; + } + + unsafe_function_result(const protected_function_result& o) = delete; + unsafe_function_result& operator=(const protected_function_result& o) = delete; + unsafe_function_result(protected_function_result&& o) noexcept; + unsafe_function_result& operator=(protected_function_result&& o) noexcept; + + template <typename T> + decltype(auto) get(difference_type index_offset = 0) const { + return stack::get<T>(L, index + static_cast<int>(index_offset)); + } + + type get_type(difference_type index_offset = 0) const noexcept { + return type_of(L, index + static_cast<int>(index_offset)); + } + + stack_proxy operator[](difference_type index_offset) const { + return stack_proxy(L, index + static_cast<int>(index_offset)); + } + + iterator begin() { + return iterator(L, index, stack_index() + return_count()); + } + iterator end() { + return iterator(L, stack_index() + return_count(), stack_index() + return_count()); + } + const_iterator begin() const { + return const_iterator(L, index, stack_index() + return_count()); + } + const_iterator end() const { + return const_iterator(L, stack_index() + return_count(), stack_index() + return_count()); + } + const_iterator cbegin() const { + return begin(); + } + const_iterator cend() const { + return end(); + } + + reverse_iterator rbegin() { + return std::reverse_iterator<iterator>(begin()); + } + reverse_iterator rend() { + return std::reverse_iterator<iterator>(end()); + } + const_reverse_iterator rbegin() const { + return std::reverse_iterator<const_iterator>(begin()); + } + const_reverse_iterator rend() const { + return std::reverse_iterator<const_iterator>(end()); + } + const_reverse_iterator crbegin() const { + return std::reverse_iterator<const_iterator>(cbegin()); + } + const_reverse_iterator crend() const { + return std::reverse_iterator<const_iterator>(cend()); + } + + call_status status() const noexcept { + return call_status::ok; + } + + bool valid() const noexcept { + return status() == call_status::ok || status() == call_status::yielded; + } + + lua_State* lua_state() const { + return L; + }; + int stack_index() const { + return index; + }; + int return_count() const { + return returncount; + }; + void abandon() noexcept { + // L = nullptr; + index = 0; + returncount = 0; + } + ~unsafe_function_result() { + if (L != nullptr) { + lua_pop(L, returncount); + } + } + }; + + namespace stack { + template <> + struct unqualified_pusher<unsafe_function_result> { + static int push(lua_State* L, const unsafe_function_result& fr) { + int p = 0; + for (int i = 0; i < fr.return_count(); ++i) { + lua_pushvalue(L, i + fr.stack_index()); + ++p; + } + return p; + } + }; + } // namespace stack +} // namespace sol + +// end of sol/unsafe_function_result.hpp + +#include <cstdint> + +namespace sol { + + namespace detail { + template <> + struct is_speshul<unsafe_function_result> : std::true_type { }; + template <> + struct is_speshul<protected_function_result> : std::true_type { }; + + template <std::size_t I, typename... Args, typename T> + stack_proxy get(types<Args...>, meta::index_value<0>, meta::index_value<I>, const T& fr) { + return stack_proxy(fr.lua_state(), fr.stack_index() + static_cast<int>(I)); + } + + template <std::size_t I, std::size_t N, typename Arg, typename... Args, typename T, meta::enable<meta::boolean<(N > 0)>> = meta::enabler> + stack_proxy get(types<Arg, Args...>, meta::index_value<N>, meta::index_value<I>, const T& fr) { + return get(types<Args...>(), meta::index_value<N - 1>(), meta::index_value<I + lua_size<Arg>::value>(), fr); + } + } // namespace detail + + template <> + struct tie_size<unsafe_function_result> : std::integral_constant<std::size_t, SIZE_MAX> { }; + + template <> + struct tie_size<protected_function_result> : std::integral_constant<std::size_t, SIZE_MAX> { }; + + template <std::size_t I> + stack_proxy get(const unsafe_function_result& fr) { + return stack_proxy(fr.lua_state(), fr.stack_index() + static_cast<int>(I)); + } + + template <std::size_t I, typename... Args> + stack_proxy get(types<Args...> t, const unsafe_function_result& fr) { + return detail::get(t, meta::index_value<I>(), meta::index_value<0>(), fr); + } + + template <std::size_t I> + stack_proxy get(const protected_function_result& fr) { + return stack_proxy(fr.lua_state(), fr.stack_index() + static_cast<int>(I)); + } + + template <std::size_t I, typename... Args> + stack_proxy get(types<Args...> t, const protected_function_result& fr) { + return detail::get(t, meta::index_value<I>(), meta::index_value<0>(), fr); + } +} // namespace sol + +// end of sol/function_result.hpp + +// beginning of sol/function_types.hpp + +// beginning of sol/function_types_core.hpp + +// beginning of sol/wrapper.hpp + +namespace sol { + + namespace detail { + template <typename T> + using array_return_type = meta::conditional_t<std::is_array<T>::value, std::add_lvalue_reference_t<T>, T>; + } + + template <typename F, typename = void> + struct wrapper { + typedef lua_bind_traits<meta::unqualified_t<F>> traits_type; + typedef typename traits_type::args_list args_list; + typedef typename traits_type::args_list free_args_list; + typedef typename traits_type::returns_list returns_list; + + template <typename... Args> + static decltype(auto) call(F& f, Args&&... args) { + return f(std::forward<Args>(args)...); + } + + struct caller { + template <typename... Args> + decltype(auto) operator()(F& fx, Args&&... args) const { + return call(fx, std::forward<Args>(args)...); + } + }; + }; + + template <typename F> + struct wrapper<F, std::enable_if_t<std::is_function<std::remove_pointer_t<meta::unqualified_t<F>>>::value>> { + typedef lua_bind_traits<std::remove_pointer_t<meta::unqualified_t<F>>> traits_type; + typedef typename traits_type::args_list args_list; + typedef typename traits_type::args_list free_args_list; + typedef typename traits_type::returns_list returns_list; + + template <F fx, typename... Args> + static decltype(auto) invoke(Args&&... args) { + return fx(std::forward<Args>(args)...); + } + + template <typename... Args> + static decltype(auto) call(F& fx, Args&&... args) { + return fx(std::forward<Args>(args)...); + } + + struct caller { + template <typename... Args> + decltype(auto) operator()(F& fx, Args&&... args) const { + return call(fx, std::forward<Args>(args)...); + } + }; + + template <F fx> + struct invoker { + template <typename... Args> + decltype(auto) operator()(Args&&... args) const { + return invoke<fx>(std::forward<Args>(args)...); + } + }; + }; + + template <typename F> + struct wrapper<F, std::enable_if_t<std::is_member_object_pointer<meta::unqualified_t<F>>::value>> { + typedef lua_bind_traits<meta::unqualified_t<F>> traits_type; + typedef typename traits_type::object_type object_type; + typedef typename traits_type::return_type return_type; + typedef typename traits_type::args_list args_list; + typedef types<object_type&, return_type> free_args_list; + typedef typename traits_type::returns_list returns_list; + + template <F fx> + static auto call(object_type& mem) -> detail::array_return_type<decltype(mem.*fx)> { + return mem.*fx; + } + + template <F fx, typename Arg, typename... Args> + static decltype(auto) invoke(object_type& mem, Arg&& arg, Args&&...) { + return mem.*fx = std::forward<Arg>(arg); + } + + template <typename Fx> + static auto call(Fx&& fx, object_type& mem) -> detail::array_return_type<decltype(mem.*fx)> { + return mem.*fx; + } + + template <typename Fx, typename Arg, typename... Args> + static void call(Fx&& fx, object_type& mem, Arg&& arg, Args&&...) { + using actual_type = meta::unqualified_t<detail::array_return_type<decltype(mem.*fx)>>; + if constexpr (std::is_array_v<actual_type>) { + using std::cbegin; + using std::cend; + auto first = cbegin(arg); + auto last = cend(arg); + for (std::size_t i = 0; first != last; ++i, ++first) { + (mem.*fx)[i] = *first; + } + } + else { + (mem.*fx) = std::forward<Arg>(arg); + } + } + + struct caller { + template <typename Fx, typename... Args> + decltype(auto) operator()(Fx&& fx, object_type& mem, Args&&... args) const { + return call(std::forward<Fx>(fx), mem, std::forward<Args>(args)...); + } + }; + + template <F fx> + struct invoker { + template <typename... Args> + decltype(auto) operator()(Args&&... args) const { + return invoke<fx>(std::forward<Args>(args)...); + } + }; + }; + + template <typename F, typename R, typename O, typename... FArgs> + struct member_function_wrapper { + typedef O object_type; + typedef lua_bind_traits<F> traits_type; + typedef typename traits_type::args_list args_list; + typedef types<object_type&, FArgs...> free_args_list; + typedef meta::tuple_types<R> returns_list; + + template <F fx, typename... Args> + static R invoke(O& mem, Args&&... args) { + return (mem.*fx)(std::forward<Args>(args)...); + } + + template <typename Fx, typename... Args> + static R call(Fx&& fx, O& mem, Args&&... args) { + return (mem.*fx)(std::forward<Args>(args)...); + } + + struct caller { + template <typename Fx, typename... Args> + decltype(auto) operator()(Fx&& fx, O& mem, Args&&... args) const { + return call(std::forward<Fx>(fx), mem, std::forward<Args>(args)...); + } + }; + + template <F fx> + struct invoker { + template <typename... Args> + decltype(auto) operator()(O& mem, Args&&... args) const { + return invoke<fx>(mem, std::forward<Args>(args)...); + } + }; + }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...)> : public member_function_wrapper<R (O::*)(Args...), R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...) const> : public member_function_wrapper<R (O::*)(Args...) const, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...) const volatile> : public member_function_wrapper<R (O::*)(Args...) const volatile, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...)&> : public member_function_wrapper<R (O::*)(Args...)&, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...) const&> : public member_function_wrapper<R (O::*)(Args...) const&, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...) const volatile&> : public member_function_wrapper<R (O::*)(Args...) const volatile&, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args..., ...)&> : public member_function_wrapper<R (O::*)(Args..., ...)&, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args..., ...) const&> : public member_function_wrapper<R (O::*)(Args..., ...) const&, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args..., ...) const volatile&> : public member_function_wrapper<R (O::*)(Args..., ...) const volatile&, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...) &&> : public member_function_wrapper<R (O::*)(Args...)&, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...) const&&> : public member_function_wrapper<R (O::*)(Args...) const&, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...) const volatile&&> : public member_function_wrapper<R (O::*)(Args...) const volatile&, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args..., ...) &&> : public member_function_wrapper<R (O::*)(Args..., ...)&, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args..., ...) const&&> : public member_function_wrapper<R (O::*)(Args..., ...) const&, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args..., ...) const volatile&&> : public member_function_wrapper<R (O::*)(Args..., ...) const volatile&, R, O, Args...> { }; + +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) + // noexcept has become a part of a function's type + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...) noexcept> : public member_function_wrapper<R (O::*)(Args...) noexcept, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...) const noexcept> : public member_function_wrapper<R (O::*)(Args...) const noexcept, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...) const volatile noexcept> : public member_function_wrapper<R (O::*)(Args...) const volatile noexcept, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...)& noexcept> : public member_function_wrapper<R (O::*)(Args...)& noexcept, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...) const& noexcept> : public member_function_wrapper<R (O::*)(Args...) const& noexcept, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...) const volatile& noexcept> : public member_function_wrapper<R (O::*)(Args...) const volatile& noexcept, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args..., ...)& noexcept> : public member_function_wrapper<R (O::*)(Args..., ...)& noexcept, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args..., ...) const& noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) const& noexcept, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args..., ...) const volatile& noexcept> + : public member_function_wrapper<R (O::*)(Args..., ...) const volatile& noexcept, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...)&& noexcept> : public member_function_wrapper<R (O::*)(Args...)& noexcept, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...) const&& noexcept> : public member_function_wrapper<R (O::*)(Args...) const& noexcept, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args...) const volatile&& noexcept> : public member_function_wrapper<R (O::*)(Args...) const volatile& noexcept, R, O, Args...> { + }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args..., ...)&& noexcept> : public member_function_wrapper<R (O::*)(Args..., ...)& noexcept, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args..., ...) const&& noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) const& noexcept, R, O, Args...> { }; + + template <typename R, typename O, typename... Args> + struct wrapper<R (O::*)(Args..., ...) const volatile&& noexcept> + : public member_function_wrapper<R (O::*)(Args..., ...) const volatile& noexcept, R, O, Args...> { }; + +#endif // noexcept is part of a function's type + +} // namespace sol + +// end of sol/wrapper.hpp + +#include <memory> + +namespace sol { namespace function_detail { + template <typename Fx, int start = 1, bool is_yielding = false> + int call(lua_State* L) { + Fx& fx = stack::get<user<Fx>>(L, upvalue_index(start)); + int nr = fx(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } + } +}} // namespace sol::function_detail + +// end of sol/function_types_core.hpp + +// beginning of sol/function_types_templated.hpp + +// beginning of sol/call.hpp + +// beginning of sol/property.hpp + +#include <type_traits> +#include <utility> + +namespace sol { + namespace detail { + struct no_prop { }; + } // namespace detail + + template <typename R, typename W> + struct property_wrapper : detail::ebco<R, 0>, detail::ebco<W, 1> { + private: + using read_base_t = detail::ebco<R, 0>; + using write_base_t = detail::ebco<W, 1>; + + public: + template <typename Rx, typename Wx> + property_wrapper(Rx&& r, Wx&& w) : read_base_t(std::forward<Rx>(r)), write_base_t(std::forward<Wx>(w)) { + } + + W& write() { + return write_base_t::value(); + } + + const W& write() const { + return write_base_t::value(); + } + + R& read() { + return read_base_t::value(); + } + + const R& read() const { + return read_base_t::value(); + } + }; + + template <typename F, typename G> + inline decltype(auto) property(F&& f, G&& g) { + typedef lua_bind_traits<meta::unqualified_t<F>> left_traits; + typedef lua_bind_traits<meta::unqualified_t<G>> right_traits; + if constexpr (left_traits::free_arity < right_traits::free_arity) { + return property_wrapper<std::decay_t<F>, std::decay_t<G>>(std::forward<F>(f), std::forward<G>(g)); + } + else { + return property_wrapper<std::decay_t<G>, std::decay_t<F>>(std::forward<G>(g), std::forward<F>(f)); + } + } + + template <typename F> + inline decltype(auto) property(F&& f) { + typedef lua_bind_traits<meta::unqualified_t<F>> left_traits; + if constexpr (left_traits::free_arity < 2) { + return property_wrapper<std::decay_t<F>, detail::no_prop>(std::forward<F>(f), detail::no_prop()); + } + else { + return property_wrapper<detail::no_prop, std::decay_t<F>>(detail::no_prop(), std::forward<F>(f)); + } + } + + template <typename F> + inline decltype(auto) readonly_property(F&& f) { + return property_wrapper<std::decay_t<F>, detail::no_prop>(std::forward<F>(f), detail::no_prop()); + } + + template <typename F> + inline decltype(auto) writeonly_property(F&& f) { + return property_wrapper<detail::no_prop, std::decay_t<F>>(detail::no_prop(), std::forward<F>(f)); + } + + template <typename T> + struct readonly_wrapper : detail::ebco<T> { + private: + using base_t = detail::ebco<T>; + + public: + using base_t::base_t; + + operator T&() { + return base_t::value(); + } + operator const T&() const { + return base_t::value(); + } + }; + + // Allow someone to make a member variable readonly (const) + template <typename R, typename T> + inline auto readonly(R T::*v) { + return readonly_wrapper<meta::unqualified_t<decltype(v)>>(v); + } + + template <typename T> + struct var_wrapper : detail::ebco<T> { + private: + using base_t = detail::ebco<T>; + + public: + using base_t::base_t; + }; + + template <typename V> + inline auto var(V&& v) { + typedef std::decay_t<V> T; + return var_wrapper<T>(std::forward<V>(v)); + } + + namespace meta { + template <typename T> + using is_member_object = std::integral_constant<bool, std::is_member_object_pointer_v<T> || is_specialization_of_v<T, readonly_wrapper>>; + + template <typename T> + inline constexpr bool is_member_object_v = is_member_object<T>::value; + + template <typename T> + using is_member_object_or_function = std::integral_constant<bool, is_member_object_v<T> || std::is_member_pointer_v<T>>; + + template <typename T> + inline constexpr bool is_member_object_or_function_v = is_member_object_or_function<T>::value; + } // namespace meta + +} // namespace sol + +// end of sol/property.hpp + +// beginning of sol/protect.hpp + +#include <utility> + +namespace sol { + + template <typename T> + struct protect_t { + T value; + + template <typename Arg, typename... Args, meta::disable<std::is_same<protect_t, meta::unqualified_t<Arg>>> = meta::enabler> + protect_t(Arg&& arg, Args&&... args) : value(std::forward<Arg>(arg), std::forward<Args>(args)...) { + } + + protect_t(const protect_t&) = default; + protect_t(protect_t&&) = default; + protect_t& operator=(const protect_t&) = default; + protect_t& operator=(protect_t&&) = default; + }; + + template <typename T> + auto protect(T&& value) { + return protect_t<std::decay_t<T>>(std::forward<T>(value)); + } + +} // namespace sol + +// end of sol/protect.hpp + +namespace sol { + namespace u_detail { + + } // namespace u_detail + + namespace policy_detail { + template <int I, int... In> + inline void handle_policy(static_stack_dependencies<I, In...>, lua_State* L, int&) { + if constexpr (sizeof...(In) == 0) { + (void)L; + return; + } + else { + absolute_index ai(L, I); + if (type_of(L, ai) != type::userdata) { + return; + } + lua_createtable(L, static_cast<int>(sizeof...(In)), 0); + stack_reference deps(L, -1); + auto per_dep = [&L, &deps](int i) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushvalue(L, i); + luaL_ref(L, deps.stack_index()); + }; + (void)per_dep; + (void)detail::swallow { int(), (per_dep(In), int())... }; + lua_setuservalue(L, ai); + } + } + + template <int... In> + inline void handle_policy(returns_self_with<In...>, lua_State* L, int& pushed) { + pushed = stack::push(L, raw_index(1)); + handle_policy(static_stack_dependencies<-1, In...>(), L, pushed); + } + + inline void handle_policy(const stack_dependencies& sdeps, lua_State* L, int&) { + absolute_index ai(L, sdeps.target); + if (type_of(L, ai) != type::userdata) { + return; + } + lua_createtable(L, static_cast<int>(sdeps.size()), 0); + stack_reference deps(L, -1); +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, static_cast<int>(sdeps.size()), detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + for (std::size_t i = 0; i < sdeps.size(); ++i) { + lua_pushvalue(L, sdeps.stack_indices[i]); + luaL_ref(L, deps.stack_index()); + } + lua_setuservalue(L, ai); + } + + template <typename P, meta::disable<std::is_base_of<detail::policy_base_tag, meta::unqualified_t<P>>> = meta::enabler> + inline void handle_policy(P&& p, lua_State* L, int& pushed) { + pushed = std::forward<P>(p)(L, pushed); + } + } // namespace policy_detail + + namespace function_detail { + inline int no_construction_error(lua_State* L) { + return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)"); + } + } // namespace function_detail + + namespace call_detail { + + template <typename R, typename W> + inline auto& pick(std::true_type, property_wrapper<R, W>& f) { + return f.read(); + } + + template <typename R, typename W> + inline auto& pick(std::false_type, property_wrapper<R, W>& f) { + return f.write(); + } + + template <typename T, typename List> + struct void_call : void_call<T, meta::function_args_t<List>> { }; + + template <typename T, typename... Args> + struct void_call<T, types<Args...>> { + static void call(Args...) { + } + }; + + template <typename T, bool checked, bool clean_stack> + struct constructor_match { + T* obj_; + reference* obj_lua_ref_; + stack::stack_detail::undefined_metatable* p_umf_; + + constructor_match(T* obj_ptr, reference& obj_lua_ref, stack::stack_detail::undefined_metatable& umf) + : obj_(obj_ptr), obj_lua_ref_(&obj_lua_ref), p_umf_(&umf) { + } + + template <typename Fx, std::size_t I, typename... R, typename... Args> + int operator()(types<Fx>, meta::index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const { + detail::default_construct func {}; + int result = stack::call_into_lua<checked, clean_stack>(r, a, L, start, func, this->obj_); + // construct userdata table + // SPECIFICALLY, after we've created it successfully. + // If the constructor exits for any reason we have to break things down... + if constexpr (clean_stack) { + obj_lua_ref_->push(); + (*this->p_umf_)(); + obj_lua_ref_->pop(); + } + else { + (*this->p_umf_)(); + } + return result; + } + }; + + namespace overload_detail { + template <std::size_t... M, typename Match, typename... Args> + inline int overload_match_arity(types<>, std::index_sequence<>, std::index_sequence<M...>, Match&&, lua_State* L, int, int, Args&&...) { + return luaL_error(L, "sol: no matching function call takes this number of arguments and the specified types"); + } + + template <typename Fx, typename... Fxs, std::size_t I, std::size_t... In, std::size_t... M, typename Match, typename... Args> + inline int overload_match_arity(types<Fx, Fxs...>, std::index_sequence<I, In...>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, + int fxarity, int start, Args&&... args) { + typedef lua_bind_traits<meta::unwrap_unqualified_t<Fx>> traits; + typedef meta::tuple_types<typename traits::return_type> return_types; + typedef typename traits::free_args_list args_list; + // compile-time eliminate any functions that we know ahead of time are of improper arity + if constexpr (!traits::runtime_variadics_t::value + && meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) { + return overload_match_arity(types<Fxs...>(), + std::index_sequence<In...>(), + std::index_sequence<M...>(), + std::forward<Match>(matchfx), + L, + fxarity, + start, + std::forward<Args>(args)...); + } + else { + if constexpr (!traits::runtime_variadics_t::value) { + if (traits::free_arity != fxarity) { + return overload_match_arity(types<Fxs...>(), + std::index_sequence<In...>(), + std::index_sequence<traits::free_arity, M...>(), + std::forward<Match>(matchfx), + L, + fxarity, + start, + std::forward<Args>(args)...); + } + } + stack::record tracking {}; + if (!stack::stack_detail::check_types(args_list(), L, start, &no_panic, tracking)) { + return overload_match_arity(types<Fxs...>(), + std::index_sequence<In...>(), + std::index_sequence<M...>(), + std::forward<Match>(matchfx), + L, + fxarity, + start, + std::forward<Args>(args)...); + } + return matchfx(types<Fx>(), meta::index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...); + } + } + + template <std::size_t... M, typename Match, typename... Args> + inline int overload_match_arity_single( + types<>, std::index_sequence<>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { + return overload_match_arity(types<>(), + std::index_sequence<>(), + std::index_sequence<M...>(), + std::forward<Match>(matchfx), + L, + fxarity, + start, + std::forward<Args>(args)...); + } + + template <typename Fx, std::size_t I, std::size_t... M, typename Match, typename... Args> + inline int overload_match_arity_single( + types<Fx>, std::index_sequence<I>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { + typedef lua_bind_traits<meta::unwrap_unqualified_t<Fx>> traits; + typedef meta::tuple_types<typename traits::return_type> return_types; + typedef typename traits::free_args_list args_list; + // compile-time eliminate any functions that we know ahead of time are of improper arity + if constexpr (!traits::runtime_variadics_t::value + && meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) { + return overload_match_arity(types<>(), + std::index_sequence<>(), + std::index_sequence<M...>(), + std::forward<Match>(matchfx), + L, + fxarity, + start, + std::forward<Args>(args)...); + } + if constexpr (!traits::runtime_variadics_t::value) { + if (traits::free_arity != fxarity) { + return overload_match_arity(types<>(), + std::index_sequence<>(), + std::index_sequence<traits::free_arity, M...>(), + std::forward<Match>(matchfx), + L, + fxarity, + start, + std::forward<Args>(args)...); + } + } + return matchfx(types<Fx>(), meta::index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...); + } + + template <typename Fx, typename Fx1, typename... Fxs, std::size_t I, std::size_t I1, std::size_t... In, std::size_t... M, typename Match, + typename... Args> + inline int overload_match_arity_single(types<Fx, Fx1, Fxs...>, std::index_sequence<I, I1, In...>, std::index_sequence<M...>, Match&& matchfx, + lua_State* L, int fxarity, int start, Args&&... args) { + typedef lua_bind_traits<meta::unwrap_unqualified_t<Fx>> traits; + typedef meta::tuple_types<typename traits::return_type> return_types; + typedef typename traits::free_args_list args_list; + // compile-time eliminate any functions that we know ahead of time are of improper arity + if constexpr (!traits::runtime_variadics_t::value + && meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) { + return overload_match_arity(types<Fx1, Fxs...>(), + std::index_sequence<I1, In...>(), + std::index_sequence<M...>(), + std::forward<Match>(matchfx), + L, + fxarity, + start, + std::forward<Args>(args)...); + } + else { + if constexpr (!traits::runtime_variadics_t::value) { + if (traits::free_arity != fxarity) { + return overload_match_arity(types<Fx1, Fxs...>(), + std::index_sequence<I1, In...>(), + std::index_sequence<traits::free_arity, M...>(), + std::forward<Match>(matchfx), + L, + fxarity, + start, + std::forward<Args>(args)...); + } + } + stack::record tracking {}; + if (!stack::stack_detail::check_types(args_list(), L, start, &no_panic, tracking)) { + return overload_match_arity(types<Fx1, Fxs...>(), + std::index_sequence<I1, In...>(), + std::index_sequence<M...>(), + std::forward<Match>(matchfx), + L, + fxarity, + start, + std::forward<Args>(args)...); + } + return matchfx(types<Fx>(), meta::index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...); + } + } + } // namespace overload_detail + + template <typename... Functions, typename Match, typename... Args> + inline int overload_match_arity(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { + return overload_detail::overload_match_arity_single(types<Functions...>(), + std::make_index_sequence<sizeof...(Functions)>(), + std::index_sequence<>(), + std::forward<Match>(matchfx), + L, + fxarity, + start, + std::forward<Args>(args)...); + } + + template <typename... Functions, typename Match, typename... Args> + inline int overload_match(Match&& matchfx, lua_State* L, int start, Args&&... args) { + int fxarity = lua_gettop(L) - (start - 1); + return overload_match_arity<Functions...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); + } + + template <typename T, typename... TypeLists, typename Match, typename... Args> + inline int construct_match(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { + // use same overload resolution matching as all other parts of the framework + return overload_match_arity<decltype(void_call<T, TypeLists>::call)...>( + std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); + } + + template <typename T, bool checked, bool clean_stack, typename... TypeLists> + inline int construct_trampolined(lua_State* L) { + static const auto& meta = usertype_traits<T>::metatable(); + int argcount = lua_gettop(L); + call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1) : call_syntax::dot; + argcount -= static_cast<int>(syntax); + + T* obj = detail::usertype_allocate<T>(L); + reference userdataref(L, -1); + stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on<T>); + + // put userdata at the first index + lua_insert(L, 1); + construct_match<T, TypeLists...>(constructor_match<T, checked, clean_stack>(obj, userdataref, umf), L, argcount, 1 + static_cast<int>(syntax)); + + userdataref.push(); + return 1; + } + + template <typename T, bool checked, bool clean_stack, typename... TypeLists> + inline int construct(lua_State* L) { + return detail::static_trampoline<&construct_trampolined<T, checked, clean_stack, TypeLists...>>(L); + } + + template <typename F, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename = void> + struct agnostic_lua_call_wrapper { + template <typename Fx, typename... Args> + static int call(lua_State* L, Fx&& f, Args&&... args) { + using uFx = meta::unqualified_t<Fx>; + static constexpr bool is_ref = is_lua_reference_v<uFx>; + if constexpr (is_ref) { + if constexpr (is_index) { + return stack::push(L, std::forward<Fx>(f), std::forward<Args>(args)...); + } + else { + std::forward<Fx>(f) = stack::unqualified_get<F>(L, boost + (is_variable ? 3 : 1)); + return 0; + } + } + else { + using wrap = wrapper<uFx>; + using traits_type = typename wrap::traits_type; + using fp_t = typename traits_type::function_pointer_type; + constexpr bool is_function_pointer_convertible = std::is_class_v<uFx> && std::is_convertible_v<std::decay_t<Fx>, fp_t>; + if constexpr (is_function_pointer_convertible) { + fp_t fx = f; + return agnostic_lua_call_wrapper<fp_t, is_index, is_variable, checked, boost, clean_stack> {}.call( + L, fx, std::forward<Args>(args)...); + } + else { + using returns_list = typename wrap::returns_list; + using args_list = typename wrap::free_args_list; + using caller = typename wrap::caller; + return stack::call_into_lua<checked, clean_stack>( + returns_list(), args_list(), L, boost + 1, caller(), std::forward<Fx>(f), std::forward<Args>(args)...); + } + } + } + }; + + template <typename T, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct agnostic_lua_call_wrapper<var_wrapper<T>, is_index, is_variable, checked, boost, clean_stack, C> { + template <typename F> + static int call(lua_State* L, F&& f) { + if constexpr (is_index) { + constexpr bool is_stack = is_stack_based_v<meta::unqualified_t<decltype(detail::unwrap(f.value()))>>; + if constexpr (clean_stack && !is_stack) { + lua_settop(L, 0); + } + return stack::push_reference(L, detail::unwrap(f.value())); + } + else { + if constexpr (std::is_const_v<meta::unwrapped_t<T>>) { + (void)f; + return luaL_error(L, "sol: cannot write to a readonly (const) variable"); + } + else { + using R = meta::unwrapped_t<T>; + if constexpr (std::is_assignable_v<std::add_lvalue_reference_t<meta::unqualified_t<R>>, R>) { + detail::unwrap(f.value()) = stack::unqualified_get<meta::unwrapped_t<T>>(L, boost + (is_variable ? 3 : 1)); + if (clean_stack) { + lua_settop(L, 0); + } + return 0; + } + else { + return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available"); + } + } + } + } + }; + + template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct agnostic_lua_call_wrapper<lua_CFunction_ref, is_index, is_variable, checked, boost, clean_stack, C> { + static int call(lua_State* L, lua_CFunction_ref f) { + return f(L); + } + }; + + template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct agnostic_lua_call_wrapper<lua_CFunction, is_index, is_variable, checked, boost, clean_stack, C> { + static int call(lua_State* L, lua_CFunction f) { + return f(L); + } + }; + +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) + template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct agnostic_lua_call_wrapper<detail::lua_CFunction_noexcept, is_index, is_variable, checked, boost, clean_stack, C> { + static int call(lua_State* L, detail::lua_CFunction_noexcept f) { + return f(L); + } + }; +#endif // noexcept function types + + template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct agnostic_lua_call_wrapper<detail::no_prop, is_index, is_variable, checked, boost, clean_stack, C> { + static int call(lua_State* L, const detail::no_prop&) { + return luaL_error(L, is_index ? "sol: cannot read from a writeonly property" : "sol: cannot write to a readonly property"); + } + }; + + template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct agnostic_lua_call_wrapper<no_construction, is_index, is_variable, checked, boost, clean_stack, C> { + static int call(lua_State* L, const no_construction&) { + return function_detail::no_construction_error(L); + } + }; + + template <typename... Args, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct agnostic_lua_call_wrapper<bases<Args...>, is_index, is_variable, checked, boost, clean_stack, C> { + static int call(lua_State*, const bases<Args...>&) { + // Uh. How did you even call this, lul + return 0; + } + }; + + template <typename T, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct agnostic_lua_call_wrapper<std::reference_wrapper<T>, is_index, is_variable, checked, boost, clean_stack, C> { + static int call(lua_State* L, std::reference_wrapper<T> f) { + agnostic_lua_call_wrapper<T, is_index, is_variable, checked, boost, clean_stack> alcw {}; + return alcw.call(L, f.get()); + } + }; + + template <typename T, typename F, bool is_index, bool is_variable, bool checked = detail::default_safe_function_calls, int boost = 0, + bool clean_stack = true, typename = void> + struct lua_call_wrapper { + template <typename Fx, typename... Args> + static int call(lua_State* L, Fx&& fx, Args&&... args) { + if constexpr (std::is_member_function_pointer_v<F>) { + using wrap = wrapper<F>; + using object_type = typename wrap::object_type; + if constexpr (sizeof...(Args) < 1) { + using Ta = meta::conditional_t<std::is_void_v<T>, object_type, T>; + static_assert(std::is_base_of_v<object_type, Ta>, + "It seems like you might have accidentally bound a class type with a member function method that does not correspond to the " + "class. For example, there could be a small type in your new_usertype<T>(...) binding, where you specify one class \"T\" " + "but then bind member methods from a complete unrelated class. Check things over!"); +#if SOL_IS_ON(SOL_SAFE_USERTYPE) + auto maybeo = stack::check_get<Ta*>(L, 1); + if (!maybeo || maybeo.value() == nullptr) { + return luaL_error(L, + "sol: received nil for 'self' argument (use ':' for accessing member functions, make sure member variables are " + "preceeded by the " + "actual object with '.' syntax)"); + } + object_type* o = static_cast<object_type*>(maybeo.value()); + return call(L, std::forward<Fx>(fx), *o); +#else + object_type& o = static_cast<object_type&>(*stack::unqualified_get<non_null<Ta*>>(L, 1)); + return call(L, std::forward<Fx>(fx), o); +#endif // Safety + } + else { + using returns_list = typename wrap::returns_list; + using args_list = typename wrap::args_list; + using caller = typename wrap::caller; + return stack::call_into_lua<checked, clean_stack>( + returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), std::forward<Fx>(fx), std::forward<Args>(args)...); + } + } + else if constexpr (std::is_member_object_pointer_v<F>) { + using wrap = wrapper<F>; + using object_type = typename wrap::object_type; + if constexpr (is_index) { + if constexpr (sizeof...(Args) < 1) { + using Ta = meta::conditional_t<std::is_void_v<T>, object_type, T>; + static_assert(std::is_base_of_v<object_type, Ta>, + "It seems like you might have accidentally bound a class type with a member function method that does not correspond " + "to the class. For example, there could be a small type in your new_usertype<T>(...) binding, where you specify one " + "class \"T\" but then bind member methods from a complete unrelated class. Check things over!"); +#if SOL_IS_ON(SOL_SAFE_USERTYPE) + auto maybeo = stack::check_get<Ta*>(L, 1); + if (!maybeo || maybeo.value() == nullptr) { + if (is_variable) { + return luaL_error(L, "sol: 'self' argument is lua_nil (bad '.' access?)"); + } + return luaL_error(L, "sol: 'self' argument is lua_nil (pass 'self' as first argument)"); + } + object_type* o = static_cast<object_type*>(maybeo.value()); + return call(L, std::forward<Fx>(fx), *o); +#else + object_type& o = static_cast<object_type&>(*stack::get<non_null<Ta*>>(L, 1)); + return call(L, std::forward<Fx>(fx), o); +#endif // Safety + } + else { + using returns_list = typename wrap::returns_list; + using caller = typename wrap::caller; + return stack::call_into_lua<checked, clean_stack>(returns_list(), + types<>(), + L, + boost + (is_variable ? 3 : 2), + caller(), + std::forward<Fx>(fx), + std::forward<Args>(args)...); + } + } + else { + using traits_type = lua_bind_traits<F>; + using return_type = typename traits_type::return_type; + constexpr bool ret_is_const = std::is_const_v<std::remove_reference_t<return_type>>; + if constexpr (ret_is_const) { + (void)fx; + (void)detail::swallow { 0, (static_cast<void>(args), 0)... }; + return luaL_error(L, "sol: cannot write to a readonly (const) variable"); + } + else { + using u_return_type = meta::unqualified_t<return_type>; + constexpr bool is_assignable = std::is_copy_assignable_v<u_return_type> || std::is_array_v<u_return_type>; + if constexpr (!is_assignable) { + (void)fx; + (void)detail::swallow { 0, ((void)args, 0)... }; + return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available"); + } + else { + using args_list = typename wrap::args_list; + using caller = typename wrap::caller; + if constexpr (sizeof...(Args) > 0) { + return stack::call_into_lua<checked, clean_stack>(types<void>(), + args_list(), + L, + boost + (is_variable ? 3 : 2), + caller(), + std::forward<Fx>(fx), + std::forward<Args>(args)...); + } + else { + using Ta = meta::conditional_t<std::is_void_v<T>, object_type, T>; +#if SOL_IS_ON(SOL_SAFE_USERTYPE) + auto maybeo = stack::check_get<Ta*>(L, 1); + if (!maybeo || maybeo.value() == nullptr) { + if (is_variable) { + return luaL_error(L, "sol: received nil for 'self' argument (bad '.' access?)"); + } + return luaL_error(L, "sol: received nil for 'self' argument (pass 'self' as first argument)"); + } + object_type* po = static_cast<object_type*>(maybeo.value()); + object_type& o = *po; +#else + object_type& o = static_cast<object_type&>(*stack::get<non_null<Ta*>>(L, 1)); +#endif // Safety + + return stack::call_into_lua<checked, clean_stack>( + types<void>(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), std::forward<Fx>(fx), o); + } + } + } + } + } + else { + agnostic_lua_call_wrapper<F, is_index, is_variable, checked, boost, clean_stack> alcw {}; + return alcw.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + } + } + }; + + template <typename T, typename F, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct lua_call_wrapper<T, readonly_wrapper<F>, is_index, is_variable, checked, boost, clean_stack, C> { + using traits_type = lua_bind_traits<F>; + using wrap = wrapper<F>; + using object_type = typename wrap::object_type; + + static int call(lua_State* L, readonly_wrapper<F>&& rw) { + if constexpr (!is_index) { + (void)rw; + return luaL_error(L, "sol: cannot write to a sol::readonly variable"); + } + else { + lua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, C> lcw; + return lcw.call(L, std::move(rw.value())); + } + } + + static int call(lua_State* L, readonly_wrapper<F>&& rw, object_type& o) { + if constexpr (!is_index) { + (void)o; + return call(L, std::move(rw)); + } + else { + lua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, C> lcw; + return lcw.call(L, rw.value(), o); + } + } + + static int call(lua_State* L, const readonly_wrapper<F>& rw) { + if constexpr (!is_index) { + (void)rw; + return luaL_error(L, "sol: cannot write to a sol::readonly variable"); + } + else { + lua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, C> lcw; + return lcw.call(L, rw.value()); + } + } + + static int call(lua_State* L, const readonly_wrapper<F>& rw, object_type& o) { + if constexpr (!is_index) { + (void)o; + return call(L, rw); + } + else { + lua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, C> lcw; + return lcw.call(L, rw.value(), o); + } + } + }; + + template <typename T, typename... Args, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct lua_call_wrapper<T, constructor_list<Args...>, is_index, is_variable, checked, boost, clean_stack, C> { + typedef constructor_list<Args...> F; + + static int call(lua_State* L, F&) { + const auto& meta = usertype_traits<T>::metatable(); + int argcount = lua_gettop(L); + call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1) : call_syntax::dot; + argcount -= static_cast<int>(syntax); + + T* obj = detail::usertype_allocate<T>(L); + reference userdataref(L, -1); + stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on<T>); + + // put userdata at the first index + lua_insert(L, 1); + // Because of the way constructors work, + // we have to kill the data, but only if the cosntructor is successfulyl invoked... + // if it's not successfully invoked and we panic, + // we cannot actually deallcoate/delete the data. + construct_match<T, Args...>( + constructor_match<T, checked, clean_stack>(obj, userdataref, umf), L, argcount, boost + 1 + 1 + static_cast<int>(syntax)); + + userdataref.push(); + return 1; + } + }; + + template <typename T, typename... Cxs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct lua_call_wrapper<T, constructor_wrapper<Cxs...>, is_index, is_variable, checked, boost, clean_stack, C> { + typedef constructor_wrapper<Cxs...> F; + + struct onmatch { + template <typename Fx, std::size_t I, typename... R, typename... Args> + int operator()(types<Fx>, meta::index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start, F& f) { + const auto& meta = usertype_traits<T>::metatable(); + T* obj = detail::usertype_allocate<T>(L); + reference userdataref(L, -1); + stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on<T>); + umf(); + + auto& func = std::get<I>(f.functions); + // put userdata at the first index + lua_insert(L, 1); + stack::call_into_lua<checked, clean_stack>(r, a, L, boost + 1 + start, func, detail::implicit_wrapper<T>(obj)); + + userdataref.push(); + return 1; + } + }; + + static int call(lua_State* L, F& f) { + call_syntax syntax = stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1); + int syntaxval = static_cast<int>(syntax); + int argcount = lua_gettop(L) - syntaxval; + return construct_match<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f); + } + }; + + template <typename T, typename Fx, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct lua_call_wrapper<T, destructor_wrapper<Fx>, is_index, is_variable, checked, boost, clean_stack, C> { + + template <typename F> + static int call(lua_State* L, F&& f) { + if constexpr (std::is_void_v<Fx>) { + return detail::usertype_alloc_destroy<T>(L); + } + else { + using uFx = meta::unqualified_t<Fx>; + lua_call_wrapper<T, uFx, is_index, is_variable, checked, boost, clean_stack> lcw {}; + return lcw.call(L, std::forward<F>(f).fx); + } + } + }; + + template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct lua_call_wrapper<T, overload_set<Fs...>, is_index, is_variable, checked, boost, clean_stack, C> { + typedef overload_set<Fs...> F; + + struct on_match { + template <typename Fx, std::size_t I, typename... R, typename... Args> + int operator()(types<Fx>, meta::index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) { + auto& f = std::get<I>(fx.functions); + return lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost> {}.call(L, f); + } + }; + + static int call(lua_State* L, F& fx) { + return overload_match_arity<Fs...>(on_match(), L, lua_gettop(L), 1, fx); + } + }; + + template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct lua_call_wrapper<T, factory_wrapper<Fs...>, is_index, is_variable, checked, boost, clean_stack, C> { + typedef factory_wrapper<Fs...> F; + + struct on_match { + template <typename Fx, std::size_t I, typename... R, typename... Args> + int operator()(types<Fx>, meta::index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) { + auto& f = std::get<I>(fx.functions); + return lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost, clean_stack> {}.call(L, f); + } + }; + + static int call(lua_State* L, F& fx) { + return overload_match_arity<Fs...>(on_match(), L, lua_gettop(L) - boost, 1 + boost, fx); + } + }; + + template <typename T, typename R, typename W, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct lua_call_wrapper<T, property_wrapper<R, W>, is_index, is_variable, checked, boost, clean_stack, C> { + typedef meta::conditional_t<is_index, R, W> P; + typedef meta::unqualified_t<P> U; + typedef wrapper<U> wrap; + typedef lua_bind_traits<U> traits_type; + typedef meta::unqualified_t<typename traits_type::template arg_at<0>> object_type; + + template <typename F, typename... Args> + static int call(lua_State* L, F&& f, Args&&... args) { + constexpr bool is_specialized = meta::any<std::is_same<U, detail::no_prop>, + meta::is_specialization_of<U, var_wrapper>, + meta::is_specialization_of<U, constructor_wrapper>, + meta::is_specialization_of<U, constructor_list>, + std::is_member_pointer<U>>::value; + if constexpr (is_specialized) { + if constexpr (is_index) { + decltype(auto) p = f.read(); + lua_call_wrapper<T, meta::unqualified_t<decltype(p)>, is_index, is_variable, checked, boost, clean_stack> lcw {}; + return lcw.call(L, p, std::forward<Args>(args)...); + } + else { + decltype(auto) p = f.write(); + lua_call_wrapper<T, meta::unqualified_t<decltype(p)>, is_index, is_variable, checked, boost, clean_stack> lcw {}; + return lcw.call(L, p, std::forward<Args>(args)...); + } + } + else { + constexpr bool non_class_object_type = meta::any<std::is_void<object_type>, + meta::boolean<lua_type_of<meta::unwrap_unqualified_t<object_type>>::value != type::userdata>>::value; + if constexpr (non_class_object_type) { + // The type being void means we don't have any arguments, so it might be a free functions? + using args_list = typename traits_type::free_args_list; + using returns_list = typename wrap::returns_list; + using caller = typename wrap::caller; + if constexpr (is_index) { + decltype(auto) pf = f.read(); + return stack::call_into_lua<checked, clean_stack>( + returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), pf); + } + else { + decltype(auto) pf = f.write(); + return stack::call_into_lua<checked, clean_stack>( + returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), pf); + } + } + else { + using args_list = meta::pop_front_type_t<typename traits_type::free_args_list>; + using Ta = T; + using Oa = std::remove_pointer_t<object_type>; +#if SOL_IS_ON(SOL_SAFE_USERTYPE) + auto maybeo = stack::check_get<Ta*>(L, 1); + if (!maybeo || maybeo.value() == nullptr) { + if (is_variable) { + return luaL_error(L, "sol: 'self' argument is lua_nil (bad '.' access?)"); + } + return luaL_error(L, "sol: 'self' argument is lua_nil (pass 'self' as first argument)"); + } + Oa* o = static_cast<Oa*>(maybeo.value()); +#else + Oa* o = static_cast<Oa*>(stack::get<non_null<Ta*>>(L, 1)); +#endif // Safety + using returns_list = typename wrap::returns_list; + using caller = typename wrap::caller; + if constexpr (is_index) { + decltype(auto) pf = f.read(); + return stack::call_into_lua<checked, clean_stack>( + returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), pf, detail::implicit_wrapper<Oa>(*o)); + } + else { + decltype(auto) pf = f.write(); + return stack::call_into_lua<checked, clean_stack>( + returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), pf, detail::implicit_wrapper<Oa>(*o)); + } + } + } + } + }; + + template <typename T, typename V, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct lua_call_wrapper<T, protect_t<V>, is_index, is_variable, checked, boost, clean_stack, C> { + typedef protect_t<V> F; + + template <typename... Args> + static int call(lua_State* L, F& fx, Args&&... args) { + return lua_call_wrapper<T, V, is_index, is_variable, true, boost, clean_stack> {}.call(L, fx.value, std::forward<Args>(args)...); + } + }; + + template <typename T, typename F, typename... Policies, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct lua_call_wrapper<T, policy_wrapper<F, Policies...>, is_index, is_variable, checked, boost, clean_stack, C> { + typedef policy_wrapper<F, Policies...> P; + + template <std::size_t... In> + static int call(std::index_sequence<In...>, lua_State* L, P& fx) { + int pushed = lua_call_wrapper<T, F, is_index, is_variable, checked, boost, false, C> {}.call(L, fx.value); + (void)detail::swallow { int(), (policy_detail::handle_policy(std::get<In>(fx.policies), L, pushed), int())... }; + return pushed; + } + + static int call(lua_State* L, P& fx) { + typedef typename P::indices indices; + return call(indices(), L, fx); + } + }; + + template <typename T, typename Y, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct lua_call_wrapper<T, yielding_t<Y>, is_index, is_variable, checked, boost, clean_stack, C> { + template <typename F> + static int call(lua_State* L, F&& f) { + return lua_call_wrapper<T, meta::unqualified_t<Y>, is_index, is_variable, checked, boost, clean_stack> {}.call(L, f.func); + } + }; + + template <typename T, typename Sig, typename P, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> + struct lua_call_wrapper<T, function_arguments<Sig, P>, is_index, is_variable, checked, boost, clean_stack, C> { + static int call(lua_State* L, const function_arguments<Sig, P>& f) { + lua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, checked, boost, clean_stack> lcw {}; + return lcw.call(L, std::get<0>(f.arguments)); + } + + static int call(lua_State* L, function_arguments<Sig, P>& f) { + lua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, checked, boost, clean_stack> lcw {}; + return lcw.call(L, std::get<0>(f.arguments)); + } + + static int call(lua_State* L, function_arguments<Sig, P>&& f) { + lua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, checked, boost, clean_stack> lcw {}; + return lcw.call(L, std::get<0>(std::move(f.arguments))); + } + }; + + template <typename T, bool is_index, bool is_variable, int boost = 0, bool checked = detail::default_safe_function_calls, bool clean_stack = true, + typename Fx, typename... Args> + inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) { + using uFx = meta::unqualified_t<Fx>; + if constexpr (meta::is_specialization_of_v<uFx, yielding_t>) { + using real_fx = meta::unqualified_t<decltype(std::forward<Fx>(fx).func)>; + lua_call_wrapper<T, real_fx, is_index, is_variable, checked, boost, clean_stack> lcw {}; + return lcw.call(L, std::forward<Fx>(fx).func, std::forward<Args>(args)...); + } + else { + lua_call_wrapper<T, uFx, is_index, is_variable, checked, boost, clean_stack> lcw {}; + return lcw.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + } + } + + template <typename T, bool is_index, bool is_variable, typename F, int start = 1, bool checked = detail::default_safe_function_calls, + bool clean_stack = true> + inline int call_user(lua_State* L) { + auto& fx = stack::unqualified_get<user<F>>(L, upvalue_index(start)); + using uFx = meta::unqualified_t<F>; + int nr = call_wrapped<T, is_index, is_variable, 0, checked, clean_stack>(L, fx); + if constexpr (meta::is_specialization_of_v<uFx, yielding_t>) { + return lua_yield(L, nr); + } + else { + return nr; + } + } + + template <typename T, typename = void> + struct is_var_bind : std::false_type { }; + + template <typename T> + struct is_var_bind<T, std::enable_if_t<std::is_member_object_pointer<T>::value>> : std::true_type { }; + + template <typename T> + struct is_var_bind<T, std::enable_if_t<is_lua_reference_or_proxy<T>::value>> : std::true_type { }; + + template <> + struct is_var_bind<detail::no_prop> : std::true_type { }; + + template <typename R, typename W> + struct is_var_bind<property_wrapper<R, W>> : std::true_type { }; + + template <typename T> + struct is_var_bind<var_wrapper<T>> : std::true_type { }; + + template <typename T> + struct is_var_bind<readonly_wrapper<T>> : is_var_bind<meta::unqualified_t<T>> { }; + + template <typename F, typename... Policies> + struct is_var_bind<policy_wrapper<F, Policies...>> : is_var_bind<meta::unqualified_t<F>> { }; + } // namespace call_detail + + template <typename T> + struct is_variable_binding : call_detail::is_var_bind<meta::unqualified_t<T>> { }; + + template <typename T> + using is_var_wrapper = meta::is_specialization_of<T, var_wrapper>; + + template <typename T> + struct is_function_binding : meta::neg<is_variable_binding<T>> { }; + +} // namespace sol + +// end of sol/call.hpp + +namespace sol { + namespace function_detail { + template <typename F, F fx> + inline int call_wrapper_variable(std::false_type, lua_State* L) { + typedef meta::bind_traits<meta::unqualified_t<F>> traits_type; + typedef typename traits_type::args_list args_list; + typedef meta::tuple_types<typename traits_type::return_type> return_type; + return stack::call_into_lua(return_type(), args_list(), L, 1, fx); + } + + template <typename R, typename V, V, typename T> + inline int call_set_assignable(std::false_type, T&&, lua_State* L) { + return luaL_error(L, "cannot write to this type: copy assignment/constructor not available"); + } + + template <typename R, typename V, V variable, typename T> + inline int call_set_assignable(std::true_type, lua_State* L, T&& mem) { + (mem.*variable) = stack::get<R>(L, 2); + return 0; + } + + template <typename R, typename V, V, typename T> + inline int call_set_variable(std::false_type, lua_State* L, T&&) { + return luaL_error(L, "cannot write to a const variable"); + } + + template <typename R, typename V, V variable, typename T> + inline int call_set_variable(std::true_type, lua_State* L, T&& mem) { + return call_set_assignable<R, V, variable>(std::is_assignable<std::add_lvalue_reference_t<R>, R>(), L, std::forward<T>(mem)); + } + + template <typename V, V variable> + inline int call_wrapper_variable(std::true_type, lua_State* L) { + typedef meta::bind_traits<meta::unqualified_t<V>> traits_type; + typedef typename traits_type::object_type T; + typedef typename traits_type::return_type R; + auto& mem = stack::get<T>(L, 1); + switch (lua_gettop(L)) { + case 1: { + decltype(auto) r = (mem.*variable); + stack::push_reference(L, std::forward<decltype(r)>(r)); + return 1; + } + case 2: + return call_set_variable<R, V, variable>(meta::neg<std::is_const<R>>(), L, mem); + default: + return luaL_error(L, "incorrect number of arguments to member variable function call"); + } + } + + template <typename F, F fx> + inline int call_wrapper_function(std::false_type, lua_State* L) { + return call_wrapper_variable<F, fx>(std::is_member_object_pointer<F>(), L); + } + + template <typename F, F fx> + inline int call_wrapper_function(std::true_type, lua_State* L) { + return call_detail::call_wrapped<void, false, false>(L, fx); + } + + template <typename F, F fx> + int call_wrapper_entry(lua_State* L) noexcept(meta::bind_traits<F>::is_noexcept) { + return call_wrapper_function<F, fx>(std::is_member_function_pointer<meta::unqualified_t<F>>(), L); + } + + template <typename... Fxs> + struct c_call_matcher { + template <typename Fx, std::size_t I, typename R, typename... Args> + int operator()(types<Fx>, meta::index_value<I>, types<R>, types<Args...>, lua_State* L, int, int) const { + typedef meta::at_in_pack_t<I, Fxs...> target; + return target::call(L); + } + }; + + template <typename F, F fx> + inline int c_call_raw(std::true_type, lua_State* L) { + return fx(L); + } + + template <typename F, F fx> + inline int c_call_raw(std::false_type, lua_State* L) { +#ifdef __clang__ + return detail::trampoline(L, function_detail::call_wrapper_entry<F, fx>); +#else + return detail::typed_static_trampoline<decltype(&function_detail::call_wrapper_entry<F, fx>), (&function_detail::call_wrapper_entry<F, fx>)>(L); +#endif // fuck you clang :c + } + + } // namespace function_detail + + template <typename F, F fx> + inline int c_call(lua_State* L) { + typedef meta::unqualified_t<F> Fu; + typedef std::integral_constant<bool, + std::is_same<Fu, lua_CFunction>::value +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) + || std::is_same<Fu, detail::lua_CFunction_noexcept>::value +#endif + > + is_raw; + return function_detail::c_call_raw<F, fx>(is_raw(), L); + } + + template <typename F, F f> + struct wrap { + typedef F type; + + static int call(lua_State* L) noexcept(noexcept(c_call<type, f>(L))) { + return c_call<type, f>(L); + } + }; + + template <typename... Fxs> + inline int c_call(lua_State* L) { + if constexpr (sizeof...(Fxs) < 2) { + using target = meta::at_in_pack_t<0, Fxs...>; + return target::call(L); + } + else { + return call_detail::overload_match_arity<typename Fxs::type...>(function_detail::c_call_matcher<Fxs...>(), L, lua_gettop(L), 1); + } + } + +} // namespace sol + +// end of sol/function_types_templated.hpp + +// beginning of sol/function_types_stateless.hpp + +namespace sol { namespace function_detail { + template <typename Function> + struct upvalue_free_function { + using function_type = std::remove_pointer_t<std::decay_t<Function>>; + using traits_type = meta::bind_traits<function_type>; + + static int real_call(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + auto udata = stack::stack_detail::get_as_upvalues<function_type*>(L); + function_type* fx = udata.first; + return call_detail::call_wrapped<void, true, false>(L, fx); + } + + template <bool is_yielding, bool no_trampoline> + static int call(lua_State* L) { + int nr; + if constexpr (no_trampoline) { + nr = real_call(L); + } + else { + nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + } + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } + } + }; + + template <typename T, typename Function> + struct upvalue_member_function { + typedef std::remove_pointer_t<std::decay_t<Function>> function_type; + typedef lua_bind_traits<function_type> traits_type; + + static int real_call(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + // Layout: + // idx 1...n: verbatim data of member function pointer + // idx n + 1: is the object's void pointer + // We don't need to store the size, because the other side is templated + // with the same member function pointer type + function_type& memfx = stack::get<user<function_type>>(L, upvalue_index(2)); + auto& item = *static_cast<T*>(stack::get<void*>(L, upvalue_index(3))); + return call_detail::call_wrapped<T, true, false, -1>(L, memfx, item); + } + + template <bool is_yielding, bool no_trampoline> + static int call(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + int nr; + if constexpr (no_trampoline) { + nr = real_call(L); + } + else { + nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + } + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } + } + + int operator()(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + return call(L); + } + }; + + template <typename T, typename Function> + struct upvalue_member_variable { + typedef std::remove_pointer_t<std::decay_t<Function>> function_type; + typedef lua_bind_traits<function_type> traits_type; + + static int real_call(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + // Layout: + // idx 1...n: verbatim data of member variable pointer + // idx n + 1: is the object's void pointer + // We don't need to store the size, because the other side is templated + // with the same member function pointer type + auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L); + auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second); + auto& mem = *objdata.first; + function_type& var = memberdata.first; + switch (lua_gettop(L)) { + case 0: + return call_detail::call_wrapped<T, true, false, -1>(L, var, mem); + case 1: + return call_detail::call_wrapped<T, false, false, -1>(L, var, mem); + default: + return luaL_error(L, "sol: incorrect number of arguments to member variable function"); + } + } + + template <bool is_yielding, bool no_trampoline> + static int call(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + int nr; + if constexpr (no_trampoline) { + nr = real_call(L); + } + else { + nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + } + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } + } + + int operator()(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + return call(L); + } + }; + + template <typename T, typename Function> + struct upvalue_member_variable<T, readonly_wrapper<Function>> { + typedef std::remove_pointer_t<std::decay_t<Function>> function_type; + typedef lua_bind_traits<function_type> traits_type; + + static int real_call(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + // Layout: + // idx 1...n: verbatim data of member variable pointer + // idx n + 1: is the object's void pointer + // We don't need to store the size, because the other side is templated + // with the same member function pointer type + auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L); + auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second); + auto& mem = *objdata.first; + function_type& var = memberdata.first; + switch (lua_gettop(L)) { + case 0: + return call_detail::call_wrapped<T, true, false, -1>(L, var, mem); + default: + return luaL_error(L, "sol: incorrect number of arguments to member variable function"); + } + } + + template <bool is_yielding, bool no_trampoline> + static int call(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + int nr; + if constexpr (no_trampoline) { + nr = real_call(L); + } + else { + nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + } + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } + } + + int operator()(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + return call(L); + } + }; + + template <typename T, typename Function> + struct upvalue_this_member_function { + typedef std::remove_pointer_t<std::decay_t<Function>> function_type; + typedef lua_bind_traits<function_type> traits_type; + + static int real_call(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + // Layout: + // idx 1...n: verbatim data of member variable pointer + function_type& memfx = stack::get<user<function_type>>(L, upvalue_index(2)); + return call_detail::call_wrapped<T, false, false>(L, memfx); + } + + template <bool is_yielding, bool no_trampoline> + static int call(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + int nr; + if constexpr (no_trampoline) { + nr = real_call(L); + } + else { + nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + } + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } + } + + int operator()(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + return call(L); + } + }; + + template <typename T, typename Function> + struct upvalue_this_member_variable { + typedef std::remove_pointer_t<std::decay_t<Function>> function_type; + + static int real_call(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) { + // Layout: + // idx 1...n: verbatim data of member variable pointer + auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L); + function_type& var = memberdata.first; + switch (lua_gettop(L)) { + case 1: + return call_detail::call_wrapped<T, true, false>(L, var); + case 2: + return call_detail::call_wrapped<T, false, false>(L, var); + default: + return luaL_error(L, "sol: incorrect number of arguments to member variable function"); + } + } + + template <bool is_yielding, bool no_trampoline> + static int call(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) { + int nr; + if constexpr (no_trampoline) { + nr = real_call(L); + } + else { + nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + } + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } + } + + int operator()(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) { + return call(L); + } + }; + + template <typename T, typename Function> + struct upvalue_this_member_variable<T, readonly_wrapper<Function>> { + typedef std::remove_pointer_t<std::decay_t<Function>> function_type; + typedef lua_bind_traits<function_type> traits_type; + + static int real_call(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) { + // Layout: + // idx 1...n: verbatim data of member variable pointer + auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L); + function_type& var = memberdata.first; + switch (lua_gettop(L)) { + case 1: + return call_detail::call_wrapped<T, true, false>(L, var); + default: + return luaL_error(L, "sol: incorrect number of arguments to member variable function"); + } + } + + template <bool is_yielding, bool no_trampoline> + static int call(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) { + int nr; + if constexpr (no_trampoline) { + nr = real_call(L); + } + else { + nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); + } + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } + } + + int operator()(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) { + return call(L); + } + }; +}} // namespace sol::function_detail + +// end of sol/function_types_stateless.hpp + +// beginning of sol/function_types_stateful.hpp + +namespace sol { namespace function_detail { + template <typename Func, bool is_yielding, bool no_trampoline> + struct functor_function { + typedef std::decay_t<meta::unwrap_unqualified_t<Func>> function_type; + function_type invocation; + + template <typename... Args> + functor_function(function_type f, Args&&... args) noexcept(std::is_nothrow_constructible_v<function_type, function_type, Args...>) + : invocation(std::move(f), std::forward<Args>(args)...) { + } + + static int call(lua_State* L, functor_function& self) noexcept(noexcept(call_detail::call_wrapped<void, true, false>(L, self.invocation))) { + int nr = call_detail::call_wrapped<void, true, false>(L, self.invocation); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } + } + + int operator()(lua_State* L) noexcept(noexcept(call_detail::call_wrapped<void, true, false>(L, invocation))) { + if constexpr (no_trampoline) { + return call(L, *this); + } + else { + return detail::trampoline(L, &call, *this); + } + } + }; + + template <typename T, typename Function, bool is_yielding, bool no_trampoline> + struct member_function { + typedef std::remove_pointer_t<std::decay_t<Function>> function_type; + typedef meta::function_return_t<function_type> return_type; + typedef meta::function_args_t<function_type> args_lists; + using traits_type = meta::bind_traits<function_type>; + function_type invocation; + T member; + + template <typename... Args> + member_function(function_type f, Args&&... args) noexcept( + std::is_nothrow_constructible_v<function_type, function_type>&& std::is_nothrow_constructible_v<T, Args...>) + : invocation(std::move(f)), member(std::forward<Args>(args)...) { + } + + static int call(lua_State* L, member_function& self) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + int nr = call_detail::call_wrapped<T, true, false, -1>(L, self.invocation, detail::unwrap(detail::deref(self.member))); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } + } + + int operator()(lua_State* L) +#if SOL_IS_ON(SOL_COMPILER_VCXX) + // MSVC is broken, what a surprise... +#else + noexcept(traits_type::is_noexcept) +#endif + { + if constexpr (no_trampoline) { + return call(L, *this); + } + else { + return detail::trampoline(L, &call, *this); + } + } + }; + + template <typename T, typename Function, bool is_yielding, bool no_trampoline> + struct member_variable { + typedef std::remove_pointer_t<std::decay_t<Function>> function_type; + typedef typename meta::bind_traits<function_type>::return_type return_type; + typedef typename meta::bind_traits<function_type>::args_list args_lists; + function_type var; + T member; + typedef std::add_lvalue_reference_t<meta::unwrapped_t<std::remove_reference_t<decltype(detail::deref(member))>>> M; + + template <typename... Args> + member_variable(function_type v, Args&&... args) noexcept( + std::is_nothrow_constructible_v<function_type, function_type>&& std::is_nothrow_constructible_v<T, Args...>) + : var(std::move(v)), member(std::forward<Args>(args)...) { + } + + static int call(lua_State* L, member_variable& self) noexcept(std::is_nothrow_copy_assignable_v<T>) { + int nr; + { + M mem = detail::unwrap(detail::deref(self.member)); + switch (lua_gettop(L)) { + case 0: + nr = call_detail::call_wrapped<T, true, false, -1>(L, self.var, mem); + break; + case 1: + nr = call_detail::call_wrapped<T, false, false, -1>(L, self.var, mem); + break; + default: + nr = luaL_error(L, "sol: incorrect number of arguments to member variable function"); + break; + } + } + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } + } + + int operator()(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) { + if constexpr (no_trampoline) { + return call(L, *this); + } + else { + return detail::trampoline(L, &call, *this); + } + } + }; +}} // namespace sol::function_detail + +// end of sol/function_types_stateful.hpp + +// beginning of sol/function_types_overloaded.hpp + +namespace sol { namespace function_detail { + template <int start_skew, typename... Functions> + struct overloaded_function { + typedef std::tuple<Functions...> overload_list; + typedef std::make_index_sequence<sizeof...(Functions)> indices; + overload_list overloads; + + overloaded_function(overload_list set) : overloads(std::move(set)) { + } + + overloaded_function(Functions... fxs) : overloads(fxs...) { + } + + template <typename Fx, std::size_t I, typename... R, typename... Args> + static int call(types<Fx>, meta::index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, overload_list& ol) { + auto& func = std::get<I>(ol); + int nr = call_detail::call_wrapped<void, true, false, start_skew>(L, func); + return nr; + } + + struct on_success { + template <typename... Args> + int operator()(Args&&... args) const { + return call(std::forward<Args>(args)...); + } + }; + + int operator()(lua_State* L) { + on_success call_obj {}; + return call_detail::overload_match<Functions...>(call_obj, L, 1 + start_skew, overloads); + } + }; +}} // namespace sol::function_detail + +// end of sol/function_types_overloaded.hpp + +// beginning of sol/resolve.hpp + +namespace sol { + +#ifndef __clang__ + // constexpr is fine for not-clang + + namespace detail { + template <typename R, typename... Args, typename F, typename = std::invoke_result_t<meta::unqualified_t<F>, Args...>> + inline constexpr auto resolve_i(types<R(Args...)>, F&&) -> R (meta::unqualified_t<F>::*)(Args...) { + using Sig = R(Args...); + typedef meta::unqualified_t<F> Fu; + return static_cast<Sig Fu::*>(&Fu::operator()); + } + + template <typename F, typename U = meta::unqualified_t<F>> + inline constexpr auto resolve_f(std::true_type, F&& f) + -> decltype(resolve_i(types<meta::function_signature_t<decltype(&U::operator())>>(), std::forward<F>(f))) { + return resolve_i(types<meta::function_signature_t<decltype(&U::operator())>>(), std::forward<F>(f)); + } + + template <typename F> + inline constexpr void resolve_f(std::false_type, F&&) { + static_assert(meta::call_operator_deducible_v<F>, "Cannot use no-template-parameter call with an overloaded functor: specify the signature"); + } + + template <typename F, typename U = meta::unqualified_t<F>> + inline constexpr auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::call_operator_deducible<U>(), std::forward<F>(f))) { + return resolve_f(meta::call_operator_deducible<U> {}, std::forward<F>(f)); + } + + template <typename... Args, typename F, typename R = std::invoke_result_t<F&, Args...>> + inline constexpr auto resolve_i(types<Args...>, F&& f) -> decltype(resolve_i(types<R(Args...)>(), std::forward<F>(f))) { + return resolve_i(types<R(Args...)>(), std::forward<F>(f)); + } + + template <typename Sig, typename C> + inline constexpr Sig C::*resolve_v(std::false_type, Sig C::*mem_func_ptr) { + return mem_func_ptr; + } + + template <typename Sig, typename C> + inline constexpr Sig C::*resolve_v(std::true_type, Sig C::*mem_variable_ptr) { + return mem_variable_ptr; + } + } // namespace detail + + template <typename... Args, typename R> + inline constexpr auto resolve(R fun_ptr(Args...)) -> R (*)(Args...) { + return fun_ptr; + } + + template <typename Sig> + inline constexpr Sig* resolve(Sig* fun_ptr) { + return fun_ptr; + } + + template <typename... Args, typename R, typename C> + inline constexpr auto resolve(R (C::*mem_ptr)(Args...)) -> R (C::*)(Args...) { + return mem_ptr; + } + + template <typename Sig, typename C> + inline constexpr Sig C::*resolve(Sig C::*mem_ptr) { + return detail::resolve_v(std::is_member_object_pointer<Sig C::*>(), mem_ptr); + } + + template <typename... Sig, typename F, meta::disable<std::is_function<meta::unqualified_t<F>>> = meta::enabler> + inline constexpr auto resolve(F&& f) -> decltype(detail::resolve_i(types<Sig...>(), std::forward<F>(f))) { + return detail::resolve_i(types<Sig...>(), std::forward<F>(f)); + } +#else + + // Clang has distinct problems with constexpr arguments, + // so don't use the constexpr versions inside of clang. + + namespace detail { + template <typename R, typename... Args, typename F, typename = std::invoke_result_t<meta::unqualified_t<F>, Args...>> + inline auto resolve_i(types<R(Args...)>, F&&) -> R (meta::unqualified_t<F>::*)(Args...) { + using Sig = R(Args...); + typedef meta::unqualified_t<F> Fu; + return static_cast<Sig Fu::*>(&Fu::operator()); + } + + template <typename F, typename U = meta::unqualified_t<F>> + inline auto resolve_f(std::true_type, F&& f) + -> decltype(resolve_i(types<meta::function_signature_t<decltype(&U::operator())>>(), std::forward<F>(f))) { + return resolve_i(types<meta::function_signature_t<decltype(&U::operator())>>(), std::forward<F>(f)); + } + + template <typename F> + inline void resolve_f(std::false_type, F&&) { + static_assert(meta::call_operator_deducible_v<F>, "Cannot use no-template-parameter call with an overloaded functor: specify the signature"); + } + + template <typename F, typename U = meta::unqualified_t<F>> + inline auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::call_operator_deducible<U>(), std::forward<F>(f))) { + return resolve_f(meta::call_operator_deducible<U> {}, std::forward<F>(f)); + } + + template <typename... Args, typename F, typename R = std::invoke_result_t<F&, Args...>> + inline auto resolve_i(types<Args...>, F&& f) -> decltype(resolve_i(types<R(Args...)>(), std::forward<F>(f))) { + return resolve_i(types<R(Args...)>(), std::forward<F>(f)); + } + + template <typename Sig, typename C> + inline Sig C::*resolve_v(std::false_type, Sig C::*mem_func_ptr) { + return mem_func_ptr; + } + + template <typename Sig, typename C> + inline Sig C::*resolve_v(std::true_type, Sig C::*mem_variable_ptr) { + return mem_variable_ptr; + } + } // namespace detail + + template <typename... Args, typename R> + inline auto resolve(R fun_ptr(Args...)) -> R (*)(Args...) { + return fun_ptr; + } + + template <typename Sig> + inline Sig* resolve(Sig* fun_ptr) { + return fun_ptr; + } + + template <typename... Args, typename R, typename C> + inline auto resolve(R (C::*mem_ptr)(Args...)) -> R (C::*)(Args...) { + return mem_ptr; + } + + template <typename Sig, typename C> + inline Sig C::*resolve(Sig C::*mem_ptr) { + return detail::resolve_v(std::is_member_object_pointer<Sig C::*>(), mem_ptr); + } + + template <typename... Sig, typename F> + inline auto resolve(F&& f) -> decltype(detail::resolve_i(types<Sig...>(), std::forward<F>(f))) { + return detail::resolve_i(types<Sig...>(), std::forward<F>(f)); + } + +#endif + +} // namespace sol + +// end of sol/resolve.hpp + +namespace sol { + namespace function_detail { + template <typename T> + struct class_indicator { + using type = T; + }; + + struct call_indicator { }; + + template <bool yielding> + int lua_c_wrapper(lua_State* L) { + lua_CFunction cf = lua_tocfunction(L, lua_upvalueindex(2)); + int nr = cf(L); + if constexpr (yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } + } + + template <bool yielding> + int lua_c_noexcept_wrapper(lua_State* L) noexcept { + detail::lua_CFunction_noexcept cf = reinterpret_cast<detail::lua_CFunction_noexcept>(lua_tocfunction(L, lua_upvalueindex(2))); + int nr = cf(L); + if constexpr (yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } + } + + struct c_function_invocation { }; + + template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args> + void select(lua_State* L, Fx&& fx, Args&&... args); + + template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args> + void select_set_fx(lua_State* L, Args&&... args) { + lua_CFunction freefunc = no_trampoline ? function_detail::call<meta::unqualified_t<Fx>, 2, is_yielding> + : detail::static_trampoline<function_detail::call<meta::unqualified_t<Fx>, 2, is_yielding>>; + + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push<user<Fx>>(L, std::forward<Args>(args)...); + stack::push(L, c_closure(freefunc, upvalues)); + } + + template <bool is_yielding, bool no_trampoline, typename R, typename... A, typename Fx, typename... Args> + void select_convertible(types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) { + using dFx = std::decay_t<meta::unwrap_unqualified_t<Fx>>; + using fx_ptr_t = R (*)(A...); + constexpr bool is_convertible = std::is_convertible_v<dFx, fx_ptr_t>; + if constexpr (is_convertible) { + fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx)); + select<is_yielding, no_trampoline>(L, std::move(fxptr), std::forward<Args>(args)...); + } + else { + using F = function_detail::functor_function<dFx, false, true>; + select_set_fx<is_yielding, no_trampoline, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + } + } + + template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args> + void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { + typedef meta::function_signature_t<meta::unwrap_unqualified_t<Fx>> Sig; + select_convertible<is_yielding, no_trampoline>(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); + } + + template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args> + void select_member_variable(lua_State* L, Fx&& fx, Args&&... args) { + using uFx = meta::unqualified_t<Fx>; + if constexpr (sizeof...(Args) < 1) { + using C = typename meta::bind_traits<uFx>::object_type; + lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx>::template call<is_yielding, no_trampoline>; + + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, fx); + stack::push(L, c_closure(freefunc, upvalues)); + } + else if constexpr (sizeof...(Args) < 2) { + using Tu = typename meta::meta_detail::unqualified_non_alias<Args...>::type; + constexpr bool is_reference = meta::is_specialization_of_v<Tu, std::reference_wrapper> || std::is_pointer_v<Tu>; + if constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) { + lua_CFunction freefunc + = &function_detail::upvalue_this_member_variable<typename Tu::type, Fx>::template call<is_yielding, no_trampoline>; + + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, fx); + stack::push(L, c_closure(freefunc, upvalues)); + } + else if constexpr (is_reference) { + typedef std::decay_t<Fx> dFx; + dFx memfxptr(std::forward<Fx>(fx)); + auto userptr = detail::ptr(std::forward<Args>(args)...); + lua_CFunction freefunc = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, + meta::unqualified_t<Fx>>::template call<is_yielding, no_trampoline>; + + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, memfxptr); + upvalues += stack::push(L, static_cast<void const*>(userptr)); + stack::push(L, c_closure(freefunc, upvalues)); + } + else { + using clean_fx = std::remove_pointer_t<std::decay_t<Fx>>; + using F = function_detail::member_variable<Tu, clean_fx, is_yielding, no_trampoline>; + select_set_fx<is_yielding, no_trampoline, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + } + } + else { + using C = typename meta::bind_traits<uFx>::object_type; + using clean_fx = std::remove_pointer_t<std::decay_t<Fx>>; + using F = function_detail::member_variable<C, clean_fx, is_yielding, no_trampoline>; + select_set_fx<is_yielding, no_trampoline, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + } + } + + template <bool is_yielding, bool no_trampoline, typename Fx, typename T, typename... Args> + void select_member_function_with(lua_State* L, Fx&& fx, T&& obj, Args&&... args) { + using dFx = std::decay_t<Fx>; + using Tu = meta::unqualified_t<T>; + if constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) { + (void)obj; + using C = typename Tu::type; + lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx>::template call<is_yielding, no_trampoline>; + + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push<user<dFx>>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + stack::push(L, c_closure(freefunc, upvalues)); + } + else { + constexpr bool is_reference = meta::is_specialization_of_v<Tu, std::reference_wrapper> || std::is_pointer_v<Tu>; + if constexpr (is_reference) { + auto userptr = detail::ptr(std::forward<T>(obj)); + lua_CFunction freefunc + = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, dFx>::template call<is_yielding, no_trampoline>; + + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push<user<dFx>>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr))); + stack::push(L, c_closure(freefunc, upvalues)); + } + else { + using F = function_detail::member_function<Tu, dFx, is_yielding, no_trampoline>; + select_set_fx<is_yielding, no_trampoline, F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...); + } + } + } + + template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args> + void select_member_function(lua_State* L, Fx&& fx, Args&&... args) { + using dFx = std::decay_t<Fx>; + if constexpr (sizeof...(Args) < 1) { + using C = typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type; + lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx>::template call<is_yielding, no_trampoline>; + + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push<user<dFx>>(L, std::forward<Fx>(fx)); + stack::push(L, c_closure(freefunc, upvalues)); + } + else { + select_member_function_with<is_yielding, no_trampoline>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + } + } + + template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args> + void select(lua_State* L, Fx&& fx, Args&&... args) { + using uFx = meta::unqualified_t<Fx>; + if constexpr (is_lua_reference_v<uFx>) { + // TODO: hoist into lambda in this case for yielding??? + stack::push(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + } + else if constexpr (is_lua_c_function_v<uFx>) { + if constexpr (no_trampoline) { + if (is_yielding) { + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push(L, std::forward<Fx>(fx)); +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) + if constexpr (std::is_nothrow_invocable_r_v<int, uFx, lua_State*>) { + detail::lua_CFunction_noexcept cf = &lua_c_noexcept_wrapper<true>; + lua_pushcclosure(L, reinterpret_cast<lua_CFunction>(cf), upvalues); + } + else +#endif + { + lua_CFunction cf = &function_detail::lua_c_wrapper<true>; + lua_pushcclosure(L, cf, upvalues); + } + } + else { + lua_pushcclosure(L, std::forward<Fx>(fx), 0); + } + } + else { + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push(L, std::forward<Fx>(fx)); +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) + if constexpr (std::is_nothrow_invocable_r_v<int, uFx, lua_State*>) { + detail::lua_CFunction_noexcept cf = &lua_c_noexcept_wrapper<is_yielding>; + lua_pushcclosure(L, reinterpret_cast<lua_CFunction>(cf), upvalues); + } + else { + lua_CFunction cf = &function_detail::lua_c_wrapper<is_yielding>; + lua_pushcclosure(L, cf, upvalues); + } +#else + lua_CFunction cf = &function_detail::lua_c_wrapper<is_yielding>; + lua_pushcclosure(L, cf, upvalues); +#endif + } + } + else if constexpr (std::is_function_v<std::remove_pointer_t<uFx>>) { + std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...); + lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx>::template call<is_yielding, no_trampoline>; + + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, target); + stack::push(L, c_closure(freefunc, upvalues)); + } + else if constexpr (std::is_member_function_pointer_v<uFx>) { + select_member_function<is_yielding, no_trampoline>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + } + else if constexpr (meta::is_member_object_v<uFx>) { + select_member_variable<is_yielding, no_trampoline>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); + } + else { + select_convertible<is_yielding, no_trampoline>(types<>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); + } + } + } // namespace function_detail + + namespace stack { + template <typename... Sigs> + struct unqualified_pusher<function_sig<Sigs...>> { + template <bool is_yielding, typename Arg0, typename... Args> + static int push_yielding(lua_State* L, Arg0&& arg0, Args&&... args) { + if constexpr (meta::is_specialization_of_v<meta::unqualified_t<Arg0>, std::function>) { + if constexpr (is_yielding) { + return stack::push<meta::unqualified_t<Arg0>>(L, detail::yield_tag, std::forward<Arg0>(arg0), std::forward<Args>(args)...); + } + else { + return stack::push(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...); + } + } + else { + function_detail::select<is_yielding, false>(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...); + return 1; + } + } + + template <typename Arg0, typename... Args> + static int push(lua_State* L, Arg0&& arg0, Args&&... args) { + if constexpr (std::is_same_v<meta::unqualified_t<Arg0>, detail::yield_tag_t>) { + push_yielding<true>(L, std::forward<Args>(args)...); + } + else if constexpr (meta::is_specialization_of_v<meta::unqualified_t<Arg0>, yielding_t>) { + push_yielding<true>(L, std::forward<Arg0>(arg0).func, std::forward<Args>(args)...); + } + else { + push_yielding<false>(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...); + } + return 1; + } + }; + + template <typename T> + struct unqualified_pusher<yielding_t<T>> { + template <typename... Args> + static int push(lua_State* L, const yielding_t<T>& f, Args&&... args) { + if constexpr (meta::is_specialization_of_v<meta::unqualified_t<T>, std::function>) { + return stack::push<T>(L, detail::yield_tag, f.func, std::forward<Args>(args)...); + } + else { + function_detail::select<true, false>(L, f.func, std::forward<Args>(args)...); + return 1; + } + } + + template <typename... Args> + static int push(lua_State* L, yielding_t<T>&& f, Args&&... args) { + if constexpr (meta::is_specialization_of_v<meta::unqualified_t<T>, std::function>) { + return stack::push<T>(L, detail::yield_tag, std::move(f.func), std::forward<Args>(args)...); + } + else { + function_detail::select<true, false>(L, std::move(f.func), std::forward<Args>(args)...); + return 1; + } + } + }; + + template <typename T, typename... Args> + struct unqualified_pusher<function_arguments<T, Args...>> { + template <std::size_t... I, typename FP> + static int push_func(std::index_sequence<I...>, lua_State* L, FP&& fp) { + return stack::push<T>(L, std::get<I>(std::forward<FP>(fp).arguments)...); + } + + static int push(lua_State* L, const function_arguments<T, Args...>& fp) { + return push_func(std::make_index_sequence<sizeof...(Args)>(), L, fp); + } + + static int push(lua_State* L, function_arguments<T, Args...>&& fp) { + return push_func(std::make_index_sequence<sizeof...(Args)>(), L, std::move(fp)); + } + }; + + template <typename Signature> + struct unqualified_pusher<std::function<Signature>> { + using TargetFunctor = function_detail::functor_function<std::function<Signature>, false, true>; + + static int push(lua_State* L, detail::yield_tag_t, const std::function<Signature>& fx) { + if (fx) { + function_detail::select_set_fx<true, false, TargetFunctor>(L, fx); + return 1; + } + return stack::push(L, lua_nil); + } + + static int push(lua_State* L, detail::yield_tag_t, std::function<Signature>&& fx) { + if (fx) { + function_detail::select_set_fx<true, false, TargetFunctor>(L, std::move(fx)); + return 1; + } + return stack::push(L, lua_nil); + } + + static int push(lua_State* L, const std::function<Signature>& fx) { + if (fx) { + function_detail::select_set_fx<false, false, TargetFunctor>(L, fx); + return 1; + } + return stack::push(L, lua_nil); + } + + static int push(lua_State* L, std::function<Signature>&& fx) { + if (fx) { + function_detail::select_set_fx<false, false, TargetFunctor>(L, std::move(fx)); + return 1; + } + return stack::push(L, lua_nil); + } + }; + + template <typename Signature> + struct unqualified_pusher<Signature, std::enable_if_t<meta::is_member_object_or_function_v<Signature>>> { + template <typename... Args> + static int push(lua_State* L, Args&&... args) { + function_detail::select<false, false>(L, std::forward<Args>(args)...); + return 1; + } + }; + + template <typename Signature> + struct unqualified_pusher<Signature, + std::enable_if_t<meta::all<std::is_function<std::remove_pointer_t<Signature>>, meta::neg<std::is_same<Signature, lua_CFunction>>, + meta::neg<std::is_same<Signature, std::remove_pointer_t<lua_CFunction>>> +#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE) + , + meta::neg<std::is_same<Signature, detail::lua_CFunction_noexcept>>, + meta::neg<std::is_same<Signature, std::remove_pointer_t<detail::lua_CFunction_noexcept>>> +#endif // noexcept function types + >::value>> { + template <typename F> + static int push(lua_State* L, F&& f) { + function_detail::select<false, true>(L, std::forward<F>(f)); + return 1; + } + }; + + template <typename... Functions> + struct unqualified_pusher<overload_set<Functions...>> { + static int push(lua_State* L, overload_set<Functions...>&& set) { + using F = function_detail::overloaded_function<0, Functions...>; + function_detail::select_set_fx<false, false, F>(L, std::move(set.functions)); + return 1; + } + + static int push(lua_State* L, const overload_set<Functions...>& set) { + using F = function_detail::overloaded_function<0, Functions...>; + function_detail::select_set_fx<false, false, F>(L, set.functions); + return 1; + } + }; + + template <typename T> + struct unqualified_pusher<protect_t<T>> { + static int push(lua_State* L, protect_t<T>&& pw) { + lua_CFunction cf = call_detail::call_user<void, false, false, protect_t<T>, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push<user<protect_t<T>>>(L, std::move(pw.value)); + return stack::push(L, c_closure(cf, upvalues)); + } + + static int push(lua_State* L, const protect_t<T>& pw) { + lua_CFunction cf = call_detail::call_user<void, false, false, protect_t<T>, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push<user<protect_t<T>>>(L, pw.value); + return stack::push(L, c_closure(cf, upvalues)); + } + }; + + template <typename F, typename G> + struct unqualified_pusher<property_wrapper<F, G>> { + static int push(lua_State* L, property_wrapper<F, G>&& pw) { + if constexpr (std::is_void_v<F>) { + return stack::push(L, std::move(pw.write())); + } + else if constexpr (std::is_void_v<G>) { + return stack::push(L, std::move(pw.read())); + } + else { + return stack::push(L, overload(std::move(pw.read()), std::move(pw.write()))); + } + } + + static int push(lua_State* L, const property_wrapper<F, G>& pw) { + if constexpr (std::is_void_v<F>) { + return stack::push(L, pw.write); + } + else if constexpr (std::is_void_v<G>) { + return stack::push(L, pw.read); + } + else { + return stack::push(L, overload(pw.read, pw.write)); + } + } + }; + + template <typename T> + struct unqualified_pusher<var_wrapper<T>> { + static int push(lua_State* L, var_wrapper<T>&& vw) { + return stack::push(L, std::move(vw.value())); + } + static int push(lua_State* L, const var_wrapper<T>& vw) { + return stack::push(L, vw.value()); + } + }; + + template <typename... Functions> + struct unqualified_pusher<factory_wrapper<Functions...>> { + static int push(lua_State* L, const factory_wrapper<Functions...>& fw) { + using F = function_detail::overloaded_function<0, Functions...>; + function_detail::select_set_fx<false, false, F>(L, fw.functions); + return 1; + } + + static int push(lua_State* L, factory_wrapper<Functions...>&& fw) { + using F = function_detail::overloaded_function<0, Functions...>; + function_detail::select_set_fx<false, false, F>(L, std::move(fw.functions)); + return 1; + } + + static int push(lua_State* L, const factory_wrapper<Functions...>& fw, function_detail::call_indicator) { + using F = function_detail::overloaded_function<1, Functions...>; + function_detail::select_set_fx<false, false, F>(L, fw.functions); + return 1; + } + + static int push(lua_State* L, factory_wrapper<Functions...>&& fw, function_detail::call_indicator) { + using F = function_detail::overloaded_function<1, Functions...>; + function_detail::select_set_fx<false, false, F>(L, std::move(fw.functions)); + return 1; + } + }; + + template <> + struct unqualified_pusher<no_construction> { + static int push(lua_State* L, no_construction) { + lua_CFunction cf = &function_detail::no_construction_error; + return stack::push(L, cf); + } + + static int push(lua_State* L, no_construction c, function_detail::call_indicator) { + return push(L, c); + } + }; + + template <typename T> + struct unqualified_pusher<detail::tagged<T, no_construction>> { + static int push(lua_State* L, detail::tagged<T, no_construction>) { + lua_CFunction cf = &function_detail::no_construction_error; + return stack::push(L, cf); + } + + static int push(lua_State* L, no_construction, function_detail::call_indicator) { + lua_CFunction cf = &function_detail::no_construction_error; + return stack::push(L, cf); + } + }; + + template <typename T, typename... Lists> + struct unqualified_pusher<detail::tagged<T, constructor_list<Lists...>>> { + static int push(lua_State* L, detail::tagged<T, constructor_list<Lists...>>) { + lua_CFunction cf = call_detail::construct<T, detail::default_safe_function_calls, true, Lists...>; + return stack::push(L, cf); + } + + static int push(lua_State* L, constructor_list<Lists...>) { + lua_CFunction cf = call_detail::construct<T, detail::default_safe_function_calls, true, Lists...>; + return stack::push(L, cf); + } + }; + + template <typename L0, typename... Lists> + struct unqualified_pusher<constructor_list<L0, Lists...>> { + typedef constructor_list<L0, Lists...> cl_t; + static int push(lua_State* L, cl_t cl) { + typedef typename meta::bind_traits<L0>::return_type T; + return stack::push<detail::tagged<T, cl_t>>(L, cl); + } + }; + + template <typename T, typename... Fxs> + struct unqualified_pusher<detail::tagged<T, constructor_wrapper<Fxs...>>> { + static int push(lua_State* L, detail::tagged<T, constructor_wrapper<Fxs...>>&& c) { + return push(L, std::move(c.value())); + } + + static int push(lua_State* L, const detail::tagged<T, const constructor_wrapper<Fxs...>>& c) { + return push(L, c.value()); + } + + static int push(lua_State* L, constructor_wrapper<Fxs...>&& c) { + lua_CFunction cf = call_detail::call_user<T, false, false, constructor_wrapper<Fxs...>, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push<user<constructor_wrapper<Fxs...>>>(L, std::move(c)); + return stack::push(L, c_closure(cf, upvalues)); + } + + static int push(lua_State* L, const constructor_wrapper<Fxs...>& c) { + lua_CFunction cf = call_detail::call_user<T, false, false, constructor_wrapper<Fxs...>, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push<user<constructor_wrapper<Fxs...>>>(L, c); + return stack::push(L, c_closure(cf, upvalues)); + } + }; + + template <typename F, typename... Fxs> + struct unqualified_pusher<constructor_wrapper<F, Fxs...>> { + static int push(lua_State* L, const constructor_wrapper<F, Fxs...>& c) { + typedef typename meta::bind_traits<F>::template arg_at<0> arg0; + typedef meta::unqualified_t<std::remove_pointer_t<arg0>> T; + return stack::push<detail::tagged<T, constructor_wrapper<F, Fxs...>>>(L, c); + } + + static int push(lua_State* L, constructor_wrapper<F, Fxs...>&& c) { + typedef typename meta::bind_traits<F>::template arg_at<0> arg0; + typedef meta::unqualified_t<std::remove_pointer_t<arg0>> T; + return stack::push<detail::tagged<T, constructor_wrapper<F, Fxs...>>>(L, std::move(c)); + } + }; + + template <typename T> + struct unqualified_pusher<detail::tagged<T, destructor_wrapper<void>>> { + static int push(lua_State* L, destructor_wrapper<void>) { + lua_CFunction cf = detail::usertype_alloc_destroy<T>; + return stack::push(L, cf); + } + }; + + template <typename T, typename Fx> + struct unqualified_pusher<detail::tagged<T, destructor_wrapper<Fx>>> { + static int push(lua_State* L, destructor_wrapper<Fx>&& c) { + lua_CFunction cf = call_detail::call_user<T, false, false, destructor_wrapper<Fx>, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push<user<destructor_wrapper<Fx>>>(L, std::move(c)); + return stack::push(L, c_closure(cf, upvalues)); + } + + static int push(lua_State* L, const destructor_wrapper<Fx>& c) { + lua_CFunction cf = call_detail::call_user<T, false, false, destructor_wrapper<Fx>, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push<user<destructor_wrapper<Fx>>>(L, c); + return stack::push(L, c_closure(cf, upvalues)); + } + }; + + template <typename Fx> + struct unqualified_pusher<destructor_wrapper<Fx>> { + static int push(lua_State* L, destructor_wrapper<Fx>&& c) { + lua_CFunction cf = call_detail::call_user<void, false, false, destructor_wrapper<Fx>, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push<user<destructor_wrapper<Fx>>>(L, std::move(c)); + return stack::push(L, c_closure(cf, upvalues)); + } + + static int push(lua_State* L, const destructor_wrapper<Fx>& c) { + lua_CFunction cf = call_detail::call_user<void, false, false, destructor_wrapper<Fx>, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push<user<destructor_wrapper<Fx>>>(L, c); + return stack::push(L, c_closure(cf, upvalues)); + } + }; + + template <typename F, typename... Policies> + struct unqualified_pusher<policy_wrapper<F, Policies...>> { + using P = policy_wrapper<F, Policies...>; + + static int push(lua_State* L, const P& p) { + lua_CFunction cf = call_detail::call_user<void, false, false, P, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push<user<P>>(L, p); + return stack::push(L, c_closure(cf, upvalues)); + } + + static int push(lua_State* L, P&& p) { + lua_CFunction cf = call_detail::call_user<void, false, false, P, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push<user<P>>(L, std::move(p)); + return stack::push(L, c_closure(cf, upvalues)); + } + }; + + template <typename T, typename F, typename... Policies> + struct unqualified_pusher<detail::tagged<T, policy_wrapper<F, Policies...>>> { + using P = policy_wrapper<F, Policies...>; + using Tagged = detail::tagged<T, P>; + + static int push(lua_State* L, const Tagged& p) { + lua_CFunction cf = call_detail::call_user<T, false, false, P, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push<user<P>>(L, p.value()); + return stack::push(L, c_closure(cf, upvalues)); + } + + static int push(lua_State* L, Tagged&& p) { + lua_CFunction cf = call_detail::call_user<T, false, false, P, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push<user<P>>(L, std::move(p.value())); + return stack::push(L, c_closure(cf, upvalues)); + } + }; + + template <typename T> + struct unqualified_pusher<push_invoke_t<T>> { + static int push(lua_State* L, push_invoke_t<T>&& pi) { + if constexpr (std::is_invocable_v<std::add_rvalue_reference_t<T>, lua_State*>) { + return stack::push(L, std::move(pi.value())(L)); + } + else { + return stack::push(L, std::move(pi.value())()); + } + } + + static int push(lua_State* L, const push_invoke_t<T>& pi) { + if constexpr (std::is_invocable_v<const T, lua_State*>) { + return stack::push(L, pi.value()(L)); + } + else { + return stack::push(L, pi.value()()); + } + } + }; + + namespace stack_detail { + template <typename Function, typename Handler> + bool check_function_pointer(lua_State* L, int index, Handler&& handler, record& tracking) noexcept { +#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE) + tracking.use(1); + bool success = lua_iscfunction(L, index) == 1; + if (success) { + // there must be at LEAST 2 upvalues; otherwise, we didn't serialize it. + const char* upvalue_name = lua_getupvalue(L, index, 2); + lua_pop(L, 1); + success = upvalue_name != nullptr; + } + if (!success) { + // expected type, actual type + handler( + L, index, type::function, type_of(L, index), "type must be a Lua C Function gotten from a function pointer serialized by sol2"); + } + return success; +#else + (void)L; + (void)index; + (void)handler; + (void)tracking; + return false; +#endif + } + + template <typename Function> + Function* get_function_pointer(lua_State* L, int index, record& tracking) noexcept { +#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE) + tracking.use(1); + auto udata = stack::stack_detail::get_as_upvalues_using_function<Function*>(L, index); + Function* fx = udata.first; + return fx; +#else + (void)L; + (void)index; + (void)tracking; + static_assert(meta::meta_detail::always_true<Function>::value, +#if SOL_IS_DEFAULT_OFF(SOL_GET_FUNCTION_POINTER_UNSAFE) + "You are attempting to retrieve a function pointer type. " + "This is inherently unsafe in sol2. In order to do this, you must turn on the " + "SOL_GET_FUNCTION_POINTER_UNSAFE configuration macro, as detailed in the documentation. " + "Please be careful!" +#else + "You are attempting to retrieve a function pointer type. " + "You explicitly turned off the ability to do this by defining " + "SOL_GET_FUNCTION_POINTER_UNSAFE or similar to be off. " + "Please reconsider this!" +#endif + ); + return nullptr; +#endif + } + } // namespace stack_detail + } // namespace stack +} // namespace sol + +// end of sol/function_types.hpp + +// beginning of sol/dump_handler.hpp + +#include <cstdint> +#include <exception> + +namespace sol { + + class dump_error : public error { + private: + int m_ec; + + public: + dump_error(int error_code_) : error("dump returned non-zero error of " + std::to_string(error_code_)), m_ec(error_code_) { + } + + int error_code() const { + return m_ec; + } + }; + + inline int dump_pass_on_error(lua_State* L_, int result_code, lua_Writer writer_function, void* userdata_pointer_, bool strip) { + (void)L_; + (void)writer_function; + (void)userdata_pointer_; + (void)strip; + return result_code; + } + + inline int dump_panic_on_error(lua_State* L_, int result_code, lua_Writer writer_function, void* userdata_pointer_, bool strip) { + (void)L_; + (void)writer_function; + (void)userdata_pointer_; + (void)strip; + return luaL_error(L_, "a non-zero error code (%d) was returned by the lua_Writer for the dump function", result_code); + } + + inline int dump_throw_on_error(lua_State* L_, int result_code, lua_Writer writer_function, void* userdata_pointer_, bool strip) { +#if SOL_IS_OFF(SOL_EXCEPTIONS) + return dump_panic_on_error(L_, result_code, writer_function, userdata_pointer_, strip); +#else + (void)L_; + (void)writer_function; + (void)userdata_pointer_; + (void)strip; + throw dump_error(result_code); +#endif // no exceptions stuff + } + +} // namespace sol + +// end of sol/dump_handler.hpp + +#include <cstdint> + +namespace sol { + template <typename ref_t, bool aligned = false> + class basic_function : public basic_object<ref_t> { + private: + using base_t = basic_object<ref_t>; + + void luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount) const { + lua_call(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount)); + } + + template <std::size_t... I, typename... Ret> + auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n) const { + luacall(n, lua_size<std::tuple<Ret...>>::value); + return stack::pop<std::tuple<Ret...>>(lua_state()); + } + + template <std::size_t I, typename Ret, meta::enable<meta::neg<std::is_void<Ret>>> = meta::enabler> + Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) const { + luacall(n, lua_size<Ret>::value); + return stack::pop<Ret>(lua_state()); + } + + template <std::size_t I> + void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) const { + luacall(n, 0); + } + + unsafe_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) const { + int stacksize = lua_gettop(lua_state()); + int firstreturn = (std::max)(1, stacksize - static_cast<int>(n)); + luacall(n, LUA_MULTRET); + int poststacksize = lua_gettop(lua_state()); + int returncount = poststacksize - (firstreturn - 1); + return unsafe_function_result(lua_state(), firstreturn, returncount); + } + + public: + using base_t::lua_state; + + basic_function() = default; + template <typename T, + meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_function>>, meta::neg<std::is_same<base_t, stack_reference>>, + meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_function(T&& r) noexcept : base_t(std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + if (!is_function<meta::unqualified_t<T>>::value) { + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_function>(lua_state(), -1, handler); + } +#endif // Safety + } + basic_function(const basic_function&) = default; + basic_function& operator=(const basic_function&) = default; + basic_function(basic_function&&) = default; + basic_function& operator=(basic_function&&) = default; + basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) { + } + basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) { + } + basic_function(lua_nil_t n) : base_t(n) { + } + template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_function(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_function>(lua_state(), -1, handler); +#endif // Safety + } + basic_function(lua_State* L, int index = -1) : base_t(L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_function>(L, index, handler); +#endif // Safety + } + basic_function(lua_State* L, ref_index index) : base_t(L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_function>(lua_state(), -1, handler); +#endif // Safety + } + + template <typename Fx> + int dump(lua_Writer writer, void* userdata, bool strip, Fx&& on_error) const { + this->push(); + auto ppn = stack::push_popper_n<false>(this->lua_state(), 1); + int r = lua_dump(this->lua_state(), writer, userdata, strip ? 1 : 0); + if (r != 0) { + return on_error(this->lua_state(), r, writer, userdata, strip); + } + return r; + } + + int dump(lua_Writer writer, void* userdata, bool strip = false) const { + return dump(writer, userdata, strip, &dump_throw_on_error); + } + + template <typename Container = bytecode> + Container dump() const { + Container bc; + (void)dump(static_cast<lua_Writer>(&basic_insert_dump_writer<Container>), static_cast<void*>(&bc), false, &dump_panic_on_error); + return bc; + } + + template <typename Container = bytecode, typename Fx> + Container dump(Fx&& on_error) const { + Container bc; + (void)dump(static_cast<lua_Writer>(&basic_insert_dump_writer<Container>), static_cast<void*>(&bc), false, std::forward<Fx>(on_error)); + return bc; + } + + template <typename... Args> + unsafe_function_result operator()(Args&&... args) const { + return call<>(std::forward<Args>(args)...); + } + + template <typename... Ret, typename... Args> + decltype(auto) operator()(types<Ret...>, Args&&... args) const { + return call<Ret...>(std::forward<Args>(args)...); + } + + template <typename... Ret, typename... Args> + decltype(auto) call(Args&&... args) const { + if (!aligned) { + base_t::push(); + } + int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); + return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), static_cast<std::ptrdiff_t>(pushcount)); + } + }; +} // namespace sol + +// end of sol/unsafe_function.hpp + +// beginning of sol/protected_function.hpp + +// beginning of sol/protected_handler.hpp + +#include <cstdint> + +namespace sol { namespace detail { + inline const char (&default_handler_name())[9] { + static const char name[9] = "sol.\xF0\x9F\x94\xA9"; + return name; + } + + template <bool ShouldPush, typename Target = reference> + struct protected_handler { + lua_State* m_L; + const Target& target; + int stack_index; + + protected_handler(std::false_type, lua_State* L_, const Target& target_) : m_L(L_), target(target_), stack_index(0) { + if (ShouldPush) { + stack_index = lua_gettop(L_) + 1; + target.push(L_); + } + } + + protected_handler(std::true_type, lua_State* L_, const Target& target_) : m_L(L_), target(target_), stack_index(0) { + if (ShouldPush) { + stack_index = target.stack_index(); + } + } + + protected_handler(lua_State* L_, const Target& target_) : protected_handler(meta::boolean<is_stack_based_v<Target>>(), L_, target_) { + } + + bool valid() const noexcept { + return ShouldPush; + } + + ~protected_handler() { + if constexpr (!is_stack_based_v<Target>) { + if (stack_index != 0) { + lua_remove(m_L, stack_index); + } + } + } + }; + + template <typename Base, typename T> + inline basic_function<Base> force_cast(T& p) { + return p; + } + + template <typename Reference, bool IsMainReference = false> + inline Reference get_default_handler(lua_State* L_) { + if (is_stack_based_v<Reference> || L_ == nullptr) + return Reference(L_, lua_nil); + L_ = IsMainReference ? main_thread(L_, L_) : L_; + lua_getglobal(L_, default_handler_name()); + auto pp = stack::pop_n(L_, 1); + return Reference(L_, -1); + } + + template <typename T> + inline void set_default_handler(lua_State* L, const T& ref) { + if (L == nullptr) { + return; + } + if (!ref.valid()) { +#if SOL_IS_ON(SOL_SAFE_STACK_CHECK) + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); +#endif // make sure stack doesn't overflow + lua_pushnil(L); + lua_setglobal(L, default_handler_name()); + } + else { + ref.push(L); + lua_setglobal(L, default_handler_name()); + } + } +}} // namespace sol::detail + +// end of sol/protected_handler.hpp + +#include <cstdint> +#include <algorithm> + +namespace sol { + + namespace detail { + template <bool ShouldPush_, typename Handler_> + inline void handle_protected_exception( + lua_State* L_, optional<const std::exception&> maybe_ex, const char* error, detail::protected_handler<ShouldPush_, Handler_>& handler_) { + handler_.stack_index = 0; + if (ShouldPush_) { + handler_.target.push(L_); + detail::call_exception_handler(L_, maybe_ex, error); + lua_call(L_, 1, 1); + } + else { + detail::call_exception_handler(L_, maybe_ex, error); + } + } + } // namespace detail + + template <typename Reference, bool Aligned = false, typename Handler = reference> + class basic_protected_function : public basic_object<Reference> { + private: + using base_t = basic_object<Reference>; + using handler_t = Handler; + inline static constexpr bool is_stack_handler_v = is_stack_based_v<handler_t>; + + basic_protected_function(std::true_type, const basic_protected_function& other_) noexcept + : base_t(other_), m_error_handler(other_.m_error_handler.copy(lua_state())) { + } + + basic_protected_function(std::false_type, const basic_protected_function& other_) noexcept : base_t(other_), m_error_handler(other_.m_error_handler) { + } + + public: + basic_protected_function() = default; + template <typename T, + meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_protected_function>>, + meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<T>>>, meta::neg<std::is_same<base_t, stack_reference>>, + meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_protected_function(T&& r) noexcept : base_t(std::forward<T>(r)), m_error_handler(get_default_handler(r.lua_state())) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + if (!is_function<meta::unqualified_t<T>>::value) { + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_protected_function>(lua_state(), -1, handler); + } +#endif // Safety + } + basic_protected_function(const basic_protected_function& other_) noexcept + : basic_protected_function(meta::boolean<is_stateless_lua_reference_v<Handler>>(), other_) { + } + basic_protected_function& operator=(const basic_protected_function& other_) { + base_t::operator=(other_); + if constexpr (is_stateless_lua_reference_v<Handler>) { + m_error_handler.copy_assign(lua_state(), other_.m_error_handler); + } + else { + m_error_handler = other_.m_error_handler; + } + return *this; + } + basic_protected_function(basic_protected_function&&) = default; + basic_protected_function& operator=(basic_protected_function&&) = default; + basic_protected_function(const basic_function<base_t>& b) : basic_protected_function(b, get_default_handler(b.lua_state())) { + } + basic_protected_function(basic_function<base_t>&& b) : basic_protected_function(std::move(b), get_default_handler(b.lua_state())) { + } + basic_protected_function(const basic_function<base_t>& b, handler_t eh) : base_t(b), m_error_handler(std::move(eh)) { + } + basic_protected_function(basic_function<base_t>&& b, handler_t eh) : base_t(std::move(b)), m_error_handler(std::move(eh)) { + } + basic_protected_function(const stack_reference& r) : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) { + } + basic_protected_function(stack_reference&& r) : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) { + } + basic_protected_function(const stack_reference& r, handler_t eh) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) { + } + basic_protected_function(stack_reference&& r, handler_t eh) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) { + } + + template <typename Super> + basic_protected_function(const proxy_base<Super>& p) : basic_protected_function(p, get_default_handler(p.lua_state())) { + } + template <typename Super> + basic_protected_function(proxy_base<Super>&& p) : basic_protected_function(std::move(p), get_default_handler(p.lua_state())) { + } + template <typename Proxy, typename HandlerReference, + meta::enable<std::is_base_of<proxy_base_tag, meta::unqualified_t<Proxy>>, + meta::neg<is_lua_index<meta::unqualified_t<HandlerReference>>>> = meta::enabler> + basic_protected_function(Proxy&& p, HandlerReference&& eh) + : basic_protected_function(detail::force_cast<base_t>(p), make_reference<handler_t>(p.lua_state(), std::forward<HandlerReference>(eh))) { + } + + template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_protected_function(lua_State* L_, T&& r) : basic_protected_function(L_, std::forward<T>(r), get_default_handler(L_)) { + } + template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_protected_function(lua_State* L_, T&& r, handler_t eh) : base_t(L_, std::forward<T>(r)), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_protected_function>(lua_state(), -1, handler); +#endif // Safety + } + + basic_protected_function(lua_nil_t n) : base_t(n), m_error_handler(n) { + } + + basic_protected_function(lua_State* L_, int index_ = -1) : basic_protected_function(L_, index_, get_default_handler(L_)) { + } + basic_protected_function(lua_State* L_, int index_, handler_t eh) : base_t(L_, index_), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_protected_function>(L_, index_, handler); +#endif // Safety + } + basic_protected_function(lua_State* L_, absolute_index index_) : basic_protected_function(L_, index_, get_default_handler(L_)) { + } + basic_protected_function(lua_State* L_, absolute_index index_, handler_t eh) : base_t(L_, index_), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_protected_function>(L_, index_, handler); +#endif // Safety + } + basic_protected_function(lua_State* L_, raw_index index_) : basic_protected_function(L_, index_, get_default_handler(L_)) { + } + basic_protected_function(lua_State* L_, raw_index index_, handler_t eh) : base_t(L_, index_), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_protected_function>(L_, index_, handler); +#endif // Safety + } + basic_protected_function(lua_State* L_, ref_index index_) : basic_protected_function(L_, index_, get_default_handler(L_)) { + } + basic_protected_function(lua_State* L_, ref_index index_, handler_t eh) : base_t(L_, index_), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_protected_function>(lua_state(), -1, handler); +#endif // Safety + } + + using base_t::lua_state; + + template <typename Fx> + int dump(lua_Writer writer, void* userdata_pointer_, bool strip, Fx&& on_error) const { + this->push(); + auto ppn = stack::push_popper_n<false>(this->lua_state(), 1); + int r = lua_dump(this->lua_state(), writer, userdata_pointer_, strip ? 1 : 0); + if (r != 0) { + return on_error(this->lua_state(), r, writer, userdata_pointer_, strip); + } + return r; + } + + int dump(lua_Writer writer, void* userdata_pointer_, bool strip = false) const { + return dump(writer, userdata_pointer_, strip, &dump_pass_on_error); + } + + template <typename Container = bytecode> + Container dump() const { + Container bc; + (void)dump(static_cast<lua_Writer>(&basic_insert_dump_writer<Container>), static_cast<void*>(&bc), false, &dump_throw_on_error); + return bc; + } + + template <typename Container = bytecode, typename Fx> + Container dump(Fx&& on_error) const { + Container bc; + (void)dump(static_cast<lua_Writer>(&basic_insert_dump_writer<Container>), static_cast<void*>(&bc), false, std::forward<Fx>(on_error)); + return bc; + } + + template <typename... Args> + protected_function_result operator()(Args&&... args) const { + return call<>(std::forward<Args>(args)...); + } + + template <typename... Ret, typename... Args> + decltype(auto) operator()(types<Ret...>, Args&&... args) const { + return call<Ret...>(std::forward<Args>(args)...); + } + + template <typename... Ret, typename... Args> + decltype(auto) call(Args&&... args) const { + if constexpr (!Aligned) { + // we do not expect the function to already be on the stack: push it + if (m_error_handler.valid(lua_state())) { + detail::protected_handler<true, handler_t> h(lua_state(), m_error_handler); + base_t::push(); + int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); + return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); + } + else { + detail::protected_handler<false, handler_t> h(lua_state(), m_error_handler); + base_t::push(); + int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); + return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); + } + } + else { + // the function is already on the stack at the right location + if (m_error_handler.valid()) { + // the handler will be pushed onto the stack manually, + // since it's not already on the stack this means we need to push our own + // function on the stack too and swap things to be in-place + if constexpr (!is_stack_handler_v) { + // so, we need to remove the function at the top and then dump the handler out ourselves + base_t::push(); + } + detail::protected_handler<true, handler_t> h(lua_state(), m_error_handler); + if constexpr (!is_stack_handler_v) { + lua_replace(lua_state(), -3); + h.stack_index = lua_absindex(lua_state(), -2); + } + int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); + return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); + } + else { + detail::protected_handler<false, handler_t> h(lua_state(), m_error_handler); + int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); + return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); + } + } + } + + ~basic_protected_function() { + if constexpr (is_stateless_lua_reference_v<handler_t>) { + this->m_error_handler.reset(lua_state()); + } + } + + static handler_t get_default_handler(lua_State* L_) { + return detail::get_default_handler<handler_t, is_main_threaded_v<base_t>>(L_); + } + + template <typename T> + static void set_default_handler(const T& ref) { + detail::set_default_handler(ref.lua_state(), ref); + } + + auto get_error_handler() const noexcept { + if constexpr (is_stateless_lua_reference_v<handler_t>) { + if constexpr (is_stack_based_v<handler_t>) { + return stack_reference(lua_state(), m_error_handler.stack_index()); + } + else { + return basic_reference<is_main_threaded_v<base_t>>(lua_state(), ref_index(m_error_handler.registry_index())); + } + } + else { + return m_error_handler; + } + } + + template <typename ErrorHandler_> + void set_error_handler(ErrorHandler_&& error_handler_) noexcept { + static_assert(!is_stack_based_v<handler_t> || is_stack_based_v<ErrorHandler_>, + "A stack-based error handler can only be set from a parameter that is also stack-based."); + if constexpr (std::is_rvalue_reference_v<ErrorHandler_>) { + m_error_handler = std::forward<ErrorHandler_>(error_handler_); + } + else { + m_error_handler.copy_assign(lua_state(), std::forward<ErrorHandler_>(error_handler_)); + } + } + + void abandon () noexcept { + this->m_error_handler.abandon(); + base_t::abandon(); + } + + private: + handler_t m_error_handler; + + template <bool b> + call_status luacall(std::ptrdiff_t argcount, std::ptrdiff_t result_count_, detail::protected_handler<b, handler_t>& h) const { + return static_cast<call_status>(lua_pcall(lua_state(), static_cast<int>(argcount), static_cast<int>(result_count_), h.stack_index)); + } + + template <std::size_t... I, bool b, typename... Ret> + auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const { + luacall(n, sizeof...(Ret), h); + return stack::pop<std::tuple<Ret...>>(lua_state()); + } + + template <std::size_t I, bool b, typename Ret> + Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const { + luacall(n, 1, h); + return stack::pop<Ret>(lua_state()); + } + + template <std::size_t I, bool b> + void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const { + luacall(n, 0, h); + } + + template <bool b> + protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const { + int stacksize = lua_gettop(lua_state()); + int poststacksize = stacksize; + int firstreturn = 1; + int returncount = 0; + call_status code = call_status::ok; +#if SOL_IS_ON(SOL_EXCEPTIONS) && SOL_IS_OFF(SOL_PROPAGATE_EXCEPTIONS) + try { +#endif // No Exceptions + firstreturn = (std::max)(1, static_cast<int>(stacksize - n - static_cast<int>(h.valid() && !is_stack_handler_v))); + code = luacall(n, LUA_MULTRET, h); + poststacksize = lua_gettop(lua_state()) - static_cast<int>(h.valid() && !is_stack_handler_v); + returncount = poststacksize - (firstreturn - 1); +#if SOL_IS_ON(SOL_EXCEPTIONS) && SOL_IS_OFF(SOL_PROPAGATE_EXCEPTIONS) + } + // Handle C++ errors thrown from C++ functions bound inside of lua + catch (const char* error) { + detail::handle_protected_exception(lua_state(), optional<const std::exception&>(nullopt), error, h); + firstreturn = lua_gettop(lua_state()); + return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); + } + catch (const std::string& error) { + detail::handle_protected_exception(lua_state(), optional<const std::exception&>(nullopt), error.c_str(), h); + firstreturn = lua_gettop(lua_state()); + return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); + } + catch (const std::exception& error) { + detail::handle_protected_exception(lua_state(), optional<const std::exception&>(error), error.what(), h); + firstreturn = lua_gettop(lua_state()); + return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); + } +#if SOL_IS_ON(SOL_EXCEPTIONS_CATCH_ALL) + // LuaJIT cannot have the catchall when the safe propagation is on + // but LuaJIT will swallow all C++ errors + // if we don't at least catch std::exception ones + catch (...) { + detail::handle_protected_exception(lua_state(), optional<const std::exception&>(nullopt), detail::protected_function_error, h); + firstreturn = lua_gettop(lua_state()); + return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); + } +#endif // Always catch edge case +#else + // do not handle exceptions: they can be propogated into C++ and keep all type information / rich information +#endif // Exceptions vs. No Exceptions + return protected_function_result(lua_state(), firstreturn, returncount, returncount, code); + } + }; +} // namespace sol + +// end of sol/protected_function.hpp + +#include <functional> + +namespace sol { + template <typename... Ret, typename... Args> + decltype(auto) stack_proxy::call(Args&&... args) { + stack_function sf(this->lua_state(), this->stack_index()); + return sf.template call<Ret...>(std::forward<Args>(args)...); + } + + inline protected_function_result::protected_function_result(unsafe_function_result&& o) noexcept + : L(o.lua_state()), index(o.stack_index()), returncount(o.return_count()), popcount(o.return_count()), err(o.status()) { + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but we will be thorough + o.abandon(); + } + + inline protected_function_result& protected_function_result::operator=(unsafe_function_result&& o) noexcept { + L = o.lua_state(); + index = o.stack_index(); + returncount = o.return_count(); + popcount = o.return_count(); + err = o.status(); + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but we will be thorough + o.abandon(); + return *this; + } + + inline unsafe_function_result::unsafe_function_result(protected_function_result&& o) noexcept + : L(o.lua_state()), index(o.stack_index()), returncount(o.return_count()) { + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but we will be thorough + o.abandon(); + } + inline unsafe_function_result& unsafe_function_result::operator=(protected_function_result&& o) noexcept { + L = o.lua_state(); + index = o.stack_index(); + returncount = o.return_count(); + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but we will be thorough + o.abandon(); + return *this; + } + + namespace detail { + template <typename... R> + struct std_shim { + unsafe_function lua_func_; + + std_shim(unsafe_function lua_func) : lua_func_(std::move(lua_func)) { + } + + template <typename... Args> + meta::return_type_t<R...> operator()(Args&&... args) { + return lua_func_.call<R...>(std::forward<Args>(args)...); + } + }; + + template <> + struct std_shim<void> { + unsafe_function lua_func_; + + std_shim(unsafe_function lua_func) : lua_func_(std::move(lua_func)) { + } + + template <typename... Args> + void operator()(Args&&... args) { + lua_func_.call<void>(std::forward<Args>(args)...); + } + }; + } // namespace detail + + namespace stack { + template <typename Signature> + struct unqualified_getter<std::function<Signature>> { + typedef meta::bind_traits<Signature> fx_t; + typedef typename fx_t::args_list args_lists; + typedef meta::tuple_types<typename fx_t::return_type> return_types; + + template <typename... R> + static std::function<Signature> get_std_func(types<R...>, lua_State* L, int index) { + detail::std_shim<R...> fx(unsafe_function(L, index)); + return fx; + } + + static std::function<Signature> get(lua_State* L, int index, record& tracking) { + tracking.use(1); + type t = type_of(L, index); + if (t == type::none || t == type::lua_nil) { + return nullptr; + } + return get_std_func(return_types(), L, index); + } + }; + + template <typename Allocator> + struct unqualified_getter<basic_bytecode<Allocator>> { + static basic_bytecode<Allocator> get(lua_State* L, int index, record& tracking) { + tracking.use(1); + stack_function sf(L, index); + return sf.dump(&dump_panic_on_error); + } + }; + } // namespace stack + +} // namespace sol + +// end of sol/function.hpp + +// beginning of sol/usertype.hpp + +// beginning of sol/usertype_core.hpp + +// beginning of sol/deprecate.hpp + +#ifndef SOL_DEPRECATED +#ifdef _MSC_VER +#define SOL_DEPRECATED __declspec(deprecated) +#elif __GNUC__ +#define SOL_DEPRECATED __attribute__((deprecated)) +#else +#define SOL_DEPRECATED [[deprecated]] +#endif // compilers +#endif // SOL_DEPRECATED + +namespace sol { namespace detail { + template <typename T> + struct SOL_DEPRECATED deprecate_type { + using type = T; + }; +}} // namespace sol::detail + +// end of sol/deprecate.hpp + +// beginning of sol/usertype_container_launch.hpp + +// beginning of sol/usertype_container.hpp + +namespace sol { + + template <typename T> + struct usertype_container; + + namespace container_detail { + + template <typename T> + struct has_clear_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(&C::clear)); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_empty_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(&C::empty)); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_erase_after_test { + private: + template <typename C> + static meta::sfinae_yes_t test( + decltype(std::declval<C>().erase_after(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>()))*); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T, typename = void> + struct has_find_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(std::declval<C>().find(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_find_test<T, std::enable_if_t<meta::is_lookup<T>::value>> { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(std::declval<C>().find(std::declval<std::add_rvalue_reference_t<typename C::key_type>>()))*); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_erase_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(std::declval<C>().erase(std::declval<typename C::iterator>()))*); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_erase_key_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(std::declval<C>().erase(std::declval<typename C::key_type>()))*); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_traits_find_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(&C::find)); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_traits_index_of_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(&C::index_of)); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_traits_insert_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(&C::insert)); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_traits_erase_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(&C::erase)); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_traits_index_set_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(&C::index_set)); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_traits_index_get_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(&C::index_get)); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_traits_set_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(&C::set)); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_traits_get_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(&C::get)); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_traits_at_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(&C::at)); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_traits_pairs_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(&C::pairs)); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_traits_ipairs_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(&C::ipairs)); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_traits_next_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(&C::next)); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_traits_add_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(&C::add)); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + struct has_traits_size_test { + private: + template <typename C> + static meta::sfinae_yes_t test(decltype(&C::size)); + template <typename C> + static meta::sfinae_no_t test(...); + + public: + static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>; + }; + + template <typename T> + using has_clear = meta::boolean<has_clear_test<T>::value>; + + template <typename T> + using has_empty = meta::boolean<has_empty_test<T>::value>; + + template <typename T> + using has_find = meta::boolean<has_find_test<T>::value>; + + template <typename T> + using has_erase = meta::boolean<has_erase_test<T>::value>; + + template <typename T> + using has_erase_key = meta::boolean<has_erase_key_test<T>::value>; + + template <typename T> + using has_erase_after = meta::boolean<has_erase_after_test<T>::value>; + + template <typename T> + using has_traits_get = meta::boolean<has_traits_get_test<T>::value>; + + template <typename T> + using has_traits_at = meta::boolean<has_traits_at_test<T>::value>; + + template <typename T> + using has_traits_set = meta::boolean<has_traits_set_test<T>::value>; + + template <typename T> + using has_traits_index_get = meta::boolean<has_traits_index_get_test<T>::value>; + + template <typename T> + using has_traits_index_set = meta::boolean<has_traits_index_set_test<T>::value>; + + template <typename T> + using has_traits_pairs = meta::boolean<has_traits_pairs_test<T>::value>; + + template <typename T> + using has_traits_ipairs = meta::boolean<has_traits_ipairs_test<T>::value>; + + template <typename T> + using has_traits_next = meta::boolean<has_traits_next_test<T>::value>; + + template <typename T> + using has_traits_add = meta::boolean<has_traits_add_test<T>::value>; + + template <typename T> + using has_traits_size = meta::boolean<has_traits_size_test<T>::value>; + + template <typename T> + using has_traits_clear = has_clear<T>; + + template <typename T> + using has_traits_empty = has_empty<T>; + + template <typename T> + using has_traits_find = meta::boolean<has_traits_find_test<T>::value>; + + template <typename T> + using has_traits_index_of = meta::boolean<has_traits_index_of_test<T>::value>; + + template <typename T> + using has_traits_insert = meta::boolean<has_traits_insert_test<T>::value>; + + template <typename T> + using has_traits_erase = meta::boolean<has_traits_erase_test<T>::value>; + + template <typename T> + struct is_forced_container : is_container<T> { }; + + template <typename T> + struct is_forced_container<as_container_t<T>> : std::true_type { }; + + template <typename T> + struct container_decay { + typedef T type; + }; + + template <typename T> + struct container_decay<as_container_t<T>> { + typedef T type; + }; + + template <typename T> + using container_decay_t = typename container_decay<meta::unqualified_t<T>>::type; + + template <typename T> + decltype(auto) get_key(std::false_type, T&& t) { + return std::forward<T>(t); + } + + template <typename T> + decltype(auto) get_key(std::true_type, T&& t) { + return t.first; + } + + template <typename T> + decltype(auto) get_value(std::false_type, T&& t) { + return std::forward<T>(t); + } + + template <typename T> + decltype(auto) get_value(std::true_type, T&& t) { + return t.second; + } + + template <typename X, typename = void> + struct usertype_container_default { + private: + typedef std::remove_pointer_t<meta::unwrap_unqualified_t<X>> T; + + public: + typedef lua_nil_t iterator; + typedef iterator sentinel; + typedef lua_nil_t value_type; + + static int at(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'at(index)' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + } + + static int get(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'get(key)' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + } + + static int index_get(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'container[key]' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + } + + static int set(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'set(key, value)' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + } + + static int index_set(lua_State* L_) { + return luaL_error( + L_, "sol: cannot call 'container[key] = value' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + } + + static int add(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'add' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + } + + static int insert(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'insert' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + } + + static int find(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'find' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + } + + static int index_of(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'index_of' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + } + + static int size(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'end' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + } + + static int clear(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'clear' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + } + + static int empty(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'empty' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + } + + static int erase(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'erase' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + } + + static int next(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'next' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + } + + static int pairs(lua_State* L_) { + return luaL_error(L_, "sol: cannot call '__pairs/pairs' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + } + + static int ipairs(lua_State* L_) { + return luaL_error(L_, "sol: cannot call '__ipairs' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + } + + static iterator begin(lua_State* L_, T&) { + luaL_error(L_, "sol: cannot call 'being' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + return lua_nil; + } + + static sentinel end(lua_State* L_, T&) { + luaL_error(L_, "sol: cannot call 'end' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); + return lua_nil; + } + }; + + template <typename X> + struct usertype_container_default<X, + std::enable_if_t<meta::all<is_forced_container<meta::unqualified_t<X>>, meta::has_value_type<meta::unqualified_t<container_decay_t<X>>>, + meta::has_iterator<meta::unqualified_t<container_decay_t<X>>>>::value>> { + private: + using T = std::remove_pointer_t<meta::unwrap_unqualified_t<container_decay_t<X>>>; + + private: + using deferred_uc = usertype_container<X>; + using is_associative = meta::is_associative<T>; + using is_lookup = meta::is_lookup<T>; + using is_ordered = meta::is_ordered<T>; + using is_matched_lookup = meta::is_matched_lookup<T>; + using iterator = typename T::iterator; + using sentinel = meta::sentinel_or_t<T, iterator>; + using value_type = typename T::value_type; + typedef meta::conditional_t<is_matched_lookup::value, std::pair<value_type, value_type>, + meta::conditional_t<is_associative::value || is_lookup::value, value_type, std::pair<std::ptrdiff_t, value_type>>> + KV; + typedef typename KV::first_type K; + typedef typename KV::second_type V; + typedef meta::conditional_t<is_matched_lookup::value, std::ptrdiff_t, K> next_K; + typedef decltype(*std::declval<iterator&>()) iterator_return; + typedef meta::conditional_t<is_associative::value || is_matched_lookup::value, std::add_lvalue_reference_t<V>, + meta::conditional_t<is_lookup::value, V, iterator_return>> + captured_type; + typedef typename meta::iterator_tag<iterator>::type iterator_category; + typedef std::is_same<iterator_category, std::input_iterator_tag> is_input_iterator; + typedef meta::conditional_t<is_input_iterator::value, V, decltype(detail::deref_move_only(std::declval<captured_type>()))> push_type; + typedef std::is_copy_assignable<V> is_copyable; + typedef meta::neg<meta::any<std::is_const<V>, std::is_const<std::remove_reference_t<iterator_return>>, meta::neg<is_copyable>>> is_writable; + typedef meta::unqualified_t<decltype(get_key(is_associative(), std::declval<std::add_lvalue_reference_t<value_type>>()))> key_type; + typedef meta::all<std::is_integral<K>, meta::neg<meta::any<is_associative, is_lookup>>> is_linear_integral; + + struct iter : detail::ebco<iterator, 0>, detail::ebco<sentinel, 1> { + using it_base = detail::ebco<iterator, 0>; + using sen_base = detail::ebco<sentinel, 1>; + main_reference keep_alive; + std::size_t index; + + iter(lua_State* L_, int stack_index_, iterator it_, sentinel sen_) noexcept + : it_base(std::move(it_)), sen_base(std::move(sen_)), keep_alive(L_, stack_index_), index(0) { + } + + iterator& it() noexcept { + return it_base::value(); + } + + const iterator& it() const noexcept { + return it_base::value(); + } + + sentinel& sen() noexcept { + return sen_base::value(); + } + + const sentinel& sen() const noexcept { + return sen_base::value(); + } + }; + + static auto& get_src(lua_State* L_) { +#if SOL_IS_ON(SOL_SAFE_USERTYPE) + auto p = stack::unqualified_check_get<T*>(L_, 1); + if (!p) { + luaL_error(L_, + "sol: 'self' is not of type '%s' (pass 'self' as first argument with ':' or call on proper type)", + detail::demangle<T>().c_str()); + } + if (p.value() == nullptr) { + luaL_error( + L_, "sol: 'self' argument is nil (pass 'self' as first argument with ':' or call on a '%s' type)", detail::demangle<T>().c_str()); + } + return *p.value(); +#else + return stack::unqualified_get<T>(L_, 1); +#endif // Safe getting with error + } + + static detail::error_result at_category(std::input_iterator_tag, lua_State* L_, T& self, std::ptrdiff_t pos) { + pos += deferred_uc::index_adjustment(L_, self); + if (pos < 0) { + return stack::push(L_, lua_nil); + } + auto it = deferred_uc::begin(L_, self); + auto e = deferred_uc::end(L_, self); + if (it == e) { + return stack::push(L_, lua_nil); + } + while (pos > 0) { + --pos; + ++it; + if (it == e) { + return stack::push(L_, lua_nil); + } + } + return get_associative(is_associative(), L_, it); + } + + static detail::error_result at_category(std::random_access_iterator_tag, lua_State* L_, T& self, std::ptrdiff_t pos) { + std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L_, self)); + pos += deferred_uc::index_adjustment(L_, self); + if (pos < 0 || pos >= len) { + return stack::push(L_, lua_nil); + } + auto it = std::next(deferred_uc::begin(L_, self), pos); + return get_associative(is_associative(), L_, it); + } + + static detail::error_result at_start(lua_State* L_, T& self, std::ptrdiff_t pos) { + return at_category(iterator_category(), L_, self, pos); + } + + template <typename Iter> + static detail::error_result get_associative(std::true_type, lua_State* L_, Iter& it) { + decltype(auto) v = *it; + return stack::stack_detail::push_reference<push_type>(L_, detail::deref_move_only(v.second)); + } + + template <typename Iter> + static detail::error_result get_associative(std::false_type, lua_State* L_, Iter& it) { + return stack::stack_detail::push_reference<push_type>(L_, detail::deref_move_only(*it)); + } + + static detail::error_result get_category(std::input_iterator_tag, lua_State* L_, T& self, K& key) { + key = static_cast<K>(key + deferred_uc::index_adjustment(L_, self)); + if (key < 0) { + return stack::push(L_, lua_nil); + } + auto it = deferred_uc::begin(L_, self); + auto e = deferred_uc::end(L_, self); + if (it == e) { + return stack::push(L_, lua_nil); + } + while (key > 0) { + --key; + ++it; + if (it == e) { + return stack::push(L_, lua_nil); + } + } + return get_associative(is_associative(), L_, it); + } + + static detail::error_result get_category(std::random_access_iterator_tag, lua_State* L_, T& self, K& key) { + std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L_, self)); + key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self)); + if (key < 0 || key >= len) { + return stack::push(L_, lua_nil); + } + auto it = std::next(deferred_uc::begin(L_, self), key); + return get_associative(is_associative(), L_, it); + } + + static detail::error_result get_it(std::true_type, lua_State* L_, T& self, K& key) { + return get_category(iterator_category(), L_, self, key); + } + + static detail::error_result get_comparative(std::true_type, lua_State* L_, T& self, K& key) { + auto fx = [&](const value_type& r) -> bool { return key == get_key(is_associative(), r); }; + auto e = deferred_uc::end(L_, self); + auto it = std::find_if(deferred_uc::begin(L_, self), e, std::ref(fx)); + if (it == e) { + return stack::push(L_, lua_nil); + } + return get_associative(is_associative(), L_, it); + } + + static detail::error_result get_comparative(std::false_type, lua_State*, T&, K&) { + return detail::error_result("cannot get this key on '%s': no suitable way to increment iterator and compare to key value '%s'", + detail::demangle<T>().data(), + detail::demangle<K>().data()); + } + + static detail::error_result get_it(std::false_type, lua_State* L_, T& self, K& key) { + return get_comparative(meta::supports_op_equal<K, key_type>(), L_, self, key); + } + + static detail::error_result set_associative(std::true_type, iterator& it, stack_object value) { + decltype(auto) v = *it; + v.second = value.as<V>(); + return {}; + } + + static detail::error_result set_associative(std::false_type, iterator& it, stack_object value) { + decltype(auto) v = *it; + v = value.as<V>(); + return {}; + } + + static detail::error_result set_writable(std::true_type, lua_State*, T&, iterator& it, stack_object value) { + return set_associative(is_associative(), it, std::move(value)); + } + + static detail::error_result set_writable(std::false_type, lua_State*, T&, iterator&, stack_object) { + return detail::error_result( + "cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle<T>().data()); + } + + static detail::error_result set_category(std::input_iterator_tag, lua_State* L_, T& self, stack_object okey, stack_object value) { + decltype(auto) key = okey.as<K>(); + key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self)); + auto e = deferred_uc::end(L_, self); + auto it = deferred_uc::begin(L_, self); + auto backit = it; + for (; key > 0 && it != e; --key, ++it) { + backit = it; + } + if (it == e) { + if (key == 0) { + return add_copyable(is_copyable(), L_, self, std::move(value), meta::has_insert_after<T>::value ? backit : it); + } + return detail::error_result("out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str()); + } + return set_writable(is_writable(), L_, self, it, std::move(value)); + } + + static detail::error_result set_category(std::random_access_iterator_tag, lua_State* L_, T& self, stack_object okey, stack_object value) { + decltype(auto) key = okey.as<K>(); + key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self)); + if (key < 0) { + return detail::error_result("sol: out of bounds (too small) for set on '%s'", detail::demangle<T>().c_str()); + } + std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L_, self)); + if (key == len) { + return add_copyable(is_copyable(), L_, self, std::move(value)); + } + else if (key >= len) { + return detail::error_result("sol: out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str()); + } + auto it = std::next(deferred_uc::begin(L_, self), key); + return set_writable(is_writable(), L_, self, it, std::move(value)); + } + + static detail::error_result set_comparative(std::true_type, lua_State* L_, T& self, stack_object okey, stack_object value) { + decltype(auto) key = okey.as<K>(); + if (!is_writable::value) { + return detail::error_result( + "cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle<T>().data()); + } + auto fx = [&](const value_type& r) -> bool { return key == get_key(is_associative(), r); }; + auto e = deferred_uc::end(L_, self); + auto it = std::find_if(deferred_uc::begin(L_, self), e, std::ref(fx)); + if (it == e) { + return {}; + } + return set_writable(is_writable(), L_, self, it, std::move(value)); + } + + static detail::error_result set_comparative(std::false_type, lua_State*, T&, stack_object, stack_object) { + return detail::error_result("cannot set this value on '%s': no suitable way to increment iterator or compare to '%s' key", + detail::demangle<T>().data(), + detail::demangle<K>().data()); + } + + template <typename Iter> + static detail::error_result set_associative_insert(std::true_type, lua_State*, T& self, Iter& it, K& key, stack_object value) { + if constexpr (meta::has_insert_with_iterator<T>::value) { + self.insert(it, value_type(key, value.as<V>())); + return {}; + } + else if constexpr (meta::has_insert<T>::value) { + self.insert(value_type(key, value.as<V>())); + return {}; + } + else { + (void)self; + (void)it; + (void)key; + return detail::error_result( + "cannot call 'set' on '%s': there is no 'insert' function on this associative type", detail::demangle<T>().c_str()); + } + } + + template <typename Iter> + static detail::error_result set_associative_insert(std::false_type, lua_State*, T& self, Iter& it, K& key, stack_object) { + if constexpr (meta::has_insert_with_iterator<T>::value) { + self.insert(it, key); + return {}; + } + else if constexpr (meta::has_insert<T>::value) { + self.insert(key); + return {}; + } + else { + (void)self; + (void)it; + (void)key; + return detail::error_result( + "cannot call 'set' on '%s': there is no 'insert' function on this non-associative type", detail::demangle<T>().c_str()); + } + } + + static detail::error_result set_associative_find(std::true_type, lua_State* L_, T& self, stack_object okey, stack_object value) { + decltype(auto) key = okey.as<K>(); + auto it = self.find(key); + if (it == deferred_uc::end(L_, self)) { + return set_associative_insert(is_associative(), L_, self, it, key, std::move(value)); + } + return set_writable(is_writable(), L_, self, it, std::move(value)); + } + + static detail::error_result set_associative_find(std::false_type, lua_State* L_, T& self, stack_object key, stack_object value) { + return set_comparative(meta::supports_op_equal<K, key_type>(), L_, self, std::move(key), std::move(value)); + } + + static detail::error_result set_it(std::true_type, lua_State* L_, T& self, stack_object key, stack_object value) { + return set_category(iterator_category(), L_, self, std::move(key), std::move(value)); + } + + static detail::error_result set_it(std::false_type, lua_State* L_, T& self, stack_object key, stack_object value) { + return set_associative_find(meta::all<has_find<T>, meta::any<is_associative, is_lookup>>(), L_, self, std::move(key), std::move(value)); + } + + template <bool idx_of = false> + static detail::error_result find_has_associative_lookup(std::true_type, lua_State* L_, T& self) { + if constexpr (!is_ordered::value && idx_of) { + (void)L_; + (void)self; + return detail::error_result("cannot perform an 'index_of': '%s's is not an ordered container", detail::demangle<T>().data()); + } + else { + decltype(auto) key = stack::unqualified_get<K>(L_, 2); + auto it = self.find(key); + if (it == deferred_uc::end(L_, self)) { + return stack::push(L_, lua_nil); + } + if constexpr (idx_of) { + auto dist = std::distance(deferred_uc::begin(L_, self), it); + dist -= deferred_uc::index_adjustment(L_, self); + return stack::push(L_, dist); + } + else { + return get_associative(is_associative(), L_, it); + } + } + } + + template <bool idx_of = false> + static detail::error_result find_has_associative_lookup(std::false_type, lua_State* L_, T& self) { + if constexpr (!is_ordered::value && idx_of) { + (void)L_; + (void)self; + return detail::error_result("cannot perform an 'index_of': '%s's is not an ordered container", detail::demangle<T>().data()); + } + else { + decltype(auto) value = stack::unqualified_get<V>(L_, 2); + auto it = self.find(value); + if (it == deferred_uc::end(L_, self)) { + return stack::push(L_, lua_nil); + } + if constexpr (idx_of) { + auto dist = std::distance(deferred_uc::begin(L_, self), it); + dist -= deferred_uc::index_adjustment(L_, self); + return stack::push(L_, dist); + } + else { + return get_associative(is_associative(), L_, it); + } + } + } + + template <bool idx_of = false> + static detail::error_result find_has(std::true_type, lua_State* L_, T& self) { + return find_has_associative_lookup<idx_of>(meta::any<is_lookup, is_associative>(), L_, self); + } + + template <typename Iter> + static detail::error_result find_associative_lookup(std::true_type, lua_State* L_, T&, Iter& it, std::size_t) { + return get_associative(is_associative(), L_, it); + } + + template <typename Iter> + static detail::error_result find_associative_lookup(std::false_type, lua_State* L_, T& self, Iter&, std::size_t idx) { + idx = static_cast<std::size_t>(static_cast<std::ptrdiff_t>(idx) - deferred_uc::index_adjustment(L_, self)); + return stack::push(L_, idx); + } + + template <bool = false> + static detail::error_result find_comparative(std::false_type, lua_State*, T&) { + return detail::error_result("cannot call 'find' on '%s': there is no 'find' function and the value_type is not equality comparable", + detail::demangle<T>().c_str()); + } + + template <bool idx_of = false> + static detail::error_result find_comparative(std::true_type, lua_State* L_, T& self) { + decltype(auto) value = stack::unqualified_get<V>(L_, 2); + auto it = deferred_uc::begin(L_, self); + auto e = deferred_uc::end(L_, self); + std::size_t idx = 0; + for (;; ++it, ++idx) { + if (it == e) { + return stack::push(L_, lua_nil); + } + if (value == get_value(is_associative(), *it)) { + break; + } + } + return find_associative_lookup(meta::all<meta::boolean<!idx_of>, meta::any<is_lookup, is_associative>>(), L_, self, it, idx); + } + + template <bool idx_of = false> + static detail::error_result find_has(std::false_type, lua_State* L_, T& self) { + return find_comparative<idx_of>(meta::supports_op_equal<V>(), L_, self); + } + + template <typename Iter> + static detail::error_result add_insert_after(std::false_type, lua_State* L_, T& self, stack_object value, Iter&) { + return add_insert_after(std::false_type(), L_, self, value); + } + + static detail::error_result add_insert_after(std::false_type, lua_State*, T&, stack_object) { + return detail::error_result("cannot call 'add' on type '%s': no suitable insert/push_back C++ functions", detail::demangle<T>().data()); + } + + template <typename Iter> + static detail::error_result add_insert_after(std::true_type, lua_State*, T& self, stack_object value, Iter& pos) { + self.insert_after(pos, value.as<V>()); + return {}; + } + + static detail::error_result add_insert_after(std::true_type, lua_State* L_, T& self, stack_object value) { + auto backit = self.before_begin(); + { + auto e = deferred_uc::end(L_, self); + for (auto it = deferred_uc::begin(L_, self); it != e; ++backit, ++it) { } + } + return add_insert_after(std::true_type(), L_, self, value, backit); + } + + template <typename Iter> + static detail::error_result add_insert(std::true_type, lua_State*, T& self, stack_object value, Iter& pos) { + self.insert(pos, value.as<V>()); + return {}; + } + + static detail::error_result add_insert(std::true_type, lua_State* L_, T& self, stack_object value) { + auto pos = deferred_uc::end(L_, self); + return add_insert(std::true_type(), L_, self, value, pos); + } + + template <typename Iter> + static detail::error_result add_insert(std::false_type, lua_State* L_, T& self, stack_object value, Iter& pos) { + return add_insert_after(meta::has_insert_after<T>(), L_, self, std::move(value), pos); + } + + static detail::error_result add_insert(std::false_type, lua_State* L_, T& self, stack_object value) { + return add_insert_after(meta::has_insert_after<T>(), L_, self, std::move(value)); + } + + template <typename Iter> + static detail::error_result add_push_back(std::true_type, lua_State*, T& self, stack_object value, Iter&) { + self.push_back(value.as<V>()); + return {}; + } + + static detail::error_result add_push_back(std::true_type, lua_State*, T& self, stack_object value) { + self.push_back(value.as<V>()); + return {}; + } + + template <typename Iter> + static detail::error_result add_push_back(std::false_type, lua_State* L_, T& self, stack_object value, Iter& pos) { + return add_insert( + std::integral_constant < bool, meta::has_insert<T>::value || meta::has_insert_with_iterator<T>::value > (), L_, self, value, pos); + } + + static detail::error_result add_push_back(std::false_type, lua_State* L_, T& self, stack_object value) { + return add_insert( + std::integral_constant < bool, meta::has_insert<T>::value || meta::has_insert_with_iterator<T>::value > (), L_, self, value); + } + + template <typename Iter> + static detail::error_result add_associative(std::true_type, lua_State* L_, T& self, stack_object key, Iter& pos) { + if constexpr (meta::has_insert_with_iterator<T>::value) { + self.insert(pos, value_type(key.as<K>(), stack::unqualified_get<V>(L_, 3))); + return {}; + } + else if constexpr (meta::has_insert<T>::value) { + self.insert(value_type(key.as<K>(), stack::unqualified_get<V>(L_, 3))); + return {}; + } + else { + (void)L_; + (void)self; + (void)key; + (void)pos; + return detail::error_result( + "cannot call 'insert' on '%s': there is no 'insert' function on this associative type", detail::demangle<T>().c_str()); + } + } + + static detail::error_result add_associative(std::true_type, lua_State* L_, T& self, stack_object key) { + auto pos = deferred_uc::end(L_, self); + return add_associative(std::true_type(), L_, self, std::move(key), pos); + } + + template <typename Iter> + static detail::error_result add_associative(std::false_type, lua_State* L_, T& self, stack_object value, Iter& pos) { + return add_push_back(meta::has_push_back<T>(), L_, self, value, pos); + } + + static detail::error_result add_associative(std::false_type, lua_State* L_, T& self, stack_object value) { + return add_push_back(meta::has_push_back<T>(), L_, self, value); + } + + template <typename Iter> + static detail::error_result add_copyable(std::true_type, lua_State* L_, T& self, stack_object value, Iter& pos) { + return add_associative(is_associative(), L_, self, std::move(value), pos); + } + + static detail::error_result add_copyable(std::true_type, lua_State* L_, T& self, stack_object value) { + return add_associative(is_associative(), L_, self, value); + } + + template <typename Iter> + static detail::error_result add_copyable(std::false_type, lua_State* L_, T& self, stack_object value, Iter&) { + return add_copyable(std::false_type(), L_, self, std::move(value)); + } + + static detail::error_result add_copyable(std::false_type, lua_State*, T&, stack_object) { + return detail::error_result("cannot call 'add' on '%s': value_type is non-copyable", detail::demangle<T>().data()); + } + + static detail::error_result insert_lookup(std::true_type, lua_State* L_, T& self, stack_object, stack_object value) { + // TODO: should we warn or error about someone calling insert on an ordered / lookup container with no associativity? + return add_copyable(std::true_type(), L_, self, std::move(value)); + } + + static detail::error_result insert_lookup(std::false_type, lua_State* L_, T& self, stack_object where, stack_object value) { + auto it = deferred_uc::begin(L_, self); + auto key = where.as<K>(); + key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self)); + std::advance(it, key); + self.insert(it, value.as<V>()); + return {}; + } + + static detail::error_result insert_after_has(std::true_type, lua_State* L_, T& self, stack_object where, stack_object value) { + auto key = where.as<K>(); + auto backit = self.before_begin(); + { + key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self)); + auto e = deferred_uc::end(L_, self); + for (auto it = deferred_uc::begin(L_, self); key > 0; ++backit, ++it, --key) { + if (backit == e) { + return detail::error_result("sol: out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str()); + } + } + } + self.insert_after(backit, value.as<V>()); + return {}; + } + + static detail::error_result insert_after_has(std::false_type, lua_State*, T&, stack_object, stack_object) { + return detail::error_result( + "cannot call 'insert' on '%s': no suitable or similar functionality detected on this container", detail::demangle<T>().data()); + } + + static detail::error_result insert_has(std::true_type, lua_State* L_, T& self, stack_object key, stack_object value) { + return insert_lookup(meta::any<is_associative, is_lookup>(), L_, self, std::move(key), std::move(value)); + } + + static detail::error_result insert_has(std::false_type, lua_State* L_, T& self, stack_object where, stack_object value) { + return insert_after_has(meta::has_insert_after<T>(), L_, self, where, value); + } + + static detail::error_result insert_copyable(std::true_type, lua_State* L_, T& self, stack_object key, stack_object value) { + return insert_has(std::integral_constant < bool, + meta::has_insert<T>::value || meta::has_insert_with_iterator<T>::value > (), + L_, + self, + std::move(key), + std::move(value)); + } + + static detail::error_result insert_copyable(std::false_type, lua_State*, T&, stack_object, stack_object) { + return detail::error_result("cannot call 'insert' on '%s': value_type is non-copyable", detail::demangle<T>().data()); + } + + static detail::error_result erase_integral(std::true_type, lua_State* L_, T& self, K& key) { + auto it = deferred_uc::begin(L_, self); + key = (static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self)); + std::advance(it, key); + self.erase(it); + + return {}; + } + + static detail::error_result erase_integral(std::false_type, lua_State* L_, T& self, const K& key) { + auto fx = [&](const value_type& r) -> bool { return key == r; }; + auto e = deferred_uc::end(L_, self); + auto it = std::find_if(deferred_uc::begin(L_, self), e, std::ref(fx)); + if (it == e) { + return {}; + } + self.erase(it); + + return {}; + } + + static detail::error_result erase_associative_lookup(std::true_type, lua_State*, T& self, const K& key) { + self.erase(key); + return {}; + } + + static detail::error_result erase_associative_lookup(std::false_type, lua_State* L_, T& self, K& key) { + return erase_integral(std::is_integral<K>(), L_, self, key); + } + + static detail::error_result erase_after_has(std::true_type, lua_State* L_, T& self, K& key) { + auto backit = self.before_begin(); + { + key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self)); + auto e = deferred_uc::end(L_, self); + for (auto it = deferred_uc::begin(L_, self); key > 0; ++backit, ++it, --key) { + if (backit == e) { + return detail::error_result("sol: out of bounds for erase on '%s'", detail::demangle<T>().c_str()); + } + } + } + self.erase_after(backit); + return {}; + } + + static detail::error_result erase_after_has(std::false_type, lua_State*, T&, const K&) { + return detail::error_result("sol: cannot call erase on '%s'", detail::demangle<T>().c_str()); + } + + static detail::error_result erase_key_has(std::true_type, lua_State* L_, T& self, K& key) { + return erase_associative_lookup(meta::any<is_associative, is_lookup>(), L_, self, key); + } + + static detail::error_result erase_key_has(std::false_type, lua_State* L_, T& self, K& key) { + return erase_after_has(has_erase_after<T>(), L_, self, key); + } + + static detail::error_result erase_has(std::true_type, lua_State* L_, T& self, K& key) { + return erase_associative_lookup(meta::any<is_associative, is_lookup>(), L_, self, key); + } + + static detail::error_result erase_has(std::false_type, lua_State* L_, T& self, K& key) { + return erase_key_has(has_erase_key<T>(), L_, self, key); + } + + static auto size_has(std::false_type, lua_State* L_, T& self) { + return std::distance(deferred_uc::begin(L_, self), deferred_uc::end(L_, self)); + } + + static auto size_has(std::true_type, lua_State*, T& self) { + return self.size(); + } + + static void clear_has(std::true_type, lua_State*, T& self) { + self.clear(); + } + + static void clear_has(std::false_type, lua_State* L_, T&) { + luaL_error(L_, "sol: cannot call clear on '%s'", detail::demangle<T>().c_str()); + } + + static bool empty_has(std::true_type, lua_State*, T& self) { + return self.empty(); + } + + static bool empty_has(std::false_type, lua_State* L_, T& self) { + return deferred_uc::begin(L_, self) == deferred_uc::end(L_, self); + } + + static detail::error_result get_associative_find(std::true_type, lua_State* L_, T& self, K& key) { + auto it = self.find(key); + if (it == deferred_uc::end(L_, self)) { + stack::push(L_, lua_nil); + return {}; + } + return get_associative(std::true_type(), L_, it); + } + + static detail::error_result get_associative_find(std::false_type, lua_State* L_, T& self, K& key) { + return get_it(is_linear_integral(), L_, self, key); + } + + static detail::error_result get_start(lua_State* L_, T& self, K& key) { + return get_associative_find(std::integral_constant < bool, is_associative::value&& has_find<T>::value > (), L_, self, key); + } + + static detail::error_result set_start(lua_State* L_, T& self, stack_object key, stack_object value) { + return set_it(is_linear_integral(), L_, self, std::move(key), std::move(value)); + } + + static std::size_t size_start(lua_State* L_, T& self) { + return static_cast<std::size_t>(size_has(meta::has_size<T>(), L_, self)); + } + + static void clear_start(lua_State* L_, T& self) { + clear_has(has_clear<T>(), L_, self); + } + + static bool empty_start(lua_State* L_, T& self) { + return empty_has(has_empty<T>(), L_, self); + } + + static detail::error_result erase_start(lua_State* L_, T& self, K& key) { + return erase_has(has_erase<T>(), L_, self, key); + } + + template <bool ip> + static int next_associative(std::true_type, lua_State* L_) { + iter& i = stack::unqualified_get<user<iter>>(L_, 1); + auto& it = i.it; + auto& end = i.end; + if (it == end) { + return stack::push(L_, lua_nil); + } + int p; + if constexpr (ip) { + ++i.index; + p = stack::push_reference(L_, i.index); + } + else { + p = stack::push_reference(L_, it->first); + } + p += stack::stack_detail::push_reference<push_type>(L_, detail::deref_move_only(it->second)); + std::advance(it, 1); + return p; + } + + template <bool> + static int next_associative(std::false_type, lua_State* L_) { + iter& i = stack::unqualified_get<user<iter>>(L_, 1); + auto& it = i.it(); + auto& end = i.sen(); + next_K k = stack::unqualified_get<next_K>(L_, 2); + if (it == end) { + return stack::push(L_, lua_nil); + } + int p; + if constexpr (std::is_integral_v<next_K>) { + p = stack::push_reference(L_, k + 1); + } + else { + p = stack::stack_detail::push_reference(L_, k + 1); + } + p += stack::stack_detail::push_reference<push_type>(L_, detail::deref_move_only(*it)); + std::advance(it, 1); + return p; + } + + template <bool ip> + static int next_iter(lua_State* L_) { + typedef meta::any<is_associative, meta::all<is_lookup, meta::neg<is_matched_lookup>>> is_assoc; + return next_associative<ip>(is_assoc(), L_); + } + + template <bool ip> + static int pairs_associative(std::true_type, lua_State* L_) { + auto& src = get_src(L_); + stack::push(L_, next_iter<ip>); + stack::push<user<iter>>(L_, L_, 1, deferred_uc::begin(L_, src), deferred_uc::begin(L_, src)); + stack::push(L_, lua_nil); + return 3; + } + + template <bool ip> + static int pairs_associative(std::false_type, lua_State* L_) { + auto& src = get_src(L_); + stack::push(L_, next_iter<ip>); + stack::push<user<iter>>(L_, L_, 1, deferred_uc::begin(L_, src), deferred_uc::end(L_, src)); + stack::push(L_, 0); + return 3; + } + + public: + static int at(lua_State* L_) { + auto& self = get_src(L_); + detail::error_result er; + { + std::ptrdiff_t pos = stack::unqualified_get<std::ptrdiff_t>(L_, 2); + er = at_start(L_, self, pos); + } + return handle_errors(L_, er); + } + + static int get(lua_State* L_) { + auto& self = get_src(L_); + detail::error_result er; + { + decltype(auto) key = stack::unqualified_get<K>(L_); + er = get_start(L_, self, key); + } + return handle_errors(L_, er); + } + + static int index_get(lua_State* L_) { + return get(L_); + } + + static int set(lua_State* L_) { + stack_object value = stack_object(L_, raw_index(3)); + if constexpr (is_linear_integral::value) { + // for non-associative containers, + // erasure only happens if it is the + // last index in the container + auto key = stack::get<K>(L_, 2); + auto self_size = deferred_uc::size(L_); + if (key == static_cast<K>(self_size)) { + if (type_of(L_, 3) == type::lua_nil) { + return erase(L_); + } + } + } + else { + if (type_of(L_, 3) == type::lua_nil) { + return erase(L_); + } + } + auto& self = get_src(L_); + detail::error_result er = set_start(L_, self, stack_object(L_, raw_index(2)), std::move(value)); + return handle_errors(L_, er); + } + + static int index_set(lua_State* L_) { + return set(L_); + } + + static int add(lua_State* L_) { + auto& self = get_src(L_); + detail::error_result er = add_copyable(is_copyable(), L_, self, stack_object(L_, raw_index(2))); + return handle_errors(L_, er); + } + + static int insert(lua_State* L_) { + auto& self = get_src(L_); + detail::error_result er = insert_copyable(is_copyable(), L_, self, stack_object(L_, raw_index(2)), stack_object(L_, raw_index(3))); + return handle_errors(L_, er); + } + + static int find(lua_State* L_) { + auto& self = get_src(L_); + detail::error_result er = find_has(has_find<T>(), L_, self); + return handle_errors(L_, er); + } + + static int index_of(lua_State* L_) { + auto& self = get_src(L_); + detail::error_result er = find_has<true>(has_find<T>(), L_, self); + return handle_errors(L_, er); + } + + static iterator begin(lua_State*, T& self) { + if constexpr (meta::has_begin_end_v<T>) { + return self.begin(); + } + else { + using std::begin; + return begin(self); + } + } + + static sentinel end(lua_State*, T& self) { + if constexpr (meta::has_begin_end_v<T>) { + return self.end(); + } + else { + using std::end; + return end(self); + } + } + + static int size(lua_State* L_) { + auto& self = get_src(L_); + std::size_t r = size_start(L_, self); + return stack::push(L_, r); + } + + static int clear(lua_State* L_) { + auto& self = get_src(L_); + clear_start(L_, self); + return 0; + } + + static int erase(lua_State* L_) { + auto& self = get_src(L_); + detail::error_result er; + { + decltype(auto) key = stack::unqualified_get<K>(L_, 2); + er = erase_start(L_, self, key); + } + return handle_errors(L_, er); + } + + static int empty(lua_State* L_) { + auto& self = get_src(L_); + return stack::push(L_, empty_start(L_, self)); + } + + static std::ptrdiff_t index_adjustment(lua_State*, T&) { + return static_cast<std::ptrdiff_t>((SOL_CONTAINER_START_INDEX_I_) == 0 ? 0 : -(SOL_CONTAINER_START_INDEX_I_)); + } + + static int pairs(lua_State* L_) { + typedef meta::any<is_associative, meta::all<is_lookup, meta::neg<is_matched_lookup>>> is_assoc; + return pairs_associative<false>(is_assoc(), L_); + } + + static int ipairs(lua_State* L_) { + typedef meta::any<is_associative, meta::all<is_lookup, meta::neg<is_matched_lookup>>> is_assoc; + return pairs_associative<true>(is_assoc(), L_); + } + + static int next(lua_State* L_) { + return stack::push(L_, next_iter<false>); + } + }; + + template <typename X> + struct usertype_container_default<X, std::enable_if_t<std::is_array<std::remove_pointer_t<meta::unwrap_unqualified_t<X>>>::value>> { + private: + typedef std::remove_pointer_t<meta::unwrap_unqualified_t<X>> T; + typedef usertype_container<X> deferred_uc; + + public: + typedef std::remove_extent_t<T> value_type; + typedef value_type* iterator; + typedef iterator sentinel; + + private: + struct iter : detail::ebco<iterator, 0>, detail::ebco<sentinel, 1> { + using it_base = detail::ebco<iterator, 0>; + using sen_base = detail::ebco<sentinel, 1>; + reference keep_alive; + + iter(lua_State* L_, int stack_index_, iterator it_, sentinel sen_) noexcept + : it_base(std::move(it_)), sen_base(std::move(sen_)), keep_alive(sol::main_thread(L_, L_), stack_index_) { + } + + iterator& it() noexcept { + return it_base::value(); + } + + const iterator& it() const noexcept { + return it_base::value(); + } + + sentinel& sen() noexcept { + return sen_base::value(); + } + + const sentinel& sen() const noexcept { + return sen_base::value(); + } + }; + + static auto& get_src(lua_State* L_) { + auto p = stack::unqualified_check_get<T*>(L_, 1); +#if SOL_IS_ON(SOL_SAFE_USERTYPE) + if (!p) { + luaL_error(L_, + "sol: 'self' is not of type '%s' (pass 'self' as first argument with ':' or call on proper type)", + detail::demangle<T>().c_str()); + } + if (p.value() == nullptr) { + luaL_error( + L_, "sol: 'self' argument is nil (pass 'self' as first argument with ':' or call on a '%s' type)", detail::demangle<T>().c_str()); + } +#endif // Safe getting with error + return *p.value(); + } + + static int find(std::true_type, lua_State* L_) { + T& self = get_src(L_); + decltype(auto) value = stack::unqualified_get<value_type>(L_, 2); + std::size_t N = std::extent<T>::value; + for (std::size_t idx = 0; idx < N; ++idx) { + using v_t = std::add_const_t<decltype(self[idx])>; + v_t v = self[idx]; + if (v == value) { + idx = static_cast<std::size_t>(static_cast<std::ptrdiff_t>(idx) - deferred_uc::index_adjustment(L_, self)); + return stack::push(L_, idx); + } + } + return stack::push(L_, lua_nil); + } + + static int find(std::false_type, lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'find' on '%s': no supported comparison operator for the value type", detail::demangle<T>().c_str()); + } + + static int next_iter(lua_State* L_) { + iter& i = stack::unqualified_get<user<iter>>(L_, 1); + auto& it = i.it(); + auto& end = i.sen(); + std::size_t k = stack::unqualified_get<std::size_t>(L_, 2); + if (it == end) { + return 0; + } + int p; + p = stack::push(L_, k + 1); + p += stack::push_reference(L_, detail::deref_move_only(*it)); + std::advance(it, 1); + return p; + } + + public: + static int clear(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'clear' on type '%s': cannot remove all items from a fixed array", detail::demangle<T>().c_str()); + } + + static int erase(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'erase' on type '%s': cannot remove an item from fixed arrays", detail::demangle<T>().c_str()); + } + + static int add(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'add' on type '%s': cannot add to fixed arrays", detail::demangle<T>().c_str()); + } + + static int insert(lua_State* L_) { + return luaL_error(L_, "sol: cannot call 'insert' on type '%s': cannot insert new entries into fixed arrays", detail::demangle<T>().c_str()); + } + + static int at(lua_State* L_) { + return get(L_); + } + + static int get(lua_State* L_) { + T& self = get_src(L_); + std::ptrdiff_t idx = stack::unqualified_get<std::ptrdiff_t>(L_, 2); + idx += deferred_uc::index_adjustment(L_, self); + if (idx >= static_cast<std::ptrdiff_t>(std::extent<T>::value) || idx < 0) { + return stack::push(L_, lua_nil); + } + return stack::push_reference(L_, detail::deref_move_only(self[idx])); + } + + static int index_get(lua_State* L_) { + return get(L_); + } + + static int set(lua_State* L_) { + T& self = get_src(L_); + std::ptrdiff_t idx = stack::unqualified_get<std::ptrdiff_t>(L_, 2); + idx += deferred_uc::index_adjustment(L_, self); + if (idx >= static_cast<std::ptrdiff_t>(std::extent<T>::value)) { + return luaL_error(L_, "sol: index out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str()); + } + if (idx < 0) { + return luaL_error(L_, "sol: index out of bounds (too small) for set on '%s'", detail::demangle<T>().c_str()); + } + self[idx] = stack::unqualified_get<value_type>(L_, 3); + return 0; + } + + static int index_set(lua_State* L_) { + return set(L_); + } + + static int index_of(lua_State* L_) { + return find(L_); + } + + static int find(lua_State* L_) { + return find(meta::supports_op_equal<value_type, value_type>(), L_); + } + + static int size(lua_State* L_) { + return stack::push(L_, std::extent<T>::value); + } + + static int empty(lua_State* L_) { + return stack::push(L_, std::extent<T>::value > 0); + } + + static int pairs(lua_State* L_) { + auto& src = get_src(L_); + stack::push(L_, next_iter); + stack::push<user<iter>>(L_, L_, 1, deferred_uc::begin(L_, src), deferred_uc::end(L_, src)); + stack::push(L_, 0); + return 3; + } + + static int ipairs(lua_State* L_) { + return pairs(L_); + } + + static int next(lua_State* L_) { + return stack::push(L_, next_iter); + } + + static std::ptrdiff_t index_adjustment(lua_State*, T&) { + return (SOL_CONTAINER_START_INDEX_I_) == 0 ? 0 : -(SOL_CONTAINER_START_INDEX_I_); + } + + static iterator begin(lua_State*, T& self) { + return std::addressof(self[0]); + } + + static sentinel end(lua_State*, T& self) { + return std::addressof(self[0]) + std::extent<T>::value; + } + }; + + template <typename X> + struct usertype_container_default<usertype_container<X>> : usertype_container_default<X> { }; + } // namespace container_detail + + template <typename T> + struct usertype_container : container_detail::usertype_container_default<T> { }; + +} // namespace sol + +// end of sol/usertype_container.hpp + +#include <unordered_map> + +namespace sol { + + namespace container_detail { + template <typename X> + struct u_c_launch { + using T = std::remove_pointer_t<meta::unqualified_t<X>>; + using uc = usertype_container<T>; + using default_uc = usertype_container_default<T>; + + static inline int real_index_get_traits(std::true_type, lua_State* L) { + return uc::index_get(L); + } + + static inline int real_index_get_traits(std::false_type, lua_State* L) { + return default_uc::index_get(L); + } + + static inline int real_index_call(lua_State* L) { + static const std::unordered_map<string_view, lua_CFunction> calls { + { "at", &real_at_call }, + { "get", &real_get_call }, + { "set", &real_set_call }, + { "size", &real_length_call }, + { "add", &real_add_call }, + { "empty", &real_empty_call }, + { "insert", &real_insert_call }, + { "clear", &real_clear_call }, + { "find", &real_find_call }, + { "index_of", &real_index_of_call }, + { "erase", &real_erase_call }, + { "pairs", &pairs_call }, + { "next", &next_call }, + }; + auto maybenameview = stack::unqualified_check_get<string_view>(L, 2); + if (maybenameview) { + const string_view& name = *maybenameview; + auto it = calls.find(name); + if (it != calls.cend()) { + return stack::push(L, it->second); + } + } + return real_index_get_traits(container_detail::has_traits_index_get<uc>(), L); + } + + static inline int real_at_traits(std::true_type, lua_State* L) { + return uc::at(L); + } + + static inline int real_at_traits(std::false_type, lua_State* L) { + return default_uc::at(L); + } + + static inline int real_at_call(lua_State* L) { + return real_at_traits(container_detail::has_traits_at<uc>(), L); + } + + static inline int real_get_traits(std::true_type, lua_State* L) { + return uc::get(L); + } + + static inline int real_get_traits(std::false_type, lua_State* L) { + return default_uc::get(L); + } + + static inline int real_get_call(lua_State* L) { + return real_get_traits(container_detail::has_traits_get<uc>(), L); + } + + static inline int real_set_traits(std::true_type, lua_State* L) { + return uc::set(L); + } + + static inline int real_set_traits(std::false_type, lua_State* L) { + return default_uc::set(L); + } + + static inline int real_set_call(lua_State* L) { + return real_set_traits(container_detail::has_traits_set<uc>(), L); + } + + static inline int real_index_set_traits(std::true_type, lua_State* L) { + return uc::index_set(L); + } + + static inline int real_index_set_traits(std::false_type, lua_State* L) { + return default_uc::index_set(L); + } + + static inline int real_new_index_call(lua_State* L) { + return real_index_set_traits(container_detail::has_traits_index_set<uc>(), L); + } + + static inline int real_pairs_traits(std::true_type, lua_State* L) { + return uc::pairs(L); + } + + static inline int real_pairs_traits(std::false_type, lua_State* L) { + return default_uc::pairs(L); + } + + static inline int real_pairs_call(lua_State* L) { + return real_pairs_traits(container_detail::has_traits_pairs<uc>(), L); + } + + static inline int real_ipairs_traits(std::true_type, lua_State* L) { + return uc::ipairs(L); + } + + static inline int real_ipairs_traits(std::false_type, lua_State* L) { + return default_uc::ipairs(L); + } + + static inline int real_ipairs_call(lua_State* L) { + return real_ipairs_traits(container_detail::has_traits_ipairs<uc>(), L); + } + + static inline int real_next_traits(std::true_type, lua_State* L) { + return uc::next(L); + } + + static inline int real_next_traits(std::false_type, lua_State* L) { + return default_uc::next(L); + } + + static inline int real_next_call(lua_State* L) { + return real_next_traits(container_detail::has_traits_next<uc>(), L); + } + + static inline int real_size_traits(std::true_type, lua_State* L) { + return uc::size(L); + } + + static inline int real_size_traits(std::false_type, lua_State* L) { + return default_uc::size(L); + } + + static inline int real_length_call(lua_State* L) { + return real_size_traits(container_detail::has_traits_size<uc>(), L); + } + + static inline int real_add_traits(std::true_type, lua_State* L) { + return uc::add(L); + } + + static inline int real_add_traits(std::false_type, lua_State* L) { + return default_uc::add(L); + } + + static inline int real_add_call(lua_State* L) { + return real_add_traits(container_detail::has_traits_add<uc>(), L); + } + + static inline int real_insert_traits(std::true_type, lua_State* L) { + return uc::insert(L); + } + + static inline int real_insert_traits(std::false_type, lua_State* L) { + return default_uc::insert(L); + } + + static inline int real_insert_call(lua_State* L) { + return real_insert_traits(container_detail::has_traits_insert<uc>(), L); + } + + static inline int real_clear_traits(std::true_type, lua_State* L) { + return uc::clear(L); + } + + static inline int real_clear_traits(std::false_type, lua_State* L) { + return default_uc::clear(L); + } + + static inline int real_clear_call(lua_State* L) { + return real_clear_traits(container_detail::has_traits_clear<uc>(), L); + } + + static inline int real_empty_traits(std::true_type, lua_State* L) { + return uc::empty(L); + } + + static inline int real_empty_traits(std::false_type, lua_State* L) { + return default_uc::empty(L); + } + + static inline int real_empty_call(lua_State* L) { + return real_empty_traits(container_detail::has_traits_empty<uc>(), L); + } + + static inline int real_erase_traits(std::true_type, lua_State* L) { + return uc::erase(L); + } + + static inline int real_erase_traits(std::false_type, lua_State* L) { + return default_uc::erase(L); + } + + static inline int real_erase_call(lua_State* L) { + return real_erase_traits(container_detail::has_traits_erase<uc>(), L); + } + + static inline int real_find_traits(std::true_type, lua_State* L) { + return uc::find(L); + } + + static inline int real_find_traits(std::false_type, lua_State* L) { + return default_uc::find(L); + } + + static inline int real_find_call(lua_State* L) { + return real_find_traits(container_detail::has_traits_find<uc>(), L); + } + + static inline int real_index_of_call(lua_State* L) { + if constexpr (container_detail::has_traits_index_of<uc>()) { + return uc::index_of(L); + } + else { + return default_uc::index_of(L); + } + } + + static inline int add_call(lua_State* L) { + return detail::typed_static_trampoline<decltype(&real_add_call), (&real_add_call)>(L); + } + + static inline int erase_call(lua_State* L) { + return detail::typed_static_trampoline<decltype(&real_erase_call), (&real_erase_call)>(L); + } + + static inline int insert_call(lua_State* L) { + return detail::typed_static_trampoline<decltype(&real_insert_call), (&real_insert_call)>(L); + } + + static inline int clear_call(lua_State* L) { + return detail::typed_static_trampoline<decltype(&real_clear_call), (&real_clear_call)>(L); + } + + static inline int empty_call(lua_State* L) { + return detail::typed_static_trampoline<decltype(&real_empty_call), (&real_empty_call)>(L); + } + + static inline int find_call(lua_State* L) { + return detail::typed_static_trampoline<decltype(&real_find_call), (&real_find_call)>(L); + } + + static inline int index_of_call(lua_State* L) { + return detail::typed_static_trampoline<decltype(&real_index_of_call), (&real_index_of_call)>(L); + } + + static inline int length_call(lua_State* L) { + return detail::typed_static_trampoline<decltype(&real_length_call), (&real_length_call)>(L); + } + + static inline int pairs_call(lua_State* L) { + return detail::typed_static_trampoline<decltype(&real_pairs_call), (&real_pairs_call)>(L); + } + + static inline int ipairs_call(lua_State* L) { + return detail::typed_static_trampoline<decltype(&real_ipairs_call), (&real_ipairs_call)>(L); + } + + static inline int next_call(lua_State* L) { + return detail::typed_static_trampoline<decltype(&real_next_call), (&real_next_call)>(L); + } + + static inline int at_call(lua_State* L) { + return detail::typed_static_trampoline<decltype(&real_at_call), (&real_at_call)>(L); + } + + static inline int get_call(lua_State* L) { + return detail::typed_static_trampoline<decltype(&real_get_call), (&real_get_call)>(L); + } + + static inline int set_call(lua_State* L) { + return detail::typed_static_trampoline<decltype(&real_set_call), (&real_set_call)>(L); + } + + static inline int index_call(lua_State* L) { + return detail::typed_static_trampoline<decltype(&real_index_call), (&real_index_call)>(L); + } + + static inline int new_index_call(lua_State* L) { + return detail::typed_static_trampoline<decltype(&real_new_index_call), (&real_new_index_call)>(L); + } + }; + } // namespace container_detail + + namespace stack { + namespace stack_detail { + template <typename T, bool is_shim = false> + struct metatable_setup { + lua_State* L; + + metatable_setup(lua_State* L) : L(L) { + } + + void operator()() { + using meta_usertype_container + = container_detail::u_c_launch<meta::conditional_t<is_shim, as_container_t<std::remove_pointer_t<T>>, std::remove_pointer_t<T>>>; + static const char* metakey + = is_shim ? &usertype_traits<as_container_t<std::remove_pointer_t<T>>>::metatable()[0] : &usertype_traits<T>::metatable()[0]; + static const std::array<luaL_Reg, 20> reg = { { + // clang-format off + { "__pairs", &meta_usertype_container::pairs_call }, + { "__ipairs", &meta_usertype_container::ipairs_call }, + { "__len", &meta_usertype_container::length_call }, + { "__index", &meta_usertype_container::index_call }, + { "__newindex", &meta_usertype_container::new_index_call }, + { "pairs", &meta_usertype_container::pairs_call }, + { "next", &meta_usertype_container::next_call }, + { "at", &meta_usertype_container::at_call }, + { "get", &meta_usertype_container::get_call }, + { "set", &meta_usertype_container::set_call }, + { "size", &meta_usertype_container::length_call }, + { "empty", &meta_usertype_container::empty_call }, + { "clear", &meta_usertype_container::clear_call }, + { "insert", &meta_usertype_container::insert_call }, + { "add", &meta_usertype_container::add_call }, + { "find", &meta_usertype_container::find_call }, + { "index_of", &meta_usertype_container::index_of_call }, + { "erase", &meta_usertype_container::erase_call }, + std::is_pointer<T>::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destroy<T> }, + { nullptr, nullptr } + // clang-format on + } }; + + if (luaL_newmetatable(L, metakey) == 1) { + luaL_setfuncs(L, reg.data(), 0); + } + lua_setmetatable(L, -2); + } + }; + } // namespace stack_detail + + template <typename T> + struct unqualified_pusher<as_container_t<T>> { + using C = meta::unqualified_t<T>; + + static int push_lvalue(std::true_type, lua_State* L, const C& cont) { + stack_detail::metatable_setup<C*, true> fx(L); + return stack::push<detail::as_pointer_tag<const C>>(L, detail::with_function_tag(), fx, detail::ptr(cont)); + } + + static int push_lvalue(std::false_type, lua_State* L, const C& cont) { + stack_detail::metatable_setup<C, true> fx(L); + return stack::push<detail::as_value_tag<C>>(L, detail::with_function_tag(), fx, cont); + } + + static int push_rvalue(std::true_type, lua_State* L, C&& cont) { + stack_detail::metatable_setup<C, true> fx(L); + return stack::push<detail::as_value_tag<C>>(L, detail::with_function_tag(), fx, std::move(cont)); + } + + static int push_rvalue(std::false_type, lua_State* L, const C& cont) { + return push_lvalue(std::is_lvalue_reference<T>(), L, cont); + } + + static int push(lua_State* L, const as_container_t<T>& as_cont) { + return push_lvalue(std::is_lvalue_reference<T>(), L, as_cont.value()); + } + + static int push(lua_State* L, as_container_t<T>&& as_cont) { + return push_rvalue(meta::all<std::is_rvalue_reference<T>, meta::neg<std::is_lvalue_reference<T>>>(), L, std::forward<T>(as_cont.value())); + } + }; + + template <typename T> + struct unqualified_pusher<as_container_t<T*>> { + using C = std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>>; + + static int push(lua_State* L, T* cont) { + stack_detail::metatable_setup<C> fx(L); + return stack::push<detail::as_pointer_tag<T>>(L, detail::with_function_tag(), fx, cont); + } + }; + + template <typename T> + struct unqualified_pusher<T, std::enable_if_t<is_container_v<T>>> { + using C = T; + + template <typename... Args> + static int push(lua_State* L, Args&&... args) { + stack_detail::metatable_setup<C> fx(L); + return stack::push<detail::as_value_tag<T>>(L, detail::with_function_tag(), fx, std::forward<Args>(args)...); + } + }; + + template <typename T> + struct unqualified_pusher<T*, std::enable_if_t<is_container_v<T>>> { + using C = std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>>; + + static int push(lua_State* L, T* cont) { + stack_detail::metatable_setup<C> fx(L); + return stack::push<detail::as_pointer_tag<T>>(L, detail::with_function_tag(), fx, cont); + } + }; + } // namespace stack + +} // namespace sol + +// end of sol/usertype_container_launch.hpp + +#include <sstream> +#include <type_traits> + +namespace sol { + namespace u_detail { + constexpr const lua_Integer toplevel_magic = static_cast<lua_Integer>(0xCCC2CCC1); + + constexpr const int environment_index = 1; + constexpr const int usertype_storage_index = 2; + constexpr const int usertype_storage_base_index = 3; + constexpr const int exact_function_index = 4; + constexpr const int magic_index = 5; + + constexpr const int simple_usertype_storage_index = 2; + constexpr const int index_function_index = 3; + constexpr const int new_index_function_index = 4; + + constexpr const int base_walking_failed_index = -32467; + constexpr const int lookup_failed_index = -42469; + + enum class submetatable_type { + // must be sequential + value, + reference, + unique, + const_reference, + const_value, + // must be LAST! + named + }; + + inline auto make_string_view(string_view s) { + return s; + } + +#if SOL_IS_ON(SOL_CHAR8_T) + inline auto make_string_view(const char8_t* s) { + return string_view(reinterpret_cast<const char*>(s)); + } +#endif + + inline auto make_string_view(call_construction) { + return string_view(to_string(meta_function::call_function)); + } + + inline auto make_string_view(meta_function mf) { + return string_view(to_string(mf)); + } + + inline auto make_string_view(base_classes_tag) { + return string_view(detail::base_class_cast_key()); + } + + template <typename Arg> + inline std::string make_string(Arg&& arg) { + string_view s = make_string_view(arg); + return std::string(s.data(), s.size()); + } + + inline int is_indexer(string_view s) { + if (s == to_string(meta_function::index)) { + return 1; + } + else if (s == to_string(meta_function::new_index)) { + return 2; + } + return 0; + } + + inline int is_indexer(meta_function mf) { + if (mf == meta_function::index) { + return 1; + } + else if (mf == meta_function::new_index) { + return 2; + } + return 0; + } + + inline int is_indexer(call_construction) { + return 0; + } + } // namespace u_detail + + namespace detail { + + template <typename T, typename IFx, typename Fx> + inline void insert_default_registrations(IFx&& ifx, Fx&& fx) { + (void)ifx; + (void)fx; + if constexpr (is_automagical<T>::value) { + if (fx(meta_function::less_than)) { + if constexpr (meta::supports_op_less<T>::value) { + lua_CFunction f = &comparsion_operator_wrap<T, std::less<>>; + ifx(meta_function::less_than, f); + } + } + if (fx(meta_function::less_than_or_equal_to)) { + if constexpr (meta::supports_op_less_equal<T>::value) { + lua_CFunction f = &comparsion_operator_wrap<T, std::less_equal<>>; + ifx(meta_function::less_than_or_equal_to, f); + } + } + if (fx(meta_function::equal_to)) { + if constexpr (meta::supports_op_equal<T>::value) { + lua_CFunction f = &comparsion_operator_wrap<T, std::equal_to<>>; + ifx(meta_function::equal_to, f); + } + else { + lua_CFunction f = &comparsion_operator_wrap<T, no_comp>; + ifx(meta_function::equal_to, f); + } + } + if (fx(meta_function::pairs)) { + ifx(meta_function::pairs, &container_detail::u_c_launch<as_container_t<T>>::pairs_call); + } + if (fx(meta_function::length)) { + if constexpr (meta::has_size<const T>::value || meta::has_size<T>::value) { + auto f = &default_size<T>; + ifx(meta_function::length, f); + } + } + if (fx(meta_function::to_string)) { + if constexpr (is_to_stringable_v<T>) { + if constexpr (!meta::is_probably_stateless_lambda_v<T> && !std::is_member_pointer_v<T>) { + auto f = &detail::static_trampoline<&default_to_string<T>>; + ifx(meta_function::to_string, f); + } + } + } + if (fx(meta_function::call_function)) { + if constexpr (is_callable_v<T>) { + if constexpr (meta::call_operator_deducible_v<T>) { + auto f = &c_call<decltype(&T::operator()), &T::operator()>; + ifx(meta_function::call_function, f); + } + } + } + } + } + } // namespace detail + + namespace stack { namespace stack_detail { + template <typename X> + void set_undefined_methods_on(stack_reference t) { + using T = std::remove_pointer_t<X>; + + lua_State* L = t.lua_state(); + + t.push(); + + detail::lua_reg_table l {}; + int index = 0; + detail::indexed_insert insert_fx(l, index); + detail::insert_default_registrations<T>(insert_fx, detail::property_always_true); + if constexpr (!std::is_pointer_v<X>) { + l[index] = luaL_Reg { to_string(meta_function::garbage_collect).c_str(), detail::make_destructor<T>() }; + } + luaL_setfuncs(L, l, 0); + + // __type table + lua_createtable(L, 0, 2); + const std::string& name = detail::demangle<T>(); + lua_pushlstring(L, name.c_str(), name.size()); + lua_setfield(L, -2, "name"); + lua_CFunction is_func = &detail::is_check<T>; + lua_pushcclosure(L, is_func, 0); + lua_setfield(L, -2, "is"); + lua_setfield(L, t.stack_index(), to_string(meta_function::type).c_str()); + + t.pop(); + } + }} // namespace stack::stack_detail +} // namespace sol + +// end of sol/usertype_core.hpp + +// beginning of sol/usertype_storage.hpp + +#include <bitset> +#include <unordered_map> +#include <memory> + +namespace sol { namespace u_detail { + + struct usertype_storage_base; + template <typename T> + struct usertype_storage; + + optional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L_, int index); + usertype_storage_base& get_usertype_storage_base(lua_State* L_, const char* gcmetakey); + template <typename T> + optional<usertype_storage<T>&> maybe_get_usertype_storage(lua_State* L_); + template <typename T> + usertype_storage<T>& get_usertype_storage(lua_State* L_); + + using index_call_function = int(lua_State*, void*); + using change_indexing_mem_func = void (usertype_storage_base::*)( + lua_State*, submetatable_type, void*, stateless_stack_reference&, lua_CFunction, lua_CFunction, lua_CFunction, lua_CFunction); + + struct index_call_storage { + index_call_function* index; + index_call_function* new_index; + void* binding_data; + }; + + struct new_index_call_storage : index_call_storage { + void* new_binding_data; + }; + + struct binding_base { + virtual void* data() = 0; + virtual ~binding_base() { + } + }; + + template <typename K, typename Fq, typename T = void> + struct binding : binding_base { + using uF = meta::unqualified_t<Fq>; + using F = meta::conditional_t<meta::is_c_str_of_v<uF, char> +#if SOL_IS_ON(SOL_CHAR8_T) + || meta::is_c_str_of_v<uF, char8_t> +#endif + || meta::is_c_str_of_v<uF, char16_t> || meta::is_c_str_of_v<uF, char32_t> || meta::is_c_str_of_v<uF, wchar_t>, + std::add_pointer_t<std::add_const_t<std::remove_all_extents_t<Fq>>>, std::decay_t<Fq>>; + F data_; + + template <typename... Args> + binding(Args&&... args) : data_(std::forward<Args>(args)...) { + } + + virtual void* data() override { + return static_cast<void*>(std::addressof(data_)); + } + + template <bool is_index = true, bool is_variable = false> + static inline int call_with_(lua_State* L_, void* target) { + constexpr int boost = !detail::is_non_factory_constructor<F>::value && std::is_same<K, call_construction>::value ? 1 : 0; + auto& f = *static_cast<F*>(target); + return call_detail::call_wrapped<T, is_index, is_variable, boost>(L_, f); + } + + template <bool is_index = true, bool is_variable = false> + static inline int call_(lua_State* L_) { + void* f = stack::get<void*>(L_, upvalue_index(usertype_storage_index)); + return call_with_<is_index, is_variable>(L_, f); + } + + template <bool is_index = true, bool is_variable = false> + static inline int call(lua_State* L_) { + int r = detail::typed_static_trampoline<decltype(&call_<is_index, is_variable>), (&call_<is_index, is_variable>)>(L_); + if constexpr (meta::is_specialization_of_v<uF, yielding_t>) { + return lua_yield(L_, r); + } + else { + return r; + } + } + + template <bool is_index = true, bool is_variable = false> + static inline int index_call_with_(lua_State* L_, void* target) { + if constexpr (!is_variable) { + if constexpr (is_lua_c_function_v<std::decay_t<F>>) { + auto& f = *static_cast<std::decay_t<F>*>(target); + return stack::push(L_, f); + } + else { + // set up upvalues + // for a chained call + int upvalues = 0; + upvalues += stack::push(L_, nullptr); + upvalues += stack::push(L_, target); + auto cfunc = &call<is_index, is_variable>; + return stack::push(L_, c_closure(cfunc, upvalues)); + } + } + else { + constexpr int boost = !detail::is_non_factory_constructor<F>::value && std::is_same<K, call_construction>::value ? 1 : 0; + auto& f = *static_cast<F*>(target); + return call_detail::call_wrapped<T, is_index, is_variable, boost>(L_, f); + } + } + + template <bool is_index = true, bool is_variable = false> + static inline int index_call_(lua_State* L_) { + void* f = stack::get<void*>(L_, upvalue_index(usertype_storage_index)); + return index_call_with_<is_index, is_variable>(L_, f); + } + + template <bool is_index = true, bool is_variable = false> + static inline int index_call(lua_State* L_) { + int r = detail::typed_static_trampoline<decltype(&index_call_<is_index, is_variable>), (&index_call_<is_index, is_variable>)>(L_); + if constexpr (meta::is_specialization_of_v<uF, yielding_t>) { + return lua_yield(L_, r); + } + else { + return r; + } + } + }; + + inline int index_fail(lua_State* L_) { + if (lua_getmetatable(L_, 1) == 1) { + int metatarget = lua_gettop(L_); + stack::get_field<false, true>(L_, stack_reference(L_, raw_index(2)), metatarget); + return 1; + } + // With runtime extensibility, we can't + // hard-error things. They have to + // return nil, like regular table types + return stack::push(L_, lua_nil); + } + + inline int index_target_fail(lua_State* L_, void*) { + return index_fail(L_); + } + + inline int new_index_fail(lua_State* L_) { + return luaL_error(L_, "sol: cannot set (new_index) into this object: no defined new_index operation on usertype"); + } + + inline int new_index_target_fail(lua_State* L_, void*) { + return new_index_fail(L_); + } + + struct string_for_each_metatable_func { + bool is_destruction = false; + bool is_index = false; + bool is_new_index = false; + bool is_static_index = false; + bool is_static_new_index = false; + bool poison_indexing = false; + bool is_unqualified_lua_CFunction = false; + bool is_unqualified_lua_reference = false; + std::string* p_key = nullptr; + reference* p_binding_ref = nullptr; + lua_CFunction call_func = nullptr; + index_call_storage* p_ics = nullptr; + usertype_storage_base* p_usb = nullptr; + void* p_derived_usb = nullptr; + lua_CFunction idx_call = nullptr, new_idx_call = nullptr, meta_idx_call = nullptr, meta_new_idx_call = nullptr; + change_indexing_mem_func change_indexing; + + void operator()(lua_State* L_, submetatable_type smt_, stateless_reference& fast_index_table_) { + std::string& key = *p_key; + usertype_storage_base& usb = *p_usb; + index_call_storage& ics = *p_ics; + + if (smt_ == submetatable_type::named) { + // do not override __call or + // other specific meta functions on named metatable: + // we need that for call construction + // and other amenities + return; + } + int fast_index_table_push = fast_index_table_.push(L_); + stateless_stack_reference t(L_, -fast_index_table_push); + if (poison_indexing) { + (usb.*change_indexing)(L_, smt_, p_derived_usb, t, idx_call, new_idx_call, meta_idx_call, meta_new_idx_call); + } + if (is_destruction + && (smt_ == submetatable_type::reference || smt_ == submetatable_type::const_reference || smt_ == submetatable_type::named + || smt_ == submetatable_type::unique)) { + // gc does not apply to us here + // for reference types (raw T*, std::ref) + // for the named metatable itself, + // or for unique_usertypes, which do their own custom destroyion + t.pop(L_); + return; + } + if (is_index || is_new_index || is_static_index || is_static_new_index) { + // do not serialize the new_index and index functions here directly + // we control those... + t.pop(L_); + return; + } + if (is_unqualified_lua_CFunction) { + stack::set_field<false, true>(L_, key, call_func, t.stack_index()); + } + else if (is_unqualified_lua_reference) { + reference& binding_ref = *p_binding_ref; + stack::set_field<false, true>(L_, key, binding_ref, t.stack_index()); + } + else { + stack::set_field<false, true>(L_, key, make_closure(call_func, nullptr, ics.binding_data), t.stack_index()); + } + t.pop(L_); + } + }; + + struct lua_reference_func { + reference key; + reference value; + + void operator()(lua_State* L_, submetatable_type smt_, stateless_reference& fast_index_table_) { + if (smt_ == submetatable_type::named) { + return; + } + int fast_index_table_push = fast_index_table_.push(L_); + stateless_stack_reference t(L_, -fast_index_table_push); + stack::set_field<false, true>(L_, key, value, t.stack_index()); + t.pop(L_); + } + }; + + struct update_bases_func { + detail::inheritance_check_function base_class_check_func; + detail::inheritance_cast_function base_class_cast_func; + lua_CFunction idx_call, new_idx_call, meta_idx_call, meta_new_idx_call; + usertype_storage_base* p_usb; + void* p_derived_usb; + change_indexing_mem_func change_indexing; + + void operator()(lua_State* L_, submetatable_type smt_, stateless_reference& fast_index_table_) { + int fast_index_table_push = fast_index_table_.push(L_); + stateless_stack_reference t(L_, -fast_index_table_push); + stack::set_field(L_, detail::base_class_check_key(), reinterpret_cast<void*>(base_class_check_func), t.stack_index()); + stack::set_field(L_, detail::base_class_cast_key(), reinterpret_cast<void*>(base_class_cast_func), t.stack_index()); + // change indexing, forcefully + (p_usb->*change_indexing)(L_, smt_, p_derived_usb, t, idx_call, new_idx_call, meta_idx_call, meta_new_idx_call); + t.pop(L_); + } + }; + + struct binding_data_equals { + void* binding_data; + + binding_data_equals(void* b) : binding_data(b) { + } + + bool operator()(const std::unique_ptr<binding_base>& ptr) const { + return binding_data == ptr->data(); + } + }; + + struct usertype_storage_base { + public: + lua_State* m_L; + std::vector<std::unique_ptr<binding_base>> storage; + std::vector<std::unique_ptr<char[]>> string_keys_storage; + std::unordered_map<string_view, index_call_storage> string_keys; + std::unordered_map<stateless_reference, stateless_reference, stateless_reference_hash, stateless_reference_equals> auxiliary_keys; + stateless_reference value_index_table; + stateless_reference reference_index_table; + stateless_reference unique_index_table; + stateless_reference const_reference_index_table; + stateless_reference const_value_index_table; + stateless_reference named_index_table; + stateless_reference type_table; + stateless_reference gc_names_table; + stateless_reference named_metatable; + new_index_call_storage base_index; + new_index_call_storage static_base_index; + bool is_using_index; + bool is_using_new_index; + std::bitset<64> properties; + + usertype_storage_base(lua_State* L_) + : m_L(L_) + , storage() + , string_keys_storage() + , string_keys() + , auxiliary_keys(0, stateless_reference_hash(L_), stateless_reference_equals(L_)) + , value_index_table() + , reference_index_table() + , unique_index_table() + , const_reference_index_table() + , const_value_index_table() + , named_index_table() + , type_table(make_reference<stateless_reference>(L_, create)) + , gc_names_table(make_reference<stateless_reference>(L_, create)) + , named_metatable(make_reference<stateless_reference>(L_, create)) + , base_index() + , static_base_index() + , is_using_index(false) + , is_using_new_index(false) + , properties() { + base_index.binding_data = nullptr; + base_index.index = index_target_fail; + base_index.new_index = new_index_target_fail; + base_index.new_binding_data = nullptr; + static_base_index.binding_data = nullptr; + static_base_index.index = index_target_fail; + static_base_index.new_binding_data = this; + static_base_index.new_index = new_index_target_set; + } + + template <typename Fx> + void for_each_table(lua_State* L_, Fx&& fx) { + for (int i = 0; i < 6; ++i) { + submetatable_type smt = static_cast<submetatable_type>(i); + stateless_reference* p_fast_index_table = nullptr; + switch (smt) { + case submetatable_type::const_value: + p_fast_index_table = &this->const_value_index_table; + break; + case submetatable_type::reference: + p_fast_index_table = &this->reference_index_table; + break; + case submetatable_type::unique: + p_fast_index_table = &this->unique_index_table; + break; + case submetatable_type::const_reference: + p_fast_index_table = &this->const_reference_index_table; + break; + case submetatable_type::named: + p_fast_index_table = &this->named_index_table; + break; + case submetatable_type::value: + default: + p_fast_index_table = &this->value_index_table; + break; + } + fx(L_, smt, *p_fast_index_table); + } + } + + void add_entry(string_view sv, index_call_storage ics) { + string_keys_storage.emplace_back(new char[sv.size()]); + std::unique_ptr<char[]>& sv_storage = string_keys_storage.back(); + std::memcpy(sv_storage.get(), sv.data(), sv.size()); + string_view stored_sv(sv_storage.get(), sv.size()); + string_keys.insert_or_assign(std::move(stored_sv), std::move(ics)); + } + + template <typename T, typename... Bases> + void update_bases(lua_State* L_, bases<Bases...>) { + static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), + "The size of this data pointer is too small to fit the inheritance checking function: Please file " + "a bug report."); + static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), + "The size of this data pointer is too small to fit the inheritance checking function: Please file " + "a bug report."); + static_assert(!meta::any_same<T, Bases...>::value, "base classes cannot list the original class as part of the bases"); + if constexpr (sizeof...(Bases) > 0) { + (void)detail::swallow { 0, ((weak_derive<Bases>::value = true), 0)... }; + + void* derived_this = static_cast<void*>(static_cast<usertype_storage<T>*>(this)); + + update_bases_func for_each_fx; + for_each_fx.base_class_check_func = &detail::inheritance<T>::template type_check_with<Bases...>; + for_each_fx.base_class_cast_func = &detail::inheritance<T>::template type_cast_with<Bases...>; + for_each_fx.idx_call = &usertype_storage<T>::template index_call_with_bases<false, Bases...>; + for_each_fx.new_idx_call = &usertype_storage<T>::template index_call_with_bases<true, Bases...>; + for_each_fx.meta_idx_call = &usertype_storage<T>::template meta_index_call_with_bases<false, Bases...>; + for_each_fx.meta_new_idx_call = &usertype_storage<T>::template meta_index_call_with_bases<true, Bases...>; + for_each_fx.p_usb = this; + for_each_fx.p_derived_usb = derived_this; + for_each_fx.change_indexing = &usertype_storage_base::change_indexing; + for_each_fx.p_derived_usb = derived_this; + this->for_each_table(L_, for_each_fx); + } + else { + (void)L_; + } + } + + void clear() { + if (value_index_table.valid(m_L)) { + stack::clear(m_L, value_index_table); + } + if (reference_index_table.valid(m_L)) { + stack::clear(m_L, reference_index_table); + } + if (unique_index_table.valid(m_L)) { + stack::clear(m_L, unique_index_table); + } + if (const_reference_index_table.valid(m_L)) { + stack::clear(m_L, const_reference_index_table); + } + if (const_value_index_table.valid(m_L)) { + stack::clear(m_L, const_value_index_table); + } + if (named_index_table.valid(m_L)) { + stack::clear(m_L, named_index_table); + } + if (type_table.valid(m_L)) { + stack::clear(m_L, type_table); + } + if (gc_names_table.valid(m_L)) { + stack::clear(m_L, gc_names_table); + } + if (named_metatable.valid(m_L)) { + auto pp = stack::push_pop(m_L, named_metatable); + int named_metatable_index = pp.index_of(named_metatable); + if (lua_getmetatable(m_L, named_metatable_index) == 1) { + stack::clear(m_L, absolute_index(m_L, -1)); + } + stack::clear(m_L, named_metatable); + } + + value_index_table.reset(m_L); + reference_index_table.reset(m_L); + unique_index_table.reset(m_L); + const_reference_index_table.reset(m_L); + const_value_index_table.reset(m_L); + named_index_table.reset(m_L); + type_table.reset(m_L); + gc_names_table.reset(m_L); + named_metatable.reset(m_L); + + storage.clear(); + string_keys.clear(); + auxiliary_keys.clear(); + string_keys_storage.clear(); + } + + template <bool is_new_index, typename Base> + static void base_walk_index(lua_State* L_, usertype_storage_base& self, bool& keep_going, int& base_result) { + using bases = typename base<Base>::type; + if (!keep_going) { + return; + } + (void)L_; + (void)self; +#if SOL_IS_ON(SOL_USE_UNSAFE_BASE_LOOKUP) + usertype_storage_base& base_storage = get_usertype_storage<Base>(L_); + base_result = self_index_call<is_new_index, true>(bases(), L_, base_storage); +#else + optional<usertype_storage<Base>&> maybe_base_storage = maybe_get_usertype_storage<Base>(L_); + if (static_cast<bool>(maybe_base_storage)) { + base_result = self_index_call<is_new_index, true>(bases(), L_, *maybe_base_storage); + keep_going = base_result == base_walking_failed_index; + } +#endif // Fast versus slow, safe base lookup + } + + template <bool is_new_index = false, bool base_walking = false, bool from_named_metatable = false, typename... Bases> + static inline int self_index_call(types<Bases...>, lua_State* L, usertype_storage_base& self) { + if constexpr (!from_named_metatable || !is_new_index) { + type k_type = stack::get<type>(L, 2); + if (k_type == type::string) { + index_call_storage* target = nullptr; + string_view k = stack::get<string_view>(L, 2); + { + auto it = self.string_keys.find(k); + if (it != self.string_keys.cend()) { + target = &it->second; + } + } + if (target != nullptr) { + // let the target decide what to do, unless it's named... + if constexpr (is_new_index) { + return (target->new_index)(L, target->binding_data); + } + else { + return (target->index)(L, target->binding_data); + } + } + } + else if (k_type != type::lua_nil && k_type != type::none) { + stateless_reference* target = nullptr; + { + stack_reference k = stack::get<stack_reference>(L, 2); + auto it = self.auxiliary_keys.find(k); + if (it != self.auxiliary_keys.cend()) { + target = &it->second; + } + } + if (target != nullptr) { + if constexpr (is_new_index) { + // set value and return + target->reset(L, 3); + return 0; + } + else { + // push target to return + // what we found + return stack::push(L, *target); + } + } + } + } + + // retrieve bases and walk through them. + bool keep_going = true; + int base_result; + (void)keep_going; + (void)base_result; + (void)detail::swallow { 1, (base_walk_index<is_new_index, Bases>(L, self, keep_going, base_result), 1)... }; + if constexpr (sizeof...(Bases) > 0) { + if (!keep_going) { + return base_result; + } + } + if constexpr (base_walking) { + // if we're JUST base-walking then don't index-fail, just + // return the false bits + return base_walking_failed_index; + } + else if constexpr (from_named_metatable) { + if constexpr (is_new_index) { + return self.static_base_index.new_index(L, self.static_base_index.new_binding_data); + } + else { + return self.static_base_index.index(L, self.static_base_index.binding_data); + } + } + else { + if constexpr (is_new_index) { + return self.base_index.new_index(L, self.base_index.new_binding_data); + } + else { + return self.base_index.index(L, self.base_index.binding_data); + } + } + } + + void change_indexing(lua_State* L_, submetatable_type submetatable_, void* derived_this_, stateless_stack_reference& t_, lua_CFunction index_, + lua_CFunction new_index_, lua_CFunction meta_index_, lua_CFunction meta_new_index_) { + usertype_storage_base& this_base = *this; + void* base_this = static_cast<void*>(&this_base); + + this->is_using_index |= true; + this->is_using_new_index |= true; + if (submetatable_ == submetatable_type::named) { + stack::set_field(L_, metatable_key, named_index_table, t_.stack_index()); + stateless_stack_reference stack_metametatable(L_, -named_metatable.push(L_)); + stack::set_field<false, true>(L_, + meta_function::index, + make_closure(meta_index_, nullptr, derived_this_, base_this, nullptr, toplevel_magic), + stack_metametatable.stack_index()); + stack::set_field<false, true>(L_, + meta_function::new_index, + make_closure(meta_new_index_, nullptr, derived_this_, base_this, nullptr, toplevel_magic), + stack_metametatable.stack_index()); + stack_metametatable.pop(L_); + } + else { + stack::set_field<false, true>( + L_, meta_function::index, make_closure(index_, nullptr, derived_this_, base_this, nullptr, toplevel_magic), t_.stack_index()); + stack::set_field<false, true>( + L_, meta_function::new_index, make_closure(new_index_, nullptr, derived_this_, base_this, nullptr, toplevel_magic), t_.stack_index()); + } + } + + template <typename T = void, typename Key, typename Value> + void set(lua_State* L, Key&& key, Value&& value); + + static int new_index_target_set(lua_State* L, void* target) { + usertype_storage_base& self = *static_cast<usertype_storage_base*>(target); + self.set(L, reference(L, raw_index(2)), reference(L, raw_index(3))); + return 0; + } + + ~usertype_storage_base() { + value_index_table.reset(m_L); + reference_index_table.reset(m_L); + unique_index_table.reset(m_L); + const_reference_index_table.reset(m_L); + const_value_index_table.reset(m_L); + named_index_table.reset(m_L); + type_table.reset(m_L); + gc_names_table.reset(m_L); + named_metatable.reset(m_L); + + auto auxiliary_first = auxiliary_keys.cbegin(); + auto auxiliary_last = auxiliary_keys.cend(); + while (auxiliary_first != auxiliary_last) { + // save a copy to what we're going to destroy + auto auxiliary_target = auxiliary_first; + // move the iterator up by 1 + ++auxiliary_first; + // extract the node and destroy the key + auto extracted_node = auxiliary_keys.extract(auxiliary_target); + extracted_node.key().reset(m_L); + extracted_node.mapped().reset(m_L); + // continue if auxiliary_first hasn't been exhausted + } + } + }; + + template <typename T> + struct usertype_storage : usertype_storage_base { + + using usertype_storage_base::usertype_storage_base; + + template <bool is_new_index, bool from_named_metatable> + static inline int index_call_(lua_State* L) { + using bases = typename base<T>::type; + usertype_storage_base& self = stack::get<light<usertype_storage_base>>(L, upvalue_index(usertype_storage_index)); + return self_index_call<is_new_index, false, from_named_metatable>(bases(), L, self); + } + + template <bool is_new_index, bool from_named_metatable, typename... Bases> + static inline int index_call_with_bases_(lua_State* L) { + using bases = types<Bases...>; + usertype_storage_base& self = stack::get<light<usertype_storage_base>>(L, upvalue_index(usertype_storage_index)); + return self_index_call<is_new_index, false, from_named_metatable>(bases(), L, self); + } + + template <bool is_new_index> + static inline int index_call(lua_State* L) { + return detail::static_trampoline<&index_call_<is_new_index, false>>(L); + } + + template <bool is_new_index, typename... Bases> + static inline int index_call_with_bases(lua_State* L) { + return detail::static_trampoline<&index_call_with_bases_<is_new_index, false, Bases...>>(L); + } + + template <bool is_new_index> + static inline int meta_index_call(lua_State* L) { + return detail::static_trampoline<&index_call_<is_new_index, true>>(L); + } + + template <bool is_new_index, typename... Bases> + static inline int meta_index_call_with_bases(lua_State* L) { + return detail::static_trampoline<&index_call_with_bases_<is_new_index, true, Bases...>>(L); + } + + template <typename Key, typename Value> + inline void set(lua_State* L, Key&& key, Value&& value); + }; + + template <typename T, typename Key, typename Value> + void usertype_storage_base::set(lua_State* L, Key&& key, Value&& value) { + using ValueU = meta::unwrap_unqualified_t<Value>; + using KeyU = meta::unwrap_unqualified_t<Key>; + using Binding = binding<KeyU, ValueU, T>; + using is_var_bind = is_variable_binding<ValueU>; + if constexpr (std::is_same_v<KeyU, call_construction>) { + (void)key; + std::unique_ptr<Binding> p_binding = std::make_unique<Binding>(std::forward<Value>(value)); + Binding& b = *p_binding; + this->storage.push_back(std::move(p_binding)); + + this->named_index_table.push(L); + absolute_index metametatable_index(L, -1); + std::string_view call_metamethod_name = to_string(meta_function::call); + lua_pushlstring(L, call_metamethod_name.data(), call_metamethod_name.size()); + stack::push(L, nullptr); + stack::push(L, b.data()); + lua_CFunction target_func = &b.template call<false, false>; + lua_pushcclosure(L, target_func, 2); + lua_rawset(L, metametatable_index); + this->named_index_table.pop(L); + } + else if constexpr (std::is_same_v<KeyU, base_classes_tag>) { + (void)key; + this->update_bases<T>(L, std::forward<Value>(value)); + } + else if constexpr ((meta::is_string_like_or_constructible<KeyU>::value || std::is_same_v<KeyU, meta_function>)) { + std::string s = u_detail::make_string(std::forward<Key>(key)); + auto storage_it = this->storage.end(); + auto string_it = this->string_keys.find(s); + if (string_it != this->string_keys.cend()) { + const auto& binding_data = string_it->second.binding_data; + storage_it = std::find_if(this->storage.begin(), this->storage.end(), binding_data_equals(binding_data)); + this->string_keys.erase(string_it); + } + + std::unique_ptr<Binding> p_binding = std::make_unique<Binding>(std::forward<Value>(value)); + Binding& b = *p_binding; + if (storage_it != this->storage.cend()) { + *storage_it = std::move(p_binding); + } + else { + this->storage.push_back(std::move(p_binding)); + } + + bool is_index = (s == to_string(meta_function::index)); + bool is_new_index = (s == to_string(meta_function::new_index)); + bool is_static_index = (s == to_string(meta_function::static_index)); + bool is_static_new_index = (s == to_string(meta_function::static_new_index)); + bool is_destruction = s == to_string(meta_function::garbage_collect); + bool poison_indexing = (!is_using_index || !is_using_new_index) && (is_var_bind::value || is_index || is_new_index); + void* derived_this = static_cast<void*>(static_cast<usertype_storage<T>*>(this)); + index_call_storage ics; + ics.binding_data = b.data(); + ics.index = is_index || is_static_index ? &Binding::template call_with_<true, is_var_bind::value> + : &Binding::template index_call_with_<true, is_var_bind::value>; + ics.new_index = is_new_index || is_static_new_index ? &Binding::template call_with_<false, is_var_bind::value> + : &Binding::template index_call_with_<false, is_var_bind::value>; + + string_for_each_metatable_func for_each_fx; + for_each_fx.is_destruction = is_destruction; + for_each_fx.is_index = is_index; + for_each_fx.is_new_index = is_new_index; + for_each_fx.is_static_index = is_static_index; + for_each_fx.is_static_new_index = is_static_new_index; + for_each_fx.poison_indexing = poison_indexing; + for_each_fx.p_key = &s; + for_each_fx.p_ics = &ics; + if constexpr (is_lua_c_function_v<ValueU>) { + for_each_fx.is_unqualified_lua_CFunction = true; + for_each_fx.call_func = *static_cast<lua_CFunction*>(ics.binding_data); + } + else if constexpr (is_lua_reference_or_proxy_v<ValueU>) { + for_each_fx.is_unqualified_lua_reference = true; + for_each_fx.p_binding_ref = static_cast<reference*>(ics.binding_data); + } + else { + for_each_fx.call_func = &b.template call<false, is_var_bind::value>; + } + for_each_fx.p_usb = this; + for_each_fx.p_derived_usb = derived_this; + for_each_fx.idx_call = &usertype_storage<T>::template index_call<false>; + for_each_fx.new_idx_call = &usertype_storage<T>::template index_call<true>; + for_each_fx.meta_idx_call = &usertype_storage<T>::template meta_index_call<false>; + for_each_fx.meta_new_idx_call = &usertype_storage<T>::template meta_index_call<true>; + for_each_fx.change_indexing = &usertype_storage_base::change_indexing; + // set base index and base new_index + // functions here + if (is_index) { + this->base_index.index = ics.index; + this->base_index.binding_data = ics.binding_data; + } + if (is_new_index) { + this->base_index.new_index = ics.new_index; + this->base_index.new_binding_data = ics.binding_data; + } + if (is_static_index) { + this->static_base_index.index = ics.index; + this->static_base_index.binding_data = ics.binding_data; + } + if (is_static_new_index) { + this->static_base_index.new_index = ics.new_index; + this->static_base_index.new_binding_data = ics.binding_data; + } + this->for_each_table(L, for_each_fx); + this->add_entry(s, std::move(ics)); + } + else { + // the reference-based implementation might compare poorly and hash + // poorly in some cases... + if constexpr (is_lua_reference_v<KeyU> && is_lua_reference_v<ValueU>) { + if (key.get_type() == type::string) { + stack::push(L, key); + std::string string_key = stack::pop<std::string>(L); + this->set<T>(L, string_key, std::forward<Value>(value)); + } + else { + lua_reference_func ref_additions_fx { key, value }; + + this->for_each_table(L, ref_additions_fx); + this->auxiliary_keys.insert_or_assign(std::forward<Key>(key), std::forward<Value>(value)); + } + } + else { + reference ref_key = make_reference(L, std::forward<Key>(key)); + reference ref_value = make_reference(L, std::forward<Value>(value)); + lua_reference_func ref_additions_fx { ref_key, ref_value }; + + this->for_each_table(L, ref_additions_fx); + this->auxiliary_keys.insert_or_assign(std::move(ref_key), std::move(ref_value)); + } + } + } + + template <typename T> + template <typename Key, typename Value> + void usertype_storage<T>::set(lua_State* L, Key&& key, Value&& value) { + static_cast<usertype_storage_base&>(*this).set<T>(L, std::forward<Key>(key), std::forward<Value>(value)); + } + + template <typename T> + inline void clear_usertype_registry_names(lua_State* L) { + using u_traits = usertype_traits<T>; + using u_const_traits = usertype_traits<const T>; + using u_unique_traits = usertype_traits<d::u<T>>; + using u_ref_traits = usertype_traits<T*>; + using u_const_ref_traits = usertype_traits<T const*>; + + stack_reference registry(L, raw_index(LUA_REGISTRYINDEX)); + registry.push(); + // eliminate all named entries for this usertype + // in the registry (luaL_newmetatable does + // [name] = new table + // in registry upon creation + stack::set_field(L, &u_traits::metatable()[0], lua_nil, registry.stack_index()); + stack::set_field(L, &u_const_traits::metatable()[0], lua_nil, registry.stack_index()); + stack::set_field(L, &u_const_ref_traits::metatable()[0], lua_nil, registry.stack_index()); + stack::set_field(L, &u_ref_traits::metatable()[0], lua_nil, registry.stack_index()); + stack::set_field(L, &u_unique_traits::metatable()[0], lua_nil, registry.stack_index()); + registry.pop(); + } + + template <typename T> + inline int destroy_usertype_storage(lua_State* L) noexcept { + clear_usertype_registry_names<T>(L); + return detail::user_alloc_destroy<usertype_storage<T>>(L); + } + + template <typename T> + inline usertype_storage<T>& create_usertype_storage(lua_State* L) { + const char* gcmetakey = &usertype_traits<T>::gc_table()[0]; + + // Make sure userdata's memory is properly in lua first, + // otherwise all the light userdata we make later will become invalid + int usertype_storage_push_count = stack::push<user<usertype_storage<T>>>(L, no_metatable, L); + stack_reference usertype_storage_ref(L, -usertype_storage_push_count); + + // create and push onto the stack a table to use as metatable for this GC + // we create a metatable to attach to the regular gc_table + // so that the destructor is called for the usertype storage + int usertype_storage_metatabe_count = stack::push(L, new_table(0, 1)); + stack_reference usertype_storage_metatable(L, -usertype_storage_metatabe_count); + // set the destroyion routine on the metatable + stack::set_field(L, meta_function::garbage_collect, &destroy_usertype_storage<T>, usertype_storage_metatable.stack_index()); + // set the metatable on the usertype storage userdata + stack::set_field(L, metatable_key, usertype_storage_metatable, usertype_storage_ref.stack_index()); + usertype_storage_metatable.pop(); + + // set the usertype storage and its metatable + // into the global table... + stack::set_field<true>(L, gcmetakey, usertype_storage_ref); + usertype_storage_ref.pop(); + + // then retrieve the lua-stored version so we have a well-pinned + // reference that does not die + stack::get_field<true>(L, gcmetakey); + usertype_storage<T>& target_umt = stack::pop<user<usertype_storage<T>>>(L); + return target_umt; + } + + inline optional<usertype_storage_base&> maybe_as_usertype_storage_base(lua_State* L, int index) { + if (type_of(L, index) != type::lightuserdata) { + return nullopt; + } + usertype_storage_base& base_storage = *static_cast<usertype_storage_base*>(stack::get<void*>(L, index)); + return base_storage; + } + + inline optional<usertype_storage_base&> maybe_get_usertype_storage_base_inside(lua_State* L, int index) { + // okay, maybe we're looking at a table that is nested? + if (type_of(L, index) != type::table) { + return nullopt; + } + stack::get_field(L, meta_function::storage, index); + auto maybe_storage_base = maybe_as_usertype_storage_base(L, -1); + lua_pop(L, 1); + return maybe_storage_base; + } + + inline optional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L, int index) { + // If we can get the index directly as this type, go for it + auto maybe_already_is_usertype_storage_base = maybe_as_usertype_storage_base(L, index); + if (maybe_already_is_usertype_storage_base) { + return maybe_already_is_usertype_storage_base; + } + return maybe_get_usertype_storage_base_inside(L, index); + } + + inline optional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L, const char* gcmetakey) { + stack::get_field<true>(L, gcmetakey); + auto maybe_storage = maybe_as_usertype_storage_base(L, lua_gettop(L)); + lua_pop(L, 1); + return maybe_storage; + } + + inline usertype_storage_base& get_usertype_storage_base(lua_State* L, const char* gcmetakey) { + stack::get_field<true>(L, gcmetakey); + stack::record tracking; + usertype_storage_base& target_umt = stack::stack_detail::unchecked_unqualified_get<user<usertype_storage_base>>(L, -1, tracking); + lua_pop(L, 1); + return target_umt; + } + + template <typename T> + inline optional<usertype_storage<T>&> maybe_get_usertype_storage(lua_State* L) { + const char* gcmetakey = &usertype_traits<T>::gc_table()[0]; + stack::get_field<true>(L, gcmetakey); + int target = lua_gettop(L); + if (!stack::check<user<usertype_storage<T>>>(L, target)) { + return nullopt; + } + usertype_storage<T>& target_umt = stack::pop<user<usertype_storage<T>>>(L); + return target_umt; + } + + template <typename T> + inline usertype_storage<T>& get_usertype_storage(lua_State* L) { + const char* gcmetakey = &usertype_traits<T>::gc_table()[0]; + stack::get_field<true>(L, gcmetakey); + usertype_storage<T>& target_umt = stack::pop<user<usertype_storage<T>>>(L); + return target_umt; + } + + template <typename T> + inline void clear_usertype_storage(lua_State* L) { + using u_traits = usertype_traits<T>; + + const char* gcmetakey = &u_traits::gc_table()[0]; + stack::get_field<true>(L, gcmetakey); + if (!stack::check<user<usertype_storage<T>>>(L)) { + lua_pop(L, 1); + return; + } + usertype_storage<T>& target_umt = stack::pop<user<usertype_storage<T>>>(L); + target_umt.clear(); + + clear_usertype_registry_names<T>(L); + + stack::set_field<true>(L, gcmetakey, lua_nil); + } + + template <typename T, automagic_flags enrollment_flags> + inline int register_usertype(lua_State* L_, automagic_enrollments enrollments_ = {}) { + using u_traits = usertype_traits<T>; + using u_const_traits = usertype_traits<const T>; + using u_unique_traits = usertype_traits<d::u<T>>; + using u_ref_traits = usertype_traits<T*>; + using u_const_ref_traits = usertype_traits<T const*>; + using uts = usertype_storage<T>; + + // always have __new_index point to usertype_storage method + // have __index always point to regular fast-lookup + // meta_method table + // if __new_index is invoked, runtime-swap + // to slow __index if necessary + // (no speed penalty because function calls + // are all read-only -- only depend on __index + // to retrieve function and then call happens VIA Lua) + + // __type entry: + // table contains key -> value lookup, + // where key is entry in metatable + // and value is type information as a string as + // best as we can give it + + // name entry: + // string that contains raw class name, + // as defined from C++ + + // is entry: + // checks if argument supplied is of type T + + // __storage entry: + // a light userdata pointing to the storage + // mostly to enable this new abstraction + // to not require the type name `T` + // to get at the C++ usertype storage within + + // we then let typical definitions potentially override these intrinsics + // it's the user's fault if they override things or screw them up: + // these names have been reserved and documented since sol2 + + // STEP 0: tell the old usertype (if it exists) + // to fuck off + clear_usertype_storage<T>(L_); + + // STEP 1: Create backing store for usertype storage + // Pretty much the most important step. + // STEP 2: Create Lua tables used for fast method indexing. + // This is done inside of the storage table's constructor + usertype_storage<T>& storage = create_usertype_storage<T>(L_); + usertype_storage_base& base_storage = storage; + void* light_storage = static_cast<void*>(&storage); + void* light_base_storage = static_cast<void*>(&base_storage); + + // STEP 3: set up GC escape hatch table entirely + storage.gc_names_table.push(L_); + stateless_stack_reference gnt(L_, -1); + stack::set_field(L_, submetatable_type::named, &u_traits::gc_table()[0], gnt.stack_index()); + stack::set_field(L_, submetatable_type::const_value, &u_const_traits::metatable()[0], gnt.stack_index()); + stack::set_field(L_, submetatable_type::const_reference, &u_const_ref_traits::metatable()[0], gnt.stack_index()); + stack::set_field(L_, submetatable_type::reference, &u_ref_traits::metatable()[0], gnt.stack_index()); + stack::set_field(L_, submetatable_type::unique, &u_unique_traits::metatable()[0], gnt.stack_index()); + stack::set_field(L_, submetatable_type::value, &u_traits::metatable()[0], gnt.stack_index()); + gnt.pop(L_); + + // STEP 4: add some useful information to the type table + stateless_stack_reference stacked_type_table(L_, -storage.type_table.push(L_)); + stack::set_field(L_, "name", detail::demangle<T>(), stacked_type_table.stack_index()); + stack::set_field(L_, "is", &detail::is_check<T>, stacked_type_table.stack_index()); + stacked_type_table.pop(L_); + + // STEP 5: create and hook up metatable, + // add intrinsics + // this one is the actual meta-handling table, + // the next one will be the one for + int for_each_backing_metatable_calls = 0; + auto for_each_backing_metatable = [&](lua_State* L_, submetatable_type smt_, stateless_reference& fast_index_table_) { + // Pointer types, AKA "references" from C++ + const char* metakey = nullptr; + switch (smt_) { + case submetatable_type::const_value: + metakey = &u_const_traits::metatable()[0]; + break; + case submetatable_type::reference: + metakey = &u_ref_traits::metatable()[0]; + break; + case submetatable_type::unique: + metakey = &u_unique_traits::metatable()[0]; + break; + case submetatable_type::const_reference: + metakey = &u_const_ref_traits::metatable()[0]; + break; + case submetatable_type::named: + metakey = &u_traits::user_metatable()[0]; + break; + case submetatable_type::value: + default: + metakey = &u_traits::metatable()[0]; + break; + } + + luaL_newmetatable(L_, metakey); + if (smt_ == submetatable_type::named) { + // the named table itself + // gets the associated name value + storage.named_metatable.reset(L_, -1); + lua_pop(L_, 1); + // but the thing we perform the methods on + // is still the metatable of the named + // table + lua_createtable(L_, 0, 6); + } + stateless_stack_reference t(L_, -1); + fast_index_table_.reset(L_, t.stack_index()); + stack::set_field<false, true>(L_, meta_function::type, storage.type_table, t.stack_index()); + // destructible? serialize default destructor here + // otherwise, not destructible: serialize a "hey you messed up" + switch (smt_) { + case submetatable_type::const_reference: + case submetatable_type::reference: + case submetatable_type::named: + break; + case submetatable_type::unique: + if constexpr (std::is_destructible_v<T>) { + stack::set_field<false, true>(L_, meta_function::garbage_collect, &detail::unique_destroy<T>, t.stack_index()); + } + else { + stack::set_field<false, true>(L_, meta_function::garbage_collect, &detail::cannot_destroy<T>, t.stack_index()); + } + break; + case submetatable_type::value: + case submetatable_type::const_value: + default: + if constexpr (std::is_destructible_v<T>) { + stack::set_field<false, true>(L_, meta_function::garbage_collect, detail::make_destructor<T>(), t.stack_index()); + } + else { + stack::set_field<false, true>(L_, meta_function::garbage_collect, &detail::cannot_destroy<T>, t.stack_index()); + } + break; + } + + static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), + "The size of this data pointer is too small to fit the inheritance checking function: file a bug " + "report."); + static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), + "The size of this data pointer is too small to fit the inheritance checking function: file a bug " + "report."); + stack::set_field<false, true>(L_, detail::base_class_check_key(), reinterpret_cast<void*>(&detail::inheritance<T>::type_check), t.stack_index()); + stack::set_field<false, true>(L_, detail::base_class_cast_key(), reinterpret_cast<void*>(&detail::inheritance<T>::type_cast), t.stack_index()); + + auto prop_fx = detail::properties_enrollment_allowed(for_each_backing_metatable_calls, storage.properties, enrollments_); + auto insert_fx = [&L_, &t, &storage](meta_function mf, lua_CFunction reg) { + stack::set_field<false, true>(L_, mf, reg, t.stack_index()); + storage.properties[static_cast<std::size_t>(mf)] = true; + }; + detail::insert_default_registrations<T>(insert_fx, prop_fx); + + // There are no variables, so serialize the fast function stuff + // be sure to reset the index stuff to the non-fast version + // if the user ever adds something later! + if (smt_ == submetatable_type::named) { + // add escape hatch storage pointer and gc names + stack::set_field<false, true>(L_, meta_function::storage, light_base_storage, t.stack_index()); + stack::set_field<false, true>(L_, meta_function::gc_names, storage.gc_names_table, t.stack_index()); + + // fancy new_indexing when using the named table + { + absolute_index named_metatable_index(L_, -storage.named_metatable.push(L_)); + stack::set_field<false, true>(L_, metatable_key, t, named_metatable_index); + storage.named_metatable.pop(L_); + } + stack_reference stack_metametatable(L_, -storage.named_index_table.push(L_)); + stack::set_field<false, true>(L_, + meta_function::index, + make_closure(uts::template meta_index_call<false>, nullptr, light_storage, light_base_storage, nullptr, toplevel_magic), + stack_metametatable.stack_index()); + stack::set_field<false, true>(L_, + meta_function::new_index, + make_closure(uts::template meta_index_call<true>, nullptr, light_storage, light_base_storage, nullptr, toplevel_magic), + stack_metametatable.stack_index()); + stack_metametatable.pop(); + } + else { + // otherwise just plain for index, + // and elaborated for new_index + stack::set_field<false, true>(L_, meta_function::index, t, t.stack_index()); + stack::set_field<false, true>(L_, + meta_function::new_index, + make_closure(uts::template index_call<true>, nullptr, light_storage, light_base_storage, nullptr, toplevel_magic), + t.stack_index()); + storage.is_using_new_index = true; + } + + ++for_each_backing_metatable_calls; + fast_index_table_.reset(L_, t.stack_index()); + t.pop(L_); + }; + + storage.for_each_table(L_, for_each_backing_metatable); + + // can only use set AFTER we initialize all the metatables + if constexpr (std::is_default_constructible_v<T> && has_flag(enrollment_flags, automagic_flags::default_constructor)) { + if (enrollments_.default_constructor) { + storage.set(L_, meta_function::construct, constructors<T()>()); + } + } + + // return the named metatable we want names linked into + storage.named_metatable.push(L_); + return 1; + } +}} // namespace sol::u_detail + +// end of sol/usertype_storage.hpp + +// beginning of sol/usertype_proxy.hpp + +namespace sol { + template <typename Table, typename Key> + struct usertype_proxy : public proxy_base<usertype_proxy<Table, Key>> { + private: + using key_type = detail::proxy_key_t<Key>; + + template <typename T, std::size_t... I> + decltype(auto) tuple_get(std::index_sequence<I...>) const& { + return tbl.template traverse_get<T>(std::get<I>(key)...); + } + + template <typename T, std::size_t... I> + decltype(auto) tuple_get(std::index_sequence<I...>) && { + return tbl.template traverse_get<T>(std::get<I>(std::move(key))...); + } + + template <std::size_t... I, typename T> + void tuple_set(std::index_sequence<I...>, T&& value) & { + if constexpr (sizeof...(I) > 1) { + tbl.traverse_set(std::get<I>(key)..., std::forward<T>(value)); + } + else { + tbl.set(std::get<I>(key)..., std::forward<T>(value)); + } + } + + template <std::size_t... I, typename T> + void tuple_set(std::index_sequence<I...>, T&& value) && { + if constexpr (sizeof...(I) > 1) { + tbl.traverse_set(std::get<I>(std::move(key))..., std::forward<T>(value)); + } + else { + tbl.set(std::get<I>(std::move(key))..., std::forward<T>(value)); + } + } + + public: + Table tbl; + key_type key; + + template <typename T> + usertype_proxy(Table table, T&& k) : tbl(table), key(std::forward<T>(k)) { + } + + template <typename T> + usertype_proxy& set(T&& item) & { + using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>; + tuple_set(idx_seq(), std::forward<T>(item)); + return *this; + } + + template <typename T> + usertype_proxy&& set(T&& item) && { + using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>; + std::move(*this).tuple_set(idx_seq(), std::forward<T>(item)); + return std::move(*this); + } + + template <typename T> + usertype_proxy& operator=(T&& other) & { + return set(std::forward<T>(other)); + } + + template <typename T> + usertype_proxy&& operator=(T&& other) && { + return std::move(*this).set(std::forward<T>(other)); + } + + template <typename T> + usertype_proxy& operator=(std::initializer_list<T> other) & { + return set(std::move(other)); + } + + template <typename T> + usertype_proxy&& operator=(std::initializer_list<T> other) && { + return std::move(*this).set(std::move(other)); + } + + template <typename T> + decltype(auto) get() const& { + using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>; + return tuple_get<T>(idx_seq()); + } + + template <typename T> + decltype(auto) get() && { + using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>; + return std::move(*this).template tuple_get<T>(idx_seq()); + } + + template <typename K> + decltype(auto) operator[](K&& k) const& { + auto keys = meta::tuplefy(key, std::forward<K>(k)); + return usertype_proxy<Table, decltype(keys)>(tbl, std::move(keys)); + } + + template <typename K> + decltype(auto) operator[](K&& k) & { + auto keys = meta::tuplefy(key, std::forward<K>(k)); + return usertype_proxy<Table, decltype(keys)>(tbl, std::move(keys)); + } + + template <typename K> + decltype(auto) operator[](K&& k) && { + auto keys = meta::tuplefy(std::move(key), std::forward<K>(k)); + return usertype_proxy<Table, decltype(keys)>(tbl, std::move(keys)); + } + + template <typename... Ret, typename... Args> + decltype(auto) call(Args&&... args) { +#if !defined(__clang__) && defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 191200000 + // MSVC is ass sometimes + return get<function>().call<Ret...>(std::forward<Args>(args)...); +#else + return get<function>().template call<Ret...>(std::forward<Args>(args)...); +#endif + } + + template <typename... Args> + decltype(auto) operator()(Args&&... args) { + return call<>(std::forward<Args>(args)...); + } + + bool valid() const { + auto pp = stack::push_pop(tbl); + auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state())); + lua_pop(lua_state(), p.levels); + return p; + } + + int push() const noexcept { + return push(this->lua_state()); + } + + int push(lua_State* L) const noexcept { + return get<reference>().push(L); + } + + type get_type() const { + type t = type::none; + auto pp = stack::push_pop(tbl); + auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state())); + if (p) { + t = type_of(lua_state(), -1); + } + lua_pop(lua_state(), p.levels); + return t; + } + + lua_State* lua_state() const { + return tbl.lua_state(); + } + }; +} // namespace sol + +// end of sol/usertype_proxy.hpp + +// beginning of sol/metatable.hpp + +// beginning of sol/table_core.hpp + +// beginning of sol/table_proxy.hpp + +namespace sol { + + template <typename Table, typename Key> + struct table_proxy : public proxy_base<table_proxy<Table, Key>> { + private: + using key_type = detail::proxy_key_t<Key>; + + template <typename T, std::size_t... I> + decltype(auto) tuple_get(std::index_sequence<I...>) const& { + return tbl.template traverse_get<T>(std::get<I>(key)...); + } + + template <typename T, std::size_t... I> + decltype(auto) tuple_get(std::index_sequence<I...>) && { + return tbl.template traverse_get<T>(std::get<I>(std::move(key))...); + } + + template <std::size_t... I, typename T> + void tuple_set(std::index_sequence<I...>, T&& value) & { + tbl.traverse_set(std::get<I>(key)..., std::forward<T>(value)); + } + + template <std::size_t... I, typename T> + void tuple_set(std::index_sequence<I...>, T&& value) && { + tbl.traverse_set(std::get<I>(std::move(key))..., std::forward<T>(value)); + } + + auto setup_table(std::true_type) { + auto p = stack::probe_get_field<std::is_same_v<meta::unqualified_t<Table>, global_table>>(lua_state(), key, tbl.stack_index()); + lua_pop(lua_state(), p.levels); + return p; + } + + bool is_valid(std::false_type) { + auto pp = stack::push_pop(tbl); + auto p = stack::probe_get_field<std::is_same_v<meta::unqualified_t<Table>, global_table>>(lua_state(), key, lua_gettop(lua_state())); + lua_pop(lua_state(), p.levels); + return p; + } + + public: + Table tbl; + key_type key; + + template <typename T> + table_proxy(Table table, T&& k) : tbl(table), key(std::forward<T>(k)) { + } + + table_proxy(const table_proxy&) = default; + table_proxy(table_proxy&&) = default; + table_proxy& operator=(const table_proxy& right) { + return set(right); + } + table_proxy& operator=(table_proxy&& right) { + return set(std::move(right)); + } + + template <typename T> + table_proxy& set(T&& item) & { + tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item)); + return *this; + } + + template <typename T> + table_proxy&& set(T&& item) && { + std::move(*this).tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item)); + return std::move(*this); + } + + template <typename... Args> + table_proxy& set_function(Args&&... args) & { + tbl.set_function(key, std::forward<Args>(args)...); + return *this; + } + + template <typename... Args> + table_proxy&& set_function(Args&&... args) && { + tbl.set_function(std::move(key), std::forward<Args>(args)...); + return std::move(*this); + } + + template <typename T, std::enable_if_t<!std::is_same_v<meta::unqualified_t<T>, table_proxy>>* = nullptr> + table_proxy& operator=(T&& other) & { + using Tu = meta::unwrap_unqualified_t<T>; + if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_invocable_v<Tu>) { + return set_function(std::forward<T>(other)); + } + else { + return set(std::forward<T>(other)); + } + } + + template <typename T, std::enable_if_t<!std::is_same_v<meta::unqualified_t<T>, table_proxy>>* = nullptr> + table_proxy&& operator=(T&& other) && { + using Tu = meta::unwrap_unqualified_t<T>; + if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_invocable_v<Tu> && !detail::is_msvc_callable_rigged_v<T>) { + return std::move(*this).set_function(std::forward<T>(other)); + } + else { + return std::move(*this).set(std::forward<T>(other)); + } + } + + template <typename T> + table_proxy& operator=(std::initializer_list<T> other) & { + return set(std::move(other)); + } + + template <typename T> + table_proxy&& operator=(std::initializer_list<T> other) && { + return std::move(*this).set(std::move(other)); + } + + template <typename T> + bool is() const { + typedef decltype(get<T>()) U; + optional<U> option = this->get<optional<U>>(); + return option.has_value(); + } + + template <typename T> + decltype(auto) get() const& { + using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>; + return tuple_get<T>(idx_seq()); + } + + template <typename T> + decltype(auto) get() && { + using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>; + return std::move(*this).template tuple_get<T>(idx_seq()); + } + + template <typename T> + decltype(auto) get_or(T&& otherwise) const { + typedef decltype(get<T>()) U; + optional<U> option = get<optional<U>>(); + if (option) { + return static_cast<U>(option.value()); + } + return static_cast<U>(std::forward<T>(otherwise)); + } + + template <typename T, typename D> + decltype(auto) get_or(D&& otherwise) const { + optional<T> option = get<optional<T>>(); + if (option) { + return static_cast<T>(option.value()); + } + return static_cast<T>(std::forward<D>(otherwise)); + } + + template <typename T> + decltype(auto) get_or_create() { + return get_or_create<T>(new_table()); + } + + template <typename T, typename Otherwise> + decltype(auto) get_or_create(Otherwise&& other) { + if (!this->valid()) { + this->set(std::forward<Otherwise>(other)); + } + return get<T>(); + } + + template <typename K> + decltype(auto) operator[](K&& k) const& { + auto keys = meta::tuplefy(key, std::forward<K>(k)); + return table_proxy<Table, decltype(keys)>(tbl, std::move(keys)); + } + + template <typename K> + decltype(auto) operator[](K&& k) & { + auto keys = meta::tuplefy(key, std::forward<K>(k)); + return table_proxy<Table, decltype(keys)>(tbl, std::move(keys)); + } + + template <typename K> + decltype(auto) operator[](K&& k) && { + auto keys = meta::tuplefy(std::move(key), std::forward<K>(k)); + return table_proxy<Table, decltype(keys)>(tbl, std::move(keys)); + } + + template <typename... Ret, typename... Args> + decltype(auto) call(Args&&... args) { + lua_State* L = this->lua_state(); + push(L); + int idx = lua_gettop(L); + stack_aligned_function func(L, idx); + return func.call<Ret...>(std::forward<Args>(args)...); + } + + template <typename... Args> + decltype(auto) operator()(Args&&... args) { + return call<>(std::forward<Args>(args)...); + } + + bool valid() const { + auto pp = stack::push_pop(tbl); + auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state())); + lua_pop(lua_state(), p.levels); + return p; + } + + int push() const noexcept { + return push(this->lua_state()); + } + + int push(lua_State* L) const noexcept { + if constexpr (std::is_same_v<meta::unqualified_t<Table>, global_table> || is_stack_table_v<meta::unqualified_t<Table>>) { + auto pp = stack::push_pop<true>(tbl); + int tableindex = pp.index_of(tbl); + int top_index = lua_gettop(L); + stack::get_field<true>(lua_state(), key, tableindex); + lua_replace(L, top_index + 1); + lua_settop(L, top_index + 1); + } + else { + auto pp = stack::push_pop<false>(tbl); + int tableindex = pp.index_of(tbl); + int aftertableindex = lua_gettop(L); + stack::get_field<false>(lua_state(), key, tableindex); + lua_replace(L, tableindex); + lua_settop(L, aftertableindex + 1); + } + return 1; + } + + type get_type() const { + type t = type::none; + auto pp = stack::push_pop(tbl); + auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state())); + if (p) { + t = type_of(lua_state(), -1); + } + lua_pop(lua_state(), p.levels); + return t; + } + + lua_State* lua_state() const { + return tbl.lua_state(); + } + + table_proxy& force() { + if (!this->valid()) { + this->set(new_table()); + } + return *this; + } + }; + + template <typename Table, typename Key, typename T> + inline bool operator==(T&& left, const table_proxy<Table, Key>& right) { + using G = decltype(stack::get<T>(nullptr, 0)); + return right.template get<optional<G>>() == left; + } + + template <typename Table, typename Key, typename T> + inline bool operator==(const table_proxy<Table, Key>& right, T&& left) { + using G = decltype(stack::get<T>(nullptr, 0)); + return right.template get<optional<G>>() == left; + } + + template <typename Table, typename Key, typename T> + inline bool operator!=(T&& left, const table_proxy<Table, Key>& right) { + using G = decltype(stack::get<T>(nullptr, 0)); + return right.template get<optional<G>>() != left; + } + + template <typename Table, typename Key, typename T> + inline bool operator!=(const table_proxy<Table, Key>& right, T&& left) { + using G = decltype(stack::get<T>(nullptr, 0)); + return right.template get<optional<G>>() != left; + } + + template <typename Table, typename Key> + inline bool operator==(lua_nil_t, const table_proxy<Table, Key>& right) { + return !right.valid(); + } + + template <typename Table, typename Key> + inline bool operator==(const table_proxy<Table, Key>& right, lua_nil_t) { + return !right.valid(); + } + + template <typename Table, typename Key> + inline bool operator!=(lua_nil_t, const table_proxy<Table, Key>& right) { + return right.valid(); + } + + template <typename Table, typename Key> + inline bool operator!=(const table_proxy<Table, Key>& right, lua_nil_t) { + return right.valid(); + } + + template <bool b> + template <typename Super> + basic_reference<b>& basic_reference<b>::operator=(proxy_base<Super>&& r) { + basic_reference<b> v = r; + this->operator=(std::move(v)); + return *this; + } + + template <bool b> + template <typename Super> + basic_reference<b>& basic_reference<b>::operator=(const proxy_base<Super>& r) { + basic_reference<b> v = r; + this->operator=(std::move(v)); + return *this; + } + + namespace stack { + template <typename Table, typename Key> + struct unqualified_pusher<table_proxy<Table, Key>> { + static int push(lua_State* L, const table_proxy<Table, Key>& p) { + return p.push(L); + } + }; + } // namespace stack +} // namespace sol + +// end of sol/table_proxy.hpp + +// beginning of sol/table_iterator.hpp + +#include <iterator> + +namespace sol { + + template <typename reference_type> + class basic_table_iterator { + public: + typedef object key_type; + typedef object mapped_type; + typedef std::pair<object, object> value_type; + typedef std::input_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + + private: + std::pair<object, object> kvp; + reference_type ref; + int tableidx = 0; + int keyidx = 0; + std::ptrdiff_t idx = 0; + + public: + basic_table_iterator() noexcept : keyidx(-1), idx(-1) { + } + + basic_table_iterator(reference_type x) noexcept : ref(std::move(x)) { + ref.push(); + tableidx = lua_gettop(ref.lua_state()); + stack::push(ref.lua_state(), lua_nil); + this->operator++(); + if (idx == -1) { + return; + } + --idx; + } + + basic_table_iterator& operator++() noexcept { + if (idx == -1) + return *this; + + if (lua_next(ref.lua_state(), tableidx) == 0) { + idx = -1; + keyidx = -1; + return *this; + } + ++idx; + kvp.first = object(ref.lua_state(), -2); + kvp.second = object(ref.lua_state(), -1); + lua_pop(ref.lua_state(), 1); + // leave key on the stack + keyidx = lua_gettop(ref.lua_state()); + return *this; + } + + basic_table_iterator operator++(int) noexcept { + auto saved = *this; + this->operator++(); + return saved; + } + + reference operator*() const noexcept { + return const_cast<reference>(kvp); + } + + bool operator==(const basic_table_iterator& right) const noexcept { + return idx == right.idx; + } + + bool operator!=(const basic_table_iterator& right) const noexcept { + return idx != right.idx; + } + + ~basic_table_iterator() { + if (keyidx != -1) { + stack::remove(ref.lua_state(), keyidx, 1); + } + if (ref.lua_state() != nullptr && ref.valid()) { + stack::remove(ref.lua_state(), tableidx, 1); + } + } + }; + +} // namespace sol + +// end of sol/table_iterator.hpp + +// beginning of sol/pairs_iterator.hpp + +// beginning of sol/stack/detail/pairs.hpp + +#include <optional> + +namespace sol { namespace stack { namespace stack_detail { + + inline bool maybe_push_lua_next_function(lua_State* L_) { + stack::get_field<true, false>(L_, "next"); + bool is_next = stack::check<protected_function>(L_); + if (is_next) { + return true; + } + stack::get_field<true, false>(L_, "table"); + stack::record tracking{}; + if (!stack::loose_table_check(L_, -1, &no_panic, tracking)) { + return false; + } + lua_getfield(L_, -1, "next"); + bool is_table_next_func = stack::check<protected_function>(L_, -1); + if (is_table_next_func) { + return true; + } + lua_pop(L_, 1); + return false; + } + + inline std::optional<protected_function> find_lua_next_function(lua_State* L_) { + if (maybe_push_lua_next_function(L_)) { + return stack::pop<protected_function>(L_); + } + return std::nullopt; + } + + inline int c_lua_next(lua_State* L_) noexcept { + stack_reference table_stack_ref(L_, raw_index(1)); + stateless_stack_reference key_stack_ref(L_, raw_index(2)); + int result = lua_next(table_stack_ref.lua_state(), table_stack_ref.stack_index()); + if (result == 0) { + stack::push(L_, lua_nil); + return 1; + } + return 2; + } + + inline int readonly_pairs(lua_State* L_) noexcept { + int pushed = 0; + if (!maybe_push_lua_next_function(L_)) { + // we do not have the "next" function in the global namespace + // from the "table" global entiry, use our own + pushed += stack::push(L_, &c_lua_next); + } + else { + pushed += 1; + } + int metatable_exists = lua_getmetatable(L_, 1); + SOL_ASSERT(metatable_exists == 1); + const auto& index_key = to_string(sol::meta_function::index); + lua_getfield(L_, lua_gettop(L_), index_key.c_str()); + lua_remove(L_, -2); + pushed += 1; + pushed += stack::push(L_, lua_nil); + return pushed; + } + +}}} // sol::stack::stack_detail + +// end of sol/stack/detail/pairs.hpp + +namespace sol { + + struct pairs_sentinel { }; + + class pairs_iterator { + private: + inline static constexpr int empty_key_index = -1; + + public: + using key_type = object; + using mapped_type = object; + using value_type = std::pair<object, object>; + using iterator_category = std::input_iterator_tag; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using const_pointer = value_type const*; + using reference = value_type&; + using const_reference = const value_type&; + + pairs_iterator() noexcept + : m_L(nullptr) + , m_next_function_ref(lua_nil) + , m_table_ref(lua_nil) + , m_cached_key_value_pair({ lua_nil, lua_nil }) + , m_key_index(empty_key_index) + , m_iteration_index(0) { + } + + pairs_iterator(const pairs_iterator&) = delete; + pairs_iterator& operator=(const pairs_iterator&) = delete; + + pairs_iterator(pairs_iterator&& right) noexcept + : m_L(right.m_L) + , m_next_function_ref(std::move(right.m_next_function_ref)) + , m_table_ref(std::move(right.m_table_ref)) + , m_cached_key_value_pair(std::move(right.m_cached_key_value_pair)) + , m_key_index(right.m_key_index) + , m_iteration_index(right.m_iteration_index) { + right.m_key_index = empty_key_index; + } + + pairs_iterator& operator=(pairs_iterator&& right) noexcept { + m_L = right.m_L; + m_next_function_ref = std::move(right.m_next_function_ref); + m_table_ref = std::move(right.m_table_ref); + m_cached_key_value_pair = std::move(right.m_cached_key_value_pair); + m_key_index = right.m_key_index; + m_iteration_index = right.m_iteration_index; + right.m_key_index = empty_key_index; + return *this; + } + + template <typename Source> + pairs_iterator(const Source& source_) noexcept : m_L(source_.lua_state()), m_key_index(empty_key_index), m_iteration_index(0) { + if (m_L == nullptr || !source_.valid()) { + m_key_index = empty_key_index; + return; + } + int source_index = -source_.push(m_L); + int abs_source_index = lua_absindex(m_L, source_index); + int metatable_exists = lua_getmetatable(m_L, abs_source_index); + lua_remove(m_L, abs_source_index); + if (metatable_exists == 1) { + // just has a metatable, but does it have __pairs ? + stack_reference metatable(m_L, raw_index(abs_source_index)); + stack::get_field<is_global_table_v<Source>, true>(m_L, meta_function::pairs, metatable.stack_index()); + optional<protected_function> maybe_pairs_function = stack::pop<optional<protected_function>>(m_L); + if (maybe_pairs_function.has_value()) { + protected_function& pairs_function = *maybe_pairs_function; + protected_function_result next_fn_and_table_and_first_key = pairs_function(source_); + if (next_fn_and_table_and_first_key.valid()) { + m_next_function_ref = next_fn_and_table_and_first_key.get<protected_function>(0); + m_table_ref = next_fn_and_table_and_first_key.get<sol::reference>(1); + m_key_index = next_fn_and_table_and_first_key.stack_index() - 1; + // remove next function and table + lua_remove(m_L, m_key_index); + lua_remove(m_L, m_key_index); + next_fn_and_table_and_first_key.abandon(); + lua_remove(m_L, abs_source_index); + this->operator++(); + m_iteration_index = 0; + return; + } + } + } + + { + auto maybe_next = stack::stack_detail::find_lua_next_function(m_L); + if (maybe_next.has_value()) { + m_next_function_ref = std::move(*maybe_next); + m_table_ref = source_; + + stack::push(m_L, lua_nil); + m_key_index = lua_gettop(m_L); + this->operator++(); + m_iteration_index = 0; + return; + } + } + + // okay, so none of the above worked and now we need to create + // a shim / polyfill instead + stack::push(m_L, &stack::stack_detail::c_lua_next); + m_next_function_ref = stack::pop<protected_function>(m_L); + m_table_ref = source_; + stack::push(m_L, lua_nil); + m_key_index = lua_gettop(m_L); + this->operator++(); + m_iteration_index = 0; + } + + pairs_iterator& operator++() { + if (m_key_index == empty_key_index) { + return *this; + } + { + sol::protected_function_result next_results = m_next_function_ref(m_table_ref, stack_reference(m_L, m_key_index)); + if (!next_results.valid()) { + // TODO: abort, or throw an error? + m_clear(); + m_key_index = empty_key_index; + return *this; + } + int next_results_count = next_results.return_count(); + if (next_results_count < 2) { + // iteration is over! + next_results.abandon(); + lua_settop(m_L, m_key_index - 1); + m_key_index = empty_key_index; + ++m_iteration_index; + return *this; + } + else { + lua_remove(m_L, m_key_index); + m_key_index = next_results.stack_index() - 1; + m_cached_key_value_pair.first = stack::get<object>(m_L, m_key_index); + m_cached_key_value_pair.second = stack::get<object>(m_L, m_key_index + 1); + lua_settop(m_L, m_key_index); + next_results.abandon(); + } + } + ++m_iteration_index; + return *this; + } + + std::ptrdiff_t index() const { + return static_cast<std::ptrdiff_t>(m_iteration_index); + } + + const_reference operator*() const noexcept { + return m_cached_key_value_pair; + } + + reference operator*() noexcept { + return m_cached_key_value_pair; + } + + friend bool operator==(const pairs_iterator& left, const pairs_iterator& right) noexcept { + return left.m_table_ref == right.m_table_ref && left.m_iteration_index == right.m_iteration_index; + } + + friend bool operator!=(const pairs_iterator& left, const pairs_iterator& right) noexcept { + return left.m_table_ref != right.m_table_ref || left.m_iteration_index != right.m_iteration_index; + } + + friend bool operator==(const pairs_iterator& left, const pairs_sentinel&) noexcept { + return left.m_key_index == empty_key_index; + } + + friend bool operator!=(const pairs_iterator& left, const pairs_sentinel&) noexcept { + return left.m_key_index != empty_key_index; + } + + friend bool operator==(const pairs_sentinel&, const pairs_iterator& left) noexcept { + return left.m_key_index == empty_key_index; + } + + friend bool operator!=(const pairs_sentinel&, const pairs_iterator& left) noexcept { + return left.m_key_index != empty_key_index; + } + + ~pairs_iterator() { + if (m_key_index != empty_key_index) { + m_clear(); + } + } + + private: + void m_clear() noexcept { + lua_remove(m_L, m_key_index); + } + + lua_State* m_L; + protected_function m_next_function_ref; + sol::reference m_table_ref; + std::pair<object, object> m_cached_key_value_pair; + int m_key_index; + int m_iteration_index; + }; + + template <typename Source> + class basic_pairs_range { + private: + using source_t = std::add_lvalue_reference_t<Source>; + source_t m_source; + + public: + using iterator = pairs_iterator; + using const_iterator = pairs_iterator; + + basic_pairs_range(source_t source_) noexcept : m_source(source_) { + } + + iterator begin() noexcept { + return iterator(m_source); + } + + iterator begin() const noexcept { + return iterator(m_source); + } + + const_iterator cbegin() const noexcept { + return const_iterator(m_source); + } + + pairs_sentinel end() noexcept { + return {}; + } + + pairs_sentinel end() const noexcept { + return {}; + } + + pairs_sentinel cend() const noexcept { + return {}; + } + }; +} // namespace sol + +// end of sol/pairs_iterator.hpp + +namespace sol { + namespace detail { + template <std::size_t n> + struct clean { + lua_State* L; + clean(lua_State* luastate) : L(luastate) { + } + ~clean() { + lua_pop(L, static_cast<int>(n)); + } + }; + + struct ref_clean { + lua_State* L; + int& pop_count; + + ref_clean(lua_State* L_, int& pop_count_) noexcept : L(L_), pop_count(pop_count_) { + } + ~ref_clean() { + lua_pop(L, static_cast<int>(pop_count)); + } + }; + + inline int fail_on_newindex(lua_State* L_) { + return luaL_error(L_, "sol: cannot modify the elements of an enumeration table"); + } + + } // namespace detail + + template <bool top_level, typename ref_t> + class basic_table_core : public basic_object<ref_t> { + private: + using base_t = basic_object<ref_t>; + + friend class state; + friend class state_view; + template <typename, typename> + friend class basic_usertype; + template <typename> + friend class basic_metatable; + + template <typename T> + using is_get_direct_tableless = meta::boolean<stack::stack_detail::is_get_direct_tableless_v<T, top_level, false>>; + + template <typename T> + using is_raw_get_direct_tableless = std::false_type; + + template <typename T> + using is_set_direct_tableless = meta::boolean<stack::stack_detail::is_set_direct_tableless_v<T, top_level, false>>; + + template <typename T> + using is_raw_set_direct_tableless = std::false_type; + + template <bool raw, typename... Ret, typename... Keys> + decltype(auto) tuple_get(int table_index, Keys&&... keys) const { + if constexpr (sizeof...(Ret) < 2) { + return traverse_get_single_maybe_tuple<raw, Ret...>(table_index, std::forward<Keys>(keys)...); + } + else { + using multi_ret = decltype(stack::pop<std::tuple<Ret...>>(nullptr)); + return multi_ret(traverse_get_single_maybe_tuple<raw, Ret>(table_index, std::forward<Keys>(keys))...); + } + } + + template <bool raw, typename Ret, size_t... I, typename Key> + decltype(auto) traverse_get_single_tuple(int table_index, std::index_sequence<I...>, Key&& key) const { + return traverse_get_single<raw, Ret>(table_index, std::get<I>(std::forward<Key>(key))...); + } + + template <bool raw, typename Ret, typename Key> + decltype(auto) traverse_get_single_maybe_tuple(int table_index, Key&& key) const { + if constexpr (meta::is_tuple_v<meta::unqualified_t<Key>>) { + return traverse_get_single_tuple<raw, Ret>( + table_index, std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<Key>>>(), std::forward<Key>(key)); + } + else { + return traverse_get_single<raw, Ret>(table_index, std::forward<Key>(key)); + } + } + + template <bool raw, typename Ret, typename... Keys> + decltype(auto) traverse_get_single(int table_index, Keys&&... keys) const { + constexpr static bool global = (meta::count_for_to_pack_v < 1, is_get_direct_tableless, meta::unqualified_t<Keys>... >> 0); + if constexpr (meta::is_optional_v<meta::unqualified_t<Ret>>) { + int popcount = 0; + detail::ref_clean c(base_t::lua_state(), popcount); + return traverse_get_deep_optional<global, raw, detail::insert_mode::none, Ret>(popcount, table_index, std::forward<Keys>(keys)...); + } + else { + detail::clean<sizeof...(Keys) - meta::count_for_pack_v<detail::is_insert_mode, meta::unqualified_t<Keys>...>> c(base_t::lua_state()); + return traverse_get_deep<global, raw, detail::insert_mode::none, Ret>(table_index, std::forward<Keys>(keys)...); + } + } + + template <bool raw, typename Pairs, std::size_t... I> + void tuple_set(std::index_sequence<I...>, Pairs&& pairs) { + constexpr static bool global = (meta::count_even_for_pack_v < is_set_direct_tableless, + meta::unqualified_t<decltype(std::get<I * 2>(std::forward<Pairs>(pairs)))>... >> 0); + auto pp = stack::push_pop<global>(*this); + int table_index = pp.index_of(*this); + lua_State* L = base_t::lua_state(); + (void)table_index; + (void)L; + void(detail::swallow { (stack::set_field<(top_level), raw>( + L, std::get<I * 2>(std::forward<Pairs>(pairs)), std::get<I * 2 + 1>(std::forward<Pairs>(pairs)), table_index), + 0)... }); + } + + template <bool global, bool raw, detail::insert_mode mode, typename T, typename Key, typename... Keys> + decltype(auto) traverse_get_deep(int table_index, Key&& key, Keys&&... keys) const { + if constexpr (std::is_same_v<meta::unqualified_t<Key>, create_if_nil_t>) { + (void)key; + return traverse_get_deep<false, raw, static_cast<detail::insert_mode>(mode | detail::insert_mode::create_if_nil), T>( + table_index, std::forward<Keys>(keys)...); + } + else { + lua_State* L = base_t::lua_state(); + stack::get_field<global, raw>(L, std::forward<Key>(key), table_index); + if constexpr (sizeof...(Keys) > 0) { + if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) { + type t = type_of(L, -1); + if (t == type::lua_nil || t == type::none) { + lua_pop(L, 1); + stack::push(L, new_table(0, 0)); + } + } + return traverse_get_deep<false, raw, mode, T>(lua_gettop(L), std::forward<Keys>(keys)...); + } + else { + if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) { + type t = type_of(L, -1); + if ((t == type::lua_nil || t == type::none) && (is_table_like_v<T>)) { + lua_pop(L, 1); + stack::push(L, new_table(0, 0)); + } + } + return stack::get<T>(L); + } + } + } + + template <bool global, bool raw, detail::insert_mode mode, typename T, typename Key, typename... Keys> + decltype(auto) traverse_get_deep_optional(int& popcount, int table_index, Key&& key, Keys&&... keys) const { + if constexpr (std::is_same_v<meta::unqualified_t<Key>, create_if_nil_t>) { + constexpr detail::insert_mode new_mode = static_cast<detail::insert_mode>(mode | detail::insert_mode::create_if_nil); + (void)key; + return traverse_get_deep_optional<global, raw, new_mode, T>(popcount, table_index, std::forward<Keys>(keys)...); + } + else if constexpr (std::is_same_v<meta::unqualified_t<Key>, update_if_empty_t>) { + constexpr detail::insert_mode new_mode = static_cast<detail::insert_mode>(mode | detail::insert_mode::update_if_empty); + (void)key; + return traverse_get_deep_optional<global, raw, new_mode, T>(popcount, table_index, std::forward<Keys>(keys)...); + } + else if constexpr (std::is_same_v<meta::unqualified_t<Key>, override_value_t>) { + constexpr detail::insert_mode new_mode = static_cast<detail::insert_mode>(mode | detail::insert_mode::override_value); + (void)key; + return traverse_get_deep_optional<global, raw, new_mode, T>(popcount, table_index, std::forward<Keys>(keys)...); + } + else { + if constexpr (sizeof...(Keys) > 0) { + lua_State* L = base_t::lua_state(); + auto p = stack::probe_get_field<global, raw>(L, std::forward<Key>(key), table_index); + popcount += p.levels; + if (!p.success) { + if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) { + lua_pop(L, 1); + constexpr bool is_seq = meta::count_for_to_pack_v < 1, std::is_integral, Keys... >> 0; + stack::push(L, new_table(static_cast<int>(is_seq), static_cast<int>(!is_seq))); + stack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index); + } + else { + return T(nullopt); + } + } + return traverse_get_deep_optional<false, raw, mode, T>(popcount, lua_gettop(L), std::forward<Keys>(keys)...); + } + else { + using R = decltype(stack::get<T>(nullptr)); + using value_type = typename meta::unqualified_t<R>::value_type; + lua_State* L = base_t::lua_state(); + auto p = stack::probe_get_field<global, raw, value_type>(L, key, table_index); + popcount += p.levels; + if (!p.success) { + if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) { + lua_pop(L, 1); + stack::push(L, new_table(0, 0)); + stack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index); + if (stack::check<value_type>(L, lua_gettop(L), &no_panic)) { + return stack::get<T>(L); + } + } + return R(nullopt); + } + return stack::get<T>(L); + } + } + } + + template <bool global, bool raw, detail::insert_mode mode, typename Key, typename... Keys> + void traverse_set_deep(int table_index, Key&& key, Keys&&... keys) const { + using KeyU = meta::unqualified_t<Key>; + if constexpr (std::is_same_v<KeyU, update_if_empty_t>) { + (void)key; + traverse_set_deep<global, raw, static_cast<detail::insert_mode>(mode | detail::insert_mode::update_if_empty)>( + table_index, std::forward<Keys>(keys)...); + } + else if constexpr (std::is_same_v<KeyU, create_if_nil_t>) { + (void)key; + traverse_set_deep<global, raw, static_cast<detail::insert_mode>(mode | detail::insert_mode::create_if_nil)>( + table_index, std::forward<Keys>(keys)...); + } + else if constexpr (std::is_same_v<KeyU, override_value_t>) { + (void)key; + traverse_set_deep<global, raw, static_cast<detail::insert_mode>(mode | detail::insert_mode::override_value)>( + table_index, std::forward<Keys>(keys)...); + } + else { + lua_State* L = base_t::lua_state(); + if constexpr (sizeof...(Keys) == 1) { + if constexpr ((mode & detail::insert_mode::update_if_empty) == detail::insert_mode::update_if_empty) { + auto p = stack::probe_get_field<global, raw>(L, key, table_index); + lua_pop(L, p.levels); + if (!p.success) { + stack::set_field<global, raw>(L, std::forward<Key>(key), std::forward<Keys>(keys)..., table_index); + } + } + else { + stack::set_field<global, raw>(L, std::forward<Key>(key), std::forward<Keys>(keys)..., table_index); + } + } + else { + if constexpr (mode != detail::insert_mode::none) { + stack::get_field<global, raw>(L, key, table_index); + type vt = type_of(L, -1); + if constexpr ((mode & detail::insert_mode::update_if_empty) == detail::insert_mode::update_if_empty + || (mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) { + if (vt == type::lua_nil || vt == type::none) { + constexpr bool is_seq = meta::count_for_to_pack_v < 1, std::is_integral, Keys... >> 0; + lua_pop(L, 1); + stack::push(L, new_table(static_cast<int>(is_seq), static_cast<int>(!is_seq))); + stack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index); + } + } + else { + if (vt != type::table) { + constexpr bool is_seq = meta::count_for_to_pack_v < 1, std::is_integral, Keys... >> 0; + lua_pop(L, 1); + stack::push(L, new_table(static_cast<int>(is_seq), static_cast<int>(!is_seq))); + stack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index); + } + } + } + else { + stack::get_field<global, raw>(L, std::forward<Key>(key), table_index); + } + traverse_set_deep<false, raw, mode>(lua_gettop(L), std::forward<Keys>(keys)...); + } + } + } + + protected: + basic_table_core(detail::no_safety_tag, lua_nil_t n) : base_t(n) { + } + basic_table_core(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) { + } + basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) { + } + template <typename T, + meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<ref_t, stack_reference>>, + meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_table_core(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward<T>(r)) { + } + template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_table_core(detail::no_safety_tag, lua_State* L, T&& r) noexcept : base_t(L, std::forward<T>(r)) { + } + + public: + using iterator = basic_table_iterator<ref_t>; + using const_iterator = iterator; + + using base_t::lua_state; + + basic_table_core() noexcept = default; + basic_table_core(const basic_table_core&) = default; + basic_table_core(basic_table_core&&) = default; + basic_table_core& operator=(const basic_table_core&) = default; + basic_table_core& operator=(basic_table_core&&) = default; + + basic_table_core(const stack_reference& r) : basic_table_core(r.lua_state(), r.stack_index()) { + } + + basic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) { + } + + template <typename T, meta::enable_any<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_table_core(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + constructor_handler handler {}; + stack::check<basic_table_core>(lua_state(), table_index, handler); +#endif // Safety + } + + basic_table_core(lua_State* L, const new_table& nt) : base_t(L, -stack::push(L, nt)) { + if (!is_stack_based<meta::unqualified_t<ref_t>>::value) { + lua_pop(L, 1); + } + } + + basic_table_core(lua_State* L, int index = -1) : basic_table_core(detail::no_safety, L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_table_core>(L, index, handler); +#endif // Safety + } + + basic_table_core(lua_State* L, ref_index index) : basic_table_core(detail::no_safety, L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + constructor_handler handler {}; + stack::check<basic_table_core>(lua_state(), table_index, handler); +#endif // Safety + } + + template <typename T, + meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<ref_t, stack_reference>>, + meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_table_core(T&& r) noexcept : basic_table_core(detail::no_safety, std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + if (!is_table<meta::unqualified_t<T>>::value) { + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + constructor_handler handler {}; + stack::check<basic_table_core>(lua_state(), table_index, handler); + } +#endif // Safety + } + + basic_table_core(lua_nil_t r) noexcept : basic_table_core(detail::no_safety, r) { + } + + basic_table_core(lua_State* L, global_tag_t t) noexcept : base_t(L, t) { + } + + iterator begin() const { + if (this->get_type() == type::table) { + return iterator(*this); + } + return iterator(); + } + + iterator end() const { + return iterator(); + } + + const_iterator cbegin() const { + return begin(); + } + + const_iterator cend() const { + return end(); + } + + basic_pairs_range<basic_table_core> pairs() noexcept { + return basic_pairs_range<basic_table_core>(*this); + } + + basic_pairs_range<const basic_table_core> pairs() const noexcept { + return basic_pairs_range<const basic_table_core>(*this); + } + + void clear() { + auto pp = stack::push_pop<false>(*this); + int table_index = pp.index_of(*this); + stack::clear(lua_state(), table_index); + } + + template <typename... Ret, typename... Keys> + decltype(auto) get(Keys&&... keys) const { + static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match"); + constexpr static bool global = meta::all<meta::boolean<top_level>, is_get_direct_tableless<meta::unqualified_t<Keys>>...>::value; + auto pp = stack::push_pop<global>(*this); + int table_index = pp.index_of(*this); + return tuple_get<false, Ret...>(table_index, std::forward<Keys>(keys)...); + } + + template <typename T, typename Key> + decltype(auto) get_or(Key&& key, T&& otherwise) const { + typedef decltype(get<T>("")) U; + optional<U> option = get<optional<U>>(std::forward<Key>(key)); + if (option) { + return static_cast<U>(option.value()); + } + return static_cast<U>(std::forward<T>(otherwise)); + } + + template <typename T, typename Key, typename D> + decltype(auto) get_or(Key&& key, D&& otherwise) const { + optional<T> option = get<optional<T>>(std::forward<Key>(key)); + if (option) { + return static_cast<T>(option.value()); + } + return static_cast<T>(std::forward<D>(otherwise)); + } + + template <typename T, typename... Keys> + decltype(auto) traverse_get(Keys&&... keys) const { + static_assert(sizeof...(Keys) > 0, "must pass at least 1 key to get"); + constexpr static bool global = (meta::count_for_to_pack_v < 1, is_get_direct_tableless, meta::unqualified_t<Keys>... >> 0); + auto pp = stack::push_pop<global>(*this); + int table_index = pp.index_of(*this); + return traverse_get_single<false, T>(table_index, std::forward<Keys>(keys)...); + } + + template <typename... Keys> + basic_table_core& traverse_set(Keys&&... keys) { + static_assert(sizeof...(Keys) > 1, "must pass at least 1 key and 1 value to set"); + constexpr static bool global + = (meta::count_when_for_to_pack_v < detail::is_not_insert_mode, 1, is_set_direct_tableless, meta::unqualified_t<Keys>... >> 0); + auto pp = stack::push_pop<global>(*this); + int table_index = pp.index_of(*this); + lua_State* L = base_t::lua_state(); + auto pn = stack::pop_n(L, static_cast<int>(sizeof...(Keys) - 2 - meta::count_for_pack_v<detail::is_insert_mode, meta::unqualified_t<Keys>...>)); + traverse_set_deep<top_level, false, detail::insert_mode::none>(table_index, std::forward<Keys>(keys)...); + return *this; + } + + template <typename... Args> + basic_table_core& set(Args&&... args) { + if constexpr (sizeof...(Args) == 2) { + traverse_set(std::forward<Args>(args)...); + } + else { + tuple_set<false>(std::make_index_sequence<sizeof...(Args) / 2>(), std::forward_as_tuple(std::forward<Args>(args)...)); + } + return *this; + } + + template <typename... Ret, typename... Keys> + decltype(auto) raw_get(Keys&&... keys) const { + static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match"); + constexpr static bool global = (meta::count_for_to_pack_v < 1, is_raw_get_direct_tableless, meta::unqualified_t<Keys>... >> 0); + auto pp = stack::push_pop<global>(*this); + int table_index = pp.index_of(*this); + return tuple_get<true, Ret...>(table_index, std::forward<Keys>(keys)...); + } + + template <typename T, typename Key> + decltype(auto) raw_get_or(Key&& key, T&& otherwise) const { + typedef decltype(raw_get<T>("")) U; + optional<U> option = raw_get<optional<U>>(std::forward<Key>(key)); + if (option) { + return static_cast<U>(option.value()); + } + return static_cast<U>(std::forward<T>(otherwise)); + } + + template <typename T, typename Key, typename D> + decltype(auto) raw_get_or(Key&& key, D&& otherwise) const { + optional<T> option = raw_get<optional<T>>(std::forward<Key>(key)); + if (option) { + return static_cast<T>(option.value()); + } + return static_cast<T>(std::forward<D>(otherwise)); + } + + template <typename T, typename... Keys> + decltype(auto) traverse_raw_get(Keys&&... keys) const { + constexpr static bool global = (meta::count_for_to_pack_v < 1, is_raw_get_direct_tableless, meta::unqualified_t<Keys>... >> 0); + auto pp = stack::push_pop<global>(*this); + int table_index = pp.index_of(*this); + return traverse_get_single<true, T>(table_index, std::forward<Keys>(keys)...); + } + + template <typename... Keys> + basic_table_core& traverse_raw_set(Keys&&... keys) { + constexpr static bool global = (meta::count_for_to_pack_v < 1, is_raw_set_direct_tableless, meta::unqualified_t<Keys>... >> 0); + auto pp = stack::push_pop<global>(*this); + lua_State* L = base_t::lua_state(); + auto pn = stack::pop_n(L, static_cast<int>(sizeof...(Keys) - 2 - meta::count_for_pack_v<detail::is_insert_mode, meta::unqualified_t<Keys>...>)); + traverse_set_deep<top_level, true, false>(std::forward<Keys>(keys)...); + return *this; + } + + template <typename... Args> + basic_table_core& raw_set(Args&&... args) { + tuple_set<true>(std::make_index_sequence<sizeof...(Args) / 2>(), std::forward_as_tuple(std::forward<Args>(args)...)); + return *this; + } + + template <typename Class, typename Key> + usertype<Class> new_usertype(Key&& key); + + template <typename Class, typename Key, automagic_flags enrollment_flags> + usertype<Class> new_usertype(Key&& key, constant_automagic_enrollments<enrollment_flags> enrollment); + + template <typename Class, typename Key> + usertype<Class> new_usertype(Key&& key, automagic_enrollments enrollment); + + template <typename Class, typename Key, typename Arg, typename... Args, + typename = std::enable_if_t<!std::is_base_of_v<automagic_enrollments, meta::unqualified_t<Arg>>>> + usertype<Class> new_usertype(Key&& key, Arg&& arg, Args&&... args); + + template <bool read_only = true, typename... Args> + table new_enum(const string_view& name, Args&&... args) { + table target = create_with(std::forward<Args>(args)...); + if constexpr (read_only) { + // Need to create a special iterator to handle this + table x + = create_with(meta_function::new_index, detail::fail_on_newindex, meta_function::index, target, meta_function::pairs, stack::stack_detail::readonly_pairs); + table shim = create_named(name, metatable_key, x); + return shim; + } + else { + set(name, target); + return target; + } + } + + template <typename T, bool read_only = true> + table new_enum(const string_view& name, std::initializer_list<std::pair<string_view, T>> items) { + table target = create(static_cast<int>(items.size()), static_cast<int>(0)); + for (const auto& kvp : items) { + target.set(kvp.first, kvp.second); + } + if constexpr (read_only) { + table x = create_with(meta_function::new_index, detail::fail_on_newindex, meta_function::index, target); + table shim = create_named(name, metatable_key, x); + return shim; + } + else { + set(name, target); + return target; + } + } + + template <typename Key = object, typename Value = object, typename Fx> + void for_each(Fx&& fx) const { + lua_State* L = base_t::lua_state(); + if constexpr (std::is_invocable_v<Fx, Key, Value>) { + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + stack::push(L, lua_nil); + while (lua_next(L, table_index)) { + Key key(L, -2); + Value value(L, -1); + auto pn = stack::pop_n(L, 1); + fx(key, value); + } + } + else { + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + stack::push(L, lua_nil); + while (lua_next(L, table_index)) { + Key key(L, -2); + Value value(L, -1); + auto pn = stack::pop_n(L, 1); + std::pair<Key&, Value&> keyvalue(key, value); + fx(keyvalue); + } + } + } + + size_t size() const { + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + lua_State* L = base_t::lua_state(); + lua_len(L, table_index); + return stack::pop<size_t>(L); + } + + bool empty() const { + return cbegin() == cend(); + } + + template <typename T> + auto operator[](T&& key) & { + return table_proxy<basic_table_core&, detail::proxy_key_t<T>>(*this, std::forward<T>(key)); + } + + template <typename T> + auto operator[](T&& key) const& { + return table_proxy<const basic_table_core&, detail::proxy_key_t<T>>(*this, std::forward<T>(key)); + } + + template <typename T> + auto operator[](T&& key) && { + return table_proxy<basic_table_core, detail::proxy_key_t<T>>(std::move(*this), std::forward<T>(key)); + } + + template <typename Sig, typename Key, typename... Args> + basic_table_core& set_function(Key&& key, Args&&... args) { + set_fx(types<Sig>(), std::forward<Key>(key), std::forward<Args>(args)...); + return *this; + } + + template <typename Key, typename... Args> + basic_table_core& set_function(Key&& key, Args&&... args) { + set_fx(types<>(), std::forward<Key>(key), std::forward<Args>(args)...); + return *this; + } + + template <typename... Args> + basic_table_core& add(Args&&... args) { + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + lua_State* L = base_t::lua_state(); + (void)detail::swallow { 0, (stack::stack_detail::raw_table_set(L, std::forward<Args>(args), table_index), 0)... }; + return *this; + } + + private: + template <typename R, typename... Args, typename Fx, typename Key, typename = std::invoke_result_t<Fx, Args...>> + void set_fx(types<R(Args...)>, Key&& key, Fx&& fx) { + set_resolved_function<R(Args...)>(std::forward<Key>(key), std::forward<Fx>(fx)); + } + + template <typename Fx, typename Key, meta::enable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler> + void set_fx(types<>, Key&& key, Fx&& fx) { + set(std::forward<Key>(key), std::forward<Fx>(fx)); + } + + template <typename Fx, typename Key, typename... Args, + meta::disable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler> + void set_fx(types<>, Key&& key, Fx&& fx, Args&&... args) { + set(std::forward<Key>(key), as_function_reference(std::forward<Fx>(fx), std::forward<Args>(args)...)); + } + + template <typename... Sig, typename... Args, typename Key> + void set_resolved_function(Key&& key, Args&&... args) { + set(std::forward<Key>(key), as_function_reference<function_sig<Sig...>>(std::forward<Args>(args)...)); + } + + public: + static inline table create(lua_State* L, int narr = 0, int nrec = 0) { + lua_createtable(L, narr, nrec); + table result(L); + lua_pop(L, 1); + return result; + } + + template <typename Key, typename Value, typename... Args> + static inline table create(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { + lua_createtable(L, narr, nrec); + table result(L); + result.set(std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...); + lua_pop(L, 1); + return result; + } + + template <typename... Args> + static inline table create_with(lua_State* L, Args&&... args) { + static_assert(sizeof...(Args) % 2 == 0, "You must have an even number of arguments for a key, value ... list."); + constexpr int narr = static_cast<int>(meta::count_odd_for_pack_v<std::is_integral, Args...>); + return create(L, narr, static_cast<int>((sizeof...(Args) / 2) - narr), std::forward<Args>(args)...); + } + + table create(int narr = 0, int nrec = 0) { + return create(base_t::lua_state(), narr, nrec); + } + + template <typename Key, typename Value, typename... Args> + table create(int narr, int nrec, Key&& key, Value&& value, Args&&... args) { + return create(base_t::lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...); + } + + template <typename Name> + table create(Name&& name, int narr = 0, int nrec = 0) { + table x = create(base_t::lua_state(), narr, nrec); + this->set(std::forward<Name>(name), x); + return x; + } + + template <typename Name, typename Key, typename Value, typename... Args> + table create(Name&& name, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { + table x = create(base_t::lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...); + this->set(std::forward<Name>(name), x); + return x; + } + + template <typename... Args> + table create_with(Args&&... args) { + return create_with(base_t::lua_state(), std::forward<Args>(args)...); + } + + template <typename Name, typename... Args> + table create_named(Name&& name, Args&&... args) { + static const int narr = static_cast<int>(meta::count_even_for_pack_v<std::is_integral, Args...>); + return create(std::forward<Name>(name), narr, (sizeof...(Args) / 2) - narr, std::forward<Args>(args)...); + } + }; +} // namespace sol + +// end of sol/table_core.hpp + +namespace sol { + + template <typename base_type> + class basic_metatable : public basic_table<base_type> { + typedef basic_table<base_type> base_t; + friend class state; + friend class state_view; + + protected: + basic_metatable(detail::no_safety_tag, lua_nil_t n) : base_t(n) { + } + basic_metatable(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) { + } + basic_metatable(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) { + } + template <typename T, + meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_metatable>>, meta::neg<std::is_same<base_type, stack_reference>>, + meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_metatable(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward<T>(r)) { + } + template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_metatable(detail::no_safety_tag, lua_State* L, T&& r) noexcept : base_t(L, std::forward<T>(r)) { + } + + template <typename R, typename... Args, typename Fx, typename Key, typename = std::invoke_result_t<Fx, Args...>> + void set_fx(types<R(Args...)>, Key&& key, Fx&& fx) { + set_resolved_function<R(Args...)>(std::forward<Key>(key), std::forward<Fx>(fx)); + } + + template <typename Fx, typename Key, meta::enable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler> + void set_fx(types<>, Key&& key, Fx&& fx) { + set(std::forward<Key>(key), std::forward<Fx>(fx)); + } + + template <typename Fx, typename Key, typename... Args, + meta::disable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler> + void set_fx(types<>, Key&& key, Fx&& fx, Args&&... args) { + set(std::forward<Key>(key), as_function_reference(std::forward<Fx>(fx), std::forward<Args>(args)...)); + } + + template <typename... Sig, typename... Args, typename Key> + void set_resolved_function(Key&& key, Args&&... args) { + set(std::forward<Key>(key), as_function_reference<function_sig<Sig...>>(std::forward<Args>(args)...)); + } + + public: + using base_t::lua_state; + + basic_metatable() noexcept = default; + basic_metatable(const basic_metatable&) = default; + basic_metatable(basic_metatable&&) = default; + basic_metatable& operator=(const basic_metatable&) = default; + basic_metatable& operator=(basic_metatable&&) = default; + basic_metatable(const stack_reference& r) : basic_metatable(r.lua_state(), r.stack_index()) { + } + basic_metatable(stack_reference&& r) : basic_metatable(r.lua_state(), r.stack_index()) { + } + template <typename T, meta::enable_any<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_metatable(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_metatable>(lua_state(), -1, handler); +#endif // Safety + } + basic_metatable(lua_State* L, int index = -1) : basic_metatable(detail::no_safety, L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_metatable>(L, index, handler); +#endif // Safety + } + basic_metatable(lua_State* L, ref_index index) : basic_metatable(detail::no_safety, L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_metatable>(lua_state(), -1, handler); +#endif // Safety + } + template <typename T, + meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_metatable>>, meta::neg<std::is_same<base_type, stack_reference>>, + meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_metatable(T&& r) noexcept : basic_metatable(detail::no_safety, std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + if (!is_table<meta::unqualified_t<T>>::value) { + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_metatable>(base_t::lua_state(), -1, handler); + } +#endif // Safety + } + basic_metatable(lua_nil_t r) noexcept : basic_metatable(detail::no_safety, r) { + } + + template <typename Key, typename Value> + basic_metatable<base_type>& set(Key&& key, Value&& value); + + template <typename Sig, typename Key, typename... Args> + basic_metatable& set_function(Key&& key, Args&&... args) { + set_fx(types<Sig>(), std::forward<Key>(key), std::forward<Args>(args)...); + return *this; + } + + template <typename Key, typename... Args> + basic_metatable& set_function(Key&& key, Args&&... args) { + set_fx(types<>(), std::forward<Key>(key), std::forward<Args>(args)...); + return *this; + } + + void unregister() { + using ustorage_base = u_detail::usertype_storage_base; + + lua_State* L = this->lua_state(); + + auto pp = stack::push_pop(*this); + int top = lua_gettop(L); + + stack_reference mt(L, -1); + stack::get_field(L, meta_function::gc_names, mt.stack_index()); + if (type_of(L, -1) != type::table) { + lua_settop(L, top); + return; + } + stack_reference gc_names_table(L, -1); + stack::get_field(L, meta_function::storage, mt.stack_index()); + if (type_of(L, -1) != type::lightuserdata) { + lua_settop(L, top); + return; + } + ustorage_base& base_storage = *static_cast<ustorage_base*>(stack::get<void*>(L, -1)); + std::array<string_view, 6> registry_traits; + for (std::size_t i = 0; i < registry_traits.size(); ++i) { + u_detail::submetatable_type smt = static_cast<u_detail::submetatable_type>(i); + stack::get_field<false, true>(L, smt, gc_names_table.stack_index()); + registry_traits[i] = stack::get<string_view>(L, -1); + } + + // get the registry + stack_reference registry(L, raw_index(LUA_REGISTRYINDEX)); + registry.push(); + // eliminate all named entries for this usertype + // in the registry (luaL_newmetatable does + // [name] = new table + // in registry upon creation) + for (std::size_t i = 0; i < registry_traits.size(); ++i) { + u_detail::submetatable_type smt = static_cast<u_detail::submetatable_type>(i); + const string_view& gcmetakey = registry_traits[i]; + if (smt == u_detail::submetatable_type::named) { + // use .data() to make it treat it like a c string, + // which it is... + stack::set_field<true>(L, gcmetakey.data(), lua_nil); + } + else { + // do not change the values in the registry: they need to be present + // no matter what, for safety's sake + // stack::set_field(L, gcmetakey, lua_nil, registry.stack_index()); + } + } + + // destroy all storage and tables + base_storage.clear(); + + // 6 strings from gc_names table, + // + 1 registry, + // + 1 gc_names table + // + 1 light userdata of storage + // + 1 registry + // 10 total, 4 left since popping off 6 gc_names tables + lua_settop(L, top); + } + }; + +} // namespace sol + +// end of sol/metatable.hpp + +namespace sol { + + template <typename T, typename base_type> + class basic_usertype : private basic_metatable<base_type> { + private: + using base_t = basic_metatable<base_type>; + using table_base_t = basic_table<base_type>; + + template <typename> + friend class basic_metatable; + + template <bool, typename> + friend class basic_table_core; + + template <std::size_t... I, typename... Args> + void tuple_set(std::index_sequence<I...>, std::tuple<Args...>&& args) { + (void)args; + (void)detail::swallow { 0, (this->set(std::get<I * 2>(std::move(args)), std::get<I * 2 + 1>(std::move(args))), 0)... }; + } + + template <typename R, typename... Args, typename Fx, typename Key, typename = std::invoke_result_t<Fx, Args...>> + void set_fx(types<R(Args...)>, Key&& key, Fx&& fx) { + set_resolved_function<R(Args...)>(std::forward<Key>(key), std::forward<Fx>(fx)); + } + + template <typename Fx, typename Key, meta::enable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler> + void set_fx(types<>, Key&& key, Fx&& fx) { + set(std::forward<Key>(key), std::forward<Fx>(fx)); + } + + template <typename Fx, typename Key, typename... Args, + meta::disable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler> + void set_fx(types<>, Key&& key, Fx&& fx, Args&&... args) { + set(std::forward<Key>(key), as_function_reference(std::forward<Fx>(fx), std::forward<Args>(args)...)); + } + + template <typename... Sig, typename... Args, typename Key> + void set_resolved_function(Key&& key, Args&&... args) { + set(std::forward<Key>(key), as_function_reference<function_sig<Sig...>>(std::forward<Args>(args)...)); + } + + public: + using base_t::base_t; + + using base_t::get; + using base_t::lua_state; + using base_t::pop; + using base_t::push; + using base_t::traverse_get; + using base_t::traverse_set; + using base_t::unregister; + + template <typename Key, typename Value> + basic_usertype& set(Key&& key, Value&& value) { + optional<u_detail::usertype_storage<T>&> maybe_uts = u_detail::maybe_get_usertype_storage<T>(this->lua_state()); + if (maybe_uts) { + u_detail::usertype_storage<T>& uts = *maybe_uts; + uts.set(this->lua_state(), std::forward<Key>(key), std::forward<Value>(value)); + } + else { + using ValueU = meta::unqualified_t<Value>; + // cannot get metatable: try regular table set? + if constexpr (detail::is_non_factory_constructor_v<ValueU> || detail::is_policy_v<ValueU>) { + // tag constructors so we don't get destroyed by lack of info + table_base_t::set(std::forward<Key>(key), detail::tagged<T, Value>(std::forward<Value>(value))); + } + else { + table_base_t::set(std::forward<Key>(key), std::forward<Value>(value)); + } + } + return *this; + } + + template <typename Sig, typename Key, typename... Args> + basic_usertype& set_function(Key&& key, Args&&... args) { + set_fx(types<Sig>(), std::forward<Key>(key), std::forward<Args>(args)...); + return *this; + } + + template <typename Key, typename... Args> + basic_usertype& set_function(Key&& key, Args&&... args) { + set_fx(types<>(), std::forward<Key>(key), std::forward<Args>(args)...); + return *this; + } + + template <typename Key> + usertype_proxy<basic_usertype&, std::decay_t<Key>> operator[](Key&& key) { + return usertype_proxy<basic_usertype&, std::decay_t<Key>>(*this, std::forward<Key>(key)); + } + + template <typename Key> + usertype_proxy<const basic_usertype&, std::decay_t<Key>> operator[](Key&& key) const { + return usertype_proxy<const basic_usertype&, std::decay_t<Key>>(*this, std::forward<Key>(key)); + } + }; + +} // namespace sol + +// end of sol/usertype.hpp + +// beginning of sol/table.hpp + +// beginning of sol/lua_table.hpp + +namespace sol { + + template <typename ref_t> + struct basic_lua_table : basic_table_core<false, ref_t> { + private: + using base_t = basic_table_core<false, ref_t>; + + friend class state; + friend class state_view; + + public: + using base_t::lua_state; + + basic_lua_table() noexcept = default; + basic_lua_table(const basic_lua_table&) = default; + basic_lua_table(basic_lua_table&&) = default; + basic_lua_table& operator=(const basic_lua_table&) = default; + basic_lua_table& operator=(basic_lua_table&&) = default; + basic_lua_table(const stack_reference& r) : basic_lua_table(r.lua_state(), r.stack_index()) { + } + basic_lua_table(stack_reference&& r) : basic_lua_table(r.lua_state(), r.stack_index()) { + } + template <typename T, meta::enable_any<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_lua_table(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_lua_table>(lua_state(), -1, handler); +#endif // Safety + } + basic_lua_table(lua_State* L, const new_table& nt) : base_t(L, nt) { + if (!is_stack_based<meta::unqualified_t<ref_t>>::value) { + lua_pop(L, 1); + } + } + basic_lua_table(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_lua_table>(L, index, handler); +#endif // Safety + } + basic_lua_table(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_lua_table>(lua_state(), -1, handler); +#endif // Safety + } + template <typename T, + meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_lua_table>>, meta::neg<std::is_same<ref_t, stack_reference>>, + meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_lua_table(T&& r) noexcept : basic_lua_table(detail::no_safety, std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + if (!is_table<meta::unqualified_t<T>>::value) { + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_lua_table>(lua_state(), -1, handler); + } +#endif // Safety + } + basic_lua_table(lua_nil_t r) noexcept : basic_lua_table(detail::no_safety, r) { + } + }; + +} // namespace sol + +// end of sol/lua_table.hpp + +namespace sol { + typedef table_core<false> table; + + template <bool is_global, typename base_type> + template <typename Class, typename Key> + usertype<Class> basic_table_core<is_global, base_type>::new_usertype(Key&& key) { + constant_automagic_enrollments<> enrollments {}; + return this->new_usertype<Class>(std::forward<Key>(key), std::move(enrollments)); + } + + template <bool is_global, typename base_type> + template <typename Class, typename Key, automagic_flags enrollment_flags> + usertype<Class> basic_table_core<is_global, base_type>::new_usertype(Key&& key, constant_automagic_enrollments<enrollment_flags> enrollments) { + int mt_index = u_detail::register_usertype<Class, enrollment_flags>(this->lua_state(), std::move(enrollments)); + usertype<Class> mt(this->lua_state(), -mt_index); + lua_pop(this->lua_state(), 1); + set(std::forward<Key>(key), mt); + return mt; + } + + template <bool is_global, typename base_type> + template <typename Class, typename Key> + usertype<Class> basic_table_core<is_global, base_type>::new_usertype(Key&& key, automagic_enrollments enrollments) { + int mt_index = u_detail::register_usertype<Class, automagic_flags::all>(this->lua_state(), std::move(enrollments)); + usertype<Class> mt(this->lua_state(), -mt_index); + lua_pop(this->lua_state(), 1); + set(std::forward<Key>(key), mt); + return mt; + } + + template <bool is_global, typename base_type> + template <typename Class, typename Key, typename Arg, typename... Args, typename> + usertype<Class> basic_table_core<is_global, base_type>::new_usertype(Key&& key, Arg&& arg, Args&&... args) { + constexpr automagic_flags enrollment_flags = meta::any_same_v<no_construction, meta::unqualified_t<Arg>, meta::unqualified_t<Args>...> + ? clear_flags(automagic_flags::all, automagic_flags::default_constructor) + : automagic_flags::all; + constant_automagic_enrollments<enrollment_flags> enrollments; + enrollments.default_constructor = !detail::any_is_constructor_v<Arg, Args...>; + enrollments.destructor = !detail::any_is_destructor_v<Arg, Args...>; + usertype<Class> ut = this->new_usertype<Class>(std::forward<Key>(key), std::move(enrollments)); + static_assert(sizeof...(Args) % 2 == static_cast<std::size_t>(!detail::any_is_constructor_v<Arg>), + "you must pass an even number of arguments to new_usertype after first passing a constructor"); + if constexpr (detail::any_is_constructor_v<Arg>) { + ut.set(meta_function::construct, std::forward<Arg>(arg)); + ut.tuple_set(std::make_index_sequence<(sizeof...(Args)) / 2>(), std::forward_as_tuple(std::forward<Args>(args)...)); + } + else { + ut.tuple_set(std::make_index_sequence<(sizeof...(Args) + 1) / 2>(), std::forward_as_tuple(std::forward<Arg>(arg), std::forward<Args>(args)...)); + } + return ut; + } + + template <typename base_type> + template <typename Key, typename Value> + basic_metatable<base_type>& basic_metatable<base_type>::set(Key&& key, Value&& value) { + this->push(); + lua_State* L = this->lua_state(); + int target = lua_gettop(L); + optional<u_detail::usertype_storage_base&> maybe_uts = nullopt; + maybe_uts = u_detail::maybe_get_usertype_storage_base(L, target); + if (maybe_uts) { + u_detail::usertype_storage_base& uts = *maybe_uts; + uts.set(L, std::forward<Key>(key), std::forward<Value>(value)); + return *this; + } + else { + base_t::set(std::forward<Key>(key), std::forward<Value>(value)); + } + this->pop(); + return *this; + } + + namespace stack { + template <> + struct unqualified_getter<metatable_key_t> { + static metatable get(lua_State* L, int index = -1) { + if (lua_getmetatable(L, index) == 0) { + return metatable(L, ref_index(LUA_REFNIL)); + } + return metatable(L, -1); + } + }; + } // namespace stack +} // namespace sol + +// end of sol/table.hpp + +// beginning of sol/state.hpp + +// beginning of sol/state_view.hpp + +// beginning of sol/environment.hpp + +namespace sol { + + template <typename base_type> + struct basic_environment : basic_table<base_type> { + private: + typedef basic_table<base_type> base_t; + + public: + using base_t::lua_state; + + basic_environment() noexcept = default; + basic_environment(const basic_environment&) = default; + basic_environment(basic_environment&&) = default; + basic_environment& operator=(const basic_environment&) = default; + basic_environment& operator=(basic_environment&&) = default; + basic_environment(const stack_reference& r) : basic_environment(r.lua_state(), r.stack_index()) { + } + basic_environment(stack_reference&& r) : basic_environment(r.lua_state(), r.stack_index()) { + } + + basic_environment(lua_State* L, new_table nt) : base_t(L, std::move(nt)) { + } + template <bool b> + basic_environment(lua_State* L, new_table t, const basic_reference<b>& fallback) : basic_environment(L, std::move(t)) { + stack_table mt(L, new_table(0, 1)); + mt.set(meta_function::index, fallback); + this->set(metatable_key, mt); + mt.pop(); + } + + basic_environment(env_key_t, const stack_reference& extraction_target) + : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<env_key_t>(this->lua_state(), -1, handler); +#endif // Safety + lua_pop(this->lua_state(), 1); + } + template <bool b> + basic_environment(env_key_t, const basic_reference<b>& extraction_target) + : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<env_key_t>(this->lua_state(), -1, handler); +#endif // Safety + lua_pop(this->lua_state(), 1); + } + basic_environment(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_environment>(L, index, handler); +#endif // Safety + } + basic_environment(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_environment>(L, -1, handler); +#endif // Safety + } + template <typename T, + meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_environment>>, meta::neg<std::is_same<base_type, stack_reference>>, + meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_environment(T&& r) noexcept : base_t(detail::no_safety, std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + if (!is_environment<meta::unqualified_t<T>>::value) { + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_environment>(lua_state(), -1, handler); + } +#endif // Safety + } + basic_environment(lua_nil_t r) noexcept : base_t(detail::no_safety, r) { + } + + template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_environment(lua_State* L, T&& r) noexcept : base_t(detail::no_safety, L, std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + if (!is_environment<meta::unqualified_t<T>>::value) { + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_environment>(lua_state(), -1, handler); + } +#endif // Safety + } + + template <typename T> + bool set_on(const T& target) const { + lua_State* L = target.lua_state(); + auto pp = stack::push_pop(target); + int target_index = pp.index_of(target); +#if SOL_LUA_VERSION_I_ < 502 + // Use lua_setfenv + this->push(); + int success_result = lua_setfenv(L, target_index); + return success_result != 0; +#else + // If this is a C function, the environment is always placed in + // the first value, as is expected of sol2 (all upvalues have an empty name, "") + if (lua_iscfunction(L, target_index) != 0) { + const char* maybe_upvalue_name = lua_getupvalue(L, target_index, 1); + if (maybe_upvalue_name == nullptr) { + return false; + } + string_view upvalue_name(maybe_upvalue_name); + if (upvalue_name == "") { + this->push(); + const char* success = lua_setupvalue(L, target_index, 1); + if (success == nullptr) { + // left things alone on the stack, pop them off + lua_pop(L, 2); + return false; + } + lua_pop(L, 1); + return true; + } + lua_pop(L, 1); + return false; + } + else { + // Must search for the right upvalue target on index + for (int upvalue_index = 1;; ++upvalue_index) { + const char* maybe_upvalue_name = lua_getupvalue(L, target_index, upvalue_index); + if (maybe_upvalue_name == nullptr) { + break; + } + string_view upvalue_name(maybe_upvalue_name); + if (upvalue_name == "_ENV") { + lua_pop(L, 1); + this->push(); + const char* success = lua_setupvalue(L, target_index, upvalue_index); + if (success == nullptr) { + // left things alone on the stack, pop them off + lua_pop(L, 1); + break; + } + // whether or not we succeeded, we found _ENV + // so we need to break + return true; + } + lua_pop(L, 1); + } + // if we get here, + // we did not find an _ENV here... + return false; + } +#endif + } + }; + + template <typename T, typename E> + bool set_environment(const basic_environment<E>& env, const T& target) { + return env.set_on(target); + } + + template <typename E = reference, typename T> + basic_environment<E> get_environment(const T& target) { + lua_State* L = target.lua_state(); + auto pp = stack::pop_n(L, stack::push_environment_of(target)); + return basic_environment<E>(L, -1); + } + + struct this_environment { + optional<environment> env; + + this_environment() : env(nullopt) { + } + this_environment(environment e) : env(std::move(e)) { + } + this_environment(const this_environment&) = default; + this_environment(this_environment&&) = default; + this_environment& operator=(const this_environment&) = default; + this_environment& operator=(this_environment&&) = default; + + explicit operator bool() const { + return static_cast<bool>(env); + } + + operator optional<environment>&() { + return env; + } + + operator const optional<environment>&() const { + return env; + } + + operator environment&() { + return env.value(); + } + + operator const environment&() const { + return env.value(); + } + }; + + namespace stack { + template <> + struct unqualified_getter<env_key_t> { + static environment get(lua_State* L, int index, record& tracking) { + tracking.use(1); + return get_environment(stack_reference(L, raw_index(index))); + } + }; + + template <> + struct unqualified_getter<this_environment> { + static this_environment get(lua_State* L, int, record& tracking) { + tracking.use(0); + lua_Debug info; + // Level 0 means current function (this C function, which may or may not be useful for us?) + // Level 1 means next call frame up the stack. (Can be nothing if function called directly from C++ with lua_p/call) + int pre_stack_size = lua_gettop(L); + if (lua_getstack(L, 1, &info) != 1) { + if (lua_getstack(L, 0, &info) != 1) { + lua_settop(L, pre_stack_size); + return this_environment(); + } + } + if (lua_getinfo(L, "f", &info) == 0) { + lua_settop(L, pre_stack_size); + return this_environment(); + } + + stack_reference f(L, -1); + environment env(env_key, f); + if (!env.valid()) { + lua_settop(L, pre_stack_size); + return this_environment(); + } + return this_environment(std::move(env)); + } + }; + } // namespace stack +} // namespace sol + +// end of sol/environment.hpp + +// beginning of sol/load_result.hpp + +#include <cstdint> + +namespace sol { + struct load_result : public proxy_base<load_result> { + private: + lua_State* L; + int index; + int returncount; + int popcount; + load_status err; + + public: + load_result() noexcept : load_result(nullptr) {} + load_result(lua_State* Ls, int stackindex = -1, int retnum = 0, int popnum = 0, load_status lerr = load_status::ok) noexcept + : L(Ls), index(stackindex), returncount(retnum), popcount(popnum), err(lerr) { + } + + // We do not want anyone to copy these around willy-nilly + // Will likely break people, but also will probably get rid of quiet bugs that have + // been lurking. (E.g., Vanilla Lua will just quietly discard over-pops and under-pops: + // LuaJIT and other Lua engines will implode and segfault at random later times.) + load_result(const load_result&) = delete; + load_result& operator=(const load_result&) = delete; + + load_result(load_result&& o) noexcept : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), err(o.err) { + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but we will be thorough + o.L = nullptr; + o.index = 0; + o.returncount = 0; + o.popcount = 0; + o.err = load_status::syntax; + } + load_result& operator=(load_result&& o) noexcept { + L = o.L; + index = o.index; + returncount = o.returncount; + popcount = o.popcount; + err = o.err; + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but we will be thorough + o.L = nullptr; + o.index = 0; + o.returncount = 0; + o.popcount = 0; + o.err = load_status::syntax; + return *this; + } + + load_status status() const noexcept { + return err; + } + + bool valid() const noexcept { + return status() == load_status::ok; + } + + template <typename T> + T get() const { + using UT = meta::unqualified_t<T>; + if constexpr (meta::is_optional_v<UT>) { + using ValueType = typename UT::value_type; + if constexpr (std::is_same_v<ValueType, error>) { + if (valid()) { + return UT(nullopt); + } + return error(detail::direct_error, stack::get<std::string>(L, index)); + } + else { + if (!valid()) { + return UT(nullopt); + } + return stack::get<UT>(L, index); + } + } + else { + if constexpr (std::is_same_v<T, error>) { +#if SOL_IS_ON(SOL_SAFE_PROXIES) + if (valid()) { + type_panic_c_str(L, index, type_of(L, index), type::none, "expecting an error type (a string, from Lua)"); + } +#endif // Check proxy type's safety + return error(detail::direct_error, stack::get<std::string>(L, index)); + } + else { +#if SOL_IS_ON(SOL_SAFE_PROXIES) + if (!valid()) { + type_panic_c_str(L, index, type_of(L, index), type::none); + } +#endif // Check proxy type's safety + return stack::get<T>(L, index); + } + } + } + + template <typename... Ret, typename... Args> + decltype(auto) call(Args&&... args) { + return get<protected_function>().template call<Ret...>(std::forward<Args>(args)...); + } + + template <typename... Args> + decltype(auto) operator()(Args&&... args) { + return call<>(std::forward<Args>(args)...); + } + + lua_State* lua_state() const noexcept { + return L; + }; + int stack_index() const noexcept { + return index; + }; + + ~load_result() { + if (L != nullptr) { + stack::remove(L, index, popcount); + } + } + }; +} // namespace sol + +// end of sol/load_result.hpp + +// beginning of sol/state_handling.hpp + +// beginning of sol/lua_value.hpp + +namespace sol { + struct lua_value { + public: + struct arr : detail::ebco<std::initializer_list<lua_value>> { + private: + using base_t = detail::ebco<std::initializer_list<lua_value>>; + + public: + using base_t::base_t; + }; + + private: + template <typename T> + using is_reference_or_lua_value_init_list + = meta::any<meta::is_specialization_of<T, std::initializer_list>, std::is_same<T, reference>, std::is_same<T, arr>>; + + template <typename T> + using is_lua_value_single_constructible = meta::any<std::is_same<T, lua_value>, is_reference_or_lua_value_init_list<T>>; + + static lua_State*& thread_local_lua_state() { +#if SOL_IS_ON(SOL_USE_THREAD_LOCAL) + static thread_local lua_State* L = nullptr; +#else + static lua_State* L = nullptr; +#endif + return L; + } + + reference ref_value; + + public: + static void set_lua_state(lua_State* L) { + thread_local_lua_state() = L; + } + + template <typename T, meta::disable<is_reference_or_lua_value_init_list<meta::unqualified_t<T>>> = meta::enabler> + lua_value(lua_State* L_, T&& value) : lua_value(((set_lua_state(L_)), std::forward<T>(value))) { + } + + template <typename T, meta::disable<is_lua_value_single_constructible<meta::unqualified_t<T>>> = meta::enabler> + lua_value(T&& value) : ref_value(make_reference(thread_local_lua_state(), std::forward<T>(value))) { + } + + lua_value(lua_State* L_, std::initializer_list<std::pair<lua_value, lua_value>> il) + : lua_value([&L_, &il]() { + set_lua_state(L_); + return std::move(il); + }()) { + } + + lua_value(std::initializer_list<std::pair<lua_value, lua_value>> il) : ref_value(make_reference(thread_local_lua_state(), std::move(il))) { + } + + lua_value(lua_State* L_, arr il) + : lua_value([&L_, &il]() { + set_lua_state(L_); + return std::move(il); + }()) { + } + + lua_value(arr il) : ref_value(make_reference(thread_local_lua_state(), std::move(il.value()))) { + } + + lua_value(lua_State* L_, reference r) + : lua_value([&L_, &r]() { + set_lua_state(L_); + return std::move(r); + }()) { + } + + lua_value(reference r) : ref_value(std::move(r)) { + } + + lua_value(const lua_value&) noexcept = default; + lua_value(lua_value&&) = default; + lua_value& operator=(const lua_value&) = default; + lua_value& operator=(lua_value&&) = default; + + const reference& value() const& { + return ref_value; + } + + reference& value() & { + return ref_value; + } + + reference&& value() && { + return std::move(ref_value); + } + + template <typename T> + decltype(auto) as() const { + ref_value.push(); + return stack::pop<T>(ref_value.lua_state()); + } + + template <typename T> + bool is() const { + int r = ref_value.registry_index(); + if (r == LUA_REFNIL) + return meta::any_same<meta::unqualified_t<T>, lua_nil_t, nullopt_t, std::nullptr_t>::value ? true : false; + if (r == LUA_NOREF) + return false; + auto pp = stack::push_pop(ref_value); + return stack::check<T>(ref_value.lua_state(), -1, &no_panic); + } + }; + + using array_value = typename lua_value::arr; + + namespace stack { + template <> + struct unqualified_pusher<lua_value> { + static int push(lua_State* L, const lua_value& lv) { + return stack::push(L, lv.value()); + } + + static int push(lua_State* L, lua_value&& lv) { + return stack::push(L, std::move(lv).value()); + } + }; + + template <> + struct unqualified_getter<lua_value> { + static lua_value get(lua_State* L, int index, record& tracking) { + return lua_value(L, stack::get<reference>(L, index, tracking)); + } + }; + } // namespace stack +} // namespace sol + +// end of sol/lua_value.hpp + +#if SOL_IS_ON(SOL_PRINT_ERRORS) +#include <iostream> +#endif + +namespace sol { + inline void register_main_thread(lua_State* L) { +#if SOL_LUA_VERSION_I_ < 502 + if (L == nullptr) { + lua_pushnil(L); + lua_setglobal(L, detail::default_main_thread_name()); + return; + } + lua_pushthread(L); + lua_setglobal(L, detail::default_main_thread_name()); +#else + (void)L; +#endif + } + + inline int default_at_panic(lua_State* L) { +#if SOL_IS_OFF(SOL_EXCEPTIONS) + (void)L; + return -1; +#else + size_t messagesize; + const char* message = lua_tolstring(L, -1, &messagesize); + if (message) { + std::string err(message, messagesize); + lua_settop(L, 0); +#if SOL_IS_ON(SOL_PRINT_ERRORS) + std::cerr << "[sol2] An error occurred and panic has been invoked: "; + std::cerr << err; + std::cerr << std::endl; +#endif + throw error(err); + } + lua_settop(L, 0); + throw error(std::string("An unexpected error occurred and panic has been invoked")); +#endif // Printing Errors + } + + inline int default_traceback_error_handler(lua_State* L) { + std::string msg = "An unknown error has triggered the default error handler"; + optional<string_view> maybetopmsg = stack::unqualified_check_get<string_view>(L, 1, &no_panic); + if (maybetopmsg) { + const string_view& topmsg = maybetopmsg.value(); + msg.assign(topmsg.data(), topmsg.size()); + } + luaL_traceback(L, L, msg.c_str(), 1); + optional<string_view> maybetraceback = stack::unqualified_check_get<string_view>(L, -1, &no_panic); + if (maybetraceback) { + const string_view& traceback = maybetraceback.value(); + msg.assign(traceback.data(), traceback.size()); + } +#if SOL_IS_ON(SOL_PRINT_ERRORS) + // std::cerr << "[sol2] An error occurred and was caught in traceback: "; + // std::cerr << msg; + // std::cerr << std::endl; +#endif // Printing + return stack::push(L, msg); + } + + inline void set_default_state(lua_State* L, lua_CFunction panic_function = &default_at_panic, + lua_CFunction traceback_function = c_call<decltype(&default_traceback_error_handler), &default_traceback_error_handler>, + exception_handler_function exf = detail::default_exception_handler) { + lua_atpanic(L, panic_function); + protected_function::set_default_handler(object(L, in_place, traceback_function)); + set_default_exception_handler(L, exf); + register_main_thread(L); + stack::luajit_exception_handler(L); + lua_value::set_lua_state(L); + } + + inline std::size_t total_memory_used(lua_State* L) { + std::size_t kb = static_cast<std::size_t>(lua_gc(L, LUA_GCCOUNT, 0)); + kb *= 1024; + kb += static_cast<std::size_t>(lua_gc(L, LUA_GCCOUNTB, 0)); + return kb; + } + + inline protected_function_result script_pass_on_error(lua_State*, protected_function_result result) { + return result; + } + + inline protected_function_result script_throw_on_error(lua_State* L, protected_function_result result) { + type t = type_of(L, result.stack_index()); + std::string err = "sol: "; + err += to_string(result.status()); + err += " error"; +#if SOL_IS_ON(SOL_EXCEPTIONS) + std::exception_ptr eptr = std::current_exception(); + if (eptr) { + err += " with a "; + try { + std::rethrow_exception(eptr); + } + catch (const std::exception& ex) { + err += "std::exception -- "; + err.append(ex.what()); + } + catch (const std::string& message) { + err += "thrown message -- "; + err.append(message); + } + catch (const char* message) { + err += "thrown message -- "; + err.append(message); + } + catch (...) { + err.append("thrown but unknown type, cannot serialize into error message"); + } + } +#endif // serialize exception information if possible + if (t == type::string) { + err += ": "; + string_view serr = stack::unqualified_get<string_view>(L, result.stack_index()); + err.append(serr.data(), serr.size()); + } +#if SOL_IS_ON(SOL_PRINT_ERRORS) + std::cerr << "[sol2] An error occurred and has been passed to an error handler: "; + std::cerr << err; + std::cerr << std::endl; +#endif + // replacing information of stack error into pfr + int target = result.stack_index(); + if (result.pop_count() > 0) { + stack::remove(L, target, result.pop_count()); + } + stack::push(L, err); + int top = lua_gettop(L); + int towards = top - target; + if (towards != 0) { + lua_rotate(L, top, towards); + } +#if SOL_IS_OFF(SOL_EXCEPTIONS) + return result; +#else + // just throw our error + throw error(detail::direct_error, err); +#endif // If exceptions are allowed + } + + inline protected_function_result script_default_on_error(lua_State* L, protected_function_result pfr) { +#if SOL_IS_ON(SOL_DEFAULT_PASS_ON_ERROR) + return script_pass_on_error(L, std::move(pfr)); +#else + return script_throw_on_error(L, std::move(pfr)); +#endif + } + + namespace stack { + inline error get_traceback_or_errors(lua_State* L) { + int p = default_traceback_error_handler(L); + sol::error err = stack::get<sol::error>(L, -p); + lua_pop(L, p); + return err; + } + } // namespace stack +} // namespace sol + +// end of sol/state_handling.hpp + +#include <memory> +#include <cstddef> + +namespace sol { + + class state_view { + private: + lua_State* L; + table reg; + global_table global; + + optional<object> is_loaded_package(const std::string& key) { + auto loaded = reg.traverse_get<optional<object>>("_LOADED", key); + bool is53mod = loaded && !(loaded->is<bool>() && !loaded->as<bool>()); + if (is53mod) + return loaded; +#if SOL_LUA_VERSION_I_ <= 501 + auto loaded51 = global.traverse_get<optional<object>>("package", "loaded", key); + bool is51mod = loaded51 && !(loaded51->is<bool>() && !loaded51->as<bool>()); + if (is51mod) + return loaded51; +#endif + return nullopt; + } + + template <typename T> + void ensure_package(const std::string& key, T&& sr) { +#if SOL_LUA_VERSION_I_ <= 501 + auto pkg = global["package"]; + if (!pkg.valid()) { + pkg = create_table_with("loaded", create_table_with(key, sr)); + } + else { + auto ld = pkg["loaded"]; + if (!ld.valid()) { + ld = create_table_with(key, sr); + } + else { + ld[key] = sr; + } + } +#endif + auto loaded = reg["_LOADED"]; + if (!loaded.valid()) { + loaded = create_table_with(key, sr); + } + else { + loaded[key] = sr; + } + } + + template <typename Fx> + object require_core(const std::string& key, Fx&& action, bool create_global = true) { + optional<object> loaded = is_loaded_package(key); + if (loaded && loaded->valid()) + return std::move(*loaded); + int before = lua_gettop(L); + action(); + int after = lua_gettop(L); + if (before == after) { + // I mean, you were supposed to return + // something, ANYTHING, from your requires script. I guess I'll just + // but some trash in here, it's on you after that? + ensure_package(key, static_cast<void*>(L)); + return object(L, lua_nil); + } + stack_reference sr(L, -1); + if (create_global) + set(key, sr); + ensure_package(key, sr); + return stack::pop<object>(L); + } + + public: + using iterator = typename global_table::iterator; + using const_iterator = typename global_table::const_iterator; + + state_view(lua_State* Ls) : L(Ls), reg(Ls, LUA_REGISTRYINDEX), global(Ls, global_tag) { + } + + state_view(this_state Ls) : state_view(Ls.L) { + } + + lua_State* lua_state() const { + return L; + } + + template <typename... Args> + void open_libraries(Args&&... args) { + static_assert(meta::all_same<lib, meta::unqualified_t<Args>...>::value, "all types must be libraries"); + if constexpr (sizeof...(args) == 0) { + luaL_openlibs(L); + return; + } + else { + lib libraries[1 + sizeof...(args)] = { lib::count, std::forward<Args>(args)... }; + + for (auto&& library : libraries) { + switch (library) { +#if SOL_LUA_VERSION_I_ <= 501 && SOL_IS_ON(SOL_USE_LUAJIT) + case lib::coroutine: +#endif // luajit opens coroutine base stuff + case lib::base: + luaL_requiref(L, "base", luaopen_base, 1); + lua_pop(L, 1); + break; + case lib::package: + luaL_requiref(L, "package", luaopen_package, 1); + lua_pop(L, 1); + break; +#if SOL_IS_OFF(SOL_USE_LUAJIT) + case lib::coroutine: +#if SOL_LUA_VERSION_I_ > 501 + luaL_requiref(L, "coroutine", luaopen_coroutine, 1); + lua_pop(L, 1); +#endif // Lua 5.2+ only + break; +#endif // Not LuaJIT - comes builtin + case lib::string: + luaL_requiref(L, "string", luaopen_string, 1); + lua_pop(L, 1); + break; + case lib::table: + luaL_requiref(L, "table", luaopen_table, 1); + lua_pop(L, 1); + break; + case lib::math: + luaL_requiref(L, "math", luaopen_math, 1); + lua_pop(L, 1); + break; + case lib::bit32: +#if SOL_IS_ON(SOL_USE_LUAJIT) + luaL_requiref(L, "bit32", luaopen_bit, 1); + lua_pop(L, 1); +#elif SOL_IS_ON(SOL_LUA_BIT32_LIB) + luaL_requiref(L, "bit32", luaopen_bit32, 1); + lua_pop(L, 1); +#else +#endif + break; + case lib::io: + luaL_requiref(L, "io", luaopen_io, 1); + lua_pop(L, 1); + break; + case lib::os: + luaL_requiref(L, "os", luaopen_os, 1); + lua_pop(L, 1); + break; + case lib::debug: + luaL_requiref(L, "debug", luaopen_debug, 1); + lua_pop(L, 1); + break; + case lib::utf8: +#if SOL_LUA_VERSION_I_ > 502 && SOL_IS_OFF(SOL_USE_LUAJIT) + luaL_requiref(L, "utf8", luaopen_utf8, 1); + lua_pop(L, 1); +#endif // Lua 5.3+ only + break; + case lib::ffi: +#if SOL_IS_ON(SOL_USE_LUAJIT) && SOL_IS_OFF(SOL_LUAJIT_FFI_DISABLED) + luaL_requiref(L, "ffi", luaopen_ffi, 1); + lua_pop(L, 1); +#endif // LuaJIT only + break; + case lib::jit: +#if SOL_IS_ON(SOL_USE_LUAJIT) + luaL_requiref(L, "jit", luaopen_jit, 0); + lua_pop(L, 1); +#endif // LuaJIT Only + break; + case lib::count: + default: + break; + } + } + } + } + + object require(const std::string& key, lua_CFunction open_function, bool create_global = true) { + luaL_requiref(L, key.c_str(), open_function, create_global ? 1 : 0); + return stack::pop<object>(L); + } + + object require_script(const std::string& key, const string_view& code, bool create_global = true, + const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + auto action = [this, &code, &chunkname, &mode]() { stack::script(L, code, chunkname, mode); }; + return require_core(key, action, create_global); + } + + object require_file(const std::string& key, const std::string& filename, bool create_global = true, load_mode mode = load_mode::any) { + auto action = [this, &filename, &mode]() { stack::script_file(L, filename, mode); }; + return require_core(key, action, create_global); + } + + void clear_package_loaders() { + optional<table> maybe_package = this->global["package"]; + if (!maybe_package) { + // package lib wasn't opened + // open package lib + return; + } + table& package = *maybe_package; + // yay for version differences... + // one day Lua 5.1 will die a peaceful death + // and its old bones will find blissful rest + auto loaders_proxy = package +#if SOL_LUA_VERSION_I_ < 502 + ["loaders"] +#else + ["searchers"] +#endif + ; + if (!loaders_proxy.valid()) { + // nothing to clear + return; + } + // we need to create the table for loaders + // table does not exist, so create and move forward + loaders_proxy = new_table(1, 0); + } + + template <typename Fx> + void add_package_loader(Fx&& fx, bool clear_all_package_loaders = false) { + optional<table> maybe_package = this->global["package"]; + if (!maybe_package) { + // package lib wasn't opened + // open package lib + return; + } + table& package = *maybe_package; + // yay for version differences... + // one day Lua 5.1 will die a peaceful death + // and its old bones will find blissful rest + auto loaders_proxy = package +#if SOL_LUA_VERSION_I_ < 502 + ["loaders"] +#else + ["searchers"] +#endif + ; + bool make_new_table = clear_all_package_loaders || !loaders_proxy.valid(); + if (make_new_table) { + // we need to create the table for loaders + // table does not exist, so create and move forward + loaders_proxy = new_table(1, 0); + } + optional<table> maybe_loaders = loaders_proxy; + if (!maybe_loaders) { + // loaders/searches + // thing exists in package, but it + // ain't a table or a table-alike...! + return; + } + table loaders = loaders_proxy; + loaders.add(std::forward<Fx>(fx)); + } + + template <typename E> + protected_function_result do_reader(lua_Reader reader, void* data, const basic_environment<E>& env, + const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + detail::typical_chunk_name_t basechunkname = {}; + const char* chunknametarget = detail::make_chunk_name("lua_Reader", chunkname, basechunkname); + load_status x = static_cast<load_status>(lua_load(L, reader, data, chunknametarget, to_string(mode).c_str())); + if (x != load_status::ok) { + return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x)); + } + stack_aligned_protected_function pf(L, -1); + set_environment(env, pf); + return pf(); + } + + protected_function_result do_reader( + lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + detail::typical_chunk_name_t basechunkname = {}; + const char* chunknametarget = detail::make_chunk_name("lua_Reader", chunkname, basechunkname); + load_status x = static_cast<load_status>(lua_load(L, reader, data, chunknametarget, to_string(mode).c_str())); + if (x != load_status::ok) { + return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x)); + } + stack_aligned_protected_function pf(L, -1); + return pf(); + } + + template <typename E> + protected_function_result do_string(const string_view& code, const basic_environment<E>& env, + const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + detail::typical_chunk_name_t basechunkname = {}; + const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); + load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())); + if (x != load_status::ok) { + return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x)); + } + stack_aligned_protected_function pf(L, -1); + set_environment(env, pf); + return pf(); + } + + protected_function_result do_string( + const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + detail::typical_chunk_name_t basechunkname = {}; + const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); + load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())); + if (x != load_status::ok) { + return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x)); + } + stack_aligned_protected_function pf(L, -1); + return pf(); + } + + template <typename E> + protected_function_result do_file(const std::string& filename, const basic_environment<E>& env, load_mode mode = load_mode::any) { + load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); + if (x != load_status::ok) { + return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x)); + } + stack_aligned_protected_function pf(L, -1); + set_environment(env, pf); + return pf(); + } + + protected_function_result do_file(const std::string& filename, load_mode mode = load_mode::any) { + load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); + if (x != load_status::ok) { + return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x)); + } + stack_aligned_protected_function pf(L, -1); + return pf(); + } + + template <typename Fx, + meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, + meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler> + protected_function_result safe_script( + lua_Reader reader, void* data, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + protected_function_result pfr = do_reader(reader, data, chunkname, mode); + if (!pfr.valid()) { + return on_error(L, std::move(pfr)); + } + return pfr; + } + + protected_function_result safe_script( + lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + return safe_script(reader, data, script_default_on_error, chunkname, mode); + } + + template <typename Fx, + meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, + meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler> + protected_function_result safe_script( + const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + protected_function_result pfr = do_string(code, chunkname, mode); + if (!pfr.valid()) { + return on_error(L, std::move(pfr)); + } + return pfr; + } + + template <typename Fx, typename E> + protected_function_result safe_script(const string_view& code, const basic_environment<E>& env, Fx&& on_error, + const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + protected_function_result pfr = do_string(code, env, chunkname, mode); + if (!pfr.valid()) { + return on_error(L, std::move(pfr)); + } + return pfr; + } + + template <typename E> + protected_function_result safe_script(const string_view& code, const basic_environment<E>& env, + const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + return safe_script(code, env, script_default_on_error, chunkname, mode); + } + + protected_function_result safe_script( + const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + return safe_script(code, script_default_on_error, chunkname, mode); + } + + template <typename Fx, + meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, + meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler> + protected_function_result safe_script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) { + protected_function_result pfr = do_file(filename, mode); + if (!pfr.valid()) { + return on_error(L, std::move(pfr)); + } + return pfr; + } + + template <typename Fx, typename E> + protected_function_result safe_script_file( + const std::string& filename, const basic_environment<E>& env, Fx&& on_error, load_mode mode = load_mode::any) { + protected_function_result pfr = do_file(filename, env, mode); + if (!pfr.valid()) { + return on_error(L, std::move(pfr)); + } + return pfr; + } + + template <typename E> + protected_function_result safe_script_file(const std::string& filename, const basic_environment<E>& env, load_mode mode = load_mode::any) { + return safe_script_file(filename, env, script_default_on_error, mode); + } + + protected_function_result safe_script_file(const std::string& filename, load_mode mode = load_mode::any) { + return safe_script_file(filename, script_default_on_error, mode); + } + + template <typename E> + unsafe_function_result unsafe_script(lua_Reader reader, void* data, const basic_environment<E>& env, + const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + detail::typical_chunk_name_t basechunkname = {}; + const char* chunknametarget = detail::make_chunk_name("lua_Reader", chunkname, basechunkname); + int index = lua_gettop(L); + if (lua_load(L, reader, data, chunknametarget, to_string(mode).c_str())) { + lua_error(L); + } + set_environment(env, stack_reference(L, raw_index(index + 1))); + if (lua_pcall(L, 0, LUA_MULTRET, 0)) { + lua_error(L); + } + int postindex = lua_gettop(L); + int returns = postindex - index; + return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns); + } + + unsafe_function_result unsafe_script( + lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + int index = lua_gettop(L); + stack::script(L, reader, data, chunkname, mode); + int postindex = lua_gettop(L); + int returns = postindex - index; + return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns); + } + + template <typename E> + unsafe_function_result unsafe_script(const string_view& code, const basic_environment<E>& env, + const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + detail::typical_chunk_name_t basechunkname = {}; + const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); + int index = lua_gettop(L); + if (luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())) { + lua_error(L); + } + set_environment(env, stack_reference(L, raw_index(index + 1))); + if (lua_pcall(L, 0, LUA_MULTRET, 0)) { + lua_error(L); + } + int postindex = lua_gettop(L); + int returns = postindex - index; + return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns); + } + + unsafe_function_result unsafe_script( + const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + int index = lua_gettop(L); + stack::script(L, code, chunkname, mode); + int postindex = lua_gettop(L); + int returns = postindex - index; + return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns); + } + + template <typename E> + unsafe_function_result unsafe_script_file(const std::string& filename, const basic_environment<E>& env, load_mode mode = load_mode::any) { + int index = lua_gettop(L); + if (luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())) { + lua_error(L); + } + set_environment(env, stack_reference(L, raw_index(index + 1))); + if (lua_pcall(L, 0, LUA_MULTRET, 0)) { + lua_error(L); + } + int postindex = lua_gettop(L); + int returns = postindex - index; + return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns); + } + + unsafe_function_result unsafe_script_file(const std::string& filename, load_mode mode = load_mode::any) { + int index = lua_gettop(L); + stack::script_file(L, filename, mode); + int postindex = lua_gettop(L); + int returns = postindex - index; + return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns); + } + + template <typename Fx, + meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, + meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler> + protected_function_result script( + const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + return safe_script(code, std::forward<Fx>(on_error), chunkname, mode); + } + + template <typename Fx, + meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, + meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler> + protected_function_result script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) { + return safe_script_file(filename, std::forward<Fx>(on_error), mode); + } + + template <typename Fx, typename E> + protected_function_result script(const string_view& code, const basic_environment<E>& env, Fx&& on_error, + const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + return safe_script(code, env, std::forward<Fx>(on_error), chunkname, mode); + } + + template <typename Fx, typename E> + protected_function_result script_file(const std::string& filename, const basic_environment<E>& env, Fx&& on_error, load_mode mode = load_mode::any) { + return safe_script_file(filename, env, std::forward<Fx>(on_error), mode); + } + + protected_function_result script( + const string_view& code, const environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + return safe_script(code, env, script_default_on_error, chunkname, mode); + } + + protected_function_result script_file(const std::string& filename, const environment& env, load_mode mode = load_mode::any) { + return safe_script_file(filename, env, script_default_on_error, mode); + } + +#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS) + protected_function_result script( + lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + return safe_script(reader, data, chunkname, mode); + } + + protected_function_result script( + const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + return safe_script(code, chunkname, mode); + } + + protected_function_result script_file(const std::string& filename, load_mode mode = load_mode::any) { + return safe_script_file(filename, mode); + } +#else + unsafe_function_result script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + return unsafe_script(code, chunkname, mode); + } + + unsafe_function_result script_file(const std::string& filename, load_mode mode = load_mode::any) { + return unsafe_script_file(filename, mode); + } +#endif + load_result load(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + detail::typical_chunk_name_t basechunkname = {}; + const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); + load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())); + return load_result(L, absolute_index(L, -1), 1, 1, x); + } + + load_result load_buffer(const char* buff, size_t size, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + return load(string_view(buff, size), chunkname, mode); + } + + load_result load_buffer( + const std::byte* buff, size_t size, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + return load(string_view(reinterpret_cast<const char*>(buff), size), chunkname, mode); + } + + load_result load_file(const std::string& filename, load_mode mode = load_mode::any) { + load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); + return load_result(L, absolute_index(L, -1), 1, 1, x); + } + + load_result load(lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + detail::typical_chunk_name_t basechunkname = {}; + const char* chunknametarget = detail::make_chunk_name("lua_Reader", chunkname, basechunkname); + load_status x = static_cast<load_status>(lua_load(L, reader, data, chunknametarget, to_string(mode).c_str())); + return load_result(L, absolute_index(L, -1), 1, 1, x); + } + + iterator begin() const { + return global.begin(); + } + + iterator end() const { + return global.end(); + } + + const_iterator cbegin() const { + return global.cbegin(); + } + + const_iterator cend() const { + return global.cend(); + } + + global_table globals() const { + // if we return a reference + // we'll be screwed a bit + return global; + } + + global_table& globals() { + return global; + } + + table registry() const { + return reg; + } + + std::size_t memory_used() const { + return total_memory_used(lua_state()); + } + + int stack_top() const { + return stack::top(L); + } + + int stack_clear() { + int s = stack_top(); + lua_pop(L, s); + return s; + } + + bool supports_gc_mode(gc_mode mode) const noexcept { +#if SOL_LUA_VERSION_I_ >= 504 + // supports all modes + (void)mode; + return true; +#endif + return mode == gc_mode::default_value; + } + + bool is_gc_on() const { +#if SOL_LUA_VERSION_I_ >= 502 + return lua_gc(lua_state(), LUA_GCISRUNNING, 0) == 1; +#else + // You cannot turn it off in Lua 5.1 + return true; +#endif + } + + void collect_garbage() { + lua_gc(lua_state(), LUA_GCCOLLECT, 0); + } + + void collect_gc() { + collect_garbage(); + } + + bool step_gc(int step_size_kilobytes) { + // THOUGHT: std::chrono-alikes to map "kilobyte size" here...? + // Make it harder to give MB or KB to a B parameter...? + // Probably overkill for now. +#if SOL_LUA_VERSION_I_ >= 504 + // The manual implies that this function is almost always successful... + // is it?? It could depend on the GC mode... + return lua_gc(lua_state(), LUA_GCSTEP, step_size_kilobytes) != 0; +#else + return lua_gc(lua_state(), LUA_GCSTEP, step_size_kilobytes) == 1; +#endif + } + + void restart_gc() { + lua_gc(lua_state(), LUA_GCRESTART, 0); + } + + void stop_gc() { + lua_gc(lua_state(), LUA_GCSTOP, 0); + } + + // Returns the old GC mode. Check support using the supports_gc_mode function. + gc_mode change_gc_mode_incremental(int pause, int step_multiplier, int step_byte_size) { + // "What the fuck does any of this mean??" + // http://www.lua.org/manual/5.4/manual.html#2.5.1 + + // THOUGHT: std::chrono-alikes to map "byte size" here...? + // Make it harder to give MB or KB to a B parameter...? + // Probably overkill for now. +#if SOL_LUA_VERSION_I_ >= 504 + int old_mode = lua_gc(lua_state(), LUA_GCINC, pause, step_multiplier, step_byte_size); + if (old_mode == LUA_GCGEN) { + return gc_mode::generational; + } + else if (old_mode == LUA_GCINC) { + return gc_mode::incremental; + } +#else + lua_gc(lua_state(), LUA_GCSETPAUSE, pause); + lua_gc(lua_state(), LUA_GCSETSTEPMUL, step_multiplier); + (void)step_byte_size; // means nothing in older versions +#endif + return gc_mode::default_value; + } + + // Returns the old GC mode. Check support using the supports_gc_mode function. + gc_mode change_gc_mode_generational(int minor_multiplier, int major_multiplier) { +#if SOL_LUA_VERSION_I_ >= 504 + // "What does this shit mean?" + // http://www.lua.org/manual/5.4/manual.html#2.5.2 + int old_mode = lua_gc(lua_state(), LUA_GCGEN, minor_multiplier, major_multiplier); + if (old_mode == LUA_GCGEN) { + return gc_mode::generational; + } + else if (old_mode == LUA_GCINC) { + return gc_mode::incremental; + } +#else + (void)minor_multiplier; + (void)major_multiplier; +#endif + return gc_mode::default_value; + } + + operator lua_State*() const { + return lua_state(); + } + + void set_panic(lua_CFunction panic) { + lua_atpanic(lua_state(), panic); + } + + void set_exception_handler(exception_handler_function handler) { + set_default_exception_handler(lua_state(), handler); + } + + template <typename... Args, typename... Keys> + decltype(auto) get(Keys&&... keys) const { + return global.get<Args...>(std::forward<Keys>(keys)...); + } + + template <typename T, typename Key> + decltype(auto) get_or(Key&& key, T&& otherwise) const { + return global.get_or(std::forward<Key>(key), std::forward<T>(otherwise)); + } + + template <typename T, typename Key, typename D> + decltype(auto) get_or(Key&& key, D&& otherwise) const { + return global.get_or<T>(std::forward<Key>(key), std::forward<D>(otherwise)); + } + + template <typename... Args> + state_view& set(Args&&... args) { + global.set(std::forward<Args>(args)...); + return *this; + } + + template <typename T, typename... Keys> + decltype(auto) traverse_get(Keys&&... keys) const { + return global.traverse_get<T>(std::forward<Keys>(keys)...); + } + + template <typename... Args> + state_view& traverse_set(Args&&... args) { + global.traverse_set(std::forward<Args>(args)...); + return *this; + } + + template <typename Class, typename... Args> + usertype<Class> new_usertype(Args&&... args) { + return global.new_usertype<Class>(std::forward<Args>(args)...); + } + + template <bool read_only = true, typename... Args> + state_view& new_enum(const string_view& name, Args&&... args) { + global.new_enum<read_only>(name, std::forward<Args>(args)...); + return *this; + } + + template <typename T, bool read_only = true> + state_view& new_enum(const string_view& name, std::initializer_list<std::pair<string_view, T>> items) { + global.new_enum<T, read_only>(name, std::move(items)); + return *this; + } + + template <typename Fx> + void for_each(Fx&& fx) { + global.for_each(std::forward<Fx>(fx)); + } + + template <typename T> + table_proxy<global_table&, detail::proxy_key_t<T>> operator[](T&& key) { + return global[std::forward<T>(key)]; + } + + template <typename T> + table_proxy<const global_table&, detail::proxy_key_t<T>> operator[](T&& key) const { + return global[std::forward<T>(key)]; + } + + template <typename Sig, typename... Args, typename Key> + state_view& set_function(Key&& key, Args&&... args) { + global.set_function<Sig>(std::forward<Key>(key), std::forward<Args>(args)...); + return *this; + } + + template <typename... Args, typename Key> + state_view& set_function(Key&& key, Args&&... args) { + global.set_function(std::forward<Key>(key), std::forward<Args>(args)...); + return *this; + } + + template <typename Name> + table create_table(Name&& name, int narr = 0, int nrec = 0) { + return global.create(std::forward<Name>(name), narr, nrec); + } + + template <typename Name, typename Key, typename Value, typename... Args> + table create_table(Name&& name, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { + return global.create(std::forward<Name>(name), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...); + } + + template <typename Name, typename... Args> + table create_named_table(Name&& name, Args&&... args) { + table x = global.create_with(std::forward<Args>(args)...); + global.set(std::forward<Name>(name), x); + return x; + } + + table create_table(int narr = 0, int nrec = 0) { + return create_table(lua_state(), narr, nrec); + } + + template <typename Key, typename Value, typename... Args> + table create_table(int narr, int nrec, Key&& key, Value&& value, Args&&... args) { + return create_table(lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...); + } + + template <typename... Args> + table create_table_with(Args&&... args) { + return create_table_with(lua_state(), std::forward<Args>(args)...); + } + + static inline table create_table(lua_State* L, int narr = 0, int nrec = 0) { + return global_table::create(L, narr, nrec); + } + + template <typename Key, typename Value, typename... Args> + static inline table create_table(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { + return global_table::create(L, narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...); + } + + template <typename... Args> + static inline table create_table_with(lua_State* L, Args&&... args) { + return global_table::create_with(L, std::forward<Args>(args)...); + } + }; +} // namespace sol + +// end of sol/state_view.hpp + +// beginning of sol/thread.hpp + +namespace sol { + struct lua_thread_state { + lua_State* L; + + lua_thread_state(lua_State* Ls) : L(Ls) { + } + + lua_State* lua_state() const noexcept { + return L; + } + operator lua_State*() const noexcept { + return lua_state(); + } + lua_State* operator->() const noexcept { + return lua_state(); + } + }; + + namespace stack { + template <> + struct unqualified_pusher<lua_thread_state> { + int push(lua_State*, lua_thread_state lts) { + lua_pushthread(lts.L); + return 1; + } + }; + + template <> + struct unqualified_getter<lua_thread_state> { + lua_thread_state get(lua_State* L, int index, record& tracking) { + tracking.use(1); + lua_thread_state lts(lua_tothread(L, index)); + return lts; + } + }; + + template <> + struct unqualified_check_getter<lua_thread_state> { + template <typename Handler> + optional<lua_thread_state> get(lua_State* L, int index, Handler&& handler, record& tracking) { + lua_thread_state lts(lua_tothread(L, index)); + if (lts.lua_state() == nullptr) { + handler(L, index, type::thread, type_of(L, index), "value is not a valid thread type"); + return nullopt; + } + tracking.use(1); + return lts; + } + }; + } // namespace stack + + template <typename ref_t> + class basic_thread : public basic_object<ref_t> { + private: + using base_t = basic_object<ref_t>; + + public: + using base_t::lua_state; + + basic_thread() noexcept = default; + basic_thread(const basic_thread&) = default; + basic_thread(basic_thread&&) = default; + template <typename T, + meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_thread>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_thread(T&& r) : base_t(std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_thread>(lua_state(), -1, handler); +#endif // Safety + } + basic_thread(const stack_reference& r) : basic_thread(r.lua_state(), r.stack_index()) {}; + basic_thread(stack_reference&& r) : basic_thread(r.lua_state(), r.stack_index()) {}; + basic_thread& operator=(const basic_thread&) = default; + basic_thread& operator=(basic_thread&&) = default; + template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_thread(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_thread>(lua_state(), -1, handler); +#endif // Safety + } + basic_thread(lua_State* L, int index = -1) : base_t(L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_thread>(L, index, handler); +#endif // Safety + } + basic_thread(lua_State* L, ref_index index) : base_t(L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_thread>(lua_state(), -1, handler); +#endif // Safety + } + basic_thread(lua_State* L, lua_State* actualthread) : basic_thread(L, lua_thread_state { actualthread }) { + } + basic_thread(lua_State* L, this_state actualthread) : basic_thread(L, lua_thread_state { actualthread.L }) { + } + basic_thread(lua_State* L, lua_thread_state actualthread) : base_t(L, -stack::push(L, actualthread)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_thread>(lua_state(), -1, handler); +#endif // Safety + if (!is_stack_based<base_t>::value) { + lua_pop(lua_state(), 1); + } + } + + state_view state() const { + return state_view(this->thread_state()); + } + + bool is_main_thread() const { + return stack::is_main_thread(this->thread_state()); + } + + lua_State* thread_state() const { + auto pp = stack::push_pop(*this); + lua_State* lthread = lua_tothread(lua_state(), -1); + return lthread; + } + + thread_status status() const { + lua_State* lthread = thread_state(); + auto lstat = static_cast<thread_status>(lua_status(lthread)); + if (lstat == thread_status::ok) { + lua_Debug ar; + if (lua_getstack(lthread, 0, &ar) > 0) + return thread_status::ok; + else if (lua_gettop(lthread) == 0) + return thread_status::dead; + else + return thread_status::yielded; + } + return lstat; + } + + basic_thread create() { + return create(lua_state()); + } + + static basic_thread create(lua_State* L) { + lua_newthread(L); + basic_thread result(L); + if (!is_stack_based<base_t>::value) { + lua_pop(L, 1); + } + return result; + } + }; + + typedef basic_thread<reference> thread; + typedef basic_thread<stack_reference> stack_thread; +} // namespace sol + +// end of sol/thread.hpp + +namespace sol { + + class state : private std::unique_ptr<lua_State, detail::state_deleter>, public state_view { + private: + typedef std::unique_ptr<lua_State, detail::state_deleter> unique_base; + + public: + state(lua_CFunction panic = default_at_panic) : unique_base(luaL_newstate()), state_view(unique_base::get()) { + set_default_state(unique_base::get(), panic); + } + + state(lua_CFunction panic, lua_Alloc alfunc, void* alpointer = nullptr) + : unique_base(lua_newstate(alfunc, alpointer)), state_view(unique_base::get()) { + set_default_state(unique_base::get(), panic); + } + + state(const state&) = delete; + state(state&&) = default; + state& operator=(const state&) = delete; + state& operator=(state&& that) { + state_view::operator=(std::move(that)); + unique_base::operator=(std::move(that)); + return *this; + } + + using state_view::get; + + ~state() { + } + }; +} // namespace sol + +// end of sol/state.hpp + +// beginning of sol/coroutine.hpp + +namespace sol { + template <typename Reference> + class basic_coroutine : public basic_object<Reference> { + private: + using base_t = basic_object<Reference>; + using handler_t = reference; + + private: + call_status stats = call_status::yielded; + + void luacall(std::ptrdiff_t argcount, std::ptrdiff_t) { +#if SOL_LUA_VERSION_I_ >= 504 + int nresults; + stats = static_cast<call_status>(lua_resume(lua_state(), nullptr, static_cast<int>(argcount), &nresults)); +#else + stats = static_cast<call_status>(lua_resume(lua_state(), nullptr, static_cast<int>(argcount))); +#endif + } + + template <std::size_t... I, typename... Ret> + auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n) { + luacall(n, sizeof...(Ret)); + return stack::pop<std::tuple<Ret...>>(lua_state()); + } + + template <std::size_t I, typename Ret> + Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) { + luacall(n, 1); + return stack::pop<Ret>(lua_state()); + } + + template <std::size_t I> + void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) { + luacall(n, 0); + } + + protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) { + int firstreturn = 1; + luacall(n, LUA_MULTRET); + int poststacksize = lua_gettop(this->lua_state()); + int returncount = poststacksize - (firstreturn - 1); + if (error()) { + if (m_error_handler.valid()) { + string_view err = stack::get<string_view>(this->lua_state(), poststacksize); + m_error_handler.push(); + stack::push(this->lua_state(), err); + lua_call(lua_state(), 1, 1); + } + return protected_function_result(this->lua_state(), lua_absindex(this->lua_state(), -1), 1, returncount, status()); + } + return protected_function_result(this->lua_state(), firstreturn, returncount, returncount, status()); + } + + public: + using base_t::lua_state; + + basic_coroutine() = default; + template <typename T, + meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_coroutine>>, + meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<T>>>, meta::neg<std::is_same<base_t, stack_reference>>, + meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_coroutine(T&& r) noexcept + : base_t(std::forward<T>(r)), m_error_handler(detail::get_default_handler<reference, is_main_threaded<base_t>::value>(r.lua_state())) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + if (!is_function<meta::unqualified_t<T>>::value) { + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_coroutine>(lua_state(), -1, handler); + } +#endif // Safety + } + + basic_coroutine(const basic_coroutine& other) = default; + basic_coroutine& operator=(const basic_coroutine&) = default; + + basic_coroutine(basic_coroutine&& other) noexcept : base_t(std::move(other)), m_error_handler(this->lua_state(), std::move(other.m_error_handler)) { + } + + basic_coroutine& operator=(basic_coroutine&& other) noexcept { + base_t::operator=(std::move(other)); + // must change the state, since it could change on the coroutine type + m_error_handler = handler_t(this->lua_state(), std::move(other.m_error_handler)); + return *this; + } + + basic_coroutine(const basic_function<base_t>& b) noexcept + : basic_coroutine(b, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(b.lua_state())) { + } + basic_coroutine(basic_function<base_t>&& b) noexcept + : basic_coroutine(std::move(b), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(b.lua_state())) { + } + basic_coroutine(const basic_function<base_t>& b, handler_t eh) noexcept : base_t(b), m_error_handler(std::move(eh)) { + } + basic_coroutine(basic_function<base_t>&& b, handler_t eh) noexcept : base_t(std::move(b)), m_error_handler(std::move(eh)) { + } + basic_coroutine(const stack_reference& r) noexcept + : basic_coroutine(r.lua_state(), r.stack_index(), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(r.lua_state())) { + } + basic_coroutine(stack_reference&& r) noexcept + : basic_coroutine(r.lua_state(), r.stack_index(), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(r.lua_state())) { + } + basic_coroutine(const stack_reference& r, handler_t eh) noexcept : basic_coroutine(r.lua_state(), r.stack_index(), std::move(eh)) { + } + basic_coroutine(stack_reference&& r, handler_t eh) noexcept : basic_coroutine(r.lua_state(), r.stack_index(), std::move(eh)) { + } + + template <typename Super> + basic_coroutine(const proxy_base<Super>& p) + : basic_coroutine(p, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(p.lua_state())) { + } + template <typename Super> + basic_coroutine(proxy_base<Super>&& p) + : basic_coroutine(std::move(p), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(p.lua_state())) { + } + template <typename Proxy, typename HandlerReference, + meta::enable<std::is_base_of<proxy_base_tag, meta::unqualified_t<Proxy>>, + meta::neg<is_lua_index<meta::unqualified_t<HandlerReference>>>> = meta::enabler> + basic_coroutine(Proxy&& p, HandlerReference&& eh) : basic_coroutine(detail::force_cast<base_t>(p), std::forward<HandlerReference>(eh)) { + } + + template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_coroutine(lua_State* L, T&& r) noexcept + : basic_coroutine(L, std::forward<T>(r), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) { + } + template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_coroutine(lua_State* L, T&& r, handler_t eh) : base_t(L, std::forward<T>(r)), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_coroutine>(lua_state(), -1, handler); +#endif // Safety + } + + basic_coroutine(lua_nil_t n) : base_t(n), m_error_handler(n) { + } + + basic_coroutine(lua_State* L, int index = -1) + : basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) { + } + basic_coroutine(lua_State* L, int index, handler_t eh) : base_t(L, index), m_error_handler(std::move(eh)) { +#ifdef SOL_SAFE_REFERENCES + constructor_handler handler {}; + stack::check<basic_coroutine>(L, index, handler); +#endif // Safety + } + basic_coroutine(lua_State* L, absolute_index index) + : basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) { + } + basic_coroutine(lua_State* L, absolute_index index, handler_t eh) : base_t(L, index), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_coroutine>(L, index, handler); +#endif // Safety + } + basic_coroutine(lua_State* L, raw_index index) + : basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) { + } + basic_coroutine(lua_State* L, raw_index index, handler_t eh) : base_t(L, index), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_coroutine>(L, index, handler); +#endif // Safety + } + basic_coroutine(lua_State* L, ref_index index) + : basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) { + } + basic_coroutine(lua_State* L, ref_index index, handler_t eh) : base_t(L, index), m_error_handler(std::move(eh)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_coroutine>(lua_state(), -1, handler); +#endif // Safety + } + + call_status status() const noexcept { + return stats; + } + + bool error() const noexcept { + call_status cs = status(); + return cs != call_status::ok && cs != call_status::yielded; + } + + bool runnable() const noexcept { + return base_t::valid() && (status() == call_status::yielded); + } + + explicit operator bool() const noexcept { + return runnable(); + } + + template <typename... Args> + protected_function_result operator()(Args&&... args) { + return call<>(std::forward<Args>(args)...); + } + + template <typename... Ret, typename... Args> + decltype(auto) operator()(types<Ret...>, Args&&... args) { + return call<Ret...>(std::forward<Args>(args)...); + } + + template <typename... Ret, typename... Args> + decltype(auto) call(Args&&... args) { + // some users screw up coroutine.create + // and try to use it with sol::coroutine without ever calling the first resume in Lua + // this makes the stack incompatible with other kinds of stacks: protect against this + // make sure coroutines don't screw us over + base_t::push(); + int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); + return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount); + } + + private: + handler_t m_error_handler; + }; +} // namespace sol + +// end of sol/coroutine.hpp + +// beginning of sol/userdata.hpp + +namespace sol { + template <typename base_type> + class basic_userdata : public basic_table<base_type> { + private: + using base_t = basic_table<base_type>; + + public: + using base_t::lua_state; + + basic_userdata() noexcept = default; + template <typename T, + meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_userdata>>, meta::neg<std::is_same<base_t, stack_reference>>, + is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_userdata(T&& r) noexcept : base_t(std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + if (!is_userdata<meta::unqualified_t<T>>::value) { + auto pp = stack::push_pop(*this); + type_assert(lua_state(), -1, type::userdata); + } +#endif // Safety + } + basic_userdata(const basic_userdata&) = default; + basic_userdata(basic_userdata&&) = default; + basic_userdata& operator=(const basic_userdata&) = default; + basic_userdata& operator=(basic_userdata&&) = default; + basic_userdata(const stack_reference& r) : basic_userdata(r.lua_state(), r.stack_index()) { + } + basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) { + } + template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_userdata(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_userdata>(L, -1, handler); +#endif // Safety + } + basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_userdata>(L, index, handler); +#endif // Safety + } + basic_userdata(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_userdata>(L, -1, handler); +#endif // Safety + } + }; + + template <typename base_type> + class basic_lightuserdata : public basic_object_base<base_type> { + typedef basic_object_base<base_type> base_t; + + public: + using base_t::lua_state; + + basic_lightuserdata() noexcept = default; + template <typename T, + meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_lightuserdata>>, meta::neg<std::is_same<base_t, stack_reference>>, + is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_lightuserdata(T&& r) noexcept : base_t(std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + if (!is_lightuserdata<meta::unqualified_t<T>>::value) { + auto pp = stack::push_pop(*this); + type_assert(lua_state(), -1, type::lightuserdata); + } +#endif // Safety + } + basic_lightuserdata(const basic_lightuserdata&) = default; + basic_lightuserdata(basic_lightuserdata&&) = default; + basic_lightuserdata& operator=(const basic_lightuserdata&) = default; + basic_lightuserdata& operator=(basic_lightuserdata&&) = default; + basic_lightuserdata(const stack_reference& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) { + } + basic_lightuserdata(stack_reference&& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) { + } + template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> + basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, std::forward<T>(r)) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_lightuserdata>(lua_state(), -1, handler); +#endif // Safety + } + basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + constructor_handler handler {}; + stack::check<basic_lightuserdata>(L, index, handler); +#endif // Safety + } + basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) { +#if SOL_IS_ON(SOL_SAFE_REFERENCES) + auto pp = stack::push_pop(*this); + constructor_handler handler {}; + stack::check<basic_lightuserdata>(lua_state(), index, handler); +#endif // Safety + } + }; + +} // namespace sol + +// end of sol/userdata.hpp + +// beginning of sol/as_args.hpp + +namespace sol { + template <typename T> + struct as_args_t { + T src; + }; + + template <typename Source> + auto as_args(Source&& source) { + return as_args_t<Source> { std::forward<Source>(source) }; + } + + namespace stack { + template <typename T> + struct unqualified_pusher<as_args_t<T>> { + int push(lua_State* L, const as_args_t<T>& e) { + int p = 0; + for (const auto& i : e.src) { + p += stack::push(L, i); + } + return p; + } + }; + } // namespace stack +} // namespace sol + +// end of sol/as_args.hpp + +// beginning of sol/variadic_args.hpp + +#include <limits> +#include <iterator> + +namespace sol { + struct variadic_args { + private: + lua_State* L; + int index; + int stacktop; + + public: + typedef stack_proxy reference_type; + typedef stack_proxy value_type; + typedef stack_proxy* pointer; + typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + typedef stack_iterator<stack_proxy, false> iterator; + typedef stack_iterator<stack_proxy, true> const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + variadic_args() = default; + variadic_args(lua_State* luastate, int stackindex = -1) : L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lua_gettop(luastate)) { + } + variadic_args(lua_State* luastate, int stackindex, int lastindex) : L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lastindex) { + } + variadic_args(const variadic_args&) = default; + variadic_args& operator=(const variadic_args&) = default; + variadic_args(variadic_args&& o) : L(o.L), index(o.index), stacktop(o.stacktop) { + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but will be thorough + o.L = nullptr; + o.index = 0; + o.stacktop = 0; + } + variadic_args& operator=(variadic_args&& o) { + L = o.L; + index = o.index; + stacktop = o.stacktop; + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but will be thorough + o.L = nullptr; + o.index = 0; + o.stacktop = 0; + return *this; + } + + iterator begin() { + return iterator(L, index, stacktop + 1); + } + iterator end() { + return iterator(L, stacktop + 1, stacktop + 1); + } + const_iterator begin() const { + return const_iterator(L, index, stacktop + 1); + } + const_iterator end() const { + return const_iterator(L, stacktop + 1, stacktop + 1); + } + const_iterator cbegin() const { + return begin(); + } + const_iterator cend() const { + return end(); + } + + reverse_iterator rbegin() { + return std::reverse_iterator<iterator>(begin()); + } + reverse_iterator rend() { + return std::reverse_iterator<iterator>(end()); + } + const_reverse_iterator rbegin() const { + return std::reverse_iterator<const_iterator>(begin()); + } + const_reverse_iterator rend() const { + return std::reverse_iterator<const_iterator>(end()); + } + const_reverse_iterator crbegin() const { + return std::reverse_iterator<const_iterator>(cbegin()); + } + const_reverse_iterator crend() const { + return std::reverse_iterator<const_iterator>(cend()); + } + + int push() const { + return push(L); + } + + int push(lua_State* target) const { + int pushcount = 0; + for (int i = index; i <= stacktop; ++i) { + lua_pushvalue(L, i); + pushcount += 1; + } + if (target != L) { + lua_xmove(L, target, pushcount); + } + return pushcount; + } + + template <typename T> + decltype(auto) get(difference_type index_offset = 0) const { + return stack::get<T>(L, index + static_cast<int>(index_offset)); + } + + type get_type(difference_type index_offset = 0) const noexcept { + return type_of(L, index + static_cast<int>(index_offset)); + } + + stack_proxy operator[](difference_type index_offset) const { + return stack_proxy(L, index + static_cast<int>(index_offset)); + } + + lua_State* lua_state() const { + return L; + }; + int stack_index() const { + return index; + }; + int leftover_count() const { + return stacktop - (index - 1); + } + std::size_t size() const { + return static_cast<std::size_t>(leftover_count()); + } + int top() const { + return stacktop; + } + }; + + namespace stack { + template <> + struct unqualified_getter<variadic_args> { + static variadic_args get(lua_State* L, int index, record& tracking) { + tracking.last = 0; + return variadic_args(L, index); + } + }; + + template <> + struct unqualified_pusher<variadic_args> { + static int push(lua_State* L, const variadic_args& ref) { + return ref.push(L); + } + }; + } // namespace stack +} // namespace sol + +// end of sol/variadic_args.hpp + +// beginning of sol/variadic_results.hpp + +// beginning of sol/as_returns.hpp + +namespace sol { + template <typename T> + struct as_returns_t : private detail::ebco<T> { + private: + using base_t = detail::ebco<T>; + + public: + using base_t::base_t; + using base_t::value; + }; + + template <typename Source> + auto as_returns(Source&& source) { + return as_returns_t<std::decay_t<Source>> { std::forward<Source>(source) }; + } + + namespace stack { + template <typename T> + struct unqualified_pusher<as_returns_t<T>> { + int push(lua_State* L, const as_returns_t<T>& e) { + auto& src = detail::unwrap(e.value()); + int p = 0; + for (const auto& i : src) { + p += stack::push(L, i); + } + return p; + } + }; + } // namespace stack +} // namespace sol + +// end of sol/as_returns.hpp + +#include <vector> + +namespace sol { + + template <typename Al = typename std::allocator<object>> + struct basic_variadic_results : public std::vector<object, Al> { + private: + using base_t = std::vector<object, Al>; + + public: + basic_variadic_results() : base_t() { + } + + basic_variadic_results(unsafe_function_result fr) : base_t() { + this->reserve(fr.return_count()); + this->insert(this->cend(), fr.begin(), fr.end()); + } + + basic_variadic_results(protected_function_result fr) : base_t() { + this->reserve(fr.return_count()); + this->insert(this->cend(), fr.begin(), fr.end()); + } + + template <typename Arg0, typename... Args, + meta::disable_any<std::is_same<meta::unqualified_t<Arg0>, basic_variadic_results>, std::is_same<meta::unqualified_t<Arg0>, function_result>, + std::is_same<meta::unqualified_t<Arg0>, protected_function_result>> = meta::enabler> + basic_variadic_results(Arg0&& arg0, Args&&... args) : base_t(std::forward<Arg0>(arg0), std::forward<Args>(args)...) { + } + + basic_variadic_results(const basic_variadic_results&) = default; + basic_variadic_results(basic_variadic_results&&) = default; + }; + + struct variadic_results : public basic_variadic_results<> { + private: + using base_t = basic_variadic_results<>; + + public: + using base_t::base_t; + }; + + template <typename Al> + struct is_container<basic_variadic_results<Al>> : std::false_type { }; + + template <> + struct is_container<variadic_results> : std::false_type { }; + + namespace stack { + template <typename Al> + struct unqualified_pusher<basic_variadic_results<Al>> { + int push(lua_State* L, const basic_variadic_results<Al>& e) { + int p = 0; + for (const auto& i : e) { + p += stack::push(L, i); + } + return p; + } + }; + + template <> + struct unqualified_pusher<variadic_results> { + int push(lua_State* L, const variadic_results& r) { + using base_t = basic_variadic_results<>; + return stack::push(L, static_cast<const base_t&>(r)); + } + }; + } // namespace stack + +} // namespace sol + +// end of sol/variadic_results.hpp + +#if SOL_IS_ON(SOL_COMPILER_GCC) +#pragma GCC diagnostic pop +#elif SOL_IS_ON(SOL_COMPILER_CLANG) +#elif SOL_IS_ON(SOL_COMPILER_VCXX) +#pragma warning(pop) +#endif // g++ + +#if SOL_IS_ON(SOL_INSIDE_UNREAL_ENGINE) +#undef check +#pragma pop_macro("check") +#endif // Unreal Engine 4 Bullshit + +#endif // SOL_HPP +// end of sol/sol.hpp + +#endif // SOL_SINGLE_INCLUDE_SOL_HPP diff --git a/src/libs/3rdparty/sol2/sol2.qbs b/src/libs/3rdparty/sol2/sol2.qbs new file mode 100644 index 0000000000..fb435308f7 --- /dev/null +++ b/src/libs/3rdparty/sol2/sol2.qbs @@ -0,0 +1,17 @@ +Product { + name: "sol2" + + Group { + prefix: "include/" + files: [ + "sol/config.hpp", + "sol/forward.hpp", + "sol/sol.hpp", + ] + } + + Export { + Depends { name: "cpp" } + cpp.includePaths: project.ide_source_tree + "/src/libs/3rdparty/sol2/include" + } +} diff --git a/src/libs/3rdparty/sqlite/sqlite3.c b/src/libs/3rdparty/sqlite/sqlite3.c index 139ee46a6a..08c593e55c 100644 --- a/src/libs/3rdparty/sqlite/sqlite3.c +++ b/src/libs/3rdparty/sqlite/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.45.1. By combining all the individual C code files into this +** version 3.45.3. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -18,7 +18,7 @@ ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in -** e876e51a0ed5c5b3126f52e532044363a014. +** 8653b758870e6ef0c98d46b3ace27849054a. */ #define SQLITE_CORE 1 #define SQLITE_AMALGAMATION 1 @@ -459,9 +459,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.45.1" -#define SQLITE_VERSION_NUMBER 3045001 -#define SQLITE_SOURCE_ID "2024-01-30 16:01:20 e876e51a0ed5c5b3126f52e532044363a014bc594cfefa87ffb5b82257cc467a" +#define SQLITE_VERSION "3.45.3" +#define SQLITE_VERSION_NUMBER 3045003 +#define SQLITE_SOURCE_ID "2024-04-15 13:34:05 8653b758870e6ef0c98d46b3ace27849054af85da891eb121e9aaa537f1e8355" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -733,6 +733,8 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. ** <li> The application must not modify the SQL statement text passed into ** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. +** <li> The application must not dereference the arrays or string pointers +** passed as the 3rd and 4th callback parameters after it returns. ** </ul> */ SQLITE_API int sqlite3_exec( @@ -2454,6 +2456,22 @@ struct sqlite3_mem_methods { ** configuration setting is never used, then the default maximum is determined ** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that ** compile-time option is not set, then the default maximum is 1073741824. +** +** [[SQLITE_CONFIG_ROWID_IN_VIEW]] +** <dt>SQLITE_CONFIG_ROWID_IN_VIEW +** <dd>The SQLITE_CONFIG_ROWID_IN_VIEW option enables or disables the ability +** for VIEWs to have a ROWID. The capability can only be enabled if SQLite is +** compiled with -DSQLITE_ALLOW_ROWID_IN_VIEW, in which case the capability +** defaults to on. This configuration option queries the current setting or +** changes the setting to off or on. The argument is a pointer to an integer. +** If that integer initially holds a value of 1, then the ability for VIEWs to +** have ROWIDs is activated. If the integer initially holds zero, then the +** ability is deactivated. Any other initial value for the integer leaves the +** setting unchanged. After changes, if any, the integer is written with +** a 1 or 0, if the ability for VIEWs to have ROWIDs is on or off. If SQLite +** is compiled without -DSQLITE_ALLOW_ROWID_IN_VIEW (which is the usual and +** recommended case) then the integer is always filled with zero, regardless +** if its initial value. ** </dl> */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ @@ -2485,6 +2503,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ +#define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */ /* ** CAPI3REF: Database Connection Configuration Options @@ -15097,6 +15116,7 @@ SQLITE_PRIVATE u32 sqlite3TreeTrace; ** 0x00010000 Beginning of DELETE/INSERT/UPDATE processing ** 0x00020000 Transform DISTINCT into GROUP BY ** 0x00040000 SELECT tree dump after all code has been generated +** 0x00080000 NOT NULL strength reduction */ /* @@ -18427,6 +18447,15 @@ struct Table { #define HasRowid(X) (((X)->tabFlags & TF_WithoutRowid)==0) #define VisibleRowid(X) (((X)->tabFlags & TF_NoVisibleRowid)==0) +/* Macro is true if the SQLITE_ALLOW_ROWID_IN_VIEW (mis-)feature is +** available. By default, this macro is false +*/ +#ifndef SQLITE_ALLOW_ROWID_IN_VIEW +# define ViewCanHaveRowid 0 +#else +# define ViewCanHaveRowid (sqlite3Config.mNoVisibleRowid==0) +#endif + /* ** Each foreign key constraint is an instance of the following structure. ** @@ -19346,6 +19375,7 @@ struct NameContext { #define NC_InAggFunc 0x020000 /* True if analyzing arguments to an agg func */ #define NC_FromDDL 0x040000 /* SQL text comes from sqlite_schema */ #define NC_NoSelect 0x080000 /* Do not descend into sub-selects */ +#define NC_Where 0x100000 /* Processing WHERE clause of a SELECT */ #define NC_OrderAgg 0x8000000 /* Has an aggregate other than count/min/max */ /* @@ -19369,6 +19399,7 @@ struct Upsert { Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */ Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */ u8 isDoUpdate; /* True for DO UPDATE. False for DO NOTHING */ + u8 isDup; /* True if 2nd or later with same pUpsertIdx */ /* Above this point is the parse tree for the ON CONFLICT clauses. ** The next group of fields stores intermediate data. */ void *pToFree; /* Free memory when deleting the Upsert object */ @@ -20140,6 +20171,11 @@ struct Sqlite3Config { #ifndef SQLITE_UNTESTABLE int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ #endif +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + u32 mNoVisibleRowid; /* TF_NoVisibleRowid if the ROWID_IN_VIEW + ** feature is disabled. 0 if rowids can + ** occur in views. */ +#endif int bLocaltimeFault; /* True to fail localtime() calls */ int (*xAltLocaltime)(const void*,void*); /* Alternative localtime() routine */ int iOnceResetThreshold; /* When to reset OP_Once counters */ @@ -20595,10 +20631,13 @@ SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex*); # define EXP754 (((u64)0x7ff)<<52) # define MAN754 ((((u64)1)<<52)-1) # define IsNaN(X) (((X)&EXP754)==EXP754 && ((X)&MAN754)!=0) +# define IsOvfl(X) (((X)&EXP754)==EXP754) SQLITE_PRIVATE int sqlite3IsNaN(double); +SQLITE_PRIVATE int sqlite3IsOverflow(double); #else -# define IsNaN(X) 0 -# define sqlite3IsNaN(X) 0 +# define IsNaN(X) 0 +# define sqlite3IsNaN(X) 0 +# define sqlite3IsOVerflow(X) 0 #endif /* @@ -21444,7 +21483,7 @@ SQLITE_PRIVATE With *sqlite3WithPush(Parse*, With*, u8); SQLITE_PRIVATE Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*); SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3*,Upsert*); SQLITE_PRIVATE Upsert *sqlite3UpsertDup(sqlite3*,Upsert*); -SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*); +SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*,Upsert*); SQLITE_PRIVATE void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int); SQLITE_PRIVATE Upsert *sqlite3UpsertOfIndex(Upsert*,Index*); SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert*); @@ -21834,6 +21873,9 @@ static const char * const sqlite3azCompileOpt[] = { "ALLOW_COVERING_INDEX_SCAN=" CTIMEOPT_VAL(SQLITE_ALLOW_COVERING_INDEX_SCAN), # endif #endif +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + "ALLOW_ROWID_IN_VIEW", +#endif #ifdef SQLITE_ALLOW_URI_AUTHORITY "ALLOW_URI_AUTHORITY", #endif @@ -22854,6 +22896,9 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { #ifndef SQLITE_UNTESTABLE 0, /* xTestCallback */ #endif +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + 0, /* mNoVisibleRowid. 0 == allow rowid-in-view */ +#endif 0, /* bLocaltimeFault */ 0, /* xAltLocaltime */ 0x7ffffffe, /* iOnceResetThreshold */ @@ -31309,6 +31354,7 @@ SQLITE_API void sqlite3_str_vappendf( if( xtype==etFLOAT ){ iRound = -precision; }else if( xtype==etGENERIC ){ + if( precision==0 ) precision = 1; iRound = precision; }else{ iRound = precision+1; @@ -34640,6 +34686,19 @@ SQLITE_PRIVATE int sqlite3IsNaN(double x){ } #endif /* SQLITE_OMIT_FLOATING_POINT */ +#ifndef SQLITE_OMIT_FLOATING_POINT +/* +** Return true if the floating point value is NaN or +Inf or -Inf. +*/ +SQLITE_PRIVATE int sqlite3IsOverflow(double x){ + int rc; /* The value return */ + u64 y; + memcpy(&y,&x,sizeof(y)); + rc = IsOvfl(y); + return rc; +} +#endif /* SQLITE_OMIT_FLOATING_POINT */ + /* ** Compute a string length that is limited to what can be stored in ** lower 30 bits of a 32-bit signed integer. @@ -35199,6 +35258,9 @@ do_atof_calc: u64 s2; rr[0] = (double)s; s2 = (u64)rr[0]; +#if defined(_MSC_VER) && _MSC_VER<1700 + if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); } +#endif rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s); if( e>0 ){ while( e>=100 ){ @@ -35641,7 +35703,7 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou assert( p->n>0 ); assert( p->n<sizeof(p->zBuf) ); p->iDP = p->n + exp; - if( iRound<0 ){ + if( iRound<=0 ){ iRound = p->iDP - iRound; if( iRound==0 && p->zBuf[i+1]>='5' ){ iRound = 1; @@ -53262,6 +53324,14 @@ SQLITE_API unsigned char *sqlite3_serialize( pOut = 0; }else{ sz = sqlite3_column_int64(pStmt, 0)*szPage; + if( sz==0 ){ + sqlite3_reset(pStmt); + sqlite3_exec(db, "BEGIN IMMEDIATE; COMMIT;", 0, 0, 0); + rc = sqlite3_step(pStmt); + if( rc==SQLITE_ROW ){ + sz = sqlite3_column_int64(pStmt, 0)*szPage; + } + } if( piSize ) *piSize = sz; if( mFlags & SQLITE_SERIALIZE_NOCOPY ){ pOut = 0; @@ -63785,7 +63855,7 @@ SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){ ** This will be either the rollback journal or the WAL file. */ SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){ -#if SQLITE_OMIT_WAL +#ifdef SQLITE_OMIT_WAL return pPager->jfd; #else return pPager->pWal ? sqlite3WalFile(pPager->pWal) : pPager->jfd; @@ -77088,7 +77158,10 @@ static int fillInCell( n = nHeader + nPayload; testcase( n==3 ); testcase( n==4 ); - if( n<4 ) n = 4; + if( n<4 ){ + n = 4; + pPayload[nPayload] = 0; + } *pnSize = n; assert( nSrc<=nPayload ); testcase( nSrc<nPayload ); @@ -79534,7 +79607,10 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( if( flags & BTREE_PREFORMAT ){ rc = SQLITE_OK; szNew = p->pBt->nPreformatSize; - if( szNew<4 ) szNew = 4; + if( szNew<4 ){ + szNew = 4; + newCell[3] = 0; + } if( ISAUTOVACUUM(p->pBt) && szNew>pPage->maxLocal ){ CellInfo info; pPage->xParseCell(pPage, newCell, &info); @@ -79596,7 +79672,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( }else if( loc<0 && pPage->nCell>0 ){ assert( pPage->leaf ); idx = ++pCur->ix; - pCur->curFlags &= ~BTCF_ValidNKey; + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); }else{ assert( pPage->leaf ); } @@ -79626,7 +79702,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( */ if( pPage->nOverflow ){ assert( rc==SQLITE_OK ); - pCur->curFlags &= ~(BTCF_ValidNKey); + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); rc = balance(pCur); /* Must make sure nOverflow is reset to zero even if the balance() @@ -88379,6 +88455,23 @@ static void serialGet( pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real; } } +static int serialGet7( + const unsigned char *buf, /* Buffer to deserialize from */ + Mem *pMem /* Memory cell to write value into */ +){ + u64 x = FOUR_BYTE_UINT(buf); + u32 y = FOUR_BYTE_UINT(buf+4); + x = (x<<32) + y; + assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 ); + swapMixedEndianFloat(x); + memcpy(&pMem->u.r, &x, sizeof(x)); + if( IsNaN(x) ){ + pMem->flags = MEM_Null; + return 1; + } + pMem->flags = MEM_Real; + return 0; +} SQLITE_PRIVATE void sqlite3VdbeSerialGet( const unsigned char *buf, /* Buffer to deserialize from */ u32 serial_type, /* Serial type to deserialize */ @@ -89058,7 +89151,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( }else if( serial_type==0 ){ rc = -1; }else if( serial_type==7 ){ - sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); + serialGet7(&aKey1[d1], &mem1); rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r); }else{ i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]); @@ -89083,14 +89176,18 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( }else if( serial_type==0 ){ rc = -1; }else{ - sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); if( serial_type==7 ){ - if( mem1.u.r<pRhs->u.r ){ + if( serialGet7(&aKey1[d1], &mem1) ){ + rc = -1; /* mem1 is a NaN */ + }else if( mem1.u.r<pRhs->u.r ){ rc = -1; }else if( mem1.u.r>pRhs->u.r ){ rc = +1; + }else{ + assert( rc==0 ); } }else{ + sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r); } } @@ -89160,7 +89257,14 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( /* RHS is null */ else{ serial_type = aKey1[idx1]; - rc = (serial_type!=0 && serial_type!=10); + if( serial_type==0 + || serial_type==10 + || (serial_type==7 && serialGet7(&aKey1[d1], &mem1)!=0) + ){ + assert( rc==0 ); + }else{ + rc = 1; + } } if( rc!=0 ){ @@ -94858,7 +94962,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ } } }else if( affinity==SQLITE_AFF_TEXT && ((flags1 | flags3) & MEM_Str)!=0 ){ - if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ + if( (flags1 & MEM_Str)!=0 ){ + pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal); + }else if( (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn1->flags & MEM_Int ); testcase( pIn1->flags & MEM_Real ); testcase( pIn1->flags & MEM_IntReal ); @@ -94867,7 +94973,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask); if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str; } - if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ + if( (flags3 & MEM_Str)!=0 ){ + pIn3->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal); + }else if( (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn3->flags & MEM_Int ); testcase( pIn3->flags & MEM_Real ); testcase( pIn3->flags & MEM_IntReal ); @@ -106212,6 +106320,8 @@ static void resolveAlias( assert( iCol>=0 && iCol<pEList->nExpr ); pOrig = pEList->a[iCol].pExpr; assert( pOrig!=0 ); + assert( !ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) ); + if( pExpr->pAggInfo ) return; db = pParse->db; pDup = sqlite3ExprDup(db, pOrig, 0); if( db->mallocFailed ){ @@ -106599,8 +106709,37 @@ static int lookupName( } } if( 0==cnt && VisibleRowid(pTab) ){ + /* pTab is a potential ROWID match. Keep track of it and match + ** the ROWID later if that seems appropriate. (Search for "cntTab" + ** to find related code.) Only allow a ROWID match if there is + ** a single ROWID match candidate. + */ +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + /* In SQLITE_ALLOW_ROWID_IN_VIEW mode, allow a ROWID match + ** if there is a single VIEW candidate or if there is a single + ** non-VIEW candidate plus multiple VIEW candidates. In other + ** words non-VIEW candidate terms take precedence over VIEWs. + */ + if( cntTab==0 + || (cntTab==1 + && ALWAYS(pMatch!=0) + && ALWAYS(pMatch->pTab!=0) + && (pMatch->pTab->tabFlags & TF_Ephemeral)!=0 + && (pTab->tabFlags & TF_Ephemeral)==0) + ){ + cntTab = 1; + pMatch = pItem; + }else{ + cntTab++; + } +#else + /* The (much more common) non-SQLITE_ALLOW_ROWID_IN_VIEW case is + ** simpler since we require exactly one candidate, which will + ** always be a non-VIEW + */ cntTab++; pMatch = pItem; +#endif } } if( pMatch ){ @@ -106726,13 +106865,13 @@ static int lookupName( ** Perhaps the name is a reference to the ROWID */ if( cnt==0 - && cntTab==1 + && cntTab>=1 && pMatch && (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0 && sqlite3IsRowid(zCol) && ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom) ){ - cnt = 1; + cnt = cntTab; if( pMatch->fg.isNestedFrom==0 ) pExpr->iColumn = -1; pExpr->affExpr = SQLITE_AFF_INTEGER; } @@ -107097,6 +107236,19 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ ** resolved. This prevents "column" from being counted as having been ** referenced, which might prevent a SELECT from being erroneously ** marked as correlated. + ** + ** 2024-03-28: Beware of aggregates. A bare column of aggregated table + ** can still evaluate to NULL even though it is marked as NOT NULL. + ** Example: + ** + ** CREATE TABLE t1(a INT NOT NULL); + ** SELECT a, a IS NULL, a IS NOT NULL, count(*) FROM t1; + ** + ** The "a IS NULL" and "a IS NOT NULL" expressions cannot be optimized + ** here because at the time this case is hit, we do not yet know whether + ** or not t1 is being aggregated. We have to assume the worst and omit + ** the optimization. The only time it is safe to apply this optimization + ** is within the WHERE clause. */ case TK_NOTNULL: case TK_ISNULL: { @@ -107107,19 +107259,36 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ anRef[i] = p->nRef; } sqlite3WalkExpr(pWalker, pExpr->pLeft); - if( 0==sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){ - testcase( ExprHasProperty(pExpr, EP_OuterON) ); - assert( !ExprHasProperty(pExpr, EP_IntValue) ); - pExpr->u.iValue = (pExpr->op==TK_NOTNULL); - pExpr->flags |= EP_IntValue; - pExpr->op = TK_INTEGER; + if( IN_RENAME_OBJECT ) return WRC_Prune; + if( sqlite3ExprCanBeNull(pExpr->pLeft) ){ + /* The expression can be NULL. So the optimization does not apply */ + return WRC_Prune; + } - for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){ - p->nRef = anRef[i]; + for(i=0, p=pNC; p; p=p->pNext, i++){ + if( (p->ncFlags & NC_Where)==0 ){ + return WRC_Prune; /* Not in a WHERE clause. Unsafe to optimize. */ } - sqlite3ExprDelete(pParse->db, pExpr->pLeft); - pExpr->pLeft = 0; } + testcase( ExprHasProperty(pExpr, EP_OuterON) ); + assert( !ExprHasProperty(pExpr, EP_IntValue) ); +#if TREETRACE_ENABLED + if( sqlite3TreeTrace & 0x80000 ){ + sqlite3DebugPrintf( + "NOT NULL strength reduction converts the following to %d:\n", + pExpr->op==TK_NOTNULL + ); + sqlite3ShowExpr(pExpr); + } +#endif /* TREETRACE_ENABLED */ + pExpr->u.iValue = (pExpr->op==TK_NOTNULL); + pExpr->flags |= EP_IntValue; + pExpr->op = TK_INTEGER; + for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){ + p->nRef = anRef[i]; + } + sqlite3ExprDelete(pParse->db, pExpr->pLeft); + pExpr->pLeft = 0; return WRC_Prune; } @@ -108019,7 +108188,9 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ } if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort; } + sNC.ncFlags |= NC_Where; if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort; + sNC.ncFlags &= ~NC_Where; /* Resolve names in table-valued-function arguments */ for(i=0; i<p->pSrc->nSrc; i++){ @@ -108558,9 +108729,10 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){ assert( pExpr->x.pList->nExpr>0 ); assert( pExpr->op==TK_FUNCTION ); pExpr = pExpr->x.pList->a[0].pExpr; - }else{ - assert( pExpr->op==TK_COLLATE ); + }else if( pExpr->op==TK_COLLATE ){ pExpr = pExpr->pLeft; + }else{ + break; } } return pExpr; @@ -111079,9 +111251,12 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){ return 0; case TK_COLUMN: assert( ExprUseYTab(p) ); - return ExprHasProperty(p, EP_CanBeNull) || - NEVER(p->y.pTab==0) || /* Reference to column of index on expr */ - (p->iColumn>=0 + return ExprHasProperty(p, EP_CanBeNull) + || NEVER(p->y.pTab==0) /* Reference to column of index on expr */ +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + || (p->iColumn==XN_ROWID && IsView(p->y.pTab)) +#endif + || (p->iColumn>=0 && p->y.pTab->aCol!=0 /* Possible due to prior error */ && ALWAYS(p->iColumn<p->y.pTab->nCol) && p->y.pTab->aCol[p->iColumn].notNull==0); @@ -123572,9 +123747,12 @@ SQLITE_PRIVATE void sqlite3CreateView( ** on a view, even though views do not have rowids. The following flag ** setting fixes this problem. But the fix can be disabled by compiling ** with -DSQLITE_ALLOW_ROWID_IN_VIEW in case there are legacy apps that - ** depend upon the old buggy behavior. */ -#ifndef SQLITE_ALLOW_ROWID_IN_VIEW - p->tabFlags |= TF_NoVisibleRowid; + ** depend upon the old buggy behavior. The ability can also be toggled + ** using sqlite3_config(SQLITE_CONFIG_ROWID_IN_VIEW,...) */ +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + p->tabFlags |= sqlite3Config.mNoVisibleRowid; /* Optional. Allow by default */ +#else + p->tabFlags |= TF_NoVisibleRowid; /* Never allow rowid in view */ #endif sqlite3TwoPartName(pParse, pName1, pName2, &pName); @@ -128947,13 +129125,13 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ double r1, r2; const char *zVal; r1 = sqlite3_value_double(pValue); - sqlite3_str_appendf(pStr, "%!.15g", r1); + sqlite3_str_appendf(pStr, "%!0.15g", r1); zVal = sqlite3_str_value(pStr); if( zVal ){ sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8); if( r1!=r2 ){ sqlite3_str_reset(pStr); - sqlite3_str_appendf(pStr, "%!.20e", r1); + sqlite3_str_appendf(pStr, "%!0.20e", r1); } } break; @@ -129255,7 +129433,7 @@ static void replaceFunc( } if( zPattern[0]==0 ){ assert( sqlite3_value_type(argv[1])!=SQLITE_NULL ); - sqlite3_result_value(context, argv[0]); + sqlite3_result_text(context, (const char*)zStr, nStr, SQLITE_TRANSIENT); return; } nPattern = sqlite3_value_bytes(argv[1]); @@ -129738,7 +129916,7 @@ static void sumFinalize(sqlite3_context *context){ if( p->approx ){ if( p->ovrfl ){ sqlite3_result_error(context,"integer overflow",-1); - }else if( !sqlite3IsNaN(p->rErr) ){ + }else if( !sqlite3IsOverflow(p->rErr) ){ sqlite3_result_double(context, p->rSum+p->rErr); }else{ sqlite3_result_double(context, p->rSum); @@ -129755,7 +129933,7 @@ static void avgFinalize(sqlite3_context *context){ double r; if( p->approx ){ r = p->rSum; - if( !sqlite3IsNaN(p->rErr) ) r += p->rErr; + if( !sqlite3IsOverflow(p->rErr) ) r += p->rErr; }else{ r = (double)(p->iSum); } @@ -129769,7 +129947,7 @@ static void totalFinalize(sqlite3_context *context){ if( p ){ if( p->approx ){ r = p->rSum; - if( !sqlite3IsNaN(p->rErr) ) r += p->rErr; + if( !sqlite3IsOverflow(p->rErr) ) r += p->rErr; }else{ r = (double)(p->iSum); } @@ -133175,7 +133353,7 @@ SQLITE_PRIVATE void sqlite3Insert( pNx->iDataCur = iDataCur; pNx->iIdxCur = iIdxCur; if( pNx->pUpsertTarget ){ - if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx) ){ + if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx, pUpsert) ){ goto insert_cleanup; } } @@ -135067,7 +135245,10 @@ static int xferOptimization( } } #ifndef SQLITE_OMIT_CHECK - if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){ + if( pDest->pCheck + && (db->mDbFlags & DBFLAG_Vacuum)==0 + && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) + ){ return 0; /* Tables have different CHECK constraints. Ticket #2252 */ } #endif @@ -139474,31 +139655,7 @@ SQLITE_PRIVATE void sqlite3Pragma( int mxCol; /* Maximum non-virtual column number */ if( pObjTab && pObjTab!=pTab ) continue; - if( !IsOrdinaryTable(pTab) ){ -#ifndef SQLITE_OMIT_VIRTUALTABLE - sqlite3_vtab *pVTab; - int a1; - if( !IsVirtual(pTab) ) continue; - if( pTab->nCol<=0 ){ - const char *zMod = pTab->u.vtab.azArg[0]; - if( sqlite3HashFind(&db->aModule, zMod)==0 ) continue; - } - sqlite3ViewGetColumnNames(pParse, pTab); - if( pTab->u.vtab.p==0 ) continue; - pVTab = pTab->u.vtab.p->pVtab; - if( NEVER(pVTab==0) ) continue; - if( NEVER(pVTab->pModule==0) ) continue; - if( pVTab->pModule->iVersion<4 ) continue; - if( pVTab->pModule->xIntegrity==0 ) continue; - sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick); - pTab->nTabRef++; - sqlite3VdbeAppendP4(v, pTab, P4_TABLEREF); - a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v); - integrityCheckResultRow(v); - sqlite3VdbeJumpHere(v, a1); -#endif - continue; - } + if( !IsOrdinaryTable(pTab) ) continue; if( isQuick || HasRowid(pTab) ){ pPk = 0; r2 = 0; @@ -139633,6 +139790,7 @@ SQLITE_PRIVATE void sqlite3Pragma( ** is REAL, we have to load the actual data using OP_Column ** to reliably determine if the value is a NULL. */ sqlite3VdbeAddOp3(v, OP_Column, p1, p3, 3); + sqlite3ColumnDefault(v, pTab, j, 3); jmp3 = sqlite3VdbeAddOp2(v, OP_NotNull, 3, labelOk); VdbeCoverage(v); } @@ -139823,6 +139981,38 @@ SQLITE_PRIVATE void sqlite3Pragma( } } } + +#ifndef SQLITE_OMIT_VIRTUALTABLE + /* Second pass to invoke the xIntegrity method on all virtual + ** tables. + */ + for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ + Table *pTab = sqliteHashData(x); + sqlite3_vtab *pVTab; + int a1; + if( pObjTab && pObjTab!=pTab ) continue; + if( IsOrdinaryTable(pTab) ) continue; + if( !IsVirtual(pTab) ) continue; + if( pTab->nCol<=0 ){ + const char *zMod = pTab->u.vtab.azArg[0]; + if( sqlite3HashFind(&db->aModule, zMod)==0 ) continue; + } + sqlite3ViewGetColumnNames(pParse, pTab); + if( pTab->u.vtab.p==0 ) continue; + pVTab = pTab->u.vtab.p->pVtab; + if( NEVER(pVTab==0) ) continue; + if( NEVER(pVTab->pModule==0) ) continue; + if( pVTab->pModule->iVersion<4 ) continue; + if( pVTab->pModule->xIntegrity==0 ) continue; + sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick); + pTab->nTabRef++; + sqlite3VdbeAppendP4(v, pTab, P4_TABLEREF); + a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v); + integrityCheckResultRow(v); + sqlite3VdbeJumpHere(v, a1); + continue; + } +#endif } { static const int iLn = VDBE_OFFSET_LINENO(2); @@ -140459,7 +140649,11 @@ static int pragmaVtabBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ j = seen[0]-1; pIdxInfo->aConstraintUsage[j].argvIndex = 1; pIdxInfo->aConstraintUsage[j].omit = 1; - if( seen[1]==0 ) return SQLITE_OK; + if( seen[1]==0 ){ + pIdxInfo->estimatedCost = (double)1000; + pIdxInfo->estimatedRows = 1000; + return SQLITE_OK; + } pIdxInfo->estimatedCost = (double)20; pIdxInfo->estimatedRows = 20; j = seen[1]-1; @@ -143686,11 +143880,7 @@ static const char *columnTypeImpl( ** data for the result-set column of the sub-select. */ if( iCol<pS->pEList->nExpr -#ifdef SQLITE_ALLOW_ROWID_IN_VIEW - && iCol>=0 -#else - && ALWAYS(iCol>=0) -#endif + && (!ViewCanHaveRowid || iCol>=0) ){ /* If iCol is less than zero, then the expression requests the ** rowid of the sub-select or view. This expression is legal (see @@ -146865,6 +147055,10 @@ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){ ** ** (11) The subquery is not a VALUES clause ** +** (12) The WHERE clause is not "rowid ISNULL" or the equivalent. This +** case only comes up if SQLite is compiled using +** SQLITE_ALLOW_ROWID_IN_VIEW. +** ** Return 0 if no changes are made and non-zero if one or more WHERE clause ** terms are duplicated into the subquery. */ @@ -146975,6 +147169,18 @@ static int pushDownWhereTerms( } #endif +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + if( ViewCanHaveRowid && (pWhere->op==TK_ISNULL || pWhere->op==TK_NOTNULL) ){ + Expr *pLeft = pWhere->pLeft; + if( ALWAYS(pLeft) + && pLeft->op==TK_COLUMN + && pLeft->iColumn < 0 + ){ + return 0; /* Restriction (12) */ + } + } +#endif + if( sqlite3ExprIsSingleTableConstraint(pWhere, pSrcList, iSrc) ){ nChng++; pSubq->selFlags |= SF_PushDown; @@ -147602,12 +147808,14 @@ SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){ while( pSel->pPrior ){ pSel = pSel->pPrior; } sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol); pTab->iPKey = -1; + pTab->eTabType = TABTYP_VIEW; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); #ifndef SQLITE_ALLOW_ROWID_IN_VIEW /* The usual case - do not allow ROWID on a subquery */ pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; #else - pTab->tabFlags |= TF_Ephemeral; /* Legacy compatibility mode */ + /* Legacy compatibility mode */ + pTab->tabFlags |= TF_Ephemeral | sqlite3Config.mNoVisibleRowid; #endif return pParse->nErr ? SQLITE_ERROR : SQLITE_OK; } @@ -147875,7 +148083,7 @@ static int selectExpander(Walker *pWalker, Select *p){ pNestedFrom = pFrom->pSelect->pEList; assert( pNestedFrom!=0 ); assert( pNestedFrom->nExpr==pTab->nCol ); - assert( VisibleRowid(pTab)==0 ); + assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid ); }else{ if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ continue; @@ -147907,7 +148115,8 @@ static int selectExpander(Walker *pWalker, Select *p){ pUsing = 0; } - nAdd = pTab->nCol + (VisibleRowid(pTab) && (selFlags&SF_NestedFrom)); + nAdd = pTab->nCol; + if( VisibleRowid(pTab) && (selFlags & SF_NestedFrom)!=0 ) nAdd++; for(j=0; j<nAdd; j++){ const char *zName; struct ExprList_item *pX; /* Newly added ExprList term */ @@ -147989,7 +148198,8 @@ static int selectExpander(Walker *pWalker, Select *p){ pX = &pNew->a[pNew->nExpr-1]; assert( pX->zEName==0 ); if( (selFlags & SF_NestedFrom)!=0 && !IN_RENAME_OBJECT ){ - if( pNestedFrom ){ + if( pNestedFrom && (!ViewCanHaveRowid || j<pNestedFrom->nExpr) ){ + assert( j<pNestedFrom->nExpr ); pX->zEName = sqlite3DbStrDup(db, pNestedFrom->a[j].zEName); testcase( pX->zEName==0 ); }else{ @@ -152923,6 +153133,9 @@ SQLITE_PRIVATE void sqlite3Update( } } if( chngRowid==0 && pPk==0 ){ +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + if( isView ) sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid); +#endif sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid); } } @@ -153460,7 +153673,8 @@ SQLITE_PRIVATE Upsert *sqlite3UpsertNew( SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget( Parse *pParse, /* The parsing context */ SrcList *pTabList, /* Table into which we are inserting */ - Upsert *pUpsert /* The ON CONFLICT clauses */ + Upsert *pUpsert, /* The ON CONFLICT clauses */ + Upsert *pAll /* Complete list of all ON CONFLICT clauses */ ){ Table *pTab; /* That table into which we are inserting */ int rc; /* Result code */ @@ -153563,6 +153777,14 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget( continue; } pUpsert->pUpsertIdx = pIdx; + if( sqlite3UpsertOfIndex(pAll,pIdx)!=pUpsert ){ + /* Really this should be an error. The isDup ON CONFLICT clause will + ** never fire. But this problem was not discovered until three years + ** after multi-CONFLICT upsert was added, and so we silently ignore + ** the problem to prevent breaking applications that might actually + ** have redundant ON CONFLICT clauses. */ + pUpsert->isDup = 1; + } break; } if( pUpsert->pUpsertIdx==0 ){ @@ -153589,9 +153811,13 @@ SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert *pUpsert){ Upsert *pNext; if( NEVER(pUpsert==0) ) return 0; pNext = pUpsert->pNextUpsert; - if( pNext==0 ) return 1; - if( pNext->pUpsertTarget==0 ) return 1; - if( pNext->pUpsertIdx==0 ) return 1; + while( 1 /*exit-by-return*/ ){ + if( pNext==0 ) return 1; + if( pNext->pUpsertTarget==0 ) return 1; + if( pNext->pUpsertIdx==0 ) return 1; + if( !pNext->isDup ) return 0; + pNext = pNext->pNextUpsert; + } return 0; } @@ -166619,16 +166845,10 @@ static SQLITE_NOINLINE void whereAddIndexedExpr( for(i=0; i<pIdx->nColumn; i++){ Expr *pExpr; int j = pIdx->aiColumn[i]; - int bMaybeNullRow; if( j==XN_EXPR ){ pExpr = pIdx->aColExpr->a[i].pExpr; - testcase( pTabItem->fg.jointype & JT_LEFT ); - testcase( pTabItem->fg.jointype & JT_RIGHT ); - testcase( pTabItem->fg.jointype & JT_LTORJ ); - bMaybeNullRow = (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0; }else if( j>=0 && (pTab->aCol[j].colFlags & COLFLAG_VIRTUAL)!=0 ){ pExpr = sqlite3ColumnExpr(pTab, &pTab->aCol[j]); - bMaybeNullRow = 0; }else{ continue; } @@ -166660,7 +166880,7 @@ static SQLITE_NOINLINE void whereAddIndexedExpr( p->iDataCur = pTabItem->iCursor; p->iIdxCur = iIdxCur; p->iIdxCol = i; - p->bMaybeNullRow = bMaybeNullRow; + p->bMaybeNullRow = (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0; if( sqlite3IndexAffinityStr(pParse->db, pIdx) ){ p->aff = pIdx->zColAff[i]; } @@ -178865,6 +179085,18 @@ SQLITE_API int sqlite3_config(int op, ...){ } #endif /* SQLITE_OMIT_DESERIALIZE */ + case SQLITE_CONFIG_ROWID_IN_VIEW: { + int *pVal = va_arg(ap,int*); +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + if( 0==*pVal ) sqlite3GlobalConfig.mNoVisibleRowid = TF_NoVisibleRowid; + if( 1==*pVal ) sqlite3GlobalConfig.mNoVisibleRowid = 0; + *pVal = (sqlite3GlobalConfig.mNoVisibleRowid==0); +#else + *pVal = 0; +#endif + break; + } + default: { rc = SQLITE_ERROR; break; @@ -204785,6 +205017,7 @@ json_parse_restart: case '[': { /* Parse array */ iThis = pParse->nBlob; + assert( i<=(u32)pParse->nJson ); jsonBlobAppendNode(pParse, JSONB_ARRAY, pParse->nJson - i, 0); iStart = pParse->nBlob; if( pParse->oom ) return -1; @@ -205183,6 +205416,10 @@ static void jsonReturnStringAsBlob(JsonString *pStr){ JsonParse px; memset(&px, 0, sizeof(px)); jsonStringTerminate(pStr); + if( pStr->eErr ){ + sqlite3_result_error_nomem(pStr->pCtx); + return; + } px.zJson = pStr->zBuf; px.nJson = pStr->nUsed; px.db = sqlite3_context_db_handle(pStr->pCtx); @@ -206508,8 +206745,9 @@ rebuild_from_cache: } p->zJson = (char*)sqlite3_value_text(pArg); p->nJson = sqlite3_value_bytes(pArg); + if( db->mallocFailed ) goto json_pfa_oom; if( p->nJson==0 ) goto json_pfa_malformed; - if( NEVER(p->zJson==0) ) goto json_pfa_oom; + assert( p->zJson!=0 ); if( jsonConvertTextToBlob(p, (flgs & JSON_KEEPERROR) ? 0 : ctx) ){ if( flgs & JSON_KEEPERROR ){ p->nErr = 1; @@ -206675,10 +206913,10 @@ static void jsonDebugPrintBlob( if( sz==0 && x<=JSONB_FALSE ){ sqlite3_str_append(pOut, "\n", 1); }else{ - u32 i; + u32 j; sqlite3_str_appendall(pOut, ": \""); - for(i=iStart+n; i<iStart+n+sz; i++){ - u8 c = pParse->aBlob[i]; + for(j=iStart+n; j<iStart+n+sz; j++){ + u8 c = pParse->aBlob[j]; if( c<0x20 || c>=0x7f ) c = '.'; sqlite3_str_append(pOut, (char*)&c, 1); } @@ -208086,6 +208324,9 @@ static int jsonEachColumn( case JEACH_VALUE: { u32 i = jsonSkipLabel(p); jsonReturnFromBlob(&p->sParse, i, ctx, 1); + if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY ){ + sqlite3_result_subtype(ctx, JSON_SUBTYPE); + } break; } case JEACH_TYPE: { @@ -208132,9 +208373,9 @@ static int jsonEachColumn( case JEACH_JSON: { if( p->sParse.zJson==0 ){ sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob, - SQLITE_STATIC); + SQLITE_TRANSIENT); }else{ - sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC); + sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_TRANSIENT); } break; } @@ -209160,11 +209401,9 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){ ** Clear the Rtree.pNodeBlob object */ static void nodeBlobReset(Rtree *pRtree){ - if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){ - sqlite3_blob *pBlob = pRtree->pNodeBlob; - pRtree->pNodeBlob = 0; - sqlite3_blob_close(pBlob); - } + sqlite3_blob *pBlob = pRtree->pNodeBlob; + pRtree->pNodeBlob = 0; + sqlite3_blob_close(pBlob); } /* @@ -209208,7 +209447,6 @@ static int nodeAcquire( &pRtree->pNodeBlob); } if( rc ){ - nodeBlobReset(pRtree); *ppNode = 0; /* If unable to open an sqlite3_blob on the desired row, that can only ** be because the shadow tables hold erroneous data. */ @@ -209268,6 +209506,7 @@ static int nodeAcquire( } *ppNode = pNode; }else{ + nodeBlobReset(pRtree); if( pNode ){ pRtree->nNodeRef--; sqlite3_free(pNode); @@ -209412,6 +209651,7 @@ static void nodeGetCoord( int iCoord, /* Which coordinate to extract */ RtreeCoord *pCoord /* OUT: Space to write result to */ ){ + assert( iCell<NCELL(pNode) ); readCoord(&pNode->zData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord); } @@ -209601,7 +209841,9 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){ sqlite3_finalize(pCsr->pReadAux); sqlite3_free(pCsr); pRtree->nCursor--; - nodeBlobReset(pRtree); + if( pRtree->nCursor==0 && pRtree->inWrTrans==0 ){ + nodeBlobReset(pRtree); + } return SQLITE_OK; } @@ -210186,7 +210428,11 @@ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){ int rc = SQLITE_OK; RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); if( rc==SQLITE_OK && ALWAYS(p) ){ - *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell); + if( p->iCell>=NCELL(pNode) ){ + rc = SQLITE_ABORT; + }else{ + *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell); + } } return rc; } @@ -210204,6 +210450,7 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ if( rc ) return rc; if( NEVER(p==0) ) return SQLITE_OK; + if( p->iCell>=NCELL(pNode) ) return SQLITE_ABORT; if( i==0 ){ sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); }else if( i<=pRtree->nDim2 ){ @@ -211685,8 +211932,7 @@ constraint: */ static int rtreeBeginTransaction(sqlite3_vtab *pVtab){ Rtree *pRtree = (Rtree *)pVtab; - assert( pRtree->inWrTrans==0 ); - pRtree->inWrTrans++; + pRtree->inWrTrans = 1; return SQLITE_OK; } @@ -211700,6 +211946,9 @@ static int rtreeEndTransaction(sqlite3_vtab *pVtab){ nodeBlobReset(pRtree); return SQLITE_OK; } +static int rtreeRollback(sqlite3_vtab *pVtab){ + return rtreeEndTransaction(pVtab); +} /* ** The xRename method for rtree module virtual tables. @@ -211818,7 +212067,7 @@ static sqlite3_module rtreeModule = { rtreeBeginTransaction, /* xBegin - begin transaction */ rtreeEndTransaction, /* xSync - sync transaction */ rtreeEndTransaction, /* xCommit - commit transaction */ - rtreeEndTransaction, /* xRollback - rollback transaction */ + rtreeRollback, /* xRollback - rollback transaction */ 0, /* xFindFunction - function overloading */ rtreeRename, /* xRename - rename the table */ rtreeSavepoint, /* xSavepoint */ @@ -245377,23 +245626,26 @@ static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){ static void fts5TokendataIterNext(Fts5Iter *pIter, int bFrom, i64 iFrom){ int ii; Fts5TokenDataIter *pT = pIter->pTokenDataIter; + Fts5Index *pIndex = pIter->pIndex; for(ii=0; ii<pT->nIter; ii++){ Fts5Iter *p = pT->apIter[ii]; if( p->base.bEof==0 && (p->base.iRowid==pIter->base.iRowid || (bFrom && p->base.iRowid<iFrom)) ){ - fts5MultiIterNext(p->pIndex, p, bFrom, iFrom); + fts5MultiIterNext(pIndex, p, bFrom, iFrom); while( bFrom && p->base.bEof==0 && p->base.iRowid<iFrom - && p->pIndex->rc==SQLITE_OK + && pIndex->rc==SQLITE_OK ){ - fts5MultiIterNext(p->pIndex, p, 0, 0); + fts5MultiIterNext(pIndex, p, 0, 0); } } } - fts5IterSetOutputsTokendata(pIter); + if( pIndex->rc==SQLITE_OK ){ + fts5IterSetOutputsTokendata(pIter); + } } /* @@ -250547,7 +250799,7 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2024-01-30 16:01:20 e876e51a0ed5c5b3126f52e532044363a014bc594cfefa87ffb5b82257cc467a", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2024-04-15 13:34:05 8653b758870e6ef0c98d46b3ace27849054af85da891eb121e9aaa537f1e8355", -1, SQLITE_TRANSIENT); } /* diff --git a/src/libs/3rdparty/sqlite/sqlite3.h b/src/libs/3rdparty/sqlite/sqlite3.h index 4fdfde004e..2618b37a7b 100644 --- a/src/libs/3rdparty/sqlite/sqlite3.h +++ b/src/libs/3rdparty/sqlite/sqlite3.h @@ -146,9 +146,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.45.1" -#define SQLITE_VERSION_NUMBER 3045001 -#define SQLITE_SOURCE_ID "2024-01-30 16:01:20 e876e51a0ed5c5b3126f52e532044363a014bc594cfefa87ffb5b82257cc467a" +#define SQLITE_VERSION "3.45.3" +#define SQLITE_VERSION_NUMBER 3045003 +#define SQLITE_SOURCE_ID "2024-04-15 13:34:05 8653b758870e6ef0c98d46b3ace27849054af85da891eb121e9aaa537f1e8355" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -420,6 +420,8 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. ** <li> The application must not modify the SQL statement text passed into ** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. +** <li> The application must not dereference the arrays or string pointers +** passed as the 3rd and 4th callback parameters after it returns. ** </ul> */ SQLITE_API int sqlite3_exec( @@ -2141,6 +2143,22 @@ struct sqlite3_mem_methods { ** configuration setting is never used, then the default maximum is determined ** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that ** compile-time option is not set, then the default maximum is 1073741824. +** +** [[SQLITE_CONFIG_ROWID_IN_VIEW]] +** <dt>SQLITE_CONFIG_ROWID_IN_VIEW +** <dd>The SQLITE_CONFIG_ROWID_IN_VIEW option enables or disables the ability +** for VIEWs to have a ROWID. The capability can only be enabled if SQLite is +** compiled with -DSQLITE_ALLOW_ROWID_IN_VIEW, in which case the capability +** defaults to on. This configuration option queries the current setting or +** changes the setting to off or on. The argument is a pointer to an integer. +** If that integer initially holds a value of 1, then the ability for VIEWs to +** have ROWIDs is activated. If the integer initially holds zero, then the +** ability is deactivated. Any other initial value for the integer leaves the +** setting unchanged. After changes, if any, the integer is written with +** a 1 or 0, if the ability for VIEWs to have ROWIDs is on or off. If SQLite +** is compiled without -DSQLITE_ALLOW_ROWID_IN_VIEW (which is the usual and +** recommended case) then the integer is always filled with zero, regardless +** if its initial value. ** </dl> */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ @@ -2172,6 +2190,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ +#define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */ /* ** CAPI3REF: Database Connection Configuration Options |