expr-lang / expr

Expression language and expression evaluation for Go
https://expr-lang.org
MIT License
5.85k stars 378 forks source link

Print brackets `(` `)` from AST #657

Closed smallfish06 closed 1 month ago

smallfish06 commented 1 month ago

Hi :) I'm using expr on several projects. While handling many expressions, I saw weird behavior

1-(1-1)

when I make this expression into tree, it works perfect

BinaryNode{
    Operator: "-",
    Left: IntegerNode{
        Value: 1,
    },
    Right: BinaryNode{
        Operator: "-",
        Left: IntegerNode{
            Value: 1,
        },
        Right: IntegerNode{
            Value: 1,
        },
    },
}

But when I try to reproduce this expression using tree, bracket is gone.

tree, _ := parser.Parse("1-(1-1)")
fmt.Println(tree.Node.String()). // 1 - 1 - 1

I found this while patching original expression and reproduce patched expression string


I read code about how does tree builder wrap expression, but seems like we also need to wrap with bracket if there was intent on original expression.

But I have no idea how to store original expression's bracket.

https://github.com/expr-lang/expr/blob/596f54f26256d389a380968bef0d6ba67b0e004f/ast/print.go#L68-L106

Are there any recommendation to handle this expression and recover it's string?

antonmedv commented 1 month ago

This is how our parser and AST are designed. Brackets basically as comments. They disappear from the AST.

graph TD;
    b1["BinaryNode(-)"]-->i1["IntegerNode(1)"];
    b1-->b2["BinaryNode(-)"];
    b2-->i2["IntegerNode(1)"];
    b2-->i3["IntegerNode(1)"]

Parser uses operator precedence to decide on how to parse. And brackets can override operator precedence ((1+2)*3).

During string printing of AST, Expr also uses operator precedence to decide if it needed to add brackets. Or in some cases adds brackets for readability.