2006-07-20 22:57:46 +00:00
|
|
|
#!/bin/sh
|
|
|
|
# Prime Mover
|
|
|
|
#
|
2006-10-15 00:28:12 +00:00
|
|
|
# (C) 2006 David Given.
|
2006-07-20 22:57:46 +00:00
|
|
|
# Prime Mover is licensed under the MIT open source license. To get the full
|
|
|
|
# license text, run this file with the '--license' option.
|
|
|
|
#
|
2006-10-15 00:28:12 +00:00
|
|
|
# $Id: shell 52 2006-10-03 22:12:33Z dtrg $
|
2006-07-20 22:57:46 +00:00
|
|
|
|
2006-07-25 09:23:21 +00:00
|
|
|
if [ -x "$(which arch 2>/dev/null)" ]; then
|
2006-07-22 12:29:40 +00:00
|
|
|
ARCH="$(arch)"
|
2006-07-25 09:23:21 +00:00
|
|
|
elif [ -x "$(which machine 2>/dev/null)" ]; then
|
2006-07-22 12:29:40 +00:00
|
|
|
ARCH="$(machine)"
|
2006-07-25 09:23:21 +00:00
|
|
|
elif [ -x "$(which uname 2>/dev/null)" ]; then
|
2006-07-22 12:29:40 +00:00
|
|
|
ARCH="$(uname -m)"
|
|
|
|
else
|
|
|
|
echo "pm: unable to determine target type, proceeding anyway"
|
|
|
|
ARCH=unknown
|
|
|
|
fi
|
|
|
|
|
2006-07-20 22:57:46 +00:00
|
|
|
THISFILE="$0"
|
2006-07-22 12:29:40 +00:00
|
|
|
PMEXEC="./.pm-exec-$ARCH"
|
2006-07-20 22:57:46 +00:00
|
|
|
set -e
|
|
|
|
|
2006-07-21 13:13:47 +00:00
|
|
|
GZFILE=/tmp/pm-$$.gz
|
|
|
|
CFILE=/tmp/pm-$$.c
|
|
|
|
trap "rm -f $GZFILE $CFILE" EXIT
|
|
|
|
|
2006-07-20 22:57:46 +00:00
|
|
|
extract_section() {
|
|
|
|
sed -e "1,/^XXXXSTART$1/d" "$THISFILE" | (
|
|
|
|
read size
|
2006-10-15 00:28:12 +00:00
|
|
|
head -c $size
|
2006-07-21 13:13:47 +00:00
|
|
|
) > $GZFILE
|
2006-10-15 00:28:12 +00:00
|
|
|
cat $GZFILE | cat
|
2006-07-20 22:57:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# If the bootstrap's built, run it.
|
|
|
|
|
2006-07-22 12:29:40 +00:00
|
|
|
if [ "$PMEXEC" -nt $0 ]; then
|
|
|
|
extract_section script | "$PMEXEC" /dev/stdin "$@"
|
2006-07-20 22:57:46 +00:00
|
|
|
exit $?
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Otherwise, compile it and restart.
|
|
|
|
|
|
|
|
echo "pm: bootstrapping..."
|
|
|
|
|
2006-07-25 09:23:21 +00:00
|
|
|
if [ -x "$(which gcc 2>/dev/null)" ]; then
|
2006-10-15 00:28:12 +00:00
|
|
|
CC="gcc -O -s"
|
2006-07-25 09:23:21 +00:00
|
|
|
else
|
|
|
|
CC="cc"
|
|
|
|
fi
|
|
|
|
|
2006-07-20 22:57:46 +00:00
|
|
|
extract_section interpreter > /tmp/pm-$$.c
|
2006-07-22 12:29:40 +00:00
|
|
|
$CC $CFILE -o "$PMEXEC" && exec "$THISFILE" "$@"
|
2006-07-20 22:57:46 +00:00
|
|
|
|
|
|
|
echo "pm: bootstrap failed."
|
|
|
|
exit 1
|
|
|
|
|
|
|
|
XXXXSTARTscript
|
2006-10-15 00:28:12 +00:00
|
|
|
38419
|
|
|
|
#!/usr/bin/lua
|
|
|
|
-- Prime Mover
|
|
|
|
--
|
|
|
|
-- © 2006 David Given.
|
|
|
|
-- Prime Mover is licensed under the MIT open source license. Search
|
|
|
|
-- for 'MIT' in this file to find the full license text.
|
|
|
|
--
|
|
|
|
-- $Id: pm 74 2006-10-12 20:11:47Z dtrg $
|
|
|
|
|
|
|
|
-- ======================================================================= --
|
|
|
|
-- GLOBALS --
|
|
|
|
-- ======================================================================= --
|
|
|
|
|
|
|
|
local VERSION = "0.1"
|
|
|
|
|
|
|
|
-- Fast versions of useful system variables.
|
|
|
|
|
|
|
|
local stdin = io.stdin
|
|
|
|
local stdout = io.stdout
|
|
|
|
local stderr = io.stderr
|
|
|
|
|
|
|
|
local string_find = string.find
|
|
|
|
local string_gsub = string.gsub
|
|
|
|
local string_sub = string.sub
|
|
|
|
local string_byte = string.byte
|
|
|
|
|
|
|
|
local table_insert = table.insert
|
|
|
|
local table_getn = table.getn
|
|
|
|
local table_concat = table.concat
|
|
|
|
|
|
|
|
local posix_stat = posix.stat
|
|
|
|
local posix_readlink = posix.readlink
|
|
|
|
local posix_unlink = posix.unlink
|
|
|
|
local posix_rmdir = posix.rmdir
|
|
|
|
|
|
|
|
local os_time = os.time
|
|
|
|
|
|
|
|
local _G = _G
|
|
|
|
local _
|
|
|
|
|
|
|
|
-- Option settings.
|
|
|
|
|
|
|
|
local delete_output_files_on_error = true
|
|
|
|
local purge_intermediate_cache = false
|
|
|
|
local no_execute = false
|
|
|
|
local input_files = {}
|
|
|
|
local targets = {}
|
|
|
|
intermediate_cache_dir = ".pm-cache/"
|
|
|
|
verbose = false
|
|
|
|
quiet = false
|
|
|
|
|
|
|
|
-- Application globals.
|
|
|
|
|
|
|
|
local sandbox = {}
|
|
|
|
local scope = {object=sandbox, next=nil}
|
|
|
|
local intermediate_cache = {}
|
|
|
|
local intermediate_cache_count = 0
|
|
|
|
local buildstages = 0
|
|
|
|
|
|
|
|
-- Atoms.
|
|
|
|
|
|
|
|
local PARENT = {}
|
|
|
|
local EMPTY = {}
|
|
|
|
local REDIRECT = {}
|
|
|
|
|
|
|
|
-- Exported symbols (set to dummy values).
|
|
|
|
|
|
|
|
message = 0
|
|
|
|
filetime = 0
|
|
|
|
filetouch = 0
|
|
|
|
install = 0
|
|
|
|
rendertable = 0
|
|
|
|
stringmodifier = {}
|
|
|
|
|
|
|
|
setmetatable(_G, {__newindex = function(t, key, value)
|
|
|
|
error("Attempt to write to new global "..key)
|
|
|
|
end})
|
|
|
|
|
|
|
|
-- ======================================================================= --
|
|
|
|
-- UTILITIES --
|
|
|
|
-- ======================================================================= --
|
|
|
|
|
|
|
|
local function message(...)
|
|
|
|
stderr:write("pm: ")
|
|
|
|
stderr:write(unpack(arg))
|
|
|
|
stderr:write("\n")
|
|
|
|
end
|
|
|
|
_G.message = message
|
|
|
|
|
|
|
|
local function usererror(...)
|
|
|
|
stderr:write("pm: ")
|
|
|
|
stderr:write(unpack(arg))
|
|
|
|
stderr:write("\n")
|
|
|
|
os.exit(1)
|
|
|
|
end
|
|
|
|
|
|
|
|
local function traceoutput(...)
|
|
|
|
stdout:write(unpack(arg))
|
|
|
|
stdout:write("\n")
|
|
|
|
end
|
|
|
|
|
|
|
|
local function assert(message, result, e)
|
|
|
|
if result then
|
|
|
|
return result
|
|
|
|
end
|
|
|
|
|
|
|
|
if (type(message) == "string") then
|
|
|
|
message = {message}
|
|
|
|
end
|
|
|
|
|
|
|
|
table.insert(message, ": ")
|
|
|
|
table.insert(message, e)
|
|
|
|
usererror(unpack(message))
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Concatenates the contents of its arguments to the specified table.
|
|
|
|
-- (Numeric indices only.)
|
|
|
|
|
|
|
|
local function table_append(t, ...)
|
|
|
|
for _, i in ipairs(arg) do
|
|
|
|
if (type(i) == "table") then
|
|
|
|
for _, j in ipairs(i) do
|
|
|
|
table_insert(t, j)
|
|
|
|
end
|
|
|
|
else
|
|
|
|
table_insert(t, i)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Merge the contents of its arguments to the specified table.
|
|
|
|
-- (Name indices. Will break on numeric indices.)
|
|
|
|
|
|
|
|
local function table_merge(t, ...)
|
|
|
|
for _, i in ipairs(arg) do
|
|
|
|
for j, k in pairs(i) do
|
|
|
|
t[j] = k
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Turn a list of strings into a single quoted string.
|
|
|
|
|
|
|
|
function rendertable(i)
|
|
|
|
if (type(i) == "string") or (type(i) == "number") then
|
|
|
|
return i
|
|
|
|
end
|
|
|
|
|
|
|
|
if (i == nil) or (i == EMPTY) then
|
|
|
|
return ""
|
|
|
|
end
|
|
|
|
|
|
|
|
local t = {}
|
|
|
|
for _, j in ipairs(i) do
|
|
|
|
local r = string_gsub(j, "\\", "\\\\")
|
|
|
|
r = string_gsub(r, '"', '\\"')
|
|
|
|
table_insert(t, r)
|
|
|
|
end
|
|
|
|
return '"'..table_concat(t, '" "')..'"'
|
|
|
|
end
|
|
|
|
local rendertable = rendertable
|
|
|
|
|
|
|
|
-- Returns just the directory part of a path.
|
|
|
|
|
|
|
|
local function dirname(f)
|
|
|
|
local f, n = string_gsub(f, "/[^/]*$", "")
|
|
|
|
if (n == 0) then
|
|
|
|
return "."
|
|
|
|
end
|
|
|
|
return f
|
|
|
|
end
|
|
|
|
posix.dirname = dirname
|
|
|
|
|
|
|
|
-- Makes an absolute path.
|
|
|
|
|
|
|
|
local function absname(f)
|
|
|
|
if string.find(f, "^/") then
|
|
|
|
return f
|
|
|
|
end
|
|
|
|
|
|
|
|
return posix.getcwd().."/"..f
|
|
|
|
end
|
|
|
|
posix.absname = absname
|
|
|
|
|
|
|
|
-- Copies a file.
|
|
|
|
|
|
|
|
local function copy(src, dest)
|
|
|
|
local s = string_gsub(src, "'", "'\"'\"'")
|
|
|
|
local d = string_gsub(dest, "'", "'\"'\"'")
|
|
|
|
local r = os.execute("cp '"..s.."' '"..d.."'")
|
|
|
|
if (r ~= 0) then
|
|
|
|
return nil, "unable to copy file"
|
|
|
|
end
|
|
|
|
return 0, nil
|
|
|
|
end
|
|
|
|
posix.copy = copy
|
|
|
|
|
|
|
|
-- Makes all directories that contain f
|
|
|
|
|
|
|
|
local function mkcontainerdir(f)
|
|
|
|
f = dirname(f)
|
|
|
|
if not posix_stat(f, "type") then
|
|
|
|
mkcontainerdir(f)
|
|
|
|
local r = posix.mkdir(f)
|
|
|
|
if not r then
|
|
|
|
usererror("unable to create directory '"..f.."'")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Install a file (suitable as a command list entry).
|
|
|
|
|
|
|
|
local function do_install(self, src, dest)
|
|
|
|
src = absname(self:__expand(src))
|
|
|
|
dest = absname(self:__expand(dest))
|
|
|
|
if verbose then
|
|
|
|
message("installing '", src, "' --> '", dest, "'")
|
|
|
|
end
|
|
|
|
|
|
|
|
mkcontainerdir(dest)
|
|
|
|
local f, e = posix.symlink(src, dest)
|
|
|
|
if f then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if (e ~= nil) then
|
|
|
|
f, e = posix.unlink(dest)
|
|
|
|
if f then
|
|
|
|
f, e = posix.symlink(src, dest)
|
|
|
|
if f then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
self:__error("couldn't install '", src, "' to '", dest,
|
|
|
|
"': ", e)
|
|
|
|
end
|
|
|
|
|
|
|
|
function install(src, dest)
|
|
|
|
return function(self, inputs, outputs)
|
|
|
|
local src = src
|
|
|
|
local dest = dest
|
|
|
|
|
|
|
|
if (dest == nil) then
|
|
|
|
dest = src
|
|
|
|
src = outputs[1]
|
|
|
|
end
|
|
|
|
if (type(src) ~= "string") then
|
|
|
|
self:__error("pm.install needs a string or an object for an input")
|
|
|
|
end
|
|
|
|
if (type(dest) ~= "string") then
|
|
|
|
self:__error("pm.install needs a string for a destination")
|
|
|
|
end
|
|
|
|
return do_install(self, src, dest)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Perform an error traceback.
|
|
|
|
|
|
|
|
local function traceback(e)
|
|
|
|
local i = 1
|
|
|
|
while true do
|
|
|
|
local t = debug.getinfo(i)
|
|
|
|
if not t then
|
|
|
|
break
|
|
|
|
end
|
|
|
|
if (t.short_src ~= "stdin") and (t.short_src ~= "[C]") then
|
|
|
|
if (t.currentline == -1) then
|
|
|
|
t.currentline = ""
|
|
|
|
end
|
|
|
|
message(" ", t.short_src, ":", t.currentline)
|
|
|
|
end
|
|
|
|
i = i + 1
|
|
|
|
end
|
|
|
|
|
|
|
|
e = string_gsub(e, "^stdin:[0-9]*: ", "")
|
|
|
|
usererror("error: ", e)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- ======================================================================= --
|
|
|
|
-- CACHE MANAGEMENT --
|
|
|
|
-- ======================================================================= --
|
|
|
|
|
|
|
|
local statted_files = {}
|
|
|
|
local function clear_stat_cache()
|
|
|
|
statted_files = {}
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Returns the timestamp of a file, or 0 if it doesn't exist.
|
|
|
|
|
|
|
|
local statted_files = {}
|
|
|
|
local function filetime(f)
|
|
|
|
local t = statted_files[f]
|
|
|
|
if t then
|
|
|
|
return t
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Stupid BeOS doesn't dereference symlinks on stat().
|
|
|
|
|
|
|
|
local realf = f
|
|
|
|
while true do
|
|
|
|
local newf, e = posix_readlink(realf)
|
|
|
|
if e then
|
|
|
|
break
|
|
|
|
end
|
|
|
|
realf = newf
|
|
|
|
end
|
|
|
|
|
|
|
|
t = posix_stat(realf, "mtime") or 0
|
|
|
|
statted_files[f] = t
|
|
|
|
return t
|
|
|
|
end
|
|
|
|
_G.filetime = filetime
|
|
|
|
|
|
|
|
-- Pretends to touch a file by manipulating the stat cache.
|
|
|
|
|
|
|
|
local function filetouch(f)
|
|
|
|
if (type(f) == "string") then
|
|
|
|
f = {f}
|
|
|
|
end
|
|
|
|
|
|
|
|
local t = os_time()
|
|
|
|
for _, i in ipairs(f) do
|
|
|
|
statted_files[i] = t
|
|
|
|
end
|
|
|
|
end
|
|
|
|
_G.filetouch = filetouch
|
|
|
|
|
|
|
|
local function create_intermediate_cache()
|
|
|
|
local d = dirname(intermediate_cache_dir)
|
|
|
|
if not quiet then
|
|
|
|
message("creating new intermediate file cache in '"..d.."'")
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Attempt to wipe the old cache directory.
|
|
|
|
|
|
|
|
local f = posix.files(d)
|
|
|
|
if not f then
|
|
|
|
-- The directory doesn't exist, so create it.
|
|
|
|
|
|
|
|
mkcontainerdir(d)
|
|
|
|
f = posix.mkdir(d)
|
|
|
|
if not f then
|
|
|
|
usererror("unable to create intermediate file cache directory")
|
|
|
|
end
|
|
|
|
else
|
|
|
|
-- The directory exists. Delete all files in it recursively.
|
|
|
|
|
|
|
|
local function rmdir(root)
|
|
|
|
local f = posix.files(root)
|
|
|
|
if not f then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
for i in f do
|
|
|
|
if ((i ~= ".") and (i ~= "..")) then
|
|
|
|
local fn = root.."/"..i
|
|
|
|
local t = posix_stat(fn, "type")
|
|
|
|
if (t == "regular") then
|
|
|
|
if not posix_unlink(fn) then
|
|
|
|
usererror("unable to purge intermediate file cache directory")
|
|
|
|
end
|
|
|
|
elseif (t == "directory") then
|
|
|
|
rmdir(fn)
|
|
|
|
posix_rmdir(fn)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
rmdir(d)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local function save_intermediate_cache()
|
|
|
|
local fn = intermediate_cache_dir.."index"
|
|
|
|
local f = io.open(fn, "w")
|
|
|
|
if not f then
|
|
|
|
usererror("unable to save intermediate cache index file '", fn, "'")
|
|
|
|
end
|
|
|
|
|
|
|
|
f:write(intermediate_cache_count, "\n")
|
|
|
|
for i, j in pairs(intermediate_cache) do
|
|
|
|
f:write(i, "\n")
|
|
|
|
f:write(j, "\n")
|
|
|
|
end
|
|
|
|
|
|
|
|
f:close()
|
|
|
|
end
|
|
|
|
|
|
|
|
local function load_intermediate_cache()
|
|
|
|
local fn = intermediate_cache_dir.."index"
|
|
|
|
local f = io.open(fn, "r")
|
|
|
|
if not f then
|
|
|
|
create_intermediate_cache()
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
intermediate_cache_count = f:read("*l")
|
|
|
|
while true do
|
|
|
|
local l1 = f:read("*l")
|
|
|
|
local l2 = f:read("*l")
|
|
|
|
|
|
|
|
if (l1 == nil) or (l2 == nil) then
|
|
|
|
break
|
|
|
|
end
|
|
|
|
|
|
|
|
intermediate_cache[l1] = l2
|
|
|
|
end
|
|
|
|
|
|
|
|
f:close()
|
|
|
|
end
|
|
|
|
|
|
|
|
local function create_intermediate_cache_key(key)
|
|
|
|
local u = intermediate_cache[key]
|
|
|
|
if not u then
|
|
|
|
intermediate_cache_count = intermediate_cache_count + 1
|
|
|
|
u = intermediate_cache_count
|
|
|
|
intermediate_cache[key] = u
|
|
|
|
save_intermediate_cache()
|
|
|
|
end
|
|
|
|
|
|
|
|
return u
|
|
|
|
end
|
|
|
|
|
|
|
|
-- ======================================================================= --
|
|
|
|
-- STRING MODIFIERS --
|
|
|
|
-- ======================================================================= --
|
|
|
|
|
|
|
|
function stringmodifier.dirname(self, s)
|
|
|
|
if (type(s) == "table") then
|
|
|
|
if (table_getn(s) == 1) then
|
|
|
|
s = s[1]
|
|
|
|
else
|
|
|
|
self:__error("tried to use string modifier 'dirname' on a table with more than one entry")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return dirname(s)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- ======================================================================= --
|
|
|
|
-- CLASS SYSTEM --
|
|
|
|
-- ======================================================================= --
|
|
|
|
|
|
|
|
--- Base class --------------------------------------------------------------
|
|
|
|
|
|
|
|
local metaclass = {
|
|
|
|
class = "metaclass",
|
|
|
|
|
|
|
|
-- Creates a new instance of a class by creating a new object and cloning
|
|
|
|
-- all properties of the called class onto it.
|
|
|
|
|
|
|
|
__call = function (self, ...)
|
|
|
|
local o = {}
|
|
|
|
for i, j in pairs(self) do
|
|
|
|
o[i] = j
|
|
|
|
end
|
|
|
|
setmetatable(o, o)
|
|
|
|
|
|
|
|
-- Determine where this object was defined.
|
|
|
|
|
|
|
|
local i = 1
|
|
|
|
while true do
|
|
|
|
local s = debug.getinfo(i, "Sl")
|
|
|
|
if s then
|
|
|
|
if (string_byte(s.source) == 64) then
|
|
|
|
o.definedat = string_sub(s.source, 2)..":"..s.currentline
|
|
|
|
end
|
|
|
|
else
|
|
|
|
break
|
|
|
|
end
|
|
|
|
i = i + 1
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Call the object's constructor and return it.
|
|
|
|
|
|
|
|
o:__init(unpack(arg))
|
|
|
|
return o
|
|
|
|
end,
|
|
|
|
|
|
|
|
-- Dummy constructor.
|
|
|
|
|
|
|
|
__init = function (self, ...)
|
|
|
|
end,
|
|
|
|
}
|
|
|
|
setmetatable(metaclass, metaclass)
|
|
|
|
|
|
|
|
--- Top-level build node ----------------------------------------------------
|
|
|
|
|
|
|
|
local node = metaclass()
|
|
|
|
node.class = "node"
|
|
|
|
|
|
|
|
-- When constructed, nodes initialise themselves from a supplied table of
|
|
|
|
-- properties. All node children take exactly one argument, allowing the
|
|
|
|
-- "constructor {properties}" construction pattern.
|
|
|
|
|
|
|
|
function node:__init(t)
|
|
|
|
metaclass.__init(self)
|
|
|
|
|
|
|
|
if (type(t) == "string") then
|
|
|
|
t = {t}
|
|
|
|
end
|
|
|
|
if (type(t) ~= "table") then
|
|
|
|
self:__error("can't be constructed with a ", type(t), "; try a table or a string")
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Copy over non-numeric parameters.
|
|
|
|
|
|
|
|
for i, j in pairs(t) do
|
|
|
|
if (tonumber(i) == nil) then
|
|
|
|
self[i] = j
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Copy any numeric parameters.
|
|
|
|
|
|
|
|
for _, i in ipairs(t) do
|
|
|
|
table_insert(self, i)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- If we're a class, don't verify.
|
|
|
|
|
|
|
|
if t.class then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
-- ensure_n_children
|
|
|
|
-- When true, ensures that the node has exactly the number of children
|
|
|
|
-- specified.
|
|
|
|
|
|
|
|
if self.ensure_n_children then
|
|
|
|
local n = self.ensure_n_children
|
|
|
|
if (table.getn(self) ~= n) then
|
|
|
|
local one
|
|
|
|
if (n == 1) then
|
|
|
|
one = "one child"
|
|
|
|
else
|
|
|
|
one = n.." children"
|
|
|
|
end
|
|
|
|
self:_error("must have exactly ", one)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- ensure_at_least_one_child
|
|
|
|
-- When true, ensures the the node has at least one child.
|
|
|
|
|
|
|
|
if self.ensure_at_least_one_child then
|
|
|
|
if (table_getn(self) < 1) then
|
|
|
|
self:__error("must have at least one child")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- construct_string_children_with
|
|
|
|
-- If set, any string children are automatically converted using the
|
|
|
|
-- specified constructor.
|
|
|
|
|
|
|
|
if self.construct_string_children_with then
|
|
|
|
local constructor = self.construct_string_children_with
|
|
|
|
for i, j in ipairs(self) do
|
|
|
|
if (type(j) == "string") then
|
|
|
|
self[i] = constructor {j}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- all_children_are_objects
|
|
|
|
-- When true, verifies that all children are objects and not something
|
|
|
|
-- else (such as strings).
|
|
|
|
|
|
|
|
if self.all_children_are_objects then
|
|
|
|
for i, j in ipairs(self) do
|
|
|
|
if (type(j) ~= "table") then
|
|
|
|
self:__error("doesn't know what to do with child ", i,
|
|
|
|
", which is a ", type(j))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Ensure that self.install is valid.
|
|
|
|
|
|
|
|
if self.install then
|
|
|
|
local t = type(self.install)
|
|
|
|
if (t == "string") or
|
|
|
|
(t == "function") then
|
|
|
|
self.install = {self.install}
|
|
|
|
end
|
|
|
|
|
|
|
|
if (type(self.install) ~= "table") then
|
|
|
|
self:__error("doesn't know what to do with its installation command, ",
|
|
|
|
"which is a ", type(self.install), " but should be a table, function ",
|
|
|
|
"or string")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- If an attempt is made to access a variable on a node that doesn't exist,
|
|
|
|
-- and the variable starts with a capital letter, it's looked up in the
|
|
|
|
-- property scope.
|
|
|
|
|
|
|
|
function node:__index(key)
|
|
|
|
local i = string_byte(key, 1)
|
|
|
|
if (i >= 65) and (i <= 90) then
|
|
|
|
-- Scan up the class hierarchy.
|
|
|
|
|
|
|
|
local recurse
|
|
|
|
recurse = function(s, key)
|
|
|
|
if not s then
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
local o = rawget(s.object, key)
|
|
|
|
if o then
|
|
|
|
if (type(o) == "table") then
|
|
|
|
|
|
|
|
-- Handle lists of the form {PARENT, "foo", "bar"...}
|
|
|
|
if (o[1] == PARENT) then
|
|
|
|
local parent = recurse(s.next, key)
|
|
|
|
local newo = {}
|
|
|
|
|
|
|
|
if parent then
|
|
|
|
if (type(parent) ~= "table") then
|
|
|
|
parent = {parent}
|
|
|
|
end
|
|
|
|
for _, j in ipairs(parent) do
|
|
|
|
table_insert(newo, j)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
for _, j in ipairs(o) do
|
|
|
|
if (j ~= PARENT) then
|
|
|
|
table_insert(newo, j)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return newo
|
|
|
|
|
|
|
|
-- Handle lists of the form {REDIRECT, "newkey"}
|
|
|
|
elseif (o[1] == REDIRECT) then
|
|
|
|
return self:__index(o[2])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return o
|
|
|
|
end
|
|
|
|
-- Tail recursion.
|
|
|
|
return recurse(s.next, key)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- We want this node looked at first, so fake up a scope entry for it.
|
|
|
|
local fakescope = {
|
|
|
|
next = scope,
|
|
|
|
object = self
|
|
|
|
}
|
|
|
|
|
|
|
|
-- Tail recursion.
|
|
|
|
return recurse(fakescope, key)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- For local properties, just return what's here.
|
|
|
|
return rawget(self, key)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Little utility that emits an error message.
|
|
|
|
|
|
|
|
function node:__error(...)
|
|
|
|
usererror("object '", self.class, "', defined at ",
|
|
|
|
self.definedat, ", ", unpack(arg))
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Causes a node to return its outputs; that is, the files the node will
|
|
|
|
-- produce when built. The parameter contains a list of input filenames; the
|
|
|
|
-- outputs of the node's children.
|
|
|
|
|
|
|
|
function node:__outputs(inputs)
|
|
|
|
self:__error("didn't implement __outputs when it should have")
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Causes a node to return its dependencies; that is, a list of *filenames*
|
|
|
|
-- whose timestamps need to be considered when checking whether a node needs
|
|
|
|
-- to be rebuilt. This is usually, but not always, the same as the inputs.
|
|
|
|
|
|
|
|
function node:__dependencies(inputs, outputs)
|
|
|
|
return inputs
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Returns the node's timestamp. It will only get built if this is older than its
|
|
|
|
-- children's timestamps.
|
|
|
|
|
|
|
|
function node:__timestamp(inputs, outputs)
|
|
|
|
local t = 0
|
|
|
|
for _, i in ipairs(outputs) do
|
|
|
|
local tt = filetime(i)
|
|
|
|
if (tt > t) then
|
|
|
|
t = tt
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return t
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Unconditionally builds the nodes' children, collating their outputs. We
|
|
|
|
-- push a new scope while we do so, to make this object's definitions visible
|
|
|
|
-- to the children. (Almost never overridden. Only file() will want to do
|
|
|
|
-- this, most likely.)
|
|
|
|
|
|
|
|
function node:__buildchildren()
|
|
|
|
local inputs = {}
|
|
|
|
scope = {object=self, next=scope}
|
|
|
|
|
|
|
|
for _, i in ipairs(self) do
|
|
|
|
table_append(inputs, i:__build())
|
|
|
|
end
|
|
|
|
self:__buildadditionalchildren()
|
|
|
|
scope = scope.next
|
|
|
|
return inputs
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Provides a hook for building any additional children that aren't actually
|
|
|
|
-- in the child list.
|
|
|
|
|
|
|
|
function node:__buildadditionalchildren()
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Cause the node's children to be built, collating their outputs, and if
|
|
|
|
-- any output is newer than the node itself, causes the node to be built.
|
|
|
|
|
|
|
|
function node:__build()
|
|
|
|
-- Build children and collate their outputs. These will become this node's
|
|
|
|
-- inputs.
|
|
|
|
|
|
|
|
local inputs = self:__buildchildren()
|
|
|
|
|
|
|
|
-- Determine the node's outputs. This will usually be automatically
|
|
|
|
-- generated, in which case the name will depend on the overall environment ---
|
|
|
|
-- including the inputs.
|
|
|
|
|
|
|
|
local outputs = self:__outputs(inputs)
|
|
|
|
|
|
|
|
-- Get the current node's timestamp. If anything this node depends on is
|
|
|
|
-- newer than that, the node needs rebuilding.
|
|
|
|
|
|
|
|
local t = self:__timestamp(inputs, outputs)
|
|
|
|
local depends = self:__dependencies(inputs, outputs)
|
|
|
|
local rebuild = false
|
|
|
|
|
|
|
|
if (t == 0) then
|
|
|
|
rebuild = true
|
|
|
|
end
|
|
|
|
|
|
|
|
if (not rebuild and depends) then
|
|
|
|
for _, i in ipairs(depends) do
|
|
|
|
local tt = filetime(i)
|
|
|
|
-- message("comparing ", t, " with ", tt, " (", rendertable({i}), ")")
|
|
|
|
if (tt > t) then
|
|
|
|
if verbose then
|
|
|
|
message("rebuilding ", self.class, " because ", i, " newer than ", rendertable(outputs))
|
|
|
|
end
|
|
|
|
rebuild = true
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if rebuild then
|
|
|
|
self:__dobuild(inputs, outputs)
|
|
|
|
filetouch(outputs)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- If an installation command was specified, execute it now.
|
|
|
|
|
|
|
|
if self.install then
|
|
|
|
self:__invoke(self.install, inputs, outputs)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- And return this nodes' outputs.
|
|
|
|
|
|
|
|
return outputs
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Builds this node from the specified input files (the node's childrens'
|
|
|
|
-- outputs).
|
|
|
|
|
|
|
|
function node:__dobuild(inputs, outputs)
|
|
|
|
self:__error("didn't implement __dobuild when it should have")
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Recursively expands any variables in a string.
|
|
|
|
|
|
|
|
function node:__expand(s)
|
|
|
|
local searching = true
|
|
|
|
while searching do
|
|
|
|
searching = false
|
|
|
|
|
|
|
|
-- Expand %{expressions}%
|
|
|
|
|
|
|
|
s = string_gsub(s, "%%{(.-)}%%", function (expr)
|
|
|
|
searching = true
|
|
|
|
|
|
|
|
local f, e = loadstring(expr, "expression")
|
|
|
|
if not f then
|
|
|
|
self:__error("couldn't compile the expression '", expr, "': ", e)
|
|
|
|
end
|
|
|
|
|
|
|
|
local env = {self=self}
|
|
|
|
setmetatable(env, {
|
|
|
|
__index = function(_, key)
|
|
|
|
return sandbox[key]
|
|
|
|
end
|
|
|
|
})
|
|
|
|
setfenv(f, env)
|
|
|
|
|
|
|
|
f, e = pcall(f, self)
|
|
|
|
if not f then
|
|
|
|
self:__error("couldn't evaluate the expression '", expr, "': ", e)
|
|
|
|
end
|
|
|
|
|
|
|
|
return rendertable(e)
|
|
|
|
end)
|
|
|
|
|
|
|
|
-- Expand %varnames%
|
|
|
|
|
|
|
|
s = string_gsub(s, "%%(.-)%%", function (varname)
|
|
|
|
searching = true
|
|
|
|
|
|
|
|
-- Parse the string reference.
|
|
|
|
|
|
|
|
local _, _, leftcolon, rightcolon = string_find(varname, "([^:]*):?(.*)$")
|
|
|
|
local _, _, varname, selectfrom, hyphen, selectto = string_find(leftcolon, "^([^[]*)%[?([^-%]]*)(%-?)([^%]]*)]?$")
|
|
|
|
|
|
|
|
-- Get the basic value that the rest of the reference is going to
|
|
|
|
-- depend on.
|
|
|
|
|
|
|
|
local result = self:__index(varname)
|
|
|
|
if not result then
|
|
|
|
self:__error("doesn't understand variable '", varname, "'")
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Process any selector, if specified.
|
|
|
|
|
|
|
|
if (selectfrom ~= "") or (hyphen ~= "") or (selectto ~= "") then
|
|
|
|
if (type(result) ~= "table") then
|
|
|
|
self:__error("tried to use a [] selector on variable '", varname,
|
|
|
|
"', which doesn't contain a table")
|
|
|
|
end
|
|
|
|
local n = table_getn(result)
|
|
|
|
|
|
|
|
selectfrom = tonumber(selectfrom)
|
|
|
|
selectto = tonumber(selectto)
|
|
|
|
|
|
|
|
if (hyphen ~= "") then
|
|
|
|
if not selectfrom then
|
|
|
|
selectfrom = 1
|
|
|
|
end
|
|
|
|
if not selectto then
|
|
|
|
selectto = n
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if not selectto then
|
|
|
|
selectto = selectfrom
|
|
|
|
end
|
|
|
|
if not selectfrom then
|
|
|
|
self:__error("tried to use an empty selector on variable '", varname, "'")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if (selectfrom < 1) or (selectto < 1) or
|
|
|
|
(selectfrom > n) or (selectto > n) or
|
|
|
|
(selectto < selectfrom) then
|
|
|
|
self:__error("tried to use an invalid selector [",
|
|
|
|
selectfrom, "-", selectto, "] on variable '", varname,
|
|
|
|
"'; only [1-", n, "] is valid")
|
|
|
|
end
|
|
|
|
|
|
|
|
local newresult = {}
|
|
|
|
for i = selectfrom, selectto do
|
|
|
|
table_insert(newresult, result[i])
|
|
|
|
end
|
|
|
|
result = newresult
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Process any string modifier, if supplied.
|
|
|
|
|
|
|
|
if (rightcolon ~= "") then
|
|
|
|
local f = stringmodifier[rightcolon]
|
|
|
|
if not f then
|
|
|
|
self:__error("tried to use an unknown string modifier '",
|
|
|
|
rightcolon, "' on variable '", varname, "'")
|
|
|
|
end
|
|
|
|
|
|
|
|
result = f(self, result)
|
|
|
|
end
|
|
|
|
|
|
|
|
return rendertable(result)
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Any remaining %% sequences must be empty, and so convert them into
|
|
|
|
-- single % sequences.
|
|
|
|
|
|
|
|
s = string_gsub(s, "%%%%", "%")
|
|
|
|
return s
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Expands any variables in a command table, and executes it.
|
|
|
|
|
|
|
|
function node:__invoke(command, inputs, outputs)
|
|
|
|
if (type(command) ~= "table") then
|
|
|
|
command = {command}
|
|
|
|
end
|
|
|
|
|
|
|
|
for _, s in ipairs(command) do
|
|
|
|
if (type(s) == "string") then
|
|
|
|
s = self:__expand(s)
|
|
|
|
if not quiet then
|
|
|
|
traceoutput(s)
|
|
|
|
end
|
|
|
|
if not no_execute then
|
|
|
|
local r = os.execute(s)
|
|
|
|
if (r ~= 0) then
|
|
|
|
return r
|
|
|
|
end
|
|
|
|
end
|
|
|
|
elseif (type(s) == "function") then
|
|
|
|
local r = s(self, inputs, outputs)
|
|
|
|
if r then
|
|
|
|
return r
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
-- ======================================================================= --
|
|
|
|
-- PROLOGUE --
|
|
|
|
-- ======================================================================= --
|
|
|
|
|
|
|
|
-- The prologue contains the standard library that all pmfiles can refer to.
|
|
|
|
-- For simplicity, it's implemented by code running inside the sandbox,
|
|
|
|
-- which means that it's basically identical to user code (and could, in
|
|
|
|
-- fact, be kept in a seperate file).
|
|
|
|
|
|
|
|
-- Here we set up the sandbox.
|
|
|
|
|
|
|
|
table_merge(sandbox, {
|
|
|
|
VERSION = VERSION,
|
|
|
|
|
|
|
|
assert = assert,
|
|
|
|
collectgarbage = collectgarbage,
|
|
|
|
dofile = dofile,
|
|
|
|
error = error,
|
|
|
|
getfenv = getfenv,
|
|
|
|
getmetatable = getmetatable,
|
|
|
|
gcinfo = gcinfo,
|
|
|
|
ipairs = ipairs,
|
|
|
|
loadfile = loadfile,
|
|
|
|
loadlib = loadlib,
|
|
|
|
loadstring = loadstring,
|
|
|
|
next = next,
|
|
|
|
pairs = pairs,
|
|
|
|
pcall = pcall,
|
|
|
|
print = print,
|
|
|
|
rawequal = rawequal,
|
|
|
|
rawget = rawget,
|
|
|
|
rawset = rawset,
|
|
|
|
require = require,
|
|
|
|
setfenv = setfenv,
|
|
|
|
setmetatable = setmetatable,
|
|
|
|
tonumber = tonumber,
|
|
|
|
tostring = tostring,
|
|
|
|
type = type,
|
|
|
|
unpack = unpack,
|
|
|
|
_VERSION = _VERSION,
|
|
|
|
xpcall = xpcall,
|
|
|
|
|
|
|
|
table = table,
|
|
|
|
io = io,
|
|
|
|
os = os,
|
|
|
|
posix = posix,
|
|
|
|
string = string,
|
|
|
|
debug = debug,
|
|
|
|
loadlib = loadlib,
|
|
|
|
|
|
|
|
pm = _G,
|
|
|
|
node = node,
|
|
|
|
|
|
|
|
PARENT = PARENT,
|
|
|
|
EMPTY = EMPTY,
|
|
|
|
REDIRECT = REDIRECT,
|
|
|
|
})
|
|
|
|
|
|
|
|
-- Cause any reads from undefined keys in the sandbox to fail with an error.
|
|
|
|
-- This helps debugging pmfiles somewhat.
|
|
|
|
|
|
|
|
setmetatable(sandbox, {
|
|
|
|
__index = function(self, key)
|
|
|
|
local value = rawget(self, key)
|
|
|
|
if (value == nil) then
|
|
|
|
error(key.." could not be found in any applicable scope")
|
|
|
|
end
|
|
|
|
return value
|
|
|
|
end
|
|
|
|
})
|
|
|
|
|
|
|
|
-- Switch into sandbox mode.
|
|
|
|
|
|
|
|
setfenv(1, sandbox)
|
|
|
|
|
|
|
|
--- Assorted utilities ------------------------------------------------------
|
|
|
|
|
|
|
|
-- Includes a file.
|
|
|
|
|
|
|
|
function include(f, ...)
|
|
|
|
local c, e = loadfile(f)
|
|
|
|
if not c then
|
|
|
|
usererror("script compilation error: ", e)
|
|
|
|
end
|
|
|
|
|
|
|
|
setfenv(c, sandbox)
|
|
|
|
local arguments = arg
|
|
|
|
xpcall(
|
|
|
|
function()
|
|
|
|
c(unpack(arguments))
|
|
|
|
end,
|
|
|
|
function(e)
|
|
|
|
message("script execution error --- traceback follows:")
|
|
|
|
traceback(e)
|
|
|
|
end
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
--- file --------------------------------------------------------------------
|
|
|
|
|
|
|
|
-- file() is pretty much the simplest clause. It takes a list of filenames,
|
|
|
|
-- and outputs them.
|
|
|
|
--
|
|
|
|
-- * Building does nothing.
|
|
|
|
-- * Its outputs are its inputs.
|
|
|
|
--
|
|
|
|
-- Note: this clause only takes *strings* as its children. If a reference is
|
|
|
|
-- made to a file that doesn't exist, an error occurs.
|
|
|
|
|
|
|
|
file = node {
|
|
|
|
class = "file",
|
|
|
|
ensure_at_least_one_child = true,
|
|
|
|
|
|
|
|
__init = function(self, p)
|
|
|
|
node.__init(self, p)
|
|
|
|
|
|
|
|
-- If we're a class, don't verify.
|
|
|
|
|
|
|
|
if ((type(p) == "table") and p.class) then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Ensure that the file's children are strings.
|
|
|
|
|
|
|
|
for i, j in ipairs(self) do
|
|
|
|
if (type(j) ~= "string") then
|
|
|
|
self:__error("doesn't know what to do with child ", i,
|
|
|
|
", which is a ", type(j))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
|
|
|
|
-- File's timestamp is special and will bail if it meets a nonexistant file.
|
|
|
|
|
|
|
|
__timestamp = function(self, inputs, outputs)
|
|
|
|
local t = 0
|
|
|
|
for _, i in ipairs(outputs) do
|
|
|
|
i = self:__expand(i)
|
|
|
|
local tt = filetime(i)
|
|
|
|
if (tt == 0) then
|
|
|
|
self:__error("is referring to the file '", i, "' which does not exist")
|
|
|
|
end
|
|
|
|
if (tt > t) then
|
|
|
|
t = tt
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return t
|
|
|
|
end,
|
|
|
|
|
|
|
|
-- Outputs are inputs.
|
|
|
|
|
|
|
|
__outputs = function(self, inputs)
|
|
|
|
local o = {}
|
|
|
|
local n
|
|
|
|
if self.only_n_children_are_outputs then
|
|
|
|
n = self.only_n_children_are_outputs
|
|
|
|
else
|
|
|
|
n = table_getn(inputs)
|
|
|
|
end
|
|
|
|
|
|
|
|
for i = 1, n do
|
|
|
|
o[i] = inputs[i]
|
|
|
|
end
|
|
|
|
|
|
|
|
return o
|
|
|
|
end,
|
|
|
|
|
|
|
|
-- Building children does nothing; outputs are inputs.
|
|
|
|
|
|
|
|
__buildchildren = function(self)
|
|
|
|
local outputs = {}
|
|
|
|
table_append(outputs, self)
|
|
|
|
return outputs
|
|
|
|
end,
|
|
|
|
|
|
|
|
-- Building does nothing.
|
|
|
|
|
|
|
|
__dobuild = function(self, inputs, outputs)
|
|
|
|
end,
|
|
|
|
}
|
|
|
|
|
|
|
|
--- group -------------------------------------------------------------------
|
|
|
|
|
|
|
|
-- group() is also the simplest clause. It does nothing, existing only to
|
|
|
|
-- group together its children.
|
|
|
|
|
|
|
|
group = node {
|
|
|
|
class = "group",
|
|
|
|
|
|
|
|
-- Outputs are inputs.
|
|
|
|
|
|
|
|
__outputs = function(self, inputs)
|
|
|
|
return inputs
|
|
|
|
end,
|
|
|
|
|
|
|
|
-- Building does nothing.
|
|
|
|
|
|
|
|
__dobuild = function(self, inputs, outputs)
|
|
|
|
end,
|
|
|
|
}
|
|
|
|
|
|
|
|
--- deponly -----------------------------------------------------------------
|
|
|
|
|
|
|
|
-- deponly() is the one-and-a-halfth most simplest clause. It acts like
|
|
|
|
-- group {}, but returns no outputs. It's useful for ensuring that building
|
|
|
|
-- one node causes another node to be built without actually using the
|
|
|
|
-- second node's outputs.
|
|
|
|
|
|
|
|
deponly = node {
|
|
|
|
class = "deponly",
|
|
|
|
ensure_at_least_one_child = true,
|
|
|
|
|
|
|
|
-- Emits no outputs
|
|
|
|
|
|
|
|
__outputs = function(self, inputs)
|
|
|
|
return {}
|
|
|
|
end,
|
|
|
|
|
|
|
|
-- Building does nothing.
|
|
|
|
|
|
|
|
__dobuild = function(self, inputs, outputs)
|
|
|
|
end,
|
|
|
|
}
|
|
|
|
|
|
|
|
--- ith ---------------------------------------------------------------------
|
|
|
|
|
|
|
|
-- ith() is the second simplest clause. It acts like group {}, but returns
|
|
|
|
-- only some of the specified output. It is suitable for extracting, say,
|
|
|
|
-- one output from a clause to pass to cfile {}.
|
|
|
|
|
|
|
|
ith = node {
|
|
|
|
class = "ith",
|
|
|
|
ensure_at_least_one_child = true,
|
|
|
|
|
|
|
|
__init = function(self, p)
|
|
|
|
node.__init(self, p)
|
|
|
|
|
|
|
|
-- If we're a class, don't verify.
|
|
|
|
|
|
|
|
if ((type(p) == "table") and p.class) then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
-- If we have an i property, ensure we don't have a from or
|
|
|
|
-- to property.
|
|
|
|
|
|
|
|
if self.i then
|
|
|
|
if self.from or self.to then
|
|
|
|
self:__error("can't have both an i property and a from or to property")
|
|
|
|
end
|
|
|
|
|
|
|
|
if (type(self.i) ~= "number") then
|
|
|
|
self:__error("doesn't know what to do with its i property, ",
|
|
|
|
"which is a ", type(self.i), " where a number was expected")
|
|
|
|
end
|
|
|
|
|
|
|
|
self.from = self.i
|
|
|
|
self.to = self.i
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Ensure the from and to properties are numbers, if they exist.
|
|
|
|
|
|
|
|
if self.from then
|
|
|
|
if (type(self.from) ~= "number") then
|
|
|
|
self:__error("doesn't know what to do with its from property, ",
|
|
|
|
"which is a ", type(self.from), " where a number was expected")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if self.to then
|
|
|
|
if (type(self.to) ~= "number") then
|
|
|
|
self:__error("doesn't know what to do with its to property, ",
|
|
|
|
"which is a ", type(self.to), " where a number was expected")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
|
|
|
|
-- Emits one output, which is one of the inputs.
|
|
|
|
|
|
|
|
__outputs = function(self, inputs)
|
|
|
|
local n = table_getn(inputs)
|
|
|
|
local from = self.from or 1
|
|
|
|
local to = self.to or n
|
|
|
|
|
|
|
|
if (from < 1) or (to > n) then
|
|
|
|
self:__error("tried to select range ", from, " to ", to,
|
|
|
|
" from only ", n, " inputs")
|
|
|
|
end
|
|
|
|
|
|
|
|
local range = {}
|
|
|
|
for i = from, to do
|
|
|
|
table_append(range, inputs[i])
|
|
|
|
end
|
|
|
|
return range
|
|
|
|
end,
|
|
|
|
|
|
|
|
-- Building does nothing.
|
|
|
|
|
|
|
|
__dobuild = function(self, inputs, outputs)
|
|
|
|
end,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
--- foreach -----------------------------------------------------------------
|
|
|
|
|
|
|
|
-- foreach {} is the counterpart to ith {}. It applies a particular rule to
|
|
|
|
-- all of its children.
|
|
|
|
|
|
|
|
foreach = node {
|
|
|
|
class = "foreach",
|
|
|
|
|
|
|
|
__init = function(self, p)
|
|
|
|
node.__init(self, p)
|
|
|
|
|
|
|
|
-- If we're a class, don't verify.
|
|
|
|
|
|
|
|
if ((type(p) == "table") and p.class) then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Ensure we have a rule property which is a table.
|
|
|
|
|
|
|
|
if not self.rule then
|
|
|
|
self:__error("must have a rule property")
|
|
|
|
end
|
|
|
|
if (type(self.rule) ~= "table") then
|
|
|
|
self:__error("doesn't know what to do with its rule property, ",
|
|
|
|
"which is a ", type(self.rule), " where a table was expected")
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
|
|
|
|
-- Build all our children via the rule.
|
|
|
|
--
|
|
|
|
-- This is pretty much a copy of node.__buildchildren().
|
|
|
|
|
|
|
|
__buildchildren = function(self)
|
|
|
|
scope = {object=self, next=scope}
|
|
|
|
|
|
|
|
local intermediate = {}
|
|
|
|
for _, i in ipairs(self) do
|
|
|
|
table_append(intermediate, i:__build())
|
|
|
|
end
|
|
|
|
|
|
|
|
local inputs = {}
|
|
|
|
for _, i in ipairs(intermediate) do
|
|
|
|
local r = self.rule { i }
|
|
|
|
table_append(inputs, r:__build())
|
|
|
|
end
|
|
|
|
|
|
|
|
self:__buildadditionalchildren()
|
|
|
|
scope = scope.next
|
|
|
|
return inputs
|
|
|
|
end,
|
|
|
|
|
|
|
|
-- Inputs are outputs --- because __buildchildren has already done the
|
|
|
|
-- necessary work.
|
|
|
|
|
|
|
|
__outputs = function(self, inputs)
|
|
|
|
return inputs
|
|
|
|
end,
|
|
|
|
|
|
|
|
-- Building does nothing.
|
|
|
|
|
|
|
|
__dobuild = function(self, inputs, outputs)
|
|
|
|
end,
|
|
|
|
}
|
|
|
|
|
|
|
|
--- Simple ---------------------------------------------------------------
|
|
|
|
|
|
|
|
-- simple is the most common clause, and implements make-like behaviour:
|
|
|
|
-- the named command is executed in order to rebuild the node.
|
|
|
|
--
|
|
|
|
-- * The timestamp is the newest timestamp of its outputs.
|
|
|
|
-- * Building executes the command.
|
|
|
|
-- * Its outputs are automatically generated by expanding the templates
|
|
|
|
-- in the 'outputs' variable.
|
|
|
|
|
|
|
|
simple = node {
|
|
|
|
class = "file",
|
|
|
|
construct_string_children_with = file,
|
|
|
|
all_children_are_objects = true,
|
|
|
|
|
|
|
|
__init = function(self, p)
|
|
|
|
node.__init(self, p)
|
|
|
|
|
|
|
|
-- If we're a class, don't verify.
|
|
|
|
|
|
|
|
if ((type(p) == "table") and p.class) then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
-- outputs must exist, and must be a table.
|
|
|
|
|
|
|
|
if not self.outputs then
|
|
|
|
self:__error("must have an outputs template set")
|
|
|
|
end
|
|
|
|
|
|
|
|
if (type(self.outputs) ~= "table") then
|
|
|
|
self:__error("doesn't know what to do with its outputs, which is a ",
|
|
|
|
type(self.outputs), " but should be a table")
|
|
|
|
end
|
|
|
|
|
|
|
|
-- There must be a command which must be a string or table.
|
|
|
|
|
|
|
|
if not self.command then
|
|
|
|
self:__error("must have a command specified")
|
|
|
|
end
|
|
|
|
if (type(self.command) == "string") then
|
|
|
|
self.command = {self.command}
|
|
|
|
end
|
|
|
|
if (type(self.command) ~= "table") then
|
|
|
|
self:__error("doesn't know what to do with its command, which is a ",
|
|
|
|
type(self.command), " but should be a string or a table")
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
|
|
|
|
-- Outputs are specified manually.
|
|
|
|
|
|
|
|
__outputs = function(self, inputs)
|
|
|
|
self["in"] = inputs
|
|
|
|
|
|
|
|
local input
|
|
|
|
if inputs then
|
|
|
|
input = inputs[1]
|
|
|
|
end
|
|
|
|
if not input then
|
|
|
|
input = ""
|
|
|
|
end
|
|
|
|
|
|
|
|
self.I = string_gsub(input, "^.*/", "")
|
|
|
|
self.I = string_gsub(self.I, "%..-$", "")
|
|
|
|
|
|
|
|
-- Construct an outputs array for use in the cache key. This mirrors
|
|
|
|
-- what the final array will be, but the unique ID is going to be 0.
|
|
|
|
|
|
|
|
self.out = {}
|
|
|
|
self.U = 0
|
|
|
|
for _, i in ipairs(self.outputs) do
|
|
|
|
i = self:__expand(i)
|
|
|
|
table_append(self.out, i)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Determine the cache key we're going to use.
|
|
|
|
|
|
|
|
local cachekey = table_concat(self.command, " && ")
|
|
|
|
cachekey = self:__expand(cachekey)
|
|
|
|
cachekey = create_intermediate_cache_key(cachekey)
|
|
|
|
|
|
|
|
-- Work out the unique ID.
|
|
|
|
--
|
|
|
|
-- Note: we're running in the sandbox, so we need to fully qualify
|
|
|
|
-- pm.intermediate_cache_dir.
|
|
|
|
|
|
|
|
self.U = pm.intermediate_cache_dir..cachekey
|
|
|
|
|
|
|
|
-- Construct the real outputs array.
|
|
|
|
|
|
|
|
self.out = {}
|
|
|
|
for _, i in ipairs(self.outputs) do
|
|
|
|
i = self:__expand(i)
|
|
|
|
mkcontainerdir(i)
|
|
|
|
table_append(self.out, i)
|
|
|
|
end
|
|
|
|
|
|
|
|
return self.out
|
|
|
|
end,
|
|
|
|
|
|
|
|
-- Building causes the command to be expanded and invoked. The 'children'
|
|
|
|
-- variable is set to the input files.
|
|
|
|
|
|
|
|
__dobuild = function(self, inputs, outputs)
|
|
|
|
self["in"] = inputs
|
|
|
|
self.out = outputs
|
|
|
|
local r = self:__invoke(self.command, inputs, outputs)
|
|
|
|
if r then
|
|
|
|
if delete_output_files_on_error then
|
|
|
|
self:__invoke({"%RM% %out%"})
|
|
|
|
end
|
|
|
|
self:__error("failed to build with return code ", r)
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
}
|
|
|
|
|
|
|
|
--- End of prologue ---------------------------------------------------------
|
|
|
|
|
|
|
|
-- Set a few useful global variables.
|
|
|
|
|
|
|
|
RM = "rm -f"
|
|
|
|
INSTALL = "ln -f"
|
|
|
|
|
|
|
|
-- Now we're done, switch out of sandbox mode again. This only works
|
|
|
|
-- because we made _G local at the top of the file, which makes it
|
|
|
|
-- lexically scoped rather than looked up via the environment.
|
|
|
|
|
|
|
|
setfenv(1, _G)
|
|
|
|
|
|
|
|
-- ======================================================================= --
|
|
|
|
-- APPLICATION DRIVER --
|
|
|
|
-- ======================================================================= --
|
|
|
|
|
|
|
|
-- Parse and process the command line options.
|
|
|
|
|
|
|
|
do
|
|
|
|
local function do_help(opt)
|
|
|
|
message("Prime Mover version ", VERSION, " © 2006 David Given")
|
|
|
|
stdout:write([[
|
|
|
|
Syntax: pm [<options...>] [<targets>]
|
|
|
|
Options:
|
|
|
|
-h --help Displays this message.
|
|
|
|
--license List Prime Mover's redistribution license.
|
|
|
|
-cX --cachedir X Sets the object file cache to directory X.
|
|
|
|
-p --purge Purges the cache before execution.
|
|
|
|
WARNING: will remove *everything* in the cache dir!
|
|
|
|
-fX --file X Reads in the pmfile X. May be specified multiple times.
|
|
|
|
-DX=Y --define X=Y Defines variable X to value Y (or true if Y omitted)
|
|
|
|
-n --no-execute Don't actually execute anything
|
|
|
|
-v --verbose Be more verbose
|
|
|
|
-q --quiet Be more quiet
|
|
|
|
|
|
|
|
If no pmfiles are explicitly specified, 'pmfile' is read.
|
|
|
|
If no targets are explicitly specified, 'default' is built.
|
|
|
|
Options and targets may be specified in any order.
|
|
|
|
]])
|
|
|
|
os.exit(0)
|
|
|
|
end
|
|
|
|
|
|
|
|
local function do_license(opt)
|
|
|
|
message("Prime Mover version ", VERSION, " © 2006 David Given")
|
|
|
|
stdout:write([[
|
|
|
|
|
|
|
|
Prime Mover is licensed under the MIT open source license.
|
|
|
|
|
|
|
|
Copyright © 2006 David Given
|
|
|
|
|
|
|
|
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.
|
|
|
|
]])
|
|
|
|
os.exit(0)
|
|
|
|
end
|
|
|
|
|
|
|
|
local function needarg(opt)
|
|
|
|
if not opt then
|
|
|
|
usererror("missing option parameter")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local function do_cachedir(opt)
|
|
|
|
needarg(opt)
|
|
|
|
intermediate_cache_dir = opt
|
|
|
|
return 1
|
|
|
|
end
|
|
|
|
|
|
|
|
local function do_inputfile(opt)
|
|
|
|
needarg(opt)
|
|
|
|
table_append(input_files, opt)
|
|
|
|
return 1
|
|
|
|
end
|
|
|
|
|
|
|
|
local function do_purgecache(opt)
|
|
|
|
purge_intermediate_cache = true
|
|
|
|
return 0
|
|
|
|
end
|
|
|
|
|
|
|
|
local function do_define(opt)
|
|
|
|
needarg(opt)
|
|
|
|
|
|
|
|
local s, e, key, value = string_find(opt, "^([^=]*)=(.*)$")
|
|
|
|
if not key then
|
|
|
|
key = opt
|
|
|
|
value = true
|
|
|
|
end
|
|
|
|
|
|
|
|
sandbox[key] = value
|
|
|
|
return 1
|
|
|
|
end
|
|
|
|
|
|
|
|
local function do_no_execute(opt)
|
|
|
|
no_execute = true
|
|
|
|
return 0
|
|
|
|
end
|
|
|
|
|
|
|
|
local function do_verbose(opt)
|
|
|
|
verbose = true
|
|
|
|
return 0
|
|
|
|
end
|
|
|
|
|
|
|
|
local function do_quiet(opt)
|
|
|
|
quiet = true
|
|
|
|
return 0
|
|
|
|
end
|
|
|
|
|
|
|
|
local argmap = {
|
|
|
|
["h"] = do_help,
|
|
|
|
["help"] = do_help,
|
|
|
|
["c"] = do_cachedir,
|
|
|
|
["cachedir"] = do_cachedir,
|
|
|
|
["p"] = do_purgecache,
|
|
|
|
["purge"] = do_purgecache,
|
|
|
|
["f"] = do_inputfile,
|
|
|
|
["file"] = do_inputfile,
|
|
|
|
["D"] = do_define,
|
|
|
|
["define"] = do_define,
|
|
|
|
["n"] = do_no_execute,
|
|
|
|
["no-execute"] = do_no_execute,
|
|
|
|
["v"] = do_verbose,
|
|
|
|
["verbose"] = do_verbose,
|
|
|
|
["q"] = do_quiet,
|
|
|
|
["quiet"] = do_quiet,
|
|
|
|
["license"] = do_license,
|
|
|
|
}
|
|
|
|
|
|
|
|
-- Called on an unrecognised option.
|
|
|
|
|
|
|
|
local function unrecognisedarg(arg)
|
|
|
|
usererror("unrecognised option '", arg, "' --- try --help for help")
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Do the actual argument parsing.
|
|
|
|
|
|
|
|
for i = 1, table_getn(arg) do
|
|
|
|
local o = arg[i]
|
|
|
|
local op
|
|
|
|
|
|
|
|
if (string_byte(o, 1) == 45) then
|
|
|
|
-- This is an option.
|
|
|
|
if (string_byte(o, 2) == 45) then
|
|
|
|
-- ...with a -- prefix.
|
|
|
|
o = string_sub(o, 3)
|
|
|
|
local fn = argmap[o]
|
|
|
|
if not fn then
|
|
|
|
unrecognisedarg("--"..o)
|
|
|
|
end
|
|
|
|
local op = arg[i+1]
|
|
|
|
i = i + fn(op)
|
|
|
|
else
|
|
|
|
-- ...without a -- prefix.
|
|
|
|
local od = string_sub(o, 2, 2)
|
|
|
|
local fn = argmap[od]
|
|
|
|
if not fn then
|
|
|
|
unrecognisedarg("-"..od)
|
|
|
|
end
|
|
|
|
op = string_sub(o, 3)
|
|
|
|
if (op == "") then
|
|
|
|
op = arg[i+1]
|
|
|
|
i = i + fn(op)
|
|
|
|
else
|
|
|
|
fn(op)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
else
|
|
|
|
-- This is a target name.
|
|
|
|
table_append(targets, o)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Option fallbacks.
|
|
|
|
|
|
|
|
if (table_getn(input_files) == 0) then
|
|
|
|
input_files = {"pmfile"}
|
|
|
|
end
|
|
|
|
|
|
|
|
if (table_getn(targets) == 0) then
|
|
|
|
targets = {"default"}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Load any input files.
|
|
|
|
|
|
|
|
for _, i in ipairs(input_files) do
|
|
|
|
sandbox.include(i, unpack(arg))
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Set up the intermediate cache.
|
|
|
|
|
|
|
|
if purge_intermediate_cache then
|
|
|
|
create_intermediate_cache()
|
|
|
|
else
|
|
|
|
load_intermediate_cache()
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Build any targets.
|
|
|
|
|
|
|
|
for _, i in ipairs(targets) do
|
|
|
|
local o = sandbox[i]
|
|
|
|
if not o then
|
|
|
|
usererror("don't know how to build '", i, "'")
|
|
|
|
end
|
|
|
|
if ((type(o) ~= "table") and not o.class) then
|
|
|
|
usererror("'", i, "' doesn't seem to be a valid target")
|
|
|
|
end
|
|
|
|
|
|
|
|
-- xpcall(
|
|
|
|
-- function()
|
|
|
|
o:__build()
|
|
|
|
-- end,
|
|
|
|
-- function(e)
|
|
|
|
-- message("rule engine execution error --- traceback follows:")
|
|
|
|
-- traceback(e)
|
|
|
|
-- end
|
|
|
|
-- )
|
|
|
|
end
|
|
|
|
|
2006-07-20 22:57:46 +00:00
|
|
|
XXXXSTARTinterpreter
|
2006-10-15 00:28:12 +00:00
|
|
|
253576
|
|
|
|
#include <signal.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <locale.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/utsname.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <grp.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <utime.h>
|
|
|
|
#include <setjmp.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <sys/times.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#line 1 "lapi.c"
|
|
|
|
#define lapi_c
|
|
|
|
#line 1 "lua.h"
|
|
|
|
#ifndef lua_h
|
|
|
|
#define lua_h
|
|
|
|
#define LUA_NUMBER int
|
|
|
|
#define LUA_NUMBER_SCAN "%d"
|
|
|
|
#define LUA_NUMBER_FMT "%d"
|
|
|
|
#define LUA_VERSION "Lua 5.0.2 (patched for Prime Mover)"
|
|
|
|
#define LUA_COPYRIGHT "Copyright (C) 1994-2004 Tecgraf, PUC-Rio"
|
|
|
|
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
|
|
|
|
#define LUA_MULTRET (-1)
|
|
|
|
#define LUA_REGISTRYINDEX (-10000)
|
|
|
|
#define LUA_GLOBALSINDEX (-10001)
|
|
|
|
#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i))
|
|
|
|
#define LUA_ERRRUN 1
|
|
|
|
#define LUA_ERRFILE 2
|
|
|
|
#define LUA_ERRSYNTAX 3
|
|
|
|
#define LUA_ERRMEM 4
|
|
|
|
#define LUA_ERRERR 5
|
|
|
|
typedef struct lua_State lua_State;typedef int(*lua_CFunction)(lua_State*L);
|
|
|
|
typedef const char*(*lua_Chunkreader)(lua_State*L,void*ud,size_t*sz);typedef
|
|
|
|
int(*lua_Chunkwriter)(lua_State*L,const void*p,size_t sz,void*ud);
|
|
|
|
#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_MINSTACK 20
|
|
|
|
#ifdef LUA_USER_H
|
|
|
|
#include LUA_USER_H
|
|
|
|
#endif
|
|
|
|
#ifndef LUA_NUMBER
|
|
|
|
typedef double lua_Number;
|
|
|
|
#else
|
|
|
|
typedef LUA_NUMBER lua_Number;
|
|
|
|
#endif
|
|
|
|
#ifndef LUA_API
|
|
|
|
#define LUA_API extern
|
|
|
|
#endif
|
|
|
|
LUA_API lua_State*lua_open(void);LUA_API void lua_close(lua_State*L);LUA_API
|
|
|
|
lua_State*lua_newthread(lua_State*L);LUA_API lua_CFunction lua_atpanic(
|
|
|
|
lua_State*L,lua_CFunction panicf);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_remove(lua_State*L,int idx);LUA_API void lua_insert(
|
|
|
|
lua_State*L,int idx);LUA_API void lua_replace(lua_State*L,int idx);LUA_API int
|
|
|
|
lua_checkstack(lua_State*L,int sz);LUA_API void lua_xmove(lua_State*from,
|
|
|
|
lua_State*to,int n);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_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 int lua_equal(lua_State*L,int idx1,int idx2);LUA_API int lua_rawequal(
|
|
|
|
lua_State*L,int idx1,int idx2);LUA_API int lua_lessthan(lua_State*L,int idx1,
|
|
|
|
int idx2);LUA_API lua_Number lua_tonumber(lua_State*L,int idx);LUA_API int
|
|
|
|
lua_toboolean(lua_State*L,int idx);LUA_API const char*lua_tostring(lua_State*L
|
|
|
|
,int idx);LUA_API size_t lua_strlen(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);LUA_API void lua_pushnil(lua_State*L);
|
|
|
|
LUA_API void lua_pushnumber(lua_State*L,lua_Number n);LUA_API void
|
|
|
|
lua_pushlstring(lua_State*L,const char*s,size_t l);LUA_API void 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 void lua_gettable(lua_State*
|
|
|
|
L,int idx);LUA_API void lua_rawget(lua_State*L,int idx);LUA_API void
|
|
|
|
lua_rawgeti(lua_State*L,int idx,int n);LUA_API void lua_newtable(lua_State*L);
|
|
|
|
LUA_API void*lua_newuserdata(lua_State*L,size_t sz);LUA_API int
|
|
|
|
lua_getmetatable(lua_State*L,int objindex);LUA_API void lua_getfenv(lua_State*
|
|
|
|
L,int idx);LUA_API void lua_settable(lua_State*L,int idx);LUA_API void
|
|
|
|
lua_rawset(lua_State*L,int idx);LUA_API void lua_rawseti(lua_State*L,int idx,
|
|
|
|
int n);LUA_API int lua_setmetatable(lua_State*L,int objindex);LUA_API int
|
|
|
|
lua_setfenv(lua_State*L,int idx);LUA_API void lua_call(lua_State*L,int nargs,
|
|
|
|
int nresults);LUA_API int lua_pcall(lua_State*L,int nargs,int nresults,int
|
|
|
|
errfunc);LUA_API int lua_cpcall(lua_State*L,lua_CFunction func,void*ud);
|
|
|
|
LUA_API int lua_load(lua_State*L,lua_Chunkreader reader,void*dt,const char*
|
|
|
|
chunkname);LUA_API int lua_dump(lua_State*L,lua_Chunkwriter writer,void*data);
|
|
|
|
LUA_API int lua_yield(lua_State*L,int nresults);LUA_API int lua_resume(
|
|
|
|
lua_State*L,int narg);LUA_API int lua_getgcthreshold(lua_State*L);LUA_API int
|
|
|
|
lua_getgccount(lua_State*L);LUA_API void lua_setgcthreshold(lua_State*L,int
|
|
|
|
newthreshold);LUA_API const char*lua_version(void);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);
|
|
|
|
#define lua_boxpointer(L,u) (*(void**)(lua_newuserdata(L,sizeof(void*)))=(u))
|
|
|
|
#define lua_unboxpointer(L,i) (*(void**)(lua_touserdata(L,i)))
|
|
|
|
#define lua_pop(L,n) lua_settop(L,-(n)-1)
|
|
|
|
#define lua_register(L,n,f) (lua_pushstring(L,n),lua_pushcfunction(L,f),\
|
|
|
|
lua_settable(L,LUA_GLOBALSINDEX))
|
|
|
|
#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_isnone(L,n) (lua_type(L,n)==LUA_TNONE)
|
|
|
|
#define lua_isnoneornil(L, n)(lua_type(L,n)<=0)
|
|
|
|
#define lua_pushliteral(L, s)lua_pushlstring(L,""s,(sizeof(s)/sizeof(char))-1)
|
|
|
|
LUA_API int lua_pushupvalues(lua_State*L);
|
|
|
|
#define lua_getregistry(L) lua_pushvalue(L,LUA_REGISTRYINDEX)
|
|
|
|
#define lua_setglobal(L,s) (lua_pushstring(L,s),lua_insert(L,-2),lua_settable(\
|
|
|
|
L,LUA_GLOBALSINDEX))
|
|
|
|
#define lua_getglobal(L,s) (lua_pushstring(L,s),lua_gettable(L,\
|
|
|
|
LUA_GLOBALSINDEX))
|
|
|
|
#define LUA_NOREF (-2)
|
|
|
|
#define LUA_REFNIL (-1)
|
|
|
|
#define lua_ref(L,lock) ((lock)?luaL_ref(L,LUA_REGISTRYINDEX):(lua_pushstring(\
|
|
|
|
L,"unlocked references are obsolete"),lua_error(L),0))
|
|
|
|
#define lua_unref(L,ref) luaL_unref(L,LUA_REGISTRYINDEX,(ref))
|
|
|
|
#define lua_getref(L,ref) lua_rawgeti(L,LUA_REGISTRYINDEX,ref)
|
|
|
|
#ifndef LUA_NUMBER_SCAN
|
|
|
|
#define LUA_NUMBER_SCAN "%lf"
|
|
|
|
#endif
|
|
|
|
#ifndef LUA_NUMBER_FMT
|
|
|
|
#define LUA_NUMBER_FMT "%.14g"
|
|
|
|
#endif
|
|
|
|
#define LUA_HOOKCALL 0
|
|
|
|
#define LUA_HOOKRET 1
|
|
|
|
#define LUA_HOOKLINE 2
|
|
|
|
#define LUA_HOOKCOUNT 3
|
|
|
|
#define LUA_HOOKTAILRET 4
|
|
|
|
#define LUA_MASKCALL (1<<LUA_HOOKCALL)
|
|
|
|
#define LUA_MASKRET (1<<LUA_HOOKRET)
|
|
|
|
#define LUA_MASKLINE (1<<LUA_HOOKLINE)
|
|
|
|
#define LUA_MASKCOUNT (1<<LUA_HOOKCOUNT)
|
|
|
|
typedef struct lua_Debug lua_Debug;typedef void(*lua_Hook)(lua_State*L,
|
|
|
|
lua_Debug*ar);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 int 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);
|
|
|
|
#define LUA_IDSIZE 60
|
|
|
|
struct lua_Debug{int event;const char*name;const char*namewhat;const char*what
|
|
|
|
;const char*source;int currentline;int nups;int linedefined;char short_src[
|
|
|
|
LUA_IDSIZE];int i_ci;};
|
|
|
|
#endif
|
|
|
|
#line 14 "lapi.c"
|
|
|
|
#line 1 "lapi.h"
|
|
|
|
#ifndef lapi_h
|
|
|
|
#define lapi_h
|
|
|
|
#line 1 "lobject.h"
|
|
|
|
#ifndef lobject_h
|
|
|
|
#define lobject_h
|
|
|
|
#line 1 "llimits.h"
|
|
|
|
#ifndef llimits_h
|
|
|
|
#define llimits_h
|
|
|
|
#ifndef BITS_INT
|
|
|
|
#if INT_MAX-20 <32760
|
|
|
|
#define BITS_INT 16
|
|
|
|
#else
|
|
|
|
#if INT_MAX >2147483640L
|
|
|
|
#define BITS_INT 32
|
|
|
|
#else
|
|
|
|
#error "you must define BITS_INT with number of bits in an integer"
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
typedef unsigned int lu_hash;typedef int ls_hash;typedef unsigned long lu_mem;
|
|
|
|
#define MAX_LUMEM ULONG_MAX
|
|
|
|
typedef long ls_nstr;typedef unsigned char lu_byte;
|
|
|
|
#define MAX_SIZET ((size_t)(~(size_t)0)-2)
|
|
|
|
#define MAX_INT (INT_MAX-2)
|
|
|
|
#define IntPoint(p) ((lu_hash)(p))
|
|
|
|
#ifndef LUSER_ALIGNMENT_T
|
|
|
|
typedef union{double u;void*s;long l;}L_Umaxalign;
|
|
|
|
#else
|
|
|
|
typedef LUSER_ALIGNMENT_T L_Umaxalign;
|
|
|
|
#endif
|
|
|
|
#ifndef LUA_UACNUMBER
|
|
|
|
typedef double l_uacNumber;
|
|
|
|
#else
|
|
|
|
typedef LUA_UACNUMBER l_uacNumber;
|
|
|
|
#endif
|
|
|
|
#ifndef lua_assert
|
|
|
|
#define lua_assert(c)
|
|
|
|
#endif
|
|
|
|
#ifndef check_exp
|
|
|
|
#define check_exp(c,e) (e)
|
|
|
|
#endif
|
|
|
|
#ifndef UNUSED
|
|
|
|
#define UNUSED(x) ((void)(x))
|
|
|
|
#endif
|
|
|
|
#ifndef cast
|
|
|
|
#define cast(t, exp)((t)(exp))
|
|
|
|
#endif
|
|
|
|
typedef unsigned long Instruction;
|
|
|
|
#ifndef LUA_MAXCALLS
|
|
|
|
#define LUA_MAXCALLS 4096
|
|
|
|
#endif
|
|
|
|
#ifndef LUA_MAXCCALLS
|
|
|
|
#define LUA_MAXCCALLS 200
|
|
|
|
#endif
|
|
|
|
#ifndef LUA_MAXCSTACK
|
|
|
|
#define LUA_MAXCSTACK 2048
|
|
|
|
#endif
|
|
|
|
#define MAXSTACK 250
|
|
|
|
#ifndef MAXVARS
|
|
|
|
#define MAXVARS 200
|
|
|
|
#endif
|
|
|
|
#ifndef MAXUPVALUES
|
|
|
|
#define MAXUPVALUES 32
|
|
|
|
#endif
|
|
|
|
#ifndef MAXPARAMS
|
|
|
|
#define MAXPARAMS 100
|
|
|
|
#endif
|
|
|
|
#ifndef MINSTRTABSIZE
|
|
|
|
#define MINSTRTABSIZE 32
|
|
|
|
#endif
|
|
|
|
#ifndef LUA_MINBUFFER
|
|
|
|
#define LUA_MINBUFFER 32
|
|
|
|
#endif
|
|
|
|
#ifndef LUA_MAXPARSERLEVEL
|
|
|
|
#define LUA_MAXPARSERLEVEL 200
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#line 12 "lobject.h"
|
|
|
|
#define NUM_TAGS LUA_TTHREAD
|
|
|
|
#define LUA_TPROTO (NUM_TAGS+1)
|
|
|
|
#define LUA_TUPVAL (NUM_TAGS+2)
|
|
|
|
typedef union GCObject GCObject;
|
|
|
|
#define CommonHeader GCObject*next;lu_byte tt;lu_byte marked
|
|
|
|
typedef struct GCheader{CommonHeader;}GCheader;typedef union{GCObject*gc;void*
|
|
|
|
p;lua_Number n;int b;}Value;typedef struct lua_TObject{int tt;Value value;}
|
|
|
|
TObject;
|
|
|
|
#define ttisnil(o) (ttype(o)==LUA_TNIL)
|
|
|
|
#define ttisnumber(o) (ttype(o)==LUA_TNUMBER)
|
|
|
|
#define ttisstring(o) (ttype(o)==LUA_TSTRING)
|
|
|
|
#define ttistable(o) (ttype(o)==LUA_TTABLE)
|
|
|
|
#define ttisfunction(o) (ttype(o)==LUA_TFUNCTION)
|
|
|
|
#define ttisboolean(o) (ttype(o)==LUA_TBOOLEAN)
|
|
|
|
#define ttisuserdata(o) (ttype(o)==LUA_TUSERDATA)
|
|
|
|
#define ttisthread(o) (ttype(o)==LUA_TTHREAD)
|
|
|
|
#define ttislightuserdata(o) (ttype(o)==LUA_TLIGHTUSERDATA)
|
|
|
|
#define ttype(o) ((o)->tt)
|
|
|
|
#define gcvalue(o) check_exp(iscollectable(o),(o)->value.gc)
|
|
|
|
#define pvalue(o) check_exp(ttislightuserdata(o),(o)->value.p)
|
|
|
|
#define nvalue(o) check_exp(ttisnumber(o),(o)->value.n)
|
|
|
|
#define tsvalue(o) check_exp(ttisstring(o),&(o)->value.gc->ts)
|
|
|
|
#define uvalue(o) check_exp(ttisuserdata(o),&(o)->value.gc->u)
|
|
|
|
#define clvalue(o) check_exp(ttisfunction(o),&(o)->value.gc->cl)
|
|
|
|
#define hvalue(o) check_exp(ttistable(o),&(o)->value.gc->h)
|
|
|
|
#define bvalue(o) check_exp(ttisboolean(o),(o)->value.b)
|
|
|
|
#define thvalue(o) check_exp(ttisthread(o),&(o)->value.gc->th)
|
|
|
|
#define l_isfalse(o) (ttisnil(o)||(ttisboolean(o)&&bvalue(o)==0))
|
|
|
|
#define setnvalue(obj,x) {TObject*i_o=(obj);i_o->tt=LUA_TNUMBER;i_o->value.n=(\
|
|
|
|
x);}
|
|
|
|
#define chgnvalue(obj,x) check_exp(ttype(obj)==LUA_TNUMBER,(obj)->value.n=(x))
|
|
|
|
#define setpvalue(obj,x) {TObject*i_o=(obj);i_o->tt=LUA_TLIGHTUSERDATA;i_o->\
|
|
|
|
value.p=(x);}
|
|
|
|
#define setbvalue(obj,x) {TObject*i_o=(obj);i_o->tt=LUA_TBOOLEAN;i_o->value.b=\
|
|
|
|
(x);}
|
|
|
|
#define setsvalue(obj,x) {TObject*i_o=(obj);i_o->tt=LUA_TSTRING;i_o->value.gc=\
|
|
|
|
cast(GCObject*,(x));lua_assert(i_o->value.gc->gch.tt==LUA_TSTRING);}
|
|
|
|
#define setuvalue(obj,x) {TObject*i_o=(obj);i_o->tt=LUA_TUSERDATA;i_o->value.\
|
|
|
|
gc=cast(GCObject*,(x));lua_assert(i_o->value.gc->gch.tt==LUA_TUSERDATA);}
|
|
|
|
#define setthvalue(obj,x) {TObject*i_o=(obj);i_o->tt=LUA_TTHREAD;i_o->value.gc\
|
|
|
|
=cast(GCObject*,(x));lua_assert(i_o->value.gc->gch.tt==LUA_TTHREAD);}
|
|
|
|
#define setclvalue(obj,x) {TObject*i_o=(obj);i_o->tt=LUA_TFUNCTION;i_o->value.\
|
|
|
|
gc=cast(GCObject*,(x));lua_assert(i_o->value.gc->gch.tt==LUA_TFUNCTION);}
|
|
|
|
#define sethvalue(obj,x) {TObject*i_o=(obj);i_o->tt=LUA_TTABLE;i_o->value.gc=\
|
|
|
|
cast(GCObject*,(x));lua_assert(i_o->value.gc->gch.tt==LUA_TTABLE);}
|
|
|
|
#define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
|
|
|
|
#define checkconsistency(obj) lua_assert(!iscollectable(obj)||(ttype(obj)==(\
|
|
|
|
obj)->value.gc->gch.tt))
|
|
|
|
#define setobj(obj1,obj2) {const TObject*o2=(obj2);TObject*o1=(obj1);\
|
|
|
|
checkconsistency(o2);o1->tt=o2->tt;o1->value=o2->value;}
|
|
|
|
#define setobjs2s setobj
|
|
|
|
#define setobj2s setobj
|
|
|
|
#define setsvalue2s setsvalue
|
|
|
|
#define setobjt2t setobj
|
|
|
|
#define setobj2t setobj
|
|
|
|
#define setobj2n setobj
|
|
|
|
#define setsvalue2n setsvalue
|
|
|
|
#define setttype(obj, tt)(ttype(obj)=(tt))
|
|
|
|
#define iscollectable(o) (ttype(o)>=LUA_TSTRING)
|
|
|
|
typedef TObject*StkId;typedef union TString{L_Umaxalign dummy;struct{
|
|
|
|
CommonHeader;lu_byte reserved;lu_hash hash;size_t len;}tsv;}TString;
|
|
|
|
#define getstr(ts) cast(const char*,(ts)+1)
|
|
|
|
#define svalue(o) getstr(tsvalue(o))
|
|
|
|
typedef union Udata{L_Umaxalign dummy;struct{CommonHeader;struct Table*
|
|
|
|
metatable;size_t len;}uv;}Udata;typedef struct Proto{CommonHeader;TObject*k;
|
|
|
|
Instruction*code;struct Proto**p;int*lineinfo;struct LocVar*locvars;TString**
|
|
|
|
upvalues;TString*source;int sizeupvalues;int sizek;int sizecode;int
|
|
|
|
sizelineinfo;int sizep;int sizelocvars;int lineDefined;GCObject*gclist;lu_byte
|
|
|
|
nups;lu_byte numparams;lu_byte is_vararg;lu_byte maxstacksize;}Proto;typedef
|
|
|
|
struct LocVar{TString*varname;int startpc;int endpc;}LocVar;typedef struct
|
|
|
|
UpVal{CommonHeader;TObject*v;TObject value;}UpVal;
|
|
|
|
#define ClosureHeader CommonHeader;lu_byte isC;lu_byte nupvalues;GCObject*\
|
|
|
|
gclist
|
|
|
|
typedef struct CClosure{ClosureHeader;lua_CFunction f;TObject upvalue[1];}
|
|
|
|
CClosure;typedef struct LClosure{ClosureHeader;struct Proto*p;TObject g;UpVal*
|
|
|
|
upvals[1];}LClosure;typedef union Closure{CClosure c;LClosure l;}Closure;
|
|
|
|
#define iscfunction(o) (ttype(o)==LUA_TFUNCTION&&clvalue(o)->c.isC)
|
|
|
|
#define isLfunction(o) (ttype(o)==LUA_TFUNCTION&&!clvalue(o)->c.isC)
|
|
|
|
typedef struct Node{TObject i_key;TObject i_val;struct Node*next;}Node;typedef
|
|
|
|
struct Table{CommonHeader;lu_byte flags;lu_byte lsizenode;struct Table*
|
|
|
|
metatable;TObject*array;Node*node;Node*firstfree;GCObject*gclist;int sizearray
|
|
|
|
;}Table;
|
|
|
|
#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))
|
|
|
|
extern const TObject luaO_nilobject;int luaO_log2(unsigned int x);int
|
|
|
|
luaO_int2fb(unsigned int x);
|
|
|
|
#define fb2int(x) (((x)&7)<<((x)>>3))
|
|
|
|
int luaO_rawequalObj(const TObject*t1,const TObject*t2);int luaO_str2d(const
|
|
|
|
char*s,lua_Number*result);const char*luaO_pushvfstring(lua_State*L,const char*
|
|
|
|
fmt,va_list argp);const char*luaO_pushfstring(lua_State*L,const char*fmt,...);
|
|
|
|
void luaO_chunkid(char*out,const char*source,int len);
|
|
|
|
#endif
|
|
|
|
#line 12 "lapi.h"
|
|
|
|
void luaA_pushobject(lua_State*L,const TObject*o);
|
|
|
|
#endif
|
|
|
|
#line 16 "lapi.c"
|
|
|
|
#line 1 "ldebug.h"
|
|
|
|
#ifndef ldebug_h
|
|
|
|
#define ldebug_h
|
|
|
|
#line 1 "lstate.h"
|
|
|
|
#ifndef lstate_h
|
|
|
|
#define lstate_h
|
|
|
|
#line 1 "ltm.h"
|
|
|
|
#ifndef ltm_h
|
|
|
|
#define ltm_h
|
|
|
|
typedef enum{TM_INDEX,TM_NEWINDEX,TM_GC,TM_MODE,TM_EQ,TM_ADD,TM_SUB,TM_MUL,
|
|
|
|
TM_DIV,TM_POW,TM_UNM,TM_LT,TM_LE,TM_CONCAT,TM_CALL,TM_N}TMS;
|
|
|
|
#define gfasttm(g,et,e) (((et)->flags&(1u<<(e)))?NULL:luaT_gettm(et,e,(g)->\
|
|
|
|
tmname[e]))
|
|
|
|
#define fasttm(l,et,e) gfasttm(G(l),et,e)
|
|
|
|
const TObject*luaT_gettm(Table*events,TMS event,TString*ename);const TObject*
|
|
|
|
luaT_gettmbyobj(lua_State*L,const TObject*o,TMS event);void luaT_init(
|
|
|
|
lua_State*L);extern const char*const luaT_typenames[];
|
|
|
|
#endif
|
|
|
|
#line 14 "lstate.h"
|
|
|
|
#line 1 "lzio.h"
|
|
|
|
#ifndef lzio_h
|
|
|
|
#define lzio_h
|
|
|
|
#define EOZ (-1)
|
|
|
|
typedef struct Zio ZIO;
|
|
|
|
#define char2int(c) cast(int,cast(unsigned char,(c)))
|
|
|
|
#define zgetc(z) (((z)->n--)>0?char2int(*(z)->p++):luaZ_fill(z))
|
|
|
|
#define zname(z) ((z)->name)
|
|
|
|
void luaZ_init(ZIO*z,lua_Chunkreader reader,void*data,const char*name);size_t
|
|
|
|
luaZ_read(ZIO*z,void*b,size_t n);int luaZ_lookahead(ZIO*z);typedef struct
|
|
|
|
Mbuffer{char*buffer;size_t buffsize;}Mbuffer;char*luaZ_openspace(lua_State*L,
|
|
|
|
Mbuffer*buff,size_t n);
|
|
|
|
#define luaZ_initbuffer(L, buff)((buff)->buffer=NULL,(buff)->buffsize=0)
|
|
|
|
#define luaZ_sizebuffer(buff) ((buff)->buffsize)
|
|
|
|
#define luaZ_buffer(buff) ((buff)->buffer)
|
|
|
|
#define luaZ_resizebuffer(L, buff,size)(luaM_reallocvector(L,(buff)->buffer,(\
|
|
|
|
buff)->buffsize,size,char),(buff)->buffsize=size)
|
|
|
|
#define luaZ_freebuffer(L, buff)luaZ_resizebuffer(L,buff,0)
|
|
|
|
struct Zio{size_t n;const char*p;lua_Chunkreader reader;void*data;const char*
|
|
|
|
name;};int luaZ_fill(ZIO*z);
|
|
|
|
#endif
|
|
|
|
#line 15 "lstate.h"
|
|
|
|
#ifndef lua_lock
|
|
|
|
#define lua_lock(L) ((void)0)
|
|
|
|
#endif
|
|
|
|
#ifndef lua_unlock
|
|
|
|
#define lua_unlock(L) ((void)0)
|
|
|
|
#endif
|
|
|
|
#ifndef lua_userstateopen
|
|
|
|
#define lua_userstateopen(l)
|
|
|
|
#endif
|
|
|
|
struct lua_longjmp;
|
|
|
|
#define defaultmeta(L) (&G(L)->_defaultmeta)
|
|
|
|
#define gt(L) (&L->_gt)
|
|
|
|
#define registry(L) (&G(L)->_registry)
|
|
|
|
#define EXTRA_STACK 5
|
|
|
|
#define BASIC_CI_SIZE 8
|
|
|
|
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
|
|
|
|
typedef struct stringtable{GCObject**hash;ls_nstr nuse;int size;}stringtable;
|
|
|
|
typedef struct CallInfo{StkId base;StkId top;int state;union{struct{const
|
|
|
|
Instruction*savedpc;const Instruction**pc;int tailcalls;}l;struct{int dummy;}c
|
|
|
|
;}u;}CallInfo;
|
|
|
|
#define CI_C (1<<0)
|
|
|
|
#define CI_HASFRAME (1<<1)
|
|
|
|
#define CI_CALLING (1<<2)
|
|
|
|
#define CI_SAVEDPC (1<<3)
|
|
|
|
#define CI_YIELD (1<<4)
|
|
|
|
#define ci_func(ci) (clvalue((ci)->base-1))
|
|
|
|
typedef struct global_State{stringtable strt;GCObject*rootgc;GCObject*
|
|
|
|
rootudata;GCObject*tmudata;Mbuffer buff;lu_mem GCthreshold;lu_mem nblocks;
|
|
|
|
lua_CFunction panic;TObject _registry;TObject _defaultmeta;struct lua_State*
|
|
|
|
mainthread;Node dummynode[1];TString*tmname[TM_N];}global_State;struct
|
|
|
|
lua_State{CommonHeader;StkId top;StkId base;global_State*l_G;CallInfo*ci;StkId
|
|
|
|
stack_last;StkId stack;int stacksize;CallInfo*end_ci;CallInfo*base_ci;
|
|
|
|
unsigned short size_ci;unsigned short nCcalls;lu_byte hookmask;lu_byte
|
|
|
|
allowhook;lu_byte hookinit;int basehookcount;int hookcount;lua_Hook hook;
|
|
|
|
TObject _gt;GCObject*openupval;GCObject*gclist;struct lua_longjmp*errorJmp;
|
|
|
|
ptrdiff_t errfunc;};
|
|
|
|
#define G(L) (L->l_G)
|
|
|
|
union GCObject{GCheader gch;union TString ts;union Udata u;union Closure cl;
|
|
|
|
struct Table h;struct Proto p;struct UpVal uv;struct lua_State th;};
|
|
|
|
#define gcotots(o) check_exp((o)->gch.tt==LUA_TSTRING,&((o)->ts))
|
|
|
|
#define gcotou(o) check_exp((o)->gch.tt==LUA_TUSERDATA,&((o)->u))
|
|
|
|
#define gcotocl(o) check_exp((o)->gch.tt==LUA_TFUNCTION,&((o)->cl))
|
|
|
|
#define gcotoh(o) check_exp((o)->gch.tt==LUA_TTABLE,&((o)->h))
|
|
|
|
#define gcotop(o) check_exp((o)->gch.tt==LUA_TPROTO,&((o)->p))
|
|
|
|
#define gcotouv(o) check_exp((o)->gch.tt==LUA_TUPVAL,&((o)->uv))
|
|
|
|
#define ngcotouv(o) check_exp((o)==NULL||(o)->gch.tt==LUA_TUPVAL,&((o)->uv))
|
|
|
|
#define gcototh(o) check_exp((o)->gch.tt==LUA_TTHREAD,&((o)->th))
|
|
|
|
#define valtogco(v) (cast(GCObject*,(v)))
|
|
|
|
lua_State*luaE_newthread(lua_State*L);void luaE_freethread(lua_State*L,
|
|
|
|
lua_State*L1);
|
|
|
|
#endif
|
|
|
|
#line 12 "ldebug.h"
|
|
|
|
#define pcRel(pc, p)(cast(int,(pc)-(p)->code)-1)
|
|
|
|
#define getline(f,pc) (((f)->lineinfo)?(f)->lineinfo[pc]:0)
|
|
|
|
#define resethookcount(L) (L->hookcount=L->basehookcount)
|
|
|
|
void luaG_inithooks(lua_State*L);void luaG_typeerror(lua_State*L,const TObject
|
|
|
|
*o,const char*opname);void luaG_concaterror(lua_State*L,StkId p1,StkId p2);
|
|
|
|
void luaG_aritherror(lua_State*L,const TObject*p1,const TObject*p2);int
|
|
|
|
luaG_ordererror(lua_State*L,const TObject*p1,const TObject*p2);void
|
|
|
|
luaG_runerror(lua_State*L,const char*fmt,...);void luaG_errormsg(lua_State*L);
|
|
|
|
int luaG_checkcode(const Proto*pt);
|
|
|
|
#endif
|
|
|
|
#line 17 "lapi.c"
|
|
|
|
#line 1 "ldo.h"
|
|
|
|
#ifndef ldo_h
|
|
|
|
#define ldo_h
|
|
|
|
#ifndef HARDSTACKTESTS
|
|
|
|
#define condhardstacktests(x) {}
|
|
|
|
#else
|
|
|
|
#define condhardstacktests(x) x
|
|
|
|
#endif
|
|
|
|
#define luaD_checkstack(L,n) if((char*)L->stack_last-(char*)L->top<=(n)*(int)\
|
|
|
|
sizeof(TObject))luaD_growstack(L,n);else condhardstacktests(luaD_reallocstack(\
|
|
|
|
L,L->stacksize));
|
|
|
|
#define incr_top(L) {luaD_checkstack(L,1);L->top++;}
|
|
|
|
#define savestack(L,p) ((char*)(p)-(char*)L->stack)
|
|
|
|
#define restorestack(L,n) ((TObject*)((char*)L->stack+(n)))
|
|
|
|
#define saveci(L,p) ((char*)(p)-(char*)L->base_ci)
|
|
|
|
#define restoreci(L,n) ((CallInfo*)((char*)L->base_ci+(n)))
|
|
|
|
typedef void(*Pfunc)(lua_State*L,void*ud);void luaD_resetprotection(lua_State*
|
|
|
|
L);int luaD_protectedparser(lua_State*L,ZIO*z,int bin);void luaD_callhook(
|
|
|
|
lua_State*L,int event,int line);StkId luaD_precall(lua_State*L,StkId func);
|
|
|
|
void luaD_call(lua_State*L,StkId func,int nResults);int luaD_pcall(lua_State*L
|
|
|
|
,Pfunc func,void*u,ptrdiff_t oldtop,ptrdiff_t ef);void luaD_poscall(lua_State*
|
|
|
|
L,int wanted,StkId firstResult);void luaD_reallocCI(lua_State*L,int newsize);
|
|
|
|
void luaD_reallocstack(lua_State*L,int newsize);void luaD_growstack(lua_State*
|
|
|
|
L,int n);void luaD_throw(lua_State*L,int errcode);int luaD_rawrunprotected(
|
|
|
|
lua_State*L,Pfunc f,void*ud);
|
|
|
|
#endif
|
|
|
|
#line 18 "lapi.c"
|
|
|
|
#line 1 "lfunc.h"
|
|
|
|
#ifndef lfunc_h
|
|
|
|
#define lfunc_h
|
|
|
|
Proto*luaF_newproto(lua_State*L);Closure*luaF_newCclosure(lua_State*L,int
|
|
|
|
nelems);Closure*luaF_newLclosure(lua_State*L,int nelems,TObject*e);UpVal*
|
|
|
|
luaF_findupval(lua_State*L,StkId level);void luaF_close(lua_State*L,StkId
|
|
|
|
level);void luaF_freeproto(lua_State*L,Proto*f);void luaF_freeclosure(
|
|
|
|
lua_State*L,Closure*c);const char*luaF_getlocalname(const Proto*func,int
|
|
|
|
local_number,int pc);
|
|
|
|
#endif
|
|
|
|
#line 19 "lapi.c"
|
|
|
|
#line 1 "lgc.h"
|
|
|
|
#ifndef lgc_h
|
|
|
|
#define lgc_h
|
|
|
|
#define luaC_checkGC(L) {lua_assert(!(L->ci->state&CI_CALLING));if(G(L)->\
|
|
|
|
nblocks>=G(L)->GCthreshold)luaC_collectgarbage(L);}
|
|
|
|
size_t luaC_separateudata(lua_State*L);void luaC_callGCTM(lua_State*L);void
|
|
|
|
luaC_sweep(lua_State*L,int all);void luaC_collectgarbage(lua_State*L);void
|
|
|
|
luaC_link(lua_State*L,GCObject*o,lu_byte tt);
|
|
|
|
#endif
|
|
|
|
#line 20 "lapi.c"
|
|
|
|
#line 1 "lmem.h"
|
|
|
|
#ifndef lmem_h
|
|
|
|
#define lmem_h
|
|
|
|
#define MEMERRMSG "not enough memory"
|
|
|
|
void*luaM_realloc(lua_State*L,void*oldblock,lu_mem oldsize,lu_mem size);void*
|
|
|
|
luaM_growaux(lua_State*L,void*block,int*size,int size_elem,int limit,const
|
|
|
|
char*errormsg);
|
|
|
|
#define luaM_free(L, b,s)luaM_realloc(L,(b),(s),0)
|
|
|
|
#define luaM_freelem(L, b)luaM_realloc(L,(b),sizeof(*(b)),0)
|
|
|
|
#define luaM_freearray(L, b,n,t)luaM_realloc(L,(b),cast(lu_mem,n)*cast(lu_mem,\
|
|
|
|
sizeof(t)),0)
|
|
|
|
#define luaM_malloc(L, t)luaM_realloc(L,NULL,0,(t))
|
|
|
|
#define luaM_new(L, t)cast(t*,luaM_malloc(L,sizeof(t)))
|
|
|
|
#define luaM_newvector(L, n,t)cast(t*,luaM_malloc(L,cast(lu_mem,n)*cast(lu_mem\
|
|
|
|
,sizeof(t))))
|
|
|
|
#define luaM_growvector(L,v,nelems,size,t,limit,e) if(((nelems)+1)>(size))((v)\
|
|
|
|
=cast(t*,luaM_growaux(L,v,&(size),sizeof(t),limit,e)))
|
|
|
|
#define luaM_reallocvector(L, v,oldn,n,t)((v)=cast(t*,luaM_realloc(L,v,cast(\
|
|
|
|
lu_mem,oldn)*cast(lu_mem,sizeof(t)),cast(lu_mem,n)*cast(lu_mem,sizeof(t)))))
|
|
|
|
#endif
|
|
|
|
#line 21 "lapi.c"
|
|
|
|
#line 1 "lstring.h"
|
|
|
|
#ifndef lstring_h
|
|
|
|
#define lstring_h
|
|
|
|
#define sizestring(l) (cast(lu_mem,sizeof(union TString))+(cast(lu_mem,l)+1)*\
|
|
|
|
sizeof(char))
|
|
|
|
#define sizeudata(l) (cast(lu_mem,sizeof(union Udata))+(l))
|
|
|
|
#define luaS_new(L, s)(luaS_newlstr(L,s,strlen(s)))
|
|
|
|
#define luaS_newliteral(L, s)(luaS_newlstr(L,""s,(sizeof(s)/sizeof(char))-1))
|
|
|
|
#define luaS_fix(s) ((s)->tsv.marked|=(1<<4))
|
|
|
|
void luaS_resize(lua_State*L,int newsize);Udata*luaS_newudata(lua_State*L,
|
|
|
|
size_t s);void luaS_freeall(lua_State*L);TString*luaS_newlstr(lua_State*L,
|
|
|
|
const char*str,size_t l);
|
|
|
|
#endif
|
|
|
|
#line 24 "lapi.c"
|
|
|
|
#line 1 "ltable.h"
|
|
|
|
#ifndef ltable_h
|
|
|
|
#define ltable_h
|
|
|
|
#define gnode(t,i) (&(t)->node[i])
|
|
|
|
#define gkey(n) (&(n)->i_key)
|
|
|
|
#define gval(n) (&(n)->i_val)
|
|
|
|
const TObject*luaH_getnum(Table*t,int key);TObject*luaH_setnum(lua_State*L,
|
|
|
|
Table*t,int key);const TObject*luaH_getstr(Table*t,TString*key);const TObject*
|
|
|
|
luaH_get(Table*t,const TObject*key);TObject*luaH_set(lua_State*L,Table*t,const
|
|
|
|
TObject*key);Table*luaH_new(lua_State*L,int narray,int lnhash);void luaH_free
|
|
|
|
(lua_State*L,Table*t);int luaH_next(lua_State*L,Table*t,StkId key);Node*
|
|
|
|
luaH_mainposition(const Table*t,const TObject*key);
|
|
|
|
#endif
|
|
|
|
#line 25 "lapi.c"
|
|
|
|
#line 1 "lundump.h"
|
|
|
|
#ifndef lundump_h
|
|
|
|
#define lundump_h
|
|
|
|
Proto*luaU_undump(lua_State*L,ZIO*Z,Mbuffer*buff);int luaU_endianness(void);
|
|
|
|
void luaU_dump(lua_State*L,const Proto*Main,lua_Chunkwriter w,void*data);void
|
|
|
|
luaU_print(const Proto*Main);
|
|
|
|
#define LUA_SIGNATURE "\033Lua"
|
|
|
|
#define VERSION 0x50
|
|
|
|
#define VERSION0 0x50
|
|
|
|
#define TEST_NUMBER ((lua_Number)3.14159265358979323846E7)
|
|
|
|
#endif
|
|
|
|
#line 27 "lapi.c"
|
|
|
|
#line 1 "lvm.h"
|
|
|
|
#ifndef lvm_h
|
|
|
|
#define lvm_h
|
|
|
|
#define tostring(L,o) ((ttype(o)==LUA_TSTRING)||(luaV_tostring(L,o)))
|
|
|
|
#define tonumber(o,n) (ttype(o)==LUA_TNUMBER||(((o)=luaV_tonumber(o,n))!=NULL)\
|
|
|
|
)
|
|
|
|
#define equalobj(L,o1,o2) (ttype(o1)==ttype(o2)&&luaV_equalval(L,o1,o2))
|
|
|
|
int luaV_lessthan(lua_State*L,const TObject*l,const TObject*r);int
|
|
|
|
luaV_equalval(lua_State*L,const TObject*t1,const TObject*t2);const TObject*
|
|
|
|
luaV_tonumber(const TObject*obj,TObject*n);int luaV_tostring(lua_State*L,StkId
|
|
|
|
obj);const TObject*luaV_gettable(lua_State*L,const TObject*t,TObject*key,int
|
|
|
|
loop);void luaV_settable(lua_State*L,const TObject*t,TObject*key,StkId val);
|
|
|
|
StkId luaV_execute(lua_State*L);void luaV_concat(lua_State*L,int total,int
|
|
|
|
last);
|
|
|
|
#endif
|
|
|
|
#line 28 "lapi.c"
|
|
|
|
const char lua_ident[]="$Lua: "LUA_VERSION" "LUA_COPYRIGHT" $\n""$Authors: "
|
|
|
|
LUA_AUTHORS" $\n""$URL: www.lua.org $\n";
|
|
|
|
#ifndef api_check
|
|
|
|
#define api_check(L, o)
|
|
|
|
#endif
|
|
|
|
#define api_checknelems(L, n)api_check(L,(n)<=(L->top-L->base))
|
|
|
|
#define api_incr_top(L) {api_check(L,L->top<L->ci->top);L->top++;}
|
|
|
|
static TObject*negindex(lua_State*L,int idx){if(idx>LUA_REGISTRYINDEX){
|
|
|
|
api_check(L,idx!=0&&-idx<=L->top-L->base);return L->top+idx;}else switch(idx){
|
|
|
|
case LUA_REGISTRYINDEX:return registry(L);case LUA_GLOBALSINDEX:return gt(L);
|
|
|
|
default:{TObject*func=(L->base-1);idx=LUA_GLOBALSINDEX-idx;lua_assert(
|
|
|
|
iscfunction(func));return(idx<=clvalue(func)->c.nupvalues)?&clvalue(func)->c.
|
|
|
|
upvalue[idx-1]:NULL;}}}static TObject*luaA_index(lua_State*L,int idx){if(idx>0
|
|
|
|
){api_check(L,idx<=L->top-L->base);return L->base+idx-1;}else{TObject*o=
|
|
|
|
negindex(L,idx);api_check(L,o!=NULL);return o;}}static TObject*
|
|
|
|
luaA_indexAcceptable(lua_State*L,int idx){if(idx>0){TObject*o=L->base+(idx-1);
|
|
|
|
api_check(L,idx<=L->stack_last-L->base);if(o>=L->top)return NULL;else return o
|
|
|
|
;}else return negindex(L,idx);}void luaA_pushobject(lua_State*L,const TObject*
|
|
|
|
o){setobj2s(L->top,o);incr_top(L);}LUA_API int lua_checkstack(lua_State*L,int
|
|
|
|
size){int res;lua_lock(L);if((L->top-L->base+size)>LUA_MAXCSTACK)res=0;else{
|
|
|
|
luaD_checkstack(L,size);if(L->ci->top<L->top+size)L->ci->top=L->top+size;res=1
|
|
|
|
;}lua_unlock(L);return res;}LUA_API void lua_xmove(lua_State*from,lua_State*to
|
|
|
|
,int n){int i;lua_lock(to);api_checknelems(from,n);from->top-=n;for(i=0;i<n;i
|
|
|
|
++){setobj2s(to->top,from->top+i);api_incr_top(to);}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_State*lua_newthread(lua_State*L){lua_State*L1;lua_lock(L);
|
|
|
|
luaC_checkGC(L);L1=luaE_newthread(L);setthvalue(L->top,L1);api_incr_top(L);
|
|
|
|
lua_unlock(L);lua_userstateopen(L1);return L1;}LUA_API int lua_gettop(
|
|
|
|
lua_State*L){return(L->top-L->base);}LUA_API void lua_settop(lua_State*L,int
|
|
|
|
idx){lua_lock(L);if(idx>=0){api_check(L,idx<=L->stack_last-L->base);while(L->
|
|
|
|
top<L->base+idx)setnilvalue(L->top++);L->top=L->base+idx;}else{api_check(L,-(
|
|
|
|
idx+1)<=(L->top-L->base));L->top+=idx+1;}lua_unlock(L);}LUA_API void
|
|
|
|
lua_remove(lua_State*L,int idx){StkId p;lua_lock(L);p=luaA_index(L,idx);while(
|
|
|
|
++p<L->top)setobjs2s(p-1,p);L->top--;lua_unlock(L);}LUA_API void lua_insert(
|
|
|
|
lua_State*L,int idx){StkId p;StkId q;lua_lock(L);p=luaA_index(L,idx);for(q=L->
|
|
|
|
top;q>p;q--)setobjs2s(q,q-1);setobjs2s(p,L->top);lua_unlock(L);}LUA_API void
|
|
|
|
lua_replace(lua_State*L,int idx){lua_lock(L);api_checknelems(L,1);setobj(
|
|
|
|
luaA_index(L,idx),L->top-1);L->top--;lua_unlock(L);}LUA_API void lua_pushvalue
|
|
|
|
(lua_State*L,int idx){lua_lock(L);setobj2s(L->top,luaA_index(L,idx));
|
|
|
|
api_incr_top(L);lua_unlock(L);}LUA_API int lua_type(lua_State*L,int idx){StkId
|
|
|
|
o=luaA_indexAcceptable(L,idx);return(o==NULL)?LUA_TNONE:ttype(o);}LUA_API
|
|
|
|
const char*lua_typename(lua_State*L,int t){UNUSED(L);return(t==LUA_TNONE)?
|
|
|
|
"no value":luaT_typenames[t];}LUA_API int lua_iscfunction(lua_State*L,int idx)
|
|
|
|
{StkId o=luaA_indexAcceptable(L,idx);return(o==NULL)?0:iscfunction(o);}LUA_API
|
|
|
|
int lua_isnumber(lua_State*L,int idx){TObject n;const TObject*o=
|
|
|
|
luaA_indexAcceptable(L,idx);return(o!=NULL&&tonumber(o,&n));}LUA_API int
|
|
|
|
lua_isstring(lua_State*L,int idx){int t=lua_type(L,idx);return(t==LUA_TSTRING
|
|
|
|
||t==LUA_TNUMBER);}LUA_API int lua_isuserdata(lua_State*L,int idx){const
|
|
|
|
TObject*o=luaA_indexAcceptable(L,idx);return(o!=NULL&&(ttisuserdata(o)||
|
|
|
|
ttislightuserdata(o)));}LUA_API int lua_rawequal(lua_State*L,int index1,int
|
|
|
|
index2){StkId o1=luaA_indexAcceptable(L,index1);StkId o2=luaA_indexAcceptable(
|
|
|
|
L,index2);return(o1==NULL||o2==NULL)?0:luaO_rawequalObj(o1,o2);}LUA_API int
|
|
|
|
lua_equal(lua_State*L,int index1,int index2){StkId o1,o2;int i;lua_lock(L);o1=
|
|
|
|
luaA_indexAcceptable(L,index1);o2=luaA_indexAcceptable(L,index2);i=(o1==NULL||
|
|
|
|
o2==NULL)?0:equalobj(L,o1,o2);lua_unlock(L);return i;}LUA_API int lua_lessthan
|
|
|
|
(lua_State*L,int index1,int index2){StkId o1,o2;int i;lua_lock(L);o1=
|
|
|
|
luaA_indexAcceptable(L,index1);o2=luaA_indexAcceptable(L,index2);i=(o1==NULL||
|
|
|
|
o2==NULL)?0:luaV_lessthan(L,o1,o2);lua_unlock(L);return i;}LUA_API lua_Number
|
|
|
|
lua_tonumber(lua_State*L,int idx){TObject n;const TObject*o=
|
|
|
|
luaA_indexAcceptable(L,idx);if(o!=NULL&&tonumber(o,&n))return nvalue(o);else
|
|
|
|
return 0;}LUA_API int lua_toboolean(lua_State*L,int idx){const TObject*o=
|
|
|
|
luaA_indexAcceptable(L,idx);return(o!=NULL)&&!l_isfalse(o);}LUA_API const char
|
|
|
|
*lua_tostring(lua_State*L,int idx){StkId o=luaA_indexAcceptable(L,idx);if(o==
|
|
|
|
NULL)return NULL;else if(ttisstring(o))return svalue(o);else{const char*s;
|
|
|
|
lua_lock(L);s=(luaV_tostring(L,o)?svalue(o):NULL);luaC_checkGC(L);lua_unlock(L
|
|
|
|
);return s;}}LUA_API size_t lua_strlen(lua_State*L,int idx){StkId o=
|
|
|
|
luaA_indexAcceptable(L,idx);if(o==NULL)return 0;else if(ttisstring(o))return
|
|
|
|
tsvalue(o)->tsv.len;else{size_t l;lua_lock(L);l=(luaV_tostring(L,o)?tsvalue(o)
|
|
|
|
->tsv.len:0);lua_unlock(L);return l;}}LUA_API lua_CFunction lua_tocfunction(
|
|
|
|
lua_State*L,int idx){StkId o=luaA_indexAcceptable(L,idx);return(o==NULL||!
|
|
|
|
iscfunction(o))?NULL:clvalue(o)->c.f;}LUA_API void*lua_touserdata(lua_State*L,
|
|
|
|
int idx){StkId o=luaA_indexAcceptable(L,idx);if(o==NULL)return NULL;switch(
|
|
|
|
ttype(o)){case LUA_TUSERDATA:return(uvalue(o)+1);case LUA_TLIGHTUSERDATA:
|
|
|
|
return pvalue(o);default:return NULL;}}LUA_API lua_State*lua_tothread(
|
|
|
|
lua_State*L,int idx){StkId o=luaA_indexAcceptable(L,idx);return(o==NULL||!
|
|
|
|
ttisthread(o))?NULL:thvalue(o);}LUA_API const void*lua_topointer(lua_State*L,
|
|
|
|
int idx){StkId o=luaA_indexAcceptable(L,idx);if(o==NULL)return NULL;else{
|
|
|
|
switch(ttype(o)){case LUA_TTABLE:return hvalue(o);case LUA_TFUNCTION:return
|
|
|
|
clvalue(o);case LUA_TTHREAD:return thvalue(o);case LUA_TUSERDATA:case
|
|
|
|
LUA_TLIGHTUSERDATA:return lua_touserdata(L,idx);default:return NULL;}}}LUA_API
|
|
|
|
void lua_pushnil(lua_State*L){lua_lock(L);setnilvalue(L->top);api_incr_top(L)
|
|
|
|
;lua_unlock(L);}LUA_API void lua_pushnumber(lua_State*L,lua_Number n){lua_lock
|
|
|
|
(L);setnvalue(L->top,n);api_incr_top(L);lua_unlock(L);}LUA_API void
|
|
|
|
lua_pushlstring(lua_State*L,const char*s,size_t len){lua_lock(L);luaC_checkGC(
|
|
|
|
L);setsvalue2s(L->top,luaS_newlstr(L,s,len));api_incr_top(L);lua_unlock(L);}
|
|
|
|
LUA_API void lua_pushstring(lua_State*L,const char*s){if(s==NULL)lua_pushnil(L
|
|
|
|
);else lua_pushlstring(L,s,strlen(s));}LUA_API const char*lua_pushvfstring(
|
|
|
|
lua_State*L,const char*fmt,va_list argp){const char*ret;lua_lock(L);
|
|
|
|
luaC_checkGC(L);ret=luaO_pushvfstring(L,fmt,argp);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);luaC_checkGC(L);va_start(argp,fmt);ret=
|
|
|
|
luaO_pushvfstring(L,fmt,argp);va_end(argp);lua_unlock(L);return ret;}LUA_API
|
|
|
|
void lua_pushcclosure(lua_State*L,lua_CFunction fn,int n){Closure*cl;lua_lock(
|
|
|
|
L);luaC_checkGC(L);api_checknelems(L,n);cl=luaF_newCclosure(L,n);cl->c.f=fn;L
|
|
|
|
->top-=n;while(n--)setobj2n(&cl->c.upvalue[n],L->top+n);setclvalue(L->top,cl);
|
|
|
|
api_incr_top(L);lua_unlock(L);}LUA_API void lua_pushboolean(lua_State*L,int b)
|
|
|
|
{lua_lock(L);setbvalue(L->top,(b!=0));api_incr_top(L);lua_unlock(L);}LUA_API
|
|
|
|
void lua_pushlightuserdata(lua_State*L,void*p){lua_lock(L);setpvalue(L->top,p)
|
|
|
|
;api_incr_top(L);lua_unlock(L);}LUA_API void lua_gettable(lua_State*L,int idx)
|
|
|
|
{StkId t;lua_lock(L);t=luaA_index(L,idx);setobj2s(L->top-1,luaV_gettable(L,t,L
|
|
|
|
->top-1,0));lua_unlock(L);}LUA_API void lua_rawget(lua_State*L,int idx){StkId
|
|
|
|
t;lua_lock(L);t=luaA_index(L,idx);api_check(L,ttistable(t));setobj2s(L->top-1,
|
|
|
|
luaH_get(hvalue(t),L->top-1));lua_unlock(L);}LUA_API void lua_rawgeti(
|
|
|
|
lua_State*L,int idx,int n){StkId o;lua_lock(L);o=luaA_index(L,idx);api_check(L
|
|
|
|
,ttistable(o));setobj2s(L->top,luaH_getnum(hvalue(o),n));api_incr_top(L);
|
|
|
|
lua_unlock(L);}LUA_API void lua_newtable(lua_State*L){lua_lock(L);luaC_checkGC
|
|
|
|
(L);sethvalue(L->top,luaH_new(L,0,0));api_incr_top(L);lua_unlock(L);}LUA_API
|
|
|
|
int lua_getmetatable(lua_State*L,int objindex){const TObject*obj;Table*mt=NULL
|
|
|
|
;int res;lua_lock(L);obj=luaA_indexAcceptable(L,objindex);if(obj!=NULL){switch
|
|
|
|
(ttype(obj)){case LUA_TTABLE:mt=hvalue(obj)->metatable;break;case
|
|
|
|
LUA_TUSERDATA:mt=uvalue(obj)->uv.metatable;break;}}if(mt==NULL||mt==hvalue(
|
|
|
|
defaultmeta(L)))res=0;else{sethvalue(L->top,mt);api_incr_top(L);res=1;}
|
|
|
|
lua_unlock(L);return res;}LUA_API void lua_getfenv(lua_State*L,int idx){StkId
|
|
|
|
o;lua_lock(L);o=luaA_index(L,idx);setobj2s(L->top,isLfunction(o)?&clvalue(o)->
|
|
|
|
l.g:gt(L));api_incr_top(L);lua_unlock(L);}LUA_API void lua_settable(lua_State*
|
|
|
|
L,int idx){StkId t;lua_lock(L);api_checknelems(L,2);t=luaA_index(L,idx);
|
|
|
|
luaV_settable(L,t,L->top-2,L->top-1);L->top-=2;lua_unlock(L);}LUA_API void
|
|
|
|
lua_rawset(lua_State*L,int idx){StkId t;lua_lock(L);api_checknelems(L,2);t=
|
|
|
|
luaA_index(L,idx);api_check(L,ttistable(t));setobj2t(luaH_set(L,hvalue(t),L->
|
|
|
|
top-2),L->top-1);L->top-=2;lua_unlock(L);}LUA_API void lua_rawseti(lua_State*L
|
|
|
|
,int idx,int n){StkId o;lua_lock(L);api_checknelems(L,1);o=luaA_index(L,idx);
|
|
|
|
api_check(L,ttistable(o));setobj2t(luaH_setnum(L,hvalue(o),n),L->top-1);L->top
|
|
|
|
--;lua_unlock(L);}LUA_API int lua_setmetatable(lua_State*L,int objindex){
|
|
|
|
TObject*obj,*mt;int res=1;lua_lock(L);api_checknelems(L,1);obj=luaA_index(L,
|
|
|
|
objindex);mt=(!ttisnil(L->top-1))?L->top-1:defaultmeta(L);api_check(L,
|
|
|
|
ttistable(mt));switch(ttype(obj)){case LUA_TTABLE:{hvalue(obj)->metatable=
|
|
|
|
hvalue(mt);break;}case LUA_TUSERDATA:{uvalue(obj)->uv.metatable=hvalue(mt);
|
|
|
|
break;}default:{res=0;break;}}L->top--;lua_unlock(L);return res;}LUA_API int
|
|
|
|
lua_setfenv(lua_State*L,int idx){StkId o;int res=0;lua_lock(L);api_checknelems
|
|
|
|
(L,1);o=luaA_index(L,idx);L->top--;api_check(L,ttistable(L->top));if(
|
|
|
|
isLfunction(o)){res=1;clvalue(o)->l.g=*(L->top);}lua_unlock(L);return res;}
|
|
|
|
LUA_API void lua_call(lua_State*L,int nargs,int nresults){StkId func;lua_lock(
|
|
|
|
L);api_checknelems(L,nargs+1);func=L->top-(nargs+1);luaD_call(L,func,nresults)
|
|
|
|
;lua_unlock(L);}struct CallS{StkId func;int nresults;};static void f_call(
|
|
|
|
lua_State*L,void*ud){struct CallS*c=cast(struct CallS*,ud);luaD_call(L,c->func
|
|
|
|
,c->nresults);}LUA_API int lua_pcall(lua_State*L,int nargs,int nresults,int
|
|
|
|
errfunc){struct CallS c;int status;ptrdiff_t func;lua_lock(L);func=(errfunc==0
|
|
|
|
)?0:savestack(L,luaA_index(L,errfunc));c.func=L->top-(nargs+1);c.nresults=
|
|
|
|
nresults;status=luaD_pcall(L,f_call,&c,savestack(L,c.func),func);lua_unlock(L)
|
|
|
|
;return status;}struct CCallS{lua_CFunction func;void*ud;};static void f_Ccall
|
|
|
|
(lua_State*L,void*ud){struct CCallS*c=cast(struct CCallS*,ud);Closure*cl;cl=
|
|
|
|
luaF_newCclosure(L,0);cl->c.f=c->func;setclvalue(L->top,cl);incr_top(L);
|
|
|
|
setpvalue(L->top,c->ud);incr_top(L);luaD_call(L,L->top-2,0);}LUA_API int
|
|
|
|
lua_cpcall(lua_State*L,lua_CFunction func,void*ud){struct CCallS c;int status;
|
|
|
|
lua_lock(L);c.func=func;c.ud=ud;status=luaD_pcall(L,f_Ccall,&c,savestack(L,L->
|
|
|
|
top),0);lua_unlock(L);return status;}LUA_API int lua_load(lua_State*L,
|
|
|
|
lua_Chunkreader reader,void*data,const char*chunkname){ZIO z;int status;int c;
|
|
|
|
lua_lock(L);if(!chunkname)chunkname="?";luaZ_init(&z,reader,data,chunkname);c=
|
|
|
|
luaZ_lookahead(&z);status=luaD_protectedparser(L,&z,(c==LUA_SIGNATURE[0]));
|
|
|
|
lua_unlock(L);return status;}LUA_API int lua_dump(lua_State*L,lua_Chunkwriter
|
|
|
|
writer,void*data){int status;TObject*o;lua_lock(L);api_checknelems(L,1);o=L->
|
|
|
|
top-1;if(isLfunction(o)&&clvalue(o)->l.nupvalues==0){luaU_dump(L,clvalue(o)->l
|
|
|
|
.p,writer,data);status=1;}else status=0;lua_unlock(L);return status;}
|
|
|
|
#define GCscalel(x) ((x)>>10)
|
|
|
|
#define GCscale(x) (cast(int,GCscalel(x)))
|
|
|
|
#define GCunscale(x) (cast(lu_mem,x)<<10)
|
|
|
|
LUA_API int lua_getgcthreshold(lua_State*L){int threshold;lua_lock(L);
|
|
|
|
threshold=GCscale(G(L)->GCthreshold);lua_unlock(L);return threshold;}LUA_API
|
|
|
|
int lua_getgccount(lua_State*L){int count;lua_lock(L);count=GCscale(G(L)->
|
|
|
|
nblocks);lua_unlock(L);return count;}LUA_API void lua_setgcthreshold(lua_State
|
|
|
|
*L,int newthreshold){lua_lock(L);if(cast(lu_mem,newthreshold)>GCscalel(
|
|
|
|
MAX_LUMEM))G(L)->GCthreshold=MAX_LUMEM;else G(L)->GCthreshold=GCunscale(
|
|
|
|
newthreshold);luaC_checkGC(L);lua_unlock(L);}LUA_API const char*lua_version(
|
|
|
|
void){return LUA_VERSION;}LUA_API int lua_error(lua_State*L){lua_lock(L);
|
|
|
|
api_checknelems(L,1);luaG_errormsg(L);lua_unlock(L);return 0;}LUA_API int
|
|
|
|
lua_next(lua_State*L,int idx){StkId t;int more;lua_lock(L);t=luaA_index(L,idx)
|
|
|
|
;api_check(L,ttistable(t));more=luaH_next(L,hvalue(t),L->top-1);if(more){
|
|
|
|
api_incr_top(L);}else L->top-=1;lua_unlock(L);return more;}LUA_API void
|
|
|
|
lua_concat(lua_State*L,int n){lua_lock(L);luaC_checkGC(L);api_checknelems(L,n)
|
|
|
|
;if(n>=2){luaV_concat(L,n,L->top-L->base-1);L->top-=(n-1);}else if(n==0){
|
|
|
|
setsvalue2s(L->top,luaS_newlstr(L,NULL,0));api_incr_top(L);}lua_unlock(L);}
|
|
|
|
LUA_API void*lua_newuserdata(lua_State*L,size_t size){Udata*u;lua_lock(L);
|
|
|
|
luaC_checkGC(L);u=luaS_newudata(L,size);setuvalue(L->top,u);api_incr_top(L);
|
|
|
|
lua_unlock(L);return u+1;}LUA_API int lua_pushupvalues(lua_State*L){Closure*
|
|
|
|
func;int n,i;lua_lock(L);api_check(L,iscfunction(L->base-1));func=clvalue(L->
|
|
|
|
base-1);n=func->c.nupvalues;luaD_checkstack(L,n+LUA_MINSTACK);for(i=0;i<n;i++)
|
|
|
|
{setobj2s(L->top,&func->c.upvalue[i]);L->top++;}lua_unlock(L);return n;}static
|
|
|
|
const char*aux_upvalue(lua_State*L,int funcindex,int n,TObject**val){Closure*
|
|
|
|
f;StkId fi=luaA_index(L,funcindex);if(!ttisfunction(fi))return NULL;f=clvalue(
|
|
|
|
fi);if(f->c.isC){if(n>f->c.nupvalues)return NULL;*val=&f->c.upvalue[n-1];
|
|
|
|
return"";}else{Proto*p=f->l.p;if(n>p->sizeupvalues)return NULL;*val=f->l.
|
|
|
|
upvals[n-1]->v;return getstr(p->upvalues[n-1]);}}LUA_API const char*
|
|
|
|
lua_getupvalue(lua_State*L,int funcindex,int n){const char*name;TObject*val;
|
|
|
|
lua_lock(L);name=aux_upvalue(L,funcindex,n,&val);if(name){setobj2s(L->top,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;TObject*val;lua_lock(L);
|
|
|
|
api_checknelems(L,1);name=aux_upvalue(L,funcindex,n,&val);if(name){L->top--;
|
|
|
|
setobj(val,L->top);}lua_unlock(L);return name;}
|
|
|
|
#line 1 "lauxlib.c"
|
|
|
|
#define lauxlib_c
|
|
|
|
#line 1 "lauxlib.h"
|
|
|
|
#ifndef lauxlib_h
|
|
|
|
#define lauxlib_h
|
|
|
|
#ifndef LUALIB_API
|
|
|
|
#define LUALIB_API LUA_API
|
|
|
|
#endif
|
|
|
|
typedef struct luaL_reg{const char*name;lua_CFunction func;}luaL_reg;
|
|
|
|
LUALIB_API void luaL_openlib(lua_State*L,const char*libname,const luaL_reg*l,
|
|
|
|
int nup);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 int
|
|
|
|
luaL_typerror(lua_State*L,int narg,const char*tname);LUALIB_API int
|
|
|
|
luaL_argerror(lua_State*L,int numarg,const char*extramsg);LUALIB_API const
|
|
|
|
char*luaL_checklstring(lua_State*L,int numArg,size_t*l);LUALIB_API const char*
|
|
|
|
luaL_optlstring(lua_State*L,int numArg,const char*def,size_t*l);LUALIB_API
|
|
|
|
lua_Number luaL_checknumber(lua_State*L,int numArg);LUALIB_API lua_Number
|
|
|
|
luaL_optnumber(lua_State*L,int nArg,lua_Number def);LUALIB_API void
|
|
|
|
luaL_checkstack(lua_State*L,int sz,const char*msg);LUALIB_API void
|
|
|
|
luaL_checktype(lua_State*L,int narg,int t);LUALIB_API void luaL_checkany(
|
|
|
|
lua_State*L,int narg);LUALIB_API int luaL_newmetatable(lua_State*L,const char*
|
|
|
|
tname);LUALIB_API void luaL_getmetatable(lua_State*L,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_findstring(const char*st,
|
|
|
|
const char*const lst[]);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_getn(lua_State*
|
|
|
|
L,int t);LUALIB_API void luaL_setn(lua_State*L,int t,int n);LUALIB_API int
|
|
|
|
luaL_loadfile(lua_State*L,const char*filename);LUALIB_API int luaL_loadbuffer(
|
|
|
|
lua_State*L,const char*buff,size_t sz,const char*name);
|
|
|
|
#define luaL_argcheck(L, cond,numarg,extramsg)if(!(cond))luaL_argerror(L,\
|
|
|
|
numarg,extramsg)
|
|
|
|
#define luaL_checkstring(L,n) (luaL_checklstring(L,(n),NULL))
|
|
|
|
#define luaL_optstring(L,n,d) (luaL_optlstring(L,(n),(d),NULL))
|
|
|
|
#define luaL_checkint(L,n) ((int)luaL_checknumber(L,n))
|
|
|
|
#define luaL_checklong(L,n) ((long)luaL_checknumber(L,n))
|
|
|
|
#define luaL_optint(L,n,d) ((int)luaL_optnumber(L,n,(lua_Number)(d)))
|
|
|
|
#define luaL_optlong(L,n,d) ((long)luaL_optnumber(L,n,(lua_Number)(d)))
|
|
|
|
#ifndef LUAL_BUFFERSIZE
|
|
|
|
#define LUAL_BUFFERSIZE BUFSIZ
|
|
|
|
#endif
|
|
|
|
typedef struct luaL_Buffer{char*p;int lvl;lua_State*L;char buffer[
|
|
|
|
LUAL_BUFFERSIZE];}luaL_Buffer;
|
|
|
|
#define luaL_putchar(B,c) ((void)((B)->p<((B)->buffer+LUAL_BUFFERSIZE)||\
|
|
|
|
luaL_prepbuffer(B)),(*(B)->p++=(char)(c)))
|
|
|
|
#define luaL_addsize(B,n) ((B)->p+=(n))
|
|
|
|
LUALIB_API void luaL_buffinit(lua_State*L,luaL_Buffer*B);LUALIB_API char*
|
|
|
|
luaL_prepbuffer(luaL_Buffer*B);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 int lua_dofile(lua_State*L,const
|
|
|
|
char*filename);LUALIB_API int lua_dostring(lua_State*L,const char*str);
|
|
|
|
LUALIB_API int lua_dobuffer(lua_State*L,const char*buff,size_t sz,const char*n
|
|
|
|
);
|
|
|
|
#define luaL_check_lstr luaL_checklstring
|
|
|
|
#define luaL_opt_lstr luaL_optlstring
|
|
|
|
#define luaL_check_number luaL_checknumber
|
|
|
|
#define luaL_opt_number luaL_optnumber
|
|
|
|
#define luaL_arg_check luaL_argcheck
|
|
|
|
#define luaL_check_string luaL_checkstring
|
|
|
|
#define luaL_opt_string luaL_optstring
|
|
|
|
#define luaL_check_int luaL_checkint
|
|
|
|
#define luaL_check_long luaL_checklong
|
|
|
|
#define luaL_opt_int luaL_optint
|
|
|
|
#define luaL_opt_long luaL_optlong
|
|
|
|
#endif
|
|
|
|
#line 24 "lauxlib.c"
|
|
|
|
#define RESERVED_REFS 2
|
|
|
|
#define FREELIST_REF 1
|
|
|
|
#define ARRAYSIZE_REF 2
|
|
|
|
#define abs_index(L, i)((i)>0||(i)<=LUA_REGISTRYINDEX?(i):lua_gettop(L)+(i)+1)
|
|
|
|
LUALIB_API int luaL_argerror(lua_State*L,int narg,const char*extramsg){
|
|
|
|
lua_Debug ar;lua_getstack(L,0,&ar);lua_getinfo(L,"n",&ar);if(strcmp(ar.
|
|
|
|
namewhat,"method")==0){narg--;if(narg==0)return luaL_error(L,
|
|
|
|
"calling `%s' on bad self (%s)",ar.name,extramsg);}if(ar.name==NULL)ar.name=
|
|
|
|
"?";return luaL_error(L,"bad argument #%d to `%s' (%s)",narg,ar.name,extramsg)
|
|
|
|
;}LUALIB_API int luaL_typerror(lua_State*L,int narg,const char*tname){const
|
|
|
|
char*msg=lua_pushfstring(L,"%s expected, got %s",tname,lua_typename(L,lua_type
|
|
|
|
(L,narg)));return luaL_argerror(L,narg,msg);}static void tag_error(lua_State*L
|
|
|
|
,int narg,int tag){luaL_typerror(L,narg,lua_typename(L,tag));}LUALIB_API void
|
|
|
|
luaL_where(lua_State*L,int level){lua_Debug ar;if(lua_getstack(L,level,&ar)){
|
|
|
|
lua_getinfo(L,"Snl",&ar);if(ar.currentline>0){lua_pushfstring(L,"%s:%d: ",ar.
|
|
|
|
short_src,ar.currentline);return;}}lua_pushliteral(L,"");}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_findstring(const char*name,const char
|
|
|
|
*const list[]){int i;for(i=0;list[i];i++)if(strcmp(list[i],name)==0)return i;
|
|
|
|
return-1;}LUALIB_API int luaL_newmetatable(lua_State*L,const char*tname){
|
|
|
|
lua_pushstring(L,tname);lua_rawget(L,LUA_REGISTRYINDEX);if(!lua_isnil(L,-1))
|
|
|
|
return 0;lua_pop(L,1);lua_newtable(L);lua_pushstring(L,tname);lua_pushvalue(L,
|
|
|
|
-2);lua_rawset(L,LUA_REGISTRYINDEX);lua_pushvalue(L,-1);lua_pushstring(L,tname
|
|
|
|
);lua_rawset(L,LUA_REGISTRYINDEX);return 1;}LUALIB_API void luaL_getmetatable(
|
|
|
|
lua_State*L,const char*tname){lua_pushstring(L,tname);lua_rawget(L,
|
|
|
|
LUA_REGISTRYINDEX);}LUALIB_API void*luaL_checkudata(lua_State*L,int ud,const
|
|
|
|
char*tname){const char*tn;if(!lua_getmetatable(L,ud))return NULL;lua_rawget(L,
|
|
|
|
LUA_REGISTRYINDEX);tn=lua_tostring(L,-1);if(tn&&(strcmp(tn,tname)==0)){lua_pop
|
|
|
|
(L,1);return lua_touserdata(L,ud);}else{lua_pop(L,1);return NULL;}}LUALIB_API
|
|
|
|
void luaL_checkstack(lua_State*L,int space,const char*mes){if(!lua_checkstack(
|
|
|
|
L,space))luaL_error(L,"stack overflow (%s)",mes);}LUALIB_API void
|
|
|
|
luaL_checktype(lua_State*L,int narg,int t){if(lua_type(L,narg)!=t)tag_error(L,
|
|
|
|
narg,t);}LUALIB_API void luaL_checkany(lua_State*L,int narg){if(lua_type(L,
|
|
|
|
narg)==LUA_TNONE)luaL_argerror(L,narg,"value expected");}LUALIB_API const char
|
|
|
|
*luaL_checklstring(lua_State*L,int narg,size_t*len){const char*s=lua_tostring(
|
|
|
|
L,narg);if(!s)tag_error(L,narg,LUA_TSTRING);if(len)*len=lua_strlen(L,narg);
|
|
|
|
return s;}LUALIB_API const char*luaL_optlstring(lua_State*L,int narg,const
|
|
|
|
char*def,size_t*len){if(lua_isnoneornil(L,narg)){if(len)*len=(def?strlen(def):
|
|
|
|
0);return def;}else return luaL_checklstring(L,narg,len);}LUALIB_API
|
|
|
|
lua_Number luaL_checknumber(lua_State*L,int narg){lua_Number d=lua_tonumber(L,
|
|
|
|
narg);if(d==0&&!lua_isnumber(L,narg))tag_error(L,narg,LUA_TNUMBER);return d;}
|
|
|
|
LUALIB_API lua_Number luaL_optnumber(lua_State*L,int narg,lua_Number def){if(
|
|
|
|
lua_isnoneornil(L,narg))return def;else return luaL_checknumber(L,narg);}
|
|
|
|
LUALIB_API int luaL_getmetafield(lua_State*L,int obj,const char*event){if(!
|
|
|
|
lua_getmetatable(L,obj))return 0;lua_pushstring(L,event);lua_rawget(L,-2);if(
|
|
|
|
lua_isnil(L,-1)){lua_pop(L,2);return 0;}else{lua_remove(L,-2);return 1;}}
|
|
|
|
LUALIB_API int luaL_callmeta(lua_State*L,int obj,const char*event){obj=
|
|
|
|
abs_index(L,obj);if(!luaL_getmetafield(L,obj,event))return 0;lua_pushvalue(L,
|
|
|
|
obj);lua_call(L,1,1);return 1;}LUALIB_API void luaL_openlib(lua_State*L,const
|
|
|
|
char*libname,const luaL_reg*l,int nup){if(libname){lua_pushstring(L,libname);
|
|
|
|
lua_gettable(L,LUA_GLOBALSINDEX);if(lua_isnil(L,-1)){lua_pop(L,1);lua_newtable
|
|
|
|
(L);lua_pushstring(L,libname);lua_pushvalue(L,-2);lua_settable(L,
|
|
|
|
LUA_GLOBALSINDEX);}lua_insert(L,-(nup+1));}for(;l->name;l++){int i;
|
|
|
|
lua_pushstring(L,l->name);for(i=0;i<nup;i++)lua_pushvalue(L,-(nup+1));
|
|
|
|
lua_pushcclosure(L,l->func,nup);lua_settable(L,-(nup+3));}lua_pop(L,nup);}
|
|
|
|
static int checkint(lua_State*L,int topop){int n=(int)lua_tonumber(L,-1);if(n
|
|
|
|
==0&&!lua_isnumber(L,-1))n=-1;lua_pop(L,topop);return n;}static void getsizes(
|
|
|
|
lua_State*L){lua_rawgeti(L,LUA_REGISTRYINDEX,ARRAYSIZE_REF);if(lua_isnil(L,-1)
|
|
|
|
){lua_pop(L,1);lua_newtable(L);lua_pushvalue(L,-1);lua_setmetatable(L,-2);
|
|
|
|
lua_pushliteral(L,"__mode");lua_pushliteral(L,"k");lua_rawset(L,-3);
|
|
|
|
lua_pushvalue(L,-1);lua_rawseti(L,LUA_REGISTRYINDEX,ARRAYSIZE_REF);}}void
|
|
|
|
luaL_setn(lua_State*L,int t,int n){t=abs_index(L,t);lua_pushliteral(L,"n");
|
|
|
|
lua_rawget(L,t);if(checkint(L,1)>=0){lua_pushliteral(L,"n");lua_pushnumber(L,(
|
|
|
|
lua_Number)n);lua_rawset(L,t);}else{getsizes(L);lua_pushvalue(L,t);
|
|
|
|
lua_pushnumber(L,(lua_Number)n);lua_rawset(L,-3);lua_pop(L,1);}}int luaL_getn(
|
|
|
|
lua_State*L,int t){int n;t=abs_index(L,t);lua_pushliteral(L,"n");lua_rawget(L,
|
|
|
|
t);if((n=checkint(L,1))>=0)return n;getsizes(L);lua_pushvalue(L,t);lua_rawget(
|
|
|
|
L,-2);if((n=checkint(L,2))>=0)return n;for(n=1;;n++){lua_rawgeti(L,t,n);if(
|
|
|
|
lua_isnil(L,-1))break;lua_pop(L,1);}lua_pop(L,1);return n-1;}
|
|
|
|
#define bufflen(B) ((B)->p-(B)->buffer)
|
|
|
|
#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE-bufflen(B)))
|
|
|
|
#define LIMIT (LUA_MINSTACK/2)
|
|
|
|
static int emptybuffer(luaL_Buffer*B){size_t l=bufflen(B);if(l==0)return 0;
|
|
|
|
else{lua_pushlstring(B->L,B->buffer,l);B->p=B->buffer;B->lvl++;return 1;}}
|
|
|
|
static void adjuststack(luaL_Buffer*B){if(B->lvl>1){lua_State*L=B->L;int toget
|
|
|
|
=1;size_t toplen=lua_strlen(L,-1);do{size_t l=lua_strlen(L,-(toget+1));if(B->
|
|
|
|
lvl-toget+1>=LIMIT||toplen>l){toplen+=l;toget++;}else break;}while(toget<B->
|
|
|
|
lvl);lua_concat(L,toget);B->lvl=B->lvl-toget+1;}}LUALIB_API char*
|
|
|
|
luaL_prepbuffer(luaL_Buffer*B){if(emptybuffer(B))adjuststack(B);return B->
|
|
|
|
buffer;}LUALIB_API void luaL_addlstring(luaL_Buffer*B,const char*s,size_t l){
|
|
|
|
while(l--)luaL_putchar(B,*s++);}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){emptybuffer(B);lua_concat(B->L,B->lvl);B->lvl=1;}LUALIB_API
|
|
|
|
void luaL_addvalue(luaL_Buffer*B){lua_State*L=B->L;size_t vl=lua_strlen(L,-1);
|
|
|
|
if(vl<=bufffree(B)){memcpy(B->p,lua_tostring(L,-1),vl);B->p+=vl;lua_pop(L,1);}
|
|
|
|
else{if(emptybuffer(B))lua_insert(L,-2);B->lvl++;adjuststack(B);}}LUALIB_API
|
|
|
|
void luaL_buffinit(lua_State*L,luaL_Buffer*B){B->L=L;B->p=B->buffer;B->lvl=0;}
|
|
|
|
LUALIB_API int luaL_ref(lua_State*L,int t){int ref;t=abs_index(L,t);if(
|
|
|
|
lua_isnil(L,-1)){lua_pop(L,1);return LUA_REFNIL;}lua_rawgeti(L,t,FREELIST_REF)
|
|
|
|
;ref=(int)lua_tonumber(L,-1);lua_pop(L,1);if(ref!=0){lua_rawgeti(L,t,ref);
|
|
|
|
lua_rawseti(L,t,FREELIST_REF);}else{ref=luaL_getn(L,t);if(ref<RESERVED_REFS)
|
|
|
|
ref=RESERVED_REFS;ref++;luaL_setn(L,t,ref);}lua_rawseti(L,t,ref);return ref;}
|
|
|
|
LUALIB_API void luaL_unref(lua_State*L,int t,int ref){if(ref>=0){t=abs_index(L
|
|
|
|
,t);lua_rawgeti(L,t,FREELIST_REF);lua_rawseti(L,t,ref);lua_pushnumber(L,(
|
|
|
|
lua_Number)ref);lua_rawseti(L,t,FREELIST_REF);}}typedef struct LoadF{FILE*f;
|
|
|
|
char buff[LUAL_BUFFERSIZE];}LoadF;static const char*getF(lua_State*L,void*ud,
|
|
|
|
size_t*size){LoadF*lf=(LoadF*)ud;(void)L;if(feof(lf->f))return NULL;*size=
|
|
|
|
fread(lf->buff,1,LUAL_BUFFERSIZE,lf->f);return(*size>0)?lf->buff:NULL;}static
|
|
|
|
int errfile(lua_State*L,int fnameindex){const char*filename=lua_tostring(L,
|
|
|
|
fnameindex)+1;lua_pushfstring(L,"cannot read %s: %s",filename,strerror(errno))
|
|
|
|
;lua_remove(L,fnameindex);return LUA_ERRFILE;}LUALIB_API int luaL_loadfile(
|
|
|
|
lua_State*L,const char*filename){LoadF lf;int status,readstatus;int c;int
|
|
|
|
fnameindex=lua_gettop(L)+1;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,fnameindex);c=ungetc(getc(lf.f),lf.f);if(!(isspace(c
|
|
|
|
)||isprint(c))&&lf.f!=stdin){fclose(lf.f);lf.f=fopen(filename,"rb");if(lf.f==
|
|
|
|
NULL)return errfile(L,fnameindex);}status=lua_load(L,getF,&lf,lua_tostring(L,-
|
|
|
|
1));readstatus=ferror(lf.f);if(lf.f!=stdin)fclose(lf.f);if(readstatus){
|
|
|
|
lua_settop(L,fnameindex);return errfile(L,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;
|
|
|
|
if(ls->size==0)return NULL;*size=ls->size;ls->size=0;return ls->s;}LUALIB_API
|
|
|
|
int luaL_loadbuffer(lua_State*L,const char*buff,size_t size,const char*name){
|
|
|
|
LoadS ls;ls.s=buff;ls.size=size;return lua_load(L,getS,&ls,name);}static void
|
|
|
|
callalert(lua_State*L,int status){if(status!=0){lua_getglobal(L,"_ALERT");if(
|
|
|
|
lua_isfunction(L,-1)){lua_insert(L,-2);lua_call(L,1,0);}else{fprintf(stderr,
|
|
|
|
"%s\n",lua_tostring(L,-2));lua_pop(L,2);}}}static int aux_do(lua_State*L,int
|
|
|
|
status){if(status==0){status=lua_pcall(L,0,LUA_MULTRET,0);}callalert(L,status)
|
|
|
|
;return status;}LUALIB_API int lua_dofile(lua_State*L,const char*filename){
|
|
|
|
return aux_do(L,luaL_loadfile(L,filename));}LUALIB_API int lua_dobuffer(
|
|
|
|
lua_State*L,const char*buff,size_t size,const char*name){return aux_do(L,
|
|
|
|
luaL_loadbuffer(L,buff,size,name));}LUALIB_API int lua_dostring(lua_State*L,
|
|
|
|
const char*str){return lua_dobuffer(L,str,strlen(str),str);}
|
|
|
|
#line 1 "lbaselib.c"
|
|
|
|
#define lbaselib_c
|
|
|
|
#line 1 "lualib.h"
|
|
|
|
#ifndef lualib_h
|
|
|
|
#define lualib_h
|
|
|
|
#ifndef LUALIB_API
|
|
|
|
#define LUALIB_API LUA_API
|
|
|
|
#endif
|
|
|
|
#define LUA_COLIBNAME "coroutine"
|
|
|
|
LUALIB_API int luaopen_base(lua_State*L);
|
|
|
|
#define LUA_TABLIBNAME "table"
|
|
|
|
LUALIB_API int luaopen_table(lua_State*L);
|
|
|
|
#define LUA_IOLIBNAME "io"
|
|
|
|
#define LUA_OSLIBNAME "os"
|
|
|
|
LUALIB_API int luaopen_io(lua_State*L);
|
|
|
|
#define LUA_STRLIBNAME "string"
|
|
|
|
LUALIB_API int luaopen_string(lua_State*L);
|
|
|
|
#define LUA_MATHLIBNAME "math"
|
|
|
|
LUALIB_API int luaopen_math(lua_State*L);
|
|
|
|
#define LUA_DBLIBNAME "debug"
|
|
|
|
LUALIB_API int luaopen_debug(lua_State*L);LUALIB_API int luaopen_loadlib(
|
|
|
|
lua_State*L);
|
|
|
|
#ifndef lua_assert
|
|
|
|
#define lua_assert(c)
|
|
|
|
#endif
|
|
|
|
#define lua_baselibopen luaopen_base
|
|
|
|
#define lua_tablibopen luaopen_table
|
|
|
|
#define lua_iolibopen luaopen_io
|
|
|
|
#define lua_strlibopen luaopen_string
|
|
|
|
#define lua_mathlibopen luaopen_math
|
|
|
|
#define lua_dblibopen luaopen_debug
|
|
|
|
#endif
|
|
|
|
#line 20 "lbaselib.c"
|
|
|
|
static int luaB_print(lua_State*L){int n=lua_gettop(L);int i;lua_getglobal(L,
|
|
|
|
"tostring");for(i=1;i<=n;i++){const char*s;lua_pushvalue(L,-1);lua_pushvalue(L
|
|
|
|
,i);lua_call(L,1,1);s=lua_tostring(L,-1);if(s==NULL)return luaL_error(L,
|
|
|
|
"`tostring' must return a string to `print'");if(i>1)fputs("\t",stdout);fputs(
|
|
|
|
s,stdout);lua_pop(L,1);}fputs("\n",stdout);return 0;}static int luaB_tonumber(
|
|
|
|
lua_State*L){int base=luaL_optint(L,2,10);if(base==10){luaL_checkany(L,1);if(
|
|
|
|
lua_isnumber(L,1)){lua_pushnumber(L,lua_tonumber(L,1));return 1;}}else{const
|
|
|
|
char*s1=luaL_checkstring(L,1);char*s2;unsigned long n;luaL_argcheck(L,2<=base
|
|
|
|
&&base<=36,2,"base out of range");n=strtoul(s1,&s2,base);if(s1!=s2){while(
|
|
|
|
isspace((unsigned char)(*s2)))s2++;if(*s2=='\0'){lua_pushnumber(L,(lua_Number)
|
|
|
|
n);return 1;}}}lua_pushnil(L);return 1;}static int luaB_error(lua_State*L){int
|
|
|
|
level=luaL_optint(L,2,1);luaL_checkany(L,1);if(!lua_isstring(L,1)||level==0)
|
|
|
|
lua_pushvalue(L,1);else{luaL_where(L,level);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;}luaL_getmetafield(L,
|
|
|
|
1,"__metatable");return 1;}static int luaB_setmetatable(lua_State*L){int t=
|
|
|
|
lua_type(L,2);luaL_checktype(L,1,LUA_TTABLE);luaL_argcheck(L,t==LUA_TNIL||t==
|
|
|
|
LUA_TTABLE,2,"nil or table expected");if(luaL_getmetafield(L,1,"__metatable"))
|
|
|
|
luaL_error(L,"cannot change a protected metatable");lua_settop(L,2);
|
|
|
|
lua_setmetatable(L,1);return 1;}static void getfunc(lua_State*L){if(
|
|
|
|
lua_isfunction(L,1))lua_pushvalue(L,1);else{lua_Debug ar;int level=luaL_optint
|
|
|
|
(L,1,1);luaL_argcheck(L,level>=0,1,"level must be non-negative");if(
|
|
|
|
lua_getstack(L,level,&ar)==0)luaL_argerror(L,1,"invalid level");lua_getinfo(L,
|
|
|
|
"f",&ar);if(lua_isnil(L,-1))luaL_error(L,
|
|
|
|
"no function environment for tail call at level %d",level);}}static int
|
|
|
|
aux_getfenv(lua_State*L){lua_getfenv(L,-1);lua_pushliteral(L,"__fenv");
|
|
|
|
lua_rawget(L,-2);return!lua_isnil(L,-1);}static int luaB_getfenv(lua_State*L){
|
|
|
|
getfunc(L);if(!aux_getfenv(L))lua_pop(L,1);return 1;}static int luaB_setfenv(
|
|
|
|
lua_State*L){luaL_checktype(L,2,LUA_TTABLE);getfunc(L);if(aux_getfenv(L))
|
|
|
|
luaL_error(L,"`setfenv' cannot change a protected environment");else lua_pop(L
|
|
|
|
,2);lua_pushvalue(L,2);if(lua_isnumber(L,1)&&lua_tonumber(L,1)==0)lua_replace(
|
|
|
|
L,LUA_GLOBALSINDEX);else if(lua_setfenv(L,-2)==0)luaL_error(L,
|
|
|
|
"`setfenv' cannot change environment of given function");return 0;}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_rawget(
|
|
|
|
lua_State*L){luaL_checktype(L,1,LUA_TTABLE);luaL_checkany(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_rawset(L,1);return 1;}static int
|
|
|
|
luaB_gcinfo(lua_State*L){lua_pushnumber(L,(lua_Number)lua_getgccount(L));
|
|
|
|
lua_pushnumber(L,(lua_Number)lua_getgcthreshold(L));return 2;}static int
|
|
|
|
luaB_collectgarbage(lua_State*L){lua_setgcthreshold(L,luaL_optint(L,1,0));
|
|
|
|
return 0;}static int luaB_type(lua_State*L){luaL_checkany(L,1);lua_pushstring(
|
|
|
|
L,lua_typename(L,lua_type(L,1)));return 1;}static int luaB_next(lua_State*L){
|
|
|
|
luaL_checktype(L,1,LUA_TTABLE);lua_settop(L,2);if(lua_next(L,1))return 2;else{
|
|
|
|
lua_pushnil(L);return 1;}}static int luaB_pairs(lua_State*L){luaL_checktype(L,
|
|
|
|
1,LUA_TTABLE);lua_pushliteral(L,"next");lua_rawget(L,LUA_GLOBALSINDEX);
|
|
|
|
lua_pushvalue(L,1);lua_pushnil(L);return 3;}static int luaB_ipairs(lua_State*L
|
|
|
|
){lua_Number i=lua_tonumber(L,2);luaL_checktype(L,1,LUA_TTABLE);if(i==0&&
|
|
|
|
lua_isnone(L,2)){lua_pushliteral(L,"ipairs");lua_rawget(L,LUA_GLOBALSINDEX);
|
|
|
|
lua_pushvalue(L,1);lua_pushnumber(L,0);return 3;}else{i++;lua_pushnumber(L,i);
|
|
|
|
lua_rawgeti(L,1,(int)i);return(lua_isnil(L,-1))?0:2;}}static int load_aux(
|
|
|
|
lua_State*L,int status){if(status==0)return 1;else{lua_pushnil(L);lua_insert(L
|
|
|
|
,-2);return 2;}}static int luaB_loadstring(lua_State*L){size_t l;const char*s=
|
|
|
|
luaL_checklstring(L,1,&l);const char*chunkname=luaL_optstring(L,2,s);return
|
|
|
|
load_aux(L,luaL_loadbuffer(L,s,l,chunkname));}static int luaB_loadfile(
|
|
|
|
lua_State*L){const char*fname=luaL_optstring(L,1,NULL);return load_aux(L,
|
|
|
|
luaL_loadfile(L,fname));}static int luaB_dofile(lua_State*L){const char*fname=
|
|
|
|
luaL_optstring(L,1,NULL);int n=lua_gettop(L);int status=luaL_loadfile(L,fname)
|
|
|
|
;if(status!=0)lua_error(L);lua_call(L,0,LUA_MULTRET);return lua_gettop(L)-n;}
|
|
|
|
static int luaB_assert(lua_State*L){luaL_checkany(L,1);if(!lua_toboolean(L,1))
|
|
|
|
return luaL_error(L,"%s",luaL_optstring(L,2,"assertion failed!"));lua_settop(L
|
|
|
|
,1);return 1;}static int luaB_unpack(lua_State*L){int n,i;luaL_checktype(L,1,
|
|
|
|
LUA_TTABLE);n=luaL_getn(L,1);luaL_checkstack(L,n,"table too big to unpack");
|
|
|
|
for(i=1;i<=n;i++)lua_rawgeti(L,1,i);return n;}static int luaB_pcall(lua_State*
|
|
|
|
L){int status;luaL_checkany(L,1);status=lua_pcall(L,lua_gettop(L)-1,
|
|
|
|
LUA_MULTRET,0);lua_pushboolean(L,(status==0));lua_insert(L,1);return
|
|
|
|
lua_gettop(L);}static int luaB_xpcall(lua_State*L){int status;luaL_checkany(L,
|
|
|
|
2);lua_settop(L,2);lua_insert(L,1);status=lua_pcall(L,0,LUA_MULTRET,1);
|
|
|
|
lua_pushboolean(L,(status==0));lua_replace(L,1);return lua_gettop(L);}static
|
|
|
|
int luaB_tostring(lua_State*L){char buff[128];luaL_checkany(L,1);if(
|
|
|
|
luaL_callmeta(L,1,"__tostring"))return 1;switch(lua_type(L,1)){case
|
|
|
|
LUA_TNUMBER:lua_pushstring(L,lua_tostring(L,1));return 1;case LUA_TSTRING:
|
|
|
|
lua_pushvalue(L,1);return 1;case LUA_TBOOLEAN:lua_pushstring(L,(lua_toboolean(
|
|
|
|
L,1)?"true":"false"));return 1;case LUA_TTABLE:sprintf(buff,"table: %p",
|
|
|
|
lua_topointer(L,1));break;case LUA_TFUNCTION:sprintf(buff,"function: %p",
|
|
|
|
lua_topointer(L,1));break;case LUA_TUSERDATA:case LUA_TLIGHTUSERDATA:sprintf(
|
|
|
|
buff,"userdata: %p",lua_touserdata(L,1));break;case LUA_TTHREAD:sprintf(buff,
|
|
|
|
"thread: %p",(void*)lua_tothread(L,1));break;case LUA_TNIL:lua_pushliteral(L,
|
|
|
|
"nil");return 1;}lua_pushstring(L,buff);return 1;}static int luaB_newproxy(
|
|
|
|
lua_State*L){lua_settop(L,1);lua_newuserdata(L,0);if(lua_toboolean(L,1)==0)
|
|
|
|
return 1;else if(lua_isboolean(L,1)){lua_newtable(L);lua_pushvalue(L,-1);
|
|
|
|
lua_pushboolean(L,1);lua_rawset(L,lua_upvalueindex(1));}else{int validproxy=0;
|
|
|
|
if(lua_getmetatable(L,1)){lua_rawget(L,lua_upvalueindex(1));validproxy=
|
|
|
|
lua_toboolean(L,-1);lua_pop(L,1);}luaL_argcheck(L,validproxy,1,
|
|
|
|
"boolean or proxy expected");lua_getmetatable(L,1);}lua_setmetatable(L,2);
|
|
|
|
return 1;}
|
|
|
|
#define REQTAB "_LOADED"
|
|
|
|
#define LUA_PATH "LUA_PATH"
|
|
|
|
#ifndef LUA_PATH_SEP
|
|
|
|
#define LUA_PATH_SEP ';'
|
|
|
|
#endif
|
|
|
|
#ifndef LUA_PATH_MARK
|
|
|
|
#define LUA_PATH_MARK '?'
|
|
|
|
#endif
|
|
|
|
#ifndef LUA_PATH_DEFAULT
|
|
|
|
#define LUA_PATH_DEFAULT "?;?.lua"
|
|
|
|
#endif
|
|
|
|
static const char*getpath(lua_State*L){const char*path;lua_getglobal(L,
|
|
|
|
LUA_PATH);path=lua_tostring(L,-1);lua_pop(L,1);if(path)return path;path=getenv
|
|
|
|
(LUA_PATH);if(path)return path;return LUA_PATH_DEFAULT;}static const char*
|
|
|
|
pushnextpath(lua_State*L,const char*path){const char*l;if(*path=='\0')return
|
|
|
|
NULL;if(*path==LUA_PATH_SEP)path++;l=strchr(path,LUA_PATH_SEP);if(l==NULL)l=
|
|
|
|
path+strlen(path);lua_pushlstring(L,path,l-path);return l;}static void
|
|
|
|
pushcomposename(lua_State*L){const char*path=lua_tostring(L,-1);const char*
|
|
|
|
wild;int n=1;while((wild=strchr(path,LUA_PATH_MARK))!=NULL){luaL_checkstack(L,
|
|
|
|
3,"too many marks in a path component");lua_pushlstring(L,path,wild-path);
|
|
|
|
lua_pushvalue(L,1);path=wild+1;n+=2;}lua_pushstring(L,path);lua_concat(L,n);}
|
|
|
|
static int luaB_require(lua_State*L){const char*path;int status=LUA_ERRFILE;
|
|
|
|
luaL_checkstring(L,1);lua_settop(L,1);lua_getglobal(L,REQTAB);if(!lua_istable(
|
|
|
|
L,2))return luaL_error(L,"`"REQTAB"' is not a table");path=getpath(L);
|
|
|
|
lua_pushvalue(L,1);lua_rawget(L,2);if(lua_toboolean(L,-1))return 1;else{while(
|
|
|
|
status==LUA_ERRFILE){lua_settop(L,3);if((path=pushnextpath(L,path))==NULL)
|
|
|
|
break;pushcomposename(L);status=luaL_loadfile(L,lua_tostring(L,-1));}}switch(
|
|
|
|
status){case 0:{lua_getglobal(L,"_REQUIREDNAME");lua_insert(L,-2);
|
|
|
|
lua_pushvalue(L,1);lua_setglobal(L,"_REQUIREDNAME");lua_call(L,0,1);lua_insert
|
|
|
|
(L,-2);lua_setglobal(L,"_REQUIREDNAME");if(lua_isnil(L,-1)){lua_pushboolean(L,
|
|
|
|
1);lua_replace(L,-2);}lua_pushvalue(L,1);lua_pushvalue(L,-2);lua_rawset(L,2);
|
|
|
|
return 1;}case LUA_ERRFILE:{return luaL_error(L,
|
|
|
|
"could not load package `%s' from path `%s'",lua_tostring(L,1),getpath(L));}
|
|
|
|
default:{return luaL_error(L,"error loading package `%s' (%s)",lua_tostring(L,
|
|
|
|
1),lua_tostring(L,-1));}}}static const luaL_reg base_funcs[]={{"error",
|
|
|
|
luaB_error},{"getmetatable",luaB_getmetatable},{"setmetatable",
|
|
|
|
luaB_setmetatable},{"getfenv",luaB_getfenv},{"setfenv",luaB_setfenv},{"next",
|
|
|
|
luaB_next},{"ipairs",luaB_ipairs},{"pairs",luaB_pairs},{"print",luaB_print},{
|
|
|
|
"tonumber",luaB_tonumber},{"tostring",luaB_tostring},{"type",luaB_type},{
|
|
|
|
"assert",luaB_assert},{"unpack",luaB_unpack},{"rawequal",luaB_rawequal},{
|
|
|
|
"rawget",luaB_rawget},{"rawset",luaB_rawset},{"pcall",luaB_pcall},{"xpcall",
|
|
|
|
luaB_xpcall},{"collectgarbage",luaB_collectgarbage},{"gcinfo",luaB_gcinfo},{
|
|
|
|
"loadfile",luaB_loadfile},{"dofile",luaB_dofile},{"loadstring",luaB_loadstring
|
|
|
|
},{"require",luaB_require},{NULL,NULL}};static int auxresume(lua_State*L,
|
|
|
|
lua_State*co,int narg){int status;if(!lua_checkstack(co,narg))luaL_error(L,
|
|
|
|
"too many arguments to resume");lua_xmove(L,co,narg);status=lua_resume(co,narg
|
|
|
|
);if(status==0){int nres=lua_gettop(co);if(!lua_checkstack(L,nres))luaL_error(
|
|
|
|
L,"too many results to resume");lua_xmove(co,L,nres);return nres;}else{
|
|
|
|
lua_xmove(co,L,1);return-1;}}static int luaB_coresume(lua_State*L){lua_State*
|
|
|
|
co=lua_tothread(L,1);int r;luaL_argcheck(L,co,1,"coroutine expected");r=
|
|
|
|
auxresume(L,co,lua_gettop(L)-1);if(r<0){lua_pushboolean(L,0);lua_insert(L,-2);
|
|
|
|
return 2;}else{lua_pushboolean(L,1);lua_insert(L,-(r+1));return r+1;}}static
|
|
|
|
int luaB_auxwrap(lua_State*L){lua_State*co=lua_tothread(L,lua_upvalueindex(1))
|
|
|
|
;int r=auxresume(L,co,lua_gettop(L));if(r<0){if(lua_isstring(L,-1)){luaL_where
|
|
|
|
(L,1);lua_insert(L,-2);lua_concat(L,2);}lua_error(L);}return r;}static int
|
|
|
|
luaB_cocreate(lua_State*L){lua_State*NL=lua_newthread(L);luaL_argcheck(L,
|
|
|
|
lua_isfunction(L,1)&&!lua_iscfunction(L,1),1,"Lua function expected");
|
|
|
|
lua_pushvalue(L,1);lua_xmove(L,NL,1);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));}static
|
|
|
|
int luaB_costatus(lua_State*L){lua_State*co=lua_tothread(L,1);luaL_argcheck(L,
|
|
|
|
co,1,"coroutine expected");if(L==co)lua_pushliteral(L,"running");else{
|
|
|
|
lua_Debug ar;if(lua_getstack(co,0,&ar)==0&&lua_gettop(co)==0)lua_pushliteral(L
|
|
|
|
,"dead");else lua_pushliteral(L,"suspended");}return 1;}static const luaL_reg
|
|
|
|
co_funcs[]={{"create",luaB_cocreate},{"wrap",luaB_cowrap},{"resume",
|
|
|
|
luaB_coresume},{"yield",luaB_yield},{"status",luaB_costatus},{NULL,NULL}};
|
|
|
|
static void base_open(lua_State*L){lua_pushliteral(L,"_G");lua_pushvalue(L,
|
|
|
|
LUA_GLOBALSINDEX);luaL_openlib(L,NULL,base_funcs,0);lua_pushliteral(L,
|
|
|
|
"_VERSION");lua_pushliteral(L,LUA_VERSION);lua_rawset(L,-3);lua_pushliteral(L,
|
|
|
|
"newproxy");lua_newtable(L);lua_pushvalue(L,-1);lua_setmetatable(L,-2);
|
|
|
|
lua_pushliteral(L,"__mode");lua_pushliteral(L,"k");lua_rawset(L,-3);
|
|
|
|
lua_pushcclosure(L,luaB_newproxy,1);lua_rawset(L,-3);lua_rawset(L,-1);}
|
|
|
|
LUALIB_API int luaopen_base(lua_State*L){base_open(L);luaL_openlib(L,
|
|
|
|
LUA_COLIBNAME,co_funcs,0);lua_newtable(L);lua_setglobal(L,REQTAB);return 0;}
|
|
|
|
#line 1 "lcode.c"
|
|
|
|
#define lcode_c
|
|
|
|
#line 1 "lcode.h"
|
|
|
|
#ifndef lcode_h
|
|
|
|
#define lcode_h
|
|
|
|
#line 1 "llex.h"
|
|
|
|
#ifndef llex_h
|
|
|
|
#define llex_h
|
|
|
|
#define FIRST_RESERVED 257
|
|
|
|
#define TOKEN_LEN (sizeof("function")/sizeof(char))
|
|
|
|
enum RESERVED{TK_AND=FIRST_RESERVED,TK_BREAK,TK_DO,TK_ELSE,TK_ELSEIF,TK_END,
|
|
|
|
TK_FALSE,TK_FOR,TK_FUNCTION,TK_IF,TK_IN,TK_LOCAL,TK_NIL,TK_NOT,TK_OR,TK_REPEAT
|
|
|
|
,TK_RETURN,TK_THEN,TK_TRUE,TK_UNTIL,TK_WHILE,TK_NAME,TK_CONCAT,TK_DOTS,TK_EQ,
|
|
|
|
TK_GE,TK_LE,TK_NE,TK_NUMBER,TK_STRING,TK_EOS};
|
|
|
|
#define NUM_RESERVED (cast(int,TK_WHILE-FIRST_RESERVED+1))
|
|
|
|
typedef union{lua_Number r;TString*ts;}SemInfo;typedef struct Token{int token;
|
|
|
|
SemInfo seminfo;}Token;typedef struct LexState{int current;int linenumber;int
|
|
|
|
lastline;Token t;Token lookahead;struct FuncState*fs;struct lua_State*L;ZIO*z;
|
|
|
|
Mbuffer*buff;TString*source;int nestlevel;}LexState;void luaX_init(lua_State*L
|
|
|
|
);void luaX_setinput(lua_State*L,LexState*LS,ZIO*z,TString*source);int
|
|
|
|
luaX_lex(LexState*LS,SemInfo*seminfo);void luaX_checklimit(LexState*ls,int val
|
|
|
|
,int limit,const char*msg);void luaX_syntaxerror(LexState*ls,const char*s);
|
|
|
|
void luaX_errorline(LexState*ls,const char*s,const char*token,int line);const
|
|
|
|
char*luaX_token2str(LexState*ls,int token);
|
|
|
|
#endif
|
|
|
|
#line 11 "lcode.h"
|
|
|
|
#line 1 "lopcodes.h"
|
|
|
|
#ifndef lopcodes_h
|
|
|
|
#define lopcodes_h
|
|
|
|
enum OpMode{iABC,iABx,iAsBx};
|
|
|
|
#define SIZE_C 9
|
|
|
|
#define SIZE_B 9
|
|
|
|
#define SIZE_Bx (SIZE_C+SIZE_B)
|
|
|
|
#define SIZE_A 8
|
|
|
|
#define SIZE_OP 6
|
|
|
|
#define POS_C SIZE_OP
|
|
|
|
#define POS_B (POS_C+SIZE_C)
|
|
|
|
#define POS_Bx POS_C
|
|
|
|
#define POS_A (POS_B+SIZE_B)
|
|
|
|
#if SIZE_Bx <BITS_INT-1
|
|
|
|
#define MAXARG_Bx ((1<<SIZE_Bx)-1)
|
|
|
|
#define MAXARG_sBx (MAXARG_Bx>>1)
|
|
|
|
#else
|
|
|
|
#define MAXARG_Bx MAX_INT
|
|
|
|
#define MAXARG_sBx MAX_INT
|
|
|
|
#endif
|
|
|
|
#define MAXARG_A ((1<<SIZE_A)-1)
|
|
|
|
#define MAXARG_B ((1<<SIZE_B)-1)
|
|
|
|
#define MAXARG_C ((1<<SIZE_C)-1)
|
|
|
|
#define MASK1(n,p) ((~((~(Instruction)0)<<n))<<p)
|
|
|
|
#define MASK0(n,p) (~MASK1(n,p))
|
|
|
|
#define GET_OPCODE(i) (cast(OpCode,(i)&MASK1(SIZE_OP,0)))
|
|
|
|
#define SET_OPCODE(i,o) ((i)=(((i)&MASK0(SIZE_OP,0))|cast(Instruction,o)))
|
|
|
|
#define GETARG_A(i) (cast(int,(i)>>POS_A))
|
|
|
|
#define SETARG_A(i,u) ((i)=(((i)&MASK0(SIZE_A,POS_A))|((cast(Instruction,u)<<\
|
|
|
|
POS_A)&MASK1(SIZE_A,POS_A))))
|
|
|
|
#define GETARG_B(i) (cast(int,((i)>>POS_B)&MASK1(SIZE_B,0)))
|
|
|
|
#define SETARG_B(i,b) ((i)=(((i)&MASK0(SIZE_B,POS_B))|((cast(Instruction,b)<<\
|
|
|
|
POS_B)&MASK1(SIZE_B,POS_B))))
|
|
|
|
#define GETARG_C(i) (cast(int,((i)>>POS_C)&MASK1(SIZE_C,0)))
|
|
|
|
#define SETARG_C(i,b) ((i)=(((i)&MASK0(SIZE_C,POS_C))|((cast(Instruction,b)<<\
|
|
|
|
POS_C)&MASK1(SIZE_C,POS_C))))
|
|
|
|
#define GETARG_Bx(i) (cast(int,((i)>>POS_Bx)&MASK1(SIZE_Bx,0)))
|
|
|
|
#define SETARG_Bx(i,b) ((i)=(((i)&MASK0(SIZE_Bx,POS_Bx))|((cast(Instruction,b)\
|
|
|
|
<<POS_Bx)&MASK1(SIZE_Bx,POS_Bx))))
|
|
|
|
#define GETARG_sBx(i) (GETARG_Bx(i)-MAXARG_sBx)
|
|
|
|
#define SETARG_sBx(i,b) SETARG_Bx((i),cast(unsigned int,(b)+MAXARG_sBx))
|
|
|
|
#define CREATE_ABC(o,a,b,c) (cast(Instruction,o)|(cast(Instruction,a)<<POS_A)|\
|
|
|
|
(cast(Instruction,b)<<POS_B)|(cast(Instruction,c)<<POS_C))
|
|
|
|
#define CREATE_ABx(o,a,bc) (cast(Instruction,o)|(cast(Instruction,a)<<POS_A)|(\
|
|
|
|
cast(Instruction,bc)<<POS_Bx))
|
|
|
|
#define NO_REG MAXARG_A
|
|
|
|
typedef enum{OP_MOVE,OP_LOADK,OP_LOADBOOL,OP_LOADNIL,OP_GETUPVAL,OP_GETGLOBAL,
|
|
|
|
OP_GETTABLE,OP_SETGLOBAL,OP_SETUPVAL,OP_SETTABLE,OP_NEWTABLE,OP_SELF,OP_ADD,
|
|
|
|
OP_SUB,OP_MUL,OP_DIV,OP_POW,OP_UNM,OP_NOT,OP_CONCAT,OP_JMP,OP_EQ,OP_LT,OP_LE,
|
|
|
|
OP_TEST,OP_CALL,OP_TAILCALL,OP_RETURN,OP_FORLOOP,OP_TFORLOOP,OP_TFORPREP,
|
|
|
|
OP_SETLIST,OP_SETLISTO,OP_CLOSE,OP_CLOSURE}OpCode;
|
|
|
|
#define NUM_OPCODES (cast(int,OP_CLOSURE+1))
|
|
|
|
enum OpModeMask{OpModeBreg=2,OpModeBrk,OpModeCrk,OpModesetA,OpModeK,OpModeT};
|
|
|
|
extern const lu_byte luaP_opmodes[NUM_OPCODES];
|
|
|
|
#define getOpMode(m) (cast(enum OpMode,luaP_opmodes[m]&3))
|
|
|
|
#define testOpMode(m, b)(luaP_opmodes[m]&(1<<(b)))
|
|
|
|
#ifdef LUA_OPNAMES
|
|
|
|
extern const char*const luaP_opnames[];
|
|
|
|
#endif
|
|
|
|
#define LFIELDS_PER_FLUSH 32
|
|
|
|
#endif
|
|
|
|
#line 13 "lcode.h"
|
|
|
|
#line 1 "lparser.h"
|
|
|
|
#ifndef lparser_h
|
|
|
|
#define lparser_h
|
|
|
|
typedef enum{VVOID,VNIL,VTRUE,VFALSE,VK,VLOCAL,VUPVAL,VGLOBAL,VINDEXED,VJMP,
|
|
|
|
VRELOCABLE,VNONRELOC,VCALL}expkind;typedef struct expdesc{expkind k;int info,
|
|
|
|
aux;int t;int f;}expdesc;struct BlockCnt;typedef struct FuncState{Proto*f;
|
|
|
|
Table*h;struct FuncState*prev;struct LexState*ls;struct lua_State*L;struct
|
|
|
|
BlockCnt*bl;int pc;int lasttarget;int jpc;int freereg;int nk;int np;int
|
|
|
|
nlocvars;int nactvar;expdesc upvalues[MAXUPVALUES];int actvar[MAXVARS];}
|
|
|
|
FuncState;Proto*luaY_parser(lua_State*L,ZIO*z,Mbuffer*buff);
|
|
|
|
#endif
|
|
|
|
#line 14 "lcode.h"
|
|
|
|
#define NO_JUMP (-1)
|
|
|
|
typedef enum BinOpr{OPR_ADD,OPR_SUB,OPR_MULT,OPR_DIV,OPR_POW,OPR_CONCAT,OPR_NE
|
|
|
|
,OPR_EQ,OPR_LT,OPR_LE,OPR_GT,OPR_GE,OPR_AND,OPR_OR,OPR_NOBINOPR}BinOpr;
|
|
|
|
#define binopistest(op) ((op)>=OPR_NE)
|
|
|
|
typedef enum UnOpr{OPR_MINUS,OPR_NOT,OPR_NOUNOPR}UnOpr;
|
|
|
|
#define getcode(fs,e) ((fs)->f->code[(e)->info])
|
|
|
|
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
|
|
|
|
int luaK_code(FuncState*fs,Instruction i,int line);int luaK_codeABx(FuncState*
|
|
|
|
fs,OpCode o,int A,unsigned int Bx);int luaK_codeABC(FuncState*fs,OpCode o,int
|
|
|
|
A,int B,int C);void luaK_fixline(FuncState*fs,int line);void luaK_nil(
|
|
|
|
FuncState*fs,int from,int n);void luaK_reserveregs(FuncState*fs,int n);void
|
|
|
|
luaK_checkstack(FuncState*fs,int n);int luaK_stringK(FuncState*fs,TString*s);
|
|
|
|
int luaK_numberK(FuncState*fs,lua_Number r);void luaK_dischargevars(FuncState*
|
|
|
|
fs,expdesc*e);int luaK_exp2anyreg(FuncState*fs,expdesc*e);void
|
|
|
|
luaK_exp2nextreg(FuncState*fs,expdesc*e);void luaK_exp2val(FuncState*fs,
|
|
|
|
expdesc*e);int luaK_exp2RK(FuncState*fs,expdesc*e);void luaK_self(FuncState*fs
|
|
|
|
,expdesc*e,expdesc*key);void luaK_indexed(FuncState*fs,expdesc*t,expdesc*k);
|
|
|
|
void luaK_goiftrue(FuncState*fs,expdesc*e);void luaK_goiffalse(FuncState*fs,
|
|
|
|
expdesc*e);void luaK_storevar(FuncState*fs,expdesc*var,expdesc*e);void
|
|
|
|
luaK_setcallreturns(FuncState*fs,expdesc*var,int nresults);int luaK_jump(
|
|
|
|
FuncState*fs);void luaK_patchlist(FuncState*fs,int list,int target);void
|
|
|
|
luaK_patchtohere(FuncState*fs,int list);void luaK_concat(FuncState*fs,int*l1,
|
|
|
|
int l2);int luaK_getlabel(FuncState*fs);void luaK_prefix(FuncState*fs,UnOpr op
|
|
|
|
,expdesc*v);void luaK_infix(FuncState*fs,BinOpr op,expdesc*v);void luaK_posfix
|
|
|
|
(FuncState*fs,BinOpr op,expdesc*v1,expdesc*v2);
|
|
|
|
#endif
|
|
|
|
#line 15 "lcode.c"
|
|
|
|
#define hasjumps(e) ((e)->t!=(e)->f)
|
|
|
|
void luaK_nil(FuncState*fs,int from,int n){Instruction*previous;if(fs->pc>fs->
|
|
|
|
lasttarget&&GET_OPCODE(*(previous=&fs->f->code[fs->pc-1]))==OP_LOADNIL){int
|
|
|
|
pfrom=GETARG_A(*previous);int pto=GETARG_B(*previous);if(pfrom<=from&&from<=
|
|
|
|
pto+1){if(from+n-1>pto)SETARG_B(*previous,from+n-1);return;}}luaK_codeABC(fs,
|
|
|
|
OP_LOADNIL,from,from+n-1,0);}int luaK_jump(FuncState*fs){int jpc=fs->jpc;int j
|
|
|
|
;fs->jpc=NO_JUMP;j=luaK_codeAsBx(fs,OP_JMP,0,NO_JUMP);luaK_concat(fs,&j,jpc);
|
|
|
|
return j;}static int luaK_condjump(FuncState*fs,OpCode op,int A,int B,int C){
|
|
|
|
luaK_codeABC(fs,op,A,B,C);return luaK_jump(fs);}static void luaK_fixjump(
|
|
|
|
FuncState*fs,int pc,int dest){Instruction*jmp=&fs->f->code[pc];int offset=dest
|
|
|
|
-(pc+1);lua_assert(dest!=NO_JUMP);if(abs(offset)>MAXARG_sBx)luaX_syntaxerror(
|
|
|
|
fs->ls,"control structure too long");SETARG_sBx(*jmp,offset);}int
|
|
|
|
luaK_getlabel(FuncState*fs){fs->lasttarget=fs->pc;return fs->pc;}static int
|
|
|
|
luaK_getjump(FuncState*fs,int pc){int offset=GETARG_sBx(fs->f->code[pc]);if(
|
|
|
|
offset==NO_JUMP)return NO_JUMP;else return(pc+1)+offset;}static Instruction*
|
|
|
|
getjumpcontrol(FuncState*fs,int pc){Instruction*pi=&fs->f->code[pc];if(pc>=1&&
|
|
|
|
testOpMode(GET_OPCODE(*(pi-1)),OpModeT))return pi-1;else return pi;}static int
|
|
|
|
need_value(FuncState*fs,int list,int cond){for(;list!=NO_JUMP;list=
|
|
|
|
luaK_getjump(fs,list)){Instruction i=*getjumpcontrol(fs,list);if(GET_OPCODE(i)
|
|
|
|
!=OP_TEST||GETARG_C(i)!=cond)return 1;}return 0;}static void patchtestreg(
|
|
|
|
Instruction*i,int reg){if(reg==NO_REG)reg=GETARG_B(*i);SETARG_A(*i,reg);}
|
|
|
|
static void luaK_patchlistaux(FuncState*fs,int list,int ttarget,int treg,int
|
|
|
|
ftarget,int freg,int dtarget){while(list!=NO_JUMP){int next=luaK_getjump(fs,
|
|
|
|
list);Instruction*i=getjumpcontrol(fs,list);if(GET_OPCODE(*i)!=OP_TEST){
|
|
|
|
lua_assert(dtarget!=NO_JUMP);luaK_fixjump(fs,list,dtarget);}else{if(GETARG_C(*
|
|
|
|
i)){lua_assert(ttarget!=NO_JUMP);patchtestreg(i,treg);luaK_fixjump(fs,list,
|
|
|
|
ttarget);}else{lua_assert(ftarget!=NO_JUMP);patchtestreg(i,freg);luaK_fixjump(
|
|
|
|
fs,list,ftarget);}}list=next;}}static void luaK_dischargejpc(FuncState*fs){
|
|
|
|
luaK_patchlistaux(fs,fs->jpc,fs->pc,NO_REG,fs->pc,NO_REG,fs->pc);fs->jpc=
|
|
|
|
NO_JUMP;}void luaK_patchlist(FuncState*fs,int list,int target){if(target==fs->
|
|
|
|
pc)luaK_patchtohere(fs,list);else{lua_assert(target<fs->pc);luaK_patchlistaux(
|
|
|
|
fs,list,target,NO_REG,target,NO_REG,target);}}void luaK_patchtohere(FuncState*
|
|
|
|
fs,int list){luaK_getlabel(fs);luaK_concat(fs,&fs->jpc,list);}void luaK_concat
|
|
|
|
(FuncState*fs,int*l1,int l2){if(l2==NO_JUMP)return;else if(*l1==NO_JUMP)*l1=l2
|
|
|
|
;else{int list=*l1;int next;while((next=luaK_getjump(fs,list))!=NO_JUMP)list=
|
|
|
|
next;luaK_fixjump(fs,list,l2);}}void luaK_checkstack(FuncState*fs,int n){int
|
|
|
|
newstack=fs->freereg+n;if(newstack>fs->f->maxstacksize){if(newstack>=MAXSTACK)
|
|
|
|
luaX_syntaxerror(fs->ls,"function or expression too complex");fs->f->
|
|
|
|
maxstacksize=cast(lu_byte,newstack);}}void luaK_reserveregs(FuncState*fs,int n
|
|
|
|
){luaK_checkstack(fs,n);fs->freereg+=n;}static void freereg(FuncState*fs,int
|
|
|
|
reg){if(reg>=fs->nactvar&®<MAXSTACK){fs->freereg--;lua_assert(reg==fs->
|
|
|
|
freereg);}}static void freeexp(FuncState*fs,expdesc*e){if(e->k==VNONRELOC)
|
|
|
|
freereg(fs,e->info);}static int addk(FuncState*fs,TObject*k,TObject*v){const
|
|
|
|
TObject*idx=luaH_get(fs->h,k);if(ttisnumber(idx)){lua_assert(luaO_rawequalObj(
|
|
|
|
&fs->f->k[cast(int,nvalue(idx))],v));return cast(int,nvalue(idx));}else{Proto*
|
|
|
|
f=fs->f;luaM_growvector(fs->L,f->k,fs->nk,f->sizek,TObject,MAXARG_Bx,
|
|
|
|
"constant table overflow");setobj2n(&f->k[fs->nk],v);setnvalue(luaH_set(fs->L,
|
|
|
|
fs->h,k),cast(lua_Number,fs->nk));return fs->nk++;}}int luaK_stringK(FuncState
|
|
|
|
*fs,TString*s){TObject o;setsvalue(&o,s);return addk(fs,&o,&o);}int
|
|
|
|
luaK_numberK(FuncState*fs,lua_Number r){TObject o;setnvalue(&o,r);return addk(
|
|
|
|
fs,&o,&o);}static int nil_constant(FuncState*fs){TObject k,v;setnilvalue(&v);
|
|
|
|
sethvalue(&k,fs->h);return addk(fs,&k,&v);}void luaK_setcallreturns(FuncState*
|
|
|
|
fs,expdesc*e,int nresults){if(e->k==VCALL){SETARG_C(getcode(fs,e),nresults+1);
|
|
|
|
if(nresults==1){e->k=VNONRELOC;e->info=GETARG_A(getcode(fs,e));}}}void
|
|
|
|
luaK_dischargevars(FuncState*fs,expdesc*e){switch(e->k){case VLOCAL:{e->k=
|
|
|
|
VNONRELOC;break;}case VUPVAL:{e->info=luaK_codeABC(fs,OP_GETUPVAL,0,e->info,0)
|
|
|
|
;e->k=VRELOCABLE;break;}case VGLOBAL:{e->info=luaK_codeABx(fs,OP_GETGLOBAL,0,e
|
|
|
|
->info);e->k=VRELOCABLE;break;}case VINDEXED:{freereg(fs,e->aux);freereg(fs,e
|
|
|
|
->info);e->info=luaK_codeABC(fs,OP_GETTABLE,0,e->info,e->aux);e->k=VRELOCABLE;
|
|
|
|
break;}case VCALL:{luaK_setcallreturns(fs,e,1);break;}default:break;}}static
|
|
|
|
int code_label(FuncState*fs,int A,int b,int jump){luaK_getlabel(fs);return
|
|
|
|
luaK_codeABC(fs,OP_LOADBOOL,A,b,jump);}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:case VTRUE:{luaK_codeABC(fs,OP_LOADBOOL,reg,e->k
|
|
|
|
==VTRUE,0);break;}case VK:{luaK_codeABx(fs,OP_LOADK,reg,e->info);break;}case
|
|
|
|
VRELOCABLE:{Instruction*pc=&getcode(fs,e);SETARG_A(*pc,reg);break;}case
|
|
|
|
VNONRELOC:{if(reg!=e->info)luaK_codeABC(fs,OP_MOVE,reg,e->info,0);break;}
|
|
|
|
default:{lua_assert(e->k==VVOID||e->k==VJMP);return;}}e->info=reg;e->k=
|
|
|
|
VNONRELOC;}static void discharge2anyreg(FuncState*fs,expdesc*e){if(e->k!=
|
|
|
|
VNONRELOC){luaK_reserveregs(fs,1);discharge2reg(fs,e,fs->freereg-1);}}static
|
|
|
|
void luaK_exp2reg(FuncState*fs,expdesc*e,int reg){discharge2reg(fs,e,reg);if(e
|
|
|
|
->k==VJMP)luaK_concat(fs,&e->t,e->info);if(hasjumps(e)){int final;int p_f=
|
|
|
|
NO_JUMP;int p_t=NO_JUMP;if(need_value(fs,e->t,1)||need_value(fs,e->f,0)){int
|
|
|
|
fj=NO_JUMP;if(e->k!=VJMP)fj=luaK_jump(fs);p_f=code_label(fs,reg,0,1);p_t=
|
|
|
|
code_label(fs,reg,1,0);luaK_patchtohere(fs,fj);}final=luaK_getlabel(fs);
|
|
|
|
luaK_patchlistaux(fs,e->f,p_f,NO_REG,final,reg,p_f);luaK_patchlistaux(fs,e->t,
|
|
|
|
final,reg,p_t,NO_REG,p_t);}e->f=e->t=NO_JUMP;e->info=reg;e->k=VNONRELOC;}void
|
|
|
|
luaK_exp2nextreg(FuncState*fs,expdesc*e){luaK_dischargevars(fs,e);freeexp(fs,e
|
|
|
|
);luaK_reserveregs(fs,1);luaK_exp2reg(fs,e,fs->freereg-1);}int luaK_exp2anyreg
|
|
|
|
(FuncState*fs,expdesc*e){luaK_dischargevars(fs,e);if(e->k==VNONRELOC){if(!
|
|
|
|
hasjumps(e))return e->info;if(e->info>=fs->nactvar){luaK_exp2reg(fs,e,e->info)
|
|
|
|
;return e->info;}}luaK_exp2nextreg(fs,e);return e->info;}void luaK_exp2val(
|
|
|
|
FuncState*fs,expdesc*e){if(hasjumps(e))luaK_exp2anyreg(fs,e);else
|
|
|
|
luaK_dischargevars(fs,e);}int luaK_exp2RK(FuncState*fs,expdesc*e){luaK_exp2val
|
|
|
|
(fs,e);switch(e->k){case VNIL:{if(fs->nk+MAXSTACK<=MAXARG_C){e->info=
|
|
|
|
nil_constant(fs);e->k=VK;return e->info+MAXSTACK;}else break;}case VK:{if(e->
|
|
|
|
info+MAXSTACK<=MAXARG_C)return e->info+MAXSTACK;else break;}default:break;}
|
|
|
|
return luaK_exp2anyreg(fs,e);}void luaK_storevar(FuncState*fs,expdesc*var,
|
|
|
|
expdesc*exp){switch(var->k){case VLOCAL:{freeexp(fs,exp);luaK_exp2reg(fs,exp,
|
|
|
|
var->info);return;}case VUPVAL:{int e=luaK_exp2anyreg(fs,exp);luaK_codeABC(fs,
|
|
|
|
OP_SETUPVAL,e,var->info,0);break;}case VGLOBAL:{int e=luaK_exp2anyreg(fs,exp);
|
|
|
|
luaK_codeABx(fs,OP_SETGLOBAL,e,var->info);break;}case VINDEXED:{int e=
|
|
|
|
luaK_exp2RK(fs,exp);luaK_codeABC(fs,OP_SETTABLE,var->info,var->aux,e);break;}
|
|
|
|
default:{lua_assert(0);break;}}freeexp(fs,exp);}void luaK_self(FuncState*fs,
|
|
|
|
expdesc*e,expdesc*key){int func;luaK_exp2anyreg(fs,e);freeexp(fs,e);func=fs->
|
|
|
|
freereg;luaK_reserveregs(fs,2);luaK_codeABC(fs,OP_SELF,func,e->info,
|
|
|
|
luaK_exp2RK(fs,key));freeexp(fs,key);e->info=func;e->k=VNONRELOC;}static void
|
|
|
|
invertjump(FuncState*fs,expdesc*e){Instruction*pc=getjumpcontrol(fs,e->info);
|
|
|
|
lua_assert(testOpMode(GET_OPCODE(*pc),OpModeT)&&GET_OPCODE(*pc)!=OP_TEST);
|
|
|
|
SETARG_A(*pc,!(GETARG_A(*pc)));}static int jumponcond(FuncState*fs,expdesc*e,
|
|
|
|
int cond){if(e->k==VRELOCABLE){Instruction ie=getcode(fs,e);if(GET_OPCODE(ie)
|
|
|
|
==OP_NOT){fs->pc--;return luaK_condjump(fs,OP_TEST,NO_REG,GETARG_B(ie),!cond);
|
|
|
|
}}discharge2anyreg(fs,e);freeexp(fs,e);return luaK_condjump(fs,OP_TEST,NO_REG,
|
|
|
|
e->info,cond);}void luaK_goiftrue(FuncState*fs,expdesc*e){int pc;
|
|
|
|
luaK_dischargevars(fs,e);switch(e->k){case VK:case VTRUE:{pc=NO_JUMP;break;}
|
|
|
|
case VFALSE:{pc=luaK_jump(fs);break;}case VJMP:{invertjump(fs,e);pc=e->info;
|
|
|
|
break;}default:{pc=jumponcond(fs,e,0);break;}}luaK_concat(fs,&e->f,pc);}void
|
|
|
|
luaK_goiffalse(FuncState*fs,expdesc*e){int pc;luaK_dischargevars(fs,e);switch(
|
|
|
|
e->k){case VNIL:case VFALSE:{pc=NO_JUMP;break;}case VTRUE:{pc=luaK_jump(fs);
|
|
|
|
break;}case VJMP:{pc=e->info;break;}default:{pc=jumponcond(fs,e,1);break;}}
|
|
|
|
luaK_concat(fs,&e->t,pc);}static void codenot(FuncState*fs,expdesc*e){
|
|
|
|
luaK_dischargevars(fs,e);switch(e->k){case VNIL:case VFALSE:{e->k=VTRUE;break;
|
|
|
|
}case VK:case VTRUE:{e->k=VFALSE;break;}case VJMP:{invertjump(fs,e);break;}
|
|
|
|
case VRELOCABLE:case VNONRELOC:{discharge2anyreg(fs,e);freeexp(fs,e);e->info=
|
|
|
|
luaK_codeABC(fs,OP_NOT,0,e->info,0);e->k=VRELOCABLE;break;}default:{lua_assert
|
|
|
|
(0);break;}}{int temp=e->f;e->f=e->t;e->t=temp;}}void luaK_indexed(FuncState*
|
|
|
|
fs,expdesc*t,expdesc*k){t->aux=luaK_exp2RK(fs,k);t->k=VINDEXED;}void
|
|
|
|
luaK_prefix(FuncState*fs,UnOpr op,expdesc*e){if(op==OPR_MINUS){luaK_exp2val(fs
|
|
|
|
,e);if(e->k==VK&&ttisnumber(&fs->f->k[e->info]))e->info=luaK_numberK(fs,-
|
|
|
|
nvalue(&fs->f->k[e->info]));else{luaK_exp2anyreg(fs,e);freeexp(fs,e);e->info=
|
|
|
|
luaK_codeABC(fs,OP_UNM,0,e->info,0);e->k=VRELOCABLE;}}else codenot(fs,e);}void
|
|
|
|
luaK_infix(FuncState*fs,BinOpr op,expdesc*v){switch(op){case OPR_AND:{
|
|
|
|
luaK_goiftrue(fs,v);luaK_patchtohere(fs,v->t);v->t=NO_JUMP;break;}case OPR_OR:
|
|
|
|
{luaK_goiffalse(fs,v);luaK_patchtohere(fs,v->f);v->f=NO_JUMP;break;}case
|
|
|
|
OPR_CONCAT:{luaK_exp2nextreg(fs,v);break;}default:{luaK_exp2RK(fs,v);break;}}}
|
|
|
|
static void codebinop(FuncState*fs,expdesc*res,BinOpr op,int o1,int o2){if(op
|
|
|
|
<=OPR_POW){OpCode opc=cast(OpCode,(op-OPR_ADD)+OP_ADD);res->info=luaK_codeABC(
|
|
|
|
fs,opc,0,o1,o2);res->k=VRELOCABLE;}else{static const OpCode ops[]={OP_EQ,OP_EQ
|
|
|
|
,OP_LT,OP_LE,OP_LT,OP_LE};int cond=1;if(op>=OPR_GT){int temp;temp=o1;o1=o2;o2=
|
|
|
|
temp;}else if(op==OPR_NE)cond=0;res->info=luaK_condjump(fs,ops[op-OPR_NE],cond
|
|
|
|
,o1,o2);res->k=VJMP;}}void luaK_posfix(FuncState*fs,BinOpr op,expdesc*e1,
|
|
|
|
expdesc*e2){switch(op){case OPR_AND:{lua_assert(e1->t==NO_JUMP);
|
|
|
|
luaK_dischargevars(fs,e2);luaK_concat(fs,&e1->f,e2->f);e1->k=e2->k;e1->info=e2
|
|
|
|
->info;e1->aux=e2->aux;e1->t=e2->t;break;}case OPR_OR:{lua_assert(e1->f==
|
|
|
|
NO_JUMP);luaK_dischargevars(fs,e2);luaK_concat(fs,&e1->t,e2->t);e1->k=e2->k;e1
|
|
|
|
->info=e2->info;e1->aux=e2->aux;e1->f=e2->f;break;}case OPR_CONCAT:{
|
|
|
|
luaK_exp2val(fs,e2);if(e2->k==VRELOCABLE&&GET_OPCODE(getcode(fs,e2))==
|
|
|
|
OP_CONCAT){lua_assert(e1->info==GETARG_B(getcode(fs,e2))-1);freeexp(fs,e1);
|
|
|
|
SETARG_B(getcode(fs,e2),e1->info);e1->k=e2->k;e1->info=e2->info;}else{
|
|
|
|
luaK_exp2nextreg(fs,e2);freeexp(fs,e2);freeexp(fs,e1);e1->info=luaK_codeABC(fs
|
|
|
|
,OP_CONCAT,0,e1->info,e2->info);e1->k=VRELOCABLE;}break;}default:{int o1=
|
|
|
|
luaK_exp2RK(fs,e1);int o2=luaK_exp2RK(fs,e2);freeexp(fs,e2);freeexp(fs,e1);
|
|
|
|
codebinop(fs,e1,op,o1,o2);}}}void luaK_fixline(FuncState*fs,int line){fs->f->
|
|
|
|
lineinfo[fs->pc-1]=line;}int luaK_code(FuncState*fs,Instruction i,int line){
|
|
|
|
Proto*f=fs->f;luaK_dischargejpc(fs);luaM_growvector(fs->L,f->code,fs->pc,f->
|
|
|
|
sizecode,Instruction,MAX_INT,"code size overflow");f->code[fs->pc]=i;
|
|
|
|
luaM_growvector(fs->L,f->lineinfo,fs->pc,f->sizelineinfo,int,MAX_INT,
|
|
|
|
"code size overflow");f->lineinfo[fs->pc]=line;return fs->pc++;}int
|
|
|
|
luaK_codeABC(FuncState*fs,OpCode o,int a,int b,int c){lua_assert(getOpMode(o)
|
|
|
|
==iABC);return luaK_code(fs,CREATE_ABC(o,a,b,c),fs->ls->lastline);}int
|
|
|
|
luaK_codeABx(FuncState*fs,OpCode o,int a,unsigned int bc){lua_assert(getOpMode
|
|
|
|
(o)==iABx||getOpMode(o)==iAsBx);return luaK_code(fs,CREATE_ABx(o,a,bc),fs->ls
|
|
|
|
->lastline);}
|
|
|
|
#line 1 "ldblib.c"
|
|
|
|
#define ldblib_c
|
|
|
|
static void settabss(lua_State*L,const char*i,const char*v){lua_pushstring(L,i
|
|
|
|
);lua_pushstring(L,v);lua_rawset(L,-3);}static void settabsi(lua_State*L,const
|
|
|
|
char*i,int v){lua_pushstring(L,i);lua_pushnumber(L,(lua_Number)v);lua_rawset(
|
|
|
|
L,-3);}static int getinfo(lua_State*L){lua_Debug ar;const char*options=
|
|
|
|
luaL_optstring(L,2,"flnSu");if(lua_isnumber(L,1)){if(!lua_getstack(L,(int)(
|
|
|
|
lua_tonumber(L,1)),&ar)){lua_pushnil(L);return 1;}}else if(lua_isfunction(L,1)
|
|
|
|
){lua_pushfstring(L,">%s",options);options=lua_tostring(L,-1);lua_pushvalue(L,
|
|
|
|
1);}else return luaL_argerror(L,1,"function or level expected");if(!
|
|
|
|
lua_getinfo(L,options,&ar))return luaL_argerror(L,2,"invalid option");
|
|
|
|
lua_newtable(L);for(;*options;options++){switch(*options){case'S':settabss(L,
|
|
|
|
"source",ar.source);settabss(L,"short_src",ar.short_src);settabsi(L,
|
|
|
|
"linedefined",ar.linedefined);settabss(L,"what",ar.what);break;case'l':
|
|
|
|
settabsi(L,"currentline",ar.currentline);break;case'u':settabsi(L,"nups",ar.
|
|
|
|
nups);break;case'n':settabss(L,"name",ar.name);settabss(L,"namewhat",ar.
|
|
|
|
namewhat);break;case'f':lua_pushliteral(L,"func");lua_pushvalue(L,-3);
|
|
|
|
lua_rawset(L,-3);break;}}return 1;}static int getlocal(lua_State*L){lua_Debug
|
|
|
|
ar;const char*name;if(!lua_getstack(L,luaL_checkint(L,1),&ar))return
|
|
|
|
luaL_argerror(L,1,"level out of range");name=lua_getlocal(L,&ar,luaL_checkint(
|
|
|
|
L,2));if(name){lua_pushstring(L,name);lua_pushvalue(L,-2);return 2;}else{
|
|
|
|
lua_pushnil(L);return 1;}}static int setlocal(lua_State*L){lua_Debug ar;if(!
|
|
|
|
lua_getstack(L,luaL_checkint(L,1),&ar))return luaL_argerror(L,1,
|
|
|
|
"level out of range");luaL_checkany(L,3);lua_pushstring(L,lua_setlocal(L,&ar,
|
|
|
|
luaL_checkint(L,2)));return 1;}static int auxupvalue(lua_State*L,int get){
|
|
|
|
const char*name;int n=luaL_checkint(L,2);luaL_checktype(L,1,LUA_TFUNCTION);if(
|
|
|
|
lua_iscfunction(L,1))return 0;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));
|
|
|
|
return get+1;}static int getupvalue(lua_State*L){return auxupvalue(L,1);}
|
|
|
|
static int setupvalue(lua_State*L){luaL_checkany(L,3);return auxupvalue(L,0);}
|
|
|
|
static const char KEY_HOOK='h';static void hookf(lua_State*L,lua_Debug*ar){
|
|
|
|
static const char*const hooknames[]={"call","return","line","count",
|
|
|
|
"tail return"};lua_pushlightuserdata(L,(void*)&KEY_HOOK);lua_rawget(L,
|
|
|
|
LUA_REGISTRYINDEX);if(lua_isfunction(L,-1)){lua_pushstring(L,hooknames[(int)ar
|
|
|
|
->event]);if(ar->currentline>=0)lua_pushnumber(L,(lua_Number)ar->currentline);
|
|
|
|
else lua_pushnil(L);lua_assert(lua_getinfo(L,"lS",ar));lua_call(L,2,0);}else
|
|
|
|
lua_pop(L,1);}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;}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 sethook(lua_State*L){if(
|
|
|
|
lua_isnoneornil(L,1)){lua_settop(L,1);lua_sethook(L,NULL,0,0);}else{const char
|
|
|
|
*smask=luaL_checkstring(L,2);int count=luaL_optint(L,3,0);luaL_checktype(L,1,
|
|
|
|
LUA_TFUNCTION);lua_sethook(L,hookf,makemask(smask,count),count);}
|
|
|
|
lua_pushlightuserdata(L,(void*)&KEY_HOOK);lua_pushvalue(L,1);lua_rawset(L,
|
|
|
|
LUA_REGISTRYINDEX);return 0;}static int gethook(lua_State*L){char buff[5];int
|
|
|
|
mask=lua_gethookmask(L);lua_Hook hook=lua_gethook(L);if(hook!=NULL&&hook!=
|
|
|
|
hookf)lua_pushliteral(L,"external hook");else{lua_pushlightuserdata(L,(void*)&
|
|
|
|
KEY_HOOK);lua_rawget(L,LUA_REGISTRYINDEX);}lua_pushstring(L,unmakemask(mask,
|
|
|
|
buff));lua_pushnumber(L,(lua_Number)lua_gethookcount(L));return 3;}static int
|
|
|
|
debug(lua_State*L){for(;;){char buffer[250];fputs("lua_debug> ",stderr);if(
|
|
|
|
fgets(buffer,sizeof(buffer),stdin)==0||strcmp(buffer,"cont\n")==0)return 0;
|
|
|
|
lua_dostring(L,buffer);lua_settop(L,0);}}
|
|
|
|
#define LEVELS1 12
|
|
|
|
#define LEVELS2 10
|
|
|
|
static int errorfb(lua_State*L){int level=1;int firstpart=1;lua_Debug ar;if(
|
|
|
|
lua_gettop(L)==0)lua_pushliteral(L,"");else if(!lua_isstring(L,1))return 1;
|
|
|
|
else lua_pushliteral(L,"\n");lua_pushliteral(L,"stack traceback:");while(
|
|
|
|
lua_getstack(L,level++,&ar)){if(level>LEVELS1&&firstpart){if(!lua_getstack(L,
|
|
|
|
level+LEVELS2,&ar))level--;else{lua_pushliteral(L,"\n\t...");while(
|
|
|
|
lua_getstack(L,level+LEVELS2,&ar))level++;}firstpart=0;continue;}
|
|
|
|
lua_pushliteral(L,"\n\t");lua_getinfo(L,"Snl",&ar);lua_pushfstring(L,"%s:",ar.
|
|
|
|
short_src);if(ar.currentline>0)lua_pushfstring(L,"%d:",ar.currentline);switch(
|
|
|
|
*ar.namewhat){case'g':case'l':case'f':case'm':lua_pushfstring(L,
|
|
|
|
" in function `%s'",ar.name);break;default:{if(*ar.what=='m')lua_pushfstring(L
|
|
|
|
," in main chunk");else if(*ar.what=='C'||*ar.what=='t')lua_pushliteral(L," ?"
|
|
|
|
);else lua_pushfstring(L," in function <%s:%d>",ar.short_src,ar.linedefined);}
|
|
|
|
}lua_concat(L,lua_gettop(L));}lua_concat(L,lua_gettop(L));return 1;}static
|
|
|
|
const luaL_reg dblib[]={{"getlocal",getlocal},{"getinfo",getinfo},{"gethook",
|
|
|
|
gethook},{"getupvalue",getupvalue},{"sethook",sethook},{"setlocal",setlocal},{
|
|
|
|
"setupvalue",setupvalue},{"debug",debug},{"traceback",errorfb},{NULL,NULL}};
|
|
|
|
LUALIB_API int luaopen_debug(lua_State*L){luaL_openlib(L,LUA_DBLIBNAME,dblib,0
|
|
|
|
);lua_pushliteral(L,"_TRACEBACK");lua_pushcfunction(L,errorfb);lua_settable(L,
|
|
|
|
LUA_GLOBALSINDEX);return 1;}
|
|
|
|
#line 1 "ldebug.c"
|
|
|
|
#define ldebug_c
|
|
|
|
static const char*getfuncname(CallInfo*ci,const char**name);
|
|
|
|
#define isLua(ci) (!((ci)->state&CI_C))
|
|
|
|
static int currentpc(CallInfo*ci){if(!isLua(ci))return-1;if(ci->state&
|
|
|
|
CI_HASFRAME)ci->u.l.savedpc=*ci->u.l.pc;return pcRel(ci->u.l.savedpc,ci_func(
|
|
|
|
ci)->l.p);}static int currentline(CallInfo*ci){int pc=currentpc(ci);if(pc<0)
|
|
|
|
return-1;else return getline(ci_func(ci)->l.p,pc);}void luaG_inithooks(
|
|
|
|
lua_State*L){CallInfo*ci;for(ci=L->ci;ci!=L->base_ci;ci--)currentpc(ci);L->
|
|
|
|
hookinit=1;}LUA_API int lua_sethook(lua_State*L,lua_Hook func,int mask,int
|
|
|
|
count){if(func==NULL||mask==0){mask=0;func=NULL;}L->hook=func;L->basehookcount
|
|
|
|
=count;resethookcount(L);L->hookmask=cast(lu_byte,mask);L->hookinit=0;return 1
|
|
|
|
;}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;lua_lock(L);for(ci=L->ci;level>0&&
|
|
|
|
ci>L->base_ci;ci--){level--;if(!(ci->state&CI_C))level-=ci->u.l.tailcalls;}if(
|
|
|
|
level>0||ci==L->base_ci)status=0;else if(level<0){status=1;ar->i_ci=0;}else{
|
|
|
|
status=1;ar->i_ci=ci-L->base_ci;}lua_unlock(L);return status;}static Proto*
|
|
|
|
getluaproto(CallInfo*ci){return(isLua(ci)?ci_func(ci)->l.p:NULL);}LUA_API
|
|
|
|
const char*lua_getlocal(lua_State*L,const lua_Debug*ar,int n){const char*name;
|
|
|
|
CallInfo*ci;Proto*fp;lua_lock(L);name=NULL;ci=L->base_ci+ar->i_ci;fp=
|
|
|
|
getluaproto(ci);if(fp){name=luaF_getlocalname(fp,n,currentpc(ci));if(name)
|
|
|
|
luaA_pushobject(L,ci->base+(n-1));}lua_unlock(L);return name;}LUA_API const
|
|
|
|
char*lua_setlocal(lua_State*L,const lua_Debug*ar,int n){const char*name;
|
|
|
|
CallInfo*ci;Proto*fp;lua_lock(L);name=NULL;ci=L->base_ci+ar->i_ci;fp=
|
|
|
|
getluaproto(ci);L->top--;if(fp){name=luaF_getlocalname(fp,n,currentpc(ci));if(
|
|
|
|
!name||name[0]=='(')name=NULL;else setobjs2s(ci->base+(n-1),L->top);}
|
|
|
|
lua_unlock(L);return name;}static void funcinfo(lua_Debug*ar,StkId func){
|
|
|
|
Closure*cl=clvalue(func);if(cl->c.isC){ar->source="=[C]";ar->linedefined=-1;ar
|
|
|
|
->what="C";}else{ar->source=getstr(cl->l.p->source);ar->linedefined=cl->l.p->
|
|
|
|
lineDefined;ar->what=(ar->linedefined==0)?"main":"Lua";}luaO_chunkid(ar->
|
|
|
|
short_src,ar->source,LUA_IDSIZE);}static const char*travglobals(lua_State*L,
|
|
|
|
const TObject*o){Table*g=hvalue(gt(L));int i=sizenode(g);while(i--){Node*n=
|
|
|
|
gnode(g,i);if(luaO_rawequalObj(o,gval(n))&&ttisstring(gkey(n)))return getstr(
|
|
|
|
tsvalue(gkey(n)));}return NULL;}static void info_tailcall(lua_State*L,
|
|
|
|
lua_Debug*ar){ar->name=ar->namewhat="";ar->what="tail";ar->linedefined=ar->
|
|
|
|
currentline=-1;ar->source="=(tail call)";luaO_chunkid(ar->short_src,ar->source
|
|
|
|
,LUA_IDSIZE);ar->nups=0;setnilvalue(L->top);}static int auxgetinfo(lua_State*L
|
|
|
|
,const char*what,lua_Debug*ar,StkId f,CallInfo*ci){int status=1;for(;*what;
|
|
|
|
what++){switch(*what){case'S':{funcinfo(ar,f);break;}case'l':{ar->currentline=
|
|
|
|
(ci)?currentline(ci):-1;break;}case'u':{ar->nups=clvalue(f)->c.nupvalues;break
|
|
|
|
;}case'n':{ar->namewhat=(ci)?getfuncname(ci,&ar->name):NULL;if(ar->namewhat==
|
|
|
|
NULL){if((ar->name=travglobals(L,f))!=NULL)ar->namewhat="global";else ar->
|
|
|
|
namewhat="";}break;}case'f':{setobj2s(L->top,f);break;}default:status=0;}}
|
|
|
|
return status;}LUA_API int lua_getinfo(lua_State*L,const char*what,lua_Debug*
|
|
|
|
ar){int status=1;lua_lock(L);if(*what=='>'){StkId f=L->top-1;if(!ttisfunction(
|
|
|
|
f))luaG_runerror(L,"value for `lua_getinfo' is not a function");status=
|
|
|
|
auxgetinfo(L,what+1,ar,f,NULL);L->top--;}else if(ar->i_ci!=0){CallInfo*ci=L->
|
|
|
|
base_ci+ar->i_ci;lua_assert(ttisfunction(ci->base-1));status=auxgetinfo(L,what
|
|
|
|
,ar,ci->base-1,ci);}else info_tailcall(L,ar);if(strchr(what,'f'))incr_top(L);
|
|
|
|
lua_unlock(L);return status;}
|
|
|
|
#define check(x) if(!(x))return 0;
|
|
|
|
#define checkjump(pt,pc) check(0<=pc&&pc<pt->sizecode)
|
|
|
|
#define checkreg(pt,reg) check((reg)<(pt)->maxstacksize)
|
|
|
|
static int precheck(const Proto*pt){check(pt->maxstacksize<=MAXSTACK);check(pt
|
|
|
|
->sizelineinfo==pt->sizecode||pt->sizelineinfo==0);lua_assert(pt->numparams+pt
|
|
|
|
->is_vararg<=pt->maxstacksize);check(GET_OPCODE(pt->code[pt->sizecode-1])==
|
|
|
|
OP_RETURN);return 1;}static int checkopenop(const Proto*pt,int pc){Instruction
|
|
|
|
i=pt->code[pc+1];switch(GET_OPCODE(i)){case OP_CALL:case OP_TAILCALL:case
|
|
|
|
OP_RETURN:{check(GETARG_B(i)==0);return 1;}case OP_SETLISTO:return 1;default:
|
|
|
|
return 0;}}static int checkRK(const Proto*pt,int r){return(r<pt->maxstacksize
|
|
|
|
||(r>=MAXSTACK&&r-MAXSTACK<pt->sizek));}static Instruction luaG_symbexec(const
|
|
|
|
Proto*pt,int lastpc,int reg){int pc;int last;last=pt->sizecode-1;check(
|
|
|
|
precheck(pt));for(pc=0;pc<lastpc;pc++){const Instruction i=pt->code[pc];OpCode
|
|
|
|
op=GET_OPCODE(i);int a=GETARG_A(i);int b=0;int c=0;checkreg(pt,a);switch(
|
|
|
|
getOpMode(op)){case iABC:{b=GETARG_B(i);c=GETARG_C(i);if(testOpMode(op,
|
|
|
|
OpModeBreg)){checkreg(pt,b);}else if(testOpMode(op,OpModeBrk))check(checkRK(pt
|
|
|
|
,b));if(testOpMode(op,OpModeCrk))check(checkRK(pt,c));break;}case iABx:{b=
|
|
|
|
GETARG_Bx(i);if(testOpMode(op,OpModeK))check(b<pt->sizek);break;}case iAsBx:{b
|
|
|
|
=GETARG_sBx(i);break;}}if(testOpMode(op,OpModesetA)){if(a==reg)last=pc;}if(
|
|
|
|
testOpMode(op,OpModeT)){check(pc+2<pt->sizecode);check(GET_OPCODE(pt->code[pc+
|
|
|
|
1])==OP_JMP);}switch(op){case OP_LOADBOOL:{check(c==0||pc+2<pt->sizecode);
|
|
|
|
break;}case OP_LOADNIL:{if(a<=reg&®<=b)last=pc;break;}case OP_GETUPVAL:case
|
|
|
|
OP_SETUPVAL:{check(b<pt->nups);break;}case OP_GETGLOBAL:case OP_SETGLOBAL:{
|
|
|
|
check(ttisstring(&pt->k[b]));break;}case OP_SELF:{checkreg(pt,a+1);if(reg==a+1
|
|
|
|
)last=pc;break;}case OP_CONCAT:{check(c<MAXSTACK&&b<c);break;}case OP_TFORLOOP
|
|
|
|
:checkreg(pt,a+c+5);if(reg>=a)last=pc;case OP_FORLOOP:checkreg(pt,a+2);case
|
|
|
|
OP_JMP:{int dest=pc+1+b;check(0<=dest&&dest<pt->sizecode);if(reg!=NO_REG&&pc<
|
|
|
|
dest&&dest<=lastpc)pc+=b;break;}case OP_CALL:case OP_TAILCALL:{if(b!=0){
|
|
|
|
checkreg(pt,a+b-1);}c--;if(c==LUA_MULTRET){check(checkopenop(pt,pc));}else if(
|
|
|
|
c!=0)checkreg(pt,a+c-1);if(reg>=a)last=pc;break;}case OP_RETURN:{b--;if(b>0)
|
|
|
|
checkreg(pt,a+b-1);break;}case OP_SETLIST:{checkreg(pt,a+(b&(LFIELDS_PER_FLUSH
|
|
|
|
-1))+1);break;}case OP_CLOSURE:{int nup;check(b<pt->sizep);nup=pt->p[b]->nups;
|
|
|
|
check(pc+nup<pt->sizecode);for(;nup>0;nup--){OpCode op1=GET_OPCODE(pt->code[pc
|
|
|
|
+nup]);check(op1==OP_GETUPVAL||op1==OP_MOVE);}break;}default:break;}}return pt
|
|
|
|
->code[last];}
|
|
|
|
#undef check
|
|
|
|
#undef checkjump
|
|
|
|
#undef checkreg
|
|
|
|
int luaG_checkcode(const Proto*pt){return luaG_symbexec(pt,pt->sizecode,NO_REG
|
|
|
|
);}static const char*kname(Proto*p,int c){c=c-MAXSTACK;if(c>=0&&ttisstring(&p
|
|
|
|
->k[c]))return svalue(&p->k[c]);else return"?";}static const char*getobjname(
|
|
|
|
CallInfo*ci,int stackpos,const char**name){if(isLua(ci)){Proto*p=ci_func(ci)->
|
|
|
|
l.p;int pc=currentpc(ci);Instruction i;*name=luaF_getlocalname(p,stackpos+1,pc
|
|
|
|
);if(*name)return"local";i=luaG_symbexec(p,pc,stackpos);lua_assert(pc!=-1);
|
|
|
|
switch(GET_OPCODE(i)){case OP_GETGLOBAL:{int g=GETARG_Bx(i);lua_assert(
|
|
|
|
ttisstring(&p->k[g]));*name=svalue(&p->k[g]);return"global";}case OP_MOVE:{int
|
|
|
|
a=GETARG_A(i);int b=GETARG_B(i);if(b<a)return getobjname(ci,b,name);break;}
|
|
|
|
case OP_GETTABLE:{int k=GETARG_C(i);*name=kname(p,k);return"field";}case
|
|
|
|
OP_SELF:{int k=GETARG_C(i);*name=kname(p,k);return"method";}default:break;}}
|
|
|
|
return NULL;}static const char*getfuncname(CallInfo*ci,const char**name){
|
|
|
|
Instruction i;if((isLua(ci)&&ci->u.l.tailcalls>0)||!isLua(ci-1))return NULL;ci
|
|
|
|
--;i=ci_func(ci)->l.p->code[currentpc(ci)];if(GET_OPCODE(i)==OP_CALL||
|
|
|
|
GET_OPCODE(i)==OP_TAILCALL)return getobjname(ci,GETARG_A(i),name);else return
|
|
|
|
NULL;}static int isinstack(CallInfo*ci,const TObject*o){StkId p;for(p=ci->base
|
|
|
|
;p<ci->top;p++)if(o==p)return 1;return 0;}void luaG_typeerror(lua_State*L,
|
|
|
|
const TObject*o,const char*op){const char*name=NULL;const char*t=
|
|
|
|
luaT_typenames[ttype(o)];const char*kind=(isinstack(L->ci,o))?getobjname(L->ci
|
|
|
|
,o-L->base,&name):NULL;if(kind)luaG_runerror(L,
|
|
|
|
"attempt to %s %s `%s' (a %s value)",op,kind,name,t);else luaG_runerror(L,
|
|
|
|
"attempt to %s a %s value",op,t);}void luaG_concaterror(lua_State*L,StkId p1,
|
|
|
|
StkId p2){if(ttisstring(p1))p1=p2;lua_assert(!ttisstring(p1));luaG_typeerror(L
|
|
|
|
,p1,"concatenate");}void luaG_aritherror(lua_State*L,const TObject*p1,const
|
|
|
|
TObject*p2){TObject temp;if(luaV_tonumber(p1,&temp)==NULL)p2=p1;luaG_typeerror
|
|
|
|
(L,p2,"perform arithmetic on");}int luaG_ordererror(lua_State*L,const TObject*
|
|
|
|
p1,const TObject*p2){const char*t1=luaT_typenames[ttype(p1)];const char*t2=
|
|
|
|
luaT_typenames[ttype(p2)];if(t1[2]==t2[2])luaG_runerror(L,
|
|
|
|
"attempt to compare two %s values",t1);else luaG_runerror(L,
|
|
|
|
"attempt to compare %s with %s",t1,t2);return 0;}static void addinfo(lua_State
|
|
|
|
*L,const char*msg){CallInfo*ci=L->ci;if(isLua(ci)){char buff[LUA_IDSIZE];int
|
|
|
|
line=currentline(ci);luaO_chunkid(buff,getstr(getluaproto(ci)->source),
|
|
|
|
LUA_IDSIZE);luaO_pushfstring(L,"%s:%d: %s",buff,line,msg);}}void luaG_errormsg
|
|
|
|
(lua_State*L){if(L->errfunc!=0){StkId errfunc=restorestack(L,L->errfunc);if(!
|
|
|
|
ttisfunction(errfunc))luaD_throw(L,LUA_ERRERR);setobjs2s(L->top,L->top-1);
|
|
|
|
setobjs2s(L->top-1,errfunc);incr_top(L);luaD_call(L,L->top-2,1);}luaD_throw(L,
|
|
|
|
LUA_ERRRUN);}void luaG_runerror(lua_State*L,const char*fmt,...){va_list argp;
|
|
|
|
va_start(argp,fmt);addinfo(L,luaO_pushvfstring(L,fmt,argp));va_end(argp);
|
|
|
|
luaG_errormsg(L);}
|
|
|
|
#line 1 "ldo.c"
|
|
|
|
#define ldo_c
|
|
|
|
struct lua_longjmp{struct lua_longjmp*previous;jmp_buf b;volatile int status;}
|
|
|
|
;static void seterrorobj(lua_State*L,int errcode,StkId oldtop){switch(errcode)
|
|
|
|
{case LUA_ERRMEM:{setsvalue2s(oldtop,luaS_new(L,MEMERRMSG));break;}case
|
|
|
|
LUA_ERRERR:{setsvalue2s(oldtop,luaS_new(L,"error in error handling"));break;}
|
|
|
|
case LUA_ERRSYNTAX:case LUA_ERRRUN:{setobjs2s(oldtop,L->top-1);break;}}L->top=
|
|
|
|
oldtop+1;}void luaD_throw(lua_State*L,int errcode){if(L->errorJmp){L->errorJmp
|
|
|
|
->status=errcode;longjmp(L->errorJmp->b,1);}else{G(L)->panic(L);exit(
|
|
|
|
EXIT_FAILURE);}}int luaD_rawrunprotected(lua_State*L,Pfunc f,void*ud){struct
|
|
|
|
lua_longjmp lj;lj.status=0;lj.previous=L->errorJmp;L->errorJmp=&lj;if(setjmp(
|
|
|
|
lj.b)==0)(*f)(L,ud);L->errorJmp=lj.previous;return lj.status;}static void
|
|
|
|
restore_stack_limit(lua_State*L){L->stack_last=L->stack+L->stacksize-1;if(L->
|
|
|
|
size_ci>LUA_MAXCALLS){int inuse=(L->ci-L->base_ci);if(inuse+1<LUA_MAXCALLS)
|
|
|
|
luaD_reallocCI(L,LUA_MAXCALLS);}}static void correctstack(lua_State*L,TObject*
|
|
|
|
oldstack){CallInfo*ci;GCObject*up;L->top=(L->top-oldstack)+L->stack;for(up=L->
|
|
|
|
openupval;up!=NULL;up=up->gch.next)gcotouv(up)->v=(gcotouv(up)->v-oldstack)+L
|
|
|
|
->stack;for(ci=L->base_ci;ci<=L->ci;ci++){ci->top=(ci->top-oldstack)+L->stack;
|
|
|
|
ci->base=(ci->base-oldstack)+L->stack;}L->base=L->ci->base;}void
|
|
|
|
luaD_reallocstack(lua_State*L,int newsize){TObject*oldstack=L->stack;
|
|
|
|
luaM_reallocvector(L,L->stack,L->stacksize,newsize,TObject);L->stacksize=
|
|
|
|
newsize;L->stack_last=L->stack+newsize-1-EXTRA_STACK;correctstack(L,oldstack);
|
|
|
|
}void luaD_reallocCI(lua_State*L,int newsize){CallInfo*oldci=L->base_ci;
|
|
|
|
luaM_reallocvector(L,L->base_ci,L->size_ci,newsize,CallInfo);L->size_ci=cast(
|
|
|
|
unsigned short,newsize);L->ci=(L->ci-oldci)+L->base_ci;L->end_ci=L->base_ci+L
|
|
|
|
->size_ci;}void luaD_growstack(lua_State*L,int n){if(n<=L->stacksize)
|
|
|
|
luaD_reallocstack(L,2*L->stacksize);else luaD_reallocstack(L,L->stacksize+n+
|
|
|
|
EXTRA_STACK);}static void luaD_growCI(lua_State*L){if(L->size_ci>LUA_MAXCALLS)
|
|
|
|
luaD_throw(L,LUA_ERRERR);else{luaD_reallocCI(L,2*L->size_ci);if(L->size_ci>
|
|
|
|
LUA_MAXCALLS)luaG_runerror(L,"stack overflow");}}void luaD_callhook(lua_State*
|
|
|
|
L,int event,int line){lua_Hook hook=L->hook;if(hook&&L->allowhook){ptrdiff_t
|
|
|
|
top=savestack(L,L->top);ptrdiff_t ci_top=savestack(L,L->ci->top);lua_Debug ar;
|
|
|
|
ar.event=event;ar.currentline=line;if(event==LUA_HOOKTAILRET)ar.i_ci=0;else ar
|
|
|
|
.i_ci=L->ci-L->base_ci;luaD_checkstack(L,LUA_MINSTACK);L->ci->top=L->top+
|
|
|
|
LUA_MINSTACK;L->allowhook=0;lua_unlock(L);(*hook)(L,&ar);lua_lock(L);
|
|
|
|
lua_assert(!L->allowhook);L->allowhook=1;L->ci->top=restorestack(L,ci_top);L->
|
|
|
|
top=restorestack(L,top);}}static void adjust_varargs(lua_State*L,int nfixargs,
|
|
|
|
StkId base){int i;Table*htab;TObject nname;int actual=L->top-base;if(actual<
|
|
|
|
nfixargs){luaD_checkstack(L,nfixargs-actual);for(;actual<nfixargs;++actual)
|
|
|
|
setnilvalue(L->top++);}actual-=nfixargs;htab=luaH_new(L,actual,1);for(i=0;i<
|
|
|
|
actual;i++)setobj2n(luaH_setnum(L,htab,i+1),L->top-actual+i);setsvalue(&nname,
|
|
|
|
luaS_newliteral(L,"n"));setnvalue(luaH_set(L,htab,&nname),cast(lua_Number,
|
|
|
|
actual));L->top-=actual;sethvalue(L->top,htab);incr_top(L);}static StkId
|
|
|
|
tryfuncTM(lua_State*L,StkId func){const TObject*tm=luaT_gettmbyobj(L,func,
|
|
|
|
TM_CALL);StkId p;ptrdiff_t funcr=savestack(L,func);if(!ttisfunction(tm))
|
|
|
|
luaG_typeerror(L,func,"call");for(p=L->top;p>func;p--)setobjs2s(p,p-1);
|
|
|
|
incr_top(L);func=restorestack(L,funcr);setobj2s(func,tm);return func;}StkId
|
|
|
|
luaD_precall(lua_State*L,StkId func){LClosure*cl;ptrdiff_t funcr=savestack(L,
|
|
|
|
func);if(!ttisfunction(func))func=tryfuncTM(L,func);if(L->ci+1==L->end_ci)
|
|
|
|
luaD_growCI(L);else condhardstacktests(luaD_reallocCI(L,L->size_ci));cl=&
|
|
|
|
clvalue(func)->l;if(!cl->isC){CallInfo*ci;Proto*p=cl->p;if(p->is_vararg)
|
|
|
|
adjust_varargs(L,p->numparams,func+1);luaD_checkstack(L,p->maxstacksize);ci=++
|
|
|
|
L->ci;L->base=L->ci->base=restorestack(L,funcr)+1;ci->top=L->base+p->
|
|
|
|
maxstacksize;ci->u.l.savedpc=p->code;ci->u.l.tailcalls=0;ci->state=CI_SAVEDPC;
|
|
|
|
while(L->top<ci->top)setnilvalue(L->top++);L->top=ci->top;return NULL;}else{
|
|
|
|
CallInfo*ci;int n;luaD_checkstack(L,LUA_MINSTACK);ci=++L->ci;L->base=L->ci->
|
|
|
|
base=restorestack(L,funcr)+1;ci->top=L->top+LUA_MINSTACK;ci->state=CI_C;if(L->
|
|
|
|
hookmask&LUA_MASKCALL)luaD_callhook(L,LUA_HOOKCALL,-1);lua_unlock(L);
|
|
|
|
#ifdef LUA_COMPATUPVALUES
|
|
|
|
lua_pushupvalues(L);
|
|
|
|
#endif
|
|
|
|
n=(*clvalue(L->base-1)->c.f)(L);lua_lock(L);return L->top-n;}}static StkId
|
|
|
|
callrethooks(lua_State*L,StkId firstResult){ptrdiff_t fr=savestack(L,
|
|
|
|
firstResult);luaD_callhook(L,LUA_HOOKRET,-1);if(!(L->ci->state&CI_C)){while(L
|
|
|
|
->ci->u.l.tailcalls--)luaD_callhook(L,LUA_HOOKTAILRET,-1);}return restorestack
|
|
|
|
(L,fr);}void luaD_poscall(lua_State*L,int wanted,StkId firstResult){StkId res;
|
|
|
|
if(L->hookmask&LUA_MASKRET)firstResult=callrethooks(L,firstResult);res=L->base
|
|
|
|
-1;L->ci--;L->base=L->ci->base;while(wanted!=0&&firstResult<L->top){setobjs2s(
|
|
|
|
res++,firstResult++);wanted--;}while(wanted-->0)setnilvalue(res++);L->top=res;
|
|
|
|
}void luaD_call(lua_State*L,StkId func,int nResults){StkId firstResult;
|
|
|
|
lua_assert(!(L->ci->state&CI_CALLING));if(++L->nCcalls>=LUA_MAXCCALLS){if(L->
|
|
|
|
nCcalls==LUA_MAXCCALLS)luaG_runerror(L,"C stack overflow");else if(L->nCcalls
|
|
|
|
>=(LUA_MAXCCALLS+(LUA_MAXCCALLS>>3)))luaD_throw(L,LUA_ERRERR);}firstResult=
|
|
|
|
luaD_precall(L,func);if(firstResult==NULL)firstResult=luaV_execute(L);
|
|
|
|
luaD_poscall(L,nResults,firstResult);L->nCcalls--;luaC_checkGC(L);}static void
|
|
|
|
resume(lua_State*L,void*ud){StkId firstResult;int nargs=*cast(int*,ud);
|
|
|
|
CallInfo*ci=L->ci;if(ci==L->base_ci){lua_assert(nargs<L->top-L->base);
|
|
|
|
luaD_precall(L,L->top-(nargs+1));}else{lua_assert(ci->state&CI_YIELD);if(ci->
|
|
|
|
state&CI_C){int nresults;lua_assert((ci-1)->state&CI_SAVEDPC);lua_assert(
|
|
|
|
GET_OPCODE(*((ci-1)->u.l.savedpc-1))==OP_CALL||GET_OPCODE(*((ci-1)->u.l.
|
|
|
|
savedpc-1))==OP_TAILCALL);nresults=GETARG_C(*((ci-1)->u.l.savedpc-1))-1;
|
|
|
|
luaD_poscall(L,nresults,L->top-nargs);if(nresults>=0)L->top=L->ci->top;}else{
|
|
|
|
ci->state&=~CI_YIELD;}}firstResult=luaV_execute(L);if(firstResult!=NULL)
|
|
|
|
luaD_poscall(L,LUA_MULTRET,firstResult);}static int resume_error(lua_State*L,
|
|
|
|
const char*msg){L->top=L->ci->base;setsvalue2s(L->top,luaS_new(L,msg));
|
|
|
|
incr_top(L);lua_unlock(L);return LUA_ERRRUN;}LUA_API int lua_resume(lua_State*
|
|
|
|
L,int nargs){int status;lu_byte old_allowhooks;lua_lock(L);if(L->ci==L->
|
|
|
|
base_ci){if(nargs>=L->top-L->base)return resume_error(L,
|
|
|
|
"cannot resume dead coroutine");}else if(!(L->ci->state&CI_YIELD))return
|
|
|
|
resume_error(L,"cannot resume non-suspended coroutine");old_allowhooks=L->
|
|
|
|
allowhook;lua_assert(L->errfunc==0&&L->nCcalls==0);status=luaD_rawrunprotected
|
|
|
|
(L,resume,&nargs);if(status!=0){L->ci=L->base_ci;L->base=L->ci->base;L->
|
|
|
|
nCcalls=0;luaF_close(L,L->base);seterrorobj(L,status,L->base);L->allowhook=
|
|
|
|
old_allowhooks;restore_stack_limit(L);}lua_unlock(L);return status;}LUA_API
|
|
|
|
int lua_yield(lua_State*L,int nresults){CallInfo*ci;lua_lock(L);ci=L->ci;if(L
|
|
|
|
->nCcalls>0)luaG_runerror(L,
|
|
|
|
"attempt to yield across metamethod/C-call boundary");if(ci->state&CI_C){if((
|
|
|
|
ci-1)->state&CI_C)luaG_runerror(L,"cannot yield a C function");if(L->top-
|
|
|
|
nresults>L->base){int i;for(i=0;i<nresults;i++)setobjs2s(L->base+i,L->top-
|
|
|
|
nresults+i);L->top=L->base+nresults;}}ci->state|=CI_YIELD;lua_unlock(L);return
|
|
|
|
-1;}int luaD_pcall(lua_State*L,Pfunc func,void*u,ptrdiff_t old_top,ptrdiff_t
|
|
|
|
ef){int status;unsigned short oldnCcalls=L->nCcalls;ptrdiff_t old_ci=saveci(L,
|
|
|
|
L->ci);lu_byte old_allowhooks=L->allowhook;ptrdiff_t old_errfunc=L->errfunc;L
|
|
|
|
->errfunc=ef;status=luaD_rawrunprotected(L,func,u);if(status!=0){StkId oldtop=
|
|
|
|
restorestack(L,old_top);luaF_close(L,oldtop);seterrorobj(L,status,oldtop);L->
|
|
|
|
nCcalls=oldnCcalls;L->ci=restoreci(L,old_ci);L->base=L->ci->base;L->allowhook=
|
|
|
|
old_allowhooks;restore_stack_limit(L);}L->errfunc=old_errfunc;return status;}
|
|
|
|
struct SParser{ZIO*z;Mbuffer buff;int bin;};static void f_parser(lua_State*L,
|
|
|
|
void*ud){struct SParser*p;Proto*tf;Closure*cl;luaC_checkGC(L);p=cast(struct
|
|
|
|
SParser*,ud);tf=p->bin?luaU_undump(L,p->z,&p->buff):luaY_parser(L,p->z,&p->
|
|
|
|
buff);cl=luaF_newLclosure(L,0,gt(L));cl->l.p=tf;setclvalue(L->top,cl);incr_top
|
|
|
|
(L);}int luaD_protectedparser(lua_State*L,ZIO*z,int bin){struct SParser p;int
|
|
|
|
status;ptrdiff_t oldtopr=savestack(L,L->top);p.z=z;p.bin=bin;luaZ_initbuffer(L
|
|
|
|
,&p.buff);status=luaD_rawrunprotected(L,f_parser,&p);luaZ_freebuffer(L,&p.buff
|
|
|
|
);if(status!=0){StkId oldtop=restorestack(L,oldtopr);seterrorobj(L,status,
|
|
|
|
oldtop);}return status;}
|
|
|
|
#line 1 "ldump.c"
|
|
|
|
#define ldump_c
|
|
|
|
#define DumpVector(b,n,size,D) DumpBlock(b,(n)*(size),D)
|
|
|
|
#define DumpLiteral(s,D) DumpBlock(""s,(sizeof(s))-1,D)
|
|
|
|
typedef struct{lua_State*L;lua_Chunkwriter write;void*data;}DumpState;static
|
|
|
|
void DumpBlock(const void*b,size_t size,DumpState*D){lua_unlock(D->L);(*D->
|
|
|
|
write)(D->L,b,size,D->data);lua_lock(D->L);}static void DumpByte(int y,
|
|
|
|
DumpState*D){char x=(char)y;DumpBlock(&x,sizeof(x),D);}static void DumpInt(int
|
|
|
|
x,DumpState*D){DumpBlock(&x,sizeof(x),D);}static void DumpSize(size_t x,
|
|
|
|
DumpState*D){DumpBlock(&x,sizeof(x),D);}static void DumpNumber(lua_Number x,
|
|
|
|
DumpState*D){DumpBlock(&x,sizeof(x),D);}static void DumpString(TString*s,
|
|
|
|
DumpState*D){if(s==NULL||getstr(s)==NULL)DumpSize(0,D);else{size_t size=s->tsv
|
|
|
|
.len+1;DumpSize(size,D);DumpBlock(getstr(s),size,D);}}static void DumpCode(
|
|
|
|
const Proto*f,DumpState*D){DumpInt(f->sizecode,D);DumpVector(f->code,f->
|
|
|
|
sizecode,sizeof(*f->code),D);}static void DumpLocals(const Proto*f,DumpState*D
|
|
|
|
){int i,n=f->sizelocvars;DumpInt(n,D);for(i=0;i<n;i++){DumpString(f->locvars[i
|
|
|
|
].varname,D);DumpInt(f->locvars[i].startpc,D);DumpInt(f->locvars[i].endpc,D);}
|
|
|
|
}static void DumpLines(const Proto*f,DumpState*D){DumpInt(f->sizelineinfo,D);
|
|
|
|
DumpVector(f->lineinfo,f->sizelineinfo,sizeof(*f->lineinfo),D);}static void
|
|
|
|
DumpUpvalues(const Proto*f,DumpState*D){int i,n=f->sizeupvalues;DumpInt(n,D);
|
|
|
|
for(i=0;i<n;i++)DumpString(f->upvalues[i],D);}static void DumpFunction(const
|
|
|
|
Proto*f,const TString*p,DumpState*D);static void DumpConstants(const Proto*f,
|
|
|
|
DumpState*D){int i,n;DumpInt(n=f->sizek,D);for(i=0;i<n;i++){const TObject*o=&f
|
|
|
|
->k[i];DumpByte(ttype(o),D);switch(ttype(o)){case LUA_TNUMBER:DumpNumber(
|
|
|
|
nvalue(o),D);break;case LUA_TSTRING:DumpString(tsvalue(o),D);break;case
|
|
|
|
LUA_TNIL:break;default:lua_assert(0);break;}}DumpInt(n=f->sizep,D);for(i=0;i<n
|
|
|
|
;i++)DumpFunction(f->p[i],f->source,D);}static void DumpFunction(const Proto*f
|
|
|
|
,const TString*p,DumpState*D){DumpString((f->source==p)?NULL:f->source,D);
|
|
|
|
DumpInt(f->lineDefined,D);DumpByte(f->nups,D);DumpByte(f->numparams,D);
|
|
|
|
DumpByte(f->is_vararg,D);DumpByte(f->maxstacksize,D);DumpLines(f,D);DumpLocals
|
|
|
|
(f,D);DumpUpvalues(f,D);DumpConstants(f,D);DumpCode(f,D);}static void
|
|
|
|
DumpHeader(DumpState*D){DumpLiteral(LUA_SIGNATURE,D);DumpByte(VERSION,D);
|
|
|
|
DumpByte(luaU_endianness(),D);DumpByte(sizeof(int),D);DumpByte(sizeof(size_t),
|
|
|
|
D);DumpByte(sizeof(Instruction),D);DumpByte(SIZE_OP,D);DumpByte(SIZE_A,D);
|
|
|
|
DumpByte(SIZE_B,D);DumpByte(SIZE_C,D);DumpByte(sizeof(lua_Number),D);
|
|
|
|
DumpNumber(TEST_NUMBER,D);}void luaU_dump(lua_State*L,const Proto*Main,
|
|
|
|
lua_Chunkwriter w,void*data){DumpState D;D.L=L;D.write=w;D.data=data;
|
|
|
|
DumpHeader(&D);DumpFunction(Main,NULL,&D);}
|
|
|
|
#line 1 "lfunc.c"
|
|
|
|
#define lfunc_c
|
|
|
|
#define sizeCclosure(n) (cast(int,sizeof(CClosure))+cast(int,sizeof(TObject)*(\
|
|
|
|
(n)-1)))
|
|
|
|
#define sizeLclosure(n) (cast(int,sizeof(LClosure))+cast(int,sizeof(TObject*)*\
|
|
|
|
((n)-1)))
|
|
|
|
Closure*luaF_newCclosure(lua_State*L,int nelems){Closure*c=cast(Closure*,
|
|
|
|
luaM_malloc(L,sizeCclosure(nelems)));luaC_link(L,valtogco(c),LUA_TFUNCTION);c
|
|
|
|
->c.isC=1;c->c.nupvalues=cast(lu_byte,nelems);return c;}Closure*
|
|
|
|
luaF_newLclosure(lua_State*L,int nelems,TObject*e){Closure*c=cast(Closure*,
|
|
|
|
luaM_malloc(L,sizeLclosure(nelems)));luaC_link(L,valtogco(c),LUA_TFUNCTION);c
|
|
|
|
->l.isC=0;c->l.g=*e;c->l.nupvalues=cast(lu_byte,nelems);return c;}UpVal*
|
|
|
|
luaF_findupval(lua_State*L,StkId level){GCObject**pp=&L->openupval;UpVal*p;
|
|
|
|
UpVal*v;while((p=ngcotouv(*pp))!=NULL&&p->v>=level){if(p->v==level)return p;pp
|
|
|
|
=&p->next;}v=luaM_new(L,UpVal);v->tt=LUA_TUPVAL;v->marked=1;v->v=level;v->next
|
|
|
|
=*pp;*pp=valtogco(v);return v;}void luaF_close(lua_State*L,StkId level){UpVal*
|
|
|
|
p;while((p=ngcotouv(L->openupval))!=NULL&&p->v>=level){setobj(&p->value,p->v);
|
|
|
|
p->v=&p->value;L->openupval=p->next;luaC_link(L,valtogco(p),LUA_TUPVAL);}}
|
|
|
|
Proto*luaF_newproto(lua_State*L){Proto*f=luaM_new(L,Proto);luaC_link(L,
|
|
|
|
valtogco(f),LUA_TPROTO);f->k=NULL;f->sizek=0;f->p=NULL;f->sizep=0;f->code=NULL
|
|
|
|
;f->sizecode=0;f->sizelineinfo=0;f->sizeupvalues=0;f->nups=0;f->upvalues=NULL;
|
|
|
|
f->numparams=0;f->is_vararg=0;f->maxstacksize=0;f->lineinfo=NULL;f->
|
|
|
|
sizelocvars=0;f->locvars=NULL;f->lineDefined=0;f->source=NULL;return f;}void
|
|
|
|
luaF_freeproto(lua_State*L,Proto*f){luaM_freearray(L,f->code,f->sizecode,
|
|
|
|
Instruction);luaM_freearray(L,f->p,f->sizep,Proto*);luaM_freearray(L,f->k,f->
|
|
|
|
sizek,TObject);luaM_freearray(L,f->lineinfo,f->sizelineinfo,int);
|
|
|
|
luaM_freearray(L,f->locvars,f->sizelocvars,struct LocVar);luaM_freearray(L,f->
|
|
|
|
upvalues,f->sizeupvalues,TString*);luaM_freelem(L,f);}void luaF_freeclosure(
|
|
|
|
lua_State*L,Closure*c){int size=(c->c.isC)?sizeCclosure(c->c.nupvalues):
|
|
|
|
sizeLclosure(c->l.nupvalues);luaM_free(L,c,size);}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){local_number--;if(
|
|
|
|
local_number==0)return getstr(f->locvars[i].varname);}}return NULL;}
|
|
|
|
#line 1 "lgc.c"
|
|
|
|
#define lgc_c
|
|
|
|
typedef struct GCState{GCObject*tmark;GCObject*wk;GCObject*wv;GCObject*wkv;
|
|
|
|
global_State*g;}GCState;
|
|
|
|
#define setbit(x,b) ((x)|=(1<<(b)))
|
|
|
|
#define resetbit(x,b) ((x)&=cast(lu_byte,~(1<<(b))))
|
|
|
|
#define testbit(x,b) ((x)&(1<<(b)))
|
|
|
|
#define unmark(x) resetbit((x)->gch.marked,0)
|
|
|
|
#define ismarked(x) ((x)->gch.marked&((1<<4)|1))
|
|
|
|
#define stringmark(s) setbit((s)->tsv.marked,0)
|
|
|
|
#define isfinalized(u) (!testbit((u)->uv.marked,1))
|
|
|
|
#define markfinalized(u) resetbit((u)->uv.marked,1)
|
|
|
|
#define KEYWEAKBIT 1
|
|
|
|
#define VALUEWEAKBIT 2
|
|
|
|
#define KEYWEAK (1<<KEYWEAKBIT)
|
|
|
|
#define VALUEWEAK (1<<VALUEWEAKBIT)
|
|
|
|
#define markobject(st,o) {checkconsistency(o);if(iscollectable(o)&&!ismarked(\
|
|
|
|
gcvalue(o)))reallymarkobject(st,gcvalue(o));}
|
|
|
|
#define condmarkobject(st,o,c) {checkconsistency(o);if(iscollectable(o)&&!\
|
|
|
|
ismarked(gcvalue(o))&&(c))reallymarkobject(st,gcvalue(o));}
|
|
|
|
#define markvalue(st,t) {if(!ismarked(valtogco(t)))reallymarkobject(st,\
|
|
|
|
valtogco(t));}
|
|
|
|
static void reallymarkobject(GCState*st,GCObject*o){lua_assert(!ismarked(o));
|
|
|
|
setbit(o->gch.marked,0);switch(o->gch.tt){case LUA_TUSERDATA:{markvalue(st,
|
|
|
|
gcotou(o)->uv.metatable);break;}case LUA_TFUNCTION:{gcotocl(o)->c.gclist=st->
|
|
|
|
tmark;st->tmark=o;break;}case LUA_TTABLE:{gcotoh(o)->gclist=st->tmark;st->
|
|
|
|
tmark=o;break;}case LUA_TTHREAD:{gcototh(o)->gclist=st->tmark;st->tmark=o;
|
|
|
|
break;}case LUA_TPROTO:{gcotop(o)->gclist=st->tmark;st->tmark=o;break;}default
|
|
|
|
:lua_assert(o->gch.tt==LUA_TSTRING);}}static void marktmu(GCState*st){GCObject
|
|
|
|
*u;for(u=st->g->tmudata;u;u=u->gch.next){unmark(u);reallymarkobject(st,u);}}
|
|
|
|
size_t luaC_separateudata(lua_State*L){size_t deadmem=0;GCObject**p=&G(L)->
|
|
|
|
rootudata;GCObject*curr;GCObject*collected=NULL;GCObject**lastcollected=&
|
|
|
|
collected;while((curr=*p)!=NULL){lua_assert(curr->gch.tt==LUA_TUSERDATA);if(
|
|
|
|
ismarked(curr)||isfinalized(gcotou(curr)))p=&curr->gch.next;else if(fasttm(L,
|
|
|
|
gcotou(curr)->uv.metatable,TM_GC)==NULL){markfinalized(gcotou(curr));p=&curr->
|
|
|
|
gch.next;}else{deadmem+=sizeudata(gcotou(curr)->uv.len);*p=curr->gch.next;curr
|
|
|
|
->gch.next=NULL;*lastcollected=curr;lastcollected=&curr->gch.next;}}*
|
|
|
|
lastcollected=G(L)->tmudata;G(L)->tmudata=collected;return deadmem;}static
|
|
|
|
void removekey(Node*n){setnilvalue(gval(n));if(iscollectable(gkey(n)))setttype
|
|
|
|
(gkey(n),LUA_TNONE);}static void traversetable(GCState*st,Table*h){int i;int
|
|
|
|
weakkey=0;int weakvalue=0;const TObject*mode;markvalue(st,h->metatable);
|
|
|
|
lua_assert(h->lsizenode||h->node==st->g->dummynode);mode=gfasttm(st->g,h->
|
|
|
|
metatable,TM_MODE);if(mode&&ttisstring(mode)){weakkey=(strchr(svalue(mode),'k'
|
|
|
|
)!=NULL);weakvalue=(strchr(svalue(mode),'v')!=NULL);if(weakkey||weakvalue){
|
|
|
|
GCObject**weaklist;h->marked&=~(KEYWEAK|VALUEWEAK);h->marked|=cast(lu_byte,(
|
|
|
|
weakkey<<KEYWEAKBIT)|(weakvalue<<VALUEWEAKBIT));weaklist=(weakkey&&weakvalue)?
|
|
|
|
&st->wkv:(weakkey)?&st->wk:&st->wv;h->gclist=*weaklist;*weaklist=valtogco(h);}
|
|
|
|
}if(!weakvalue){i=h->sizearray;while(i--)markobject(st,&h->array[i]);}i=
|
|
|
|
sizenode(h);while(i--){Node*n=gnode(h,i);if(!ttisnil(gval(n))){lua_assert(!
|
|
|
|
ttisnil(gkey(n)));condmarkobject(st,gkey(n),!weakkey);condmarkobject(st,gval(n
|
|
|
|
),!weakvalue);}}}static void traverseproto(GCState*st,Proto*f){int i;
|
|
|
|
stringmark(f->source);for(i=0;i<f->sizek;i++){if(ttisstring(f->k+i))stringmark
|
|
|
|
(tsvalue(f->k+i));}for(i=0;i<f->sizeupvalues;i++)stringmark(f->upvalues[i]);
|
|
|
|
for(i=0;i<f->sizep;i++)markvalue(st,f->p[i]);for(i=0;i<f->sizelocvars;i++)
|
|
|
|
stringmark(f->locvars[i].varname);lua_assert(luaG_checkcode(f));}static void
|
|
|
|
traverseclosure(GCState*st,Closure*cl){if(cl->c.isC){int i;for(i=0;i<cl->c.
|
|
|
|
nupvalues;i++)markobject(st,&cl->c.upvalue[i]);}else{int i;lua_assert(cl->l.
|
|
|
|
nupvalues==cl->l.p->nups);markvalue(st,hvalue(&cl->l.g));markvalue(st,cl->l.p)
|
|
|
|
;for(i=0;i<cl->l.nupvalues;i++){UpVal*u=cl->l.upvals[i];if(!u->marked){
|
|
|
|
markobject(st,&u->value);u->marked=1;}}}}static void checkstacksizes(lua_State
|
|
|
|
*L,StkId max){int used=L->ci-L->base_ci;if(4*used<L->size_ci&&2*BASIC_CI_SIZE<
|
|
|
|
L->size_ci)luaD_reallocCI(L,L->size_ci/2);else condhardstacktests(
|
|
|
|
luaD_reallocCI(L,L->size_ci));used=max-L->stack;if(4*used<L->stacksize&&2*(
|
|
|
|
BASIC_STACK_SIZE+EXTRA_STACK)<L->stacksize)luaD_reallocstack(L,L->stacksize/2)
|
|
|
|
;else condhardstacktests(luaD_reallocstack(L,L->stacksize));}static void
|
|
|
|
traversestack(GCState*st,lua_State*L1){StkId o,lim;CallInfo*ci;markobject(st,
|
|
|
|
gt(L1));lim=L1->top;for(ci=L1->base_ci;ci<=L1->ci;ci++){lua_assert(ci->top<=L1
|
|
|
|
->stack_last);lua_assert(ci->state&(CI_C|CI_HASFRAME|CI_SAVEDPC));if(lim<ci->
|
|
|
|
top)lim=ci->top;}for(o=L1->stack;o<L1->top;o++)markobject(st,o);for(;o<=lim;o
|
|
|
|
++)setnilvalue(o);checkstacksizes(L1,lim);}static void propagatemarks(GCState*
|
|
|
|
st){while(st->tmark){switch(st->tmark->gch.tt){case LUA_TTABLE:{Table*h=gcotoh
|
|
|
|
(st->tmark);st->tmark=h->gclist;traversetable(st,h);break;}case LUA_TFUNCTION:
|
|
|
|
{Closure*cl=gcotocl(st->tmark);st->tmark=cl->c.gclist;traverseclosure(st,cl);
|
|
|
|
break;}case LUA_TTHREAD:{lua_State*th=gcototh(st->tmark);st->tmark=th->gclist;
|
|
|
|
traversestack(st,th);break;}case LUA_TPROTO:{Proto*p=gcotop(st->tmark);st->
|
|
|
|
tmark=p->gclist;traverseproto(st,p);break;}default:lua_assert(0);}}}static int
|
|
|
|
valismarked(const TObject*o){if(ttisstring(o))stringmark(tsvalue(o));return!
|
|
|
|
iscollectable(o)||testbit(o->value.gc->gch.marked,0);}static void
|
|
|
|
cleartablekeys(GCObject*l){while(l){Table*h=gcotoh(l);int i=sizenode(h);
|
|
|
|
lua_assert(h->marked&KEYWEAK);while(i--){Node*n=gnode(h,i);if(!valismarked(
|
|
|
|
gkey(n)))removekey(n);}l=h->gclist;}}static void cleartablevalues(GCObject*l){
|
|
|
|
while(l){Table*h=gcotoh(l);int i=h->sizearray;lua_assert(h->marked&VALUEWEAK);
|
|
|
|
while(i--){TObject*o=&h->array[i];if(!valismarked(o))setnilvalue(o);}i=
|
|
|
|
sizenode(h);while(i--){Node*n=gnode(h,i);if(!valismarked(gval(n)))removekey(n)
|
|
|
|
;}l=h->gclist;}}static void freeobj(lua_State*L,GCObject*o){switch(o->gch.tt){
|
|
|
|
case LUA_TPROTO:luaF_freeproto(L,gcotop(o));break;case LUA_TFUNCTION:
|
|
|
|
luaF_freeclosure(L,gcotocl(o));break;case LUA_TUPVAL:luaM_freelem(L,gcotouv(o)
|
|
|
|
);break;case LUA_TTABLE:luaH_free(L,gcotoh(o));break;case LUA_TTHREAD:{
|
|
|
|
lua_assert(gcototh(o)!=L&&gcototh(o)!=G(L)->mainthread);luaE_freethread(L,
|
|
|
|
gcototh(o));break;}case LUA_TSTRING:{luaM_free(L,o,sizestring(gcotots(o)->tsv.
|
|
|
|
len));break;}case LUA_TUSERDATA:{luaM_free(L,o,sizeudata(gcotou(o)->uv.len));
|
|
|
|
break;}default:lua_assert(0);}}static int sweeplist(lua_State*L,GCObject**p,
|
|
|
|
int limit){GCObject*curr;int count=0;while((curr=*p)!=NULL){if(curr->gch.
|
|
|
|
marked>limit){unmark(curr);p=&curr->gch.next;}else{count++;*p=curr->gch.next;
|
|
|
|
freeobj(L,curr);}}return count;}static void sweepstrings(lua_State*L,int all){
|
|
|
|
int i;for(i=0;i<G(L)->strt.size;i++){G(L)->strt.nuse-=sweeplist(L,&G(L)->strt.
|
|
|
|
hash[i],all);}}static void checkSizes(lua_State*L,size_t deadmem){if(G(L)->
|
|
|
|
strt.nuse<cast(ls_nstr,G(L)->strt.size/4)&&G(L)->strt.size>MINSTRTABSIZE*2)
|
|
|
|
luaS_resize(L,G(L)->strt.size/2);if(luaZ_sizebuffer(&G(L)->buff)>LUA_MINBUFFER
|
|
|
|
*2){size_t newsize=luaZ_sizebuffer(&G(L)->buff)/2;luaZ_resizebuffer(L,&G(L)->
|
|
|
|
buff,newsize);}G(L)->GCthreshold=2*G(L)->nblocks-deadmem;}static void do1gcTM(
|
|
|
|
lua_State*L,Udata*udata){const TObject*tm=fasttm(L,udata->uv.metatable,TM_GC);
|
|
|
|
if(tm!=NULL){setobj2s(L->top,tm);setuvalue(L->top+1,udata);L->top+=2;luaD_call
|
|
|
|
(L,L->top-2,0);}}void luaC_callGCTM(lua_State*L){lu_byte oldah=L->allowhook;L
|
|
|
|
->allowhook=0;L->top++;while(G(L)->tmudata!=NULL){GCObject*o=G(L)->tmudata;
|
|
|
|
Udata*udata=gcotou(o);G(L)->tmudata=udata->uv.next;udata->uv.next=G(L)->
|
|
|
|
rootudata;G(L)->rootudata=o;setuvalue(L->top-1,udata);unmark(o);markfinalized(
|
|
|
|
udata);do1gcTM(L,udata);}L->top--;L->allowhook=oldah;}void luaC_sweep(
|
|
|
|
lua_State*L,int all){if(all)all=256;sweeplist(L,&G(L)->rootudata,all);
|
|
|
|
sweepstrings(L,all);sweeplist(L,&G(L)->rootgc,all);}static void markroot(
|
|
|
|
GCState*st,lua_State*L){global_State*g=st->g;markobject(st,defaultmeta(L));
|
|
|
|
markobject(st,registry(L));traversestack(st,g->mainthread);if(L!=g->mainthread
|
|
|
|
)markvalue(st,L);}static size_t mark(lua_State*L){size_t deadmem;GCState st;
|
|
|
|
GCObject*wkv;st.g=G(L);st.tmark=NULL;st.wkv=st.wk=st.wv=NULL;markroot(&st,L);
|
|
|
|
propagatemarks(&st);cleartablevalues(st.wkv);cleartablevalues(st.wv);wkv=st.
|
|
|
|
wkv;st.wkv=NULL;st.wv=NULL;deadmem=luaC_separateudata(L);marktmu(&st);
|
|
|
|
propagatemarks(&st);cleartablekeys(wkv);cleartablekeys(st.wk);cleartablevalues
|
|
|
|
(st.wv);cleartablekeys(st.wkv);cleartablevalues(st.wkv);return deadmem;}void
|
|
|
|
luaC_collectgarbage(lua_State*L){size_t deadmem=mark(L);luaC_sweep(L,0);
|
|
|
|
checkSizes(L,deadmem);luaC_callGCTM(L);}void luaC_link(lua_State*L,GCObject*o,
|
|
|
|
lu_byte tt){o->gch.next=G(L)->rootgc;G(L)->rootgc=o;o->gch.marked=0;o->gch.tt=
|
|
|
|
tt;}
|
|
|
|
#line 1 "liolib.c"
|
|
|
|
#define liolib_c
|
|
|
|
#ifndef USE_TMPNAME
|
|
|
|
#ifdef __GNUC__
|
|
|
|
#define USE_TMPNAME 0
|
|
|
|
#else
|
|
|
|
#define USE_TMPNAME 1
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifndef USE_POPEN
|
|
|
|
#ifdef _POSIX_C_SOURCE
|
|
|
|
#if _POSIX_C_SOURCE >=2
|
|
|
|
#define USE_POPEN 1
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifndef USE_POPEN
|
|
|
|
#define USE_POPEN 0
|
|
|
|
#endif
|
|
|
|
#if !USE_POPEN
|
|
|
|
#define pclose(f) (-1)
|
|
|
|
#endif
|
|
|
|
#define FILEHANDLE "FILE*"
|
|
|
|
#define IO_INPUT "_input"
|
|
|
|
#define IO_OUTPUT "_output"
|
|
|
|
static int pushresult(lua_State*L,int i,const char*filename){if(i){
|
|
|
|
lua_pushboolean(L,1);return 1;}else{lua_pushnil(L);if(filename)lua_pushfstring
|
|
|
|
(L,"%s: %s",filename,strerror(errno));else lua_pushfstring(L,"%s",strerror(
|
|
|
|
errno));lua_pushnumber(L,errno);return 3;}}static FILE**topfile(lua_State*L,
|
|
|
|
int findex){FILE**f=(FILE**)luaL_checkudata(L,findex,FILEHANDLE);if(f==NULL)
|
|
|
|
luaL_argerror(L,findex,"bad file");return f;}static int io_type(lua_State*L){
|
|
|
|
FILE**f=(FILE**)luaL_checkudata(L,1,FILEHANDLE);if(f==NULL)lua_pushnil(L);else
|
|
|
|
if(*f==NULL)lua_pushliteral(L,"closed file");else lua_pushliteral(L,"file");
|
|
|
|
return 1;}static FILE*tofile(lua_State*L,int findex){FILE**f=topfile(L,findex)
|
|
|
|
;if(*f==NULL)luaL_error(L,"attempt to use a closed file");return*f;}static
|
|
|
|
FILE**newfile(lua_State*L){FILE**pf=(FILE**)lua_newuserdata(L,sizeof(FILE*));*
|
|
|
|
pf=NULL;luaL_getmetatable(L,FILEHANDLE);lua_setmetatable(L,-2);return pf;}
|
|
|
|
static void registerfile(lua_State*L,FILE*f,const char*name,const char*impname
|
|
|
|
){lua_pushstring(L,name);*newfile(L)=f;if(impname){lua_pushstring(L,impname);
|
|
|
|
lua_pushvalue(L,-2);lua_settable(L,-6);}lua_settable(L,-3);}static int
|
|
|
|
aux_close(lua_State*L){FILE*f=tofile(L,1);if(f==stdin||f==stdout||f==stderr)
|
|
|
|
return 0;else{int ok=(pclose(f)!=-1)||(fclose(f)==0);if(ok)*(FILE**)
|
|
|
|
lua_touserdata(L,1)=NULL;return ok;}}static int io_close(lua_State*L){if(
|
|
|
|
lua_isnone(L,1)&&lua_type(L,lua_upvalueindex(1))==LUA_TTABLE){lua_pushstring(L
|
|
|
|
,IO_OUTPUT);lua_rawget(L,lua_upvalueindex(1));}return pushresult(L,aux_close(L
|
|
|
|
),NULL);}static int io_gc(lua_State*L){FILE**f=topfile(L,1);if(*f!=NULL)
|
|
|
|
aux_close(L);return 0;}static int io_tostring(lua_State*L){char buff[128];FILE
|
|
|
|
**f=topfile(L,1);if(*f==NULL)strcpy(buff,"closed");else sprintf(buff,"%p",
|
|
|
|
lua_touserdata(L,1));lua_pushfstring(L,"file (%s)",buff);return 1;}static int
|
|
|
|
io_open(lua_State*L){const char*filename=luaL_checkstring(L,1);const char*mode
|
|
|
|
=luaL_optstring(L,2,"r");FILE**pf=newfile(L);*pf=fopen(filename,mode);return(*
|
|
|
|
pf==NULL)?pushresult(L,0,filename):1;}static int io_popen(lua_State*L){
|
|
|
|
#if !USE_POPEN
|
|
|
|
luaL_error(L,"`popen' not supported");return 0;
|
|
|
|
#else
|
|
|
|
const char*filename=luaL_checkstring(L,1);const char*mode=luaL_optstring(L,2,
|
|
|
|
"r");FILE**pf=newfile(L);*pf=popen(filename,mode);return(*pf==NULL)?pushresult
|
|
|
|
(L,0,filename):1;
|
|
|
|
#endif
|
|
|
|
}static int io_tmpfile(lua_State*L){FILE**pf=newfile(L);*pf=tmpfile();return(*
|
|
|
|
pf==NULL)?pushresult(L,0,NULL):1;}static FILE*getiofile(lua_State*L,const char
|
|
|
|
*name){lua_pushstring(L,name);lua_rawget(L,lua_upvalueindex(1));return tofile(
|
|
|
|
L,-1);}static int g_iofile(lua_State*L,const char*name,const char*mode){if(!
|
|
|
|
lua_isnoneornil(L,1)){const char*filename=lua_tostring(L,1);lua_pushstring(L,
|
|
|
|
name);if(filename){FILE**pf=newfile(L);*pf=fopen(filename,mode);if(*pf==NULL){
|
|
|
|
lua_pushfstring(L,"%s: %s",filename,strerror(errno));luaL_argerror(L,1,
|
|
|
|
lua_tostring(L,-1));}}else{tofile(L,1);lua_pushvalue(L,1);}lua_rawset(L,
|
|
|
|
lua_upvalueindex(1));}lua_pushstring(L,name);lua_rawget(L,lua_upvalueindex(1))
|
|
|
|
;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);static void aux_lines(lua_State*L,int idx,int close)
|
|
|
|
{lua_pushliteral(L,FILEHANDLE);lua_rawget(L,LUA_REGISTRYINDEX);lua_pushvalue(L
|
|
|
|
,idx);lua_pushboolean(L,close);lua_pushcclosure(L,io_readline,3);}static int
|
|
|
|
f_lines(lua_State*L){tofile(L,1);aux_lines(L,1,0);return 1;}static int
|
|
|
|
io_lines(lua_State*L){if(lua_isnoneornil(L,1)){lua_pushstring(L,IO_INPUT);
|
|
|
|
lua_rawget(L,lua_upvalueindex(1));return f_lines(L);}else{const char*filename=
|
|
|
|
luaL_checkstring(L,1);FILE**pf=newfile(L);*pf=fopen(filename,"r");
|
|
|
|
luaL_argcheck(L,*pf,1,strerror(errno));aux_lines(L,lua_gettop(L),1);return 1;}
|
|
|
|
}static int read_number(lua_State*L,FILE*f){lua_Number d;if(fscanf(f,
|
|
|
|
LUA_NUMBER_SCAN,&d)==1){lua_pushnumber(L,d);return 1;}else return 0;}static
|
|
|
|
int test_eof(lua_State*L,FILE*f){int c=getc(f);ungetc(c,f);lua_pushlstring(L,
|
|
|
|
NULL,0);return(c!=EOF);}static int read_line(lua_State*L,FILE*f){luaL_Buffer b
|
|
|
|
;luaL_buffinit(L,&b);for(;;){size_t l;char*p=luaL_prepbuffer(&b);if(fgets(p,
|
|
|
|
LUAL_BUFFERSIZE,f)==NULL){luaL_pushresult(&b);return(lua_strlen(L,-1)>0);}l=
|
|
|
|
strlen(p);if(p[l-1]!='\n')luaL_addsize(&b,l);else{luaL_addsize(&b,l-1);
|
|
|
|
luaL_pushresult(&b);return 1;}}}static int read_chars(lua_State*L,FILE*f,
|
|
|
|
size_t n){size_t rlen;size_t nr;luaL_Buffer b;luaL_buffinit(L,&b);rlen=
|
|
|
|
LUAL_BUFFERSIZE;do{char*p=luaL_prepbuffer(&b);if(rlen>n)rlen=n;nr=fread(p,
|
|
|
|
sizeof(char),rlen,f);luaL_addsize(&b,nr);n-=nr;}while(n>0&&nr==rlen);
|
|
|
|
luaL_pushresult(&b);return(n==0||lua_strlen(L,-1)>0);}static int g_read(
|
|
|
|
lua_State*L,FILE*f,int first){int nargs=lua_gettop(L)-1;int success;int n;if(
|
|
|
|
nargs==0){success=read_line(L,f);n=first+1;}else{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)lua_tonumber(L,n);success=(l
|
|
|
|
==0)?test_eof(L,f):read_chars(L,f,l);}else{const char*p=lua_tostring(L,n);
|
|
|
|
luaL_argcheck(L,p&&p[0]=='*',n,"invalid option");switch(p[1]){case'n':success=
|
|
|
|
read_number(L,f);break;case'l':success=read_line(L,f);break;case'a':read_chars
|
|
|
|
(L,f,~((size_t)0));success=1;break;case'w':return luaL_error(L,
|
|
|
|
"obsolete option `*w' to `read'");default:return luaL_argerror(L,n,
|
|
|
|
"invalid format");}}}}if(!success){lua_pop(L,1);lua_pushnil(L);}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,1),2);}static int
|
|
|
|
io_readline(lua_State*L){FILE*f=*(FILE**)lua_touserdata(L,lua_upvalueindex(2))
|
|
|
|
;if(f==NULL)luaL_error(L,"file is already closed");if(read_line(L,f))return 1;
|
|
|
|
else{if(lua_toboolean(L,lua_upvalueindex(3))){lua_settop(L,0);lua_pushvalue(L,
|
|
|
|
lua_upvalueindex(2));aux_close(L);}return 0;}}static int g_write(lua_State*L,
|
|
|
|
FILE*f,int arg){int nargs=lua_gettop(L)-1;int status=1;for(;nargs--;arg++){if(
|
|
|
|
lua_type(L,arg)==LUA_TNUMBER){status=status&&fprintf(f,LUA_NUMBER_FMT,
|
|
|
|
lua_tonumber(L,arg))>0;}else{size_t l;const char*s=luaL_checklstring(L,arg,&l)
|
|
|
|
;status=status&&(fwrite(s,sizeof(char),l,f)==l);}}return pushresult(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){return g_write(L,tofile(L,1),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,1
|
|
|
|
);int op=luaL_findstring(luaL_optstring(L,2,"cur"),modenames);long offset=
|
|
|
|
luaL_optlong(L,3,0);luaL_argcheck(L,op!=-1,2,"invalid mode");op=fseek(f,offset
|
|
|
|
,mode[op]);if(op)return pushresult(L,0,NULL);else{lua_pushnumber(L,ftell(f));
|
|
|
|
return 1;}}static int io_flush(lua_State*L){return pushresult(L,fflush(
|
|
|
|
getiofile(L,IO_OUTPUT))==0,NULL);}static int f_flush(lua_State*L){return
|
|
|
|
pushresult(L,fflush(tofile(L,1))==0,NULL);}static const luaL_reg iolib[]={{
|
|
|
|
"input",io_input},{"output",io_output},{"lines",io_lines},{"close",io_close},{
|
|
|
|
"flush",io_flush},{"open",io_open},{"popen",io_popen},{"read",io_read},{
|
|
|
|
"tmpfile",io_tmpfile},{"type",io_type},{"write",io_write},{NULL,NULL}};static
|
|
|
|
const luaL_reg flib[]={{"flush",f_flush},{"read",f_read},{"lines",f_lines},{
|
|
|
|
"seek",f_seek},{"write",f_write},{"close",io_close},{"__gc",io_gc},{
|
|
|
|
"__tostring",io_tostring},{NULL,NULL}};static void createmeta(lua_State*L){
|
|
|
|
luaL_newmetatable(L,FILEHANDLE);lua_pushliteral(L,"__index");lua_pushvalue(L,-
|
|
|
|
2);lua_rawset(L,-3);luaL_openlib(L,NULL,flib,0);}static int io_execute(
|
|
|
|
lua_State*L){lua_pushnumber(L,system(luaL_checkstring(L,1)));return 1;}static
|
|
|
|
int io_remove(lua_State*L){const char*filename=luaL_checkstring(L,1);return
|
|
|
|
pushresult(L,remove(filename)==0,filename);}static int io_rename(lua_State*L){
|
|
|
|
const char*fromname=luaL_checkstring(L,1);const char*toname=luaL_checkstring(L
|
|
|
|
,2);return pushresult(L,rename(fromname,toname)==0,fromname);}static int
|
|
|
|
io_tmpname(lua_State*L){
|
|
|
|
#if !USE_TMPNAME
|
|
|
|
luaL_error(L,"`tmpname' not supported");return 0;
|
|
|
|
#else
|
|
|
|
char buff[L_tmpnam];if(tmpnam(buff)!=buff)return luaL_error(L,
|
|
|
|
"unable to generate a unique filename in `tmpname'");lua_pushstring(L,buff);
|
|
|
|
return 1;
|
|
|
|
#endif
|
|
|
|
}static int io_getenv(lua_State*L){lua_pushstring(L,getenv(luaL_checkstring(L,
|
|
|
|
1)));return 1;}static int io_clock(lua_State*L){lua_pushnumber(L,((lua_Number)
|
|
|
|
clock())/(lua_Number)CLOCKS_PER_SEC);return 1;}static void setfield(lua_State*
|
|
|
|
L,const char*key,int value){lua_pushstring(L,key);lua_pushnumber(L,value);
|
|
|
|
lua_rawset(L,-3);}static void setboolfield(lua_State*L,const char*key,int
|
|
|
|
value){lua_pushstring(L,key);lua_pushboolean(L,value);lua_rawset(L,-3);}static
|
|
|
|
int getboolfield(lua_State*L,const char*key){int res;lua_pushstring(L,key);
|
|
|
|
lua_gettable(L,-2);res=lua_toboolean(L,-1);lua_pop(L,1);return res;}static int
|
|
|
|
getfield(lua_State*L,const char*key,int d){int res;lua_pushstring(L,key);
|
|
|
|
lua_gettable(L,-2);if(lua_isnumber(L,-1))res=(int)(lua_tonumber(L,-1));else{if
|
|
|
|
(d==-2)return luaL_error(L,"field `%s' missing in date table",key);res=d;}
|
|
|
|
lua_pop(L,1);return res;}static int io_date(lua_State*L){const char*s=
|
|
|
|
luaL_optstring(L,1,"%c");time_t t=(time_t)(luaL_optnumber(L,2,-1));struct tm*
|
|
|
|
stm;if(t==(time_t)(-1))t=time(NULL);if(*s=='!'){stm=gmtime(&t);s++;}else stm=
|
|
|
|
localtime(&t);if(stm==NULL)lua_pushnil(L);else if(strcmp(s,"*t")==0){
|
|
|
|
lua_newtable(L);setfield(L,"sec",stm->tm_sec);setfield(L,"min",stm->tm_min);
|
|
|
|
setfield(L,"hour",stm->tm_hour);setfield(L,"day",stm->tm_mday);setfield(L,
|
|
|
|
"month",stm->tm_mon+1);setfield(L,"year",stm->tm_year+1900);setfield(L,"wday",
|
|
|
|
stm->tm_wday+1);setfield(L,"yday",stm->tm_yday+1);setboolfield(L,"isdst",stm->
|
|
|
|
tm_isdst);}else{char b[256];if(strftime(b,sizeof(b),s,stm))lua_pushstring(L,b)
|
|
|
|
;else return luaL_error(L,"`date' format too long");}return 1;}static int
|
|
|
|
io_time(lua_State*L){if(lua_isnoneornil(L,1))lua_pushnumber(L,time(NULL));else
|
|
|
|
{time_t t;struct tm ts;luaL_checktype(L,1,LUA_TTABLE);lua_settop(L,1);ts.
|
|
|
|
tm_sec=getfield(L,"sec",0);ts.tm_min=getfield(L,"min",0);ts.tm_hour=getfield(L
|
|
|
|
,"hour",12);ts.tm_mday=getfield(L,"day",-2);ts.tm_mon=getfield(L,"month",-2)-1
|
|
|
|
;ts.tm_year=getfield(L,"year",-2)-1900;ts.tm_isdst=getboolfield(L,"isdst");t=
|
|
|
|
mktime(&ts);if(t==(time_t)(-1))lua_pushnil(L);else lua_pushnumber(L,t);}return
|
|
|
|
1;}static int io_difftime(lua_State*L){lua_pushnumber(L,difftime((time_t)(
|
|
|
|
luaL_checknumber(L,1)),(time_t)(luaL_optnumber(L,2,0))));return 1;}static int
|
|
|
|
io_setloc(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=lua_tostring(
|
|
|
|
L,1);int op=luaL_findstring(luaL_optstring(L,2,"all"),catnames);luaL_argcheck(
|
|
|
|
L,l||lua_isnoneornil(L,1),1,"string expected");luaL_argcheck(L,op!=-1,2,
|
|
|
|
"invalid option");lua_pushstring(L,setlocale(cat[op],l));return 1;}static int
|
|
|
|
io_exit(lua_State*L){exit(luaL_optint(L,1,EXIT_SUCCESS));return 0;}static
|
|
|
|
const luaL_reg syslib[]={{"clock",io_clock},{"date",io_date},{"difftime",
|
|
|
|
io_difftime},{"execute",io_execute},{"exit",io_exit},{"getenv",io_getenv},{
|
|
|
|
"remove",io_remove},{"rename",io_rename},{"setlocale",io_setloc},{"time",
|
|
|
|
io_time},{"tmpname",io_tmpname},{NULL,NULL}};LUALIB_API int luaopen_io(
|
|
|
|
lua_State*L){luaL_openlib(L,LUA_OSLIBNAME,syslib,0);createmeta(L);
|
|
|
|
lua_pushvalue(L,-1);luaL_openlib(L,LUA_IOLIBNAME,iolib,1);registerfile(L,stdin
|
|
|
|
,"stdin",IO_INPUT);registerfile(L,stdout,"stdout",IO_OUTPUT);registerfile(L,
|
|
|
|
stderr,"stderr",NULL);return 1;}
|
|
|
|
#line 1 "llex.c"
|
|
|
|
#define llex_c
|
|
|
|
#define next(LS) (LS->current=zgetc(LS->z))
|
|
|
|
static const char*const token2string[]={"and","break","do","else","elseif",
|
|
|
|
"end","false","for","function","if","in","local","nil","not","or","repeat",
|
|
|
|
"return","then","true","until","while","*name","..","...","==",">=","<=","~=",
|
|
|
|
"*number","*string","<eof>"};void luaX_init(lua_State*L){int i;for(i=0;i<
|
|
|
|
NUM_RESERVED;i++){TString*ts=luaS_new(L,token2string[i]);luaS_fix(ts);
|
|
|
|
lua_assert(strlen(token2string[i])+1<=TOKEN_LEN);ts->tsv.reserved=cast(lu_byte
|
|
|
|
,i+1);}}
|
|
|
|
#define MAXSRC 80
|
|
|
|
void luaX_checklimit(LexState*ls,int val,int limit,const char*msg){if(val>
|
|
|
|
limit){msg=luaO_pushfstring(ls->L,"too many %s (limit=%d)",msg,limit);
|
|
|
|
luaX_syntaxerror(ls,msg);}}void luaX_errorline(LexState*ls,const char*s,const
|
|
|
|
char*token,int line){lua_State*L=ls->L;char buff[MAXSRC];luaO_chunkid(buff,
|
|
|
|
getstr(ls->source),MAXSRC);luaO_pushfstring(L,"%s:%d: %s near `%s'",buff,line,
|
|
|
|
s,token);luaD_throw(L,LUA_ERRSYNTAX);}static void luaX_error(LexState*ls,const
|
|
|
|
char*s,const char*token){luaX_errorline(ls,s,token,ls->linenumber);}void
|
|
|
|
luaX_syntaxerror(LexState*ls,const char*msg){const char*lasttoken;switch(ls->t
|
|
|
|
.token){case TK_NAME:lasttoken=getstr(ls->t.seminfo.ts);break;case TK_STRING:
|
|
|
|
case TK_NUMBER:lasttoken=luaZ_buffer(ls->buff);break;default:lasttoken=
|
|
|
|
luaX_token2str(ls,ls->t.token);break;}luaX_error(ls,msg,lasttoken);}const char
|
|
|
|
*luaX_token2str(LexState*ls,int token){if(token<FIRST_RESERVED){lua_assert(
|
|
|
|
token==(unsigned char)token);return luaO_pushfstring(ls->L,"%c",token);}else
|
|
|
|
return token2string[token-FIRST_RESERVED];}static void luaX_lexerror(LexState*
|
|
|
|
ls,const char*s,int token){if(token==TK_EOS)luaX_error(ls,s,luaX_token2str(ls,
|
|
|
|
token));else luaX_error(ls,s,luaZ_buffer(ls->buff));}static void inclinenumber
|
|
|
|
(LexState*LS){next(LS);++LS->linenumber;luaX_checklimit(LS,LS->linenumber,
|
|
|
|
MAX_INT,"lines in a chunk");}void luaX_setinput(lua_State*L,LexState*LS,ZIO*z,
|
|
|
|
TString*source){LS->L=L;LS->lookahead.token=TK_EOS;LS->z=z;LS->fs=NULL;LS->
|
|
|
|
linenumber=1;LS->lastline=1;LS->source=source;next(LS);if(LS->current=='#'){do
|
|
|
|
{next(LS);}while(LS->current!='\n'&&LS->current!=EOZ);}}
|
|
|
|
#define EXTRABUFF 32
|
|
|
|
#define MAXNOCHECK 5
|
|
|
|
#define checkbuffer(LS, len)if(((len)+MAXNOCHECK)*sizeof(char)>luaZ_sizebuffer\
|
|
|
|
((LS)->buff))luaZ_openspace((LS)->L,(LS)->buff,(len)+EXTRABUFF)
|
|
|
|
#define save(LS, c,l)(luaZ_buffer((LS)->buff)[l++]=cast(char,c))
|
|
|
|
#define save_and_next(LS, l)(save(LS,LS->current,l),next(LS))
|
|
|
|
static size_t readname(LexState*LS){size_t l=0;checkbuffer(LS,l);do{
|
|
|
|
checkbuffer(LS,l);save_and_next(LS,l);}while(isalnum(LS->current)||LS->current
|
|
|
|
=='_');save(LS,'\0',l);return l-1;}static void read_numeral(LexState*LS,int
|
|
|
|
comma,SemInfo*seminfo){size_t l=0;checkbuffer(LS,l);if(comma)save(LS,'.',l);
|
|
|
|
while(isdigit(LS->current)){checkbuffer(LS,l);save_and_next(LS,l);}if(LS->
|
|
|
|
current=='.'){save_and_next(LS,l);if(LS->current=='.'){save_and_next(LS,l);
|
|
|
|
save(LS,'\0',l);luaX_lexerror(LS,
|
|
|
|
"ambiguous syntax (decimal point x string concatenation)",TK_NUMBER);}}while(
|
|
|
|
isdigit(LS->current)){checkbuffer(LS,l);save_and_next(LS,l);}if(LS->current==
|
|
|
|
'e'||LS->current=='E'){save_and_next(LS,l);if(LS->current=='+'||LS->current==
|
|
|
|
'-')save_and_next(LS,l);while(isdigit(LS->current)){checkbuffer(LS,l);
|
|
|
|
save_and_next(LS,l);}}save(LS,'\0',l);if(!luaO_str2d(luaZ_buffer(LS->buff),&
|
|
|
|
seminfo->r))luaX_lexerror(LS,"malformed number",TK_NUMBER);}static void
|
|
|
|
read_long_string(LexState*LS,SemInfo*seminfo){int cont=0;size_t l=0;
|
|
|
|
checkbuffer(LS,l);save(LS,'[',l);save_and_next(LS,l);if(LS->current=='\n')
|
|
|
|
inclinenumber(LS);for(;;){checkbuffer(LS,l);switch(LS->current){case EOZ:save(
|
|
|
|
LS,'\0',l);luaX_lexerror(LS,(seminfo)?"unfinished long string":
|
|
|
|
"unfinished long comment",TK_EOS);break;case'[':save_and_next(LS,l);if(LS->
|
|
|
|
current=='['){cont++;save_and_next(LS,l);}continue;case']':save_and_next(LS,l)
|
|
|
|
;if(LS->current==']'){if(cont==0)goto endloop;cont--;save_and_next(LS,l);}
|
|
|
|
continue;case'\n':save(LS,'\n',l);inclinenumber(LS);if(!seminfo)l=0;continue;
|
|
|
|
default:save_and_next(LS,l);}}endloop:save_and_next(LS,l);save(LS,'\0',l);if(
|
|
|
|
seminfo)seminfo->ts=luaS_newlstr(LS->L,luaZ_buffer(LS->buff)+2,l-5);}static
|
|
|
|
void read_string(LexState*LS,int del,SemInfo*seminfo){size_t l=0;checkbuffer(
|
|
|
|
LS,l);save_and_next(LS,l);while(LS->current!=del){checkbuffer(LS,l);switch(LS
|
|
|
|
->current){case EOZ:save(LS,'\0',l);luaX_lexerror(LS,"unfinished string",
|
|
|
|
TK_EOS);break;case'\n':save(LS,'\0',l);luaX_lexerror(LS,"unfinished string",
|
|
|
|
TK_STRING);break;case'\\':next(LS);switch(LS->current){case'a':save(LS,'\a',l)
|
|
|
|
;next(LS);break;case'b':save(LS,'\b',l);next(LS);break;case'f':save(LS,'\f',l)
|
|
|
|
;next(LS);break;case'n':save(LS,'\n',l);next(LS);break;case'r':save(LS,'\r',l)
|
|
|
|
;next(LS);break;case't':save(LS,'\t',l);next(LS);break;case'v':save(LS,'\v',l)
|
|
|
|
;next(LS);break;case'\n':save(LS,'\n',l);inclinenumber(LS);break;case EOZ:
|
|
|
|
break;default:{if(!isdigit(LS->current))save_and_next(LS,l);else{int c=0;int i
|
|
|
|
=0;do{c=10*c+(LS->current-'0');next(LS);}while(++i<3&&isdigit(LS->current));if
|
|
|
|
(c>UCHAR_MAX){save(LS,'\0',l);luaX_lexerror(LS,"escape sequence too large",
|
|
|
|
TK_STRING);}save(LS,c,l);}}}break;default:save_and_next(LS,l);}}save_and_next(
|
|
|
|
LS,l);save(LS,'\0',l);seminfo->ts=luaS_newlstr(LS->L,luaZ_buffer(LS->buff)+1,l
|
|
|
|
-3);}int luaX_lex(LexState*LS,SemInfo*seminfo){for(;;){switch(LS->current){
|
|
|
|
case'\n':{inclinenumber(LS);continue;}case'-':{next(LS);if(LS->current!='-')
|
|
|
|
return'-';next(LS);if(LS->current=='['&&(next(LS),LS->current=='['))
|
|
|
|
read_long_string(LS,NULL);else while(LS->current!='\n'&&LS->current!=EOZ)next(
|
|
|
|
LS);continue;}case'[':{next(LS);if(LS->current!='[')return'[';else{
|
|
|
|
read_long_string(LS,seminfo);return TK_STRING;}}case'=':{next(LS);if(LS->
|
|
|
|
current!='=')return'=';else{next(LS);return TK_EQ;}}case'<':{next(LS);if(LS->
|
|
|
|
current!='=')return'<';else{next(LS);return TK_LE;}}case'>':{next(LS);if(LS->
|
|
|
|
current!='=')return'>';else{next(LS);return TK_GE;}}case'~':{next(LS);if(LS->
|
|
|
|
current!='=')return'~';else{next(LS);return TK_NE;}}case'"':case'\'':{
|
|
|
|
read_string(LS,LS->current,seminfo);return TK_STRING;}case'.':{next(LS);if(LS
|
|
|
|
->current=='.'){next(LS);if(LS->current=='.'){next(LS);return TK_DOTS;}else
|
|
|
|
return TK_CONCAT;}else if(!isdigit(LS->current))return'.';else{read_numeral(LS
|
|
|
|
,1,seminfo);return TK_NUMBER;}}case EOZ:{return TK_EOS;}default:{if(isspace(LS
|
|
|
|
->current)){next(LS);continue;}else if(isdigit(LS->current)){read_numeral(LS,0
|
|
|
|
,seminfo);return TK_NUMBER;}else if(isalpha(LS->current)||LS->current=='_'){
|
|
|
|
size_t l=readname(LS);TString*ts=luaS_newlstr(LS->L,luaZ_buffer(LS->buff),l);
|
|
|
|
if(ts->tsv.reserved>0)return ts->tsv.reserved-1+FIRST_RESERVED;seminfo->ts=ts;
|
|
|
|
return TK_NAME;}else{int c=LS->current;if(iscntrl(c))luaX_error(LS,
|
|
|
|
"invalid control char",luaO_pushfstring(LS->L,"char(%d)",c));next(LS);return c
|
|
|
|
;}}}}}
|
|
|
|
#undef next
|
|
|
|
#line 1 "lmem.c"
|
|
|
|
#define lmem_c
|
|
|
|
#ifndef l_realloc
|
|
|
|
#define l_realloc(b,os,s) realloc(b,s)
|
|
|
|
#endif
|
|
|
|
#ifndef l_free
|
|
|
|
#define l_free(b,os) free(b)
|
|
|
|
#endif
|
|
|
|
#define MINSIZEARRAY 4
|
|
|
|
void*luaM_growaux(lua_State*L,void*block,int*size,int size_elems,int limit,
|
|
|
|
const char*errormsg){void*newblock;int newsize=(*size)*2;if(newsize<
|
|
|
|
MINSIZEARRAY)newsize=MINSIZEARRAY;else if(*size>=limit/2){if(*size<limit-
|
|
|
|
MINSIZEARRAY)newsize=limit;else luaG_runerror(L,errormsg);}newblock=
|
|
|
|
luaM_realloc(L,block,cast(lu_mem,*size)*cast(lu_mem,size_elems),cast(lu_mem,
|
|
|
|
newsize)*cast(lu_mem,size_elems));*size=newsize;return newblock;}void*
|
|
|
|
luaM_realloc(lua_State*L,void*block,lu_mem oldsize,lu_mem size){lua_assert((
|
|
|
|
oldsize==0)==(block==NULL));if(size==0){if(block!=NULL){l_free(block,oldsize);
|
|
|
|
block=NULL;}else return NULL;}else if(size>=MAX_SIZET)luaG_runerror(L,
|
|
|
|
"memory allocation error: block too big");else{block=l_realloc(block,oldsize,
|
|
|
|
size);if(block==NULL){if(L)luaD_throw(L,LUA_ERRMEM);else return NULL;}}if(L){
|
|
|
|
lua_assert(G(L)!=NULL&&G(L)->nblocks>0);G(L)->nblocks-=oldsize;G(L)->nblocks+=
|
|
|
|
size;}return block;}
|
|
|
|
#line 1 "loadlib.c"
|
|
|
|
#undef LOADLIB
|
|
|
|
#ifdef USE_DLOPEN
|
|
|
|
#define LOADLIB
|
|
|
|
#include <dlfcn.h> /* dg: magic anchor comment */
|
|
|
|
static int loadlib(lua_State*L){const char*path=luaL_checkstring(L,1);const
|
|
|
|
char*init=luaL_checkstring(L,2);void*lib=dlopen(path,RTLD_NOW);if(lib!=NULL){
|
|
|
|
lua_CFunction f=(lua_CFunction)dlsym(lib,init);if(f!=NULL){
|
|
|
|
lua_pushlightuserdata(L,lib);lua_pushcclosure(L,f,1);return 1;}}lua_pushnil(L)
|
|
|
|
;lua_pushstring(L,dlerror());lua_pushstring(L,(lib!=NULL)?"init":"open");if(
|
|
|
|
lib!=NULL)dlclose(lib);return 3;}
|
|
|
|
#endif
|
|
|
|
#ifndef USE_DLL
|
|
|
|
#ifdef _WIN32
|
|
|
|
#define USE_DLL 1
|
|
|
|
#else
|
|
|
|
#define USE_DLL 0
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if USE_DLL
|
|
|
|
#define LOADLIB
|
|
|
|
#include <windows.h> /* dg: magic anchor comment */
|
|
|
|
static void pusherror(lua_State*L){int error=GetLastError();char buffer[128];
|
|
|
|
if(FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM,0,
|
|
|
|
error,0,buffer,sizeof(buffer),0))lua_pushstring(L,buffer);else lua_pushfstring
|
|
|
|
(L,"system error %d\n",error);}static int loadlib(lua_State*L){const char*path
|
|
|
|
=luaL_checkstring(L,1);const char*init=luaL_checkstring(L,2);HINSTANCE lib=
|
|
|
|
LoadLibrary(path);if(lib!=NULL){lua_CFunction f=(lua_CFunction)GetProcAddress(
|
|
|
|
lib,init);if(f!=NULL){lua_pushlightuserdata(L,lib);lua_pushcclosure(L,f,1);
|
|
|
|
return 1;}}lua_pushnil(L);pusherror(L);lua_pushstring(L,(lib!=NULL)?"init":
|
|
|
|
"open");if(lib!=NULL)FreeLibrary(lib);return 3;}
|
|
|
|
#endif
|
|
|
|
#ifndef LOADLIB
|
|
|
|
#ifdef linux
|
|
|
|
#define LOADLIB
|
|
|
|
#endif
|
|
|
|
#ifdef sun
|
|
|
|
#define LOADLIB
|
|
|
|
#endif
|
|
|
|
#ifdef sgi
|
|
|
|
#define LOADLIB
|
|
|
|
#endif
|
|
|
|
#ifdef BSD
|
|
|
|
#define LOADLIB
|
|
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
|
|
#define LOADLIB
|
|
|
|
#endif
|
|
|
|
#ifdef LOADLIB
|
|
|
|
#undef LOADLIB
|
|
|
|
#define LOADLIB "`loadlib' not installed (check your Lua configuration)"
|
|
|
|
#else
|
|
|
|
#define LOADLIB "`loadlib' not supported"
|
|
|
|
#endif
|
|
|
|
static int loadlib(lua_State*L){lua_pushnil(L);lua_pushliteral(L,LOADLIB);
|
|
|
|
lua_pushliteral(L,"absent");return 3;}
|
|
|
|
#endif
|
|
|
|
LUALIB_API int luaopen_loadlib(lua_State*L){lua_register(L,"loadlib",loadlib);
|
|
|
|
return 0;}
|
|
|
|
#line 1 "lobject.c"
|
|
|
|
#define lobject_c
|
|
|
|
#ifndef lua_str2number
|
|
|
|
#define lua_str2number(s,p) strtod((s),(p))
|
|
|
|
#endif
|
|
|
|
const TObject luaO_nilobject={LUA_TNIL,{NULL}};int luaO_int2fb(unsigned int x)
|
|
|
|
{int m=0;while(x>=(1<<3)){x=(x+1)>>1;m++;}return(m<<3)|cast(int,x);}int
|
|
|
|
luaO_log2(unsigned int x){static const lu_byte log_8[255]={0,1,1,2,2,2,2,3,3,3
|
|
|
|
,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5
|
|
|
|
,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
|
|
|
|
,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
|
|
|
|
,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
|
|
|
|
,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,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};if(x>=0x00010000){if(x>=0x01000000)return log_8[((x>>
|
|
|
|
24)&0xff)-1]+24;else return log_8[((x>>16)&0xff)-1]+16;}else{if(x>=0x00000100)
|
|
|
|
return log_8[((x>>8)&0xff)-1]+8;else if(x)return log_8[(x&0xff)-1];return-1;}}
|
|
|
|
int luaO_rawequalObj(const TObject*t1,const TObject*t2){if(ttype(t1)!=ttype(t2
|
|
|
|
))return 0;else switch(ttype(t1)){case LUA_TNIL:return 1;case LUA_TNUMBER:
|
|
|
|
return nvalue(t1)==nvalue(t2);case LUA_TBOOLEAN:return bvalue(t1)==bvalue(t2);
|
|
|
|
case LUA_TLIGHTUSERDATA:return pvalue(t1)==pvalue(t2);default:lua_assert(
|
|
|
|
iscollectable(t1));return gcvalue(t1)==gcvalue(t2);}}int luaO_str2d(const char
|
|
|
|
*s,lua_Number*result){char*endptr;lua_Number res=lua_str2number(s,&endptr);if(
|
|
|
|
endptr==s)return 0;while(isspace((unsigned char)(*endptr)))endptr++;if(*endptr
|
|
|
|
!='\0')return 0;*result=res;return 1;}static void pushstr(lua_State*L,const
|
|
|
|
char*str){setsvalue2s(L->top,luaS_new(L,str));incr_top(L);}const char*
|
|
|
|
luaO_pushvfstring(lua_State*L,const char*fmt,va_list argp){int n=1;pushstr(L,
|
|
|
|
"");for(;;){const char*e=strchr(fmt,'%');if(e==NULL)break;setsvalue2s(L->top,
|
|
|
|
luaS_newlstr(L,fmt,e-fmt));incr_top(L);switch(*(e+1)){case's':pushstr(L,va_arg
|
|
|
|
(argp,char*));break;case'c':{char buff[2];buff[0]=cast(char,va_arg(argp,int));
|
|
|
|
buff[1]='\0';pushstr(L,buff);break;}case'd':setnvalue(L->top,cast(lua_Number,
|
|
|
|
va_arg(argp,int)));incr_top(L);break;case'f':setnvalue(L->top,cast(lua_Number,
|
|
|
|
va_arg(argp,l_uacNumber)));incr_top(L);break;case'%':pushstr(L,"%");break;
|
|
|
|
default:lua_assert(0);}n+=2;fmt=e+2;}pushstr(L,fmt);luaV_concat(L,n+1,L->top-L
|
|
|
|
->base-1);L->top-=n;return svalue(L->top-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;}void luaO_chunkid(
|
|
|
|
char*out,const char*source,int bufflen){if(*source=='='){strncpy(out,source+1,
|
|
|
|
bufflen);out[bufflen-1]='\0';}else{if(*source=='@'){int l;source++;bufflen-=
|
|
|
|
sizeof(" `...' ");l=strlen(source);strcpy(out,"");if(l>bufflen){source+=(l-
|
|
|
|
bufflen);strcat(out,"...");}strcat(out,source);}else{int len=strcspn(source,
|
|
|
|
"\n");bufflen-=sizeof(" [string \"...\"] ");if(len>bufflen)len=bufflen;strcpy(
|
|
|
|
out,"[string \"");if(source[len]!='\0'){strncat(out,source,len);strcat(out,
|
|
|
|
"...");}else strcat(out,source);strcat(out,"\"]");}}}
|
|
|
|
#line 1 "lopcodes.c"
|
|
|
|
#define lopcodes_c
|
|
|
|
#ifdef LUA_OPNAMES
|
|
|
|
const char*const luaP_opnames[]={"MOVE","LOADK","LOADBOOL","LOADNIL",
|
|
|
|
"GETUPVAL","GETGLOBAL","GETTABLE","SETGLOBAL","SETUPVAL","SETTABLE","NEWTABLE"
|
|
|
|
,"SELF","ADD","SUB","MUL","DIV","POW","UNM","NOT","CONCAT","JMP","EQ","LT",
|
|
|
|
"LE","TEST","CALL","TAILCALL","RETURN","FORLOOP","TFORLOOP","TFORPREP",
|
|
|
|
"SETLIST","SETLISTO","CLOSE","CLOSURE"};
|
|
|
|
#endif
|
|
|
|
#define opmode(t,b,bk,ck,sa,k,m) (((t)<<OpModeT)|((b)<<OpModeBreg)|((bk)<<\
|
|
|
|
OpModeBrk)|((ck)<<OpModeCrk)|((sa)<<OpModesetA)|((k)<<OpModeK)|(m))
|
|
|
|
const lu_byte luaP_opmodes[NUM_OPCODES]={opmode(0,1,0,0,1,0,iABC),opmode(0,0,0
|
|
|
|
,0,1,1,iABx),opmode(0,0,0,0,1,0,iABC),opmode(0,1,0,0,1,0,iABC),opmode(0,0,0,0,
|
|
|
|
1,0,iABC),opmode(0,0,0,0,1,1,iABx),opmode(0,1,0,1,1,0,iABC),opmode(0,0,0,0,0,1
|
|
|
|
,iABx),opmode(0,0,0,0,0,0,iABC),opmode(0,0,1,1,0,0,iABC),opmode(0,0,0,0,1,0,
|
|
|
|
iABC),opmode(0,1,0,1,1,0,iABC),opmode(0,0,1,1,1,0,iABC),opmode(0,0,1,1,1,0,
|
|
|
|
iABC),opmode(0,0,1,1,1,0,iABC),opmode(0,0,1,1,1,0,iABC),opmode(0,0,1,1,1,0,
|
|
|
|
iABC),opmode(0,1,0,0,1,0,iABC),opmode(0,1,0,0,1,0,iABC),opmode(0,1,0,1,1,0,
|
|
|
|
iABC),opmode(0,0,0,0,0,0,iAsBx),opmode(1,0,1,1,0,0,iABC),opmode(1,0,1,1,0,0,
|
|
|
|
iABC),opmode(1,0,1,1,0,0,iABC),opmode(1,1,0,0,1,0,iABC),opmode(0,0,0,0,0,0,
|
|
|
|
iABC),opmode(0,0,0,0,0,0,iABC),opmode(0,0,0,0,0,0,iABC),opmode(0,0,0,0,0,0,
|
|
|
|
iAsBx),opmode(1,0,0,0,0,0,iABC),opmode(0,0,0,0,0,0,iAsBx),opmode(0,0,0,0,0,0,
|
|
|
|
iABx),opmode(0,0,0,0,0,0,iABx),opmode(0,0,0,0,0,0,iABC),opmode(0,0,0,0,1,0,
|
|
|
|
iABx)};
|
|
|
|
#line 1 "lparser.c"
|
|
|
|
#define lparser_c
|
|
|
|
#define getlocvar(fs, i)((fs)->f->locvars[(fs)->actvar[i]])
|
|
|
|
#define enterlevel(ls) if(++(ls)->nestlevel>LUA_MAXPARSERLEVEL)\
|
|
|
|
luaX_syntaxerror(ls,"too many syntax levels");
|
|
|
|
#define leavelevel(ls) ((ls)->nestlevel--)
|
|
|
|
typedef struct BlockCnt{struct BlockCnt*previous;int breaklist;int nactvar;int
|
|
|
|
upval;int isbreakable;}BlockCnt;static void chunk(LexState*ls);static void
|
|
|
|
expr(LexState*ls,expdesc*v);static void next(LexState*ls){ls->lastline=ls->
|
|
|
|
linenumber;if(ls->lookahead.token!=TK_EOS){ls->t=ls->lookahead;ls->lookahead.
|
|
|
|
token=TK_EOS;}else ls->t.token=luaX_lex(ls,&ls->t.seminfo);}static void
|
|
|
|
lookahead(LexState*ls){lua_assert(ls->lookahead.token==TK_EOS);ls->lookahead.
|
|
|
|
token=luaX_lex(ls,&ls->lookahead.seminfo);}static void error_expected(LexState
|
|
|
|
*ls,int token){luaX_syntaxerror(ls,luaO_pushfstring(ls->L,"`%s' expected",
|
|
|
|
luaX_token2str(ls,token)));}static int testnext(LexState*ls,int c){if(ls->t.
|
|
|
|
token==c){next(ls);return 1;}else return 0;}static void check(LexState*ls,int
|
|
|
|
c){if(!testnext(ls,c))error_expected(ls,c);}
|
|
|
|
#define check_condition(ls,c,msg) {if(!(c))luaX_syntaxerror(ls,msg);}
|
|
|
|
static void check_match(LexState*ls,int what,int who,int where){if(!testnext(
|
|
|
|
ls,what)){if(where==ls->linenumber)error_expected(ls,what);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_condition(ls,(ls->t.token==TK_NAME),"<name> expected");ts=ls
|
|
|
|
->t.seminfo.ts;next(ls);return ts;}static void init_exp(expdesc*e,expkind k,
|
|
|
|
int i){e->f=e->t=NO_JUMP;e->k=k;e->info=i;}static void codestring(LexState*ls,
|
|
|
|
expdesc*e,TString*s){init_exp(e,VK,luaK_stringK(ls->fs,s));}static void
|
|
|
|
checkname(LexState*ls,expdesc*e){codestring(ls,e,str_checkname(ls));}static
|
|
|
|
int luaI_registerlocalvar(LexState*ls,TString*varname){FuncState*fs=ls->fs;
|
|
|
|
Proto*f=fs->f;luaM_growvector(ls->L,f->locvars,fs->nlocvars,f->sizelocvars,
|
|
|
|
LocVar,MAX_INT,"");f->locvars[fs->nlocvars].varname=varname;return fs->
|
|
|
|
nlocvars++;}static void new_localvar(LexState*ls,TString*name,int n){FuncState
|
|
|
|
*fs=ls->fs;luaX_checklimit(ls,fs->nactvar+n+1,MAXVARS,"local variables");fs->
|
|
|
|
actvar[fs->nactvar+n]=luaI_registerlocalvar(ls,name);}static void
|
|
|
|
adjustlocalvars(LexState*ls,int nvars){FuncState*fs=ls->fs;fs->nactvar+=nvars;
|
|
|
|
for(;nvars;nvars--){getlocvar(fs,fs->nactvar-nvars).startpc=fs->pc;}}static
|
|
|
|
void removevars(LexState*ls,int tolevel){FuncState*fs=ls->fs;while(fs->nactvar
|
|
|
|
>tolevel)getlocvar(fs,--fs->nactvar).endpc=fs->pc;}static void new_localvarstr
|
|
|
|
(LexState*ls,const char*name,int n){new_localvar(ls,luaS_new(ls->L,name),n);}
|
|
|
|
static void create_local(LexState*ls,const char*name){new_localvarstr(ls,name,
|
|
|
|
0);adjustlocalvars(ls,1);}static int indexupvalue(FuncState*fs,TString*name,
|
|
|
|
expdesc*v){int i;Proto*f=fs->f;for(i=0;i<f->nups;i++){if(fs->upvalues[i].k==v
|
|
|
|
->k&&fs->upvalues[i].info==v->info){lua_assert(fs->f->upvalues[i]==name);
|
|
|
|
return i;}}luaX_checklimit(fs->ls,f->nups+1,MAXUPVALUES,"upvalues");
|
|
|
|
luaM_growvector(fs->L,fs->f->upvalues,f->nups,fs->f->sizeupvalues,TString*,
|
|
|
|
MAX_INT,"");fs->f->upvalues[f->nups]=name;fs->upvalues[f->nups]=*v;return f->
|
|
|
|
nups++;}static int searchvar(FuncState*fs,TString*n){int i;for(i=fs->nactvar-1
|
|
|
|
;i>=0;i--){if(n==getlocvar(fs,i).varname)return i;}return-1;}static void
|
|
|
|
markupval(FuncState*fs,int level){BlockCnt*bl=fs->bl;while(bl&&bl->nactvar>
|
|
|
|
level)bl=bl->previous;if(bl)bl->upval=1;}static void singlevaraux(FuncState*fs
|
|
|
|
,TString*n,expdesc*var,int base){if(fs==NULL)init_exp(var,VGLOBAL,NO_REG);else
|
|
|
|
{int v=searchvar(fs,n);if(v>=0){init_exp(var,VLOCAL,v);if(!base)markupval(fs,v
|
|
|
|
);}else{singlevaraux(fs->prev,n,var,0);if(var->k==VGLOBAL){if(base)var->info=
|
|
|
|
luaK_stringK(fs,n);}else{var->info=indexupvalue(fs,n,var);var->k=VUPVAL;}}}}
|
|
|
|
static TString*singlevar(LexState*ls,expdesc*var,int base){TString*varname=
|
|
|
|
str_checkname(ls);singlevaraux(ls->fs,varname,var,base);return varname;}static
|
|
|
|
void adjust_assign(LexState*ls,int nvars,int nexps,expdesc*e){FuncState*fs=ls
|
|
|
|
->fs;int extra=nvars-nexps;if(e->k==VCALL){extra++;if(extra<=0)extra=0;else
|
|
|
|
luaK_reserveregs(fs,extra-1);luaK_setcallreturns(fs,e,extra);}else{if(e->k!=
|
|
|
|
VVOID)luaK_exp2nextreg(fs,e);if(extra>0){int reg=fs->freereg;luaK_reserveregs(
|
|
|
|
fs,extra);luaK_nil(fs,reg,extra);}}}static void code_params(LexState*ls,int
|
|
|
|
nparams,int dots){FuncState*fs=ls->fs;adjustlocalvars(ls,nparams);
|
|
|
|
luaX_checklimit(ls,fs->nactvar,MAXPARAMS,"parameters");fs->f->numparams=cast(
|
|
|
|
lu_byte,fs->nactvar);fs->f->is_vararg=cast(lu_byte,dots);if(dots)create_local(
|
|
|
|
ls,"arg");luaK_reserveregs(fs,fs->nactvar);}static void enterblock(FuncState*
|
|
|
|
fs,BlockCnt*bl,int isbreakable){bl->breaklist=NO_JUMP;bl->isbreakable=
|
|
|
|
isbreakable;bl->nactvar=fs->nactvar;bl->upval=0;bl->previous=fs->bl;fs->bl=bl;
|
|
|
|
lua_assert(fs->freereg==fs->nactvar);}static void leaveblock(FuncState*fs){
|
|
|
|
BlockCnt*bl=fs->bl;fs->bl=bl->previous;removevars(fs->ls,bl->nactvar);if(bl->
|
|
|
|
upval)luaK_codeABC(fs,OP_CLOSE,bl->nactvar,0,0);lua_assert(bl->nactvar==fs->
|
|
|
|
nactvar);fs->freereg=fs->nactvar;luaK_patchtohere(fs,bl->breaklist);}static
|
|
|
|
void pushclosure(LexState*ls,FuncState*func,expdesc*v){FuncState*fs=ls->fs;
|
|
|
|
Proto*f=fs->f;int i;luaM_growvector(ls->L,f->p,fs->np,f->sizep,Proto*,
|
|
|
|
MAXARG_Bx,"constant table overflow");f->p[fs->np++]=func->f;init_exp(v,
|
|
|
|
VRELOCABLE,luaK_codeABx(fs,OP_CLOSURE,0,fs->np-1));for(i=0;i<func->f->nups;i++
|
|
|
|
){OpCode o=(func->upvalues[i].k==VLOCAL)?OP_MOVE:OP_GETUPVAL;luaK_codeABC(fs,o
|
|
|
|
,0,func->upvalues[i].info,0);}}static void open_func(LexState*ls,FuncState*fs)
|
|
|
|
{Proto*f=luaF_newproto(ls->L);fs->f=f;fs->prev=ls->fs;fs->ls=ls;fs->L=ls->L;ls
|
|
|
|
->fs=fs;fs->pc=0;fs->lasttarget=0;fs->jpc=NO_JUMP;fs->freereg=0;fs->nk=0;fs->h
|
|
|
|
=luaH_new(ls->L,0,0);fs->np=0;fs->nlocvars=0;fs->nactvar=0;fs->bl=NULL;f->
|
|
|
|
source=ls->source;f->maxstacksize=2;}static void close_func(LexState*ls){
|
|
|
|
lua_State*L=ls->L;FuncState*fs=ls->fs;Proto*f=fs->f;removevars(ls,0);
|
|
|
|
luaK_codeABC(fs,OP_RETURN,0,1,0);luaM_reallocvector(L,f->code,f->sizecode,fs->
|
|
|
|
pc,Instruction);f->sizecode=fs->pc;luaM_reallocvector(L,f->lineinfo,f->
|
|
|
|
sizelineinfo,fs->pc,int);f->sizelineinfo=fs->pc;luaM_reallocvector(L,f->k,f->
|
|
|
|
sizek,fs->nk,TObject);f->sizek=fs->nk;luaM_reallocvector(L,f->p,f->sizep,fs->
|
|
|
|
np,Proto*);f->sizep=fs->np;luaM_reallocvector(L,f->locvars,f->sizelocvars,fs->
|
|
|
|
nlocvars,LocVar);f->sizelocvars=fs->nlocvars;luaM_reallocvector(L,f->upvalues,
|
|
|
|
f->sizeupvalues,f->nups,TString*);f->sizeupvalues=f->nups;lua_assert(
|
|
|
|
luaG_checkcode(f));lua_assert(fs->bl==NULL);ls->fs=fs->prev;}Proto*luaY_parser
|
|
|
|
(lua_State*L,ZIO*z,Mbuffer*buff){struct LexState lexstate;struct FuncState
|
|
|
|
funcstate;lexstate.buff=buff;lexstate.nestlevel=0;luaX_setinput(L,&lexstate,z,
|
|
|
|
luaS_new(L,zname(z)));open_func(&lexstate,&funcstate);next(&lexstate);chunk(&
|
|
|
|
lexstate);check_condition(&lexstate,(lexstate.t.token==TK_EOS),
|
|
|
|
"<eof> expected");close_func(&lexstate);lua_assert(funcstate.prev==NULL);
|
|
|
|
lua_assert(funcstate.f->nups==0);lua_assert(lexstate.nestlevel==0);return
|
|
|
|
funcstate.f;}static void luaY_field(LexState*ls,expdesc*v){FuncState*fs=ls->fs
|
|
|
|
;expdesc key;luaK_exp2anyreg(fs,v);next(ls);checkname(ls,&key);luaK_indexed(fs
|
|
|
|
,v,&key);}static void luaY_index(LexState*ls,expdesc*v){next(ls);expr(ls,v);
|
|
|
|
luaK_exp2val(ls->fs,v);check(ls,']');}struct ConsControl{expdesc v;expdesc*t;
|
|
|
|
int nh;int na;int tostore;};static void recfield(LexState*ls,struct
|
|
|
|
ConsControl*cc){FuncState*fs=ls->fs;int reg=ls->fs->freereg;expdesc key,val;if
|
|
|
|
(ls->t.token==TK_NAME){luaX_checklimit(ls,cc->nh,MAX_INT,
|
|
|
|
"items in a constructor");cc->nh++;checkname(ls,&key);}else luaY_index(ls,&key
|
|
|
|
);check(ls,'=');luaK_exp2RK(fs,&key);expr(ls,&val);luaK_codeABC(fs,OP_SETTABLE
|
|
|
|
,cc->t->info,luaK_exp2RK(fs,&key),luaK_exp2RK(fs,&val));fs->freereg=reg;}
|
|
|
|
static void closelistfield(FuncState*fs,struct ConsControl*cc){if(cc->v.k==
|
|
|
|
VVOID)return;luaK_exp2nextreg(fs,&cc->v);cc->v.k=VVOID;if(cc->tostore==
|
|
|
|
LFIELDS_PER_FLUSH){luaK_codeABx(fs,OP_SETLIST,cc->t->info,cc->na-1);cc->
|
|
|
|
tostore=0;fs->freereg=cc->t->info+1;}}static void lastlistfield(FuncState*fs,
|
|
|
|
struct ConsControl*cc){if(cc->tostore==0)return;if(cc->v.k==VCALL){
|
|
|
|
luaK_setcallreturns(fs,&cc->v,LUA_MULTRET);luaK_codeABx(fs,OP_SETLISTO,cc->t->
|
|
|
|
info,cc->na-1);}else{if(cc->v.k!=VVOID)luaK_exp2nextreg(fs,&cc->v);
|
|
|
|
luaK_codeABx(fs,OP_SETLIST,cc->t->info,cc->na-1);}fs->freereg=cc->t->info+1;}
|
|
|
|
static void listfield(LexState*ls,struct ConsControl*cc){expr(ls,&cc->v);
|
|
|
|
luaX_checklimit(ls,cc->na,MAXARG_Bx,"items in a constructor");cc->na++;cc->
|
|
|
|
tostore++;}static void constructor(LexState*ls,expdesc*t){FuncState*fs=ls->fs;
|
|
|
|
int line=ls->linenumber;int pc=luaK_codeABC(fs,OP_NEWTABLE,0,0,0);struct
|
|
|
|
ConsControl cc;cc.na=cc.nh=cc.tostore=0;cc.t=t;init_exp(t,VRELOCABLE,pc);
|
|
|
|
init_exp(&cc.v,VVOID,0);luaK_exp2nextreg(ls->fs,t);check(ls,'{');do{lua_assert
|
|
|
|
(cc.v.k==VVOID||cc.tostore>0);testnext(ls,';');if(ls->t.token=='}')break;
|
|
|
|
closelistfield(fs,&cc);switch(ls->t.token){case TK_NAME:{lookahead(ls);if(ls->
|
|
|
|
lookahead.token!='=')listfield(ls,&cc);else recfield(ls,&cc);break;}case'[':{
|
|
|
|
recfield(ls,&cc);break;}default:{listfield(ls,&cc);break;}}}while(testnext(ls,
|
|
|
|
',')||testnext(ls,';'));check_match(ls,'}','{',line);lastlistfield(fs,&cc);
|
|
|
|
SETARG_B(fs->f->code[pc],luaO_int2fb(cc.na));SETARG_C(fs->f->code[pc],
|
|
|
|
luaO_log2(cc.nh)+1);}static void parlist(LexState*ls){int nparams=0;int dots=0
|
|
|
|
;if(ls->t.token!=')'){do{switch(ls->t.token){case TK_DOTS:dots=1;next(ls);
|
|
|
|
break;case TK_NAME:new_localvar(ls,str_checkname(ls),nparams++);break;default:
|
|
|
|
luaX_syntaxerror(ls,"<name> or `...' expected");}}while(!dots&&testnext(ls,','
|
|
|
|
));}code_params(ls,nparams,dots);}static void body(LexState*ls,expdesc*e,int
|
|
|
|
needself,int line){FuncState new_fs;open_func(ls,&new_fs);new_fs.f->
|
|
|
|
lineDefined=line;check(ls,'(');if(needself)create_local(ls,"self");parlist(ls)
|
|
|
|
;check(ls,')');chunk(ls);check_match(ls,TK_END,TK_FUNCTION,line);close_func(ls
|
|
|
|
);pushclosure(ls,&new_fs,e);}static int explist1(LexState*ls,expdesc*v){int n=
|
|
|
|
1;expr(ls,v);while(testnext(ls,',')){luaK_exp2nextreg(ls->fs,v);expr(ls,v);n++
|
|
|
|
;}return n;}static void funcargs(LexState*ls,expdesc*f){FuncState*fs=ls->fs;
|
|
|
|
expdesc args;int base,nparams;int line=ls->linenumber;switch(ls->t.token){case
|
|
|
|
'(':{if(line!=ls->lastline)luaX_syntaxerror(ls,
|
|
|
|
"ambiguous syntax (function call x new statement)");next(ls);if(ls->t.token==
|
|
|
|
')')args.k=VVOID;else{explist1(ls,&args);luaK_setcallreturns(fs,&args,
|
|
|
|
LUA_MULTRET);}check_match(ls,')','(',line);break;}case'{':{constructor(ls,&
|
|
|
|
args);break;}case TK_STRING:{codestring(ls,&args,ls->t.seminfo.ts);next(ls);
|
|
|
|
break;}default:{luaX_syntaxerror(ls,"function arguments expected");return;}}
|
|
|
|
lua_assert(f->k==VNONRELOC);base=f->info;if(args.k==VCALL)nparams=LUA_MULTRET;
|
|
|
|
else{if(args.k!=VVOID)luaK_exp2nextreg(fs,&args);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;}static void prefixexp(LexState*ls,expdesc*v){switch(
|
|
|
|
ls->t.token){case'(':{int line=ls->linenumber;next(ls);expr(ls,v);check_match(
|
|
|
|
ls,')','(',line);luaK_dischargevars(ls->fs,v);return;}case TK_NAME:{singlevar(
|
|
|
|
ls,v,1);return;}
|
|
|
|
#ifdef LUA_COMPATUPSYNTAX
|
|
|
|
case'%':{TString*varname;int line=ls->linenumber;next(ls);varname=singlevar(ls
|
|
|
|
,v,1);if(v->k!=VUPVAL)luaX_errorline(ls,"global upvalues are obsolete",getstr(
|
|
|
|
varname),line);return;}
|
|
|
|
#endif
|
|
|
|
default:{luaX_syntaxerror(ls,"unexpected symbol");return;}}}static void
|
|
|
|
primaryexp(LexState*ls,expdesc*v){FuncState*fs=ls->fs;prefixexp(ls,v);for(;;){
|
|
|
|
switch(ls->t.token){case'.':{luaY_field(ls,v);break;}case'[':{expdesc key;
|
|
|
|
luaK_exp2anyreg(fs,v);luaY_index(ls,&key);luaK_indexed(fs,v,&key);break;}case
|
|
|
|
':':{expdesc key;next(ls);checkname(ls,&key);luaK_self(fs,v,&key);funcargs(ls,
|
|
|
|
v);break;}case'(':case TK_STRING:case'{':{luaK_exp2nextreg(fs,v);funcargs(ls,v
|
|
|
|
);break;}default:return;}}}static void simpleexp(LexState*ls,expdesc*v){switch
|
|
|
|
(ls->t.token){case TK_NUMBER:{init_exp(v,VK,luaK_numberK(ls->fs,ls->t.seminfo.
|
|
|
|
r));next(ls);break;}case TK_STRING:{codestring(ls,v,ls->t.seminfo.ts);next(ls)
|
|
|
|
;break;}case TK_NIL:{init_exp(v,VNIL,0);next(ls);break;}case TK_TRUE:{init_exp
|
|
|
|
(v,VTRUE,0);next(ls);break;}case TK_FALSE:{init_exp(v,VFALSE,0);next(ls);break
|
|
|
|
;}case'{':{constructor(ls,v);break;}case TK_FUNCTION:{next(ls);body(ls,v,0,ls
|
|
|
|
->linenumber);break;}default:{primaryexp(ls,v);break;}}}static UnOpr getunopr(
|
|
|
|
int op){switch(op){case TK_NOT:return OPR_NOT;case'-':return OPR_MINUS;default
|
|
|
|
:return OPR_NOUNOPR;}}static BinOpr getbinopr(int op){switch(op){case'+':
|
|
|
|
return OPR_ADD;case'-':return OPR_SUB;case'*':return OPR_MULT;case'/':return
|
|
|
|
OPR_DIV;case'^':return OPR_POW;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;}}static const
|
|
|
|
struct{lu_byte left;lu_byte right;}priority[]={{6,6},{6,6},{7,7},{7,7},{10,9},
|
|
|
|
{5,4},{3,3},{3,3},{3,3},{3,3},{3,3},{3,3},{2,2},{1,1}};
|
|
|
|
#define UNARY_PRIORITY 8
|
|
|
|
static BinOpr subexpr(LexState*ls,expdesc*v,int limit){BinOpr op;UnOpr uop;
|
|
|
|
enterlevel(ls);uop=getunopr(ls->t.token);if(uop!=OPR_NOUNOPR){next(ls);subexpr
|
|
|
|
(ls,v,UNARY_PRIORITY);luaK_prefix(ls->fs,uop,v);}else simpleexp(ls,v);op=
|
|
|
|
getbinopr(ls->t.token);while(op!=OPR_NOBINOPR&&cast(int,priority[op].left)>
|
|
|
|
limit){expdesc v2;BinOpr nextop;next(ls);luaK_infix(ls->fs,op,v);nextop=
|
|
|
|
subexpr(ls,&v2,cast(int,priority[op].right));luaK_posfix(ls->fs,op,v,&v2);op=
|
|
|
|
nextop;}leavelevel(ls);return op;}static void expr(LexState*ls,expdesc*v){
|
|
|
|
subexpr(ls,v,-1);}static int block_follow(int token){switch(token){case
|
|
|
|
TK_ELSE:case TK_ELSEIF:case TK_END:case TK_UNTIL:case TK_EOS:return 1;default:
|
|
|
|
return 0;}}static void block(LexState*ls){FuncState*fs=ls->fs;BlockCnt bl;
|
|
|
|
enterblock(fs,&bl,0);chunk(ls);lua_assert(bl.breaklist==NO_JUMP);leaveblock(fs
|
|
|
|
);}struct LHS_assign{struct LHS_assign*prev;expdesc v;};static void
|
|
|
|
check_conflict(LexState*ls,struct LHS_assign*lh,expdesc*v){FuncState*fs=ls->fs
|
|
|
|
;int extra=fs->freereg;int conflict=0;for(;lh;lh=lh->prev){if(lh->v.k==
|
|
|
|
VINDEXED){if(lh->v.info==v->info){conflict=1;lh->v.info=extra;}if(lh->v.aux==v
|
|
|
|
->info){conflict=1;lh->v.aux=extra;}}}if(conflict){luaK_codeABC(fs,OP_MOVE,fs
|
|
|
|
->freereg,v->info,0);luaK_reserveregs(fs,1);}}static void assignment(LexState*
|
|
|
|
ls,struct LHS_assign*lh,int nvars){expdesc e;check_condition(ls,VLOCAL<=lh->v.
|
|
|
|
k&&lh->v.k<=VINDEXED,"syntax error");if(testnext(ls,',')){struct LHS_assign nv
|
|
|
|
;nv.prev=lh;primaryexp(ls,&nv.v);if(nv.v.k==VLOCAL)check_conflict(ls,lh,&nv.v)
|
|
|
|
;assignment(ls,&nv,nvars+1);}else{int nexps;check(ls,'=');nexps=explist1(ls,&e
|
|
|
|
);if(nexps!=nvars){adjust_assign(ls,nvars,nexps,&e);if(nexps>nvars)ls->fs->
|
|
|
|
freereg-=nexps-nvars;}else{luaK_setcallreturns(ls->fs,&e,1);luaK_storevar(ls->
|
|
|
|
fs,&lh->v,&e);return;}}init_exp(&e,VNONRELOC,ls->fs->freereg-1);luaK_storevar(
|
|
|
|
ls->fs,&lh->v,&e);}static void cond(LexState*ls,expdesc*v){expr(ls,v);if(v->k
|
|
|
|
==VNIL)v->k=VFALSE;luaK_goiftrue(ls->fs,v);luaK_patchtohere(ls->fs,v->t);}
|
|
|
|
#ifndef MAXEXPWHILE
|
|
|
|
#define MAXEXPWHILE 100
|
|
|
|
#endif
|
|
|
|
#define EXTRAEXP 5
|
|
|
|
static void whilestat(LexState*ls,int line){Instruction codeexp[MAXEXPWHILE+
|
|
|
|
EXTRAEXP];int lineexp;int i;int sizeexp;FuncState*fs=ls->fs;int whileinit,
|
|
|
|
blockinit,expinit;expdesc v;BlockCnt bl;next(ls);whileinit=luaK_jump(fs);
|
|
|
|
expinit=luaK_getlabel(fs);expr(ls,&v);if(v.k==VK)v.k=VTRUE;lineexp=ls->
|
|
|
|
linenumber;luaK_goiffalse(fs,&v);luaK_concat(fs,&v.f,fs->jpc);fs->jpc=NO_JUMP;
|
|
|
|
sizeexp=fs->pc-expinit;if(sizeexp>MAXEXPWHILE)luaX_syntaxerror(ls,
|
|
|
|
"`while' condition too complex");for(i=0;i<sizeexp;i++)codeexp[i]=fs->f->code[
|
|
|
|
expinit+i];fs->pc=expinit;enterblock(fs,&bl,1);check(ls,TK_DO);blockinit=
|
|
|
|
luaK_getlabel(fs);block(ls);luaK_patchtohere(fs,whileinit);if(v.t!=NO_JUMP)v.t
|
|
|
|
+=fs->pc-expinit;if(v.f!=NO_JUMP)v.f+=fs->pc-expinit;for(i=0;i<sizeexp;i++)
|
|
|
|
luaK_code(fs,codeexp[i],lineexp);check_match(ls,TK_END,TK_WHILE,line);
|
|
|
|
leaveblock(fs);luaK_patchlist(fs,v.t,blockinit);luaK_patchtohere(fs,v.f);}
|
|
|
|
static void repeatstat(LexState*ls,int line){FuncState*fs=ls->fs;int
|
|
|
|
repeat_init=luaK_getlabel(fs);expdesc v;BlockCnt bl;enterblock(fs,&bl,1);next(
|
|
|
|
ls);block(ls);check_match(ls,TK_UNTIL,TK_REPEAT,line);cond(ls,&v);
|
|
|
|
luaK_patchlist(fs,v.f,repeat_init);leaveblock(fs);}static int exp1(LexState*ls
|
|
|
|
){expdesc e;int k;expr(ls,&e);k=e.k;luaK_exp2nextreg(ls->fs,&e);return k;}
|
|
|
|
static void forbody(LexState*ls,int base,int line,int nvars,int isnum){
|
|
|
|
BlockCnt bl;FuncState*fs=ls->fs;int prep,endfor;adjustlocalvars(ls,nvars);
|
|
|
|
check(ls,TK_DO);enterblock(fs,&bl,1);prep=luaK_getlabel(fs);block(ls);
|
|
|
|
luaK_patchtohere(fs,prep-1);endfor=(isnum)?luaK_codeAsBx(fs,OP_FORLOOP,base,
|
|
|
|
NO_JUMP):luaK_codeABC(fs,OP_TFORLOOP,base,0,nvars-3);luaK_fixline(fs,line);
|
|
|
|
luaK_patchlist(fs,(isnum)?endfor:luaK_jump(fs),prep);leaveblock(fs);}static
|
|
|
|
void fornum(LexState*ls,TString*varname,int line){FuncState*fs=ls->fs;int base
|
|
|
|
=fs->freereg;new_localvar(ls,varname,0);new_localvarstr(ls,"(for limit)",1);
|
|
|
|
new_localvarstr(ls,"(for step)",2);check(ls,'=');exp1(ls);check(ls,',');exp1(
|
|
|
|
ls);if(testnext(ls,','))exp1(ls);else{luaK_codeABx(fs,OP_LOADK,fs->freereg,
|
|
|
|
luaK_numberK(fs,1));luaK_reserveregs(fs,1);}luaK_codeABC(fs,OP_SUB,fs->freereg
|
|
|
|
-3,fs->freereg-3,fs->freereg-1);luaK_jump(fs);forbody(ls,base,line,3,1);}
|
|
|
|
static void forlist(LexState*ls,TString*indexname){FuncState*fs=ls->fs;expdesc
|
|
|
|
e;int nvars=0;int line;int base=fs->freereg;new_localvarstr(ls,
|
|
|
|
"(for generator)",nvars++);new_localvarstr(ls,"(for state)",nvars++);
|
|
|
|
new_localvar(ls,indexname,nvars++);while(testnext(ls,','))new_localvar(ls,
|
|
|
|
str_checkname(ls),nvars++);check(ls,TK_IN);line=ls->linenumber;adjust_assign(
|
|
|
|
ls,nvars,explist1(ls,&e),&e);luaK_checkstack(fs,3);luaK_codeAsBx(fs,
|
|
|
|
OP_TFORPREP,base,NO_JUMP);forbody(ls,base,line,nvars,0);}static void forstat(
|
|
|
|
LexState*ls,int line){FuncState*fs=ls->fs;TString*varname;BlockCnt bl;
|
|
|
|
enterblock(fs,&bl,0);next(ls);varname=str_checkname(ls);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);}static void test_then_block(LexState*ls,
|
|
|
|
expdesc*v){next(ls);cond(ls,v);check(ls,TK_THEN);block(ls);}static void ifstat
|
|
|
|
(LexState*ls,int line){FuncState*fs=ls->fs;expdesc v;int escapelist=NO_JUMP;
|
|
|
|
test_then_block(ls,&v);while(ls->t.token==TK_ELSEIF){luaK_concat(fs,&
|
|
|
|
escapelist,luaK_jump(fs));luaK_patchtohere(fs,v.f);test_then_block(ls,&v);}if(
|
|
|
|
ls->t.token==TK_ELSE){luaK_concat(fs,&escapelist,luaK_jump(fs));
|
|
|
|
luaK_patchtohere(fs,v.f);next(ls);block(ls);}else luaK_concat(fs,&escapelist,v
|
|
|
|
.f);luaK_patchtohere(fs,escapelist);check_match(ls,TK_END,TK_IF,line);}static
|
|
|
|
void localfunc(LexState*ls){expdesc v,b;FuncState*fs=ls->fs;new_localvar(ls,
|
|
|
|
str_checkname(ls),0);init_exp(&v,VLOCAL,fs->freereg);luaK_reserveregs(fs,1);
|
|
|
|
adjustlocalvars(ls,1);body(ls,&b,0,ls->linenumber);luaK_storevar(fs,&v,&b);
|
|
|
|
getlocvar(fs,fs->nactvar-1).startpc=fs->pc;}static void localstat(LexState*ls)
|
|
|
|
{int nvars=0;int nexps;expdesc e;do{new_localvar(ls,str_checkname(ls),nvars++)
|
|
|
|
;}while(testnext(ls,','));if(testnext(ls,'='))nexps=explist1(ls,&e);else{e.k=
|
|
|
|
VVOID;nexps=0;}adjust_assign(ls,nvars,nexps,&e);adjustlocalvars(ls,nvars);}
|
|
|
|
static int funcname(LexState*ls,expdesc*v){int needself=0;singlevar(ls,v,1);
|
|
|
|
while(ls->t.token=='.')luaY_field(ls,v);if(ls->t.token==':'){needself=1;
|
|
|
|
luaY_field(ls,v);}return needself;}static void funcstat(LexState*ls,int line){
|
|
|
|
int needself;expdesc v,b;next(ls);needself=funcname(ls,&v);body(ls,&b,needself
|
|
|
|
,line);luaK_storevar(ls->fs,&v,&b);luaK_fixline(ls->fs,line);}static void
|
|
|
|
exprstat(LexState*ls){FuncState*fs=ls->fs;struct LHS_assign v;primaryexp(ls,&v
|
|
|
|
.v);if(v.v.k==VCALL){luaK_setcallreturns(fs,&v.v,0);}else{v.prev=NULL;
|
|
|
|
assignment(ls,&v,1);}}static void retstat(LexState*ls){FuncState*fs=ls->fs;
|
|
|
|
expdesc e;int first,nret;next(ls);if(block_follow(ls->t.token)||ls->t.token==
|
|
|
|
';')first=nret=0;else{nret=explist1(ls,&e);if(e.k==VCALL){luaK_setcallreturns(
|
|
|
|
fs,&e,LUA_MULTRET);if(nret==1){SET_OPCODE(getcode(fs,&e),OP_TAILCALL);
|
|
|
|
lua_assert(GETARG_A(getcode(fs,&e))==fs->nactvar);}first=fs->nactvar;nret=
|
|
|
|
LUA_MULTRET;}else{if(nret==1)first=luaK_exp2anyreg(fs,&e);else{
|
|
|
|
luaK_exp2nextreg(fs,&e);first=fs->nactvar;lua_assert(nret==fs->freereg-first);
|
|
|
|
}}}luaK_codeABC(fs,OP_RETURN,first,nret+1,0);}static void breakstat(LexState*
|
|
|
|
ls){FuncState*fs=ls->fs;BlockCnt*bl=fs->bl;int upval=0;next(ls);while(bl&&!bl
|
|
|
|
->isbreakable){upval|=bl->upval;bl=bl->previous;}if(!bl)luaX_syntaxerror(ls,
|
|
|
|
"no loop to break");if(upval)luaK_codeABC(fs,OP_CLOSE,bl->nactvar,0,0);
|
|
|
|
luaK_concat(fs,&bl->breaklist,luaK_jump(fs));}static int statement(LexState*ls
|
|
|
|
){int line=ls->linenumber;switch(ls->t.token){case TK_IF:{ifstat(ls,line);
|
|
|
|
return 0;}case TK_WHILE:{whilestat(ls,line);return 0;}case TK_DO:{next(ls);
|
|
|
|
block(ls);check_match(ls,TK_END,TK_DO,line);return 0;}case TK_FOR:{forstat(ls,
|
|
|
|
line);return 0;}case TK_REPEAT:{repeatstat(ls,line);return 0;}case TK_FUNCTION
|
|
|
|
:{funcstat(ls,line);return 0;}case TK_LOCAL:{next(ls);if(testnext(ls,
|
|
|
|
TK_FUNCTION))localfunc(ls);else localstat(ls);return 0;}case TK_RETURN:{
|
|
|
|
retstat(ls);return 1;}case TK_BREAK:{breakstat(ls);return 1;}default:{exprstat
|
|
|
|
(ls);return 0;}}}static void chunk(LexState*ls){int islast=0;enterlevel(ls);
|
|
|
|
while(!islast&&!block_follow(ls->t.token)){islast=statement(ls);testnext(ls,
|
|
|
|
';');lua_assert(ls->fs->freereg>=ls->fs->nactvar);ls->fs->freereg=ls->fs->
|
|
|
|
nactvar;}leavelevel(ls);}
|
|
|
|
#line 1 "lposix.c"
|
|
|
|
#define MYNAME "posix"
|
|
|
|
#define MYVERSION MYNAME" library for "LUA_VERSION" / Nov 2003"
|
|
|
|
#ifndef MYBUFSIZ
|
|
|
|
#define MYBUFSIZ 512
|
|
|
|
#endif
|
|
|
|
#line 1 "modemuncher.h"
|
|
|
|
struct modeLookup{char rwx;mode_t bits;};typedef struct modeLookup modeLookup;
|
|
|
|
static modeLookup modesel[]={{'r',S_IRUSR},{'w',S_IWUSR},{'x',S_IXUSR},{'r',
|
|
|
|
S_IRGRP},{'w',S_IWGRP},{'x',S_IXGRP},{'r',S_IROTH},{'w',S_IWOTH},{'x',S_IXOTH}
|
|
|
|
,{(char)NULL,(mode_t)-1}};static int rwxrwxrwx(mode_t*mode,const char*p){int
|
|
|
|
count;mode_t tmp_mode=*mode;tmp_mode&=~(S_ISUID|S_ISGID);for(count=0;count<9;
|
|
|
|
count++){if(*p==modesel[count].rwx)tmp_mode|=modesel[count].bits;else if(*p==
|
|
|
|
'-')tmp_mode&=~modesel[count].bits;else if(*p=='s')switch(count){case 2:
|
|
|
|
tmp_mode|=S_ISUID|S_IXUSR;break;case 5:tmp_mode|=S_ISGID|S_IXGRP;break;default
|
|
|
|
:return-4;break;}p++;}*mode=tmp_mode;return 0;}static void modechopper(mode_t
|
|
|
|
mode,char*p){int count;char*pp;pp=p;for(count=0;count<9;count++){if(mode&
|
|
|
|
modesel[count].bits)*p=modesel[count].rwx;else*p='-';p++;}*p=0;if(mode&S_ISUID
|
|
|
|
)pp[2]=(mode&S_IXUSR)?'s':'S';if(mode&S_ISGID)pp[5]=(mode&S_IXGRP)?'s':'S';}
|
|
|
|
static int mode_munch(mode_t*mode,const char*p){char op=0;mode_t affected_bits
|
|
|
|
,ch_mode;int doneFlag=0;
|
|
|
|
#ifdef DEBUG
|
|
|
|
char tmp[10];
|
|
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
|
|
modechopper(*mode,tmp);printf("modemuncher: got base mode = %s\n",tmp);
|
|
|
|
#endif
|
|
|
|
while(!doneFlag){affected_bits=0;ch_mode=0;
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("modemuncher step 1\n");
|
|
|
|
#endif
|
|
|
|
if(*p=='r'||*p=='-')return rwxrwxrwx(mode,p);for(;;p++)switch(*p){case'u':
|
|
|
|
affected_bits|=04700;break;case'g':affected_bits|=02070;break;case'o':
|
|
|
|
affected_bits|=01007;break;case'a':affected_bits|=07777;break;case' ':break;
|
|
|
|
default:goto no_more_affected;}no_more_affected:if(affected_bits==0)
|
|
|
|
affected_bits=07777;
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("modemuncher step 2 (*p='%c')\n",*p);
|
|
|
|
#endif
|
|
|
|
switch(*p){case'+':case'-':case'=':op=*p;break;case' ':break;default:return-1;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("modemuncher step 3\n");
|
|
|
|
#endif
|
|
|
|
for(p++;*p!=0;p++)switch(*p){case'r':ch_mode|=00444;break;case'w':ch_mode|=
|
|
|
|
00222;break;case'x':ch_mode|=00111;break;case's':ch_mode|=06000;break;case' ':
|
|
|
|
break;default:goto specs_done;}specs_done:
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("modemuncher step 4\n");
|
|
|
|
#endif
|
|
|
|
if(*p!=',')doneFlag=1;if(*p!=0&&*p!=' '&&*p!=','){
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("modemuncher: comma error!\n");printf("modemuncher: doneflag = %u\n",
|
|
|
|
doneFlag);
|
|
|
|
#endif
|
|
|
|
return-2;}p++;if(ch_mode)switch(op){case'+':*mode=*mode|=ch_mode&affected_bits
|
|
|
|
;break;case'-':*mode=*mode&=~(ch_mode&affected_bits);break;case'=':*mode=
|
|
|
|
ch_mode&affected_bits;break;default:return-3;}}
|
|
|
|
#ifdef DEBUG
|
|
|
|
modechopper(*mode,tmp);printf("modemuncher: returning mode = %s\n",tmp);
|
|
|
|
#endif
|
|
|
|
return 0;}
|
|
|
|
#line 38 "lposix.c"
|
|
|
|
static const char*filetype(mode_t m){if(S_ISREG(m))return"regular";else if(
|
|
|
|
S_ISLNK(m))return"link";else if(S_ISDIR(m))return"directory";else if(S_ISCHR(m
|
|
|
|
))return"character device";else if(S_ISBLK(m))return"block device";else if(
|
|
|
|
S_ISFIFO(m))return"fifo";
|
|
|
|
#ifdef S_ISSOCK
|
|
|
|
else if(S_ISSOCK(m))return"socket";
|
|
|
|
#endif
|
|
|
|
else return"?";}typedef int(*Selector)(lua_State*L,int i,const void*data);
|
|
|
|
static int doselection(lua_State*L,int i,const char*const S[],Selector F,const
|
|
|
|
void*data){if(lua_isnone(L,i)){lua_newtable(L);for(i=0;S[i]!=NULL;i++){
|
|
|
|
lua_pushstring(L,S[i]);F(L,i,data);lua_settable(L,-3);}return 1;}else{int j=
|
|
|
|
luaL_findstring(luaL_checkstring(L,i),S);if(j==-1)luaL_argerror(L,i,
|
|
|
|
"unknown selector");return F(L,j,data);}}static void storeindex(lua_State*L,
|
|
|
|
int i,const char*value){lua_pushstring(L,value);lua_rawseti(L,-2,i);}static
|
|
|
|
void storestring(lua_State*L,const char*name,const char*value){lua_pushstring(
|
|
|
|
L,name);lua_pushstring(L,value);lua_settable(L,-3);}static void storenumber(
|
|
|
|
lua_State*L,const char*name,lua_Number value){lua_pushstring(L,name);
|
|
|
|
lua_pushnumber(L,value);lua_settable(L,-3);}static int pusherror(lua_State*L,
|
|
|
|
const char*info){lua_pushnil(L);if(info==NULL)lua_pushstring(L,strerror(errno)
|
|
|
|
);else lua_pushfstring(L,"%s: %s",info,strerror(errno));lua_pushnumber(L,errno
|
|
|
|
);return 3;}static int lposix_pushresult(lua_State*L,int i,const char*info){if
|
|
|
|
(i!=-1){lua_pushnumber(L,i);return 1;}else return pusherror(L,info);}static
|
|
|
|
void badoption(lua_State*L,int i,const char*what,int option){luaL_argerror(L,2
|
|
|
|
,lua_pushfstring(L,"unknown %s option `%c'",what,option));}static uid_t
|
|
|
|
mygetuid(lua_State*L,int i){if(lua_isnone(L,i))return-1;else if(lua_isnumber(L
|
|
|
|
,i))return(uid_t)lua_tonumber(L,i);else if(lua_isstring(L,i)){struct passwd*p=
|
|
|
|
getpwnam(lua_tostring(L,i));return(p==NULL)?-1:p->pw_uid;}else return
|
|
|
|
luaL_typerror(L,i,"string or number");}static gid_t mygetgid(lua_State*L,int i
|
|
|
|
){if(lua_isnone(L,i))return-1;else if(lua_isnumber(L,i))return(gid_t)
|
|
|
|
lua_tonumber(L,i);else if(lua_isstring(L,i)){struct group*g=getgrnam(
|
|
|
|
lua_tostring(L,i));return(g==NULL)?-1:g->gr_gid;}else return luaL_typerror(L,i
|
|
|
|
,"string or number");}static int Perrno(lua_State*L){lua_pushstring(L,strerror
|
|
|
|
(errno));lua_pushnumber(L,errno);return 2;}static int Pdir(lua_State*L){const
|
|
|
|
char*path=luaL_optstring(L,1,".");DIR*d=opendir(path);if(d==NULL)return
|
|
|
|
pusherror(L,path);else{int i;struct dirent*entry;lua_newtable(L);for(i=1;(
|
|
|
|
entry=readdir(d))!=NULL;i++)storeindex(L,i,entry->d_name);closedir(d);return 1
|
|
|
|
;}}static int aux_files(lua_State*L){DIR*d=lua_touserdata(L,lua_upvalueindex(1
|
|
|
|
));struct dirent*entry;if(d==NULL)luaL_error(L,"attempt to use closed dir");
|
|
|
|
entry=readdir(d);if(entry==NULL){closedir(d);lua_pushnil(L);lua_replace(L,
|
|
|
|
lua_upvalueindex(1));lua_pushnil(L);}else{lua_pushstring(L,entry->d_name);
|
|
|
|
#if 0
|
|
|
|
#ifdef _DIRENT_HAVE_D_TYPE
|
|
|
|
lua_pushstring(L,filetype(DTTOIF(entry->d_type)));return 2;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}return 1;}static int Pfiles(lua_State*L){const char*path=luaL_optstring(L,1,
|
|
|
|
".");DIR*d=opendir(path);if(d==NULL)return pusherror(L,path);else{
|
|
|
|
lua_pushlightuserdata(L,d);lua_pushcclosure(L,aux_files,1);return 1;}}static
|
|
|
|
int Pgetcwd(lua_State*L){char buf[MYBUFSIZ];if(getcwd(buf,sizeof(buf))==NULL)
|
|
|
|
return pusherror(L,".");else{lua_pushstring(L,buf);return 1;}}static int
|
|
|
|
Pmkdir(lua_State*L){const char*path=luaL_checkstring(L,1);return
|
|
|
|
lposix_pushresult(L,mkdir(path,0777),path);}static int Pchdir(lua_State*L){
|
|
|
|
const char*path=luaL_checkstring(L,1);return lposix_pushresult(L,chdir(path),
|
|
|
|
path);}static int Prmdir(lua_State*L){const char*path=luaL_checkstring(L,1);
|
|
|
|
return lposix_pushresult(L,rmdir(path),path);}static int Punlink(lua_State*L){
|
|
|
|
const char*path=luaL_checkstring(L,1);return lposix_pushresult(L,unlink(path),
|
|
|
|
path);}static int Plink(lua_State*L){const char*oldpath=luaL_checkstring(L,1);
|
|
|
|
const char*newpath=luaL_checkstring(L,2);return lposix_pushresult(L,link(
|
|
|
|
oldpath,newpath),NULL);}static int Psymlink(lua_State*L){const char*oldpath=
|
|
|
|
luaL_checkstring(L,1);const char*newpath=luaL_checkstring(L,2);return
|
|
|
|
lposix_pushresult(L,symlink(oldpath,newpath),NULL);}static int Preadlink(
|
|
|
|
lua_State*L){char buf[MYBUFSIZ];const char*path=luaL_checkstring(L,1);int n=
|
|
|
|
readlink(path,buf,sizeof(buf));if(n==-1)return pusherror(L,path);
|
|
|
|
lua_pushlstring(L,buf,n);return 1;}static int Paccess(lua_State*L){int mode=
|
|
|
|
F_OK;const char*path=luaL_checkstring(L,1);const char*s;for(s=luaL_optstring(L
|
|
|
|
,2,"f");*s!=0;s++)switch(*s){case' ':break;case'r':mode|=R_OK;break;case'w':
|
|
|
|
mode|=W_OK;break;case'x':mode|=X_OK;break;case'f':mode|=F_OK;break;default:
|
|
|
|
badoption(L,2,"mode",*s);break;}return lposix_pushresult(L,access(path,mode),
|
|
|
|
path);}static int Pmkfifo(lua_State*L){const char*path=luaL_checkstring(L,1);
|
|
|
|
return lposix_pushresult(L,mkfifo(path,0777),path);}static int Pexec(lua_State
|
|
|
|
*L){const char*path=luaL_checkstring(L,1);int i,n=lua_gettop(L);char**argv=
|
|
|
|
malloc((n+1)*sizeof(char*));if(argv==NULL)luaL_error(L,"not enough memory");
|
|
|
|
argv[0]=(char*)path;for(i=1;i<n;i++)argv[i]=(char*)luaL_checkstring(L,i+1);
|
|
|
|
argv[i]=NULL;execvp(path,argv);return pusherror(L,path);}static int Pfork(
|
|
|
|
lua_State*L){return lposix_pushresult(L,fork(),NULL);}static int Pwait(
|
|
|
|
lua_State*L){pid_t pid=luaL_optint(L,1,-1);return lposix_pushresult(L,waitpid(
|
|
|
|
pid,NULL,0),NULL);}static int Pkill(lua_State*L){pid_t pid=luaL_checkint(L,1);
|
|
|
|
int sig=luaL_optint(L,2,SIGTERM);return lposix_pushresult(L,kill(pid,sig),NULL
|
|
|
|
);}static int Psleep(lua_State*L){unsigned int seconds=luaL_checkint(L,1);
|
|
|
|
lua_pushnumber(L,sleep(seconds));return 1;}static int Pputenv(lua_State*L){
|
|
|
|
size_t l;const char*s=luaL_checklstring(L,1,&l);char*e=malloc(++l);return
|
|
|
|
lposix_pushresult(L,(e==NULL)?-1:putenv(memcpy(e,s,l)),s);}
|
|
|
|
#ifdef linux
|
|
|
|
static int Psetenv(lua_State*L){const char*name=luaL_checkstring(L,1);const
|
|
|
|
char*value=luaL_checkstring(L,2);int overwrite=lua_isnoneornil(L,3)||
|
|
|
|
lua_toboolean(L,3);return lposix_pushresult(L,setenv(name,value,overwrite),
|
|
|
|
name);}static int Punsetenv(lua_State*L){const char*name=luaL_checkstring(L,1)
|
|
|
|
;unsetenv(name);return 0;}
|
|
|
|
#endif
|
|
|
|
static int Pgetenv(lua_State*L){if(lua_isnone(L,1)){extern char**environ;char*
|
|
|
|
*e;if(*environ==NULL)lua_pushnil(L);else lua_newtable(L);for(e=environ;*e!=
|
|
|
|
NULL;e++){char*s=*e;char*eq=strchr(s,'=');if(eq==NULL){lua_pushstring(L,s);
|
|
|
|
lua_pushboolean(L,0);}else{lua_pushlstring(L,s,eq-s);lua_pushstring(L,eq+1);}
|
|
|
|
lua_settable(L,-3);}}else lua_pushstring(L,getenv(luaL_checkstring(L,1)));
|
|
|
|
return 1;}static int Pumask(lua_State*L){char m[10];mode_t mode;umask(mode=
|
|
|
|
umask(0));mode=(~mode)&0777;if(!lua_isnone(L,1)){if(mode_munch(&mode,
|
|
|
|
luaL_checkstring(L,1))){lua_pushnil(L);return 1;}mode&=0777;umask(~mode);}
|
|
|
|
modechopper(mode,m);lua_pushstring(L,m);return 1;}static int Pchmod(lua_State*
|
|
|
|
L){mode_t mode;struct stat s;const char*path=luaL_checkstring(L,1);const char*
|
|
|
|
modestr=luaL_checkstring(L,2);if(stat(path,&s))return pusherror(L,path);mode=s
|
|
|
|
.st_mode;if(mode_munch(&mode,modestr))luaL_argerror(L,2,"bad mode");return
|
|
|
|
lposix_pushresult(L,chmod(path,mode),path);}static int Pchown(lua_State*L){
|
|
|
|
const char*path=luaL_checkstring(L,1);uid_t uid=mygetuid(L,2);gid_t gid=
|
|
|
|
mygetgid(L,3);return lposix_pushresult(L,chown(path,uid,gid),path);}static int
|
|
|
|
Putime(lua_State*L){struct utimbuf times;time_t currtime=time(NULL);const
|
|
|
|
char*path=luaL_checkstring(L,1);times.modtime=luaL_optnumber(L,2,currtime);
|
|
|
|
times.actime=luaL_optnumber(L,3,currtime);return lposix_pushresult(L,utime(
|
|
|
|
path,×),path);}static int FgetID(lua_State*L,int i,const void*data){
|
|
|
|
switch(i){case 0:lua_pushnumber(L,getegid());break;case 1:lua_pushnumber(L,
|
|
|
|
geteuid());break;case 2:lua_pushnumber(L,getgid());break;case 3:lua_pushnumber
|
|
|
|
(L,getuid());break;case 4:lua_pushnumber(L,getpgrp());break;case 5:
|
|
|
|
lua_pushnumber(L,getpid());break;case 6:lua_pushnumber(L,getppid());break;}
|
|
|
|
return 1;}static const char*const SgetID[]={"egid","euid","gid","uid","pgrp",
|
|
|
|
"pid","ppid",NULL};static int Pgetprocessid(lua_State*L){return doselection(L,
|
|
|
|
1,SgetID,FgetID,NULL);}static int Pttyname(lua_State*L){int fd=luaL_optint(L,1
|
|
|
|
,0);lua_pushstring(L,ttyname(fd));return 1;}static int Pctermid(lua_State*L){
|
|
|
|
char b[L_ctermid];lua_pushstring(L,ctermid(b));return 1;}static int Pgetlogin(
|
|
|
|
lua_State*L){lua_pushstring(L,getlogin());return 1;}static int Fgetpasswd(
|
|
|
|
lua_State*L,int i,const void*data){const struct passwd*p=data;switch(i){case 0
|
|
|
|
:lua_pushstring(L,p->pw_name);break;case 1:lua_pushnumber(L,p->pw_uid);break;
|
|
|
|
case 2:lua_pushnumber(L,p->pw_gid);break;case 3:lua_pushstring(L,p->pw_dir);
|
|
|
|
break;case 4:lua_pushstring(L,p->pw_shell);break;case 5:lua_pushstring(L,p->
|
|
|
|
pw_gecos);break;case 6:lua_pushstring(L,p->pw_passwd);break;}return 1;}static
|
|
|
|
const char*const Sgetpasswd[]={"name","uid","gid","dir","shell","gecos",
|
|
|
|
"passwd",NULL};static int Pgetpasswd(lua_State*L){struct passwd*p=NULL;if(
|
|
|
|
lua_isnoneornil(L,1))p=getpwuid(geteuid());else if(lua_isnumber(L,1))p=
|
|
|
|
getpwuid((uid_t)lua_tonumber(L,1));else if(lua_isstring(L,1))p=getpwnam(
|
|
|
|
lua_tostring(L,1));else luaL_typerror(L,1,"string or number");if(p==NULL)
|
|
|
|
lua_pushnil(L);else doselection(L,2,Sgetpasswd,Fgetpasswd,p);return 1;}static
|
|
|
|
int Pgetgroup(lua_State*L){struct group*g=NULL;if(lua_isnumber(L,1))g=getgrgid
|
|
|
|
((gid_t)lua_tonumber(L,1));else if(lua_isstring(L,1))g=getgrnam(lua_tostring(L
|
|
|
|
,1));else luaL_typerror(L,1,"string or number");if(g==NULL)lua_pushnil(L);else
|
|
|
|
{int i;lua_newtable(L);storestring(L,"name",g->gr_name);storenumber(L,"gid",g
|
|
|
|
->gr_gid);for(i=0;g->gr_mem[i]!=NULL;i++)storeindex(L,i+1,g->gr_mem[i]);}
|
|
|
|
return 1;}static int Psetuid(lua_State*L){return lposix_pushresult(L,setuid(
|
|
|
|
mygetuid(L,1)),NULL);}static int Psetgid(lua_State*L){return lposix_pushresult
|
|
|
|
(L,setgid(mygetgid(L,1)),NULL);}struct mytimes{struct tms t;clock_t elapsed;};
|
|
|
|
#define pushtime(L,x) lua_pushnumber(L,((lua_Number)x)/CLK_TCK)
|
|
|
|
static int Ftimes(lua_State*L,int i,const void*data){const struct mytimes*t=
|
|
|
|
data;switch(i){case 0:pushtime(L,t->t.tms_utime);break;case 1:pushtime(L,t->t.
|
|
|
|
tms_stime);break;case 2:pushtime(L,t->t.tms_cutime);break;case 3:pushtime(L,t
|
|
|
|
->t.tms_cstime);break;case 4:pushtime(L,t->elapsed);break;}return 1;}static
|
|
|
|
const char*const Stimes[]={"utime","stime","cutime","cstime","elapsed",NULL};
|
|
|
|
#define storetime(L,name,x) storenumber(L,name,(lua_Number)x/CLK_TCK)
|
|
|
|
static int Ptimes(lua_State*L){struct mytimes t;t.elapsed=times(&t.t);return
|
|
|
|
doselection(L,1,Stimes,Ftimes,&t);}struct mystat{struct stat s;char mode[10];
|
|
|
|
const char*type;};static int Fstat(lua_State*L,int i,const void*data){const
|
|
|
|
struct mystat*s=data;switch(i){case 0:lua_pushstring(L,s->mode);break;case 1:
|
|
|
|
lua_pushnumber(L,s->s.st_ino);break;case 2:lua_pushnumber(L,s->s.st_dev);break
|
|
|
|
;case 3:lua_pushnumber(L,s->s.st_nlink);break;case 4:lua_pushnumber(L,s->s.
|
|
|
|
st_uid);break;case 5:lua_pushnumber(L,s->s.st_gid);break;case 6:lua_pushnumber
|
|
|
|
(L,s->s.st_size);break;case 7:lua_pushnumber(L,s->s.st_atime);break;case 8:
|
|
|
|
lua_pushnumber(L,s->s.st_mtime);break;case 9:lua_pushnumber(L,s->s.st_ctime);
|
|
|
|
break;case 10:lua_pushstring(L,s->type);break;case 11:lua_pushnumber(L,s->s.
|
|
|
|
st_mode);break;}return 1;}static const char*const Sstat[]={"mode","ino","dev",
|
|
|
|
"nlink","uid","gid","size","atime","mtime","ctime","type","_mode",NULL};static
|
|
|
|
int Pstat(lua_State*L){struct mystat s;const char*path=luaL_checkstring(L,1);
|
|
|
|
if(stat(path,&s.s)==-1)return pusherror(L,path);s.type=filetype(s.s.st_mode);
|
|
|
|
modechopper(s.s.st_mode,s.mode);return doselection(L,2,Sstat,Fstat,&s);}static
|
|
|
|
int Puname(lua_State*L){struct utsname u;luaL_Buffer b;const char*s;if(uname(
|
|
|
|
&u)==-1)return pusherror(L,NULL);luaL_buffinit(L,&b);for(s=luaL_optstring(L,1,
|
|
|
|
"%s %n %r %v %m");*s;s++)if(*s!='%')luaL_putchar(&b,*s);else switch(*++s){case
|
|
|
|
'%':luaL_putchar(&b,*s);break;case'm':luaL_addstring(&b,u.machine);break;case
|
|
|
|
'n':luaL_addstring(&b,u.nodename);break;case'r':luaL_addstring(&b,u.release);
|
|
|
|
break;case's':luaL_addstring(&b,u.sysname);break;case'v':luaL_addstring(&b,u.
|
|
|
|
version);break;default:badoption(L,2,"format",*s);break;}luaL_pushresult(&b);
|
|
|
|
return 1;}static const int Kpathconf[]={_PC_LINK_MAX,_PC_MAX_CANON,
|
|
|
|
_PC_MAX_INPUT,_PC_NAME_MAX,_PC_PATH_MAX,_PC_PIPE_BUF,_PC_CHOWN_RESTRICTED,
|
|
|
|
_PC_NO_TRUNC,_PC_VDISABLE,-1};static int Fpathconf(lua_State*L,int i,const
|
|
|
|
void*data){const char*path=data;lua_pushnumber(L,pathconf(path,Kpathconf[i]));
|
|
|
|
return 1;}static const char*const Spathconf[]={"link_max","max_canon",
|
|
|
|
"max_input","name_max","path_max","pipe_buf","chown_restricted","no_trunc",
|
|
|
|
"vdisable",NULL};static int Ppathconf(lua_State*L){const char*path=
|
|
|
|
luaL_checkstring(L,1);return doselection(L,2,Spathconf,Fpathconf,path);}static
|
|
|
|
const int Ksysconf[]={_SC_ARG_MAX,_SC_CHILD_MAX,_SC_CLK_TCK,_SC_NGROUPS_MAX,
|
|
|
|
_SC_STREAM_MAX,_SC_TZNAME_MAX,_SC_OPEN_MAX,_SC_JOB_CONTROL,_SC_SAVED_IDS,
|
|
|
|
_SC_VERSION,-1};static int Fsysconf(lua_State*L,int i,const void*data){
|
|
|
|
lua_pushnumber(L,sysconf(Ksysconf[i]));return 1;}static const char*const
|
|
|
|
Ssysconf[]={"arg_max","child_max","clk_tck","ngroups_max","stream_max",
|
|
|
|
"tzname_max","open_max","job_control","saved_ids","version",NULL};static int
|
|
|
|
Psysconf(lua_State*L){return doselection(L,1,Ssysconf,Fsysconf,NULL);}static
|
|
|
|
const luaL_reg R[]={{"access",Paccess},{"chdir",Pchdir},{"chmod",Pchmod},{
|
|
|
|
"chown",Pchown},{"ctermid",Pctermid},{"dir",Pdir},{"errno",Perrno},{"exec",
|
|
|
|
Pexec},{"files",Pfiles},{"fork",Pfork},{"getcwd",Pgetcwd},{"getenv",Pgetenv},{
|
|
|
|
"getgroup",Pgetgroup},{"getlogin",Pgetlogin},{"getpasswd",Pgetpasswd},{
|
|
|
|
"getprocessid",Pgetprocessid},{"kill",Pkill},{"link",Plink},{"mkdir",Pmkdir},{
|
|
|
|
"mkfifo",Pmkfifo},{"pathconf",Ppathconf},{"putenv",Pputenv},{"readlink",
|
|
|
|
Preadlink},{"rmdir",Prmdir},{"setgid",Psetgid},{"setuid",Psetuid},{"sleep",
|
|
|
|
Psleep},{"stat",Pstat},{"symlink",Psymlink},{"sysconf",Psysconf},{"times",
|
|
|
|
Ptimes},{"ttyname",Pttyname},{"umask",Pumask},{"uname",Puname},{"unlink",
|
|
|
|
Punlink},{"utime",Putime},{"wait",Pwait},
|
|
|
|
#ifdef linux
|
|
|
|
{"setenv",Psetenv},{"unsetenv",Punsetenv},
|
|
|
|
#endif
|
|
|
|
{NULL,NULL}};LUALIB_API int luaopen_posix(lua_State*L){luaL_openlib(L,MYNAME,R
|
|
|
|
,0);lua_pushliteral(L,"version");lua_pushliteral(L,MYVERSION);lua_settable(L,-
|
|
|
|
3);return 1;}
|
|
|
|
#line 1 "lstate.c"
|
|
|
|
#define lstate_c
|
|
|
|
#ifndef LUA_USERSTATE
|
|
|
|
#define EXTRASPACE 0
|
|
|
|
#else
|
|
|
|
union UEXTRASPACE{L_Umaxalign a;LUA_USERSTATE b;};
|
|
|
|
#define EXTRASPACE (sizeof(union UEXTRASPACE))
|
|
|
|
#endif
|
|
|
|
static int default_panic(lua_State*L){UNUSED(L);return 0;}static lua_State*
|
|
|
|
mallocstate(lua_State*L){lu_byte*block=(lu_byte*)luaM_malloc(L,sizeof(
|
|
|
|
lua_State)+EXTRASPACE);if(block==NULL)return NULL;else{block+=EXTRASPACE;
|
|
|
|
return cast(lua_State*,block);}}static void freestate(lua_State*L,lua_State*L1
|
|
|
|
){luaM_free(L,cast(lu_byte*,L1)-EXTRASPACE,sizeof(lua_State)+EXTRASPACE);}
|
|
|
|
static void stack_init(lua_State*L1,lua_State*L){L1->stack=luaM_newvector(L,
|
|
|
|
BASIC_STACK_SIZE+EXTRA_STACK,TObject);L1->stacksize=BASIC_STACK_SIZE+
|
|
|
|
EXTRA_STACK;L1->top=L1->stack;L1->stack_last=L1->stack+(L1->stacksize-
|
|
|
|
EXTRA_STACK)-1;L1->base_ci=luaM_newvector(L,BASIC_CI_SIZE,CallInfo);L1->ci=L1
|
|
|
|
->base_ci;L1->ci->state=CI_C;setnilvalue(L1->top++);L1->base=L1->ci->base=L1->
|
|
|
|
top;L1->ci->top=L1->top+LUA_MINSTACK;L1->size_ci=BASIC_CI_SIZE;L1->end_ci=L1->
|
|
|
|
base_ci+L1->size_ci;}static void freestack(lua_State*L,lua_State*L1){
|
|
|
|
luaM_freearray(L,L1->base_ci,L1->size_ci,CallInfo);luaM_freearray(L,L1->stack,
|
|
|
|
L1->stacksize,TObject);}static void f_luaopen(lua_State*L,void*ud){
|
|
|
|
global_State*g=luaM_new(NULL,global_State);UNUSED(ud);if(g==NULL)luaD_throw(L,
|
|
|
|
LUA_ERRMEM);L->l_G=g;g->mainthread=L;g->GCthreshold=0;g->strt.size=0;g->strt.
|
|
|
|
nuse=0;g->strt.hash=NULL;setnilvalue(defaultmeta(L));setnilvalue(registry(L));
|
|
|
|
luaZ_initbuffer(L,&g->buff);g->panic=default_panic;g->rootgc=NULL;g->rootudata
|
|
|
|
=NULL;g->tmudata=NULL;setnilvalue(gkey(g->dummynode));setnilvalue(gval(g->
|
|
|
|
dummynode));g->dummynode->next=NULL;g->nblocks=sizeof(lua_State)+sizeof(
|
|
|
|
global_State);stack_init(L,L);defaultmeta(L)->tt=LUA_TTABLE;sethvalue(
|
|
|
|
defaultmeta(L),luaH_new(L,0,0));hvalue(defaultmeta(L))->metatable=hvalue(
|
|
|
|
defaultmeta(L));sethvalue(gt(L),luaH_new(L,0,4));sethvalue(registry(L),
|
|
|
|
luaH_new(L,4,4));luaS_resize(L,MINSTRTABSIZE);luaT_init(L);luaX_init(L);
|
|
|
|
luaS_fix(luaS_newliteral(L,MEMERRMSG));g->GCthreshold=4*G(L)->nblocks;}static
|
|
|
|
void preinit_state(lua_State*L){L->stack=NULL;L->stacksize=0;L->errorJmp=NULL;
|
|
|
|
L->hook=NULL;L->hookmask=L->hookinit=0;L->basehookcount=0;L->allowhook=1;
|
|
|
|
resethookcount(L);L->openupval=NULL;L->size_ci=0;L->nCcalls=0;L->base_ci=L->ci
|
|
|
|
=NULL;L->errfunc=0;setnilvalue(gt(L));}static void close_state(lua_State*L){
|
|
|
|
luaF_close(L,L->stack);if(G(L)){luaC_sweep(L,1);lua_assert(G(L)->rootgc==NULL)
|
|
|
|
;lua_assert(G(L)->rootudata==NULL);luaS_freeall(L);luaZ_freebuffer(L,&G(L)->
|
|
|
|
buff);}freestack(L,L);if(G(L)){lua_assert(G(L)->nblocks==sizeof(lua_State)+
|
|
|
|
sizeof(global_State));luaM_freelem(NULL,G(L));}freestate(NULL,L);}lua_State*
|
|
|
|
luaE_newthread(lua_State*L){lua_State*L1=mallocstate(L);luaC_link(L,valtogco(
|
|
|
|
L1),LUA_TTHREAD);preinit_state(L1);L1->l_G=L->l_G;stack_init(L1,L);setobj2n(gt
|
|
|
|
(L1),gt(L));return L1;}void luaE_freethread(lua_State*L,lua_State*L1){
|
|
|
|
luaF_close(L1,L1->stack);lua_assert(L1->openupval==NULL);freestack(L,L1);
|
|
|
|
freestate(L,L1);}LUA_API lua_State*lua_open(void){lua_State*L=mallocstate(NULL
|
|
|
|
);if(L){L->tt=LUA_TTHREAD;L->marked=0;L->next=L->gclist=NULL;preinit_state(L);
|
|
|
|
L->l_G=NULL;if(luaD_rawrunprotected(L,f_luaopen,NULL)!=0){close_state(L);L=
|
|
|
|
NULL;}}lua_userstateopen(L);return L;}static void callallgcTM(lua_State*L,void
|
|
|
|
*ud){UNUSED(ud);luaC_callGCTM(L);}LUA_API void lua_close(lua_State*L){lua_lock
|
|
|
|
(L);L=G(L)->mainthread;luaF_close(L,L->stack);luaC_separateudata(L);L->errfunc
|
|
|
|
=0;do{L->ci=L->base_ci;L->base=L->top=L->ci->base;L->nCcalls=0;}while(
|
|
|
|
luaD_rawrunprotected(L,callallgcTM,NULL)!=0);lua_assert(G(L)->tmudata==NULL);
|
|
|
|
close_state(L);}
|
|
|
|
#line 1 "lstring.c"
|
|
|
|
#define lstring_c
|
|
|
|
void luaS_freeall(lua_State*L){lua_assert(G(L)->strt.nuse==0);luaM_freearray(L
|
|
|
|
,G(L)->strt.hash,G(L)->strt.size,TString*);}void luaS_resize(lua_State*L,int
|
|
|
|
newsize){GCObject**newhash=luaM_newvector(L,newsize,GCObject*);stringtable*tb=
|
|
|
|
&G(L)->strt;int i;for(i=0;i<newsize;i++)newhash[i]=NULL;for(i=0;i<tb->size;i++
|
|
|
|
){GCObject*p=tb->hash[i];while(p){GCObject*next=p->gch.next;lu_hash h=gcotots(
|
|
|
|
p)->tsv.hash;int h1=lmod(h,newsize);lua_assert(cast(int,h%newsize)==lmod(h,
|
|
|
|
newsize));p->gch.next=newhash[h1];newhash[h1]=p;p=next;}}luaM_freearray(L,tb->
|
|
|
|
hash,tb->size,TString*);tb->size=newsize;tb->hash=newhash;}static TString*
|
|
|
|
newlstr(lua_State*L,const char*str,size_t l,lu_hash h){TString*ts=cast(TString
|
|
|
|
*,luaM_malloc(L,sizestring(l)));stringtable*tb;ts->tsv.len=l;ts->tsv.hash=h;ts
|
|
|
|
->tsv.marked=0;ts->tsv.tt=LUA_TSTRING;ts->tsv.reserved=0;memcpy(ts+1,str,l*
|
|
|
|
sizeof(char));((char*)(ts+1))[l]='\0';tb=&G(L)->strt;h=lmod(h,tb->size);ts->
|
|
|
|
tsv.next=tb->hash[h];tb->hash[h]=valtogco(ts);tb->nuse++;if(tb->nuse>cast(
|
|
|
|
ls_nstr,tb->size)&&tb->size<=MAX_INT/2)luaS_resize(L,tb->size*2);return ts;}
|
|
|
|
TString*luaS_newlstr(lua_State*L,const char*str,size_t l){GCObject*o;lu_hash h
|
|
|
|
=(lu_hash)l;size_t step=(l>>5)+1;size_t l1;for(l1=l;l1>=step;l1-=step)h=h^((h
|
|
|
|
<<5)+(h>>2)+(unsigned char)(str[l1-1]));for(o=G(L)->strt.hash[lmod(h,G(L)->
|
|
|
|
strt.size)];o!=NULL;o=o->gch.next){TString*ts=gcotots(o);if(ts->tsv.len==l&&(
|
|
|
|
memcmp(str,getstr(ts),l)==0))return ts;}return newlstr(L,str,l,h);}Udata*
|
|
|
|
luaS_newudata(lua_State*L,size_t s){Udata*u;u=cast(Udata*,luaM_malloc(L,
|
|
|
|
sizeudata(s)));u->uv.marked=(1<<1);u->uv.tt=LUA_TUSERDATA;u->uv.len=s;u->uv.
|
|
|
|
metatable=hvalue(defaultmeta(L));u->uv.next=G(L)->rootudata;G(L)->rootudata=
|
|
|
|
valtogco(u);return u;}
|
|
|
|
#line 1 "lstrlib.c"
|
|
|
|
#define lstrlib_c
|
|
|
|
#ifndef uchar
|
|
|
|
#define uchar(c) ((unsigned char)(c))
|
|
|
|
#endif
|
|
|
|
typedef long sint32;static int str_len(lua_State*L){size_t l;luaL_checklstring
|
|
|
|
(L,1,&l);lua_pushnumber(L,(lua_Number)l);return 1;}static sint32 posrelat(
|
|
|
|
sint32 pos,size_t len){return(pos>=0)?pos:(sint32)len+pos+1;}static int
|
|
|
|
str_sub(lua_State*L){size_t l;const char*s=luaL_checklstring(L,1,&l);sint32
|
|
|
|
start=posrelat(luaL_checklong(L,2),l);sint32 end=posrelat(luaL_optlong(L,3,-1)
|
|
|
|
,l);if(start<1)start=1;if(end>(sint32)l)end=(sint32)l;if(start<=end)
|
|
|
|
lua_pushlstring(L,s+start-1,end-start+1);else lua_pushliteral(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);luaL_buffinit(L,&b);for(i=0;i<l;i++)luaL_putchar(&b
|
|
|
|
,tolower(uchar(s[i])));luaL_pushresult(&b);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);luaL_buffinit(L,&b);for(i=0;i<l;i++)luaL_putchar(&b,toupper(uchar(s[i]))
|
|
|
|
);luaL_pushresult(&b);return 1;}static int str_rep(lua_State*L){size_t l;
|
|
|
|
luaL_Buffer b;const char*s=luaL_checklstring(L,1,&l);int n=luaL_checkint(L,2);
|
|
|
|
luaL_buffinit(L,&b);while(n-->0)luaL_addlstring(&b,s,l);luaL_pushresult(&b);
|
|
|
|
return 1;}static int str_byte(lua_State*L){size_t l;const char*s=
|
|
|
|
luaL_checklstring(L,1,&l);sint32 pos=posrelat(luaL_optlong(L,2,1),l);if(pos<=0
|
|
|
|
||(size_t)(pos)>l)return 0;lua_pushnumber(L,uchar(s[pos-1]));return 1;}static
|
|
|
|
int str_char(lua_State*L){int n=lua_gettop(L);int i;luaL_Buffer b;
|
|
|
|
luaL_buffinit(L,&b);for(i=1;i<=n;i++){int c=luaL_checkint(L,i);luaL_argcheck(L
|
|
|
|
,uchar(c)==c,i,"invalid value");luaL_putchar(&b,uchar(c));}luaL_pushresult(&b)
|
|
|
|
;return 1;}static int writer(lua_State*L,const void*b,size_t size,void*B){(
|
|
|
|
void)L;luaL_addlstring((luaL_Buffer*)B,(const char*)b,size);return 1;}static
|
|
|
|
int str_dump(lua_State*L){luaL_Buffer b;luaL_checktype(L,1,LUA_TFUNCTION);
|
|
|
|
luaL_buffinit(L,&b);if(!lua_dump(L,writer,&b))luaL_error(L,
|
|
|
|
"unable to dump given function");luaL_pushresult(&b);return 1;}
|
|
|
|
#ifndef MAX_CAPTURES
|
|
|
|
#define MAX_CAPTURES 32
|
|
|
|
#endif
|
|
|
|
#define CAP_UNFINISHED (-1)
|
|
|
|
#define CAP_POSITION (-2)
|
|
|
|
typedef struct MatchState{const char*src_init;const char*src_end;lua_State*L;
|
|
|
|
int level;struct{const char*init;sint32 len;}capture[MAX_CAPTURES];}MatchState
|
|
|
|
;
|
|
|
|
#define ESC '%'
|
|
|
|
#define SPECIALS "^$*+?.([%-"
|
|
|
|
static int check_capture(MatchState*ms,int l){l-='1';if(l<0||l>=ms->level||ms
|
|
|
|
->capture[l].len==CAP_UNFINISHED)return luaL_error(ms->L,
|
|
|
|
"invalid capture index");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*luaI_classend(MatchState*ms,const char*p){switch(*p++){
|
|
|
|
case ESC:{if(*p=='\0')luaL_error(ms->L,"malformed pattern (ends with `%')");
|
|
|
|
return p+1;}case'[':{if(*p=='^')p++;do{if(*p=='\0')luaL_error(ms->L,
|
|
|
|
"malformed pattern (missing `]')");if(*(p++)==ESC&&*p!='\0')p++;}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'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;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++;}while(++p<ec){if(*p==ESC){p++;if(match_class(c,*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 luaI_singlematch(int
|
|
|
|
c,const char*p,const char*ep){switch(*p){case'.':return 1;case ESC:return
|
|
|
|
match_class(c,*(p+1));case'[':return matchbracketclass(c,p,ep-1);default:
|
|
|
|
return(uchar(*p)==c);}}static const char*match(MatchState*ms,const char*s,
|
|
|
|
const char*p);static const char*matchbalance(MatchState*ms,const char*s,const
|
|
|
|
char*p){if(*p==0||*(p+1)==0)luaL_error(ms->L,"unbalanced pattern");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;}static const
|
|
|
|
char*max_expand(MatchState*ms,const char*s,const char*p,const char*ep){sint32
|
|
|
|
i=0;while((s+i)<ms->src_end&&luaI_singlematch(uchar(*(s+i)),p,ep))i++;while(i
|
|
|
|
>=0){const char*res=match(ms,(s+i),ep+1);if(res)return res;i--;}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(s<ms->src_end&&luaI_singlematch(uchar(*s),p,ep))s++;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>=MAX_CAPTURES)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)ms->level--;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;
|
|
|
|
if((res=match(ms,s,p))==NULL)ms->capture[l].len=CAP_UNFINISHED;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){init:switch(*p){case
|
|
|
|
'(':{if(*(p+1)==')')return start_capture(ms,s,p+2,CAP_POSITION);else return
|
|
|
|
start_capture(ms,s,p+1,CAP_UNFINISHED);}case')':{return end_capture(ms,s,p+1);
|
|
|
|
}case ESC:{switch(*(p+1)){case'b':{s=matchbalance(ms,s,p+2);if(s==NULL)return
|
|
|
|
NULL;p+=4;goto init;}case'f':{const char*ep;char previous;p+=2;if(*p!='[')
|
|
|
|
luaL_error(ms->L,"missing `[' after `%%f' in pattern");ep=luaI_classend(ms,p);
|
|
|
|
previous=(s==ms->src_init)?'\0':*(s-1);if(matchbracketclass(uchar(previous),p,
|
|
|
|
ep-1)||!matchbracketclass(uchar(*s),p,ep-1))return NULL;p=ep;goto init;}
|
|
|
|
default:{if(isdigit(uchar(*(p+1)))){s=match_capture(ms,s,*(p+1));if(s==NULL)
|
|
|
|
return NULL;p+=2;goto init;}goto dflt;}}}case'\0':{return s;}case'$':{if(*(p+1
|
|
|
|
)=='\0')return(s==ms->src_end)?s:NULL;else goto dflt;}default:dflt:{const char
|
|
|
|
*ep=luaI_classend(ms,p);int m=s<ms->src_end&&luaI_singlematch(uchar(*s),p,ep);
|
|
|
|
switch(*ep){case'?':{const char*res;if(m&&((res=match(ms,s+1,ep+1))!=NULL))
|
|
|
|
return res;p=ep+1;goto init;}case'*':{return max_expand(ms,s,p,ep);}case'+':{
|
|
|
|
return(m?max_expand(ms,s+1,p,ep):NULL);}case'-':{return min_expand(ms,s,p,ep);
|
|
|
|
}default:{if(!m)return NULL;s++;p=ep;goto init;}}}}}static const char*lmemfind
|
|
|
|
(const char*s1,size_t l1,const char*s2,size_t l2){if(l2==0)return s1;else if(
|
|
|
|
l2>l1)return NULL;else{const char*init;l2--;l1=l1-l2;while(l1>0&&(init=(const
|
|
|
|
char*)memchr(s1,*s2,l1))!=NULL){init++;if(memcmp(init,s2+1,l2)==0)return init-
|
|
|
|
1;else{l1-=init-s1;s1=init;}}return NULL;}}static void push_onecapture(
|
|
|
|
MatchState*ms,int i){int l=ms->capture[i].len;if(l==CAP_UNFINISHED)luaL_error(
|
|
|
|
ms->L,"unfinished capture");if(l==CAP_POSITION)lua_pushnumber(ms->L,(
|
|
|
|
lua_Number)(ms->capture[i].init-ms->src_init+1));else lua_pushlstring(ms->L,ms
|
|
|
|
->capture[i].init,l);}static int push_captures(MatchState*ms,const char*s,
|
|
|
|
const char*e){int i;luaL_checkstack(ms->L,ms->level,"too many captures");if(ms
|
|
|
|
->level==0&&s){lua_pushlstring(ms->L,s,e-s);return 1;}else{for(i=0;i<ms->level
|
|
|
|
;i++)push_onecapture(ms,i);return ms->level;}}static int str_find(lua_State*L)
|
|
|
|
{size_t l1,l2;const char*s=luaL_checklstring(L,1,&l1);const char*p=
|
|
|
|
luaL_checklstring(L,2,&l2);sint32 init=posrelat(luaL_optlong(L,3,1),l1)-1;if(
|
|
|
|
init<0)init=0;else if((size_t)(init)>l1)init=(sint32)l1;if(lua_toboolean(L,4)
|
|
|
|
||strpbrk(p,SPECIALS)==NULL){const char*s2=lmemfind(s+init,l1-init,p,l2);if(s2
|
|
|
|
){lua_pushnumber(L,(lua_Number)(s2-s+1));lua_pushnumber(L,(lua_Number)(s2-s+l2
|
|
|
|
));return 2;}}else{MatchState ms;int anchor=(*p=='^')?(p++,1):0;const char*s1=
|
|
|
|
s+init;ms.L=L;ms.src_init=s;ms.src_end=s+l1;do{const char*res;ms.level=0;if((
|
|
|
|
res=match(&ms,s1,p))!=NULL){lua_pushnumber(L,(lua_Number)(s1-s+1));
|
|
|
|
lua_pushnumber(L,(lua_Number)(res-s));return push_captures(&ms,NULL,0)+2;}}
|
|
|
|
while(s1++<ms.src_end&&!anchor);}lua_pushnil(L);return 1;}static int gfind_aux
|
|
|
|
(lua_State*L){MatchState ms;const char*s=lua_tostring(L,lua_upvalueindex(1));
|
|
|
|
size_t ls=lua_strlen(L,lua_upvalueindex(1));const char*p=lua_tostring(L,
|
|
|
|
lua_upvalueindex(2));const char*src;ms.L=L;ms.src_init=s;ms.src_end=s+ls;for(
|
|
|
|
src=s+(size_t)lua_tonumber(L,lua_upvalueindex(3));src<=ms.src_end;src++){const
|
|
|
|
char*e;ms.level=0;if((e=match(&ms,src,p))!=NULL){int newstart=e-s;if(e==src)
|
|
|
|
newstart++;lua_pushnumber(L,(lua_Number)newstart);lua_replace(L,
|
|
|
|
lua_upvalueindex(3));return push_captures(&ms,src,e);}}return 0;}static int
|
|
|
|
gfind(lua_State*L){luaL_checkstring(L,1);luaL_checkstring(L,2);lua_settop(L,2)
|
|
|
|
;lua_pushnumber(L,0);lua_pushcclosure(L,gfind_aux,3);return 1;}static void
|
|
|
|
add_s(MatchState*ms,luaL_Buffer*b,const char*s,const char*e){lua_State*L=ms->L
|
|
|
|
;if(lua_isstring(L,3)){const char*news=lua_tostring(L,3);size_t l=lua_strlen(L
|
|
|
|
,3);size_t i;for(i=0;i<l;i++){if(news[i]!=ESC)luaL_putchar(b,news[i]);else{i++
|
|
|
|
;if(!isdigit(uchar(news[i])))luaL_putchar(b,news[i]);else{int level=
|
|
|
|
check_capture(ms,news[i]);push_onecapture(ms,level);luaL_addvalue(b);}}}}else{
|
|
|
|
int n;lua_pushvalue(L,3);n=push_captures(ms,s,e);lua_call(L,n,1);if(
|
|
|
|
lua_isstring(L,-1))luaL_addvalue(b);else lua_pop(L,1);}}static int str_gsub(
|
|
|
|
lua_State*L){size_t srcl;const char*src=luaL_checklstring(L,1,&srcl);const
|
|
|
|
char*p=luaL_checkstring(L,2);int max_s=luaL_optint(L,4,srcl+1);int anchor=(*p
|
|
|
|
=='^')?(p++,1):0;int n=0;MatchState ms;luaL_Buffer b;luaL_argcheck(L,
|
|
|
|
lua_gettop(L)>=3&&(lua_isstring(L,3)||lua_isfunction(L,3)),3,
|
|
|
|
"string or function expected");luaL_buffinit(L,&b);ms.L=L;ms.src_init=src;ms.
|
|
|
|
src_end=src+srcl;while(n<max_s){const char*e;ms.level=0;e=match(&ms,src,p);if(
|
|
|
|
e){n++;add_s(&ms,&b,src,e);}if(e&&e>src)src=e;else if(src<ms.src_end)
|
|
|
|
luaL_putchar(&b,*src++);else break;if(anchor)break;}luaL_addlstring(&b,src,ms.
|
|
|
|
src_end-src);luaL_pushresult(&b);lua_pushnumber(L,(lua_Number)n);return 2;}
|
|
|
|
#define MAX_ITEM 512
|
|
|
|
#define MAX_FORMAT 20
|
|
|
|
static void luaI_addquoted(lua_State*L,luaL_Buffer*b,int arg){size_t l;const
|
|
|
|
char*s=luaL_checklstring(L,arg,&l);luaL_putchar(b,'"');while(l--){switch(*s){
|
|
|
|
case'"':case'\\':case'\n':{luaL_putchar(b,'\\');luaL_putchar(b,*s);break;}case
|
|
|
|
'\0':{luaL_addlstring(b,"\\000",4);break;}default:{luaL_putchar(b,*s);break;}}
|
|
|
|
s++;}luaL_putchar(b,'"');}static const char*scanformat(lua_State*L,const char*
|
|
|
|
strfrmt,char*form,int*hasprecision){const char*p=strfrmt;while(strchr("-+ #0",
|
|
|
|
*p))p++;if(isdigit(uchar(*p)))p++;if(isdigit(uchar(*p)))p++;if(*p=='.'){p++;*
|
|
|
|
hasprecision=1;if(isdigit(uchar(*p)))p++;if(isdigit(uchar(*p)))p++;}if(isdigit
|
|
|
|
(uchar(*p)))luaL_error(L,"invalid format (width or precision too long)");if(p-
|
|
|
|
strfrmt+2>MAX_FORMAT)luaL_error(L,"invalid format (too long)");form[0]='%';
|
|
|
|
strncpy(form+1,strfrmt,p-strfrmt+1);form[p-strfrmt+2]=0;return p;}static int
|
|
|
|
str_format(lua_State*L){int arg=1;size_t sfl;const char*strfrmt=
|
|
|
|
luaL_checklstring(L,arg,&sfl);const char*strfrmt_end=strfrmt+sfl;luaL_Buffer b
|
|
|
|
;luaL_buffinit(L,&b);while(strfrmt<strfrmt_end){if(*strfrmt!='%')luaL_putchar(
|
|
|
|
&b,*strfrmt++);else if(*++strfrmt=='%')luaL_putchar(&b,*strfrmt++);else{char
|
|
|
|
form[MAX_FORMAT];char buff[MAX_ITEM];int hasprecision=0;if(isdigit(uchar(*
|
|
|
|
strfrmt))&&*(strfrmt+1)=='$')return luaL_error(L,
|
|
|
|
"obsolete option (d$) to `format'");arg++;strfrmt=scanformat(L,strfrmt,form,&
|
|
|
|
hasprecision);switch(*strfrmt++){case'c':case'd':case'i':{sprintf(buff,form,
|
|
|
|
luaL_checkint(L,arg));break;}case'o':case'u':case'x':case'X':{sprintf(buff,
|
|
|
|
form,(unsigned int)(luaL_checknumber(L,arg)));break;}case'e':case'E':case'f':
|
|
|
|
case'g':case'G':{sprintf(buff,form,luaL_checknumber(L,arg));break;}case'q':{
|
|
|
|
luaI_addquoted(L,&b,arg);continue;}case's':{size_t l;const char*s=
|
|
|
|
luaL_checklstring(L,arg,&l);if(!hasprecision&&l>=100){lua_pushvalue(L,arg);
|
|
|
|
luaL_addvalue(&b);continue;}else{sprintf(buff,form,s);break;}}default:{return
|
|
|
|
luaL_error(L,"invalid option to `format'");}}luaL_addlstring(&b,buff,strlen(
|
|
|
|
buff));}}luaL_pushresult(&b);return 1;}static const luaL_reg strlib[]={{"len",
|
|
|
|
str_len},{"sub",str_sub},{"lower",str_lower},{"upper",str_upper},{"char",
|
|
|
|
str_char},{"rep",str_rep},{"byte",str_byte},{"format",str_format},{"dump",
|
|
|
|
str_dump},{"find",str_find},{"gfind",gfind},{"gsub",str_gsub},{NULL,NULL}};
|
|
|
|
LUALIB_API int luaopen_string(lua_State*L){luaL_openlib(L,LUA_STRLIBNAME,
|
|
|
|
strlib,0);return 1;}
|
|
|
|
#line 1 "ltable.c"
|
|
|
|
#define ltable_c
|
|
|
|
#if BITS_INT >26
|
|
|
|
#define MAXBITS 24
|
|
|
|
#else
|
|
|
|
#define MAXBITS (BITS_INT-2)
|
|
|
|
#endif
|
|
|
|
#define toobig(x) ((((x)-1)>>MAXBITS)!=0)
|
|
|
|
#ifndef lua_number2int
|
|
|
|
#define lua_number2int(i,n) ((i)=(int)(n))
|
|
|
|
#endif
|
|
|
|
#define hashpow2(t,n) (gnode(t,lmod((n),sizenode(t))))
|
|
|
|
#define hashstr(t,str) hashpow2(t,(str)->tsv.hash)
|
|
|
|
#define hashboolean(t,p) hashpow2(t,p)
|
|
|
|
#define hashmod(t,n) (gnode(t,((n)%((sizenode(t)-1)|1))))
|
|
|
|
#define hashpointer(t,p) hashmod(t,IntPoint(p))
|
|
|
|
#define numints cast(int,sizeof(lua_Number)/sizeof(int))
|
|
|
|
static Node*hashnum(const Table*t,lua_Number n){unsigned int a[numints];int i;
|
|
|
|
n+=1;lua_assert(sizeof(a)<=sizeof(n));memcpy(a,&n,sizeof(a));for(i=1;i<numints
|
|
|
|
;i++)a[0]+=a[i];return hashmod(t,cast(lu_hash,a[0]));}Node*luaH_mainposition(
|
|
|
|
const Table*t,const TObject*key){switch(ttype(key)){case LUA_TNUMBER:return
|
|
|
|
hashnum(t,nvalue(key));case LUA_TSTRING:return hashstr(t,tsvalue(key));case
|
|
|
|
LUA_TBOOLEAN:return hashboolean(t,bvalue(key));case LUA_TLIGHTUSERDATA:return
|
|
|
|
hashpointer(t,pvalue(key));default:return hashpointer(t,gcvalue(key));}}static
|
|
|
|
int arrayindex(const TObject*key){if(ttisnumber(key)){int k;lua_number2int(k,
|
|
|
|
(nvalue(key)));if(cast(lua_Number,k)==nvalue(key)&&k>=1&&!toobig(k))return k;}
|
|
|
|
return-1;}static int luaH_index(lua_State*L,Table*t,StkId key){int i;if(
|
|
|
|
ttisnil(key))return-1;i=arrayindex(key);if(0<=i&&i<=t->sizearray){return i-1;}
|
|
|
|
else{const TObject*v=luaH_get(t,key);if(v==&luaO_nilobject)luaG_runerror(L,
|
|
|
|
"invalid key for `next'");i=cast(int,(cast(const lu_byte*,v)-cast(const
|
|
|
|
lu_byte*,gval(gnode(t,0))))/sizeof(Node));return i+t->sizearray;}}int
|
|
|
|
luaH_next(lua_State*L,Table*t,StkId key){int i=luaH_index(L,t,key);for(i++;i<t
|
|
|
|
->sizearray;i++){if(!ttisnil(&t->array[i])){setnvalue(key,cast(lua_Number,i+1)
|
|
|
|
);setobj2s(key+1,&t->array[i]);return 1;}}for(i-=t->sizearray;i<sizenode(t);i
|
|
|
|
++){if(!ttisnil(gval(gnode(t,i)))){setobj2s(key,gkey(gnode(t,i)));setobj2s(key
|
|
|
|
+1,gval(gnode(t,i)));return 1;}}return 0;}static void computesizes(int nums[],
|
|
|
|
int ntotal,int*narray,int*nhash){int i;int a=nums[0];int na=a;int n=(na==0)?-1
|
|
|
|
:0;for(i=1;a<*narray&&*narray>=twoto(i-1);i++){if(nums[i]>0){a+=nums[i];if(a>=
|
|
|
|
twoto(i-1)){n=i;na=a;}}}lua_assert(na<=*narray&&*narray<=ntotal);*nhash=ntotal
|
|
|
|
-na;*narray=(n==-1)?0:twoto(n);lua_assert(na<=*narray&&na>=*narray/2);}static
|
|
|
|
void numuse(const Table*t,int*narray,int*nhash){int nums[MAXBITS+1];int i,lg;
|
|
|
|
int totaluse=0;for(i=0,lg=0;lg<=MAXBITS;lg++){int ttlg=twoto(lg);if(ttlg>t->
|
|
|
|
sizearray){ttlg=t->sizearray;if(i>=ttlg)break;}nums[lg]=0;for(;i<ttlg;i++){if(
|
|
|
|
!ttisnil(&t->array[i])){nums[lg]++;totaluse++;}}}for(;lg<=MAXBITS;lg++)nums[lg
|
|
|
|
]=0;*narray=totaluse;i=sizenode(t);while(i--){Node*n=&t->node[i];if(!ttisnil(
|
|
|
|
gval(n))){int k=arrayindex(gkey(n));if(k>=0){nums[luaO_log2(k-1)+1]++;(*narray
|
|
|
|
)++;}totaluse++;}}computesizes(nums,totaluse,narray,nhash);}static void
|
|
|
|
setarrayvector(lua_State*L,Table*t,int size){int i;luaM_reallocvector(L,t->
|
|
|
|
array,t->sizearray,size,TObject);for(i=t->sizearray;i<size;i++)setnilvalue(&t
|
|
|
|
->array[i]);t->sizearray=size;}static void setnodevector(lua_State*L,Table*t,
|
|
|
|
int lsize){int i;int size=twoto(lsize);if(lsize>MAXBITS)luaG_runerror(L,
|
|
|
|
"table overflow");if(lsize==0){t->node=G(L)->dummynode;lua_assert(ttisnil(gkey
|
|
|
|
(t->node)));lua_assert(ttisnil(gval(t->node)));lua_assert(t->node->next==NULL)
|
|
|
|
;}else{t->node=luaM_newvector(L,size,Node);for(i=0;i<size;i++){t->node[i].next
|
|
|
|
=NULL;setnilvalue(gkey(gnode(t,i)));setnilvalue(gval(gnode(t,i)));}}t->
|
|
|
|
lsizenode=cast(lu_byte,lsize);t->firstfree=gnode(t,size-1);}static void resize
|
|
|
|
(lua_State*L,Table*t,int nasize,int nhsize){int i;int oldasize=t->sizearray;
|
|
|
|
int oldhsize=t->lsizenode;Node*nold;Node temp[1];if(oldhsize)nold=t->node;else
|
|
|
|
{lua_assert(t->node==G(L)->dummynode);temp[0]=t->node[0];nold=temp;setnilvalue
|
|
|
|
(gkey(G(L)->dummynode));setnilvalue(gval(G(L)->dummynode));lua_assert(G(L)->
|
|
|
|
dummynode->next==NULL);}if(nasize>oldasize)setarrayvector(L,t,nasize);
|
|
|
|
setnodevector(L,t,nhsize);if(nasize<oldasize){t->sizearray=nasize;for(i=nasize
|
|
|
|
;i<oldasize;i++){if(!ttisnil(&t->array[i]))setobjt2t(luaH_setnum(L,t,i+1),&t->
|
|
|
|
array[i]);}luaM_reallocvector(L,t->array,oldasize,nasize,TObject);}for(i=twoto
|
|
|
|
(oldhsize)-1;i>=0;i--){Node*old=nold+i;if(!ttisnil(gval(old)))setobjt2t(
|
|
|
|
luaH_set(L,t,gkey(old)),gval(old));}if(oldhsize)luaM_freearray(L,nold,twoto(
|
|
|
|
oldhsize),Node);}static void rehash(lua_State*L,Table*t){int nasize,nhsize;
|
|
|
|
numuse(t,&nasize,&nhsize);resize(L,t,nasize,luaO_log2(nhsize)+1);}Table*
|
|
|
|
luaH_new(lua_State*L,int narray,int lnhash){Table*t=luaM_new(L,Table);
|
|
|
|
luaC_link(L,valtogco(t),LUA_TTABLE);t->metatable=hvalue(defaultmeta(L));t->
|
|
|
|
flags=cast(lu_byte,~0);t->array=NULL;t->sizearray=0;t->lsizenode=0;t->node=
|
|
|
|
NULL;setarrayvector(L,t,narray);setnodevector(L,t,lnhash);return t;}void
|
|
|
|
luaH_free(lua_State*L,Table*t){if(t->lsizenode)luaM_freearray(L,t->node,
|
|
|
|
sizenode(t),Node);luaM_freearray(L,t->array,t->sizearray,TObject);luaM_freelem
|
|
|
|
(L,t);}
|
|
|
|
#if 0
|
|
|
|
void luaH_remove(Table*t,Node*e){Node*mp=luaH_mainposition(t,gkey(e));if(e!=mp
|
|
|
|
){while(mp->next!=e)mp=mp->next;mp->next=e->next;}else{if(e->next!=NULL)??}
|
|
|
|
lua_assert(ttisnil(gval(node)));setnilvalue(gkey(e));e->next=NULL;}
|
|
|
|
#endif
|
|
|
|
static TObject*newkey(lua_State*L,Table*t,const TObject*key){TObject*val;Node*
|
|
|
|
mp=luaH_mainposition(t,key);if(!ttisnil(gval(mp))){Node*othern=
|
|
|
|
luaH_mainposition(t,gkey(mp));Node*n=t->firstfree;if(othern!=mp){while(othern
|
|
|
|
->next!=mp)othern=othern->next;othern->next=n;*n=*mp;mp->next=NULL;setnilvalue
|
|
|
|
(gval(mp));}else{n->next=mp->next;mp->next=n;mp=n;}}setobj2t(gkey(mp),key);
|
|
|
|
lua_assert(ttisnil(gval(mp)));for(;;){if(ttisnil(gkey(t->firstfree)))return
|
|
|
|
gval(mp);else if(t->firstfree==t->node)break;else(t->firstfree)--;}setbvalue(
|
|
|
|
gval(mp),0);rehash(L,t);val=cast(TObject*,luaH_get(t,key));lua_assert(
|
|
|
|
ttisboolean(val));setnilvalue(val);return val;}static const TObject*
|
|
|
|
luaH_getany(Table*t,const TObject*key){if(ttisnil(key))return&luaO_nilobject;
|
|
|
|
else{Node*n=luaH_mainposition(t,key);do{if(luaO_rawequalObj(gkey(n),key))
|
|
|
|
return gval(n);else n=n->next;}while(n);return&luaO_nilobject;}}const TObject*
|
|
|
|
luaH_getnum(Table*t,int key){if(1<=key&&key<=t->sizearray)return&t->array[key-
|
|
|
|
1];else{lua_Number nk=cast(lua_Number,key);Node*n=hashnum(t,nk);do{if(
|
|
|
|
ttisnumber(gkey(n))&&nvalue(gkey(n))==nk)return gval(n);else n=n->next;}while(
|
|
|
|
n);return&luaO_nilobject;}}const TObject*luaH_getstr(Table*t,TString*key){Node
|
|
|
|
*n=hashstr(t,key);do{if(ttisstring(gkey(n))&&tsvalue(gkey(n))==key)return gval
|
|
|
|
(n);else n=n->next;}while(n);return&luaO_nilobject;}const TObject*luaH_get(
|
|
|
|
Table*t,const TObject*key){switch(ttype(key)){case LUA_TSTRING:return
|
|
|
|
luaH_getstr(t,tsvalue(key));case LUA_TNUMBER:{int k;lua_number2int(k,(nvalue(
|
|
|
|
key)));if(cast(lua_Number,k)==nvalue(key))return luaH_getnum(t,k);}default:
|
|
|
|
return luaH_getany(t,key);}}TObject*luaH_set(lua_State*L,Table*t,const TObject
|
|
|
|
*key){const TObject*p=luaH_get(t,key);t->flags=0;if(p!=&luaO_nilobject)return
|
|
|
|
cast(TObject*,p);else{if(ttisnil(key))luaG_runerror(L,"table index is nil");
|
|
|
|
else if(ttisnumber(key)&&nvalue(key)!=nvalue(key))luaG_runerror(L,
|
|
|
|
"table index is NaN");return newkey(L,t,key);}}TObject*luaH_setnum(lua_State*L
|
|
|
|
,Table*t,int key){const TObject*p=luaH_getnum(t,key);if(p!=&luaO_nilobject)
|
|
|
|
return cast(TObject*,p);else{TObject k;setnvalue(&k,cast(lua_Number,key));
|
|
|
|
return newkey(L,t,&k);}}
|
|
|
|
#line 1 "ltablib.c"
|
|
|
|
#define ltablib_c
|
|
|
|
#define aux_getn(L,n) (luaL_checktype(L,n,LUA_TTABLE),luaL_getn(L,n))
|
|
|
|
static int luaB_foreachi(lua_State*L){int i;int n=aux_getn(L,1);luaL_checktype
|
|
|
|
(L,2,LUA_TFUNCTION);for(i=1;i<=n;i++){lua_pushvalue(L,2);lua_pushnumber(L,(
|
|
|
|
lua_Number)i);lua_rawgeti(L,1,i);lua_call(L,2,1);if(!lua_isnil(L,-1))return 1;
|
|
|
|
lua_pop(L,1);}return 0;}static int luaB_foreach(lua_State*L){luaL_checktype(L,
|
|
|
|
1,LUA_TTABLE);luaL_checktype(L,2,LUA_TFUNCTION);lua_pushnil(L);for(;;){if(
|
|
|
|
lua_next(L,1)==0)return 0;lua_pushvalue(L,2);lua_pushvalue(L,-3);lua_pushvalue
|
|
|
|
(L,-3);lua_call(L,2,1);if(!lua_isnil(L,-1))return 1;lua_pop(L,2);}}static int
|
|
|
|
luaB_getn(lua_State*L){lua_pushnumber(L,(lua_Number)aux_getn(L,1));return 1;}
|
|
|
|
static int luaB_setn(lua_State*L){luaL_checktype(L,1,LUA_TTABLE);luaL_setn(L,1
|
|
|
|
,luaL_checkint(L,2));return 0;}static int luaB_tinsert(lua_State*L){int v=
|
|
|
|
lua_gettop(L);int n=aux_getn(L,1)+1;int pos;if(v==2)pos=n;else{pos=
|
|
|
|
luaL_checkint(L,2);if(pos>n)n=pos;v=3;}luaL_setn(L,1,n);while(--n>=pos){
|
|
|
|
lua_rawgeti(L,1,n);lua_rawseti(L,1,n+1);}lua_pushvalue(L,v);lua_rawseti(L,1,
|
|
|
|
pos);return 0;}static int luaB_tremove(lua_State*L){int n=aux_getn(L,1);int
|
|
|
|
pos=luaL_optint(L,2,n);if(n<=0)return 0;luaL_setn(L,1,n-1);lua_rawgeti(L,1,pos
|
|
|
|
);for(;pos<n;pos++){lua_rawgeti(L,1,pos+1);lua_rawseti(L,1,pos);}lua_pushnil(L
|
|
|
|
);lua_rawseti(L,1,n);return 1;}static int str_concat(lua_State*L){luaL_Buffer
|
|
|
|
b;size_t lsep;const char*sep=luaL_optlstring(L,2,"",&lsep);int i=luaL_optint(L
|
|
|
|
,3,1);int n=luaL_optint(L,4,0);luaL_checktype(L,1,LUA_TTABLE);if(n==0)n=
|
|
|
|
luaL_getn(L,1);luaL_buffinit(L,&b);for(;i<=n;i++){lua_rawgeti(L,1,i);
|
|
|
|
luaL_argcheck(L,lua_isstring(L,-1),1,"table contains non-strings");
|
|
|
|
luaL_addvalue(&b);if(i!=n)luaL_addlstring(&b,sep,lsep);}luaL_pushresult(&b);
|
|
|
|
return 1;}static void set2(lua_State*L,int i,int j){lua_rawseti(L,1,i);
|
|
|
|
lua_rawseti(L,1,j);}static int sort_comp(lua_State*L,int a,int b){if(!
|
|
|
|
lua_isnil(L,2)){int res;lua_pushvalue(L,2);lua_pushvalue(L,a-1);lua_pushvalue(
|
|
|
|
L,b-2);lua_call(L,2,1);res=lua_toboolean(L,-1);lua_pop(L,1);return res;}else
|
|
|
|
return lua_lessthan(L,a,b);}static void auxsort(lua_State*L,int l,int u){while
|
|
|
|
(l<u){int i,j;lua_rawgeti(L,1,l);lua_rawgeti(L,1,u);if(sort_comp(L,-1,-2))set2
|
|
|
|
(L,l,u);else lua_pop(L,2);if(u-l==1)break;i=(l+u)/2;lua_rawgeti(L,1,i);
|
|
|
|
lua_rawgeti(L,1,l);if(sort_comp(L,-2,-1))set2(L,i,l);else{lua_pop(L,1);
|
|
|
|
lua_rawgeti(L,1,u);if(sort_comp(L,-1,-2))set2(L,i,u);else lua_pop(L,2);}if(u-l
|
|
|
|
==2)break;lua_rawgeti(L,1,i);lua_pushvalue(L,-1);lua_rawgeti(L,1,u-1);set2(L,i
|
|
|
|
,u-1);i=l;j=u-1;for(;;){while(lua_rawgeti(L,1,++i),sort_comp(L,-1,-2)){if(i>u)
|
|
|
|
luaL_error(L,"invalid order function for sorting");lua_pop(L,1);}while(
|
|
|
|
lua_rawgeti(L,1,--j),sort_comp(L,-3,-1)){if(j<l)luaL_error(L,
|
|
|
|
"invalid order function for sorting");lua_pop(L,1);}if(j<i){lua_pop(L,3);break
|
|
|
|
;}set2(L,i,j);}lua_rawgeti(L,1,u-1);lua_rawgeti(L,1,i);set2(L,u-1,i);if(i-l<u-
|
|
|
|
i){j=l;i=i-1;l=i+2;}else{j=i+1;i=u;u=j-2;}auxsort(L,j,i);}}static int
|
|
|
|
luaB_sort(lua_State*L){int n=aux_getn(L,1);luaL_checkstack(L,40,"");if(!
|
|
|
|
lua_isnoneornil(L,2))luaL_checktype(L,2,LUA_TFUNCTION);lua_settop(L,2);auxsort
|
|
|
|
(L,1,n);return 0;}static const luaL_reg tab_funcs[]={{"concat",str_concat},{
|
|
|
|
"foreach",luaB_foreach},{"foreachi",luaB_foreachi},{"getn",luaB_getn},{"setn",
|
|
|
|
luaB_setn},{"sort",luaB_sort},{"insert",luaB_tinsert},{"remove",luaB_tremove},
|
|
|
|
{NULL,NULL}};LUALIB_API int luaopen_table(lua_State*L){luaL_openlib(L,
|
|
|
|
LUA_TABLIBNAME,tab_funcs,0);return 1;}
|
|
|
|
#line 1 "ltests.c"
|
|
|
|
#define ltests_c
|
|
|
|
#ifdef LUA_DEBUG
|
|
|
|
#define lua_pushintegral(L,i) lua_pushnumber(L,cast(lua_Number,(i)))
|
|
|
|
static lua_State*lua_state=NULL;int islocked=0;
|
|
|
|
#define func_at(L,k) (L->ci->base+(k)-1)
|
|
|
|
static void setnameval(lua_State*L,const char*name,int val){lua_pushstring(L,
|
|
|
|
name);lua_pushintegral(L,val);lua_settable(L,-3);}
|
|
|
|
#define MARK 0x55
|
|
|
|
#ifndef EXTERNMEMCHECK
|
|
|
|
#define HEADER (sizeof(L_Umaxalign))
|
|
|
|
#define MARKSIZE 16
|
|
|
|
#define blockhead(b) (cast(char*,b)-HEADER)
|
|
|
|
#define setsize(newblock, size)(*cast(size_t*,newblock)=size)
|
|
|
|
#define checkblocksize(b, size)(size==(*cast(size_t*,blockhead(b))))
|
|
|
|
#define fillmem(mem,size) memset(mem,-MARK,size)
|
|
|
|
#else
|
|
|
|
#define HEADER 0
|
|
|
|
#define MARKSIZE 0
|
|
|
|
#define blockhead(b) (b)
|
|
|
|
#define setsize(newblock, size)
|
|
|
|
#define checkblocksize(b,size) (1)
|
|
|
|
#define fillmem(mem,size)
|
|
|
|
#endif
|
|
|
|
unsigned long memdebug_numblocks=0;unsigned long memdebug_total=0;unsigned
|
|
|
|
long memdebug_maxmem=0;unsigned long memdebug_memlimit=ULONG_MAX;static void*
|
|
|
|
checkblock(void*block,size_t size){void*b=blockhead(block);int i;for(i=0;i<
|
|
|
|
MARKSIZE;i++)lua_assert(*(cast(char*,b)+HEADER+size+i)==MARK+i);return b;}
|
|
|
|
static void freeblock(void*block,size_t size){if(block){lua_assert(
|
|
|
|
checkblocksize(block,size));block=checkblock(block,size);fillmem(block,size+
|
|
|
|
HEADER+MARKSIZE);free(block);memdebug_numblocks--;memdebug_total-=size;}}void*
|
|
|
|
debug_realloc(void*block,size_t oldsize,size_t size){lua_assert(oldsize==0||
|
|
|
|
checkblocksize(block,oldsize));lua_assert(block!=NULL||size>0);if(size==0){
|
|
|
|
freeblock(block,oldsize);return NULL;}else if(size>oldsize&&memdebug_total+
|
|
|
|
size-oldsize>memdebug_memlimit)return NULL;else{void*newblock;int i;size_t
|
|
|
|
realsize=HEADER+size+MARKSIZE;size_t commonsize=(oldsize<size)?oldsize:size;if
|
|
|
|
(realsize<size)return NULL;newblock=malloc(realsize);if(newblock==NULL)return
|
|
|
|
NULL;if(block){memcpy(cast(char*,newblock)+HEADER,block,commonsize);freeblock(
|
|
|
|
block,oldsize);}fillmem(cast(char*,newblock)+HEADER+commonsize,size-commonsize
|
|
|
|
);memdebug_total+=size;if(memdebug_total>memdebug_maxmem)memdebug_maxmem=
|
|
|
|
memdebug_total;memdebug_numblocks++;setsize(newblock,size);for(i=0;i<MARKSIZE;
|
|
|
|
i++)*(cast(char*,newblock)+HEADER+size+i)=cast(char,MARK+i);return cast(char*,
|
|
|
|
newblock)+HEADER;}}static char*buildop(Proto*p,int pc,char*buff){Instruction i
|
|
|
|
=p->code[pc];OpCode o=GET_OPCODE(i);const char*name=luaP_opnames[o];int line=
|
|
|
|
getline(p,pc);sprintf(buff,"(%4d) %4d - ",line,pc);switch(getOpMode(o)){case
|
|
|
|
iABC:sprintf(buff+strlen(buff),"%-12s%4d %4d %4d",name,GETARG_A(i),GETARG_B(i)
|
|
|
|
,GETARG_C(i));break;case iABx:sprintf(buff+strlen(buff),"%-12s%4d %4d",name,
|
|
|
|
GETARG_A(i),GETARG_Bx(i));break;case iAsBx:sprintf(buff+strlen(buff),
|
|
|
|
"%-12s%4d %4d",name,GETARG_A(i),GETARG_sBx(i));break;}return buff;}
|
|
|
|
#if 0
|
|
|
|
void luaI_printcode(Proto*pt,int size){int pc;for(pc=0;pc<size;pc++){char buff
|
|
|
|
[100];printf("%s\n",buildop(pt,pc,buff));}printf("-------\n");}
|
|
|
|
#endif
|
|
|
|
static int listcode(lua_State*L){int pc;Proto*p;luaL_argcheck(L,lua_isfunction
|
|
|
|
(L,1)&&!lua_iscfunction(L,1),1,"Lua function expected");p=clvalue(func_at(L,1)
|
|
|
|
)->l.p;lua_newtable(L);setnameval(L,"maxstack",p->maxstacksize);setnameval(L,
|
|
|
|
"numparams",p->numparams);for(pc=0;pc<p->sizecode;pc++){char buff[100];
|
|
|
|
lua_pushintegral(L,pc+1);lua_pushstring(L,buildop(p,pc,buff));lua_settable(L,-
|
|
|
|
3);}return 1;}static int listk(lua_State*L){Proto*p;int i;luaL_argcheck(L,
|
|
|
|
lua_isfunction(L,1)&&!lua_iscfunction(L,1),1,"Lua function expected");p=
|
|
|
|
clvalue(func_at(L,1))->l.p;lua_newtable(L);for(i=0;i<p->sizek;i++){
|
|
|
|
lua_pushintegral(L,i+1);luaA_pushobject(L,p->k+i);lua_settable(L,-3);}return 1
|
|
|
|
;}static int listlocals(lua_State*L){Proto*p;int pc=luaL_checkint(L,2)-1;int i
|
|
|
|
=0;const char*name;luaL_argcheck(L,lua_isfunction(L,1)&&!lua_iscfunction(L,1),
|
|
|
|
1,"Lua function expected");p=clvalue(func_at(L,1))->l.p;while((name=
|
|
|
|
luaF_getlocalname(p,++i,pc))!=NULL)lua_pushstring(L,name);return i-1;}static
|
|
|
|
int get_limits(lua_State*L){lua_newtable(L);setnameval(L,"BITS_INT",BITS_INT);
|
|
|
|
setnameval(L,"LFPF",LFIELDS_PER_FLUSH);setnameval(L,"MAXVARS",MAXVARS);
|
|
|
|
setnameval(L,"MAXPARAMS",MAXPARAMS);setnameval(L,"MAXSTACK",MAXSTACK);
|
|
|
|
setnameval(L,"MAXUPVALUES",MAXUPVALUES);return 1;}static int mem_query(
|
|
|
|
lua_State*L){if(lua_isnone(L,1)){lua_pushintegral(L,memdebug_total);
|
|
|
|
lua_pushintegral(L,memdebug_numblocks);lua_pushintegral(L,memdebug_maxmem);
|
|
|
|
return 3;}else{memdebug_memlimit=luaL_checkint(L,1);return 0;}}static int
|
|
|
|
hash_query(lua_State*L){if(lua_isnone(L,2)){luaL_argcheck(L,lua_type(L,1)==
|
|
|
|
LUA_TSTRING,1,"string expected");lua_pushintegral(L,tsvalue(func_at(L,1))->tsv
|
|
|
|
.hash);}else{TObject*o=func_at(L,1);Table*t;luaL_checktype(L,2,LUA_TTABLE);t=
|
|
|
|
hvalue(func_at(L,2));lua_pushintegral(L,luaH_mainposition(t,o)-t->node);}
|
|
|
|
return 1;}static int stacklevel(lua_State*L){unsigned long a=0;
|
|
|
|
lua_pushintegral(L,(int)(L->top-L->stack));lua_pushintegral(L,(int)(L->
|
|
|
|
stack_last-L->stack));lua_pushintegral(L,(int)(L->ci-L->base_ci));
|
|
|
|
lua_pushintegral(L,(int)(L->end_ci-L->base_ci));lua_pushintegral(L,(unsigned
|
|
|
|
long)&a);return 5;}static int table_query(lua_State*L){const Table*t;int i=
|
|
|
|
luaL_optint(L,2,-1);luaL_checktype(L,1,LUA_TTABLE);t=hvalue(func_at(L,1));if(i
|
|
|
|
==-1){lua_pushintegral(L,t->sizearray);lua_pushintegral(L,sizenode(t));
|
|
|
|
lua_pushintegral(L,t->firstfree-t->node);}else if(i<t->sizearray){
|
|
|
|
lua_pushintegral(L,i);luaA_pushobject(L,&t->array[i]);lua_pushnil(L);}else if(
|
|
|
|
(i-=t->sizearray)<sizenode(t)){if(!ttisnil(gval(gnode(t,i)))||ttisnil(gkey(
|
|
|
|
gnode(t,i)))||ttisnumber(gkey(gnode(t,i)))){luaA_pushobject(L,gkey(gnode(t,i))
|
|
|
|
);}else lua_pushstring(L,"<undef>");luaA_pushobject(L,gval(gnode(t,i)));if(t->
|
|
|
|
node[i].next)lua_pushintegral(L,t->node[i].next-t->node);else lua_pushnil(L);}
|
|
|
|
return 3;}static int string_query(lua_State*L){stringtable*tb=&G(L)->strt;int
|
|
|
|
s=luaL_optint(L,2,0)-1;if(s==-1){lua_pushintegral(L,tb->nuse);lua_pushintegral
|
|
|
|
(L,tb->size);return 2;}else if(s<tb->size){GCObject*ts;int n=0;for(ts=tb->hash
|
|
|
|
[s];ts;ts=ts->gch.next){setsvalue2s(L->top,gcotots(ts));incr_top(L);n++;}
|
|
|
|
return n;}return 0;}static int tref(lua_State*L){int level=lua_gettop(L);int
|
|
|
|
lock=luaL_optint(L,2,1);luaL_checkany(L,1);lua_pushvalue(L,1);lua_pushintegral
|
|
|
|
(L,lua_ref(L,lock));assert(lua_gettop(L)==level+1);return 1;}static int getref
|
|
|
|
(lua_State*L){int level=lua_gettop(L);lua_getref(L,luaL_checkint(L,1));assert(
|
|
|
|
lua_gettop(L)==level+1);return 1;}static int unref(lua_State*L){int level=
|
|
|
|
lua_gettop(L);lua_unref(L,luaL_checkint(L,1));assert(lua_gettop(L)==level);
|
|
|
|
return 0;}static int metatable(lua_State*L){luaL_checkany(L,1);if(lua_isnone(L
|
|
|
|
,2)){if(lua_getmetatable(L,1)==0)lua_pushnil(L);}else{lua_settop(L,2);
|
|
|
|
luaL_checktype(L,2,LUA_TTABLE);lua_setmetatable(L,1);}return 1;}static int
|
|
|
|
upvalue(lua_State*L){int n=luaL_checkint(L,2);luaL_checktype(L,1,LUA_TFUNCTION
|
|
|
|
);if(lua_isnone(L,3)){const char*name=lua_getupvalue(L,1,n);if(name==NULL)
|
|
|
|
return 0;lua_pushstring(L,name);return 2;}else{const char*name=lua_setupvalue(
|
|
|
|
L,1,n);lua_pushstring(L,name);return 1;}}static int newuserdata(lua_State*L){
|
|
|
|
size_t size=luaL_checkint(L,1);char*p=cast(char*,lua_newuserdata(L,size));
|
|
|
|
while(size--)*p++='\0';return 1;}static int pushuserdata(lua_State*L){
|
|
|
|
lua_pushlightuserdata(L,cast(void*,luaL_checkint(L,1)));return 1;}static int
|
|
|
|
udataval(lua_State*L){lua_pushintegral(L,cast(int,lua_touserdata(L,1)));return
|
|
|
|
1;}static int doonnewstack(lua_State*L){lua_State*L1=lua_newthread(L);size_t
|
|
|
|
l;const char*s=luaL_checklstring(L,1,&l);int status=luaL_loadbuffer(L1,s,l,s);
|
|
|
|
if(status==0)status=lua_pcall(L1,0,0,0);lua_pushintegral(L,status);return 1;}
|
|
|
|
static int s2d(lua_State*L){lua_pushnumber(L,*cast(const double*,
|
|
|
|
luaL_checkstring(L,1)));return 1;}static int d2s(lua_State*L){double d=
|
|
|
|
luaL_checknumber(L,1);lua_pushlstring(L,cast(char*,&d),sizeof(d));return 1;}
|
|
|
|
static int newstate(lua_State*L){lua_State*L1=lua_open();if(L1){
|
|
|
|
lua_userstateopen(L1);lua_pushintegral(L,(unsigned long)L1);}else lua_pushnil(
|
|
|
|
L);return 1;}static int loadlib(lua_State*L){static const luaL_reg libs[]={{
|
|
|
|
"mathlibopen",luaopen_math},{"strlibopen",luaopen_string},{"iolibopen",
|
|
|
|
luaopen_io},{"tablibopen",luaopen_table},{"dblibopen",luaopen_debug},{
|
|
|
|
"baselibopen",luaopen_base},{NULL,NULL}};lua_State*L1=cast(lua_State*,cast(
|
|
|
|
unsigned long,luaL_checknumber(L,1)));lua_pushvalue(L1,LUA_GLOBALSINDEX);
|
|
|
|
luaL_openlib(L1,NULL,libs,0);return 0;}static int closestate(lua_State*L){
|
|
|
|
lua_State*L1=cast(lua_State*,cast(unsigned long,luaL_checknumber(L,1)));
|
|
|
|
lua_close(L1);lua_unlock(L);return 0;}static int doremote(lua_State*L){
|
|
|
|
lua_State*L1=cast(lua_State*,cast(unsigned long,luaL_checknumber(L,1)));size_t
|
|
|
|
lcode;const char*code=luaL_checklstring(L,2,&lcode);int status;lua_settop(L1,
|
|
|
|
0);status=luaL_loadbuffer(L1,code,lcode,code);if(status==0)status=lua_pcall(L1
|
|
|
|
,0,LUA_MULTRET,0);if(status!=0){lua_pushnil(L);lua_pushintegral(L,status);
|
|
|
|
lua_pushstring(L,lua_tostring(L1,-1));return 3;}else{int i=0;while(!lua_isnone
|
|
|
|
(L1,++i))lua_pushstring(L,lua_tostring(L1,i));lua_pop(L1,i-1);return i-1;}}
|
|
|
|
static int log2_aux(lua_State*L){lua_pushintegral(L,luaO_log2(luaL_checkint(L,
|
|
|
|
1)));return 1;}static int int2fb_aux(lua_State*L){int b=luaO_int2fb(
|
|
|
|
luaL_checkint(L,1));lua_pushintegral(L,b);lua_pushintegral(L,fb2int(b));return
|
|
|
|
2;}static int test_do(lua_State*L){const char*p=luaL_checkstring(L,1);if(*p==
|
|
|
|
'@')lua_dofile(L,p+1);else lua_dostring(L,p);return lua_gettop(L);}static
|
|
|
|
const char*const delimits=" \t\n,;";static void skip(const char**pc){while(**
|
|
|
|
pc!='\0'&&strchr(delimits,**pc))(*pc)++;}static int getnum_aux(lua_State*L,
|
|
|
|
const char**pc){int res=0;int sig=1;skip(pc);if(**pc=='.'){res=cast(int,
|
|
|
|
lua_tonumber(L,-1));lua_pop(L,1);(*pc)++;return res;}else if(**pc=='-'){sig=-1
|
|
|
|
;(*pc)++;}while(isdigit(cast(int,**pc)))res=res*10+(*(*pc)++)-'0';return sig*
|
|
|
|
res;}static const char*getname_aux(char*buff,const char**pc){int i=0;skip(pc);
|
|
|
|
while(**pc!='\0'&&!strchr(delimits,**pc))buff[i++]=*(*pc)++;buff[i]='\0';
|
|
|
|
return buff;}
|
|
|
|
#define EQ(s1) (strcmp(s1,inst)==0)
|
|
|
|
#define getnum (getnum_aux(L,&pc))
|
|
|
|
#define getname (getname_aux(buff,&pc))
|
|
|
|
static int testC(lua_State*L){char buff[30];const char*pc=luaL_checkstring(L,1
|
|
|
|
);for(;;){const char*inst=getname;if EQ("")return 0;else if EQ("isnumber"){
|
|
|
|
lua_pushintegral(L,lua_isnumber(L,getnum));}else if EQ("isstring"){
|
|
|
|
lua_pushintegral(L,lua_isstring(L,getnum));}else if EQ("istable"){
|
|
|
|
lua_pushintegral(L,lua_istable(L,getnum));}else if EQ("iscfunction"){
|
|
|
|
lua_pushintegral(L,lua_iscfunction(L,getnum));}else if EQ("isfunction"){
|
|
|
|
lua_pushintegral(L,lua_isfunction(L,getnum));}else if EQ("isuserdata"){
|
|
|
|
lua_pushintegral(L,lua_isuserdata(L,getnum));}else if EQ("isudataval"){
|
|
|
|
lua_pushintegral(L,lua_islightuserdata(L,getnum));}else if EQ("isnil"){
|
|
|
|
lua_pushintegral(L,lua_isnil(L,getnum));}else if EQ("isnull"){lua_pushintegral
|
|
|
|
(L,lua_isnone(L,getnum));}else if EQ("tonumber"){lua_pushnumber(L,lua_tonumber
|
|
|
|
(L,getnum));}else if EQ("tostring"){const char*s=lua_tostring(L,getnum);
|
|
|
|
lua_pushstring(L,s);}else if EQ("strlen"){lua_pushintegral(L,lua_strlen(L,
|
|
|
|
getnum));}else if EQ("tocfunction"){lua_pushcfunction(L,lua_tocfunction(L,
|
|
|
|
getnum));}else if EQ("return"){return getnum;}else if EQ("gettop"){
|
|
|
|
lua_pushintegral(L,lua_gettop(L));}else if EQ("settop"){lua_settop(L,getnum);}
|
|
|
|
else if EQ("pop"){lua_pop(L,getnum);}else if EQ("pushnum"){lua_pushintegral(L,
|
|
|
|
getnum);}else if EQ("pushnil"){lua_pushnil(L);}else if EQ("pushbool"){
|
|
|
|
lua_pushboolean(L,getnum);}else if EQ("tobool"){lua_pushintegral(L,
|
|
|
|
lua_toboolean(L,getnum));}else if EQ("pushvalue"){lua_pushvalue(L,getnum);}
|
|
|
|
else if EQ("pushcclosure"){lua_pushcclosure(L,testC,getnum);}else if EQ(
|
|
|
|
"pushupvalues"){lua_pushupvalues(L);}else if EQ("remove"){lua_remove(L,getnum)
|
|
|
|
;}else if EQ("insert"){lua_insert(L,getnum);}else if EQ("replace"){lua_replace
|
|
|
|
(L,getnum);}else if EQ("gettable"){lua_gettable(L,getnum);}else if EQ(
|
|
|
|
"settable"){lua_settable(L,getnum);}else if EQ("next"){lua_next(L,-2);}else if
|
|
|
|
EQ("concat"){lua_concat(L,getnum);}else if EQ("lessthan"){int a=getnum;
|
|
|
|
lua_pushboolean(L,lua_lessthan(L,a,getnum));}else if EQ("equal"){int a=getnum;
|
|
|
|
lua_pushboolean(L,lua_equal(L,a,getnum));}else if EQ("rawcall"){int narg=
|
|
|
|
getnum;int nres=getnum;lua_call(L,narg,nres);}else if EQ("call"){int narg=
|
|
|
|
getnum;int nres=getnum;lua_pcall(L,narg,nres,0);}else if EQ("loadstring"){
|
|
|
|
size_t sl;const char*s=luaL_checklstring(L,getnum,&sl);luaL_loadbuffer(L,s,sl,
|
|
|
|
s);}else if EQ("loadfile"){luaL_loadfile(L,luaL_checkstring(L,getnum));}else
|
|
|
|
if EQ("setmetatable"){lua_setmetatable(L,getnum);}else if EQ("getmetatable"){
|
|
|
|
if(lua_getmetatable(L,getnum)==0)lua_pushnil(L);}else if EQ("type"){
|
|
|
|
lua_pushstring(L,lua_typename(L,lua_type(L,getnum)));}else if EQ("getn"){int i
|
|
|
|
=getnum;lua_pushintegral(L,luaL_getn(L,i));}else if EQ("setn"){int i=getnum;
|
|
|
|
int n=cast(int,lua_tonumber(L,-1));luaL_setn(L,i,n);lua_pop(L,1);}else
|
|
|
|
luaL_error(L,"unknown instruction %s",buff);}return 0;}static void yieldf(
|
|
|
|
lua_State*L,lua_Debug*ar){lua_yield(L,0);}static int setyhook(lua_State*L){if(
|
|
|
|
lua_isnoneornil(L,1))lua_sethook(L,NULL,0,0);else{const char*smask=
|
|
|
|
luaL_checkstring(L,1);int count=luaL_optint(L,2,0);int mask=0;if(strchr(smask,
|
|
|
|
'l'))mask|=LUA_MASKLINE;if(count>0)mask|=LUA_MASKCOUNT;lua_sethook(L,yieldf,
|
|
|
|
mask,count);}return 0;}static int coresume(lua_State*L){int status;lua_State*
|
|
|
|
co=lua_tothread(L,1);luaL_argcheck(L,co,1,"coroutine expected");status=
|
|
|
|
lua_resume(co,0);if(status!=0){lua_pushboolean(L,0);lua_insert(L,-2);return 2;
|
|
|
|
}else{lua_pushboolean(L,1);return 1;}}static const struct luaL_reg tests_funcs
|
|
|
|
[]={{"hash",hash_query},{"limits",get_limits},{"listcode",listcode},{"listk",
|
|
|
|
listk},{"listlocals",listlocals},{"loadlib",loadlib},{"stacklevel",stacklevel}
|
|
|
|
,{"querystr",string_query},{"querytab",table_query},{"doit",test_do},{"testC",
|
|
|
|
testC},{"ref",tref},{"getref",getref},{"unref",unref},{"d2s",d2s},{"s2d",s2d},
|
|
|
|
{"metatable",metatable},{"upvalue",upvalue},{"newuserdata",newuserdata},{
|
|
|
|
"pushuserdata",pushuserdata},{"udataval",udataval},{"doonnewstack",
|
|
|
|
doonnewstack},{"newstate",newstate},{"closestate",closestate},{"doremote",
|
|
|
|
doremote},{"log2",log2_aux},{"int2fb",int2fb_aux},{"totalmem",mem_query},{
|
|
|
|
"resume",coresume},{"setyhook",setyhook},{NULL,NULL}};static void fim(void){if
|
|
|
|
(!islocked)lua_close(lua_state);lua_assert(memdebug_numblocks==0);lua_assert(
|
|
|
|
memdebug_total==0);}static int l_panic(lua_State*L){UNUSED(L);fprintf(stderr,
|
|
|
|
"unable to recover; exiting\n");return 0;}int luaB_opentests(lua_State*L){
|
|
|
|
lua_atpanic(L,l_panic);lua_userstateopen(L);lua_state=L;luaL_openlib(L,"T",
|
|
|
|
tests_funcs,0);atexit(fim);return 0;}
|
|
|
|
#undef main
|
|
|
|
int main(int argc,char*argv[]){char*limit=getenv("MEMLIMIT");if(limit)
|
|
|
|
memdebug_memlimit=strtoul(limit,NULL,10);l_main(argc,argv);return 0;}
|
|
|
|
#endif
|
|
|
|
#line 1 "ltm.c"
|
|
|
|
#define ltm_c
|
|
|
|
const char*const luaT_typenames[]={"nil","boolean","userdata","number",
|
|
|
|
"string","table","function","userdata","thread"};void luaT_init(lua_State*L){
|
|
|
|
static const char*const luaT_eventname[]={"__index","__newindex","__gc",
|
|
|
|
"__mode","__eq","__add","__sub","__mul","__div","__pow","__unm","__lt","__le",
|
|
|
|
"__concat","__call"};int i;for(i=0;i<TM_N;i++){G(L)->tmname[i]=luaS_new(L,
|
|
|
|
luaT_eventname[i]);luaS_fix(G(L)->tmname[i]);}}const TObject*luaT_gettm(Table*
|
|
|
|
events,TMS event,TString*ename){const TObject*tm=luaH_getstr(events,ename);
|
|
|
|
lua_assert(event<=TM_EQ);if(ttisnil(tm)){events->flags|=cast(lu_byte,1u<<event
|
|
|
|
);return NULL;}else return tm;}const TObject*luaT_gettmbyobj(lua_State*L,const
|
|
|
|
TObject*o,TMS event){TString*ename=G(L)->tmname[event];switch(ttype(o)){case
|
|
|
|
LUA_TTABLE:return luaH_getstr(hvalue(o)->metatable,ename);case LUA_TUSERDATA:
|
|
|
|
return luaH_getstr(uvalue(o)->uv.metatable,ename);default:return&
|
|
|
|
luaO_nilobject;}}
|
|
|
|
#line 1 "lua.c"
|
|
|
|
#define lua_c
|
|
|
|
#ifdef LUA_USERCONFIG
|
|
|
|
#include LUA_USERCONFIG
|
|
|
|
#endif
|
|
|
|
#ifdef _POSIX_C_SOURCE
|
|
|
|
#define stdin_is_tty() isatty(0)
|
|
|
|
#else
|
|
|
|
#define stdin_is_tty() 1
|
|
|
|
#endif
|
|
|
|
#ifndef PROMPT
|
|
|
|
#define PROMPT "> "
|
|
|
|
#endif
|
|
|
|
#ifndef PROMPT2
|
|
|
|
#define PROMPT2 ">> "
|
|
|
|
#endif
|
|
|
|
#ifndef PROGNAME
|
|
|
|
#define PROGNAME "lua"
|
|
|
|
#endif
|
|
|
|
#ifndef lua_userinit
|
|
|
|
#define lua_userinit(L) openstdlibs(L)
|
|
|
|
#endif
|
|
|
|
#ifndef LUA_EXTRALIBS
|
|
|
|
#define LUA_EXTRALIBS
|
|
|
|
#endif
|
|
|
|
static lua_State*L=NULL;static const char*progname=PROGNAME;LUALIB_API int
|
|
|
|
luaopen_posix(lua_State*L);static const luaL_reg lualibs[]={{"base",
|
|
|
|
luaopen_base},{"table",luaopen_table},{"io",luaopen_io},{"string",
|
|
|
|
luaopen_string},{"debug",luaopen_debug},{"loadlib",luaopen_loadlib},{"posix",
|
|
|
|
luaopen_posix},LUA_EXTRALIBS{NULL,NULL}};static void lstop(lua_State*l,
|
|
|
|
lua_Debug*ar){(void)ar;lua_sethook(l,NULL,0,0);luaL_error(l,"interrupted!");}
|
|
|
|
static void laction(int i){signal(i,SIG_DFL);lua_sethook(L,lstop,LUA_MASKCALL|
|
|
|
|
LUA_MASKRET|LUA_MASKCOUNT,1);}static void print_usage(void){fprintf(stderr,
|
|
|
|
"usage: %s [options] [script [args]].\n""Available options are:\n"
|
|
|
|
" - execute stdin as a file\n"" -e stat execute string `stat'\n"
|
|
|
|
" -i enter interactive mode after executing `script'\n"
|
|
|
|
" -l name load and run library `name'\n"
|
|
|
|
" -v show version information\n"" -- stop handling options\n",
|
|
|
|
progname);}static void l_message(const char*pname,const char*msg){if(pname)
|
|
|
|
fprintf(stderr,"%s: ",pname);fprintf(stderr,"%s\n",msg);}static int report(int
|
|
|
|
status){const char*msg;if(status){msg=lua_tostring(L,-1);if(msg==NULL)msg=
|
|
|
|
"(error with no message)";l_message(progname,msg);lua_pop(L,1);}return status;
|
|
|
|
}static int lcall(int narg,int clear){int status;int base=lua_gettop(L)-narg;
|
|
|
|
lua_pushliteral(L,"_TRACEBACK");lua_rawget(L,LUA_GLOBALSINDEX);lua_insert(L,
|
|
|
|
base);signal(SIGINT,laction);status=lua_pcall(L,narg,(clear?0:LUA_MULTRET),
|
|
|
|
base);signal(SIGINT,SIG_DFL);lua_remove(L,base);return status;}static void
|
|
|
|
print_version(void){l_message(NULL,LUA_VERSION" "LUA_COPYRIGHT);}static void
|
|
|
|
getargs(char*argv[],int n){int i;lua_newtable(L);for(i=0;argv[i];i++){
|
|
|
|
lua_pushnumber(L,i-n);lua_pushstring(L,argv[i]);lua_rawset(L,-3);}
|
|
|
|
lua_pushliteral(L,"n");lua_pushnumber(L,i-n-1);lua_rawset(L,-3);}static int
|
|
|
|
docall(int status){if(status==0)status=lcall(0,1);return report(status);}
|
|
|
|
static int file_input(const char*name){return docall(luaL_loadfile(L,name));}
|
|
|
|
static int dostring(const char*s,const char*name){return docall(
|
|
|
|
luaL_loadbuffer(L,s,strlen(s),name));}static int load_file(const char*name){
|
|
|
|
lua_pushliteral(L,"require");lua_rawget(L,LUA_GLOBALSINDEX);if(!lua_isfunction
|
|
|
|
(L,-1)){lua_pop(L,1);return file_input(name);}else{lua_pushstring(L,name);
|
|
|
|
return report(lcall(1,1));}}
|
|
|
|
#ifndef lua_saveline
|
|
|
|
#define lua_saveline(L,line)
|
|
|
|
#endif
|
|
|
|
#ifndef lua_readline
|
|
|
|
#define lua_readline(L,prompt) readline(L,prompt)
|
|
|
|
#ifndef MAXINPUT
|
|
|
|
#define MAXINPUT 512
|
|
|
|
#endif
|
|
|
|
static int readline(lua_State*l,const char*prompt){static char buffer[MAXINPUT
|
|
|
|
];if(prompt){fputs(prompt,stdout);fflush(stdout);}if(fgets(buffer,sizeof(
|
|
|
|
buffer),stdin)==NULL)return 0;else{lua_pushstring(l,buffer);return 1;}}
|
|
|
|
#endif
|
|
|
|
static const char*get_prompt(int firstline){const char*p=NULL;lua_pushstring(L
|
|
|
|
,firstline?"_PROMPT":"_PROMPT2");lua_rawget(L,LUA_GLOBALSINDEX);p=lua_tostring
|
|
|
|
(L,-1);if(p==NULL)p=(firstline?PROMPT:PROMPT2);lua_pop(L,1);return p;}static
|
|
|
|
int incomplete(int status){if(status==LUA_ERRSYNTAX&&strstr(lua_tostring(L,-1)
|
|
|
|
,"near `<eof>'")!=NULL){lua_pop(L,1);return 1;}else return 0;}static int
|
|
|
|
load_string(void){int status;lua_settop(L,0);if(lua_readline(L,get_prompt(1))
|
|
|
|
==0)return-1;if(lua_tostring(L,-1)[0]=='='){lua_pushfstring(L,"return %s",
|
|
|
|
lua_tostring(L,-1)+1);lua_remove(L,-2);}for(;;){status=luaL_loadbuffer(L,
|
|
|
|
lua_tostring(L,1),lua_strlen(L,1),"=stdin");if(!incomplete(status))break;if(
|
|
|
|
lua_readline(L,get_prompt(0))==0)return-1;lua_concat(L,lua_gettop(L));}
|
|
|
|
lua_saveline(L,lua_tostring(L,1));lua_remove(L,1);return status;}static void
|
|
|
|
manual_input(void){int status;const char*oldprogname=progname;progname=NULL;
|
|
|
|
while((status=load_string())!=-1){if(status==0)status=lcall(0,0);report(status
|
|
|
|
);if(status==0&&lua_gettop(L)>0){lua_getglobal(L,"print");lua_insert(L,1);if(
|
|
|
|
lua_pcall(L,lua_gettop(L)-1,0,0)!=0)l_message(progname,lua_pushfstring(L,
|
|
|
|
"error calling `print' (%s)",lua_tostring(L,-1)));}}lua_settop(L,0);fputs("\n"
|
|
|
|
,stdout);progname=oldprogname;}static int handle_argv(char*argv[],int*
|
|
|
|
interactive){if(argv[1]==NULL){if(stdin_is_tty()){print_version();manual_input
|
|
|
|
();}else file_input(NULL);}else{int i;for(i=1;argv[i]!=NULL;i++){if(argv[i][0]
|
|
|
|
!='-')break;switch(argv[i][1]){case'-':{if(argv[i][2]!='\0'){print_usage();
|
|
|
|
return 1;}i++;goto endloop;}case'\0':{file_input(NULL);break;}case'i':{*
|
|
|
|
interactive=1;break;}case'v':{print_version();break;}case'e':{const char*chunk
|
|
|
|
=argv[i]+2;if(*chunk=='\0')chunk=argv[++i];if(chunk==NULL){print_usage();
|
|
|
|
return 1;}if(dostring(chunk,"=<command line>")!=0)return 1;break;}case'l':{
|
|
|
|
const char*filename=argv[i]+2;if(*filename=='\0')filename=argv[++i];if(
|
|
|
|
filename==NULL){print_usage();return 1;}if(load_file(filename))return 1;break;
|
|
|
|
}case'c':{l_message(progname,"option `-c' is deprecated");break;}case's':{
|
|
|
|
l_message(progname,"option `-s' is deprecated");break;}default:{print_usage();
|
|
|
|
return 1;}}}endloop:if(argv[i]!=NULL){const char*filename=argv[i];getargs(argv
|
|
|
|
,i);lua_setglobal(L,"arg");if(strcmp(filename,"/dev/stdin")==0)filename=NULL;
|
|
|
|
return file_input(filename);}}return 0;}static void openstdlibs(lua_State*l){
|
|
|
|
const luaL_reg*lib=lualibs;for(;lib->func;lib++){lib->func(l);lua_settop(l,0);
|
|
|
|
}}static int handle_luainit(void){const char*init=getenv("LUA_INIT");if(init==
|
|
|
|
NULL)return 0;else if(init[0]=='@')return file_input(init+1);else return
|
|
|
|
dostring(init,"=LUA_INIT");}struct Smain{int argc;char**argv;int status;};
|
|
|
|
static int pmain(lua_State*l){struct Smain*s=(struct Smain*)lua_touserdata(l,1
|
|
|
|
);int status;int interactive=0;if(s->argv[0]&&s->argv[0][0])progname=s->argv[0
|
|
|
|
];L=l;lua_userinit(l);status=handle_luainit();if(status==0){status=handle_argv
|
|
|
|
(s->argv,&interactive);if(status==0&&interactive)manual_input();}s->status=
|
|
|
|
status;return 0;}int main(int argc,char*argv[]){int status;struct Smain s;
|
|
|
|
lua_State*l=lua_open();if(l==NULL){l_message(argv[0],
|
|
|
|
"cannot create state: not enough memory");return EXIT_FAILURE;}s.argc=argc;s.
|
|
|
|
argv=argv;status=lua_cpcall(l,&pmain,&s);report(status);lua_close(l);return(
|
|
|
|
status||s.status)?EXIT_FAILURE:EXIT_SUCCESS;}
|
|
|
|
#line 1 "lundump.c"
|
|
|
|
#define lundump_c
|
|
|
|
#define LoadByte (lu_byte)ezgetc
|
|
|
|
typedef struct{lua_State*L;ZIO*Z;Mbuffer*b;int swap;const char*name;}LoadState
|
|
|
|
;static void unexpectedEOZ(LoadState*S){luaG_runerror(S->L,
|
|
|
|
"unexpected end of file in %s",S->name);}static int ezgetc(LoadState*S){int c=
|
|
|
|
zgetc(S->Z);if(c==EOZ)unexpectedEOZ(S);return c;}static void ezread(LoadState*
|
|
|
|
S,void*b,int n){int r=luaZ_read(S->Z,b,n);if(r!=0)unexpectedEOZ(S);}static
|
|
|
|
void LoadBlock(LoadState*S,void*b,size_t size){if(S->swap){char*p=(char*)b+
|
|
|
|
size-1;int n=size;while(n--)*p--=(char)ezgetc(S);}else ezread(S,b,size);}
|
|
|
|
static void LoadVector(LoadState*S,void*b,int m,size_t size){if(S->swap){char*
|
|
|
|
q=(char*)b;while(m--){char*p=q+size-1;int n=size;while(n--)*p--=(char)ezgetc(S
|
|
|
|
);q+=size;}}else ezread(S,b,m*size);}static int LoadInt(LoadState*S){int x;
|
|
|
|
LoadBlock(S,&x,sizeof(x));if(x<0)luaG_runerror(S->L,"bad integer in %s",S->
|
|
|
|
name);return x;}static size_t LoadSize(LoadState*S){size_t x;LoadBlock(S,&x,
|
|
|
|
sizeof(x));return x;}static lua_Number LoadNumber(LoadState*S){lua_Number x;
|
|
|
|
LoadBlock(S,&x,sizeof(x));return x;}static TString*LoadString(LoadState*S){
|
|
|
|
size_t size=LoadSize(S);if(size==0)return NULL;else{char*s=luaZ_openspace(S->L
|
|
|
|
,S->b,size);ezread(S,s,size);return luaS_newlstr(S->L,s,size-1);}}static void
|
|
|
|
LoadCode(LoadState*S,Proto*f){int size=LoadInt(S);f->code=luaM_newvector(S->L,
|
|
|
|
size,Instruction);f->sizecode=size;LoadVector(S,f->code,size,sizeof(*f->code))
|
|
|
|
;}static void LoadLocals(LoadState*S,Proto*f){int i,n;n=LoadInt(S);f->locvars=
|
|
|
|
luaM_newvector(S->L,n,LocVar);f->sizelocvars=n;for(i=0;i<n;i++){f->locvars[i].
|
|
|
|
varname=LoadString(S);f->locvars[i].startpc=LoadInt(S);f->locvars[i].endpc=
|
|
|
|
LoadInt(S);}}static void LoadLines(LoadState*S,Proto*f){int size=LoadInt(S);f
|
|
|
|
->lineinfo=luaM_newvector(S->L,size,int);f->sizelineinfo=size;LoadVector(S,f->
|
|
|
|
lineinfo,size,sizeof(*f->lineinfo));}static void LoadUpvalues(LoadState*S,
|
|
|
|
Proto*f){int i,n;n=LoadInt(S);if(n!=0&&n!=f->nups)luaG_runerror(S->L,
|
|
|
|
"bad nupvalues in %s: read %d; expected %d",S->name,n,f->nups);f->upvalues=
|
|
|
|
luaM_newvector(S->L,n,TString*);f->sizeupvalues=n;for(i=0;i<n;i++)f->upvalues[
|
|
|
|
i]=LoadString(S);}static Proto*LoadFunction(LoadState*S,TString*p);static void
|
|
|
|
LoadConstants(LoadState*S,Proto*f){int i,n;n=LoadInt(S);f->k=luaM_newvector(S
|
|
|
|
->L,n,TObject);f->sizek=n;for(i=0;i<n;i++){TObject*o=&f->k[i];int t=LoadByte(S
|
|
|
|
);switch(t){case LUA_TNUMBER:setnvalue(o,LoadNumber(S));break;case LUA_TSTRING
|
|
|
|
:setsvalue2n(o,LoadString(S));break;case LUA_TNIL:setnilvalue(o);break;default
|
|
|
|
:luaG_runerror(S->L,"bad constant type (%d) in %s",t,S->name);break;}}n=
|
|
|
|
LoadInt(S);f->p=luaM_newvector(S->L,n,Proto*);f->sizep=n;for(i=0;i<n;i++)f->p[
|
|
|
|
i]=LoadFunction(S,f->source);}static Proto*LoadFunction(LoadState*S,TString*p)
|
|
|
|
{Proto*f=luaF_newproto(S->L);f->source=LoadString(S);if(f->source==NULL)f->
|
|
|
|
source=p;f->lineDefined=LoadInt(S);f->nups=LoadByte(S);f->numparams=LoadByte(S
|
|
|
|
);f->is_vararg=LoadByte(S);f->maxstacksize=LoadByte(S);LoadLines(S,f);
|
|
|
|
LoadLocals(S,f);LoadUpvalues(S,f);LoadConstants(S,f);LoadCode(S,f);
|
|
|
|
#ifndef TRUST_BINARIES
|
|
|
|
if(!luaG_checkcode(f))luaG_runerror(S->L,"bad code in %s",S->name);
|
|
|
|
#endif
|
|
|
|
return f;}static void LoadSignature(LoadState*S){const char*s=LUA_SIGNATURE;
|
|
|
|
while(*s!=0&&ezgetc(S)==*s)++s;if(*s!=0)luaG_runerror(S->L,
|
|
|
|
"bad signature in %s",S->name);}static void TestSize(LoadState*S,int s,const
|
|
|
|
char*what){int r=LoadByte(S);if(r!=s)luaG_runerror(S->L,
|
|
|
|
"virtual machine mismatch in %s: ""size of %s is %d but read %d",S->name,what,
|
|
|
|
s,r);}
|
|
|
|
#define TESTSIZE(s,w) TestSize(S,s,w)
|
|
|
|
#define V(v) v/16,v%16
|
|
|
|
static void LoadHeader(LoadState*S){int version;lua_Number x,tx=TEST_NUMBER;
|
|
|
|
LoadSignature(S);version=LoadByte(S);if(version>VERSION)luaG_runerror(S->L,
|
|
|
|
"%s too new: ""read version %d.%d; expected at most %d.%d",S->name,V(version),
|
|
|
|
V(VERSION));if(version<VERSION0)luaG_runerror(S->L,"%s too old: "
|
|
|
|
"read version %d.%d; expected at least %d.%d",S->name,V(version),V(VERSION0));
|
|
|
|
S->swap=(luaU_endianness()!=LoadByte(S));TESTSIZE(sizeof(int),"int");TESTSIZE(
|
|
|
|
sizeof(size_t),"size_t");TESTSIZE(sizeof(Instruction),"Instruction");TESTSIZE(
|
|
|
|
SIZE_OP,"OP");TESTSIZE(SIZE_A,"A");TESTSIZE(SIZE_B,"B");TESTSIZE(SIZE_C,"C");
|
|
|
|
TESTSIZE(sizeof(lua_Number),"number");x=LoadNumber(S);if((long)x!=(long)tx)
|
|
|
|
luaG_runerror(S->L,"unknown number format in %s",S->name);}static Proto*
|
|
|
|
LoadChunk(LoadState*S){LoadHeader(S);return LoadFunction(S,NULL);}Proto*
|
|
|
|
luaU_undump(lua_State*L,ZIO*Z,Mbuffer*buff){LoadState S;const char*s=zname(Z);
|
|
|
|
if(*s=='@'||*s=='=')S.name=s+1;else if(*s==LUA_SIGNATURE[0])S.name=
|
|
|
|
"binary string";else S.name=s;S.L=L;S.Z=Z;S.b=buff;return LoadChunk(&S);}int
|
|
|
|
luaU_endianness(void){int x=1;return*(char*)&x;}
|
|
|
|
#line 1 "lvm.c"
|
|
|
|
#define lvm_c
|
|
|
|
#ifndef lua_number2str
|
|
|
|
#define lua_number2str(s,n) sprintf((s),LUA_NUMBER_FMT,(n))
|
|
|
|
#endif
|
|
|
|
#define MAXTAGLOOP 100
|
|
|
|
const TObject*luaV_tonumber(const TObject*obj,TObject*n){lua_Number num;if(
|
|
|
|
ttisnumber(obj))return obj;if(ttisstring(obj)&&luaO_str2d(svalue(obj),&num)){
|
|
|
|
setnvalue(n,num);return n;}else return NULL;}int luaV_tostring(lua_State*L,
|
|
|
|
StkId obj){if(!ttisnumber(obj))return 0;else{char s[32];lua_number2str(s,
|
|
|
|
nvalue(obj));setsvalue2s(obj,luaS_new(L,s));return 1;}}static void traceexec(
|
|
|
|
lua_State*L){lu_byte mask=L->hookmask;if(mask&LUA_MASKCOUNT){if(L->hookcount==
|
|
|
|
0){resethookcount(L);luaD_callhook(L,LUA_HOOKCOUNT,-1);return;}}if(mask&
|
|
|
|
LUA_MASKLINE){CallInfo*ci=L->ci;Proto*p=ci_func(ci)->l.p;int newline=getline(p
|
|
|
|
,pcRel(*ci->u.l.pc,p));if(!L->hookinit){luaG_inithooks(L);return;}lua_assert(
|
|
|
|
ci->state&CI_HASFRAME);if(pcRel(*ci->u.l.pc,p)==0)ci->u.l.savedpc=*ci->u.l.pc;
|
|
|
|
if(*ci->u.l.pc<=ci->u.l.savedpc||newline!=getline(p,pcRel(ci->u.l.savedpc,p)))
|
|
|
|
{luaD_callhook(L,LUA_HOOKLINE,newline);ci=L->ci;}ci->u.l.savedpc=*ci->u.l.pc;}
|
|
|
|
}static void callTMres(lua_State*L,const TObject*f,const TObject*p1,const
|
|
|
|
TObject*p2){setobj2s(L->top,f);setobj2s(L->top+1,p1);setobj2s(L->top+2,p2);
|
|
|
|
luaD_checkstack(L,3);L->top+=3;luaD_call(L,L->top-3,1);L->top--;}static void
|
|
|
|
callTM(lua_State*L,const TObject*f,const TObject*p1,const TObject*p2,const
|
|
|
|
TObject*p3){setobj2s(L->top,f);setobj2s(L->top+1,p1);setobj2s(L->top+2,p2);
|
|
|
|
setobj2s(L->top+3,p3);luaD_checkstack(L,4);L->top+=4;luaD_call(L,L->top-4,0);}
|
|
|
|
static const TObject*luaV_index(lua_State*L,const TObject*t,TObject*key,int
|
|
|
|
loop){const TObject*tm=fasttm(L,hvalue(t)->metatable,TM_INDEX);if(tm==NULL)
|
|
|
|
return&luaO_nilobject;if(ttisfunction(tm)){callTMres(L,tm,t,key);return L->top
|
|
|
|
;}else return luaV_gettable(L,tm,key,loop);}static const TObject*
|
|
|
|
luaV_getnotable(lua_State*L,const TObject*t,TObject*key,int loop){const
|
|
|
|
TObject*tm=luaT_gettmbyobj(L,t,TM_INDEX);if(ttisnil(tm))luaG_typeerror(L,t,
|
|
|
|
"index");if(ttisfunction(tm)){callTMres(L,tm,t,key);return L->top;}else return
|
|
|
|
luaV_gettable(L,tm,key,loop);}const TObject*luaV_gettable(lua_State*L,const
|
|
|
|
TObject*t,TObject*key,int loop){if(loop>MAXTAGLOOP)luaG_runerror(L,
|
|
|
|
"loop in gettable");if(ttistable(t)){Table*h=hvalue(t);const TObject*v=
|
|
|
|
luaH_get(h,key);if(!ttisnil(v))return v;else return luaV_index(L,t,key,loop+1)
|
|
|
|
;}else return luaV_getnotable(L,t,key,loop+1);}void luaV_settable(lua_State*L,
|
|
|
|
const TObject*t,TObject*key,StkId val){const TObject*tm;int loop=0;do{if(
|
|
|
|
ttistable(t)){Table*h=hvalue(t);TObject*oldval=luaH_set(L,h,key);if(!ttisnil(
|
|
|
|
oldval)||(tm=fasttm(L,h->metatable,TM_NEWINDEX))==NULL){setobj2t(oldval,val);
|
|
|
|
return;}}else if(ttisnil(tm=luaT_gettmbyobj(L,t,TM_NEWINDEX)))luaG_typeerror(L
|
|
|
|
,t,"index");if(ttisfunction(tm)){callTM(L,tm,t,key,val);return;}t=tm;}while(++
|
|
|
|
loop<=MAXTAGLOOP);luaG_runerror(L,"loop in settable");}static int call_binTM(
|
|
|
|
lua_State*L,const TObject*p1,const TObject*p2,StkId res,TMS event){ptrdiff_t
|
|
|
|
result=savestack(L,res);const TObject*tm=luaT_gettmbyobj(L,p1,event);if(
|
|
|
|
ttisnil(tm))tm=luaT_gettmbyobj(L,p2,event);if(!ttisfunction(tm))return 0;
|
|
|
|
callTMres(L,tm,p1,p2);res=restorestack(L,result);setobjs2s(res,L->top);return
|
|
|
|
1;}static const TObject*get_compTM(lua_State*L,Table*mt1,Table*mt2,TMS event){
|
|
|
|
const TObject*tm1=fasttm(L,mt1,event);const TObject*tm2;if(tm1==NULL)return
|
|
|
|
NULL;if(mt1==mt2)return tm1;tm2=fasttm(L,mt2,event);if(tm2==NULL)return NULL;
|
|
|
|
if(luaO_rawequalObj(tm1,tm2))return tm1;return NULL;}static int call_orderTM(
|
|
|
|
lua_State*L,const TObject*p1,const TObject*p2,TMS event){const TObject*tm1=
|
|
|
|
luaT_gettmbyobj(L,p1,event);const TObject*tm2;if(ttisnil(tm1))return-1;tm2=
|
|
|
|
luaT_gettmbyobj(L,p2,event);if(!luaO_rawequalObj(tm1,tm2))return-1;callTMres(L
|
|
|
|
,tm1,p1,p2);return!l_isfalse(L->top);}static int luaV_strcmp(const TString*ls,
|
|
|
|
const TString*rs){const char*l=getstr(ls);size_t ll=ls->tsv.len;const char*r=
|
|
|
|
getstr(rs);size_t lr=rs->tsv.len;for(;;){int temp=strcoll(l,r);if(temp!=0)
|
|
|
|
return temp;else{size_t len=strlen(l);if(len==lr)return(len==ll)?0:1;else if(
|
|
|
|
len==ll)return-1;len++;l+=len;ll-=len;r+=len;lr-=len;}}}int luaV_lessthan(
|
|
|
|
lua_State*L,const TObject*l,const TObject*r){int res;if(ttype(l)!=ttype(r))
|
|
|
|
return luaG_ordererror(L,l,r);else if(ttisnumber(l))return nvalue(l)<nvalue(r)
|
|
|
|
;else if(ttisstring(l))return luaV_strcmp(tsvalue(l),tsvalue(r))<0;else if((
|
|
|
|
res=call_orderTM(L,l,r,TM_LT))!=-1)return res;return luaG_ordererror(L,l,r);}
|
|
|
|
static int luaV_lessequal(lua_State*L,const TObject*l,const TObject*r){int res
|
|
|
|
;if(ttype(l)!=ttype(r))return luaG_ordererror(L,l,r);else if(ttisnumber(l))
|
|
|
|
return nvalue(l)<=nvalue(r);else if(ttisstring(l))return luaV_strcmp(tsvalue(l
|
|
|
|
),tsvalue(r))<=0;else if((res=call_orderTM(L,l,r,TM_LE))!=-1)return res;else
|
|
|
|
if((res=call_orderTM(L,r,l,TM_LT))!=-1)return!res;return luaG_ordererror(L,l,r
|
|
|
|
);}int luaV_equalval(lua_State*L,const TObject*t1,const TObject*t2){const
|
|
|
|
TObject*tm;lua_assert(ttype(t1)==ttype(t2));switch(ttype(t1)){case LUA_TNIL:
|
|
|
|
return 1;case LUA_TNUMBER:return nvalue(t1)==nvalue(t2);case LUA_TBOOLEAN:
|
|
|
|
return bvalue(t1)==bvalue(t2);case LUA_TLIGHTUSERDATA:return pvalue(t1)==
|
|
|
|
pvalue(t2);case LUA_TUSERDATA:{if(uvalue(t1)==uvalue(t2))return 1;tm=
|
|
|
|
get_compTM(L,uvalue(t1)->uv.metatable,uvalue(t2)->uv.metatable,TM_EQ);break;}
|
|
|
|
case LUA_TTABLE:{if(hvalue(t1)==hvalue(t2))return 1;tm=get_compTM(L,hvalue(t1)
|
|
|
|
->metatable,hvalue(t2)->metatable,TM_EQ);break;}default:return gcvalue(t1)==
|
|
|
|
gcvalue(t2);}if(tm==NULL)return 0;callTMres(L,tm,t1,t2);return!l_isfalse(L->
|
|
|
|
top);}void luaV_concat(lua_State*L,int total,int last){do{StkId top=L->base+
|
|
|
|
last+1;int n=2;if(!tostring(L,top-2)||!tostring(L,top-1)){if(!call_binTM(L,top
|
|
|
|
-2,top-1,top-2,TM_CONCAT))luaG_concaterror(L,top-2,top-1);}else if(tsvalue(top
|
|
|
|
-1)->tsv.len>0){lu_mem tl=cast(lu_mem,tsvalue(top-1)->tsv.len)+cast(lu_mem,
|
|
|
|
tsvalue(top-2)->tsv.len);char*buffer;int i;while(n<total&&tostring(L,top-n-1))
|
|
|
|
{tl+=tsvalue(top-n-1)->tsv.len;n++;}if(tl>MAX_SIZET)luaG_runerror(L,
|
|
|
|
"string size overflow");buffer=luaZ_openspace(L,&G(L)->buff,tl);tl=0;for(i=n;i
|
|
|
|
>0;i--){size_t l=tsvalue(top-i)->tsv.len;memcpy(buffer+tl,svalue(top-i),l);tl
|
|
|
|
+=l;}setsvalue2s(top-n,luaS_newlstr(L,buffer,tl));}total-=n-1;last-=n-1;}while
|
|
|
|
(total>1);}static void Arith(lua_State*L,StkId ra,const TObject*rb,const
|
|
|
|
TObject*rc,TMS op){TObject tempb,tempc;const TObject*b,*c;if((b=luaV_tonumber(
|
|
|
|
rb,&tempb))!=NULL&&(c=luaV_tonumber(rc,&tempc))!=NULL){switch(op){case TM_ADD:
|
|
|
|
setnvalue(ra,nvalue(b)+nvalue(c));break;case TM_SUB:setnvalue(ra,nvalue(b)-
|
|
|
|
nvalue(c));break;case TM_MUL:setnvalue(ra,nvalue(b)*nvalue(c));break;case
|
|
|
|
TM_DIV:setnvalue(ra,nvalue(b)/nvalue(c));break;case TM_POW:{const TObject*f=
|
|
|
|
luaH_getstr(hvalue(gt(L)),G(L)->tmname[TM_POW]);ptrdiff_t res=savestack(L,ra);
|
|
|
|
if(!ttisfunction(f))luaG_runerror(L,"`__pow' (`^' operator) is not a function"
|
|
|
|
);callTMres(L,f,b,c);ra=restorestack(L,res);setobjs2s(ra,L->top);break;}
|
|
|
|
default:lua_assert(0);break;}}else if(!call_binTM(L,rb,rc,ra,op))
|
|
|
|
luaG_aritherror(L,rb,rc);}
|
|
|
|
#define runtime_check(L, c){if(!(c))return 0;}
|
|
|
|
#define RA(i) (base+GETARG_A(i))
|
|
|
|
#define XRA(i) (L->base+GETARG_A(i))
|
|
|
|
#define RB(i) (base+GETARG_B(i))
|
|
|
|
#define RKB(i) ((GETARG_B(i)<MAXSTACK)?RB(i):k+GETARG_B(i)-MAXSTACK)
|
|
|
|
#define RC(i) (base+GETARG_C(i))
|
|
|
|
#define RKC(i) ((GETARG_C(i)<MAXSTACK)?RC(i):k+GETARG_C(i)-MAXSTACK)
|
|
|
|
#define KBx(i) (k+GETARG_Bx(i))
|
|
|
|
#define dojump(pc, i)((pc)+=(i))
|
|
|
|
StkId luaV_execute(lua_State*L){LClosure*cl;TObject*k;const Instruction*pc;
|
|
|
|
callentry:if(L->hookmask&LUA_MASKCALL){L->ci->u.l.pc=&pc;luaD_callhook(L,
|
|
|
|
LUA_HOOKCALL,-1);}retentry:L->ci->u.l.pc=&pc;lua_assert(L->ci->state==
|
|
|
|
CI_SAVEDPC||L->ci->state==(CI_SAVEDPC|CI_CALLING));L->ci->state=CI_HASFRAME;pc
|
|
|
|
=L->ci->u.l.savedpc;cl=&clvalue(L->base-1)->l;k=cl->p->k;for(;;){const
|
|
|
|
Instruction i=*pc++;StkId base,ra;if((L->hookmask&(LUA_MASKLINE|LUA_MASKCOUNT)
|
|
|
|
)&&(--L->hookcount==0||L->hookmask&LUA_MASKLINE)){traceexec(L);if(L->ci->state
|
|
|
|
&CI_YIELD){L->ci->u.l.savedpc=pc-1;L->ci->state=CI_YIELD|CI_SAVEDPC;return
|
|
|
|
NULL;}}base=L->base;ra=RA(i);lua_assert(L->ci->state&CI_HASFRAME);lua_assert(
|
|
|
|
base==L->ci->base);lua_assert(L->top<=L->stack+L->stacksize&&L->top>=base);
|
|
|
|
lua_assert(L->top==L->ci->top||GET_OPCODE(i)==OP_CALL||GET_OPCODE(i)==
|
|
|
|
OP_TAILCALL||GET_OPCODE(i)==OP_RETURN||GET_OPCODE(i)==OP_SETLISTO);switch(
|
|
|
|
GET_OPCODE(i)){case OP_MOVE:{setobjs2s(ra,RB(i));break;}case OP_LOADK:{
|
|
|
|
setobj2s(ra,KBx(i));break;}case OP_LOADBOOL:{setbvalue(ra,GETARG_B(i));if(
|
|
|
|
GETARG_C(i))pc++;break;}case OP_LOADNIL:{TObject*rb=RB(i);do{setnilvalue(rb--)
|
|
|
|
;}while(rb>=ra);break;}case OP_GETUPVAL:{int b=GETARG_B(i);setobj2s(ra,cl->
|
|
|
|
upvals[b]->v);break;}case OP_GETGLOBAL:{TObject*rb=KBx(i);const TObject*v;
|
|
|
|
lua_assert(ttisstring(rb)&&ttistable(&cl->g));v=luaH_getstr(hvalue(&cl->g),
|
|
|
|
tsvalue(rb));if(!ttisnil(v)){setobj2s(ra,v);}else setobj2s(XRA(i),luaV_index(L
|
|
|
|
,&cl->g,rb,0));break;}case OP_GETTABLE:{StkId rb=RB(i);TObject*rc=RKC(i);if(
|
|
|
|
ttistable(rb)){const TObject*v=luaH_get(hvalue(rb),rc);if(!ttisnil(v)){
|
|
|
|
setobj2s(ra,v);}else setobj2s(XRA(i),luaV_index(L,rb,rc,0));}else setobj2s(XRA
|
|
|
|
(i),luaV_getnotable(L,rb,rc,0));break;}case OP_SETGLOBAL:{lua_assert(
|
|
|
|
ttisstring(KBx(i))&&ttistable(&cl->g));luaV_settable(L,&cl->g,KBx(i),ra);break
|
|
|
|
;}case OP_SETUPVAL:{int b=GETARG_B(i);setobj(cl->upvals[b]->v,ra);break;}case
|
|
|
|
OP_SETTABLE:{luaV_settable(L,ra,RKB(i),RKC(i));break;}case OP_NEWTABLE:{int b=
|
|
|
|
GETARG_B(i);b=fb2int(b);sethvalue(ra,luaH_new(L,b,GETARG_C(i)));luaC_checkGC(L
|
|
|
|
);break;}case OP_SELF:{StkId rb=RB(i);TObject*rc=RKC(i);runtime_check(L,
|
|
|
|
ttisstring(rc));setobjs2s(ra+1,rb);if(ttistable(rb)){const TObject*v=
|
|
|
|
luaH_getstr(hvalue(rb),tsvalue(rc));if(!ttisnil(v)){setobj2s(ra,v);}else
|
|
|
|
setobj2s(XRA(i),luaV_index(L,rb,rc,0));}else setobj2s(XRA(i),luaV_getnotable(L
|
|
|
|
,rb,rc,0));break;}case OP_ADD:{TObject*rb=RKB(i);TObject*rc=RKC(i);if(
|
|
|
|
ttisnumber(rb)&&ttisnumber(rc)){setnvalue(ra,nvalue(rb)+nvalue(rc));}else
|
|
|
|
Arith(L,ra,rb,rc,TM_ADD);break;}case OP_SUB:{TObject*rb=RKB(i);TObject*rc=RKC(
|
|
|
|
i);if(ttisnumber(rb)&&ttisnumber(rc)){setnvalue(ra,nvalue(rb)-nvalue(rc));}
|
|
|
|
else Arith(L,ra,rb,rc,TM_SUB);break;}case OP_MUL:{TObject*rb=RKB(i);TObject*rc
|
|
|
|
=RKC(i);if(ttisnumber(rb)&&ttisnumber(rc)){setnvalue(ra,nvalue(rb)*nvalue(rc))
|
|
|
|
;}else Arith(L,ra,rb,rc,TM_MUL);break;}case OP_DIV:{TObject*rb=RKB(i);TObject*
|
|
|
|
rc=RKC(i);if(ttisnumber(rb)&&ttisnumber(rc)){setnvalue(ra,nvalue(rb)/nvalue(rc
|
|
|
|
));}else Arith(L,ra,rb,rc,TM_DIV);break;}case OP_POW:{Arith(L,ra,RKB(i),RKC(i)
|
|
|
|
,TM_POW);break;}case OP_UNM:{const TObject*rb=RB(i);TObject temp;if(tonumber(
|
|
|
|
rb,&temp)){setnvalue(ra,-nvalue(rb));}else{setnilvalue(&temp);if(!call_binTM(L
|
|
|
|
,RB(i),&temp,ra,TM_UNM))luaG_aritherror(L,RB(i),&temp);}break;}case OP_NOT:{
|
|
|
|
int res=l_isfalse(RB(i));setbvalue(ra,res);break;}case OP_CONCAT:{int b=
|
|
|
|
GETARG_B(i);int c=GETARG_C(i);luaV_concat(L,c-b+1,c);base=L->base;setobjs2s(RA
|
|
|
|
(i),base+b);luaC_checkGC(L);break;}case OP_JMP:{dojump(pc,GETARG_sBx(i));break
|
|
|
|
;}case OP_EQ:{if(equalobj(L,RKB(i),RKC(i))!=GETARG_A(i))pc++;else dojump(pc,
|
|
|
|
GETARG_sBx(*pc)+1);break;}case OP_LT:{if(luaV_lessthan(L,RKB(i),RKC(i))!=
|
|
|
|
GETARG_A(i))pc++;else dojump(pc,GETARG_sBx(*pc)+1);break;}case OP_LE:{if(
|
|
|
|
luaV_lessequal(L,RKB(i),RKC(i))!=GETARG_A(i))pc++;else dojump(pc,GETARG_sBx(*
|
|
|
|
pc)+1);break;}case OP_TEST:{TObject*rb=RB(i);if(l_isfalse(rb)==GETARG_C(i))pc
|
|
|
|
++;else{setobjs2s(ra,rb);dojump(pc,GETARG_sBx(*pc)+1);}break;}case OP_CALL:
|
|
|
|
case OP_TAILCALL:{StkId firstResult;int b=GETARG_B(i);int nresults;if(b!=0)L->
|
|
|
|
top=ra+b;nresults=GETARG_C(i)-1;firstResult=luaD_precall(L,ra);if(firstResult)
|
|
|
|
{if(firstResult>L->top){lua_assert(L->ci->state==(CI_C|CI_YIELD));(L->ci-1)->u
|
|
|
|
.l.savedpc=pc;(L->ci-1)->state=CI_SAVEDPC;return NULL;}luaD_poscall(L,nresults
|
|
|
|
,firstResult);if(nresults>=0)L->top=L->ci->top;}else{if(GET_OPCODE(i)==OP_CALL
|
|
|
|
){(L->ci-1)->u.l.savedpc=pc;(L->ci-1)->state=(CI_SAVEDPC|CI_CALLING);}else{int
|
|
|
|
aux;base=(L->ci-1)->base;ra=RA(i);if(L->openupval)luaF_close(L,base);for(aux=
|
|
|
|
0;ra+aux<L->top;aux++)setobjs2s(base+aux-1,ra+aux);(L->ci-1)->top=L->top=base+
|
|
|
|
aux;lua_assert(L->ci->state&CI_SAVEDPC);(L->ci-1)->u.l.savedpc=L->ci->u.l.
|
|
|
|
savedpc;(L->ci-1)->u.l.tailcalls++;(L->ci-1)->state=CI_SAVEDPC;L->ci--;L->base
|
|
|
|
=L->ci->base;}goto callentry;}break;}case OP_RETURN:{CallInfo*ci=L->ci-1;int b
|
|
|
|
=GETARG_B(i);if(b!=0)L->top=ra+b-1;lua_assert(L->ci->state&CI_HASFRAME);if(L->
|
|
|
|
openupval)luaF_close(L,base);L->ci->state=CI_SAVEDPC;L->ci->u.l.savedpc=pc;if(
|
|
|
|
!(ci->state&CI_CALLING)){lua_assert((ci->state&CI_C)||ci->u.l.pc!=&pc);return
|
|
|
|
ra;}else{int nresults;lua_assert(ttisfunction(ci->base-1)&&(ci->state&
|
|
|
|
CI_SAVEDPC));lua_assert(GET_OPCODE(*(ci->u.l.savedpc-1))==OP_CALL);nresults=
|
|
|
|
GETARG_C(*(ci->u.l.savedpc-1))-1;luaD_poscall(L,nresults,ra);if(nresults>=0)L
|
|
|
|
->top=L->ci->top;goto retentry;}}case OP_FORLOOP:{lua_Number step,idx,limit;
|
|
|
|
const TObject*plimit=ra+1;const TObject*pstep=ra+2;if(!ttisnumber(ra))
|
|
|
|
luaG_runerror(L,"`for' initial value must be a number");if(!tonumber(plimit,ra
|
|
|
|
+1))luaG_runerror(L,"`for' limit must be a number");if(!tonumber(pstep,ra+2))
|
|
|
|
luaG_runerror(L,"`for' step must be a number");step=nvalue(pstep);idx=nvalue(
|
|
|
|
ra)+step;limit=nvalue(plimit);if(step>0?idx<=limit:idx>=limit){dojump(pc,
|
|
|
|
GETARG_sBx(i));chgnvalue(ra,idx);}break;}case OP_TFORLOOP:{int nvar=GETARG_C(i
|
|
|
|
)+1;StkId cb=ra+nvar+2;setobjs2s(cb,ra);setobjs2s(cb+1,ra+1);setobjs2s(cb+2,ra
|
|
|
|
+2);L->top=cb+3;luaD_call(L,cb,nvar);L->top=L->ci->top;ra=XRA(i)+2;cb=ra+nvar;
|
|
|
|
do{nvar--;setobjs2s(ra+nvar,cb+nvar);}while(nvar>0);if(ttisnil(ra))pc++;else
|
|
|
|
dojump(pc,GETARG_sBx(*pc)+1);break;}case OP_TFORPREP:{if(ttistable(ra)){
|
|
|
|
setobjs2s(ra+1,ra);setobj2s(ra,luaH_getstr(hvalue(gt(L)),luaS_new(L,"next")));
|
|
|
|
}dojump(pc,GETARG_sBx(i));break;}case OP_SETLIST:case OP_SETLISTO:{int bc;int
|
|
|
|
n;Table*h;runtime_check(L,ttistable(ra));h=hvalue(ra);bc=GETARG_Bx(i);if(
|
|
|
|
GET_OPCODE(i)==OP_SETLIST)n=(bc&(LFIELDS_PER_FLUSH-1))+1;else{n=L->top-ra-1;L
|
|
|
|
->top=L->ci->top;}bc&=~(LFIELDS_PER_FLUSH-1);for(;n>0;n--)setobj2t(luaH_setnum
|
|
|
|
(L,h,bc+n),ra+n);break;}case OP_CLOSE:{luaF_close(L,ra);break;}case OP_CLOSURE
|
|
|
|
:{Proto*p;Closure*ncl;int nup,j;p=cl->p->p[GETARG_Bx(i)];nup=p->nups;ncl=
|
|
|
|
luaF_newLclosure(L,nup,&cl->g);ncl->l.p=p;for(j=0;j<nup;j++,pc++){if(
|
|
|
|
GET_OPCODE(*pc)==OP_GETUPVAL)ncl->l.upvals[j]=cl->upvals[GETARG_B(*pc)];else{
|
|
|
|
lua_assert(GET_OPCODE(*pc)==OP_MOVE);ncl->l.upvals[j]=luaF_findupval(L,base+
|
|
|
|
GETARG_B(*pc));}}setclvalue(ra,ncl);luaC_checkGC(L);break;}}}}
|
|
|
|
#line 1 "lzio.c"
|
|
|
|
#define lzio_c
|
|
|
|
int luaZ_fill(ZIO*z){size_t size;const char*buff=z->reader(NULL,z->data,&size)
|
|
|
|
;if(buff==NULL||size==0)return EOZ;z->n=size-1;z->p=buff;return char2int(*(z->
|
|
|
|
p++));}int luaZ_lookahead(ZIO*z){if(z->n==0){int c=luaZ_fill(z);if(c==EOZ)
|
|
|
|
return c;z->n++;z->p--;}return char2int(*z->p);}void luaZ_init(ZIO*z,
|
|
|
|
lua_Chunkreader reader,void*data,const char*name){z->reader=reader;z->data=
|
|
|
|
data;z->name=name;z->n=0;z->p=NULL;}size_t luaZ_read(ZIO*z,void*b,size_t n){
|
|
|
|
while(n){size_t m;if(z->n==0){if(luaZ_fill(z)==EOZ)return n;else{++z->n;--z->p
|
|
|
|
;}}m=(n<=z->n)?n:z->n;memcpy(b,z->p,m);z->n-=m;z->p+=m;b=(char*)b+m;n-=m;}
|
|
|
|
return 0;}char*luaZ_openspace(lua_State*L,Mbuffer*buff,size_t n){if(n>buff->
|
|
|
|
buffsize){if(n<LUA_MINBUFFER)n=LUA_MINBUFFER;luaM_reallocvector(L,buff->buffer
|
|
|
|
,buff->buffsize,n,char);buff->buffsize=n;}return buff->buffer;}
|
|
|
|
|