From 4992a006e4f958b344af67fe4b99c10e7f6905cb Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Mon, 24 Nov 2014 23:12:32 -0700 Subject: [PATCH] Add ParenExpr. --- influxql/ast.go | 10 ++++++++++ influxql/parser.go | 16 ++++++++++++++++ influxql/parser_test.go | 22 +++++++++++++++++++--- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/influxql/ast.go b/influxql/ast.go index 59c9add9de..f60935e58f 100644 --- a/influxql/ast.go +++ b/influxql/ast.go @@ -46,6 +46,7 @@ func (_ *BooleanLiteral) node() {} func (_ *TimeLiteral) node() {} func (_ *DurationLiteral) node() {} func (_ *BinaryExpr) node() {} +func (_ *ParenExpr) node() {} // Query represents a collection of order statements. type Query struct { @@ -83,6 +84,7 @@ func (_ *BooleanLiteral) expr() {} func (_ *TimeLiteral) expr() {} func (_ *DurationLiteral) expr() {} func (_ *BinaryExpr) expr() {} +func (_ *ParenExpr) expr() {} // Source represents a source of data for a statement. type Source interface { @@ -227,6 +229,11 @@ type BinaryExpr struct { RHS Expr } +// ParenExpr represents a parenthesized expression. +type ParenExpr struct { + Expr Expr +} + // Visitor can be called by Walk to traverse an AST hierarchy. // The Visit() function is called once per node. type Visitor interface { @@ -274,6 +281,9 @@ func Walk(v Visitor, node Node) { Walk(v, n.LHS) Walk(v, n.RHS) + case *ParenExpr: + Walk(v, n.Expr) + case *Call: for _, expr := range n.Args { Walk(v, expr) diff --git a/influxql/parser.go b/influxql/parser.go index 7f134d6f1c..8dfcb977bc 100644 --- a/influxql/parser.go +++ b/influxql/parser.go @@ -487,6 +487,22 @@ func (p *Parser) ParseExpr() (Expr, error) { // parseUnaryExpr parses an non-binary expression. func (p *Parser) parseUnaryExpr() (Expr, error) { + // If the first token is a LPAREN then parse it as its own grouped expression. + if tok, _, _ := p.scanIgnoreWhitespace(); tok == LPAREN { + expr, err := p.ParseExpr() + if err != nil { + return nil, err + } + + // Expect an RPAREN at the end. + if tok, pos, lit := p.scanIgnoreWhitespace(); tok != RPAREN { + return nil, newParseError(tokstr(tok, lit), []string{")"}, pos) + } + + return &ParenExpr{Expr: expr}, nil + } + p.unscan() + // Read next token. tok, pos, lit := p.scanIgnoreWhitespace() switch tok { diff --git a/influxql/parser_test.go b/influxql/parser_test.go index d23ec4308a..015e7f8bee 100644 --- a/influxql/parser_test.go +++ b/influxql/parser_test.go @@ -216,7 +216,23 @@ func TestParser_ParseExpr(t *testing.T) { }, }, - // 8. Complex binary expression. + // 8. Binary expression with LHS paren group. + { + s: `(1 + 2) * 3`, + expr: &influxql.BinaryExpr{ + Op: influxql.MUL, + LHS: &influxql.ParenExpr{ + Expr: &influxql.BinaryExpr{ + Op: influxql.ADD, + LHS: &influxql.NumberLiteral{Val: 1}, + RHS: &influxql.NumberLiteral{Val: 2}, + }, + }, + RHS: &influxql.NumberLiteral{Val: 3}, + }, + }, + + // 9. Complex binary expression. { s: `value + 3 < 30 AND 1 + 2 OR true`, expr: &influxql.BinaryExpr{ @@ -242,7 +258,7 @@ func TestParser_ParseExpr(t *testing.T) { }, }, - // 9. Function call (empty) + // 10. Function call (empty) { s: `my_func()`, expr: &influxql.Call{ @@ -250,7 +266,7 @@ func TestParser_ParseExpr(t *testing.T) { }, }, - // 10. Function call (multi-arg) + // 11. Function call (multi-arg) { s: `my_func(1, 2 + 3)`, expr: &influxql.Call{