name = "statements block",
terminators = block_terminators,
primary = function (lx)
+ -- FIXME use gg.optkeyword()
local x = stat (lx)
if lx:is_keyword (lx:peek(), ";") then lx:next() end
return x
--------------------------------------------------------------------------------
-- Helper function for "return <expr_list>" parsing.
--- Called when parsing return statements
+-- Called when parsing return statements.
+-- The specific test for initial ";" is because it's not a block terminator,
+-- so without itgg.list would choke on "return ;" statements.
+-- We don't make a modified copy of block_terminators because this list
+-- is sometimes modified at runtime, and the return parser would get out of
+-- sync if it was relying on a copy.
--------------------------------------------------------------------------------
-local return_expr_list_parser = gg.list {
- expr, separators = ",", terminators = block_terminators }
+local return_expr_list_parser = gg.multisequence{
+ { ";" , builder = function() return { } end },
+ default = gg.list {
+ expr, separators = ",", terminators = block_terminators } }
--------------------------------------------------------------------------------
-- for header, between [for] and [do] (exclusive).
else
-- Forin: there might be several vars
local a = lx:is_keyword (lx:next(), ",", "in")
- if a=="in" then var_list = { var } else
+ if a=="in" then var_list = { var, lineinfo = var.lineinfo } else
-- several vars; first "," skipped, read other vars
var_list = gg.list{
primary = id, separators = ",", terminators = "in" } (lx)
local function funcdef_builder(x)
local name, method, func = x[1], x[2], x[3]
if method then
- name = { tag="Index", name, method }
+ name = { tag="Index", name, method, lineinfo = {
+ first = name.lineinfo.first,
+ last = method.lineinfo.last } }
_G.table.insert (func[1], 1, {tag="Id", "self"})
end
- return { tag="Set", {name}, {func} }
+ local r = { tag="Set", {name}, {func} }
+ r[1].lineinfo = name.lineinfo
+ r[2].lineinfo = func.lineinfo
+ return r
end
else
assert (#e > 0)
if #e > 1 then
- gg.parse_error (lx, "comma is not a valid statement separator") end
+ gg.parse_error (lx,
+ "comma is not a valid statement separator; statement can be "..
+ "separated by semicolons, or not separated at all") end
if e[1].tag ~= "Call" and e[1].tag ~= "Invoke" then
- gg.parse_error (lx, "This expression is of type '%s'; "..
- "only function and method calls make valid statements",
- e[1].tag or "<list>")
+ local typename
+ if e[1].tag == 'Id' then typename = "an identifier"
+ elseif e[1].tag == 'Op' then typename = "an arithmetic operation"
+ else typename = "of type '"..(e[1].tag or "<list>".."'" end
+
+ gg.parse_error (lx, "This expression is " .. typename ..
+ "; only function and method call expressions "..
+ "can be used as statements");
end
return e[1]
end
end
-local local_stat_parser = gg.multisequence{
+local_stat_parser = gg.multisequence{
-- local function <name> <func_val>
{ "function", id, func_val, builder =
- function(x) return { tag="Localrec", { x[1] }, { x[2] } } end },
+ function(x)
+ local vars = { x[1], lineinfo = x[1].lineinfo }
+ local vals = { x[2], lineinfo = x[2].lineinfo }
+ return { tag="Localrec", vars, vals }
+ end },
-- local <id_list> ( = <expr_list> )?
default = gg.sequence{ id_list, gg.onkeyword{ "=", expr_list },
builder = function(x) return {tag="Local", x[1], x[2] or { } } end } }
stat.assignments = {
["="] = "Set" }
-function stat.assignments:add(k, v) self[k] = v end
\ No newline at end of file
+function stat.assignments:add(k, v) self[k] = v end