mirror of
https://github.com/MontFerret/ferret.git
synced 2025-11-06 08:39:09 +02:00
Feature/#293 regular exp operator (#326)
* Added Regexp operator * Added simple type check * Fixed linting issue
This commit is contained in:
77
pkg/compiler/compiler_regexp_test.go
Normal file
77
pkg/compiler/compiler_regexp_test.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package compiler_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"testing"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/compiler"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestRegexpOperator(t *testing.T) {
|
||||
Convey("Should be possible to use positive regular expression operator", t, func() {
|
||||
out := compiler.New().
|
||||
MustCompile(`
|
||||
RETURN "foo" =~ "^f[o].$"
|
||||
`).
|
||||
MustRun(context.Background())
|
||||
|
||||
So(string(out), ShouldEqual, `true`)
|
||||
})
|
||||
|
||||
Convey("Should be possible to use negative regular expression operator", t, func() {
|
||||
out := compiler.New().
|
||||
MustCompile(`
|
||||
RETURN "foo" !~ "[a-z]+bar$"
|
||||
`).
|
||||
MustRun(context.Background())
|
||||
|
||||
So(string(out), ShouldEqual, `true`)
|
||||
})
|
||||
|
||||
Convey("Should be possible to use negative regular expression operator", t, func() {
|
||||
c := compiler.New()
|
||||
c.RegisterFunction("T::REGEXP", func(_ context.Context, _ ...core.Value) (value core.Value, e error) {
|
||||
return values.NewString("[a-z]+bar$"), nil
|
||||
})
|
||||
|
||||
out := c.
|
||||
MustCompile(`
|
||||
RETURN "foo" !~ T::REGEXP()
|
||||
`).
|
||||
MustRun(context.Background())
|
||||
|
||||
So(string(out), ShouldEqual, `true`)
|
||||
})
|
||||
|
||||
Convey("Should return an error during compilation when a regexp string invalid", t, func() {
|
||||
_, err := compiler.New().
|
||||
Compile(`
|
||||
RETURN "foo" !~ "[ ]\K(?<!\d )(?=(?: ?\d){8})(?!(?: ?\d){9})\d[ \d]+\d"
|
||||
`)
|
||||
|
||||
So(err, ShouldBeError)
|
||||
})
|
||||
|
||||
Convey("Should return an error during compilation when a regexp is not a string", t, func() {
|
||||
right := []string{
|
||||
"[]",
|
||||
"{}",
|
||||
"1",
|
||||
"1.1",
|
||||
"TRUE",
|
||||
}
|
||||
|
||||
for _, r := range right {
|
||||
_, err := compiler.New().
|
||||
Compile(fmt.Sprintf(`
|
||||
RETURN "foo" !~ %s
|
||||
`, r))
|
||||
|
||||
So(err, ShouldBeError)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package compiler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -1187,6 +1188,36 @@ func (v *visitor) doVisitEqualityOperator(ctx *fql.ExpressionContext, scope *sco
|
||||
return operators.NewEqualityOperator(v.getSourceMap(equalityOp), left, right, equalityOp.GetText())
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitRegexpOperator(ctx *fql.ExpressionContext, scope *scope) (core.Expression, error) {
|
||||
regexpOp := ctx.RegexpOperator().(*fql.RegexpOperatorContext)
|
||||
rawExps := ctx.AllExpression()
|
||||
exps, err := v.doVisitAllExpressions(rawExps, scope)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
left := exps[0]
|
||||
right := exps[1]
|
||||
|
||||
switch lit := right.(type) {
|
||||
case literals.StringLiteral:
|
||||
_, err := regexp.Compile(string(lit))
|
||||
|
||||
if err != nil {
|
||||
src := v.getSourceMap(rawExps[1])
|
||||
|
||||
return nil, errors.Wrap(err, src.String())
|
||||
}
|
||||
case *literals.ArrayLiteral, *literals.ObjectLiteral, literals.BooleanLiteral, literals.FloatLiteral, literals.IntLiteral:
|
||||
src := v.getSourceMap(rawExps[1])
|
||||
|
||||
return nil, errors.Wrap(errors.New("expected a string literal or a function call"), src.String())
|
||||
}
|
||||
|
||||
return operators.NewRegexpOperator(v.getSourceMap(regexpOp), left, right, regexpOp.GetText())
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitInOperator(ctx *fql.ExpressionContext, scope *scope) (core.OperatorExpression, error) {
|
||||
exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope)
|
||||
|
||||
@@ -1333,6 +1364,12 @@ func (v *visitor) doVisitExpression(ctx *fql.ExpressionContext, scope *scope) (c
|
||||
return v.doVisitLogicalOperator(ctx, scope)
|
||||
}
|
||||
|
||||
regexpOp := ctx.RegexpOperator()
|
||||
|
||||
if regexpOp != nil {
|
||||
return v.doVisitRegexpOperator(ctx, scope)
|
||||
}
|
||||
|
||||
variable := ctx.Variable()
|
||||
|
||||
if variable != nil {
|
||||
|
||||
Reference in New Issue
Block a user