aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs')
-rw-r--r--src/libs/3rdparty/CMakeLists.txt2
m---------src/libs/3rdparty/googletest0
-rw-r--r--src/libs/3rdparty/lua/CMakeLists.txt75
-rw-r--r--src/libs/3rdparty/lua/LICENSE16
-rw-r--r--src/libs/3rdparty/lua/README6
-rw-r--r--src/libs/3rdparty/lua/doc/contents.html678
-rw-r--r--src/libs/3rdparty/lua/doc/index.css21
-rw-r--r--src/libs/3rdparty/lua/doc/logo.gifbin0 -> 9893 bytes
-rw-r--r--src/libs/3rdparty/lua/doc/lua.1155
-rw-r--r--src/libs/3rdparty/lua/doc/lua.css161
-rw-r--r--src/libs/3rdparty/lua/doc/luac.1118
-rw-r--r--src/libs/3rdparty/lua/doc/manual.css21
-rw-r--r--src/libs/3rdparty/lua/doc/manual.html12046
-rw-r--r--src/libs/3rdparty/lua/doc/osi-certified-72x60.pngbin0 -> 3774 bytes
-rw-r--r--src/libs/3rdparty/lua/doc/readme.html337
-rw-r--r--src/libs/3rdparty/lua/lua.qbs81
-rw-r--r--src/libs/3rdparty/lua/src/lapi.c1463
-rw-r--r--src/libs/3rdparty/lua/src/lapi.h52
-rw-r--r--src/libs/3rdparty/lua/src/lauxlib.c1112
-rw-r--r--src/libs/3rdparty/lua/src/lauxlib.h301
-rw-r--r--src/libs/3rdparty/lua/src/lbaselib.c549
-rw-r--r--src/libs/3rdparty/lua/src/lcode.c1871
-rw-r--r--src/libs/3rdparty/lua/src/lcode.h104
-rw-r--r--src/libs/3rdparty/lua/src/lcorolib.c210
-rw-r--r--src/libs/3rdparty/lua/src/lctype.c64
-rw-r--r--src/libs/3rdparty/lua/src/lctype.h101
-rw-r--r--src/libs/3rdparty/lua/src/ldblib.c483
-rw-r--r--src/libs/3rdparty/lua/src/ldebug.c924
-rw-r--r--src/libs/3rdparty/lua/src/ldebug.h63
-rw-r--r--src/libs/3rdparty/lua/src/ldo.c1024
-rw-r--r--src/libs/3rdparty/lua/src/ldo.h88
-rw-r--r--src/libs/3rdparty/lua/src/ldump.c230
-rw-r--r--src/libs/3rdparty/lua/src/lfunc.c294
-rw-r--r--src/libs/3rdparty/lua/src/lfunc.h64
-rw-r--r--src/libs/3rdparty/lua/src/lgc.c1739
-rw-r--r--src/libs/3rdparty/lua/src/lgc.h202
-rw-r--r--src/libs/3rdparty/lua/src/linit.c65
-rw-r--r--src/libs/3rdparty/lua/src/liolib.c828
-rw-r--r--src/libs/3rdparty/lua/src/ljumptab.h112
-rw-r--r--src/libs/3rdparty/lua/src/llex.c581
-rw-r--r--src/libs/3rdparty/lua/src/llex.h91
-rw-r--r--src/libs/3rdparty/lua/src/llimits.h380
-rw-r--r--src/libs/3rdparty/lua/src/lmathlib.c764
-rw-r--r--src/libs/3rdparty/lua/src/lmem.c215
-rw-r--r--src/libs/3rdparty/lua/src/lmem.h93
-rw-r--r--src/libs/3rdparty/lua/src/loadlib.c767
-rw-r--r--src/libs/3rdparty/lua/src/lobject.c602
-rw-r--r--src/libs/3rdparty/lua/src/lobject.h815
-rw-r--r--src/libs/3rdparty/lua/src/lopcodes.c104
-rw-r--r--src/libs/3rdparty/lua/src/lopcodes.h405
-rw-r--r--src/libs/3rdparty/lua/src/lopnames.h103
-rw-r--r--src/libs/3rdparty/lua/src/loslib.c428
-rw-r--r--src/libs/3rdparty/lua/src/lparser.c1967
-rw-r--r--src/libs/3rdparty/lua/src/lparser.h171
-rw-r--r--src/libs/3rdparty/lua/src/lprefix.h45
-rw-r--r--src/libs/3rdparty/lua/src/lstate.c445
-rw-r--r--src/libs/3rdparty/lua/src/lstate.h409
-rw-r--r--src/libs/3rdparty/lua/src/lstring.c273
-rw-r--r--src/libs/3rdparty/lua/src/lstring.h57
-rw-r--r--src/libs/3rdparty/lua/src/lstrlib.c1874
-rw-r--r--src/libs/3rdparty/lua/src/ltable.c980
-rw-r--r--src/libs/3rdparty/lua/src/ltable.h65
-rw-r--r--src/libs/3rdparty/lua/src/ltablib.c430
-rw-r--r--src/libs/3rdparty/lua/src/ltm.c271
-rw-r--r--src/libs/3rdparty/lua/src/ltm.h104
-rw-r--r--src/libs/3rdparty/lua/src/lua.c679
-rw-r--r--src/libs/3rdparty/lua/src/lua.h523
-rw-r--r--src/libs/3rdparty/lua/src/lua.hpp9
-rw-r--r--src/libs/3rdparty/lua/src/luac.c723
-rw-r--r--src/libs/3rdparty/lua/src/luaconf.h793
-rw-r--r--src/libs/3rdparty/lua/src/lualib.h52
-rw-r--r--src/libs/3rdparty/lua/src/lundump.c335
-rw-r--r--src/libs/3rdparty/lua/src/lundump.h36
-rw-r--r--src/libs/3rdparty/lua/src/lutf8lib.c291
-rw-r--r--src/libs/3rdparty/lua/src/lvm.c1901
-rw-r--r--src/libs/3rdparty/lua/src/lvm.h141
-rw-r--r--src/libs/3rdparty/lua/src/lzio.c68
-rw-r--r--src/libs/3rdparty/lua/src/lzio.h66
-rw-r--r--src/libs/3rdparty/sol2/CMakeLists.txt12
-rw-r--r--src/libs/3rdparty/sol2/LICENSE.txt20
-rw-r--r--src/libs/3rdparty/sol2/include/sol/config.hpp57
-rw-r--r--src/libs/3rdparty/sol2/include/sol/forward.hpp1340
-rw-r--r--src/libs/3rdparty/sol2/include/sol/sol.hpp29202
-rw-r--r--src/libs/3rdparty/sol2/sol2.qbs17
-rw-r--r--src/libs/3rdparty/sqlite/sqlite3.c484
-rw-r--r--src/libs/3rdparty/sqlite/sqlite3.h25
-rw-r--r--src/libs/cplusplus/ResolveExpression.cpp8
-rw-r--r--src/libs/extensionsystem/CMakeLists.txt8
-rw-r--r--src/libs/extensionsystem/extensionsystem.qbs3
-rw-r--r--src/libs/extensionsystem/optionsparser.cpp2
-rw-r--r--src/libs/extensionsystem/plugindetailsview.cpp10
-rw-r--r--src/libs/extensionsystem/pluginmanager.cpp84
-rw-r--r--src/libs/extensionsystem/pluginmanager.h7
-rw-r--r--src/libs/extensionsystem/pluginmanager_p.h6
-rw-r--r--src/libs/extensionsystem/pluginspec.cpp94
-rw-r--r--src/libs/extensionsystem/pluginspec.h28
-rw-r--r--src/libs/extensionsystem/pluginview.cpp2
-rw-r--r--src/libs/languageserverprotocol/jsonobject.h3
-rw-r--r--src/libs/languageserverprotocol/jsonrpcmessages.h14
-rw-r--r--src/libs/languageserverprotocol/languagefeatures.cpp4
-rw-r--r--src/libs/languageserverprotocol/lsptypes.cpp8
-rw-r--r--src/libs/languageserverprotocol/lsputils.h19
-rw-r--r--src/libs/languageserverprotocol/progresssupport.cpp6
-rw-r--r--src/libs/languageserverprotocol/servercapabilities.cpp16
-rw-r--r--src/libs/languageserverprotocol/workspace.cpp5
-rw-r--r--src/libs/languageutils/componentversion.cpp63
-rw-r--r--src/libs/languageutils/componentversion.h61
-rw-r--r--src/libs/libs.qbs2
-rw-r--r--src/libs/modelinglib/CMakeLists.txt4
-rw-r--r--src/libs/modelinglib/modelinglib.qbs8
-rw-r--r--src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp133
-rw-r--r--src/libs/modelinglib/qmt/config/stereotypedefinitionparser.h3
-rw-r--r--src/libs/modelinglib/qmt/diagram/dobject.cpp28
-rw-r--r--src/libs/modelinglib/qmt/diagram/dobject.h11
-rw-r--r--src/libs/modelinglib/qmt/diagram/drelation.cpp25
-rw-r--r--src/libs/modelinglib/qmt/diagram/drelation.h32
-rw-r--r--src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp5
-rw-r--r--src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp5
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/capabilities/windable.h2
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp79
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.h2
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp65
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/classitem.h1
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp46
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/componentitem.h1
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp42
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.h1
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp43
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/itemitem.h1
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp184
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/objectitem.h9
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp40
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/packageitem.h1
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp52
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/relationitem.h2
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp4
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp24
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp86
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h5
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.cpp14
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.h2
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.cpp10
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.h3
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp2
-rw-r--r--src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.cpp39
-rw-r--r--src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.h7
-rw-r--r--src/libs/modelinglib/qmt/model/mdiagram.h2
-rw-r--r--src/libs/modelinglib/qmt/model/mobject.cpp7
-rw-r--r--src/libs/modelinglib/qmt/model/mobject.h3
-rw-r--r--src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.cpp1
-rw-r--r--src/libs/modelinglib/qmt/model_ui/modeltreefilterdata.cpp43
-rw-r--r--src/libs/modelinglib/qmt/model_ui/modeltreefilterdata.h72
-rw-r--r--src/libs/modelinglib/qmt/model_ui/sortedtreemodel.cpp220
-rw-r--r--src/libs/modelinglib/qmt/model_ui/sortedtreemodel.h7
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.cpp426
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.h43
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/modeltreefilter.cpp173
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/modeltreefilter.h39
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.cpp46
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.h4
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp281
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h143
-rw-r--r--src/libs/modelinglib/qmt/serializer/diagramserializer.cpp31
-rw-r--r--src/libs/modelinglib/qmt/serializer/diagramserializer.h3
-rw-r--r--src/libs/modelinglib/qmt/serializer/modelserializer.cpp1
-rw-r--r--src/libs/modelinglib/qmt/stereotype/customrelation.cpp5
-rw-r--r--src/libs/modelinglib/qmt/stereotype/customrelation.h8
-rw-r--r--src/libs/modelinglib/qmt/stereotype/shapevalue.cpp2
-rw-r--r--src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp9
-rw-r--r--src/libs/modelinglib/qmt/stereotype/stereotypecontroller.h1
-rw-r--r--src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp15
-rw-r--r--src/libs/modelinglib/qmt/stereotype/stereotypeicon.h25
-rw-r--r--src/libs/modelinglib/qmt/style/defaultstyleengine.cpp201
-rw-r--r--src/libs/modelinglib/qmt/style/defaultstyleengine.h8
-rw-r--r--src/libs/modelinglib/qmt/style/relationvisuals.cpp58
-rw-r--r--src/libs/modelinglib/qmt/style/relationvisuals.h42
-rw-r--r--src/libs/modelinglib/qmt/style/stylecontroller.cpp6
-rw-r--r--src/libs/modelinglib/qmt/style/stylecontroller.h4
-rw-r--r--src/libs/modelinglib/qmt/style/styledrelation.cpp6
-rw-r--r--src/libs/modelinglib/qmt/style/styledrelation.h6
-rw-r--r--src/libs/modelinglib/qmt/style/styleengine.h4
-rw-r--r--src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp54
-rw-r--r--src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h7
-rw-r--r--src/libs/modelinglib/qmt/tasks/ielementtasks.h7
-rw-r--r--src/libs/modelinglib/qmt/tasks/voidelementtasks.cpp20
-rw-r--r--src/libs/modelinglib/qmt/tasks/voidelementtasks.h7
-rw-r--r--src/libs/modelinglib/qtserialization/inc/qark/serialize_container.h1
-rw-r--r--src/libs/nanotrace/CMakeLists.txt1
-rw-r--r--src/libs/nanotrace/nanotracehr.cpp56
-rw-r--r--src/libs/nanotrace/nanotracehr.h362
-rw-r--r--src/libs/nanotrace/staticstring.h116
m---------src/libs/qlitehtml0
-rw-r--r--src/libs/qmljs/CMakeLists.txt1
-rw-r--r--src/libs/qmljs/qmljs.qbs1
-rw-r--r--src/libs/qmljs/qmljsbind.cpp17
-rw-r--r--src/libs/qmljs/qmljsbind.h1
-rw-r--r--src/libs/qmljs/qmljscheck.cpp26
-rw-r--r--src/libs/qmljs/qmljscheck.h2
-rw-r--r--src/libs/qmljs/qmljsicons.cpp5
-rw-r--r--src/libs/qmljs/qmljsicons.h1
-rw-r--r--src/libs/qmljs/qmljsindenter.cpp603
-rw-r--r--src/libs/qmljs/qmljsindenter.h51
-rw-r--r--src/libs/qmljs/qmljsinterpreter.cpp51
-rw-r--r--src/libs/qmljs/qmljsinterpreter.h29
-rw-r--r--src/libs/qmljs/qmljsstaticanalysismessage.cpp5
-rw-r--r--src/libs/qmlpuppetcommunication/container/imagecontainer.cpp9
-rw-r--r--src/libs/qtcreatorcdbext/pyvalue.cpp17
-rw-r--r--src/libs/solutions/tasking/tasktree.cpp34
-rw-r--r--src/libs/solutions/tasking/tasktree.h18
-rw-r--r--src/libs/sqlite/CMakeLists.txt4
-rw-r--r--src/libs/sqlite/sqlitebasestatement.cpp203
-rw-r--r--src/libs/sqlite/sqlitebasestatement.h82
-rw-r--r--src/libs/sqlite/sqliteexception.cpp30
-rw-r--r--src/libs/sqlite/sqliteexception.h9
-rw-r--r--src/libs/sqlite/sqliteids.h11
-rw-r--r--src/libs/sqlite/sqliteindex.h19
-rw-r--r--src/libs/sqlite/sqlitetracing.cpp38
-rw-r--r--src/libs/sqlite/sqlitetracing.h29
-rw-r--r--src/libs/sqlite/sqlitevalue.h62
-rw-r--r--src/libs/utils/CMakeLists.txt1
-rw-r--r--src/libs/utils/algorithm.h8
-rw-r--r--src/libs/utils/devicefileaccess.cpp8
-rw-r--r--src/libs/utils/environment.cpp92
-rw-r--r--src/libs/utils/expected.h9
-rw-r--r--src/libs/utils/filepath.cpp19
-rw-r--r--src/libs/utils/fileutils.cpp3
-rw-r--r--src/libs/utils/fsengine/fsengine_impl.h3
-rw-r--r--src/libs/utils/fsengine/fsenginehandler.cpp31
-rw-r--r--src/libs/utils/fsengine/rootinjectfsengine.h38
-rw-r--r--src/libs/utils/namevaluesdialog.cpp6
-rw-r--r--src/libs/utils/outputformatter.cpp19
-rw-r--r--src/libs/utils/qtcprocess.cpp5
-rw-r--r--src/libs/utils/reloadpromptutils.cpp6
-rw-r--r--src/libs/utils/smallstring.h113
-rw-r--r--src/libs/utils/stringutils.cpp6
-rw-r--r--src/libs/utils/stringutils.h2
-rw-r--r--src/libs/utils/stylehelper.cpp8
-rw-r--r--src/libs/utils/theme/theme.cpp38
-rw-r--r--src/libs/utils/theme/theme.h2
-rw-r--r--src/libs/utils/tooltip/tooltip.cpp8
-rw-r--r--src/libs/utils/utils.qbs3
241 files changed, 78845 insertions, 1864 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>
+&middot;
+<A HREF="#contents">contents</A>
+&middot;
+<A HREF="#index">index</A>
+&middot;
+<A HREF="http://www.lua.org/manual/">other versions</A>
+</DIV>
+
+<P>
+<SMALL>
+Copyright &copy; 2020&ndash;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 &ndash; Introduction</A>
+<P>
+<LI><A HREF="manual.html#2">2 &ndash; Basic Concepts</A>
+<UL>
+<LI><A HREF="manual.html#2.1">2.1 &ndash; Values and Types</A>
+<LI><A HREF="manual.html#2.2">2.2 &ndash; Environments and the Global Environment</A>
+<LI><A HREF="manual.html#2.3">2.3 &ndash; Error Handling</A>
+<LI><A HREF="manual.html#2.4">2.4 &ndash; Metatables and Metamethods</A>
+<LI><A HREF="manual.html#2.5">2.5 &ndash; Garbage Collection</A>
+<UL>
+<LI><A HREF="manual.html#2.5.1">2.5.1 &ndash; Incremental Garbage Collection</A>
+<LI><A HREF="manual.html#2.5.2">2.5.2 &ndash; Generational Garbage Collection</A>
+<LI><A HREF="manual.html#2.5.3">2.5.3 &ndash; Garbage-Collection Metamethods</A>
+<LI><A HREF="manual.html#2.5.4">2.5.4 &ndash; Weak Tables</A>
+</UL>
+<LI><A HREF="manual.html#2.6">2.6 &ndash; Coroutines</A>
+</UL>
+<P>
+<LI><A HREF="manual.html#3">3 &ndash; The Language</A>
+<UL>
+<LI><A HREF="manual.html#3.1">3.1 &ndash; Lexical Conventions</A>
+<LI><A HREF="manual.html#3.2">3.2 &ndash; Variables</A>
+<LI><A HREF="manual.html#3.3">3.3 &ndash; Statements</A>
+<UL>
+<LI><A HREF="manual.html#3.3.1">3.3.1 &ndash; Blocks</A>
+<LI><A HREF="manual.html#3.3.2">3.3.2 &ndash; Chunks</A>
+<LI><A HREF="manual.html#3.3.3">3.3.3 &ndash; Assignment</A>
+<LI><A HREF="manual.html#3.3.4">3.3.4 &ndash; Control Structures</A>
+<LI><A HREF="manual.html#3.3.5">3.3.5 &ndash; For Statement</A>
+<LI><A HREF="manual.html#3.3.6">3.3.6 &ndash; Function Calls as Statements</A>
+<LI><A HREF="manual.html#3.3.7">3.3.7 &ndash; Local Declarations</A>
+<LI><A HREF="manual.html#3.3.8">3.3.8 &ndash; To-be-closed Variables</A>
+</UL>
+<LI><A HREF="manual.html#3.4">3.4 &ndash; Expressions</A>
+<UL>
+<LI><A HREF="manual.html#3.4.1">3.4.1 &ndash; Arithmetic Operators</A>
+<LI><A HREF="manual.html#3.4.2">3.4.2 &ndash; Bitwise Operators</A>
+<LI><A HREF="manual.html#3.4.3">3.4.3 &ndash; Coercions and Conversions</A>
+<LI><A HREF="manual.html#3.4.4">3.4.4 &ndash; Relational Operators</A>
+<LI><A HREF="manual.html#3.4.5">3.4.5 &ndash; Logical Operators</A>
+<LI><A HREF="manual.html#3.4.6">3.4.6 &ndash; Concatenation</A>
+<LI><A HREF="manual.html#3.4.7">3.4.7 &ndash; The Length Operator</A>
+<LI><A HREF="manual.html#3.4.8">3.4.8 &ndash; Precedence</A>
+<LI><A HREF="manual.html#3.4.9">3.4.9 &ndash; Table Constructors</A>
+<LI><A HREF="manual.html#3.4.10">3.4.10 &ndash; Function Calls</A>
+<LI><A HREF="manual.html#3.4.11">3.4.11 &ndash; Function Definitions</A>
+<LI><A HREF="manual.html#3.4.12">3.4.12 &ndash; Lists of expressions, multiple results, and adjustment<A>
+
+</UL>
+<LI><A HREF="manual.html#3.5">3.5 &ndash; Visibility Rules</A>
+</UL>
+<P>
+<LI><A HREF="manual.html#4">4 &ndash; The Application Program Interface</A>
+<UL>
+<LI><A HREF="manual.html#4.1">4.1 &ndash; The Stack</A>
+<UL>
+<LI><A HREF="manual.html#4.1.1">4.1.1 &ndash; Stack Size</A>
+<LI><A HREF="manual.html#4.1.2">4.1.2 &ndash; Valid and Acceptable Indices</A>
+<LI><A HREF="manual.html#4.1.3">4.1.3 &ndash; Pointers to strings</A>
+</UL>
+<LI><A HREF="manual.html#4.2">4.2 &ndash; C Closures</A>
+<LI><A HREF="manual.html#4.3">4.3 &ndash; Registry</A>
+<LI><A HREF="manual.html#4.4">4.4 &ndash; Error Handling in C</A>
+<UL>
+<LI><A HREF="manual.html#4.4.1">4.4.1 &ndash; Status Codes</A>
+</UL>
+<LI><A HREF="manual.html#4.5">4.5 &ndash; Handling Yields in C</A>
+<LI><A HREF="manual.html#4.6">4.6 &ndash; Functions and Types</A>
+<LI><A HREF="manual.html#4.7">4.7 &ndash; The Debug Interface</A>
+</UL>
+<P>
+<LI><A HREF="manual.html#5">5 &ndash; The Auxiliary Library</A>
+<UL>
+<LI><A HREF="manual.html#5.1">5.1 &ndash; Functions and Types</A>
+</UL>
+<P>
+<LI><A HREF="manual.html#6">6 &ndash; The Standard Libraries</A>
+<UL>
+<LI><A HREF="manual.html#6.1">6.1 &ndash; Basic Functions</A>
+<LI><A HREF="manual.html#6.2">6.2 &ndash; Coroutine Manipulation</A>
+<LI><A HREF="manual.html#6.3">6.3 &ndash; Modules</A>
+<LI><A HREF="manual.html#6.4">6.4 &ndash; String Manipulation</A>
+<UL>
+<LI><A HREF="manual.html#6.4.1">6.4.1 &ndash; Patterns</A>
+<LI><A HREF="manual.html#6.4.2">6.4.2 &ndash; Format Strings for Pack and Unpack</A>
+</UL>
+<LI><A HREF="manual.html#6.5">6.5 &ndash; UTF-8 Support</A>
+<LI><A HREF="manual.html#6.6">6.6 &ndash; Table Manipulation</A>
+<LI><A HREF="manual.html#6.7">6.7 &ndash; Mathematical Functions</A>
+<LI><A HREF="manual.html#6.8">6.8 &ndash; Input and Output Facilities</A>
+<LI><A HREF="manual.html#6.9">6.9 &ndash; Operating System Facilities</A>
+<LI><A HREF="manual.html#6.10">6.10 &ndash; The Debug Library</A>
+</UL>
+<P>
+<LI><A HREF="manual.html#7">7 &ndash; Lua Standalone</A>
+<P>
+<LI><A HREF="manual.html#8">8 &ndash; Incompatibilities with the Previous Version</A>
+<UL>
+<LI><A HREF="manual.html#8.1">8.1 &ndash; Incompatibilities in the Language</A>
+<LI><A HREF="manual.html#8.2">8.2 &ndash; Incompatibilities in the Libraries</A>
+<LI><A HREF="manual.html#8.3">8.3 &ndash; Incompatibilities in the API</A>
+</UL>
+<P>
+<LI><A HREF="manual.html#9">9 &ndash; 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>&nbsp;</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
new file mode 100644
index 0000000000..5c77eacc3b
--- /dev/null
+++ b/src/libs/3rdparty/lua/doc/logo.gif
Binary files differ
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 &copy; 2020&ndash;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>
+&middot;
+<A HREF="contents.html#index">index</A>
+&middot;
+<A HREF="http://www.lua.org/manual/">other versions</A>
+</DIV>
+
+<!-- ====================================================================== -->
+<p>
+
+<!-- $Id: manual.of $ -->
+
+
+
+
+<h1>1 &ndash; <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&nbsp;C and C++.
+The Lua distribution includes a host program called <code>lua</code>,
+which uses the Lua library to offer a complete,
+standalone Lua interpreter,
+for interactive or batch use.
+Lua is intended to be used both as a powerful, lightweight,
+embeddable scripting language for any program that needs one,
+and as a powerful but lightweight and efficient stand-alone language.
+
+
+<p>
+As an extension language, Lua has no notion of a "main" program:
+it works <em>embedded</em> in a host client,
+called the <em>embedding program</em> or simply the <em>host</em>.
+(Frequently, this host is the stand-alone <code>lua</code> program.)
+The host program can invoke functions to execute a piece of Lua code,
+can write and read Lua variables,
+and can register C&nbsp;functions to be called by Lua code.
+Through the use of C&nbsp;functions, Lua can be augmented to cope with
+a wide range of different domains,
+thus creating customized programming languages sharing a syntactical framework.
+
+
+<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 &ndash; <a name="2">Basic Concepts</a></h1>
+
+
+
+<p>
+This section describes the basic concepts of the language.
+
+
+
+
+
+<h2>2.1 &ndash; <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">&sect;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">&sect;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&nbsp;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&nbsp;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">&sect;2.4</a>).
+Userdata values cannot be created or modified in Lua,
+only through the C&nbsp;API.
+This guarantees the integrity of data owned by
+the host program and C&nbsp;libraries.
+
+
+<p>
+The type <em>thread</em> represents independent threads of execution
+and it is used to implement coroutines (see <a href="#2.6">&sect;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">&sect;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">&sect;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 &ndash; <a name="2.2">Environments and the Global Environment</a></h2>
+
+<p>
+As we will discuss further in <a href="#3.2">&sect;3.2</a> and <a href="#3.3.3">&sect;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">&sect;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">&sect;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">&sect;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 &ndash; <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&nbsp;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 &ndash; <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">&sect;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">&sect;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>&amp;</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">&sect;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>&lt;&lt;</code>) operation.
+Behavior similar to the bitwise AND operation.
+</li>
+
+<li><b><code>__shr</code>: </b>
+the bitwise right shift (<code>&gt;&gt;</code>) operation.
+Behavior similar to the bitwise AND operation.
+</li>
+
+<li><b><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">&sect;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>&lt;</code>) operation.
+Behavior similar to the addition operation,
+except that Lua will try a metamethod only when the values
+being compared are neither both numbers nor both strings.
+Moreover, the result of the call is always converted to a boolean.
+</li>
+
+<li><b><code>__le</code>: </b>
+the less equal (<code>&lt;=</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">&sect;2.5.3</a>),
+<code>__close</code> (see <a href="#3.3.8">&sect;3.3.8</a>),
+<code>__mode</code> (see <a href="#2.5.4">&sect;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">&sect;2.5.3</a>).
+It is also a good practice to set the metatable of an object
+right after its creation.
+
+
+
+
+
+<h2>2.5 &ndash; <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">&sect;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&nbsp;code,
+it never collects objects accessible through the registry (see <a href="#4.3">&sect;4.3</a>),
+which includes the global environment (see <a href="#2.2">&sect;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&nbsp;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 &ndash; <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&nbsp;Kbytes.
+
+
+
+
+
+<h3>2.5.2 &ndash; <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 &ndash; <a name="2.5.3">Garbage-Collection Metamethods</a></h3>
+
+<p>
+You can set garbage-collector metamethods for tables
+and, using the C&nbsp;API,
+for full userdata (see <a href="#2.4">&sect;2.4</a>).
+These metamethods, 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 &ndash; <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&nbsp;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 &ndash; <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 &ndash; <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>}&nbsp;means&nbsp;0 or more <em>a</em>'s, and
+[<em>a</em>]&nbsp;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 &lsquo;<b>=</b>&rsquo;.
+The complete syntax of Lua can be found in <a href="#9">&sect;9</a>
+at the end of this manual.
+
+
+
+
+
+<h2>3.1 &ndash; <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>
+ + - * / % ^ #
+ &amp; ~ | &lt;&lt; &gt;&gt; //
+ == ~= &lt;= &gt;= &lt; &gt; =
+ ( ) { } [ ] ::
+ ; : , . .. ...
+</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&nbsp;0 is written as <code>[[</code>,
+an opening long bracket of level&nbsp;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&nbsp;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&nbsp;97,
+newline is coded as&nbsp;10, and '<code>1</code>' is coded as&nbsp;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 &ndash; <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">&sect;3.1</a>).
+
+
+<p>
+Any variable name is assumed to be global unless explicitly declared
+as a local (see <a href="#3.3.7">&sect;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">&sect;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 &lsquo;<b>[</b>&rsquo; exp &lsquo;<b>]</b>&rsquo;
+</pre><p>
+The meaning of accesses to table fields can be changed via metatables
+(see <a href="#2.4">&sect;2.4</a>).
+
+
+<p>
+The syntax <code>var.Name</code> is just syntactic sugar for
+<code>var["Name"]</code>:
+
+<pre>
+ var ::= prefixexp &lsquo;<b>.</b>&rsquo; 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">&sect;2.2</a>).
+
+
+
+
+
+<h2>3.3 &ndash; <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 &ndash; <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 ::= &lsquo;<b>;</b>&rsquo;
+</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">&sect;3.3.4</a>).
+
+
+
+
+
+<h3>3.3.2 &ndash; <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">&sect;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">&sect;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 &ndash; <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 &lsquo;<b>=</b>&rsquo; explist
+ varlist ::= var {&lsquo;<b>,</b>&rsquo; var}
+ explist ::= exp {&lsquo;<b>,</b>&rsquo; exp}
+</pre><p>
+Expressions are discussed in <a href="#3.4">&sect;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">&sect;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&nbsp;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">&sect;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">&sect;2.4</a>).
+
+
+
+
+
+<h3>3.3.4 &ndash; <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">&sect;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>&ndash;<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 ::= &lsquo;<b>::</b>&rsquo; Name &lsquo;<b>::</b>&rsquo;
+</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] [&lsquo;<b>;</b>&rsquo;]
+</pre>
+
+<p>
+The <b>return</b> statement can only be written
+as the last statement of a block.
+If it is 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 &ndash; <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 &lsquo;<b>=</b>&rsquo; exp &lsquo;<b>,</b>&rsquo; exp [&lsquo;<b>,</b>&rsquo; 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&nbsp;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 {&lsquo;<b>,</b>&rsquo; Name}
+</pre><p>
+A <b>for</b> statement like
+
+<pre>
+ for <em>var_1</em>, &middot;&middot;&middot;, <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">&sect;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">&sect;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 &ndash; <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">&sect;3.4.10</a>.
+
+
+
+
+
+<h3>3.3.7 &ndash; <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 [&lsquo;<b>=</b>&rsquo; explist]
+ attnamelist ::= Name attrib {&lsquo;<b>,</b>&rsquo; Name attrib}
+</pre><p>
+If present, an initial assignment has the same semantics
+of a multiple assignment (see <a href="#3.3.3">&sect;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 ::= [&lsquo;<b>&lt;</b>&rsquo; Name &lsquo;<b>&gt;</b>&rsquo;]
+</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">&sect;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">&sect;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">&sect;3.5</a>.
+
+
+
+
+
+<h3>3.3.8 &ndash; <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 &ndash; <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 ::= &lsquo;<b>...</b>&rsquo;
+ exp ::= exp binop exp
+ exp ::= unop exp
+ prefixexp ::= var | functioncall | &lsquo;<b>(</b>&rsquo; exp &lsquo;<b>)</b>&rsquo;
+</pre>
+
+<p>
+Numerals and literal strings are explained in <a href="#3.1">&sect;3.1</a>;
+variables are explained in <a href="#3.2">&sect;3.2</a>;
+function definitions are explained in <a href="#3.4.11">&sect;3.4.11</a>;
+function calls are explained in <a href="#3.4.10">&sect;3.4.10</a>;
+table constructors are explained in <a href="#3.4.9">&sect;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">&sect;3.4.11</a>.
+
+
+<p>
+Binary operators comprise arithmetic operators (see <a href="#3.4.1">&sect;3.4.1</a>),
+bitwise operators (see <a href="#3.4.2">&sect;3.4.2</a>),
+relational operators (see <a href="#3.4.4">&sect;3.4.4</a>), logical operators (see <a href="#3.4.5">&sect;3.4.5</a>),
+and the concatenation operator (see <a href="#3.4.6">&sect;3.4.6</a>).
+Unary operators comprise the unary minus (see <a href="#3.4.1">&sect;3.4.1</a>),
+the unary bitwise NOT (see <a href="#3.4.2">&sect;3.4.2</a>),
+the unary logical <b>not</b> (see <a href="#3.4.5">&sect;3.4.5</a>),
+and the unary <em>length operator</em> (see <a href="#3.4.7">&sect;3.4.7</a>).
+
+
+
+
+
+<h3>3.4.1 &ndash; <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">&sect;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&nbsp;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 &ndash; <a name="3.4.2">Bitwise Operators</a></h3><p>
+Lua supports the following bitwise operators:
+
+<ul>
+<li><b><code>&amp;</code>: </b>bitwise AND</li>
+<li><b><code>&#124;</code>: </b>bitwise OR</li>
+<li><b><code>~</code>: </b>bitwise exclusive OR</li>
+<li><b><code>&gt;&gt;</code>: </b>right shift</li>
+<li><b><code>&lt;&lt;</code>: </b>left shift</li>
+<li><b><code>~</code>: </b>unary bitwise NOT</li>
+</ul>
+
+<p>
+All bitwise operations convert its operands to integers
+(see <a href="#3.4.3">&sect;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 &ndash; <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"&lt;1</code> raises an error
+(see <a href="#3.4.4">&sect;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 &ndash; <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>&lt;</code>: </b>less than</li>
+<li><b><code>&gt;</code>: </b>greater than</li>
+<li><b><code>&lt;=</code>: </b>less or equal</li>
+<li><b><code>&gt;=</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">&sect;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">&sect;2.4</a>).
+A comparison <code>a &gt; b</code> is translated to <code>b &lt; a</code>
+and <code>a &gt;= b</code> is translated to <code>b &lt;= a</code>.
+
+
+<p>
+Following the IEEE 754 standard,
+the special value NaN is considered neither less than,
+nor equal to, nor greater than any value, including itself.
+
+
+
+
+
+<h3>3.4.5 &ndash; <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">&sect;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 --&gt; 10
+ 10 or error() --&gt; 10
+ nil or "a" --&gt; "a"
+ nil and 10 --&gt; nil
+ false and error() --&gt; false
+ false and nil --&gt; false
+ false or nil --&gt; nil
+ 10 and 20 --&gt; 20
+</pre>
+
+
+
+
+<h3>3.4.6 &ndash; <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">&sect;3.4.3</a>).
+Otherwise, the <code>__concat</code> metamethod is called (see <a href="#2.4">&sect;2.4</a>).
+
+
+
+
+
+<h3>3.4.7 &ndash; <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">&sect;2.4</a>).
+
+
+
+
+
+<h3>3.4.8 &ndash; <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
+ &lt; &gt; &lt;= &gt;= ~= ==
+ |
+ ~
+ &amp;
+ &lt;&lt; &gt;&gt;
+ ..
+ + -
+ * / // %
+ 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 &ndash; <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 ::= &lsquo;<b>{</b>&rsquo; [fieldlist] &lsquo;<b>}</b>&rsquo;
+ fieldlist ::= field {fieldsep field} [fieldsep]
+ field ::= &lsquo;<b>[</b>&rsquo; exp &lsquo;<b>]</b>&rsquo; &lsquo;<b>=</b>&rsquo; exp | Name &lsquo;<b>=</b>&rsquo; exp | exp
+ fieldsep ::= &lsquo;<b>,</b>&rsquo; | &lsquo;<b>;</b>&rsquo;
+</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">&sect;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 &ndash; <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">&sect;2.4</a>).
+
+
+<p>
+The form
+
+<pre>
+ functioncall ::= prefixexp &lsquo;<b>:</b>&rsquo; 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 ::= &lsquo;<b>(</b>&rsquo; [explist] &lsquo;<b>)</b>&rsquo;
+ 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 &ndash; <a name="3.4.11">Function Definitions</a></h3>
+
+<p>
+The syntax for function definition is
+
+<pre>
+ functiondef ::= <b>function</b> funcbody
+ funcbody ::= &lsquo;<b>(</b>&rsquo; [parlist] &lsquo;<b>)</b>&rsquo; 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 {&lsquo;<b>.</b>&rsquo; Name} [&lsquo;<b>:</b>&rsquo; 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 [&lsquo;<b>,</b>&rsquo; &lsquo;<b>...</b>&rsquo;] | &lsquo;<b>...</b>&rsquo;
+</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">&sect;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">&sect;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, ... --&gt; (nothing)
+ g(3, 4) a=3, b=4, ... --&gt; (nothing)
+ g(3, 4, 5, 8) a=3, b=4, ... --&gt; 5 8
+ g(5, r()) a=5, b=1, ... --&gt; 2 3
+</pre>
+
+<p>
+Results are returned using the <b>return</b> statement (see <a href="#3.3.4">&sect;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 &ndash; <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">&sect;3.3.4</a>).</li>
+
+<li>A table constructor,
+for instance <code>{e1, e2, e3}</code> (see <a href="#3.4.9">&sect;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">&sect;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">&sect;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">&sect;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">&sect;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">&sect;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 &ndash; <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) --&gt; 10
+ x = x+1
+ do -- another block
+ local x = x+1 -- another 'x'
+ print(x) --&gt; 12
+ end
+ print(x) --&gt; 11
+ end
+ print(x) --&gt; 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 &ndash; <a name="4">The Application Program Interface</a></h1>
+
+
+
+<p>
+
+This section describes the C&nbsp;API for Lua, that is,
+the set of C&nbsp;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&nbsp;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 &ndash; <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&nbsp;functions that are still active.
+This stack initially contains any arguments to the C&nbsp;function
+and it is where the C&nbsp;function 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&nbsp;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&nbsp;1 represents the first element
+(that is, the element that was pushed onto the stack first)
+and
+index&nbsp;<em>n</em> represents the last element;
+index&nbsp;-1 also represents the last element
+(that is, the element at the&nbsp;top)
+and index <em>-n</em> represents the first element.
+
+
+
+
+
+<h3>4.1.1 &ndash; <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 &ndash; <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&nbsp;1 and the stack top
+(<code>1 &le; abs(index) &le; top</code>)
+
+plus <em>pseudo-indices</em>,
+which represent some positions that are accessible to C&nbsp;code
+but that are not in the stack.
+Pseudo-indices are used to access the registry (see <a href="#4.3">&sect;4.3</a>)
+and the upvalues of a C&nbsp;function (see <a href="#4.2">&sect;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">&sect;4.2</a>) greater than the real number
+of upvalues in the current C&nbsp;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&nbsp;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 &ndash; <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 &ndash; <a name="4.2">C Closures</a></h2>
+
+<p>
+When a C&nbsp;function is created,
+it is possible to associate some values with it,
+thus creating a <em>C&nbsp;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&nbsp;function is called,
+its upvalues are located at specific pseudo-indices.
+These pseudo-indices are produced by the macro
+<a href="#lua_upvalueindex"><code>lua_upvalueindex</code></a>.
+The first 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&nbsp;closure can also change the values
+of its corresponding upvalues.
+
+
+
+
+
+<h2>4.3 &ndash; <a name="4.3">Registry</a></h2>
+
+<p>
+Lua provides a <em>registry</em>,
+a predefined table that can be used by any C&nbsp;code to
+store whatever Lua values it needs to store.
+The registry table is always accessible at pseudo-index
+<a name="pdf-LUA_REGISTRYINDEX"><code>LUA_REGISTRYINDEX</code></a>.
+Any C&nbsp;library can store data into this table,
+but it must take care to choose keys
+that are different from those used
+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&nbsp;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 &ndash; <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&nbsp;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&nbsp;function is called by Lua with a Lua state,
+it can do whatever it wants on that Lua state,
+as it should be already protected.
+However,
+when C code operates on other Lua states
+(e.g., a Lua-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">&sect;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">&sect;4.1.1</a>).
+
+
+
+
+
+<h3>4.4.1 &ndash; <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 &ndash; <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&nbsp;function <code>foo</code> calls an API function
+and this API function yields
+(directly or indirectly by calling another function that yields),
+Lua cannot return to <code>foo</code> any more,
+because the <code>longjmp</code> removes its frame from the C&nbsp;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&nbsp;function called from Lua which we will call
+the <em>original function</em>.
+This original function then calls one of those three functions in the C API,
+which we will call the <em>callee function</em>,
+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&nbsp;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 &ndash; <a name="4.6">Functions and Types</a></h2>
+
+<p>
+Here we list all functions and types from the C&nbsp;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, &ndash;]</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&nbsp;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>&amp;</code>)</li>
+<li><b><a name="pdf-LUA_OPBOR"><code>LUA_OPBOR</code></a>: </b> performs bitwise OR (<code>|</code>)</li>
+<li><b><a name="pdf-LUA_OPBXOR"><code>LUA_OPBXOR</code></a>: </b> performs bitwise exclusive OR (<code>~</code>)</li>
+<li><b><a name="pdf-LUA_OPSHL"><code>LUA_OPSHL</code></a>: </b> performs left shift (<code>&lt;&lt;</code>)</li>
+<li><b><a name="pdf-LUA_OPSHR"><code>LUA_OPSHR</code></a>: </b> performs right shift (<code>&gt;&gt;</code>)</li>
+
+</ul>
+
+
+
+
+<hr><h3><a name="lua_atpanic"><code>lua_atpanic</code></a></h3><p>
+<span class="apii">[-0, +0, &ndash;]</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">&sect;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&nbsp;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">&sect;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&nbsp;functions.
+
+
+<p>
+In order to communicate properly with Lua,
+a C&nbsp;function must use the following protocol,
+which defines the way parameters and results are passed:
+a C&nbsp;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&nbsp;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&nbsp;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 &lt;= 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, &ndash;]</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, &ndash;]</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&nbsp;5.4.3.)
+
+
+
+
+
+<hr><h3><a name="lua_closethread"><code>lua_closethread</code></a></h3><p>
+<span class="apii">[-0, +?, &ndash;]</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&nbsp;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&nbsp;0.
+Also returns&nbsp;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>&lt;</code>)</li>
+<li><b><a name="pdf-LUA_OPLE"><code>LUA_OPLE</code></a>: </b> compares for less or equal (<code>&lt;=</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>&nbsp;is&nbsp;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">&sect;3.4.6</a>).
+
+
+
+
+
+<hr><h3><a name="lua_copy"><code>lua_copy</code></a></h3><p>
+<span class="apii">[-0, +0, &ndash;]</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, &ndash;]</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&nbsp;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, &ndash;]</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">&sect;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">&sect;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, &ndash;]</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">&sect;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, &ndash;]</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">&sect;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), &ndash;]</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&nbsp;1.
+Otherwise,
+the function returns&nbsp;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">&sect;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, &ndash;]</span>
+<pre>int lua_gettop (lua_State *L);</pre>
+
+<p>
+Returns the index of the top element in the stack.
+Because indices start at&nbsp;1,
+this result is equal to the number of elements in the stack;
+in particular, 0&nbsp;means an empty stack.
+
+
+
+
+
+<hr><h3><a name="lua_getiuservalue"><code>lua_getiuservalue</code></a></h3><p>
+<span class="apii">[-0, +1, &ndash;]</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, &ndash;]</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, &ndash;]</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&nbsp;otherwise.
+
+
+
+
+
+<hr><h3><a name="lua_iscfunction"><code>lua_iscfunction</code></a></h3><p>
+<span class="apii">[-0, +0, &ndash;]</span>
+<pre>int lua_iscfunction (lua_State *L, int index);</pre>
+
+<p>
+Returns 1 if the value at the given index is a C&nbsp;function,
+and 0&nbsp;otherwise.
+
+
+
+
+
+<hr><h3><a name="lua_isfunction"><code>lua_isfunction</code></a></h3><p>
+<span class="apii">[-0, +0, &ndash;]</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&nbsp;otherwise.
+
+
+
+
+
+<hr><h3><a name="lua_isinteger"><code>lua_isinteger</code></a></h3><p>
+<span class="apii">[-0, +0, &ndash;]</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&nbsp;otherwise.
+
+
+
+
+
+<hr><h3><a name="lua_islightuserdata"><code>lua_islightuserdata</code></a></h3><p>
+<span class="apii">[-0, +0, &ndash;]</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&nbsp;otherwise.
+
+
+
+
+
+<hr><h3><a name="lua_isnil"><code>lua_isnil</code></a></h3><p>
+<span class="apii">[-0, +0, &ndash;]</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&nbsp;otherwise.
+
+
+
+
+
+<hr><h3><a name="lua_isnone"><code>lua_isnone</code></a></h3><p>
+<span class="apii">[-0, +0, &ndash;]</span>
+<pre>int lua_isnone (lua_State *L, int index);</pre>
+
+<p>
+Returns 1 if the given index is not valid,
+and 0&nbsp;otherwise.
+
+
+
+
+
+<hr><h3><a name="lua_isnoneornil"><code>lua_isnoneornil</code></a></h3><p>
+<span class="apii">[-0, +0, &ndash;]</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&nbsp;otherwise.
+
+
+
+
+
+<hr><h3><a name="lua_isnumber"><code>lua_isnumber</code></a></h3><p>
+<span class="apii">[-0, +0, &ndash;]</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&nbsp;otherwise.
+
+
+
+
+
+<hr><h3><a name="lua_isstring"><code>lua_isstring</code></a></h3><p>
+<span class="apii">[-0, +0, &ndash;]</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&nbsp;otherwise.
+
+
+
+
+
+<hr><h3><a name="lua_istable"><code>lua_istable</code></a></h3><p>
+<span class="apii">[-0, +0, &ndash;]</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&nbsp;otherwise.
+
+
+
+
+
+<hr><h3><a name="lua_isthread"><code>lua_isthread</code></a></h3><p>
+<span class="apii">[-0, +0, &ndash;]</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&nbsp;otherwise.
+
+
+
+
+
+<hr><h3><a name="lua_isuserdata"><code>lua_isuserdata</code></a></h3><p>
+<span class="apii">[-0, +0, &ndash;]</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&nbsp;otherwise.
+
+
+
+
+
+<hr><h3><a name="lua_isyieldable"><code>lua_isyieldable</code></a></h3><p>
+<span class="apii">[-0, +0, &ndash;]</span>
+<pre>int lua_isyieldable (lua_State *L);</pre>
+
+<p>
+Returns 1 if the given coroutine can yield,
+and 0&nbsp;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">&sect;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">&sect;3.4.7</a>) and
+may trigger a metamethod for the "length" event (see <a href="#2.4">&sect;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, &ndash;]</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">&sect;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">&sect;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">&sect;4.3</a>).
+When loading main chunks,
+this upvalue will be the <code>_ENV</code> variable (see <a href="#2.2">&sect;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, &ndash;]</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">&sect;2.5</a>).
+Moreover, if the userdata is marked for finalization (see <a href="#2.5.3">&sect;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&ndash;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&nbsp;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), &ndash;]</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), &ndash;]</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">&sect;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, &ndash;]</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&nbsp;closure onto the stack.
+This function receives a pointer to a C&nbsp;function
+and pushes onto the stack a Lua value of type <code>function</code> that,
+when called, invokes the corresponding C&nbsp;function.
+The parameter <code>n</code> tells how many upvalues this function will have
+(see <a href="#4.2">&sect;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&nbsp;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&nbsp;closure (see <a href="#4.2">&sect;4.2</a>).
+To create a C&nbsp;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&nbsp;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&nbsp;function</em>,
+which is just a pointer to the C&nbsp;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, &ndash;]</span>
+<pre>void lua_pushcfunction (lua_State *L, lua_CFunction f);</pre>
+
+<p>
+Pushes a C&nbsp;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">&sect;4.1.3</a>).
+It is similar to the ISO&nbsp;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, &ndash;]</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, &ndash;]</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, &ndash;]</span>
+<pre>void lua_pushlightuserdata (lua_State *L, void *p);</pre>
+
+<p>
+Pushes a light userdata onto the stack.
+
+
+<p>
+Userdata represent C&nbsp;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&nbsp;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">&sect;4.1.3</a>).
+
+
+
+
+
+<hr><h3><a name="lua_pushnil"><code>lua_pushnil</code></a></h3><p>
+<span class="apii">[-0, +1, &ndash;]</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, &ndash;]</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">&sect;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, &ndash;]</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, &ndash;]</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, &ndash;]</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&nbsp;0.
+Also returns&nbsp;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, &ndash;]</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, &ndash;]</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, &ndash;]</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, &ndash;]</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&nbsp;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&nbsp;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, &ndash;]</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, &ndash;]</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, +?, &ndash;]</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">[-?, +?, &ndash;]</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">&sect;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, &ndash;]</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, &ndash;]</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">&sect;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">&sect;2.4</a>).
+
+
+
+
+
+<hr><h3><a name="lua_setiuservalue"><code>lua_setiuservalue</code></a></h3><p>
+<span class="apii">[-1, +0, &ndash;]</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, &ndash;]</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">&sect;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&nbsp;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&nbsp;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, &ndash;]</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, &ndash;]</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, &ndash;]</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">&sect;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, &ndash;]</span>
+<pre>int lua_toboolean (lua_State *L, int index);</pre>
+
+<p>
+Converts the Lua value at the given index to a C&nbsp;boolean
+value (0&nbsp;or&nbsp;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, &ndash;]</span>
+<pre>lua_CFunction lua_tocfunction (lua_State *L, int index);</pre>
+
+<p>
+Converts a value at the given index to a C&nbsp;function.
+That value must be a C&nbsp;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">&sect;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&nbsp;stack was already unwound,
+so that any automatic C&nbsp;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, &ndash;]</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, &ndash;]</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">&sect;3.4.3</a>);
+otherwise, <code>lua_tointegerx</code> returns&nbsp;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&nbsp;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">&sect;4.1.3</a>).
+This string always has a zero ('<code>\0</code>')
+after its last character (as in&nbsp;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, &ndash;]</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, &ndash;]</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&nbsp;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">&sect;3.4.3</a>);
+otherwise, <a href="#lua_tonumberx"><code>lua_tonumberx</code></a> returns&nbsp;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, &ndash;]</span>
+<pre>const void *lua_topointer (lua_State *L, int index);</pre>
+
+<p>
+Converts the value at the given index to a generic
+C&nbsp;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, &ndash;]</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, &ndash;]</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, &ndash;]</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, &ndash;]</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, &ndash;]</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">&sect;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, &ndash;]</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, &ndash;]</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&nbsp;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">[-?, +?, &ndash;]</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">&sect;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&nbsp;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&nbsp;function that yielded (see <a href="#4.5">&sect;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">&sect;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 &ndash; <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&nbsp;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&nbsp;for C&nbsp;functions).
+</li>
+
+<li><b><code>isvararg</code>: </b>
+true if the function is a variadic function
+(always true for C&nbsp;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, &ndash;]</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, &ndash;]</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, &ndash;]</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>&gt;</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, "&gt;S", &amp;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), &ndash;]</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, &ndash;]</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&nbsp;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), &ndash;]</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, &ndash;]</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, &ndash;]</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, &ndash;]</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, &ndash;]</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, &ndash;]</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 &ndash; <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&nbsp;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 &ndash; <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">[-?, +?, &ndash;]</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&nbsp;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&nbsp;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, &amp;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(&amp;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, &amp;b, sz)</code>.</li>
+
+<li>Then produce the string into that space.</li>
+
+<li>
+Finish by calling <code>luaL_pushresultsize(&amp;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, &ndash;]</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, +?, &ndash;]</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, &ndash;]</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">[-?, +?, &ndash;]</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&nbsp;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&nbsp;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, +?, &ndash;]</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&nbsp;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&nbsp;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">&sect;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, &ndash;]</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, &ndash;]</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, &ndash;]</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, &ndash;]</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&nbsp;C allocation functions
+and then sets a warning function and a panic function (see <a href="#4.4">&sect;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, &ndash;]</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, &ndash;]</span>
+<pre>void luaL_pushfail (lua_State *L);</pre>
+
+<p>
+Pushes the <b>fail</b> value onto the stack (see <a href="#6">&sect;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, &ndash;]</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&nbsp;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">&sect;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&nbsp;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, &ndash;]</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, &ndash;]</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&nbsp;0 is the running function,
+level&nbsp;1 is the function that called the running function,
+etc.
+
+
+<p>
+This function is used to build a prefix for error messages.
+
+
+
+
+
+
+
+<h1>6 &ndash; <a name="6">The Standard Libraries</a></h1>
+
+
+
+<p>
+The standard Lua libraries provide useful functions
+that are implemented in&nbsp;C through the C&nbsp;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&nbsp;API
+and are provided as separate C&nbsp;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">&sect;6.1</a>);</li>
+
+<li>coroutine library (<a href="#6.2">&sect;6.2</a>);</li>
+
+<li>package library (<a href="#6.3">&sect;6.3</a>);</li>
+
+<li>string manipulation (<a href="#6.4">&sect;6.4</a>);</li>
+
+<li>basic UTF-8 support (<a href="#6.5">&sect;6.5</a>);</li>
+
+<li>table manipulation (<a href="#6.6">&sect;6.6</a>);</li>
+
+<li>mathematical functions (<a href="#6.7">&sect;6.7</a>) (sin, log, etc.);</li>
+
+<li>input and output (<a href="#6.8">&sect;6.8</a>);</li>
+
+<li>operating system facilities (<a href="#6.9">&sect;6.9</a>);</li>
+
+<li>debug facilities (<a href="#6.10">&sect;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&nbsp;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 &ndash; <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">&sect;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">&sect;2.5.2</a>).
+A zero means to not change that value.
+</li>
+
+</ul><p>
+See <a href="#2.5">&sect;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">&sect;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&nbsp;1 (the default), the error position is where the
+<code>error</code> function was called.
+Level&nbsp;2 points the error to where the function
+that called <code>error</code> was called; and so on.
+Passing a level&nbsp;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">&sect;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&ndash;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">&sect;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">&sect;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&ndash;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, &middot;&middot;&middot;])</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&nbsp;<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 (&middot;&middot;&middot;)</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, &middot;&middot;&middot;)</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">&sect;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">&sect;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&nbsp;10, the letter '<code>A</code>' (in either upper or lower case)
+represents&nbsp;10, '<code>B</code>' represents&nbsp;11, and so forth,
+with '<code>Z</code>' representing 35.
+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, &middot;&middot;&middot;)</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, &middot;&middot;&middot;])</code></a></h3>
+
+
+<p>
+This function is similar to <a href="#pdf-pcall"><code>pcall</code></a>,
+except that it sets a new message handler <code>msgh</code>.
+
+
+
+
+
+
+
+<h2>6.2 &ndash; <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">&sect;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&nbsp;function.
+
+
+
+
+<p>
+<hr><h3><a name="pdf-coroutine.resume"><code>coroutine.resume (co [, val1, &middot;&middot;&middot;])</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 (&middot;&middot;&middot;)</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 &ndash; <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&nbsp;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&nbsp;loader.
+
+
+<p>
+Lua initializes the C&nbsp;path <a href="#pdf-package.cpath"><code>package.cpath</code></a> in the same way
+it initializes the Lua path <a href="#pdf-package.path"><code>package.path</code></a>,
+using the environment variable <a name="pdf-LUA_CPATH_5_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">&sect;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&nbsp;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&nbsp;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&nbsp;library,
+including if necessary a path and an extension.
+<code>funcname</code> must be the exact name exported by the C&nbsp;library
+(which may depend on the C&nbsp;compiler and linker used).
+
+
+<p>
+This functionality is not supported by ISO&nbsp;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">&sect;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&nbsp;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&nbsp;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&nbsp;library,
+this searcher first uses a dynamic link facility to link the
+application with the library.
+Then it tries to find a C&nbsp;function inside the library to
+be used as the loader.
+The name of this C&nbsp;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&nbsp;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&nbsp;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&nbsp;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 &ndash; <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&nbsp;1
+(not at&nbsp;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&nbsp;1;
+the default value for <code>j</code> is&nbsp;<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 (&middot;&middot;&middot;)</code></a></h3>
+Receives zero or more integers.
+Returns a string with length equal to the number of arguments,
+in which each character has the internal 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">&sect;6.4.1</a>) in the string <code>s</code>.
+If it finds a match, then <code>find</code> returns the indices of&nbsp;<code>s</code>
+where this occurrence starts and ends;
+otherwise, it returns <b>fail</b>.
+A third, optional numeric argument <code>init</code> specifies
+where to start the search;
+its default value is&nbsp;1 and can be negative.
+A <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, &middot;&middot;&middot;)</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&nbsp;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">&sect;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&nbsp;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">&sect;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&nbsp;<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&nbsp;<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")
+ --&gt; x="hello hello world world"
+
+ x = string.gsub("hello world", "%w+", "%0 %0", 1)
+ --&gt; x="hello hello world"
+
+ x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
+ --&gt; x="world hello Lua from"
+
+ x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
+ --&gt; x="home = /home/roberto, user = roberto"
+
+ x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
+ return load(s)()
+ end)
+ --&gt; x="4+5 = 9"
+
+ local t = {name="lua", version="5.4"}
+ x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
+ --&gt; 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">&sect;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&nbsp;1 and can be negative.
+
+
+
+
+<p>
+<hr><h3><a name="pdf-string.pack"><code>string.pack (fmt, v1, v2, &middot;&middot;&middot;)</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">&sect;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">&sect;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">&sect;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 &ndash; <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&nbsp;<em>x</em>, end with&nbsp;<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&nbsp;1;
+the character matching "<code>.</code>" is captured with number&nbsp;2,
+and the part matching "<code>%s*</code>" has number&nbsp;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&nbsp;and&nbsp;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>
+ &gt; string.gsub("abc", "()a*()", print);
+ --&gt; 1 2
+ --&gt; 3 3
+ --&gt; 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 &ndash; <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>&lt;</code>: </b>sets little endian</li>
+<li><b><code>&gt;</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 &lt;=&gt;!</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 &ndash; <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 (&middot;&middot;&middot;)</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">&sect;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 &ndash; <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">&sect;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] &middot;&middot;&middot; sep..list[j]</code>.
+The default value for <code>sep</code> is the empty string,
+the default for <code>i</code> is 1,
+and the default for <code>j</code> is <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], &middot;&middot;&middot;, 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],&middot;&middot;&middot; = a1[f],&middot;&middot;&middot;,a1[e]</code>.
+The default for <code>a2</code> is <code>a1</code>.
+The destination range can overlap with the source range.
+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 (&middot;&middot;&middot;)</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], &middot;&middot;&middot;, 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 &lt;= j</code> implies <code>not comp(list[j],list[i])</code>.
+If <code>comp</code> is not given,
+then the standard Lua operator <code>&lt;</code> is used instead.
+
+
+<p>
+The <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], &middot;&middot;&middot;, list[j]
+</pre><p>
+By default, <code>i</code> is&nbsp;1 and <code>j</code> is <code>#list</code>.
+
+
+
+
+
+
+
+<h2>6.7 &ndash; <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, &middot;&middot;&middot;)</code></a></h3>
+
+
+<p>
+Returns the argument with the maximum value,
+according to the Lua operator <code>&lt;</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, &middot;&middot;&middot;)</code></a></h3>
+
+
+<p>
+Returns the argument with the minimum value,
+according to the Lua operator <code>&lt;</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>&pi;</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&nbsp;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 &ndash; <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, &middot;&middot;&middot;])</code></a></h3>
+
+
+<p>
+Opens the given file name in read mode
+and returns an iterator function that
+works like <code>file:lines(&middot;&middot;&middot;)</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 (&middot;&middot;&middot;)</code></a></h3>
+
+
+<p>
+Equivalent to <code>io.input():read(&middot;&middot;&middot;)</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 (&middot;&middot;&middot;)</code></a></h3>
+
+
+<p>
+Equivalent to <code>io.output():write(&middot;&middot;&middot;)</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 (&middot;&middot;&middot;)</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 (&middot;&middot;&middot;)</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&nbsp;C function <code>setvbuf</code> in your platform for
+more details.
+
+
+
+
+<p>
+<hr><h3><a name="pdf-file:write"><code>file:write (&middot;&middot;&middot;)</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 &ndash; <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&nbsp;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&ndash;12), <code>day</code> (1&ndash;31),
+<code>hour</code> (0&ndash;23), <code>min</code> (0&ndash;59),
+<code>sec</code> (0&ndash;61, due to leap seconds),
+<code>wday</code> (weekday, 1&ndash;7, Sunday is&nbsp;1),
+<code>yday</code> (day of the year, 1&ndash;366),
+and <code>isdst</code> (daylight saving flag, a boolean).
+This last field may be absent
+if the information is not available.
+
+
+<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&nbsp;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&nbsp;function <code>gmtime</code> and C&nbsp;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&nbsp;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&nbsp;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&nbsp;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 &ndash; <a name="6.10">The Debug Library</a></h2>
+
+<p>
+This library provides
+the functionality of the debug interface (<a href="#4.7">&sect;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&nbsp;0 is the current function (<code>getinfo</code> itself);
+level&nbsp;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&nbsp;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">&sect;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&nbsp;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&nbsp;2 to get more information about
+the running function.
+(Level&nbsp;0 is the <code>getinfo</code> function,
+and level&nbsp;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 &ndash; <a name="7">Lua Standalone</a></h1>
+
+<p>
+Although Lua has been designed as an extension language,
+to be embedded in a host C&nbsp;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&nbsp;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>, &middot;&middot;&middot;, <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&nbsp;<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 &ndash; <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&nbsp;5.3 to Lua&nbsp;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 &ndash; <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 &ndash; <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 &ndash; <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 &ndash; <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">&sect;3.4.8</a>;
+for a description of the terminals
+Name, Numeral,
+and LiteralString, see <a href="#3.1">&sect;3.1</a>.)
+
+
+
+
+<pre>
+
+ chunk ::= block
+
+ block ::= {stat} [retstat]
+
+ stat ::= &lsquo;<b>;</b>&rsquo; |
+ varlist &lsquo;<b>=</b>&rsquo; explist |
+ functioncall |
+ label |
+ <b>break</b> |
+ <b>goto</b> Name |
+ <b>do</b> block <b>end</b> |
+ <b>while</b> exp <b>do</b> block <b>end</b> |
+ <b>repeat</b> block <b>until</b> exp |
+ <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 &lsquo;<b>=</b>&rsquo; exp &lsquo;<b>,</b>&rsquo; exp [&lsquo;<b>,</b>&rsquo; 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 [&lsquo;<b>=</b>&rsquo; explist]
+
+ attnamelist ::= Name attrib {&lsquo;<b>,</b>&rsquo; Name attrib}
+
+ attrib ::= [&lsquo;<b>&lt;</b>&rsquo; Name &lsquo;<b>&gt;</b>&rsquo;]
+
+ retstat ::= <b>return</b> [explist] [&lsquo;<b>;</b>&rsquo;]
+
+ label ::= &lsquo;<b>::</b>&rsquo; Name &lsquo;<b>::</b>&rsquo;
+
+ funcname ::= Name {&lsquo;<b>.</b>&rsquo; Name} [&lsquo;<b>:</b>&rsquo; Name]
+
+ varlist ::= var {&lsquo;<b>,</b>&rsquo; var}
+
+ var ::= Name | prefixexp &lsquo;<b>[</b>&rsquo; exp &lsquo;<b>]</b>&rsquo; | prefixexp &lsquo;<b>.</b>&rsquo; Name
+
+ namelist ::= Name {&lsquo;<b>,</b>&rsquo; Name}
+
+ explist ::= exp {&lsquo;<b>,</b>&rsquo; exp}
+
+ exp ::= <b>nil</b> | <b>false</b> | <b>true</b> | Numeral | LiteralString | &lsquo;<b>...</b>&rsquo; | functiondef |
+ prefixexp | tableconstructor | exp binop exp | unop exp
+
+ prefixexp ::= var | functioncall | &lsquo;<b>(</b>&rsquo; exp &lsquo;<b>)</b>&rsquo;
+
+ functioncall ::= prefixexp args | prefixexp &lsquo;<b>:</b>&rsquo; Name args
+
+ args ::= &lsquo;<b>(</b>&rsquo; [explist] &lsquo;<b>)</b>&rsquo; | tableconstructor | LiteralString
+
+ functiondef ::= <b>function</b> funcbody
+
+ funcbody ::= &lsquo;<b>(</b>&rsquo; [parlist] &lsquo;<b>)</b>&rsquo; block <b>end</b>
+
+ parlist ::= namelist [&lsquo;<b>,</b>&rsquo; &lsquo;<b>...</b>&rsquo;] | &lsquo;<b>...</b>&rsquo;
+
+ tableconstructor ::= &lsquo;<b>{</b>&rsquo; [fieldlist] &lsquo;<b>}</b>&rsquo;
+
+ fieldlist ::= field {fieldsep field} [fieldsep]
+
+ field ::= &lsquo;<b>[</b>&rsquo; exp &lsquo;<b>]</b>&rsquo; &lsquo;<b>=</b>&rsquo; exp | Name &lsquo;<b>=</b>&rsquo; exp | exp
+
+ fieldsep ::= &lsquo;<b>,</b>&rsquo; | &lsquo;<b>;</b>&rsquo;
+
+ binop ::= &lsquo;<b>+</b>&rsquo; | &lsquo;<b>-</b>&rsquo; | &lsquo;<b>*</b>&rsquo; | &lsquo;<b>/</b>&rsquo; | &lsquo;<b>//</b>&rsquo; | &lsquo;<b>^</b>&rsquo; | &lsquo;<b>%</b>&rsquo; |
+ &lsquo;<b>&amp;</b>&rsquo; | &lsquo;<b>~</b>&rsquo; | &lsquo;<b>|</b>&rsquo; | &lsquo;<b>&gt;&gt;</b>&rsquo; | &lsquo;<b>&lt;&lt;</b>&rsquo; | &lsquo;<b>..</b>&rsquo; |
+ &lsquo;<b>&lt;</b>&rsquo; | &lsquo;<b>&lt;=</b>&rsquo; | &lsquo;<b>&gt;</b>&rsquo; | &lsquo;<b>&gt;=</b>&rsquo; | &lsquo;<b>==</b>&rsquo; | &lsquo;<b>~=</b>&rsquo; |
+ <b>and</b> | <b>or</b>
+
+ unop ::= &lsquo;<b>-</b>&rsquo; | <b>not</b> | &lsquo;<b>#</b>&rsquo; | &lsquo;<b>~</b>&rsquo;
+
+</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
new file mode 100644
index 0000000000..07df5f6ee7
--- /dev/null
+++ b/src/libs/3rdparty/lua/doc/osi-certified-72x60.png
Binary files differ
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>
+&middot;
+<A HREF="#install">installation</A>
+&middot;
+<A HREF="#changes">changes</A>
+&middot;
+<A HREF="#license">license</A>
+&middot;
+<A HREF="contents.html">reference manual</A>
+</DIV>
+
+<H2><A NAME="about">About Lua</A></H2>
+<P>
+Lua is a powerful, 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 &mdash; edit <TT>Makefile</TT>.
+ <LI> How to build Lua &mdash; edit <TT>src/Makefile</TT>.
+ <LI> Lua features &mdash; 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 &mdash; 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 &copy; 1994&ndash;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, &registry->array[LUA_RIDX_MAINTHREAD - 1], L);
+ /* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */
+ sethvalue(L, &registry->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
diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp
index 4fc1cd2d56..e779c447bf 100644
--- a/src/libs/cplusplus/ResolveExpression.cpp
+++ b/src/libs/cplusplus/ResolveExpression.cpp
@@ -1062,6 +1062,8 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList<LookupItem> &bas
}
typedefsResolver.resolve(&ty, &scope, r.binding());
+ if (auto ref = ty->asReferenceType()) // deref if needed
+ ty = ref->elementType();
if (Q_UNLIKELY(debug))
qDebug() << "- after typedef resolving:" << oo.prettyType(ty);
@@ -1082,6 +1084,9 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList<LookupItem> &bas
if (ClassOrNamespace *binding = findClass(type, scope))
return binding;
+ if (ClassOrNamespace *binding = findClass(type, r.scope())) // local classes and structs
+ return binding;
+
} else {
ClassOrNamespace *binding
= findClassForTemplateParameterInExpressionScope(r.binding(),
@@ -1176,6 +1181,9 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList<LookupItem> &bas
if (ClassOrNamespace *binding = findClass(ty, scope, enclosingBinding))
return binding;
+
+ if (ClassOrNamespace *binding = findClass(ty, r.scope())) // local classes and structs
+ return binding;
}
}
diff --git a/src/libs/extensionsystem/CMakeLists.txt b/src/libs/extensionsystem/CMakeLists.txt
index c8e3766806..a1768577b0 100644
--- a/src/libs/extensionsystem/CMakeLists.txt
+++ b/src/libs/extensionsystem/CMakeLists.txt
@@ -20,10 +20,16 @@ add_qtc_library(ExtensionSystem
find_package(Qt6 COMPONENTS Test QUIET)
+# If ExtensionSystem was compiled with QtTest, it should provide the test options
+# and the test related API, regardless if Qt Creator was compiled with tests or not,
+# and regardless if an external plugin is compiled with tests or not.
+# ExtensionSystem may not require QtTest in public headers though.
+# API with EXTENSIONSYSTEM_TEST_EXPORT (like CppPluginSpec) should only be exported
+# if Qt Creator is compiled with tests.
extend_qtc_library(ExtensionSystem
CONDITION TARGET Qt::Test
DEPENDS Qt::Test
- DEFINES WITH_TESTS
+ PUBLIC_DEFINES EXTENSIONSYSTEM_WITH_TESTOPTION
)
extend_qtc_library(ExtensionSystem
diff --git a/src/libs/extensionsystem/extensionsystem.qbs b/src/libs/extensionsystem/extensionsystem.qbs
index 72fe2f4c3c..c34e97e754 100644
--- a/src/libs/extensionsystem/extensionsystem.qbs
+++ b/src/libs/extensionsystem/extensionsystem.qbs
@@ -2,6 +2,7 @@ QtcLibrary {
name: "ExtensionSystem"
cpp.defines: base.concat(["EXTENSIONSYSTEM_LIBRARY", "IDE_TEST_DIR=\".\""])
+ .concat(qtc.withPluginTests ? ["EXTENSIONSYSTEM_WITH_TESTOPTION"] : [])
Depends { name: "Qt"; submodules: ["core", "widgets"] }
Depends { name: "Qt.testlib"; condition: qtc.withPluginTests }
@@ -35,5 +36,7 @@ QtcLibrary {
Export {
Depends { name: "Qt.core" }
+ Depends { name: "qtc" }
+ cpp.defines: qtc.withPluginTests ? ["EXTENSIONSYSTEM_WITH_TESTOPTION"] : []
}
}
diff --git a/src/libs/extensionsystem/optionsparser.cpp b/src/libs/extensionsystem/optionsparser.cpp
index dd9d03944a..21dfba16ec 100644
--- a/src/libs/extensionsystem/optionsparser.cpp
+++ b/src/libs/extensionsystem/optionsparser.cpp
@@ -64,7 +64,7 @@ bool OptionsParser::parse()
continue;
if (checkForNoCrashcheckOption())
continue;
-#ifdef WITH_TESTS
+#ifdef EXTENSIONSYSTEM_WITH_TESTOPTION
if (checkForTestOptions())
continue;
if (checkForScenarioOption())
diff --git a/src/libs/extensionsystem/plugindetailsview.cpp b/src/libs/extensionsystem/plugindetailsview.cpp
index 73fa2b1229..35e646bad7 100644
--- a/src/libs/extensionsystem/plugindetailsview.cpp
+++ b/src/libs/extensionsystem/plugindetailsview.cpp
@@ -8,6 +8,7 @@
#include "pluginspec.h"
#include <utils/algorithm.h>
+#include <utils/infolabel.h>
#include <utils/layoutbuilder.h>
#include <QCoreApplication>
@@ -54,6 +55,7 @@ public:
, copyright(createContentsLabel())
, license(createTextEdit())
, dependencies(new QListWidget(q))
+ , softLoadable(new Utils::InfoLabel)
{
using namespace Layouting;
@@ -70,7 +72,8 @@ public:
Tr::tr("Description:"), description, br,
Tr::tr("Copyright:"), copyright, br,
Tr::tr("License:"), license, br,
- Tr::tr("Dependencies:"), dependencies,
+ Tr::tr("Dependencies:"), dependencies, br,
+ Tr::tr("Loadable without restart:"), softLoadable, br,
noMargin
}.attachTo(q);
// clang-format on
@@ -90,6 +93,7 @@ public:
QLabel *copyright = nullptr;
QTextEdit *license = nullptr;
QListWidget *dependencies = nullptr;
+ Utils::InfoLabel *softLoadable = nullptr;
private:
QLabel *createContentsLabel() {
@@ -142,7 +146,7 @@ void PluginDetailsView::update(PluginSpec *spec)
d->vendor->setText(spec->vendor());
d->component->setText(spec->category().isEmpty() ? Tr::tr("None") : spec->category());
d->url->setText(QString::fromLatin1("<a href=\"%1\">%1</a>").arg(spec->url()));
- d->location->setText(QDir::toNativeSeparators(spec->filePath()));
+ d->location->setText(spec->filePath().toUserOutput());
const QString pattern = spec->platformSpecification().pattern();
const QString platform = pattern.isEmpty() ? Tr::tr("All") : pattern;
const QString platformString = Tr::tr("%1 (current: \"%2\")")
@@ -157,6 +161,8 @@ void PluginDetailsView::update(PluginSpec *spec)
d->license->setText(spec->license());
d->dependencies->addItems(Utils::transform<QList>(spec->dependencies(),
&PluginDependency::toString));
+ d->softLoadable->setType(spec->isSoftLoadable() ? Utils::InfoLabel::Ok
+ : Utils::InfoLabel::NotOk);
}
void PluginDetailsView::showModal(QWidget *parent, PluginSpec *spec)
diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp
index b5a64e2054..718a66a727 100644
--- a/src/libs/extensionsystem/pluginmanager.cpp
+++ b/src/libs/extensionsystem/pluginmanager.cpp
@@ -42,7 +42,7 @@
#include <QTimer>
#include <QWriteLocker>
-#ifdef WITH_TESTS
+#ifdef EXTENSIONSYSTEM_WITH_TESTOPTION
#include <utils/hostosinfo.h>
#include <QTest>
#include <QThread>
@@ -443,7 +443,7 @@ FutureSynchronizer *PluginManager::futureSynchronizer()
\sa setPluginPaths()
*/
-QStringList PluginManager::pluginPaths()
+FilePaths PluginManager::pluginPaths()
{
return d->pluginPaths;
}
@@ -455,7 +455,7 @@ QStringList PluginManager::pluginPaths()
\sa pluginPaths()
\sa loadPlugins()
*/
-void PluginManager::setPluginPaths(const QStringList &paths)
+void PluginManager::setPluginPaths(const FilePaths &paths)
{
d->setPluginPaths(paths);
}
@@ -641,11 +641,13 @@ void PluginManager::remoteArguments(const QString &serializedArgument, QObject *
for (const PluginSpec *ps : plugins()) {
if (ps->state() == PluginSpec::Running) {
const QStringList pluginOptions = subList(serializedArguments, QLatin1Char(':') + ps->name());
- QObject *socketParent = ps->plugin()->remoteCommand(pluginOptions, workingDirectory,
- arguments);
- if (socketParent && socket) {
- socket->setParent(socketParent);
- socket = nullptr;
+ if (IPlugin *plugin = ps->plugin()) {
+ QObject *socketParent
+ = plugin->remoteCommand(pluginOptions, workingDirectory, arguments);
+ if (socketParent && socket) {
+ socket->setParent(socketParent);
+ socket = nullptr;
+ }
}
}
}
@@ -745,7 +747,7 @@ void PluginManager::formatOptions(QTextStream &str, int optionIndentation, int d
QLatin1String("Disable startup check for previously crashed instance"),
optionIndentation,
descriptionIndentation);
-#ifdef WITH_TESTS
+#ifdef EXTENSIONSYSTEM_WITH_TESTOPTION
formatOption(str, QString::fromLatin1(OptionsParser::TEST_OPTION)
+ QLatin1String(" <plugin>[,testfunction[:testdata]]..."), QString(),
QLatin1String("Run plugin's tests (by default a separate settings path is used)"),
@@ -798,7 +800,7 @@ bool PluginManager::testRunRequested()
return !d->testSpecs.empty();
}
-#ifdef WITH_TESTS
+#ifdef EXTENSIONSYSTEM_WITH_TESTOPTION
// Called in plugin initialization, the scenario function will be called later, from main
bool PluginManager::registerScenario(const QString &scenarioId, std::function<bool()> scenarioStarter)
{
@@ -956,17 +958,18 @@ void PluginManagerPrivate::startDelayedInitialize()
}
NANOTRACE_SHUTDOWN();
emit q->initializationDone();
-#ifdef WITH_TESTS
- if (PluginManager::testRunRequested())
- startTests();
- else if (PluginManager::isScenarioRequested()) {
- if (PluginManager::runScenario()) {
- const QString info = QString("Successfully started scenario \"%1\"...").arg(d->m_requestedScenario);
- qInfo("%s", qPrintable(info));
- } else {
- QMetaObject::invokeMethod(this, [] { emit m_instance->scenarioFinished(1); });
- }
+#ifdef EXTENSIONSYSTEM_WITH_TESTOPTION
+ if (PluginManager::testRunRequested())
+ startTests();
+ else if (PluginManager::isScenarioRequested()) {
+ if (PluginManager::runScenario()) {
+ const QString info
+ = QString("Successfully started scenario \"%1\"...").arg(d->m_requestedScenario);
+ qInfo("%s", qPrintable(info));
+ } else {
+ QMetaObject::invokeMethod(this, [] { emit m_instance->scenarioFinished(1); });
}
+ }
#endif
}
@@ -1068,14 +1071,15 @@ void PluginManagerPrivate::checkForDuplicatePlugins()
static QHash<IPlugin *, QList<TestCreator>> g_testCreators;
-void PluginManagerPrivate::addTestCreator(IPlugin *plugin, const TestCreator &testCreator)
+void PluginManagerPrivate::addTestCreator(
+ [[maybe_unused]] IPlugin *plugin, [[maybe_unused]] const TestCreator &testCreator)
{
-#ifdef WITH_TESTS
+#ifdef EXTENSIONSYSTEM_WITH_TESTOPTION
g_testCreators[plugin].append(testCreator);
#endif
}
-#ifdef WITH_TESTS
+#ifdef EXTENSIONSYSTEM_WITH_TESTOPTION
using TestPlan = QHash<QObject *, QStringList>; // Object -> selected test functions
@@ -1456,7 +1460,7 @@ void PluginManagerPrivate::shutdown()
shutdownEventLoop->exec();
}
deleteAll();
-#ifdef WITH_TESTS
+#ifdef EXTENSIONSYSTEM_WITH_TESTOPTION
if (PluginManager::isScenarioRunning("TestModelManagerInterface")) {
qDebug() << "Point 2: Expect the next call to Point 3 triggers a crash";
QThread::sleep(5);
@@ -1728,7 +1732,7 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt
/*!
\internal
*/
-void PluginManagerPrivate::setPluginPaths(const QStringList &paths)
+void PluginManagerPrivate::setPluginPaths(const FilePaths &paths)
{
qCDebug(pluginLog) << "Plugin search paths:" << paths;
qCDebug(pluginLog) << "Required IID:" << pluginIID;
@@ -1737,17 +1741,18 @@ void PluginManagerPrivate::setPluginPaths(const QStringList &paths)
readPluginPaths();
}
-static const QStringList pluginFiles(const QStringList &pluginPaths)
+static const FilePaths pluginFiles(const FilePaths &pluginPaths)
{
- QStringList pluginFiles;
- QStringList searchPaths = pluginPaths;
+ FilePaths pluginFiles;
+ FilePaths searchPaths = pluginPaths;
while (!searchPaths.isEmpty()) {
- const QDir dir(searchPaths.takeFirst());
- const QFileInfoList files = dir.entryInfoList(QDir::Files | QDir::NoSymLinks);
- const QStringList absoluteFilePaths = Utils::transform(files, &QFileInfo::absoluteFilePath);
- pluginFiles += Utils::filtered(absoluteFilePaths, [](const QString &path) { return QLibrary::isLibrary(path); });
- const QFileInfoList dirs = dir.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot);
- searchPaths += Utils::transform(dirs, &QFileInfo::absoluteFilePath);
+ const FilePath dir = searchPaths.takeFirst().absoluteFilePath();
+ const FilePaths files = dir.dirEntries(QDir::Files | QDir::NoSymLinks);
+ pluginFiles += Utils::filtered(files, [](const FilePath &path) {
+ return QLibrary::isLibrary(path.toFSPathString());
+ });
+ const FilePaths dirs = dir.dirEntries(QDir::Dirs | QDir::NoDotAndDotDot);
+ searchPaths += dirs;
}
return pluginFiles;
}
@@ -1789,11 +1794,12 @@ void PluginManagerPrivate::readPluginPaths()
QVector<PluginSpec *> newSpecs;
// from the file system
- for (const QString &pluginFile : pluginFiles(pluginPaths)) {
- expected_str<PluginSpec *> spec = PluginSpecImpl::read(pluginFile);
+ for (const FilePath &pluginFile : pluginFiles(pluginPaths)) {
+ expected_str<PluginSpec *> spec = readCppPluginSpec(pluginFile);
if (!spec) {
- qCInfo(pluginLog).noquote()
- << QString("Ignoring plugin \"%1\" because: %2").arg(pluginFile).arg(spec.error());
+ qCInfo(pluginLog).noquote() << QString("Ignoring plugin \"%1\" because: %2")
+ .arg(pluginFile.toUserOutput())
+ .arg(spec.error());
continue;
}
newSpecs.append(*spec);
@@ -1801,7 +1807,7 @@ void PluginManagerPrivate::readPluginPaths()
// static
for (const QStaticPlugin &plugin : QPluginLoader::staticPlugins()) {
- expected_str<PluginSpec *> spec = PluginSpecImpl::read(plugin);
+ expected_str<PluginSpec *> spec = readCppPluginSpec(plugin);
QTC_ASSERT_EXPECTED(spec, continue);
newSpecs.append(*spec);
}
diff --git a/src/libs/extensionsystem/pluginmanager.h b/src/libs/extensionsystem/pluginmanager.h
index 74237db5b3..c5045e7187 100644
--- a/src/libs/extensionsystem/pluginmanager.h
+++ b/src/libs/extensionsystem/pluginmanager.h
@@ -6,6 +6,7 @@
#include "extensionsystem_global.h"
#include <aggregation/aggregate.h>
+#include <utils/filepath.h>
#include <utils/qtcsettings.h>
#include <QObject>
@@ -69,8 +70,8 @@ public:
static QVector<PluginSpec *> loadQueue();
static void loadPlugins();
static void loadPluginsAtRuntime(const QSet<PluginSpec *> &plugins);
- static QStringList pluginPaths();
- static void setPluginPaths(const QStringList &paths);
+ static Utils::FilePaths pluginPaths();
+ static void setPluginPaths(const Utils::FilePaths &paths);
static QString pluginIID();
static void setPluginIID(const QString &iid);
static const QVector<PluginSpec *> plugins();
@@ -106,7 +107,7 @@ public:
static bool testRunRequested();
-#ifdef WITH_TESTS
+#ifdef EXTENSIONSYSTEM_WITH_TESTOPTION
static bool registerScenario(const QString &scenarioId, std::function<bool()> scenarioStarter);
static bool isScenarioRequested();
static bool runScenario();
diff --git a/src/libs/extensionsystem/pluginmanager_p.h b/src/libs/extensionsystem/pluginmanager_p.h
index 2404a8b49e..a761614223 100644
--- a/src/libs/extensionsystem/pluginmanager_p.h
+++ b/src/libs/extensionsystem/pluginmanager_p.h
@@ -53,7 +53,7 @@ public:
void addPlugins(const QVector<PluginSpec *> &specs);
void shutdown();
- void setPluginPaths(const QStringList &paths);
+ void setPluginPaths(const Utils::FilePaths &paths);
const QVector<ExtensionSystem::PluginSpec *> loadQueue();
void loadPlugin(PluginSpec *spec, PluginSpec::State destState);
void resolveDependencies();
@@ -91,7 +91,7 @@ public:
QHash<QString, QVector<PluginSpec *>> pluginCategories;
QVector<PluginSpec *> pluginSpecs;
std::vector<TestSpec> testSpecs;
- QStringList pluginPaths;
+ Utils::FilePaths pluginPaths;
QString pluginIID;
QVector<QObject *> allObjects; // ### make this a QVector<QPointer<QObject> > > ?
QStringList defaultDisabledPlugins; // Plugins/Ignored from install settings
@@ -151,7 +151,7 @@ private:
void deleteAll();
void checkForDuplicatePlugins();
-#ifdef WITH_TESTS
+#ifdef EXTENSIONSYSTEM_WITH_TESTOPTION
void startTests();
#endif
};
diff --git a/src/libs/extensionsystem/pluginspec.cpp b/src/libs/extensionsystem/pluginspec.cpp
index abed26c7fb..2d492c385f 100644
--- a/src/libs/extensionsystem/pluginspec.cpp
+++ b/src/libs/extensionsystem/pluginspec.cpp
@@ -23,6 +23,8 @@
#include <QJsonValue>
#include <QPluginLoader>
+Q_LOGGING_CATEGORY(pluginSpecLog, "qtc.extensionsystem.plugin", QtWarningMsg)
+
using namespace ExtensionSystem::Internal;
using namespace Utils;
@@ -198,9 +200,9 @@ public:
QRegularExpression platformSpecification;
QVector<ExtensionSystem::PluginDependency> dependencies;
- PluginSpecImpl::PluginArgumentDescriptions argumentDescriptions;
- QString location;
- QString filePath;
+ PluginSpec::PluginArgumentDescriptions argumentDescriptions;
+ FilePath location;
+ FilePath filePath;
bool experimental{false};
bool deprecated{false};
@@ -232,14 +234,14 @@ public:
/*!
\internal
*/
-PluginSpecImpl::PluginSpecImpl()
+CppPluginSpec::CppPluginSpec()
: d(new PluginSpecImplPrivate)
{}
/*!
\internal
*/
-PluginSpecImpl::~PluginSpecImpl() = default;
+CppPluginSpec::~CppPluginSpec() = default;
/*!
Returns the plugin name. This is valid after the PluginSpec::Read state is
@@ -489,7 +491,7 @@ PluginSpec::PluginArgumentDescriptions PluginSpec::argumentDescriptions() const
/*!
Returns the absolute path to the directory containing the plugin.
*/
-QString PluginSpec::location() const
+FilePath PluginSpec::location() const
{
return d->location;
}
@@ -497,7 +499,7 @@ QString PluginSpec::location() const
/*!
Returns the absolute path to the plugin.
*/
-QString PluginSpec::filePath() const
+FilePath PluginSpec::filePath() const
{
return d->filePath;
}
@@ -576,7 +578,7 @@ bool PluginSpec::provides(const QString &pluginName, const QString &pluginVersio
already been successfully loaded. That is, the PluginSpec::Loaded state
is reached.
*/
-IPlugin *PluginSpecImpl::plugin() const
+IPlugin *CppPluginSpec::plugin() const
{
return d->plugin;
}
@@ -690,19 +692,20 @@ namespace {
\internal
Returns false if the file does not represent a Qt Creator plugin.
*/
-expected_str<PluginSpec *> PluginSpecImpl::read(const QString &fileName)
+expected_str<PluginSpec *> readCppPluginSpec(const FilePath &fileName)
{
- auto spec = new PluginSpecImpl;
+ auto spec = new CppPluginSpec;
+
+ const FilePath absPath = fileName.absoluteFilePath();
- QFileInfo fileInfo(fileName);
- spec->setLocation(fileInfo.absolutePath());
- spec->setFilePath(fileInfo.absoluteFilePath());
+ spec->setLocation(absPath.parentDir());
+ spec->setFilePath(absPath);
spec->d->loader.emplace();
if (Utils::HostOsInfo::isMacHost())
spec->d->loader->setLoadHints(QLibrary::ExportExternalSymbolsHint);
- spec->d->loader->setFileName(fileInfo.absoluteFilePath());
+ spec->d->loader->setFileName(absPath.toFSPathString());
if (spec->d->loader->fileName().isEmpty())
return make_unexpected(::ExtensionSystem::Tr::tr("Cannot open file"));
@@ -713,9 +716,9 @@ expected_str<PluginSpec *> PluginSpecImpl::read(const QString &fileName)
return spec;
}
-expected_str<PluginSpec *> PluginSpecImpl::read(const QStaticPlugin &plugin)
+expected_str<PluginSpec *> readCppPluginSpec(const QStaticPlugin &plugin)
{
- auto spec = new PluginSpecImpl;
+ auto spec = new CppPluginSpec;
qCDebug(pluginLog) << "\nReading meta data of static plugin";
spec->d->staticPlugin = plugin;
@@ -769,7 +772,7 @@ Utils::expected_str<void> PluginSpec::reportError(const QString &error)
/*!
\internal
*/
-expected_str<void> PluginSpecImpl::readMetaData(const QJsonObject &pluginMetaData)
+expected_str<void> CppPluginSpec::readMetaData(const QJsonObject &pluginMetaData)
{
qCDebug(pluginLog).noquote() << "MetaData:" << QJsonDocument(pluginMetaData).toJson();
QJsonValue value;
@@ -1009,7 +1012,7 @@ Utils::expected_str<void> PluginSpecPrivate::readMetaData(const QJsonObject &dat
}
}
- state = PluginSpecImpl::Read;
+ state = PluginSpec::Read;
return {};
}
@@ -1059,11 +1062,11 @@ bool PluginSpec::resolveDependencies(const QVector<PluginSpec *> &specs)
{
if (hasError())
return false;
- if (state() > PluginSpecImpl::Resolved)
+ if (state() > PluginSpec::Resolved)
return true; // We are resolved already.
- if (state() == PluginSpecImpl::Resolved)
- setState(PluginSpecImpl::Read); // Go back, so we just re-resolve the dependencies.
- if (state() != PluginSpecImpl::Read) {
+ if (state() == PluginSpec::Resolved)
+ setState(PluginSpec::Read); // Go back, so we just re-resolve the dependencies.
+ if (state() != PluginSpec::Read) {
setError(::ExtensionSystem::Tr::tr("Resolving dependencies failed because state != Read"));
return false;
}
@@ -1092,7 +1095,7 @@ bool PluginSpec::resolveDependencies(const QVector<PluginSpec *> &specs)
d->dependencySpecs = resolvedDependencies;
- d->state = PluginSpecImpl::Resolved;
+ d->state = PluginSpec::Resolved;
return true;
}
@@ -1108,38 +1111,39 @@ void PluginSpec::setState(State state)
d->state = state;
}
-void PluginSpec::setLocation(const QString &location)
+void PluginSpec::setLocation(const FilePath &location)
{
d->location = location;
}
-void PluginSpec::setFilePath(const QString &filePath)
+void PluginSpec::setFilePath(const FilePath &filePath)
{
d->filePath = filePath;
}
void PluginSpec::setError(const QString &errorString)
{
+ qCWarning(pluginSpecLog).noquote() << "[" << name() << "]"
+ << "Plugin error:" << errorString;
d->errorString = errorString;
}
/*!
\internal
*/
-bool PluginSpecImpl::loadLibrary()
+bool CppPluginSpec::loadLibrary()
{
if (hasError())
return false;
- if (state() != PluginSpecImpl::Resolved) {
- if (state() == PluginSpecImpl::Loaded)
+ if (state() != PluginSpec::Resolved) {
+ if (state() == PluginSpec::Loaded)
return true;
setError(::ExtensionSystem::Tr::tr("Loading the library failed because state != Resolved"));
return false;
}
if (d->loader && !d->loader->load()) {
- setError(QDir::toNativeSeparators(filePath()) + QString::fromLatin1(": ")
- + d->loader->errorString());
+ setError(filePath().toUserOutput() + QString::fromLatin1(": ") + d->loader->errorString());
return false;
}
auto *pluginObject = d->loader ? qobject_cast<IPlugin *>(d->loader->instance())
@@ -1150,7 +1154,7 @@ bool PluginSpecImpl::loadLibrary()
d->loader->unload();
return false;
}
- setState(PluginSpecImpl::Loaded);
+ setState(PluginSpec::Loaded);
d->plugin = pluginObject;
return true;
}
@@ -1158,13 +1162,13 @@ bool PluginSpecImpl::loadLibrary()
/*!
\internal
*/
-bool PluginSpecImpl::initializePlugin()
+bool CppPluginSpec::initializePlugin()
{
if (hasError())
return false;
- if (state() != PluginSpecImpl::Loaded) {
- if (state() == PluginSpecImpl::Initialized)
+ if (state() != PluginSpec::Loaded) {
+ if (state() == PluginSpec::Initialized)
return true;
setError(
::ExtensionSystem::Tr::tr("Initializing the plugin failed because state != Loaded"));
@@ -1180,20 +1184,20 @@ bool PluginSpecImpl::initializePlugin()
setError(::ExtensionSystem::Tr::tr("Plugin initialization failed: %1").arg(err));
return false;
}
- setState(PluginSpecImpl::Initialized);
+ setState(PluginSpec::Initialized);
return true;
}
/*!
\internal
*/
-bool PluginSpecImpl::initializeExtensions()
+bool CppPluginSpec::initializeExtensions()
{
if (hasError())
return false;
- if (state() != PluginSpecImpl::Initialized) {
- if (state() == PluginSpecImpl::Running)
+ if (state() != PluginSpec::Initialized) {
+ if (state() == PluginSpec::Running)
return true;
setError(::ExtensionSystem::Tr::tr(
"Cannot perform extensionsInitialized because state != Initialized"));
@@ -1205,19 +1209,19 @@ bool PluginSpecImpl::initializeExtensions()
return false;
}
d->plugin->extensionsInitialized();
- setState(PluginSpecImpl::Running);
+ setState(PluginSpec::Running);
return true;
}
/*!
\internal
*/
-bool PluginSpecImpl::delayedInitialize()
+bool CppPluginSpec::delayedInitialize()
{
if (hasError())
return true;
- if (state() != PluginSpecImpl::Running)
+ if (state() != PluginSpec::Running)
return false;
if (!d->plugin) {
setError(::ExtensionSystem::Tr::tr(
@@ -1231,21 +1235,21 @@ bool PluginSpecImpl::delayedInitialize()
/*!
\internal
*/
-IPlugin::ShutdownFlag PluginSpecImpl::stop()
+IPlugin::ShutdownFlag CppPluginSpec::stop()
{
if (hasError())
return IPlugin::ShutdownFlag::SynchronousShutdown;
if (!d->plugin)
return IPlugin::SynchronousShutdown;
- setState(PluginSpecImpl::Stopped);
+ setState(PluginSpec::Stopped);
return d->plugin->aboutToShutdown();
}
/*!
\internal
*/
-void PluginSpecImpl::kill()
+void CppPluginSpec::kill()
{
if (hasError())
return;
@@ -1254,6 +1258,6 @@ void PluginSpecImpl::kill()
return;
delete d->plugin;
d->plugin = nullptr;
- setState(PluginSpecImpl::Deleted);
+ setState(PluginSpec::Deleted);
}
} // namespace ExtensionSystem
diff --git a/src/libs/extensionsystem/pluginspec.h b/src/libs/extensionsystem/pluginspec.h
index 09b8f55618..7d45fe82c1 100644
--- a/src/libs/extensionsystem/pluginspec.h
+++ b/src/libs/extensionsystem/pluginspec.h
@@ -8,6 +8,7 @@
#include "iplugin.h"
#include <utils/expected.h>
+#include <utils/filepath.h>
#include <QHash>
#include <QStaticPlugin>
@@ -120,8 +121,8 @@ public:
virtual QJsonObject metaData() const;
virtual PerformanceData &performanceData() const;
virtual PluginArgumentDescriptions argumentDescriptions() const;
- virtual QString location() const;
- virtual QString filePath() const;
+ virtual Utils::FilePath location() const;
+ virtual Utils::FilePath filePath() const;
virtual QStringList arguments() const;
virtual void setArguments(const QStringList &arguments);
virtual void addArgument(const QString &argument);
@@ -160,8 +161,8 @@ protected:
protected:
virtual void setState(State state);
- virtual void setLocation(const QString &location);
- virtual void setFilePath(const QString &filePath);
+ virtual void setLocation(const Utils::FilePath &location);
+ virtual void setFilePath(const Utils::FilePath &filePath);
virtual Utils::expected_str<void> readMetaData(const QJsonObject &metaData);
Utils::expected_str<void> reportError(const QString &error);
@@ -169,10 +170,20 @@ private:
std::unique_ptr<Internal::PluginSpecPrivate> d;
};
-class EXTENSIONSYSTEM_TEST_EXPORT PluginSpecImpl : public PluginSpec
+EXTENSIONSYSTEM_EXPORT Utils::expected_str<PluginSpec *> readCppPluginSpec(
+ const Utils::FilePath &filePath);
+EXTENSIONSYSTEM_EXPORT Utils::expected_str<PluginSpec *> readCppPluginSpec(
+ const QStaticPlugin &plugin);
+
+class EXTENSIONSYSTEM_TEST_EXPORT CppPluginSpec : public PluginSpec
{
+ friend EXTENSIONSYSTEM_EXPORT Utils::expected_str<PluginSpec *> readCppPluginSpec(
+ const Utils::FilePath &filePath);
+ friend EXTENSIONSYSTEM_EXPORT Utils::expected_str<PluginSpec *> readCppPluginSpec(
+ const QStaticPlugin &plugin);
+
public:
- ~PluginSpecImpl() override;
+ ~CppPluginSpec() override;
// linked plugin instance, valid after 'Loaded' state is reached
IPlugin *plugin() const override;
@@ -184,13 +195,10 @@ public:
IPlugin::ShutdownFlag stop() override;
void kill() override;
- static Utils::expected_str<PluginSpec *> read(const QString &filePath);
- static Utils::expected_str<PluginSpec *> read(const QStaticPlugin &plugin);
-
Utils::expected_str<void> readMetaData(const QJsonObject &pluginMetaData) override;
protected:
- PluginSpecImpl();
+ CppPluginSpec();
private:
std::unique_ptr<Internal::PluginSpecImplPrivate> d;
diff --git a/src/libs/extensionsystem/pluginview.cpp b/src/libs/extensionsystem/pluginview.cpp
index 07fa11c7a9..902f90aca4 100644
--- a/src/libs/extensionsystem/pluginview.cpp
+++ b/src/libs/extensionsystem/pluginview.cpp
@@ -119,7 +119,7 @@ public:
toolTip = Tr::tr("Path: %1\nPlugin is disabled by command line argument.");
else
toolTip = Tr::tr("Path: %1");
- return toolTip.arg(QDir::toNativeSeparators(m_spec->filePath()));
+ return toolTip.arg(m_spec->filePath().toUserOutput());
}
if (role == Qt::DecorationRole) {
bool ok = !m_spec->hasError();
diff --git a/src/libs/languageserverprotocol/jsonobject.h b/src/libs/languageserverprotocol/jsonobject.h
index fd90453da1..ce2ad50a40 100644
--- a/src/libs/languageserverprotocol/jsonobject.h
+++ b/src/libs/languageserverprotocol/jsonobject.h
@@ -93,7 +93,8 @@ private:
template<typename T, typename V>
JsonObject::iterator JsonObject::insertVariant(const Key key, const V &variant)
{
- return std::holds_alternative<T>(variant) ? insert(key, std::get<T>(variant)) : end();
+ const auto v = std::get_if<T>(&variant);
+ return v ? insert(key, *v) : end();
}
template<typename T1, typename T2, typename... Args, typename V>
diff --git a/src/libs/languageserverprotocol/jsonrpcmessages.h b/src/libs/languageserverprotocol/jsonrpcmessages.h
index 680bff9578..a794f7f819 100644
--- a/src/libs/languageserverprotocol/jsonrpcmessages.h
+++ b/src/libs/languageserverprotocol/jsonrpcmessages.h
@@ -68,19 +68,19 @@ public:
private:
friend size_t qHash(const MessageId &id)
{
- if (std::holds_alternative<int>(id))
- return QT_PREPEND_NAMESPACE(qHash(std::get<int>(id)));
- if (std::holds_alternative<QString>(id))
- return QT_PREPEND_NAMESPACE(qHash(std::get<QString>(id)));
+ if (const int *iid = std::get_if<int>(&id))
+ return QT_PREPEND_NAMESPACE(qHash(*iid));
+ if (const QString *sid = std::get_if<QString>(&id))
+ return QT_PREPEND_NAMESPACE(qHash(*sid));
return QT_PREPEND_NAMESPACE(qHash(0));
}
friend QDebug operator<<(QDebug stream, const MessageId &id)
{
- if (std::holds_alternative<int>(id))
- stream << std::get<int>(id);
+ if (const int *iid = std::get_if<int>(&id))
+ stream << *iid;
else
- stream << std::get<QString>(id);
+ stream << *std::get_if<QString>(&id);
return stream;
}
};
diff --git a/src/libs/languageserverprotocol/languagefeatures.cpp b/src/libs/languageserverprotocol/languagefeatures.cpp
index dcf076bd03..30e2b6bd84 100644
--- a/src/libs/languageserverprotocol/languagefeatures.cpp
+++ b/src/libs/languageserverprotocol/languagefeatures.cpp
@@ -303,8 +303,8 @@ HoverContent::HoverContent(const QJsonValue &value)
bool HoverContent::isValid() const
{
- if (std::holds_alternative<MarkedString>(*this))
- return std::get<MarkedString>(*this).isValid();
+ if (const auto s = std::get_if<MarkedString>(this))
+ return s->isValid();
return true;
}
diff --git a/src/libs/languageserverprotocol/lsptypes.cpp b/src/libs/languageserverprotocol/lsptypes.cpp
index cb327642e3..1bc8707572 100644
--- a/src/libs/languageserverprotocol/lsptypes.cpp
+++ b/src/libs/languageserverprotocol/lsptypes.cpp
@@ -101,10 +101,10 @@ MarkupOrString::MarkupOrString(const QJsonValue &val)
QJsonValue MarkupOrString::toJson() const
{
- if (std::holds_alternative<QString>(*this))
- return std::get<QString>(*this);
- if (std::holds_alternative<MarkupContent>(*this))
- return QJsonValue(std::get<MarkupContent>(*this));
+ if (const auto s = std::get_if<QString>(this))
+ return *s;
+ if (const auto c = std::get_if<MarkupContent>(this))
+ return QJsonValue(*c);
return {};
}
diff --git a/src/libs/languageserverprotocol/lsputils.h b/src/libs/languageserverprotocol/lsputils.h
index 0c815bafd8..32e2bfa6b7 100644
--- a/src/libs/languageserverprotocol/lsputils.h
+++ b/src/libs/languageserverprotocol/lsputils.h
@@ -89,15 +89,16 @@ public:
QList<T> toListOrEmpty() const
{
- if (std::holds_alternative<QList<T>>(*this))
- return std::get<QList<T>>(*this);
+ if (const auto l = std::get_if<QList<T>>(this))
+ return *l;
return {};
}
QList<T> toList() const
{
- QTC_ASSERT(std::holds_alternative<QList<T>>(*this), return {});
- return std::get<QList<T>>(*this);
+ const auto l = std::get_if<QList<T>>(this);
+ QTC_ASSERT(l, return {});
+ return *l;
}
bool isNull() const { return std::holds_alternative<std::nullptr_t>(*this); }
};
@@ -127,15 +128,17 @@ public:
T value(const T &defaultValue = T()) const
{
- QTC_ASSERT(std::holds_alternative<T>(*this), return defaultValue);
- return std::get<T>(*this);
+ const auto t = std::get_if<T>(this);
+ QTC_ASSERT(t, return defaultValue);
+ return *t;
}
template<typename Type>
LanguageClientValue<Type> transform()
{
- QTC_ASSERT(!std::holds_alternative<T>(*this), return LanguageClientValue<Type>());
- return Type(std::get<T>(*this));
+ const auto t = std::get_if<T>(this);
+ QTC_ASSERT(t, return LanguageClientValue<Type>());
+ return Type(*t);
}
bool isNull() const { return std::holds_alternative<std::nullptr_t>(*this); }
diff --git a/src/libs/languageserverprotocol/progresssupport.cpp b/src/libs/languageserverprotocol/progresssupport.cpp
index 2ae4af1b98..ce110782dc 100644
--- a/src/libs/languageserverprotocol/progresssupport.cpp
+++ b/src/libs/languageserverprotocol/progresssupport.cpp
@@ -21,9 +21,9 @@ ProgressToken::ProgressToken(const QJsonValue &value)
ProgressToken::operator QJsonValue() const
{
- if (std::holds_alternative<QString>(*this))
- return QJsonValue(std::get<QString>(*this));
- return QJsonValue(std::get<int>(*this));
+ if (const auto s = std::get_if<QString>(this))
+ return QJsonValue(*s);
+ return QJsonValue(*std::get_if<int>(this));
}
ProgressParams::ProgressType ProgressParams::value() const
diff --git a/src/libs/languageserverprotocol/servercapabilities.cpp b/src/libs/languageserverprotocol/servercapabilities.cpp
index 0c57f47131..b109d08687 100644
--- a/src/libs/languageserverprotocol/servercapabilities.cpp
+++ b/src/libs/languageserverprotocol/servercapabilities.cpp
@@ -189,10 +189,10 @@ void ServerCapabilities::setCallHierarchyProvider(
const std::variant<bool, WorkDoneProgressOptions> &callHierarchyProvider)
{
QJsonValue val;
- if (std::holds_alternative<bool>(callHierarchyProvider))
- val = std::get<bool>(callHierarchyProvider);
- else if (std::holds_alternative<WorkDoneProgressOptions>(callHierarchyProvider))
- val = QJsonObject(std::get<WorkDoneProgressOptions>(callHierarchyProvider));
+ if (const auto boolvalue = std::get_if<bool>(&callHierarchyProvider))
+ val = *boolvalue;
+ else if (const auto options = std::get_if<WorkDoneProgressOptions>(&callHierarchyProvider))
+ val = QJsonObject(*options);
insert(callHierarchyProviderKey, val);
}
@@ -211,10 +211,10 @@ void ServerCapabilities::setTypeHierarchyProvider(
const std::variant<bool, WorkDoneProgressOptions> &typeHierarchyProvider)
{
QJsonValue val;
- if (std::holds_alternative<bool>(typeHierarchyProvider))
- val = std::get<bool>(typeHierarchyProvider);
- else if (std::holds_alternative<WorkDoneProgressOptions>(typeHierarchyProvider))
- val = QJsonObject(std::get<WorkDoneProgressOptions>(typeHierarchyProvider));
+ if (const auto boolvalue = std::get_if<bool>(&typeHierarchyProvider))
+ val = *boolvalue;
+ else if (const auto options = std::get_if<WorkDoneProgressOptions>(&typeHierarchyProvider))
+ val = QJsonObject(*options);
insert(typeHierarchyProviderKey, val);
}
diff --git a/src/libs/languageserverprotocol/workspace.cpp b/src/libs/languageserverprotocol/workspace.cpp
index 2d49be2d5f..0d37b80934 100644
--- a/src/libs/languageserverprotocol/workspace.cpp
+++ b/src/libs/languageserverprotocol/workspace.cpp
@@ -64,10 +64,11 @@ ExecuteCommandParams::ExecuteCommandParams(const Command &command)
LanguageServerProtocol::WorkSpaceFolderResult::operator const QJsonValue() const
{
- if (!std::holds_alternative<QList<WorkSpaceFolder>>(*this))
+ const auto folders = std::get_if<QList<WorkSpaceFolder>>(this);
+ if (!folders)
return QJsonValue::Null;
QJsonArray array;
- for (const auto &folder : std::get<QList<WorkSpaceFolder>>(*this))
+ for (const auto &folder : *folders)
array.append(QJsonValue(folder));
return array;
}
diff --git a/src/libs/languageutils/componentversion.cpp b/src/libs/languageutils/componentversion.cpp
index 6c599e300b..f041740d3b 100644
--- a/src/libs/languageutils/componentversion.cpp
+++ b/src/libs/languageutils/componentversion.cpp
@@ -10,27 +10,17 @@
namespace LanguageUtils {
-const int ComponentVersion::NoVersion = -1;
-const int ComponentVersion::MaxVersion = std::numeric_limits<int>::max();
+// QTC_TEMP
-ComponentVersion::ComponentVersion()
- : _major(NoVersion), _minor(NoVersion)
+ComponentVersion::ComponentVersion(QStringView versionString)
+ : _major(NoVersion)
+ , _minor(NoVersion)
{
-}
-
-ComponentVersion::ComponentVersion(int major, int minor)
- : _major(major), _minor(minor)
-{
-}
-
-ComponentVersion::ComponentVersion(const QString &versionString)
- : _major(NoVersion), _minor(NoVersion)
-{
- int dotIdx = versionString.indexOf(QLatin1Char('.'));
+ auto dotIdx = versionString.indexOf(QLatin1Char('.'));
if (dotIdx == -1)
return;
bool ok = false;
- int maybeMajor = versionString.left(dotIdx).toInt(&ok);
+ auto maybeMajor = versionString.left(dotIdx).toInt(&ok);
if (!ok)
return;
int maybeMinor = versionString.mid(dotIdx + 1).toInt(&ok);
@@ -40,15 +30,6 @@ ComponentVersion::ComponentVersion(const QString &versionString)
_minor = maybeMinor;
}
-ComponentVersion::~ComponentVersion()
-{
-}
-
-bool ComponentVersion::isValid() const
-{
- return _major >= 0 && _minor >= 0;
-}
-
QString ComponentVersion::toString() const
{
QByteArray temp;
@@ -65,36 +46,4 @@ void ComponentVersion::addToHash(QCryptographicHash &hash) const
hash.addData(reinterpret_cast<const char *>(&_minor), sizeof(_minor));
}
-bool operator<(const ComponentVersion &lhs, const ComponentVersion &rhs)
-{
- return lhs.majorVersion() < rhs.majorVersion()
- || (lhs.majorVersion() == rhs.majorVersion() && lhs.minorVersion() < rhs.minorVersion());
-}
-
-bool operator<=(const ComponentVersion &lhs, const ComponentVersion &rhs)
-{
- return lhs.majorVersion() < rhs.majorVersion()
- || (lhs.majorVersion() == rhs.majorVersion() && lhs.minorVersion() <= rhs.minorVersion());
-}
-
-bool operator>(const ComponentVersion &lhs, const ComponentVersion &rhs)
-{
- return rhs < lhs;
-}
-
-bool operator>=(const ComponentVersion &lhs, const ComponentVersion &rhs)
-{
- return rhs <= lhs;
-}
-
-bool operator==(const ComponentVersion &lhs, const ComponentVersion &rhs)
-{
- return lhs.majorVersion() == rhs.majorVersion() && lhs.minorVersion() == rhs.minorVersion();
-}
-
-bool operator!=(const ComponentVersion &lhs, const ComponentVersion &rhs)
-{
- return !(lhs == rhs);
-}
-
} // namespace LanguageUtils
diff --git a/src/libs/languageutils/componentversion.h b/src/libs/languageutils/componentversion.h
index 4b39e8402a..2b8311a6cb 100644
--- a/src/libs/languageutils/componentversion.h
+++ b/src/libs/languageutils/componentversion.h
@@ -9,6 +9,10 @@ QT_BEGIN_NAMESPACE
class QCryptographicHash;
QT_END_NAMESPACE
+#include <QStringView>
+
+#include <limits>
+
namespace LanguageUtils {
class LANGUAGEUTILS_EXPORT ComponentVersion
@@ -17,25 +21,56 @@ class LANGUAGEUTILS_EXPORT ComponentVersion
int _minor;
public:
- static const int NoVersion;
- static const int MaxVersion;
+ static constexpr int NoVersion = -1;
+ static constexpr int MaxVersion = std::numeric_limits<int>::max();
+
+ ComponentVersion()
+ : _major(NoVersion)
+ , _minor(NoVersion)
+ {}
- ComponentVersion();
- ComponentVersion(int major, int minor);
- explicit ComponentVersion(const QString &versionString);
- ~ComponentVersion();
+ ComponentVersion(int major, int minor)
+ : _major(major)
+ , _minor(minor)
+ {}
+
+ explicit ComponentVersion(QStringView versionString);
+ ~ComponentVersion() = default;
int majorVersion() const { return _major; }
int minorVersion() const { return _minor; }
- friend bool LANGUAGEUTILS_EXPORT operator<(const ComponentVersion &lhs, const ComponentVersion &rhs);
- friend bool LANGUAGEUTILS_EXPORT operator<=(const ComponentVersion &lhs, const ComponentVersion &rhs);
- friend bool LANGUAGEUTILS_EXPORT operator>(const ComponentVersion &lhs, const ComponentVersion &rhs);
- friend bool LANGUAGEUTILS_EXPORT operator>=(const ComponentVersion &lhs, const ComponentVersion &rhs);
- friend bool LANGUAGEUTILS_EXPORT operator==(const ComponentVersion &lhs, const ComponentVersion &rhs);
- friend bool LANGUAGEUTILS_EXPORT operator!=(const ComponentVersion &lhs, const ComponentVersion &rhs);
+ friend bool operator<(const ComponentVersion &lhs, const ComponentVersion &rhs)
+ {
+ return std::tie(lhs._major, lhs._minor) < std::tie(rhs._major, rhs._minor);
+ }
+
+ friend bool operator<=(const ComponentVersion &lhs, const ComponentVersion &rhs)
+ {
+ return std::tie(lhs._major, lhs._minor) <= std::tie(rhs._major, rhs._minor);
+ }
+
+ friend bool operator>(const ComponentVersion &lhs, const ComponentVersion &rhs)
+ {
+ return rhs < lhs;
+ }
+
+ friend bool operator>=(const ComponentVersion &lhs, const ComponentVersion &rhs)
+ {
+ return rhs <= lhs;
+ }
+
+ friend bool operator==(const ComponentVersion &lhs, const ComponentVersion &rhs)
+ {
+ return lhs.majorVersion() == rhs.majorVersion() && lhs.minorVersion() == rhs.minorVersion();
+ }
+
+ friend bool operator!=(const ComponentVersion &lhs, const ComponentVersion &rhs)
+ {
+ return !(lhs == rhs);
+ }
- bool isValid() const;
+ bool isValid() const { return _major >= 0 && _minor >= 0; }
QString toString() const;
void addToHash(QCryptographicHash &hash) const;
};
diff --git a/src/libs/libs.qbs b/src/libs/libs.qbs
index a6426d4ae4..aaf42e181c 100644
--- a/src/libs/libs.qbs
+++ b/src/libs/libs.qbs
@@ -26,7 +26,9 @@ Project {
"utils/utils.qbs",
"3rdparty/libptyqt/ptyqt.qbs",
"3rdparty/libvterm/vterm.qbs",
+ "3rdparty/lua/lua.qbs",
"3rdparty/qtkeychain/qtkeychain.qbs",
+ "3rdparty/sol2/sol2.qbs",
"3rdparty/syntax-highlighting/syntax-highlighting.qbs",
"3rdparty/winpty/winpty.qbs",
"3rdparty/yaml-cpp/yaml-cpp.qbs",
diff --git a/src/libs/modelinglib/CMakeLists.txt b/src/libs/modelinglib/CMakeLists.txt
index 27801f479a..e966b39459 100644
--- a/src/libs/modelinglib/CMakeLists.txt
+++ b/src/libs/modelinglib/CMakeLists.txt
@@ -126,12 +126,15 @@ add_qtc_library(Modeling
qmt/model/mrelation.cpp qmt/model/mrelation.h
qmt/model/msourceexpansion.cpp qmt/model/msourceexpansion.h
qmt/model/mvisitor.h
+ qmt/model_ui/modeltreefilterdata.h qmt/model_ui/modeltreefilterdata.cpp
qmt/model_ui/modeltreeviewinterface.h
qmt/model_ui/sortedtreemodel.cpp qmt/model_ui/sortedtreemodel.h
qmt/model_ui/stereotypescontroller.cpp qmt/model_ui/stereotypescontroller.h
qmt/model_ui/treemodel.cpp qmt/model_ui/treemodel.h
qmt/model_ui/treemodelmanager.cpp qmt/model_ui/treemodelmanager.h
+ qmt/model_widgets_ui/addrelatedelementsdialog.h qmt/model_widgets_ui/addrelatedelementsdialog.cpp
qmt/model_widgets_ui/classmembersedit.cpp qmt/model_widgets_ui/classmembersedit.h
+ qmt/model_widgets_ui/modeltreefilter.h qmt/model_widgets_ui/modeltreefilter.cpp
qmt/model_widgets_ui/modeltreeview.cpp qmt/model_widgets_ui/modeltreeview.h
qmt/model_widgets_ui/palettebox.cpp qmt/model_widgets_ui/palettebox.h
qmt/model_widgets_ui/propertiesview.cpp qmt/model_widgets_ui/propertiesview.h
@@ -158,6 +161,7 @@ add_qtc_library(Modeling
qmt/style/defaultstyle.h
qmt/style/objectvisuals.cpp qmt/style/objectvisuals.h
qmt/style/relationstarterstyle.cpp qmt/style/relationstarterstyle.h
+ qmt/style/relationvisuals.cpp qmt/style/relationvisuals.h
qmt/style/stylecontroller.cpp qmt/style/stylecontroller.h
qmt/style/style.cpp
qmt/style/styledobject.cpp qmt/style/styledobject.h
diff --git a/src/libs/modelinglib/modelinglib.qbs b/src/libs/modelinglib/modelinglib.qbs
index 90fc1d0d98..9929bf33c0 100644
--- a/src/libs/modelinglib/modelinglib.qbs
+++ b/src/libs/modelinglib/modelinglib.qbs
@@ -238,6 +238,8 @@ QtcLibrary {
"model_controller/mselection.h",
"model_controller/mvoidvisitor.cpp",
"model_controller/mvoidvisitor.h",
+ "model_ui/modeltreefilterdata.cpp",
+ "model_ui/modeltreefilterdata.h",
"model_ui/modeltreeviewinterface.h",
"model_ui/sortedtreemodel.cpp",
"model_ui/sortedtreemodel.h",
@@ -247,8 +249,12 @@ QtcLibrary {
"model_ui/treemodel.h",
"model_ui/treemodelmanager.cpp",
"model_ui/treemodelmanager.h",
+ "model_widgets_ui/addrelatedelementsdialog.h",
+ "model_widgets_ui/addrelatedelementsdialog.cpp",
"model_widgets_ui/classmembersedit.cpp",
"model_widgets_ui/classmembersedit.h",
+ "model_widgets_ui/modeltreefilter.cpp",
+ "model_widgets_ui/modeltreefilter.h",
"model_widgets_ui/modeltreeview.cpp",
"model_widgets_ui/modeltreeview.h",
"model_widgets_ui/palettebox.cpp",
@@ -295,6 +301,8 @@ QtcLibrary {
"style/objectvisuals.h",
"style/relationstarterstyle.cpp",
"style/relationstarterstyle.h",
+ "style/relationvisuals.cpp",
+ "style/relationvisuals.h",
"style/style.cpp",
"style/style.h",
"style/stylecontroller.cpp",
diff --git a/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp b/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp
index b3caebb164..981641e0ad 100644
--- a/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp
+++ b/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp
@@ -28,12 +28,15 @@ static const int KEYWORD_WIDTH = 6;
static const int KEYWORD_HEIGHT = 7;
static const int KEYWORD_MINWIDTH = 8;
static const int KEYWORD_MINHEIGHT = 9;
-static const int KEYWORD_LOCK_SIZE = 10;
-static const int KEYWORD_DISPLAY = 11;
-static const int KEYWORD_TEXTALIGN = 12;
-static const int KEYWORD_BASECOLOR = 13;
-static const int KEYWORD_SHAPE = 14;
-static const int KEYWORD_OUTLINE = 15;
+static const int KEYWORD_ICONWIDTH = 10;
+static const int KEYWORD_ICONHEIGHT = 11;
+static const int KEYWORD_LOCK_SIZE = 12;
+static const int KEYWORD_DISPLAY = 13;
+static const int KEYWORD_TEXTALIGN = 14;
+static const int KEYWORD_BASECOLOR = 15;
+static const int KEYWORD_SHAPE = 16;
+static const int KEYWORD_OUTLINE = 17;
+static const int KEYWORD_Z = 18;
// Shape items
static const int KEYWORD_CIRCLE = 30;
@@ -102,8 +105,18 @@ static const int KEYWORD_DASH = 136;
static const int KEYWORD_DASHDOT = 137;
static const int KEYWORD_DASHDOTDOT = 138;
static const int KEYWORD_COLOR = 139;
-
-// Operatoren
+static const int KEYWORD_EMPHASIZED = 140;
+
+// Shape Value Units and Origin
+static const int KEYWORD_ABS = 150;
+static const int KEYWORD_FIX = 151;
+static const int KEYWORD_SCALE = 152;
+static const int KEYWORD_FRACT = 153;
+static const int KEYWORD_ORIGIN = 154;
+static const int KEYWORD_CENTER = 155;
+static const int KEYWORD_SIZE = 156;
+
+// Operators
static const int OPERATOR_SEMICOLON = 1;
static const int OPERATOR_BRACE_OPEN = 2;
static const int OPERATOR_BRACE_CLOSE = 3;
@@ -111,6 +124,7 @@ static const int OPERATOR_COLON = 4;
static const int OPERATOR_COMMA = 5;
static const int OPERATOR_PERIOD = 6;
static const int OPERATOR_MINUS = 7;
+static const int OPERATOR_PERCENTAGE = 8;
template <typename T, typename U>
QHash<T, U> operator<<(QHash<T, U> hash, QPair<T, U> pair) {
@@ -213,12 +227,15 @@ void StereotypeDefinitionParser::parse(ITextSource *source)
{"height", KEYWORD_HEIGHT},
{"minwidth", KEYWORD_MINWIDTH},
{"minheight", KEYWORD_MINHEIGHT},
+ {"iconwidth", KEYWORD_ICONWIDTH},
+ {"iconheight", KEYWORD_ICONHEIGHT},
{"locksize", KEYWORD_LOCK_SIZE},
{"display", KEYWORD_DISPLAY},
{"textalignment", KEYWORD_TEXTALIGN},
{"basecolor", KEYWORD_BASECOLOR},
{"shape", KEYWORD_SHAPE},
{"outline", KEYWORD_OUTLINE},
+ {"z", KEYWORD_Z},
{"circle", KEYWORD_CIRCLE},
{"ellipse", KEYWORD_ELLIPSE},
{"line", KEYWORD_LINE},
@@ -276,7 +293,15 @@ void StereotypeDefinitionParser::parse(ITextSource *source)
{"dash", KEYWORD_DASH},
{"dashdot", KEYWORD_DASHDOT},
{"dashdotdot", KEYWORD_DASHDOTDOT},
- {"color", KEYWORD_COLOR}});
+ {"color", KEYWORD_COLOR},
+ {"emphasized", KEYWORD_EMPHASIZED},
+ {"abs", KEYWORD_ABS},
+ {"fix", KEYWORD_FIX},
+ {"scale", KEYWORD_SCALE},
+ {"fract", KEYWORD_FRACT},
+ {"origin", KEYWORD_ORIGIN},
+ {"center", KEYWORD_CENTER},
+ {"size", KEYWORD_SIZE}});
textScanner.setOperators({{";", OPERATOR_SEMICOLON},
{"{", OPERATOR_BRACE_OPEN},
@@ -284,7 +309,8 @@ void StereotypeDefinitionParser::parse(ITextSource *source)
{":", OPERATOR_COLON},
{",", OPERATOR_COMMA},
{".", OPERATOR_PERIOD},
- {"-", OPERATOR_MINUS}});
+ {"-", OPERATOR_MINUS},
+ {"%", OPERATOR_PERCENTAGE}});
textScanner.setSource(source);
@@ -364,6 +390,23 @@ void StereotypeDefinitionParser::parseIcon()
case KEYWORD_MINHEIGHT:
stereotypeIcon.setMinHeight(parseFloatProperty());
break;
+ case KEYWORD_ICONWIDTH:
+ stereotypeIcon.setIconWith(parseFloatProperty());
+ break;
+ case KEYWORD_ICONHEIGHT:
+ stereotypeIcon.setIconHeight(parseFloatProperty());
+ break;
+ case KEYWORD_Z:
+ {
+ const static QHash<QString, StereotypeIcon::DepthLayer> zNames = QHash<QString, StereotypeIcon::DepthLayer>()
+ << qMakePair(QString("behinditems"), StereotypeIcon::DepthBehindItems)
+ << qMakePair(QString("amongitems"), StereotypeIcon::DepthAmongItems)
+ << qMakePair(QString("beforeitems"), StereotypeIcon::DepthBeforeItems);
+ parseEnum<StereotypeIcon::DepthLayer>(
+ parseIdentifierProperty(), zNames, token.sourcePos(),
+ [&](StereotypeIcon::DepthLayer layer) { stereotypeIcon.setDepthLayer(layer); });
+ break;
+ }
case KEYWORD_LOCK_SIZE:
{
const static QHash<QString, StereotypeIcon::SizeLock> lockNames
@@ -577,7 +620,7 @@ QHash<int, StereotypeDefinitionParser::IconCommandParameter> StereotypeDefinitio
throw StereotypeDefinitionParserError("Property given twice.", token.sourcePos());
IconCommandParameter parameter = parameters.value(token.subtype());
if (parameter.type() == IconCommandParameter::ShapeValue)
- parameter.setShapeValue(ShapeValueF(parseFloatProperty(), parameter.unit(), parameter.origin()));
+ parameter.setShapeValue(parseShapeValueProperty(parameter.unit(), parameter.origin()));
else if (parameter.type() == IconCommandParameter::Boolean)
parameter.setBoolean(parseBoolProperty());
else
@@ -650,8 +693,6 @@ void StereotypeDefinitionParser::parseRelation(CustomRelation::Element element)
}
case KEYWORD_COLOR:
{
- if (element != CustomRelation::Element::Relation)
- throwUnknownPropertyError(token);
Value expression = parseProperty();
if (expression.type() == Color) {
relation.setColorType(CustomRelation::ColorType::Custom);
@@ -663,6 +704,10 @@ void StereotypeDefinitionParser::parseRelation(CustomRelation::Element element)
relation.setColorType(CustomRelation::ColorType::EndA);
} else if (colorName == "b") {
relation.setColorType(CustomRelation::ColorType::EndB);
+ } else if (colorName == "warning") {
+ relation.setColorType(CustomRelation::ColorType::Warning);
+ } else if (colorName == "error") {
+ relation.setColorType(CustomRelation::ColorType::Error);
} else if (QColor::isValidColor(colorName)) {
relation.setColorType(CustomRelation::ColorType::Custom);
relation.setColor(QColor(colorName));
@@ -674,6 +719,9 @@ void StereotypeDefinitionParser::parseRelation(CustomRelation::Element element)
}
break;
}
+ case KEYWORD_EMPHASIZED:
+ relation.setEmphasized(parseBoolProperty());
+ break;
case KEYWORD_END:
parseRelationEnd(&relation);
break;
@@ -976,6 +1024,65 @@ StereotypeDefinitionParser::Value StereotypeDefinitionParser::parseProperty()
return parseExpression();
}
+ShapeValueF StereotypeDefinitionParser::parseShapeValueProperty(ShapeValueF::Unit unit, ShapeValueF::Origin origin)
+{
+ expectColon();
+ qreal value = parseFloatExpression();
+ // unit
+ Token token = d->m_scanner->read();
+ if (token.type() == Token::TokenOperator) {
+ switch (token.subtype()) {
+ case OPERATOR_PERCENTAGE:
+ unit = ShapeValueF::UnitPercentage;
+ break;
+ default:
+ d->m_scanner->unread(token);
+ break;
+ }
+ } else if (token.type() == Token::TokenKeyword) {
+ switch (token.subtype()) {
+ case KEYWORD_ABS:
+ unit = ShapeValueF::UnitAbsolute;
+ break;
+ case KEYWORD_FIX:
+ unit = ShapeValueF::UnitRelative;
+ break;
+ case KEYWORD_SCALE:
+ unit = ShapeValueF::UnitScaled;
+ break;
+ case KEYWORD_FRACT:
+ unit = ShapeValueF::UnitPercentage;
+ break;
+ default:
+ d->m_scanner->unread(token);
+ break;
+ }
+ } else {
+ d->m_scanner->unread(token);
+ }
+ // origin
+ token = d->m_scanner->read();
+ if (token.type() == Token::TokenKeyword) {
+ switch (token.subtype()) {
+ case KEYWORD_ORIGIN:
+ origin = ShapeValueF::OriginTopOrLeft;
+ break;
+ case KEYWORD_CENTER:
+ origin = ShapeValueF::OriginCenter;
+ break;
+ case KEYWORD_SIZE:
+ origin = ShapeValueF::OriginBottomOrRight;
+ break;
+ default:
+ d->m_scanner->unread(token);
+ break;
+ }
+ } else {
+ d->m_scanner->unread(token);
+ }
+ return ShapeValueF(value, unit, origin);
+}
+
QString StereotypeDefinitionParser::parseStringExpression()
{
Token token = d->m_scanner->read();
diff --git a/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.h b/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.h
index e32126c730..97b14211ca 100644
--- a/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.h
+++ b/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.h
@@ -6,6 +6,7 @@
#include <QObject>
#include "qmt/infrastructure/exceptions.h"
#include "qmt/stereotype/customrelation.h"
+#include "qmt/stereotype/shapevalue.h"
#include "qmt/stereotype/toolbar.h"
#include "sourcepos.h"
@@ -20,7 +21,6 @@ class ITextSource;
class Token;
class StereotypeIcon;
class Toolbar;
-class ShapeValueF;
class QMT_EXPORT StereotypeDefinitionParserError : public Exception
{
@@ -97,6 +97,7 @@ private:
bool parseBoolProperty();
QColor parseColorProperty();
Value parseProperty();
+ ShapeValueF parseShapeValueProperty(ShapeValueF::Unit unit, ShapeValueF::Origin origin);
QString parseStringExpression();
qreal parseFloatExpression();
diff --git a/src/libs/modelinglib/qmt/diagram/dobject.cpp b/src/libs/modelinglib/qmt/diagram/dobject.cpp
index 4e0e5cb642..68e954b857 100644
--- a/src/libs/modelinglib/qmt/diagram/dobject.cpp
+++ b/src/libs/modelinglib/qmt/diagram/dobject.cpp
@@ -25,7 +25,10 @@ DObject::DObject(const DObject &rhs)
m_visualSecondaryRole(rhs.m_visualSecondaryRole),
m_stereotypeDisplay(rhs.m_stereotypeDisplay),
m_isAutoSized(rhs.m_isAutoSized),
- m_isVisualEmphasized(rhs.m_isVisualEmphasized)
+ m_isVisualEmphasized(rhs.m_isVisualEmphasized),
+ m_hasLinkedFile(rhs.m_hasLinkedFile),
+ m_imagePath(rhs.m_imagePath),
+ m_image(rhs.m_image)
{
}
@@ -49,6 +52,9 @@ DObject &DObject::operator =(const DObject &rhs)
m_stereotypeDisplay = rhs.m_stereotypeDisplay;
m_isAutoSized = rhs.m_isAutoSized;
m_isVisualEmphasized = rhs.m_isVisualEmphasized;
+ m_hasLinkedFile = rhs.m_hasLinkedFile;
+ m_imagePath = rhs.m_imagePath;
+ m_image = rhs.m_image;
}
return *this;
}
@@ -113,6 +119,26 @@ void DObject::setVisualEmphasized(bool visualEmphasized)
m_isVisualEmphasized = visualEmphasized;
}
+void DObject::setLinkedFile(bool linkedFile)
+{
+ m_hasLinkedFile = linkedFile;
+}
+
+bool DObject::hasImage() const
+{
+ return !m_image.isNull();
+}
+
+void DObject::setImagePath(const QString &path)
+{
+ m_imagePath = path;
+}
+
+void DObject::setImage(const QImage &image)
+{
+ m_image = image;
+}
+
void DObject::accept(DVisitor *visitor)
{
visitor->visitDObject(this);
diff --git a/src/libs/modelinglib/qmt/diagram/dobject.h b/src/libs/modelinglib/qmt/diagram/dobject.h
index c8cf2b0e4d..bf43edea12 100644
--- a/src/libs/modelinglib/qmt/diagram/dobject.h
+++ b/src/libs/modelinglib/qmt/diagram/dobject.h
@@ -7,6 +7,7 @@
#include "qmt/infrastructure/uid.h"
+#include <QImage>
#include <QList>
#include <QPointF>
#include <QRectF>
@@ -78,6 +79,13 @@ public:
void setAutoSized(bool autoSized);
bool isVisualEmphasized() const { return m_isVisualEmphasized; }
void setVisualEmphasized(bool visualEmphasized);
+ bool hasLinkedFile() const { return m_hasLinkedFile; }
+ void setLinkedFile(bool linkedFile);
+ QString imagePath() const { return m_imagePath; }
+ void setImagePath(const QString &path);
+ bool hasImage() const;
+ QImage image() const { return m_image; }
+ void setImage(const QImage &image);
void accept(DVisitor *visitor) override;
void accept(DConstVisitor *visitor) const override;
@@ -95,6 +103,9 @@ private:
StereotypeDisplay m_stereotypeDisplay = StereotypeSmart;
bool m_isAutoSized = true;
bool m_isVisualEmphasized = false;
+ bool m_hasLinkedFile = false;
+ QString m_imagePath;
+ QImage m_image;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/diagram/drelation.cpp b/src/libs/modelinglib/qmt/diagram/drelation.cpp
index a21f61c707..890bd275e4 100644
--- a/src/libs/modelinglib/qmt/diagram/drelation.cpp
+++ b/src/libs/modelinglib/qmt/diagram/drelation.cpp
@@ -65,6 +65,31 @@ void DRelation::setIntermediatePoints(const QList<DRelation::IntermediatePoint>
m_intermediatePoints = intermediatePoints;
}
+void DRelation::setVisualPrimaryRole(VisualPrimaryRole visualPrimaryRole)
+{
+ m_visualPrimaryRole = visualPrimaryRole;
+}
+
+void DRelation::setVisualSecondaryRole(VisualSecondaryRole visualSecondaryRole)
+{
+ m_visualSecondaryRole = visualSecondaryRole;
+}
+
+void DRelation::setVisualEmphasized(bool visualEmphasized)
+{
+ m_isVisualEmphasized = visualEmphasized;
+}
+
+void DRelation::setColor(const QColor &color)
+{
+ m_color = color;
+}
+
+void DRelation::setThickness(qreal thickness)
+{
+ m_thickness = thickness;
+}
+
void DRelation::accept(DVisitor *visitor)
{
visitor->visitDRelation(this);
diff --git a/src/libs/modelinglib/qmt/diagram/drelation.h b/src/libs/modelinglib/qmt/diagram/drelation.h
index 34bdaf1986..ed5624ad9f 100644
--- a/src/libs/modelinglib/qmt/diagram/drelation.h
+++ b/src/libs/modelinglib/qmt/diagram/drelation.h
@@ -5,6 +5,7 @@
#include "delement.h"
+#include <QColor>
#include <QList>
#include <QPointF>
@@ -15,6 +16,22 @@ class DObject;
class QMT_EXPORT DRelation : public DElement
{
public:
+ enum VisualPrimaryRole {
+ PrimaryRoleNormal,
+ PrimaryRoleCustom1,
+ PrimaryRoleCustom2,
+ PrimaryRoleCustom3,
+ PrimaryRoleCustom4,
+ PrimaryRoleCustom5
+ };
+
+ enum VisualSecondaryRole {
+ SecondaryRoleNone,
+ SecondaryRoleWarning,
+ SecondaryRoleError,
+ SecondaryRoleSoften
+ };
+
class IntermediatePoint
{
public:
@@ -42,6 +59,16 @@ public:
void setName(const QString &name);
const QList<IntermediatePoint> intermediatePoints() const { return m_intermediatePoints; }
void setIntermediatePoints(const QList<IntermediatePoint> &intermediatePoints);
+ VisualPrimaryRole visualPrimaryRole() const { return m_visualPrimaryRole; }
+ void setVisualPrimaryRole(VisualPrimaryRole visualPrimaryRole);
+ VisualSecondaryRole visualSecondaryRole() const { return m_visualSecondaryRole; }
+ void setVisualSecondaryRole(VisualSecondaryRole visualSecondaryRole);
+ bool isVisualEmphasized() const { return m_isVisualEmphasized; }
+ void setVisualEmphasized(bool visualEmphasized);
+ QColor color() const { return m_color; }
+ void setColor(const QColor &color);
+ qreal thickness() const { return m_thickness; }
+ void setThickness(qreal thickness);
void accept(DVisitor *visitor) override;
void accept(DConstVisitor *visitor) const override;
@@ -53,6 +80,11 @@ private:
Uid m_endBUid;
QString m_name;
QList<IntermediatePoint> m_intermediatePoints;
+ VisualPrimaryRole m_visualPrimaryRole = PrimaryRoleNormal;
+ VisualSecondaryRole m_visualSecondaryRole = SecondaryRoleNone;
+ bool m_isVisualEmphasized = false;
+ QColor m_color;
+ qreal m_thickness = 0;
};
bool operator==(const DRelation::IntermediatePoint &lhs, const DRelation::IntermediatePoint &rhs);
diff --git a/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp b/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp
index 5e88175812..5e4c072588 100644
--- a/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp
+++ b/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp
@@ -49,7 +49,10 @@ void DFlatAssignmentVisitor::visitDObject(const DObject *object)
target->setVisualPrimaryRole(object->visualPrimaryRole());
target->setVisualSecondaryRole(object->visualSecondaryRole());
target->setVisualEmphasized(object->isVisualEmphasized());
+ target->setLinkedFile(object->hasLinkedFile());
target->setStereotypeDisplay(object->stereotypeDisplay());
+ target->setImagePath(object->imagePath());
+ target->setImage(object->image());
}
void DFlatAssignmentVisitor::visitDPackage(const DPackage *package)
@@ -100,6 +103,8 @@ void DFlatAssignmentVisitor::visitDRelation(const DRelation *relation)
QMT_ASSERT(target, return);
target->setStereotypes(relation->stereotypes());
target->setIntermediatePoints(relation->intermediatePoints());
+ target->setVisualPrimaryRole(relation->visualPrimaryRole());
+ target->setThickness(relation->thickness());
}
void DFlatAssignmentVisitor::visitDInheritance(const DInheritance *inheritance)
diff --git a/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp b/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp
index 91a95438ad..2dd079e1bc 100644
--- a/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp
+++ b/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp
@@ -65,13 +65,16 @@ void DUpdateVisitor::visitMObject(const MObject *object)
}
if (isUpdating(object->name() != dobject->name()))
dobject->setName(object->name());
+ bool hasLinkedFile = !object->linkedFileName().isEmpty();
+ if (isUpdating(hasLinkedFile != dobject->hasLinkedFile()))
+ dobject->setLinkedFile(hasLinkedFile);
// TODO unlikely that this is called for all objects if hierarchy is modified
// PERFORM remove loop
int depth = 1;
const MObject *owner = object->owner();
while (owner) {
owner = owner->owner();
- depth += 1;
+ depth += 3;
}
if (isUpdating(depth != dobject->depth()))
dobject->setDepth(depth);
diff --git a/src/libs/modelinglib/qmt/diagram_scene/capabilities/windable.h b/src/libs/modelinglib/qmt/diagram_scene/capabilities/windable.h
index a21f1caea3..c31249e5c1 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/capabilities/windable.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/capabilities/windable.h
@@ -20,7 +20,7 @@ public:
virtual void insertHandle(int beforeIndex, const QPointF &pos, double rasterWidth, double rasterHeight) = 0;
virtual void deleteHandle(int index) = 0;
virtual void setHandlePos(int index, const QPointF &pos) = 0;
- virtual void dropHandle(int index, double rasterWidth, double rasterHeight) = 0;
+ virtual void dropHandle(int index, bool extraSnap, double rasterWidth, double rasterHeight) = 0;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp
index de8b82de20..9366a39503 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp
@@ -209,15 +209,26 @@ DSelection DiagramSceneModel::selectedElements() const
return selection;
}
-DElement *DiagramSceneModel::findTopmostElement(const QPointF &scenePos) const
+QGraphicsItem *DiagramSceneModel::findTopmostItem(const QPointF &scenePos) const
{
// fetch affected items from scene in correct drawing order to find topmost element
const QList<QGraphicsItem *> items = m_graphicsScene->items(scenePos);
+ QGraphicsItem *candidate = NULL;
for (QGraphicsItem *item : items) {
- if (m_graphicsItems.contains(item))
- return m_itemToElementMap.value(item);
+ if (m_graphicsItems.contains(item)) {
+ if (!candidate || item->zValue() > candidate->zValue())
+ candidate = item;
+ }
}
- return nullptr;
+ return candidate;
+}
+
+DElement *DiagramSceneModel::findTopmostElement(const QPointF &scenePos) const
+{
+ QGraphicsItem *item = findTopmostItem(scenePos);
+ if (!item)
+ return nullptr;
+ return m_itemToElementMap.value(item);
}
DObject *DiagramSceneModel::findTopmostObject(const QPointF &scenePos) const
@@ -230,16 +241,13 @@ DObject *DiagramSceneModel::findTopmostObject(const QPointF &scenePos) const
ObjectItem *DiagramSceneModel::findTopmostObjectItem(const QPointF &scenePos) const
{
- // fetch affected items from scene in correct drawing order to find topmost element
- const QList<QGraphicsItem *> items = m_graphicsScene->items(scenePos);
- for (QGraphicsItem *item : std::as_const(items)) {
- if (m_graphicsItems.contains(item)) {
- DObject *object = dynamic_cast<DObject *>(m_itemToElementMap.value(item));
- if (object)
- return dynamic_cast<ObjectItem *>(item);
- }
- }
- return nullptr;
+ QGraphicsItem *item = findTopmostItem(scenePos);
+ if (!item)
+ return nullptr;
+ DObject *object = dynamic_cast<DObject *>(m_itemToElementMap.value(item));
+ if (!object)
+ return nullptr;
+ return dynamic_cast<ObjectItem *>(item);
}
QGraphicsItem *DiagramSceneModel::graphicsItem(DElement *element) const
@@ -353,7 +361,8 @@ void DiagramSceneModel::selectAllElements()
void DiagramSceneModel::selectElement(DElement *element)
{
QGraphicsItem *selectItem = m_elementToItemMap.value(element);
- for (QGraphicsItem *item : std::as_const(m_selectedItems)) {
+ auto selectedItems = m_selectedItems;
+ for (QGraphicsItem *item : std::as_const(selectedItems)) {
if (item != selectItem)
item->setSelected(false);
}
@@ -363,9 +372,17 @@ void DiagramSceneModel::selectElement(DElement *element)
void DiagramSceneModel::editElement(DElement *element)
{
- auto editable = dynamic_cast<IEditable *>(m_elementToItemMap.value(element));
- if (editable && editable->isEditable())
+ QGraphicsItem *item = m_elementToItemMap.value(element);
+ auto editable = dynamic_cast<IEditable *>(item);
+ if (editable && editable->isEditable()) {
+ auto selectable = dynamic_cast<ISelectable *>(item);
+ if (selectable && item != m_focusItem) {
+ unsetFocusItem();
+ selectable->setFocusSelected(true);
+ m_focusItem = item;
+ }
editable->edit();
+ }
}
void DiagramSceneModel::copyToClipboard()
@@ -507,9 +524,8 @@ void DiagramSceneModel::selectItem(QGraphicsItem *item, bool multiSelect)
{
if (!multiSelect) {
if (!item->isSelected()) {
- // We have to create a copy since "setSelected" may modify m_selectedItems
- const QSet<QGraphicsItem *> copy = m_selectedItems;
- for (QGraphicsItem *selectedItem : copy) {
+ auto selectedItems = m_selectedItems;
+ for (QGraphicsItem *selectedItem : std::as_const(selectedItems)) {
if (selectedItem != item)
selectedItem->setSelected(false);
}
@@ -624,6 +640,7 @@ void DiagramSceneModel::keyReleaseEvent(QKeyEvent *event)
void DiagramSceneModel::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
+ m_mousePressed = true;
updateFocusItem(Utils::toSet(m_graphicsScene->selectedItems()));
m_latchController->mousePressEventLatching(event);
mousePressEventReparenting(event);
@@ -658,8 +675,10 @@ void DiagramSceneModel::mouseMoveEventReparenting(QGraphicsSceneMouseEvent *even
void DiagramSceneModel::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
+ m_mousePressed = false;
m_latchController->mouseReleaseEventLatching(event);
mouseReleaseEventReparenting(event);
+ recalcSceneRectSize();
}
void DiagramSceneModel::mouseReleaseEventReparenting(QGraphicsSceneMouseEvent *event)
@@ -851,7 +870,7 @@ void DiagramSceneModel::onSelectionChanged()
QSet<QGraphicsItem *> newSecondarySelectedItems;
// select all contained objects secondarily
- for (QGraphicsItem *selectedItem : std::as_const(m_secondarySelectedItems)) {
+ for (QGraphicsItem *selectedItem : std::as_const(m_selectedItems)) {
const QList<QGraphicsItem *> items = collectCollidingObjectItems(selectedItem, CollidingInnerItems);
for (QGraphicsItem *item : items) {
if (!item->isSelected() && dynamic_cast<ISelectable *>(item)
@@ -908,7 +927,8 @@ void DiagramSceneModel::onSelectionChanged()
}
}
- for (QGraphicsItem *item : std::as_const(m_secondarySelectedItems)) {
+ auto secondarySelectedItems = m_secondarySelectedItems;
+ for (QGraphicsItem *item : std::as_const(secondarySelectedItems)) {
if (!newSecondarySelectedItems.contains(item)) {
auto selectable = dynamic_cast<ISelectable *>(item);
QMT_ASSERT(selectable, return);
@@ -1039,8 +1059,19 @@ void DiagramSceneModel::recalcSceneRectSize()
if (!dynamic_cast<SwimlaneItem *>(item))
sceneRect |= item->mapRectToScene(item->boundingRect());
}
- m_sceneRect = sceneRect;
- emit sceneRectChanged(sceneRect);
+ if (m_mousePressed) {
+ if (sceneRect.left() < m_sceneRect.left())
+ m_sceneRect.setLeft(sceneRect.left());
+ if (sceneRect.right() > m_sceneRect.right())
+ m_sceneRect.setRight(sceneRect.right());
+ if (sceneRect.top() < m_sceneRect.top())
+ m_sceneRect.setTop(sceneRect.top());
+ if (sceneRect.bottom() > m_sceneRect.bottom())
+ m_sceneRect.setBottom(sceneRect.bottom());
+ } else {
+ m_sceneRect = sceneRect;
+ }
+ emit sceneRectChanged(m_sceneRect);
}
QGraphicsItem *DiagramSceneModel::createGraphicsItem(DElement *element)
diff --git a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.h b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.h
index 0021faf459..b976f421f9 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.h
@@ -79,6 +79,7 @@ public:
bool hasSelection() const;
bool hasMultiObjectsSelection() const;
DSelection selectedElements() const;
+ QGraphicsItem *findTopmostItem(const QPointF &scenePos) const;
DElement *findTopmostElement(const QPointF &scenePos) const;
DObject *findTopmostObject(const QPointF &scenePos) const;
ObjectItem *findTopmostObjectItem(const QPointF &scenePos) const;
@@ -169,6 +170,7 @@ private:
QGraphicsItem *m_focusItem = nullptr;
QRectF m_sceneRect;
QList<Uid> m_relationEndsUid;
+ bool m_mousePressed = false;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp
index 14ad25b2c1..23a9c524a2 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp
@@ -85,29 +85,16 @@ void ClassItem::update()
m_methodsText.clear();
}
- // custom icon
- if (stereotypeIconDisplay() == StereotypeIcon::DisplayIcon) {
- if (!m_customIcon)
- m_customIcon = new CustomIconItem(diagramSceneModel(), this);
- m_customIcon->setStereotypeIconId(stereotypeIconId());
- m_customIcon->setBaseSize(stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(), CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT));
- m_customIcon->setBrush(style->fillBrush());
- m_customIcon->setPen(style->outerLinePen());
- m_customIcon->setZValue(SHAPE_ZVALUE);
- } else if (m_customIcon) {
- m_customIcon->scene()->removeItem(m_customIcon);
- delete m_customIcon;
- m_customIcon = nullptr;
- }
+ updateCustomIcon(style);
// shape
- if (!m_customIcon) {
+ if (!customIconItem()) {
if (!m_shape)
m_shape = new QGraphicsRectItem(this);
m_shape->setBrush(style->fillBrush());
m_shape->setPen(style->outerLinePen());
m_shape->setZValue(SHAPE_ZVALUE);
- } else if (m_shape){
+ } else if (m_shape) {
m_shape->scene()->removeItem(m_shape);
delete m_shape;
m_shape = nullptr;
@@ -259,7 +246,7 @@ void ClassItem::update()
m_templateParameterBox = nullptr;
}
- updateSelectionMarker(m_customIcon);
+ updateSelectionMarker(customIconItem());
updateRelationStarter();
updateAlignmentButtons();
updateGeometry();
@@ -267,8 +254,8 @@ void ClassItem::update()
bool ClassItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
{
- if (m_customIcon) {
- QList<QPolygonF> polygons = m_customIcon->outline();
+ if (customIconItem()) {
+ QList<QPolygonF> polygons = customIconItem()->outline();
for (int i = 0; i < polygons.size(); ++i)
polygons[i].translate(object()->pos() + object()->rect().topLeft());
if (shapeIcon().textAlignment() == qmt::StereotypeIcon::TextalignBelow) {
@@ -508,7 +495,7 @@ DClass::TemplateDisplay ClassItem::templateDisplay() const
DClass::TemplateDisplay templateDisplay = diagramClass->templateDisplay();
if (templateDisplay == DClass::TemplateSmart) {
- if (m_customIcon)
+ if (customIconItem())
templateDisplay = DClass::TemplateName;
else
templateDisplay = DClass::TemplateBox;
@@ -521,8 +508,8 @@ QSizeF ClassItem::calcMinimumGeometry() const
double width = 0.0;
double height = 0.0;
- if (m_customIcon) {
- QSizeF sz = stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(),
+ if (customIconItem()) {
+ QSizeF sz = customIconItemMinimumSize(customIconItem(),
CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT);
if (shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignTop
&& shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignCenter)
@@ -589,12 +576,7 @@ void ClassItem::updateGeometry()
height = geometry.height();
if (object()->isAutoSized()) {
- if (!m_customIcon) {
- if (width < MINIMUM_AUTO_WIDTH)
- width = MINIMUM_AUTO_WIDTH;
- if (height < MINIMUM_AUTO_HEIGHT)
- height = MINIMUM_AUTO_HEIGHT;
- }
+ correctAutoSize(customIconItem(), width, height, MINIMUM_AUTO_WIDTH, MINIMUM_AUTO_HEIGHT);
} else {
QRectF rect = object()->rect();
if (rect.width() > width)
@@ -619,15 +601,15 @@ void ClassItem::updateGeometry()
// a backup for the graphics item used for manual resized and persistency.
object()->setRect(rect);
- if (m_customIcon) {
- m_customIcon->setPos(left, top);
- m_customIcon->setActualSize(QSizeF(width, height));
+ if (customIconItem()) {
+ customIconItem()->setPos(left, top);
+ customIconItem()->setActualSize(QSizeF(width, height));
}
if (m_shape)
m_shape->setRect(rect);
- if (m_customIcon) {
+ if (customIconItem()) {
switch (shapeIcon().textAlignment()) {
case qmt::StereotypeIcon::TextalignBelow:
y += height + BODY_VERT_BORDER;
@@ -679,7 +661,7 @@ void ClassItem::updateGeometry()
y += nameItem()->boundingRect().height();
}
if (m_contextLabel) {
- if (m_customIcon)
+ if (customIconItem())
m_contextLabel->resetMaxWidth();
else
m_contextLabel->setMaxWidth(width - 2 * BODY_HORIZ_BORDER);
@@ -692,7 +674,7 @@ void ClassItem::updateGeometry()
y += 8.0;
}
if (m_attributes) {
- if (m_customIcon)
+ if (customIconItem())
m_attributes->setPos(-m_attributes->boundingRect().width() / 2.0, y);
else
m_attributes->setPos(left + BODY_HORIZ_BORDER, y);
@@ -704,7 +686,7 @@ void ClassItem::updateGeometry()
y += 8.0;
}
if (m_methods) {
- if (m_customIcon)
+ if (customIconItem())
m_methods->setPos(-m_methods->boundingRect().width() / 2.0, y);
else
m_methods->setPos(left + BODY_HORIZ_BORDER, y);
@@ -765,21 +747,22 @@ void ClassItem::updateMembers(const Style *style)
break;
}
+ bool needBr = false;
if (text && !text->isEmpty())
- *text += "<br/>";
+ needBr = true;
- bool addNewline = false;
- bool addSpace = false;
if (currentVisibility)
*currentVisibility = member.visibility();
if (currentGroup && member.group() != *currentGroup) {
- *text += QString("[%1]").arg(member.group());
- addNewline = true;
+ needBr = false;
+ *text += QString("<p style=\"padding:0;margin-top:6;margin-bottom:0;\"><b>[%1]</b></p>").arg(member.group());
*currentGroup = member.group();
}
- if (addNewline)
+
+ if (needBr)
*text += "<br/>";
+ bool addSpace = false;
bool haveSignal = false;
bool haveSlot = false;
if (member.visibility() != MClassMember::VisibilityUndefined) {
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.h
index 83ce0a9a5a..cc92ab1ff5 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.h
@@ -53,7 +53,6 @@ private:
void updateGeometry();
void updateMembers(const Style *style);
- CustomIconItem *m_customIcon = nullptr;
QGraphicsRectItem *m_shape = nullptr;
QGraphicsSimpleTextItem *m_baseClasses = nullptr;
QGraphicsSimpleTextItem *m_namespace = nullptr;
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp
index 6a54a001e5..e7fffcbf9a 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp
@@ -53,24 +53,11 @@ void ComponentItem::update()
const Style *style = adaptedStyle(stereotypeIconId());
- // custom icon
- if (stereotypeIconDisplay() == StereotypeIcon::DisplayIcon) {
- if (!m_customIcon)
- m_customIcon = new CustomIconItem(diagramSceneModel(), this);
- m_customIcon->setStereotypeIconId(stereotypeIconId());
- m_customIcon->setBaseSize(stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(), CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT));
- m_customIcon->setBrush(style->fillBrush());
- m_customIcon->setPen(style->outerLinePen());
- m_customIcon->setZValue(SHAPE_ZVALUE);
- } else if (m_customIcon) {
- m_customIcon->scene()->removeItem(m_customIcon);
- delete m_customIcon;
- m_customIcon = nullptr;
- }
+ updateCustomIcon(style);
// shape
bool deleteRects = false;
- if (!m_customIcon) {
+ if (!customIconItem()) {
if (!m_shape)
m_shape = new QGraphicsRectItem(this);
m_shape->setBrush(style->fillBrush());
@@ -130,7 +117,7 @@ void ComponentItem::update()
m_contextLabel = nullptr;
}
- updateSelectionMarker(m_customIcon);
+ updateSelectionMarker(customIconItem());
updateRelationStarter();
updateAlignmentButtons();
updateGeometry();
@@ -138,8 +125,8 @@ void ComponentItem::update()
bool ComponentItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
{
- if (m_customIcon) {
- QList<QPolygonF> polygons = m_customIcon->outline();
+ if (customIconItem()) {
+ QList<QPolygonF> polygons = customIconItem()->outline();
for (int i = 0; i < polygons.size(); ++i)
polygons[i].translate(object()->pos() + object()->rect().topLeft());
if (shapeIcon().textAlignment() == qmt::StereotypeIcon::TextalignBelow) {
@@ -207,14 +194,16 @@ QSizeF ComponentItem::calcMinimumGeometry() const
{
double width = 0.0;
double height = 0.0;
+ double customMinHeight = 0.0;
- if (m_customIcon) {
- QSizeF sz = stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(),
+ if (customIconItem()) {
+ QSizeF sz = customIconItemMinimumSize(customIconItem(),
CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT);
if (shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignTop
&& shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignCenter)
return sz;
width = sz.width();
+ customMinHeight = sz.height();
}
height += BODY_VERT_BORDER;
@@ -234,7 +223,7 @@ QSizeF ComponentItem::calcMinimumGeometry() const
height += m_contextLabel->height();
height += BODY_VERT_BORDER;
- if (!hasPlainShape()) {
+ if (!customIconItem() && !hasPlainShape()) {
width = RECT_WIDTH * 0.5 + BODY_HORIZ_BORDER + width + BODY_HORIZ_BORDER + RECT_WIDTH * 0.5;
double minHeight = UPPER_RECT_Y + RECT_HEIGHT + RECT_Y_DISTANCE + RECT_HEIGHT + LOWER_RECT_MIN_Y;
if (height < minHeight)
@@ -243,6 +232,9 @@ QSizeF ComponentItem::calcMinimumGeometry() const
width = BODY_HORIZ_BORDER + width + BODY_HORIZ_BORDER;
}
+ if (height < customMinHeight)
+ height = customMinHeight;
+
return GeometryUtilities::ensureMinimumRasterSize(QSizeF(width, height), 2 * RASTER_WIDTH, 2 * RASTER_HEIGHT);
}
@@ -259,7 +251,7 @@ void ComponentItem::updateGeometry()
height = geometry.height();
if (object()->isAutoSized()) {
- // nothing
+ correctAutoSize(customIconItem(), width, height, 0, 0);
} else {
QRectF rect = object()->rect();
if (rect.width() > width)
@@ -283,9 +275,9 @@ void ComponentItem::updateGeometry()
// a backup for the graphics item used for manual resized and persistency.
object()->setRect(rect);
- if (m_customIcon) {
- m_customIcon->setPos(left, top);
- m_customIcon->setActualSize(QSizeF(width, height));
+ if (customIconItem()) {
+ customIconItem()->setPos(left, top);
+ customIconItem()->setActualSize(QSizeF(width, height));
}
if (m_shape)
@@ -303,7 +295,7 @@ void ComponentItem::updateGeometry()
m_lowerRect->setPos(left - RECT_WIDTH * 0.5, top + UPPER_RECT_Y + RECT_HEIGHT + RECT_Y_DISTANCE);
}
- if (m_customIcon) {
+ if (customIconItem()) {
switch (shapeIcon().textAlignment()) {
case qmt::StereotypeIcon::TextalignBelow:
y += height + BODY_VERT_BORDER;
@@ -345,7 +337,7 @@ void ComponentItem::updateGeometry()
y += nameItem()->boundingRect().height();
}
if (m_contextLabel) {
- if (m_customIcon) {
+ if (customIconItem()) {
m_contextLabel->resetMaxWidth();
} else {
double maxContextWidth = width - 2 * BODY_HORIZ_BORDER - (hasPlainShape() ? 0 : RECT_WIDTH);
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.h
index f00fbf30eb..f4910f53ce 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.h
@@ -41,7 +41,6 @@ private:
QSizeF calcMinimumGeometry() const;
void updateGeometry();
- CustomIconItem *m_customIcon = nullptr;
QGraphicsRectItem *m_shape = nullptr;
QGraphicsRectItem *m_upperRect = nullptr;
QGraphicsRectItem *m_lowerRect = nullptr;
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp
index c37c38b3bb..951d6f3b1a 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp
@@ -47,23 +47,10 @@ void DiagramItem::update()
const Style *style = adaptedStyle(stereotypeIconId());
- // custom icon
- if (stereotypeIconDisplay() == StereotypeIcon::DisplayIcon) {
- if (!m_customIcon)
- m_customIcon = new CustomIconItem(diagramSceneModel(), this);
- m_customIcon->setStereotypeIconId(stereotypeIconId());
- m_customIcon->setBaseSize(stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(), CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT));
- m_customIcon->setBrush(style->fillBrush());
- m_customIcon->setPen(style->outerLinePen());
- m_customIcon->setZValue(SHAPE_ZVALUE);
- } else if (m_customIcon) {
- m_customIcon->scene()->removeItem(m_customIcon);
- delete m_customIcon;
- m_customIcon = nullptr;
- }
+ updateCustomIcon(style);
// shape
- if (!m_customIcon) {
+ if (!customIconItem()) {
if (!m_body)
m_body = new QGraphicsPolygonItem(this);
m_body->setBrush(style->fillBrush());
@@ -93,15 +80,15 @@ void DiagramItem::update()
// diagram name
updateNameItem(style);
- updateSelectionMarker(m_customIcon);
+ updateSelectionMarker(customIconItem());
updateAlignmentButtons();
updateGeometry();
}
bool DiagramItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
{
- if (m_customIcon) {
- QList<QPolygonF> polygons = m_customIcon->outline();
+ if (customIconItem()) {
+ QList<QPolygonF> polygons = customIconItem()->outline();
for (int i = 0; i < polygons.size(); ++i)
polygons[i].translate(object()->pos() + object()->rect().topLeft());
if (shapeIcon().textAlignment() == qmt::StereotypeIcon::TextalignBelow) {
@@ -131,8 +118,8 @@ QSizeF DiagramItem::calcMinimumGeometry() const
double width = MINIMUM_WIDTH;
double height = 0.0;
- if (m_customIcon) {
- QSizeF sz = stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(),
+ if (customIconItem()) {
+ QSizeF sz = customIconItemMinimumSize(customIconItem(),
CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT);
if (shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignTop
&& shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignCenter)
@@ -175,12 +162,7 @@ void DiagramItem::updateGeometry()
height = geometry.height();
if (object()->isAutoSized()) {
- if (!m_customIcon) {
- if (width < MINIMUM_AUTO_WIDTH)
- width = MINIMUM_AUTO_WIDTH;
- if (height < MINIMUM_AUTO_HEIGHT)
- height = MINIMUM_AUTO_HEIGHT;
- }
+ correctAutoSize(customIconItem(), width, height, MINIMUM_AUTO_WIDTH, MINIMUM_AUTO_HEIGHT);
} else {
QRectF rect = object()->rect();
if (rect.width() > width)
@@ -203,9 +185,9 @@ void DiagramItem::updateGeometry()
// a backup for the graphics item used for manual resized and persistency.
object()->setRect(rect);
- if (m_customIcon) {
- m_customIcon->setPos(left, top);
- m_customIcon->setActualSize(QSizeF(width, height));
+ if (customIconItem()) {
+ customIconItem()->setPos(left, top);
+ customIconItem()->setActualSize(QSizeF(width, height));
}
if (m_body) {
@@ -227,7 +209,7 @@ void DiagramItem::updateGeometry()
m_fold->setPolygon(foldPolygon);
}
- if (m_customIcon) {
+ if (customIconItem()) {
switch (shapeIcon().textAlignment()) {
case qmt::StereotypeIcon::TextalignBelow:
y += height + BODY_VERT_BORDER;
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.h
index 81012b04a1..88d9f9a7a8 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.h
@@ -29,7 +29,6 @@ private:
QSizeF calcMinimumGeometry() const;
void updateGeometry();
- CustomIconItem *m_customIcon = nullptr;
QGraphicsPolygonItem *m_body = nullptr;
QGraphicsPolygonItem *m_fold = nullptr;
};
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp
index 97a1b337fc..9855889b08 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp
@@ -52,22 +52,10 @@ void ItemItem::update()
const Style *style = adaptedStyle(shapeIconId());
- if (!shapeIconId().isEmpty()) {
- if (!m_customIcon)
- m_customIcon = new CustomIconItem(diagramSceneModel(), this);
- m_customIcon->setStereotypeIconId(shapeIconId());
- m_customIcon->setBaseSize(stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(), CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT));
- m_customIcon->setBrush(style->fillBrush());
- m_customIcon->setPen(style->outerLinePen());
- m_customIcon->setZValue(SHAPE_ZVALUE);
- } else if (m_customIcon) {
- m_customIcon->scene()->removeItem(m_customIcon);
- delete m_customIcon;
- m_customIcon = nullptr;
- }
+ updateCustomIcon(style);
// shape
- if (!m_customIcon) {
+ if (!customIconItem()) {
if (!m_shape)
m_shape = new QGraphicsRectItem(this);
m_shape->setBrush(style->fillBrush());
@@ -100,7 +88,7 @@ void ItemItem::update()
m_contextLabel = nullptr;
}
- updateSelectionMarker(m_customIcon);
+ updateSelectionMarker(customIconItem());
updateRelationStarter();
updateAlignmentButtons();
updateGeometry();
@@ -108,8 +96,8 @@ void ItemItem::update()
bool ItemItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
{
- if (m_customIcon) {
- QList<QPolygonF> polygons = m_customIcon->outline();
+ if (customIconItem()) {
+ QList<QPolygonF> polygons = customIconItem()->outline();
for (int i = 0; i < polygons.size(); ++i)
polygons[i].translate(object()->pos() + object()->rect().topLeft());
if (shapeIcon().textAlignment() == qmt::StereotypeIcon::TextalignBelow) {
@@ -152,14 +140,16 @@ QSizeF ItemItem::calcMinimumGeometry() const
{
double width = 0.0;
double height = 0.0;
+ double customMinHeight = 0.0;
- if (m_customIcon) {
- QSizeF sz = stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(),
+ if (customIconItem()) {
+ QSizeF sz = customIconItemMinimumSize(customIconItem(),
CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT);
if (shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignTop
&& shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignCenter)
return sz;
width = sz.width();
+ customMinHeight = sz.height();
}
height += BODY_VERT_BORDER;
@@ -181,6 +171,9 @@ QSizeF ItemItem::calcMinimumGeometry() const
width = BODY_HORIZ_BORDER + width + BODY_HORIZ_BORDER;
+ if (height < customMinHeight)
+ height = customMinHeight;
+
return GeometryUtilities::ensureMinimumRasterSize(QSizeF(width, height), 2 * RASTER_WIDTH, 2 * RASTER_HEIGHT);
}
@@ -197,7 +190,7 @@ void ItemItem::updateGeometry()
height = geometry.height();
if (object()->isAutoSized()) {
- // nothing
+ correctAutoSize(customIconItem(), width, height, 0, 0);
} else {
QRectF rect = object()->rect();
if (rect.width() > width)
@@ -221,15 +214,15 @@ void ItemItem::updateGeometry()
// a backup for the graphics item used for manual resized and persistency.
object()->setRect(rect);
- if (m_customIcon) {
- m_customIcon->setPos(left, top);
- m_customIcon->setActualSize(QSizeF(width, height));
+ if (customIconItem()) {
+ customIconItem()->setPos(left, top);
+ customIconItem()->setActualSize(QSizeF(width, height));
}
if (m_shape)
m_shape->setRect(rect);
- if (m_customIcon) {
+ if (customIconItem()) {
switch (shapeIcon().textAlignment()) {
case qmt::StereotypeIcon::TextalignBelow:
y += height + BODY_VERT_BORDER;
@@ -271,7 +264,7 @@ void ItemItem::updateGeometry()
y += nameItem()->boundingRect().height();
}
if (m_contextLabel) {
- if (m_customIcon) {
+ if (customIconItem()) {
m_contextLabel->resetMaxWidth();
} else {
double maxContextWidth = width - 2 * BODY_HORIZ_BORDER;
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.h
index 327b3799ac..de091a2bc7 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.h
@@ -39,7 +39,6 @@ private:
QSizeF calcMinimumGeometry() const;
void updateGeometry();
- CustomIconItem *m_customIcon = nullptr;
QGraphicsRectItem *m_shape = nullptr;
ContextLabelItem *m_contextLabel = nullptr;
};
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp
index 0fe32080cf..d4f6bd386b 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp
@@ -185,6 +185,8 @@ void ObjectItem::setFocusSelected(bool focusSelected)
if (m_isFocusSelected != focusSelected) {
m_isFocusSelected = focusSelected;
update();
+ if (m_nameItem)
+ m_nameItem->setEditable(focusSelected);
}
}
@@ -353,9 +355,9 @@ void ObjectItem::relationDrawn(const QString &id, ObjectItem *targetItem, const
elementType = targetItem->stereotypeIconId();
else if (!targetItem->shapeIconId().isEmpty())
elementType = targetItem->shapeIconId();
- else
- elementType = targetItem->elementType();
- if (!endItems.contains(elementType)) {
+ if ((!elementType.isEmpty() && !endItems.contains(elementType))
+ && !endItems.contains(targetItem->elementType()))
+ {
return;
}
// create relation
@@ -498,6 +500,7 @@ void ObjectItem::updateStereotypes(const QString &stereotypeIconId, StereotypeIc
m_stereotypeIcon = new CustomIconItem(m_diagramSceneModel, this);
m_stereotypeIcon->setStereotypeIconId(stereotypeIconId);
m_stereotypeIcon->setBaseSize(QSizeF(m_stereotypeIcon->shapeWidth(), m_stereotypeIcon->shapeHeight()));
+ m_stereotypeIcon->setActualSize(QSizeF(m_stereotypeIcon->shapeWidth(), m_stereotypeIcon->shapeHeight()));
m_stereotypeIcon->setBrush(style->fillBrush());
m_stereotypeIcon->setPen(style->innerLinePen());
} else if (m_stereotypeIcon) {
@@ -518,45 +521,92 @@ void ObjectItem::updateStereotypes(const QString &stereotypeIconId, StereotypeIc
}
}
-QSizeF ObjectItem::stereotypeIconMinimumSize(const StereotypeIcon &stereotypeIcon,
+QSizeF ObjectItem::customIconItemMinimumSize(const CustomIconItem *customIconItem,
qreal minimumWidth, qreal minimumHeight) const
{
Q_UNUSED(minimumWidth)
qreal width = 0.0;
qreal height = 0.0;
- if (stereotypeIcon.hasMinWidth() && !stereotypeIcon.hasMinHeight()) {
- width = stereotypeIcon.minWidth();
- if (stereotypeIcon.sizeLock() == StereotypeIcon::LockHeight || stereotypeIcon.sizeLock() == StereotypeIcon::LockSize)
- height = stereotypeIcon.minHeight();
- else
- height = width * stereotypeIcon.height() / stereotypeIcon.width();
- } else if (!stereotypeIcon.hasMinWidth() && stereotypeIcon.hasMinHeight()) {
- height = stereotypeIcon.minHeight();
- if (stereotypeIcon.sizeLock() == StereotypeIcon::LockWidth || stereotypeIcon.sizeLock() == StereotypeIcon::LockSize)
- width = stereotypeIcon.minWidth();
- else
- width = height * stereotypeIcon.width() / stereotypeIcon.height();
- } else if (stereotypeIcon.hasMinWidth() && stereotypeIcon.hasMinHeight()) {
- if (stereotypeIcon.sizeLock() == StereotypeIcon::LockRatio) {
+ if (customIconItem->hasImage()) {
+ const QImage &image = customIconItem->image();
+ width = minimumWidth;
+ height = image.height() * width / image.width();
+ if (height < minimumHeight) {
+ height = minimumHeight;
+ width = image.width() * height / image.height();
+ }
+ } else {
+ const StereotypeIcon &stereotypeIcon = customIconItem->stereotypeIcon();
+ if (stereotypeIcon.hasMinWidth() && !stereotypeIcon.hasMinHeight()) {
width = stereotypeIcon.minWidth();
- height = width * stereotypeIcon.height() / stereotypeIcon.width();
- if (height < stereotypeIcon.minHeight()) {
+ if (stereotypeIcon.sizeLock() == StereotypeIcon::LockHeight || stereotypeIcon.sizeLock() == StereotypeIcon::LockSize)
height = stereotypeIcon.minHeight();
+ else
+ height = width * stereotypeIcon.height() / stereotypeIcon.width();
+ } else if (!stereotypeIcon.hasMinWidth() && stereotypeIcon.hasMinHeight()) {
+ height = stereotypeIcon.minHeight();
+ if (stereotypeIcon.sizeLock() == StereotypeIcon::LockWidth || stereotypeIcon.sizeLock() == StereotypeIcon::LockSize)
+ width = stereotypeIcon.minWidth();
+ else
width = height * stereotypeIcon.width() / stereotypeIcon.height();
- QMT_CHECK(width <= stereotypeIcon.minWidth());
+ } else if (stereotypeIcon.hasMinWidth() && stereotypeIcon.hasMinHeight()) {
+ if (stereotypeIcon.sizeLock() == StereotypeIcon::LockRatio) {
+ width = stereotypeIcon.minWidth();
+ height = width * stereotypeIcon.height() / stereotypeIcon.width();
+ if (height < stereotypeIcon.minHeight()) {
+ height = stereotypeIcon.minHeight();
+ width = height * stereotypeIcon.width() / stereotypeIcon.height();
+ QMT_CHECK(width <= stereotypeIcon.minWidth());
+ }
+ } else {
+ width = stereotypeIcon.minWidth();
+ height = stereotypeIcon.minHeight();
}
} else {
- width = stereotypeIcon.minWidth();
- height = stereotypeIcon.minHeight();
+ height = minimumHeight;
+ width = height * stereotypeIcon.width() / stereotypeIcon.height();
}
- } else {
- height = minimumHeight;
- width = height * stereotypeIcon.width() / stereotypeIcon.height();
}
return QSizeF(width, height);
}
+void ObjectItem::correctAutoSize(const CustomIconItem* customIconItem, qreal &width, qreal &height, qreal minimumWidth, qreal minimumHeight) const
+{
+ if (customIconItem) {
+ if (customIconItem->hasImage()) {
+ width = customIconItem->image().width();
+ height = customIconItem->image().height();
+ }
+ } else {
+ if (width < minimumWidth)
+ width = minimumWidth;
+ if (height < minimumHeight)
+ height = minimumHeight;
+ }
+}
+
+void ObjectItem::updateCustomIcon(const Style *style)
+{
+ if (object()->hasImage()) {
+ if (!m_customIcon)
+ m_customIcon = new CustomIconItem(diagramSceneModel(), this);
+ m_customIcon->setImage(object()->image());
+ m_customIcon->setZValue(SHAPE_ZVALUE);
+ } else if (!shapeIconId().isEmpty()) {
+ if (!m_customIcon)
+ m_customIcon = new CustomIconItem(diagramSceneModel(), this);
+ m_customIcon->setStereotypeIconId(shapeIconId());
+ m_customIcon->setBrush(style->fillBrush());
+ m_customIcon->setPen(style->outerLinePen());
+ m_customIcon->setZValue(SHAPE_ZVALUE);
+ } else if (m_customIcon) {
+ m_customIcon->scene()->removeItem(m_customIcon);
+ delete m_customIcon;
+ m_customIcon = nullptr;
+ }
+}
+
bool ObjectItem::suppressTextDisplay() const
{
return m_shapeIcon.textAlignment() == StereotypeIcon::TextalignNone;
@@ -564,6 +614,7 @@ bool ObjectItem::suppressTextDisplay() const
void ObjectItem::updateNameItem(const Style *style)
{
+ QString display_name = buildDisplayName();
if (!suppressTextDisplay()) {
if (!m_nameItem) {
m_nameItem = new EditableTextItem(this);
@@ -582,16 +633,18 @@ void ObjectItem::updateNameItem(const Style *style)
QObject::connect(m_nameItem, &EditableTextItem::returnKeyPressed, m_nameItem,
[this] { this->m_nameItem->clearFocus(); });
}
- if (style->headerFont() != m_nameItem->font())
- m_nameItem->setFont(style->headerFont());
+ QFont font = style->headerFont();
+ if (object()->hasLinkedFile())
+ font.setUnderline(true);
+ if (font != m_nameItem->font())
+ m_nameItem->setFont(font);
if (style->textBrush().color() != m_nameItem->defaultTextColor())
m_nameItem->setDefaultTextColor(style->textBrush().color());
if (!m_nameItem->hasFocus()) {
- QString name = buildDisplayName();
- if (name != m_nameItem->toPlainText())
- m_nameItem->setPlainText(name);
+ if (display_name != m_nameItem->toPlainText())
+ m_nameItem->setPlainText(display_name);
}
- } else if (m_nameItem ){
+ } else if (m_nameItem) {
m_nameItem->scene()->removeItem(m_nameItem);
delete m_nameItem;
m_nameItem = nullptr;
@@ -621,30 +674,45 @@ void ObjectItem::setObjectName(const QString &objectName)
void ObjectItem::updateDepth()
{
- setZValue(m_object->depth());
+ int depth_delta = 0;
+ switch (m_shapeIcon.depthLayer()) {
+ case StereotypeIcon::DepthBehindItems:
+ depth_delta = -1;
+ break;
+ case StereotypeIcon::DepthAmongItems:
+ depth_delta = 0;
+ break;
+ case StereotypeIcon::DepthBeforeItems:
+ depth_delta = 1;
+ break;
+ }
+ setZValue(m_object->depth() + depth_delta);
}
-void ObjectItem::updateSelectionMarker(CustomIconItem *customIconItem)
+void ObjectItem::updateSelectionMarker(const CustomIconItem *customIconItem)
{
if (customIconItem) {
- StereotypeIcon stereotypeIcon = customIconItem->stereotypeIcon();
ResizeFlags resizeFlags = ResizeUnlocked;
- switch (stereotypeIcon.sizeLock()) {
- case StereotypeIcon::LockNone:
- resizeFlags = ResizeUnlocked;
- break;
- case StereotypeIcon::LockWidth:
- resizeFlags = ResizeLockedWidth;
- break;
- case StereotypeIcon::LockHeight:
- resizeFlags = ResizeLockedHeight;
- break;
- case StereotypeIcon::LockSize:
- resizeFlags = ResizeLockedSize;
- break;
- case StereotypeIcon::LockRatio:
+ if (customIconItem->hasImage()) {
resizeFlags = ResizeLockedRatio;
- break;
+ } else {
+ switch (customIconItem->stereotypeIcon().sizeLock()) {
+ case StereotypeIcon::LockNone:
+ resizeFlags = ResizeUnlocked;
+ break;
+ case StereotypeIcon::LockWidth:
+ resizeFlags = ResizeLockedWidth;
+ break;
+ case StereotypeIcon::LockHeight:
+ resizeFlags = ResizeLockedHeight;
+ break;
+ case StereotypeIcon::LockSize:
+ resizeFlags = ResizeLockedSize;
+ break;
+ case StereotypeIcon::LockRatio:
+ resizeFlags = ResizeLockedRatio;
+ break;
+ }
}
updateSelectionMarker(resizeFlags);
} else {
@@ -990,6 +1058,10 @@ void ObjectItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
addSeparator = true;
if (element_tasks->extendContextMenu(object(), diagramSceneModel()->diagram(), &menu))
addSeparator = true;
+ if (element_tasks->hasLinkedFile(m_object, m_diagramSceneModel->diagram())) {
+ menu.addAction(new ContextMenuAction(Tr::tr("Open Linked File"), "openLinkedFile", &menu));
+ addSeparator = true;
+ }
if (addSeparator)
menu.addSeparator();
menu.addAction(new ContextMenuAction(Tr::tr("Remove"), "remove",
@@ -1000,12 +1072,12 @@ void ObjectItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
QMenu alignMenu;
alignMenu.setTitle(Tr::tr("Align Objects"));
alignMenu.addAction(new ContextMenuAction(Tr::tr("Align Left"), "alignLeft", &alignMenu));
- alignMenu.addAction(new ContextMenuAction(Tr::tr("Center Vertically"), "centerVertically",
+ alignMenu.addAction(new ContextMenuAction(Tr::tr("Center Horizontally"), "centerHorizontally",
&alignMenu));
alignMenu.addAction(new ContextMenuAction(Tr::tr("Align Right"), "alignRight", &alignMenu));
alignMenu.addSeparator();
alignMenu.addAction(new ContextMenuAction(Tr::tr("Align Top"), "alignTop", &alignMenu));
- alignMenu.addAction(new ContextMenuAction(Tr::tr("Center Horizontally"), "centerHorizontally",
+ alignMenu.addAction(new ContextMenuAction(Tr::tr("Center Vertically"), "centerVertically",
&alignMenu));
alignMenu.addAction(new ContextMenuAction(Tr::tr("Align Bottom"), "alignBottom", &alignMenu));
alignMenu.addSeparator();
@@ -1022,7 +1094,6 @@ void ObjectItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
layoutMenu.addAction(new ContextMenuAction(Tr::tr("Equal Vertical Space"), "sameVBorderDistance", &alignMenu));
layoutMenu.setEnabled(m_diagramSceneModel->hasMultiObjectsSelection());
menu.addMenu(&layoutMenu);
- menu.addAction(new ContextMenuAction(Tr::tr("Add Related Elements"), "addRelatedElements", &menu));
QAction *selectedAction = menu.exec(event->screenPos());
if (selectedAction) {
@@ -1035,6 +1106,8 @@ void ObjectItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
m_diagramSceneModel->diagramSceneController()->elementTasks()->openDiagram(m_object, m_diagramSceneModel->diagram());
} else if (action->id() == "createDiagram") {
m_diagramSceneModel->diagramSceneController()->elementTasks()->createAndOpenDiagram(m_object, m_diagramSceneModel->diagram());
+ } else if (action->id() == "openLinkedFile") {
+ m_diagramSceneModel->diagramSceneController()->elementTasks()->openLinkedFile(m_object, m_diagramSceneModel->diagram());
} else if (action->id() == "remove") {
DSelection selection = m_diagramSceneModel->selectedElements();
if (selection.isEmpty())
@@ -1073,11 +1146,6 @@ void ObjectItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
align(IAlignable::AlignHeight, "height");
} else if (action->id() == "sameSize") {
align(IAlignable::AlignSize, "size");
- } else if (action->id() == "addRelatedElements") {
- DSelection selection = m_diagramSceneModel->selectedElements();
- if (selection.isEmpty())
- selection.append(m_object->uid(), m_diagramSceneModel->diagram()->uid());
- m_diagramSceneModel->diagramSceneController()->addRelatedElements(selection, m_diagramSceneModel->diagram());
}
}
}
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.h
index e7acd5705c..254ef215ca 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.h
@@ -120,8 +120,12 @@ protected:
StereotypeIcon::Display stereotypeDisplay, const Style *style);
StereotypesItem *stereotypesItem() const { return m_stereotypesItem; }
CustomIconItem *stereotypeIconItem() const { return m_stereotypeIcon; }
- QSizeF stereotypeIconMinimumSize(const StereotypeIcon &stereotypeIcon, qreal minimumWidth,
+ CustomIconItem *customIconItem() const { return m_customIcon; }
+ QSizeF customIconItemMinimumSize(const CustomIconItem* customIconItem, qreal minimumWidth,
qreal minimumHeight) const;
+ void correctAutoSize(const CustomIconItem *customIconItem, qreal& width, qreal& height,
+ qreal minimumWidth, qreal minimumHeight) const;
+ void updateCustomIcon(const Style* style);
bool suppressTextDisplay() const;
void updateNameItem(const Style *style);
EditableTextItem *nameItem() const { return m_nameItem; }
@@ -130,7 +134,7 @@ protected:
void setObjectName(const QString &objectName);
void updateDepth();
- void updateSelectionMarker(CustomIconItem *customIconItem);
+ void updateSelectionMarker(const CustomIconItem* customIconItem);
void updateSelectionMarker(ResizeFlags resizeFlags);
void updateSelectionMarkerGeometry(const QRectF &objectRect);
void updateRelationStarter();
@@ -169,6 +173,7 @@ private:
StereotypeIcon::Display m_stereotypeIconDisplay = StereotypeIcon::DisplayLabel;
StereotypesItem *m_stereotypesItem = nullptr;
CustomIconItem *m_stereotypeIcon = nullptr;
+ CustomIconItem *m_customIcon = nullptr;
EditableTextItem *m_nameItem = nullptr;
RectangularSelectionItem *m_selectionMarker = nullptr;
RelationStarter *m_relationStarter = nullptr;
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp
index b473d17ec8..03e6d8d0f5 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp
@@ -64,23 +64,10 @@ void PackageItem::update()
const Style *style = adaptedStyle(stereotypeIconId());
- // custom icon
- if (stereotypeIconDisplay() == StereotypeIcon::DisplayIcon) {
- if (!m_customIcon)
- m_customIcon = new CustomIconItem(diagramSceneModel(), this);
- m_customIcon->setStereotypeIconId(stereotypeIconId());
- m_customIcon->setBaseSize(stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(), CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT));
- m_customIcon->setBrush(style->fillBrush());
- m_customIcon->setPen(style->outerLinePen());
- m_customIcon->setZValue(SHAPE_ZVALUE);
- } else if (m_customIcon) {
- m_customIcon->scene()->removeItem(m_customIcon);
- delete m_customIcon;
- m_customIcon = nullptr;
- }
+ updateCustomIcon(style);
// shape
- if (!m_customIcon) {
+ if (!customIconItem()) {
if (!m_shape)
m_shape = new QGraphicsPolygonItem(this);
m_shape->setBrush(style->fillBrush());
@@ -111,7 +98,7 @@ void PackageItem::update()
m_contextLabel = nullptr;
}
- updateSelectionMarker(m_customIcon);
+ updateSelectionMarker(customIconItem());
updateRelationStarter();
updateAlignmentButtons();
updateGeometry();
@@ -119,8 +106,8 @@ void PackageItem::update()
bool PackageItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
{
- if (m_customIcon) {
- QList<QPolygonF> polygons = m_customIcon->outline();
+ if (customIconItem()) {
+ QList<QPolygonF> polygons = customIconItem()->outline();
for (int i = 0; i < polygons.size(); ++i)
polygons[i].translate(object()->pos() + object()->rect().topLeft());
if (shapeIcon().textAlignment() == qmt::StereotypeIcon::TextalignBelow) {
@@ -169,8 +156,8 @@ PackageItem::ShapeGeometry PackageItem::calcMinimumGeometry() const
double width = 0.0;
double height = 0.0;
- if (m_customIcon) {
- QSizeF sz = stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(),
+ if (customIconItem()) {
+ QSizeF sz = customIconItemMinimumSize(customIconItem(),
CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT);
if (shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignTop
&& shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignCenter)
@@ -244,12 +231,7 @@ void PackageItem::updateGeometry()
// calc width and height
if (object()->isAutoSized()) {
- if (!m_customIcon) {
- if (width < MINIMUM_AUTO_WIDTH)
- width = MINIMUM_AUTO_WIDTH;
- if (height < MINIMUM_AUTO_HEIGHT)
- height = MINIMUM_AUTO_HEIGHT;
- }
+ correctAutoSize(customIconItem(), width, height, MINIMUM_AUTO_WIDTH, MINIMUM_AUTO_HEIGHT);
} else {
QRectF rect = object()->rect();
if (rect.width() > width)
@@ -273,9 +255,9 @@ void PackageItem::updateGeometry()
// a backup for the graphics item used for manual resized and persistency.
object()->setRect(rect);
- if (m_customIcon) {
- m_customIcon->setPos(left, top);
- m_customIcon->setActualSize(QSizeF(width, height));
+ if (customIconItem()) {
+ customIconItem()->setPos(left, top);
+ customIconItem()->setActualSize(QSizeF(width, height));
switch (shapeIcon().textAlignment()) {
case qmt::StereotypeIcon::TextalignBelow:
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.h
index 19c2fe54ab..f87af2fa35 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.h
@@ -40,7 +40,6 @@ private:
ShapeGeometry calcMinimumGeometry() const;
void updateGeometry();
- CustomIconItem *m_customIcon = nullptr;
QGraphicsPolygonItem *m_shape = nullptr;
ContextLabelItem *m_contextLabel = nullptr;
};
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp
index a2f444f59e..ca9dd8c3a2 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp
@@ -380,7 +380,12 @@ void RelationItem::setHandlePos(int index, const QPointF &pos)
}
}
-void RelationItem::dropHandle(int index, double rasterWidth, double rasterHeight)
+static inline bool between(double v, double mid, double range)
+{
+ return v >= mid-range && v <= mid+range;
+}
+
+void RelationItem::dropHandle(int index, bool extraSnap, double rasterWidth, double rasterHeight)
{
if (index == 0) {
m_grabbedEndA = false;
@@ -398,9 +403,40 @@ void RelationItem::dropHandle(int index, double rasterWidth, double rasterHeight
QMT_ASSERT(index >= 0 && index < intermediatePoints.size(), return);
QPointF pos = intermediatePoints.at(index).pos();
- double x = qRound(pos.x() / rasterWidth) * rasterWidth;
- double y = qRound(pos.y() / rasterHeight) * rasterHeight;
- intermediatePoints[index].setPos(QPointF(x, y));
+ static constexpr int ANGLE = 20.0;
+ bool roundX = true;
+ bool roundY = true;
+ if (extraSnap) {
+ if (index >= 1) {
+ double angle = GeometryUtilities::calcAngle(QLineF(intermediatePoints.at(index).pos(),
+ intermediatePoints.at(index - 1).pos()));
+ if (between(qAbs(angle), 90, ANGLE)) {
+ pos.setX(intermediatePoints.at(index - 1).pos().x());
+ roundX = false;
+ }
+ if (between(angle, 0, ANGLE) || between(qAbs(angle), 180, ANGLE)) {
+ pos.setY(intermediatePoints.at(index - 1).pos().y());
+ roundY = false;
+ }
+ }
+ if (index < intermediatePoints.size() - 1) {
+ double angle = GeometryUtilities::calcAngle(QLineF(intermediatePoints.at(index).pos(),
+ intermediatePoints.at(index + 1).pos()));
+ if (between(qAbs(angle), 90, ANGLE)) {
+ pos.setX(intermediatePoints.at(index + 1).pos().x());
+ roundX = false;
+ }
+ if (between(angle, 0, ANGLE) || between(qAbs(angle), 180, ANGLE)) {
+ pos.setY(intermediatePoints.at(index + 1).pos().y());
+ roundY = false;
+ }
+ }
+ }
+ if (roundX)
+ pos.setX(qRound(pos.x() / rasterWidth) * rasterWidth);
+ if (roundY)
+ pos.setY(qRound(pos.y() / rasterHeight) * rasterHeight);
+ intermediatePoints[index].setPos(pos);
m_diagramSceneModel->diagramController()->startUpdateElement(m_relation, m_diagramSceneModel->diagram(), DiagramController::UpdateMinor);
m_relation->setIntermediatePoints(intermediatePoints);
@@ -507,9 +543,11 @@ void RelationItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
const Style *RelationItem::adaptedStyle()
{
- DObject *endAObject = m_diagramSceneModel->diagramController()->findElement<DObject>(m_relation->endAUid(), m_diagramSceneModel->diagram());
- DObject *endBObject = m_diagramSceneModel->diagramController()->findElement<DObject>(m_relation->endBUid(), m_diagramSceneModel->diagram());
- StyledRelation styledRelation(m_relation, endAObject, endBObject);
+ const DObject *endAObject = m_diagramSceneModel->diagramController()->findElement<DObject>(m_relation->endAUid(), m_diagramSceneModel->diagram());
+ const DObject *endBObject = m_diagramSceneModel->diagramController()->findElement<DObject>(m_relation->endBUid(), m_diagramSceneModel->diagram());
+ const CustomRelation customRelation = m_diagramSceneModel->stereotypeController()
+ ->findCustomRelationByStereotype(m_relation->stereotypes().value(0));
+ StyledRelation styledRelation(m_relation, endAObject, endBObject, &customRelation);
return m_diagramSceneModel->styleController()->adaptRelationStyle(styledRelation);
}
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.h
index a43b8b2749..0980d232e4 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.h
@@ -56,7 +56,7 @@ public:
void insertHandle(int beforeIndex, const QPointF &pos, double rasterWidth, double rasterHeight) override;
void deleteHandle(int index) override;
void setHandlePos(int index, const QPointF &pos) override;
- void dropHandle(int index, double rasterWidth, double rasterHeight) override;
+ void dropHandle(int index, bool extraSnap, double rasterWidth, double rasterHeight) override;
virtual void update();
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp
index ad668f6bee..9313327c87 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp
@@ -57,7 +57,9 @@ void StereotypeDisplayVisitor::visitDObject(const DObject *object)
DObject::StereotypeDisplay stereotypeDisplay = object->stereotypeDisplay();
m_stereotypeIconId = m_stereotypeController->findStereotypeIconId(m_stereotypeIconElement, object->stereotypes());
- if (m_stereotypeIconId.isEmpty() && stereotypeDisplay == DObject::StereotypeIcon) {
+ if (object->hasImage() && stereotypeDisplay == DObject::StereotypeSmart) {
+ stereotypeDisplay = DObject::StereotypeLabel;
+ } else if (m_stereotypeIconId.isEmpty() && stereotypeDisplay == DObject::StereotypeIcon) {
stereotypeDisplay = DObject::StereotypeLabel;
} else if (!m_stereotypeIconId.isEmpty() && stereotypeDisplay == DObject::StereotypeSmart) {
StereotypeIcon stereotypeIcon = m_stereotypeController->findStereotypeIcon(m_stereotypeIconId);
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp
index 3a14eb10d9..632da76f05 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp
@@ -384,27 +384,29 @@ void ArrowItem::updateShaft(const Style *style)
QMT_ASSERT(m_shaftItem, return);
QPen pen(style->linePen());
+ pen.setCapStyle(Qt::FlatCap);
+
+ auto scale = [&pen](qreal v) {
+ return v / ((pen.widthF() - 1.0) / 2.0 + 1.0);
+ };
+
switch (m_shaft) {
case ShaftSolid:
break;
case ShaftDashed:
- pen.setDashPattern(QVector<qreal>()
- << (4.0 / pen.widthF()) << (4.0 / pen.widthF()));
+ pen.setDashPattern(QVector<qreal>() << scale(5.0) << scale(3.0));
break;
case ShaftDot:
- pen.setDashPattern(QVector<qreal>()
- << (2.0 / pen.widthF()) << (2.0 / pen.widthF()));
+ pen.setDashPattern(QVector<qreal>() << scale(3.0) << scale(3.0));
break;
case ShaftDashDot:
- pen.setDashPattern(QVector<qreal>()
- << (4.0 / pen.widthF()) << (2.0 / pen.widthF())
- << (2.0 / pen.widthF()) << (2.0 / pen.widthF()));
+ pen.setDashPattern(QVector<qreal>() << scale(5.0) << scale(3.0)
+ << scale(3.0) << scale(3.0));
break;
case ShaftDashDotDot:
- pen.setDashPattern(QVector<qreal>()
- << (4.0 / pen.widthF()) << (2.0 / pen.widthF())
- << (2.0 / pen.widthF()) << (2.0 / pen.widthF())
- << (2.0 / pen.widthF()) << (2.0 / pen.widthF()));
+ pen.setDashPattern(QVector<qreal>() << scale(5.0) << scale(3.0)
+ << scale(3.0) << scale(3.0)
+ << scale(3.0) << scale(3.0));
break;
}
m_shaftItem->setPen(pen);
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp
index 066f9b7875..36e4c4f789 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp
@@ -57,55 +57,97 @@ void CustomIconItem::setPen(const QPen &pen)
m_pen = pen;
}
+void CustomIconItem::setImage(const QImage &image)
+{
+ m_image = image;
+}
+
double CustomIconItem::shapeWidth() const
{
- return m_stereotypeIcon.width();
+ if (!m_image.isNull())
+ return m_image.width();
+ return m_stereotypeIcon.hasIconWidth() ? m_stereotypeIcon.iconWidth()
+ : m_stereotypeIcon.width();
}
double CustomIconItem::shapeHeight() const
{
- return m_stereotypeIcon.height();
+ if (!m_image.isNull())
+ return m_image.height();
+ return m_stereotypeIcon.hasIconHeight() ? m_stereotypeIcon.iconHeight()
+ : m_stereotypeIcon.height();
}
QRectF CustomIconItem::boundingRect() const
{
- ShapeSizeVisitor visitor(QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
+ if (!m_image.isNull())
+ return QRectF(QPointF(0.0, 0.0), m_actualSize) | childrenBoundingRect();
+ ShapeSizeVisitor visitor(QPointF(0.0, 0.0),
+ QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()),
+ m_baseSize,
+ m_actualSize);
m_stereotypeIcon.iconShape().visitShapes(&visitor);
return visitor.boundingRect() | childrenBoundingRect();
}
-void CustomIconItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+void CustomIconItem::paint(QPainter *painter,
+ const QStyleOptionGraphicsItem *option,
+ QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
painter->save();
- painter->setBrush(m_brush);
- painter->setPen(m_pen);
+ if (!m_image.isNull()) {
+ painter->drawImage(QRectF(QPointF(0.0, 0.0), m_actualSize), m_image);
+ } else {
+ painter->setBrush(m_brush);
+ painter->setPen(m_pen);
#ifdef DEBUG_OUTLINE
- ShapePolygonVisitor visitor(QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
- IconShape shape = m_stereotypeIcon.outlineShape();
- if (shape.isEmpty())
- shape = m_stereotypeIcon.iconShape();
- shape.visitShapes(&visitor);
- painter->drawPath(visitor.path());
- ShapePaintVisitor visitor1(painter, QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
- m_stereotypeIcon.iconShape().visitShapes(&visitor1);
+ ShapePolygonVisitor visitor(QPointF(0.0, 0.0),
+ QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()),
+ m_baseSize,
+ m_actualSize);
+ IconShape shape = m_stereotypeIcon.outlineShape();
+ if (shape.isEmpty())
+ shape = m_stereotypeIcon.iconShape();
+ shape.visitShapes(&visitor);
+ painter->drawPath(visitor.path());
+ ShapePaintVisitor visitor1(painter,
+ QPointF(0.0, 0.0),
+ QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()),
+ m_baseSize,
+ m_actualSize);
+ m_stereotypeIcon.iconShape().visitShapes(&visitor1);
#else
- ShapePaintVisitor visitor(painter, QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
- m_stereotypeIcon.iconShape().visitShapes(&visitor);
+ ShapePaintVisitor visitor(painter,
+ QPointF(0.0, 0.0),
+ QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()),
+ m_baseSize,
+ m_actualSize);
+ m_stereotypeIcon.iconShape().visitShapes(&visitor);
#endif
+ }
painter->restore();
}
QList<QPolygonF> CustomIconItem::outline() const
{
- ShapePolygonVisitor visitor(QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
- IconShape shape = m_stereotypeIcon.outlineShape();
- if (shape.isEmpty())
- shape = m_stereotypeIcon.iconShape();
- shape.visitShapes(&visitor);
- return visitor.toPolygons();
+ if (!m_image.isNull()) {
+ QList<QPolygonF> polygons;
+ polygons.append(QPolygonF(QRectF(QPointF(0.0, 0.0), m_actualSize)));
+ return polygons;
+ } else {
+ ShapePolygonVisitor visitor(QPointF(0.0, 0.0),
+ QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()),
+ m_baseSize,
+ m_actualSize);
+ IconShape shape = m_stereotypeIcon.outlineShape();
+ if (shape.isEmpty())
+ shape = m_stereotypeIcon.iconShape();
+ shape.visitShapes(&visitor);
+ return visitor.toPolygons();
+ }
}
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h b/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h
index 7f85e87516..f61db552ac 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h
@@ -9,6 +9,7 @@
#include "qmt/stereotype/stereotypeicon.h"
#include <QBrush>
+#include <QImage>
#include <QPen>
namespace qmt {
@@ -26,6 +27,9 @@ public:
void setActualSize(const QSizeF &actualSize);
void setBrush(const QBrush &brush);
void setPen(const QPen &pen);
+ QImage image() const { return m_image; }
+ bool hasImage() const { return !m_image.isNull(); }
+ void setImage(const QImage &image);
StereotypeIcon stereotypeIcon() const { return m_stereotypeIcon; }
double shapeWidth() const;
double shapeHeight() const;
@@ -43,6 +47,7 @@ private:
QSizeF m_actualSize;
QBrush m_brush;
QPen m_pen;
+ QImage m_image;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.cpp
index 60275cb5ec..185321d84c 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.cpp
@@ -13,13 +13,18 @@ namespace qmt {
EditableTextItem::EditableTextItem(QGraphicsItem *parent)
: QGraphicsTextItem(parent)
{
- setTextInteractionFlags(Qt::TextEditorInteraction);
+ setTextInteractionFlags(Qt::NoTextInteraction);
}
EditableTextItem::~EditableTextItem()
{
}
+void EditableTextItem::setEditable(bool editable)
+{
+ setTextInteractionFlags(editable ? Qt::TextEditorInteraction : Qt::NoTextInteraction);
+}
+
void EditableTextItem::setShowFocus(bool showFocus)
{
m_showFocus = showFocus;
@@ -72,13 +77,6 @@ void EditableTextItem::keyReleaseEvent(QKeyEvent *event)
QGraphicsTextItem::keyReleaseEvent(event);
}
-void EditableTextItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
-{
- scene()->clearSelection();
- parentItem()->setSelected(true);
- QGraphicsTextItem::mousePressEvent(event);
-}
-
void EditableTextItem::focusOutEvent(QFocusEvent *event)
{
QGraphicsTextItem::focusOutEvent(event);
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.h b/src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.h
index 7c361b72fd..b18bf85cfc 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.h
@@ -19,6 +19,7 @@ signals:
void returnKeyPressed();
public:
+ void setEditable(bool editable);
void setShowFocus(bool showFocus);
void setFilterReturnKey(bool filterReturnKey);
void setFilterTabKey(bool filterTabKey);
@@ -30,7 +31,6 @@ public:
protected:
void keyPressEvent(QKeyEvent *event) override;
void keyReleaseEvent(QKeyEvent *event) override;
- void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void focusOutEvent(QFocusEvent *event) override;
private:
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.cpp
index 8206a7fe9a..231b78a3a0 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.cpp
@@ -79,7 +79,10 @@ protected:
{
m_lastPos = event->scenePos();
QPointF delta = m_lastPos - m_startPos;
- m_owner->moveHandle(m_pointIndex, delta, Release, m_qualifier);
+ HandleQualifier qualifier = m_qualifier;
+ if (qualifier == None && (event->modifiers() & Qt::ShiftModifier) != 0)
+ qualifier = SnapHandle;
+ m_owner->moveHandle(m_pointIndex, delta, Release, qualifier);
clearFocus();
}
@@ -267,6 +270,7 @@ void PathSelectionItem::moveHandle(int pointIndex, const QPointF &deltaMove, Han
{
switch (handleQualifier) {
case None:
+ case SnapHandle:
{
if (handleStatus == Press) {
m_focusHandleItem = m_handles.at(pointIndex);
@@ -275,13 +279,13 @@ void PathSelectionItem::moveHandle(int pointIndex, const QPointF &deltaMove, Han
QPointF newPos = m_originalHandlePos + deltaMove;
m_windable->setHandlePos(pointIndex, newPos);
if (handleStatus == Release) {
- m_windable->dropHandle(pointIndex, RASTER_WIDTH, RASTER_HEIGHT);
+ m_windable->dropHandle(pointIndex, handleQualifier == SnapHandle, RASTER_WIDTH, RASTER_HEIGHT);
m_focusHandleItem = nullptr;
}
break;
}
case DeleteHandle:
- if (handleStatus == Press)
+ if (handleStatus == Release)
m_windable->deleteHandle(pointIndex);
break;
}
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.h b/src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.h
index 0c4891948a..06a2d36c49 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.h
@@ -25,7 +25,8 @@ class PathSelectionItem : public QGraphicsItem
enum HandleQualifier {
None,
- DeleteHandle
+ DeleteHandle,
+ SnapHandle
};
public:
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp
index 26b8ebc1c4..49bca85162 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp
@@ -121,11 +121,13 @@ void RelationStarter::keyPressEvent(QKeyEvent *event)
m_currentPreviewArrowIntermediatePoints.append(p);
// Do not update the preview arrow here because last two points are now identical which looks wired
}
+ event->accept();
} else if (event->key() == Qt::Key_Control) {
if (!m_currentPreviewArrowIntermediatePoints.isEmpty()) {
m_currentPreviewArrowIntermediatePoints.removeLast();
updateCurrentPreviewArrow(m_currentPreviewArrow->lastLineSegment().p1());
}
+ event->accept();
}
}
diff --git a/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.cpp b/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.cpp
index 5634c4eb7f..eba246676d 100644
--- a/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.cpp
+++ b/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.cpp
@@ -14,9 +14,14 @@
#include <QDragLeaveEvent>
#include <QDropEvent>
#include <QMimeData>
+#include <QScrollBar>
namespace qmt {
+namespace {
+const qreal ADJUSTMENT = 80;
+};
+
DiagramView::DiagramView(QWidget *parent)
: QGraphicsView(parent)
{
@@ -25,6 +30,9 @@ DiagramView::DiagramView(QWidget *parent)
setDragMode(QGraphicsView::RubberBandDrag);
setFrameShape(QFrame::NoFrame);
setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+ m_panTimer.setInterval(200);
+ m_panTimer.setSingleShot(false);
+ connect(&m_panTimer, &QTimer::timeout, this, &DiagramView::onPanTimeout);
}
DiagramView::~DiagramView()
@@ -130,12 +138,41 @@ void DiagramView::dropEvent(QDropEvent *event)
}
}
+void DiagramView::mousePressEvent(QMouseEvent *event)
+{
+ m_panTimer.start();
+ QGraphicsView::mousePressEvent(event);
+}
+
+void DiagramView::mouseReleaseEvent(QMouseEvent *event)
+{
+ m_panTimer.stop();
+ QGraphicsView::mouseReleaseEvent(event);
+}
+
+void DiagramView::mouseMoveEvent(QMouseEvent *event)
+{
+ QGraphicsView::mouseMoveEvent(event);
+ m_lastMouse = event->pos();
+}
+
void DiagramView::onSceneRectChanged(const QRectF &sceneRect)
{
// add some adjustment to all 4 sides
- static const qreal ADJUSTMENT = 80;
QRectF rect = sceneRect.adjusted(-ADJUSTMENT, -ADJUSTMENT, ADJUSTMENT, ADJUSTMENT);
setSceneRect(rect);
}
+void DiagramView::onPanTimeout()
+{
+ if (m_lastMouse.x() < ADJUSTMENT)
+ horizontalScrollBar()->triggerAction(QScrollBar::SliderSingleStepSub);
+ else if (m_lastMouse.x() > viewport()->size().width() - ADJUSTMENT)
+ horizontalScrollBar()->triggerAction(QScrollBar::SliderSingleStepAdd);
+ if (m_lastMouse.y() < ADJUSTMENT)
+ verticalScrollBar()->triggerAction(QScrollBar::SliderSingleStepSub);
+ else if (m_lastMouse.y() > viewport()->size().height() - ADJUSTMENT)
+ verticalScrollBar()->triggerAction(QScrollBar::SliderSingleStepAdd);
+}
+
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.h b/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.h
index 41386f09bd..4eee60ff44 100644
--- a/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.h
+++ b/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.h
@@ -7,6 +7,7 @@
#include "qmt/infrastructure/qmt_global.h"
#include <QPointer>
+#include <QTimer>
namespace qmt {
@@ -27,11 +28,17 @@ protected:
void dragLeaveEvent(QDragLeaveEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
void dropEvent(QDropEvent *event) override;
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
private:
void onSceneRectChanged(const QRectF &sceneRect);
+ void onPanTimeout();
QPointer<DiagramSceneModel> m_diagramSceneModel;
+ QPointF m_lastMouse;
+ QTimer m_panTimer;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/model/mdiagram.h b/src/libs/modelinglib/qmt/model/mdiagram.h
index 8f327daabc..bebe17cb50 100644
--- a/src/libs/modelinglib/qmt/model/mdiagram.h
+++ b/src/libs/modelinglib/qmt/model/mdiagram.h
@@ -21,7 +21,7 @@ public:
MDiagram &operator=(const MDiagram &rhs);
- const QList<DElement *> &diagramElements() const { return m_elements; }
+ const QList<DElement *> diagramElements() const { return m_elements; }
DElement *findDiagramElement(const Uid &key) const;
DElement *findDelegate(const Uid &modelUid) const;
void setDiagramElements(const QList<DElement *> &elements);
diff --git a/src/libs/modelinglib/qmt/model/mobject.cpp b/src/libs/modelinglib/qmt/model/mobject.cpp
index 734be13567..1e6bf8d0b3 100644
--- a/src/libs/modelinglib/qmt/model/mobject.cpp
+++ b/src/libs/modelinglib/qmt/model/mobject.cpp
@@ -20,6 +20,7 @@ MObject::MObject()
MObject::MObject(const MObject &rhs)
: MElement(rhs),
m_name(rhs.m_name),
+ m_linkedfilename(rhs.m_linkedfilename),
m_children(true),
m_relations(true)
{
@@ -34,6 +35,7 @@ MObject &MObject::operator =(const MObject &rhs)
if (this != &rhs) {
MElement::operator=(rhs);
m_name = rhs.m_name;
+ m_linkedfilename = rhs.m_linkedfilename;
// no deep copy; list of children remains unchanged
}
return *this;
@@ -44,6 +46,11 @@ void MObject::setName(const QString &name)
m_name = name;
}
+void MObject::setLinkedFileName(const QString &linkedfilename)
+{
+ m_linkedfilename = linkedfilename;
+}
+
void MObject::setChildren(const Handles<MObject> &children)
{
m_children = children;
diff --git a/src/libs/modelinglib/qmt/model/mobject.h b/src/libs/modelinglib/qmt/model/mobject.h
index 1dc95887d9..33a475ed6e 100644
--- a/src/libs/modelinglib/qmt/model/mobject.h
+++ b/src/libs/modelinglib/qmt/model/mobject.h
@@ -23,6 +23,8 @@ public:
QString name() const { return m_name; }
void setName(const QString &name);
+ QString linkedFileName() const { return m_linkedfilename; }
+ void setLinkedFileName(const QString &linkedfilename);
const Handles<MObject> &children() const { return m_children; }
void setChildren(const Handles<MObject> &children);
@@ -48,6 +50,7 @@ public:
private:
QString m_name;
+ QString m_linkedfilename;
Handles<MObject> m_children;
Handles<MRelation> m_relations;
};
diff --git a/src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.cpp b/src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.cpp
index deb458e4bc..66cfb4576f 100644
--- a/src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.cpp
+++ b/src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.cpp
@@ -35,6 +35,7 @@ void MFlatAssignmentVisitor::visitMObject(const MObject *object)
auto targetObject = dynamic_cast<MObject *>(m_target);
QMT_ASSERT(targetObject, return);
targetObject->setName(object->name());
+ targetObject->setLinkedFileName(object->linkedFileName());
}
void MFlatAssignmentVisitor::visitMPackage(const MPackage *package)
diff --git a/src/libs/modelinglib/qmt/model_ui/modeltreefilterdata.cpp b/src/libs/modelinglib/qmt/model_ui/modeltreefilterdata.cpp
new file mode 100644
index 0000000000..ba411690f5
--- /dev/null
+++ b/src/libs/modelinglib/qmt/model_ui/modeltreefilterdata.cpp
@@ -0,0 +1,43 @@
+// Copyright (C) 2018 Jochen Becher
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "modeltreefilterdata.h"
+
+namespace qmt {
+
+void ModelTreeViewData::setShowRelations(bool newShowRelations)
+{
+ m_showRelations = newShowRelations;
+}
+
+void ModelTreeViewData::setShowDiagramElements(bool newShowDiagramElements)
+{
+ m_showDiagramElements = newShowDiagramElements;
+}
+
+void ModelTreeFilterData::setType(Type newType)
+{
+ m_type = newType;
+}
+
+void ModelTreeFilterData::setCustomId(const QString &newCustomId)
+{
+ m_customId = newCustomId;
+}
+
+void ModelTreeFilterData::setStereotypes(const QStringList &newStereotypes)
+{
+ m_stereotypes = newStereotypes;
+}
+
+void ModelTreeFilterData::setName(const QString &newName)
+{
+ m_name = newName;
+}
+
+void ModelTreeFilterData::setDirection(Direction newDirection)
+{
+ m_direction = newDirection;
+}
+
+} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/model_ui/modeltreefilterdata.h b/src/libs/modelinglib/qmt/model_ui/modeltreefilterdata.h
new file mode 100644
index 0000000000..3af018fefd
--- /dev/null
+++ b/src/libs/modelinglib/qmt/model_ui/modeltreefilterdata.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2018 Jochen Becher
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <QString>
+#include <QStringList>
+
+namespace qmt {
+
+class ModelTreeViewData
+{
+public:
+
+ bool showRelations() const { return m_showRelations; }
+ void setShowRelations(bool newShowRelations);
+
+ bool showDiagramElements() const { return m_showDiagramElements; }
+ void setShowDiagramElements(bool newShowDiagramElements);
+
+private:
+ bool m_showRelations = true;
+ bool m_showDiagramElements = false;
+};
+
+class ModelTreeFilterData
+{
+public:
+ enum class Type {
+ Any,
+ Package,
+ Component,
+ Class,
+ Diagram,
+ Item,
+ Dependency,
+ Association,
+ Inheritance,
+ Connection
+ };
+
+ enum class Direction {
+ Any,
+ Outgoing,
+ Incoming,
+ Bidirectional
+ };
+
+ Type type() const { return m_type; }
+ void setType(Type newType);
+
+ QString customId() const { return m_customId; }
+ void setCustomId(const QString &newCustomId);
+
+ QStringList stereotypes() const { return m_stereotypes; }
+ void setStereotypes(const QStringList &newStereotypes);
+
+ QString name() const { return m_name; }
+ void setName(const QString &newName);
+
+ Direction direction() const { return m_direction; }
+ void setDirection(Direction newDirection);
+
+private:
+ Type m_type = Type::Any;
+ QString m_customId;
+ QStringList m_stereotypes;
+ QString m_name;
+ Direction m_direction = Direction::Any;
+};
+
+} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/model_ui/sortedtreemodel.cpp b/src/libs/modelinglib/qmt/model_ui/sortedtreemodel.cpp
index 972c2f9c00..e69e1635a7 100644
--- a/src/libs/modelinglib/qmt/model_ui/sortedtreemodel.cpp
+++ b/src/libs/modelinglib/qmt/model_ui/sortedtreemodel.cpp
@@ -3,14 +3,203 @@
#include "sortedtreemodel.h"
+#include "qmt/model/massociation.h"
+#include "qmt/model/mcanvasdiagram.h"
+#include "qmt/model/mclass.h"
+#include "qmt/model/mcomponent.h"
+#include "qmt/model/mconnection.h"
+#include "qmt/model/mdependency.h"
+#include "qmt/model/minheritance.h"
+#include "qmt/model/mitem.h"
+#include "qmt/model/mpackage.h"
+#include "qmt/model/mconstvisitor.h"
#include "treemodel.h"
namespace qmt {
+namespace {
+
+class Filter : public MConstVisitor {
+public:
+
+ void setModelTreeViewData(const ModelTreeViewData *viewData)
+ {
+ m_viewData = viewData;
+ }
+
+ void setModelTreeFilterData(const ModelTreeFilterData *filterData)
+ {
+ m_filterData = filterData;
+ }
+
+ bool keep() const { return m_keep; }
+
+ void visitMElement(const MElement *element) override
+ {
+ if (!m_filterData->stereotypes().isEmpty()) {
+ const QStringList stereotypes = element->stereotypes();
+ bool containsElementStereotype = std::any_of(
+ stereotypes.constBegin(), stereotypes.constEnd(),
+ [&](const QString &s) { return m_filterData->stereotypes().contains(s); });
+ if (!containsElementStereotype) {
+ m_keep = false;
+ return;
+ }
+ }
+ }
+
+ void visitMObject(const MObject *object) override
+ {
+ if (!m_filterData->name().isEmpty() && m_filterData->name() != object->name())
+ m_keep = false;
+ else
+ visitMElement(object);
+ }
+
+ void visitMPackage(const MPackage *package) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Package)
+ {
+ m_keep = false;
+ } else {
+ visitMObject(package);
+ }
+ }
+
+ void visitMClass(const MClass *klass) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Class)
+ {
+ m_keep = false;
+ } else {
+ visitMObject(klass);
+ }
+ }
+
+ void visitMComponent(const MComponent *component) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Component)
+ {
+ m_keep = false;
+ } else {
+ visitMObject(component);
+ }
+ }
+
+ void visitMDiagram(const MDiagram *diagram) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Diagram)
+ {
+ m_keep = false;
+ } else {
+ visitMObject(diagram);
+ }
+ }
+
+ void visitMCanvasDiagram(const MCanvasDiagram *diagram) override
+ {
+ visitMDiagram(diagram);
+ }
+
+ void visitMItem(const MItem *item) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Item)
+ {
+ m_keep = false;
+ } else {
+ visitMObject(item);
+ }
+ }
+
+ void visitMRelation(const MRelation *relation) override
+ {
+ if (!m_viewData->showRelations())
+ m_keep = false;
+ else if (!m_filterData->name().isEmpty() && m_filterData->name() != relation->name())
+ m_keep = false;
+ else
+ visitMElement(relation);
+ }
+
+ void visitMDependency(const MDependency *dependency) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Dependency)
+ {
+ m_keep = false;
+ } else {
+ switch (m_filterData->direction()) {
+ case ModelTreeFilterData::Direction::Any:
+ break;
+ case ModelTreeFilterData::Direction::Outgoing:
+ if (dependency->direction() != MDependency::AToB)
+ m_keep = false;
+ break;
+ case ModelTreeFilterData::Direction::Incoming:
+ if (dependency->direction() != MDependency::BToA)
+ m_keep = false;
+ break;
+ case ModelTreeFilterData::Direction::Bidirectional:
+ if (dependency->direction() != MDependency::Bidirectional)
+ m_keep = false;
+ break;
+ }
+ if (m_keep)
+ visitMRelation(dependency);
+ }
+ }
+
+ void visitMInheritance(const MInheritance *inheritance) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Inheritance)
+ {
+ m_keep = false;
+ } else {
+ visitMRelation(inheritance);
+ }
+ }
+
+ void visitMAssociation(const MAssociation *association) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Association)
+ {
+ m_keep = false;
+ } else {
+ visitMRelation(association);
+ }
+ }
+
+ void visitMConnection(const MConnection *connection) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Connection)
+ {
+ m_keep = false;
+ } else {
+ visitMRelation(connection);
+ }
+ }
+
+private:
+ const ModelTreeViewData *m_viewData = nullptr;
+ const ModelTreeFilterData *m_filterData = nullptr;
+ bool m_keep = true;
+};
+
+}
+
SortedTreeModel::SortedTreeModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
setDynamicSortFilter(false);
+ setRecursiveFilteringEnabled(true);
setSortCaseSensitivity(Qt::CaseInsensitive);
m_delayedSortTimer.setSingleShot(true);
@@ -33,6 +222,37 @@ void SortedTreeModel::setTreeModel(TreeModel *treeModel)
startDelayedSortTimer();
}
+void SortedTreeModel::setModelTreeViewData(const ModelTreeViewData &viewData)
+{
+ m_modelTreeViewData = viewData;
+ beginResetModel();
+ endResetModel();
+ startDelayedSortTimer();
+}
+
+void SortedTreeModel::setModelTreeFilterData(const ModelTreeFilterData &filterData)
+{
+ m_modelTreeViewFilterData = filterData;
+ beginResetModel();
+ endResetModel();
+ startDelayedSortTimer();
+}
+
+bool SortedTreeModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
+{
+ QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
+ MElement *element = m_treeModel->element(index);
+ if (element) {
+ Filter filter;
+ filter.setModelTreeViewData(&m_modelTreeViewData);
+ filter.setModelTreeFilterData(&m_modelTreeViewFilterData);
+ element->accept(&filter);
+ if (!filter.keep())
+ return false;
+ }
+ return true;
+}
+
bool SortedTreeModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
TreeModel::ItemType leftItemType = TreeModel::ItemType(sourceModel()->data(left, TreeModel::RoleItemType).toInt());
diff --git a/src/libs/modelinglib/qmt/model_ui/sortedtreemodel.h b/src/libs/modelinglib/qmt/model_ui/sortedtreemodel.h
index 0c01cf7de7..797a321132 100644
--- a/src/libs/modelinglib/qmt/model_ui/sortedtreemodel.h
+++ b/src/libs/modelinglib/qmt/model_ui/sortedtreemodel.h
@@ -4,6 +4,7 @@
#pragma once
#include "qmt/infrastructure/qmt_global.h"
+#include "qmt/model_ui/modeltreefilterdata.h"
#include <QSortFilterProxyModel>
#include <QTimer>
@@ -21,7 +22,11 @@ public:
TreeModel *treeModel() const { return m_treeModel; }
void setTreeModel(TreeModel *treeModel);
+ void setModelTreeViewData(const ModelTreeViewData &viewData);
+ void setModelTreeFilterData(const ModelTreeFilterData &filterData);
+
protected:
+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
private:
@@ -32,6 +37,8 @@ private:
void startDelayedSortTimer();
TreeModel *m_treeModel = nullptr;
+ ModelTreeViewData m_modelTreeViewData;
+ ModelTreeFilterData m_modelTreeViewFilterData;
QTimer m_delayedSortTimer;
};
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.cpp b/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.cpp
new file mode 100644
index 0000000000..40499e2839
--- /dev/null
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.cpp
@@ -0,0 +1,426 @@
+// Copyright (C) 2018 Jochen Becher
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "addrelatedelementsdialog.h"
+
+#include <qmt/tasks/diagramscenecontroller.h>
+#include <qmt/diagram_controller/dselection.h>
+#include <qmt/model/mdiagram.h>
+#include <qmt/model/mrelation.h>
+#include <qmt/model/mdependency.h>
+#include <qmt/model/minheritance.h>
+#include <qmt/model/massociation.h>
+#include <qmt/model/mconnection.h>
+#include <qmt/model_controller/modelcontroller.h>
+#include <qmt/model_controller/mvoidvisitor.h>
+
+#include "../../modelinglibtr.h"
+
+#include <utils/layoutbuilder.h>
+
+#include <QComboBox>
+#include <QDialogButtonBox>
+#include <QLabel>
+#include <QStringListModel>
+
+namespace qmt {
+
+namespace {
+
+enum class RelationType {
+ Any,
+ Dependency,
+ Association,
+ Inheritance,
+ Connection
+};
+
+enum class RelationDirection {
+ Any,
+ Outgoing,
+ Incoming,
+ Bidirectional
+};
+
+enum class ElementType {
+ Any,
+ Package,
+ Component,
+ Class,
+ Diagram,
+ Item,
+};
+
+class Filter : public qmt::MVoidConstVisitor {
+public:
+
+ void setRelationType(RelationType newRelationType)
+ {
+ m_relationType = newRelationType;
+ }
+
+ void setRelationTypeId(const QString &newRelationTypeId)
+ {
+ m_relationTypeId = newRelationTypeId;
+ }
+
+ void setRelationDirection(RelationDirection newRelationDirection)
+ {
+ m_relationDirection = newRelationDirection;
+ }
+
+ void setRelationStereotypes(const QStringList &newRelationStereotypes)
+ {
+ m_relationStereotypes = newRelationStereotypes;
+ }
+
+ void setElementType(ElementType newElementType)
+ {
+ m_elementType = newElementType;
+ }
+
+ void setElementStereotypes(const QStringList &newElementStereotypes)
+ {
+ m_elementStereotypes = newElementStereotypes;
+ }
+
+ void setObject(const qmt::DObject *dobject, const qmt::MObject *mobject)
+ {
+ m_dobject = dobject;
+ m_mobject = mobject;
+ }
+
+ void setRelation(const qmt::MRelation *relation)
+ {
+ m_relation = relation;
+ }
+
+ bool keep() const { return m_keep; }
+
+ void reset()
+ {
+ m_dobject = nullptr;
+ m_mobject = nullptr;
+ m_relation = nullptr;
+ m_keep = true;
+ }
+
+ // MConstVisitor interface
+ void visitMObject(const qmt::MObject *object) override
+ {
+ if (!m_elementStereotypes.isEmpty()) {
+ const QStringList stereotypes = object->stereotypes();
+ bool containsElementStereotype = std::any_of(
+ stereotypes.constBegin(), stereotypes.constEnd(),
+ [&](const QString &s) { return m_elementStereotypes.contains(s); });
+ if (!containsElementStereotype) {
+ m_keep = false;
+ return;
+ }
+ }
+ }
+
+ void visitMPackage(const qmt::MPackage *package) override
+ {
+ if (m_elementType == ElementType::Any || m_elementType == ElementType::Package)
+ qmt::MVoidConstVisitor::visitMPackage(package);
+ else
+ m_keep = false;
+ }
+
+ void visitMClass(const qmt::MClass *klass) override
+ {
+ if (m_elementType == ElementType::Any || m_elementType == ElementType::Class)
+ qmt::MVoidConstVisitor::visitMClass(klass);
+ else
+ m_keep = false;
+ }
+
+ void visitMComponent(const qmt::MComponent *component) override
+ {
+ if (m_elementType == ElementType::Any || m_elementType == ElementType::Component)
+ qmt::MVoidConstVisitor::visitMComponent(component);
+ else
+ m_keep = false;
+ }
+
+ void visitMDiagram(const qmt::MDiagram *diagram) override
+ {
+ if (m_elementType == ElementType::Any || m_elementType == ElementType::Diagram)
+ qmt::MVoidConstVisitor::visitMDiagram(diagram);
+ else
+ m_keep = false;
+ }
+
+ void visitMItem(const qmt::MItem *item) override
+ {
+ if (m_elementType == ElementType::Any || m_elementType == ElementType::Item)
+ qmt::MVoidConstVisitor::visitMItem(item);
+ else
+ m_keep = false;
+ }
+
+ void visitMRelation(const qmt::MRelation *relation) override
+ {
+ if (!m_relationStereotypes.isEmpty()) {
+ const QStringList relationStereotypes = relation->stereotypes();
+ bool containsRelationStereotype = std::any_of(
+ relationStereotypes.constBegin(), relationStereotypes.constEnd(),
+ [&](const QString &s) { return m_relationStereotypes.contains(s); });
+ if (!containsRelationStereotype) {
+ m_keep = false;
+ return;
+ }
+ }
+ }
+
+ void visitMDependency(const qmt::MDependency *dependency) override
+ {
+ if (m_relationDirection != RelationDirection::Any) {
+ bool keep = false;
+ if (m_relationDirection == RelationDirection::Outgoing) {
+ if (dependency->direction() == qmt::MDependency::AToB && dependency->endAUid() == m_mobject->uid())
+ keep = true;
+ else if (dependency->direction() == qmt::MDependency::BToA && dependency->endBUid() == m_mobject->uid())
+ keep = true;
+ } else if (m_relationDirection == RelationDirection::Incoming) {
+ if (dependency->direction() == qmt::MDependency::AToB && dependency->endBUid() == m_mobject->uid())
+ keep = true;
+ else if (dependency->direction() == qmt::MDependency::BToA && dependency->endAUid() == m_mobject->uid())
+ keep = true;
+ } else if (m_relationDirection == RelationDirection::Bidirectional) {
+ if (dependency->direction() == qmt::MDependency::Bidirectional)
+ keep = true;
+ }
+ m_keep = keep;
+ if (!keep)
+ return;
+ }
+ if (m_relationType == RelationType::Any || m_relationType == RelationType::Dependency)
+ qmt::MVoidConstVisitor::visitMDependency(dependency);
+ else
+ m_keep = false;
+ }
+
+ bool testDirection(const qmt::MRelation *relation)
+ {
+ if (m_relationDirection != RelationDirection::Any) {
+ bool keep = false;
+ if (m_relationDirection == RelationDirection::Outgoing) {
+ if (relation->endAUid() == m_mobject->uid())
+ keep = true;
+ } else if (m_relationDirection == RelationDirection::Incoming) {
+ if (relation->endBUid() == m_mobject->uid())
+ keep = true;
+ }
+ m_keep = keep;
+ if (!keep)
+ return false;
+ }
+ return true;
+ }
+
+ void visitMInheritance(const qmt::MInheritance *inheritance) override
+ {
+ if (!testDirection(inheritance))
+ return;
+ if (m_relationType == RelationType::Any || m_relationType == RelationType::Inheritance)
+ qmt::MVoidConstVisitor::visitMInheritance(inheritance);
+ else
+ m_keep = false;
+ }
+
+ void visitMAssociation(const qmt::MAssociation *association) override
+ {
+ if (!testDirection(association))
+ return;
+ if (m_relationType == RelationType::Any || m_relationType == RelationType::Association)
+ qmt::MVoidConstVisitor::visitMAssociation(association);
+ else
+ m_keep = false;
+ }
+
+ void visitMConnection(const qmt::MConnection *connection) override
+ {
+ if (!testDirection(connection))
+ return;
+ if (m_relationType == RelationType::Any || m_relationType == RelationType::Connection)
+ qmt::MVoidConstVisitor::visitMConnection(connection);
+ else
+ m_keep = false;
+ }
+
+private:
+ RelationType m_relationType = RelationType::Any;
+ QString m_relationTypeId;
+ RelationDirection m_relationDirection = RelationDirection::Any;
+ QStringList m_relationStereotypes;
+ ElementType m_elementType = ElementType::Any;
+ QStringList m_elementStereotypes;
+ const qmt::DObject *m_dobject = nullptr;
+ const qmt::MObject *m_mobject = nullptr;
+ const qmt::MRelation *m_relation = nullptr;
+ bool m_keep = true;
+};
+} // namespace
+
+class AddRelatedElementsDialog::Private {
+public:
+ qmt::DiagramSceneController *m_diagramSceneController = nullptr;
+ qmt::DSelection m_selection;
+ qmt::Uid m_diagramUid;
+ QStringListModel m_relationTypeModel;
+ QStringListModel m_relationDirectionModel;
+ QStringListModel m_relationStereotypesModel;
+ QStringListModel m_elementTypeModel;
+ QStringListModel m_elementStereotypesModel;
+ Filter m_filter;
+
+ QComboBox *RelationTypeCombobox;
+ QComboBox *DirectionCombobox;
+ QComboBox *StereotypesCombobox;
+ QComboBox *ElementStereotypesCombobox;
+ QComboBox *ElementTypeComboBox;
+ QLabel *NumberOfMatchingElementsValue;
+ QDialogButtonBox *buttonBox;
+};
+
+AddRelatedElementsDialog::AddRelatedElementsDialog(QWidget *parent) :
+ QDialog(parent),
+ d(new Private)
+{
+ setMinimumWidth(500);
+
+ d->RelationTypeCombobox = new QComboBox;
+ d->DirectionCombobox = new QComboBox;
+ d->StereotypesCombobox = new QComboBox;
+ d->StereotypesCombobox->setEditable(true);
+ d->ElementTypeComboBox = new QComboBox;
+ d->ElementStereotypesCombobox = new QComboBox;
+ d->ElementStereotypesCombobox->setEditable(true);
+ d->NumberOfMatchingElementsValue = new QLabel;
+ d->buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
+
+ using namespace Layouting;
+ Column {
+ Group {
+ title(Tr::tr("Relation Attributes")),
+ Form {
+ Tr::tr("Type"), d->RelationTypeCombobox, br,
+ Tr::tr("Direction"), d->DirectionCombobox, br,
+ Tr::tr("Stereotypes"), d->StereotypesCombobox, br,
+ },
+ },
+ Group {
+ title(Tr::tr("Other Element Attributes")),
+ Form {
+ Tr::tr("Type"), d->ElementTypeComboBox, br,
+ Tr::tr("Stereotypes"), d->ElementStereotypesCombobox, br,
+ },
+ },
+ Row {
+ Tr::tr("Number of matching elements: "), d->NumberOfMatchingElementsValue, st,
+ },
+ st,
+ d->buttonBox,
+ }.attachTo(this);
+
+ connect(d->RelationTypeCombobox, &QComboBox::currentIndexChanged, this, &AddRelatedElementsDialog::updateNumberOfElements);
+ connect(d->DirectionCombobox, &QComboBox::currentIndexChanged, this, &AddRelatedElementsDialog::updateNumberOfElements);
+ connect(d->StereotypesCombobox, &QComboBox::currentTextChanged, this, &AddRelatedElementsDialog::updateNumberOfElements);
+ connect(d->ElementTypeComboBox, &QComboBox::currentIndexChanged, this, &AddRelatedElementsDialog::updateNumberOfElements);
+ connect(d->ElementStereotypesCombobox, &QComboBox::currentTextChanged, this, &AddRelatedElementsDialog::updateNumberOfElements);
+ connect(d->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(d->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
+ connect(this, &QDialog::accepted, this, &AddRelatedElementsDialog::onAccepted);
+}
+
+AddRelatedElementsDialog::~AddRelatedElementsDialog()
+{
+ delete d;
+}
+
+void AddRelatedElementsDialog::setDiagramSceneController(qmt::DiagramSceneController *diagramSceneController)
+{
+ d->m_diagramSceneController = diagramSceneController;
+}
+
+void AddRelatedElementsDialog::setElements(const qmt::DSelection &selection, qmt::MDiagram *diagram)
+{
+ d->m_selection = selection;
+ d->m_diagramUid = diagram->uid();
+ QStringList relationTypes = {"Any", "Dependency", "Association", "Inheritance"};
+ d->m_relationTypeModel.setStringList(relationTypes);
+ d->RelationTypeCombobox->setModel(&d->m_relationTypeModel);
+ QStringList relationDirections = {"Any", "Outgoing (->)", "Incoming (<-)", "Bidirectional (<->)"};
+ d->m_relationDirectionModel.setStringList(relationDirections);
+ d->DirectionCombobox->setModel(&d->m_relationDirectionModel);
+ QStringList relationStereotypes = { };
+ d->m_relationStereotypesModel.setStringList(relationStereotypes);
+ d->StereotypesCombobox->setModel(&d->m_relationStereotypesModel);
+ QStringList elementTypes = {"Any", "Package", "Component", "Class", "Diagram", "Item"};
+ d->m_elementTypeModel.setStringList(elementTypes);
+ d->ElementTypeComboBox->setModel(&d->m_elementTypeModel);
+ QStringList elementStereotypes = { };
+ d->m_elementStereotypesModel.setStringList(elementStereotypes);
+ d->ElementStereotypesCombobox->setModel(&d->m_elementStereotypesModel);
+ updateNumberOfElements();
+}
+
+void AddRelatedElementsDialog::onAccepted()
+{
+ qmt::MDiagram *diagram = d->m_diagramSceneController->modelController()->findElement<qmt::MDiagram>(d->m_diagramUid);
+ if (diagram) {
+ updateFilter();
+ d->m_diagramSceneController->addRelatedElements(
+ d->m_selection, diagram,
+ [this](qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation) -> bool
+ {
+ return this->filter(dobject, mobject, relation);
+ });
+ }
+}
+
+void AddRelatedElementsDialog::updateFilter()
+{
+ d->m_filter.setRelationType((RelationType) d->RelationTypeCombobox->currentIndex());
+ d->m_filter.setRelationDirection((RelationDirection) d->DirectionCombobox->currentIndex());
+ d->m_filter.setRelationStereotypes(d->StereotypesCombobox->currentText().split(',', Qt::SkipEmptyParts));
+ d->m_filter.setElementType((ElementType) d->ElementTypeComboBox->currentIndex());
+ d->m_filter.setElementStereotypes(d->ElementStereotypesCombobox->currentText().split(',', Qt::SkipEmptyParts));
+}
+
+bool AddRelatedElementsDialog::filter(qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation)
+{
+ d->m_filter.reset();
+ d->m_filter.setObject(dobject, mobject);
+ d->m_filter.setRelation(relation);
+ relation->accept(&d->m_filter);
+ if (!d->m_filter.keep())
+ return false;
+ qmt::MObject *targetObject = nullptr;
+ if (relation->endAUid() != mobject->uid())
+ targetObject = d->m_diagramSceneController->modelController()->findObject(relation->endAUid());
+ else if (relation->endBUid() != mobject->uid())
+ targetObject = d->m_diagramSceneController->modelController()->findObject(relation->endBUid());
+ if (!targetObject)
+ return false;
+ targetObject->accept(&d->m_filter);
+ return d->m_filter.keep();
+}
+
+void AddRelatedElementsDialog::updateNumberOfElements()
+{
+ qmt::MDiagram *diagram = d->m_diagramSceneController->modelController()->findElement<qmt::MDiagram>(d->m_diagramUid);
+ if (diagram) {
+ updateFilter();
+ d->NumberOfMatchingElementsValue->setText(QString::number(d->m_diagramSceneController->countRelatedElements(
+ d->m_selection, diagram,
+ [this](qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation) -> bool
+ {
+ return this->filter(dobject, mobject, relation);
+ })));
+ }
+}
+
+} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.h b/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.h
new file mode 100644
index 0000000000..e0fefa1c6c
--- /dev/null
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2018 Jochen Becher
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "qmt/infrastructure/qmt_global.h"
+
+#include <QDialog>
+
+namespace qmt {
+
+class DSelection;
+class DObject;
+class MObject;
+class MDiagram;
+class MRelation;
+class DiagramSceneController;
+}
+
+namespace qmt {
+
+class QMT_EXPORT AddRelatedElementsDialog : public QDialog
+{
+ Q_OBJECT
+ class Private;
+
+public:
+ explicit AddRelatedElementsDialog(QWidget *parent = nullptr);
+ ~AddRelatedElementsDialog();
+
+ void setDiagramSceneController(qmt::DiagramSceneController *diagramSceneController);
+ void setElements(const qmt::DSelection &selection, qmt::MDiagram *diagram);
+
+private:
+ void onAccepted();
+ void updateFilter();
+ bool filter(qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation);
+ void updateNumberOfElements();
+
+ Private *d = nullptr;
+};
+
+} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/modeltreefilter.cpp b/src/libs/modelinglib/qmt/model_widgets_ui/modeltreefilter.cpp
new file mode 100644
index 0000000000..3fa671283a
--- /dev/null
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/modeltreefilter.cpp
@@ -0,0 +1,173 @@
+// Copyright (C) 2018 Jochen Becher
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "modeltreefilter.h"
+
+#include "../../modelinglibtr.h"
+
+#include <utils/layoutbuilder.h>
+
+#include <QCheckBox>
+#include <QComboBox>
+#include <QFrame>
+#include <QLabel>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QStringListModel>
+
+namespace qmt {
+
+class ModelTreeFilter::Private {
+public:
+ QStringListModel m_typeModel;
+ QStringListModel m_stereotypesModel;
+ QStringListModel m_directionModel;
+
+ QPushButton *resetViewButton;
+ QCheckBox *relationsCheckBox;
+ QCheckBox *diagramElementsCheckBox;
+ QPushButton *clearFilterButton;
+ QComboBox *typeComboBox;
+ QComboBox *stereotypesComboBox;
+ QLineEdit *nameLineEdit;
+ QComboBox *directionComboBox;
+};
+
+ModelTreeFilter::ModelTreeFilter(QWidget *parent) :
+ QWidget(parent),
+ d(new Private)
+{
+ d->resetViewButton = new QPushButton(Tr::tr("Reset"));
+ d->relationsCheckBox = new QCheckBox(Tr::tr("Relations"));
+ d->diagramElementsCheckBox = new QCheckBox(Tr::tr("Diagram Elements"));
+ d->diagramElementsCheckBox->setMaximumHeight(0);
+ d->clearFilterButton = new QPushButton(Tr::tr("Clear"));
+ d->typeComboBox = new QComboBox;
+ d->stereotypesComboBox = new QComboBox;
+ d->stereotypesComboBox->setEditable(true);
+ d->nameLineEdit = new QLineEdit;
+ d->directionComboBox = new QComboBox;
+
+ const auto boldLabel = [] (const QString &title) -> QLabel * {
+ auto label = new QLabel(title);
+ QFont boldFont = label->font();
+ boldFont.setWeight(QFont::Bold);
+ label->setFont(boldFont);
+ return label;
+ };
+
+ const auto line = [] () -> QFrame * {
+ auto line = new QFrame;
+ line->setFrameShadow(QFrame::Plain);
+ line->setFrameShape(QFrame::HLine);
+ return line;
+ };
+
+ const int margin = 9;
+
+ using namespace Layouting;
+ Column {
+ Column {
+ Row {
+ boldLabel(Tr::tr("View")), st, d->resetViewButton
+ },
+ d->relationsCheckBox,
+ d->diagramElementsCheckBox,
+ customMargin({margin, 0, margin, 0}),
+ },
+ Space(10),
+ line(),
+ Column {
+ Row {
+ boldLabel(Tr::tr("Filter")), st, d->clearFilterButton
+ },
+ Space(10),
+ Form {
+ Tr::tr("Type:"), d->typeComboBox, br,
+ Tr::tr("Stereotypes:"), d->stereotypesComboBox, br,
+ Tr::tr("Name:"), d->nameLineEdit, br,
+ Tr::tr("Direction:"), d->directionComboBox, br,
+ },
+ customMargin({margin, 0, margin, 0}),
+ },
+ st,
+ line(),
+ customMargin({0, margin, 0, 0}),
+ }.attachTo(this);
+
+ connect(d->resetViewButton, &QPushButton::clicked, this, &ModelTreeFilter::resetView);
+ connect(d->relationsCheckBox, &QCheckBox::clicked, this, &ModelTreeFilter::onViewChanged);
+ connect(d->diagramElementsCheckBox, &QCheckBox::clicked, this, &ModelTreeFilter::onViewChanged);
+ connect(d->clearFilterButton, &QPushButton::clicked, this, &ModelTreeFilter::clearFilter);
+ connect(d->typeComboBox, &QComboBox::currentIndexChanged, this, [this](int index) {
+ d->directionComboBox->setDisabled(index != (int) ModelTreeFilterData::Type::Dependency);
+ });
+ connect(d->typeComboBox, &QComboBox::currentIndexChanged, this, &ModelTreeFilter::onFilterChanged);
+ connect(d->stereotypesComboBox, &QComboBox::currentTextChanged, this, &ModelTreeFilter::onFilterChanged);
+ connect(d->nameLineEdit, &QLineEdit::textChanged, this, &ModelTreeFilter::onFilterChanged);
+ connect(d->directionComboBox, &QComboBox::currentTextChanged, this, &ModelTreeFilter::onFilterChanged);
+ setupFilter();
+ resetView();
+ clearFilter();
+}
+
+ModelTreeFilter::~ModelTreeFilter()
+{
+ delete d;
+}
+
+void ModelTreeFilter::setupFilter()
+{
+ QStringList types = {"Any", "Package", "Component", "Class", "Diagram", "Item",
+ "Dependency", "Association", "Inheritance", "Connection"};
+ d->m_typeModel.setStringList(types);
+ d->typeComboBox->setModel(&d->m_typeModel);
+
+ QStringList stereotypes = { };
+ d->m_stereotypesModel.setStringList(stereotypes);
+ d->stereotypesComboBox->setModel(&d->m_stereotypesModel);
+
+ QStringList directions = {"Any", "Outgoing (->)", "Incoming (<-)", "Bidirectional (<->)"};
+ d->m_directionModel.setStringList(directions);
+ d->directionComboBox->setModel(&d->m_directionModel);
+}
+
+void ModelTreeFilter::resetView()
+{
+ d->relationsCheckBox->setChecked(true);
+ d->diagramElementsCheckBox->setChecked(false);
+ onViewChanged();
+}
+
+void ModelTreeFilter::clearFilter()
+{
+ d->typeComboBox->setCurrentIndex(0);
+ d->stereotypesComboBox->clearEditText();
+ d->nameLineEdit->clear();
+ d->directionComboBox->setCurrentIndex(0);
+ onFilterChanged();
+}
+
+void ModelTreeFilter::onViewChanged()
+{
+ ModelTreeViewData modelTreeViewData;
+ modelTreeViewData.setShowRelations(d->relationsCheckBox->isChecked());
+ modelTreeViewData.setShowDiagramElements(d->diagramElementsCheckBox->isChecked());
+ emit viewDataChanged(modelTreeViewData);
+}
+
+void ModelTreeFilter::onFilterChanged()
+{
+ ModelTreeFilterData modelTreeFilterData;
+ modelTreeFilterData.setType((ModelTreeFilterData::Type) d->typeComboBox->currentIndex());
+ modelTreeFilterData.setCustomId(QString());
+ modelTreeFilterData.setStereotypes(d->stereotypesComboBox->currentText().split(',', Qt::SkipEmptyParts));
+ modelTreeFilterData.setName(d->nameLineEdit->text().trimmed());
+ if (modelTreeFilterData.type() == ModelTreeFilterData::Type::Dependency)
+ modelTreeFilterData.setDirection((ModelTreeFilterData::Direction) d->directionComboBox->currentIndex());
+ else
+ modelTreeFilterData.setDirection(ModelTreeFilterData::Direction::Any);
+ emit filterDataChanged(modelTreeFilterData);
+}
+
+} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/modeltreefilter.h b/src/libs/modelinglib/qmt/model_widgets_ui/modeltreefilter.h
new file mode 100644
index 0000000000..1de7237c6e
--- /dev/null
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/modeltreefilter.h
@@ -0,0 +1,39 @@
+// Copyright (C) 2018 Jochen Becher
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "qmt/infrastructure/qmt_global.h"
+#include "qmt/model_ui/modeltreefilterdata.h"
+
+#include <QWidget>
+
+namespace qmt {
+
+class QMT_EXPORT ModelTreeFilter : public QWidget
+{
+ Q_OBJECT
+ class Private;
+
+public:
+ explicit ModelTreeFilter(QWidget *parent = nullptr);
+ ~ModelTreeFilter();
+
+signals:
+ void viewDataChanged(const ModelTreeViewData &modelTreeViewData);
+ void filterDataChanged(const ModelTreeFilterData &modelTreeFilterData);
+
+private:
+
+ void setupFilter();
+ void resetView();
+ void clearFilter();
+ void onViewChanged();
+ void onFilterChanged();
+
+private:
+ Private *d = nullptr;
+};
+
+
+} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.cpp b/src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.cpp
index 68c22ce6df..875b1fa105 100644
--- a/src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.cpp
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.cpp
@@ -71,6 +71,46 @@ void ModelTreeView::setElementTasks(IElementTasks *elementTasks)
m_elementTasks = elementTasks;
}
+static void StoreStatus(QTreeView *view, QSortFilterProxyModel *model, const QModelIndex &parent, QVector<QModelIndex> &expanded_items)
+{
+ for (int index = 0; index < model->rowCount(parent); ++index) {
+ auto proxy_index = model->index(index, 0, parent);
+ if (view->isExpanded(proxy_index)) {
+ auto source_index = model->mapToSource(proxy_index);
+ expanded_items.append(source_index);
+ }
+ StoreStatus(view, model, proxy_index, expanded_items);
+ }
+}
+
+static void ApplyStatus(QTreeView *view, QSortFilterProxyModel *model, QVector<QModelIndex> &expanded_items)
+{
+ for (auto source_index : expanded_items) {
+ auto proxy_index = model->mapFromSource(source_index);
+ view->setExpanded(proxy_index, true);
+ }
+}
+
+void ModelTreeView::setModelTreeViewData(const ModelTreeViewData &viewData)
+{
+ if (m_sortedTreeModel) {
+ QVector<QModelIndex> expanded_items;
+ StoreStatus(this, m_sortedTreeModel, QModelIndex(), expanded_items);
+ m_sortedTreeModel->setModelTreeViewData(viewData);
+ ApplyStatus(this, m_sortedTreeModel, expanded_items);
+ }
+}
+
+void ModelTreeView::setModelTreeFilterData(const ModelTreeFilterData &filterData)
+{
+ if (m_sortedTreeModel) {
+ QVector<QModelIndex> expanded_items;
+ StoreStatus(this, m_sortedTreeModel, QModelIndex(), expanded_items);
+ m_sortedTreeModel->setModelTreeFilterData(filterData);
+ ApplyStatus(this, m_sortedTreeModel, expanded_items);
+ }
+}
+
QModelIndex ModelTreeView::mapToSourceModelIndex(const QModelIndex &index) const
{
return m_sortedTreeModel->mapToSource(index);
@@ -237,6 +277,10 @@ void ModelTreeView::contextMenuEvent(QContextMenuEvent *event)
menu.addAction(new ContextMenuAction(Tr::tr("Open Diagram"), "openDiagram", &menu));
addSeparator = true;
}
+ if (m_elementTasks->hasLinkedFile(melement)) {
+ menu.addAction(new ContextMenuAction(Tr::tr("Open Linked File"), "openLinkedFile", &menu));
+ addSeparator = true;
+ }
if (melement->owner()) {
if (addSeparator)
menu.addSeparator();
@@ -253,6 +297,8 @@ void ModelTreeView::contextMenuEvent(QContextMenuEvent *event)
m_elementTasks->openClassDefinition(melement);
} else if (action->id() == "openDiagram") {
m_elementTasks->openDiagram(melement);
+ } else if (action->id() == "openLinkedFile") {
+ m_elementTasks->openLinkedFile(melement);
} else if (action->id() == "delete") {
MSelection selection;
selection.append(melement->uid(), melement->owner()->uid());
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.h b/src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.h
index 0c07cb0372..e5537644a3 100644
--- a/src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.h
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.h
@@ -5,6 +5,7 @@
#include "qmt/infrastructure/qmt_global.h"
#include "qmt/model_ui/modeltreeviewinterface.h"
+#include "qmt/model_ui/modeltreefilterdata.h"
#include <QElapsedTimer>
#include <QTreeView>
@@ -32,6 +33,9 @@ public:
void setTreeModel(SortedTreeModel *model);
void setElementTasks(IElementTasks *elementTasks);
+ void setModelTreeViewData(const ModelTreeViewData &viewData);
+ void setModelTreeFilterData(const ModelTreeFilterData &filterData);
+
QModelIndex mapToSourceModelIndex(const QModelIndex &index) const;
void selectFromSourceModelIndex(const QModelIndex &index);
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp
index 969313ca33..11df24188d 100644
--- a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp
@@ -43,6 +43,7 @@
#include "qmt/diagram_scene/items/stereotypedisplayvisitor.h"
#include "qmt/stereotype/stereotypecontroller.h"
#include "qmt/stereotype/customrelation.h"
+#include "qmt/style/relationvisuals.h"
#include "qmt/style/stylecontroller.h"
#include "qmt/style/style.h"
#include "qmt/style/objectvisuals.h"
@@ -237,6 +238,61 @@ static DClass::TemplateDisplay translateIndexToTemplateDisplay(int index)
return map[index];
}
+static int translateRelationVisualPrimaryRoleToIndex(DRelation::VisualPrimaryRole visualRole)
+{
+ switch (visualRole) {
+ case DRelation::PrimaryRoleNormal:
+ return 0;
+ case DRelation::PrimaryRoleCustom1:
+ return 1;
+ case DRelation::PrimaryRoleCustom2:
+ return 2;
+ case DRelation::PrimaryRoleCustom3:
+ return 3;
+ case DRelation::PrimaryRoleCustom4:
+ return 4;
+ case DRelation::PrimaryRoleCustom5:
+ return 5;
+ }
+ return 0;
+}
+
+static DRelation::VisualPrimaryRole translateIndexToRelationVisualPrimaryRole(int index)
+{
+ static const DRelation::VisualPrimaryRole map[] = {
+ DRelation::PrimaryRoleNormal,
+ DRelation::PrimaryRoleCustom1, DRelation::PrimaryRoleCustom2, DRelation::PrimaryRoleCustom3,
+ DRelation::PrimaryRoleCustom4, DRelation::PrimaryRoleCustom5
+ };
+ QMT_ASSERT(index >= 0 && index <= 5, return DRelation::PrimaryRoleNormal);
+ return map[index];
+}
+
+static int translateRelationVisualSecondaryRoleToIndex(DRelation::VisualSecondaryRole visualRole)
+{
+ switch (visualRole) {
+ case DRelation::SecondaryRoleNone:
+ return 0;
+ case DRelation::SecondaryRoleWarning:
+ return 1;
+ case DRelation::SecondaryRoleError:
+ return 2;
+ case DRelation::SecondaryRoleSoften:
+ return 3;
+ }
+ return 0;
+}
+
+static DRelation::VisualSecondaryRole translateIndexToRelationVisualSecondaryRole(int index)
+{
+ static const DRelation::VisualSecondaryRole map[] = {
+ DRelation::SecondaryRoleNone,
+ DRelation::SecondaryRoleWarning, DRelation::SecondaryRoleError, DRelation::SecondaryRoleSoften
+ };
+ QMT_ASSERT(index >= 0 && index <= 5, return DRelation::SecondaryRoleNone);
+ return map[index];
+}
+
static int translateAnnotationVisualRoleToIndex(DAnnotation::VisualRole visualRole)
{
switch (visualRole) {
@@ -398,6 +454,7 @@ void PropertiesView::MView::visitMPackage(const MPackage *package)
else
setTitle<MPackage>(m_modelElements, Tr::tr("Package"), Tr::tr("Packages"));
visitMObject(package);
+ visitMObjectBehind(package);
}
void PropertiesView::MView::visitMClass(const MClass *klass)
@@ -472,12 +529,14 @@ void PropertiesView::MView::visitMClass(const MClass *klass)
}
if (m_classMembersEdit->isEnabled() != isSingleSelection)
m_classMembersEdit->setEnabled(isSingleSelection);
+ visitMObjectBehind(klass);
}
void PropertiesView::MView::visitMComponent(const MComponent *component)
{
setTitle<MComponent>(m_modelElements, Tr::tr("Component"), Tr::tr("Components"));
visitMObject(component);
+ visitMObjectBehind(component);
}
void PropertiesView::MView::visitMDiagram(const MDiagram *diagram)
@@ -497,6 +556,7 @@ void PropertiesView::MView::visitMCanvasDiagram(const MCanvasDiagram *diagram)
{
setTitle<MCanvasDiagram>(m_modelElements, Tr::tr("Canvas Diagram"), Tr::tr("Canvas Diagrams"));
visitMDiagram(diagram);
+ visitMDiagramBehind(diagram);
}
void PropertiesView::MView::visitMItem(const MItem *item)
@@ -521,6 +581,7 @@ void PropertiesView::MView::visitMItem(const MItem *item)
if (m_itemVarietyEdit->isEnabled() != isSingleSelection)
m_itemVarietyEdit->setEnabled(isSingleSelection);
}
+ visitMObjectBehind(item);
}
void PropertiesView::MView::visitMRelation(const MRelation *relation)
@@ -850,6 +911,7 @@ void PropertiesView::MView::visitDElement(const DElement *element)
void PropertiesView::MView::visitDObject(const DObject *object)
{
visitDElement(object);
+ visitDObjectBefore(object);
#ifdef SHOW_DEBUG_PROPERTIES
if (!m_posRectLabel) {
m_posRectLabel = new QLabel(m_topWidget);
@@ -1057,6 +1119,52 @@ void PropertiesView::MView::visitDItem(const DItem *item)
void PropertiesView::MView::visitDRelation(const DRelation *relation)
{
visitDElement(relation);
+ if (!m_relationVisualPrimaryRoleSelector) {
+ m_relationVisualPrimaryRoleSelector = new PaletteBox(m_topWidget);
+ setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleNormal);
+ setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleCustom1);
+ setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleCustom2);
+ setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleCustom3);
+ setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleCustom4);
+ setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleCustom5);
+ addRow(Tr::tr("Color:"), m_relationVisualPrimaryRoleSelector, "color");
+ connect(m_relationVisualPrimaryRoleSelector, &PaletteBox::activated,
+ this, &PropertiesView::MView::onRelationVisualPrimaryRoleChanged);
+ }
+ if (!m_relationVisualPrimaryRoleSelector->hasFocus()) {
+ DRelation::VisualPrimaryRole visualPrimaryRole;
+ if (haveSameValue(m_diagramElements, &DRelation::visualPrimaryRole, &visualPrimaryRole))
+ m_relationVisualPrimaryRoleSelector->setCurrentIndex(translateRelationVisualPrimaryRoleToIndex(visualPrimaryRole));
+ else
+ m_relationVisualPrimaryRoleSelector->setCurrentIndex(-1);
+ }
+ if (!m_relationVisualSecondaryRoleSelector) {
+ m_relationVisualSecondaryRoleSelector = new QComboBox(m_topWidget);
+ m_relationVisualSecondaryRoleSelector->addItems({ Tr::tr("Normal"), Tr::tr("Warning"), Tr::tr("Error"), Tr::tr("Soften") });
+ addRow(Tr::tr("Role:"), m_relationVisualSecondaryRoleSelector, "role");
+ connect(m_relationVisualSecondaryRoleSelector, QOverload<int>::of(&QComboBox::activated),
+ this, &PropertiesView::MView::onRelationVisualSecondaryRoleChanged);
+ }
+ if (!m_relationVisualSecondaryRoleSelector->hasFocus()) {
+ DRelation::VisualSecondaryRole visualSecondaryRole;
+ if (haveSameValue(m_diagramElements, &DRelation::visualSecondaryRole, &visualSecondaryRole))
+ m_relationVisualSecondaryRoleSelector->setCurrentIndex(translateRelationVisualSecondaryRoleToIndex(visualSecondaryRole));
+ else
+ m_relationVisualSecondaryRoleSelector->setCurrentIndex(-1);
+ }
+ if (!m_relationVisualEmphasizedCheckbox) {
+ m_relationVisualEmphasizedCheckbox = new QCheckBox(Tr::tr("Emphasized"), m_topWidget);
+ addRow(QString(), m_relationVisualEmphasizedCheckbox, "emphasized");
+ connect(m_relationVisualEmphasizedCheckbox, &QAbstractButton::clicked,
+ this, &PropertiesView::MView::onRelationVisualEmphasizedChanged);
+ }
+ if (!m_relationVisualEmphasizedCheckbox->hasFocus()) {
+ bool emphasized;
+ if (haveSameValue(m_diagramElements, &DRelation::isVisualEmphasized, &emphasized))
+ m_relationVisualEmphasizedCheckbox->setChecked(emphasized);
+ else
+ m_relationVisualEmphasizedCheckbox->setChecked(false);
+ }
#ifdef SHOW_DEBUG_PROPERTIES
if (!m_pointsLabel) {
m_pointsLabel = new QLabel(m_topWidget);
@@ -1145,6 +1253,26 @@ void PropertiesView::MView::visitDSwimlane(const DSwimlane *swimlane)
visitDElement(swimlane);
}
+void PropertiesView::MView::visitMElementBehind(const MElement *element)
+{
+ Q_UNUSED(element)
+}
+
+void PropertiesView::MView::visitMObjectBehind(const MObject *object)
+{
+ visitMElementBehind(object);
+}
+
+void PropertiesView::MView::visitMDiagramBehind(const MDiagram *diagram)
+{
+ visitMObjectBehind(diagram);
+}
+
+void PropertiesView::MView::visitDObjectBefore(const DObject *object)
+{
+ Q_UNUSED(object);
+}
+
void PropertiesView::MView::onStereotypesChanged(const QString &stereotypes)
{
QList<QString> set = m_stereotypesController->fromString(stereotypes);
@@ -1392,7 +1520,42 @@ void PropertiesView::MView::onAnnotationVisualRoleChanged(int visualRoleIndex)
{
DAnnotation::VisualRole visualRole = translateIndexToAnnotationVisualRole((visualRoleIndex));
assignModelElement<DAnnotation, DAnnotation::VisualRole>(
- m_diagramElements, SelectionMulti, visualRole, &DAnnotation::visualRole, &DAnnotation::setVisualRole);
+ m_diagramElements, SelectionMulti, visualRole, &DAnnotation::visualRole, &DAnnotation::setVisualRole);
+}
+
+
+void PropertiesView::MView::onRelationVisualPrimaryRoleChanged(int visualRoleIndex)
+{
+ DRelation::VisualPrimaryRole visualRole = translateIndexToRelationVisualPrimaryRole(visualRoleIndex);
+ assignModelElement<DRelation, DRelation::VisualPrimaryRole>(
+ m_diagramElements, SelectionMulti, visualRole,
+ &DRelation::visualPrimaryRole, &DRelation::setVisualPrimaryRole);
+}
+
+void PropertiesView::MView::onRelationVisualSecondaryRoleChanged(int visualRoleIndex)
+{
+ DRelation::VisualSecondaryRole visualRole = translateIndexToRelationVisualSecondaryRole(visualRoleIndex);
+ assignModelElement<DRelation, DRelation::VisualSecondaryRole>(
+ m_diagramElements, SelectionMulti, visualRole,
+ &DRelation::visualSecondaryRole, &DRelation::setVisualSecondaryRole);
+}
+
+void PropertiesView::MView::onRelationVisualEmphasizedChanged(bool visualEmphasized)
+{
+ assignModelElement<DRelation, bool>(m_diagramElements, SelectionMulti, visualEmphasized,
+ &DRelation::isVisualEmphasized, &DRelation::setVisualEmphasized);
+}
+
+void PropertiesView::MView::onRelationColorChanged(const QColor &color)
+{
+ assignModelElement<DRelation, QColor>(m_diagramElements, SelectionMulti, color,
+ &DRelation::color, &DRelation::setColor);
+}
+
+void PropertiesView::MView::onRelationThicknessChanged(qreal thickness)
+{
+ assignModelElement<DRelation, qreal>(m_diagramElements, SelectionMulti, thickness,
+ &DRelation::thickness, &DRelation::setThickness);
}
void PropertiesView::MView::prepare()
@@ -1553,7 +1716,8 @@ void PropertiesView::MView::setPrimaryRolePalette(StyleEngine::ElementType eleme
DObject::VisualPrimaryRole visualPrimaryRole, const QColor &baseColor)
{
int index = translateVisualPrimaryRoleToIndex(visualPrimaryRole);
- const Style *style = m_propertiesView->styleController()->adaptObjectStyle(elementType, ObjectVisuals(visualPrimaryRole, DObject::SecondaryRoleNone, false, baseColor, 0));
+ const Style *style = m_propertiesView->styleController()->adaptObjectStyle(
+ elementType, ObjectVisuals(visualPrimaryRole, DObject::SecondaryRoleNone, false, baseColor, 0));
m_visualPrimaryRoleSelector->setBrush(index, style->fillBrush());
m_visualPrimaryRoleSelector->setLinePen(index, style->linePen());
}
@@ -1595,112 +1759,15 @@ QString PropertiesView::MView::formatTemplateParameters(const QList<QString> &te
return templateParamters;
}
-template<class T, class V>
-QList<T *> PropertiesView::MView::filter(const QList<V *> &elements)
-{
- QList<T *> filtered;
- for (V *element : elements) {
- auto t = dynamic_cast<T *>(element);
- if (t)
- filtered.append(t);
- }
- return filtered;
-}
-
-template<class T, class V, class BASE>
-bool PropertiesView::MView::haveSameValue(const QList<BASE *> &baseElements, V (T::*getter)() const, V *value)
+void PropertiesView::MView::setRelationPrimaryRolePalette(StyleEngine::ElementType elementType,
+ DRelation::VisualPrimaryRole visualPrimaryRole)
{
- const QList<T *> elements = filter<T>(baseElements);
- QMT_CHECK(!elements.isEmpty());
- V candidate = V(); // avoid warning of reading uninitialized variable
- bool haveCandidate = false;
- for (T *element : elements) {
- if (!haveCandidate) {
- candidate = ((*element).*getter)();
- haveCandidate = true;
- } else {
- if (candidate != ((*element).*getter)())
- return false;
- }
- }
- QMT_CHECK(haveCandidate);
- if (!haveCandidate)
- return false;
- if (value)
- *value = candidate;
- return true;
-}
-
-template<class T, class V, class BASE>
-void PropertiesView::MView::assignModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
- const V &value, V (T::*getter)() const, void (T::*setter)(const V &))
-{
- const QList<T *> elements = filter<T>(baseElements);
- if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
- for (T *element : elements) {
- if (value != ((*element).*getter)()) {
- m_propertiesView->beginUpdate(element);
- ((*element).*setter)(value);
- m_propertiesView->endUpdate(element, false);
- }
- }
- }
-}
-
-template<class T, class V, class BASE>
-void PropertiesView::MView::assignModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
- const V &value, V (T::*getter)() const, void (T::*setter)(V))
-{
- const QList<T *> elements = filter<T>(baseElements);
- if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
- for (T *element : elements) {
- if (value != ((*element).*getter)()) {
- m_propertiesView->beginUpdate(element);
- ((*element).*setter)(value);
- m_propertiesView->endUpdate(element, false);
- }
- }
- }
-}
-
-template<class T, class E, class V, class BASE>
-void PropertiesView::MView::assignEmbeddedModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
- const V &value, E (T::*getter)() const,
- void (T::*setter)(const E &),
- V (E::*vGetter)() const, void (E::*vSetter)(const V &))
-{
- const QList<T *> elements = filter<T>(baseElements);
- if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
- for (T *element : elements) {
- E embedded = ((*element).*getter)();
- if (value != (embedded.*vGetter)()) {
- m_propertiesView->beginUpdate(element);
- (embedded.*vSetter)(value);
- ((*element).*setter)(embedded);
- m_propertiesView->endUpdate(element, false);
- }
- }
- }
-}
-
-template<class T, class E, class V, class BASE>
-void PropertiesView::MView::assignEmbeddedModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
- const V &value, E (T::*getter)() const,
- void (T::*setter)(const E &),
- V (E::*vGetter)() const, void (E::*vSetter)(V))
-{
- const QList<T *> elements = filter<T>(baseElements);
- if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
- for (T *element : elements) {
- E embedded = ((*element).*getter)();
- if (value != (embedded.*vGetter)()) {
- m_propertiesView->beginUpdate(element);
- (embedded.*vSetter)(value);
- ((*element).*setter)(embedded);
- m_propertiesView->endUpdate(element, false);
- }
- }
- }
+ int index = translateRelationVisualPrimaryRoleToIndex(visualPrimaryRole);
+ const Style *style = m_propertiesView->styleController()->adaptRelationStyle(
+ elementType, RelationVisuals(DObject::PrimaryRoleNormal, visualPrimaryRole,
+ DRelation::SecondaryRoleNone, false));
+ m_relationVisualPrimaryRoleSelector->setBrush(index, style->fillBrush());
+ m_relationVisualPrimaryRoleSelector->setLinePen(index, style->linePen());
}
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h
index 4762803a20..8fa9f0d137 100644
--- a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h
@@ -8,6 +8,8 @@
#include "qmt/model/mconstvisitor.h"
#include "qmt/diagram/dconstvisitor.h"
#include "qmt/diagram/dobject.h"
+#include "qmt/diagram/drelation.h"
+#include "qmt/infrastructure/qmtassert.h"
#include "qmt/stereotype/stereotypeicon.h"
#include "qmt/style/styleengine.h"
@@ -76,6 +78,11 @@ public:
void edit();
protected:
+ virtual void visitMElementBehind(const MElement *element);
+ virtual void visitMObjectBehind(const MObject *object);
+ virtual void visitMDiagramBehind(const MDiagram *diagram);
+ virtual void visitDObjectBefore(const DObject *object);
+
void onStereotypesChanged(const QString &stereotypes);
void onObjectNameChanged(const QString &name);
void onNamespaceChanged(const QString &umlNamespace);
@@ -110,6 +117,11 @@ protected:
void onPlainShapeChanged(bool plainShape);
void onItemShapeChanged(const QString &shape);
void onAutoWidthChanged(bool autoWidthed);
+ void onRelationVisualPrimaryRoleChanged(int visualRoleIndex);
+ void onRelationVisualSecondaryRoleChanged(int visualRoleIndex);
+ void onRelationVisualEmphasizedChanged(bool visualEmphasized);
+ void onRelationColorChanged(const QColor &color);
+ void onRelationThicknessChanged(qreal thickness);
void onAnnotationVisualRoleChanged(int visualRoleIndex);
void prepare();
@@ -139,6 +151,9 @@ protected:
QList<QString> splitTemplateParameters(const QString &templateParameters);
QString formatTemplateParameters(const QList<QString> &templateParametersList);
+ void setRelationPrimaryRolePalette(StyleEngine::ElementType elementType,
+ DRelation::VisualPrimaryRole visualPrimaryRole);
+
enum SelectionType {
SelectionSingle,
SelectionMulti
@@ -149,6 +164,9 @@ protected:
template<class T, class V, class BASE>
bool haveSameValue(const QList<BASE *> &baseElements, V (T::*getter)() const, V *value);
template<class T, class V, class BASE>
+ bool isValueChanged(const QList<BASE *> &baseElements, SelectionType selectionType,
+ const V &value, V (T::*getter)() const);
+ template<class T, class V, class BASE>
void assignModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
const V &value, V (T::*getter)() const, void (T::*setter)(const V &));
template<class T, class V, class BASE>
@@ -232,7 +250,132 @@ protected:
QCheckBox *m_annotationAutoWidthCheckbox = nullptr;
QComboBox *m_annotationVisualRoleSelector = nullptr;
// DRelation
+ PaletteBox *m_relationVisualPrimaryRoleSelector = nullptr;
+ QComboBox *m_relationVisualSecondaryRoleSelector = nullptr;
+ QCheckBox *m_relationVisualEmphasizedCheckbox = nullptr;
QLabel *m_pointsLabel = nullptr;
};
+template<class T, class V>
+QList<T *> PropertiesView::MView::filter(const QList<V *> &elements)
+{
+ QList<T *> filtered;
+ for (auto *element : elements) {
+ auto t = dynamic_cast<T *>(element);
+ if (t)
+ filtered.append(t);
+ }
+ return filtered;
+}
+
+template<class T, class V, class BASE>
+inline bool PropertiesView::MView::haveSameValue(const QList<BASE *> &baseElements, V (T::*getter)() const, V *value)
+{
+ QList<T *> elements = filter<T>(baseElements);
+ QMT_CHECK(!elements.isEmpty());
+ V candidate = V(); // avoid warning of reading uninitialized variable
+ bool haveCandidate = false;
+ for (const auto *element : elements) {
+ if (!haveCandidate) {
+ candidate = ((*element).*getter)();
+ haveCandidate = true;
+ } else {
+ if (candidate != ((*element).*getter)())
+ return false;
+ }
+ }
+ QMT_CHECK(haveCandidate);
+ if (!haveCandidate)
+ return false;
+ if (value)
+ *value = candidate;
+ return true;
+}
+
+template<class T, class V, class BASE>
+inline bool PropertiesView::MView::isValueChanged(const QList<BASE *> &baseElements, SelectionType selectionType,
+ const V &value, V (T::*getter)() const)
+{
+ QList<T *> elements = filter<T>(baseElements);
+ if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
+ for (const auto *element : elements) {
+ if (value != ((*element).*getter)())
+ return true;
+ }
+ }
+ return false;
+}
+
+template<class T, class V, class BASE>
+inline void PropertiesView::MView::assignModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
+ const V &value, V (T::*getter)() const, void (T::*setter)(const V &))
+{
+ QList<T *> elements = filter<T>(baseElements);
+ if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
+ for (auto *element : elements) {
+ if (value != ((*element).*getter)()) {
+ m_propertiesView->beginUpdate(element);
+ ((*element).*setter)(value);
+ m_propertiesView->endUpdate(element, false);
+ }
+ }
+ }
+}
+
+template<class T, class V, class BASE>
+inline void PropertiesView::MView::assignModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
+ const V &value, V (T::*getter)() const, void (T::*setter)(V))
+{
+ QList<T *> elements = filter<T>(baseElements);
+ if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
+ for (auto *element : elements) {
+ if (value != ((*element).*getter)()) {
+ m_propertiesView->beginUpdate(element);
+ ((*element).*setter)(value);
+ m_propertiesView->endUpdate(element, false);
+ }
+ }
+ }
+}
+
+template<class T, class E, class V, class BASE>
+inline void PropertiesView::MView::assignEmbeddedModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
+ const V &value, E (T::*getter)() const,
+ void (T::*setter)(const E &),
+ V (E::*vGetter)() const, void (E::*vSetter)(const V &))
+{
+ QList<T *> elements = filter<T>(baseElements);
+ if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
+ for (auto *element : elements) {
+ E embedded = ((*element).*getter)();
+ if (value != (embedded.*vGetter)()) {
+ m_propertiesView->beginUpdate(element);
+ (embedded.*vSetter)(value);
+ ((*element).*setter)(embedded);
+ m_propertiesView->endUpdate(element, false);
+ }
+ }
+ }
+}
+
+template<class T, class E, class V, class BASE>
+inline void PropertiesView::MView::assignEmbeddedModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
+ const V &value, E (T::*getter)() const,
+ void (T::*setter)(const E &),
+ V (E::*vGetter)() const, void (E::*vSetter)(V))
+{
+ QList<T *> elements = filter<T>(baseElements);
+ if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
+ for (auto *element : elements) {
+ E embedded = ((*element).*getter)();
+ if (value != (embedded.*vGetter)()) {
+ m_propertiesView->beginUpdate(element);
+ (embedded.*vSetter)(value);
+ ((*element).*setter)(embedded);
+ m_propertiesView->endUpdate(element, false);
+ }
+ }
+ }
+}
+
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/serializer/diagramserializer.cpp b/src/libs/modelinglib/qmt/serializer/diagramserializer.cpp
index 5170d4fdc7..2d68862c32 100644
--- a/src/libs/modelinglib/qmt/serializer/diagramserializer.cpp
+++ b/src/libs/modelinglib/qmt/serializer/diagramserializer.cpp
@@ -29,10 +29,35 @@
#include "qark/qxmlinarchive.h"
#include "qark/serialize.h"
+#include <QBuffer>
+
using namespace qmt;
namespace qark {
+template<class Archive>
+inline void save(Archive &archive, const QImage &image)
+{
+ QByteArray a;
+ QBuffer buffer(&a);
+ buffer.open(QIODevice::WriteOnly);
+ image.save(&buffer, "PNG");
+ // TODO add write(const QByteArray &)
+ archive.write(QString::fromLatin1(a.toBase64()));
+}
+
+template<class Archive>
+inline void load(Archive &archive, QImage &image)
+{
+ QString s;
+ // TODO add read(QByteArray &)
+ archive.read(&s);
+ QByteArray a = QByteArray::fromBase64(s.toLatin1());
+ QBuffer buffer(&a);
+ buffer.open(QIODevice::ReadOnly);
+ image.load(&buffer, "PNG");
+}
+
// DElement
QARK_REGISTER_TYPE_NAME(DElement, "DElement")
@@ -102,7 +127,10 @@ inline void Access<Archive, DObject>::serialize(Archive &archive, DObject &objec
|| attr("visual-role", object, &visualRole, &setVisualRole)
|| attr("visual-role2", object, &DObject::visualSecondaryRole, &DObject::setVisualSecondaryRole)
|| attr("visual-emphasized", object, &DObject::isVisualEmphasized, &DObject::setVisualEmphasized)
+ || attr("linkedfile", object, &DObject::hasLinkedFile, &DObject::setLinkedFile)
|| attr("stereotype-display", object, &DObject::stereotypeDisplay, &DObject::setStereotypeDisplay)
+ || attr("image-path", object, &DObject::imagePath, &DObject::setImagePath)
+ || attr("image", object, &DObject::image, &DObject::setImage)
// depth is not persistent
|| end;
}
@@ -220,6 +248,9 @@ inline void Access<Archive, DRelation>::serialize(Archive &archive, DRelation &r
|| attr("b", relation, &DRelation::endBUid, &DRelation::setEndBUid)
|| attr("name", relation, &DRelation::name, &DRelation::setName)
|| attr("points", relation, &DRelation::intermediatePoints, &DRelation::setIntermediatePoints)
+ || attr("visualPrimaryRole", relation, &DRelation::visualPrimaryRole, &DRelation::setVisualPrimaryRole)
+ || attr("visualSecondaryRole", relation, &DRelation::visualSecondaryRole, &DRelation::setVisualSecondaryRole)
+ || attr("thickness", relation, &DRelation::thickness, &DRelation::setThickness)
|| end;
}
diff --git a/src/libs/modelinglib/qmt/serializer/diagramserializer.h b/src/libs/modelinglib/qmt/serializer/diagramserializer.h
index a571ff94ef..aa5d1adb52 100644
--- a/src/libs/modelinglib/qmt/serializer/diagramserializer.h
+++ b/src/libs/modelinglib/qmt/serializer/diagramserializer.h
@@ -6,6 +6,7 @@
#include "qmt/diagram/dannotation.h"
#include "qmt/diagram/dobject.h"
#include "qmt/diagram/dclass.h"
+#include "qmt/diagram/drelation.h"
#include "qark/serialize_enum.h"
@@ -16,5 +17,7 @@ QARK_SERIALIZE_ENUM(qmt::DObject::VisualSecondaryRole)
QARK_SERIALIZE_ENUM(qmt::DObject::StereotypeDisplay)
QARK_SERIALIZE_ENUM(qmt::DClass::TemplateDisplay)
QARK_SERIALIZE_ENUM(qmt::DAnnotation::VisualRole)
+QARK_SERIALIZE_ENUM(qmt::DRelation::VisualPrimaryRole)
+QARK_SERIALIZE_ENUM(qmt::DRelation::VisualSecondaryRole)
} // namespace qark
diff --git a/src/libs/modelinglib/qmt/serializer/modelserializer.cpp b/src/libs/modelinglib/qmt/serializer/modelserializer.cpp
index 115eba08d0..935a825ab2 100644
--- a/src/libs/modelinglib/qmt/serializer/modelserializer.cpp
+++ b/src/libs/modelinglib/qmt/serializer/modelserializer.cpp
@@ -95,6 +95,7 @@ inline void Access<Archive, MObject>::serialize(Archive &archive, MObject &objec
archive || tag(object)
|| base<MElement>(object)
|| attr("name", object, &MObject::name, &MObject::setName)
+ || attr("linkedfilename", object, &MObject::linkedFileName, &MObject::setLinkedFileName)
|| attr("children", object, &MObject::children, &MObject::setChildren)
|| attr("relations", object, &MObject::relations, &MObject::setRelations)
|| end;
diff --git a/src/libs/modelinglib/qmt/stereotype/customrelation.cpp b/src/libs/modelinglib/qmt/stereotype/customrelation.cpp
index fa9c80a1a0..cc80da1b80 100644
--- a/src/libs/modelinglib/qmt/stereotype/customrelation.cpp
+++ b/src/libs/modelinglib/qmt/stereotype/customrelation.cpp
@@ -114,4 +114,9 @@ void CustomRelation::setColor(const QColor &color)
m_color = color;
}
+void CustomRelation::setEmphasized(bool emphasized)
+{
+ m_emphasized = emphasized;
+}
+
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/stereotype/customrelation.h b/src/libs/modelinglib/qmt/stereotype/customrelation.h
index 7125865ade..dd32c542c0 100644
--- a/src/libs/modelinglib/qmt/stereotype/customrelation.h
+++ b/src/libs/modelinglib/qmt/stereotype/customrelation.h
@@ -55,7 +55,10 @@ public:
enum class ColorType {
EndA,
EndB,
- Custom
+ Custom,
+ Warning,
+ Error,
+ Soften,
};
class End {
@@ -113,6 +116,8 @@ public:
void setColorType(ColorType colorType);
QColor color() const { return m_color; }
void setColor(const QColor &color);
+ bool emphasized() const { return m_emphasized; }
+ void setEmphasized(bool emphasized);
friend auto qHash(CustomRelation::Relationship relationship) {
return ::qHash(static_cast<int>(relationship));
@@ -139,6 +144,7 @@ private:
ShaftPattern m_shaftPattern = ShaftPattern::Solid;
ColorType m_colorType = ColorType::EndA;
QColor m_color;
+ bool m_emphasized = false;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/stereotype/shapevalue.cpp b/src/libs/modelinglib/qmt/stereotype/shapevalue.cpp
index 9e1ee46c15..cf8ea5ef65 100644
--- a/src/libs/modelinglib/qmt/stereotype/shapevalue.cpp
+++ b/src/libs/modelinglib/qmt/stereotype/shapevalue.cpp
@@ -29,7 +29,7 @@ qreal ShapeValueF::mapScaledTo(qreal scaledOrigin, qreal originalSize, qreal bas
v = originalSize != 0 ? (m_value * actualSize / originalSize) : m_value;
break;
case UnitPercentage:
- v = m_value * actualSize;
+ v = m_value * actualSize / 100.0;
break;
}
switch (m_origin) {
diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp b/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp
index 030c9e12a5..f557e80c4b 100644
--- a/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp
+++ b/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp
@@ -68,6 +68,7 @@ public:
QHash<QPair<StereotypeIcon::Element, QString>, QString> m_stereotypeToIconIdMap;
QHash<QString, StereotypeIcon> m_iconIdToStereotypeIconsMap;
QHash<QString, CustomRelation> m_relationIdToCustomRelationMap;
+ QHash<QString, CustomRelation> m_stereotypeToCustomRelationMap;
QList<Toolbar> m_toolbars;
QList<Toolbar> m_elementToolbars;
QHash<IconKey, QIcon> m_iconMap;
@@ -150,6 +151,11 @@ CustomRelation StereotypeController::findCustomRelation(const QString &customRel
return d->m_relationIdToCustomRelationMap.value(customRelationId);
}
+CustomRelation StereotypeController::findCustomRelationByStereotype(const QString &steoreotype) const
+{
+ return d->m_stereotypeToCustomRelationMap.value(steoreotype);
+}
+
QIcon StereotypeController::createIcon(StereotypeIcon::Element element, const QList<QString> &stereotypes,
const QString &defaultIconPath, const Style *style, const QSize &size,
const QMarginsF &margins, qreal lineWidth)
@@ -251,6 +257,9 @@ void StereotypeController::addStereotypeIcon(const StereotypeIcon &stereotypeIco
void StereotypeController::addCustomRelation(const CustomRelation &customRelation)
{
d->m_relationIdToCustomRelationMap.insert(customRelation.id(), customRelation);
+ QString stereotype = Utils::toList(customRelation.stereotypes()).value(0);
+ if (!stereotype.isEmpty())
+ d->m_stereotypeToCustomRelationMap.insert(stereotype, customRelation);
}
void StereotypeController::addToolbar(const Toolbar &toolbar)
diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.h b/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.h
index 676f9a275a..45bc3bbd18 100644
--- a/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.h
+++ b/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.h
@@ -33,6 +33,7 @@ public:
const QList<QString> &stereotypes) const;
StereotypeIcon findStereotypeIcon(const QString &stereotypeIconId) const;
CustomRelation findCustomRelation(const QString &customRelationId) const;
+ CustomRelation findCustomRelationByStereotype(const QString &steoreotype) const;
QIcon createIcon(StereotypeIcon::Element element, const QList<QString> &stereotypes,
const QString &defaultIconPath, const Style *style,
const QSize &size, const QMarginsF &margins, qreal lineWidth);
diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp
index 8bcf5df170..19e466c509 100644
--- a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp
+++ b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp
@@ -62,6 +62,21 @@ void StereotypeIcon::setMinHeight(qreal minHeight)
m_minHeight = minHeight;
}
+void StereotypeIcon::setIconWith(qreal iconWidth)
+{
+ m_iconWidth = iconWidth;
+}
+
+void StereotypeIcon::setIconHeight(qreal iconHeight)
+{
+ m_iconHeight = iconHeight;
+}
+
+void StereotypeIcon::setDepthLayer(DepthLayer depthLayer)
+{
+ m_depthLayer = depthLayer;
+}
+
void StereotypeIcon::setSizeLock(StereotypeIcon::SizeLock sizeLock)
{
m_sizeLock = sizeLock;
diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h
index be45245da5..fcb5f1a15c 100644
--- a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h
+++ b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h
@@ -31,6 +31,12 @@ public:
DisplaySmart
};
+ enum DepthLayer {
+ DepthBehindItems,
+ DepthAmongItems,
+ DepthBeforeItems,
+ };
+
enum SizeLock {
LockNone,
LockWidth,
@@ -62,12 +68,20 @@ public:
void setWidth(qreal width);
qreal height() const { return m_height; }
void setHeight(qreal height);
- bool hasMinWidth() const { return m_minWidth > 0; }
+ bool hasMinWidth() const { return m_minWidth > 0.0; }
qreal minWidth() const { return m_minWidth; }
void setMinWidth(qreal minWidth);
- bool hasMinHeight() const { return m_minHeight > 0; }
+ bool hasMinHeight() const { return m_minHeight > 0.0; }
qreal minHeight() const { return m_minHeight; }
void setMinHeight(qreal minHeight);
+ bool hasIconWidth() const { return m_iconWidth > 0.0; }
+ qreal iconWidth() const { return m_iconWidth; }
+ void setIconWith(qreal iconWidth);
+ bool hasIconHeight() const { return m_iconHeight > 0.0; }
+ qreal iconHeight() const { return m_iconHeight; }
+ void setIconHeight(qreal iconHeight);
+ DepthLayer depthLayer() const { return m_depthLayer; }
+ void setDepthLayer(DepthLayer depthLayer);
SizeLock sizeLock() const { return m_sizeLock; }
void setSizeLock(SizeLock sizeLock);
Display display() const { return m_display; }
@@ -90,8 +104,11 @@ private:
QString m_name;
qreal m_width = 100.0;
qreal m_height = 100.0;
- qreal m_minWidth = -1;
- qreal m_minHeight = -1;
+ qreal m_minWidth = -1.0;
+ qreal m_minHeight = -1.0;
+ qreal m_iconWidth = -1.0;
+ qreal m_iconHeight = -1.0;
+ DepthLayer m_depthLayer = DepthAmongItems;
SizeLock m_sizeLock = LockNone;
Display m_display = DisplaySmart;
TextAlignment m_textAlignment = TextalignBelow;
diff --git a/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp b/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp
index 74e91837dc..bce1804892 100644
--- a/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp
+++ b/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp
@@ -5,6 +5,7 @@
#include "defaultstyle.h"
#include "objectvisuals.h"
+#include "relationvisuals.h"
#include "styledobject.h"
#include "styledrelation.h"
@@ -14,6 +15,7 @@
#include "qmt/diagram/ditem.h"
#include "qmt/diagram/dannotation.h"
#include "qmt/infrastructure/qmtassert.h"
+#include "qmt/stereotype/customrelation.h"
#include <utils/algorithm.h>
@@ -73,25 +75,29 @@ bool operator==(const ObjectStyleKey &lhs, const ObjectStyleKey &rhs)
class RelationStyleKey
{
public:
- RelationStyleKey(StyleEngine::ElementType elementType = StyleEngine::TypeOther,
- DObject::VisualPrimaryRole visualPrimaryRole = DObject::PrimaryRoleNormal)
+ RelationStyleKey(StyleEngine::ElementType elementType, const RelationVisuals &relationVisuals,
+ bool withObject = false)
: m_elementType(elementType),
- m_visualPrimaryRole(visualPrimaryRole)
+ m_relationVisuals(relationVisuals),
+ m_withObject(withObject)
{
}
StyleEngine::ElementType m_elementType = StyleEngine::TypeOther;
- DObject::VisualPrimaryRole m_visualPrimaryRole = DObject::PrimaryRoleNormal;
+ RelationVisuals m_relationVisuals;
+ bool m_withObject = false;
};
size_t qHash(const RelationStyleKey &styleKey)
{
- return ::qHash(styleKey.m_elementType) ^ ::qHash(styleKey.m_visualPrimaryRole);
+ return ::qHash(styleKey.m_elementType) ^ qHash(styleKey.m_relationVisuals);
}
bool operator==(const RelationStyleKey &lhs, const RelationStyleKey &rhs)
{
- return lhs.m_elementType == rhs.m_elementType && lhs.m_visualPrimaryRole == rhs.m_visualPrimaryRole;
+ return lhs.m_elementType == rhs.m_elementType
+ && lhs.m_relationVisuals == rhs.m_relationVisuals
+ && lhs.m_withObject == rhs.m_withObject;
}
class AnnotationStyleKey
@@ -253,34 +259,6 @@ const Style *DefaultStyleEngine::applyObjectStyle(const Style *baseStyle, StyleE
return derivedStyle;
}
-static bool areStackingRoles(DObject::VisualPrimaryRole rhsPrimaryRole,
- DObject::VisualSecondaryRole rhsSecondaryRole,
- DObject::VisualPrimaryRole lhsPrimaryRole,
- DObject::VisualSecondaryRole lhsSecondaryRols)
-{
- switch (rhsSecondaryRole) {
- case DObject::SecondaryRoleNone:
- case DObject::SecondaryRoleLighter:
- case DObject::SecondaryRoleDarker:
- case DObject::SecondaryRoleFlat:
- switch (lhsSecondaryRols) {
- case DObject::SecondaryRoleNone:
- case DObject::SecondaryRoleLighter:
- case DObject::SecondaryRoleDarker:
- case DObject::SecondaryRoleFlat:
- return lhsPrimaryRole == rhsPrimaryRole;
- case DObject::SecondaryRoleSoften:
- case DObject::SecondaryRoleOutline:
- return false;
- }
- break;
- case DObject::SecondaryRoleSoften:
- case DObject::SecondaryRoleOutline:
- return false;
- }
- return true;
-}
-
const Style *DefaultStyleEngine::applyObjectStyle(const Style *baseStyle, const StyledObject &styledObject,
const Parameters *parameters)
{
@@ -325,10 +303,12 @@ const Style *DefaultStyleEngine::applyObjectStyle(const Style *baseStyle, const
}
int depth = 0;
if (!depths.isEmpty()) {
- for (auto it = depths.cbegin(); it != depths.cend(); ++it) {
- if (it->m_elementType == elementType
- && areStackingRoles(it->m_visualPrimaryRole, it->m_visualSecondaryRole,
- styledVisualPrimaryRole, styledVisualSecondaryRole)) {
+ const QList<int> keys = Utils::sorted(depths.keys());
+ for (int d : keys) {
+ DepthProperties properties = depths.value(d);
+ if (properties.m_elementType == elementType
+ && areStackingRoles(properties.m_visualPrimaryRole, properties.m_visualSecondaryRole,
+ styledVisualPrimaryRole, styledVisualSecondaryRole)) {
++depth;
} else {
depth = 0;
@@ -345,13 +325,100 @@ const Style *DefaultStyleEngine::applyObjectStyle(const Style *baseStyle, const
parameters);
}
+const Style *DefaultStyleEngine::applyRelationStyle(const Style *baseStyle, ElementType elementType, const RelationVisuals &relationVisuals, const Parameters *parameters)
+{
+ Q_UNUSED(parameters);
+
+ RelationStyleKey key(elementType, relationVisuals);
+ const Style *derivedStyle = m_relationStyleMap.value(key);
+ if (!derivedStyle) {
+ auto style = new Style(baseStyle->type());
+ static QColor customColors[] = {
+ QColor(0xEE, 0x8E, 0x99).darker(110), // ROLE_CUSTOM1,
+ QColor(0x80, 0xAF, 0x47).lighter(130), // ROLE_CUSTOM2,
+ QColor(0xFF, 0xA1, 0x5B).lighter(100), // ROLE_CUSTOM3,
+ QColor(0x55, 0xC4, 0xCF).lighter(120), // ROLE_CUSTOM4,
+ QColor(0xFF, 0xE1, 0x4B) // ROLE_CUSTOM5,
+ };
+
+ int index = static_cast<int>(relationVisuals.visualPrimaryRole()) - static_cast<int>(DRelation::PrimaryRoleCustom1);
+ QColor lineColor = index >= 0 && index <= 4 ? customColors[index] : Qt::black;
+ switch (relationVisuals.visualSecondaryRole()) {
+ case DRelation::SecondaryRoleNone:
+ break;
+ case DRelation::SecondaryRoleWarning:
+ lineColor = Qt::yellow;
+ break;
+ case DRelation::SecondaryRoleError:
+ lineColor = Qt::red;
+ break;
+ case DRelation::SecondaryRoleSoften:
+ lineColor = Qt::gray;
+ break;
+ }
+
+ QColor fillColor = lineColor == Qt::black ? Qt::darkGray : lineColor.lighter(150);
+ QPen linePen = baseStyle->linePen();
+ linePen.setWidth(1);
+ linePen.setColor(lineColor);
+ style->setLinePen(linePen);
+ QBrush textBrush = baseStyle->textBrush();
+ textBrush.setColor(Qt::black);
+ style->setTextBrush(textBrush);
+ QBrush brush = baseStyle->fillBrush();
+ brush.setColor(fillColor);
+ brush.setStyle(Qt::SolidPattern);
+ style->setFillBrush(brush);
+ style->setNormalFont(baseStyle->normalFont());
+ style->setSmallFont(baseStyle->smallFont());
+ style->setHeaderFont(baseStyle->headerFont());
+ m_relationStyleMap.insert(key, style);
+ derivedStyle = style;
+ }
+ return derivedStyle;
+}
+
const Style *DefaultStyleEngine::applyRelationStyle(const Style *baseStyle, const StyledRelation &styledRelation,
const Parameters *parameters)
{
Q_UNUSED(parameters)
ElementType elementType = objectType(styledRelation.endA());
- RelationStyleKey key(elementType, styledRelation.endA() ? styledRelation.endA()->visualPrimaryRole() : DObject::PrimaryRoleNormal);
+ RelationVisuals relationVisuals;
+ if (styledRelation.customRelation()) {
+ switch (styledRelation.customRelation()->colorType()) {
+ case CustomRelation::ColorType::EndA:
+ // TODO implement
+ break;
+ case CustomRelation::ColorType::EndB:
+ // TODO implement
+ break;
+ case CustomRelation::ColorType::Custom:
+ // TODO implement
+ break;
+ case CustomRelation::ColorType::Warning:
+ relationVisuals.setVisualSecondaryRole(DRelation::VisualSecondaryRole::SecondaryRoleWarning);
+ break;
+ case CustomRelation::ColorType::Error:
+ relationVisuals.setVisualSecondaryRole(DRelation::VisualSecondaryRole::SecondaryRoleError);
+ break;
+ case CustomRelation::ColorType::Soften:
+ relationVisuals.setVisualSecondaryRole(DRelation::VisualSecondaryRole::SecondaryRoleSoften);
+ break;
+ }
+ relationVisuals.setEmphasized(styledRelation.customRelation()->emphasized());
+ }
+ if (styledRelation.endA())
+ relationVisuals.setVisualObjectPrimaryRole(styledRelation.endA()->visualPrimaryRole());
+ if (styledRelation.relation()) {
+ if (styledRelation.relation()->visualPrimaryRole() != DRelation::VisualPrimaryRole::PrimaryRoleNormal)
+ relationVisuals.setVisualPrimaryRole(styledRelation.relation()->visualPrimaryRole());
+ if (styledRelation.relation()->visualSecondaryRole() != DRelation::VisualSecondaryRole::SecondaryRoleNone)
+ relationVisuals.setVisualSecondaryRole(styledRelation.relation()->visualSecondaryRole());
+ if (styledRelation.relation()->isVisualEmphasized())
+ relationVisuals.setEmphasized(styledRelation.relation()->isVisualEmphasized());
+ }
+ RelationStyleKey key(elementType, relationVisuals, true);
const Style *derivedStyle = m_relationStyleMap.value(key);
if (!derivedStyle) {
auto style = new Style(baseStyle->type());
@@ -365,12 +432,36 @@ const Style *DefaultStyleEngine::applyRelationStyle(const Style *baseStyle, cons
QColor lineColor = DefaultStyleEngine::lineColor(objectType(object), objectVisuals);
QColor fillColor = lineColor;
+ static QColor customColors[] = {
+ QColor(0xEE, 0x8E, 0x99).darker(110), // ROLE_CUSTOM1,
+ QColor(0x80, 0xAF, 0x47).lighter(130), // ROLE_CUSTOM2,
+ QColor(0xFF, 0xA1, 0x5B).lighter(100), // ROLE_CUSTOM3,
+ QColor(0x55, 0xC4, 0xCF).lighter(120), // ROLE_CUSTOM4,
+ QColor(0xFF, 0xE1, 0x4B) // ROLE_CUSTOM5,
+ };
+
+ int index = static_cast<int>(relationVisuals.visualPrimaryRole()) - static_cast<int>(DRelation::PrimaryRoleCustom1);
+ lineColor = (index >= 0 && index <= 4) ? customColors[index] : lineColor;
+ switch (relationVisuals.visualSecondaryRole()) {
+ case DRelation::SecondaryRoleNone:
+ break;
+ case DRelation::SecondaryRoleWarning:
+ lineColor = QColor(0xffc800);
+ break;
+ case DRelation::SecondaryRoleError:
+ lineColor = Qt::red;
+ break;
+ case DRelation::SecondaryRoleSoften:
+ lineColor = Qt::gray;
+ break;
+ }
+
QPen linePen = baseStyle->linePen();
- linePen.setWidth(1);
+ linePen.setWidth(relationVisuals.isEmphasized() ? 3 : 1);
linePen.setColor(lineColor);
style->setLinePen(linePen);
QBrush textBrush = baseStyle->textBrush();
- textBrush.setColor(QColor("black"));
+ textBrush.setColor(Qt::black);
style->setTextBrush(textBrush);
QBrush brush = baseStyle->fillBrush();
brush.setColor(fillColor);
@@ -497,6 +588,34 @@ DefaultStyleEngine::ElementType DefaultStyleEngine::objectType(const DObject *ob
return elementType;
}
+bool DefaultStyleEngine::areStackingRoles(DObject::VisualPrimaryRole rhsPrimaryRole,
+ DObject::VisualSecondaryRole rhsSecondaryRole,
+ DObject::VisualPrimaryRole lhsPrimaryRole,
+ DObject::VisualSecondaryRole lhsSecondaryRols)
+{
+ switch (rhsSecondaryRole) {
+ case DObject::SecondaryRoleNone:
+ case DObject::SecondaryRoleLighter:
+ case DObject::SecondaryRoleDarker:
+ case DObject::SecondaryRoleFlat:
+ switch (lhsSecondaryRols) {
+ case DObject::SecondaryRoleNone:
+ case DObject::SecondaryRoleLighter:
+ case DObject::SecondaryRoleDarker:
+ case DObject::SecondaryRoleFlat:
+ return lhsPrimaryRole == rhsPrimaryRole;
+ case DObject::SecondaryRoleSoften:
+ case DObject::SecondaryRoleOutline:
+ return false;
+ }
+ break;
+ case DObject::SecondaryRoleSoften:
+ case DObject::SecondaryRoleOutline:
+ return false;
+ }
+ return true;
+}
+
QColor DefaultStyleEngine::baseColor(ElementType elementType, ObjectVisuals objectVisuals)
{
if (objectVisuals.visualSecondaryRole() == DObject::SecondaryRoleOutline)
diff --git a/src/libs/modelinglib/qmt/style/defaultstyleengine.h b/src/libs/modelinglib/qmt/style/defaultstyleengine.h
index 67cdf9ed85..b5ebe557e0 100644
--- a/src/libs/modelinglib/qmt/style/defaultstyleengine.h
+++ b/src/libs/modelinglib/qmt/style/defaultstyleengine.h
@@ -37,6 +37,9 @@ public:
const Parameters *parameters) override;
const Style *applyObjectStyle(const Style *baseStyle, const StyledObject &styledObject,
const Parameters *parameters) override;
+ const Style *applyRelationStyle(const Style *baseStyle, ElementType elementType,
+ const RelationVisuals &relationVisuals,
+ const Parameters *parameters) override;
const Style *applyRelationStyle(const Style *baseStyle, const StyledRelation &styledRelation,
const Parameters *parameters) override;
const Style *applyAnnotationStyle(const Style *baseStyle, const DAnnotation *annotation,
@@ -54,6 +57,11 @@ private:
ElementType objectType(const DObject *object);
+ bool areStackingRoles(DObject::VisualPrimaryRole rhsPrimaryRole,
+ DObject::VisualSecondaryRole rhsSecondaryRole,
+ DObject::VisualPrimaryRole lhsPrimaryRole,
+ DObject::VisualSecondaryRole lhsSecondaryRols);
+
QColor baseColor(ElementType elementType, ObjectVisuals objectVisuals);
QColor lineColor(ElementType elementType, const ObjectVisuals &objectVisuals);
QColor fillColor(ElementType elementType, const ObjectVisuals &objectVisuals);
diff --git a/src/libs/modelinglib/qmt/style/relationvisuals.cpp b/src/libs/modelinglib/qmt/style/relationvisuals.cpp
new file mode 100644
index 0000000000..d297047ae1
--- /dev/null
+++ b/src/libs/modelinglib/qmt/style/relationvisuals.cpp
@@ -0,0 +1,58 @@
+// Copyright (C) 2024 Jochen Becher
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "relationvisuals.h"
+
+namespace qmt {
+
+RelationVisuals::RelationVisuals() {}
+
+RelationVisuals::RelationVisuals(DObject::VisualPrimaryRole visualObjectPrimaryRole,
+ DRelation::VisualPrimaryRole visualPrimaryRole,
+ DRelation::VisualSecondaryRole visualSecondaryRole,
+ bool emphasized)
+ : m_visualObjectPrimaryRole(visualObjectPrimaryRole)
+ , m_visualPrimaryRole(visualPrimaryRole)
+ , m_visualSecondaryRole(visualSecondaryRole)
+ , m_isEmphasized(emphasized)
+{}
+
+RelationVisuals::~RelationVisuals() {}
+
+void RelationVisuals::setVisualPrimaryRole(DRelation::VisualPrimaryRole VisualPrimaryRole)
+{
+ m_visualPrimaryRole = VisualPrimaryRole;
+}
+
+void RelationVisuals::setVisualObjectPrimaryRole(DObject::VisualPrimaryRole visualPrimaryRole)
+{
+ m_visualObjectPrimaryRole = visualPrimaryRole;
+}
+
+void RelationVisuals::setVisualSecondaryRole(DRelation::VisualSecondaryRole visualSecondaryRole)
+{
+ m_visualSecondaryRole = visualSecondaryRole;
+}
+
+void RelationVisuals::setEmphasized(bool emphasized)
+{
+ m_isEmphasized = emphasized;
+}
+
+bool operator==(const RelationVisuals &lhs, const RelationVisuals &rhs)
+{
+ return lhs.visualObjectPrimaryRole() == rhs.visualObjectPrimaryRole()
+ && lhs.visualPrimaryRole() == rhs.visualPrimaryRole()
+ && lhs.visualSecondaryRole() == rhs.visualSecondaryRole()
+ && lhs.isEmphasized() == rhs.isEmphasized();
+}
+
+size_t qHash(const RelationVisuals &relationVisuals)
+{
+ return ::qHash(static_cast<int>(relationVisuals.visualObjectPrimaryRole()))
+ ^ ::qHash(static_cast<int>(relationVisuals.visualPrimaryRole()))
+ ^ ::qHash(static_cast<int>(relationVisuals.visualSecondaryRole()))
+ ^ ::qHash(relationVisuals.isEmphasized());
+}
+
+} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/style/relationvisuals.h b/src/libs/modelinglib/qmt/style/relationvisuals.h
new file mode 100644
index 0000000000..be87a7d291
--- /dev/null
+++ b/src/libs/modelinglib/qmt/style/relationvisuals.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2024 Jochen Becher
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "qmt/diagram/drelation.h"
+#include "qmt/diagram/dobject.h"
+
+#include <QColor>
+
+namespace qmt {
+
+class QMT_EXPORT RelationVisuals
+{
+public:
+ RelationVisuals();
+ RelationVisuals(DObject::VisualPrimaryRole visualObjectPrimaryRole,
+ DRelation::VisualPrimaryRole visualPrimaryRole,
+ DRelation::VisualSecondaryRole visualSecondaryRole,
+ bool emphasized);
+ ~RelationVisuals();
+
+ DObject::VisualPrimaryRole visualObjectPrimaryRole() const { return m_visualObjectPrimaryRole; }
+ void setVisualObjectPrimaryRole(DObject::VisualPrimaryRole visualPrimaryRole);
+ DRelation::VisualPrimaryRole visualPrimaryRole() const { return m_visualPrimaryRole; }
+ void setVisualPrimaryRole(DRelation::VisualPrimaryRole visualPrimaryRole);
+ DRelation::VisualSecondaryRole visualSecondaryRole() const { return m_visualSecondaryRole; }
+ void setVisualSecondaryRole(DRelation::VisualSecondaryRole visualSecondaryRole);
+ bool isEmphasized() const { return m_isEmphasized; }
+ void setEmphasized(bool emphasized);
+
+private:
+ DObject::VisualPrimaryRole m_visualObjectPrimaryRole = DObject::PrimaryRoleNormal;
+ DRelation::VisualPrimaryRole m_visualPrimaryRole = DRelation::PrimaryRoleNormal;
+ DRelation::VisualSecondaryRole m_visualSecondaryRole = DRelation::SecondaryRoleNone;
+ bool m_isEmphasized = false;
+};
+
+bool operator==(const RelationVisuals &lhs, const RelationVisuals &rhs);
+size_t qHash(const RelationVisuals &relationVisuals);
+
+} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/style/stylecontroller.cpp b/src/libs/modelinglib/qmt/style/stylecontroller.cpp
index 5cd50c1738..bbfc28622e 100644
--- a/src/libs/modelinglib/qmt/style/stylecontroller.cpp
+++ b/src/libs/modelinglib/qmt/style/stylecontroller.cpp
@@ -63,6 +63,12 @@ const Style *StyleController::adaptObjectStyle(const StyledObject &object)
return m_defaultStyleEngine->applyObjectStyle(m_defaultStyle.data(), object, &parameters);
}
+const Style *StyleController::adaptRelationStyle(StyleEngine::ElementType elementType, const RelationVisuals &relationVisuals)
+{
+ Parameters parameters(this);
+ return m_defaultStyleEngine->applyRelationStyle(m_defaultStyle.data(), elementType, relationVisuals, &parameters);
+}
+
const Style *StyleController::adaptRelationStyle(const StyledRelation &relation)
{
Parameters parameters(this);
diff --git a/src/libs/modelinglib/qmt/style/stylecontroller.h b/src/libs/modelinglib/qmt/style/stylecontroller.h
index 2627bb2caa..afa566460f 100644
--- a/src/libs/modelinglib/qmt/style/stylecontroller.h
+++ b/src/libs/modelinglib/qmt/style/stylecontroller.h
@@ -4,7 +4,6 @@
#pragma once
#include "styleengine.h"
-#include "qmt/diagram/dobject.h"
#include <QObject>
#include <QScopedPointer>
@@ -14,6 +13,7 @@ namespace qmt {
class Style;
class ObjectVisuals;
class StyledObject;
+class RelationVisuals;
class StyledRelation;
class DAnnotation;
class DBoundary;
@@ -33,6 +33,8 @@ public:
const Style *adaptObjectStyle(StyleEngine::ElementType elementType,
const ObjectVisuals &objectVisuals);
const Style *adaptObjectStyle(const StyledObject &object);
+ const Style *adaptRelationStyle(StyleEngine::ElementType elementType,
+ const RelationVisuals &relationVisuals);
const Style *adaptRelationStyle(const StyledRelation &relation);
const Style *adaptAnnotationStyle(const DAnnotation *annotation);
const Style *adaptBoundaryStyle(const DBoundary *boundary);
diff --git a/src/libs/modelinglib/qmt/style/styledrelation.cpp b/src/libs/modelinglib/qmt/style/styledrelation.cpp
index 3c78abf96d..144e5f22ac 100644
--- a/src/libs/modelinglib/qmt/style/styledrelation.cpp
+++ b/src/libs/modelinglib/qmt/style/styledrelation.cpp
@@ -5,10 +5,12 @@
namespace qmt {
-StyledRelation::StyledRelation(const DRelation *relation, const DObject *endA, const DObject *endB)
+StyledRelation::StyledRelation(const DRelation *relation, const DObject *endA, const DObject *endB,
+ const CustomRelation *customRelation)
: m_relation(relation),
m_endA(endA),
- m_endB(endB)
+ m_endB(endB),
+ m_customRelation(customRelation)
{
}
diff --git a/src/libs/modelinglib/qmt/style/styledrelation.h b/src/libs/modelinglib/qmt/style/styledrelation.h
index 422947908e..27e8735463 100644
--- a/src/libs/modelinglib/qmt/style/styledrelation.h
+++ b/src/libs/modelinglib/qmt/style/styledrelation.h
@@ -9,21 +9,25 @@ namespace qmt {
class DRelation;
class DObject;
+class CustomRelation;
class QMT_EXPORT StyledRelation
{
public:
- StyledRelation(const DRelation *relation, const DObject *endA, const DObject *endB);
+ StyledRelation(const DRelation *relation, const DObject *endA, const DObject *endB,
+ const CustomRelation *customRelation);
~StyledRelation();
const DRelation *relation() const { return m_relation; }
const DObject *endA() const { return m_endA; }
const DObject *endB() const { return m_endB; }
+ const CustomRelation *customRelation() const { return m_customRelation; }
private:
const DRelation *m_relation = nullptr;
const DObject *m_endA = nullptr;
const DObject *m_endB = nullptr;
+ const CustomRelation *m_customRelation = nullptr;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/style/styleengine.h b/src/libs/modelinglib/qmt/style/styleengine.h
index e78f4303d9..463a62a194 100644
--- a/src/libs/modelinglib/qmt/style/styleengine.h
+++ b/src/libs/modelinglib/qmt/style/styleengine.h
@@ -14,6 +14,7 @@ namespace qmt {
class Style;
class ObjectVisuals;
class StyledObject;
+class RelationVisuals;
class StyledRelation;
class DAnnotation;
@@ -51,6 +52,9 @@ public:
const Parameters *parameters) = 0;
virtual const Style *applyObjectStyle(const Style *baseStyle, const StyledObject &,
const Parameters *) = 0;
+ virtual const Style *applyRelationStyle(const Style *baseStyle, ElementType elementType,
+ const RelationVisuals &relationVisuals,
+ const Parameters *) = 0;
virtual const Style *applyRelationStyle(const Style *baseStyle, const StyledRelation &,
const Parameters *) = 0;
virtual const Style *applyAnnotationStyle(const Style *baseStyle, const DAnnotation *,
diff --git a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp
index 00aacf9c82..51f414f66e 100644
--- a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp
+++ b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp
@@ -421,7 +421,44 @@ void DiagramSceneController::dropNewModelElement(MObject *modelObject, MPackage
emit newElementCreated(element, diagram);
}
-void DiagramSceneController::addRelatedElements(const DSelection &selection, MDiagram *diagram)
+int DiagramSceneController::countRelatedElements(const DSelection &selection, MDiagram *diagram, std::function<bool (qmt::DObject *, qmt::MObject *, qmt::MRelation *)> filter)
+{
+ int counter = 0;
+ const QList<DSelection::Index> indices = selection.indices();
+ for (const DSelection::Index &index : indices) {
+ DElement *delement = m_diagramController->findElement(index.elementKey(), diagram);
+ QMT_ASSERT(delement, return 0);
+ DObject *dobject = dynamic_cast<DObject *>(delement);
+ if (dobject && dobject->modelUid().isValid()) {
+ MObject *mobject = m_modelController->findElement<MObject>(delement->modelUid());
+ if (mobject) {
+ const QList<MRelation *> relations = m_modelController->findRelationsOfObject(mobject);
+ QList<MRelation *> filteredRelations;
+ const QList<MRelation *> *relationsList = nullptr;
+ if (filter) {
+ for (MRelation *relation : relations) {
+ if (filter(dobject, mobject, relation))
+ filteredRelations.append(relation);
+ }
+ relationsList = &filteredRelations;
+ } else {
+ relationsList = &relations;
+ }
+ for (MRelation *relation : *relationsList) {
+ if (relation->endAUid() != mobject->uid())
+ ++counter;
+ else if (relation->endBUid() != mobject->uid())
+ ++counter;
+ }
+ }
+ }
+ }
+ return counter;
+}
+
+void DiagramSceneController::addRelatedElements(
+ const DSelection &selection, MDiagram *diagram,
+ std::function<bool (qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation)> filter)
{
m_diagramController->undoController()->beginMergeSequence(Tr::tr("Add Related Element"));
const QList<DSelection::Index> indices = selection.indices();
@@ -435,8 +472,19 @@ void DiagramSceneController::addRelatedElements(const DSelection &selection, MDi
qreal dAngle = 360.0 / 11.5;
qreal dRadius = 100.0;
const QList<MRelation *> relations = m_modelController->findRelationsOfObject(mobject);
+ QList<MRelation *> filteredRelations;
+ const QList<MRelation *> *relationsList = nullptr;
+ if (filter) {
+ for (MRelation *relation : relations) {
+ if (filter(dobject, mobject, relation))
+ filteredRelations.append(relation);
+ }
+ relationsList = &filteredRelations;
+ } else {
+ relationsList = &relations;
+ }
int count = 0;
- for (MRelation *relation : relations) {
+ for (MRelation *relation : *relationsList) {
if (relation->endAUid() != mobject->uid() || relation->endBUid() != mobject->uid())
++count;
}
@@ -446,7 +494,7 @@ void DiagramSceneController::addRelatedElements(const DSelection &selection, MDi
}
qreal radius = 200.0;
qreal angle = 0.0;
- for (MRelation *relation : relations) {
+ for (MRelation *relation : *relationsList) {
QPointF pos(dobject->pos());
pos += QPointF(radius * sin(angle / 180 * M_PI), -radius * cos(angle / 180 * M_PI));
bool added = false;
diff --git a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h
index a062fa10c4..14e704a192 100644
--- a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h
+++ b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h
@@ -86,7 +86,12 @@ public:
DElement *topMostElementAtPos, const QPointF &pos, MDiagram *diagram, const QPoint &viewPos, const QSize &viewSize);
void dropNewModelElement(MObject *modelObject, MPackage *parentPackage, const QPointF &pos,
MDiagram *diagram);
- void addRelatedElements(const DSelection &selection, MDiagram *diagram);
+ int countRelatedElements(
+ const DSelection &selection, MDiagram *diagram,
+ std::function<bool (qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation)> filter);
+ void addRelatedElements(
+ const DSelection &selection, MDiagram *diagram,
+ std::function<bool (qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation)> filter);
MPackage *findSuitableParentPackage(DElement *topmostDiagramElement, MDiagram *diagram);
MDiagram *findDiagramBySearchId(MPackage *package, const QString &diagramName);
diff --git a/src/libs/modelinglib/qmt/tasks/ielementtasks.h b/src/libs/modelinglib/qmt/tasks/ielementtasks.h
index a40277d874..8c22632762 100644
--- a/src/libs/modelinglib/qmt/tasks/ielementtasks.h
+++ b/src/libs/modelinglib/qmt/tasks/ielementtasks.h
@@ -59,8 +59,13 @@ public:
virtual void createAndOpenDiagram(const MElement *) = 0;
virtual void createAndOpenDiagram(const DElement *, const MDiagram *) = 0;
+ virtual bool hasLinkedFile(const MElement *) const = 0;
+ virtual bool hasLinkedFile(const DElement *, const MDiagram *) const = 0;
+ virtual void openLinkedFile(const MElement *) = 0;
+ virtual void openLinkedFile(const DElement *, const MDiagram *) = 0;
+
virtual bool extendContextMenu(const DElement *, const MDiagram *, QMenu *) = 0;
- virtual bool handleContextMenuAction(const DElement *, const MDiagram *, const QString &) = 0;
+ virtual bool handleContextMenuAction(DElement *, MDiagram *, const QString &) = 0;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/tasks/voidelementtasks.cpp b/src/libs/modelinglib/qmt/tasks/voidelementtasks.cpp
index 2bd7fbe049..fdc2e24bd4 100644
--- a/src/libs/modelinglib/qmt/tasks/voidelementtasks.cpp
+++ b/src/libs/modelinglib/qmt/tasks/voidelementtasks.cpp
@@ -147,12 +147,30 @@ void VoidElementTasks::createAndOpenDiagram(const DElement *, const MDiagram *)
{
}
+bool VoidElementTasks::hasLinkedFile(const MElement *) const
+{
+ return false;
+}
+
+bool VoidElementTasks::hasLinkedFile(const DElement *, const MDiagram *) const
+{
+ return false;
+}
+
+void VoidElementTasks::openLinkedFile(const MElement *)
+{
+}
+
+void VoidElementTasks::openLinkedFile(const DElement *, const MDiagram *)
+{
+}
+
bool VoidElementTasks::extendContextMenu(const DElement *, const MDiagram *, QMenu *)
{
return false;
}
-bool VoidElementTasks::handleContextMenuAction(const DElement *, const MDiagram *, const QString &)
+bool VoidElementTasks::handleContextMenuAction(DElement *, MDiagram *, const QString &)
{
return false;
}
diff --git a/src/libs/modelinglib/qmt/tasks/voidelementtasks.h b/src/libs/modelinglib/qmt/tasks/voidelementtasks.h
index 3e3d483d9a..9e8753b71e 100644
--- a/src/libs/modelinglib/qmt/tasks/voidelementtasks.h
+++ b/src/libs/modelinglib/qmt/tasks/voidelementtasks.h
@@ -51,8 +51,13 @@ public:
void createAndOpenDiagram(const MElement *) override;
void createAndOpenDiagram(const DElement *, const MDiagram *) override;
+ bool hasLinkedFile(const qmt::MElement *) const override;
+ bool hasLinkedFile(const qmt::DElement *, const qmt::MDiagram *) const override;
+ void openLinkedFile(const qmt::MElement *) override;
+ void openLinkedFile(const qmt::DElement *, const qmt::MDiagram *) override;
+
bool extendContextMenu(const DElement *, const MDiagram *, QMenu *) override;
- bool handleContextMenuAction(const DElement *, const MDiagram *, const QString &) override;
+ bool handleContextMenuAction(DElement *, MDiagram *, const QString &) override;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qtserialization/inc/qark/serialize_container.h b/src/libs/modelinglib/qtserialization/inc/qark/serialize_container.h
index c95f2c3f96..109b77d991 100644
--- a/src/libs/modelinglib/qtserialization/inc/qark/serialize_container.h
+++ b/src/libs/modelinglib/qtserialization/inc/qark/serialize_container.h
@@ -4,6 +4,7 @@
#pragma once
#include "parameters.h"
+#include "tag.h"
#include <QList>
#include <QHash>
diff --git a/src/libs/nanotrace/CMakeLists.txt b/src/libs/nanotrace/CMakeLists.txt
index 011c26f049..50693644ea 100644
--- a/src/libs/nanotrace/CMakeLists.txt
+++ b/src/libs/nanotrace/CMakeLists.txt
@@ -4,6 +4,7 @@ add_qtc_library(Nanotrace
nanotraceglobals.h
nanotrace.cpp nanotrace.h
nanotracehr.cpp nanotracehr.h
+ staticstring.h
PUBLIC_DEPENDS Qt::Core Qt::Gui
PROPERTIES
CXX_VISIBILITY_PRESET default
diff --git a/src/libs/nanotrace/nanotracehr.cpp b/src/libs/nanotrace/nanotracehr.cpp
index 07d2ff95ac..0006227434 100644
--- a/src/libs/nanotrace/nanotracehr.cpp
+++ b/src/libs/nanotrace/nanotracehr.cpp
@@ -45,6 +45,18 @@ unsigned int getUnsignedIntegerHash(std::thread::id id)
return static_cast<unsigned int>(std::hash<std::thread::id>{}(id) & 0xFFFFFFFF);
}
+template<std::size_t capacity>
+constexpr bool isArgumentValid(const StaticString<capacity> &string)
+{
+ return string.isValid() && string.size();
+}
+
+template<typename String>
+constexpr bool isArgumentValid(const String &string)
+{
+ return string.size();
+}
+
template<typename TraceEvent>
void printEvent(std::ostream &out, const TraceEvent &event, qint64 processId, std::thread::id threadId)
{
@@ -67,23 +79,24 @@ void printEvent(std::ostream &out, const TraceEvent &event, qint64 processId, st
out << R"(,"flow_in":true)";
}
- if (event.arguments.size())
+ if (isArgumentValid(event.arguments)) {
out << R"(,"args":)" << event.arguments;
+ }
out << "}";
}
-void writeMetaEvent(TraceFile<Tracing::IsEnabled> *file, std::string_view key, std::string_view value)
+void writeMetaEvent(TraceFile<Tracing::IsEnabled> &file, std::string_view key, std::string_view value)
{
- std::lock_guard lock{file->fileMutex};
- auto &out = file->out;
+ std::lock_guard lock{file.fileMutex};
+ auto &out = file.out;
if (out.is_open()) {
- file->out << R"({"name":")" << key << R"(","ph":"M", "pid":)"
- << getUnsignedIntegerHash(QCoreApplication::applicationPid()) << R"(,"tid":)"
- << getUnsignedIntegerHash(std::this_thread::get_id()) << R"(,"args":{"name":")"
- << value << R"("}})"
- << ",\n";
+ file.out << R"({"name":")" << key << R"(","ph":"M", "pid":)"
+ << getUnsignedIntegerHash(QCoreApplication::applicationPid()) << R"(,"tid":)"
+ << getUnsignedIntegerHash(std::this_thread::get_id()) << R"(,"args":{"name":")"
+ << value << R"("}})"
+ << ",\n";
}
}
@@ -103,7 +116,6 @@ std::string getThreadName()
} // namespace
-namespace Internal {
template<typename String>
void convertToString(String &string, const QImage &image)
{
@@ -132,14 +144,11 @@ void convertToString(String &string, const QImage &image)
return "alpha premultiplied"sv;
}))));
- Internal::convertToString(string, dict);
+ convertToString(string, dict);
}
-template NANOTRACE_EXPORT void convertToString(std::string &string, const QImage &image);
template NANOTRACE_EXPORT void convertToString(ArgumentsString &string, const QImage &image);
-} // namespace Internal
-
template<typename TraceEvent>
void flushEvents(const Utils::span<TraceEvent> events,
std::thread::id threadId,
@@ -148,8 +157,8 @@ void flushEvents(const Utils::span<TraceEvent> events,
if (events.empty())
return;
- std::lock_guard lock{eventQueue.file->fileMutex};
- auto &out = eventQueue.file->out;
+ std::lock_guard lock{eventQueue.file.fileMutex};
+ auto &out = eventQueue.file.out;
if (out.is_open()) {
auto processId = QCoreApplication::applicationPid();
@@ -200,17 +209,17 @@ void finalizeFile(EnabledTraceFile &file)
template<typename TraceEvent>
void flushInThread(EnabledEventQueue<TraceEvent> &eventQueue)
{
- if (eventQueue.file->processing.valid())
- eventQueue.file->processing.wait();
+ if (eventQueue.file.processing.valid())
+ eventQueue.file.processing.wait();
auto flush = [&](const Utils::span<TraceEvent> &events, std::thread::id threadId) {
flushEvents(events, threadId, eventQueue);
};
- eventQueue.file->processing = std::async(std::launch::async,
- flush,
- eventQueue.currentEvents.subspan(0, eventQueue.eventsIndex),
- eventQueue.threadId);
+ eventQueue.file.processing = std::async(std::launch::async,
+ flush,
+ eventQueue.currentEvents.subspan(0, eventQueue.eventsIndex),
+ eventQueue.threadId);
eventQueue.currentEvents = eventQueue.currentEvents.data() == eventQueue.eventsOne.data()
? eventQueue.eventsTwo
: eventQueue.eventsOne;
@@ -223,10 +232,11 @@ template NANOTRACE_EXPORT void flushInThread(
EnabledEventQueue<StringViewWithStringArgumentsTraceEvent> &eventQueue);
template<typename TraceEvent>
-EventQueue<TraceEvent, Tracing::IsEnabled>::EventQueue(EnabledTraceFile *file)
+EventQueue<TraceEvent, Tracing::IsEnabled>::EventQueue(EnabledTraceFile &file)
: file{file}
, threadId{std::this_thread::get_id()}
{
+ setEventsSpans(*eventArrayOne.get(), *eventArrayTwo.get());
Internal::EventQueueTracker<TraceEvent>::get().addQueue(this);
if (auto thread = QThread::currentThread()) {
auto name = getThreadName();
diff --git a/src/libs/nanotrace/nanotracehr.h b/src/libs/nanotrace/nanotracehr.h
index 7856ea3582..810e4e3c5d 100644
--- a/src/libs/nanotrace/nanotracehr.h
+++ b/src/libs/nanotrace/nanotracehr.h
@@ -5,16 +5,22 @@
#include "nanotraceglobals.h"
+#include "staticstring.h"
+
#include <utils/smallstring.h>
#include <utils/span.h>
#include <QByteArrayView>
+#include <QList>
+#include <QMap>
#include <QStringView>
+#include <QVarLengthArray>
#include <QVariant>
#include <array>
#include <atomic>
#include <chrono>
+#include <exception>
#include <fstream>
#include <future>
#include <mutex>
@@ -41,7 +47,7 @@ enum class Tracing { IsDisabled, IsEnabled };
# define NO_UNIQUE_ADDRESS
#endif
-using ArgumentsString = Utils::BasicSmallString<510>;
+using ArgumentsString = StaticString<3700>;
namespace Literals {
struct TracerLiteral
@@ -80,44 +86,41 @@ struct IsDictonary
inline constexpr IsDictonary isDictonary;
-namespace Internal {
-
template<typename String>
void convertToString(String &string, std::string_view text)
{
- string.append(R"(")");
+ string.append('\"');
string.append(text);
- string.append(R"(")");
+ string.append('\"');
}
template<typename String>
void convertToString(String &string, const QImage &image);
-extern template NANOTRACE_EXPORT void convertToString(std::string &string, const QImage &image);
extern template NANOTRACE_EXPORT void convertToString(ArgumentsString &string, const QImage &image);
template<typename String, std::size_t size>
void convertToString(String &string, const char (&text)[size])
{
- string.append(R"(")");
- string.append(text);
- string.append(R"(")");
+ string.append('\"');
+ string.append(std::string_view{text, size - 1});
+ string.append('\"');
}
template<typename String>
void convertToString(String &string, QStringView text)
{
- string.append(R"(")");
+ string.append('\"');
string.append(Utils::PathString{text});
- string.append(R"(")");
+ string.append('\"');
}
template<typename String>
void convertToString(String &string, const QByteArray &text)
{
- string.append(R"(")");
+ string.append('\"');
string.append(std::string_view(text.data(), Utils::usize(text)));
- string.append(R"(")");
+ string.append('\"');
}
template<typename String>
@@ -129,28 +132,29 @@ void convertToString(String &string, bool isTrue)
string.append("false");
}
-template<typename String, typename Callable, typename = std::enable_if_t<std::is_invocable_v<Callable>>>
+template<typename String, typename Callable, typename std::enable_if_t<std::is_invocable_v<Callable>, bool> = true>
void convertToString(String &string, Callable &&callable)
{
convertToString(string, callable());
}
-template<typename String>
-void convertToString(String &string, int number)
+template<typename String, typename Number, typename std::enable_if_t<std::is_arithmetic_v<Number>, bool> = true>
+void convertToString(String &string, Number number)
{
- string.append(Utils::SmallString::number(number));
+ string.append(number);
}
-template<typename String>
-void convertToString(String &string, long long number)
+template<typename Enumeration>
+constexpr std::underlying_type_t<Enumeration> to_underlying(Enumeration enumeration) noexcept
{
- string.append(Utils::SmallString::number(number));
+ static_assert(std::is_enum_v<Enumeration>, "to_underlying expect an enumeration");
+ return static_cast<std::underlying_type_t<Enumeration>>(enumeration);
}
-template<typename String>
-void convertToString(String &string, double number)
+template<typename String, typename Enumeration, typename std::enable_if_t<std::is_enum_v<Enumeration>, bool> = true>
+void convertToString(String &string, Enumeration enumeration)
{
- string.append(Utils::SmallString::number(number));
+ string.append(to_underlying(enumeration));
}
template<typename String>
@@ -165,14 +169,14 @@ void convertToString(String &string, const QVariant &value)
convertToString(string, value.toString());
}
-template<typename String, typename... Arguments>
-void convertToString(String &string, const std::tuple<const IsDictonary &, Arguments...> &dictonary);
-
-template<typename String, typename... Arguments>
-void convertToString(String &string, const std::tuple<const IsArray &, Arguments...> &list);
-
-template<typename String, template<typename...> typename Container, typename... Arguments>
-void convertToString(String &string, const Container<Arguments...> &container);
+template<typename String, typename Type>
+void convertToString(String &string, const std::optional<Type> &value)
+{
+ if (value)
+ convertToString(string, *value);
+ else
+ convertToString(string, "empty optional");
+}
template<typename String, typename Value>
void convertArrayEntryToString(String &string, const Value &value)
@@ -184,15 +188,15 @@ void convertArrayEntryToString(String &string, const Value &value)
template<typename String, typename... Entries>
void convertArrayToString(String &string, const IsArray &, Entries &...entries)
{
- string.append(R"([)");
+ string.append('[');
(convertArrayEntryToString(string, entries), ...);
if (sizeof...(entries))
string.pop_back();
- string.append("]");
+ string.append(']');
}
template<typename String, typename... Arguments>
-void convertToString(String &string, const std::tuple<const IsArray &, Arguments...> &list)
+void convertToString(String &string, const std::tuple<IsArray, Arguments...> &list)
{
std::apply([&](auto &&...entries) { convertArrayToString(string, entries...); }, list);
}
@@ -202,55 +206,107 @@ void convertDictonaryEntryToString(String &string, const std::tuple<Key, Value>
{
const auto &[key, value] = argument;
convertToString(string, key);
- string.append(":");
+ string.append(':');
convertToString(string, value);
- string.append(",");
+ string.append(',');
}
template<typename String, typename... Entries>
void convertDictonaryToString(String &string, const IsDictonary &, Entries &...entries)
{
- string.append(R"({)");
+ string.append('{');
(convertDictonaryEntryToString(string, entries), ...);
if (sizeof...(entries))
string.pop_back();
- string.append("}");
+ string.append('}');
}
template<typename String, typename... Arguments>
-void convertToString(String &string, const std::tuple<const IsDictonary &, Arguments...> &dictonary)
+void convertToString(String &string, const std::tuple<IsDictonary, Arguments...> &dictonary)
{
std::apply([&](auto &&...entries) { convertDictonaryToString(string, entries...); }, dictonary);
}
-template<typename String, template<typename...> typename Container, typename... Arguments>
-void convertToString(String &string, const Container<Arguments...> &container)
+template<typename T>
+struct is_container : std::false_type
+{};
+
+template<typename... Arguments>
+struct is_container<std::vector<Arguments...>> : std::true_type
+{};
+
+template<typename... Arguments>
+struct is_container<QList<Arguments...>> : std::true_type
+{};
+
+template<typename T, qsizetype Prealloc>
+struct is_container<QVarLengthArray<T, Prealloc>> : std::true_type
+{};
+
+template<typename String, typename Container, typename std::enable_if_t<is_container<Container>::value, bool> = true>
+void convertToString(String &string, const Container &values)
+{
+ string.append('[');
+
+ for (const auto &value : values) {
+ convertToString(string, value);
+ string.append(',');
+ }
+
+ if (values.size())
+ string.pop_back();
+
+ string.append(']');
+}
+
+template<typename T>
+struct is_map : std::false_type
+{};
+
+template<typename... Arguments>
+struct is_map<QtPrivate::QKeyValueRange<Arguments...>> : std::true_type
+{};
+
+template<typename... Arguments>
+struct is_map<std::map<Arguments...>> : std::true_type
+{};
+
+template<typename String, typename Map, typename std::enable_if_t<is_map<Map>::value, bool> = true>
+void convertToString(String &string, const Map &map)
{
- string.append("[");
- for (const auto &entry : container) {
- convertToString(string, entry);
- string.append(",");
+ string.append('{');
+
+ for (const auto &[key, value] : map) {
+ convertToString(string, key);
+ string.append(':');
+ convertToString(string, value);
+ string.append(',');
}
- if (container.size())
+ if (map.begin() != map.end())
string.pop_back();
- string.append("]");
+ string.append('}');
+}
+
+template<typename String, typename Key, typename Value>
+void convertToString(String &string, const QMap<Key, Value> &dictonary)
+{
+ convertToString(string, dictonary.asKeyValueRange());
}
+namespace Internal {
+
template<typename String, typename... Arguments>
-String toArguments(Arguments &&...arguments)
+void toArguments(String &text, Arguments &&...arguments)
{
- String text;
constexpr auto argumentCount = sizeof...(Arguments);
- text.append("{");
+ text.append('{');
(convertDictonaryEntryToString(text, arguments), ...);
if (argumentCount)
text.pop_back();
- text.append("}");
-
- return text;
+ text.append('}');
}
inline std::string_view toArguments(std::string_view arguments)
@@ -259,48 +315,58 @@ inline std::string_view toArguments(std::string_view arguments)
}
template<typename String>
-void appendArguments(String &eventArguments)
+void setArguments(String &eventArguments)
{
- eventArguments = {};
+ if constexpr (std::is_same_v<String, std::string_view>)
+ eventArguments = {};
+ else
+ eventArguments.clear();
}
template<typename String>
-void appendArguments(String &eventArguments, TracerLiteral arguments)
+void setArguments(String &eventArguments, TracerLiteral arguments)
{
eventArguments = arguments;
}
template<typename String, typename... Arguments>
-[[maybe_unused]] void appendArguments(String &eventArguments, Arguments &&...arguments)
+[[maybe_unused]] void setArguments(String &eventArguments, Arguments &&...arguments)
{
static_assert(
!std::is_same_v<String, std::string_view>,
R"(The arguments type of the tracing event queue is a string view. You can only provide trace token arguments as TracerLiteral (""_t).)");
- eventArguments = Internal::toArguments<String>(std::forward<Arguments>(arguments)...);
+ if constexpr (std::is_same_v<String, std::string_view>)
+ eventArguments = {};
+ else
+ eventArguments.clear();
+ Internal::toArguments(eventArguments, std::forward<Arguments>(arguments)...);
}
} // namespace Internal
template<typename Key, typename Value>
-auto keyValue(Key &&key, Value &&value)
+auto keyValue(const Key &key, Value &&value)
{
- return std::forward_as_tuple(std::forward<Key>(key), std::forward<Value>(value));
+ if constexpr (std::is_lvalue_reference_v<Value>)
+ return std::tuple<const Key &, const Value &>(key, value);
+ else
+ return std::tuple<const Key &, std::decay_t<Value>>(key, value);
}
template<typename... Entries>
auto dictonary(Entries &&...entries)
{
- return std::forward_as_tuple(isDictonary, std::forward<Entries>(entries)...);
+ return std::make_tuple(isDictonary, std::forward<Entries>(entries)...);
}
template<typename... Entries>
auto array(Entries &&...entries)
{
- return std::forward_as_tuple(isArray, std::forward<Entries>(entries)...);
+ return std::make_tuple(isArray, std::forward<Entries>(entries)...);
}
-enum class IsFlow : std::size_t { No = 0, Out = 1 << 0, In = 1 << 1, InOut = In | Out };
+enum class IsFlow : char { No = 0, Out = 1 << 0, In = 1 << 1, InOut = In | Out };
inline bool operator&(IsFlow first, IsFlow second)
{
@@ -309,7 +375,7 @@ inline bool operator&(IsFlow first, IsFlow second)
}
template<typename String, typename ArgumentsString>
-struct TraceEvent
+struct alignas(4096) TraceEvent
{
using StringType = String;
using ArgumentType = std::conditional_t<std::is_same_v<String, std::string_view>, TracerLiteral, String>;
@@ -324,13 +390,13 @@ struct TraceEvent
String name;
String category;
- ArgumentsString arguments;
TimePoint time;
Duration duration;
std::size_t id = 0;
- std::size_t bindId : 62;
- IsFlow flow : 2;
+ std::size_t bindId = 0;
+ IsFlow flow = IsFlow::No;
char type = ' ';
+ ArgumentsString arguments;
};
using StringViewTraceEvent = TraceEvent<std::string_view, std::string_view>;
@@ -413,6 +479,8 @@ class EventQueue
{
public:
using IsActive = std::false_type;
+
+ template<typename TraceFile> EventQueue(TraceFile &) {}
};
namespace Internal {
@@ -423,7 +491,13 @@ class EventQueueTracker
using Queue = EventQueue<TraceEvent, Tracing::IsEnabled>;
public:
- EventQueueTracker() = default;
+ EventQueueTracker()
+ {
+ terminateHandler = std::get_terminate();
+
+ std::set_terminate([]() { EventQueueTracker::get().terminate(); });
+ }
+
EventQueueTracker(const EventQueueTracker &) = delete;
EventQueueTracker(EventQueueTracker &&) = delete;
EventQueueTracker &operator=(const EventQueueTracker &) = delete;
@@ -457,8 +531,25 @@ public:
}
private:
+ void terminate()
+ {
+ flushAll();
+ if (terminateHandler)
+ terminateHandler();
+ }
+
+ void flushAll()
+ {
+ std::lock_guard lock{mutex};
+
+ for (auto queue : queues)
+ queue->flush();
+ }
+
+private:
std::mutex mutex;
std::vector<Queue *> queues;
+ std::terminate_handler terminateHandler = nullptr;
};
} // namespace Internal
@@ -466,11 +557,12 @@ template<typename TraceEvent>
class EventQueue<TraceEvent, Tracing::IsEnabled>
{
using TraceEventsSpan = Utils::span<TraceEvent>;
+ using TraceEvents = std::array<TraceEvent, 1000>;
public:
using IsActive = std::true_type;
- EventQueue(EnabledTraceFile *file);
+ EventQueue(EnabledTraceFile &file);
~EventQueue();
@@ -483,7 +575,9 @@ public:
EventQueue &operator=(const EventQueue &) = delete;
EventQueue &operator=(EventQueue &&) = delete;
- EnabledTraceFile *file = nullptr;
+ EnabledTraceFile &file;
+ std::unique_ptr<TraceEvents> eventArrayOne = std::make_unique<TraceEvents>();
+ std::unique_ptr<TraceEvents> eventArrayTwo = std::make_unique<TraceEvents>();
TraceEventsSpan eventsOne;
TraceEventsSpan eventsTwo;
TraceEventsSpan currentEvents;
@@ -505,35 +599,6 @@ extern template class NANOTRACE_EXPORT_EXTERN_TEMPLATE EventQueue<StringTraceEve
extern template class NANOTRACE_EXPORT_EXTERN_TEMPLATE
EventQueue<StringViewWithStringArgumentsTraceEvent, Tracing::IsEnabled>;
-template<typename TraceEvent, std::size_t eventCount, Tracing isEnabled>
-class EventQueueData : public EventQueue<TraceEvent, isEnabled>
-{
-public:
- using IsActive = std::true_type;
-
- EventQueueData(TraceFile<Tracing::IsDisabled> &) {}
-};
-
-template<typename TraceEvent, std::size_t eventCount>
-class EventQueueData<TraceEvent, eventCount, Tracing::IsEnabled>
- : public EventQueue<TraceEvent, Tracing::IsEnabled>
-{
- using TraceEvents = std::array<TraceEvent, eventCount>;
- using Base = EventQueue<TraceEvent, Tracing::IsEnabled>;
-
-public:
- using IsActive = std::true_type;
-
- EventQueueData(EnabledTraceFile &file)
- : Base{&file}
- {
- Base::setEventsSpans(*eventsOne.get(), *eventsTwo.get());
- }
-
- std::unique_ptr<TraceEvents> eventsOne = std::make_unique<TraceEvents>();
- std::unique_ptr<TraceEvents> eventsTwo = std::make_unique<TraceEvents>();
-};
-
template<typename TraceEvent>
TraceEvent &getTraceEvent(EnabledEventQueue<TraceEvent> &eventQueue)
{
@@ -1150,6 +1215,10 @@ public:
return std::pair<TracerType, FlowTokenType>();
}
+ template<typename... Arguments>
+ void threadEvent(ArgumentType, Arguments &&...)
+ {}
+
static constexpr bool isActive() { return false; }
};
@@ -1237,6 +1306,24 @@ public:
std::forward_as_tuple(PrivateTag{}, traceName, bindId, m_self)};
}
+ template<typename... Arguments>
+ void threadEvent(ArgumentType traceName, Arguments &&...arguments)
+ {
+ if (isEnabled == IsEnabled::No)
+ return;
+
+ auto &traceEvent = getTraceEvent(m_eventQueue);
+
+ traceEvent.time = Clock::now();
+ traceEvent.name = std::move(traceName);
+ traceEvent.category = traceName;
+ traceEvent.type = 'i';
+ traceEvent.id = 0;
+ traceEvent.bindId = 0;
+ traceEvent.flow = IsFlow::No;
+ Internal::setArguments(traceEvent.arguments, std::forward<Arguments>(arguments)...);
+ }
+
EnabledEventQueue<TraceEvent> &eventQueue() const { return m_eventQueue; }
std::string_view name() const { return m_name; }
@@ -1270,7 +1357,7 @@ private:
traceEvent.id = id;
traceEvent.bindId = bindId;
traceEvent.flow = flow;
- Internal::appendArguments(traceEvent.arguments, std::forward<Arguments>(arguments)...);
+ Internal::setArguments(traceEvent.arguments, std::forward<Arguments>(arguments)...);
traceEvent.time = Clock::now();
}
@@ -1296,7 +1383,7 @@ private:
traceEvent.id = id;
traceEvent.bindId = bindId;
traceEvent.flow = flow;
- Internal::appendArguments(traceEvent.arguments, std::forward<Arguments>(arguments)...);
+ Internal::setArguments(traceEvent.arguments, std::forward<Arguments>(arguments)...);
}
template<typename... Arguments>
@@ -1316,9 +1403,11 @@ private:
traceEvent.id = id;
traceEvent.bindId = 0;
traceEvent.flow = IsFlow::No;
- Internal::appendArguments(traceEvent.arguments, std::forward<Arguments>(arguments)...);
+ Internal::setArguments(traceEvent.arguments, std::forward<Arguments>(arguments)...);
}
+ CategoryFunctionPointer self() { return m_self; }
+
private:
StringType m_name;
EnabledEventQueue<TraceEvent> &m_eventQueue;
@@ -1403,11 +1492,8 @@ class Tracer<Category, std::true_type>
, flow{flow}
, m_category{category}
{
- if (category().isEnabled == IsEnabled::Yes) {
- Internal::appendArguments<ArgumentsStringType>(m_arguments,
- std::forward<Arguments>(arguments)...);
- m_start = Clock::now();
- }
+ if (category().isEnabled == IsEnabled::Yes)
+ sendBeginTrace(std::forward<Arguments>(arguments)...);
}
public:
@@ -1426,13 +1512,15 @@ public:
: m_name{name}
, m_category{category}
{
- if (category().isEnabled == IsEnabled::Yes) {
- Internal::appendArguments<ArgumentsStringType>(m_arguments,
- std::forward<Arguments>(arguments)...);
- m_start = Clock::now();
- }
+ if (category().isEnabled == IsEnabled::Yes)
+ sendBeginTrace(std::forward<Arguments>(arguments)...);
}
+ template<typename... Arguments>
+ [[nodiscard]] Tracer(ArgumentType name, Category &category, Arguments &&...arguments)
+ : Tracer(std::move(name), category.self(), std::forward<Arguments>(arguments)...)
+ {}
+
Tracer(const Tracer &) = delete;
Tracer &operator=(const Tracer &) = delete;
Tracer(Tracer &&other) noexcept = delete;
@@ -1440,7 +1528,7 @@ public:
TokenType createToken() { return {0, m_category}; }
- ~Tracer() { sendTrace(); }
+ ~Tracer() { sendEndTrace(); }
template<typename... Arguments>
Tracer beginDuration(ArgumentType name, Arguments &&...arguments)
@@ -1457,44 +1545,52 @@ public:
template<typename... Arguments>
void end(Arguments &&...arguments)
{
- sendTrace(std::forward<Arguments>(arguments)...);
+ sendEndTrace(std::forward<Arguments>(arguments)...);
m_name = {};
}
private:
template<typename... Arguments>
- void sendTrace(Arguments &&...arguments)
+ void sendBeginTrace(Arguments &&...arguments)
+ {
+ auto &category = m_category();
+ if (category.isEnabled == IsEnabled::Yes) {
+ auto &traceEvent = getTraceEvent(category.eventQueue());
+ traceEvent.name = m_name;
+ traceEvent.category = category.name();
+ traceEvent.bindId = m_bindId;
+ traceEvent.flow = flow;
+ traceEvent.type = 'B';
+ Internal::setArguments<ArgumentsStringType>(traceEvent.arguments,
+ std::forward<Arguments>(arguments)...);
+ traceEvent.time = Clock::now();
+ }
+ }
+
+ template<typename... Arguments>
+ void sendEndTrace(Arguments &&...arguments)
{
if (m_name.size()) {
- auto category = m_category();
+ auto &category = m_category();
if (category.isEnabled == IsEnabled::Yes) {
- auto duration = Clock::now() - m_start;
+ auto end = Clock::now();
auto &traceEvent = getTraceEvent(category.eventQueue());
- traceEvent.name = m_name;
+ traceEvent.name = std::move(m_name);
traceEvent.category = category.name();
- traceEvent.time = m_start;
- traceEvent.duration = duration;
+ traceEvent.time = end;
traceEvent.bindId = m_bindId;
traceEvent.flow = flow;
- traceEvent.type = 'X';
- if (sizeof...(arguments)) {
- m_arguments.clear();
- Internal::appendArguments<ArgumentsStringType>(traceEvent.arguments,
- std::forward<Arguments>(
- arguments)...);
- } else {
- traceEvent.arguments = m_arguments;
- }
+ traceEvent.type = 'E';
+ Internal::setArguments<ArgumentsStringType>(traceEvent.arguments,
+ std::forward<Arguments>(arguments)...);
}
}
}
private:
- TimePoint m_start;
StringType m_name;
- ArgumentsStringType m_arguments;
- std::size_t m_bindId;
- IsFlow flow;
+ std::size_t m_bindId = 0;
+ IsFlow flow = IsFlow::No;
CategoryFunctionPointer m_category;
};
diff --git a/src/libs/nanotrace/staticstring.h b/src/libs/nanotrace/staticstring.h
new file mode 100644
index 0000000000..d787bd2fe3
--- /dev/null
+++ b/src/libs/nanotrace/staticstring.h
@@ -0,0 +1,116 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#pragma once
+
+#include <utils/smallstringview.h>
+
+#if !(defined(__cpp_lib_to_chars) && (__cpp_lib_to_chars >= 201611L))
+# include <QLocale>
+#endif
+
+#include <array>
+#include <charconv>
+#include <limits>
+
+namespace NanotraceHR {
+
+template<std::size_t Capacity>
+class StaticString
+{
+public:
+ StaticString() = default;
+ StaticString(const StaticString &) = delete;
+ StaticString &operator=(const StaticString &) = delete;
+
+ char *data() { return m_data.data(); }
+
+ const char *data() const { return m_data.data(); }
+
+ void append(Utils::SmallStringView string) noexcept
+ {
+ auto newSize = m_size + string.size();
+
+ if (newSize <= Capacity) {
+ std::char_traits<char>::copy(std::next(data(), static_cast<std::ptrdiff_t>(m_size)),
+ string.data(),
+ string.size());
+ m_size = newSize;
+ } else {
+ m_size = Capacity + 1;
+ }
+ }
+
+ void append(char character) noexcept
+ {
+ auto newSize = m_size + 1;
+
+ if (newSize <= Capacity) {
+ auto current = std::next(data(), static_cast<std::ptrdiff_t>(m_size));
+ *current = character;
+
+ m_size = newSize;
+ } else {
+ m_size = Capacity + 1;
+ }
+ }
+
+ template<typename Type, typename std::enable_if_t<std::is_arithmetic_v<Type>, bool> = true>
+ void append(Type number)
+ {
+#if !(defined(__cpp_lib_to_chars) && (__cpp_lib_to_chars >= 201611L))
+ if constexpr (std::is_floating_point_v<Type>) {
+ QLocale locale{QLocale::Language::C};
+ append(locale.toString(number).toStdString());
+ return;
+ }
+#endif
+ // 2 bytes for the sign and because digits10 returns the floor
+ char buffer[std::numeric_limits<Type>::digits10 + 2];
+ auto result = std::to_chars(buffer, buffer + sizeof(buffer), number);
+ auto endOfConversionString = result.ptr;
+
+ append({buffer, endOfConversionString});
+ }
+
+ void pop_back() { --m_size; }
+
+ StaticString &operator+=(Utils::SmallStringView string) noexcept
+ {
+ append(string);
+
+ return *this;
+ }
+
+ StaticString &operator+=(char character) noexcept
+ {
+ append(character);
+
+ return *this;
+ }
+
+ template<typename Type, typename = std::enable_if_t<std::is_arithmetic_v<Type>>>
+ StaticString &operator+=(Type number) noexcept
+ {
+ append(number);
+
+ return *this;
+ }
+
+ bool isValid() const { return m_size <= Capacity; }
+
+ std::size_t size() const { return m_size; }
+
+ friend std::ostream &operator<<(std::ostream &out, const StaticString &text)
+ {
+ return out << std::string_view{text.data(), text.size()};
+ }
+
+ void clear() { m_size = 0; }
+
+private:
+ std::array<char, Capacity> m_data;
+ std::size_t m_size = 0;
+};
+
+} // namespace NanotraceHR
diff --git a/src/libs/qlitehtml b/src/libs/qlitehtml
-Subproject 9c7b5d073bf4713250648cf7ea35580f489f7fd
+Subproject 4f737256c0a698ff3ba380cbaef1ba80a16fc3a
diff --git a/src/libs/qmljs/CMakeLists.txt b/src/libs/qmljs/CMakeLists.txt
index 4ca15cf7cc..a4966a8b4a 100644
--- a/src/libs/qmljs/CMakeLists.txt
+++ b/src/libs/qmljs/CMakeLists.txt
@@ -33,7 +33,6 @@ add_qtc_library(QmlJS
qmljsfindexportedcpptypes.cpp qmljsfindexportedcpptypes.h
qmljsicons.cpp qmljsicons.h
qmljsimportdependencies.cpp qmljsimportdependencies.h
- qmljsindenter.cpp qmljsindenter.h
qmljsinterpreter.cpp qmljsinterpreter.h
qmljslineinfo.cpp qmljslineinfo.h
qmljslink.cpp qmljslink.h
diff --git a/src/libs/qmljs/qmljs.qbs b/src/libs/qmljs/qmljs.qbs
index 18434c83ba..d5cc21faf1 100644
--- a/src/libs/qmljs/qmljs.qbs
+++ b/src/libs/qmljs/qmljs.qbs
@@ -28,7 +28,6 @@ QtcLibrary {
"qmljsfindexportedcpptypes.cpp", "qmljsfindexportedcpptypes.h",
"qmljsicons.cpp", "qmljsicons.h",
"qmljsimportdependencies.cpp", "qmljsimportdependencies.h",
- "qmljsindenter.cpp", "qmljsindenter.h",
"qmljsinterpreter.cpp", "qmljsinterpreter.h",
"qmljsdialect.cpp", "qmljsdialect.h",
"qmljslineinfo.cpp", "qmljslineinfo.h",
diff --git a/src/libs/qmljs/qmljsbind.cpp b/src/libs/qmljs/qmljsbind.cpp
index 6ccddcbe63..163680998f 100644
--- a/src/libs/qmljs/qmljsbind.cpp
+++ b/src/libs/qmljs/qmljsbind.cpp
@@ -333,6 +333,23 @@ bool Bind::visit(UiInlineComponent *ast)
return true;
}
+bool Bind::visit(UiEnumDeclaration *ast)
+{
+ if (_currentObjectValue) {
+ UiEnumValue *value = new UiEnumValue(ast, &_valueOwner, _currentObjectValue->originId());
+ _qmlObjects.insert(ast, value);
+ _currentObjectValue->setMember(ast->name, value);
+ // add enum value's keys as member to its parent object
+ for (auto it = ast->members; it; it = it->next) {
+ const QString name = it->member.toString();
+ _currentObjectValue->setMember(name, _valueOwner.intValue());
+ _currentObjectValue->setPropertyInfo(
+ name, PropertyInfo(PropertyInfo::Readable | PropertyInfo::ValueType));
+ }
+ }
+ return true;
+}
+
bool Bind::visit(AST::TemplateLiteral *ast)
{
Node::accept(ast->expression, this);
diff --git a/src/libs/qmljs/qmljsbind.h b/src/libs/qmljs/qmljsbind.h
index 08a60c17cc..d7096abdb2 100644
--- a/src/libs/qmljs/qmljsbind.h
+++ b/src/libs/qmljs/qmljsbind.h
@@ -57,6 +57,7 @@ protected:
bool visit(AST::UiScriptBinding *ast) override;
bool visit(AST::UiArrayBinding *ast) override;
bool visit(AST::UiInlineComponent *ast) override;
+ bool visit(AST::UiEnumDeclaration *ast) override;
// QML/JS
bool visit(AST::TemplateLiteral *ast) override;
diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp
index 7ceff0e78d..8cf85f11ed 100644
--- a/src/libs/qmljs/qmljscheck.cpp
+++ b/src/libs/qmljs/qmljscheck.cpp
@@ -846,6 +846,32 @@ bool Check::visit(UiObjectInitializer *)
return true;
}
+bool Check::visit(AST::UiEnumDeclaration *ast)
+{
+ const Value *localLookup = _scopeChain.lookup(ast->name.toString());
+ Utils::FilePath fp;
+ int line, column;
+ if (localLookup->getSourceLocation(&fp, &line, &column)) {
+ // if it's not "us" we get shadowed by another enum declaration
+ if (int(ast->identifierToken.startLine) != line || int(ast->identifierToken.startColumn) != column)
+ addMessage(ErrDuplicateId, SourceLocation(0, 0, line, column));
+ }
+ return true;
+}
+
+bool Check::visit(AST::UiEnumMemberList *ast)
+{
+ QStringList names;
+ for (auto it = ast; it; it = it->next) {
+ if (!it->member.first().isUpper())
+ addMessage(ErrInvalidEnumValue, it->memberToken); // better a different message?
+ if (names.contains(it->member)) // duplicate enum value
+ addMessage(ErrInvalidEnumValue, it->memberToken); // better a different message?
+ names.append(it->member.toString());
+ }
+ return true;
+}
+
bool Check::visit(AST::TemplateLiteral *ast)
{
Node::accept(ast->expression, this);
diff --git a/src/libs/qmljs/qmljscheck.h b/src/libs/qmljs/qmljscheck.h
index 1fb96d251b..d7fc6cc425 100644
--- a/src/libs/qmljs/qmljscheck.h
+++ b/src/libs/qmljs/qmljscheck.h
@@ -57,6 +57,8 @@ protected:
bool visit(AST::FunctionDeclaration *ast) override;
bool visit(AST::FunctionExpression *ast) override;
bool visit(AST::UiObjectInitializer *) override;
+ bool visit(AST::UiEnumDeclaration *ast) override;
+ bool visit(AST::UiEnumMemberList *ast) override;
bool visit(AST::TemplateLiteral *ast) override;
bool visit(AST::BinaryExpression *ast) override;
diff --git a/src/libs/qmljs/qmljsicons.cpp b/src/libs/qmljs/qmljsicons.cpp
index 0086843553..a0522ca726 100644
--- a/src/libs/qmljs/qmljsicons.cpp
+++ b/src/libs/qmljs/qmljsicons.cpp
@@ -120,3 +120,8 @@ QIcon Icons::functionDeclarationIcon()
{
return Utils::CodeModelIcon::iconForType(Utils::CodeModelIcon::FuncPublic);
}
+
+QIcon Icons::enumMemberIcon()
+{
+ return Utils::CodeModelIcon::iconForType(Utils::CodeModelIcon::Enum);
+}
diff --git a/src/libs/qmljs/qmljsicons.h b/src/libs/qmljs/qmljsicons.h
index 4466d07a18..1565ae5355 100644
--- a/src/libs/qmljs/qmljsicons.h
+++ b/src/libs/qmljs/qmljsicons.h
@@ -28,6 +28,7 @@ public:
static QIcon scriptBindingIcon();
static QIcon publicMemberIcon();
static QIcon functionDeclarationIcon();
+ static QIcon enumMemberIcon();
private:
Icons();
diff --git a/src/libs/qmljs/qmljsindenter.cpp b/src/libs/qmljs/qmljsindenter.cpp
deleted file mode 100644
index 8055847d90..0000000000
--- a/src/libs/qmljs/qmljsindenter.cpp
+++ /dev/null
@@ -1,603 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-/*
- This file is a self-contained interactive indenter for Qt Script.
-
- The general problem of indenting a program is ill posed. On
- the one hand, an indenter has to analyze programs written in a
- free-form formal language that is best described in terms of
- tokens, not characters, not lines. On the other hand, indentation
- applies to lines and white space characters matter, and otherwise
- the programs to indent are formally invalid in general, as they
- are begin edited.
-
- The approach taken here works line by line. We receive a program
- consisting of N lines or more, and we want to compute the
- indentation appropriate for the Nth line. Lines beyond the Nth
- lines are of no concern to us, so for simplicity we pretend the
- program has exactly N lines and we call the Nth line the "bottom
- line". Typically, we have to indent the bottom line when it's
- still empty, so we concentrate our analysis on the N - 1 lines
- that precede.
-
- By inspecting the (N - 1)-th line, the (N - 2)-th line, ...
- backwards, we determine the kind of the bottom line and indent it
- accordingly.
-
- * The bottom line is a comment line. See
- bottomLineStartsInCComment() and
- indentWhenBottomLineStartsInCComment().
- * The bottom line is a continuation line. See isContinuationLine()
- and indentForContinuationLine().
- * The bottom line is a standalone line. See
- indentForStandaloneLine().
-
- Certain tokens that influence the indentation, notably braces,
- are looked for in the lines. This is done by simple string
- comparison, without a real tokenizer. Confusing constructs such
- as comments and string literals are removed beforehand.
-*/
-
-#include <qmljs/qmljsindenter.h>
-#include <qmljs/qmljsscanner.h>
-
-#include <QTextBlock>
-
-using namespace QmlJS;
-
-/*
- Saves and restores the state of the global linizer. This enables
- backtracking.
-
- Identical to the defines in qmljslineinfo.cpp
-*/
-#define YY_SAVE() LinizerState savedState = yyLinizerState
-#define YY_RESTORE() yyLinizerState = savedState
-
-
-QmlJSIndenter::QmlJSIndenter()
- : caseOrDefault(QRegularExpression(QLatin1String(
- "^\\s*(?:"
- "case\\b[^:]+|"
- "default)"
- "\\s*:.*$")))
-
-{
-
- /*
- The indenter supports a few parameters:
-
- * ppHardwareTabSize is the size of a '\t' in your favorite editor.
- * ppIndentSize is the size of an indentation, or software tab
- size.
- * ppContinuationIndentSize is the extra indent for a continuation
- line, when there is nothing to align against on the previous
- line.
- * ppCommentOffset is the indentation within a C-style comment,
- when it cannot be picked up.
- */
-
- ppHardwareTabSize = 8;
- ppIndentSize = 4;
- ppContinuationIndentSize = 8;
- ppCommentOffset = 2;
-}
-
-QmlJSIndenter::~QmlJSIndenter()
-{
-}
-
-void QmlJSIndenter::setTabSize(int size)
-{
- ppHardwareTabSize = size;
-}
-
-void QmlJSIndenter::setIndentSize(int size)
-{
- ppIndentSize = size;
- ppContinuationIndentSize = 2 * size;
-}
-
-/*
- Returns true if string t is made only of white space; otherwise
- returns false.
-*/
-bool QmlJSIndenter::isOnlyWhiteSpace(const QString &t) const
-{
- return firstNonWhiteSpace(t).isNull();
-}
-
-/*
- Assuming string t is a line, returns the column number of a given
- index. Column numbers and index are identical for strings that don't
- contain '\t's.
-*/
-int QmlJSIndenter::columnForIndex(const QString &t, int index) const
-{
- int col = 0;
- if (index > t.length())
- index = t.length();
-
- for (int i = 0; i < index; i++) {
- if (t.at(i) == QLatin1Char('\t'))
- col = ((col / ppHardwareTabSize) + 1) * ppHardwareTabSize;
- else
- col++;
- }
- return col;
-}
-
-/*
- Returns the indentation size of string t.
-*/
-int QmlJSIndenter::indentOfLine(const QString &t) const
-{
- return columnForIndex(t, t.indexOf(firstNonWhiteSpace(t)));
-}
-
-/*
- Replaces t[k] by ch, unless t[k] is '\t'. Tab characters are better
- left alone since they break the "index equals column" rule. No
- provisions are taken against '\n' or '\r', which shouldn't occur in
- t anyway.
-*/
-void QmlJSIndenter::eraseChar(QString &t, int k, QChar ch) const
-{
- if (t.at(k) != QLatin1Char('\t'))
- t[k] = ch;
-}
-
-/*
- Returns '(' if the last parenthesis is opening, ')' if it is
- closing, and QChar() if there are no parentheses in t.
-*/
-QChar QmlJSIndenter::lastParen() const
-{
- for (int index = yyLinizerState.tokens.size() - 1; index != -1; --index) {
- const Token &token = yyLinizerState.tokens.at(index);
-
- if (token.is(Token::LeftParenthesis))
- return QLatin1Char('(');
-
- else if (token.is(Token::RightParenthesis))
- return QLatin1Char(')');
- }
-
- return QChar();
-}
-
-/*
- Returns true if typedIn the same as okayCh or is null; otherwise
- returns false.
-*/
-bool QmlJSIndenter::okay(QChar typedIn, QChar okayCh) const
-{
- return typedIn == QChar() || typedIn == okayCh;
-}
-
-/*
- Returns the recommended indent for the bottom line of yyProgram
- assuming that it starts in a C-style comment, a condition that is
- tested elsewhere.
-
- Essentially, we're trying to align against some text on the
- previous line.
-*/
-int QmlJSIndenter::indentWhenBottomLineStartsInMultiLineComment()
-{
- QTextBlock block = yyProgram.lastBlock().previous();
- QString blockText;
-
- for (; block.isValid(); block = block.previous()) {
- blockText = block.text();
-
- if (! isOnlyWhiteSpace(blockText))
- break;
- }
-
- return indentOfLine(blockText);
-}
-
-/*
- Returns the recommended indent for the bottom line of yyProgram,
- assuming it's a continuation line.
-
- We're trying to align the continuation line against some parenthesis
- or other bracked left opened on a previous line, or some interesting
- operator such as '='.
-*/
-int QmlJSIndenter::indentForContinuationLine()
-{
- int braceDepth = 0;
- int delimDepth = 0;
-
- bool leftBraceFollowed = *yyLeftBraceFollows;
-
- for (int i = 0; i < SmallRoof; i++) {
- int hook = -1;
-
- int j = yyLine->length();
- while (j > 0 && hook < 0) {
- j--;
- QChar ch = yyLine->at(j);
-
- switch (ch.unicode()) {
- case ')':
- delimDepth++;
- break;
- case ']':
- braceDepth++;
- break;
- case '}':
- braceDepth++;
- break;
- case '(':
- delimDepth--;
- /*
- An unclosed delimiter is a good place to align at,
- at least for some styles (including Qt's).
- */
- if (delimDepth == -1)
- hook = j;
- break;
-
- case '[':
- braceDepth--;
- /*
- An unclosed delimiter is a good place to align at,
- at least for some styles (including Qt's).
- */
- if (braceDepth == -1)
- hook = j;
- break;
- case '{':
- braceDepth--;
- /*
- A left brace followed by other stuff on the same
- line is typically for an enum or an initializer.
- Such a brace must be treated just like the other
- delimiters.
- */
- if (braceDepth == -1) {
- if (j < yyLine->length() - 1)
- hook = j;
- else
- return 0; // shouldn't happen
- }
- break;
- case '=':
- /*
- An equal sign is a very natural alignment hook
- because it's usually the operator with the lowest
- precedence in statements it appears in. Case in
- point:
-
- int x = 1 +
- 2;
-
- However, we have to beware of constructs such as
- default arguments and explicit enum constant
- values:
-
- void foo(int x = 0,
- int y = 0);
-
- And not
-
- void foo(int x = 0,
- int y = 0);
-
- These constructs are caracterized by a ',' at the
- end of the unfinished lines or by unbalanced
- parentheses.
- */
- Q_ASSERT(j - 1 >= 0);
-
- if (QString::fromLatin1("!=<>").indexOf(yyLine->at(j - 1)) == -1 &&
- j + 1 < yyLine->length() && yyLine->at(j + 1) != QLatin1Char('=')) {
- if (braceDepth == 0 && delimDepth == 0 &&
- j < yyLine->length() - 1 &&
- !yyLine->endsWith(QLatin1Char(',')) &&
- (yyLine->contains(QLatin1Char('(')) == yyLine->contains(QLatin1Char(')'))))
- hook = j;
- }
- }
- }
-
- if (hook >= 0) {
- /*
- Yes, we have a delimiter or an operator to align
- against! We don't really align against it, but rather
- against the following token, if any. In this example,
- the following token is "11":
-
- int x = (11 +
- 2);
-
- If there is no such token, we use a continuation indent:
-
- static QRegExp foo(QString(
- "foo foo foo foo foo foo foo foo foo"));
- */
- hook++;
- while (hook < yyLine->length()) {
- if (!yyLine->at(hook).isSpace())
- return columnForIndex(*yyLine, hook);
- hook++;
- }
- return indentOfLine(*yyLine) + ppContinuationIndentSize;
- }
-
- if (braceDepth != 0)
- break;
-
- /*
- The line's delimiters are balanced. It looks like a
- continuation line or something.
- */
- if (delimDepth == 0) {
- if (leftBraceFollowed) {
- /*
- We have
-
- int main()
- {
-
- or
-
- Bar::Bar()
- : Foo(x)
- {
-
- The "{" should be flush left.
- */
- if (!isContinuationLine())
- return indentOfLine(*yyLine);
- } else if (isContinuationLine() || yyLine->endsWith(QLatin1Char(','))) {
- /*
- We have
-
- x = a +
- b +
- c;
-
- or
-
- int t[] = {
- 1, 2, 3,
- 4, 5, 6
-
- The "c;" should fall right under the "b +", and the
- "4, 5, 6" right under the "1, 2, 3,".
- */
- return indentOfLine(*yyLine);
- } else {
- /*
- We have
-
- stream << 1 +
- 2;
-
- We could, but we don't, try to analyze which
- operator has precedence over which and so on, to
- obtain the excellent result
-
- stream << 1 +
- 2;
-
- We do have a special trick above for the assignment
- operator above, though.
- */
- return indentOfLine(*yyLine) + ppContinuationIndentSize;
- }
- }
-
- if (!readLine())
- break;
- }
- return 0;
-}
-
-/*
- Returns the recommended indent for the bottom line of yyProgram if
- that line is standalone (or should be indented likewise).
-
- Indenting a standalone line is tricky, mostly because of braceless
- control statements. Grossly, we are looking backwards for a special
- line, a "hook line", that we can use as a starting point to indent,
- and then modify the indentation level according to the braces met
- along the way to that hook.
-
- Let's consider a few examples. In all cases, we want to indent the
- bottom line.
-
- Example 1:
-
- x = 1;
- y = 2;
-
- The hook line is "x = 1;". We met 0 opening braces and 0 closing
- braces. Therefore, "y = 2;" inherits the indent of "x = 1;".
-
- Example 2:
-
- if (x) {
- y;
-
- The hook line is "if (x) {". No matter what precedes it, "y;" has
- to be indented one level deeper than the hook line, since we met one
- opening brace along the way.
-
- Example 3:
-
- if (a)
- while (b) {
- c;
- }
- d;
-
- To indent "d;" correctly, we have to go as far as the "if (a)".
- Compare with
-
- if (a) {
- while (b) {
- c;
- }
- d;
-
- Still, we're striving to go back as little as possible to
- accommodate people with irregular indentation schemes. A hook line
- near at hand is much more reliable than a remote one.
-*/
-int QmlJSIndenter::indentForStandaloneLine()
-{
- for (int i = 0; i < SmallRoof; i++) {
- if (!*yyLeftBraceFollows) {
- YY_SAVE();
-
- if (matchBracelessControlStatement()) {
- /*
- The situation is this, and we want to indent "z;":
-
- if (x &&
- y)
- z;
-
- yyLine is "if (x &&".
- */
- return indentOfLine(*yyLine) + ppIndentSize;
- }
- YY_RESTORE();
- }
-
- if (yyLine->endsWith(QLatin1Char(';')) || yyLine->contains(QLatin1Char('{'))) {
- /*
- The situation is possibly this, and we want to indent
- "z;":
-
- while (x)
- y;
- z;
-
- We return the indent of "while (x)". In place of "y;",
- any arbitrarily complex compound statement can appear.
- */
-
- if (*yyBraceDepth > 0) {
- do {
- if (!readLine())
- break;
- } while (*yyBraceDepth > 0);
- }
-
- LinizerState hookState;
-
- while (isContinuationLine())
- readLine();
- hookState = yyLinizerState;
-
- readLine();
- if (*yyBraceDepth <= 0) {
- do {
- if (!matchBracelessControlStatement())
- break;
- hookState = yyLinizerState;
- } while (readLine());
- }
-
- yyLinizerState = hookState;
-
- while (isContinuationLine())
- readLine();
-
- int indentChange = - *yyBraceDepth;
- if (caseOrDefault.match(*yyLine).hasMatch())
- ++indentChange;
-
- /*
- Never trust lines containing only '{' or '}', as some
- people (Richard M. Stallman) format them weirdly.
- */
- if (yyLine->trimmed().length() > 1)
- return indentOfLine(*yyLine) + indentChange * ppIndentSize;
- }
-
- if (!readLine())
- return -*yyBraceDepth * ppIndentSize;
- }
- return 0;
-}
-
-/*
- Returns the recommended indent for the bottom line of program.
- Unless null, typedIn stores the character of yyProgram that
- triggered reindentation.
-
- This function works better if typedIn is set properly; it is
- slightly more conservative if typedIn is completely wild, and
- slighly more liberal if typedIn is always null. The user might be
- annoyed by the liberal behavior.
-*/
-int QmlJSIndenter::indentForBottomLine(QTextBlock begin, QTextBlock end, QChar typedIn)
-{
- if (begin == end)
- return 0;
-
- const QTextBlock last = end.previous();
-
- initialize(begin, last);
-
- QString bottomLine = last.text();
- QChar firstCh = firstNonWhiteSpace(bottomLine);
- int indent = 0;
-
- if (bottomLineStartsInMultilineComment()) {
- /*
- The bottom line starts in a C-style comment. Indent it
- smartly, unless the user has already played around with it,
- in which case it's better to leave her stuff alone.
- */
- if (isOnlyWhiteSpace(bottomLine))
- indent = indentWhenBottomLineStartsInMultiLineComment();
- else
- indent = indentOfLine(bottomLine);
- } else {
- if (isUnfinishedLine())
- indent = indentForContinuationLine();
- else
- indent = indentForStandaloneLine();
-
- if ((okay(typedIn, QLatin1Char('}')) && firstCh == QLatin1Char('}'))
- || (okay(typedIn, QLatin1Char(']')) && firstCh == QLatin1Char(']'))) {
- /*
- A closing brace is one level more to the left than the
- code it follows.
- */
- indent -= ppIndentSize;
- } else if (okay(typedIn, QLatin1Char(':'))) {
- if (caseOrDefault.match(bottomLine).hasMatch()) {
- /*
- Move a case label (or the ':' in front of a
- constructor initialization list) one level to the
- left, but only if the user did not play around with
- it yet. Some users have exotic tastes in the
- matter, and most users probably are not patient
- enough to wait for the final ':' to format their
- code properly.
-
- We don't attempt the same for goto labels, as the
- user is probably the middle of "foo::bar". (Who
- uses goto, anyway?)
- */
- if (indentOfLine(bottomLine) <= indent)
- indent -= ppIndentSize;
- else
- indent = indentOfLine(bottomLine);
- }
- }
- }
-
- return qMax(0, indent);
-}
-
diff --git a/src/libs/qmljs/qmljsindenter.h b/src/libs/qmljs/qmljsindenter.h
deleted file mode 100644
index 55141c1b3b..0000000000
--- a/src/libs/qmljs/qmljsindenter.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include <qmljs/qmljs_global.h>
-#include <qmljs/qmljslineinfo.h>
-
-#include <QRegularExpression>
-
-QT_FORWARD_DECLARE_CLASS(QTextBlock)
-
-namespace QmlJS {
-
-class QMLJS_EXPORT QmlJSIndenter : public LineInfo
-{
- Q_DISABLE_COPY(QmlJSIndenter)
-
-public:
- QmlJSIndenter();
- ~QmlJSIndenter();
-
- void setTabSize(int size);
- void setIndentSize(int size);
-
- int indentForBottomLine(QTextBlock firstBlock, QTextBlock lastBlock, QChar typedIn);
-
-private:
- bool isOnlyWhiteSpace(const QString &t) const;
- int columnForIndex(const QString &t, int index) const;
- int indentOfLine(const QString &t) const;
-
- void eraseChar(QString &t, int k, QChar ch) const;
- QChar lastParen() const;
- bool okay(QChar typedIn, QChar okayCh) const;
-
- int indentWhenBottomLineStartsInMultiLineComment();
- int indentForContinuationLine();
- int indentForStandaloneLine();
-
-private:
- int ppHardwareTabSize;
- int ppIndentSize;
- int ppContinuationIndentSize;
- int ppCommentOffset;
-
-private:
- QRegularExpression caseOrDefault;
-};
-
-} // namespace QmlJS
diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index 5d687d5cd7..09bc6aecdb 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -635,6 +635,52 @@ const CppComponentValue *QmlEnumValue::owner() const
return m_owner;
}
+UiEnumValue::UiEnumValue(AST::UiEnumDeclaration *ast,
+ ValueOwner *valueOwner, const QString &originId)
+ : ObjectValue(valueOwner, originId)
+ , m_name(ast->name.toString())
+{
+ setClassName("enum");
+ m_path = Utils::FilePath::fromUserInput(originId);
+ m_line = ast->identifierToken.startLine;
+ m_column = ast->identifierToken.startColumn;
+
+ for (auto it = ast->members; it; it = it->next) {
+ const QString name = it->member.toString();
+ setMember(name, valueOwner->intValue());
+ setPropertyInfo(name, PropertyInfo(PropertyInfo::Readable|PropertyInfo::ValueType));
+ m_keys.append(name);
+ m_values.append(it->value);
+ }
+}
+
+UiEnumValue::~UiEnumValue()
+{
+}
+
+const UiEnumValue *UiEnumValue::asUiEnumValue() const
+{
+ return this;
+}
+
+bool UiEnumValue::getSourceLocation(Utils::FilePath *path, int *line, int *column) const
+{
+ *path = m_path;
+ *line = m_line;
+ *column = m_column;
+ return true;
+}
+
+QString UiEnumValue::name() const
+{
+ return m_name;
+}
+
+QStringList UiEnumValue::keys() const
+{
+ return m_keys;
+}
+
////////////////////////////////////////////////////////////////////////////////
// ValueVisitor
////////////////////////////////////////////////////////////////////////////////
@@ -791,6 +837,11 @@ const QmlEnumValue *Value::asQmlEnumValue() const
return nullptr;
}
+const UiEnumValue *Value::asUiEnumValue() const
+{
+ return nullptr;
+}
+
const QmlPrototypeReference *Value::asQmlPrototypeReference() const
{
return nullptr;
diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h
index 8651196aef..aeb3c9e438 100644
--- a/src/libs/qmljs/qmljsinterpreter.h
+++ b/src/libs/qmljs/qmljsinterpreter.h
@@ -44,6 +44,7 @@ class NumberValue;
class ModuleApiInfo;
class ObjectValue;
class QmlEnumValue;
+class UiEnumValue;
class QmlPrototypeReference;
class RealValue;
class Reference;
@@ -115,6 +116,7 @@ public:
virtual const CppComponentValue *asCppComponentValue() const;
virtual const ASTObjectValue *asAstObjectValue() const;
virtual const QmlEnumValue *asQmlEnumValue() const;
+ virtual const UiEnumValue *asUiEnumValue() const;
virtual const QmlPrototypeReference *asQmlPrototypeReference() const;
virtual const ASTPropertyReference *asAstPropertyReference() const;
virtual const ASTVariableReference *asAstVariableReference() const;
@@ -246,6 +248,12 @@ template <> Q_INLINE_TEMPLATE const QmlEnumValue *value_cast(const Value *v)
else return nullptr;
}
+template <> Q_INLINE_TEMPLATE const UiEnumValue *value_cast(const Value *v)
+{
+ if (v) return v->asUiEnumValue();
+ else return nullptr;
+}
+
template <> Q_INLINE_TEMPLATE const QmlPrototypeReference *value_cast(const Value *v)
{
if (v) return v->asQmlPrototypeReference();
@@ -559,6 +567,27 @@ private:
int m_enumIndex;
};
+class QMLJS_EXPORT UiEnumValue : public ObjectValue
+{
+public:
+ UiEnumValue(AST::UiEnumDeclaration *uiEnum, ValueOwner *valueOwner,
+ const QString &originId);
+ ~UiEnumValue();
+
+ const UiEnumValue *asUiEnumValue() const override;
+ bool getSourceLocation(Utils::FilePath *path, int *line, int *column) const override;
+ QString name() const;
+ QStringList keys() const;
+
+private:
+ const QString m_name;
+ Utils::FilePath m_path;
+ int m_line;
+ int m_column;
+ QStringList m_keys;
+ QList<int> m_values;
+};
+
// A ObjectValue based on a FakeMetaObject.
// May only have other CppComponentValue as ancestors.
diff --git a/src/libs/qmljs/qmljsstaticanalysismessage.cpp b/src/libs/qmljs/qmljsstaticanalysismessage.cpp
index 5b15e69428..432b97aba7 100644
--- a/src/libs/qmljs/qmljsstaticanalysismessage.cpp
+++ b/src/libs/qmljs/qmljsstaticanalysismessage.cpp
@@ -189,8 +189,9 @@ StaticAnalysisMessages::StaticAnalysisMessages()
Tr::tr("Maximum string value length is %1."), 1);
newMsg(ErrInvalidArrayValueLength, Error,
Tr::tr("%1 elements expected in array value."), 1);
- newMsg(WarnImperativeCodeNotEditableInVisualDesigner, Warning,
- Tr::tr("Imperative code is not supported in Qt Design Studio."));
+ newMsg(WarnImperativeCodeNotEditableInVisualDesigner,
+ Warning,
+ Tr::tr("JavaScript can break the visual tooling in Qt Design Studio."));
newMsg(WarnUnsupportedTypeInVisualDesigner, Warning,
Tr::tr("This type (%1) is not supported in Qt Design Studio."), 1);
newMsg(WarnReferenceToParentItemNotSupportedByVisualDesigner, Warning,
diff --git a/src/libs/qmlpuppetcommunication/container/imagecontainer.cpp b/src/libs/qmlpuppetcommunication/container/imagecontainer.cpp
index 545d4d927d..7747a9d118 100644
--- a/src/libs/qmlpuppetcommunication/container/imagecontainer.cpp
+++ b/src/libs/qmlpuppetcommunication/container/imagecontainer.cpp
@@ -15,7 +15,7 @@
#define QTC_ASSERT_STRING(cond) qDebug("SOFT ASSERT: \"" cond"\" in file " __FILE__ ", line " QTC_ASSERT_STRINGIFY(__LINE__))
#define QTC_ASSERT(cond, action) if (cond) {} else { QTC_ASSERT_STRING(#cond); action; } do {} while (0)
-static Q_LOGGING_CATEGORY(imageContainerDebug, "qtc.imagecontainer.debug", QtDebugMsg)
+static Q_LOGGING_CATEGORY(imageContainerDebug, "qtc.imagecontainer")
namespace QmlDesigner {
@@ -194,9 +194,10 @@ static void readSharedMemory(qint32 key, ImageContainer &container)
QImage image = QImage(imageWidth, imageHeight, QImage::Format(imageFormat));
image.setDevicePixelRatio(pixelRatio);
- if (image.isNull())
- qCInfo(imageContainerDebug()) << Q_FUNC_INFO << "Not able to create image:" << imageWidth << imageHeight << imageFormat;
- else
+ if (image.isNull()) {
+ if (imageWidth || imageHeight || imageFormat)
+ qCWarning(imageContainerDebug) << Q_FUNC_INFO << "Not able to create image:" << imageWidth << imageHeight << imageFormat;
+ } else
std::memcpy(image.bits(), reinterpret_cast<const qint32*>(sharedMemory.constData()) + 6, byteCount);
container.setImage(image);
diff --git a/src/libs/qtcreatorcdbext/pyvalue.cpp b/src/libs/qtcreatorcdbext/pyvalue.cpp
index f3813abf85..671f4d5350 100644
--- a/src/libs/qtcreatorcdbext/pyvalue.cpp
+++ b/src/libs/qtcreatorcdbext/pyvalue.cpp
@@ -13,8 +13,23 @@ constexpr bool debuggingValueEnabled() { return debugPyValue || debugPyCdbextMod
static std::map<CIDebugSymbolGroup *, std::list<PyValue *>> valuesForSymbolGroup;
+void dumpSymbolGroup(CIDebugSymbolGroup *symbolGroup)
+{
+ if (!debuggingValueEnabled())
+ return;
+
+ ULONG count;
+ if (FAILED(symbolGroup->GetNumberSymbols(&count)))
+ return;
+ DebugPrint() << "Symbol group " << symbolGroup << " has " << count << " symbols";
+ for (ULONG i = 0; i < count; ++i)
+ DebugPrint() << " " << i << ": " << PyValue(i, symbolGroup).name();
+}
+
void PyValue::indicesMoved(CIDebugSymbolGroup *symbolGroup, ULONG start, ULONG delta)
{
+ if (debuggingValueEnabled())
+ DebugPrint() << "PyValue::indicesMoved " << symbolGroup << " start " << start << " delta " << delta << "\n";
if (delta == 0)
return;
ULONG count;
@@ -26,6 +41,7 @@ void PyValue::indicesMoved(CIDebugSymbolGroup *symbolGroup, ULONG start, ULONG d
if (val->m_index >= start && val->m_index + delta < count)
val->m_index += delta;
}
+ dumpSymbolGroup(symbolGroup);
}
PyValue::PyValue(unsigned long index, CIDebugSymbolGroup *symbolGroup)
@@ -146,6 +162,7 @@ bool PyValue::expand()
return false;
if (params.Flags & DEBUG_SYMBOL_EXPANDED)
return true;
+ dumpSymbolGroup(m_symbolGroup);
if (FAILED(m_symbolGroup->ExpandSymbol(m_index, TRUE)))
return false;
if (FAILED(m_symbolGroup->GetSymbolParameters(m_index, 1, &params)))
diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp
index 7d37bf9758..107559d6a5 100644
--- a/src/libs/solutions/tasking/tasktree.cpp
+++ b/src/libs/solutions/tasking/tasktree.cpp
@@ -3,6 +3,8 @@
#include "tasktree.h"
+#include "barrier.h"
+
#include <QDebug>
#include <QEventLoop>
#include <QFutureWatcher>
@@ -882,6 +884,20 @@ private:
*/
/*!
+ \variable parallelIdealThreadCountLimit
+ A convenient global group's element describing the parallel execution mode with a limited
+ number of tasks running simultanously. The limit is equal to the ideal number of threads
+ excluding the calling thread.
+
+ This is a shortcut to:
+ \code
+ parallelLimit(qMax(QThread::idealThreadCount() - 1, 1))
+ \endcode
+
+ \sa parallel, parallelLimit()
+*/
+
+/*!
\variable stopOnError
A convenient global group's element describing the StopOnError workflow policy.
@@ -1161,6 +1177,7 @@ const GroupItem nullItem = GroupItem({});
const GroupItem sequential = parallelLimit(1);
const GroupItem parallel = parallelLimit(0);
+const GroupItem parallelIdealThreadCountLimit = parallelLimit(qMax(QThread::idealThreadCount() - 1, 1));
const GroupItem stopOnError = workflowPolicy(WorkflowPolicy::StopOnError);
const GroupItem continueOnError = workflowPolicy(WorkflowPolicy::ContinueOnError);
@@ -1473,6 +1490,23 @@ ExecutableItem ExecutableItem::withLog(const QString &logName) const
};
}
+ExecutableItem ExecutableItem::withCancelImpl(
+ const std::function<void(QObject *, const std::function<void()> &)> &connectWrapper) const
+{
+ const auto onSetup = [connectWrapper](Barrier &barrier) {
+ connectWrapper(&barrier, [barrierPtr = &barrier] { barrierPtr->advance(); });
+ };
+ return Group {
+ parallel,
+ stopOnSuccessOrError,
+ Group {
+ finishAllAndError,
+ BarrierTask(onSetup)
+ },
+ *this
+ };
+}
+
class TaskTreePrivate;
class TaskNode;
class RuntimeContainer;
diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h
index 8ea255303b..9b1e4b9eaf 100644
--- a/src/libs/solutions/tasking/tasktree.h
+++ b/src/libs/solutions/tasking/tasktree.h
@@ -187,7 +187,7 @@ public:
}
private:
- static StorageConstructor ctor() { return [] { return new StorageStruct; }; }
+ static StorageConstructor ctor() { return [] { return new StorageStruct(); }; }
static StorageDestructor dtor() {
return [](void *storage) { delete static_cast<StorageStruct *>(storage); };
}
@@ -290,10 +290,25 @@ public:
ExecutableItem withTimeout(std::chrono::milliseconds timeout,
const std::function<void()> &handler = {}) const;
ExecutableItem withLog(const QString &logName) const;
+ template <typename SenderSignalPairGetter>
+ ExecutableItem withCancel(SenderSignalPairGetter &&getter) const
+ {
+ const auto connectWrapper = [getter](QObject *guard, const std::function<void()> &trigger) {
+ const auto senderSignalPair = getter();
+ QObject::connect(senderSignalPair.first, senderSignalPair.second, guard, [trigger] {
+ trigger();
+ }, static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::SingleShotConnection));
+ };
+ return withCancelImpl(connectWrapper);
+ }
protected:
ExecutableItem() = default;
ExecutableItem(const TaskHandler &handler) : GroupItem(handler) {}
+
+private:
+ ExecutableItem withCancelImpl(
+ const std::function<void(QObject *, const std::function<void()> &)> &connectWrapper) const;
};
class TASKING_EXPORT Group : public ExecutableItem
@@ -375,6 +390,7 @@ TASKING_EXPORT extern const GroupItem nullItem;
TASKING_EXPORT extern const GroupItem sequential;
TASKING_EXPORT extern const GroupItem parallel;
+TASKING_EXPORT extern const GroupItem parallelIdealThreadCountLimit;
TASKING_EXPORT extern const GroupItem stopOnError;
TASKING_EXPORT extern const GroupItem continueOnError;
diff --git a/src/libs/sqlite/CMakeLists.txt b/src/libs/sqlite/CMakeLists.txt
index 2c7e1ebbf3..f86f31871a 100644
--- a/src/libs/sqlite/CMakeLists.txt
+++ b/src/libs/sqlite/CMakeLists.txt
@@ -31,7 +31,7 @@ endif()
add_qtc_library(Sqlite
PROPERTIES AUTOMOC OFF AUTOUIC OFF
- DEPENDS Qt::Core Threads::Threads ${CMAKE_DL_LIBS} SqliteInternal
+ DEPENDS Qt::Core Threads::Threads ${CMAKE_DL_LIBS} SqliteInternal Nanotrace
INCLUDES
../3rdparty/sqlite
PUBLIC_INCLUDES
@@ -58,7 +58,7 @@ add_qtc_library(Sqlite
sqlitesessionchangeset.cpp sqlitesessionchangeset.h
sqlitesessions.cpp sqlitesessions.h
sqlitetable.h
- sqlitetransaction.h
+ sqlitetracing.cpp sqlitetracing.h
sqlitetransaction.h
sqlitevalue.h
sqlitewritestatement.h
diff --git a/src/libs/sqlite/sqlitebasestatement.cpp b/src/libs/sqlite/sqlitebasestatement.cpp
index 23466c0cea..8557bf6ad2 100644
--- a/src/libs/sqlite/sqlitebasestatement.cpp
+++ b/src/libs/sqlite/sqlitebasestatement.cpp
@@ -26,32 +26,7 @@ extern "C" int sqlite3_carray_bind(
namespace Sqlite {
-namespace {
-using TraceFile = NanotraceHR::TraceFile<sqliteTracingStatus()>;
-
-TraceFile traceFile{"sqlite.json"};
-
-thread_local NanotraceHR::EventQueueData<NanotraceHR::StringViewTraceEvent, 10000, sqliteTracingStatus()>
- eventQueueData(traceFile);
-
-NanotraceHR::StringViewCategory<sqliteTracingStatus()> &sqliteLowLevelCategory();
-
-thread_local NanotraceHR::StringViewCategory<sqliteTracingStatus()> sqliteLowLevelCategory_{
- "sqlite low level"_t, eventQueueData, sqliteLowLevelCategory};
-
-NanotraceHR::StringViewCategory<sqliteTracingStatus()> &sqliteLowLevelCategory()
-{
- return sqliteLowLevelCategory_;
-}
-
-thread_local NanotraceHR::StringViewCategory<sqliteTracingStatus()> sqliteHighLevelCategory_{
- "sqlite high level"_t, eventQueueData, sqliteHighLevelCategory};
-} // namespace
-
-NanotraceHR::StringViewCategory<sqliteTracingStatus()> &sqliteHighLevelCategory()
-{
- return sqliteHighLevelCategory_;
-}
+using NanotraceHR::keyValue;
BaseStatement::BaseStatement(Utils::SmallStringView sqlStatement, Database &database)
: m_database(database)
@@ -107,14 +82,18 @@ void BaseStatement::waitForUnlockNotify() const
void BaseStatement::reset() const noexcept
{
- NanotraceHR::Tracer tracer{"reset"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"reset"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle())};
sqlite3_reset(m_compiledStatement.get());
}
bool BaseStatement::next() const
{
- NanotraceHR::Tracer tracer{"next"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"next"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle())};
int resultCode;
do {
@@ -141,7 +120,10 @@ void BaseStatement::step() const
void BaseStatement::bindNull(int index)
{
- NanotraceHR::Tracer tracer{"bind null"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"bind null"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("index", index)};
int resultCode = sqlite3_bind_null(m_compiledStatement.get(), index);
if (resultCode != SQLITE_OK)
@@ -155,7 +137,11 @@ void BaseStatement::bind(int index, NullValue)
void BaseStatement::bind(int index, int value)
{
- NanotraceHR::Tracer tracer{"bind int"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"bind int"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("index", index),
+ keyValue("value", value)};
int resultCode = sqlite3_bind_int(m_compiledStatement.get(), index, value);
if (resultCode != SQLITE_OK)
@@ -164,7 +150,11 @@ void BaseStatement::bind(int index, int value)
void BaseStatement::bind(int index, long long value)
{
- NanotraceHR::Tracer tracer{"bind long long"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"bind long long"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("index", index),
+ keyValue("value", value)};
int resultCode = sqlite3_bind_int64(m_compiledStatement.get(), index, value);
if (resultCode != SQLITE_OK)
@@ -173,7 +163,11 @@ void BaseStatement::bind(int index, long long value)
void BaseStatement::bind(int index, double value)
{
- NanotraceHR::Tracer tracer{"bind double"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"bind double"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("index", index),
+ keyValue("value", value)};
int resultCode = sqlite3_bind_double(m_compiledStatement.get(), index, value);
if (resultCode != SQLITE_OK)
@@ -182,7 +176,11 @@ void BaseStatement::bind(int index, double value)
void BaseStatement::bind(int index, void *pointer)
{
- NanotraceHR::Tracer tracer{"bind pointer"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"bind pointer"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("index", index),
+ keyValue("pointer", reinterpret_cast<std::uintptr_t>(pointer))};
int resultCode = sqlite3_bind_pointer(m_compiledStatement.get(), index, pointer, "carray", nullptr);
if (resultCode != SQLITE_OK)
@@ -191,7 +189,12 @@ void BaseStatement::bind(int index, void *pointer)
void BaseStatement::bind(int index, Utils::span<const int> values)
{
- NanotraceHR::Tracer tracer{"bind int span"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"bind int span"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("index", index),
+ keyValue("pointer", reinterpret_cast<std::uintptr_t>(values.data())),
+ keyValue("size", values.size())};
int resultCode = sqlite3_carray_bind(m_compiledStatement.get(),
index,
@@ -205,7 +208,12 @@ void BaseStatement::bind(int index, Utils::span<const int> values)
void BaseStatement::bind(int index, Utils::span<const long long> values)
{
- NanotraceHR::Tracer tracer{"bind long long span"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"bind long long span"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("index", index),
+ keyValue("pointer", reinterpret_cast<std::uintptr_t>(values.data())),
+ keyValue("size", values.size())};
int resultCode = sqlite3_carray_bind(m_compiledStatement.get(),
index,
@@ -219,7 +227,12 @@ void BaseStatement::bind(int index, Utils::span<const long long> values)
void BaseStatement::bind(int index, Utils::span<const double> values)
{
- NanotraceHR::Tracer tracer{"bind double span"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"bind double span"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("index", index),
+ keyValue("pointer", reinterpret_cast<std::uintptr_t>(values.data())),
+ keyValue("size", values.size())};
int resultCode = sqlite3_carray_bind(m_compiledStatement.get(),
index,
@@ -233,7 +246,12 @@ void BaseStatement::bind(int index, Utils::span<const double> values)
void BaseStatement::bind(int index, Utils::span<const char *> values)
{
- NanotraceHR::Tracer tracer{"bind const char* span"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"bind const char* span"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("index", index),
+ keyValue("pointer", reinterpret_cast<std::uintptr_t>(values.data())),
+ keyValue("size", values.size())};
int resultCode = sqlite3_carray_bind(m_compiledStatement.get(),
index,
@@ -247,7 +265,11 @@ void BaseStatement::bind(int index, Utils::span<const char *> values)
void BaseStatement::bind(int index, Utils::SmallStringView text)
{
- NanotraceHR::Tracer tracer{"bind string"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"bind string"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("index", index),
+ keyValue("text", text)};
int resultCode = sqlite3_bind_text(m_compiledStatement.get(),
index,
@@ -260,7 +282,12 @@ void BaseStatement::bind(int index, Utils::SmallStringView text)
void BaseStatement::bind(int index, BlobView blobView)
{
- NanotraceHR::Tracer tracer{"bind blob"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"bind blob"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("index", index),
+ keyValue("pointer", reinterpret_cast<std::uintptr_t>(blobView.data())),
+ keyValue("size", blobView.size())};
int resultCode = SQLITE_OK;
@@ -280,7 +307,11 @@ void BaseStatement::bind(int index, BlobView blobView)
void BaseStatement::bind(int index, const Value &value)
{
- NanotraceHR::Tracer tracer{"bind value"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{
+ "bind value"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ };
switch (value.type()) {
case ValueType::Integer:
@@ -303,7 +334,11 @@ void BaseStatement::bind(int index, const Value &value)
void BaseStatement::bind(int index, ValueView value)
{
- NanotraceHR::Tracer tracer{"bind value"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{
+ "bind value"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ };
switch (value.type()) {
case ValueType::Integer:
@@ -326,7 +361,9 @@ void BaseStatement::bind(int index, ValueView value)
void BaseStatement::prepare(Utils::SmallStringView sqlStatement)
{
- NanotraceHR::Tracer tracer{"prepare"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"prepare"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sql statement", sqlStatement)};
if (!m_database.isLocked())
throw DatabaseIsNotLocked{};
@@ -342,14 +379,18 @@ void BaseStatement::prepare(Utils::SmallStringView sqlStatement)
nullptr);
m_compiledStatement.reset(sqliteStatement);
- if (resultCode == SQLITE_LOCKED)
+ if (resultCode == SQLITE_LOCKED) {
+ tracer.tick("wait for unlock"_t);
waitForUnlockNotify();
+ }
} while (resultCode == SQLITE_LOCKED);
if (resultCode != SQLITE_OK)
Sqlite::throwError(resultCode, sqliteDatabaseHandle());
+
+ tracer.end(keyValue("sqlite statement", handle()));
}
sqlite3 *BaseStatement::sqliteDatabaseHandle() const
@@ -427,7 +468,10 @@ StringType convertToTextForColumn(sqlite3_stmt *sqlStatment, int column)
Type BaseStatement::fetchType(int column) const
{
- NanotraceHR::Tracer tracer{"fetch type"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"fetch type"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("column", column)};
auto dataType = sqlite3_column_type(m_compiledStatement.get(), column);
@@ -449,9 +493,16 @@ Type BaseStatement::fetchType(int column) const
int BaseStatement::fetchIntValue(int column) const
{
- NanotraceHR::Tracer tracer{"fetch int"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"fetch int"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("column", column)};
+
+ auto value = sqlite3_column_int(m_compiledStatement.get(), column);
- return sqlite3_column_int(m_compiledStatement.get(), column);
+ tracer.end(keyValue("value", value));
+
+ return value;
}
template<>
@@ -473,9 +524,16 @@ long BaseStatement::fetchValue<long>(int column) const
long long BaseStatement::fetchLongLongValue(int column) const
{
- NanotraceHR::Tracer tracer{"fetch long long"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"fetch long long"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("column", column)};
+
+ auto value = sqlite3_column_int64(m_compiledStatement.get(), column);
- return sqlite3_column_int64(m_compiledStatement.get(), column);
+ tracer.end(keyValue("value", value));
+
+ return value;
}
template<>
@@ -486,14 +544,24 @@ long long BaseStatement::fetchValue<long long>(int column) const
double BaseStatement::fetchDoubleValue(int column) const
{
- NanotraceHR::Tracer tracer{"fetch double"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"fetch double"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("column", column)};
+
+ auto value = sqlite3_column_double(m_compiledStatement.get(), column);
+
+ tracer.end(keyValue("value", value));
- return sqlite3_column_double(m_compiledStatement.get(), column);
+ return value;
}
BlobView BaseStatement::fetchBlobValue(int column) const
{
- NanotraceHR::Tracer tracer{"fetch blob"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{"fetch blob"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("column", column)};
return convertToBlobForColumn(m_compiledStatement.get(), column);
}
@@ -507,7 +575,16 @@ double BaseStatement::fetchValue<double>(int column) const
template<typename StringType>
StringType BaseStatement::fetchValue(int column) const
{
- return convertToTextForColumn<StringType>(m_compiledStatement.get(), column);
+ NanotraceHR::Tracer tracer{"fetch string value"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("column", column)};
+
+ auto text = convertToTextForColumn<StringType>(m_compiledStatement.get(), column);
+
+ tracer.end(keyValue("text", text));
+
+ return text;
}
template SQLITE_EXPORT Utils::SmallStringView BaseStatement::fetchValue<Utils::SmallStringView>(
@@ -519,11 +596,25 @@ template SQLITE_EXPORT Utils::PathString BaseStatement::fetchValue<Utils::PathSt
Utils::SmallStringView BaseStatement::fetchSmallStringViewValue(int column) const
{
- return fetchValue<Utils::SmallStringView>(column);
+ NanotraceHR::Tracer tracer{"fetch string view"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("column", column)};
+
+ auto text = fetchValue<Utils::SmallStringView>(column);
+
+ tracer.end(keyValue("text", text));
+
+ return text;
}
ValueView BaseStatement::fetchValueView(int column) const
{
+ NanotraceHR::Tracer tracer{"fetch value view"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", handle()),
+ keyValue("column", column)};
+
int dataType = sqlite3_column_type(m_compiledStatement.get(), column);
switch (dataType) {
case SQLITE_NULL:
@@ -543,7 +634,11 @@ ValueView BaseStatement::fetchValueView(int column) const
void BaseStatement::Deleter::operator()(sqlite3_stmt *statement)
{
- NanotraceHR::Tracer tracer{"finalize"_t, sqliteLowLevelCategory()};
+ NanotraceHR::Tracer tracer{
+ "finalize"_t,
+ sqliteLowLevelCategory(),
+ keyValue("sqlite statement", reinterpret_cast<std::uintptr_t>(statement)),
+ };
sqlite3_finalize(statement);
}
diff --git a/src/libs/sqlite/sqlitebasestatement.h b/src/libs/sqlite/sqlitebasestatement.h
index d2306c67a5..3710021ff5 100644
--- a/src/libs/sqlite/sqlitebasestatement.h
+++ b/src/libs/sqlite/sqlitebasestatement.h
@@ -9,6 +9,7 @@
#include "sqliteblob.h"
#include "sqliteexception.h"
#include "sqliteids.h"
+#include "sqlitetracing.h"
#include "sqlitetransaction.h"
#include "sqlitevalue.h"
@@ -30,8 +31,6 @@ using std::int64_t;
namespace Sqlite {
-using namespace NanotraceHR::Literals;
-
class Database;
class DatabaseBackend;
@@ -44,17 +43,6 @@ constexpr static std::underlying_type_t<Enumeration> to_underlying(Enumeration e
return static_cast<std::underlying_type_t<Enumeration>>(enumeration);
}
-constexpr NanotraceHR::Tracing sqliteTracingStatus()
-{
-#ifdef ENABLE_SQLITE_TRACING
- return NanotraceHR::tracingStatus();
-#else
- return NanotraceHR::Tracing::IsDisabled;
-#endif
-}
-
-SQLITE_EXPORT NanotraceHR::StringViewCategory<sqliteTracingStatus()> &sqliteHighLevelCategory();
-
class SQLITE_EXPORT BaseStatement
{
public:
@@ -136,6 +124,11 @@ public:
protected:
~BaseStatement() = default;
+ std::uintptr_t handle() const
+ {
+ return reinterpret_cast<std::uintptr_t>(m_compiledStatement.get());
+ }
+
private:
struct Deleter
{
@@ -166,7 +159,12 @@ public:
void execute()
{
- NanotraceHR::Tracer tracer{"execute"_t, sqliteHighLevelCategory()};
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{
+ "execute"_t,
+ sqliteHighLevelCategory(),
+ keyValue("sqlite statement", BaseStatement::handle()),
+ };
Resetter resetter{this};
BaseStatement::next();
@@ -175,7 +173,10 @@ public:
template<typename... ValueType>
void bindValues(const ValueType &...values)
{
- NanotraceHR::Tracer tracer{"bind"_t, sqliteHighLevelCategory()};
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"bind"_t,
+ sqliteHighLevelCategory(),
+ keyValue("sqlite statement", BaseStatement::handle())};
static_assert(BindParameterCount == sizeof...(values), "Wrong binding parameter count!");
@@ -186,7 +187,10 @@ public:
template<typename... ValueType>
void write(const ValueType&... values)
{
- NanotraceHR::Tracer tracer{"write"_t, sqliteHighLevelCategory()};
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"write"_t,
+ sqliteHighLevelCategory(),
+ keyValue("sqlite statement", BaseStatement::handle())};
Resetter resetter{this};
bindValues(values...);
@@ -206,24 +210,37 @@ public:
struct is_container<QVarLengthArray<T, Prealloc>> : std::true_type
{};
+ template<typename T>
+ struct is_small_container : std::false_type
+ {};
+
+ template<typename T, qsizetype Prealloc>
+ struct is_small_container<QVarLengthArray<T, Prealloc>> : std::true_type
+ {};
+
template<typename Container,
std::size_t capacity = 32,
typename = std::enable_if_t<is_container<Container>::value>,
typename... QueryTypes>
auto values(const QueryTypes &...queryValues)
{
- NanotraceHR::Tracer tracer{"values"_t, sqliteHighLevelCategory()};
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"values"_t,
+ sqliteHighLevelCategory(),
+ keyValue("sqlite statement", BaseStatement::handle())};
Resetter resetter{this};
Container resultValues;
- resultValues.reserve(std::max(capacity, m_maximumResultCount));
+ using size_tupe = typename Container::size_type;
+ if constexpr (!is_small_container<Container>::value)
+ resultValues.reserve(static_cast<size_tupe>(std::max(capacity, m_maximumResultCount)));
bindValues(queryValues...);
while (BaseStatement::next())
emplaceBackValues(resultValues);
- setMaximumResultCount(resultValues.size());
+ setMaximumResultCount(static_cast<std::size_t>(resultValues.size()));
return resultValues;
}
@@ -241,7 +258,10 @@ public:
template<typename ResultType, typename... QueryTypes>
auto value(const QueryTypes &...queryValues)
{
- NanotraceHR::Tracer tracer{"value"_t, sqliteHighLevelCategory()};
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"value"_t,
+ sqliteHighLevelCategory(),
+ keyValue("sqlite statement", BaseStatement::handle())};
Resetter resetter{this};
ResultType resultValue{};
@@ -257,7 +277,10 @@ public:
template<typename ResultType, typename... QueryTypes>
auto optionalValue(const QueryTypes &...queryValues)
{
- NanotraceHR::Tracer tracer{"optionalValue"_t, sqliteHighLevelCategory()};
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"optionalValue"_t,
+ sqliteHighLevelCategory(),
+ keyValue("sqlite statement", BaseStatement::handle())};
Resetter resetter{this};
std::optional<ResultType> resultValue;
@@ -273,6 +296,7 @@ public:
template<typename Type>
static auto toValue(Utils::SmallStringView sqlStatement, Database &database)
{
+ using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"toValue"_t, sqliteHighLevelCategory()};
StatementImplementation statement(sqlStatement, database);
@@ -287,7 +311,10 @@ public:
template<typename Callable, typename... QueryTypes>
void readCallback(Callable &&callable, const QueryTypes &...queryValues)
{
- NanotraceHR::Tracer tracer{"readCallback"_t, sqliteHighLevelCategory()};
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"readCallback"_t,
+ sqliteHighLevelCategory(),
+ keyValue("sqlite statement", BaseStatement::handle())};
Resetter resetter{this};
@@ -304,7 +331,10 @@ public:
template<typename Container, typename... QueryTypes>
void readTo(Container &container, const QueryTypes &...queryValues)
{
- NanotraceHR::Tracer tracer{"readTo"_t, sqliteHighLevelCategory()};
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"readTo"_t,
+ sqliteHighLevelCategory(),
+ keyValue("sqlite statement", BaseStatement::handle())};
Resetter resetter{this};
@@ -402,9 +432,11 @@ public:
private:
using TracerCategory = std::decay_t<decltype(sqliteHighLevelCategory())>;
- NanotraceHR::Tracer<TracerCategory, typename TracerCategory::IsActive> tracer{
- "range"_t, sqliteHighLevelCategory()};
StatementImplementation &m_statement;
+ NanotraceHR::Tracer<TracerCategory, typename TracerCategory::IsActive> tracer{
+ "range"_t,
+ sqliteHighLevelCategory(),
+ NanotraceHR::keyValue("sqlite statement", m_statement.handle())};
};
template<typename ResultType>
diff --git a/src/libs/sqlite/sqliteexception.cpp b/src/libs/sqlite/sqliteexception.cpp
index b5f581ad68..bb4a474adb 100644
--- a/src/libs/sqlite/sqliteexception.cpp
+++ b/src/libs/sqlite/sqliteexception.cpp
@@ -3,14 +3,20 @@
#include "sqliteexception.h"
+#include "sqlitetracing.h"
+
#include <utils/smallstringio.h>
+#include <nanotrace/nanotracehr.h>
+
#include <sqlite.h>
#include <QDebug>
namespace Sqlite {
+using NanotraceHR::keyValue;
+
const char *Exception::what() const noexcept
{
return "Sqlite::Exception";
@@ -18,7 +24,10 @@ const char *Exception::what() const noexcept
const char *ExceptionWithMessage::what() const noexcept
{
- return "Sqlite::ExceptionWithMessage";
+ static Utils::SmallString text = Utils::SmallString::join(
+ {"Sqlite::ExceptionWithMessage", m_sqliteErrorMessage});
+
+ return text.data();
}
void ExceptionWithMessage::printWarning() const
@@ -26,6 +35,13 @@ void ExceptionWithMessage::printWarning() const
qWarning() << what() << m_sqliteErrorMessage;
}
+StatementIsBusy::StatementIsBusy(Utils::SmallString &&sqliteErrorMessage)
+ : ExceptionWithMessage{std::move(sqliteErrorMessage)}
+{
+ sqliteHighLevelCategory().threadEvent("StatementIsBusy"_t,
+ keyValue("error message", std::string_view{what()}));
+}
+
const char *StatementIsBusy::what() const noexcept
{
return "Sqlite::StatementIsBusy";
@@ -36,9 +52,19 @@ const char *DatabaseIsBusy::what() const noexcept
return "Sqlite::DatabaseIsBusy";
}
+StatementHasError::StatementHasError(Utils::SmallString &&sqliteErrorMessage)
+ : ExceptionWithMessage{std::move(sqliteErrorMessage)}
+{
+ sqliteHighLevelCategory().threadEvent("StatementHasError"_t,
+ keyValue("error message", std::string_view{what()}));
+}
+
const char *StatementHasError::what() const noexcept
{
- return "Sqlite::StatementHasError";
+ static Utils::SmallString text = Utils::SmallString::join(
+ {"Sqlite::StatementHasError: ", message()});
+
+ return text.data();
}
const char *StatementIsMisused::what() const noexcept
diff --git a/src/libs/sqlite/sqliteexception.h b/src/libs/sqlite/sqliteexception.h
index f0cadfc748..17a0639e19 100644
--- a/src/libs/sqlite/sqliteexception.h
+++ b/src/libs/sqlite/sqliteexception.h
@@ -23,13 +23,15 @@ public:
class SQLITE_EXPORT ExceptionWithMessage : public Exception
{
public:
- ExceptionWithMessage(Utils::SmallString &&sqliteErrorMessage = Utils::SmallString{})
+ ExceptionWithMessage(Utils::SmallString &&sqliteErrorMessage = {})
: m_sqliteErrorMessage(std::move(sqliteErrorMessage))
{}
const char *what() const noexcept override;
void printWarning() const;
+ std::string_view message() const noexcept { return m_sqliteErrorMessage; }
+
private:
Utils::SmallString m_sqliteErrorMessage;
};
@@ -37,7 +39,7 @@ private:
class SQLITE_EXPORT StatementIsBusy : public ExceptionWithMessage
{
public:
- using ExceptionWithMessage::ExceptionWithMessage;
+ StatementIsBusy(Utils::SmallString &&sqliteErrorMessage);
const char *what() const noexcept override;
};
@@ -90,7 +92,8 @@ public:
class SQLITE_EXPORT StatementHasError : public ExceptionWithMessage
{
public:
- using ExceptionWithMessage::ExceptionWithMessage;
+ StatementHasError(Utils::SmallString &&sqliteErrorMessage);
+
const char *what() const noexcept override;
};
diff --git a/src/libs/sqlite/sqliteids.h b/src/libs/sqlite/sqliteids.h
index d64e4d9645..1ffd546d9f 100644
--- a/src/libs/sqlite/sqliteids.h
+++ b/src/libs/sqlite/sqliteids.h
@@ -5,6 +5,7 @@
#include <utils/span.h>
+#include <nanotrace/nanotracehr.h>
#include <type_traits>
#include <vector>
@@ -64,6 +65,15 @@ public:
[[noreturn, deprecated]] InternalIntegerType operator&() const { throw std::exception{}; }
+ template<typename String>
+ friend void convertToString(String &string, BasicId id)
+ {
+ if (id.isValid())
+ NanotraceHR::convertToString(string, id.internalId());
+ else
+ NanotraceHR::convertToString(string, "invalid");
+ }
+
private:
InternalIntegerType id = 0;
};
@@ -88,4 +98,5 @@ struct hash<Sqlite::BasicId<Type, InternalIntegerType>>
return std::hash<InternalIntegerType>{}(id.internalId());
}
};
+
} // namespace std
diff --git a/src/libs/sqlite/sqliteindex.h b/src/libs/sqlite/sqliteindex.h
index f320fcd599..7c7a8dbb2b 100644
--- a/src/libs/sqlite/sqliteindex.h
+++ b/src/libs/sqlite/sqliteindex.h
@@ -40,6 +40,8 @@ public:
return Utils::SmallString::join({"CREATE ",
m_indexType == IndexType::Unique ? "UNIQUE " : "",
"INDEX IF NOT EXISTS index_",
+ kindName(),
+ "_",
m_tableName,
"_",
m_columnNames.join("_"),
@@ -65,6 +67,23 @@ public:
}
private:
+ std::string_view kindName() const
+ {
+ using namespace std::string_view_literals;
+
+ if (m_indexType == IndexType::Unique && m_condition.hasContent())
+ return "unique_partial"sv;
+
+ if (m_indexType == IndexType::Unique)
+ return "unique"sv;
+
+ if (m_condition.hasContent())
+ return "partial"sv;
+
+ return "normal"sv;
+ }
+
+private:
Utils::SmallString m_tableName;
Utils::SmallStringVector m_columnNames;
IndexType m_indexType;
diff --git a/src/libs/sqlite/sqlitetracing.cpp b/src/libs/sqlite/sqlitetracing.cpp
new file mode 100644
index 0000000000..700546f146
--- /dev/null
+++ b/src/libs/sqlite/sqlitetracing.cpp
@@ -0,0 +1,38 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "sqlitetracing.h"
+
+namespace Sqlite {
+
+TraceFile &traceFile()
+{
+ static TraceFile traceFile{"tracing.json"};
+
+ return traceFile;
+}
+
+namespace {
+
+thread_local NanotraceHR::EventQueue<NanotraceHR::StringViewWithStringArgumentsTraceEvent,
+ sqliteTracingStatus()>
+ eventQueue(traceFile());
+
+} // namespace
+
+NanotraceHR::StringViewWithStringArgumentsCategory<sqliteTracingStatus()> &sqliteLowLevelCategory()
+{
+ thread_local NanotraceHR::StringViewWithStringArgumentsCategory<sqliteTracingStatus()>
+ sqliteLowLevelCategory_{"sqlite low level"_t, eventQueue, sqliteLowLevelCategory};
+ return sqliteLowLevelCategory_;
+}
+
+NanotraceHR::StringViewWithStringArgumentsCategory<sqliteTracingStatus()> &sqliteHighLevelCategory()
+{
+ thread_local NanotraceHR::StringViewWithStringArgumentsCategory<sqliteTracingStatus()>
+ sqliteHighLevelCategory_{"sqlite high level"_t, eventQueue, sqliteHighLevelCategory};
+
+ return sqliteHighLevelCategory_;
+}
+
+} // namespace Sqlite
diff --git a/src/libs/sqlite/sqlitetracing.h b/src/libs/sqlite/sqlitetracing.h
new file mode 100644
index 0000000000..8dadc6de0d
--- /dev/null
+++ b/src/libs/sqlite/sqlitetracing.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "sqliteglobal.h"
+
+#include <nanotrace/nanotracehr.h>
+
+namespace Sqlite {
+using namespace NanotraceHR::Literals;
+
+constexpr NanotraceHR::Tracing sqliteTracingStatus()
+{
+#ifdef ENABLE_SQLITE_TRACING
+ return NanotraceHR::Tracing::IsEnabled;
+#else
+ return NanotraceHR::Tracing::IsDisabled;
+#endif
+}
+
+using TraceFile = NanotraceHR::TraceFile<sqliteTracingStatus()>;
+
+SQLITE_EXPORT TraceFile &traceFile();
+
+NanotraceHR::StringViewWithStringArgumentsCategory<sqliteTracingStatus()> &sqliteLowLevelCategory();
+
+SQLITE_EXPORT NanotraceHR::StringViewWithStringArgumentsCategory<sqliteTracingStatus()> &
+sqliteHighLevelCategory();
+
+} // namespace Sqlite
diff --git a/src/libs/sqlite/sqlitevalue.h b/src/libs/sqlite/sqlitevalue.h
index fe576f3fec..725682494b 100644
--- a/src/libs/sqlite/sqlitevalue.h
+++ b/src/libs/sqlite/sqlitevalue.h
@@ -6,6 +6,7 @@
#include "sqliteblob.h"
#include "sqliteexception.h"
+#include <nanotrace/nanotracehr.h>
#include <utils/smallstring.h>
#include <QVariant>
@@ -33,7 +34,7 @@ public:
explicit ValueBase(NullValue) {}
explicit ValueBase(VariantType &&value)
- : value(value)
+ : value(std::move(value))
{}
explicit ValueBase(const char *value)
@@ -43,6 +44,7 @@ public:
explicit ValueBase(long long value)
: value(value)
{}
+
explicit ValueBase(int value)
: value(static_cast<long long>(value))
{}
@@ -60,11 +62,6 @@ public:
{}
- explicit ValueBase(StringType &&value)
- : value(std::move(value))
-
- {}
-
explicit ValueBase(BlobView value)
: value(value)
@@ -229,14 +226,42 @@ public:
class ValueView : public ValueBase<Utils::SmallStringView, BlobView>
{
public:
+ ValueView() = default;
+
+ explicit ValueView(NullValue) {}
+
explicit ValueView(ValueBase &&base)
: ValueBase(std::move(base))
{}
+ explicit ValueView(Utils::SmallStringView value)
+ : ValueBase(value)
+ {}
+
+ explicit ValueView(BlobView value)
+ : ValueBase(value)
+ {}
+
+ explicit ValueView(long long value)
+ : ValueBase(value)
+ {}
+
+ explicit ValueView(int value)
+ : ValueBase(static_cast<long long>(value))
+ {}
+
+ explicit ValueView(uint value)
+ : ValueBase(static_cast<long long>(value))
+ {}
+
+ explicit ValueView(double value)
+ : ValueBase(value)
+ {}
+
template<typename Type>
static ValueView create(Type &&value_)
{
- return ValueView{ValueBase{value_}};
+ return ValueView(std::forward<Type>(value_));
}
};
@@ -386,4 +411,27 @@ private:
};
using Values = std::vector<Value>;
+
+template<typename String>
+void convertToString(String &string, const Value &value)
+{
+ switch (value.type()) {
+ case ValueType::Null:
+ convertToString(string, "null");
+ break;
+ case ValueType::Integer:
+ convertToString(string, value.toInteger());
+ break;
+ case ValueType::Float:
+ convertToString(string, value.toFloat());
+ break;
+ case ValueType::String:
+ convertToString(string, value.toStringView());
+ break;
+ case ValueType::Blob:
+ convertToString(string, "blob");
+ break;
+ }
+}
+
} // namespace Sqlite
diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt
index 3dff6c4f6f..c1cf3f86a8 100644
--- a/src/libs/utils/CMakeLists.txt
+++ b/src/libs/utils/CMakeLists.txt
@@ -270,7 +270,6 @@ extend_qtc_library(Utils
fsengine/fsengine_impl.h
fsengine/diriterator.h
fsengine/fileiteratordevicesappender.h
- fsengine/rootinjectfsengine.h
fsengine/fixedlistfsengine.h
fsengine/fsenginehandler.cpp
fsengine/fsenginehandler.h
diff --git a/src/libs/utils/algorithm.h b/src/libs/utils/algorithm.h
index d1c3f37bff..849316c9a9 100644
--- a/src/libs/utils/algorithm.h
+++ b/src/libs/utils/algorithm.h
@@ -987,6 +987,14 @@ C filtered(const C &container, R (S::*predicate)() const)
return out;
}
+template<typename C, typename R, typename S>
+Q_REQUIRED_RESULT C filtered(const C &container, R S::*predicate)
+{
+ C out;
+ std::copy_if(std::begin(container), std::end(container), inserter(out), std::mem_fn(predicate));
+ return out;
+}
+
//////////////////
// filteredCast
/////////////////
diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp
index 50d1f276ef..303ffa6bf5 100644
--- a/src/libs/utils/devicefileaccess.cpp
+++ b/src/libs/utils/devicefileaccess.cpp
@@ -1059,6 +1059,10 @@ expected_str<QByteArray> UnixDeviceFileAccess::fileContents(const FilePath &file
if (disconnected())
return make_unexpected_disconnected();
+ expected_str<FilePath> localSource = filePath.localSource();
+ if (localSource && *localSource != filePath)
+ return localSource->fileContents(limit, offset);
+
QStringList args = {"if=" + filePath.path()};
if (limit > 0 || offset > 0) {
const qint64 gcd = std::gcd(limit, offset);
@@ -1088,6 +1092,10 @@ expected_str<qint64> UnixDeviceFileAccess::writeFileContents(const FilePath &fil
if (disconnected())
return make_unexpected_disconnected();
+ expected_str<FilePath> localSource = filePath.localSource();
+ if (localSource && *localSource != filePath)
+ return localSource->writeFileContents(data);
+
QStringList args = {"of=" + filePath.path()};
RunResult result = runInShell({"dd", args, OsType::OsTypeLinux}, data);
diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp
index be43f2a206..190cde2d2d 100644
--- a/src/libs/utils/environment.cpp
+++ b/src/libs/utils/environment.cpp
@@ -433,60 +433,82 @@ const NameValueDictionary &Environment::resolved() const
m_dict = Environment::systemEnvironment().toDictionary();
m_fullDict = true;
break;
- case SetFixedDictionary:
- m_dict = std::get<SetFixedDictionary>(item);
- m_fullDict = true;
+ case SetFixedDictionary: {
+ const auto dict = std::get_if<SetFixedDictionary>(&item);
+ if (QTC_GUARD(dict)) {
+ m_dict = *dict;
+ m_fullDict = true;
+ }
break;
+ }
case SetValue: {
- auto [key, value, enabled] = std::get<SetValue>(item);
- m_dict.set(key, value, enabled);
+ const auto setvalue = std::get_if<SetValue>(&item);
+ if (QTC_GUARD(setvalue)) {
+ auto [key, value, enabled] = *setvalue;
+ m_dict.set(key, value, enabled);
+ }
break;
}
case SetFallbackValue: {
- auto [key, value] = std::get<SetFallbackValue>(item);
- if (m_fullDict) {
- if (m_dict.value(key).isEmpty())
+ const auto fallbackvalue = std::get_if<SetFallbackValue>(&item);
+ if (QTC_GUARD(fallbackvalue)) {
+ auto [key, value] = *fallbackvalue;
+ if (m_fullDict) {
+ if (m_dict.value(key).isEmpty())
+ m_dict.set(key, value, true);
+ } else {
+ QTC_ASSERT(false, qDebug() << "operating on partial dictionary");
m_dict.set(key, value, true);
- } else {
- QTC_ASSERT(false, qDebug() << "operating on partial dictionary");
- m_dict.set(key, value, true);
+ }
}
break;
}
- case UnsetValue:
- m_dict.unset(std::get<UnsetValue>(item));
+ case UnsetValue: {
+ const auto unsetvalue = std::get_if<UnsetValue>(&item);
+ if (QTC_GUARD(unsetvalue))
+ m_dict.unset(*unsetvalue);
break;
+ }
case PrependOrSet: {
- auto [key, value, sep] = std::get<PrependOrSet>(item);
- QTC_ASSERT(!key.contains('='), return m_dict);
- const auto it = m_dict.findKey(key);
- if (it == m_dict.m_values.end()) {
- m_dict.m_values.insert(DictKey(key, m_dict.nameCaseSensitivity()), {value, true});
- } else {
- // Prepend unless it is already there
- const QString toPrepend = value + pathListSeparator(sep);
- if (!it.value().first.startsWith(toPrepend))
- it.value().first.prepend(toPrepend);
+ const auto prependorset = std::get_if<PrependOrSet>(&item);
+ if (QTC_GUARD(prependorset)) {
+ auto [key, value, sep] = *prependorset;
+ QTC_ASSERT(!key.contains('='), return m_dict);
+ const auto it = m_dict.findKey(key);
+ if (it == m_dict.m_values.end()) {
+ m_dict.m_values.insert(DictKey(key, m_dict.nameCaseSensitivity()), {value, true});
+ } else {
+ // Prepend unless it is already there
+ const QString toPrepend = value + pathListSeparator(sep);
+ if (!it.value().first.startsWith(toPrepend))
+ it.value().first.prepend(toPrepend);
+ }
}
break;
}
case AppendOrSet: {
- auto [key, value, sep] = std::get<AppendOrSet>(item);
- QTC_ASSERT(!key.contains('='), return m_dict);
- const auto it = m_dict.findKey(key);
- if (it == m_dict.m_values.end()) {
- m_dict.m_values.insert(DictKey(key, m_dict.nameCaseSensitivity()), {value, true});
- } else {
- // Prepend unless it is already there
- const QString toAppend = pathListSeparator(sep) + value;
- if (!it.value().first.endsWith(toAppend))
- it.value().first.append(toAppend);
+ const auto appendorset = std::get_if<AppendOrSet>(&item);
+ if (QTC_GUARD(appendorset)) {
+ auto [key, value, sep] = *appendorset;
+ QTC_ASSERT(!key.contains('='), return m_dict);
+ const auto it = m_dict.findKey(key);
+ if (it == m_dict.m_values.end()) {
+ m_dict.m_values.insert(DictKey(key, m_dict.nameCaseSensitivity()), {value, true});
+ } else {
+ // Prepend unless it is already there
+ const QString toAppend = pathListSeparator(sep) + value;
+ if (!it.value().first.endsWith(toAppend))
+ it.value().first.append(toAppend);
+ }
}
break;
}
case Modify: {
- EnvironmentItems items = std::get<Modify>(item);
- m_dict.modify(items);
+ const auto modify = std::get_if<Modify>(&item);
+ if (QTC_GUARD(modify)) {
+ EnvironmentItems items = *modify;
+ m_dict.modify(items);
+ }
break;
}
case SetupEnglishOutput:
diff --git a/src/libs/utils/expected.h b/src/libs/utils/expected.h
index 33231c1246..0e018eb8ab 100644
--- a/src/libs/utils/expected.h
+++ b/src/libs/utils/expected.h
@@ -30,3 +30,12 @@ using expected_str = tl::expected<T, QString>;
} \
do { \
} while (0)
+
+#define QTC_CHECK_EXPECTED(expected) \
+ if (Q_LIKELY(expected)) { \
+ } else { \
+ ::Utils::writeAssertLocation( \
+ QString("%1:%2: %3").arg(__FILE__).arg(__LINE__).arg(expected.error()).toUtf8().data()); \
+ } \
+ do { \
+ } while (0)
diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp
index 1b9b6e943c..b62f222475 100644
--- a/src/libs/utils/filepath.cpp
+++ b/src/libs/utils/filepath.cpp
@@ -19,9 +19,11 @@
#include <QFileInfo>
#include <QRegularExpression>
#include <QStringView>
+#include <QTemporaryFile>
#include <QUrl>
+
+#include <QtConcurrent>
#include <QtGlobal>
-#include <QTemporaryFile>
#ifdef Q_OS_WIN
#ifdef QTCREATOR_PCH_H
@@ -1497,21 +1499,28 @@ FilePath FilePath::relativePathFrom(const FilePath &anchor) const
FilePath absPath;
QString filename;
- if (isFile()) {
+
+ const QList<FilePathInfo> infos
+ = QtConcurrent::blockingMapped(QList<FilePath>{*this, anchor}, [](const FilePath &path) {
+ return path.filePathInfo();
+ });
+
+ if (infos.first().fileFlags.testFlag(FilePathInfo::FileFlag::FileType)) {
absPath = absolutePath();
filename = fileName();
- } else if (isDir()) {
+ } else if (infos.first().fileFlags.testFlag(FilePathInfo::FileFlag::DirectoryType)) {
absPath = absoluteFilePath();
} else {
return {};
}
FilePath absoluteAnchorPath;
- if (anchor.isFile())
+ if (infos.last().fileFlags.testFlag(FilePathInfo::FileFlag::FileType))
absoluteAnchorPath = anchor.absolutePath();
- else if (anchor.isDir())
+ else if (infos.last().fileFlags.testFlag(FilePathInfo::FileFlag::DirectoryType))
absoluteAnchorPath = anchor.absoluteFilePath();
else
return {};
+
QString relativeFilePath = calcRelativePath(absPath.pathView(), absoluteAnchorPath.pathView());
if (!filename.isEmpty()) {
if (relativeFilePath == ".")
diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp
index a2998e2f07..b3649a457d 100644
--- a/src/libs/utils/fileutils.cpp
+++ b/src/libs/utils/fileutils.cpp
@@ -197,7 +197,8 @@ FileSaver::FileSaver(const FilePath &filePath, QIODevice::OpenMode mode)
m_file.reset(tf);
} else {
const bool readOnlyOrAppend = mode & (QIODevice::ReadOnly | QIODevice::Append);
- m_isSafe = !readOnlyOrAppend && !filePath.hasHardLinks();
+ m_isSafe = !readOnlyOrAppend && !filePath.hasHardLinks()
+ && !qtcEnvironmentVariableIsSet("QTC_DISABLE_ATOMICSAVE");
if (m_isSafe)
m_file.reset(new SaveFile(filePath));
else
diff --git a/src/libs/utils/fsengine/fsengine_impl.h b/src/libs/utils/fsengine/fsengine_impl.h
index 9d11b917ac..1a49f77cd2 100644
--- a/src/libs/utils/fsengine/fsengine_impl.h
+++ b/src/libs/utils/fsengine/fsengine_impl.h
@@ -48,7 +48,8 @@ public:
uint ownerId(FileOwner) const override;
QString owner(FileOwner) const override;
-#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
+ // The FileTime change in QAbstractFileEngine, in qtbase, is in since Qt 6.7.1
+#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 1)
using FileTime = QFile::FileTime;
#endif
bool setFileTime(const QDateTime &newDate, FileTime time) override;
diff --git a/src/libs/utils/fsengine/fsenginehandler.cpp b/src/libs/utils/fsengine/fsenginehandler.cpp
index 29fe759a86..d6751d8b6a 100644
--- a/src/libs/utils/fsengine/fsenginehandler.cpp
+++ b/src/libs/utils/fsengine/fsenginehandler.cpp
@@ -3,17 +3,42 @@
#include "fsenginehandler.h"
+#include "fileiteratordevicesappender.h"
#include "fixedlistfsengine.h"
-#include "fsengine_impl.h"
-#include "rootinjectfsengine.h"
-
#include "fsengine.h"
+#include "fsengine_impl.h"
#include "../algorithm.h"
#include "../hostosinfo.h"
+#include <QtCore/private/qfsfileengine_p.h>
+
namespace Utils::Internal {
+class RootInjectFSEngine final : public QFSFileEngine
+{
+public:
+ using QFSFileEngine::QFSFileEngine;
+
+public:
+#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
+ IteratorUniquePtr beginEntryList(const QString &path,
+ QDir::Filters filters,
+ const QStringList &filterNames) override
+ {
+ return std::make_unique<FileIteratorWrapper>(
+ QFSFileEngine::beginEntryList(path, filters, filterNames));
+ }
+#else
+ Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override
+ {
+ std::unique_ptr<QAbstractFileEngineIterator> baseIterator(
+ QFSFileEngine::beginEntryList(filters, filterNames));
+ return new FileIteratorWrapper(std::move(baseIterator));
+ }
+#endif
+};
+
static FilePath removeDoubleSlash(const QString &fileName)
{
// Reduce every two or more slashes to a single slash.
diff --git a/src/libs/utils/fsengine/rootinjectfsengine.h b/src/libs/utils/fsengine/rootinjectfsengine.h
deleted file mode 100644
index 9eb6a8a832..0000000000
--- a/src/libs/utils/fsengine/rootinjectfsengine.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "fileiteratordevicesappender.h"
-
-#include <QtCore/private/qfsfileengine_p.h>
-
-namespace Utils {
-namespace Internal {
-
-class RootInjectFSEngine : public QFSFileEngine
-{
-public:
- using QFSFileEngine::QFSFileEngine;
-
-public:
-#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
- IteratorUniquePtr beginEntryList(const QString &path,
- QDir::Filters filters,
- const QStringList &filterNames) override
- {
- return std::make_unique<FileIteratorWrapper>(
- QFSFileEngine::beginEntryList(path, filters, filterNames));
- }
-#else
- Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override
- {
- std::unique_ptr<QAbstractFileEngineIterator> baseIterator(
- QFSFileEngine::beginEntryList(filters, filterNames));
- return new FileIteratorWrapper(std::move(baseIterator));
- }
-#endif
-};
-
-} // namespace Internal
-} // namespace Utils
diff --git a/src/libs/utils/namevaluesdialog.cpp b/src/libs/utils/namevaluesdialog.cpp
index 35587f8791..0b009c7568 100644
--- a/src/libs/utils/namevaluesdialog.cpp
+++ b/src/libs/utils/namevaluesdialog.cpp
@@ -45,7 +45,11 @@ signals:
void lostFocus();
private:
- void focusOutEvent(QFocusEvent *) override { emit lostFocus(); }
+ void focusOutEvent(QFocusEvent *e) override
+ {
+ QPlainTextEdit::focusOutEvent(e);
+ emit lostFocus();
+ }
};
} // namespace Internal
diff --git a/src/libs/utils/outputformatter.cpp b/src/libs/utils/outputformatter.cpp
index f8b3d8cec7..a318bb1cca 100644
--- a/src/libs/utils/outputformatter.cpp
+++ b/src/libs/utils/outputformatter.cpp
@@ -402,23 +402,32 @@ const QList<FormattedText> OutputFormatter::linkifiedText(
}
for (int nextLocalTextPos = 0; nextLocalTextPos < t.text.size(); ) {
-
- // There are no more links in this part, so copy the rest of the text as-is.
- if (nextLinkSpecIndex >= linkSpecs.size()) {
+ const auto copyRestOfSegmentAsIs = [&] {
linkified << FormattedText(t.text.mid(nextLocalTextPos), t.format);
totalTextLengthSoFar += t.text.length() - nextLocalTextPos;
+ };
+
+ // We are out of links.
+ if (nextLinkSpecIndex >= linkSpecs.size()) {
+ copyRestOfSegmentAsIs();
break;
}
const OutputLineParser::LinkSpec &linkSpec = linkSpecs.at(nextLinkSpecIndex);
const int localLinkStartPos = linkSpec.startPos - totalPreviousTextLength;
+
+ // There are more links, but not in this segment.
+ if (localLinkStartPos >= t.text.size()) {
+ copyRestOfSegmentAsIs();
+ break;
+ }
+
++nextLinkSpecIndex;
// We ignore links that would cross format boundaries.
if (localLinkStartPos < nextLocalTextPos
|| localLinkStartPos + linkSpec.length > t.text.length()) {
- linkified << FormattedText(t.text.mid(nextLocalTextPos), t.format);
- totalTextLengthSoFar += t.text.length() - nextLocalTextPos;
+ copyRestOfSegmentAsIs();
break;
}
diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp
index b399d86b36..3f06e04fc1 100644
--- a/src/libs/utils/qtcprocess.cpp
+++ b/src/libs/utils/qtcprocess.cpp
@@ -769,6 +769,7 @@ private:
std::unique_ptr<ProcessInterfaceHandler> m_processHandler;
mutable QMutex m_mutex;
QList<ProcessInterfaceSignal *> m_signals;
+ Guard m_guard;
};
class ProcessPrivate : public QObject
@@ -961,6 +962,10 @@ GeneralProcessBlockingImpl::GeneralProcessBlockingImpl(ProcessPrivate *parent)
bool GeneralProcessBlockingImpl::waitForSignal(ProcessSignalType newSignal, QDeadlineTimer timeout)
{
+ QTC_ASSERT(!m_guard.isLocked(), qWarning("Process::waitForSignal() called recursively. "
+ "The call is being ignored."); return false);
+ GuardLocker locker(m_guard);
+
m_processHandler->setParent(nullptr);
QThread thread;
diff --git a/src/libs/utils/reloadpromptutils.cpp b/src/libs/utils/reloadpromptutils.cpp
index 5257138245..8a07592d3f 100644
--- a/src/libs/utils/reloadpromptutils.cpp
+++ b/src/libs/utils/reloadpromptutils.cpp
@@ -89,12 +89,10 @@ QTCREATOR_UTILS_EXPORT FileDeletedPromptAnswer
"Do you want to save it under a different name, or close "
"the editor?").arg(QDir::toNativeSeparators(fileName));
QMessageBox box(QMessageBox::Question, title, msg, QMessageBox::NoButton, parent);
- QPushButton *close =
- box.addButton(Tr::tr("&Close"), QMessageBox::RejectRole);
+ QPushButton *saveas = box.addButton(Tr::tr("Save &as..."), QMessageBox::ActionRole);
+ QPushButton *close = box.addButton(Tr::tr("&Close"), QMessageBox::RejectRole);
QPushButton *closeAll =
box.addButton(Tr::tr("C&lose All"), QMessageBox::RejectRole);
- QPushButton *saveas =
- box.addButton(Tr::tr("Save &as..."), QMessageBox::ActionRole);
QPushButton *save =
box.addButton(Tr::tr("&Save"), QMessageBox::AcceptRole);
box.setDefaultButton(saveas);
diff --git a/src/libs/utils/smallstring.h b/src/libs/utils/smallstring.h
index c522a6cae9..e8c3d74b92 100644
--- a/src/libs/utils/smallstring.h
+++ b/src/libs/utils/smallstring.h
@@ -93,7 +93,7 @@ public:
static_cast<std::size_t>(std::distance(begin, end))}
{}
- template<typename Type, typename = std::enable_if_t<std::is_pointer<Type>::value>>
+ template<typename Type, typename std::enable_if_t<std::is_pointer<Type>::value, bool> = true>
BasicSmallString(Type characterPointer) noexcept
: BasicSmallString(characterPointer, std::char_traits<char>::length(characterPointer))
{
@@ -118,7 +118,7 @@ public:
template<typename BeginIterator,
typename EndIterator,
- typename = std::enable_if_t<std::is_same<BeginIterator, EndIterator>::value>>
+ typename std::enable_if_t<std::is_same<BeginIterator, EndIterator>::value, bool> = true>
BasicSmallString(BeginIterator begin, EndIterator end) noexcept
: BasicSmallString(&(*begin), size_type(end - begin))
{}
@@ -354,6 +354,14 @@ public:
return false;
}
+ bool startsWith(QStringView subStringToSearch) const noexcept
+ {
+ if (size() >= Utils::usize(subStringToSearch))
+ return subStringToSearch == QLatin1StringView{data(), subStringToSearch.size()};
+
+ return false;
+ }
+
bool startsWith(char characterToSearch) const noexcept
{
return data()[0] == characterToSearch;
@@ -423,13 +431,55 @@ public:
size_type oldSize = size();
size_type newSize = oldSize + string.size();
- reserve(optimalCapacity(newSize));
+ if (fitsNotInCapacity(newSize))
+ reserve(optimalCapacity(newSize));
+
std::char_traits<char>::copy(std::next(data(), static_cast<std::ptrdiff_t>(oldSize)),
string.data(),
string.size());
setSize(newSize);
}
+ void append(char character) noexcept
+ {
+ size_type oldSize = size();
+ size_type newSize = oldSize + 1;
+
+ if (fitsNotInCapacity(newSize))
+ reserve(optimalCapacity(newSize));
+
+ auto current = std::next(data(), static_cast<std::ptrdiff_t>(oldSize));
+ *current = character;
+ setSize(newSize);
+ }
+
+ template<typename Type, typename std::enable_if_t<std::is_arithmetic_v<Type>, bool> = true>
+ void append(Type number)
+ {
+#if defined(__cpp_lib_to_chars) && (__cpp_lib_to_chars >= 201611L)
+ // 2 bytes for the sign and because digits10 returns the floor
+ char buffer[std::numeric_limits<Type>::digits10 + 2];
+ auto result = std::to_chars(buffer, buffer + sizeof(buffer), number);
+ auto endOfConversionString = result.ptr;
+
+ append({buffer, endOfConversionString});
+#else
+ if constexpr (std::is_floating_point_v<Type>) {
+ QLocale locale{QLocale::Language::C};
+ append(locale.toString(number));
+ return;
+ } else {
+ // 2 bytes for the sign and because digits10 returns the floor
+ char buffer[std::numeric_limits<Type>::digits10 + 2];
+ auto result = std::to_chars(buffer, buffer + sizeof(buffer), number);
+ auto endOfConversionString = result.ptr;
+
+ append({buffer, endOfConversionString});
+ }
+
+#endif
+ }
+
void append(QStringView string) noexcept
{
QStringEncoder encoder{QStringEncoder::Utf8};
@@ -469,6 +519,13 @@ public:
return *this;
}
+ BasicSmallString &operator+=(char character) noexcept
+ {
+ append(character);
+
+ return *this;
+ }
+
BasicSmallString &operator+=(QStringView string) noexcept
{
append(string);
@@ -476,6 +533,14 @@ public:
return *this;
}
+ template<typename Type, typename std::enable_if_t<std::is_arithmetic_v<Type>, bool> = true>
+ BasicSmallString &operator+=(Type number) noexcept
+ {
+ append(number);
+
+ return *this;
+ }
+
BasicSmallString &operator+=(std::initializer_list<SmallStringView> list) noexcept
{
appendInitializerList(list, size());
@@ -580,37 +645,12 @@ public:
return joinedString;
}
- static
- BasicSmallString number(int number)
+ template<typename Type, typename std::enable_if_t<std::is_arithmetic_v<Type>, bool> = true>
+ static BasicSmallString number(Type number)
{
- // 2 bytes for the sign and because digits10 returns the floor
- char buffer[std::numeric_limits<int>::digits10 + 2];
- auto result = std::to_chars(buffer, buffer + sizeof(buffer), number);
- auto endOfConversionString = result.ptr;
- return BasicSmallString(buffer, endOfConversionString);
- }
-
- static BasicSmallString number(long long int number) noexcept
- {
- // 2 bytes for the sign and because digits10 returns the floor
- char buffer[std::numeric_limits<long long int>::digits10 + 2];
- auto result = std::to_chars(buffer, buffer + sizeof(buffer), number);
- auto endOfConversionString = result.ptr;
- return BasicSmallString(buffer, endOfConversionString);
- }
-
- static BasicSmallString number(double number) noexcept
- {
-#if defined(__cpp_lib_to_chars) && (__cpp_lib_to_chars >= 201611L)
- // 2 bytes for the sign and because digits10 returns the floor
- char buffer[std::numeric_limits<double>::digits10 + 2];
- auto result = std::to_chars(buffer, buffer + sizeof(buffer), number);
- auto endOfConversionString = result.ptr;
- return BasicSmallString(buffer, endOfConversionString);
-#else
- QLocale locale{QLocale::Language::C};
- return BasicSmallString{locale.toString(number)};
-#endif
+ BasicSmallString string;
+ string.append(number);
+ return string;
}
char &operator[](std::size_t index) noexcept { return *(data() + index); }
@@ -655,7 +695,6 @@ public:
friend BasicSmallString operator+(const BasicSmallString &first,
const char (&second)[ArraySize]) noexcept
{
-
return operator+(first, SmallStringView(second));
}
@@ -687,8 +726,10 @@ unittest_public:
bool fitsNotInCapacity(size_type capacity) const noexcept
{
- return (isShortString() && capacity > shortStringCapacity())
- || (!isShortString() && capacity > m_data.reference.capacity);
+ if (isShortString())
+ return capacity > shortStringCapacity();
+
+ return capacity > m_data.reference.capacity;
}
static size_type optimalHeapCapacity(const size_type size) noexcept
diff --git a/src/libs/utils/stringutils.cpp b/src/libs/utils/stringutils.cpp
index d8de512b32..55a2902acc 100644
--- a/src/libs/utils/stringutils.cpp
+++ b/src/libs/utils/stringutils.cpp
@@ -672,4 +672,10 @@ void MarkdownHighlighter::highlightBlock(const QString &text)
}
}
+QString ansiColoredText(const QString &text, const QColor &color)
+{
+ static const QString formatString("\033[38;2;%1;%2;%3m%4\033[0m");
+ return formatString.arg(color.red()).arg(color.green()).arg(color.blue()).arg(text);
+}
+
} // namespace Utils
diff --git a/src/libs/utils/stringutils.h b/src/libs/utils/stringutils.h
index 3e729e672c..cab6d774f3 100644
--- a/src/libs/utils/stringutils.h
+++ b/src/libs/utils/stringutils.h
@@ -138,4 +138,6 @@ private:
QBrush m_codeBgBrush;
};
+QTCREATOR_UTILS_EXPORT QString ansiColoredText(const QString &text, const QColor &color);
+
} // namespace Utils
diff --git a/src/libs/utils/stylehelper.cpp b/src/libs/utils/stylehelper.cpp
index 69b5e39556..07f526a4af 100644
--- a/src/libs/utils/stylehelper.cpp
+++ b/src/libs/utils/stylehelper.cpp
@@ -1010,7 +1010,13 @@ QFont StyleHelper::uiFont(UiElement element)
const qreal qrealPointSize = metrics.pixelSize * pixelsToPointSizeFactor;
font.setPointSizeF(qrealPointSize);
- font.setWeight(metrics.weight);
+ // Intermediate font weights can produce blurry rendering and are harder to read.
+ // For "non-retina" screens, apply the weight only for some fonts.
+ static const bool isHighDpi = qApp->devicePixelRatio() >= 2;
+ const bool setWeight = isHighDpi || element == UiElementCaptionStrong
+ || element <= UiElementH4;
+ if (setWeight)
+ font.setWeight(metrics.weight);
return font;
}
diff --git a/src/libs/utils/theme/theme.cpp b/src/libs/utils/theme/theme.cpp
index 9b24078f86..536deafc22 100644
--- a/src/libs/utils/theme/theme.cpp
+++ b/src/libs/utils/theme/theme.cpp
@@ -18,6 +18,7 @@
namespace Utils {
static Theme *m_creatorTheme = nullptr;
+static std::optional<QPalette> m_initialPalette;
ThemePrivate::ThemePrivate()
{
@@ -37,9 +38,25 @@ Theme *proxyTheme()
return new Theme(m_creatorTheme);
}
+static bool paletteIsDark(const QPalette &pal)
+{
+ return pal.color(QPalette::Window).lightnessF() < pal.color(QPalette::WindowText).lightnessF();
+}
+
+static bool isOverridingPalette(const Theme *theme)
+{
+ if (theme->flag(Theme::DerivePaletteFromTheme))
+ return true;
+ if (theme->flag(Theme::DerivePaletteFromThemeIfNeeded)
+ && paletteIsDark(Theme::initialPalette()) != theme->flag(Theme::DarkUserInterface)) {
+ return true;
+ }
+ return false;
+}
+
void setThemeApplicationPalette()
{
- if (m_creatorTheme && m_creatorTheme->flag(Theme::ApplyThemePaletteGlobally))
+ if (m_creatorTheme && isOverridingPalette(m_creatorTheme))
QApplication::setPalette(m_creatorTheme->palette());
}
@@ -185,7 +202,7 @@ void Theme::setDisplayName(const QString &name)
void Theme::readSettingsInternal(QSettings &settings)
{
- const QStringList includes = settings.value("Includes").toString().split(",", Qt::SkipEmptyParts);
+ const QStringList includes = settings.value("Includes").toStringList();
for (const QString &include : includes) {
FilePath path = FilePath::fromString(d->fileName);
@@ -311,7 +328,13 @@ bool Theme::systemUsesDarkMode()
if (HostOsInfo::isMacHost())
return macOSSystemIsDark();
- return false;
+ // Avoid enforcing the initial palette.
+ // The initial palette must be set after setting the macOS appearance in setInitialPalette,
+ // but systemUsesDarkMode is used to determine the default theme, which is in turn required
+ // for the setInitialPalette call
+ if (m_initialPalette)
+ return paletteIsDark(*m_initialPalette);
+ return paletteIsDark(QApplication::palette());
}
// If you copy QPalette, default values stay at default, even if that default is different
@@ -347,14 +370,17 @@ void Theme::setHelpMenu(QMenu *menu)
QPalette Theme::initialPalette()
{
- static QPalette palette = copyPalette(QApplication::palette());
- return palette;
+ if (!m_initialPalette) {
+ m_initialPalette = copyPalette(QApplication::palette());
+ QApplication::setPalette(*m_initialPalette);
+ }
+ return *m_initialPalette;
}
QPalette Theme::palette() const
{
QPalette pal = initialPalette();
- if (!flag(DerivePaletteFromTheme))
+ if (!isOverridingPalette(this))
return pal;
const static struct {
diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h
index 6b3bf97d45..cd89c3ae48 100644
--- a/src/libs/utils/theme/theme.h
+++ b/src/libs/utils/theme/theme.h
@@ -527,7 +527,7 @@ public:
DrawToolBarBorders,
ComboBoxDrawTextShadow,
DerivePaletteFromTheme,
- ApplyThemePaletteGlobally,
+ DerivePaletteFromThemeIfNeeded,
FlatToolBars,
FlatSideBarIcons,
FlatProjectsMode,
diff --git a/src/libs/utils/tooltip/tooltip.cpp b/src/libs/utils/tooltip/tooltip.cpp
index 93f4c1d2ff..da11540c08 100644
--- a/src/libs/utils/tooltip/tooltip.cpp
+++ b/src/libs/utils/tooltip/tooltip.cpp
@@ -288,9 +288,11 @@ void ToolTip::hideTipWithDelay()
void ToolTip::hideTipImmediately()
{
if (m_tip) {
- m_tip->close();
- m_tip->deleteLater();
- m_tip = nullptr;
+ TipLabel *tip = m_tip.data();
+ m_tip.clear();
+
+ tip->close();
+ tip->deleteLater();
}
m_showTimer.stop();
m_hideDelayTimer.stop();
diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs
index 211d184f73..9ef9108a2f 100644
--- a/src/libs/utils/utils.qbs
+++ b/src/libs/utils/utils.qbs
@@ -374,8 +374,7 @@ QtcLibrary {
"fsenginehandler.cpp",
"fsenginehandler.h",
"fsengine_impl.cpp",
- "fsengine_impl.h",
- "rootinjectfsengine.h",
+ "fsengine_impl.h"
]
}