@@ -100,7 +100,9 @@ fn and_chain(
100100 conds
101101 . into_iter ( )
102102 . reduce ( |acc, elem| {
103- tree ! ( ( binary_expr operator: ( infix_operator "&&" ) left: { acc} right: { elem} ) )
103+ let operator_range = ctx. empty_source_range_between ( acc, elem) ;
104+ let operator = ctx. literal_with_source_range ( "infix_operator" , "&&" , operator_range) ;
105+ tree ! ( ( binary_expr operator: { operator} left: { acc} right: { elem} ) )
104106 } )
105107 . expect ( "control-flow statement must have at least one condition" )
106108}
@@ -126,21 +128,15 @@ fn member_chain(
126128 ctx : & mut yeast:: build:: BuildCtx < ' _ , SwiftContext > ,
127129 parts : Vec < yeast:: Id > ,
128130) -> yeast:: Id {
129- // `member_chain` builds the imported expression inside the larger import
130- // declaration rule. The imported expression should span the import path,
131- // not the whole declaration including the `import` keyword.
132- let source_range = ctx. source_range . take ( ) ;
133131 let mut iter = parts. into_iter ( ) ;
134132 let first = iter
135133 . next ( )
136134 . expect ( "identifier with `part:` must have at least one part" ) ;
137135 let init = tree ! ( ( identifier #{ first} ) ) ;
138- let result = iter. fold (
136+ iter. fold (
139137 init,
140138 |acc, elem| tree ! ( ( member_access_expr base: { acc} member_name_node: ( identifier #{ elem} ) ) ) ,
141- ) ;
142- ctx. source_range = source_range;
143- result
139+ )
144140}
145141
146142/// Compound-assignment operator spellings (`+=`, `<<=`, ...). Used to tell a
@@ -865,6 +861,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
865861 // form is matched first.
866862 rule!(
867863 ( optionalBindingCondition
864+ bindingSpecifier: @@spec
868865 pattern: ( identifierPattern identifier: @name)
869866 initializer: ( initializerClause value: @val) )
870867 =>
@@ -873,18 +870,20 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
873870 pattern: ( call_expr
874871 callee: ( member_access_expr base: ( identifier "Optional" ) member_name_node: ( identifier "some" ) )
875872 argument: ( argument value: ( expr_pattern
876- modifier: ( modifier "let" )
873+ modifier: ( modifier # { spec } )
877874 expr: ( identifier #{ name} ) ) ) ) )
878875 ) ,
879876 rule!(
880- ( optionalBindingCondition pattern: ( identifierPattern identifier: @name) )
877+ ( optionalBindingCondition
878+ bindingSpecifier: @@spec
879+ pattern: ( identifierPattern identifier: @name) )
881880 =>
882881 ( pattern_guard_expr
883882 value: ( identifier #{ name} )
884883 pattern: ( call_expr
885884 callee: ( member_access_expr base: ( identifier "Optional" ) member_name_node: ( identifier "some" ) )
886885 argument: ( argument value: ( expr_pattern
887- modifier: ( modifier "let" )
886+ modifier: ( modifier # { spec } )
888887 expr: ( identifier #{ name} ) ) ) ) )
889888 ) ,
890889 // A single condition in an `if`/`while`/`guard` condition list unwraps to
@@ -968,11 +967,18 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
968967 } ) ,
969968 // try/try?/try! expr → unary_expr with operator "try", "try?" or "try!"
970969 rule!(
971- ( tryExpr questionOrExclamationMark: _? @@m expression: @e)
970+ ( tryExpr
971+ tryKeyword: @@keyword
972+ questionOrExclamationMark: _? @@m
973+ expression: @e)
972974 =>
973975 expr {
974976 let op = format!( "try{}" , m. map( |m| ctx. source_text( m) ) . unwrap_or_default( ) ) ;
975- tree!( ( unary_expr operator: ( prefix_operator #{ op} ) operand: { e} ) )
977+ let operator_range =
978+ ctx. source_range_of_all( std:: iter:: once( keyword) . chain( m) ) ;
979+ let operator =
980+ ctx. literal_with_source_range( "prefix_operator" , & op, operator_range) ;
981+ tree!( ( unary_expr operator: { operator} operand: { e} ) )
976982 }
977983 ) ,
978984 // Do-catch → try_expr
@@ -1006,17 +1012,27 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
10061012 // Catch block without error binding
10071013 rule!( ( catchClause body: @body) => ( catch_clause body: { body} ) ) ,
10081014 // As expression (type cast) — as?, as!
1009- rule!( ( asExpr expression: @val questionOrExclamationMark: _? @@mark type : @ty) => type_cast_expr {
1015+ rule!( ( asExpr expression: @val asKeyword : @@keyword questionOrExclamationMark: _? @@mark type : @ty) => type_cast_expr {
10101016 let op = format!( "as{}" , mark. map( |m| ctx. source_text( m) ) . unwrap_or_default( ) ) ;
1011- tree!( ( type_cast_expr expr: { val} operator: ( infix_operator #{ op} ) type : { ty} ) )
1017+ let operator_range =
1018+ ctx. source_range_of_all( std:: iter:: once( keyword) . chain( mark) ) ;
1019+ let operator = ctx. literal_with_source_range( "infix_operator" , & op, operator_range) ;
1020+ tree!( ( type_cast_expr expr: { val} operator: { operator} type : { ty} ) )
10121021 } ) ,
10131022 // Check expression (`x is T`) → type_test_expr
1014- rule!( ( isExpr expression: @val type : @ty) => ( type_test_expr expr: { val} operator: ( infix_operator "is" ) type : { ty} ) ) ,
1023+ rule!( ( isExpr expression: @val isKeyword: @@keyword type : @ty) => ( type_test_expr
1024+ expr: { val}
1025+ operator: { ctx. literal_with_source_range_of( "infix_operator" , "is" , keyword) }
1026+ type : { ty} ) ) ,
10151027 // Await expression → unary_expr with operator "await"
1016- rule!( ( awaitExpr expression: @val) => ( unary_expr operator: ( prefix_operator "await" ) operand: { val} ) ) ,
1028+ rule!( ( awaitExpr awaitKeyword: @@keyword expression: @val) => ( unary_expr
1029+ operator: { ctx. literal_with_source_range_of( "prefix_operator" , "await" , keyword) }
1030+ operand: { val} ) ) ,
10171031 // Force-unwrap (`x!`) → postfix unary_expr, via swift-syntax's dedicated
10181032 // `forceUnwrapExpr` node.
1019- rule!( ( forceUnwrapExpr expression: @e) => ( unary_expr operator: ( postfix_operator "!" ) operand: { e} ) ) ,
1033+ rule!( ( forceUnwrapExpr expression: @e exclamationMark: @@mark) => ( unary_expr
1034+ operator: { ctx. literal_with_source_range_of( "postfix_operator" , "!" , mark) }
1035+ operand: { e} ) ) ,
10201036 // ---- Imports ----
10211037 // An import declaration. The dotted path (a list of
10221038 // `importPathComponent`s) becomes a `name_node`/`member_access_expr`
@@ -1036,9 +1052,14 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
10361052 import_declaration {
10371053 let last = * parts. last( ) . ok_or( "import has no path" ) ?;
10381054 let pattern = match kind {
1039- None => tree!( ( named_pattern
1040- name_node: ( identifier #{ last} )
1041- sub_pattern: ( bulk_importing_pattern) ) ) ,
1055+ None => {
1056+ let bulk = ctx. with_node_source_range( ctx. matched_source_range, |ctx| {
1057+ tree!( ctx, ( bulk_importing_pattern) )
1058+ } ) ;
1059+ tree!( ( named_pattern
1060+ name_node: ( identifier #{ last} )
1061+ sub_pattern: { bulk} ) )
1062+ }
10421063 Some ( _) => tree!( ( identifier #{ last} ) ) ,
10431064 } ;
10441065 tree!( ( import_declaration
0 commit comments