unified: Handle assignment etc. in unresolved operator sequences

Adds rules for mapping things like `=` and `as!` to `infix_operator`s,
so that they are present in the output (which for unresolved operators
expects an alternating sequence of values and `infix_operator`s).

For ternary operators, we expand this into _two_ unresolved infix
operators, `?` and `:` respectively.
This commit is contained in:
Taus
2026-07-24 19:45:29 +00:00
parent 0c17c699c1
commit c60900f573
6 changed files with 328 additions and 1 deletions

View File

@@ -205,6 +205,28 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
=>
(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

View File

@@ -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"

View File

@@ -0,0 +1,4 @@
func casts(_ a: Any, _ b: Int) {
_ = a as Int .& b
_ = a is Int .& b
}

View File

@@ -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"

View File

@@ -0,0 +1,3 @@
func choose(_ c: Bool, _ a: Int, _ b: Int, _ d: Int) -> Int {
return c ? a : b .& d
}

View File

@@ -92,7 +92,7 @@ top_level
element:
name_expr
identifier: identifier "_"
unsupported_node "="
infix_operator "="
name_expr
identifier: identifier "a"
infix_operator ".&"