Skip to content

Commit

Permalink
support for for-else and while-else
Browse files Browse the repository at this point in the history
  • Loading branch information
simeonschaub committed Oct 14, 2024
1 parent 9483de8 commit f418f4a
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 11 deletions.
8 changes: 4 additions & 4 deletions src/expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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}
Expand Down Expand Up @@ -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)
Expand Down
14 changes: 14 additions & 0 deletions src/parser.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down
44 changes: 37 additions & 7 deletions test/expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,21 @@
LineNumberNode(3)
)
)
if VERSION >= v"1.12-"
@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)
)
)
end
@test parsestmt("while cond\n\nend") ==
Expr(:while,
:cond,
Expand All @@ -206,6 +221,21 @@
LineNumberNode(3)
)
)
if VERSION >= v"1.12-"
@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
end

Expand Down Expand Up @@ -361,7 +391,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))
Expand All @@ -371,11 +401,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
Expand Down Expand Up @@ -583,8 +613,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)") ==
Expand Down Expand Up @@ -754,7 +784,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
Expand Down
4 changes: 4 additions & 0 deletions test/parser.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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))"
Expand Down

0 comments on commit f418f4a

Please sign in to comment.