Lunatic t.: handle prefix-problematic commands for real, definelevelname, ...

git-svn-id: https://svn.eduke32.com/eduke32@2763 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2012-06-17 19:45:37 +00:00
parent 5bdbd2eda5
commit 67dabd84f8
6 changed files with 105 additions and 50 deletions

View file

@ -69,6 +69,7 @@ extern "C" {
#define RECSYNCBUFSIZ 2520 //2520 is the (LCM of 1-8)*3 #define RECSYNCBUFSIZ 2520 //2520 is the (LCM of 1-8)*3
#define MOVEFIFOSIZ 2 #define MOVEFIFOSIZ 2
// KEEPINSYNC lunatic/con_lang.lua
#define MAXVOLUMES 7 #define MAXVOLUMES 7
#define MAXLEVELS 64 #define MAXLEVELS 64
#define MAXGAMETYPES 16 #define MAXGAMETYPES 16

View file

@ -10,6 +10,9 @@ return
{ {
MAXVOLUMES = 7,
MAXLEVELS = 64,
-- KEEPINSYNC gamedef.h -- KEEPINSYNC gamedef.h
labels = labels =
{ {

View file

@ -582,11 +582,9 @@ local function basicSerialize(o)
if (o == -1/0) then return "-1/0" end -- -inf if (o == -1/0) then return "-1/0" end -- -inf
return tostring(o) return tostring(o)
else -- must be a string elseif (type(o) == "boolean") then
if (type(o) ~= "string") then return tostring(o)
error("cannot save a " .. type(o) .. " as key of a table", 3); elseif (type(o) == "string") then
end
return string.format("%q", o) return string.format("%q", o)
end end
end end
@ -599,8 +597,10 @@ local function save(name, value, saved, strings)
strings[#strings+1] = name .. "=" strings[#strings+1] = name .. "="
if (type(value) == "number" or type(value) == "string") then local str = basicSerialize(value)
strings[#strings+1] = basicSerialize(value) .. "\n"
if (str ~= nil) then
strings[#strings+1] = str .. "\n"
elseif (type(value) == "table") then elseif (type(value) == "table") then
if (saved[value]) then -- value already saved? if (saved[value]) then -- value already saved?
strings[#strings+1] = saved[value] .. "\n" -- use its previous name strings[#strings+1] = saved[value] .. "\n" -- use its previous name
@ -609,7 +609,11 @@ local function save(name, value, saved, strings)
strings[#strings+1] = "{}\n" -- create a new table strings[#strings+1] = "{}\n" -- create a new table
for k,v in pairs(value) do -- save its fields for k,v in pairs(value) do -- save its fields
local fieldname = string.format("%s[%s]", name, basicSerialize(k)) local keystr = basicSerialize(k)
if (keystr == nil) then
error("cannot save a " .. type(k) .. " as key of a table", 2);
end
local fieldname = string.format("%s[%s]", name, keystr)
if (type(v)=="table" and not tmpgvtabs[v]) then if (type(v)=="table" and not tmpgvtabs[v]) then
error("cannot save \""..name.. error("cannot save \""..name..
"\": gamevar tables may only contain tables that are also gamevars", 2) "\": gamevar tables may only contain tables that are also gamevars", 2)

View file

@ -118,7 +118,7 @@ local function lookup_defined_label(identifier)
if (num == nil) then if (num == nil) then
errprintf("label \"%s\" is not defined", identifier) errprintf("label \"%s\" is not defined", identifier)
return -inf return -inf -- return a number for type cleanness
end end
return num return num
@ -133,7 +133,7 @@ local function do_define_label(identifier, idornum)
else else
assert(idornum ~= nil) assert(idornum ~= nil)
num = lookup_defined_label(idornum) num = lookup_defined_label(idornum)
if (num == -1/0) then if (num == -inf) then
return return
end end
end end
@ -200,6 +200,38 @@ else
end end
end end
--- Per-module game data
local g_data = {}
local EPMUL = con.MAXLEVELS
local function reset_gamedata()
g_data = {}
-- [EPMUL*ep + lev] = { ptime=<num>, dtime=<num>, fn=<str>, name=<str> }
g_data.levels = {}
end
local function cmd_definelevelname(vol, lev, fn, ptstr, dtstr, levname)
if (vol < 0 or vol >= con.MAXVOLUMES) then
errprintf("volume number exceeds maximum volume count.")
end
if (lev < 0 or lev >= con.MAXLEVELS) then
errprintf("level number exceeds maximum number of levels per episode.")
end
-- TODO: Bcorrectfilename(fn)
local function secs(tstr)
local m, s = string.match(tstr, ".+:.+")
m, s = tonumber(m), tonumber(s)
return (m and s) and m*60+s or 0
end
g_data.levels[EPMUL*vol+lev] = {
ptime=secs(ptstr), dtime=secs(dtstr), fn=fn, name=levname
}
end
----==== patterns ====---- ----==== patterns ====----
@ -231,8 +263,8 @@ local t_identifier = Var("t_identifier")
-- This one matches keywords, too: -- This one matches keywords, too:
local t_identifier_all = Var("t_identifier_all") local t_identifier_all = Var("t_identifier_all")
local t_define = Var("t_define") local t_define = Var("t_define")
-- NOTE: no chance to whitespace in filenames: -- NOTE: no chance to whitespace and double quotes in filenames:
local t_filename = lpeg.C((anychar-Set(" \t\r\n"))^1) local t_filename = lpeg.C((anychar-Set(" \t\r\n\""))^1)
local t_newline_term_str = match_until(anychar, newline) local t_newline_term_str = match_until(anychar, newline)
-- new-style inline arrays and structures: -- new-style inline arrays and structures:
@ -295,6 +327,8 @@ local function cmd(...)
end end
local t_time = lpeg.C(alphanum*alphanum^-1*":"*alphanum*alphanum^-1) -- for definelevelname
-- The command names will be attached to the front of the patterns later! -- The command names will be attached to the front of the patterns later!
--== Top level CON commands ==-- --== Top level CON commands ==--
@ -318,7 +352,8 @@ local Co = {
definecheat = newline_term_string, -- XXX: actually tricker syntax (TS) definecheat = newline_term_string, -- XXX: actually tricker syntax (TS)
definegamefuncname = newline_term_string, -- XXX: TS? definegamefuncname = newline_term_string, -- XXX: TS?
definegametype = n_defines(2) * newline_term_string, definegametype = n_defines(2) * newline_term_string,
definelevelname = n_defines(2) * newline_term_string, -- XXX: TS definelevelname = n_defines(2) * sp1 * t_filename * sp1 * t_time * sp1 * t_time *
newline_term_string / cmd_definelevelname,
defineskillname = sp1 * t_define * newline_term_string, defineskillname = sp1 * t_define * newline_term_string,
definevolumename = sp1 * t_define * newline_term_string, definevolumename = sp1 * t_define * newline_term_string,
@ -326,7 +361,7 @@ local Co = {
defineprojectile = cmd(D,D,D), defineprojectile = cmd(D,D,D),
definesound = sp1 * t_define * sp1 * maybe_quoted_filename * n_defines(5), -- XXX: TS definesound = sp1 * t_define * sp1 * maybe_quoted_filename * n_defines(5), -- XXX: TS
-- NOTE: gamevar.ogg is OK, too -- NOTE: gamevar.ogg and the like is OK, too
music = sp1 * t_define * match_until(sp1 * t_filename, sp1 * con.keyword * sp1), music = sp1 * t_define * match_until(sp1 * t_filename, sp1 * con.keyword * sp1),
--- 3. Game Settings --- 3. Game Settings
@ -393,6 +428,10 @@ local setperxvarcmd = -- set<actor/player>var[<idx>].<member> <var>
arraypat * memberpat * sp1 * t_rvar arraypat * memberpat * sp1 * t_rvar
-- NOTE about prefixes: most is handled by all_alt_pattern(), however commands
-- that have no arguments and that are prefixes of other commands MUST be
-- suffixed with a "* #sp1" pattern.
local Ci = { local Ci = {
-- these can appear anywhere in the script -- these can appear anywhere in the script
["break"] = cmd(), ["break"] = cmd(),
@ -605,7 +644,7 @@ local Ci = {
activatebysector = cmd(R,R), activatebysector = cmd(R,R),
addlogvar = cmd(R), addlogvar = cmd(R),
-- addlog = cmd(), -- must come after addlogvar addlog = cmd() * #sp1,
addweaponvar = cmd(R,R), -- exec SPECIAL HANDLING! addweaponvar = cmd(R,R), -- exec SPECIAL HANDLING!
cansee = cmd(R,R,R,R,R,R,R,R,W), cansee = cmd(R,R,R,R,R,R,R,R,W),
canseespr = cmd(R,R,W), canseespr = cmd(R,R,W),
@ -638,8 +677,7 @@ local Ci = {
operatesectors = cmd(R,R), operatesectors = cmd(R,R),
palfrom = (sp1 * t_define)^-4, palfrom = (sp1 * t_define)^-4,
-- must come after all other operate* commands operate = cmd() * #sp1,
-- operate = cmd(),
myos = cmd(R,R,R,R,R), myos = cmd(R,R,R,R,R),
myosx = cmd(R,R,R,R,R), myosx = cmd(R,R,R,R,R),
@ -768,7 +806,7 @@ local Cif = {
ifclient = cmd(), ifclient = cmd(),
ifcanshoottarget = cmd(), ifcanshoottarget = cmd(),
ifcanseetarget = cmd(), ifcanseetarget = cmd(),
-- ifcansee = cmd(), ifcansee = cmd() * #sp1,
ifbulletnear = cmd(), ifbulletnear = cmd(),
ifawayfromwall = cmd(), ifawayfromwall = cmd(),
ifactornotstayput = cmd(), ifactornotstayput = cmd(),
@ -883,7 +921,7 @@ end
-- attach the command names at the front! -- attach the command names at the front!
local function attachnames(kwtab) local function attachnames(kwtab)
for cmdname,cmdpat in pairs(kwtab) do for cmdname,cmdpat in pairs(kwtab) do
-- The always-nil-returning function at the end is so that every -- The match-time function capture at the end is so that every
-- command acts as a barrier to captures to prevent stack overflow (and -- command acts as a barrier to captures to prevent stack overflow (and
-- to make lpeg.match return a subject position at the end) -- to make lpeg.match return a subject position at the end)
kwtab[cmdname] = lpeg.Cmt(Keyw(cmdname) * cmdpat, after_cmd_Cmt) kwtab[cmdname] = lpeg.Cmt(Keyw(cmdname) * cmdpat, after_cmd_Cmt)
@ -895,20 +933,36 @@ attachnames(Ci)
attachnames(Cif) attachnames(Cif)
-- Takes one or more tables and +'s all its patterns together in the order of -- Takes one or more tables and +'s all its patterns together in reverse
-- appearance. -- lexicographical order.
-- The tables must map command names to their patterns. -- Each such PATTAB must be a table that maps command names to their patterns.
local function all_alt_pattern(...) local function all_alt_pattern(...)
local pat = Pat(false) local cmds = {}
local args = {...} local args = {...}
assert(#args <= 2)
for argi=1,#args do for argi=1,#args do
local pattab = args[argi] local pattab = args[argi]
-- NOTE: pairs() iterates in undefined order!
-- We can't handle prefix-problematic commands this way here. -- pairs() iterates in undefined order, so we first fill in the names...
for cmdname,cmdpat in pairs(pattab) do for cmdname,_ in pairs(pattab) do
pat = cmdpat + pat cmds[#cmds+1] = cmdname
end end
end end
-- ...and then sort them in ascending lexicographical order
table.sort(cmds)
local pat = Pat(false)
for i=1,#cmds do
local ourpat = args[1][cmds[i]] or args[2][cmds[i]]
-- shorter commands go at the end!
pat = pat + ourpat
end
return pat return pat
end end
@ -917,20 +971,9 @@ local function warn_on_lonely_else()
warnprintf("found `else' with no `if'") warnprintf("found `else' with no `if'")
end end
-- NOTE: The indented text is not true, e.g. addlog vs. addlogvar:
-- since 'addlog' has no args, it will get matched given an 'addlogvar' in the subject: local con_inner_command = all_alt_pattern(Ci)
-- About prefixes: I think it's not a problem *here* if e.g. "getactor" comes local con_if_begs = all_alt_pattern(Cif)
-- before "getactorvar", because the pattern for the former will fail
-- eventually in the ordered choice if fed with the latter. However, it DOES
-- matter in the keyword list, see NotKeyw() trace function and comment in
-- con_lang.lua.
-- Do we have more of them? Yes.
-- operate/operate*
-- ifcansee/ifcanseetarget
local con_outer_command = all_alt_pattern(Co)
-- Empty-arged commands that are prefixes of others must come last:
local con_inner_command = all_alt_pattern(Ci) + "addlog" + "operate"
local con_if_begs = all_alt_pattern(Cif) + "ifcansee"
local lone_else = ("else" * sp1)/warn_on_lonely_else local lone_else = ("else" * sp1)/warn_on_lonely_else
@ -989,7 +1032,7 @@ local Grammar = Pat{
-- A translation unit is a (possibly empty) sequence of outer CON -- A translation unit is a (possibly empty) sequence of outer CON
-- commands, separated by at least one whitespace which may be -- commands, separated by at least one whitespace which may be
-- omitted at the EOF. -- omitted at the EOF.
sp0 * ((con_outer_command + all_alt_pattern(Cb)) * sp1)^0, sp0 * (all_alt_pattern(Co, Cb) * sp1)^0,
-- Some often-used terminals follow. These appear here because we're -- Some often-used terminals follow. These appear here because we're
-- hitting a limit with LPeg else. -- hitting a limit with LPeg else.
@ -1085,6 +1128,7 @@ function parse(contents) -- local
if (not idx) then if (not idx) then
printf("[%d] Match failed.", g_recurslevel) printf("[%d] Match failed.", g_recurslevel)
g_numerrors = inf
elseif (idx == #contents+1) then elseif (idx == #contents+1) then
if (g_numerrors ~= 0) then if (g_numerrors ~= 0) then
printf("[%d] Matched whole contents (%d errors).", printf("[%d] Matched whole contents (%d errors).",
@ -1098,6 +1142,7 @@ function parse(contents) -- local
printf("[%d] Match succeeded up to %d (line %d, col %d; len=%d)", printf("[%d] Match succeeded up to %d (line %d, col %d; len=%d)",
g_recurslevel, idx, i, col, #contents) g_recurslevel, idx, i, col, #contents)
g_numerrors = inf
-- printf("Line goes from %d to %d", bi, ei) -- printf("Line goes from %d to %d", bi, ei)
local suffix = "" local suffix = ""
@ -1131,6 +1176,7 @@ if (not _EDUKE32_LUNATIC) then
g_recurslevel = -1 g_recurslevel = -1
g_badids = {} g_badids = {}
reset_labels() reset_labels()
reset_gamedata()
g_numerrors = 0 g_numerrors = 0

View file

@ -32,12 +32,13 @@ mt.__newindex = function (t, n, v)
rawset(t, n, v) rawset(t, n, v)
end end
-- PK: change from original: -- PK: change from original (undeclared-refs in main allowed):
--[[
mt.__index = function (t, n) mt.__index = function (t, n)
if not mt.__declared[n] and what() ~= "C" then if not mt.__declared[n] then
local w = what()
if w ~= "main" and w ~= "C" then
error("variable '"..n.."' is not declared", 2) error("variable '"..n.."' is not declared", 2)
end end
end
return rawget(t, n) return rawget(t, n)
end end
--]]

View file

@ -22,9 +22,9 @@ end
gamevar("ourvar") gamevar("ourvar")
gamevar("ourvar2") gamevar("ourvar2")
-- test nans, infs, precision, subnorms -- test nans, infs, precision, subnorms, booleans
ourvar2 = { "asd"; 0/0, 1/0, -1/0, 0.12345678901234567, 1e-314 } ourvar2 = { "asd"; 0/0, 1/0, -1/0, 0.12345678901234567, 1e-314, true }
ourvar = { ourvar2; 1, 2, 3, "qwe" } ourvar = { ourvar2; 1, 2, 3, "qwe"; [true]=0, [false]=1 }
ourvar[#ourvar+1] = ourvar; ourvar[#ourvar+1] = ourvar;
local gvstr = DBG_.serializeGamevars() local gvstr = DBG_.serializeGamevars()