LunaCON: statically check some member assignments with literal numbers.

And issue warnings whenever the assignment would fail (error) at game time.

git-svn-id: https://svn.eduke32.com/eduke32@4195 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2013-12-11 21:23:42 +00:00
parent a7ed1a6fe9
commit 44351528db
3 changed files with 50 additions and 25 deletions

View file

@ -349,12 +349,22 @@ local function S2U(label)
return { s2u(label), label } return { s2u(label), label }
end end
-- Some literal checker functions (LITERAL_CHECKING).
-- KEEPINSYNC with the actual setter code.
local function litok_gem1(lit)
return (lit >= -1)
end
local function litok_ge0(lit)
return (lit >= 0)
end
local ActorLabels = { local ActorLabels = {
x = SP".x", x = SP".x",
y = SP".y", y = SP".y",
z = SP".z", z = SP".z",
cstat = SP".cstat", cstat = SP".cstat",
picnum = { SP".picnum", SP":set_picnum(%%s)" }, picnum = { SP".picnum", SP":set_picnum(%%s)", litok_ge0 },
shade = SP".shade", shade = SP".shade",
pal = SP".pal", pal = SP".pal",
clipdist = SP".clipdist", clipdist = SP".clipdist",
@ -364,10 +374,10 @@ local ActorLabels = {
yrepeat = SP".yrepeat", yrepeat = SP".yrepeat",
xoffset = SP".xoffset", xoffset = SP".xoffset",
yoffset = SP".yoffset", yoffset = SP".yoffset",
sectnum = { SP".sectnum", SP":changesect(%%s)" }, -- set: for tsprite sectnum = { SP".sectnum", SP":changesect(%%s)", litok_ge0 }, -- set: for tsprite
statnum = { SP".statnum" }, statnum = { SP".statnum" },
ang = SP".ang", ang = SP".ang",
owner = { SP".owner", SP":_set_owner(%%s)" }, owner = { SP".owner", SP":_set_owner(%%s)", litok_ge0 },
xvel = SP".xvel", xvel = SP".xvel",
yvel = { SP".yvel", SP":_set_yvel(%%s)" }, -- XXX yvel = { SP".yvel", SP":_set_yvel(%%s)" }, -- XXX
zvel = SP".zvel", zvel = SP".zvel",
@ -380,10 +390,11 @@ local ActorLabels = {
-- ActorExtra labels... -- ActorExtra labels...
htcgg = AC".cgg", htcgg = AC".cgg",
-- XXX: why <0 allowed?
htpicnum = { AC".picnum", AC":set_picnum(%%s)" }, htpicnum = { AC".picnum", AC":set_picnum(%%s)" },
htang = AC".ang", htang = AC".ang",
htextra = AC".extra", htextra = AC".extra",
htowner = { AC".owner", AC":set_owner(%%s)" }, htowner = { AC".owner", AC":set_owner(%%s)", litok_ge0 },
htmovflag = AC"._movflag", htmovflag = AC"._movflag",
httempang = AC".tempang", httempang = AC".tempang",
htactorstayput = AC".stayputsect", -- NAME htactorstayput = AC".stayputsect", -- NAME
@ -674,7 +685,7 @@ local SectorLabels = {
floorstat = SEC".floorstat", floorstat = SEC".floorstat",
-- CEILING -- CEILING
ceilingpicnum = { SEC".ceilingpicnum", SEC":set_ceilingpicnum(%%s)" }, ceilingpicnum = { SEC".ceilingpicnum", SEC":set_ceilingpicnum(%%s)", litok_ge0 },
ceilingslope = SEC".ceilingheinum", -- NAME ceilingslope = SEC".ceilingheinum", -- NAME
ceilingshade = SEC".ceilingshade", ceilingshade = SEC".ceilingshade",
@ -684,7 +695,7 @@ local SectorLabels = {
ceilingypanning = SEC".ceilingypanning", ceilingypanning = SEC".ceilingypanning",
-- FLOOR -- FLOOR
floorpicnum = { SEC".floorpicnum", SEC":set_floorpicnum(%%s)" }, floorpicnum = { SEC".floorpicnum", SEC":set_floorpicnum(%%s)", litok_ge0 },
floorslope = SEC".floorheinum", -- NAME floorslope = SEC".floorheinum", -- NAME
floorshade = SEC".floorshade", floorshade = SEC".floorshade",
@ -718,8 +729,8 @@ local WallLabels = {
nextwall = { WAL".nextwall", WAL":_set_nextwall(%%s)" }, nextwall = { WAL".nextwall", WAL":_set_nextwall(%%s)" },
nextsector = { WAL".nextsector", WAL":_set_nextsector(%%s)" }, nextsector = { WAL".nextsector", WAL":_set_nextsector(%%s)" },
cstat = WAL".cstat", cstat = WAL".cstat",
picnum = { WAL".picnum", WAL":set_picnum(%%s)" }, picnum = { WAL".picnum", WAL":set_picnum(%%s)", litok_ge0 },
overpicnum = { WAL".overpicnum", WAL":set_overpicnum(%%s)" }, overpicnum = { WAL".overpicnum", WAL":set_overpicnum(%%s)", litok_ge0 },
shade = WAL".shade", shade = WAL".shade",
pal = WAL".pal", pal = WAL".pal",
xrepeat = WAL".xrepeat", xrepeat = WAL".xrepeat",
@ -751,17 +762,17 @@ local ProjectileLabels = {
hitradius = PROJ".hitradius", hitradius = PROJ".hitradius",
range = PROJ".range", range = PROJ".range",
flashcolor = PROJ".flashcolor", flashcolor = PROJ".flashcolor",
spawns = { PROJ".spawns", PROJ":set_spawns(%%s)" }, spawns = { PROJ".spawns", PROJ":set_spawns(%%s)", litok_gem1 },
sound = { PROJ".sound", PROJ":set_sound(%%s)" }, sound = { PROJ".sound", PROJ":set_sound(%%s)", litok_gem1 },
isound = { PROJ".isound", PROJ":set_isound(%%s)" }, isound = { PROJ".isound", PROJ":set_isound(%%s)", litok_gem1 },
vel = PROJ".vel", vel = PROJ".vel",
decal = { PROJ".decal", PROJ":set_decal(%%s)" }, decal = { PROJ".decal", PROJ":set_decal(%%s)", litok_gem1 },
trail = { PROJ".trail", PROJ":set_trail(%%s)" }, trail = { PROJ".trail", PROJ":set_trail(%%s)", litok_gem1 },
tnum = PROJ".tnum", tnum = PROJ".tnum",
drop = PROJ".drop", drop = PROJ".drop",
offset = PROJ".offset", offset = PROJ".offset",
bounces = PROJ".bounces", bounces = PROJ".bounces",
bsound = { PROJ".bsound", PROJ":set_bsound(%%s)" }, bsound = { PROJ".bsound", PROJ":set_bsound(%%s)", litok_gem1 },
toffset = PROJ".toffset", toffset = PROJ".toffset",
extra = PROJ".extra", extra = PROJ".extra",
extra_rand = PROJ".extra_rand", extra_rand = PROJ".extra_rand",
@ -817,7 +828,7 @@ local UserdefLabels = {
fta_on = UD".fta_on", fta_on = UD".fta_on",
god = UDRO".god", god = UDRO".god",
idplayers = UDRO".idplayers", idplayers = UDRO".idplayers",
level_number = { UD".level_number", UD":set_level_number(%%s)" }, level_number = { UD".level_number", UD":set_level_number(%%s)", {0, MAXLEVELS-1} },
levelstats = UD".levelstats", levelstats = UD".levelstats",
lockout = UDRO".lockout", lockout = UDRO".lockout",
m_player_skill = UDRO".m_player_skill", m_player_skill = UDRO".m_player_skill",
@ -835,7 +846,7 @@ local UserdefLabels = {
showallmap = UD".showallmap", showallmap = UD".showallmap",
showweapons = UDRO".showweapons", showweapons = UDRO".showweapons",
statusbarscale = UDRO".statusbarscale", statusbarscale = UDRO".statusbarscale",
volume_number = { UD".volume_number", UD":set_volume_number(%%s)" }, volume_number = { UD".volume_number", UD":set_volume_number(%%s)", {0, MAXVOLUMES} },
weaponscale = UDRO".weaponscale", weaponscale = UDRO".weaponscale",
weaponswitch = UD".weaponswitch", weaponswitch = UD".weaponswitch",
} }

View file

@ -655,10 +655,10 @@ from `0` to `255`.
===== `sector` methods ===== `sector` methods
`sec:set_ceilingpicnum(tilenum)`, `sec:set_floorpicnum(tilenum)`:: `sec:set_ceilingpicnum(tilenum)`, {nbsp} `sec:set_floorpicnum(tilenum)`::
Set the tile number of the ceiling or floor. Set the tile number of the ceiling or floor.
[[sec_cfz_at]] `sec:ceilingzat(pos)`, `sec:floorzat(pos)`:: [[sec_cfz_at]] `sec:ceilingzat(pos)`, {nbsp} `sec:floorzat(pos)`::
Return the z coordinate of sector `sec`'s ceiling or floor at position `pos`, Return the z coordinate of sector `sec`'s ceiling or floor at position `pos`,
which can be anything indexable with the strings `x` and `y`. which can be anything indexable with the strings `x` and `y`.

View file

@ -1894,8 +1894,15 @@ local function StructAccess(Structname, writep, index, membertab)
return "_MEMBINVALID" return "_MEMBINVALID"
end end
-- Function checking a literal number for being OK for assignment to this
-- member. Can also be a table {min, max}. See con_lang.lua, LITERAL_CHECKING.
local lit_ok_func_or_table
if (type(armembcode)=="table") then if (type(armembcode)=="table") then
-- Read and write accesses differ. -- Read and write accesses differ.
if (writep) then
lit_ok_func_or_table = armembcode[3]
end
armembcode = armembcode[writep and 2 or 1] armembcode = armembcode[writep and 2 or 1]
if (armembcode==nil) then if (armembcode==nil) then
errprintf("%s access to %s[].%s is not available", errprintf("%s access to %s[].%s is not available",
@ -1947,7 +1954,7 @@ local function StructAccess(Structname, writep, index, membertab)
end end
end end
return code, ismethod return code, ismethod, lit_ok_func_or_table
end end
function lookup.array_expr(writep, structname, index, membertab) function lookup.array_expr(writep, structname, index, membertab)
@ -2020,13 +2027,20 @@ end
local function SetStructCmd(accessfunc, pattern) local function SetStructCmd(accessfunc, pattern)
local function capfunc(idx, memb, var) local function capfunc(idx, memb, var)
local membercode, ismethod = accessfunc(true, idx, memb) -- litok: function or table
--[[ local membercode, ismethod, litok = accessfunc(true, idx, memb)
local member = memb[1]:lower()
if (type(var)=="number" and var<0 and member:match("picnum")) then -- Light static checking for literal values being OK for member
warnprintf("member '.%s' is set to a negative value", member) -- assignment. LITERAL_CHECKING.
if (type(var)=="number" and litok) then
if (type(litok)=="table" and not (var>=litok[1] and var<=litok[2]) or
type(litok)=="function" and not litok(var)) then
local member = memb[1]:lower()
warnprintf("setting member '.%s' to %d will fail at game time",
member, var)
end
end end
--]]
if (ismethod) then if (ismethod) then
-- METHOD_MEMBER syntax -- METHOD_MEMBER syntax