ParseExpr parses an expression by building the binary expression tree.
()
| 214 | |
| 215 | // ParseExpr parses an expression by building the binary expression tree. |
| 216 | func (p *Parser) ParseExpr() (Expr, error) { |
| 217 | var err error |
| 218 | root := &BinaryExpr{} |
| 219 | // parse a non-binary expression type to start. This variable will always be |
| 220 | // the root of the expression tree. |
| 221 | root.RHS, err = p.parseUnaryExpr() |
| 222 | if err != nil { |
| 223 | return nil, err |
| 224 | } |
| 225 | |
| 226 | // loop over operations and unary exprs and build a tree based on precedence. |
| 227 | for { |
| 228 | // if the next token is NOT an operator then return the expression. |
| 229 | op, pos, lit := p.scanIgnoreWhitespace() |
| 230 | if !op.isOperator() { |
| 231 | p.unscan() |
| 232 | if op != EOF && op != Rparen && op != Comma && op != Pipe { |
| 233 | return nil, newParseError(tokstr(op, lit), []string{"operator", "')'", "','", "'|'"}, pos, p.expr) |
| 234 | } |
| 235 | return root.RHS, nil |
| 236 | } |
| 237 | |
| 238 | if op == In || op == IIn { |
| 239 | // expect LPAREN after in |
| 240 | tok, pos, lit := p.scanIgnoreWhitespace() |
| 241 | p.unscan() |
| 242 | if tok != Lparen && (p.c != nil && !p.c.IsMacroList(lit)) { |
| 243 | return nil, newParseError(tokstr(op, lit), []string{"'('"}, pos, p.expr) |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | var rhs Expr |
| 248 | switch op { |
| 249 | case Not: |
| 250 | // the first variant of the negation operator. |
| 251 | // The operator that is negated appears immediately |
| 252 | // after the `not` operator, e.g. ps.name not in ('cmd.exe') |
| 253 | op1, pos, lit := p.scanIgnoreWhitespace() |
| 254 | if !op1.isOperator() { |
| 255 | return nil, newParseError(tokstr(op, lit), []string{"operator"}, pos, p.expr) |
| 256 | } |
| 257 | // parse the next expression after operator |
| 258 | rhs1, err := p.parseUnaryExpr() |
| 259 | if err != nil { |
| 260 | return nil, err |
| 261 | } |
| 262 | rhs = &BinaryExpr{RHS: rhs1, Op: op1} |
| 263 | default: |
| 264 | op1, _, _ := p.scanIgnoreWhitespace() |
| 265 | // if the negation appears after the operator |
| 266 | // try to parse an entire binary expr and wrap |
| 267 | // it inside the `not` expression. This is the |
| 268 | // second variant of the negating expressions, e.g. |
| 269 | // ps.name = 'cmd.exe' and not (ps.name in ('powershell.exe')) |
| 270 | if op1 == Not { |
| 271 | binaryExpr, err := p.ParseExpr() |
| 272 | if err != nil { |
| 273 | return nil, err |