Lunatic: cleanup

git-svn-id: https://svn.eduke32.com/eduke32@2863 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2012-08-06 20:00:23 +00:00
parent f4c7e3f77e
commit b983ec7b49
4 changed files with 129 additions and 149 deletions

View file

@ -6,16 +6,18 @@
-- * con.labels -- * con.labels
-- * con.keyword -- * con.keyword
return local lpeg = lpeg
{
MAXVOLUMES = 7, module(...)
MAXLEVELS = 64,
MAXSKILLS = 7,
MAXSOUNDS = 4096, MAXVOLUMES = 7
MAXLEVELS = 64
MAXSKILLS = 7
MAXSOUNDS = 4096
-- KEEPINSYNC gamedef.h -- KEEPINSYNC gamedef.h
@ -157,7 +159,7 @@ labels =
EVENT_LOADGAME = 91, EVENT_LOADGAME = 91,
EVENT_SAVEGAME = 92, EVENT_SAVEGAME = 92,
}, },
}, }
-- NOTE: These MUST be in reverse lexicographical order! -- NOTE: These MUST be in reverse lexicographical order!
@ -533,5 +535,3 @@ lpeg.P(false) +
"activatebysector" + "activatebysector" +
"action" + "action" +
lpeg.P(false) lpeg.P(false)
}

View file

