contrib: remove obsolete luasrcdiet packaging, its built as part of luci-base now
[project/luci.git] / contrib / luasrcdiet / lua / lparser.lua
diff --git a/contrib/luasrcdiet/lua/lparser.lua b/contrib/luasrcdiet/lua/lparser.lua
deleted file mode 100644 (file)
index a1e10e0..0000000
+++ /dev/null
@@ -1,1295 +0,0 @@
---[[--------------------------------------------------------------------
-
-  lparser.lua: Lua 5.1 parser in Lua
-  This file is part of LuaSrcDiet, based on Yueliang material.
-
-  Copyright (c) 2008 Kein-Hong Man <khman@users.sf.net>
-  The COPYRIGHT file describes the conditions
-  under which this software may be distributed.
-
-  See the ChangeLog for more information.
-
-----------------------------------------------------------------------]]
-
---[[--------------------------------------------------------------------
--- NOTES:
--- * This is a version of the native 5.1.x parser from Yueliang 0.4.0,
---   with significant modifications to handle LuaSrcDiet's needs:
---   (1) needs pre-built token tables instead of a module.method
---   (2) lparser.error is an optional error handler (from llex)
---   (3) not full parsing, currently fakes raw/unlexed constants
---   (4) parser() returns globalinfo, localinfo tables
--- * Please read technotes.txt for more technical details.
--- * NO support for 'arg' vararg functions (LUA_COMPAT_VARARG)
--- * A lot of the parser is unused, but might later be useful for
---   full-on parsing and analysis for a few measly bytes saved.
-----------------------------------------------------------------------]]
-
-local base = _G
-local string = require "string"
-module "lparser"
-local _G = base.getfenv()
-
---[[--------------------------------------------------------------------
--- variable and data structure initialization
-----------------------------------------------------------------------]]
-
-----------------------------------------------------------------------
--- initialization: main variables
-----------------------------------------------------------------------
-
-local toklist,                  -- grammar-only token tables (token table,
-      seminfolist,              -- semantic information table, line number
-      toklnlist,                -- table, cross-reference table)
-      xreflist,
-      tpos,                     -- token position
-
-      line,                     -- start line # for error messages
-      lastln,                   -- last line # for ambiguous syntax chk
-      tok, seminfo, ln, xref,   -- token, semantic info, line
-      nameref,                  -- proper position of <name> token
-      fs,                       -- current function state
-      top_fs,                   -- top-level function state
-
-      globalinfo,               -- global variable information table
-      globallookup,             -- global variable name lookup table
-      localinfo,                -- local variable information table
-      ilocalinfo,               -- inactive locals (prior to activation)
-      ilocalrefs                -- corresponding references to activate
-
--- forward references for local functions
-local explist1, expr, block, exp1, body, chunk
-
-----------------------------------------------------------------------
--- initialization: data structures
-----------------------------------------------------------------------
-
-local gmatch = string.gmatch
-
-local block_follow = {}         -- lookahead check in chunk(), returnstat()
-for v in gmatch("else elseif end until <eof>", "%S+") do
-  block_follow[v] = true
-end
-
-local stat_call = {}            -- lookup for calls in stat()
-for v in gmatch("if while do for repeat function local return break", "%S+") do
-  stat_call[v] = v.."_stat"
-end
-
-local binopr_left = {}          -- binary operators, left priority
-local binopr_right = {}         -- binary operators, right priority
-for op, lt, rt in gmatch([[
-{+ 6 6}{- 6 6}{* 7 7}{/ 7 7}{% 7 7}
-{^ 10 9}{.. 5 4}
-{~= 3 3}{== 3 3}
-{< 3 3}{<= 3 3}{> 3 3}{>= 3 3}
-{and 2 2}{or 1 1}
-]], "{(%S+)%s(%d+)%s(%d+)}") do
-  binopr_left[op] = lt + 0
-  binopr_right[op] = rt + 0
-end
-
-local unopr = { ["not"] = true, ["-"] = true,
-                ["#"] = true, } -- unary operators
-local UNARY_PRIORITY = 8        -- priority for unary operators
-
---[[--------------------------------------------------------------------
--- support functions
-----------------------------------------------------------------------]]
-
-----------------------------------------------------------------------
--- formats error message and throws error (duplicated from llex)
--- * a simplified version, does not report what token was responsible
-----------------------------------------------------------------------
-
-local function errorline(s, line)
-  local e = error or base.error
-  e(string.format("(source):%d: %s", line or ln, s))
-end
-
-----------------------------------------------------------------------
--- handles incoming token, semantic information pairs
--- * NOTE: 'nextt' is named 'next' originally
-----------------------------------------------------------------------
-
--- reads in next token
-local function nextt()
-  lastln = toklnlist[tpos]
-  tok, seminfo, ln, xref
-    = toklist[tpos], seminfolist[tpos], toklnlist[tpos], xreflist[tpos]
-  tpos = tpos + 1
-end
-
--- peek at next token (single lookahead for table constructor)
-local function lookahead()
-  return toklist[tpos]
-end
-
-----------------------------------------------------------------------
--- throws a syntax error, or if token expected is not there
-----------------------------------------------------------------------
-
-local function syntaxerror(msg)
-  local tok = tok
-  if tok ~= "<number>" and tok ~= "<string>" then
-    if tok == "<name>" then tok = seminfo end
-    tok = "'"..tok.."'"
-  end
-  errorline(msg.." near "..tok)
-end
-
-local function error_expected(token)
-  syntaxerror("'"..token.."' expected")
-end
-
-----------------------------------------------------------------------
--- tests for a token, returns outcome
--- * return value changed to boolean
-----------------------------------------------------------------------
-
-local function testnext(c)
-  if tok == c then nextt(); return true end
-end
-
-----------------------------------------------------------------------
--- check for existence of a token, throws error if not found
-----------------------------------------------------------------------
-
-local function check(c)
-  if tok ~= c then error_expected(c) end
-end
-
-----------------------------------------------------------------------
--- verify existence of a token, then skip it
-----------------------------------------------------------------------
-
-local function checknext(c)
-  check(c); nextt()
-end
-
-----------------------------------------------------------------------
--- throws error if condition not matched
-----------------------------------------------------------------------
-
-local function check_condition(c, msg)
-  if not c then syntaxerror(msg) end
-end
-
-----------------------------------------------------------------------
--- verifies token conditions are met or else throw error
-----------------------------------------------------------------------
-
-local function check_match(what, who, where)
-  if not testnext(what) then
-    if where == ln then
-      error_expected(what)
-    else
-      syntaxerror("'"..what.."' expected (to close '"..who.."' at line "..where..")")
-    end
-  end
-end
-
-----------------------------------------------------------------------
--- expect that token is a name, return the name
-----------------------------------------------------------------------
-
-local function str_checkname()
-  check("<name>")
-  local ts = seminfo
-  nameref = xref
-  nextt()
-  return ts
-end
-
-----------------------------------------------------------------------
--- adds given string s in string pool, sets e as VK
-----------------------------------------------------------------------
-
-local function codestring(e, s)
-  e.k = "VK"
-end
-
-----------------------------------------------------------------------
--- consume a name token, adds it to string pool
-----------------------------------------------------------------------
-
-local function checkname(e)
-  codestring(e, str_checkname())
-end
-
---[[--------------------------------------------------------------------
--- variable (global|local|upvalue) handling
--- * to track locals and globals, we can extend Yueliang's minimal
---   variable management code with little trouble
--- * entry point is singlevar() for variable lookups
--- * lookup tables (bl.locallist) are maintained awkwardly in the basic
---   block data structures, PLUS the function data structure (this is
---   an inelegant hack, since bl is nil for the top level of a function)
-----------------------------------------------------------------------]]
-
-----------------------------------------------------------------------
--- register a local variable, create local variable object, set in
--- to-activate variable list
--- * used in new_localvarliteral(), parlist(), fornum(), forlist(),
---   localfunc(), localstat()
-----------------------------------------------------------------------
-
-local function new_localvar(name, special)
-  local bl = fs.bl
-  local locallist
-  -- locate locallist in current block object or function root object
-  if bl then
-    locallist = bl.locallist
-  else
-    locallist = fs.locallist
-  end
-  -- build local variable information object and set localinfo
-  local id = #localinfo + 1
-  localinfo[id] = {             -- new local variable object
-    name = name,                -- local variable name
-    xref = { nameref },         -- xref, first value is declaration
-    decl = nameref,             -- location of declaration, = xref[1]
-  }
-  if special then               -- "self" must be not be changed
-    localinfo[id].isself = true
-  end
-  -- this can override a local with the same name in the same scope
-  -- but first, keep it inactive until it gets activated
-  local i = #ilocalinfo + 1
-  ilocalinfo[i] = id
-  ilocalrefs[i] = locallist
-end
-
-----------------------------------------------------------------------
--- actually activate the variables so that they are visible
--- * remember Lua semantics, e.g. RHS is evaluated first, then LHS
--- * used in parlist(), forbody(), localfunc(), localstat(), body()
-----------------------------------------------------------------------
-
-local function adjustlocalvars(nvars)
-  local sz = #ilocalinfo
-  -- i goes from left to right, in order of local allocation, because
-  -- of something like: local a,a,a = 1,2,3 which gives a = 3
-  while nvars > 0 do
-    nvars = nvars - 1
-    local i = sz - nvars
-    local id = ilocalinfo[i]            -- local's id
-    local obj = localinfo[id]
-    local name = obj.name               -- name of local
-    obj.act = xref                      -- set activation location
-    ilocalinfo[i] = nil
-    local locallist = ilocalrefs[i]     -- ref to lookup table to update
-    ilocalrefs[i] = nil
-    local existing = locallist[name]    -- if existing, remove old first!
-    if existing then                    -- do not overlap, set special
-      obj = localinfo[existing]         -- form of rem, as -id
-      obj.rem = -id
-    end
-    locallist[name] = id                -- activate, now visible to Lua
-  end
-end
-
-----------------------------------------------------------------------
--- remove (deactivate) variables in current scope (before scope exits)
--- * zap entire locallist tables since we are not allocating registers
--- * used in leaveblock(), close_func()
-----------------------------------------------------------------------
-
-local function removevars()
-  local bl = fs.bl
-  local locallist
-  -- locate locallist in current block object or function root object
-  if bl then
-    locallist = bl.locallist
-  else
-    locallist = fs.locallist
-  end
-  -- enumerate the local list at current scope and deactivate 'em
-  for name, id in base.pairs(locallist) do
-    local obj = localinfo[id]
-    obj.rem = xref                      -- set deactivation location
-  end
-end
-
-----------------------------------------------------------------------
--- creates a new local variable given a name
--- * skips internal locals (those starting with '('), so internal
---   locals never needs a corresponding adjustlocalvars() call
--- * special is true for "self" which must not be optimized
--- * used in fornum(), forlist(), parlist(), body()
-----------------------------------------------------------------------
-
-local function new_localvarliteral(name, special)
-  if string.sub(name, 1, 1) == "(" then  -- can skip internal locals
-    return
-  end
-  new_localvar(name, special)
-end
-
-----------------------------------------------------------------------
--- search the local variable namespace of the given fs for a match
--- * returns localinfo index
--- * used only in singlevaraux()
-----------------------------------------------------------------------
-
-local function searchvar(fs, n)
-  local bl = fs.bl
-  local locallist
-  if bl then
-    locallist = bl.locallist
-    while locallist do
-      if locallist[n] then return locallist[n] end  -- found
-      bl = bl.prev
-      locallist = bl and bl.locallist
-    end
-  end
-  locallist = fs.locallist
-  return locallist[n] or -1  -- found or not found (-1)
-end
-
-----------------------------------------------------------------------
--- handle locals, globals and upvalues and related processing
--- * search mechanism is recursive, calls itself to search parents
--- * used only in singlevar()
-----------------------------------------------------------------------
-
-local function singlevaraux(fs, n, var)
-  if fs == nil then  -- no more levels?
-    var.k = "VGLOBAL"  -- default is global variable
-    return "VGLOBAL"
-  else
-    local v = searchvar(fs, n)  -- look up at current level
-    if v >= 0 then
-      var.k = "VLOCAL"
-      var.id = v
-      --  codegen may need to deal with upvalue here
-      return "VLOCAL"
-    else  -- not found at current level; try upper one
-      if singlevaraux(fs.prev, n, var) == "VGLOBAL" then
-        return "VGLOBAL"
-      end
-      -- else was LOCAL or UPVAL, handle here
-      var.k = "VUPVAL"  -- upvalue in this level
-      return "VUPVAL"
-    end--if v
-  end--if fs
-end
-
-----------------------------------------------------------------------
--- consume a name token, creates a variable (global|local|upvalue)
--- * used in prefixexp(), funcname()
-----------------------------------------------------------------------
-
-local function singlevar(v)
-  local name = str_checkname()
-  singlevaraux(fs, name, v)
-  ------------------------------------------------------------------
-  -- variable tracking
-  ------------------------------------------------------------------
-  if v.k == "VGLOBAL" then
-    -- if global being accessed, keep track of it by creating an object
-    local id = globallookup[name]
-    if not id then
-      id = #globalinfo + 1
-      globalinfo[id] = {                -- new global variable object
-        name = name,                    -- global variable name
-        xref = { nameref },             -- xref, first value is declaration
-      }
-      globallookup[name] = id           -- remember it
-    else
-      local obj = globalinfo[id].xref
-      obj[#obj + 1] = nameref           -- add xref
-    end
-  else
-    -- local/upvalue is being accessed, keep track of it
-    local id = v.id
-    local obj = localinfo[id].xref
-    obj[#obj + 1] = nameref             -- add xref
-  end
-end
-
---[[--------------------------------------------------------------------
--- state management functions with open/close pairs
-----------------------------------------------------------------------]]
-
-----------------------------------------------------------------------
--- enters a code unit, initializes elements
-----------------------------------------------------------------------
-
-local function enterblock(isbreakable)
-  local bl = {}  -- per-block state
-  bl.isbreakable = isbreakable
-  bl.prev = fs.bl
-  bl.locallist = {}
-  fs.bl = bl
-end
-
-----------------------------------------------------------------------
--- leaves a code unit, close any upvalues
-----------------------------------------------------------------------
-
-local function leaveblock()
-  local bl = fs.bl
-  removevars()
-  fs.bl = bl.prev
-end
-
-----------------------------------------------------------------------
--- opening of a function
--- * top_fs is only for anchoring the top fs, so that parser() can
---   return it to the caller function along with useful output
--- * used in parser() and body()
-----------------------------------------------------------------------
-
-local function open_func()
-  local new_fs  -- per-function state
-  if not fs then  -- top_fs is created early
-    new_fs = top_fs
-  else
-    new_fs = {}
-  end
-  new_fs.prev = fs  -- linked list of function states
-  new_fs.bl = nil
-  new_fs.locallist = {}
-  fs = new_fs
-end
-
-----------------------------------------------------------------------
--- closing of a function
--- * used in parser() and body()
-----------------------------------------------------------------------
-
-local function close_func()
-  removevars()
-  fs = fs.prev
-end
-
---[[--------------------------------------------------------------------
--- other parsing functions
--- * for table constructor, parameter list, argument list
-----------------------------------------------------------------------]]
-
-----------------------------------------------------------------------
--- parse a function name suffix, for function call specifications
--- * used in primaryexp(), funcname()
-----------------------------------------------------------------------
-
-local function field(v)
-  -- field -> ['.' | ':'] NAME
-  local key = {}
-  nextt()  -- skip the dot or colon
-  checkname(key)
-  v.k = "VINDEXED"
-end
-
-----------------------------------------------------------------------
--- parse a table indexing suffix, for constructors, expressions
--- * used in recfield(), primaryexp()
-----------------------------------------------------------------------
-
-local function yindex(v)
-  -- index -> '[' expr ']'
-  nextt()  -- skip the '['
-  expr(v)
-  checknext("]")
-end
-
-----------------------------------------------------------------------
--- parse a table record (hash) field
--- * used in constructor()
-----------------------------------------------------------------------
-
-local function recfield(cc)
-  -- recfield -> (NAME | '['exp1']') = exp1
-  local key, val = {}, {}
-  if tok == "<name>" then
-    checkname(key)
-  else-- tok == '['
-    yindex(key)
-  end
-  checknext("=")
-  expr(val)
-end
-
-----------------------------------------------------------------------
--- emit a set list instruction if enough elements (LFIELDS_PER_FLUSH)
--- * note: retained in this skeleton because it modifies cc.v.k
--- * used in constructor()
-----------------------------------------------------------------------
-
-local function closelistfield(cc)
-  if cc.v.k == "VVOID" then return end  -- there is no list item
-  cc.v.k = "VVOID"
-end
-
-----------------------------------------------------------------------
--- parse a table list (array) field
--- * used in constructor()
-----------------------------------------------------------------------
-
-local function listfield(cc)
-  expr(cc.v)
-end
-
-----------------------------------------------------------------------
--- parse a table constructor
--- * used in funcargs(), simpleexp()
-----------------------------------------------------------------------
-
-local function constructor(t)
-  -- constructor -> '{' [ field { fieldsep field } [ fieldsep ] ] '}'
-  -- field -> recfield | listfield
-  -- fieldsep -> ',' | ';'
-  local line = ln
-  local cc = {}
-  cc.v = {}
-  cc.t = t
-  t.k = "VRELOCABLE"
-  cc.v.k = "VVOID"
-  checknext("{")
-  repeat
-    if tok == "}" then break end
-    -- closelistfield(cc) here
-    local c = tok
-    if c == "<name>" then  -- may be listfields or recfields
-      if lookahead() ~= "=" then  -- look ahead: expression?
-        listfield(cc)
-      else
-        recfield(cc)
-      end
-    elseif c == "[" then  -- constructor_item -> recfield
-      recfield(cc)
-    else  -- constructor_part -> listfield
-      listfield(cc)
-    end
-  until not testnext(",") and not testnext(";")
-  check_match("}", "{", line)
-  -- lastlistfield(cc) here
-end
-
-----------------------------------------------------------------------
--- parse the arguments (parameters) of a function declaration
--- * used in body()
-----------------------------------------------------------------------
-
-local function parlist()
-  -- parlist -> [ param { ',' param } ]
-  local nparams = 0
-  if tok ~= ")" then  -- is 'parlist' not empty?
-    repeat
-      local c = tok
-      if c == "<name>" then  -- param -> NAME
-        new_localvar(str_checkname())
-        nparams = nparams + 1
-      elseif c == "..." then
-        nextt()
-        fs.is_vararg = true
-      else
-        syntaxerror("<name> or '...' expected")
-      end
-    until fs.is_vararg or not testnext(",")
-  end--if
-  adjustlocalvars(nparams)
-end
-
-----------------------------------------------------------------------
--- parse the parameters of a function call
--- * contrast with parlist(), used in function declarations
--- * used in primaryexp()
-----------------------------------------------------------------------
-
-local function funcargs(f)
-  local args = {}
-  local line = ln
-  local c = tok
-  if c == "(" then  -- funcargs -> '(' [ explist1 ] ')'
-    if line ~= lastln then
-      syntaxerror("ambiguous syntax (function call x new statement)")
-    end
-    nextt()
-    if tok == ")" then  -- arg list is empty?
-      args.k = "VVOID"
-    else
-      explist1(args)
-    end
-    check_match(")", "(", line)
-  elseif c == "{" then  -- funcargs -> constructor
-    constructor(args)
-  elseif c == "<string>" then  -- funcargs -> STRING
-    codestring(args, seminfo)
-    nextt()  -- must use 'seminfo' before 'next'
-  else
-    syntaxerror("function arguments expected")
-    return
-  end--if c
-  f.k = "VCALL"
-end
-
---[[--------------------------------------------------------------------
--- mostly expression functions
-----------------------------------------------------------------------]]
-
-----------------------------------------------------------------------
--- parses an expression in parentheses or a single variable
--- * used in primaryexp()
-----------------------------------------------------------------------
-
-local function prefixexp(v)
-  -- prefixexp -> NAME | '(' expr ')'
-  local c = tok
-  if c == "(" then
-    local line = ln
-    nextt()
-    expr(v)
-    check_match(")", "(", line)
-  elseif c == "<name>" then
-    singlevar(v)
-  else
-    syntaxerror("unexpected symbol")
-  end--if c
-end
-
-----------------------------------------------------------------------
--- parses a prefixexp (an expression in parentheses or a single
--- variable) or a function call specification
--- * used in simpleexp(), assignment(), expr_stat()
-----------------------------------------------------------------------
-
-local function primaryexp(v)
-  -- primaryexp ->
-  --    prefixexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs }
-  prefixexp(v)
-  while true do
-    local c = tok
-    if c == "." then  -- field
-      field(v)
-    elseif c == "[" then  -- '[' exp1 ']'
-      local key = {}
-      yindex(key)
-    elseif c == ":" then  -- ':' NAME funcargs
-      local key = {}
-      nextt()
-      checkname(key)
-      funcargs(v)
-    elseif c == "(" or c == "<string>" or c == "{" then  -- funcargs
-      funcargs(v)
-    else
-      return
-    end--if c
-  end--while
-end
-
-----------------------------------------------------------------------
--- parses general expression types, constants handled here
--- * used in subexpr()
-----------------------------------------------------------------------
-
-local function simpleexp(v)
-  -- simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... |
-  --              constructor | FUNCTION body | primaryexp
-  local c = tok
-  if c == "<number>" then
-    v.k = "VKNUM"
-  elseif c == "<string>" then
-    codestring(v, seminfo)
-  elseif c == "nil" then
-    v.k = "VNIL"
-  elseif c == "true" then
-    v.k = "VTRUE"
-  elseif c == "false" then
-    v.k = "VFALSE"
-  elseif c == "..." then  -- vararg
-    check_condition(fs.is_vararg == true,
-                    "cannot use '...' outside a vararg function");
-    v.k = "VVARARG"
-  elseif c == "{" then  -- constructor
-    constructor(v)
-    return
-  elseif c == "function" then
-    nextt()
-    body(v, false, ln)
-    return
-  else
-    primaryexp(v)
-    return
-  end--if c
-  nextt()
-end
-
-------------------------------------------------------------------------
--- Parse subexpressions. Includes handling of unary operators and binary
--- operators. A subexpr is given the rhs priority level of the operator
--- immediately left of it, if any (limit is -1 if none,) and if a binop
--- is found, limit is compared with the lhs priority level of the binop
--- in order to determine which executes first.
--- * recursively called
--- * used in expr()
-------------------------------------------------------------------------
-
-local function subexpr(v, limit)
-  -- subexpr -> (simpleexp | unop subexpr) { binop subexpr }
-  --   * where 'binop' is any binary operator with a priority
-  --     higher than 'limit'
-  local op = tok
-  local uop = unopr[op]
-  if uop then
-    nextt()
-    subexpr(v, UNARY_PRIORITY)
-  else
-    simpleexp(v)
-  end
-  -- expand while operators have priorities higher than 'limit'
-  op = tok
-  local binop = binopr_left[op]
-  while binop and binop > limit do
-    local v2 = {}
-    nextt()
-    -- read sub-expression with higher priority
-    local nextop = subexpr(v2, binopr_right[op])
-    op = nextop
-    binop = binopr_left[op]
-  end
-  return op  -- return first untreated operator
-end
-
-----------------------------------------------------------------------
--- Expression parsing starts here. Function subexpr is entered with the
--- left operator (which is non-existent) priority of -1, which is lower
--- than all actual operators. Expr information is returned in parm v.
--- * used in cond(), explist1(), index(), recfield(), listfield(),
---   prefixexp(), while_stat(), exp1()
-----------------------------------------------------------------------
-
--- this is a forward-referenced local
-function expr(v)
-  -- expr -> subexpr
-  subexpr(v, 0)
-end
-
---[[--------------------------------------------------------------------
--- third level parsing functions
-----------------------------------------------------------------------]]
-
-------------------------------------------------------------------------
--- parse a variable assignment sequence
--- * recursively called
--- * used in expr_stat()
-------------------------------------------------------------------------
-
-local function assignment(v)
-  local e = {}
-  local c = v.v.k
-  check_condition(c == "VLOCAL" or c == "VUPVAL" or c == "VGLOBAL"
-                  or c == "VINDEXED", "syntax error")
-  if testnext(",") then  -- assignment -> ',' primaryexp assignment
-    local nv = {}  -- expdesc
-    nv.v = {}
-    primaryexp(nv.v)
-    -- lparser.c deals with some register usage conflict here
-    assignment(nv)
-  else  -- assignment -> '=' explist1
-    checknext("=")
-    explist1(e)
-    return  -- avoid default
-  end
-  e.k = "VNONRELOC"
-end
-
-----------------------------------------------------------------------
--- parse a for loop body for both versions of the for loop
--- * used in fornum(), forlist()
-----------------------------------------------------------------------
-
-local function forbody(nvars, isnum)
-  -- forbody -> DO block
-  checknext("do")
-  enterblock(false)  -- scope for declared variables
-  adjustlocalvars(nvars)
-  block()
-  leaveblock()  -- end of scope for declared variables
-end
-
-----------------------------------------------------------------------
--- parse a numerical for loop, calls forbody()
--- * used in for_stat()
-----------------------------------------------------------------------
-
-local function fornum(varname)
-  -- fornum -> NAME = exp1, exp1 [, exp1] DO body
-  local line = line
-  new_localvarliteral("(for index)")
-  new_localvarliteral("(for limit)")
-  new_localvarliteral("(for step)")
-  new_localvar(varname)
-  checknext("=")
-  exp1()  -- initial value
-  checknext(",")
-  exp1()  -- limit
-  if testnext(",") then
-    exp1()  -- optional step
-  else
-    -- default step = 1
-  end
-  forbody(1, true)
-end
-
-----------------------------------------------------------------------
--- parse a generic for loop, calls forbody()
--- * used in for_stat()
-----------------------------------------------------------------------
-
-local function forlist(indexname)
-  -- forlist -> NAME {, NAME} IN explist1 DO body
-  local e = {}
-  -- create control variables
-  new_localvarliteral("(for generator)")
-  new_localvarliteral("(for state)")
-  new_localvarliteral("(for control)")
-  -- create declared variables
-  new_localvar(indexname)
-  local nvars = 1
-  while testnext(",") do
-    new_localvar(str_checkname())
-    nvars = nvars + 1
-  end
-  checknext("in")
-  local line = line
-  explist1(e)
-  forbody(nvars, false)
-end
-
-----------------------------------------------------------------------
--- parse a function name specification
--- * used in func_stat()
-----------------------------------------------------------------------
-
-local function funcname(v)
-  -- funcname -> NAME {field} [':' NAME]
-  local needself = false
-  singlevar(v)
-  while tok == "." do
-    field(v)
-  end
-  if tok == ":" then
-    needself = true
-    field(v)
-  end
-  return needself
-end
-
-----------------------------------------------------------------------
--- parse the single expressions needed in numerical for loops
--- * used in fornum()
-----------------------------------------------------------------------
-
--- this is a forward-referenced local
-function exp1()
-  -- exp1 -> expr
-  local e = {}
-  expr(e)
-end
-
-----------------------------------------------------------------------
--- parse condition in a repeat statement or an if control structure
--- * used in repeat_stat(), test_then_block()
-----------------------------------------------------------------------
-
-local function cond()
-  -- cond -> expr
-  local v = {}
-  expr(v)  -- read condition
-end
-
-----------------------------------------------------------------------
--- parse part of an if control structure, including the condition
--- * used in if_stat()
-----------------------------------------------------------------------
-
-local function test_then_block()
-  -- test_then_block -> [IF | ELSEIF] cond THEN block
-  nextt()  -- skip IF or ELSEIF
-  cond()
-  checknext("then")
-  block()  -- 'then' part
-end
-
-----------------------------------------------------------------------
--- parse a local function statement
--- * used in local_stat()
-----------------------------------------------------------------------
-
-local function localfunc()
-  -- localfunc -> NAME body
-  local v, b = {}
-  new_localvar(str_checkname())
-  v.k = "VLOCAL"
-  adjustlocalvars(1)
-  body(b, false, ln)
-end
-
-----------------------------------------------------------------------
--- parse a local variable declaration statement
--- * used in local_stat()
-----------------------------------------------------------------------
-
-local function localstat()
-  -- localstat -> NAME {',' NAME} ['=' explist1]
-  local nvars = 0
-  local e = {}
-  repeat
-    new_localvar(str_checkname())
-    nvars = nvars + 1
-  until not testnext(",")
-  if testnext("=") then
-    explist1(e)
-  else
-    e.k = "VVOID"
-  end
-  adjustlocalvars(nvars)
-end
-
-----------------------------------------------------------------------
--- parse a list of comma-separated expressions
--- * used in return_stat(), localstat(), funcargs(), assignment(),
---   forlist()
-----------------------------------------------------------------------
-
--- this is a forward-referenced local
-function explist1(e)
-  -- explist1 -> expr { ',' expr }
-  expr(e)
-  while testnext(",") do
-    expr(e)
-  end
-end
-
-----------------------------------------------------------------------
--- parse function declaration body
--- * used in simpleexp(), localfunc(), func_stat()
-----------------------------------------------------------------------
-
--- this is a forward-referenced local
-function body(e, needself, line)
-  -- body ->  '(' parlist ')' chunk END
-  open_func()
-  checknext("(")
-  if needself then
-    new_localvarliteral("self", true)
-    adjustlocalvars(1)
-  end
-  parlist()
-  checknext(")")
-  chunk()
-  check_match("end", "function", line)
-  close_func()
-end
-
-----------------------------------------------------------------------
--- parse a code block or unit
--- * used in do_stat(), while_stat(), forbody(), test_then_block(),
---   if_stat()
-----------------------------------------------------------------------
-
--- this is a forward-referenced local
-function block()
-  -- block -> chunk
-  enterblock(false)
-  chunk()
-  leaveblock()
-end
-
---[[--------------------------------------------------------------------
--- second level parsing functions, all with '_stat' suffix
--- * since they are called via a table lookup, they cannot be local
---   functions (a lookup table of local functions might be smaller...)
--- * stat() -> *_stat()
-----------------------------------------------------------------------]]
-
-----------------------------------------------------------------------
--- initial parsing for a for loop, calls fornum() or forlist()
--- * removed 'line' parameter (used to set debug information only)
--- * used in stat()
-----------------------------------------------------------------------
-
-function for_stat()
-  -- stat -> for_stat -> FOR (fornum | forlist) END
-  local line = line
-  enterblock(true)  -- scope for loop and control variables
-  nextt()  -- skip 'for'
-  local varname = str_checkname()  -- first variable name
-  local c = tok
-  if c == "=" then
-    fornum(varname)
-  elseif c == "," or c == "in" then
-    forlist(varname)
-  else
-    syntaxerror("'=' or 'in' expected")
-  end
-  check_match("end", "for", line)
-  leaveblock()  -- loop scope (`break' jumps to this point)
-end
-
-----------------------------------------------------------------------
--- parse a while-do control structure, body processed by block()
--- * used in stat()
-----------------------------------------------------------------------
-
-function while_stat()
-  -- stat -> while_stat -> WHILE cond DO block END
-  local line = line
-  nextt()  -- skip WHILE
-  cond()  -- parse condition
-  enterblock(true)
-  checknext("do")
-  block()
-  check_match("end", "while", line)
-  leaveblock()
-end
-
-----------------------------------------------------------------------
--- parse a repeat-until control structure, body parsed by chunk()
--- * originally, repeatstat() calls breakstat() too if there is an
---   upvalue in the scope block; nothing is actually lexed, it is
---   actually the common code in breakstat() for closing of upvalues
--- * used in stat()
-----------------------------------------------------------------------
-
-function repeat_stat()
-  -- stat -> repeat_stat -> REPEAT block UNTIL cond
-  local line = line
-  enterblock(true)  -- loop block
-  enterblock(false)  -- scope block
-  nextt()  -- skip REPEAT
-  chunk()
-  check_match("until", "repeat", line)
-  cond()
-  -- close upvalues at scope level below
-  leaveblock()  -- finish scope
-  leaveblock()  -- finish loop
-end
-
-----------------------------------------------------------------------
--- parse an if control structure
--- * used in stat()
-----------------------------------------------------------------------
-
-function if_stat()
-  -- stat -> if_stat -> IF cond THEN block
-  --                    {ELSEIF cond THEN block} [ELSE block] END
-  local line = line
-  local v = {}
-  test_then_block()  -- IF cond THEN block
-  while tok == "elseif" do
-    test_then_block()  -- ELSEIF cond THEN block
-  end
-  if tok == "else" then
-    nextt()  -- skip ELSE
-    block()  -- 'else' part
-  end
-  check_match("end", "if", line)
-end
-
-----------------------------------------------------------------------
--- parse a return statement
--- * used in stat()
-----------------------------------------------------------------------
-
-function return_stat()
-  -- stat -> return_stat -> RETURN explist
-  local e = {}
-  nextt()  -- skip RETURN
-  local c = tok
-  if block_follow[c] or c == ";" then
-    -- return no values
-  else
-    explist1(e)  -- optional return values
-  end
-end
-
-----------------------------------------------------------------------
--- parse a break statement
--- * used in stat()
-----------------------------------------------------------------------
-
-function break_stat()
-  -- stat -> break_stat -> BREAK
-  local bl = fs.bl
-  nextt()  -- skip BREAK
-  while bl and not bl.isbreakable do -- find a breakable block
-    bl = bl.prev
-  end
-  if not bl then
-    syntaxerror("no loop to break")
-  end
-end
-
-----------------------------------------------------------------------
--- parse a function call with no returns or an assignment statement
--- * the struct with .prev is used for name searching in lparse.c,
---   so it is retained for now; present in assignment() also
--- * used in stat()
-----------------------------------------------------------------------
-
-function expr_stat()
-  -- stat -> expr_stat -> func | assignment
-  local v = {}
-  v.v = {}
-  primaryexp(v.v)
-  if v.v.k == "VCALL" then  -- stat -> func
-    -- call statement uses no results
-  else  -- stat -> assignment
-    v.prev = nil
-    assignment(v)
-  end
-end
-
-----------------------------------------------------------------------
--- parse a function statement
--- * used in stat()
-----------------------------------------------------------------------
-
-function function_stat()
-  -- stat -> function_stat -> FUNCTION funcname body
-  local line = line
-  local v, b = {}, {}
-  nextt()  -- skip FUNCTION
-  local needself = funcname(v)
-  body(b, needself, line)
-end
-
-----------------------------------------------------------------------
--- parse a simple block enclosed by a DO..END pair
--- * used in stat()
-----------------------------------------------------------------------
-
-function do_stat()
-  -- stat -> do_stat -> DO block END
-  local line = line
-  nextt()  -- skip DO
-  block()
-  check_match("end", "do", line)
-end
-
-----------------------------------------------------------------------
--- parse a statement starting with LOCAL
--- * used in stat()
-----------------------------------------------------------------------
-
-function local_stat()
-  -- stat -> local_stat -> LOCAL FUNCTION localfunc
-  --                    -> LOCAL localstat
-  nextt()  -- skip LOCAL
-  if testnext("function") then  -- local function?
-    localfunc()
-  else
-    localstat()
-  end
-end
-
---[[--------------------------------------------------------------------
--- main functions, top level parsing functions
--- * accessible functions are: init(lexer), parser()
--- * [entry] -> parser() -> chunk() -> stat()
-----------------------------------------------------------------------]]
-
-----------------------------------------------------------------------
--- initial parsing for statements, calls '_stat' suffixed functions
--- * used in chunk()
-----------------------------------------------------------------------
-
-local function stat()
-  -- stat -> if_stat while_stat do_stat for_stat repeat_stat
-  --         function_stat local_stat return_stat break_stat
-  --         expr_stat
-  line = ln  -- may be needed for error messages
-  local c = tok
-  local fn = stat_call[c]
-  -- handles: if while do for repeat function local return break
-  if fn then
-    _G[fn]()
-    -- return or break must be last statement
-    if c == "return" or c == "break" then return true end
-  else
-    expr_stat()
-  end
-  return false
-end
-
-----------------------------------------------------------------------
--- parse a chunk, which consists of a bunch of statements
--- * used in parser(), body(), block(), repeat_stat()
-----------------------------------------------------------------------
-
--- this is a forward-referenced local
-function chunk()
-  -- chunk -> { stat [';'] }
-  local islast = false
-  while not islast and not block_follow[tok] do
-    islast = stat()
-    testnext(";")
-  end
-end
-
-----------------------------------------------------------------------
--- performs parsing, returns parsed data structure
-----------------------------------------------------------------------
-
-function parser()
-  open_func()
-  fs.is_vararg = true  -- main func. is always vararg
-  nextt()  -- read first token
-  chunk()
-  check("<eof>")
-  close_func()
-  return globalinfo, localinfo
-end
-
-----------------------------------------------------------------------
--- initialization function
-----------------------------------------------------------------------
-
-function init(tokorig, seminfoorig, toklnorig)
-  tpos = 1                      -- token position
-  top_fs = {}                   -- reset top level function state
-  ------------------------------------------------------------------
-  -- set up grammar-only token tables; impedance-matching...
-  -- note that constants returned by the lexer is source-level, so
-  -- for now, fake(!) constant tokens (TK_NUMBER|TK_STRING|TK_LSTRING)
-  ------------------------------------------------------------------
-  local j = 1
-  toklist, seminfolist, toklnlist, xreflist = {}, {}, {}, {}
-  for i = 1, #tokorig do
-    local tok = tokorig[i]
-    local yep = true
-    if tok == "TK_KEYWORD" or tok == "TK_OP" then
-      tok = seminfoorig[i]
-    elseif tok == "TK_NAME" then
-      tok = "<name>"
-      seminfolist[j] = seminfoorig[i]
-    elseif tok == "TK_NUMBER" then
-      tok = "<number>"
-      seminfolist[j] = 0  -- fake!
-    elseif tok == "TK_STRING" or tok == "TK_LSTRING" then
-      tok = "<string>"
-      seminfolist[j] = ""  -- fake!
-    elseif tok == "TK_EOS" then
-      tok = "<eof>"
-    else
-      -- non-grammar tokens; ignore them
-      yep = false
-    end
-    if yep then  -- set rest of the information
-      toklist[j] = tok
-      toklnlist[j] = toklnorig[i]
-      xreflist[j] = i
-      j = j + 1
-    end
-  end--for
-  ------------------------------------------------------------------
-  -- initialize data structures for variable tracking
-  ------------------------------------------------------------------
-  globalinfo, globallookup, localinfo = {}, {}, {}
-  ilocalinfo, ilocalrefs = {}, {}
-end
-
-return _G