diff --git a/src/expr.jl b/src/expr.jl index b436e744..11e862cf 100644 --- a/src/expr.jl +++ b/src/expr.jl @@ -138,7 +138,7 @@ function _string_to_Expr(args) # """\n a\n b""" ==> "a\nb" return only(args2) else - # This only happens when the kind is K"string" or when an error has occurred. + # This only happens when the kind is K"string" or when an error has occurred. return Expr(:string, args2...) end end @@ -157,7 +157,7 @@ function _fixup_Expr_children!(head, loc, args) arg = args[i] was_parens = @isexpr(arg, :parens) arg = _strip_parens(arg) - if @isexpr(arg, :(=)) && eq_to_kw_in_call && i > 1 + if @isexpr(arg, :(=)) && eq_to_kw_in_call && i > 1 arg = Expr(:kw, arg.args...) elseif k != K"parens" && @isexpr(arg, :., 1) && arg.args[1] isa Tuple h, a = arg.args[1]::Tuple{SyntaxHead,Any} @@ -310,10 +310,10 @@ function _internal_node_to_Expr(source, srcrange, head, childranges, childheads, args[1] = length(iters) == 1 ? only(iters) : Expr(:block, iters...) # Add extra line number node for the `end` of the block. This may seem # useless but it affects code coverage. - push!(args[2].args, endloc) + push!(args[end].args, endloc) elseif k == K"while" # Line number node for the `end` of the block as in `for` loops. - push!(args[2].args, endloc) + push!(args[end].args, endloc) elseif k in KSet"tuple vect braces" # Move parameters blocks to args[1] _reorder_parameters!(args, 1) diff --git a/src/parser.jl b/src/parser.jl index 0cd65f7a..933d8a9c 100644 --- a/src/parser.jl +++ b/src/parser.jl @@ -1813,6 +1813,13 @@ function parse_resword(ps::ParseState) bump(ps, TRIVIA_FLAG) parse_cond(ps) parse_block(ps) + bump_trivia(ps) + if peek(ps) == K"else" + else_mark = position(ps) + bump(ps, TRIVIA_FLAG) + parse_block(ps) + min_supported_version(v"1.12", ps, else_mark, "`else` after `for`") + end bump_closing_token(ps, K"end") emit(ps, mark, K"while") elseif word == K"for" @@ -1821,6 +1828,13 @@ function parse_resword(ps::ParseState) bump(ps, TRIVIA_FLAG) parse_iteration_specs(ps) parse_block(ps) + bump_trivia(ps) + if peek(ps) == K"else" + else_mark = position(ps) + bump(ps, TRIVIA_FLAG) + parse_block(ps) + min_supported_version(v"1.12", ps, else_mark, "`else` after `for`") + end bump_closing_token(ps, K"end") emit(ps, mark, K"for") elseif word == K"let" diff --git a/test/expr.jl b/test/expr.jl index 9361937f..b6fc44b5 100644 --- a/test/expr.jl +++ b/test/expr.jl @@ -189,6 +189,19 @@ LineNumberNode(3) ) ) + @test parsestmt("for x=xs\ny\nelse\nz\nend") == + Expr(:for, + Expr(:(=), :x, :xs), + Expr(:block, + LineNumberNode(2), + :y, + ), + Expr(:block, + LineNumberNode(4), + :z, + LineNumberNode(5) + ) + ) @test parsestmt("while cond\n\nend") == Expr(:while, :cond, @@ -206,6 +219,19 @@ LineNumberNode(3) ) ) + @test parsestmt("while cond\ny\nelse\nz\nend") == + Expr(:while, + :cond, + Expr(:block, + LineNumberNode(2), + :y, + ), + Expr(:block, + LineNumberNode(4), + :z, + LineNumberNode(5) + ) + ) end end @@ -361,7 +387,7 @@ Expr(:call, :f, Expr(:parameters, Expr(:kw, :b, 2))) @test parsestmt("f(a=1; b=2)") == Expr(:call, :f, Expr(:parameters, Expr(:kw, :b, 2)), Expr(:kw, :a, 1)) - @test parsestmt("f(a; b; c)") == + @test parsestmt("f(a; b; c)") == Expr(:call, :f, Expr(:parameters, Expr(:parameters, :c), :b), :a) @test parsestmt("+(a=1,)") == Expr(:call, :+, Expr(:kw, :a, 1)) @@ -371,11 +397,11 @@ # Operator calls: = is not :kw @test parsestmt("(x=1) != 2") == Expr(:call, :!=, Expr(:(=), :x, 1), 2) - @test parsestmt("+(a=1)") == + @test parsestmt("+(a=1)") == Expr(:call, :+, Expr(:(=), :a, 1)) - @test parsestmt("(a=1)'") == + @test parsestmt("(a=1)'") == Expr(Symbol("'"), Expr(:(=), :a, 1)) - @test parsestmt("(a=1)'ᵀ") == + @test parsestmt("(a=1)'ᵀ") == Expr(:call, Symbol("'ᵀ"), Expr(:(=), :a, 1)) # Dotcall @@ -583,8 +609,8 @@ Expr(:generator, :x, Expr(:filter, :z, Expr(:(=), :a, :as), Expr(:(=), :b, :bs))) @test parsestmt("(x for a in as, b in bs for c in cs, d in ds)") == - Expr(:flatten, - Expr(:generator, + Expr(:flatten, + Expr(:generator, Expr(:generator, :x, Expr(:(=), :c, :cs), Expr(:(=), :d, :ds)), Expr(:(=), :a, :as), Expr(:(=), :b, :bs))) @test parsestmt("(x for a in as for b in bs if z)") == @@ -754,7 +780,7 @@ @test parsestmt("global x ~ 1") == Expr(:global, Expr(:call, :~, :x, 1)) @test parsestmt("global x += 1") == Expr(:global, Expr(:+=, :x, 1)) - # Parsing of global/local with + # Parsing of global/local with @test parsestmt("global (x,y)") == Expr(:global, :x, :y) @test parsestmt("local (x,y)") == Expr(:local, :x, :y) end diff --git a/test/parser.jl b/test/parser.jl index e6115ad4..67d7f804 100644 --- a/test/parser.jl +++ b/test/parser.jl @@ -474,9 +474,13 @@ tests = [ # while "while cond body end" => "(while cond (block body))" "while x < y \n a \n b \n end" => "(while (call-i x < y) (block a b))" + ((v=v"1.12",), "while x < y \n a \n else \n b \n end") => + "(while (call-i x < y) (block a) (block b))" # for "for x in xs end" => "(for (iteration (in x xs)) (block))" "for x in xs, y in ys \n a \n end" => "(for (iteration (in x xs) (in y ys)) (block a))" + ((v=v"1.12",), "for x in xs \n a \n else \n b \n end") => + "(for (iteration (in x xs)) (block a) (block b))" # let "let x=1\n end" => "(let (block (= x 1)) (block))" "let x=1 ; end" => "(let (block (= x 1)) (block))"