@ -4,6 +4,7 @@
_EDUKE32_LUNATIC = true _EDUKE32_LUNATIC = true
local ffi = require("ffi") local ffi = require("ffi")
local ffiC = ffi.C
---=== Duke3D engine and game definitions ===--- ---=== Duke3D engine and game definitions ===---
ffi.cdef[[ ffi.cdef[[
@ -107,8 +108,7 @@ ffi.cdef[[int32_t engine_main_arrays_are_static, engine_v8;]]
-- NOTE TO SELF: This is not C, never EVER write -- NOTE TO SELF: This is not C, never EVER write
-- if (x) -- if (x)
-- when checking a C variable x for 'thuthiness' -- when checking a C variable x for 'thuthiness'
if (ffi.C.engine_main_arrays_are_static ~= 0) then if (ffiC.engine_main_arrays_are_static ~= 0) then
-- print('main arrays are static');
decl[[ decl[[
sectortype sector[]; sectortype sector[];
walltype wall[]; walltype wall[];
@ -116,7 +116,6 @@ if (ffi.C.engine_main_arrays_are_static ~= 0) then
spriteext_t spriteext[]; spriteext_t spriteext[];
]] ]]
else else
-- print('main arrays are pointers');
decl[[ decl[[
sectortype *sector; sectortype *sector;
walltype *wall; walltype *wall;
@ -125,7 +124,7 @@ else
]] ]]
end end
if (ffi.C.engine_v8 == 0) then if (ffiC.engine_v8 == 0) then
-- V7 -- V7
ffi.cdef[[ ffi.cdef[[
enum enum
@ -279,9 +278,9 @@ typedef struct {
int16_t ang, oang, angvel, cursectnum, look_ang, last_extra, subweapon; int16_t ang, oang, angvel, cursectnum, look_ang, last_extra, subweapon;
]] ]]
..repeat_n_elts("int16_t", "_ma", ffi.C.MAX_WEAPONS) ..repeat_n_elts("int16_t", "_ma", ffiC.MAX_WEAPONS)
..repeat_n_elts("int16_t", "_aa", ffi.C.MAX_WEAPONS) ..repeat_n_elts("int16_t", "_aa", ffiC.MAX_WEAPONS)
..repeat_n_elts("int16_t", "_ia", ffi.C.GET_MAX).. ..repeat_n_elts("int16_t", "_ia", ffiC.GET_MAX)..
[[ [[
// int16_t max_ammo_amount[MAX_WEAPONS], ammo_amount[MAX_WEAPONS], inv_amount[GET_MAX]; // int16_t max_ammo_amount[MAX_WEAPONS], ammo_amount[MAX_WEAPONS], inv_amount[GET_MAX];
int16_t wackedbyactor, pyoff, opyoff; int16_t wackedbyactor, pyoff, opyoff;
@ -295,7 +294,7 @@ typedef struct {
int16_t dummyplayersprite, extra_extra8; int16_t dummyplayersprite, extra_extra8;
int16_t actorsqu, timebeforeexit, customexitsound, last_pissed_time; int16_t actorsqu, timebeforeexit, customexitsound, last_pissed_time;
]] ]]
..repeat_n_elts("int16_t", "_w", ffi.C.MAX_WEAPONS).. ..repeat_n_elts("int16_t", "_w", ffiC.MAX_WEAPONS)..
[[ [[
// int16_t weaprecs[MAX_WEAPONS]; // int16_t weaprecs[MAX_WEAPONS];
int16_t weapon_sway, crack_time, bobcounter; int16_t weapon_sway, crack_time, bobcounter;
@ -501,7 +500,28 @@ int32_t ksqrt(uint32_t num);
ffi.cdef "double gethitickms(void);" ffi.cdef "double gethitickms(void);"
local ffiC = ffi.C
local assert = assert
local error = error
local ipairs = ipairs
local loadstring = loadstring
local pairs = pairs
local print = print
local rawget = rawget
local rawset = rawset
local setmetatable = setmetatable
local setfenv = setfenv
local type = type
local string = string
local table = table
-- http://lua-users.org/wiki/SandBoxes says "potentially unsafe"
-- as it allows to see implementations of functions.
--local string_dump = string.dump
string.dump = nil
-- sanity-check struct type sizes -- sanity-check struct type sizes
for i=0,6 do for i=0,6 do
@ -510,12 +530,12 @@ for i=0,6 do
end end
--- default defines --- default defines
local con = require("con_lang") local con_lang = require("con_lang")
for i=1,#con.labels do for i=1,#con_lang.labels do
local strbuf = {"enum {"} local strbuf = {"enum {"}
for label, val in pairs(con.labels[i]) do for label, val in pairs(con_lang.labels[i]) do
strbuf[#strbuf+1] = string.format("%s = %d,", label, val) strbuf[#strbuf+1] = string.format("%s = %d,", label, val)
end end
strbuf[#strbuf+1] = "};" strbuf[#strbuf+1] = "};"
@ -526,23 +546,13 @@ end
---=== Set up restricted global environment ===--- ---=== Set up restricted global environment ===---
-- These are for this file...
local string = string
local table = table
-- http://lua-users.org/wiki/SandBoxes says "potentially unsafe"
-- as it allows to see implementations of functions.
local string_dump = string.dump
string.dump = nil
gv_tmp = gv_ -- required by randgen gv_tmp = gv_ -- required by randgen
local allowed_modules = { local allowed_modules = {
coroutine=coroutine, bit=bit, table=table, math=math, string=string, coroutine=coroutine, bit=bit, table=table, math=math, string=string,
os = { os = {
clock = function() return gv_.gethitickms()/1000 end, clock = function() return gv_.gethitickms()*0.001 end,
}, },
randgen = require("randgen"), randgen = require("randgen"),
@ -551,13 +561,11 @@ local allowed_modules = {
bitar = require("bitar"), bitar = require("bitar"),
} }
local package_loaded = {}
for modname, themodule in pairs(allowed_modules) do for modname, themodule in pairs(allowed_modules) do
local mt = { local mt = {
__index = themodule, __index = themodule,
__newindex = function(tab,idx,val) __newindex = function(tab,idx,val)
error("modifying base module table forbidden") error("modifying base module table forbidden", 2)
end, end,
__metatable = true, __metatable = true,
} }
@ -566,9 +574,9 @@ for modname, themodule in pairs(allowed_modules) do
allowed_modules[modname] = setmetatable({}, mt) allowed_modules[modname] = setmetatable({}, mt)
end end
local function check_valid_modname(modname) local function check_valid_modname(modname, errlev)
if (type(modname) ~= "string") then if (type(modname) ~= "string") then
error("module name must be a string", 5) error("module name must be a string", errlev+1)
end end
-- TODO: restrict valid names? -- TODO: restrict valid names?
@ -579,8 +587,10 @@ local function errorf(level, fmt, ...)
error(errmsg, level+1) error(errmsg, level+1)
end end
local ERRLEV = 5
local package_loaded = {}
local modname_stack = {}
local ERRLEV = 5
local function readintostr(fn) local function readintostr(fn)
-- XXX: this is pretty much the same as the code in El_RunOnce() -- XXX: this is pretty much the same as the code in El_RunOnce()
@ -619,7 +629,7 @@ end
-- path. Also, our require never messes with the global environment, -- path. Also, our require never messes with the global environment,
-- it only returns the module. -- it only returns the module.
local function our_require(modname) local function our_require(modname)
check_valid_modname(modname) check_valid_modname(modname, 2)
-- see whether it's a base module name first -- see whether it's a base module name first
if (allowed_modules[modname] ~= nil) then if (allowed_modules[modname] ~= nil) then
@ -641,31 +651,27 @@ local function our_require(modname)
errorf(ERRLEV-1, "Couldn't load \"%s\": %s", modname, errmsg) errorf(ERRLEV-1, "Couldn't load \"%s\": %s", modname, errmsg)
end end
local modtab = modfunc(modname) package_loaded[modname] = true
table.insert(modname_stack, modname)
if (modtab ~= nil) then -- Run the module code!
if (type(modtab) ~= "table") then modfunc(modname) -- TODO: call protected and report errors here later
errorf(ERRLEV-1, "Didn't load module \"%s\": expected table as return value", modname)
end
package_loaded[modname] = modtab table.remove(modname_stack)
else
modtab = package_loaded[modname]
if (type(modtab) ~= "table") then local modtab = package_loaded[modname]
errorf(ERRLEV-1, "Didn't load module \"%s\": expected module() to be called", modname)
end
end
-- Protect module table... if (type(modtab) == "table") then
-- Protect module table if there is one...
local mt = { local mt = {
__index = modtab, __index = modtab,
__newindex = function(tab,idx,val) __newindex = function(tab,idx,val)
error("modifying module table forbidden", 2) error("modifying module table forbidden", 2)
end, end,
} }
-- ..here:
setmetatable(modtab, mt) setmetatable(modtab, mt)
end
return modtab return modtab
end end
@ -674,85 +680,68 @@ end
-- _G tweaks -- pull in only 'safe' stuff -- _G tweaks -- pull in only 'safe' stuff
local G_ = {} -- our soon-to-be global environment local G_ = {} -- our soon-to-be global environment
-- Old global environment, to access thrown-out functions later in this chunk.
-- Also, inside this file, we must refer to functions like 'pairs' by using
-- this table, since user code could later do pairs=nil.
local oG = _G
local module_mt = { local module_mt = {
__index = function (_, n) __index = function (_, n)
error("attempt to read undeclared variable '"..n.."'", 2) error("attempt to read undeclared variable '"..n.."'", 2)
end, end,
} }
-- replacement for "module" -- Our 'module' replacement doesn't get the module name from the function args
local function our_module(modname) -- since a malicious user could remove other loaded modules this way.
check_valid_modname(modname) -- TODO: make transactional?
local function our_module()
local modname = modname_stack[#modname_stack]
if (type(modname) ~= "string") then
error("'module' must be called at the top level of a require'd file", 2)
end
local M = oG.setmetatable({}, module_mt) local M = setmetatable({}, module_mt)
package_loaded[modname] = M package_loaded[modname] = M
-- change the environment of the function which called us: -- change the environment of the function which called us:
oG.setfenv(2, M) setfenv(2, M)
end end
-- overridden 'error' that always passes a string to the base 'error' -- overridden 'error' that always passes a string to the base 'error'
local function our_error(errmsg, level) local function our_error(errmsg, level)
if (type(errmsg) ~= "string") then if (type(errmsg) ~= "string") then
oG.error("error using 'error': error message must be a string", 2) error("error using 'error': error message must be a string", 2)
end end
if (level) then if (level) then
if (type(level) ~= "number") then if (type(level) ~= "number") then
oG.error("error using 'error': error level must be a number", 2) error("error using 'error': error level must be a number", 2)
end end
oG.error(errmsg, level==0 and 0 or level+1) error(errmsg, level==0 and 0 or level+1)
end end
oG.error(errmsg, 2) error(errmsg, 2)
end end
G_.require = our_require
G_.module = our_module
---G_.coroutine = coroutine
G_.assert = assert G_.assert = assert
G_.error = our_error
G_.ipairs = ipairs
G_.pairs = pairs
G_.pcall = pcall
G_.print = print -- TODO: --> initprintf or OSD_Printf; why not needed on linux?
G_.module = our_module
G_.next = next
G_.require = our_require
G_.select = select
G_.tostring = tostring G_.tostring = tostring
G_.tonumber = tonumber G_.tonumber = tonumber
--rawget
G_.xpcall = xpcall
G_.ipairs = ipairs
G_.print = print -- TODO: --> initprintf or OSD_Printf; why not needed on linux?
G_.pcall = pcall
--gcinfo --DEPRECATED
--module
--setfenv
--require
--rawset
--jit
---G_.bit = bit
--package
G_.error = our_error
--debug
--loadfile
--rawequal
--load
G_.unpack = unpack
G_.pairs = pairs
---G_.table = table
G_._VERSION = _VERSION
--newproxy --NOT STD?
--collectgarbage
--dofile
G_.next = next
---G_.math = math
--loadstring
--_G
G_.select = select
---G_.string = string
G_.type = type G_.type = type
--getmetatable G_.unpack = unpack
--getfenv G_.xpcall = xpcall
--setmetatable G_._VERSION = _VERSION
-- Available through our 'require':
-- bit, coroutine, math, string, table
-- Not available:
-- collectgarbage, debug, dofile, gcinfo (DEPRECATED), getfenv, getmetatable,
-- jit, load, loadfile, loadstring, newproxy (NOT STD?), package, rawequal,
-- rawget, rawset, setfenv, setmetatable
G_._G = G_ G_._G = G_
@ -772,21 +761,15 @@ local lunacon = require("lunacon")
-- (also in functions created after this point) refer to G_ ! -- (also in functions created after this point) refer to G_ !
setfenv(1, G_) setfenv(1, G_)
-- We MUST remember to call base lib functions through oG here. -- Print keys and values of a table.
-- 'tostring' is a special case: it is used in 'print', i.e. the global 'tostring', -- REMEMBER special position of 'tostring' (it's looked up and used as a global
-- which is looked up in the current environment! Thus, we must REMOVE it and -- from 'print')
-- 'print' for release, or write our own, atomic 'print'.
local error = oG.error
local type = oG.type
local pairs = oG.pairs
-- print keys and values of a table
local function printkv(label, table) local function printkv(label, table)
oG.print('========== Keys and values of '..label) print('========== Keys and values of '..label)
for k,v in oG.pairs(table) do for k,v in pairs(table) do
oG.print(k .. ': ' .. tostring(v)) print(k .. ': ' .. tostring(v))
end end
oG.print('----------') print('----------')
end end
--printkv('_G AFTER SETFENV', _G) --printkv('_G AFTER SETFENV', _G)
@ -796,23 +779,26 @@ end
-- error(..., 2) is to blame the caller and get its line numbers -- error(..., 2) is to blame the caller and get its line numbers
-- set metatable and forbid setting it further
local function setmtonce(tab, mt)
mt.__metatable = true
return setmetatable(tab, mt)
end
local tmpmt = { local tmpmt = {
__index = function() error('dummy variable: read access forbidden', 2) end, __index = function() error('dummy variable: read access forbidden', 2) end,
__newindex = function() error('dummy variable: write access forbidden', 2) end, __newindex = function() error('dummy variable: write access forbidden', 2) end,
__metatable = true, -- forbid setting the metatable
} }
oG.setmetatable(dummy_empty_table, tmpmt) setmtonce(dummy_empty_table, tmpmt)
gv = gv_ gv = gv_
local tmpmt = { local tmpmt = {
__index = ffiC, __index = ffiC,
__newindex = function() error("cannot create new or write into existing fields of 'gv'", 2) end, __newindex = function() error("cannot create new or write into existing fields of 'gv'", 2) end,
__metatable = true,
} }
oG.setmetatable(gv, tmpmt) setmtonce(gv, tmpmt)
---- indirect C array access ---- ---- indirect C array access ----
sector = {}
local tmpmt = { local tmpmt = {
__index = function(tab, key) __index = function(tab, key)
if (key >= 0 and key < ffiC.numsectors) then return ffiC.sector[key] end if (key >= 0 and key < ffiC.numsectors) then return ffiC.sector[key] end
@ -820,11 +806,9 @@ local tmpmt = {
end, end,
__newindex = function(tab, key, val) error('cannot write directly to sector[] struct', 2) end, __newindex = function(tab, key, val) error('cannot write directly to sector[] struct', 2) end,
__metatable = true,
} }
oG.setmetatable(sector, tmpmt) sector = setmtonce({}, tmpmt)
wall = {}
local tmpmt = { local tmpmt = {
__index = function(tab, key) __index = function(tab, key)
if (key >= 0 and key < ffiC.numwalls) then return ffiC.wall[key] end if (key >= 0 and key < ffiC.numwalls) then return ffiC.wall[key] end
@ -832,9 +816,8 @@ local tmpmt = {
end, end,
__newindex = function(tab, key, val) error('cannot write directly to wall[] struct', 2) end, __newindex = function(tab, key, val) error('cannot write directly to wall[] struct', 2) end,
__metatable = true,
} }
oG.setmetatable(wall, tmpmt) wall = setmtonce({}, tmpmt)
-- create a safe indirection for an ffi.C array -- create a safe indirection for an ffi.C array
local function creategtab(ctab, maxidx, name) local function creategtab(ctab, maxidx, name)
@ -849,10 +832,9 @@ local function creategtab(ctab, maxidx, name)
__newindex = function(tab, key, val) __newindex = function(tab, key, val)
error('cannot write directly to '..name, 2) error('cannot write directly to '..name, 2)
end, end,
__metatable = true,
} }
oG.setmetatable(tab, tmpmt)
return tab return setmtonce(tab, tmpmt)
end end
sprite = creategtab(ffiC.sprite, ffiC.MAXSPRITES, 'sprite[] struct') sprite = creategtab(ffiC.sprite, ffiC.MAXSPRITES, 'sprite[] struct')
@ -980,12 +962,12 @@ function gamevar(name, initval) -- aka 'declare'
error(string.format("Duplicate declaration of identifier '%s'", name), 2) error(string.format("Duplicate declaration of identifier '%s'", name), 2)
end end
if (oG.rawget(G_, name) ~= nil) then if (rawget(G_, name) ~= nil) then
error(string.format("Identifier name '%s' is already used in the global environment", name), 2) error(string.format("Identifier name '%s' is already used in the global environment", name), 2)
end end
gamevarNames[name] = true gamevarNames[name] = true
oG.rawset(G_, name, initval or false) rawset(G_, name, initval or false)
end end
@ -1070,14 +1052,14 @@ local function loadGamevarsString(string)
gamevarNames = {}; -- clear gamevars gamevarNames = {}; -- clear gamevars
--]=] --]=]
oG.assert(oG.loadstring(string))() assert(loadstring(string))()
end end
-- REMOVE this for release -- REMOVE this for release
DBG_ = {} DBG_ = {}
DBG_.printkv = printkv DBG_.printkv = printkv
DBG_.loadstring = oG.loadstring DBG_.loadstring = loadstring
DBG_.serializeGamevars = serializeGamevars DBG_.serializeGamevars = serializeGamevars
DBG_.loadGamevarsString = loadGamevarsString DBG_.loadGamevarsString = loadGamevarsString
@ -1089,8 +1071,7 @@ DBG_.loadGamevarsString = loadGamevarsString
-- PiL 14.2 continued -- PiL 14.2 continued
-- We need this at the end because we were previously doing just that! -- We need this at the end because we were previously doing just that!
-- XXX: but user modules will want to do "function thisfunc() ... " setmetatable(
oG.setmetatable(
G_, { G_, {
__newindex = function (_1, n, _2) __newindex = function (_1, n, _2)
error("attempt to write to undeclared variable '"..n.."'", 2) error("attempt to write to undeclared variable '"..n.."'", 2)
@ -1104,4 +1085,4 @@ oG.setmetatable(
-- what we've set up will be available when this chunk is left. -- what we've set up will be available when this chunk is left.
-- In particular, we need the functions defined after setting this chunk's -- In particular, we need the functions defined after setting this chunk's
-- environment earlier. -- environment earlier.
oG.setfenv(0, _G) setfenv(0, _G)

View file

@ -203,7 +203,7 @@ gameevent(gv.EVENT_ENTERLEVEL,
t = gv.gethitickms()-t t = gv.gethitickms()-t
-- x86_64: 35ns/call, x86: 290 ns/call? -- x86_64: 35ns/call, x86: 280 ns/call
-- Windows 32-bit: about 1 us/call? -- Windows 32-bit: about 1 us/call?
printf("%d gethitickms() calls took %.03f ms (%.03f us/call)", printf("%d gethitickms() calls took %.03f ms (%.03f us/call)",
N, t, (t*1000)/N) N, t, (t*1000)/N)

View file

@ -63,9 +63,8 @@ local t4 = os.clock()
-- x86_64 (embedded): approx. 200 ms (vs. the 100 ms of direct -- x86_64 (embedded): approx. 200 ms (vs. the 100 ms of direct
-- ffiC.rand_jkiss_dbl()): -- ffiC.rand_jkiss_dbl()):
-- x86: 170 ms
print(1000*(t2-t1)) print(1000*(t2-t1))
print(1000*(t3-t2)) -- x86_64: approx. 500 ms print(1000*(t3-t2)) -- x86_64: 500 ms, x86: 700 ms
print(1000*(t4-t3)) -- x86_64: approx. 35 ms print(1000*(t4-t3)) -- x86_64, x86: about 35 ms <- thanks to allocation sinking (else, about 500 ms?)
print(v) print(v)
return {} -- appease Lunatic's require