mirror of
				https://github.com/MontFerret/ferret.git
				synced 2025-10-30 23:37:40 +02:00 
			
		
		
		
	Feature/#1 array comparison operators (#71)
* #1 Added ALL IN * #1 Completed Array operator * #1 Fixed linting issues
This commit is contained in:
		| @@ -1632,6 +1632,329 @@ func TestInOperator(t *testing.T) { | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestArrayOperator(t *testing.T) { | ||||
| 	Convey("ALL", t, func() { | ||||
| 		Convey("[1,2,3] ALL IN [1,2,3] should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3] ALL IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[1,2,4] ALL IN [1,2,3] should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,4] ALL IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[4,5,6] ALL NOT IN [1,2,3] should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [4,5,6] ALL NOT IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[1,2,3] ALL > 0 should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3] ALL > 0 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[1,2,3] ALL > 2 should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3] ALL > 2 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[1,2,3] ALL >= 3 should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3] ALL >= 3 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("['foo','bar'] ALL != 'moo' should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN ['foo', 'bar'] ALL != 'moo' | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("ANY", t, func() { | ||||
| 		Convey("[1,2,3] ANY IN [1,2,3] should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3] ANY IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[4,2,5] ANY IN [1,2,3] should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [4,2,5] ANY IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[4,5,6] ANY IN [1,2,3] should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [4,5,6] ANY IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[4,5,6] ANY NOT IN [1,2,3] should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [4,5,6] ANY NOT IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[1,2,3 ] ANY == 2 should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3 ] ANY == 2 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[1,2,3 ] ANY == 4 should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3 ] ANY == 4 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("['foo','bar'] ANY == 'foo' should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN ['foo', 'bar'] ANY == 'foo' | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("NONE", t, func() { | ||||
| 		Convey("[1,2,3] NONE IN [1,2,3] should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3] NONE IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[4,2,5] NONE IN [1,2,3] should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [4,2,5] NONE IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[4,5,6] NONE IN [1,2,3] should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [4,5,6] NONE IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[4,5,6] NONE NOT IN [1,2,3] should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [4,5,6] NONE NOT IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[1,2,3] NONE > 99 should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3] NONE > 99 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[1,2,3] NONE < 99 should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3] NONE < 99 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("['foo','bar'] NONE == 'foo' should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN ['foo','bar'] NONE == 'foo' | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestForTernaryExpression(t *testing.T) { | ||||
| 	Convey("RETURN foo ? TRUE : (FOR i IN 1..5 RETURN i*2)", t, func() { | ||||
| 		c := compiler.New() | ||||
|   | ||||
| @@ -758,6 +758,132 @@ func (v *visitor) doVisitAllExpressions(contexts []fql.IExpressionContext, scope | ||||
| 	return ret, nil | ||||
| } | ||||
|  | ||||
| func (v *visitor) doVisitMathOperator(ctx *fql.ExpressionContext, scope *scope) (core.OperatorExpression, error) { | ||||
| 	mathOp := ctx.MathOperator().(*fql.MathOperatorContext) | ||||
| 	exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	left := exps[0] | ||||
| 	right := exps[1] | ||||
|  | ||||
| 	return operators.NewMathOperator( | ||||
| 		v.getSourceMap(mathOp), | ||||
| 		left, | ||||
| 		right, | ||||
| 		operators.MathOperatorType(mathOp.GetText()), | ||||
| 	) | ||||
| } | ||||
|  | ||||
| func (v *visitor) doVisitNotOperator(ctx *fql.ExpressionContext, scope *scope) (core.OperatorExpression, error) { | ||||
| 	exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	exp := exps[0] | ||||
|  | ||||
| 	return operators.NewLogicalOperator( | ||||
| 		v.getSourceMap(ctx), | ||||
| 		nil, | ||||
| 		exp, | ||||
| 		"NOT", | ||||
| 	) | ||||
| } | ||||
|  | ||||
| func (v *visitor) doVisitLogicalOperator(ctx *fql.ExpressionContext, scope *scope) (core.OperatorExpression, error) { | ||||
| 	logicalOp := ctx.LogicalOperator().(*fql.LogicalOperatorContext) | ||||
| 	exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	left := exps[0] | ||||
| 	right := exps[1] | ||||
|  | ||||
| 	return operators.NewLogicalOperator(v.getSourceMap(logicalOp), left, right, logicalOp.GetText()) | ||||
| } | ||||
|  | ||||
| func (v *visitor) doVisitEqualityOperator(ctx *fql.ExpressionContext, scope *scope) (core.OperatorExpression, error) { | ||||
| 	equalityOp := ctx.EqualityOperator().(*fql.EqualityOperatorContext) | ||||
| 	exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	left := exps[0] | ||||
| 	right := exps[1] | ||||
|  | ||||
| 	return operators.NewEqualityOperator(v.getSourceMap(equalityOp), left, right, equalityOp.GetText()) | ||||
| } | ||||
|  | ||||
| func (v *visitor) doVisitInOperator(ctx *fql.ExpressionContext, scope *scope) (core.OperatorExpression, error) { | ||||
| 	exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	left := exps[0] | ||||
| 	right := exps[1] | ||||
|  | ||||
| 	if len(exps) != 2 { | ||||
| 		return nil, v.unexpectedToken(ctx) | ||||
| 	} | ||||
|  | ||||
| 	return operators.NewInOperator( | ||||
| 		v.getSourceMap(ctx), | ||||
| 		left, | ||||
| 		right, | ||||
| 		ctx.Not() != nil, | ||||
| 	) | ||||
| } | ||||
|  | ||||
| func (v *visitor) doVisitArrayOperator(ctx *fql.ExpressionContext, scope *scope) (core.OperatorExpression, error) { | ||||
| 	var comparator core.OperatorExpression | ||||
| 	var err error | ||||
|  | ||||
| 	if ctx.InOperator() != nil { | ||||
| 		comparator, err = v.doVisitInOperator(ctx, scope) | ||||
| 	} else if ctx.EqualityOperator() != nil { | ||||
| 		comparator, err = v.doVisitEqualityOperator(ctx, scope) | ||||
| 	} else { | ||||
| 		return nil, v.unexpectedToken(ctx) | ||||
| 	} | ||||
|  | ||||
| 	exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if len(exps) != 2 { | ||||
| 		return nil, v.unexpectedToken(ctx) | ||||
| 	} | ||||
|  | ||||
| 	left := exps[0] | ||||
| 	right := exps[1] | ||||
|  | ||||
| 	aotype, err := operators.ToIsValidArrayOperatorType(ctx.ArrayOperator().GetText()) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return operators.NewArrayOperator( | ||||
| 		v.getSourceMap(ctx), | ||||
| 		left, | ||||
| 		right, | ||||
| 		aotype, | ||||
| 		comparator, | ||||
| 	) | ||||
| } | ||||
|  | ||||
| func (v *visitor) doVisitExpression(ctx *fql.ExpressionContext, scope *scope) (core.Expression, error) { | ||||
| 	variable := ctx.Variable() | ||||
|  | ||||
| @@ -819,52 +945,34 @@ func (v *visitor) doVisitExpression(ctx *fql.ExpressionContext, scope *scope) (c | ||||
| 		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 { | ||||
| 		equalityOp := equalityOp.(*fql.EqualityOperatorContext) | ||||
| 		exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		left := exps[0] | ||||
| 		right := exps[1] | ||||
|  | ||||
| 		return operators.NewEqualityOperator(v.getSourceMap(equalityOp), left, right, equalityOp.GetText()) | ||||
| 		return v.doVisitEqualityOperator(ctx, scope) | ||||
| 	} | ||||
|  | ||||
| 	logicalOp := ctx.LogicalOperator() | ||||
|  | ||||
| 	if logicalOp != nil { | ||||
| 		logicalOp := logicalOp.(*fql.LogicalOperatorContext) | ||||
| 		exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		left := exps[0] | ||||
| 		right := exps[1] | ||||
|  | ||||
| 		return operators.NewLogicalOperator(v.getSourceMap(logicalOp), left, right, logicalOp.GetText()) | ||||
| 		return v.doVisitLogicalOperator(ctx, scope) | ||||
| 	} | ||||
|  | ||||
| 	mathOp := ctx.MathOperator() | ||||
|  | ||||
| 	if mathOp != nil { | ||||
| 		mathOp := mathOp.(*fql.MathOperatorContext) | ||||
| 		exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		left := exps[0] | ||||
| 		right := exps[1] | ||||
|  | ||||
| 		return operators.NewMathOperator(v.getSourceMap(mathOp), left, right, mathOp.GetText()) | ||||
| 		return v.doVisitMathOperator(ctx, scope) | ||||
| 	} | ||||
|  | ||||
| 	questionCtx := ctx.QuestionMark() | ||||
| @@ -883,43 +991,10 @@ func (v *visitor) doVisitExpression(ctx *fql.ExpressionContext, scope *scope) (c | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	inOp := ctx.In() | ||||
|  | ||||
| 	if inOp != nil { | ||||
| 		exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		left := exps[0] | ||||
| 		right := exps[1] | ||||
|  | ||||
| 		return operators.NewInOperator( | ||||
| 			v.getSourceMap(ctx), | ||||
| 			left, | ||||
| 			right, | ||||
| 			ctx.Not() != nil, | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	notOp := ctx.Not() | ||||
|  | ||||
| 	if notOp != nil { | ||||
| 		exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		exp := exps[0] | ||||
|  | ||||
| 		return operators.NewLogicalOperator( | ||||
| 			v.getSourceMap(ctx), | ||||
| 			nil, | ||||
| 			exp, | ||||
| 			"NOT", | ||||
| 		) | ||||
| 		return v.doVisitNotOperator(ctx, scope) | ||||
| 	} | ||||
|  | ||||
| 	rangeOp := ctx.RangeOperator() | ||||
|   | ||||
| @@ -122,7 +122,6 @@ forExpressionReturn | ||||
|     | forExpression | ||||
|     ; | ||||
|  | ||||
|  | ||||
| variableDeclaration | ||||
|     : Let Identifier Assign expression | ||||
|     | Let Identifier Assign OpenParen forExpression CloseParen | ||||
| @@ -217,7 +216,8 @@ expression | ||||
|     | OpenParen expressionSequence CloseParen | ||||
|     | Plus expression | ||||
|     | Minus expression | ||||
|     | expression (Not)? In expression | ||||
|     | expression arrayOperator (Not)? (inOperator | equalityOperator) expression | ||||
|     | expression (Not)? inOperator expression | ||||
|     | Not expression | ||||
|     | expression QuestionMark expression? Colon expression | ||||
|     | rangeOperator | ||||
| @@ -239,6 +239,16 @@ forTernaryExpression | ||||
|     | expression QuestionMark OpenParen forExpression CloseParen Colon OpenParen forExpression CloseParen | ||||
|     ; | ||||
|  | ||||
| arrayOperator | ||||
|     : All | ||||
|     | Any | ||||
|     | None | ||||
|     ; | ||||
|  | ||||
| inOperator | ||||
|     : In | ||||
|     ; | ||||
|  | ||||
| equalityOperator | ||||
|     : Gt | ||||
|     | Lt | ||||
|   | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -300,6 +300,18 @@ func (s *BaseFqlParserListener) EnterForTernaryExpression(ctx *ForTernaryExpress | ||||
| // ExitForTernaryExpression is called when production forTernaryExpression is exited. | ||||
| func (s *BaseFqlParserListener) ExitForTernaryExpression(ctx *ForTernaryExpressionContext) {} | ||||
|  | ||||
| // EnterArrayOperator is called when production arrayOperator is entered. | ||||
| func (s *BaseFqlParserListener) EnterArrayOperator(ctx *ArrayOperatorContext) {} | ||||
|  | ||||
| // ExitArrayOperator is called when production arrayOperator is exited. | ||||
| func (s *BaseFqlParserListener) ExitArrayOperator(ctx *ArrayOperatorContext) {} | ||||
|  | ||||
| // EnterInOperator is called when production inOperator is entered. | ||||
| func (s *BaseFqlParserListener) EnterInOperator(ctx *InOperatorContext) {} | ||||
|  | ||||
| // ExitInOperator is called when production inOperator is exited. | ||||
| func (s *BaseFqlParserListener) ExitInOperator(ctx *InOperatorContext) {} | ||||
|  | ||||
| // EnterEqualityOperator is called when production equalityOperator is entered. | ||||
| func (s *BaseFqlParserListener) EnterEqualityOperator(ctx *EqualityOperatorContext) {} | ||||
|  | ||||
|   | ||||
| @@ -191,6 +191,14 @@ func (v *BaseFqlParserVisitor) VisitForTernaryExpression(ctx *ForTernaryExpressi | ||||
| 	return v.VisitChildren(ctx) | ||||
| } | ||||
|  | ||||
| func (v *BaseFqlParserVisitor) VisitArrayOperator(ctx *ArrayOperatorContext) interface{} { | ||||
| 	return v.VisitChildren(ctx) | ||||
| } | ||||
|  | ||||
| func (v *BaseFqlParserVisitor) VisitInOperator(ctx *InOperatorContext) interface{} { | ||||
| 	return v.VisitChildren(ctx) | ||||
| } | ||||
|  | ||||
| func (v *BaseFqlParserVisitor) VisitEqualityOperator(ctx *EqualityOperatorContext) interface{} { | ||||
| 	return v.VisitChildren(ctx) | ||||
| } | ||||
|   | ||||
| @@ -145,6 +145,12 @@ type FqlParserListener interface { | ||||
| 	// EnterForTernaryExpression is called when entering the forTernaryExpression production. | ||||
| 	EnterForTernaryExpression(c *ForTernaryExpressionContext) | ||||
|  | ||||
| 	// EnterArrayOperator is called when entering the arrayOperator production. | ||||
| 	EnterArrayOperator(c *ArrayOperatorContext) | ||||
|  | ||||
| 	// EnterInOperator is called when entering the inOperator production. | ||||
| 	EnterInOperator(c *InOperatorContext) | ||||
|  | ||||
| 	// EnterEqualityOperator is called when entering the equalityOperator production. | ||||
| 	EnterEqualityOperator(c *EqualityOperatorContext) | ||||
|  | ||||
| @@ -295,6 +301,12 @@ type FqlParserListener interface { | ||||
| 	// ExitForTernaryExpression is called when exiting the forTernaryExpression production. | ||||
| 	ExitForTernaryExpression(c *ForTernaryExpressionContext) | ||||
|  | ||||
| 	// ExitArrayOperator is called when exiting the arrayOperator production. | ||||
| 	ExitArrayOperator(c *ArrayOperatorContext) | ||||
|  | ||||
| 	// ExitInOperator is called when exiting the inOperator production. | ||||
| 	ExitInOperator(c *InOperatorContext) | ||||
|  | ||||
| 	// ExitEqualityOperator is called when exiting the equalityOperator production. | ||||
| 	ExitEqualityOperator(c *EqualityOperatorContext) | ||||
|  | ||||
|   | ||||
| @@ -145,6 +145,12 @@ type FqlParserVisitor interface { | ||||
| 	// Visit a parse tree produced by FqlParser#forTernaryExpression. | ||||
| 	VisitForTernaryExpression(ctx *ForTernaryExpressionContext) interface{} | ||||
|  | ||||
| 	// Visit a parse tree produced by FqlParser#arrayOperator. | ||||
| 	VisitArrayOperator(ctx *ArrayOperatorContext) interface{} | ||||
|  | ||||
| 	// Visit a parse tree produced by FqlParser#inOperator. | ||||
| 	VisitInOperator(ctx *InOperatorContext) interface{} | ||||
|  | ||||
| 	// Visit a parse tree produced by FqlParser#equalityOperator. | ||||
| 	VisitEqualityOperator(ctx *EqualityOperatorContext) interface{} | ||||
|  | ||||
|   | ||||
							
								
								
									
										25
									
								
								pkg/runtime/collections/hash-table.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								pkg/runtime/collections/hash-table.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| package collections | ||||
|  | ||||
| import "github.com/MontFerret/ferret/pkg/runtime/core" | ||||
|  | ||||
| func ToHashTable(iterator Iterator) (map[uint64]core.Value, error) { | ||||
| 	result := make(map[uint64]core.Value) | ||||
|  | ||||
| 	for iterator.HasNext() { | ||||
| 		val, _, err := iterator.Next() | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		h := val.Hash() | ||||
|  | ||||
| 		_, exists := result[h] | ||||
|  | ||||
| 		if !exists { | ||||
| 			result[h] = val | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| } | ||||
							
								
								
									
										8
									
								
								pkg/runtime/core/operator.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								pkg/runtime/core/operator.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| package core | ||||
|  | ||||
| import "context" | ||||
|  | ||||
| type OperatorExpression interface { | ||||
| 	Expression | ||||
| 	Eval(ctx context.Context, left, right Value) (Value, error) | ||||
| } | ||||
							
								
								
									
										193
									
								
								pkg/runtime/expressions/operators/array.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								pkg/runtime/expressions/operators/array.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,193 @@ | ||||
| package operators | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| ) | ||||
|  | ||||
| type ( | ||||
| 	ArrayOperatorType int | ||||
| 	ArrayOperator     struct { | ||||
| 		*baseOperator | ||||
| 		aotype     ArrayOperatorType | ||||
| 		comparator core.OperatorExpression | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	ArrayOperatorTypeAll  ArrayOperatorType = 0 | ||||
| 	ArrayOperatorTypeAny  ArrayOperatorType = 1 | ||||
| 	ArrayOperatorTypeNone ArrayOperatorType = 2 | ||||
| ) | ||||
|  | ||||
| func IsValidArrayOperatorType(aotype ArrayOperatorType) bool { | ||||
| 	switch aotype { | ||||
| 	case ArrayOperatorTypeAll, ArrayOperatorTypeAny, ArrayOperatorTypeNone: | ||||
| 		return true | ||||
| 	default: | ||||
| 		return false | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func ToIsValidArrayOperatorType(stype string) (ArrayOperatorType, error) { | ||||
| 	switch stype { | ||||
| 	case "ALL": | ||||
| 		return ArrayOperatorTypeAll, nil | ||||
| 	case "ANY": | ||||
| 		return ArrayOperatorTypeAny, nil | ||||
| 	case "NONE": | ||||
| 		return ArrayOperatorTypeNone, nil | ||||
| 	default: | ||||
| 		return ArrayOperatorType(-1), core.Error(core.ErrInvalidArgument, stype) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func NewArrayOperator( | ||||
| 	src core.SourceMap, | ||||
| 	left core.Expression, | ||||
| 	right core.Expression, | ||||
| 	aotype ArrayOperatorType, | ||||
| 	comparator core.OperatorExpression, | ||||
| ) (*ArrayOperator, error) { | ||||
| 	if left == nil { | ||||
| 		return nil, core.Error(core.ErrMissedArgument, "left expression") | ||||
| 	} | ||||
|  | ||||
| 	if right == nil { | ||||
| 		return nil, core.Error(core.ErrMissedArgument, "right expression") | ||||
| 	} | ||||
|  | ||||
| 	if IsValidArrayOperatorType(aotype) == false { | ||||
| 		return nil, core.Error(core.ErrInvalidArgument, "operator type") | ||||
| 	} | ||||
|  | ||||
| 	if comparator == nil { | ||||
| 		return nil, core.Error(core.ErrMissedArgument, "comparator expression") | ||||
| 	} | ||||
|  | ||||
| 	base := &baseOperator{src, left, right} | ||||
|  | ||||
| 	return &ArrayOperator{base, aotype, comparator}, nil | ||||
| } | ||||
|  | ||||
| func (operator *ArrayOperator) Exec(ctx context.Context, scope *core.Scope) (core.Value, error) { | ||||
| 	left, err := operator.left.Exec(ctx, scope) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.False, core.SourceError(operator.src, err) | ||||
| 	} | ||||
|  | ||||
| 	right, err := operator.right.Exec(ctx, scope) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.False, core.SourceError(operator.src, err) | ||||
| 	} | ||||
|  | ||||
| 	return operator.Eval(ctx, left, right) | ||||
| } | ||||
|  | ||||
| func (operator *ArrayOperator) Eval(ctx context.Context, left, right core.Value) (core.Value, error) { | ||||
| 	err := core.ValidateType(left, core.ArrayType) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		// TODO: Return the error? AQL just returns false | ||||
| 		return values.False, nil | ||||
| 	} | ||||
|  | ||||
| 	arr := left.(*values.Array) | ||||
|  | ||||
| 	switch operator.aotype { | ||||
| 	case ArrayOperatorTypeAll: | ||||
| 		return operator.all(ctx, arr, right) | ||||
| 	case ArrayOperatorTypeAny: | ||||
| 		return operator.any(ctx, arr, right) | ||||
| 	default: | ||||
| 		return operator.none(ctx, arr, right) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (operator *ArrayOperator) all(ctx context.Context, arr *values.Array, value core.Value) (core.Value, error) { | ||||
| 	result := values.False | ||||
| 	var err error | ||||
|  | ||||
| 	arr.ForEach(func(el core.Value, _ int) bool { | ||||
| 		out, e := operator.comparator.Eval(ctx, el, value) | ||||
|  | ||||
| 		if e != nil { | ||||
| 			err = e | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		if out == values.True { | ||||
| 			result = values.True | ||||
| 		} else { | ||||
| 			result = values.False | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		return true | ||||
| 	}) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.False, err | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
| func (operator *ArrayOperator) any(ctx context.Context, arr *values.Array, value core.Value) (core.Value, error) { | ||||
| 	result := values.False | ||||
| 	var err error | ||||
|  | ||||
| 	arr.ForEach(func(el core.Value, _ int) bool { | ||||
| 		out, e := operator.comparator.Eval(ctx, el, value) | ||||
|  | ||||
| 		if e != nil { | ||||
| 			err = e | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		if out == values.True { | ||||
| 			result = values.True | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		return true | ||||
| 	}) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.False, err | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
| func (operator *ArrayOperator) none(ctx context.Context, arr *values.Array, value core.Value) (core.Value, error) { | ||||
| 	result := values.False | ||||
| 	var err error | ||||
|  | ||||
| 	arr.ForEach(func(el core.Value, _ int) bool { | ||||
| 		out, e := operator.comparator.Eval(ctx, el, value) | ||||
|  | ||||
| 		if e != nil { | ||||
| 			err = e | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		if out == values.False { | ||||
| 			result = values.True | ||||
| 		} else { | ||||
| 			result = values.False | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		return true | ||||
| 	}) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.False, err | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| } | ||||
| @@ -8,11 +8,11 @@ import ( | ||||
| type ( | ||||
| 	EqualityOperator struct { | ||||
| 		*baseOperator | ||||
| 		fn Operator | ||||
| 		fn OperatorFunc | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| var equalityOperators = map[string]Operator{ | ||||
| var equalityOperators = map[string]OperatorFunc{ | ||||
| 	"==": Equal, | ||||
| 	"!=": NotEqual, | ||||
| 	">":  Greater, | ||||
| @@ -30,7 +30,7 @@ func NewEqualityOperator( | ||||
| 	fn, exists := equalityOperators[operator] | ||||
|  | ||||
| 	if !exists { | ||||
| 		return nil, core.Error(core.ErrInvalidArgument, "operator") | ||||
| 		return nil, core.Error(core.ErrInvalidArgument, "aotype") | ||||
| 	} | ||||
|  | ||||
| 	return &EqualityOperator{ | ||||
| @@ -52,5 +52,9 @@ func (operator *EqualityOperator) Exec(ctx context.Context, scope *core.Scope) ( | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return operator.Eval(ctx, left, right) | ||||
| } | ||||
|  | ||||
| func (operator *EqualityOperator) Eval(_ context.Context, left, right core.Value) (core.Value, error) { | ||||
| 	return operator.fn(left, right), nil | ||||
| } | ||||
|   | ||||
| @@ -17,11 +17,11 @@ func NewInOperator( | ||||
| 	right core.Expression, | ||||
| 	not bool, | ||||
| ) (*InOperator, error) { | ||||
| 	if core.IsNil(left) { | ||||
| 	if left == nil { | ||||
| 		return nil, core.Error(core.ErrMissedArgument, "left expression") | ||||
| 	} | ||||
|  | ||||
| 	if core.IsNil(right) { | ||||
| 	if right == nil { | ||||
| 		return nil, core.Error(core.ErrMissedArgument, "right expression") | ||||
| 	} | ||||
|  | ||||
| @@ -41,7 +41,11 @@ func (operator *InOperator) Exec(ctx context.Context, scope *core.Scope) (core.V | ||||
| 		return values.False, core.SourceError(operator.src, err) | ||||
| 	} | ||||
|  | ||||
| 	err = core.ValidateType(right, core.ArrayType) | ||||
| 	return operator.Eval(ctx, left, right) | ||||
| } | ||||
|  | ||||
| func (operator *InOperator) Eval(_ context.Context, left, right core.Value) (core.Value, error) { | ||||
| 	err := core.ValidateType(right, core.ArrayType) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		// TODO: Return the error? AQL just returns false | ||||
|   | ||||
| @@ -15,17 +15,17 @@ type ( | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	AndType LogicalOperatorType = 0 | ||||
| 	OrType  LogicalOperatorType = 1 | ||||
| 	NotType LogicalOperatorType = 2 | ||||
| 	LogicalOperatorTypeAnd LogicalOperatorType = 0 | ||||
| 	LogicalOperatorTypeOr  LogicalOperatorType = 1 | ||||
| 	LogicalOperatorTypeNot LogicalOperatorType = 2 | ||||
| ) | ||||
|  | ||||
| var logicalOperators = map[string]LogicalOperatorType{ | ||||
| 	"&&":  AndType, | ||||
| 	"AND": AndType, | ||||
| 	"||":  OrType, | ||||
| 	"OR":  OrType, | ||||
| 	"NOT": NotType, | ||||
| 	"&&":  LogicalOperatorTypeAnd, | ||||
| 	"AND": LogicalOperatorTypeAnd, | ||||
| 	"||":  LogicalOperatorTypeOr, | ||||
| 	"OR":  LogicalOperatorTypeOr, | ||||
| 	"NOT": LogicalOperatorTypeNot, | ||||
| } | ||||
|  | ||||
| func NewLogicalOperator( | ||||
| @@ -51,7 +51,7 @@ func NewLogicalOperator( | ||||
| } | ||||
|  | ||||
| func (operator *LogicalOperator) Exec(ctx context.Context, scope *core.Scope) (core.Value, error) { | ||||
| 	if operator.value == NotType { | ||||
| 	if operator.value == LogicalOperatorTypeNot { | ||||
| 		val, err := operator.right.Exec(ctx, scope) | ||||
|  | ||||
| 		if err != nil { | ||||
| @@ -69,7 +69,7 @@ func (operator *LogicalOperator) Exec(ctx context.Context, scope *core.Scope) (c | ||||
|  | ||||
| 	leftBool := values.ToBoolean(left) | ||||
|  | ||||
| 	if operator.value == AndType && leftBool == values.False { | ||||
| 	if operator.value == LogicalOperatorTypeAnd && leftBool == values.False { | ||||
| 		if left.Type() == core.BooleanType { | ||||
| 			return values.False, nil | ||||
| 		} | ||||
| @@ -77,7 +77,7 @@ func (operator *LogicalOperator) Exec(ctx context.Context, scope *core.Scope) (c | ||||
| 		return left, nil | ||||
| 	} | ||||
|  | ||||
| 	if operator.value == OrType && leftBool == values.True { | ||||
| 	if operator.value == LogicalOperatorTypeOr && leftBool == values.True { | ||||
| 		return left, nil | ||||
| 	} | ||||
|  | ||||
| @@ -89,3 +89,25 @@ func (operator *LogicalOperator) Exec(ctx context.Context, scope *core.Scope) (c | ||||
|  | ||||
| 	return right, nil | ||||
| } | ||||
|  | ||||
| func (operator *LogicalOperator) Eval(_ context.Context, left, right core.Value) (core.Value, error) { | ||||
| 	if operator.value == LogicalOperatorTypeNot { | ||||
| 		return Not(right, values.None), nil | ||||
| 	} | ||||
|  | ||||
| 	leftBool := values.ToBoolean(left) | ||||
|  | ||||
| 	if operator.value == LogicalOperatorTypeAnd && leftBool == values.False { | ||||
| 		if left.Type() == core.BooleanType { | ||||
| 			return values.False, nil | ||||
| 		} | ||||
|  | ||||
| 		return left, nil | ||||
| 	} | ||||
|  | ||||
| 	if operator.value == LogicalOperatorTypeOr && leftBool == values.True { | ||||
| 		return left, nil | ||||
| 	} | ||||
|  | ||||
| 	return right, nil | ||||
| } | ||||
|   | ||||
| @@ -6,32 +6,45 @@ import ( | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| ) | ||||
|  | ||||
| type MathOperator struct { | ||||
| 	*baseOperator | ||||
| 	fn       Operator | ||||
| 	leftOnly bool | ||||
| } | ||||
| type ( | ||||
| 	MathOperatorType string | ||||
| 	MathOperator     struct { | ||||
| 		*baseOperator | ||||
| 		fn       OperatorFunc | ||||
| 		leftOnly bool | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| var mathOperators = map[string]Operator{ | ||||
| 	"+":  Add, | ||||
| 	"-":  Subtract, | ||||
| 	"*":  Multiply, | ||||
| 	"/":  Divide, | ||||
| 	"%":  Modulus, | ||||
| 	"++": Increment, | ||||
| 	"--": Decrement, | ||||
| const ( | ||||
| 	MathOperatorTypeAdd       MathOperatorType = "+" | ||||
| 	MathOperatorTypeSubtract  MathOperatorType = "-" | ||||
| 	MathOperatorTypeMultiply  MathOperatorType = "*" | ||||
| 	MathOperatorTypeDivide    MathOperatorType = "/" | ||||
| 	MathOperatorTypeModulus   MathOperatorType = "%" | ||||
| 	MathOperatorTypeIncrement MathOperatorType = "++" | ||||
| 	MathOperatorTypeDecrement MathOperatorType = "--" | ||||
| ) | ||||
|  | ||||
| var mathOperators = map[MathOperatorType]OperatorFunc{ | ||||
| 	MathOperatorTypeAdd:       Add, | ||||
| 	MathOperatorTypeSubtract:  Subtract, | ||||
| 	MathOperatorTypeMultiply:  Multiply, | ||||
| 	MathOperatorTypeDivide:    Divide, | ||||
| 	MathOperatorTypeModulus:   Modulus, | ||||
| 	MathOperatorTypeIncrement: Increment, | ||||
| 	MathOperatorTypeDecrement: Decrement, | ||||
| } | ||||
|  | ||||
| func NewMathOperator( | ||||
| 	src core.SourceMap, | ||||
| 	left core.Expression, | ||||
| 	right core.Expression, | ||||
| 	operator string, | ||||
| 	operator MathOperatorType, | ||||
| ) (*MathOperator, error) { | ||||
| 	fn, exists := mathOperators[operator] | ||||
|  | ||||
| 	if !exists { | ||||
| 		return nil, core.Error(core.ErrInvalidArgument, "operator") | ||||
| 		return nil, core.Error(core.ErrInvalidArgument, "operator type") | ||||
| 	} | ||||
|  | ||||
| 	var leftOnly bool | ||||
| @@ -55,7 +68,7 @@ func (operator *MathOperator) Exec(ctx context.Context, scope *core.Scope) (core | ||||
| 	} | ||||
|  | ||||
| 	if operator.leftOnly { | ||||
| 		return operator.fn(left, values.None), nil | ||||
| 		return operator.Eval(ctx, left, values.None) | ||||
| 	} | ||||
|  | ||||
| 	right, err := operator.right.Exec(ctx, scope) | ||||
| @@ -64,5 +77,13 @@ func (operator *MathOperator) Exec(ctx context.Context, scope *core.Scope) (core | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return operator.Eval(ctx, left, right) | ||||
| } | ||||
|  | ||||
| func (operator *MathOperator) Eval(_ context.Context, left, right core.Value) (core.Value, error) { | ||||
| 	if operator.leftOnly { | ||||
| 		return operator.fn(left, values.None), nil | ||||
| 	} | ||||
|  | ||||
| 	return operator.fn(left, right), nil | ||||
| } | ||||
|   | ||||
| @@ -6,18 +6,23 @@ import ( | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| ) | ||||
|  | ||||
| type Operator func(left, right core.Value) core.Value | ||||
|  | ||||
| type baseOperator struct { | ||||
| 	src   core.SourceMap | ||||
| 	left  core.Expression | ||||
| 	right core.Expression | ||||
| } | ||||
| type ( | ||||
| 	OperatorFunc func(left, right core.Value) core.Value | ||||
| 	baseOperator struct { | ||||
| 		src   core.SourceMap | ||||
| 		left  core.Expression | ||||
| 		right core.Expression | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| func (operator *baseOperator) Exec(_ context.Context, _ *core.Scope) (core.Value, error) { | ||||
| 	return values.None, core.ErrInvalidOperation | ||||
| } | ||||
|  | ||||
| func (operator *baseOperator) Eval(_ context.Context, _, _ core.Value) (core.Value, error) { | ||||
| 	return values.None, core.ErrInvalidOperation | ||||
| } | ||||
|  | ||||
| // Equality | ||||
| func Equal(left, right core.Value) core.Value { | ||||
| 	if left.Compare(right) == 0 { | ||||
|   | ||||
| @@ -44,13 +44,17 @@ func (operator *RangeOperator) Exec(ctx context.Context, scope *core.Scope) (cor | ||||
| 		return values.None, core.SourceError(operator.src, err) | ||||
| 	} | ||||
|  | ||||
| 	err = core.ValidateType(left, core.IntType) | ||||
| 	right, err := operator.right.Exec(ctx, scope) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, core.SourceError(operator.src, err) | ||||
| 	} | ||||
|  | ||||
| 	right, err := operator.right.Exec(ctx, scope) | ||||
| 	return operator.Eval(ctx, left, right) | ||||
| } | ||||
|  | ||||
| func (operator *RangeOperator) Eval(_ context.Context, left, right core.Value) (core.Value, error) { | ||||
| 	err := core.ValidateType(left, core.IntType) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, core.SourceError(operator.src, err) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user