mirror of
https://github.com/MontFerret/ferret.git
synced 2025-11-06 08:39:09 +02:00
Next (#214)
* Renamed DOCUMENT to PAGE * Added PageLoadParams * Added PageLoadParams * Renamed LoadPageParams -> PageLoadParams * Added support for context.Done() (#201) * Bug/#189 operators precedence (#202) * Fixed math operators precedence * Fixed logical operators precedence * Fixed array operator * Added support for parentheses to enforce a different operator evaluation order * Feature/#200 drivers (#209) * Added new interfaces * Renamed dynamic to cdp driver * Renamed drivers * Added ELEMENT_EXISTS function (#210) * Renamed back PAGE to DOCUMENT (#211) * Added Getter and Setter interfaces
This commit is contained in:
65
pkg/compiler/compiler_precedence_test.go
Normal file
65
pkg/compiler/compiler_precedence_test.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package compiler_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/MontFerret/ferret/pkg/compiler"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestPrecedence(t *testing.T) {
|
||||
Convey("Math operators", t, func() {
|
||||
Convey("2 + 2 * 2", func() {
|
||||
c := compiler.New()
|
||||
|
||||
p := c.MustCompile(`RETURN 2 + 2 * 2`)
|
||||
|
||||
out := p.MustRun(context.Background())
|
||||
|
||||
So(string(out), ShouldEqual, "6")
|
||||
})
|
||||
|
||||
Convey("2 * 2 + 2", func() {
|
||||
c := compiler.New()
|
||||
|
||||
p := c.MustCompile(`RETURN 2 * 2 + 2`)
|
||||
|
||||
out := p.MustRun(context.Background())
|
||||
|
||||
So(string(out), ShouldEqual, "6")
|
||||
})
|
||||
|
||||
Convey("2 * (2 + 2)", func() {
|
||||
c := compiler.New()
|
||||
|
||||
p := c.MustCompile(`RETURN 2 * (2 + 2)`)
|
||||
|
||||
out := p.MustRun(context.Background())
|
||||
|
||||
So(string(out), ShouldEqual, "8")
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Logical", t, func() {
|
||||
Convey("TRUE OR TRUE AND FALSE", func() {
|
||||
c := compiler.New()
|
||||
|
||||
p := c.MustCompile(`RETURN TRUE OR TRUE AND FALSE`)
|
||||
|
||||
out := p.MustRun(context.Background())
|
||||
|
||||
So(string(out), ShouldEqual, "true")
|
||||
})
|
||||
|
||||
Convey("FALSE AND TRUE OR TRUE", func() {
|
||||
c := compiler.New()
|
||||
|
||||
p := c.MustCompile(`RETURN FALSE AND TRUE OR TRUE`)
|
||||
|
||||
out := p.MustRun(context.Background())
|
||||
|
||||
So(string(out), ShouldEqual, "true")
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -352,10 +352,16 @@ func (v *visitor) doVisitFilterClause(ctx *fql.FilterClauseContext, scope *scope
|
||||
return operators.NewEqualityOperator(v.getSourceMap(ctx), left, right, equalityOp.GetText())
|
||||
}
|
||||
|
||||
logicalOp := exp.LogicalOperator()
|
||||
logicalAndOp := exp.LogicalAndOperator()
|
||||
|
||||
if logicalOp != nil {
|
||||
return operators.NewLogicalOperator(v.getSourceMap(ctx), left, right, logicalOp.GetText())
|
||||
if logicalAndOp != nil {
|
||||
return operators.NewLogicalOperator(v.getSourceMap(ctx), left, right, logicalAndOp.GetText())
|
||||
}
|
||||
|
||||
logicalOrOp := exp.LogicalOrOperator()
|
||||
|
||||
if logicalOrOp != nil {
|
||||
return operators.NewLogicalOperator(v.getSourceMap(ctx), left, right, logicalOrOp.GetText())
|
||||
}
|
||||
} else {
|
||||
// should be unary operator
|
||||
@@ -1078,7 +1084,21 @@ func (v *visitor) doVisitAllExpressions(contexts []fql.IExpressionContext, scope
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitMathOperator(ctx *fql.ExpressionContext, scope *scope) (core.OperatorExpression, error) {
|
||||
mathOp := ctx.MathOperator().(*fql.MathOperatorContext)
|
||||
var operator operators.MathOperatorType
|
||||
multiCtx := ctx.MultiplicativeOperator()
|
||||
|
||||
if multiCtx != nil {
|
||||
operator = operators.MathOperatorType(multiCtx.GetText())
|
||||
} else {
|
||||
additiveCtx := ctx.AdditiveOperator()
|
||||
|
||||
if additiveCtx == nil {
|
||||
return nil, ErrInvalidToken
|
||||
}
|
||||
|
||||
operator = operators.MathOperatorType(additiveCtx.GetText())
|
||||
}
|
||||
|
||||
exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope)
|
||||
|
||||
if err != nil {
|
||||
@@ -1089,10 +1109,10 @@ func (v *visitor) doVisitMathOperator(ctx *fql.ExpressionContext, scope *scope)
|
||||
right := exps[1]
|
||||
|
||||
return operators.NewMathOperator(
|
||||
v.getSourceMap(mathOp),
|
||||
v.getSourceMap(ctx),
|
||||
left,
|
||||
right,
|
||||
operators.MathOperatorType(mathOp.GetText()),
|
||||
operator,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1115,7 +1135,22 @@ func (v *visitor) doVisitUnaryOperator(ctx *fql.ExpressionContext, scope *scope)
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitLogicalOperator(ctx *fql.ExpressionContext, scope *scope) (core.OperatorExpression, error) {
|
||||
logicalOp := ctx.LogicalOperator().(*fql.LogicalOperatorContext)
|
||||
var operator string
|
||||
|
||||
logicalAndOp := ctx.LogicalAndOperator()
|
||||
|
||||
if logicalAndOp != nil {
|
||||
operator = logicalAndOp.GetText()
|
||||
} else {
|
||||
logicalOrOp := ctx.LogicalOrOperator()
|
||||
|
||||
if logicalOrOp == nil {
|
||||
return nil, ErrInvalidToken
|
||||
}
|
||||
|
||||
operator = logicalOrOp.GetText()
|
||||
}
|
||||
|
||||
exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope)
|
||||
|
||||
if err != nil {
|
||||
@@ -1125,7 +1160,7 @@ func (v *visitor) doVisitLogicalOperator(ctx *fql.ExpressionContext, scope *scop
|
||||
left := exps[0]
|
||||
right := exps[1]
|
||||
|
||||
return operators.NewLogicalOperator(v.getSourceMap(logicalOp), left, right, logicalOp.GetText())
|
||||
return operators.NewLogicalOperator(v.getSourceMap(ctx), left, right, operator)
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitEqualityOperator(ctx *fql.ExpressionContext, scope *scope) (core.OperatorExpression, error) {
|
||||
@@ -1206,13 +1241,83 @@ func (v *visitor) doVisitArrayOperator(ctx *fql.ExpressionContext, scope *scope)
|
||||
)
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitExpressionGroup(ctx *fql.ExpressionGroupContext, scope *scope) (core.Expression, error) {
|
||||
exp := ctx.Expression()
|
||||
|
||||
if exp == nil {
|
||||
return nil, ErrInvalidToken
|
||||
}
|
||||
|
||||
return v.doVisitExpression(exp.(*fql.ExpressionContext), scope)
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitExpression(ctx *fql.ExpressionContext, scope *scope) (core.Expression, error) {
|
||||
seq := ctx.ExpressionGroup()
|
||||
|
||||
if seq != nil {
|
||||
return v.doVisitExpressionGroup(seq.(*fql.ExpressionGroupContext), scope)
|
||||
}
|
||||
|
||||
member := ctx.MemberExpression()
|
||||
|
||||
if member != nil {
|
||||
return v.doVisitMemberExpression(member.(*fql.MemberExpressionContext), scope)
|
||||
}
|
||||
|
||||
funCall := ctx.FunctionCallExpression()
|
||||
|
||||
if funCall != nil {
|
||||
return v.doVisitFunctionCallExpression(funCall.(*fql.FunctionCallExpressionContext), scope)
|
||||
}
|
||||
|
||||
notOp := ctx.UnaryOperator()
|
||||
|
||||
if notOp != nil {
|
||||
return v.doVisitUnaryOperator(ctx, scope)
|
||||
}
|
||||
|
||||
multiOp := ctx.MultiplicativeOperator()
|
||||
|
||||
if multiOp != nil {
|
||||
return v.doVisitMathOperator(ctx, scope)
|
||||
}
|
||||
|
||||
addOp := ctx.AdditiveOperator()
|
||||
|
||||
if addOp != nil {
|
||||
return v.doVisitMathOperator(ctx, scope)
|
||||
}
|
||||
|
||||
arrOp := ctx.ArrayOperator()
|
||||
|
||||
if arrOp != nil {
|
||||
return v.doVisitArrayOperator(ctx, scope)
|
||||
}
|
||||
|
||||
equalityOp := ctx.EqualityOperator()
|
||||
|
||||
if equalityOp != nil {
|
||||
return v.doVisitEqualityOperator(ctx, scope)
|
||||
}
|
||||
|
||||
inOp := ctx.InOperator()
|
||||
|
||||
if inOp != nil {
|
||||
return v.doVisitInOperator(ctx, scope)
|
||||
}
|
||||
|
||||
logicalAndOp := ctx.LogicalAndOperator()
|
||||
|
||||
if logicalAndOp != nil {
|
||||
return v.doVisitLogicalOperator(ctx, scope)
|
||||
}
|
||||
|
||||
logicalOrOp := ctx.LogicalOrOperator()
|
||||
|
||||
if logicalOrOp != nil {
|
||||
return v.doVisitLogicalOperator(ctx, scope)
|
||||
}
|
||||
|
||||
variable := ctx.Variable()
|
||||
|
||||
if variable != nil {
|
||||
@@ -1255,54 +1360,12 @@ func (v *visitor) doVisitExpression(ctx *fql.ExpressionContext, scope *scope) (c
|
||||
return v.doVisitObjectLiteral(obj.(*fql.ObjectLiteralContext), scope)
|
||||
}
|
||||
|
||||
funCall := ctx.FunctionCallExpression()
|
||||
|
||||
if funCall != nil {
|
||||
return v.doVisitFunctionCallExpression(funCall.(*fql.FunctionCallExpressionContext), scope)
|
||||
}
|
||||
|
||||
member := ctx.MemberExpression()
|
||||
|
||||
if member != nil {
|
||||
return v.doVisitMemberExpression(member.(*fql.MemberExpressionContext), scope)
|
||||
}
|
||||
|
||||
none := ctx.NoneLiteral()
|
||||
|
||||
if none != nil {
|
||||
return v.doVisitNoneLiteral(none.(*fql.NoneLiteralContext))
|
||||
}
|
||||
|
||||
arrOp := ctx.ArrayOperator()
|
||||
|
||||
if arrOp != nil {
|
||||
return v.doVisitArrayOperator(ctx, scope)
|
||||
}
|
||||
|
||||
inOp := ctx.InOperator()
|
||||
|
||||
if inOp != nil {
|
||||
return v.doVisitInOperator(ctx, scope)
|
||||
}
|
||||
|
||||
equalityOp := ctx.EqualityOperator()
|
||||
|
||||
if equalityOp != nil {
|
||||
return v.doVisitEqualityOperator(ctx, scope)
|
||||
}
|
||||
|
||||
logicalOp := ctx.LogicalOperator()
|
||||
|
||||
if logicalOp != nil {
|
||||
return v.doVisitLogicalOperator(ctx, scope)
|
||||
}
|
||||
|
||||
mathOp := ctx.MathOperator()
|
||||
|
||||
if mathOp != nil {
|
||||
return v.doVisitMathOperator(ctx, scope)
|
||||
}
|
||||
|
||||
questionCtx := ctx.QuestionMark()
|
||||
|
||||
if questionCtx != nil {
|
||||
|
||||
Reference in New Issue
Block a user