diff --git a/lib/lua/parser.ex b/lib/lua/parser.ex index 4c43efe..38abe31 100644 --- a/lib/lua/parser.ex +++ b/lib/lua/parser.ex @@ -249,7 +249,11 @@ defmodule Lua.Parser do # Placeholder implementations for statements (Phase 3) defp parse_return([{:keyword, :return, pos} | rest]) do - case peek(rest) do + # Comments are whitespace between the `return` keyword and the block + # terminator, so look past them when deciding whether this is a bare + # (valueless) return. For terminator/EOF the comment tokens stay in `rest` + # for the block parser to collect as orphaned/trailing comments. + case peek(skip_comments(rest)) do # End of block or statement {:keyword, terminator, _} when terminator in [:end, :else, :elseif, :until] -> {:ok, %Statement.Return{values: [], meta: Meta.new(pos)}, rest} @@ -258,7 +262,7 @@ defmodule Lua.Parser do {:ok, %Statement.Return{values: [], meta: Meta.new(pos)}, rest} {:delimiter, :semicolon, _} -> - {_, rest2} = consume(rest) + {_, rest2} = consume(skip_comments(rest)) {:ok, %Statement.Return{values: [], meta: Meta.new(pos)}, rest2} _ -> diff --git a/test/lua/parser/statement_test.exs b/test/lua/parser/statement_test.exs index d59bae1..f3dd5ea 100644 --- a/test/lua/parser/statement_test.exs +++ b/test/lua/parser/statement_test.exs @@ -201,6 +201,39 @@ defmodule Lua.Parser.StatementTest do } = chunk end + test "parses a bare return followed by a comment before elseif/else" do + # A comment sits between an empty `return` and the block terminator. + # Comments are whitespace to Lua, so the return is still empty and the + # branch continues normally. Regression: the parser used to treat the + # comment token as the start of a return expression and fail with + # "Expected expression". + assert {:ok, chunk} = + Parser.parse(""" + if x > 0 then + return + -- leading comment on elseif + elseif x < 0 then + return + -- leading comment on else + else + return + -- trailing comment before end + end + """) + + assert %{ + block: %{ + stmts: [ + %Statement.If{ + then_block: %{stmts: [%Statement.Return{values: []}]}, + elseifs: [{%Expr.BinOp{op: :lt}, %{stmts: [%Statement.Return{values: []}]}}], + else_block: %{stmts: [%Statement.Return{values: []}]} + } + ] + } + } = chunk + end + test "parses if with elseif" do assert {:ok, chunk} = Parser.parse("""