From 91047d6d90c9a5a96b62c43ad6801af1bb25ffe9 Mon Sep 17 00:00:00 2001 From: helixhorned Date: Thu, 24 Jan 2013 20:03:10 +0000 Subject: [PATCH] Lunatic translator: struct read access. git-svn-id: https://svn.eduke32.com/eduke32@3433 1a8010ca-5511-0410-912e-c29ae57300e0 --- polymer/eduke32/source/lunatic/con_lang.lua | 420 +++++++++++++++++--- polymer/eduke32/source/lunatic/control.lua | 8 +- polymer/eduke32/source/lunatic/defs.ilua | 6 +- polymer/eduke32/source/lunatic/lunacon.lua | 119 +++--- 4 files changed, 440 insertions(+), 113 deletions(-) diff --git a/polymer/eduke32/source/lunatic/con_lang.lua b/polymer/eduke32/source/lunatic/con_lang.lua index d7f98fe7f..c433b7bbf 100644 --- a/polymer/eduke32/source/lunatic/con_lang.lua +++ b/polymer/eduke32/source/lunatic/con_lang.lua @@ -302,74 +302,382 @@ wdata_members = "int32_t flashcolor", } -ActorLabels = -{ - x = "sprite[%s].x", - y = "sprite[%s].y", - z = "sprite[%s].z", - cstat = "sprite[%s].cstat", - picnum = "sprite[%s].picnum", - shade = "sprite[%s].shade", - pal = "sprite[%s].pal", - clipdist = "sprite[%s].clipdist", --- filler = "sprite[%s].filler", - detail = "sprite[%s].filler", - xrepeat = "sprite[%s].xrepeat", - yrepeat = "sprite[%s].yrepeat", - xoffset = "sprite[%s].xoffset", - yoffset = "sprite[%s].yoffset", - sectnum = "sprite[%s].sectnum", - statnum = "sprite[%s].statnum", - ang = "sprite[%s].ang", - owner = "sprite[%s].owner", - xvel = "sprite[%s].xvel", - yvel = "sprite[%s].yvel", - zvel = "sprite[%s].zvel", - lotag = "sprite[%s].lotag", - hitag = "sprite[%s].hitag", - extra = "sprite[%s].extra", + +local SP = function(memb) return "sprite[%s]"..memb end +local AC = function(memb) return "actor[%s]"..memb end +local SX = function(memb) return "spriteext[%s]"..memb end + +-- Generate code to access a signed member as unsigned. +local function s2u(label) + return "(_bit.band("..label.."+65536),65535)" +end + +local function S2U(label) + return { s2u(label), label } +end + +local ActorLabels = { + x = SP".x", + y = SP".y", + z = SP".z", + cstat = SP".cstat", + picnum = SP".picnum", + shade = SP".shade", + pal = SP".pal", + clipdist = SP".clipdist", +-- filler = SP".filler", + detail = SP".filler", -- NAME + xrepeat = SP".xrepeat", + yrepeat = SP".yrepeat", + xoffset = SP".xoffset", + yoffset = SP".yoffset", + sectnum = SP".sectnum", + statnum = SP".statnum", + ang = SP".ang", + owner = SP".owner", + xvel = SP".xvel", + yvel = SP".yvel", + zvel = SP".zvel", + lotag = SP".lotag", + hitag = SP".hitag", + extra = SP".extra", -- { get, set } -- Read access differs from write: - ulotag = { "(sprite[%s].lotag+65536)%65535", "sprite[%s].lotag" }, - uhitag = { "(sprite[%s].hitag+65536)%65535", "sprite[%s].hitag" }, + ulotag = S2U(SP".lotag"), + uhitag = S2U(SP".hitag"), -- ActorExtra labels... - htcgg = "actor[%s].cgg", - htpicnum = "actor[%s].picnum", - htang = "actor[%s].ang", - htextra = "actor[%s].extra", - htowner = "actor[%s].owner", - htmovflag = "actor[%s].movflag", - httempang = "actor[%s].tempang", - htactorstayput = "actor[%s].actorstayput", - htdispicnum = "actor[%s].dispicnum", - httimetosleep = "actor[%s].timetosleep", - htfloorz = "actor[%s].floorz", - htceilingz = "actor[%s].ceilingz", - htlastvx = "actor[%s].lastvx", - htlastvy = "actor[%s].lastvy", - htbposx = "actor[%s].bpos.x", - htbposy = "actor[%s].bpos.y", - htbposz = "actor[%s].bpos.z", + htcgg = AC".cgg", + htpicnum = AC".picnum", + htang = AC".ang", + htextra = AC".extra", + htowner = AC".owner", + htmovflag = AC".movflag", + httempang = AC".tempang", + htactorstayput = AC".actorstayput", + htdispicnum = AC".dispicnum", + httimetosleep = AC".timetosleep", + htfloorz = AC".floorz", + htceilingz = AC".ceilingz", + htlastvx = AC".lastvx", + htlastvy = AC".lastvy", + htbposx = AC".bpos.x", + htbposy = AC".bpos.y", + htbposz = AC".bpos.z", -- Read access differs from write, write not available: - htg_t = { "actor[%s].get_t_data(%s)" }, - htflags = "actor[%s].flags", + htg_t = { AC":get_t_data(%s)" }, + htflags = AC".flags", -- model flags - angoff = "spriteext[%s].angoff", - pitch = "spriteext[%s].pitch", - roll = "spriteext[%s].roll", - mdxoff = "spriteext[%s].xoff", - mdyoff = "spriteext[%s].yoff", - mdzoff = "spriteext[%s].zoff", - mdflags = "spriteext[%s].mdflags", - xpanning = "spriteext[%s].xpanning", - ypanning = "spriteext[%s].ypanning", + angoff = SX".angoff", + pitch = SX".pitch", + roll = SX".roll", + mdxoff = SX".xoff", + mdyoff = SX".yoff", + mdzoff = SX".zoff", + mdflags = SX".mdflags", + xpanning = SX".xpanning", + ypanning = SX".ypanning", alpha = { "_math.floor(spriteext[%s].alpha*255)" }, } +local PL = function(memb) return "player[%s]"..memb end + +local PlayerLabels = { + posx = PL".pos.x", + posy = PL".pos.y", + posz = PL".pos.z", + oposx = PL".opos.x", + oposy = PL".opos.y", + oposz = PL".opos.z", + posxv = PL".vel.x", -- NAME + posyv = PL".vel.y", + poszv = PL".vel.z", + -- NOTE: no access for .npos + bobposx = PL".bobposx", + bobposy = PL".bobposy", + + truefz = PL".truefz", + truecz = PL".truecz", + player_par = PL".player_par", + + randomflamex = PL".randomflamex", + exitx = PL".exitx", + exity = PL".exity", + + runspeed = PL".runspeed", + max_player_health = PL".max_player_health", + max_shield_amount = PL".max_shield_amount", + + autostep = PL".autostep", + autostep_sbw = PL".autostep_sbw", + + interface_toggle_flag = PL".interface_toggle_flag", + + -- NOTE: *bombControl etc. are accessed by gamevars in CON + + max_actors_killed = PL".max_actors_killed", + actors_killed = PL".actors_killed", + + -- NOTE the special case: + gotweapon = { "("..PL":have_weapon(%s) and 1 or 0)" }, + zoom = PL".zoom", + + loogiex = {}, + loogiey = {}, + + sbs = PL".sbs", + sound_pitch = PL".sound_pitch", + + ang = PL".ang", + oang = PL".oang", + angvel = PL".angvel", + + cursectnum = PL".cursectnum", + + look_ang = PL".look_ang", + last_extra = PL".last_extra", + subweapon = PL".subweapon", + + max_ammo_amount = { PL":get_max_ammo_amount(%s)" }, + ammo_amount = { PL":get_ammo_amount(%s)" }, + -- NOTE: no direct access for .inv_amount (but see end) + + wackedbyactor = PL".wackedbyactor", + pyoff = PL".pyoff", + opyoff = PL".opyoff", + + horiz = PL".horiz", + horizoff = PL".horizoff", + ohoriz = PL".ohoriz", + ohorizoff = PL".ohorizoff", + + newowner = { PL".newowner" }, + + jumping_counter = PL".jumping_counter", + airleft = PL".airleft", + + fta = PL".fta", + ftq = PL".ftq", + access_wallnum = PL".access_wallnum", + access_spritenum = PL".access_spritenum", + + got_access = PL".got_access", + weapon_ang = PL".weapon_ang", + visibility = PL".visibility", + + somethingonplayer = PL".somethingonplayer", + on_crane = PL".on_crane", + + i = { PL".i" }, + + one_parallax_sectnum = { PL".one_parallax_sectnum" }, + + random_club_frame = PL".random_club_frame", + one_eighty_count = PL".one_eighty_count", + + dummyplayersprite = { PL".dummyplayersprite" }, + extra_extra8 = PL".extra_extra8", + + actorsqu = PL".actorsqu", + timebeforeexit = PL".timebeforeexit", + customexitsound = { PL".customexitsound" }, + + last_pissed_time = PL".last_pissed_time", + + weaprecs = { PL".weaprecs" }, + + weapon_sway = PL".weapon_sway", + crack_time = PL".crack_time", + bobcounter = PL".bobcounter", + + -- NOTE: no access for .orotscrnang + rotscrnang = PL".rotscrnang", + dead_flag = PL".dead_flag", + + holoduke_on = PL".holoduke_on", + pycount = PL".pycount", + transporter_hold = PL".transporter_hold", + + max_secret_rooms = PL".max_secret_rooms", + secret_rooms = PL".secret_rooms", + + frag = PL".frag", + fraggedself = PL".fraggedself", + quick_kick = PL".quick_kick", + last_quick_kick = PL".last_quick_kick", + + return_to_center = PL".return_to_center", + reloading = PL".reloading", + weapreccnt = PL".weapreccnt", + + aim_mode = PL".aim_mode", + auto_aim = PL".auto_aim", + weaponswitch = PL".weaponswitch", + movement_lock = PL".movement_lock", + team = PL".team", + + tipincs = PL".tipincs", + hbomb_hold_delay = PL".hbomb_hold_delay", + frag_ps = PL".frag_ps", + kickback_pic = PL".kickback_pic", + + gm = PL".gm", + on_warping_sector = PL".on_warping_sector", + footprintcount = PL".footprintcount", + hurt_delay = PL".hurt_delay", + + hbomb_on = PL".hbomb_on", + jumping_toggle = PL".jumping_toggle", + rapid_fire_hold = PL".rapid_fire_hold", + on_ground = PL".on_ground", + + inven_icon = PL".inven_icon", + buttonpalette = PL".buttonpalette", + over_shoulder_on = PL".over_shoulder_on", + show_empty_weapon = PL".show_empty_weapon", + + jetpack_on = PL".jetpack_on", + spritebridge = PL".spritebridge", + lastrandomspot = PL".lastrandomspot", + + scuba_on = PL".scuba_on", + footprintpal = PL".footprintpal", + heat_on = PL".heat_on", + invdisptime = PL".invdisptime", + holster_weapon = PL".holster_weapon", + falling_counter = PL".falling_counter", + footprintshade = PL".footprintshade", + + refresh_inventory = PL".refresh_inventory", + last_full_weapon = PL".last_full_weapon", + + walking_snd_toggle = PL".walking_snd_toggle", + palookup = PL".palookup", + hard_landing = PL".hard_landing", + fist_incs = PL".fist_incs", + + toggle_key_flag = PL".toggle_key_flag", + knuckle_incs = PL".knuckle_incs", + knee_incs = PL".knee_incs", + access_incs = PL".access_incs", + + numloogs = PL".numloogs", + loogcnt = PL".loogcnt", + scream_voice = PL".scream_voice", + + last_weapon = PL".last_weapon", + cheat_phase = PL".cheat_phase", + weapon_pos = PL".weapon_pos", + wantweaponfire = PL".wantweaponfire", + + curr_weapon = { PL".curr_weapon" }, + + palette = PL".palette", + + -- NOTE the special case: + pals = {}, + pals_time = PL".pals.f", + + name = {}, + + -- Access to .inv_amount + steroids_amount = { PL":get_inv_amount(0)", }, + shield_amount = { PL":get_inv_amount(1)", }, + scuba_amount = { PL":get_inv_amount(2)", }, + holoduke_amount = { PL":get_inv_amount(3)", }, + jetpack_amount = { PL":get_inv_amount(4)", }, + -- 5: dummy + -- 6: no "access_amount" + heat_amount = { PL":get_inv_amount(7)" }, + -- 8: dummy + firstaid_amount = { PL":get_inv_amount(9)" }, + boot_amount = { PL":get_inv_amount(10)" }, +} + +local SEC = function(memb) return "sector[%s]"..memb end +local SECRO = function(memb) return { "sector[%s]"..memb } end + +local SectorLabels = { + wallptr = SECRO".wallptr", + wallnum = SECRO".wallnum", + + ceilingz = SEC".ceilingz", + floorz = SEC".floorz", + + ceilingstat = SEC".ceilingstat", + floorstat = SEC".floorstat", + + -- CEILING + ceilingpicnum = SECRO".ceilingpicnum", + + ceilingslope = SEC".ceilingheinum", -- NAME + ceilingshade = SEC".ceilingshade", + + ceilingpal = SEC".ceilingpal", + ceilingxpanning = SEC".ceilingxpanning", + ceilingypanning = SEC".ceilingypanning", + + -- FLOOR + floorpicnum = SECRO".floorpicnum", + + floorslope = SEC".floorheinum", -- NAME + floorshade = SEC".floorshade", + + floorpal = SEC".floorpal", + floorxpanning = SEC".floorxpanning", + floorypanning = SEC".floorypanning", + + visibility = SEC".visibility", + filler = SEC".filler", + alignto = SEC".filler", -- NAME + + lotag = SEC".lotag", + hitag = SEC".hitag", + extra = SEC".extra", + + ceilingbunch = {}, + floorbunch = {}, + + ulotag = S2U(SEC".lotag"), + uhitag = S2U(SEC".hitag"), +} + +local WAL = function(memb) return "wall[%s]"..memb end +local WALRO = function(memb) return { "wall[%s]"..memb } end + +local WallLabels = { + x = WAL".x", + y = WAL".y", + point2 = WALRO".point2", + nextwall = WALRO".nextwall", + nextsector = WALRO".nextsector", + cstat = WAL".cstat", + picnum = WALRO".picnum", + overpicnum = WALRO".overpicnum", + shade = WAL".shade", + pal = WAL".pal", + xrepeat = WAL".xrepeat", + yrepeat = WAL".yrepeat", + xpanning = WAL".xpanning", + ypanning = WAL".ypanning", + lotag = WAL".lotag", + hitag = WAL".hitag", + extra = WAL".extra", + + ulotag = S2U(WAL".lotag"), + uhitag = S2U(WAL".hitag"), +} + +StructAccessCode = +{ + sector = SectorLabels, + wall = WallLabels, + sprite = ActorLabels, + player = PlayerLabels, +} -- NOTE: These MUST be in reverse lexicographical order! -- Per CON syntax, valid identifiers names are disjunct from keywords, diff --git a/polymer/eduke32/source/lunatic/control.lua b/polymer/eduke32/source/lunatic/control.lua index 2b212303f..32a2fa905 100644 --- a/polymer/eduke32/source/lunatic/control.lua +++ b/polymer/eduke32/source/lunatic/control.lua @@ -281,10 +281,6 @@ end --- Helper functions (might be exported later) --- -local function have_weapon(ps, weap) - return (bit.band(ps.gotweapon, bit.lshift(1, weap)) ~= 0) -end - local function have_ammo_at_max(ps, weap) return (ps:get_ammo_amount(weap) >= ps:get_max_ammo_amount(weap)) end @@ -301,7 +297,7 @@ end local function P_AddWeaponAmmoCommon(ps, weap, amount) P_AddAmmo(ps, weap, amount) - if (ps.curr_weapon==ffiC.KNEE_WEAPON and have_weapon(ps, weap)) then + if (ps.curr_weapon==ffiC.KNEE_WEAPON and ps:have_weapon(weap)) then ffiC.P_AddWeaponMaybeSwitch(ps, weap); end end @@ -597,7 +593,7 @@ function _addweapon(ps, weap, amount) error("Invalid weapon ID "..weap, 2) end - if (not have_weapon(ps, weap)) then + if (not ps:have_weapon(weap)) then ffiC.P_AddWeaponMaybeSwitch(ps, weap); elseif (have_ammo_at_max(ps, weap)) then return true diff --git a/polymer/eduke32/source/lunatic/defs.ilua b/polymer/eduke32/source/lunatic/defs.ilua index aa5ddd9bd..7db39ac82 100644 --- a/polymer/eduke32/source/lunatic/defs.ilua +++ b/polymer/eduke32/source/lunatic/defs.ilua @@ -227,7 +227,7 @@ local DUKEPLAYER_STRUCT = [[ int8_t numloogs, loogcnt, scream_voice; int8_t last_weapon, cheat_phase, weapon_pos, wantweaponfire; - int8_t const curr_weapon; + const int8_t curr_weapon; uint8_t palette; palette_t pals; @@ -866,6 +866,10 @@ local player_mt = { stomp = con._pstomp, + have_weapon = function(p, weap) + return (bit.band(p.gotweapon, bit.lshift(1, weap)) ~= 0) + end, + -- XXX: is the correct spelling "whack"? wack = function(p, no_return_to_center) p.horiz = p.horiz + 64 diff --git a/polymer/eduke32/source/lunatic/lunacon.lua b/polymer/eduke32/source/lunatic/lunacon.lua index 96e0fe72f..f9bbededd 100644 --- a/polymer/eduke32/source/lunatic/lunacon.lua +++ b/polymer/eduke32/source/lunatic/lunacon.lua @@ -390,7 +390,7 @@ local function reset_labels() g_badids = {} -- NO is also a valid `move', `ai' or `action', but they are handled - -- separately in lookup_composite(). + -- separately in lookup.composite(). g_labeldef = { NO = 0, -- NOTE: these are read-only gamevars in C-CON @@ -416,7 +416,10 @@ local function reset_labels() end end -local function lookup_defined_label(pos, maybe_minus_str, identifier) +-- Table of functions doing various lookups (label, gamevar, ...) +local lookup = {} + +function lookup.defined_label(pos, maybe_minus_str, identifier) local num = g_labeldef[identifier] if (num == nil) then @@ -471,7 +474,7 @@ local function check_composite_literal(labeltype, pos, num) end end -local function lookup_composite(labeltype, pos, identifier) +function lookup.composite(labeltype, pos, identifier) if (identifier=="NO") then -- NO is a special case and is valid for move, action and ai, -- being the same as passing a literal 0. @@ -858,7 +861,7 @@ function Cmd.gamevar(identifier, initval, flags) end end -local function lookup_gamevar(identifier, writable) +function lookup.gamevar(identifier, writable) local gv = g_gamevar[identifier] if (gv == nil) then @@ -880,7 +883,7 @@ end local function maybe_gamevar_Cmt(subj, pos, identifier) if (g_gamevar[identifier]) then - return true, lookup_gamevar(identifier) + return true, lookup.gamevar(identifier) end end @@ -1099,41 +1102,57 @@ local getperxvarcmd = -- getvar[]. <> local setperxvarcmd = -- setvar[].<> arraypat * singlememberpat * sp1 * tok.rvar +-- Function generating code for a struct read/write access. +local function StructAccess(Structname, writep, index, membertab) + assert(type(membertab)=="table") + local member, parm2 = membertab[1], membertab[2] + assert(member ~= nil) + + -- Look up array+member name first, e.g. "spriteext[%s].angoff". + local armembcode = conl.StructAccessCode[Structname][member] + if (armembcode == nil) then + errprintf("invalid %s member `.%s'", Structname, member) + return "_MEMBINVALID" + end + + if (type(armembcode)=="table") then + -- Read and write accesses differ. + armembcode = armembcode[writep and 2 or 1] + if (armembcode==nil) then + errprintf("%s access to %s[].%s is not available", + writep and "write" or "read", Structname, member) + return "_MEMBNOACCESS" + end + end + + local _, numparms = armembcode:gsub("%%s", "%%s", 2) + if (#membertab ~= numparms) then + local nums = { "one", "two" } + errprintf("%s[].%s has %s parameter%s, but %s given", Structname, + member, nums[numparms], numparms==1 and "" or "s", + nums[#membertab]) + return "_MEMBINVPARM" + end + + return format(armembcode, index, parm2) +end + + +function lookup.array_expr(writep, structname, index, membertab) + if (conl.StructAccessCode[structname] == nil) then +-- warnprintf("gamearray access: NYI") + return "_NYI" + end + + return StructAccess(structname, writep, index, membertab) +end + local Access = { - -- : whether the actor is written to. - actor = function(writtenp, index, membertab) - assert(type(membertab)=="table") - local member, parm2 = membertab[1], membertab[2] - assert(member ~= nil) - - -- Look up array+member name first, e.g. "spriteext[%s].angoff". - local armembcode = conl.ActorLabels[member] - if (armembcode == nil) then - errprintf("invalid CON actor member `%s'", member) - return "_MEMBINVALID" - end - - if (type(armembcode)=="table") then - -- Read and write accesses differ. - armembcode = armembcode[writtenp and 2 or 1] - if (armembcode==nil) then - assert(writtenp) - errprintf("write access to CON actor[].%s is not available", member) - return "_MEMBRO" - end - end - - local _, numparms = armembcode:gsub("%%s", "%%s", 2) - if (#membertab ~= numparms) then - local one = numparms==1 - errprintf("CON actor[].%s has %s parameter%s, but %d given", member, - one and "one" or "two", one and "" or "s", #membertab) - return "_MEMBINVPARM" - end - - return format(armembcode, index, parm2) - end, + sector = function(...) return StructAccess("sector", ...) end, + wall = function(...) return StructAccess("wall", ...) end, + xsprite = function(...) return StructAccess("sprite", ...) end, + player = function(...) return StructAccess("player", ...) end, } local function GetStructCmd(accessfunc) @@ -1206,11 +1225,11 @@ local Cinner = { / handle.state, --- 1. get*, set* - getactor = GetStructCmd(Access.actor), + getactor = GetStructCmd(Access.xsprite), getinput = getstructcmd, - getplayer = getstructcmd, + getplayer = GetStructCmd(Access.player), getprojectile = getstructcmd, - getsector = getstructcmd, + getsector = GetStructCmd(Access.sector), getthisprojectile = getstructcmd, gettspr = getstructcmd, -- NOTE: {get,set}userdef is the only struct that can be accessed without @@ -1222,7 +1241,7 @@ local Cinner = { -- We disallow them unless CONs in the wild crop up that actually used -- these. getuserdef = (arraypat + sp1)/{} * singlememberpat * sp1 * tok.wvar, - getwall = getstructcmd, + getwall = GetStructCmd(Access.wall), getactorvar = getperxvarcmd, getplayervar = getperxvarcmd, @@ -2040,31 +2059,31 @@ local Grammar = Pat{ -- However, this conflicts with bad-identifiers, so it should be checked last. -- This would also handle LNGA2's "00000000h", though would give problems with -- e.g. "800h" (hex 0x800 or decimal 800?). - t_define = (POS() * lpeg.C(tok.maybe_minus) * tok.identifier / lookup_defined_label) + tok.number, + t_define = (POS() * lpeg.C(tok.maybe_minus) * tok.identifier / lookup.defined_label) + tok.number, -- Defines and constants can take the place of vars that are only read. -- XXX: now, when tok.rvar fails, the tok.define failure message is printed. - t_rvar = Var("t_botharrayexp") / function() --[[warnprintf("t_rvar: array exprs NYI")--]] return "_NYIVAR" end - + lpeg.Cmt(tok.identifier, maybe_gamevar_Cmt) + tok.define, + t_rvar = Var("t_botharrayexp") + lpeg.Cmt(tok.identifier, maybe_gamevar_Cmt) + tok.define, -- For written-to vars, only (non-parm2) array exprs and writable gamevars -- are permitted. NOTE: C-CON doesn't support inline array exprs here. t_wvar = Var("t_singlearrayexp") / function() errprintf("t_wvar: array exprs NYI") return "_NYIVAR" end - + (tok.identifier / function(id) return lookup_gamevar(id, true) end), + + (tok.identifier / function(id) return lookup.gamevar(id, true) end), t_move = - POS()*tok.identifier / function(...) return lookup_composite(LABEL.MOVE, ...) end + + POS()*tok.identifier / function(...) return lookup.composite(LABEL.MOVE, ...) end + POS()*tok.number / function(...) return check_composite_literal(LABEL.MOVE, ...) end, t_ai = - POS()*tok.identifier / function(...) return lookup_composite(LABEL.AI, ...) end + + POS()*tok.identifier / function(...) return lookup.composite(LABEL.AI, ...) end + POS()*tok.number / function(...) return check_composite_literal(LABEL.AI, ...) end, t_action = - POS()*tok.identifier / function(...) return lookup_composite(LABEL.ACTION, ...) end + + POS()*tok.identifier / function(...) return lookup.composite(LABEL.ACTION, ...) end + POS()*tok.number / function(...) return check_composite_literal(LABEL.ACTION, ...) end, -- New-style inline arrays and structures. - t_botharrayexp = tok.identifier * arraypat * bothmemberpat^-1, + t_botharrayexp = tok.identifier * arraypat * bothmemberpat^-1 + / function(...) return lookup.array_expr(false, ...) end, t_singlearrayexp = tok.identifier * arraypat * singlememberpat^-1, -- SWITCH