diff --git a/polymer/eduke32/source/lunatic/con_lang.lua b/polymer/eduke32/source/lunatic/con_lang.lua index ffb4647d9..8b8848e83 100644 --- a/polymer/eduke32/source/lunatic/con_lang.lua +++ b/polymer/eduke32/source/lunatic/con_lang.lua @@ -2,369 +2,376 @@ -- require("lpeg") -- con_keyword = dofile("con_lang.lua") +-- NOTE: These MUST be in reverse lexicographical order! +-- Per CON syntax, valid identifiers names are disjunct from keywords, +-- so that a rule like +-- t_identifier = -con_keyword * (sp1 + "[") * t_identifier_all +-- (from the final grammar in lunacon.lua) must match the longest +-- possible keyword name, else the negation might wrongly not fail. + return lpeg.P(false) + -"{" + "}" + -"action" + -"activatebysector" + -"activatecheat" + -"actor" + -"addammo" + -"addinventory" + -"addkills" + -"addlog" + -"addlogvar" + -"addphealth" + -"addstrength" + -"addvar" + -"addvarvar" + -"addweapon" + -"addweaponvar" + -"ai" + -"andvar" + -"andvarvar" + -"angoff" + -"angoffvar" + -"betaname" + -"break" + -"cactor" + -"calchypotenuse" + -"cansee" + -"canseespr" + -"case" + -"changespritesect" + -"changespritestat" + -"cheatkeys" + -"checkactivatormotion" + -"checkavailinven" + -"checkavailweapon" + -"clearmapstate" + -"clipdist" + -"clipmove" + -"clipmovenoslide" + -"cmenu" + -"copy" + -"cos" + -"count" + -"cstat" + -"cstator" + -"debris" + -"debug" + -"default" + -"define" + -"definecheat" + -"definegamefuncname" + -"definegametype" + -"definelevelname" + -"defineprojectile" + -"definequote" + -"defineskillname" + -"definesound" + -"definevolumename" + -"digitalnumber" + -"digitalnumberz" + -"displayrand" + -"displayrandvar" + -"displayrandvarvar" + -"dist" + -"divvar" + -"divvarvar" + -"dragpoint" + -"dynamicremap" + -"echo" + -"else" + -"enda" + -"endevent" + -"endofgame" + -"ends" + -"endswitch" + -"enhanced" + -"eqspawn" + -"eqspawnvar" + -"eshoot" + -"eshootvar" + -"espawn" + -"espawnvar" + -"eventloadactor" + -"ezshoot" + -"ezshootvar" + -"fall" + -"findnearactor" + -"findnearactor3d" + -"findnearactor3dvar" + -"findnearactorvar" + -"findnearactorz" + -"findnearactorzvar" + -"findnearsprite" + -"findnearsprite3d" + -"findnearsprite3dvar" + -"findnearspritevar" + -"findnearspritez" + -"findnearspritezvar" + -"findotherplayer" + -"findplayer" + -"flash" + -"gamearray" + -"gamestartup" + -"gametext" + -"gametextz" + -"gamevar" + -"getactor" + -"getactorangle" + -"getactorvar" + -"getangle" + -"getangletotarget" + -"getarraysize" + -"getceilzofslope" + -"getcurraddress" + -"getflorzofslope" + -"getincangle" + -"getinput" + -"getkeyname" + -"getlastpal" + -"getplayer" + -"getplayerangle" + -"getplayervar" + -"getpname" + -"getprojectile" + -"getsector" + -"gettextureceiling" + -"gettexturefloor" + -"getthisprojectile" + -"getticks" + -"gettimedate" + -"gettspr" + -"getuserdef" + -"getwall" + -"getzrange" + -"globalsound" + -"globalsoundvar" + -"gmaxammo" + -"guniqhudid" + -"guts" + -"headspritesect" + -"headspritestat" + -"hitradius" + -"hitradiusvar" + -"hitscan" + -"ifaction" + -"ifactioncount" + -"ifactor" + -"ifactornotstayput" + -"ifactorsound" + -"ifai" + -"ifangdiffl" + -"ifawayfromwall" + -"ifbulletnear" + -"ifcansee" + -"ifcanseetarget" + -"ifcanshoottarget" + -"ifceilingdistl" + -"ifclient" + -"ifcount" + -"ifdead" + -"iffloordistl" + -"ifgapzl" + -"ifgotweaponce" + -"ifhitspace" + -"ifhitweapon" + -"ifinouterspace" + -"ifinspace" + -"ifinwater" + -"ifmove" + -"ifmultiplayer" + -"ifnosounds" + -"ifnotmoving" + -"ifonwater" + -"ifoutside" + -"ifp" + -"ifpdistg" + -"ifpdistl" + -"ifphealthl" + -"ifpinventory" + -"ifrespawn" + -"ifrnd" + -"ifserver" + -"ifsound" + -"ifspawnedby" + -"ifspritepal" + -"ifsquished" + -"ifstrength" + -"ifvarand" + -"ifvare" + -"ifvareither" + -"ifvarg" + -"ifvarl" + -"ifvarn" + -"ifvaror" + -"ifvarvarand" + -"ifvarvare" + -"ifvarvareither" + -"ifvarvarg" + -"ifvarvarl" + -"ifvarvarn" + -"ifvarvaror" + -"ifvarvarxor" + -"ifvarxor" + -"ifwasweapon" + -"include" + -"includedefault" + -"inittimer" + -"insertspriteq" + -"jump" + -"killit" + -"ldist" + -"lineintersect" + -"loadmapstate" + -"lockplayer" + -"lotsofglass" + -"mail" + -"mikesnd" + -"minitext" + -"modvar" + -"modvarvar" + -"money" + -"move" + -"movesprite" + -"mulscale" + -"mulvar" + -"mulvarvar" + -"music" + -"myos" + -"myospal" + -"myospalx" + -"myosx" + -"neartag" + -"nextspritesect" + -"nextspritestat" + -"nullop" + -"onevent" + -"operate" + -"operateactivators" + -"operatemasterswitches" + -"operaterespawns" + -"operatesectors" + -"orvar" + -"orvarvar" + -"palfrom" + -"paper" + -"pkick" + -"precache" + -"prevspritesect" + -"prevspritestat" + -"pstomp" + -"qgetsysstr" + -"qspawn" + -"qspawnvar" + -"qsprintf" + -"qstrcat" + -"qstrcpy" + -"qstrlen" + -"qstrncat" + -"qsubstr" + -"quake" + -"quote" + -"randvar" + -"randvarvar" + -"rayintersect" + -"readarrayfromfile" + -"readgamevar" + -"redefinequote" + -"resetactioncount" + -"resetcount" + -"resetplayer" + -"resizearray" + -"respawnhitag" + -"return" + -"rotatepoint" + -"rotatesprite" + -"rotatesprite16" + -"save" + -"savegamevar" + -"savemapstate" + -"savenn" + -"scriptsize" + -"sectclearinterpolation" + -"sectgethitag" + -"sectgetlotag" + -"sectorofwall" + -"sectsetinterpolation" + -"setactor" + -"setactorangle" + -"setactorsoundpitch" + -"setactorvar" + -"setarray" + -"setaspect" + -"setcfgname" + -"setdefname" + -"setgamename" + -"setgamepalette" + -"setinput" + -"setplayer" + -"setplayerangle" + -"setplayervar" + -"setprojectile" + -"setsector" + -"setsprite" + -"setthisprojectile" + -"settspr" + -"setuserdef" + -"setvar" + -"setvarvar" + -"setwall" + -"shiftvarl" + -"shiftvarr" + -"shoot" + -"shootvar" + -"showview" + -"showviewunbiased" + -"sin" + -"sizeat" + -"sizeto" + -"sleeptime" + -"smaxammo" + -"sound" + -"soundonce" + -"soundoncevar" + -"soundvar" + -"spawn" + -"spgethitag" + -"spgetlotag" + -"spriteflags" + -"spritenopal" + -"spritenoshade" + -"spritenvg" + -"spritepal" + -"spriteshadow" + -"sqrt" + -"ssp" + -"startlevel" + -"starttrack" + -"starttrackvar" + -"state" + -"stopactorsound" + -"stopallsounds" + -"stopsound" + -"stopsoundvar" + -"strength" + -"subvar" + -"subvarvar" + -"switch" + -"time" + -"tip" + -"tossweapon" + -"updatesector" + -"updatesectorz" + -"useractor" + -"userquote" + -"wackplayer" + -"whilevarn" + -"whilevarvarn" + -"writearraytofile" + -"xorvar" + -"xorvarvar" + -"zshoot" + +"{" + "zshootvar" + +"zshoot" + +"xorvarvar" + +"xorvar" + +"writearraytofile" + +"whilevarvarn" + +"whilevarn" + +"wackplayer" + +"userquote" + +"useractor" + +"updatesectorz" + +"updatesector" + +"tossweapon" + +"tip" + +"time" + +"switch" + +"subvarvar" + +"subvar" + +"strength" + +"stopsoundvar" + +"stopsound" + +"stopallsounds" + +"stopactorsound" + +"state" + +"starttrackvar" + +"starttrack" + +"startlevel" + +"ssp" + +"sqrt" + +"spriteshadow" + +"spritepal" + +"spritenvg" + +"spritenoshade" + +"spritenopal" + +"spriteflags" + +"spgetlotag" + +"spgethitag" + +"spawn" + +"soundvar" + +"soundoncevar" + +"soundonce" + +"sound" + +"smaxammo" + +"sleeptime" + +"sizeto" + +"sizeat" + +"sin" + +"showviewunbiased" + +"showview" + +"shootvar" + +"shoot" + +"shiftvarr" + +"shiftvarl" + +"setwall" + +"setvarvar" + +"setvar" + +"setuserdef" + +"settspr" + +"setthisprojectile" + +"setsprite" + +"setsector" + +"setprojectile" + +"setplayervar" + +"setplayerangle" + +"setplayer" + +"setinput" + +"setgamepalette" + +"setgamename" + +"setdefname" + +"setcfgname" + +"setaspect" + +"setarray" + +"setactorvar" + +"setactorsoundpitch" + +"setactorangle" + +"setactor" + +"sectsetinterpolation" + +"sectorofwall" + +"sectgetlotag" + +"sectgethitag" + +"sectclearinterpolation" + +"scriptsize" + +"savenn" + +"savemapstate" + +"savegamevar" + +"save" + +"rotatesprite16" + +"rotatesprite" + +"rotatepoint" + +"return" + +"respawnhitag" + +"resizearray" + +"resetplayer" + +"resetcount" + +"resetactioncount" + +"redefinequote" + +"readgamevar" + +"readarrayfromfile" + +"rayintersect" + +"randvarvar" + +"randvar" + +"quote" + +"quake" + +"qsubstr" + +"qstrncat" + +"qstrlen" + +"qstrcpy" + +"qstrcat" + +"qsprintf" + +"qspawnvar" + +"qspawn" + +"qgetsysstr" + +"pstomp" + +"prevspritestat" + +"prevspritesect" + +"precache" + +"pkick" + +"paper" + +"palfrom" + +"orvarvar" + +"orvar" + +"operatesectors" + +"operaterespawns" + +"operatemasterswitches" + +"operateactivators" + +"operate" + +"onevent" + +"nullop" + +"nextspritestat" + +"nextspritesect" + +"neartag" + +"myosx" + +"myospalx" + +"myospal" + +"myos" + +"music" + +"mulvarvar" + +"mulvar" + +"mulscale" + +"movesprite" + +"move" + +"money" + +"modvarvar" + +"modvar" + +"minitext" + +"mikesnd" + +"mail" + +"lotsofglass" + +"lockplayer" + +"loadmapstate" + +"lineintersect" + +"ldist" + +"killit" + +"jump" + +"insertspriteq" + +"inittimer" + +"includedefault" + +"include" + +"ifwasweapon" + +"ifvarxor" + +"ifvarvarxor" + +"ifvarvaror" + +"ifvarvarn" + +"ifvarvarl" + +"ifvarvarg" + +"ifvarvareither" + +"ifvarvare" + +"ifvarvarand" + +"ifvaror" + +"ifvarn" + +"ifvarl" + +"ifvarg" + +"ifvareither" + +"ifvare" + +"ifvarand" + +"ifstrength" + +"ifsquished" + +"ifspritepal" + +"ifspawnedby" + +"ifsound" + +"ifserver" + +"ifrnd" + +"ifrespawn" + +"ifpinventory" + +"ifphealthl" + +"ifpdistl" + +"ifpdistg" + +"ifp" + +"ifoutside" + +"ifonwater" + +"ifnotmoving" + +"ifnosounds" + +"ifmultiplayer" + +"ifmove" + +"ifinwater" + +"ifinspace" + +"ifinouterspace" + +"ifhitweapon" + +"ifhitspace" + +"ifgotweaponce" + +"ifgapzl" + +"iffloordistl" + +"ifdead" + +"ifcount" + +"ifclient" + +"ifceilingdistl" + +"ifcanshoottarget" + +"ifcanseetarget" + +"ifcansee" + +"ifbulletnear" + +"ifawayfromwall" + +"ifangdiffl" + +"ifai" + +"ifactorsound" + +"ifactornotstayput" + +"ifactor" + +"ifactioncount" + +"ifaction" + +"hitscan" + +"hitradiusvar" + +"hitradius" + +"headspritestat" + +"headspritesect" + +"guts" + +"guniqhudid" + +"gmaxammo" + +"globalsoundvar" + +"globalsound" + +"getzrange" + +"getwall" + +"getuserdef" + +"gettspr" + +"gettimedate" + +"getticks" + +"getthisprojectile" + +"gettexturefloor" + +"gettextureceiling" + +"getsector" + +"getprojectile" + +"getpname" + +"getplayervar" + +"getplayerangle" + +"getplayer" + +"getlastpal" + +"getkeyname" + +"getinput" + +"getincangle" + +"getflorzofslope" + +"getcurraddress" + +"getceilzofslope" + +"getarraysize" + +"getangletotarget" + +"getangle" + +"getactorvar" + +"getactorangle" + +"getactor" + +"gamevar" + +"gametextz" + +"gametext" + +"gamestartup" + +"gamearray" + +"flash" + +"findplayer" + +"findotherplayer" + +"findnearspritezvar" + +"findnearspritez" + +"findnearspritevar" + +"findnearsprite3dvar" + +"findnearsprite3d" + +"findnearsprite" + +"findnearactorzvar" + +"findnearactorz" + +"findnearactorvar" + +"findnearactor3dvar" + +"findnearactor3d" + +"findnearactor" + +"fall" + +"ezshootvar" + +"ezshoot" + +"eventloadactor" + +"espawnvar" + +"espawn" + +"eshootvar" + +"eshoot" + +"eqspawnvar" + +"eqspawn" + +"enhanced" + +"endswitch" + +"ends" + +"endofgame" + +"endevent" + +"enda" + +"else" + +"echo" + +"dynamicremap" + +"dragpoint" + +"divvarvar" + +"divvar" + +"dist" + +"displayrandvarvar" + +"displayrandvar" + +"displayrand" + +"digitalnumberz" + +"digitalnumber" + +"definevolumename" + +"definesound" + +"defineskillname" + +"definequote" + +"defineprojectile" + +"definelevelname" + +"definegametype" + +"definegamefuncname" + +"definecheat" + +"define" + +"default" + +"debug" + +"debris" + +"cstator" + +"cstat" + +"count" + +"cos" + +"copy" + +"cmenu" + +"clipmovenoslide" + +"clipmove" + +"clipdist" + +"clearmapstate" + +"checkavailweapon" + +"checkavailinven" + +"checkactivatormotion" + +"cheatkeys" + +"changespritestat" + +"changespritesect" + +"case" + +"canseespr" + +"cansee" + +"calchypotenuse" + +"cactor" + +"break" + +"betaname" + +"angoffvar" + +"angoff" + +"andvarvar" + +"andvar" + +"ai" + +"addweaponvar" + +"addweapon" + +"addvarvar" + +"addvar" + +"addstrength" + +"addphealth" + +"addlogvar" + +"addlog" + +"addkills" + +"addinventory" + +"addammo" + +"actor" + +"activatecheat" + +"activatebysector" + +"action" + lpeg.P(false) diff --git a/polymer/eduke32/source/lunatic/lunacon.lua b/polymer/eduke32/source/lunatic/lunacon.lua index 10242d4de..7d1d1bd19 100644 --- a/polymer/eduke32/source/lunatic/lunacon.lua +++ b/polymer/eduke32/source/lunatic/lunacon.lua @@ -160,7 +160,6 @@ local Co = { --== Run time CON commands ==-- --- 1. Gamevar Operators - local varop = cmd(W,D) local varvarop = cmd(W,R) @@ -168,18 +167,20 @@ local varvarop = cmd(W,R) local arraypat = sp0 * "[" * sp0 * t_define * sp0 * "]" -- The member name must match keywords, too (_all), because e.g. cstat is a member -- of sprite[] +-- XXX: actor and sprite members can have parm2, e.g. this is legal: +-- ifvare player[THISACTOR].gotweapon 4 0 +-- but not parsed currently. local memberpat = sp0 * "." * sp0 * t_identifier_all local getstructcmd = -- get[]. ()? <> -- existence of a second parameter is determined later -- This is wrong, (sp1 id)? will match (sp1 wvar) if there's no 2nd param: -- arraypat * memberpat * (sp1 * t_identifier)^-1 * sp1 * t_wvar --- XXX: This is still wrong. - arraypat * memberpat * sp1 * (t_identifier * sp1 * t_wvar + t_wvar) + arraypat * memberpat * sp1 * (t_rvar * sp1 * t_wvar + t_wvar) local setstructcmd = -- set[]. ()? -- existence of a second parameter is determined later - arraypat * memberpat * sp1 * (t_identifier * sp1 * t_rvar + t_rvar) + arraypat * memberpat * sp1 * (t_rvar * sp1 * t_rvar + t_rvar) local getperxvarcmd = -- getvar[]. <> arraypat * memberpat * sp1 * t_wvar @@ -201,7 +202,6 @@ local Ci = { getplayer = getstructcmd, getprojectile = getstructcmd, getsector = getstructcmd, - getsprite = getstructcmd, getthisprojectile = getstructcmd, gettspr = getstructcmd, getuserdef = getstructcmd, @@ -215,7 +215,6 @@ local Ci = { setplayer = setstructcmd, setprojectile = setstructcmd, setsector = setstructcmd, - setsprite = setstructcmd, setthisprojectile = setstructcmd, settspr = setstructcmd, setuserdef = setstructcmd, @@ -224,6 +223,8 @@ local Ci = { setactorvar = setperxvarcmd, setplayervar = setperxvarcmd, + setsprite = cmd(R,R,R,R), + setvarvar = varvarop, addvarvar = varvarop, subvarvar = varvarop, @@ -253,7 +254,7 @@ local Ci = { calchypotenuse = cmd(W,R,R), sin = cmd(W,R), cos = cmd(W,R), - mulscale = cmd(W,R,R), + mulscale = cmd(W,R,R,R), getangle = cmd(W,R,R), getincangle = cmd(W,R,R), @@ -365,20 +366,20 @@ local Ci = { tossweapon = cmd(), wackplayer = cmd(), - -- sprite searching - findplayer = cmd(D,D), - findotherplayer = cmd(D,D), + -- player/sprite searching + findplayer = cmd(W), + findotherplayer = cmd(W), findnearspritezvar = cmd(D,R,R,W), findnearspritez = cmd(D,D,D,W), - findnearspritevar = cmd(D,R,W), findnearsprite3dvar = cmd(D,R,W), findnearsprite3d = cmd(D,D,W), + findnearspritevar = cmd(D,R,W), findnearsprite = cmd(D,D,W), findnearactorzvar = cmd(D,R,R,W), findnearactorz = cmd(D,D,D,W), - findnearactorvar = cmd(D,R,W), findnearactor3dvar = cmd(D,R,W), findnearactor3d = cmd(D,D,W), + findnearactorvar = cmd(D,R,W), findnearactor = cmd(D,D,W), -- quotes @@ -407,7 +408,7 @@ local Ci = { displayrand = cmd(W), displayrandvar = cmd(W,D), displayrandvarvar = cmd(W,R), - dist = cmd(W), + dist = cmd(W,R,R), dragpoint = cmd(R,R,R), hitscan = cmd(R,R,R,R,R,R,R,W,W,W,W,W,W,R), -- 7R 6W 1R @@ -418,7 +419,7 @@ local Ci = { digitalnumberz = cmd(W,R,R,R,R,R,R,R,R,R,R,R), -- 1W 11R minitext = cmd(R,R,R,R,R), - ldist = cmd(W), + ldist = cmd(W,R,R), lineintersect = cmd(R,R,R,R,R,R,R,R,R,R,W,W,W,W), -- 10R 4W rayintersect = cmd(R,R,R,R,R,R,R,R,R,R,W,W,W,W), -- 10R 4W loadmapstate = cmd(), @@ -564,25 +565,85 @@ local Cif = { } +----==== Tracing and reporting ====---- +local string = require("string") + +-- newlineidxs will contain the 1-based file offsets to "\n" characters +local newlineidxs = {} + +local function printf(fmt, ...) + print(string.format(fmt, ...)) +end + +-- Returns index into the sorted table tab such that +-- tab[index] <= searchelt < tab[index+1]. +-- Preconditions: +-- tab[i] < tab[i+1] for 1 <= i < #tab +-- tab[1] <= searchelt < tab[#tab] +-- If tab has less than 2 elements, returns nil. +local function bsearch(tab, searchelt) +-- printf("bsearch(tab, %d)", searchelt) + local l, r = 1, #tab + local i + + if (r <= 1) then + return + end + + while (l ~= r) do + i = l + math.ceil((r-l)/2) -- l < i <= r + assert(l < i and i <= r) + local elt = tab[i] +-- printf("l=%d tab[%d]=%d r=%d", l, i, elt, r) + + if (searchelt == elt) then + return i + end + + if (searchelt < elt) then + r = i-1 + else -- (searchelt > elt) + l = i + end + end + +-- printf("return tab[%d]=%d", l, tab[l]) + return l +end + +local function getlinecol(pos) + local line = bsearch(newlineidxs, pos) + local col = pos-newlineidxs[line] + return line, col +end + -- A generic trace function, prints a position together with the match content -- A non-existing 'doit' means 'true'. -function TraceFunc(pat, doit) +local function TraceFunc(pat, label, doit) pat = Pat(pat) if (doit==nil or doit) then - pat = lpeg.Cmt(pat, function (subj, pos, a) print(pos..":"..a); return true; end) + local function tfunc(subj, pos, a) + local line, col = getlinecol(pos) + printf("%d,%d:%s:%s", line, col, label, a) + return true + end + pat = lpeg.Cmt(pat, tfunc) end return pat end -- These are tracers for specific patterns which can be disabled -- if desired. -local function Keyw(kwname) return TraceFunc(kwname, false) end -local function Stmt(cmdpat) return TraceFunc(cmdpat, false) end +local function Keyw(kwname) return TraceFunc(kwname, "kw", true) end +local function NotKeyw(text) return TraceFunc(text, "!kw", true) end +local function Ident(idname) return TraceFunc(idname, "id", true) end +local function Stmt(cmdpat) return TraceFunc(cmdpat, "st", true) end +----==== Translator continued ====---- -- attach the command names at the front! -function attachnames(kwtab) +local function attachnames(kwtab) for cmdname,cmdpat in pairs(kwtab) do kwtab[cmdname] = Keyw(cmdname) * cmdpat end @@ -596,7 +657,7 @@ attachnames(Cif) -- Takes one or more tables and +'s all its patterns together in the order of -- appearance. -- The tables must map command names to their patterns. -function all_alt_pattern(...) +local function all_alt_pattern(...) local pat = Pat(false) local args = {...} for argi=1,#args do @@ -614,9 +675,11 @@ local function warn_on_lonely_else(subj, pos) return true end --- About prefixes: I think it's not a problem if e.g. "getactor" comes before --- "getactorvar", because the pattern for the former will fail eventually in --- the ordered choice if fed with the latter. +-- About prefixes: I think it's not a problem *here* if e.g. "getactor" comes +-- 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. local con_outer_command = all_alt_pattern(Co) local con_inner_command = all_alt_pattern(Ci) local con_if_begs = all_alt_pattern(Cif) @@ -668,7 +731,7 @@ local Grammar = Pat{ -- getactor[THISACTOR].x x -- getactor [THISACTOR].y y -- This is in need of cleanup! - t_identifier = -(con_keyword * (sp1 + "[")) * t_identifier_all, + t_identifier = -NotKeyw(con_keyword * (sp1 + "[")) * Ident(t_identifier_all), t_define = Pat("-")^-1 * sp0 * (t_identifier + t_number), t_arrayexp = t_identifier * arraypat * memberpat^-1, @@ -698,47 +761,15 @@ local Grammar = Pat{ stmt_list = Var("single_stmt") * (sp1 * Var("single_stmt"))^0, } + local math = require("math") -local string = require("string") -local function printf(fmt, ...) - print(string.format(fmt, ...)) -end - --- Returns index into the sorted table tab such that --- tab[index] <= searchelt < tab[index+1]. --- Preconditions: --- tab[i] < tab[i+1] for 1 <= i < #tab --- tab[1] <= searchelt < tab[#tab] --- If tab has less than 2 elements, returns nil. -local function bsearch(tab, searchelt) --- printf("bsearch(tab, %d)", searchelt) - local l, r = 1, #tab - local i - - if (r <= 1) then - return +local function setup_newlineidxs(contents) + newlineidxs = {} + for i in string.gmatch(contents, "()\n") do + newlineidxs[#newlineidxs+1] = i end - - while (l ~= r) do - i = l + math.ceil((r-l)/2) -- l < i <= r - assert(l < i and i <= r) - local elt = tab[i] --- printf("l=%d tab[%d]=%d r=%d", l, i, elt, r) - - if (searchelt == elt) then - return i - end - - if (searchelt < elt) then - r = i-1 - else -- (searchelt > elt) - l = i - end - end - --- printf("return tab[%d]=%d", l, tab[l]) - return l + newlineidxs[#newlineidxs+1] = #contents+1 -- dummy newline end ---=== stand-alone: ===--- @@ -749,14 +780,9 @@ if (not EDUKE32_LUNATIC) then assert(filename) local contents = io.open(filename):read("*all") - local idx = lpeg.match(Grammar, contents) + setup_newlineidxs(contents) - -- newlineidxs will contain the 1-based file offsets to "\n" characters - local newlineidxs = {} - for i in string.gmatch(contents, "()\n") do - newlineidxs[#newlineidxs+1] = i - end - newlineidxs[#newlineidxs+1] = #contents+1 -- dummy newline + local idx = lpeg.match(Grammar, contents) if (not idx) then print("Match failed.") @@ -768,10 +794,12 @@ if (not EDUKE32_LUNATIC) then return end - printf("Match succeeded up to %d (len=%d)", idx, #contents) - - local i = bsearch(newlineidxs, idx) + local i, col = getlinecol(idx) local bi, ei = newlineidxs[i]+1, newlineidxs[i+1]-1 - printf("Line goes from %d to %d", bi, ei) + + printf("Match succeeded up to %d (line %d, col %d; len=%d)", + idx, i, col, #contents) + +-- printf("Line goes from %d to %d", bi, ei) print(string.sub(contents, bi, ei)) end