Skip to content

Commit 30109d4

Browse files
authored
Disallow trailing junk in generators (#497)
Disallow generator syntax with trailing non-delimited expressions (y for x in xs a) (y for x in xs a, b) Allow parameter syntax such as f(y for x in xs; a) because the flisp parser allowed this it's used in Base in at least one location. Disallow the almost-equivalent block syntax for now: (y for x in xs; a) because the flisp parser disallowed it and users can always get the same thing with some extra parentheses.
1 parent 5c134f4 commit 30109d4

File tree

2 files changed

+22
-8
lines changed

2 files changed

+22
-8
lines changed

src/parser.jl

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2706,7 +2706,7 @@ end
27062706
function parse_call_arglist(ps::ParseState, closer)
27072707
ps = ParseState(ps, for_generator=true)
27082708

2709-
parse_brackets(ps, closer) do _, _, _, _
2709+
parse_brackets(ps, closer, false) do _, _, _, _
27102710
return (needs_parameters=true,)
27112711
end
27122712
end
@@ -3123,7 +3123,7 @@ end
31233123
#
31243124
# flisp: parts of parse-paren- and parse-arglist
31253125
function parse_brackets(after_parse::Function,
3126-
ps::ParseState, closing_kind)
3126+
ps::ParseState, closing_kind, generator_is_last=true)
31273127
ps = ParseState(ps, range_colon_enabled=true,
31283128
space_sensitive=false,
31293129
where_enabled=true,
@@ -3159,18 +3159,22 @@ function parse_brackets(after_parse::Function,
31593159
if num_subexprs == 1
31603160
had_splat = peek_behind(ps).kind == K"..."
31613161
end
3162-
t = peek_token(ps, skip_newlines=true)
3163-
k = kind(t)
3162+
k = peek(ps, skip_newlines=true)
3163+
if k == K"for"
3164+
# Generator syntax
3165+
# (x for a in as) ==> (parens (generator x (iteration (in a as))))
3166+
parse_generator(ps, mark)
3167+
if generator_is_last
3168+
break
3169+
end
3170+
k = peek(ps, skip_newlines=true)
3171+
end
31643172
if k == K","
31653173
had_commas = true
31663174
bump(ps, TRIVIA_FLAG)
31673175
elseif k == K";" || k == closing_kind
31683176
# Handled above
31693177
continue
3170-
elseif k == K"for"
3171-
# Generator syntax
3172-
# (x for a in as) ==> (parens (generator x (iteration (in a as))))
3173-
parse_generator(ps, mark)
31743178
else
31753179
# Error - recovery done when consuming closing_kind
31763180
break

test/parser.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ tests = [
371371
"@x(a, b)" => "(macrocall-p @x a b)"
372372
"A.@x(y)" => "(macrocall-p (. A @x) y)"
373373
"A.@x(y).z" => "(. (macrocall-p (. A @x) y) z)"
374+
"f(y for x = xs; a)" => "(call f (generator y (iteration (in x xs))) (parameters a))"
374375
# do
375376
"f() do\nend" => "(call f (do (tuple) (block)))"
376377
"f() do ; body end" => "(call f (do (tuple) (block body)))"
@@ -435,6 +436,7 @@ tests = [
435436
"A.@S{a}" => "(macrocall (. A @S) (braces a))"
436437
"@S{a}.b" => "(. (macrocall @S (braces a)) b)"
437438
"S{a,b}" => "(curly S a b)"
439+
"T{y for x = xs; a}" => "(curly T (generator y (iteration (in x xs))) (parameters a))"
438440
# String macros
439441
"x\"str\"" => """(macrocall @x_str (string-r "str"))"""
440442
"x`str`" => """(macrocall @x_cmd (cmdstring-r "str"))"""
@@ -729,6 +731,9 @@ tests = [
729731
"(a=1;)" => "(block-p (= a 1))"
730732
"(a;b;;c)" => "(block-p a b c)"
731733
"(a=1; b=2)" => "(block-p (= a 1) (= b 2))"
734+
# Following is an error for flisp compatibility. But it could be
735+
# allowed as valid block syntax in the future?
736+
"(y for x = xs; a)" => "(parens (generator y (iteration (in x xs))) (error-t ✘ a))"
732737
# Parentheses used for grouping
733738
"(a * b)" => "(parens (call-i a * b))"
734739
"(a=1)" => "(parens (= a 1))"
@@ -1075,6 +1080,11 @@ parsestmt_test_specs = [
10751080
"x in'``\$" => "(call-i x in (call-i (juxtapose (char '`' (error-t)) (cmdstring-r (error-t))) \$ (error)))"
10761081
"var\"#\"`str`" => "(juxtapose (var # (error-t)) (cmdstring-r \"str\"))"
10771082
"var\"#\"\"str\"" => "(juxtapose (var # (error-t)) (error-t) (string \"str\"))"
1083+
1084+
# trailing junk in generators (issue #407)
1085+
"(x for x = xs a)" => "(parens (generator x (iteration (in x xs))) (error-t a))"
1086+
"(x for x = xs a, b)" => "(parens (generator x (iteration (in x xs))) (error-t a ✘ b))"
1087+
"f(x for x = xs a)" => "(call f (generator x (iteration (in x xs))) (error-t a))"
10781088
]
10791089

10801090
@testset "Parser does not crash on broken code" begin

0 commit comments

Comments
 (0)