From f5192feee1f5d7352ead6aef301c7eac22cc860e Mon Sep 17 00:00:00 2001 From: ArArgon Date: Thu, 27 Jun 2024 13:07:41 -0700 Subject: [PATCH 1/8] feat: support more declarations and partial signatures --- .../src/semgrep-move-on-aptos/grammar.js | 22 +++- .../test/corpus/partials_and_decls.txt | 124 ++++++++++++++++++ .../src/tree-sitter-move-on-aptos | 2 +- 3 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/partials_and_decls.txt diff --git a/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js b/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js index f24dfe7..1af396b 100644 --- a/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js +++ b/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js @@ -13,9 +13,14 @@ module.exports = grammar(base_grammar, { name: 'move_on_aptos', conflicts: ($, previous) => previous.concat([ - [$.typed_metavariable, $.name_access_chain] + [$.typed_metavariable, $.name_access_chain], + [$.term, $.declaration], ]), + precedences: $ => [ + [$._sequence_item, $.declaration], + ], + /* Support for semgrep ellipsis ('...') and metavariables ('$FOO'), if they're not already part of the base grammar. @@ -24,7 +29,7 @@ module.exports = grammar(base_grammar, { // Semgrep components, source: semgrep-rust ellipsis: $ => '...', deep_ellipsis: $ => seq('<...', $._expr, '...>'), - + // Typed metavariable (an expression, not a parameter) // This is grammatically indistinguishable from `$.type_hint_expr: $ => seq('(', $._expr, ':', $.type, ')')`. // This will be handled by the semgrep converter by checking the metavariable name (`$`). @@ -39,14 +44,25 @@ module.exports = grammar(base_grammar, { // Alternate "entry point". Allows parsing a standalone list of sequence items (statements). semgrep_statement: $ => seq('__SEMGREP_STATEMENT', repeat1(choice( $._sequence_item, - $.constant_decl, + $.declaration, ))), + // Alternate "entry point". Allows parsing partial declarations (signatures). + semgrep_partial: $ => seq('__SEMGREP_PARTIAL', seq( + optional($.attributes), + repeat($.module_member_modifier), + choice( + $._function_signature, + $._struct_signature, + ) + )), + // Extend the source_file rule to allow semgrep constructs source_file: ($, previous) => choice( previous, $.semgrep_expression, $.semgrep_statement, + $.semgrep_partial, ), // Module declaration diff --git a/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/partials_and_decls.txt b/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/partials_and_decls.txt new file mode 100644 index 0000000..41c84c6 --- /dev/null +++ b/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/partials_and_decls.txt @@ -0,0 +1,124 @@ +======================= +Function in Statement +======================= + +__SEMGREP_STATEMENT +fun $TEST (...) : ... { ... } + +--- + +(source_file + (semgrep_statement + (declaration + (function_decl + (identifier) + (parameters + (parameter + (ellipsis))) + (type + (ellipsis)) + (block + (ellipsis)))))) + +======================= +Declarations +======================= + +__SEMGREP_STATEMENT +use 0xabcd::ff; +struct $STRUCT has ... { ... } +const $CONST : ... = $FOO(...); +... +fun hello (...) { + let XXX = $STRUCT { ... }; + ... +} + +--- + +(source_file + (semgrep_statement + (declaration + (use_decl + (module_ident + (numerical_addr + (number)) + (identifier)))) + (declaration + (struct_decl + (identifier) + (abilities + (ability + (ellipsis))) + (body + (field_annot + (ellipsis))))) + (declaration + (constant_decl + (identifier) + (type + (ellipsis)) + (call_expr + (name_access_chain + (identifier)) + (call_args + (ellipsis))))) + (ellipsis) + (declaration + (function_decl + (identifier) + (parameters + (parameter + (ellipsis))) + (block + (let_expr + (bind_list + (var_name + (identifier))) + (pack_expr + (name_access_chain + (identifier)) + (expr_field + (ellipsis)))) + (ellipsis)))))) + +======================= +Function Signature +======================= + +__SEMGREP_PARTIAL +#[test] +public(friend) fun $FUNC (...) + +--- + +(source_file + (semgrep_partial + (attributes + (attribute + (identifier))) + (module_member_modifier + (visibility)) + (identifier) + (parameters + (parameter + (ellipsis))))) + +======================= +Struct Signature +======================= + +__SEMGREP_PARTIAL +public native struct $STRUCT has ... + +--- + +(source_file + (semgrep_partial + (module_member_modifier + (visibility)) + (module_member_modifier) + (identifier) + (abilities + (ability + (ellipsis))))) diff --git a/lang/semgrep-grammars/src/tree-sitter-move-on-aptos b/lang/semgrep-grammars/src/tree-sitter-move-on-aptos index ce1a8ff..6386ab8 160000 --- a/lang/semgrep-grammars/src/tree-sitter-move-on-aptos +++ b/lang/semgrep-grammars/src/tree-sitter-move-on-aptos @@ -1 +1 @@ -Subproject commit ce1a8ff1b95005ae45e3674c00e795aac24aec35 +Subproject commit 6386ab86368bf5de37440824eef4f94040e8f547 From a7b069b08e72c45c377f9c86577ea601666a851a Mon Sep 17 00:00:00 2001 From: ArArgon Date: Fri, 28 Jun 2024 11:41:06 -0700 Subject: [PATCH 2/8] fix: ellipsis in script --- .../src/semgrep-move-on-aptos/grammar.js | 8 ++++ .../test/corpus/semgrep.txt | 45 ++++++++++++++++++- .../src/tree-sitter-move-on-aptos | 2 +- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js b/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js index 1af396b..ed76ffe 100644 --- a/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js +++ b/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js @@ -19,6 +19,7 @@ module.exports = grammar(base_grammar, { precedences: $ => [ [$._sequence_item, $.declaration], + [$._script_use_decl, $._script_constant_decl, $._script_func_decl, $._script_spec_block], ], /* @@ -71,6 +72,13 @@ module.exports = grammar(base_grammar, { $.ellipsis, ), + // Script members + // We cannot mimic the `declaration` trick here, as the script members are strictly ordered. + _script_use_decl: ($, previous) => choice(previous, $.ellipsis), + _script_constant_decl: ($, previous) => choice(previous, $.ellipsis), + _script_func_decl: ($, previous) => choice(previous, $.ellipsis), + _script_spec_block: ($, previous) => choice(previous, $.ellipsis), + // Spec block members _spec_block_member: ($, previous) => choice( previous, diff --git a/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/semgrep.txt b/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/semgrep.txt index e974ff3..c512d56 100644 --- a/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/semgrep.txt +++ b/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/semgrep.txt @@ -399,4 +399,47 @@ __SEMGREP_EXPRESSION { (ellipsis) (var (name_access_chain - (identifier)))))) \ No newline at end of file + (identifier)))))) + +======================= +Script +======================= + +script { + ... + use std::vec::{...}; + ... + const aa: u32 = ...; + ... + spec { ... } + ... +} +--- + +(source_file + (script + (declaration + (ellipsis)) + (declaration + (use_decl + (module_ident + (identifier) + (identifier)) + (member + (ellipsis)))) + (declaration + (ellipsis)) + (declaration + (constant_decl + (identifier) + (type + (primitive_type + (number_type))) + (ellipsis))) + (declaration + (ellipsis)) + (declaration + (spec_block + (ellipsis))) + (declaration + (ellipsis)))) \ No newline at end of file diff --git a/lang/semgrep-grammars/src/tree-sitter-move-on-aptos b/lang/semgrep-grammars/src/tree-sitter-move-on-aptos index 6386ab8..09e7c0f 160000 --- a/lang/semgrep-grammars/src/tree-sitter-move-on-aptos +++ b/lang/semgrep-grammars/src/tree-sitter-move-on-aptos @@ -1 +1 @@ -Subproject commit 6386ab86368bf5de37440824eef4f94040e8f547 +Subproject commit 09e7c0f3172686e6f7887fcf7170285211f7f3a6 From 7954412b70b96db99199daf9a38f2f173ca19d1d Mon Sep 17 00:00:00 2001 From: ArArgon Date: Fri, 28 Jun 2024 14:14:20 -0700 Subject: [PATCH 3/8] chore: support address block scope matching --- .../src/semgrep-move-on-aptos/grammar.js | 6 +++++ .../test/corpus/semgrep.txt | 23 ++++++++++++++++++- .../src/tree-sitter-move-on-aptos | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js b/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js index ed76ffe..b8ecdb7 100644 --- a/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js +++ b/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js @@ -79,6 +79,12 @@ module.exports = grammar(base_grammar, { _script_func_decl: ($, previous) => choice(previous, $.ellipsis), _script_spec_block: ($, previous) => choice(previous, $.ellipsis), + // Address block members + _address_member: ($, previous) => choice( + previous, + $.ellipsis, + ), + // Spec block members _spec_block_member: ($, previous) => choice( previous, diff --git a/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/semgrep.txt b/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/semgrep.txt index c512d56..0cedbc7 100644 --- a/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/semgrep.txt +++ b/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/semgrep.txt @@ -442,4 +442,25 @@ script { (spec_block (ellipsis))) (declaration - (ellipsis)))) \ No newline at end of file + (ellipsis)))) + +======================= +Address Block +======================= + +address $ADDR { + ... + module $MOD { ... } + ... +} +--- + +(source_file + (address_block + (identifier) + (ellipsis) + (module + (identifier) + (declaration + (ellipsis))) + (ellipsis))) \ No newline at end of file diff --git a/lang/semgrep-grammars/src/tree-sitter-move-on-aptos b/lang/semgrep-grammars/src/tree-sitter-move-on-aptos index 09e7c0f..e6d412d 160000 --- a/lang/semgrep-grammars/src/tree-sitter-move-on-aptos +++ b/lang/semgrep-grammars/src/tree-sitter-move-on-aptos @@ -1 +1 @@ -Subproject commit 09e7c0f3172686e6f7887fcf7170285211f7f3a6 +Subproject commit e6d412dcd503b99308f75b596da66c26f491ece8 From a1be1c028167268f8875ebfd4174cd5b7002e03f Mon Sep 17 00:00:00 2001 From: ArArgon Date: Mon, 1 Jul 2024 11:00:54 -0700 Subject: [PATCH 4/8] refactor: remove `__SEMGREP` directives --- .../src/semgrep-move-on-aptos/grammar.js | 13 +++++++------ .../test/corpus/partials_and_decls.txt | 4 ---- .../semgrep-move-on-aptos/test/corpus/semgrep.txt | 14 +++++--------- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js b/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js index b8ecdb7..06817b3 100644 --- a/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js +++ b/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js @@ -15,6 +15,7 @@ module.exports = grammar(base_grammar, { conflicts: ($, previous) => previous.concat([ [$.typed_metavariable, $.name_access_chain], [$.term, $.declaration], + [$._module_path, $.spec_block_target] ]), precedences: $ => [ @@ -37,26 +38,26 @@ module.exports = grammar(base_grammar, { typed_metavariable: $ => seq('(', $.identifier, ':', $.type, ')'), // Alternate "entry point". Allows parsing a standalone expression. - semgrep_expression: $ => seq('__SEMGREP_EXPRESSION', choice( + semgrep_expression: $ => choice( $._expr, $.let_expr, - )), + ), // Alternate "entry point". Allows parsing a standalone list of sequence items (statements). - semgrep_statement: $ => seq('__SEMGREP_STATEMENT', repeat1(choice( + semgrep_statement: $ => repeat1(choice( $._sequence_item, $.declaration, - ))), + )), // Alternate "entry point". Allows parsing partial declarations (signatures). - semgrep_partial: $ => seq('__SEMGREP_PARTIAL', seq( + semgrep_partial: $ => seq( optional($.attributes), repeat($.module_member_modifier), choice( $._function_signature, $._struct_signature, ) - )), + ), // Extend the source_file rule to allow semgrep constructs source_file: ($, previous) => choice( diff --git a/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/partials_and_decls.txt b/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/partials_and_decls.txt index 41c84c6..7b94de3 100644 --- a/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/partials_and_decls.txt +++ b/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/partials_and_decls.txt @@ -2,7 +2,6 @@ Function in Statement ======================= -__SEMGREP_STATEMENT fun $TEST (...) : ... { ... } --- @@ -24,7 +23,6 @@ fun $TEST (...) : ... { ... } Declarations ======================= -__SEMGREP_STATEMENT use 0xabcd::ff; struct $STRUCT has ... { ... } const $CONST : ... = $FOO(...); @@ -86,7 +84,6 @@ fun hello (...) { Function Signature ======================= -__SEMGREP_PARTIAL #[test] public(friend) fun $FUNC (...) @@ -108,7 +105,6 @@ public(friend) fun $FUNC (...) Struct Signature ======================= -__SEMGREP_PARTIAL public native struct $STRUCT has ... --- diff --git a/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/semgrep.txt b/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/semgrep.txt index 0cedbc7..5cd6f80 100644 --- a/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/semgrep.txt +++ b/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/semgrep.txt @@ -2,7 +2,6 @@ Semgrep Ellipsis ==================== -__SEMGREP_EXPRESSION ... --- @@ -15,7 +14,6 @@ __SEMGREP_EXPRESSION Semgrep Metavariables ======================== -__SEMGREP_EXPRESSION call(..., $VAR) --- @@ -35,7 +33,6 @@ call(..., $VAR) Semgrep Statement ==== -__SEMGREP_STATEMENT let _: u64 = if (cond) { ... } else { s2 + <... $...SOME ...> }.f; --- @@ -162,7 +159,6 @@ module 0xdeadbeef::mod { Typed Metavariables ======================= -__SEMGREP_EXPRESSION call(arr1, arr2, ($VAR: u32), $VAR2) --- @@ -269,7 +265,7 @@ module 0xdeadbeef::mod { Function Call with Type Arguments ======================= -__SEMGREP_EXPRESSION { +{ borrow_global_mut>(...); exists<...> (...); test_fun<..., $T1, ...> (...); @@ -319,7 +315,6 @@ __SEMGREP_EXPRESSION { Let Expression Match ======================= -__SEMGREP_EXPRESSION let test::Token { ... } = $VAR --- @@ -342,7 +337,6 @@ let test::Token { ... } = $VAR Let Expr 2 ======================= -__SEMGREP_EXPRESSION let Lock { coins, $VAR2: ..., } = ... --- @@ -367,19 +361,21 @@ let Lock { coins, $VAR2: ..., } = ... Multiline Statements 1 ======================= -__SEMGREP_STATEMENT ... +... +... --- (source_file (semgrep_statement + (ellipsis) (ellipsis))) ======================= Multiline Statements 2 ======================= -__SEMGREP_EXPRESSION { +{ let t = 100; ... t From e008477a92dc966bb4f98091d08c0479020b52ab Mon Sep 17 00:00:00 2001 From: ArArgon Date: Tue, 2 Jul 2024 09:53:45 -0700 Subject: [PATCH 5/8] misc: sync upstream grammar --- lang/semgrep-grammars/src/tree-sitter-move-on-aptos | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/semgrep-grammars/src/tree-sitter-move-on-aptos b/lang/semgrep-grammars/src/tree-sitter-move-on-aptos index e6d412d..bbce7d8 160000 --- a/lang/semgrep-grammars/src/tree-sitter-move-on-aptos +++ b/lang/semgrep-grammars/src/tree-sitter-move-on-aptos @@ -1 +1 @@ -Subproject commit e6d412dcd503b99308f75b596da66c26f491ece8 +Subproject commit bbce7d8bf664ceee1bb6426f231df8ca888bffbd From 3327afa7183bc6b563ca2b4a3c359cc8c567b99f Mon Sep 17 00:00:00 2001 From: ArArgon Date: Tue, 2 Jul 2024 10:09:39 -0700 Subject: [PATCH 6/8] misc: sync upstream grammar --- lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js | 4 ++-- lang/semgrep-grammars/src/tree-sitter-move-on-aptos | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js b/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js index 06817b3..6c33155 100644 --- a/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js +++ b/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js @@ -18,10 +18,10 @@ module.exports = grammar(base_grammar, { [$._module_path, $.spec_block_target] ]), - precedences: $ => [ + precedences: ($, previous) => previous.concat([ [$._sequence_item, $.declaration], [$._script_use_decl, $._script_constant_decl, $._script_func_decl, $._script_spec_block], - ], + ]), /* Support for semgrep ellipsis ('...') and metavariables ('$FOO'), diff --git a/lang/semgrep-grammars/src/tree-sitter-move-on-aptos b/lang/semgrep-grammars/src/tree-sitter-move-on-aptos index bbce7d8..3235a9f 160000 --- a/lang/semgrep-grammars/src/tree-sitter-move-on-aptos +++ b/lang/semgrep-grammars/src/tree-sitter-move-on-aptos @@ -1 +1 @@ -Subproject commit bbce7d8bf664ceee1bb6426f231df8ca888bffbd +Subproject commit 3235a9fc83872d7d20800b0713f7c6e9966442d1 From 4c5086cc8cf9d0423c2d6dd61f35b0108ac7da0f Mon Sep 17 00:00:00 2001 From: ArArgon Date: Mon, 8 Jul 2024 10:01:25 -0700 Subject: [PATCH 7/8] feat: support matching k-v attributes --- .../src/semgrep-move-on-aptos/grammar.js | 7 +++++ .../test/corpus/partials_and_decls.txt | 31 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js b/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js index 6c33155..a7786a7 100644 --- a/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js +++ b/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js @@ -126,6 +126,13 @@ module.exports = grammar(base_grammar, { $.ellipsis, ), + // attribute value + // (e.g. `#[attr(key = ...)]`) + _attribute_val: ($, previous) => choice( + previous, + $.ellipsis, + ), + // use member // (e.g. `use module_ident::...;`, `use module_ident::{..., item_ident}`) _use_member: ($, previous) => choice( diff --git a/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/partials_and_decls.txt b/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/partials_and_decls.txt index 7b94de3..df6be7e 100644 --- a/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/partials_and_decls.txt +++ b/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/partials_and_decls.txt @@ -118,3 +118,34 @@ public native struct $STRUCT has ... (abilities (ability (ellipsis))))) + +======================= +Function Attributes +======================= + +#[attr(key = ...), attr2 = ..., attr3(...), ...] +fun $FUN (...) + +--- + +(source_file + (semgrep_partial + (attributes + (attribute + (identifier) + (attribute + (identifier) + (ellipsis))) + (attribute + (identifier) + (ellipsis)) + (attribute + (identifier) + (attribute + (ellipsis))) + (attribute + (ellipsis))) + (identifier) + (parameters + (parameter + (ellipsis))))) \ No newline at end of file From b6960ca07d5bd45232cbbf8043ca7088d4bd0758 Mon Sep 17 00:00:00 2001 From: ArArgon Date: Tue, 9 Jul 2024 15:31:06 -0700 Subject: [PATCH 8/8] feat: more ellipsis support in field access --- .../src/semgrep-move-on-aptos/grammar.js | 13 +++++- .../test/corpus/semgrep.txt | 46 ++++++++++++++++++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js b/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js index a7786a7..e0b84aa 100644 --- a/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js +++ b/lang/semgrep-grammars/src/semgrep-move-on-aptos/grammar.js @@ -140,12 +140,18 @@ module.exports = grammar(base_grammar, { $.ellipsis, ), + // term + term: ($, previous) => choice( + ...previous.members, + $.ellipsis, + $.deep_ellipsis, + ), + // expression _expr: ($, previous) => choice( ...previous.members, $.ellipsis, $.deep_ellipsis, - $.field_access_ellipsis_expr, ), // unary expression @@ -157,6 +163,11 @@ module.exports = grammar(base_grammar, { $.typed_metavariable, ), + _dot_or_index_chain: ($, previous) => choice( + ...previous.members, + $.field_access_ellipsis_expr, + ), + // function parameter // (e.g. `call( ..., arg, ...)`) parameter: ($, previous) => choice( diff --git a/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/semgrep.txt b/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/semgrep.txt index 5cd6f80..fd859b0 100644 --- a/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/semgrep.txt +++ b/lang/semgrep-grammars/src/semgrep-move-on-aptos/test/corpus/semgrep.txt @@ -459,4 +459,48 @@ address $ADDR { (identifier) (declaration (ellipsis))) - (ellipsis))) \ No newline at end of file + (ellipsis))) + + +======================= +More Ellipsis in Field Access +======================= + +let $LEFT = <... $OBJ ...>.inner; +let $LEFT2 = ... . ... . ...; +let $LEFT3 = ... . ... .func(...); + +--- + +(source_file + (semgrep_statement + (let_expr + (bind_list + (var_name + (identifier))) + (access_field + (deep_ellipsis + (var + (name_access_chain + (identifier)))) + (identifier))) + (let_expr + (bind_list + (var_name + (identifier))) + (field_access_ellipsis_expr + (field_access_ellipsis_expr + (ellipsis) + (ellipsis)) + (ellipsis))) + (let_expr + (bind_list + (var_name + (identifier))) + (receiver_call + (field_access_ellipsis_expr + (ellipsis) + (ellipsis)) + (identifier) + (call_args + (ellipsis)))))) \ No newline at end of file