diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 575c66733a5..a3b05cbdb1a 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -205,6 +205,28 @@ fn translation_rules() -> Vec> { => (assign_expr target: {l} value: {r}) ), + // In an unresolved `sequenceExpr` (below) the operator positions are not + // only `binaryOperatorExpr`s: a plain assignment (`=`), an `as`/`is` cast + // and the ternary `?:` can also appear unfolded. Map each to an + // `infix_operator` (keeping its spelling) so the sequence stays a clean + // alternation of operands and operators instead of dropping the operator + // to an opaque `unsupported_node`. These bare nodes only occur inside an + // unresolved sequence — folded forms are handled by the dedicated rules + // above (assignment) and below (`ternaryExpr`). + rule!((assignmentExpr) @op => (infix_operator #{op})), + rule!((unresolvedAsExpr) @op => (infix_operator #{op})), + rule!((unresolvedIsExpr) @op => (infix_operator #{op})), + // The ternary is a three-part operator (`? thenExpr :`) that *wraps* a + // nested expression. Splice it into `?`, the then-expression, `:` so the + // then-expression survives as a real (traversable) operand rather than + // being buried in an opaque token. + rule!( + (unresolvedTernaryExpr questionMark: @@q thenExpression: @then colon: @@c) + => + expr_or_operator* { + vec![tree!((infix_operator #{q})), then, tree!((infix_operator #{c}))] + } + ), // Escape hatch: an operator chain the front-end could not resolve // (because it uses an operator of unknown precedence, e.g. imported from // another module) stays a flat `sequenceExpr`. Preserve it as an diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output new file mode 100644 index 00000000000..a0563c7bc88 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output @@ -0,0 +1,141 @@ +func casts(_ a: Any, _ b: Int) { + _ = a as Int .& b + _ = a is Int .& b +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + sequenceExpr + elements: + discardAssignmentExpr + wildcard: _ + assignmentExpr + equal: = + declReferenceExpr + baseName: identifier "a" + unresolvedAsExpr + asKeyword: as + typeExpr + type: + identifierType + name: identifier "Int" + binaryOperatorExpr + operator: binaryOperator ".&" + declReferenceExpr + baseName: identifier "b" + codeBlockItem + item: + sequenceExpr + elements: + discardAssignmentExpr + wildcard: _ + assignmentExpr + equal: = + declReferenceExpr + baseName: identifier "a" + unresolvedIsExpr + isKeyword: is + typeExpr + type: + identifierType + name: identifier "Int" + binaryOperatorExpr + operator: binaryOperator ".&" + declReferenceExpr + baseName: identifier "b" + name: identifier "casts" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: Any + firstName: _ + secondName: identifier "a" + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "b" + funcKeyword: func + +--- + +top_level + body: + block + stmt: + function_declaration + name: identifier "casts" + parameter: + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Any" + pattern: + name_pattern + identifier: identifier "a" + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "b" + body: + block + stmt: + unresolved_operator_sequence + element: + name_expr + identifier: identifier "_" + infix_operator "=" + name_expr + identifier: identifier "a" + infix_operator "as" + unsupported_node "Int" + infix_operator ".&" + name_expr + identifier: identifier "b" + unresolved_operator_sequence + element: + name_expr + identifier: identifier "_" + infix_operator "=" + name_expr + identifier: identifier "a" + infix_operator "is" + unsupported_node "Int" + infix_operator ".&" + name_expr + identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.swift b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.swift new file mode 100644 index 00000000000..b22c93eb31e --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.swift @@ -0,0 +1,4 @@ +func casts(_ a: Any, _ b: Int) { + _ = a as Int .& b + _ = a is Int .& b +} diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output new file mode 100644 index 00000000000..57274c32a9c --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output @@ -0,0 +1,157 @@ +func choose(_ c: Bool, _ a: Int, _ b: Int, _ d: Int) -> Int { + return c ? a : b .& d +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + expression: + sequenceExpr + elements: + declReferenceExpr + baseName: identifier "c" + unresolvedTernaryExpr + colon: : + questionMark: ? + thenExpression: + declReferenceExpr + baseName: identifier "a" + declReferenceExpr + baseName: identifier "b" + binaryOperatorExpr + operator: binaryOperator ".&" + declReferenceExpr + baseName: identifier "d" + returnKeyword: return + name: identifier "choose" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: identifier "Bool" + firstName: _ + secondName: identifier "c" + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "a" + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "b" + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "d" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Int" + funcKeyword: func + +--- + +top_level + body: + block + stmt: + function_declaration + name: identifier "choose" + parameter: + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Bool" + pattern: + name_pattern + identifier: identifier "c" + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "a" + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "b" + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "d" + return_type: + named_type_expr + name: identifier "Int" + body: + block + stmt: + return_expr + value: + unresolved_operator_sequence + element: + name_expr + identifier: identifier "c" + infix_operator "?" + name_expr + identifier: identifier "a" + infix_operator ":" + name_expr + identifier: identifier "b" + infix_operator ".&" + name_expr + identifier: identifier "d" diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.swift b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.swift new file mode 100644 index 00000000000..54f164eee9a --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.swift @@ -0,0 +1,3 @@ +func choose(_ c: Bool, _ a: Int, _ b: Int, _ d: Int) -> Int { + return c ? a : b .& d +} diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output index 7ecd448f03b..46dc8ca6ae8 100644 --- a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output @@ -92,7 +92,7 @@ top_level element: name_expr identifier: identifier "_" - unsupported_node "=" + infix_operator "=" name_expr identifier: identifier "a" infix_operator ".&"