The syntax tree of the macro passed to Expression Macro is folded, but I think it should not be folded.
This is because if the expression contains a custom operator, the precedence of that operator will not be evaluated correctly.
If the Sequence Expression is passed before it is folded, we can do the appropriate processing ourselves if necessary. For example, we can add custom operators to the operator table and fold them, or we can make a compile error if a custom operator is included. However, if they are pre-folded, the opportunity to do so is lost.
For example, the following operator "Ă—" is defined,
infix operator Ă—: MultiplicationPrecedence
func Ă—(left: Double, right: Double) -> Double {
left * right
}
If the following expression is passed to Expression Macro,
a + b Ă— c == 10
The syntax tree that is passed to the macro would look like this
InfixOperatorExprSyntax
├─leftOperand: InfixOperatorExprSyntax
│ ├─leftOperand: InfixOperatorExprSyntax
│ │ ├─leftOperand: IdentifierExprSyntax
│ │ │ ╰─identifier: identifier("a")
│ │ ├─operatorOperand: BinaryOperatorExprSyntax
│ │ │ ╰─operatorToken: binaryOperator("+")
│ │ ╰─rightOperand: IdentifierExprSyntax
│ │ ╰─identifier: identifier("b")
│ ├─operatorOperand: BinaryOperatorExprSyntax
│ │ ╰─operatorToken: binaryOperator("×")
│ ╰─rightOperand: IdentifierExprSyntax
│ ╰─identifier: identifier("c")
├─operatorOperand: BinaryOperatorExprSyntax
│ ╰─operatorToken: binaryOperator("==")
╰─rightOperand: IntegerLiteralExprSyntax
╰─digits: integerLiteral("10")
This incorrectly evaluates the precedence of custom operators. Because the "Ă—" operator has higher precedence than the + operator. It should be as follows
InfixOperatorExprSyntax
├─leftOperand: InfixOperatorExprSyntax
│ ├─leftOperand: IdentifierExprSyntax
│ │ ╰─identifier: identifier("a")
│ ├─operatorOperand: BinaryOperatorExprSyntax
│ │ ╰─operatorToken: binaryOperator("+")
│ ╰─rightOperand: InfixOperatorExprSyntax
│ ├─leftOperand: IdentifierExprSyntax
│ │ ╰─identifier: identifier("b")
│ ├─operatorOperand: BinaryOperatorExprSyntax
│ │ ╰─operatorToken: binaryOperator("×")
│ ╰─rightOperand: IdentifierExprSyntax
│ ╰─identifier: identifier("c")
├─operatorOperand: BinaryOperatorExprSyntax
│ ╰─operatorToken: binaryOperator("==")
╰─rightOperand: IntegerLiteralExprSyntax
╰─digits: integerLiteral("10")
Would it be more practical to have the original sequence expression passed than to have it folded with the wrong precedence?
In any case, I think it is more natural to leave it to the use site to decide whether to fold or not.