local utils = require 'luainlua.common.utils' local tokenizer = require 'luainlua.lua.tokenizer' local ll1 = require 'luainlua.ll1.ll1' local __GRAMMAR__ = {} __GRAMMAR__.grammar = {['funcbody'] = {[1] = {[1] = 'LPAREN', [2] = '$funcbody\'maybe#1', [3] = 'RPAREN', [4] = '$block', [5] = 'END'}, ['variable'] = '$funcbody'}, ['exp_stop'] = {[1] = {[1] = '$tableconstructor'}, [2] = {[1] = '$primaryexp', [2] = '$exp_stop\'star#1'}, [3] = {[1] = '$functiondef'}, [4] = {[1] = 'DOTS'}, [5] = {[1] = 'String'}, [6] = {[1] = 'Number'}, [7] = {[1] = 'TRUE'}, [8] = {[1] = 'FALSE'}, [9] = {[1] = 'NIL'}, ['variable'] = '$exp_stop'}, ['exp8\'maybe#1'] = {[1] = {[1] = '$exp8\'group#1', ['tag'] = '#present'}, [2] = {[1] = ''}, ['variable'] = '$exp8\'maybe#1'}, ['exp5'] = {[1] = {[1] = '$exp6', [2] = '$exp5\''}, ['variable'] = '$exp5'}, ['block\'star#1'] = {[1] = {[1] = '$stat', [2] = '$block\'star#1', ['tag'] = '#list'}, [2] = {[1] = ''}, ['variable'] = '$block\'star#1'}, ['assignment'] = {[1] = {[1] = 'EQ', [2] = '$explist'}, [2] = {[1] = 'COMMA', [2] = '$primaryexp', [3] = '$assignment\'star#1', [4] = '$assignment'}, ['variable'] = '$assignment'}, ['assignment_or_call'] = {[1] = {[1] = '$primaryexp', [2] = '$assignment_or_call\'star#1', [3] = '$assignment_or_call\'maybe#1'}, ['variable'] = '$assignment_or_call'}, ['parlist'] = {[1] = {[1] = '$parlist\'star#1', [2] = '$parlist\'group#2'}, ['variable'] = '$parlist'}, ['tableconstructor'] = {[1] = {[1] = 'LBRACE', [2] = '$tableconstructor\'star#1', [3] = 'RBRACE'}, ['variable'] = '$tableconstructor'}, ['exp3'] = {[1] = {[1] = '$exp4', [2] = '$exp3\''}, ['variable'] = '$exp3'}, ['funcname\'group#1'] = {[1] = {[1] = 'PERIOD', [2] = 'Name'}, ['variable'] = '$funcname\'group#1'}, ['exp7'] = {[1] = {[1] = '$exp8'}, [2] = {[1] = '$level7', [2] = '$exp7'}, ['variable'] = '$exp7'}, ['funcname\'group#2'] = {[1] = {[1] = 'COLON', [2] = 'Name'}, ['variable'] = '$funcname\'group#2'}, ['level7'] = {[1] = {[1] = 'MIN'}, [2] = {[1] = 'HASH'}, [3] = {[1] = 'NOT'}, ['variable'] = '$level7'}, ['unop'] = {[1] = {[1] = 'HASH'}, [2] = {[1] = 'NOT'}, [3] = {[1] = 'MIN'}, ['variable'] = '$unop'}, ['funcbody\'maybe#1'] = {[1] = {[1] = '$parlist', ['tag'] = '#present'}, [2] = {[1] = ''}, ['variable'] = '$funcbody\'maybe#1'}, ['assignment\'star#1'] = {[1] = {[1] = '$suffix', [2] = '$assignment\'star#1', ['tag'] = '#list'}, [2] = {[1] = ''}, ['variable'] = '$assignment\'star#1'}, ['retstat\'maybe#1'] = {[1] = {[1] = '$explist', ['tag'] = '#present'}, [2] = {[1] = ''}, ['variable'] = '$retstat\'maybe#1'}, ['level3'] = {[1] = {[1] = 'EQEQ'}, [2] = {[1] = 'NOTEQ'}, [3] = {[1] = 'GE'}, [4] = {[1] = 'LE'}, [5] = {[1] = 'GT'}, [6] = {[1] = 'LT'}, ['variable'] = '$level3'}, ['binop'] = {[1] = {[1] = 'OR'}, [2] = {[1] = 'AND'}, [3] = {[1] = 'NOTEQ'}, [4] = {[1] = 'EQEQ'}, [5] = {[1] = 'GE'}, [6] = {[1] = 'GT'}, [7] = {[1] = 'LE'}, [8] = {[1] = 'LT'}, [9] = {[1] = 'CONCAT'}, [10] = {[1] = 'MOD'}, [11] = {[1] = 'POW'}, [12] = {[1] = 'DIV'}, [13] = {[1] = 'MUL'}, [14] = {[1] = 'MIN'}, [15] = {[1] = 'PLUS'}, ['variable'] = '$binop'}, ['block'] = {[1] = {[1] = '$block\'star#1', [2] = '$block\'maybe#1'}, ['variable'] = '$block'}, ['stat\'group#1\'maybe#1'] = {[1] = {[1] = '$stat\'group#1\'group#1', ['tag'] = '#present'}, [2] = {[1] = ''}, ['variable'] = '$stat\'group#1\'maybe#1'}, ['tableconstructor\'star#1'] = {[1] = {[1] = '$field', [2] = '$tableconstructor\'star#1', ['tag'] = '#list'}, [2] = {[1] = ''}, ['variable'] = '$tableconstructor\'star#1'}, ['field'] = {[1] = {[1] = '$exp', [2] = '$field\'maybe#1', ['tag'] = 'exp'}, [2] = {[1] = 'Name', [2] = 'EQ', [3] = '$exp', [4] = '$field\'maybe#2', ['tag'] = 'assign'}, [3] = {[1] = 'LBRACK', [2] = '$exp', [3] = 'RBRACK', [4] = 'EQ', [5] = '$exp', [6] = '$field\'maybe#3'}, ['variable'] = '$field'}, ['functiondef'] = {[1] = {[1] = 'FUNCTION', [2] = '$funcbody'}, ['variable'] = '$functiondef'}, ['exp4\'maybe#1'] = {[1] = {[1] = '$exp4\'group#1', ['tag'] = '#present'}, [2] = {[1] = ''}, ['variable'] = '$exp4\'maybe#1'}, ['funcname'] = {[1] = {[1] = 'Name', [2] = '$funcname\'star#1', [3] = '$funcname\'maybe#1'}, ['variable'] = '$funcname'}, ['exp2\''] = {[1] = {[1] = ''}, [2] = {[1] = '$level2', [2] = '$exp3', [3] = '$exp2\''}, ['variable'] = '$exp2\''}, ['funcname\'star#1'] = {[1] = {[1] = '$funcname\'group#1', [2] = '$funcname\'star#1', ['tag'] = '#list'}, [2] = {[1] = ''}, ['variable'] = '$funcname\'star#1'}, ['stat\'group#4'] = {[1] = {[1] = 'ELSE', [2] = '$block'}, ['variable'] = '$stat\'group#4'}, ['exp4\'group#1'] = {[1] = {[1] = '$level4', [2] = '$exp4'}, ['variable'] = '$exp4\'group#1'}, ['retstat'] = {[1] = {[1] = 'RETURN', [2] = '$retstat\'maybe#1', [3] = '$retstat\'maybe#2'}, ['variable'] = '$retstat'}, ['exp6\''] = {[1] = {[1] = ''}, [2] = {[1] = '$level6', [2] = '$exp7', [3] = '$exp6\''}, ['variable'] = '$exp6\''}, ['root'] = {[1] = {[1] = '$block'}, ['variable'] = '$root'}, ['block\'maybe#1'] = {[1] = {[1] = '$retstat', ['tag'] = '#present'}, [2] = {[1] = ''}, ['variable'] = '$block\'maybe#1'}, ['level1'] = {[1] = {[1] = 'OR'}, ['variable'] = '$level1'}, ['exp'] = {[1] = {[1] = '$exp2', [2] = '$exp\''}, ['variable'] = '$exp'}, ['exp3\''] = {[1] = {[1] = ''}, [2] = {[1] = '$level3', [2] = '$exp4', [3] = '$exp3\''}, ['variable'] = '$exp3\''}, ['explist\'star#1'] = {[1] = {[1] = '$explist\'group#1', [2] = '$explist\'star#1', ['tag'] = '#list'}, [2] = {[1] = ''}, ['variable'] = '$explist\'star#1'}, ['label'] = {[1] = {[1] = 'QUAD', [2] = 'Name', [3] = 'QUAD'}, ['variable'] = '$label'}, ['funcname\'maybe#1'] = {[1] = {[1] = '$funcname\'group#2', ['tag'] = '#present'}, [2] = {[1] = ''}, ['variable'] = '$funcname\'maybe#1'}, ['level8'] = {[1] = {[1] = 'POW'}, ['variable'] = '$level8'}, ['assignment_or_call\'maybe#1'] = {[1] = {[1] = '$assignment', ['tag'] = '#present'}, [2] = {[1] = ''}, ['variable'] = '$assignment_or_call\'maybe#1'}, ['level6'] = {[1] = {[1] = 'MOD'}, [2] = {[1] = 'DIV'}, [3] = {[1] = 'MUL'}, ['variable'] = '$level6'}, ['level5'] = {[1] = {[1] = 'MIN'}, [2] = {[1] = 'PLUS'}, ['variable'] = '$level5'}, ['exp\''] = {[1] = {[1] = ''}, [2] = {[1] = '$level1', [2] = '$exp2', [3] = '$exp\''}, ['variable'] = '$exp\''}, ['stat\'group#2\'maybe#1'] = {[1] = {[1] = '$stat\'group#2\'group#1', ['tag'] = '#present'}, [2] = {[1] = ''}, ['variable'] = '$stat\'group#2\'maybe#1'}, ['stat\'group#1'] = {[1] = {[1] = '$namelist', [2] = '$stat\'group#1\'maybe#1'}, [2] = {[1] = 'FUNCTION', [2] = 'Name', [3] = '$funcbody'}, ['variable'] = '$stat\'group#1'}, ['fieldsep'] = {[1] = {[1] = 'SEMICOLON'}, [2] = {[1] = 'COMMA'}, ['variable'] = '$fieldsep'}, ['stat\'maybe#1'] = {[1] = {[1] = '$stat\'group#4', ['tag'] = '#present'}, [2] = {[1] = ''}, ['variable'] = '$stat\'maybe#1'}, ['namelist\'group#1'] = {[1] = {[1] = 'COMMA', [2] = 'Name'}, ['variable'] = '$namelist\'group#1'}, ['stat\'star#1'] = {[1] = {[1] = '$stat\'group#3', [2] = '$stat\'star#1', ['tag'] = '#list'}, [2] = {[1] = ''}, ['variable'] = '$stat\'star#1'}, ['exp5\''] = {[1] = {[1] = ''}, [2] = {[1] = '$level5', [2] = '$exp6', [3] = '$exp5\'', ['tag'] = 'minus'}, ['variable'] = '$exp5\''}, ['args\'maybe#1'] = {[1] = {[1] = '$explist', ['tag'] = '#present'}, [2] = {[1] = ''}, ['variable'] = '$args\'maybe#1'}, ['stat\'group#3'] = {[1] = {[1] = 'ELSEIF', [2] = '$exp', [3] = 'THEN', [4] = '$block'}, ['variable'] = '$stat\'group#3'}, ['stat\'group#2\'group#1'] = {[1] = {[1] = 'COMMA', [2] = '$exp'}, ['variable'] = '$stat\'group#2\'group#1'}, ['parlist\'group#2'] = {[1] = {[1] = 'DOTS'}, [2] = {[1] = 'Name'}, ['variable'] = '$parlist\'group#2'}, ['stat\'group#2'] = {[1] = {[1] = '$namelist', [2] = 'IN', [3] = '$explist', [4] = 'DO', [5] = '$block', [6] = 'END', ['tag'] = 'foreach'}, [2] = {[1] = 'Name', [2] = 'EQ', [3] = '$exp', [4] = 'COMMA', [5] = '$exp', [6] = '$stat\'group#2\'maybe#1', [7] = 'DO', [8] = '$block', [9] = 'END', ['tag'] = 'forcounter'}, ['variable'] = '$stat\'group#2'}, ['stat\'group#1\'group#1'] = {[1] = {[1] = 'EQ', [2] = '$explist'}, ['variable'] = '$stat\'group#1\'group#1'}, ['retstat\'maybe#2'] = {[1] = {[1] = 'SEMICOLON', ['tag'] = '#present'}, [2] = {[1] = ''}, ['variable'] = '$retstat\'maybe#2'}, ['exp4'] = {[1] = {[1] = '$exp5', [2] = '$exp4\'maybe#1'}, ['variable'] = '$exp4'}, ['field\'maybe#1'] = {[1] = {[1] = '$fieldsep', ['tag'] = '#present'}, [2] = {[1] = ''}, ['variable'] = '$field\'maybe#1'}, ['exp6'] = {[1] = {[1] = '$exp7', [2] = '$exp6\''}, ['variable'] = '$exp6'}, ['exp_stop\'star#1'] = {[1] = {[1] = '$suffix', [2] = '$exp_stop\'star#1', ['tag'] = '#list'}, [2] = {[1] = ''}, ['variable'] = '$exp_stop\'star#1'}, ['parlist\'group#1'] = {[1] = {[1] = 'Name', [2] = 'COMMA', ['tag'] = 'namelist'}, ['variable'] = '$parlist\'group#1'}, ['field\'maybe#2'] = {[1] = {[1] = '$fieldsep', ['tag'] = '#present'}, [2] = {[1] = ''}, ['variable'] = '$field\'maybe#2'}, ['field\'maybe#3'] = {[1] = {[1] = '$fieldsep', ['tag'] = '#present'}, [2] = {[1] = ''}, ['variable'] = '$field\'maybe#3'}, ['assignment_or_call\'star#1'] = {[1] = {[1] = '$assignment_or_call\'group#1', [2] = '$assignment_or_call\'star#1', ['tag'] = '#list'}, [2] = {[1] = ''}, ['variable'] = '$assignment_or_call\'star#1'}, ['explist'] = {[1] = {[1] = '$exp', [2] = '$explist\'star#1'}, ['variable'] = '$explist'}, ['namelist'] = {[1] = {[1] = 'Name', [2] = '$namelist\'star#1'}, ['variable'] = '$namelist'}, ['exp8\'group#1'] = {[1] = {[1] = '$level8', [2] = '$exp8'}, ['variable'] = '$exp8\'group#1'}, ['level4'] = {[1] = {[1] = 'CONCAT'}, ['variable'] = '$level4'}, ['primaryexp'] = {[1] = {[1] = 'LPAREN', [2] = '$exp', [3] = 'RPAREN'}, [2] = {[1] = 'Name'}, ['variable'] = '$primaryexp'}, ['level2'] = {[1] = {[1] = 'AND'}, ['variable'] = '$level2'}, ['stat'] = {[1] = {[1] = 'LOCAL', [2] = '$stat\'group#1'}, [2] = {[1] = 'FUNCTION', [2] = '$funcname', [3] = '$funcbody'}, [3] = {[1] = 'FOR', [2] = '$stat\'group#2'}, [4] = {[1] = 'IF', [2] = '$exp', [3] = 'THEN', [4] = '$block', [5] = '$stat\'star#1', [6] = '$stat\'maybe#1', [7] = 'END'}, [5] = {[1] = 'REPEAT', [2] = '$block', [3] = 'UNTIL', [4] = '$exp'}, [6] = {[1] = 'WHILE', [2] = '$exp', [3] = 'DO', [4] = '$block', [5] = 'END'}, [7] = {[1] = 'DO', [2] = '$block', [3] = 'END'}, [8] = {[1] = 'GOTO', [2] = 'Name'}, [9] = {[1] = 'BREAK'}, [10] = {[1] = '$label'}, [11] = {[1] = '$assignment_or_call'}, [12] = {[1] = 'SEMICOLON'}, ['variable'] = '$stat'}, ['assignment_or_call\'group#1'] = {[1] = {[1] = '$args', ['tag'] = 'call'}, [2] = {[1] = 'COLON', [2] = 'Name', [3] = '$args'}, [3] = {[1] = 'LBRACK', [2] = '$exp', [3] = 'RBRACK'}, [4] = {[1] = 'PERIOD', [2] = 'Name'}, ['variable'] = '$assignment_or_call\'group#1'}, ['namelist\'star#1'] = {[1] = {[1] = '$namelist\'group#1', [2] = '$namelist\'star#1', ['tag'] = '#list'}, [2] = {[1] = ''}, ['variable'] = '$namelist\'star#1'}, ['suffix'] = {[1] = {[1] = '$args'}, [2] = {[1] = 'COLON', [2] = 'Name', [3] = '$args'}, [3] = {[1] = 'LBRACK', [2] = '$exp', [3] = 'RBRACK'}, [4] = {[1] = 'PERIOD', [2] = 'Name'}, ['variable'] = '$suffix'}, ['exp8'] = {[1] = {[1] = '$exp_stop', [2] = '$exp8\'maybe#1'}, ['variable'] = '$exp8'}, ['explist\'group#1'] = {[1] = {[1] = 'COMMA', [2] = '$exp'}, ['variable'] = '$explist\'group#1'}, ['args'] = {[1] = {[1] = 'String'}, [2] = {[1] = '$tableconstructor'}, [3] = {[1] = 'LPAREN', [2] = '$args\'maybe#1', [3] = 'RPAREN'}, ['variable'] = '$args'}, ['parlist\'star#1'] = {[1] = {[1] = '$parlist\'group#1', [2] = '$parlist\'star#1', ['tag'] = '#list'}, [2] = {[1] = ''}, ['variable'] = '$parlist\'star#1'}, ['exp2'] = {[1] = {[1] = '$exp3', [2] = '$exp2\''}, ['variable'] = '$exp2'}} __GRAMMAR__.grammar[1] = 'luainlua/lua/parser_table.lua' local ast = {} function ast:__newindex(key, val) if type(key) ~= 'string' then return rawset(self, key, val) end assert(not self[key], 'Fields passed to a node should be initialized only once.') rawset(self, key, val) -- other stuff if val.kind then table.insert(self, val) assert(not val.parent, 'Fields passed to a node should be unowned.') rawset(val, 'parent', self) end end function ast:set(key, val) if not key or not val then return self end if not val.kind then print(debug.traceback()) end assert(val.kind, 'Set should only be called on child trees.') self[key] = val return self end function ast:list(...) local list = {...} for child in utils.loop(list) do if not child.kind then print(debug.traceback()) end assert(child.kind, 'List should only be called on child trees.') table.insert(self, child) assert(not child.parent or child.parent.kind == 'explist', 'Children passed to list(...) should be unowned.') rawset(child, 'parent', self) end return self end function ast:children() return utils.loop(self) end local function node(location, kind) return setmetatable({kind = kind, location = location}, {__index = ast, __newindex = ast.__newindex}) end local function from(token, kind) if not kind then if tostring(token) == 'Name' then kind = 'name' else kind = 'leaf' end end local leaf = node(token.location, kind) leaf.token = token leaf.value = token[2] return leaf end -- this will either reduce to an index, a call, a name, or a grouped expression -- // Shape of a suffix: {index = shape(from(name)), args = shape(args)} -- suffix := '.' Name {\: suffix_dot :\} // field -- | '[' $exp ']' {\: suffix_bracket :\} // field -- | ':' Name $args {\: suffix_colon :\} // arg -- | $args {\: suffix_args :\} // arg -- primaryexp := Name [: from(_1) :] -- | '(' $exp ')' [: _2 :] -- primary_suffix := $primaryexp $suffix* -- Plan: recurse on the structural inductive properties of a list local function handle_primary_suffix(left, suffixlist) if #suffixlist == 0 then return left end -- pop the first element out of suffixlist local suffix = suffixlist[1] local rest = utils.sublist(suffixlist, 2) if suffix.index and not suffix.args then return handle_primary_suffix( node(left.location, 'index'):set('left', left):set('right', suffix.index), rest) elseif suffix.args and not suffix.index then return handle_primary_suffix( node(left.location, 'call'):set('target', left):set('args', suffix.args), rest) elseif suffix.args and suffix.index then local index = node(left.location, 'index'):set('left', left):set('right', suffix.index) return handle_primary_suffix( node(index.location, 'selfcall'):set('target', index):set('args', suffix.args), rest) end error 'unimplemented' end local function suffix_dot(_, name) return { index = from(name, "string"), args = nil, } end local function suffix_bracket(_, exp) return { index = exp, args = nil, } end local function suffix_colon(_, name, args) return { index = from(name, "string"), args = args, } end local function suffix_args(args) return { index = nil, args = args, } end local function parlist_namelist(namelist, trail) local parameters = node(namelist[1] and namelist[1].location or trail.location, 'parameters') for name in utils.loop(namelist) do parameters:list(from(name)) end if trail[1] == 'DOTS' then rawset(parameters, 'vararg', from(trail)) else parameters:list(from(trail)) end return parameters end local function goto_list(self) return self:go '#list' end local make_binop = function(left, rest) if #rest == 0 then return left end assert(#rest == 2 and rest[1].kind == 'binop' and not rest[1].left) local hole, binop = unpack(rest) hole.left = left return binop end local start_binop = function(bop, right, rest) -- In ocaml style pseduocode -- let start (+) e_r rest = -- let o = hole() in -- match rest with -- | None -> o, (o (+) e_r) -- | Some(., e_l' (*) e_r' as e') -> -- let e'' = fill(e', ., (o (+) e_r) in -- o, e'' -- Invariant: expn' is always "holed" and expn is always whole -- Invariant: immediately holed expn' is always holey on the left local hole = node(bop.location, 'binop') hole.operator = bop hole.right = right -- implicit: hole.left is the hole if #rest == 0 then return {hole, hole} end assert(#rest == 2 and rest[1].kind == 'binop' and not rest[1].left) rest[1].left = hole return {hole, rest[2]} end local function start_right_binop(bop, right) -- invariant: right is whole, return is immediately holed local hole = node(bop.location, 'binop') hole.operator = bop hole.right = right return hole end local function make_right_binop(left, binop_opt) local binop = binop_opt[1] if not binop then return left end assert(binop.kind == 'binop' and not binop.left) binop.left = left return binop end __GRAMMAR__.convert = function(token) return token[1] end __GRAMMAR__.prologue = function(stream) local tokens = {} for token in tokenizer(stream) do table.insert(tokens, token) end return tokens end __GRAMMAR__.epilogue = function(...) return ... end __GRAMMAR__.default_action = function(...) return {...} end __GRAMMAR__.grammar["funcbody"][1].action = function(_1, parameters_opt, _, block) local parameters = parameters_opt[1] or node(_1.location, 'parameters') return {parameters, block} end __GRAMMAR__.grammar["exp_stop"][1].action = function(_1) return _1 end __GRAMMAR__.grammar["exp_stop"][2].action = handle_primary_suffix __GRAMMAR__.grammar["exp_stop"][3].action = function(_1) return _1 end __GRAMMAR__.grammar["exp_stop"][4].action = function(_1) return node(_1.location, 'vararg') end __GRAMMAR__.grammar["exp_stop"][5].action = function(_1) return from(_1, 'string') end __GRAMMAR__.grammar["exp_stop"][6].action = function(_1) return from(_1, 'number') end __GRAMMAR__.grammar["exp_stop"][7].action = function(_1) return node(_1.location, 'true') end __GRAMMAR__.grammar["exp_stop"][8].action = function(_1) return node(_1.location, 'false') end __GRAMMAR__.grammar["exp_stop"][9].action = function(_1) return node(_1.location, 'nil') end __GRAMMAR__.grammar["exp8'maybe#1"][1].action = function(item) return {item} end __GRAMMAR__.grammar["exp8'maybe#1"][2].action = function() return {} end __GRAMMAR__.grammar["exp5"][1].action = make_binop __GRAMMAR__.grammar["block'star#1"][1].action = function(item, list) table.insert(list, 1, item); return list end __GRAMMAR__.grammar["block'star#1"][2].action = function() return {} end __GRAMMAR__.grammar["assignment"][1].action = function(_1, _2) return {{}, _2} end __GRAMMAR__.grammar["assignment"][2].action = function(_, _1, _2, _3) local left, right = unpack(_3) table.insert(left, 1, handle_primary_suffix(_1, _2)); return {left, right} end __GRAMMAR__.grammar["assignment_or_call"][1].action = function(left, suffixes, assignment_opt) local assignment = #assignment_opt == 0 and {} or assignment_opt[1] -- let's reduce to call or assignment if (#suffixes == 0 or not suffixes[#suffixes].args) and #assignment == 0 then error('Parser error: you can only specify a call or an assignment here') end if #suffixes ~= 0 and #assignment ~= 0 and suffixes[#suffixes].args then error 'Parser error: you cannot assign to a call' end if #assignment ~= 0 then -- assignment case -- assignment is a list of subsequent assignments local ps = handle_primary_suffix(left, suffixes) assert(ps.kind == 'index' or ps.kind == 'name') local lvals, rvals = unpack(assignment) table.insert(lvals, 1, ps) lvals = node(ps.location, 'lvalues'):list(unpack(lvals)) local tree = node(ps.location, 'assignments') tree.left = lvals tree.right = rvals return tree else -- call case local ps = handle_primary_suffix(left, suffixes) assert(ps.kind == 'call' or ps.kind == 'selfcall') return node(ps.location, 'callstmt'):list(ps) end end __GRAMMAR__.grammar["parlist"][1].action = parlist_namelist __GRAMMAR__.grammar["tableconstructor"][1].action = function(_1, _2, _3) return node(_1.location, 'table'):list(unpack(_2)) end __GRAMMAR__.grammar["exp3"][1].action = make_binop __GRAMMAR__.grammar["funcname'group#1"][1].action = function(_1, _2) return from(_2) end __GRAMMAR__.grammar["exp7"][1].action = function(_1) return _1 end __GRAMMAR__.grammar["exp7"][2].action = function(_1, _2) return node(_1.location, 'unop'):set('operator', _1):set('operand', _2) end __GRAMMAR__.grammar["funcname'group#2"][1].action = function(_1, _2) return from(_2) end __GRAMMAR__.grammar["level7"][1].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["level7"][2].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["level7"][3].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["unop"][1].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["unop"][2].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["unop"][3].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["funcbody'maybe#1"][1].action = function(item) return {item} end __GRAMMAR__.grammar["funcbody'maybe#1"][2].action = function() return {} end __GRAMMAR__.grammar["assignment'star#1"][1].action = function(item, list) table.insert(list, 1, item); return list end __GRAMMAR__.grammar["assignment'star#1"][2].action = function() return {} end __GRAMMAR__.grammar["retstat'maybe#1"][1].action = function(item) return {item} end __GRAMMAR__.grammar["retstat'maybe#1"][2].action = function() return {} end __GRAMMAR__.grammar["level3"][1].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["level3"][2].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["level3"][3].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["level3"][4].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["level3"][5].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["level3"][6].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["binop"][1].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["binop"][2].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["binop"][3].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["binop"][4].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["binop"][5].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["binop"][6].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["binop"][7].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["binop"][8].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["binop"][9].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["binop"][10].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["binop"][11].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["binop"][12].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["binop"][13].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["binop"][14].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["binop"][15].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["block"][1].action = function(stats, ret) local tree = node((stats[1] and stats[1].location) or (ret[1] and ret[1].location), 'block') tree:list(unpack(stats)) return tree:set('ret', (#ret ~= 0 and ret[1]) or nil) end __GRAMMAR__.grammar["stat'group#1'maybe#1"][1].action = function(item) return {item} end __GRAMMAR__.grammar["stat'group#1'maybe#1"][2].action = function() return {} end __GRAMMAR__.grammar["tableconstructor'star#1"][1].action = function(item, list) table.insert(list, 1, item); return list end __GRAMMAR__.grammar["tableconstructor'star#1"][2].action = function() return {} end __GRAMMAR__.grammar["field"][1].action = function(_1, _2) return node(_1.location, 'element'):set('value', _1) end __GRAMMAR__.grammar["field"][2].action = function(_1, _2, _3, _4) return node(_1.location, 'element'):set('index', from(_1, 'string')):set('value', _3) end __GRAMMAR__.grammar["field"][3].action = function(_1, _2, _3, _4, _5, _6) return node(_1.location, 'element'):set('index', _2):set('value', _5) end __GRAMMAR__.grammar["functiondef"][1].action = function(_1, _2) return node(_1.location, 'function'):set('parameters', _2[1]):set('body', _2[2]) end __GRAMMAR__.grammar["exp4'maybe#1"][1].action = function(item) return {item} end __GRAMMAR__.grammar["exp4'maybe#1"][2].action = function() return {} end __GRAMMAR__.grammar["funcname"][1].action = function(name, names, colon) local tree = node(name.location, 'funcnames') colon = colon[1] tree:list(from(name)) tree:list(unpack(names)) if colon then tree.colon = colon end return tree end __GRAMMAR__.grammar["exp2'"][1].action = function(_1) return {} end __GRAMMAR__.grammar["exp2'"][2].action = start_binop __GRAMMAR__.grammar["funcname'star#1"][1].action = function(item, list) table.insert(list, 1, item); return list end __GRAMMAR__.grammar["funcname'star#1"][2].action = function() return {} end __GRAMMAR__.grammar["stat'group#4"][1].action = function(_1, _2) return node(_1.location, 'else'):set('block', _2) end __GRAMMAR__.grammar["exp4'group#1"][1].action = start_right_binop __GRAMMAR__.grammar["retstat"][1].action = function(_1, _2, _3) return #_2 == 0 and node(_1.location, 'return') or node(_1.location, 'return'):set('explist', _2[1]) end __GRAMMAR__.grammar["exp6'"][1].action = function(_1) return {} end __GRAMMAR__.grammar["exp6'"][2].action = start_binop __GRAMMAR__.grammar["root"][1].action = function(_1) return _1 end __GRAMMAR__.grammar["block'maybe#1"][1].action = function(item) return {item} end __GRAMMAR__.grammar["block'maybe#1"][2].action = function() return {} end __GRAMMAR__.grammar["level1"][1].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["exp"][1].action = make_binop __GRAMMAR__.grammar["exp3'"][1].action = function(_1) return {} end __GRAMMAR__.grammar["exp3'"][2].action = start_binop __GRAMMAR__.grammar["explist'star#1"][1].action = function(item, list) table.insert(list, 1, item); return list end __GRAMMAR__.grammar["explist'star#1"][2].action = function() return {} end __GRAMMAR__.grammar["label"][1].action = function(_1, _2, _3) return node(_1.location, 'label'):set('name', from(_2)) end __GRAMMAR__.grammar["funcname'maybe#1"][1].action = function(item) return {item} end __GRAMMAR__.grammar["funcname'maybe#1"][2].action = function() return {} end __GRAMMAR__.grammar["level8"][1].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["assignment_or_call'maybe#1"][1].action = function(item) return {item} end __GRAMMAR__.grammar["assignment_or_call'maybe#1"][2].action = function() return {} end __GRAMMAR__.grammar["level6"][1].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["level6"][2].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["level6"][3].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["level5"][1].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["level5"][2].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["exp'"][1].action = function(_1) return {} end __GRAMMAR__.grammar["exp'"][2].action = start_binop __GRAMMAR__.grammar["stat'group#2'maybe#1"][1].action = function(item) return {item} end __GRAMMAR__.grammar["stat'group#2'maybe#1"][2].action = function() return {} end __GRAMMAR__.grammar["stat'group#1"][1].action = function(_1, _2) return node(_1.location, 'localassign'):set('left', _1):set('right', _2[1]) end __GRAMMAR__.grammar["stat'group#1"][2].action = function(_1, _2, _3) return node(_1.location, 'localfunctiondef'):set('name', from(_2)):set('function', node(_3[1].location, 'function'):set('parameters', _3[1]):set('body', _3[2])) end __GRAMMAR__.grammar["fieldsep"][1].action = function(_1) return {} end __GRAMMAR__.grammar["fieldsep"][2].action = function(_1) return {} end __GRAMMAR__.grammar["stat'maybe#1"][1].action = function(item) return {item} end __GRAMMAR__.grammar["stat'maybe#1"][2].action = function() return {} end __GRAMMAR__.grammar["namelist'group#1"][1].action = function(_1, _2) return from(_2) end __GRAMMAR__.grammar["stat'star#1"][1].action = function(item, list) table.insert(list, 1, item); return list end __GRAMMAR__.grammar["stat'star#1"][2].action = function() return {} end __GRAMMAR__.grammar["exp5'"][1].action = function(_1) return {} end __GRAMMAR__.grammar["exp5'"][2].action = start_binop __GRAMMAR__.grammar["args'maybe#1"][1].action = function(item) return {item} end __GRAMMAR__.grammar["args'maybe#1"][2].action = function() return {} end __GRAMMAR__.grammar["stat'group#3"][1].action = function(_1, _2, _3, _4) return node(_1.location, 'elseif'):set('cond', _2):set('block', _4) end __GRAMMAR__.grammar["stat'group#2'group#1"][1].action = function(_1, _2) return _2 end __GRAMMAR__.grammar["parlist'group#2"][1].action = function(_1) return _1 end __GRAMMAR__.grammar["parlist'group#2"][2].action = function(_1) return _1 end __GRAMMAR__.grammar["stat'group#2"][1].action = function(_1, _2, _3, _4, _5, _6) return node(_1.location, 'foreach'):set('names', _1):set('iterator', _3):set('block', _5) end __GRAMMAR__.grammar["stat'group#2"][2].action = function(_1, _2, _3, _4, _5, _6, _7, _8, _9) return node(_1.location, 'fori'):set('id', from(_1)):set('start', _3):set('finish', _5):set('step', _6[1]):set('block', _8) end __GRAMMAR__.grammar["stat'group#1'group#1"][1].action = function(_1, _2) return _2 end __GRAMMAR__.grammar["retstat'maybe#2"][1].action = function(item) return {item} end __GRAMMAR__.grammar["retstat'maybe#2"][2].action = function() return {} end __GRAMMAR__.grammar["exp4"][1].action = make_right_binop __GRAMMAR__.grammar["field'maybe#1"][1].action = function(item) return {item} end __GRAMMAR__.grammar["field'maybe#1"][2].action = function() return {} end __GRAMMAR__.grammar["exp6"][1].action = make_binop __GRAMMAR__.grammar["exp_stop'star#1"][1].action = function(item, list) table.insert(list, 1, item); return list end __GRAMMAR__.grammar["exp_stop'star#1"][2].action = function() return {} end __GRAMMAR__.grammar["parlist'group#1"][1].action = function(_1, _2) return _1 end __GRAMMAR__.grammar["field'maybe#2"][1].action = function(item) return {item} end __GRAMMAR__.grammar["field'maybe#2"][2].action = function() return {} end __GRAMMAR__.grammar["field'maybe#3"][1].action = function(item) return {item} end __GRAMMAR__.grammar["field'maybe#3"][2].action = function() return {} end __GRAMMAR__.grammar["assignment_or_call'star#1"][1].action = function(item, list) table.insert(list, 1, item); return list end __GRAMMAR__.grammar["assignment_or_call'star#1"][2].action = function() return {} end __GRAMMAR__.grammar["explist"][1].action = function(exp, explist) local tree = node(exp.location, 'explist') tree:list(exp) tree:list(unpack(explist)) return tree end __GRAMMAR__.grammar["namelist"][1].action = function(name, names) local tree = node(name.location, 'names') tree:list(from(name)) tree:list(unpack(names)) return tree end __GRAMMAR__.grammar["exp8'group#1"][1].action = start_right_binop __GRAMMAR__.grammar["level4"][1].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["primaryexp"][1].action = function(_1, _2, _3) return _2 end __GRAMMAR__.grammar["primaryexp"][2].action = function(_1) return from(_1) end __GRAMMAR__.grammar["level2"][1].action = function(_1) return from(_1, 'op') end __GRAMMAR__.grammar["stat"][1].action = function(_1, _2) return _2 end __GRAMMAR__.grammar["stat"][2].action = function(_1, _2, _3) if _2.colon then local name = node(_3[1].location, 'name') name.value = 'self' table.insert(_3[1], 1, name) end return node(_1.location, 'functiondef'):set('funcname', _2):set('function', node(_3[1].location, 'function'):set('parameters', _3[1]):set('body', _3[2])) end __GRAMMAR__.grammar["stat"][3].action = function(_1, _2) return _2 end __GRAMMAR__.grammar["stat"][4].action = function(_1, _2, _3, _4, _5, _6, _7) return node(_1.location, 'if') :set('cond', _2) :set('block', _4) :set('elseifs', #_5 > 0 and node(_5[1].location, 'elseif'):list(unpack(_5)) or nil) :set('else_', _6[1]) end __GRAMMAR__.grammar["stat"][5].action = function(_1, _2, _3, _4) return node(_1.location, 'repeat'):set('cond', _4):set('block', _2) end __GRAMMAR__.grammar["stat"][6].action = function(_1, _2, _3, _4, _5) return node(_1.location, 'while'):set('cond', _2):set('block', _4) end __GRAMMAR__.grammar["stat"][7].action = function(_1, _2, _3) return _2 end __GRAMMAR__.grammar["stat"][8].action = function(_1, _2) return node(_1.location, 'goto'):set('label', from(_2)) end __GRAMMAR__.grammar["stat"][9].action = function(_1) return node(_1.location, 'break') end __GRAMMAR__.grammar["stat"][10].action = function(_1) return _1 end __GRAMMAR__.grammar["stat"][11].action = function(_1) return _1 end __GRAMMAR__.grammar["stat"][12].action = function(_1) return node(_1.location, 'empty') end __GRAMMAR__.grammar["assignment_or_call'group#1"][1].action = suffix_args __GRAMMAR__.grammar["assignment_or_call'group#1"][2].action = suffix_colon __GRAMMAR__.grammar["assignment_or_call'group#1"][3].action = suffix_bracket __GRAMMAR__.grammar["assignment_or_call'group#1"][4].action = suffix_dot __GRAMMAR__.grammar["namelist'star#1"][1].action = function(item, list) table.insert(list, 1, item); return list end __GRAMMAR__.grammar["namelist'star#1"][2].action = function() return {} end __GRAMMAR__.grammar["suffix"][1].action = suffix_args __GRAMMAR__.grammar["suffix"][2].action = suffix_colon __GRAMMAR__.grammar["suffix"][3].action = suffix_bracket __GRAMMAR__.grammar["suffix"][4].action = suffix_dot __GRAMMAR__.grammar["exp8"][1].action = make_right_binop __GRAMMAR__.grammar["explist'group#1"][1].action = function(_1, _2) return _2 end __GRAMMAR__.grammar["args"][1].action = function(_1) return node(_1.location, 'args'):list(from(_1, 'string')) end __GRAMMAR__.grammar["args"][2].action = function(_1) return node(_1.location, 'args'):list(_1) end __GRAMMAR__.grammar["args"][3].action = function(_1, _2, _3) return (#_2 == 0 and node(_1.location, 'args')) or node(_1.location, 'args'):list(unpack(_2[1])) end __GRAMMAR__.grammar["parlist'star#1"][1].action = function(item, list) table.insert(list, 1, item); return list end __GRAMMAR__.grammar["parlist'star#1"][2].action = function() return {} end __GRAMMAR__.grammar["exp2"][1].action = make_binop __GRAMMAR__.grammar["assignment_or_call'star#1"].conflict = {} __GRAMMAR__.grammar["assignment_or_call'star#1"].conflict["LPAREN"] = function(self, tokens) -- always reduce to call return self:go '#list' end __GRAMMAR__.grammar["parlist'star#1"].conflict = {} __GRAMMAR__.grammar["parlist'star#1"].conflict["Name"] = function(self, tokens) if tostring(tokens[2]) == 'COMMA' then return self:go '#list' else return self:go '' end end __GRAMMAR__.grammar["field"].conflict = {} __GRAMMAR__.grammar["field"].conflict["Name"] = function(self, tokens) if tostring(tokens[2]) == 'EQ' then return self:go 'assign' else return self:go 'exp' end end __GRAMMAR__.grammar["exp5'"].conflict = {} __GRAMMAR__.grammar["exp5'"].conflict["MIN"] = function(self, tokens) return self:go 'minus' end __GRAMMAR__.grammar["exp_stop'star#1"].conflict = {} __GRAMMAR__.grammar["exp_stop'star#1"].conflict["LPAREN"] = goto_list __GRAMMAR__.grammar["exp_stop'star#1"].conflict["LBRACK"] = goto_list __GRAMMAR__.grammar["exp_stop'star#1"].conflict["String"] = goto_list __GRAMMAR__.grammar["exp_stop'star#1"].conflict["LBRACE"] = goto_list __GRAMMAR__.grammar["stat'group#2"].conflict = {} __GRAMMAR__.grammar["stat'group#2"].conflict["Name"] = function(self, tokens) if tostring(tokens[2]) == 'EQ' then return self:go 'forcounter' else return self:go 'foreach' end end __GRAMMAR__.ll1 = ll1(__GRAMMAR__.grammar) return setmetatable( __GRAMMAR__, {__call = function(this, str) local tokens = {} for _, token in ipairs(this.prologue(str)) do table.insert( tokens, setmetatable( token, {__tostring = function(self) return this.convert(self) end})) end local result = this.ll1:parse(tokens) return this.epilogue(result) end})