-
Notifications
You must be signed in to change notification settings - Fork 583
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Scala: allow ellipsis in for loop headers #5661
Changes from all commits
9c82a2a
d7645df
a2e0dd0
af535e3
0b20b94
b5560dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1052,16 +1052,25 @@ and for_header = | |
* expr option (* cond *) | ||
* expr option (* next *) | ||
(* newvar: *) | ||
| ForEach of | ||
pattern | ||
* tok (* 'in' Python, 'range' Go, 'as' PHP, '' Java *) | ||
* expr (* pattern 'in' expr *) | ||
| ForEach of for_each | ||
(* Scala *) | ||
| MultiForEach of multi_for_each list | ||
(* Lua. todo: merge with ForEach? *) | ||
(* pattern 'in' expr *) | ||
| ForIn of for_var_or_expr list (* init *) * expr list | ||
(* sgrep: *) | ||
| ForEllipsis of (* ... *) tok | ||
|
||
and for_each = | ||
pattern | ||
* tok (* 'in' Python, 'range' Go, 'as' PHP, '' Java, '<-' Scala *) | ||
* expr (* pattern 'in' expr *) | ||
|
||
and multi_for_each = | ||
| FE of for_each | ||
| FECond of for_each * tok * expr | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe in comment you can put an example, like x <- xs if x > 2 |
||
| FEllipsis of tok | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I usually add a semgrep-ext: comment before those constructs that are Semgrep specific. |
||
|
||
and for_var_or_expr = | ||
(* newvar: *) | ||
| ForInitVar of entity * variable_definition | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2250,9 +2250,13 @@ and m_for_header a b = | |
| G.ForClassic (a1, a2, a3), B.ForClassic (b1, b2, b3) -> | ||
(m_list m_for_var_or_expr) a1 b1 >>= fun () -> | ||
m_option m_expr a2 b2 >>= fun () -> m_option m_expr a3 b3 | ||
| G.ForEach (a1, at, a2), B.ForEach (b1, bt, b2) -> | ||
m_pattern a1 b1 >>= fun () -> | ||
m_tok at bt >>= fun () -> m_expr a2 b2 | ||
| G.ForEach a1, B.ForEach b1 -> m_for_each a1 b1 | ||
| G.MultiForEach a1, B.MultiForEach b1 -> | ||
m_list_with_dots ~less_is_ok:false m_multi_for_each | ||
(function | ||
| G.FEllipsis _ -> true | ||
| _ -> false) | ||
a1 b1 | ||
| G.ForIn (a1, a2), B.ForIn (b1, b2) -> | ||
(m_list m_for_var_or_expr) a1 b1 >>= fun () -> | ||
m_list_with_dots m_expr | ||
|
@@ -2262,9 +2266,23 @@ and m_for_header a b = | |
~less_is_ok:false a2 b2 | ||
| G.ForClassic _, _ | ||
| G.ForEach _, _ | ||
| G.MultiForEach _, _ | ||
| G.ForIn _, _ -> | ||
fail () | ||
|
||
and m_for_each (a1, at, a2) (b1, bt, b2) = | ||
m_pattern a1 b1 >>= fun () -> | ||
m_tok at bt >>= fun () -> m_expr a2 b2 | ||
|
||
and m_multi_for_each a b = | ||
match (a, b) with | ||
| G.FE a1, B.FE b1 -> m_for_each a1 b1 | ||
| G.FECond (a1, at, a2), B.FECond (b1, bt, b2) -> | ||
m_for_each a1 b1 >>= fun () -> | ||
m_tok at bt >>= fun () -> m_expr a2 b2 | ||
| G.FEllipsis _, _ -> return () | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this can can happen given the definition of m_list_with_dots, but I guess it does not hurt. |
||
| _ -> fail () | ||
|
||
and m_block a b = | ||
match (a.s, b.s) with | ||
| G.Block _, B.Block _ -> m_stmt a b | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -562,24 +562,7 @@ and v_stmt = function | |
let v1 = v_tok v1 | ||
and v2 = v2 |> G.unbracket |> v_enumerators | ||
and v3 = v_for_body v3 in | ||
List.fold_right | ||
(fun gen stmt -> | ||
match gen with | ||
| `G (pat, tok, e, guards) -> | ||
G.For | ||
( v1, | ||
G.ForEach (pat, tok, e), | ||
List.fold_right | ||
(fun (g_tok, g_e) stmt -> | ||
G.If (g_tok, G.Cond g_e, stmt, None) |> G.s) | ||
guards stmt ) | ||
|> G.s | ||
| `GIf guards -> | ||
List.fold_right | ||
(fun (g_tok, g_e) stmt -> | ||
G.If (g_tok, G.Cond g_e, stmt, None) |> G.s) | ||
guards stmt) | ||
v2 v3 | ||
G.For (v1, G.MultiForEach v2, v3) |> G.s | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I usually try to avoid adding a construct in AST_generic when it's useful only for one language, but |
||
| Return (v1, v2) -> | ||
let v1 = v_tok v1 and v2 = v_option v_expr v2 in | ||
G.Return (v1, v2, G.sc) |> G.s | ||
|
@@ -601,8 +584,18 @@ and v_stmt = function | |
and v_enumerators v = v_list v_enumerator v | ||
|
||
and v_enumerator = function | ||
| G v1 -> `G (v_generator v1) | ||
| GIf v1 -> `GIf (v_list v_guard v1) | ||
| G v1 -> ( | ||
let pat, tok, e, guards = v_generator v1 in | ||
match guards with | ||
| [] -> G.FE (pat, tok, e) | ||
| (tok2, cond) :: guards -> | ||
let conds = | ||
List.fold_left | ||
(fun e (tok, c) -> G.special (G.Op G.And, tok) [ e; c ]) | ||
cond guards | ||
in | ||
G.FECond ((pat, tok, e), tok2, conds)) | ||
| GEllipsis tok -> G.FEllipsis tok | ||
|
||
and v_generator | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
//ERROR: match | ||
val x = for (w <- u if foo) yield w | ||
|
||
//ERROR: match | ||
val y = for (a <- b; w <- u if foo; c <- d) yield w | ||
|
||
//OK: | ||
val z = for (a <- b; w <- u if bar) yield w |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
for (...; $X <- $Y if foo; ...) yield ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
During the "changelog meeting" this week, Bruno said he is now the one who is looking at the changelog to help producing the release notes, and that he thinks we don't generally write good changelog entries (that allow him to do that job easily). I think he will have problems understanding the purpose of this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can ask him directly, but my understanding is that he would like to know that this change is to allow Scala users to use ellipsis to write patterns matching a sequence of nested for loops. He actually emphasized a lot the what, why, and how but I'm not sure how that would be instantiated in this particular case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think an example would be nice "(e.g., you can write a pattern like for(...; $X <- bar(); ...) { ... }".
Otherwise I feel the associated issue (#5650) mentioned in the changelog can help answer the what/why/how.